Update Red Bear driver substrate
Red Bear OS Team
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
#ifndef _LINUX_DEVICE_H
|
||||
#define _LINUX_DEVICE_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include "types.h"
|
||||
#include <stddef.h>
|
||||
|
||||
struct device_driver {
|
||||
@@ -27,11 +27,7 @@ static inline void dev_set_drvdata(struct device *dev, void *data)
|
||||
dev->driver_data = data;
|
||||
}
|
||||
|
||||
struct class {
|
||||
const char *name;
|
||||
};
|
||||
|
||||
extern struct device *devm_kzalloc(struct device *dev, size_t size, gfp_t flags);
|
||||
extern void *devm_kzalloc(struct device *dev, size_t size, gfp_t flags);
|
||||
extern void devm_kfree(struct device *dev, void *ptr);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef _LINUX_FIRMWARE_H
|
||||
#define _LINUX_FIRMWARE_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
struct firmware {
|
||||
@@ -23,4 +24,6 @@ extern int request_firmware_nowait(
|
||||
extern int request_firmware_direct(const struct firmware **fw,
|
||||
const char *name, struct device *dev);
|
||||
|
||||
#define FW_ACTION_HOTPLUG 0
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3,29 +3,16 @@
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
static inline int in_interrupt(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
extern void local_irq_save(unsigned long *flags);
|
||||
extern void local_irq_restore(unsigned long flags);
|
||||
extern void local_irq_disable(void);
|
||||
extern void local_irq_enable(void);
|
||||
extern int irqs_disabled(void);
|
||||
|
||||
static inline int in_irq(void)
|
||||
{
|
||||
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) {}
|
||||
static inline int in_interrupt(void) { return irqs_disabled(); }
|
||||
static inline int in_irq(void) { return irqs_disabled(); }
|
||||
|
||||
#define disable_irq_nosync(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_unlock(struct mutex *lock);
|
||||
extern int mutex_is_locked(struct mutex *lock);
|
||||
|
||||
static inline int mutex_trylock(struct mutex *lock)
|
||||
{
|
||||
(void)lock;
|
||||
return 1;
|
||||
}
|
||||
extern int mutex_trylock(struct mutex *lock);
|
||||
|
||||
#define DEFINE_MUTEX(name) struct mutex name = { .__opaque = {0} }
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ struct pci_device_id {
|
||||
|
||||
struct pci_dev {
|
||||
u16 vendor;
|
||||
u16 device;
|
||||
u16 device_id;
|
||||
u8 bus_number;
|
||||
u8 dev_number;
|
||||
u8 func_number;
|
||||
@@ -33,7 +33,7 @@ struct pci_dev {
|
||||
u64 resource_start[6];
|
||||
u64 resource_len[6];
|
||||
void *driver_data;
|
||||
struct device device;
|
||||
struct device device_obj;
|
||||
};
|
||||
|
||||
struct pci_driver {
|
||||
|
||||
@@ -11,39 +11,13 @@ struct timer_list {
|
||||
unsigned char __opaque[64];
|
||||
};
|
||||
|
||||
static inline void setup_timer(struct timer_list *timer,
|
||||
void (*function)(unsigned long),
|
||||
unsigned long data)
|
||||
{
|
||||
timer->function = function;
|
||||
timer->data = data;
|
||||
timer->expires = 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
extern void setup_timer(struct timer_list *timer,
|
||||
void (*function)(unsigned long),
|
||||
unsigned long data);
|
||||
extern int mod_timer(struct timer_list *timer, unsigned long expires);
|
||||
extern int del_timer(struct timer_list *timer);
|
||||
extern int del_timer_sync(struct timer_list *timer);
|
||||
extern int timer_pending(const struct timer_list *timer);
|
||||
|
||||
#define DEFINE_TIMER(_name, _function, _flags, _data) \
|
||||
struct timer_list _name = { .function = (_function), .data = (_data) }
|
||||
|
||||
@@ -2,13 +2,19 @@
|
||||
|
||||
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::dma;
|
||||
pub use rust_impl::drm_shim;
|
||||
pub use rust_impl::firmware;
|
||||
pub use rust_impl::io;
|
||||
pub use rust_impl::irq;
|
||||
pub use rust_impl::mac80211;
|
||||
pub use rust_impl::memory;
|
||||
pub use rust_impl::net;
|
||||
pub use rust_impl::pci;
|
||||
pub use rust_impl::sync;
|
||||
pub use rust_impl::wireless;
|
||||
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
|
||||
/// global `Mutex` (which needs `T: Send`). Raw pointers are not `Send` by
|
||||
/// default since the compiler can't prove thread-safety. Here each `(ptr,
|
||||
/// Layout)` pair is exclusively owned by the device that allocated it — only
|
||||
/// default since the compiler can't prove thread-safety. Here each tracked
|
||||
/// pointer is exclusively owned by the device that allocated it — only
|
||||
/// freed via `devm_kfree` or `devres_free_all` — so sending across threads is
|
||||
/// safe.
|
||||
struct TrackedAlloc(*mut u8, Layout);
|
||||
struct TrackedAlloc(*mut u8);
|
||||
unsafe impl Send for TrackedAlloc {}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
let layout = match tracked_layout(size, flags) {
|
||||
Some(layout) => layout,
|
||||
None => return ptr,
|
||||
};
|
||||
if tracked_layout(size, flags).is_none() {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
if let Ok(mut devres_map) = DEVRES_MAP.lock() {
|
||||
devres_map
|
||||
.entry(dev as usize)
|
||||
.or_default()
|
||||
.push(TrackedAlloc(ptr, layout));
|
||||
.push(TrackedAlloc(ptr));
|
||||
}
|
||||
|
||||
ptr
|
||||
|
||||
@@ -1,5 +1,87 @@
|
||||
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)]
|
||||
pub struct Firmware {
|
||||
pub size: usize,
|
||||
@@ -35,54 +117,68 @@ pub extern "C" fn request_firmware(fw: *mut *mut Firmware, name: *const u8, _dev
|
||||
return -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,
|
||||
Err(_) => return -22,
|
||||
}
|
||||
let name_str = match firmware_name(name) {
|
||||
Ok(name_str) => name_str,
|
||||
Err(err) => return err,
|
||||
};
|
||||
|
||||
let firmware_path = format!("/scheme/firmware/{}", name_str);
|
||||
log::info!(
|
||||
"request_firmware: loading '{}' via {}",
|
||||
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;
|
||||
match load_firmware_bytes(&name_str) {
|
||||
Ok(data) => install_firmware(fw, data),
|
||||
Err(err) => err,
|
||||
}
|
||||
unsafe { ptr::copy_nonoverlapping(data.as_ptr(), ptr, size) };
|
||||
}
|
||||
|
||||
let firmware = Box::new(Firmware {
|
||||
size,
|
||||
data: ptr as *const u8,
|
||||
#[no_mangle]
|
||||
pub extern "C" fn request_firmware_direct(
|
||||
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
|
||||
}
|
||||
|
||||
@@ -93,3 +189,89 @@ pub extern "C" fn release_firmware(fw: *mut Firmware) {
|
||||
}
|
||||
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);
|
||||
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!(
|
||||
"dma32_alloc: virt_to_phys failed for {:#x}",
|
||||
candidate as usize
|
||||
|
||||
@@ -2,6 +2,8 @@ pub mod device;
|
||||
pub mod dma;
|
||||
pub mod drm_shim;
|
||||
pub mod firmware;
|
||||
pub mod mac80211;
|
||||
pub mod net;
|
||||
pub mod idr;
|
||||
pub mod io;
|
||||
pub mod irq;
|
||||
@@ -10,4 +12,5 @@ pub mod pci;
|
||||
pub mod sync;
|
||||
pub mod timer;
|
||||
pub mod wait;
|
||||
pub mod wireless;
|
||||
pub mod workqueue;
|
||||
|
||||
@@ -2,9 +2,7 @@ use std::os::raw::c_ulong;
|
||||
use std::ptr;
|
||||
use std::sync::Mutex;
|
||||
|
||||
use redox_driver_sys::pci::{
|
||||
enumerate_pci_class, PciDevice, PciDeviceInfo, PciLocation, PCI_CLASS_DISPLAY,
|
||||
};
|
||||
use redox_driver_sys::pci::{enumerate_pci_all, PciDevice, PciDeviceInfo, PciLocation};
|
||||
|
||||
const EINVAL: i32 = 22;
|
||||
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,
|
||||
Err(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| {
|
||||
matching_id_entry(&candidate, driver.id_table).map(|id_ptr| (candidate, id_ptr))
|
||||
}) else {
|
||||
log::info!("pci_register_driver: no matching PCI display device found");
|
||||
log::info!("pci_register_driver: no matching PCI device found");
|
||||
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]
|
||||
pub extern "C" fn mutex_unlock(m: *mut LinuxMutex) {
|
||||
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);
|
||||
}
|
||||
|
||||
#[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]
|
||||
pub extern "C" fn irqs_disabled() -> bool {
|
||||
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);
|
||||
}
|
||||
|
||||
#[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::mem;
|
||||
use std::os::raw::c_int;
|
||||
use std::os::raw::{c_int, c_ulong};
|
||||
use std::ptr;
|
||||
use std::sync::atomic::{AtomicBool, AtomicPtr, AtomicU64, Ordering};
|
||||
use std::sync::{Arc, Mutex, OnceLock};
|
||||
@@ -117,8 +117,8 @@ fn join_all_handles(entry: &TimerEntry) {
|
||||
#[no_mangle]
|
||||
pub extern "C" fn setup_timer(
|
||||
timer: *mut TimerList,
|
||||
function: extern "C" fn(*mut u8),
|
||||
data: *mut u8,
|
||||
function: extern "C" fn(c_ulong),
|
||||
data: c_ulong,
|
||||
) {
|
||||
if timer.is_null() {
|
||||
return;
|
||||
@@ -131,13 +131,13 @@ pub extern "C" fn setup_timer(
|
||||
TimerList {
|
||||
expires: AtomicU64::new(0),
|
||||
function: AtomicPtr::new(function_ptr),
|
||||
data: AtomicPtr::new(data),
|
||||
data: AtomicPtr::new(data as usize as *mut u8),
|
||||
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]
|
||||
@@ -185,8 +185,8 @@ pub extern "C" fn mod_timer(timer: *mut TimerList, expires: u64) -> i32 {
|
||||
}
|
||||
|
||||
let function =
|
||||
unsafe { std::mem::transmute::<usize, extern "C" fn(*mut u8)>(function_addr) };
|
||||
function(data_addr as *mut u8);
|
||||
unsafe { std::mem::transmute::<usize, extern "C" fn(c_ulong)>(function_addr) };
|
||||
function(data_addr as c_ulong);
|
||||
|
||||
if entry_for_thread.generation.load(Ordering::Acquire) == generation {
|
||||
entry_for_thread.active.store(false, Ordering::Release);
|
||||
|
||||
Reference in New Issue
Block a user