Update Red Bear driver substrate
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -61,6 +61,23 @@ index 94a1eb17..3fd91156 100644
|
|||||||
+ Ok(values) => {
|
+ Ok(values) => {
|
||||||
+ log::debug!("{}._PS0 => {:?}", device_path, values);
|
+ log::debug!("{}._PS0 => {:?}", device_path, values);
|
||||||
+ }
|
+ }
|
||||||
|
@@
|
||||||
|
while let Some((descriptor, len)) = AnyDescriptor::parse(&data[i..]) {
|
||||||
|
descriptors.push(descriptor);
|
||||||
|
i += len;
|
||||||
|
}
|
||||||
|
+ let descriptor_count = descriptors.len();
|
||||||
|
+
|
||||||
|
+ if i < data.len() {
|
||||||
|
+ log::warn!(
|
||||||
|
+ "port {} slot {} config {} descriptor parsing stopped early at byte {} of {}",
|
||||||
|
+ port_id,
|
||||||
|
+ slot,
|
||||||
|
+ index,
|
||||||
|
+ i,
|
||||||
|
+ data.len()
|
||||||
|
+ );
|
||||||
|
+ }
|
||||||
+ Err(error) => {
|
+ Err(error) => {
|
||||||
+ log::warn!("Failed to power on {} with _PS0: {:?}", device_path, error);
|
+ log::warn!("Failed to power on {} with _PS0: {:?}", device_path, error);
|
||||||
+ }
|
+ }
|
||||||
@@ -1039,3 +1056,300 @@ index 670a5526..24ce3d68 100644
|
|||||||
}
|
}
|
||||||
UnitKind::Target {} => {
|
UnitKind::Target {} => {
|
||||||
if config.log_debug {
|
if config.log_debug {
|
||||||
|
diff --git a/drivers/storage/usbscsid/src/main.rs b/drivers/storage/usbscsid/src/main.rs
|
||||||
|
--- a/drivers/storage/usbscsid/src/main.rs
|
||||||
|
+++ b/drivers/storage/usbscsid/src/main.rs
|
||||||
|
@@
|
||||||
|
fn main() {
|
||||||
|
daemon::Daemon::new(daemon);
|
||||||
|
}
|
||||||
|
fn daemon(daemon: daemon::Daemon) -> ! {
|
||||||
|
- let mut args = env::args().skip(1);
|
||||||
|
+ if let Err(err) = run(daemon) {
|
||||||
|
+ eprintln!("usbscsid: startup failed: {err}");
|
||||||
|
+ std::process::exit(1);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ std::process::exit(0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+fn run(daemon: daemon::Daemon) -> Result<(), String> {
|
||||||
|
+ let mut args = env::args().skip(1);
|
||||||
|
|
||||||
|
const USAGE: &'static str = "usbscsid <scheme> <port> <protocol>";
|
||||||
|
|
||||||
|
- let scheme = args.next().expect(USAGE);
|
||||||
|
- let port = args
|
||||||
|
- .next()
|
||||||
|
- .expect(USAGE)
|
||||||
|
- .parse::<PortId>()
|
||||||
|
- .expect("Expected port ID");
|
||||||
|
- let protocol = args
|
||||||
|
- .next()
|
||||||
|
- .expect(USAGE)
|
||||||
|
- .parse::<u8>()
|
||||||
|
- .expect("protocol has to be a number 0-255");
|
||||||
|
+ let scheme = args.next().ok_or_else(|| USAGE.to_string())?;
|
||||||
|
+ let port_arg = args.next().ok_or_else(|| USAGE.to_string())?;
|
||||||
|
+ let protocol_arg = args.next().ok_or_else(|| USAGE.to_string())?;
|
||||||
|
+ let port = port_arg
|
||||||
|
+ .parse::<PortId>()
|
||||||
|
+ .map_err(|err| format!("invalid port id `{port_arg}`: {err}"))?;
|
||||||
|
+ let protocol = protocol_arg
|
||||||
|
+ .parse::<u8>()
|
||||||
|
+ .map_err(|err| format!("invalid protocol `{protocol_arg}`: {err}"))?;
|
||||||
|
@@
|
||||||
|
- let handle =
|
||||||
|
- XhciClientHandle::new(scheme.to_owned(), port).expect("Failed to open XhciClientHandle");
|
||||||
|
+ let handle = XhciClientHandle::new(scheme.to_owned(), port)
|
||||||
|
+ .map_err(|err| format!("failed to open XHCI client handle: {err}"))?;
|
||||||
|
|
||||||
|
let desc = handle
|
||||||
|
.get_standard_descs()
|
||||||
|
- .expect("Failed to get standard descriptors");
|
||||||
|
+ .map_err(|err| format!("failed to get standard descriptors: {err}"))?;
|
||||||
|
@@
|
||||||
|
- .expect("Failed to find suitable configuration");
|
||||||
|
+ .ok_or_else(|| "failed to find suitable BOT configuration".to_string())?;
|
||||||
|
@@
|
||||||
|
- .expect("Failed to configure endpoints");
|
||||||
|
+ .map_err(|err| format!("failed to configure endpoints: {err}"))?;
|
||||||
|
|
||||||
|
- 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)
|
||||||
|
+ .map_err(|err| format!("failed to setup protocol: {err}"))?;
|
||||||
|
@@
|
||||||
|
- let mut scsi = Scsi::new(&mut *protocol).expect("usbscsid: failed to setup SCSI");
|
||||||
|
+ let mut scsi =
|
||||||
|
+ Scsi::new(&mut *protocol).map_err(|err| format!("failed to setup SCSI: {err}"))?;
|
||||||
|
println!("SCSI initialized");
|
||||||
|
- let mut buffer = [0u8; 512];
|
||||||
|
- scsi.read(&mut *protocol, 0, &mut buffer).unwrap();
|
||||||
|
- println!("DISK CONTENT: {}", base64::encode(&buffer[..]));
|
||||||
|
|
||||||
|
- let event_queue = event::EventQueue::new().unwrap();
|
||||||
|
+ let event_queue =
|
||||||
|
+ event::EventQueue::new().map_err(|err| format!("failed to create event queue: {err}"))?;
|
||||||
|
@@
|
||||||
|
- .unwrap();
|
||||||
|
+ .map_err(|err| format!("failed to subscribe scheme event handle: {err}"))?;
|
||||||
|
|
||||||
|
for event in event_queue {
|
||||||
|
- match event.unwrap().user_data {
|
||||||
|
- Event::Scheme => driver_block::FuturesExecutor
|
||||||
|
- .block_on(scheme.tick())
|
||||||
|
- .unwrap(),
|
||||||
|
+ let event = match event {
|
||||||
|
+ Ok(event) => event,
|
||||||
|
+ Err(err) => {
|
||||||
|
+ eprintln!("usbscsid: event queue error: {err}");
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
+ match event.user_data {
|
||||||
|
+ Event::Scheme => {
|
||||||
|
+ if let Err(err) = driver_block::FuturesExecutor.block_on(scheme.tick()) {
|
||||||
|
+ eprintln!("usbscsid: scheme tick failed: {err}");
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- std::process::exit(0);
|
||||||
|
+ Ok(())
|
||||||
|
}
|
||||||
|
diff --git a/drivers/storage/usbscsid/src/protocol/mod.rs b/drivers/storage/usbscsid/src/protocol/mod.rs
|
||||||
|
--- a/drivers/storage/usbscsid/src/protocol/mod.rs
|
||||||
|
+++ b/drivers/storage/usbscsid/src/protocol/mod.rs
|
||||||
|
@@
|
||||||
|
#[error("attempted recovery failed")]
|
||||||
|
RecoveryFailed,
|
||||||
|
|
||||||
|
+ #[error("unsupported USB mass-storage protocol 0x{0:02X}")]
|
||||||
|
+ UnsupportedProtocol(u8),
|
||||||
|
+
|
||||||
|
#[error("protocol error")]
|
||||||
|
ProtocolError(&'static str),
|
||||||
|
}
|
||||||
|
@@
|
||||||
|
pub fn setup<'a>(
|
||||||
|
handle: &'a XhciClientHandle,
|
||||||
|
protocol: u8,
|
||||||
|
- dev_desc: &DevDesc,
|
||||||
|
+ _dev_desc: &DevDesc,
|
||||||
|
conf_desc: &ConfDesc,
|
||||||
|
if_desc: &IfDesc,
|
||||||
|
-) -> Option<Box<dyn Protocol + 'a>> {
|
||||||
|
+) -> Result<Box<dyn Protocol + 'a>, ProtocolError> {
|
||||||
|
match protocol {
|
||||||
|
- 0x50 => Some(Box::new(
|
||||||
|
- BulkOnlyTransport::init(handle, conf_desc, if_desc).unwrap(),
|
||||||
|
- )),
|
||||||
|
- _ => None,
|
||||||
|
+ 0x50 => BulkOnlyTransport::init(handle, conf_desc, if_desc)
|
||||||
|
+ .map(|transport| Box::new(transport) as Box<dyn Protocol + 'a>),
|
||||||
|
+ _ => Err(ProtocolError::UnsupportedProtocol(protocol)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
diff --git a/drivers/storage/usbscsid/src/scsi/mod.rs b/drivers/storage/usbscsid/src/scsi/mod.rs
|
||||||
|
--- a/drivers/storage/usbscsid/src/scsi/mod.rs
|
||||||
|
+++ b/drivers/storage/usbscsid/src/scsi/mod.rs
|
||||||
|
@@
|
||||||
|
#[error("overflow")]
|
||||||
|
Overflow(&'static str),
|
||||||
|
+
|
||||||
|
+ #[error("SCSI command failed: {0}")]
|
||||||
|
+ CommandFailed(&'static str),
|
||||||
|
}
|
||||||
|
@@
|
||||||
|
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());
|
||||||
|
+ eprintln!(
|
||||||
|
+ "usbscsid: MODE SENSE(10) failed; sense data: {:?}",
|
||||||
|
+ self.res_ff_sense_data()
|
||||||
|
+ );
|
||||||
|
+ return Err(ScsiError::CommandFailed("MODE SENSE(10)"));
|
||||||
|
}
|
||||||
|
diff --git a/drivers/usb/xhcid/src/xhci/event.rs b/drivers/usb/xhcid/src/xhci/event.rs
|
||||||
|
--- a/drivers/usb/xhcid/src/xhci/event.rs
|
||||||
|
+++ b/drivers/usb/xhcid/src/xhci/event.rs
|
||||||
|
@@
|
||||||
|
#[test]
|
||||||
|
fn grow_preserves_existing_ring_state() {
|
||||||
|
- let mut ring = EventRing::new::<super::super::CONTEXT_64>(true).unwrap();
|
||||||
|
+ let mut ring = EventRing::new::<{ super::super::CONTEXT_64 }>(true).unwrap();
|
||||||
|
@@
|
||||||
|
- ring.grow::<super::super::CONTEXT_64>(true, old_len + 64)
|
||||||
|
+ ring.grow::<{ super::super::CONTEXT_64 }>(true, old_len + 64)
|
||||||
|
.unwrap();
|
||||||
|
diff --git a/drivers/usb/xhcid/src/xhci/mod.rs b/drivers/usb/xhcid/src/xhci/mod.rs
|
||||||
|
--- a/drivers/usb/xhcid/src/xhci/mod.rs
|
||||||
|
+++ b/drivers/usb/xhcid/src/xhci/mod.rs
|
||||||
|
@@
|
||||||
|
let dev_desc = self.get_desc(port_id, slot).await?;
|
||||||
|
debug!("Got the full device descriptor!");
|
||||||
|
+ info!(
|
||||||
|
+ "port {} slot {} device {:04X}:{:04X} class {}.{} proto {} has {} configuration(s)",
|
||||||
|
+ port_id,
|
||||||
|
+ slot,
|
||||||
|
+ dev_desc.vendor,
|
||||||
|
+ dev_desc.product,
|
||||||
|
+ dev_desc.class,
|
||||||
|
+ dev_desc.sub_class,
|
||||||
|
+ dev_desc.protocol,
|
||||||
|
+ dev_desc.config_descs.len()
|
||||||
|
+ );
|
||||||
|
self.port_states.get_mut(&port_id).unwrap().dev_desc = Some(dev_desc);
|
||||||
|
@@
|
||||||
|
debug!("Updated the default control pipe");
|
||||||
|
+ info!("port {} slot {} starting subdriver matching", port_id, slot);
|
||||||
|
|
||||||
|
match self.spawn_drivers(port_id) {
|
||||||
|
Ok(()) => (),
|
||||||
|
@@
|
||||||
|
trace!("Got config and device descriptors on port {}", port);
|
||||||
|
let drivers_usercfg: &DriversConfig = &DRIVERS_CONFIG;
|
||||||
|
+
|
||||||
|
+ if config_desc.interface_descs.is_empty() {
|
||||||
|
+ warn!(
|
||||||
|
+ "No interface descriptors found for port {} in configuration {}; no subdrivers can be matched",
|
||||||
|
+ port,
|
||||||
|
+ config_desc.configuration_value
|
||||||
|
+ );
|
||||||
|
+ }
|
||||||
|
|
||||||
|
for ifdesc in config_desc.interface_descs.iter() {
|
||||||
|
diff --git a/drivers/usb/xhcid/src/xhci/scheme.rs b/drivers/usb/xhcid/src/xhci/scheme.rs
|
||||||
|
--- a/drivers/usb/xhcid/src/xhci/scheme.rs
|
||||||
|
+++ b/drivers/usb/xhcid/src/xhci/scheme.rs
|
||||||
|
@@
|
||||||
|
pub 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),
|
||||||
|
Hid(usb::HidDescriptor),
|
||||||
|
SuperSpeedCompanion(usb::SuperSpeedCompanionDescriptor),
|
||||||
|
SuperSpeedPlusCompanion(usb::SuperSpeedPlusIsochCmpDescriptor),
|
||||||
|
+ Unknown { kind: u8 },
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AnyDescriptor {
|
||||||
|
@@
|
||||||
|
- _ => {
|
||||||
|
- //panic!("Descriptor unknown {}: bytes {:#0x?}", kind, bytes);
|
||||||
|
- return None;
|
||||||
|
- }
|
||||||
|
+ _ => Self::Unknown { kind },
|
||||||
|
},
|
||||||
|
len.into(),
|
||||||
|
))
|
||||||
|
@@
|
||||||
|
- let mut interface_descs = SmallVec::new();
|
||||||
|
+ let mut interface_descs = SmallVec::<[IfDesc; 1]>::new();
|
||||||
|
let mut iter = descriptors.into_iter().peekable();
|
||||||
|
@@
|
||||||
|
Some(AnyDescriptor::Hid(h)) if idesc.class == 3 => {
|
||||||
|
hid_descs.push(h.into());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
+ Some(AnyDescriptor::Unknown { kind }) => {
|
||||||
|
+ log::warn!(
|
||||||
|
+ "port {} slot {} iface {} skipping unknown descriptor kind {} while collecting endpoints",
|
||||||
|
+ port_id,
|
||||||
|
+ slot,
|
||||||
|
+ idesc.number,
|
||||||
|
+ kind
|
||||||
|
+ );
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
Some(unexpected) => {
|
||||||
|
log::warn!("expected endpoint, got {:X?}", unexpected);
|
||||||
|
break;
|
||||||
|
@@
|
||||||
|
} else {
|
||||||
|
log::warn!("expected interface, got {:?}", item);
|
||||||
|
// TODO
|
||||||
|
//break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ log::info!(
|
||||||
|
+ "port {} slot {} config {} parsed {} descriptor entries into {} interface(s)",
|
||||||
|
+ port_id,
|
||||||
|
+ slot,
|
||||||
|
+ index,
|
||||||
|
+ descriptor_count,
|
||||||
|
+ interface_descs.len()
|
||||||
|
+ );
|
||||||
|
+
|
||||||
|
+ for if_desc in interface_descs.iter() {
|
||||||
|
+ let number: u8 = if_desc.number;
|
||||||
|
+ let alternate_setting: u8 = if_desc.alternate_setting;
|
||||||
|
+ let class: u8 = if_desc.class;
|
||||||
|
+ let sub_class: u8 = if_desc.sub_class;
|
||||||
|
+ let protocol: u8 = if_desc.protocol;
|
||||||
|
+ let endpoint_count: usize = if_desc.endpoints.len();
|
||||||
|
+ log::info!(
|
||||||
|
+ "port {} slot {} config {} iface {} alt {} class {}.{} proto {} endpoints {}",
|
||||||
|
+ port_id,
|
||||||
|
+ slot,
|
||||||
|
+ index,
|
||||||
|
+ number,
|
||||||
|
+ alternate_setting,
|
||||||
|
+ class,
|
||||||
|
+ sub_class,
|
||||||
|
+ protocol,
|
||||||
|
+ endpoint_count
|
||||||
|
+ );
|
||||||
|
+ }
|
||||||
|
|||||||
@@ -1,13 +1,34 @@
|
|||||||
use core::ptr::NonNull;
|
use core::ptr::NonNull;
|
||||||
use std::sync::atomic::{AtomicI32, Ordering};
|
use std::sync::atomic::{AtomicI32, Ordering};
|
||||||
|
|
||||||
use redox_syscall::flag::{MAP_SHARED, O_CLOEXEC, O_RDWR, PROT_READ, PROT_WRITE};
|
use redox_syscall::flag::{MAP_PRIVATE, O_CLOEXEC, PROT_READ, PROT_WRITE};
|
||||||
use redox_syscall::PAGE_SIZE;
|
use redox_syscall::PAGE_SIZE;
|
||||||
use syscall as redox_syscall;
|
use syscall as redox_syscall;
|
||||||
|
|
||||||
use crate::{DriverError, Result};
|
use crate::{DriverError, Result};
|
||||||
|
|
||||||
/// SAFETY: Cached FD for `/scheme/memory/physical`. -1 means uninitialized.
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
enum DmaMemoryType {
|
||||||
|
Writeback,
|
||||||
|
Uncacheable,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DmaMemoryType {
|
||||||
|
const fn suffix(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::Writeback => "wb",
|
||||||
|
Self::Uncacheable => "uc",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const DMA_MEMORY_TYPE: DmaMemoryType = if cfg!(any(target_arch = "x86", target_arch = "x86_64")) {
|
||||||
|
DmaMemoryType::Writeback
|
||||||
|
} else {
|
||||||
|
DmaMemoryType::Uncacheable
|
||||||
|
};
|
||||||
|
|
||||||
|
/// SAFETY: Cached FD for `/scheme/memory/scheme-root`. -1 means uninitialized.
|
||||||
/// This FD is process-lifetime cached for performance. If scheme:memory
|
/// This FD is process-lifetime cached for performance. If scheme:memory
|
||||||
/// restarts (which should never happen — it's a kernel scheme), all
|
/// restarts (which should never happen — it's a kernel scheme), all
|
||||||
/// in-flight DMA operations are already undefined behavior.
|
/// in-flight DMA operations are already undefined behavior.
|
||||||
@@ -19,7 +40,7 @@ fn get_dma_memory_fd() -> Result<i32> {
|
|||||||
return Ok(current);
|
return Ok(current);
|
||||||
}
|
}
|
||||||
|
|
||||||
let fd = libredox::call::open("/scheme/memory/physical", (O_CLOEXEC | O_RDWR) as i32, 0)
|
let fd = libredox::call::open("/scheme/memory/scheme-root", O_CLOEXEC as i32, 0)
|
||||||
.map_err(|e| DriverError::Io(std::io::Error::from_raw_os_error(e.errno())))?;
|
.map_err(|e| DriverError::Io(std::io::Error::from_raw_os_error(e.errno())))?;
|
||||||
|
|
||||||
let raw = fd as i32;
|
let raw = fd as i32;
|
||||||
@@ -68,7 +89,11 @@ fn virt_to_phys_cached(virt: usize) -> Result<usize> {
|
|||||||
|
|
||||||
enum DmaStorage {
|
enum DmaStorage {
|
||||||
/// Allocated via scheme:memory — freed via munmap
|
/// Allocated via scheme:memory — freed via munmap
|
||||||
SchemeMapped { ptr: NonNull<u8>, size: usize },
|
SchemeMapped {
|
||||||
|
ptr: NonNull<u8>,
|
||||||
|
size: usize,
|
||||||
|
region_fd: i32,
|
||||||
|
},
|
||||||
/// Allocated via heap — freed via dealloc
|
/// Allocated via heap — freed via dealloc
|
||||||
Heap {
|
Heap {
|
||||||
ptr: NonNull<u8>,
|
ptr: NonNull<u8>,
|
||||||
@@ -126,10 +151,9 @@ impl DmaBuffer {
|
|||||||
/// Allocate physically contiguous memory via scheme:memory/physical.
|
/// Allocate physically contiguous memory via scheme:memory/physical.
|
||||||
fn allocate_via_scheme(mem_fd: i32, size: usize, _align: usize) -> Result<Self> {
|
fn allocate_via_scheme(mem_fd: i32, size: usize, _align: usize) -> Result<Self> {
|
||||||
// Open a physical memory region of the requested size
|
// Open a physical memory region of the requested size
|
||||||
let path = format!("zeroed@{}", size);
|
let path = format!("zeroed@{}?phys_contiguous", DMA_MEMORY_TYPE.suffix());
|
||||||
let region_fd =
|
let region_fd = libredox::call::openat(mem_fd as usize, &path, O_CLOEXEC as i32, 0)
|
||||||
libredox::call::openat(mem_fd as usize, &path, (O_CLOEXEC | O_RDWR) as i32, 0)
|
.map_err(|e| DriverError::Io(std::io::Error::from_raw_os_error(e.errno())))?;
|
||||||
.map_err(|e| DriverError::Io(std::io::Error::from_raw_os_error(e.errno())))?;
|
|
||||||
|
|
||||||
// Map it into our address space
|
// Map it into our address space
|
||||||
let ptr = unsafe {
|
let ptr = unsafe {
|
||||||
@@ -137,7 +161,7 @@ impl DmaBuffer {
|
|||||||
fd: region_fd as usize,
|
fd: region_fd as usize,
|
||||||
offset: 0,
|
offset: 0,
|
||||||
length: size,
|
length: size,
|
||||||
flags: MAP_SHARED.bits() as u32,
|
flags: MAP_PRIVATE.bits() as u32,
|
||||||
prot: (PROT_READ | PROT_WRITE).bits() as u32,
|
prot: (PROT_READ | PROT_WRITE).bits() as u32,
|
||||||
addr: core::ptr::null_mut(),
|
addr: core::ptr::null_mut(),
|
||||||
})
|
})
|
||||||
@@ -154,6 +178,17 @@ impl DmaBuffer {
|
|||||||
let _ = libredox::call::close(region_fd as usize);
|
let _ = libredox::call::close(region_fd as usize);
|
||||||
|
|
||||||
let phys_addr = virt_to_phys_cached(ptr as usize)?;
|
let phys_addr = virt_to_phys_cached(ptr as usize)?;
|
||||||
|
for page in 1..size.div_ceil(PAGE_SIZE) {
|
||||||
|
let translated = virt_to_phys_cached(ptr as usize + page * PAGE_SIZE)?;
|
||||||
|
if translated != phys_addr + page * PAGE_SIZE {
|
||||||
|
return Err(DriverError::Other(format!(
|
||||||
|
"DMA mapping is not physically contiguous across page {}: expected {:#x}, got {:#x}",
|
||||||
|
page,
|
||||||
|
phys_addr + page * PAGE_SIZE,
|
||||||
|
translated
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
let ptr = NonNull::new(ptr as *mut u8)
|
let ptr = NonNull::new(ptr as *mut u8)
|
||||||
.ok_or_else(|| DriverError::Other("DMA mmap returned null".into()))?;
|
.ok_or_else(|| DriverError::Other("DMA mmap returned null".into()))?;
|
||||||
|
|
||||||
@@ -165,7 +200,11 @@ impl DmaBuffer {
|
|||||||
);
|
);
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
storage: DmaStorage::SchemeMapped { ptr, size },
|
storage: DmaStorage::SchemeMapped {
|
||||||
|
ptr,
|
||||||
|
size,
|
||||||
|
region_fd: region_fd as i32,
|
||||||
|
},
|
||||||
phys_addr,
|
phys_addr,
|
||||||
size,
|
size,
|
||||||
})
|
})
|
||||||
@@ -205,8 +244,13 @@ impl DmaBuffer {
|
|||||||
impl Drop for DmaBuffer {
|
impl Drop for DmaBuffer {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
match &self.storage {
|
match &self.storage {
|
||||||
DmaStorage::SchemeMapped { ptr, size } => {
|
DmaStorage::SchemeMapped {
|
||||||
|
ptr,
|
||||||
|
size,
|
||||||
|
region_fd,
|
||||||
|
} => {
|
||||||
let _ = unsafe { libredox::call::munmap(ptr.as_ptr() as *mut (), *size) };
|
let _ = unsafe { libredox::call::munmap(ptr.as_ptr() as *mut (), *size) };
|
||||||
|
let _ = libredox::call::close(*region_fd as usize);
|
||||||
}
|
}
|
||||||
DmaStorage::Heap { ptr, layout } => {
|
DmaStorage::Heap { ptr, layout } => {
|
||||||
unsafe { std::alloc::dealloc(ptr.as_ptr(), *layout) };
|
unsafe { std::alloc::dealloc(ptr.as_ptr(), *layout) };
|
||||||
|
|||||||
@@ -149,6 +149,12 @@ impl MsixTable {
|
|||||||
let (irq, fd) = allocate_irq_vector(cpu_id)?;
|
let (irq, fd) = allocate_irq_vector(cpu_id)?;
|
||||||
self.program_x86_message(index, cpu_id, irq)?;
|
self.program_x86_message(index, cpu_id, irq)?;
|
||||||
self.unmask_vector(index);
|
self.unmask_vector(index);
|
||||||
|
log::info!(
|
||||||
|
"redox-driver-sys: allocated MSI-X vector {} -> irq {} on cpu {}",
|
||||||
|
index,
|
||||||
|
irq,
|
||||||
|
cpu_id
|
||||||
|
);
|
||||||
Ok(MsixVector { fd, index, irq })
|
Ok(MsixVector { fd, index, irq })
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,7 +294,15 @@ fn allocate_irq_vector(cpu_id: u8) -> Result<(u32, File)> {
|
|||||||
.create_new(true)
|
.create_new(true)
|
||||||
.open(&path)
|
.open(&path)
|
||||||
{
|
{
|
||||||
Ok(fd) => return Ok((irq, fd)),
|
Ok(fd) => {
|
||||||
|
log::debug!(
|
||||||
|
"redox-driver-sys: reserved irq vector {} from {} for cpu {}",
|
||||||
|
irq,
|
||||||
|
path,
|
||||||
|
cpu_id
|
||||||
|
);
|
||||||
|
return Ok((irq, fd));
|
||||||
|
}
|
||||||
Err(err) if err.kind() == ErrorKind::AlreadyExists => continue,
|
Err(err) if err.kind() == ErrorKind::AlreadyExists => continue,
|
||||||
Err(err) if err.kind() == ErrorKind::NotFound => continue,
|
Err(err) if err.kind() == ErrorKind::NotFound => continue,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|||||||
+10
-7
@@ -64,16 +64,19 @@ Driver access pattern:
|
|||||||
- Register as scheme: daemon name becomes `/scheme/<name>`
|
- Register as scheme: daemon name becomes `/scheme/<name>`
|
||||||
- PCI devices discovered via `pcid` daemon → spawns drivers
|
- PCI devices discovered via `pcid` daemon → spawns drivers
|
||||||
|
|
||||||
## POSIX GAPS IN RELIBC (blocking Wayland)
|
## HISTORICAL POSIX GAPS IN RELIBC (Wayland-facing)
|
||||||
|
|
||||||
| Missing API | Location to implement |
|
| Missing API | Location to implement |
|
||||||
|-------------|----------------------|
|
|-------------|----------------------|
|
||||||
| signalfd/signalfd4 | `relibc/source/src/header/signal/` |
|
| signalfd/signalfd4 | `relibc/source/src/header/signal/` — now source-visible in the current Red Bear tree |
|
||||||
| timerfd_create/settime/gettime | `relibc/source/src/header/sys_timerfd/` (NEW) |
|
| timerfd_create/settime/gettime | `relibc/source/src/header/sys_timerfd/` — now source-visible in the current Red Bear tree |
|
||||||
| eventfd | `relibc/source/src/header/sys_eventfd/` (NEW) |
|
| eventfd | `relibc/source/src/header/sys_eventfd/` — now source-visible in the current Red Bear tree |
|
||||||
| F_DUPFD_CLOEXEC | `relibc/source/src/header/fcntl/` |
|
| F_DUPFD_CLOEXEC | `relibc/source/src/header/fcntl/` — now source-visible in the current Red Bear tree |
|
||||||
| MSG_CMSG_CLOEXEC, MSG_NOSIGNAL | `relibc/source/src/header/sys_socket/` |
|
| MSG_CMSG_CLOEXEC, MSG_NOSIGNAL | `relibc/source/src/header/sys_socket/` — now source-visible in the current Red Bear tree |
|
||||||
| open_memstream | `relibc/source/src/header/stdio/` |
|
| open_memstream | `relibc/source/src/header/stdio/` — now source-visible in the current Red Bear tree |
|
||||||
|
|
||||||
|
The current relibc work is therefore no longer just “add the missing Wayland APIs.” The higher-value
|
||||||
|
remaining work is completeness depth, downstream cleanup, and runtime validation.
|
||||||
|
|
||||||
## ANTI-PATTERNS
|
## ANTI-PATTERNS
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ BINS=(
|
|||||||
# depending on the target architecture
|
# depending on the target architecture
|
||||||
case "${TARGET}" in
|
case "${TARGET}" in
|
||||||
i586-unknown-redox | i686-unknown-redox | x86_64-unknown-redox)
|
i586-unknown-redox | i686-unknown-redox | x86_64-unknown-redox)
|
||||||
BINS+=(ac97d bgad sb16d vboxd)
|
BINS+=(ac97d sb16d vboxd)
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
;;
|
;;
|
||||||
|
|||||||
Reference in New Issue
Block a user