Update Red Bear driver substrate
Red Bear OS Team
This commit is contained in:
@@ -1353,3 +1353,540 @@ diff --git a/drivers/usb/xhcid/src/xhci/scheme.rs b/drivers/usb/xhcid/src/xhci/s
|
|||||||
+ endpoint_count
|
+ endpoint_count
|
||||||
+ );
|
+ );
|
||||||
+ }
|
+ }
|
||||||
|
diff --git a/drivers/audio/ac97d/src/main.rs b/drivers/audio/ac97d/src/main.rs
|
||||||
|
--- a/drivers/audio/ac97d/src/main.rs
|
||||||
|
+++ b/drivers/audio/ac97d/src/main.rs
|
||||||
|
@@
|
||||||
|
fn daemon(daemon: daemon::Daemon, pcid_handle: PciFunctionHandle) -> ! {
|
||||||
|
let pci_config = pcid_handle.config();
|
||||||
|
|
||||||
|
let mut name = pci_config.func.name();
|
||||||
|
name.push_str("_ac97");
|
||||||
|
+
|
||||||
|
+ common::setup_logging(
|
||||||
|
+ "audio",
|
||||||
|
+ "pci",
|
||||||
|
+ &name,
|
||||||
|
+ common::output_level(),
|
||||||
|
+ common::file_level(),
|
||||||
|
+ );
|
||||||
|
+
|
||||||
|
+ let bar0 = match pci_config.func.bars[0] {
|
||||||
|
+ pcid_interface::PciBar::Port(port) => port,
|
||||||
|
+ ref other => {
|
||||||
|
+ log::warn!(
|
||||||
|
+ "ac97d: unsupported BAR0 layout for {}: expected port BAR, found {}",
|
||||||
|
+ pci_config.func.display(),
|
||||||
|
+ other.display(),
|
||||||
|
+ );
|
||||||
|
+ std::process::exit(0);
|
||||||
|
+ }
|
||||||
|
+ };
|
||||||
|
+ let bar1 = match pci_config.func.bars[1] {
|
||||||
|
+ pcid_interface::PciBar::Port(port) => port,
|
||||||
|
+ ref other => {
|
||||||
|
+ log::warn!(
|
||||||
|
+ "ac97d: unsupported BAR1 layout for {}: expected port BAR, found {}",
|
||||||
|
+ pci_config.func.display(),
|
||||||
|
+ other.display(),
|
||||||
|
+ );
|
||||||
|
+ std::process::exit(0);
|
||||||
|
+ }
|
||||||
|
+ };
|
||||||
|
-
|
||||||
|
- let bar0 = pci_config.func.bars[0].expect_port();
|
||||||
|
- let bar1 = pci_config.func.bars[1].expect_port();
|
||||||
|
@@
|
||||||
|
println!(" + ac97 {}", pci_config.func.display());
|
||||||
|
-
|
||||||
|
- common::setup_logging(
|
||||||
|
- "audio",
|
||||||
|
- "pci",
|
||||||
|
- &name,
|
||||||
|
- common::output_level(),
|
||||||
|
- common::file_level(),
|
||||||
|
- );
|
||||||
|
diff --git a/drivers/input/ps2d/src/main.rs b/drivers/input/ps2d/src/main.rs
|
||||||
|
--- a/drivers/input/ps2d/src/main.rs
|
||||||
|
+++ b/drivers/input/ps2d/src/main.rs
|
||||||
|
@@
|
||||||
|
use common::acquire_port_io_rights;
|
||||||
|
use event::{user_data, EventQueue};
|
||||||
|
use inputd::ProducerHandle;
|
||||||
|
+use log::{error, warn};
|
||||||
|
@@
|
||||||
|
mod controller;
|
||||||
|
mod mouse;
|
||||||
|
mod state;
|
||||||
|
mod vm;
|
||||||
|
+
|
||||||
|
+fn exit_bootsafe(daemon: &mut Option<daemon::Daemon>, reason: &str) -> ! {
|
||||||
|
+ warn!("ps2d: {}; disabling PS/2 input for this boot", reason);
|
||||||
|
+ if let Some(daemon) = daemon.take() {
|
||||||
|
+ daemon.ready();
|
||||||
|
+ }
|
||||||
|
+ process::exit(0);
|
||||||
|
+}
|
||||||
|
@@
|
||||||
|
+ let mut daemon = Some(daemon);
|
||||||
|
+
|
||||||
|
+ if let Err(err) = acquire_port_io_rights() {
|
||||||
|
+ exit_bootsafe(&mut daemon, &format!("failed to get I/O permission: {err}"));
|
||||||
|
+ }
|
||||||
|
|
||||||
|
- let input = ProducerHandle::new().expect("ps2d: failed to open input producer");
|
||||||
|
+ let input = match ProducerHandle::new() {
|
||||||
|
+ Ok(input) => input,
|
||||||
|
+ Err(err) => exit_bootsafe(&mut daemon, &format!("failed to open input producer: {err}")),
|
||||||
|
+ };
|
||||||
|
@@
|
||||||
|
- let event_queue: EventQueue<Source> =
|
||||||
|
- EventQueue::new().expect("ps2d: failed to create event queue");
|
||||||
|
+ let event_queue: EventQueue<Source> = match EventQueue::new() {
|
||||||
|
+ Ok(event_queue) => event_queue,
|
||||||
|
+ Err(err) => exit_bootsafe(&mut daemon, &format!("failed to create event queue: {err}")),
|
||||||
|
+ };
|
||||||
|
@@
|
||||||
|
- .open("/scheme/serio/0")
|
||||||
|
- .expect("ps2d: failed to open /scheme/serio/0");
|
||||||
|
+ .open("/scheme/serio/0")
|
||||||
|
+ .unwrap_or_else(|err| {
|
||||||
|
+ exit_bootsafe(&mut daemon, &format!("failed to open /scheme/serio/0: {err}"))
|
||||||
|
+ });
|
||||||
|
|
||||||
|
- event_queue
|
||||||
|
- .subscribe(
|
||||||
|
- key_file.as_raw_fd() as usize,
|
||||||
|
- Source::Keyboard,
|
||||||
|
- event::EventFlags::READ,
|
||||||
|
- )
|
||||||
|
- .unwrap();
|
||||||
|
+ if let Err(err) = event_queue.subscribe(
|
||||||
|
+ key_file.as_raw_fd() as usize,
|
||||||
|
+ Source::Keyboard,
|
||||||
|
+ event::EventFlags::READ,
|
||||||
|
+ ) {
|
||||||
|
+ exit_bootsafe(&mut daemon, &format!("failed to subscribe keyboard serio fd: {err}"));
|
||||||
|
+ }
|
||||||
|
@@
|
||||||
|
- .open("/scheme/serio/1")
|
||||||
|
- .expect("ps2d: failed to open /scheme/serio/1");
|
||||||
|
+ .open("/scheme/serio/1")
|
||||||
|
+ .unwrap_or_else(|err| {
|
||||||
|
+ exit_bootsafe(&mut daemon, &format!("failed to open /scheme/serio/1: {err}"))
|
||||||
|
+ });
|
||||||
|
|
||||||
|
- event_queue
|
||||||
|
- .subscribe(
|
||||||
|
- mouse_file.as_raw_fd() as usize,
|
||||||
|
- Source::Mouse,
|
||||||
|
- event::EventFlags::READ,
|
||||||
|
- )
|
||||||
|
- .unwrap();
|
||||||
|
+ if let Err(err) = event_queue.subscribe(
|
||||||
|
+ mouse_file.as_raw_fd() as usize,
|
||||||
|
+ Source::Mouse,
|
||||||
|
+ event::EventFlags::READ,
|
||||||
|
+ ) {
|
||||||
|
+ exit_bootsafe(&mut daemon, &format!("failed to subscribe mouse serio fd: {err}"));
|
||||||
|
+ }
|
||||||
|
@@
|
||||||
|
- .open(format!("/scheme/time/{}", syscall::CLOCK_MONOTONIC))
|
||||||
|
- .expect("ps2d: failed to open /scheme/time");
|
||||||
|
+ .open(format!("/scheme/time/{}", syscall::CLOCK_MONOTONIC))
|
||||||
|
+ .unwrap_or_else(|err| {
|
||||||
|
+ exit_bootsafe(&mut daemon, &format!("failed to open /scheme/time: {err}"))
|
||||||
|
+ });
|
||||||
|
|
||||||
|
- event_queue
|
||||||
|
- .subscribe(
|
||||||
|
- time_file.as_raw_fd() as usize,
|
||||||
|
- Source::Time,
|
||||||
|
- event::EventFlags::READ,
|
||||||
|
- )
|
||||||
|
- .unwrap();
|
||||||
|
+ if let Err(err) = event_queue.subscribe(
|
||||||
|
+ time_file.as_raw_fd() as usize,
|
||||||
|
+ Source::Time,
|
||||||
|
+ event::EventFlags::READ,
|
||||||
|
+ ) {
|
||||||
|
+ exit_bootsafe(&mut daemon, &format!("failed to subscribe timer fd: {err}"));
|
||||||
|
+ }
|
||||||
|
|
||||||
|
- libredox::call::setrens(0, 0).expect("ps2d: failed to enter null namespace");
|
||||||
|
+ if let Err(err) = libredox::call::setrens(0, 0) {
|
||||||
|
+ exit_bootsafe(&mut daemon, &format!("failed to enter null namespace: {err}"));
|
||||||
|
+ }
|
||||||
|
|
||||||
|
- daemon.ready();
|
||||||
|
-
|
||||||
|
- let mut ps2d = Ps2d::new(input, time_file);
|
||||||
|
+ let mut ps2d = match Ps2d::new(input, time_file) {
|
||||||
|
+ Ok(ps2d) => ps2d,
|
||||||
|
+ Err(err) => exit_bootsafe(
|
||||||
|
+ &mut daemon,
|
||||||
|
+ &format!("PS/2 controller initialization failed: {err:?}"),
|
||||||
|
+ ),
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
+ daemon.take().unwrap().ready();
|
||||||
|
|
||||||
|
let mut data = [0; 256];
|
||||||
|
- for event in event_queue.map(|e| e.expect("ps2d: failed to get next event").user_data) {
|
||||||
|
+ for event in event_queue {
|
||||||
|
+ let event = match event {
|
||||||
|
+ Ok(event) => event.user_data,
|
||||||
|
+ Err(err) => {
|
||||||
|
+ error!("ps2d: failed to get next event: {err}");
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ };
|
||||||
|
// There are some gotchas with ps/2 controllers that require this weird
|
||||||
|
diff --git a/drivers/input/ps2d/src/state.rs b/drivers/input/ps2d/src/state.rs
|
||||||
|
--- a/drivers/input/ps2d/src/state.rs
|
||||||
|
+++ b/drivers/input/ps2d/src/state.rs
|
||||||
|
@@
|
||||||
|
-use crate::controller::Ps2;
|
||||||
|
+use crate::controller::{Error as Ps2Error, Ps2};
|
||||||
|
@@
|
||||||
|
impl Ps2d {
|
||||||
|
- pub fn new(input: ProducerHandle, time_file: File) -> Self {
|
||||||
|
+ pub fn new(input: ProducerHandle, time_file: File) -> Result<Self, Ps2Error> {
|
||||||
|
let mut ps2 = Ps2::new();
|
||||||
|
- ps2.init().expect("failed to initialize");
|
||||||
|
+ ps2.init()?;
|
||||||
|
@@
|
||||||
|
if !this.vmmouse {
|
||||||
|
// This triggers initializing the mouse
|
||||||
|
this.handle_mouse(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
- this
|
||||||
|
+ Ok(this)
|
||||||
|
}
|
||||||
|
diff --git a/drivers/usb/xhcid/src/main.rs b/drivers/usb/xhcid/src/main.rs
|
||||||
|
--- a/drivers/usb/xhcid/src/main.rs
|
||||||
|
+++ b/drivers/usb/xhcid/src/main.rs
|
||||||
|
@@
|
||||||
|
+use std::convert::TryFrom;
|
||||||
|
use std::fs::File;
|
||||||
|
+use std::io;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
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::irq_helpers::allocate_single_interrupt_vector;
|
||||||
|
use pcid_interface::{PciFeature, PciFeatureInfo, PciFunctionHandle};
|
||||||
|
+#[cfg(target_arch = "x86_64")]
|
||||||
|
+use pcid_interface::{MsiSetFeatureInfo, SetFeatureInfo};
|
||||||
|
@@
|
||||||
|
mod usb;
|
||||||
|
mod xhci;
|
||||||
|
|
||||||
|
+#[cfg(target_arch = "x86_64")]
|
||||||
|
+fn allocate_msix_interrupt(
|
||||||
|
+ pcid_handle: &mut PciFunctionHandle,
|
||||||
|
+ msix_info: pcid_interface::msi::MsixInfo,
|
||||||
|
+) -> io::Result<File> {
|
||||||
|
+ let mut info = unsafe { msix_info.map_and_mask_all(pcid_handle) };
|
||||||
|
+ let destination_id = read_bsp_apic_id()?;
|
||||||
|
+ let (vector, interrupt_handle) = allocate_single_interrupt_vector(destination_id)?
|
||||||
|
+ .ok_or_else(|| io::Error::new(io::ErrorKind::WouldBlock, "no interrupt vectors left"))?;
|
||||||
|
+ let lapic_id = u8::try_from(destination_id)
|
||||||
|
+ .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "BSP apic id out of range"))?;
|
||||||
|
+ let msg_addr_and_data = pcid_interface::msi::MsiAddrAndData {
|
||||||
|
+ addr: pcid_interface::msi::x86::message_address(lapic_id, false, false),
|
||||||
|
+ data: pcid_interface::msi::x86::message_data_edge_triggered(
|
||||||
|
+ pcid_interface::msi::x86::DeliveryMode::Fixed,
|
||||||
|
+ vector,
|
||||||
|
+ ),
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
+ let table_entry_pointer = info.table_entry_pointer(0);
|
||||||
|
+ table_entry_pointer.write_addr_and_data(msg_addr_and_data);
|
||||||
|
+ table_entry_pointer.unmask();
|
||||||
|
+
|
||||||
|
+ pcid_handle.enable_feature(PciFeature::MsiX);
|
||||||
|
+ log::debug!("Enabled MSI-X");
|
||||||
|
+
|
||||||
|
+ Ok(interrupt_handle)
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#[cfg(target_arch = "x86_64")]
|
||||||
|
+fn allocate_msi_interrupt(pcid_handle: &mut PciFunctionHandle) -> io::Result<File> {
|
||||||
|
+ let destination_id = read_bsp_apic_id()?;
|
||||||
|
+ let (vector, interrupt_handle) = allocate_single_interrupt_vector(destination_id)?
|
||||||
|
+ .ok_or_else(|| io::Error::new(io::ErrorKind::WouldBlock, "no interrupt vectors left"))?;
|
||||||
|
+ let lapic_id = u8::try_from(destination_id)
|
||||||
|
+ .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "BSP apic id out of range"))?;
|
||||||
|
+ let set_feature_info = MsiSetFeatureInfo {
|
||||||
|
+ multi_message_enable: Some(0),
|
||||||
|
+ message_address_and_data: Some(pcid_interface::msi::MsiAddrAndData {
|
||||||
|
+ addr: pcid_interface::msi::x86::message_address(lapic_id, false, false),
|
||||||
|
+ data: pcid_interface::msi::x86::message_data_edge_triggered(
|
||||||
|
+ pcid_interface::msi::x86::DeliveryMode::Fixed,
|
||||||
|
+ vector,
|
||||||
|
+ ),
|
||||||
|
+ }),
|
||||||
|
+ mask_bits: None,
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
+ pcid_handle.set_feature_info(SetFeatureInfo::Msi(set_feature_info));
|
||||||
|
+ pcid_handle.enable_feature(PciFeature::Msi);
|
||||||
|
+ log::debug!("Enabled MSI");
|
||||||
|
+
|
||||||
|
+ Ok(interrupt_handle)
|
||||||
|
+}
|
||||||
|
@@
|
||||||
|
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("xhcid: 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();
|
||||||
|
-
|
||||||
|
- (Some(interrupt_handle), InterruptMethod::Msi)
|
||||||
|
- };
|
||||||
|
-
|
||||||
|
- pcid_handle.enable_feature(PciFeature::MsiX);
|
||||||
|
- log::debug!("Enabled MSI-X");
|
||||||
|
-
|
||||||
|
- method
|
||||||
|
- } else if has_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 {
|
||||||
|
+ match pcid_handle.feature_info(PciFeature::MsiX) {
|
||||||
|
+ PciFeatureInfo::MsiX(msix_info) => match allocate_msix_interrupt(pcid_handle, msix_info)
|
||||||
|
+ {
|
||||||
|
+ Ok(interrupt_handle) => return (Some(interrupt_handle), InterruptMethod::Msi),
|
||||||
|
+ Err(err) => {
|
||||||
|
+ log::warn!("xhcid: MSI-X setup failed, falling back: {err}");
|
||||||
|
+ }
|
||||||
|
+ },
|
||||||
|
+ feature_info => {
|
||||||
|
+ log::warn!(
|
||||||
|
+ "xhcid: MSI-X feature probe returned unexpected descriptor {:?}; falling back",
|
||||||
|
+ feature_info
|
||||||
|
+ );
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if has_msi {
|
||||||
|
+ match allocate_msi_interrupt(pcid_handle) {
|
||||||
|
+ Ok(interrupt_handle) => return (Some(interrupt_handle), InterruptMethod::Msi),
|
||||||
|
+ Err(err) => {
|
||||||
|
+ log::warn!("xhcid: MSI setup failed, falling back: {err}");
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if let Some(irq) = pci_config.func.legacy_interrupt_line {
|
||||||
|
log::debug!("Legacy IRQ {}", irq);
|
||||||
|
@@
|
||||||
|
log::info!("XHCI {}", pci_config.func.display());
|
||||||
|
|
||||||
|
let scheme_name = format!("usb.{}", name);
|
||||||
|
- let socket = Socket::create().expect("xhcid: failed to create usb scheme");
|
||||||
|
+ let socket = match Socket::create() {
|
||||||
|
+ Ok(socket) => socket,
|
||||||
|
+ Err(err) => {
|
||||||
|
+ log::error!("xhcid: failed to create usb scheme: {err}");
|
||||||
|
+ std::process::exit(0);
|
||||||
|
+ }
|
||||||
|
+ };
|
||||||
|
|
||||||
|
let mut state = SchemeState::new();
|
||||||
|
- let hci = Arc::new(
|
||||||
|
- Xhci::<N>::new(scheme_name.clone(), address, interrupt_method, pcid_handle)
|
||||||
|
- .expect("xhcid: failed to allocate device"),
|
||||||
|
- );
|
||||||
|
- register_sync_scheme(&socket, &scheme_name, &mut &*hci)
|
||||||
|
- .expect("xhcid: failed to regsiter scheme to namespace");
|
||||||
|
+ let hci = match Xhci::<N>::new(scheme_name.clone(), address, interrupt_method, pcid_handle) {
|
||||||
|
+ Ok(hci) => Arc::new(hci),
|
||||||
|
+ Err(err) => {
|
||||||
|
+ log::error!("xhcid: failed to allocate device: {err}");
|
||||||
|
+ std::process::exit(0);
|
||||||
|
+ }
|
||||||
|
+ };
|
||||||
|
+ if let Err(err) = register_sync_scheme(&socket, &scheme_name, &mut &*hci) {
|
||||||
|
+ log::error!("xhcid: failed to register scheme to namespace: {err}");
|
||||||
|
+ std::process::exit(0);
|
||||||
|
+ }
|
||||||
|
diff --git a/drivers/usb/xhcid/src/xhci/device_enumerator.rs b/drivers/usb/xhcid/src/xhci/device_enumerator.rs
|
||||||
|
--- a/drivers/usb/xhcid/src/xhci/device_enumerator.rs
|
||||||
|
+++ b/drivers/usb/xhcid/src/xhci/device_enumerator.rs
|
||||||
|
@@
|
||||||
|
impl<const N: usize> DeviceEnumerator<N> {
|
||||||
|
+ fn is_port_disabled_state(flags: &PortFlags) -> bool {
|
||||||
|
+ flags.contains(PortFlags::PP)
|
||||||
|
+ && flags.contains(PortFlags::CCS)
|
||||||
|
+ && !flags.contains(PortFlags::PED)
|
||||||
|
+ && !flags.contains(PortFlags::PR)
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ fn wait_for_stable_port_flags(
|
||||||
|
+ &self,
|
||||||
|
+ port_id: PortId,
|
||||||
|
+ mut flags: PortFlags,
|
||||||
|
+ ) -> Option<PortFlags> {
|
||||||
|
+ const MAX_ATTEMPTS: usize = 8;
|
||||||
|
+ const STABILIZE_DELAY: Duration = Duration::from_millis(20);
|
||||||
|
+
|
||||||
|
+ if flags.contains(PortFlags::PED) || Self::is_port_disabled_state(&flags) {
|
||||||
|
+ return Some(flags);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ for attempt in 0..MAX_ATTEMPTS {
|
||||||
|
+ debug!(
|
||||||
|
+ "Port {} reported transient flags {:?}; waiting for a stable state ({}/{})",
|
||||||
|
+ port_id,
|
||||||
|
+ flags,
|
||||||
|
+ attempt + 1,
|
||||||
|
+ MAX_ATTEMPTS
|
||||||
|
+ );
|
||||||
|
+ std::thread::sleep(STABILIZE_DELAY);
|
||||||
|
+
|
||||||
|
+ flags = {
|
||||||
|
+ let ports = self.hci.ports.lock().unwrap();
|
||||||
|
+ let index = port_id.root_hub_port_index();
|
||||||
|
+ if index >= ports.len() {
|
||||||
|
+ warn!(
|
||||||
|
+ "Port {} disappeared while waiting for a stable state",
|
||||||
|
+ port_id
|
||||||
|
+ );
|
||||||
|
+ return None;
|
||||||
|
+ }
|
||||||
|
+ ports[index].flags()
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
+ if flags.contains(PortFlags::PED) || Self::is_port_disabled_state(&flags) {
|
||||||
|
+ return Some(flags);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ None
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
pub fn new(hci: Arc<Xhci<N>>) -> Self {
|
||||||
|
let request_queue = hci.device_enumerator_receiver.clone();
|
||||||
|
DeviceEnumerator { hci, request_queue }
|
||||||
|
}
|
||||||
|
@@
|
||||||
|
loop {
|
||||||
|
debug!("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)
|
||||||
|
- }
|
||||||
|
+ Err(err) => {
|
||||||
|
+ warn!("xhcid: device enumerator shutting down: {}", err);
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
};
|
||||||
|
@@
|
||||||
|
- if flags.contains(PortFlags::CCS) {
|
||||||
|
+ if flags.contains(PortFlags::CCS) {
|
||||||
|
+ let Some(flags) = self.wait_for_stable_port_flags(port_id, flags) else {
|
||||||
|
+ warn!(
|
||||||
|
+ "Port {} never reached a stable connected state; ignoring this change",
|
||||||
|
+ port_id
|
||||||
|
+ );
|
||||||
|
+ continue;
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
debug!(
|
||||||
|
"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::PED) {
|
||||||
|
- let disabled_state = flags.contains(PortFlags::PP)
|
||||||
|
- && flags.contains(PortFlags::CCS)
|
||||||
|
- && !flags.contains(PortFlags::PED)
|
||||||
|
- && !flags.contains(PortFlags::PR);
|
||||||
|
-
|
||||||
|
- if !disabled_state {
|
||||||
|
- panic!(
|
||||||
|
- "Port {} isn't in the disabled state! Current flags: {:?}",
|
||||||
|
- port_id, flags
|
||||||
|
- );
|
||||||
|
- } else {
|
||||||
|
- debug!("Port {} has entered the disabled state.", port_id);
|
||||||
|
- }
|
||||||
|
+ debug!("Port {} has entered the disabled state.", port_id);
|
||||||
|
@@
|
||||||
|
if !enabled_state {
|
||||||
|
warn!(
|
||||||
|
"Port {} isn't in the enabled state! Current flags: {:?}",
|
||||||
|
port_id, flags
|
||||||
|
);
|
||||||
|
- } else {
|
||||||
|
- debug!(
|
||||||
|
- "Port {} is in the enabled state. Proceeding with enumeration",
|
||||||
|
- port_id
|
||||||
|
- );
|
||||||
|
+ continue;
|
||||||
|
}
|
||||||
|
+ debug!(
|
||||||
|
+ "Port {} is in the enabled state. Proceeding with enumeration",
|
||||||
|
+ port_id
|
||||||
|
+ );
|
||||||
|
}
|
||||||
|
diff --git a/drivers/usb/xhcid/src/xhci/irq_reactor.rs b/drivers/usb/xhcid/src/xhci/irq_reactor.rs
|
||||||
|
--- a/drivers/usb/xhcid/src/xhci/irq_reactor.rs
|
||||||
|
+++ b/drivers/usb/xhcid/src/xhci/irq_reactor.rs
|
||||||
|
@@
|
||||||
|
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_id })
|
||||||
|
- .expect(
|
||||||
|
- format!(
|
||||||
|
- "Failed to transmit device numeration request on port {}",
|
||||||
|
- port_id
|
||||||
|
- )
|
||||||
|
- .as_str(),
|
||||||
|
- );
|
||||||
|
+ if let Err(err) = self
|
||||||
|
+ .device_enumerator_sender
|
||||||
|
+ .send(DeviceEnumerationRequest { port_id })
|
||||||
|
+ {
|
||||||
|
+ warn!(
|
||||||
|
+ "Failed to transmit device enumeration request on port {}: {}",
|
||||||
|
+ port_id,
|
||||||
|
+ err
|
||||||
|
+ );
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
{
|
||||||
|
let mut ports = self.hci.ports.lock().unwrap();
|
||||||
|
|||||||
@@ -219,6 +219,43 @@ index b3683125..be7db1be 100644
|
|||||||
pub fn feature_info() -> FeatureInfo {
|
pub fn feature_info() -> FeatureInfo {
|
||||||
cpuid()
|
cpuid()
|
||||||
diff --git a/src/context/memory.rs b/src/context/memory.rs
|
diff --git a/src/context/memory.rs b/src/context/memory.rs
|
||||||
|
--- a/src/context/memory.rs
|
||||||
|
+++ b/src/context/memory.rs
|
||||||
|
@@
|
||||||
|
let new_flags = grant_flags.write(grant_flags.has_write() && allow_writable);
|
||||||
|
- let Some(flush) = (unsafe {
|
||||||
|
- addr_space
|
||||||
|
- .table
|
||||||
|
- .utable
|
||||||
|
- .map_phys(faulting_page.start_address(), frame.base(), new_flags)
|
||||||
|
- }) else {
|
||||||
|
- // TODO
|
||||||
|
- return Err(PfError::Oom);
|
||||||
|
- };
|
||||||
|
+ let flush = if faulting_frame_opt.is_some() {
|
||||||
|
+ let Some((_, _, flush)) = (unsafe {
|
||||||
|
+ addr_space
|
||||||
|
+ .table
|
||||||
|
+ .utable
|
||||||
|
+ .remap_with_full(faulting_page.start_address(), |_, _| {
|
||||||
|
+ Some((frame.base(), new_flags))
|
||||||
|
+ })
|
||||||
|
+ }) else {
|
||||||
|
+ return Err(PfError::Oom);
|
||||||
|
+ };
|
||||||
|
+ flush
|
||||||
|
+ } else {
|
||||||
|
+ let Some(flush) = (unsafe {
|
||||||
|
+ addr_space
|
||||||
|
+ .table
|
||||||
|
+ .utable
|
||||||
|
+ .map_phys(faulting_page.start_address(), frame.base(), new_flags)
|
||||||
|
+ }) else {
|
||||||
|
+ return Err(PfError::Oom);
|
||||||
|
+ };
|
||||||
|
+ flush
|
||||||
|
+ };
|
||||||
|
diff --git a/src/context/memory.rs b/src/context/memory.rs
|
||||||
index 94519448..368efb0d 100644
|
index 94519448..368efb0d 100644
|
||||||
--- a/src/context/memory.rs
|
--- a/src/context/memory.rs
|
||||||
+++ b/src/context/memory.rs
|
+++ b/src/context/memory.rs
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#ifndef _LINUX_DEVICE_H
|
#ifndef _LINUX_DEVICE_H
|
||||||
#define _LINUX_DEVICE_H
|
#define _LINUX_DEVICE_H
|
||||||
|
|
||||||
#include <linux/types.h>
|
#include "types.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
struct device_driver {
|
struct device_driver {
|
||||||
@@ -27,11 +27,7 @@ static inline void dev_set_drvdata(struct device *dev, void *data)
|
|||||||
dev->driver_data = data;
|
dev->driver_data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct class {
|
extern void *devm_kzalloc(struct device *dev, size_t size, gfp_t flags);
|
||||||
const char *name;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern struct device *devm_kzalloc(struct device *dev, size_t size, gfp_t flags);
|
|
||||||
extern void devm_kfree(struct device *dev, void *ptr);
|
extern void devm_kfree(struct device *dev, void *ptr);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#ifndef _LINUX_FIRMWARE_H
|
#ifndef _LINUX_FIRMWARE_H
|
||||||
#define _LINUX_FIRMWARE_H
|
#define _LINUX_FIRMWARE_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
|
||||||
struct firmware {
|
struct firmware {
|
||||||
@@ -23,4 +24,6 @@ extern int request_firmware_nowait(
|
|||||||
extern int request_firmware_direct(const struct firmware **fw,
|
extern int request_firmware_direct(const struct firmware **fw,
|
||||||
const char *name, struct device *dev);
|
const char *name, struct device *dev);
|
||||||
|
|
||||||
|
#define FW_ACTION_HOTPLUG 0
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -3,29 +3,16 @@
|
|||||||
|
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/irq.h>
|
#include <linux/irq.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
|
||||||
static inline int in_interrupt(void)
|
extern void local_irq_save(unsigned long *flags);
|
||||||
{
|
extern void local_irq_restore(unsigned long flags);
|
||||||
return 0;
|
extern void local_irq_disable(void);
|
||||||
}
|
extern void local_irq_enable(void);
|
||||||
|
extern int irqs_disabled(void);
|
||||||
|
|
||||||
static inline int in_irq(void)
|
static inline int in_interrupt(void) { return irqs_disabled(); }
|
||||||
{
|
static inline int in_irq(void) { return irqs_disabled(); }
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void local_irq_save(unsigned long *flags)
|
|
||||||
{
|
|
||||||
(void)flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void local_irq_restore(unsigned long flags)
|
|
||||||
{
|
|
||||||
(void)flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void local_irq_disable(void) {}
|
|
||||||
static inline void local_irq_enable(void) {}
|
|
||||||
|
|
||||||
#define disable_irq_nosync(irq) ((void)(irq))
|
#define disable_irq_nosync(irq) ((void)(irq))
|
||||||
#define enable_irq(irq) ((void)(irq))
|
#define enable_irq(irq) ((void)(irq))
|
||||||
|
|||||||
@@ -11,12 +11,7 @@ extern void mutex_init(struct mutex *lock);
|
|||||||
extern void mutex_lock(struct mutex *lock);
|
extern void mutex_lock(struct mutex *lock);
|
||||||
extern void mutex_unlock(struct mutex *lock);
|
extern void mutex_unlock(struct mutex *lock);
|
||||||
extern int mutex_is_locked(struct mutex *lock);
|
extern int mutex_is_locked(struct mutex *lock);
|
||||||
|
extern int mutex_trylock(struct mutex *lock);
|
||||||
static inline int mutex_trylock(struct mutex *lock)
|
|
||||||
{
|
|
||||||
(void)lock;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define DEFINE_MUTEX(name) struct mutex name = { .__opaque = {0} }
|
#define DEFINE_MUTEX(name) struct mutex name = { .__opaque = {0} }
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ struct pci_device_id {
|
|||||||
|
|
||||||
struct pci_dev {
|
struct pci_dev {
|
||||||
u16 vendor;
|
u16 vendor;
|
||||||
u16 device;
|
u16 device_id;
|
||||||
u8 bus_number;
|
u8 bus_number;
|
||||||
u8 dev_number;
|
u8 dev_number;
|
||||||
u8 func_number;
|
u8 func_number;
|
||||||
@@ -33,7 +33,7 @@ struct pci_dev {
|
|||||||
u64 resource_start[6];
|
u64 resource_start[6];
|
||||||
u64 resource_len[6];
|
u64 resource_len[6];
|
||||||
void *driver_data;
|
void *driver_data;
|
||||||
struct device device;
|
struct device device_obj;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pci_driver {
|
struct pci_driver {
|
||||||
|
|||||||
@@ -11,39 +11,13 @@ struct timer_list {
|
|||||||
unsigned char __opaque[64];
|
unsigned char __opaque[64];
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void setup_timer(struct timer_list *timer,
|
extern void setup_timer(struct timer_list *timer,
|
||||||
void (*function)(unsigned long),
|
void (*function)(unsigned long),
|
||||||
unsigned long data)
|
unsigned long data);
|
||||||
{
|
extern int mod_timer(struct timer_list *timer, unsigned long expires);
|
||||||
timer->function = function;
|
extern int del_timer(struct timer_list *timer);
|
||||||
timer->data = data;
|
extern int del_timer_sync(struct timer_list *timer);
|
||||||
timer->expires = 0;
|
extern int timer_pending(const struct timer_list *timer);
|
||||||
}
|
|
||||||
|
|
||||||
static inline int mod_timer(struct timer_list *timer, unsigned long expires)
|
|
||||||
{
|
|
||||||
(void)timer;
|
|
||||||
(void)expires;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int del_timer(struct timer_list *timer)
|
|
||||||
{
|
|
||||||
(void)timer;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int del_timer_sync(struct timer_list *timer)
|
|
||||||
{
|
|
||||||
(void)timer;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int timer_pending(const struct timer_list *timer)
|
|
||||||
{
|
|
||||||
(void)timer;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define DEFINE_TIMER(_name, _function, _flags, _data) \
|
#define DEFINE_TIMER(_name, _function, _flags, _data) \
|
||||||
struct timer_list _name = { .function = (_function), .data = (_data) }
|
struct timer_list _name = { .function = (_function), .data = (_data) }
|
||||||
|
|||||||
@@ -2,13 +2,19 @@
|
|||||||
|
|
||||||
pub mod rust_impl;
|
pub mod rust_impl;
|
||||||
|
|
||||||
|
#[cfg(all(test, not(target_os = "redox")))]
|
||||||
|
mod test_host_redox_shims;
|
||||||
|
|
||||||
pub use rust_impl::device;
|
pub use rust_impl::device;
|
||||||
pub use rust_impl::dma;
|
pub use rust_impl::dma;
|
||||||
pub use rust_impl::drm_shim;
|
pub use rust_impl::drm_shim;
|
||||||
pub use rust_impl::firmware;
|
pub use rust_impl::firmware;
|
||||||
pub use rust_impl::io;
|
pub use rust_impl::io;
|
||||||
pub use rust_impl::irq;
|
pub use rust_impl::irq;
|
||||||
|
pub use rust_impl::mac80211;
|
||||||
pub use rust_impl::memory;
|
pub use rust_impl::memory;
|
||||||
|
pub use rust_impl::net;
|
||||||
pub use rust_impl::pci;
|
pub use rust_impl::pci;
|
||||||
pub use rust_impl::sync;
|
pub use rust_impl::sync;
|
||||||
|
pub use rust_impl::wireless;
|
||||||
pub use rust_impl::workqueue;
|
pub use rust_impl::workqueue;
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ const GFP_DMA32: u32 = 2;
|
|||||||
|
|
||||||
/// Wrapper to make raw pointers `Send`, required because `DEVRES_MAP` is a
|
/// Wrapper to make raw pointers `Send`, required because `DEVRES_MAP` is a
|
||||||
/// global `Mutex` (which needs `T: Send`). Raw pointers are not `Send` by
|
/// global `Mutex` (which needs `T: Send`). Raw pointers are not `Send` by
|
||||||
/// default since the compiler can't prove thread-safety. Here each `(ptr,
|
/// default since the compiler can't prove thread-safety. Here each tracked
|
||||||
/// Layout)` pair is exclusively owned by the device that allocated it — only
|
/// pointer is exclusively owned by the device that allocated it — only
|
||||||
/// freed via `devm_kfree` or `devres_free_all` — so sending across threads is
|
/// freed via `devm_kfree` or `devres_free_all` — so sending across threads is
|
||||||
/// safe.
|
/// safe.
|
||||||
struct TrackedAlloc(*mut u8, Layout);
|
struct TrackedAlloc(*mut u8);
|
||||||
unsafe impl Send for TrackedAlloc {}
|
unsafe impl Send for TrackedAlloc {}
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
@@ -42,16 +42,15 @@ pub extern "C" fn devm_kzalloc(dev: *mut u8, size: usize, flags: u32) -> *mut u8
|
|||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
let layout = match tracked_layout(size, flags) {
|
if tracked_layout(size, flags).is_none() {
|
||||||
Some(layout) => layout,
|
return ptr;
|
||||||
None => return ptr,
|
}
|
||||||
};
|
|
||||||
|
|
||||||
if let Ok(mut devres_map) = DEVRES_MAP.lock() {
|
if let Ok(mut devres_map) = DEVRES_MAP.lock() {
|
||||||
devres_map
|
devres_map
|
||||||
.entry(dev as usize)
|
.entry(dev as usize)
|
||||||
.or_default()
|
.or_default()
|
||||||
.push(TrackedAlloc(ptr, layout));
|
.push(TrackedAlloc(ptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr
|
ptr
|
||||||
|
|||||||
@@ -1,5 +1,87 @@
|
|||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
|
fn firmware_search_roots() -> Vec<std::path::PathBuf> {
|
||||||
|
let mut roots = Vec::new();
|
||||||
|
if let Some(root) = std::env::var_os("REDBEAR_LINUX_KPI_FIRMWARE_ROOT") {
|
||||||
|
roots.push(root.into());
|
||||||
|
}
|
||||||
|
roots.push("/scheme/firmware".into());
|
||||||
|
roots.push("/lib/firmware".into());
|
||||||
|
roots
|
||||||
|
}
|
||||||
|
|
||||||
|
fn firmware_name(name: *const u8) -> Result<String, i32> {
|
||||||
|
if name.is_null() {
|
||||||
|
return Err(-22);
|
||||||
|
}
|
||||||
|
|
||||||
|
let name_str = unsafe {
|
||||||
|
let len = {
|
||||||
|
let mut l = 0;
|
||||||
|
while *name.add(l) != 0 {
|
||||||
|
l += 1;
|
||||||
|
}
|
||||||
|
l
|
||||||
|
};
|
||||||
|
let slice = std::slice::from_raw_parts(name, len);
|
||||||
|
match std::str::from_utf8(slice) {
|
||||||
|
Ok(s) => s.to_string(),
|
||||||
|
Err(_) => return Err(-22),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(name_str)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_firmware_bytes(name: &str) -> Result<Vec<u8>, i32> {
|
||||||
|
for root in firmware_search_roots() {
|
||||||
|
let candidate = root.join(name);
|
||||||
|
match std::fs::read(&candidate) {
|
||||||
|
Ok(bytes) => {
|
||||||
|
log::info!(
|
||||||
|
"request_firmware: loaded '{}' via {}",
|
||||||
|
name,
|
||||||
|
candidate.display()
|
||||||
|
);
|
||||||
|
return Ok(bytes);
|
||||||
|
}
|
||||||
|
Err(err) if err.kind() == std::io::ErrorKind::NotFound => continue,
|
||||||
|
Err(err) => {
|
||||||
|
log::error!(
|
||||||
|
"request_firmware: failed to load '{}' via {}: {}",
|
||||||
|
name,
|
||||||
|
candidate.display(),
|
||||||
|
err
|
||||||
|
);
|
||||||
|
return Err(-5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log::error!("request_firmware: failed to locate '{}'", name);
|
||||||
|
Err(-2)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn install_firmware(fw: *mut *mut Firmware, data: Vec<u8>) -> i32 {
|
||||||
|
let size = data.len();
|
||||||
|
let layout = match std::alloc::Layout::from_size_align(size, 1) {
|
||||||
|
Ok(l) => l,
|
||||||
|
Err(_) => return -12,
|
||||||
|
};
|
||||||
|
let ptr = unsafe { std::alloc::alloc(layout) };
|
||||||
|
if ptr.is_null() {
|
||||||
|
return -12;
|
||||||
|
}
|
||||||
|
unsafe { ptr::copy_nonoverlapping(data.as_ptr(), ptr, size) };
|
||||||
|
|
||||||
|
let firmware = Box::new(Firmware {
|
||||||
|
size,
|
||||||
|
data: ptr as *const u8,
|
||||||
|
});
|
||||||
|
unsafe { *fw = Box::into_raw(firmware) };
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct Firmware {
|
pub struct Firmware {
|
||||||
pub size: usize,
|
pub size: usize,
|
||||||
@@ -35,54 +117,68 @@ pub extern "C" fn request_firmware(fw: *mut *mut Firmware, name: *const u8, _dev
|
|||||||
return -22;
|
return -22;
|
||||||
}
|
}
|
||||||
|
|
||||||
let name_str = unsafe {
|
let name_str = match firmware_name(name) {
|
||||||
let len = {
|
Ok(name_str) => name_str,
|
||||||
let mut l = 0;
|
Err(err) => return err,
|
||||||
while *name.add(l) != 0 {
|
|
||||||
l += 1;
|
|
||||||
}
|
|
||||||
l
|
|
||||||
};
|
|
||||||
let slice = std::slice::from_raw_parts(name, len);
|
|
||||||
match std::str::from_utf8(slice) {
|
|
||||||
Ok(s) => s,
|
|
||||||
Err(_) => return -22,
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let firmware_path = format!("/scheme/firmware/{}", name_str);
|
match load_firmware_bytes(&name_str) {
|
||||||
log::info!(
|
Ok(data) => install_firmware(fw, data),
|
||||||
"request_firmware: loading '{}' via {}",
|
Err(err) => err,
|
||||||
name_str,
|
|
||||||
firmware_path
|
|
||||||
);
|
|
||||||
|
|
||||||
let data = match std::fs::read(&firmware_path) {
|
|
||||||
Ok(d) => d,
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("request_firmware: failed to load '{}': {}", name_str, e);
|
|
||||||
return -2;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let size = data.len();
|
|
||||||
let layout = match std::alloc::Layout::from_size_align(size, 1) {
|
|
||||||
Ok(l) => l,
|
|
||||||
Err(_) => return -12,
|
|
||||||
};
|
|
||||||
let ptr = unsafe { std::alloc::alloc(layout) };
|
|
||||||
if ptr.is_null() {
|
|
||||||
return -12;
|
|
||||||
}
|
}
|
||||||
unsafe { ptr::copy_nonoverlapping(data.as_ptr(), ptr, size) };
|
}
|
||||||
|
|
||||||
let firmware = Box::new(Firmware {
|
#[no_mangle]
|
||||||
size,
|
pub extern "C" fn request_firmware_direct(
|
||||||
data: ptr as *const u8,
|
fw: *mut *mut Firmware,
|
||||||
|
name: *const u8,
|
||||||
|
dev: *mut u8,
|
||||||
|
) -> i32 {
|
||||||
|
request_firmware(fw, name, dev)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn request_firmware_nowait(
|
||||||
|
_dev: *mut u8,
|
||||||
|
_uevent: i32,
|
||||||
|
name: *const u8,
|
||||||
|
context: *mut u8,
|
||||||
|
cont: Option<extern "C" fn(*const Firmware, *mut u8)>,
|
||||||
|
) -> i32 {
|
||||||
|
let Some(cont) = cont else {
|
||||||
|
return -22;
|
||||||
|
};
|
||||||
|
|
||||||
|
let name_str = match firmware_name(name) {
|
||||||
|
Ok(name_str) => name_str,
|
||||||
|
Err(err) => return err,
|
||||||
|
};
|
||||||
|
|
||||||
|
let fw_ptr = match load_firmware_bytes(&name_str) {
|
||||||
|
Ok(data) => {
|
||||||
|
let mut fw_ptr: *mut Firmware = ptr::null_mut();
|
||||||
|
let rc = install_firmware(&mut fw_ptr, data);
|
||||||
|
if rc != 0 {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
fw_ptr
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
log::warn!(
|
||||||
|
"request_firmware_nowait: unable to pre-load '{}': {}",
|
||||||
|
name_str,
|
||||||
|
err
|
||||||
|
);
|
||||||
|
ptr::null_mut()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let fw_addr = fw_ptr as usize;
|
||||||
|
let context_addr = context as usize;
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
cont(fw_addr as *const Firmware, context_addr as *mut u8);
|
||||||
});
|
});
|
||||||
unsafe { *fw = Box::into_raw(firmware) };
|
|
||||||
|
|
||||||
log::info!("request_firmware: loaded {} bytes for '{}'", size, name_str);
|
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,3 +189,89 @@ pub extern "C" fn release_firmware(fw: *mut Firmware) {
|
|||||||
}
|
}
|
||||||
unsafe { drop(Box::from_raw(fw)) };
|
unsafe { drop(Box::from_raw(fw)) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use std::ffi::CString;
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
use std::sync::Mutex;
|
||||||
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
|
static TEST_ENV_LOCK: std::sync::LazyLock<Mutex<()>> =
|
||||||
|
std::sync::LazyLock::new(|| Mutex::new(()));
|
||||||
|
|
||||||
|
fn temp_root(prefix: &str) -> std::path::PathBuf {
|
||||||
|
let stamp = SystemTime::now()
|
||||||
|
.duration_since(UNIX_EPOCH)
|
||||||
|
.unwrap()
|
||||||
|
.as_nanos();
|
||||||
|
let path = std::env::temp_dir().join(format!("{prefix}-{stamp}"));
|
||||||
|
std::fs::create_dir_all(&path).unwrap();
|
||||||
|
path
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn request_firmware_direct_uses_override_root() {
|
||||||
|
let _guard = TEST_ENV_LOCK.lock().unwrap();
|
||||||
|
let root = temp_root("rbos-linux-kpi-fw");
|
||||||
|
std::fs::write(root.join("iwlwifi-test.ucode"), [1u8, 2, 3]).unwrap();
|
||||||
|
unsafe {
|
||||||
|
std::env::set_var("REDBEAR_LINUX_KPI_FIRMWARE_ROOT", &root);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut fw: *mut Firmware = ptr::null_mut();
|
||||||
|
let name = CString::new("iwlwifi-test.ucode").unwrap();
|
||||||
|
let rc = request_firmware_direct(&mut fw, name.as_ptr().cast::<u8>(), ptr::null_mut());
|
||||||
|
assert_eq!(rc, 0);
|
||||||
|
assert!(!fw.is_null());
|
||||||
|
assert_eq!(unsafe { (*fw).size }, 3);
|
||||||
|
release_firmware(fw);
|
||||||
|
unsafe {
|
||||||
|
std::env::remove_var("REDBEAR_LINUX_KPI_FIRMWARE_ROOT");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn request_firmware_nowait_invokes_callback() {
|
||||||
|
let _guard = TEST_ENV_LOCK.lock().unwrap();
|
||||||
|
let root = temp_root("rbos-linux-kpi-fw-nowait");
|
||||||
|
std::fs::write(root.join("iwlwifi-test-async.ucode"), [9u8, 8, 7]).unwrap();
|
||||||
|
unsafe {
|
||||||
|
std::env::set_var("REDBEAR_LINUX_KPI_FIRMWARE_ROOT", &root);
|
||||||
|
}
|
||||||
|
|
||||||
|
static CALLED: AtomicBool = AtomicBool::new(false);
|
||||||
|
|
||||||
|
extern "C" fn callback(fw: *const Firmware, _context: *mut u8) {
|
||||||
|
assert!(!fw.is_null());
|
||||||
|
CALLED.store(true, Ordering::Release);
|
||||||
|
release_firmware(fw as *mut Firmware);
|
||||||
|
}
|
||||||
|
|
||||||
|
let name = CString::new("iwlwifi-test-async.ucode").unwrap();
|
||||||
|
let rc = request_firmware_nowait(
|
||||||
|
ptr::null_mut(),
|
||||||
|
0,
|
||||||
|
name.as_ptr().cast::<u8>(),
|
||||||
|
ptr::null_mut(),
|
||||||
|
Some(callback),
|
||||||
|
);
|
||||||
|
assert_eq!(rc, 0);
|
||||||
|
|
||||||
|
for _ in 0..100 {
|
||||||
|
if CALLED.load(Ordering::Acquire) {
|
||||||
|
unsafe {
|
||||||
|
std::env::remove_var("REDBEAR_LINUX_KPI_FIRMWARE_ROOT");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(5));
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
std::env::remove_var("REDBEAR_LINUX_KPI_FIRMWARE_ROOT");
|
||||||
|
}
|
||||||
|
panic!("request_firmware_nowait callback was not invoked");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -72,6 +72,24 @@ fn dma32_alloc(size: usize) -> *mut u8 {
|
|||||||
|
|
||||||
let phys = virt_to_phys(candidate as usize);
|
let phys = virt_to_phys(candidate as usize);
|
||||||
if phys == 0 {
|
if phys == 0 {
|
||||||
|
#[cfg(all(test, not(target_os = "redox")))]
|
||||||
|
let host_test_fallback = true;
|
||||||
|
#[cfg(not(all(test, not(target_os = "redox"))))]
|
||||||
|
let host_test_fallback = false;
|
||||||
|
|
||||||
|
if host_test_fallback {
|
||||||
|
log::debug!(
|
||||||
|
"dma32_alloc: host test fallback for virt={:#x} without translation",
|
||||||
|
candidate as usize
|
||||||
|
);
|
||||||
|
if let Ok(mut tracker) = DMA32_TRACKER.lock() {
|
||||||
|
tracker.insert(SendU8Ptr(candidate), layout);
|
||||||
|
return candidate;
|
||||||
|
}
|
||||||
|
unsafe { dealloc(candidate, layout) };
|
||||||
|
return ptr::null_mut();
|
||||||
|
}
|
||||||
|
|
||||||
log::warn!(
|
log::warn!(
|
||||||
"dma32_alloc: virt_to_phys failed for {:#x}",
|
"dma32_alloc: virt_to_phys failed for {:#x}",
|
||||||
candidate as usize
|
candidate as usize
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ pub mod device;
|
|||||||
pub mod dma;
|
pub mod dma;
|
||||||
pub mod drm_shim;
|
pub mod drm_shim;
|
||||||
pub mod firmware;
|
pub mod firmware;
|
||||||
|
pub mod mac80211;
|
||||||
|
pub mod net;
|
||||||
pub mod idr;
|
pub mod idr;
|
||||||
pub mod io;
|
pub mod io;
|
||||||
pub mod irq;
|
pub mod irq;
|
||||||
@@ -10,4 +12,5 @@ pub mod pci;
|
|||||||
pub mod sync;
|
pub mod sync;
|
||||||
pub mod timer;
|
pub mod timer;
|
||||||
pub mod wait;
|
pub mod wait;
|
||||||
|
pub mod wireless;
|
||||||
pub mod workqueue;
|
pub mod workqueue;
|
||||||
|
|||||||
@@ -2,9 +2,7 @@ use std::os::raw::c_ulong;
|
|||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
use redox_driver_sys::pci::{
|
use redox_driver_sys::pci::{enumerate_pci_all, PciDevice, PciDeviceInfo, PciLocation};
|
||||||
enumerate_pci_class, PciDevice, PciDeviceInfo, PciLocation, PCI_CLASS_DISPLAY,
|
|
||||||
};
|
|
||||||
|
|
||||||
const EINVAL: i32 = 22;
|
const EINVAL: i32 = 22;
|
||||||
const ENODEV: i32 = 19;
|
const ENODEV: i32 = 19;
|
||||||
@@ -354,7 +352,7 @@ pub extern "C" fn pci_register_driver(drv: *mut PciDriver) -> i32 {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let devices = match enumerate_pci_class(PCI_CLASS_DISPLAY) {
|
let devices = match enumerate_pci_all() {
|
||||||
Ok(devices) => devices,
|
Ok(devices) => devices,
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
log::warn!("pci_register_driver: PCI enumeration failed: {}", error);
|
log::warn!("pci_register_driver: PCI enumeration failed: {}", error);
|
||||||
@@ -365,7 +363,7 @@ pub extern "C" fn pci_register_driver(drv: *mut PciDriver) -> i32 {
|
|||||||
let Some((info, id_ptr)) = devices.into_iter().find_map(|candidate| {
|
let Some((info, id_ptr)) = devices.into_iter().find_map(|candidate| {
|
||||||
matching_id_entry(&candidate, driver.id_table).map(|id_ptr| (candidate, id_ptr))
|
matching_id_entry(&candidate, driver.id_table).map(|id_ptr| (candidate, id_ptr))
|
||||||
}) else {
|
}) else {
|
||||||
log::info!("pci_register_driver: no matching PCI display device found");
|
log::info!("pci_register_driver: no matching PCI device found");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,22 @@ pub extern "C" fn mutex_lock(m: *mut LinuxMutex) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn mutex_trylock(m: *mut LinuxMutex) -> i32 {
|
||||||
|
if m.is_null() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if unsafe { &*m }
|
||||||
|
.state
|
||||||
|
.compare_exchange(UNLOCKED, LOCKED, Ordering::Acquire, Ordering::Relaxed)
|
||||||
|
.is_ok()
|
||||||
|
{
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn mutex_unlock(m: *mut LinuxMutex) {
|
pub extern "C" fn mutex_unlock(m: *mut LinuxMutex) {
|
||||||
if m.is_null() {
|
if m.is_null() {
|
||||||
@@ -121,6 +137,18 @@ pub extern "C" fn local_irq_restore(flags: u64) {
|
|||||||
IRQ_DEPTH.store(flags as u32, Ordering::Release);
|
IRQ_DEPTH.store(flags as u32, Ordering::Release);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn local_irq_disable() {
|
||||||
|
IRQ_DEPTH.fetch_add(1, Ordering::Acquire);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn local_irq_enable() {
|
||||||
|
let _ = IRQ_DEPTH.fetch_update(Ordering::AcqRel, Ordering::Relaxed, |depth| {
|
||||||
|
Some(depth.saturating_sub(1))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn irqs_disabled() -> bool {
|
pub extern "C" fn irqs_disabled() -> bool {
|
||||||
IRQ_DEPTH.load(Ordering::Acquire) > 0
|
IRQ_DEPTH.load(Ordering::Acquire) > 0
|
||||||
@@ -175,3 +203,29 @@ pub extern "C" fn reinit_completion(c: *mut Completion) {
|
|||||||
}
|
}
|
||||||
unsafe { &*c }.done.store(0, Ordering::Release);
|
unsafe { &*c }.done.store(0, Ordering::Release);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mutex_trylock_reflects_lock_state() {
|
||||||
|
let mut lock = LinuxMutex {
|
||||||
|
state: AtomicU8::new(UNLOCKED),
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(mutex_trylock(&mut lock), 1);
|
||||||
|
assert_eq!(mutex_trylock(&mut lock), 0);
|
||||||
|
mutex_unlock(&mut lock);
|
||||||
|
assert_eq!(mutex_trylock(&mut lock), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn local_irq_disable_enable_tracks_depth() {
|
||||||
|
IRQ_DEPTH.store(0, Ordering::Release);
|
||||||
|
local_irq_disable();
|
||||||
|
assert!(irqs_disabled());
|
||||||
|
local_irq_enable();
|
||||||
|
assert!(!irqs_disabled());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::os::raw::c_int;
|
use std::os::raw::{c_int, c_ulong};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::sync::atomic::{AtomicBool, AtomicPtr, AtomicU64, Ordering};
|
use std::sync::atomic::{AtomicBool, AtomicPtr, AtomicU64, Ordering};
|
||||||
use std::sync::{Arc, Mutex, OnceLock};
|
use std::sync::{Arc, Mutex, OnceLock};
|
||||||
@@ -117,8 +117,8 @@ fn join_all_handles(entry: &TimerEntry) {
|
|||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn setup_timer(
|
pub extern "C" fn setup_timer(
|
||||||
timer: *mut TimerList,
|
timer: *mut TimerList,
|
||||||
function: extern "C" fn(*mut u8),
|
function: extern "C" fn(c_ulong),
|
||||||
data: *mut u8,
|
data: c_ulong,
|
||||||
) {
|
) {
|
||||||
if timer.is_null() {
|
if timer.is_null() {
|
||||||
return;
|
return;
|
||||||
@@ -131,13 +131,13 @@ pub extern "C" fn setup_timer(
|
|||||||
TimerList {
|
TimerList {
|
||||||
expires: AtomicU64::new(0),
|
expires: AtomicU64::new(0),
|
||||||
function: AtomicPtr::new(function_ptr),
|
function: AtomicPtr::new(function_ptr),
|
||||||
data: AtomicPtr::new(data),
|
data: AtomicPtr::new(data as usize as *mut u8),
|
||||||
active: AtomicBool::new(false),
|
active: AtomicBool::new(false),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
reset_timer_entry(timer, function_ptr, data);
|
reset_timer_entry(timer, function_ptr, data as usize as *mut u8);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@@ -185,8 +185,8 @@ pub extern "C" fn mod_timer(timer: *mut TimerList, expires: u64) -> i32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let function =
|
let function =
|
||||||
unsafe { std::mem::transmute::<usize, extern "C" fn(*mut u8)>(function_addr) };
|
unsafe { std::mem::transmute::<usize, extern "C" fn(c_ulong)>(function_addr) };
|
||||||
function(data_addr as *mut u8);
|
function(data_addr as c_ulong);
|
||||||
|
|
||||||
if entry_for_thread.generation.load(Ordering::Acquire) == generation {
|
if entry_for_thread.generation.load(Ordering::Acquire) == generation {
|
||||||
entry_for_thread.active.store(false, Ordering::Release);
|
entry_for_thread.active.store(false, Ordering::Release);
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
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_PRIVATE, O_CLOEXEC, PROT_READ, PROT_WRITE};
|
use redox_syscall::data::Map;
|
||||||
|
use redox_syscall::flag::{MapFlags, 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;
|
||||||
|
|
||||||
@@ -155,18 +156,15 @@ impl DmaBuffer {
|
|||||||
let region_fd = libredox::call::openat(mem_fd as usize, &path, O_CLOEXEC as i32, 0)
|
let region_fd = libredox::call::openat(mem_fd as usize, &path, 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())))?;
|
||||||
|
|
||||||
// Map it into our address space
|
let map = Map {
|
||||||
let ptr = unsafe {
|
offset: 0,
|
||||||
libredox::call::mmap(libredox::call::MmapArgs {
|
size,
|
||||||
fd: region_fd as usize,
|
flags: MapFlags::from_bits_truncate((MAP_PRIVATE | PROT_READ | PROT_WRITE).bits()),
|
||||||
offset: 0,
|
address: 0,
|
||||||
length: size,
|
};
|
||||||
flags: MAP_PRIVATE.bits() as u32,
|
|
||||||
prot: (PROT_READ | PROT_WRITE).bits() as u32,
|
// Map it into our address space through SYS_FMAP with combined map+prot flags.
|
||||||
addr: core::ptr::null_mut(),
|
let ptr = unsafe { redox_syscall::call::fmap(region_fd as usize, &map) }.map_err(|e| {
|
||||||
})
|
|
||||||
}
|
|
||||||
.map_err(|e| {
|
|
||||||
let _ = libredox::call::close(region_fd as usize);
|
let _ = libredox::call::close(region_fd as usize);
|
||||||
DriverError::MappingFailed {
|
DriverError::MappingFailed {
|
||||||
phys: 0,
|
phys: 0,
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#[cfg(all(target_arch = "x86_64", target_os = "redox"))]
|
||||||
use syscall as redox_syscall;
|
use syscall as redox_syscall;
|
||||||
|
|
||||||
use crate::Result;
|
use crate::Result;
|
||||||
|
|||||||
@@ -12,14 +12,18 @@
|
|||||||
//!
|
//!
|
||||||
//! ```no_run
|
//! ```no_run
|
||||||
//! use redox_driver_sys::pci::PciDevice;
|
//! use redox_driver_sys::pci::PciDevice;
|
||||||
|
//! use redox_driver_sys::Result;
|
||||||
//!
|
//!
|
||||||
//! // Open a PCI device by location
|
//! fn example() -> Result<()> {
|
||||||
//! let dev = PciDevice::open(0, 0x10, 0, 0)?;
|
//! // Open a PCI device by location
|
||||||
//! let vendor = dev.vendor_id();
|
//! let mut dev = PciDevice::open(0, 0x10, 0, 0)?;
|
||||||
//! let bars = dev.parse_bars()?;
|
//! let _vendor = dev.vendor_id();
|
||||||
//! if let Some(bar) = bars[0].memory_info() {
|
//! let bars = dev.parse_bars()?;
|
||||||
//! let mmio = dev.map_bar(0, bar.addr, bar.size)?;
|
//! if let Some((addr, size)) = bars[0].memory_info() {
|
||||||
//! let reg = mmio.read32(0);
|
//! let mmio = dev.map_bar(0, addr, size)?;
|
||||||
|
//! let _reg = mmio.read32(0);
|
||||||
|
//! }
|
||||||
|
//! Ok(())
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use core::ptr;
|
use core::ptr;
|
||||||
use core::sync::atomic::{AtomicPtr, Ordering};
|
use core::sync::atomic::{AtomicPtr, Ordering};
|
||||||
|
|
||||||
|
use redox_syscall::data::Map;
|
||||||
use redox_syscall::flag::{
|
use redox_syscall::flag::{
|
||||||
MAP_SHARED, O_CLOEXEC, O_RDONLY, O_RDWR, O_WRONLY, PROT_READ, PROT_WRITE,
|
MAP_SHARED, O_CLOEXEC, O_RDONLY, O_RDWR, O_WRONLY, PROT_READ, PROT_WRITE,
|
||||||
};
|
};
|
||||||
@@ -110,20 +111,19 @@ impl MmioRegion {
|
|||||||
let root_fd = ensure_memory_root()?;
|
let root_fd = ensure_memory_root()?;
|
||||||
let mem_fd = root_fd.openat(&path, (O_CLOEXEC | mode) as i32, 0)?;
|
let mem_fd = root_fd.openat(&path, (O_CLOEXEC | mode) as i32, 0)?;
|
||||||
|
|
||||||
let ptr = unsafe {
|
let map = Map {
|
||||||
libredox::call::mmap(libredox::call::MmapArgs {
|
offset: phys_addr as usize,
|
||||||
fd: mem_fd.raw(),
|
size: aligned_size,
|
||||||
offset: phys_addr,
|
flags: mmap_prot | redox_syscall::MapFlags::from_bits_truncate(MAP_SHARED.bits()),
|
||||||
length: aligned_size,
|
address: 0,
|
||||||
flags: MAP_SHARED.bits() as u32,
|
};
|
||||||
prot: mmap_prot.bits() as u32,
|
|
||||||
addr: ptr::null_mut(),
|
let ptr = unsafe { redox_syscall::call::fmap(mem_fd.raw(), &map) }.map_err(|e| {
|
||||||
})
|
DriverError::MappingFailed {
|
||||||
}
|
phys: phys_addr,
|
||||||
.map_err(|e| DriverError::MappingFailed {
|
size,
|
||||||
phys: phys_addr,
|
reason: format!("{e:?}"),
|
||||||
size,
|
}
|
||||||
reason: format!("{e:?}"),
|
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
|||||||
@@ -585,7 +585,7 @@ impl std::io::Write for PciDevice {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enumerate_pci_class(class: u8) -> Result<Vec<PciDeviceInfo>> {
|
fn enumerate_pci_filtered(class: Option<u8>) -> Result<Vec<PciDeviceInfo>> {
|
||||||
let entries = std::fs::read_dir("/scheme/pci")?;
|
let entries = std::fs::read_dir("/scheme/pci")?;
|
||||||
let mut devices = Vec::new();
|
let mut devices = Vec::new();
|
||||||
|
|
||||||
@@ -609,8 +609,10 @@ pub fn enumerate_pci_class(class: u8) -> Result<Vec<PciDeviceInfo>> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let class_code = data[0x0b];
|
let class_code = data[0x0b];
|
||||||
if class_code != class {
|
if let Some(class) = class {
|
||||||
continue;
|
if class_code != class {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let vendor_id = u16::from_le_bytes([data[0x00], data[0x01]]);
|
let vendor_id = u16::from_le_bytes([data[0x00], data[0x01]]);
|
||||||
let device_id = u16::from_le_bytes([data[0x02], data[0x03]]);
|
let device_id = u16::from_le_bytes([data[0x02], data[0x03]]);
|
||||||
@@ -641,12 +643,23 @@ pub fn enumerate_pci_class(class: u8) -> Result<Vec<PciDeviceInfo>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
log::debug!(
|
log::debug!(
|
||||||
"PCI enumeration for class {class:#04x}: found {} devices",
|
"PCI enumeration{}: found {} devices",
|
||||||
|
class
|
||||||
|
.map(|class| format!(" for class {class:#04x}"))
|
||||||
|
.unwrap_or_default(),
|
||||||
devices.len()
|
devices.len()
|
||||||
);
|
);
|
||||||
Ok(devices)
|
Ok(devices)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn enumerate_pci_class(class: u8) -> Result<Vec<PciDeviceInfo>> {
|
||||||
|
enumerate_pci_filtered(Some(class))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enumerate_pci_all() -> Result<Vec<PciDeviceInfo>> {
|
||||||
|
enumerate_pci_filtered(None)
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_scheme_entry(name: &str) -> Option<PciLocation> {
|
fn parse_scheme_entry(name: &str) -> Option<PciLocation> {
|
||||||
let parts: Vec<&str> = name.splitn(3, "--").collect();
|
let parts: Vec<&str> = name.splitn(3, "--").collect();
|
||||||
if parts.len() != 3 {
|
if parts.len() != 3 {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
# Configuration file for the Rust/GCC cross-compilers, relibc and libtool
|
# Configuration file for the Rust/GCC cross-compilers, relibc and libtool
|
||||||
|
|
||||||
PREFIX=prefix/$(TARGET)
|
PREFIX=prefix/$(TARGET)
|
||||||
|
TOOLCHAIN_EXPORT_DIR?=$(ROOT)/build/toolchain-export/$(TARGET)
|
||||||
|
|
||||||
PREFIX_INSTALL=$(PREFIX)/sysroot/
|
PREFIX_INSTALL=$(PREFIX)/sysroot/
|
||||||
PREFIX_PATH=$(ROOT)/$(PREFIX_INSTALL)/bin
|
PREFIX_PATH=$(ROOT)/$(PREFIX_INSTALL)/bin
|
||||||
@@ -25,6 +26,13 @@ PREFIX_CONFIG=CI=1 COOKBOOK_CLEAN_BUILD=true COOKBOOK_CLEAN_TARGET=false COOKBOO
|
|||||||
|
|
||||||
prefix: $(PREFIX)/sysroot
|
prefix: $(PREFIX)/sysroot
|
||||||
|
|
||||||
|
export-toolchain: $(PREFIX)/sysroot FORCE
|
||||||
|
ifeq ($(PODMAN_BUILD),1)
|
||||||
|
$(PODMAN_RUN) make $@ TOOLCHAIN_EXPORT_DIR="$(TOOLCHAIN_EXPORT_DIR)"
|
||||||
|
else
|
||||||
|
"$(ROOT)/local/scripts/export-$(TARGET)-toolchain.sh" "$(TOOLCHAIN_EXPORT_DIR)"
|
||||||
|
endif
|
||||||
|
|
||||||
# Remove prefix builds and downloads
|
# Remove prefix builds and downloads
|
||||||
prefix_clean:
|
prefix_clean:
|
||||||
rm -rf $(PREFIX)
|
rm -rf $(PREFIX)
|
||||||
|
|||||||
+1
-1
@@ -23,7 +23,7 @@ ifeq ($(ARCH),i586)
|
|||||||
kvm?=yes
|
kvm?=yes
|
||||||
endif
|
endif
|
||||||
else ifeq ($(ARCH),x86_64)
|
else ifeq ($(ARCH),x86_64)
|
||||||
gpu?=vga
|
gpu?=virtio
|
||||||
uefi?=yes
|
uefi?=yes
|
||||||
VGA_SUPPORTED=yes
|
VGA_SUPPORTED=yes
|
||||||
QEMU_ARCH=x86_64
|
QEMU_ARCH=x86_64
|
||||||
|
|||||||
Reference in New Issue
Block a user