Add runtime registers, testing for TLB to XHCI
This commit is contained in:
+4
-2
@@ -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); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
use syscall::io::Mmio;
|
||||
|
||||
pub struct EventRingSte {
|
||||
pub address: Mmio<u64>,
|
||||
pub size: Mmio<u16>,
|
||||
_rsvd: Mmio<u16>,
|
||||
_rsvd2: Mmio<u32>,
|
||||
}
|
||||
@@ -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<u32>,
|
||||
}
|
||||
|
||||
pub struct XhciInterrupter {
|
||||
iman: Mmio<u32>,
|
||||
imod: Mmio<u32>,
|
||||
erstsz: Mmio<u32>,
|
||||
_rsvd: Mmio<u32>,
|
||||
erstba: Mmio<u64>,
|
||||
erdp: Mmio<u64>,
|
||||
}
|
||||
|
||||
pub struct XhciRun {
|
||||
mfindex: Mmio<u32>,
|
||||
_rsvd: [Mmio<u32>; 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<Dma<XhciDeviceContext>>,
|
||||
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());
|
||||
}
|
||||
}
|
||||
@@ -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<RefCell<Pty>>,
|
||||
flags: usize,
|
||||
}
|
||||
|
||||
impl PtyTermios {
|
||||
pub fn new(pty: Weak<RefCell<Pty>>, flags: usize) -> Self {
|
||||
PtyTermios {
|
||||
pty: pty,
|
||||
flags: flags,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Resource for PtyTermios {
|
||||
fn boxed_clone(&self) -> Box<Resource> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
|
||||
fn pty(&self) -> Weak<RefCell<Pty>> {
|
||||
self.pty.clone()
|
||||
}
|
||||
|
||||
fn flags(&self) -> usize {
|
||||
self.flags
|
||||
}
|
||||
|
||||
fn path(&self, buf: &mut [u8]) -> Result<usize> {
|
||||
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<usize> {
|
||||
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<usize> {
|
||||
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<usize> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn fcntl(&mut self, cmd: usize, arg: usize) -> Result<usize> {
|
||||
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<usize> {
|
||||
None
|
||||
}
|
||||
}
|
||||
@@ -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<u64>,
|
||||
pub status: Mmio<u32>,
|
||||
pub control: Mmio<u32>,
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user