Update Red Bear driver substrate

Red Bear OS Team
This commit is contained in:
2026-04-16 12:43:10 +01:00
parent 6259dc06da
commit 6c418bb03b
23 changed files with 982 additions and 169 deletions
+537
View File
@@ -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();
+37
View File
@@ -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 {
+8
View File
@@ -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
View File
@@ -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