From b4209a6a9ca0527f2a0981e1eb4c6d73d25b2e26 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 27 Jul 2017 21:01:42 -0600 Subject: [PATCH] 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 - } -}