Compare commits

..

1 Commits

Author SHA1 Message Date
alnyan 93a0584605 fuzzy: simple syscall fuzzing tool 2025-08-08 03:47:43 +03:00
433 changed files with 3444 additions and 79100 deletions
Generated
+1 -1
View File
@@ -499,7 +499,7 @@ dependencies = [
[[package]]
name = "discrete_range_map"
version = "0.6.2"
source = "git+https://git.alnyan.me/yggdrasil/discrete_range_map.git#0c932f7cc7ff55253519e3465ddeea8fe69083be"
source = "git+https://git.alnyan.me/yggdrasil/discrete_range_map.git#6b54882b190b02fb013f22cbe9664f6273e846ae"
dependencies = [
"btree_monstrousity",
"either",
-1
View File
@@ -7,7 +7,6 @@ exclude = [
"toolchain",
"userspace/dynload-program",
"userspace/lib/ygglibc",
"userspace",
"toolchain-c"
]
members = [
+1 -1
View File
@@ -5,7 +5,7 @@
"llvm-target": "aarch64-unknown-none",
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32",
"max-atomic-width": 128,
"target-pointer-width": 64,
"target-pointer-width": "64",
"features": "+v8a,+strict-align,-neon,-fp-armv8",
"disable-redzone": true,
Binary file not shown.
+1327 -514
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -6,7 +6,7 @@
"llvm-target": "riscv64",
"data-layout": "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128",
"max-atomic-width": 64,
"target-pointer-width": 64,
"target-pointer-width": "64",
"features": "+m,+a,+c",
"disable-redzone": true,
+1 -1
View File
@@ -7,7 +7,7 @@
"llvm-target": "x86_64-unknown-linux-gnu",
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
"max-atomic-width": 64,
"target-pointer-width": 64,
"target-pointer-width": "64",
"features": "-avx,-sse,-avx2,+soft-float",
"disable-redzone": true,
+1 -1
View File
@@ -1,7 +1,7 @@
[package]
name = "yggdrasil-kernel"
version = "0.1.0"
edition = "2024"
edition = "2021"
build = "build.rs"
authors = ["Mark Poliakov <mark@alnyan.me>"]
+1 -1
View File
@@ -1,7 +1,7 @@
[package]
name = "kernel-arch"
version = "0.1.0"
edition = "2024"
edition = "2021"
[target.'cfg(all(target_os = "none", target_arch = "x86_64"))'.dependencies]
kernel-arch-x86_64.path = "x86_64"
+1 -1
View File
@@ -1,7 +1,7 @@
[package]
name = "kernel-arch-aarch64"
version = "0.1.0"
edition = "2024"
edition = "2021"
[dependencies]
yggdrasil-abi.workspace = true
+16 -21
View File
@@ -66,7 +66,7 @@ impl FpContext {
///
/// It is up to the caller to ensure `this` is a valid pointer to store the FPU context in.
pub unsafe fn store(this: *mut Self) {
unsafe { __aarch64_fp_store_context(this as _) }
__aarch64_fp_store_context(this as _)
}
/// Loads the FPU with the context stored in `this` pointer.
@@ -75,7 +75,7 @@ impl FpContext {
///
/// It is up to the caller to ensure `this` is a valid pointer to load the FPU context from.
pub unsafe fn restore(this: *const Self) {
unsafe { __aarch64_fp_restore_context(this as _) }
__aarch64_fp_restore_context(this as _)
}
}
@@ -177,12 +177,7 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
stack.push(entry as _);
stack.push(arg);
setup_common_context(
&mut stack,
(__aarch64_task_enter_kernel as *const ()).addr(),
0,
0,
);
setup_common_context(&mut stack, __aarch64_task_enter_kernel as _, 0, 0);
let sp = stack.build();
@@ -217,7 +212,7 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
setup_common_context(
&mut stack,
(__aarch64_task_enter_user as *const ()).addr(),
__aarch64_task_enter_user as _,
ttbr0,
context.thread_pointer as _,
);
@@ -236,8 +231,9 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
}
unsafe fn enter(&self) -> ! {
unsafe { FpContext::restore(self.fp_context.get()) };
unsafe { __aarch64_enter_task(self.inner.get()) }
FpContext::restore(self.fp_context.get());
__aarch64_enter_task(self.inner.get())
}
unsafe fn switch(&self, from: &Self) {
@@ -245,20 +241,19 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
let src = from.inner.get();
if dst != src {
unsafe {
// Save the old context
FpContext::store(from.fp_context.get());
// Load next context
FpContext::restore(self.fp_context.get());
// Save the old context
FpContext::store(from.fp_context.get());
// Load next context
FpContext::restore(self.fp_context.get());
__aarch64_switch_task(self.inner.get(), from.inner.get())
}
__aarch64_switch_task(self.inner.get(), from.inner.get())
}
}
unsafe fn switch_and_drop(&self, thread: *const ()) {
unsafe { FpContext::restore(self.fp_context.get()) };
unsafe { __aarch64_switch_task_and_drop(self.inner.get(), thread) };
FpContext::restore(self.fp_context.get());
__aarch64_switch_task_and_drop(self.inner.get(), thread);
}
fn set_thread_pointer(&self, _tp: usize) {
@@ -298,7 +293,7 @@ fn setup_common_context(builder: &mut StackBuilder, entry: usize, ttbr0: u64, tp
builder.push(0); // x19
}
unsafe extern "C" {
extern "C" {
fn __aarch64_enter_task(to: *mut TaskContextInner) -> !;
fn __aarch64_switch_task(to: *mut TaskContextInner, from: *mut TaskContextInner);
fn __aarch64_switch_task_and_drop(to: *mut TaskContextInner, thread: *const ()) -> !;
+3 -3
View File
@@ -13,11 +13,11 @@ use aarch64_cpu::{
use alloc::{boxed::Box, sync::Arc, vec::Vec};
use device_api::interrupt::LocalInterruptController;
use kernel_arch_interface::{
Architecture,
cpu::{CpuData, CpuImpl, IpiQueue},
guard::IrqGuard,
task::Scheduler,
util::OneTimeInit,
Architecture,
};
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
@@ -25,7 +25,7 @@ pub mod context;
pub mod mem;
pub use context::TaskContextImpl;
pub use mem::{KernelTableManagerImpl, process::ProcessAddressSpaceImpl};
pub use mem::{process::ProcessAddressSpaceImpl, KernelTableManagerImpl};
pub struct ArchitectureImpl;
@@ -101,7 +101,7 @@ impl Architecture for ArchitectureImpl {
let id = (MPIDR_EL1.get() & 0xFF) as u32;
let cpu = Box::leak(Box::new(CpuImpl::<Self, S>::new(id, data)));
unsafe { cpu.set_local() };
cpu.set_local();
}
fn local_cpu() -> *mut () {
+17 -21
View File
@@ -1,7 +1,7 @@
use core::ops::Range;
use aarch64_cpu::registers::{TTBR0_EL1, TTBR1_EL1};
use kernel_arch_interface::{KERNEL_VIRT_OFFSET, mem::DeviceMemoryAttributes};
use kernel_arch_interface::{mem::DeviceMemoryAttributes, KERNEL_VIRT_OFFSET};
use libk_mm_interface::{
address::PhysicalAddress,
device::{DevicePageManager, DevicePageTableLevel},
@@ -10,7 +10,7 @@ use libk_mm_interface::{
use crate::mem::{
auto_lower_address,
table::{L1, L2, L3, PageAttributes, PageEntry, PageTable},
table::{PageAttributes, PageEntry, PageTable, L1, L2, L3},
tlb_flush_range_va,
};
@@ -98,26 +98,22 @@ impl DevicePageTableLevel for L3DeviceMemory {
}
pub unsafe fn setup() {
unsafe {
// 0..IDENTITY_SIZE_L1 -> lower RAM region
for i in 0..IDENTITY_SIZE_L1 {
let phys = PhysicalAddress::from_usize(i << L1::SHIFT);
KERNEL_L1[i] = PageEntry::normal_block(phys, PageAttributes::empty());
}
// DEVICE_L1 -> Device L2 table
// 0..DEVICE_MAPPING_L3_COUNT -> Device L3 tables -> Device L3 pages
// ..512 -> Device L2 pages
for i in 0..DEVICE_MAPPING_L3_COUNT {
let phys = PhysicalAddress::from_usize(auto_lower_address(
&raw const DEVICE_MEMORY.normal.0[i],
));
DEVICE_MEMORY.large.0[i] = PageEntry::table(phys, PageAttributes::empty());
}
let phys =
PhysicalAddress::from_usize(auto_lower_address(&raw const DEVICE_MEMORY.large.0));
KERNEL_L1[DEVICE_L1] = PageEntry::table(phys, PageAttributes::empty());
// 0..IDENTITY_SIZE_L1 -> lower RAM region
for i in 0..IDENTITY_SIZE_L1 {
let phys = PhysicalAddress::from_usize(i << L1::SHIFT);
KERNEL_L1[i] = PageEntry::normal_block(phys, PageAttributes::empty());
}
// DEVICE_L1 -> Device L2 table
// 0..DEVICE_MAPPING_L3_COUNT -> Device L3 tables -> Device L3 pages
// ..512 -> Device L2 pages
for i in 0..DEVICE_MAPPING_L3_COUNT {
let phys =
PhysicalAddress::from_usize(auto_lower_address(&raw const DEVICE_MEMORY.normal.0[i]));
DEVICE_MEMORY.large.0[i] = PageEntry::table(phys, PageAttributes::empty());
}
let phys = PhysicalAddress::from_usize(auto_lower_address(&raw const DEVICE_MEMORY.large.0));
KERNEL_L1[DEVICE_L1] = PageEntry::table(phys, PageAttributes::empty());
}
pub unsafe fn load() {
+12 -20
View File
@@ -4,9 +4,9 @@ use aarch64_cpu::{
registers::{MAIR_EL1, SCTLR_EL1, TCR_EL1},
};
use kernel_arch_interface::{
KERNEL_VIRT_OFFSET,
mem::{DeviceMemoryAttributes, KernelTableManager, RawDeviceMemoryMapping},
sync::IrqSafeSpinlock,
KERNEL_VIRT_OFFSET,
};
use libk_mm_interface::{address::PhysicalAddress, table::EntryLevel};
use tock_registers::interfaces::{ReadWriteable, Writeable};
@@ -14,7 +14,7 @@ use yggdrasil_abi::error::Error;
pub use intrinsics::*;
use crate::{ArchitectureImpl, mem::table::L1};
use crate::{mem::table::L1, ArchitectureImpl};
pub mod fixed;
pub mod intrinsics;
@@ -52,18 +52,14 @@ impl KernelTableManager for KernelTableManagerImpl {
attrs: DeviceMemoryAttributes,
) -> Result<RawDeviceMemoryMapping<Self>, Error> {
let _lock = KERNEL_MEMORY_LOCK.lock();
unsafe {
#[allow(static_mut_refs)]
fixed::DEVICE_MEMORY.map_device_pages(PhysicalAddress::from_u64(base), count, attrs)
}
#[allow(static_mut_refs)]
fixed::DEVICE_MEMORY.map_device_pages(PhysicalAddress::from_u64(base), count, attrs)
}
unsafe fn unmap_device_pages(mapping: &RawDeviceMemoryMapping<Self>) {
let _lock = KERNEL_MEMORY_LOCK.lock();
unsafe {
#[allow(static_mut_refs)]
fixed::DEVICE_MEMORY.unmap_device_pages(mapping);
}
#[allow(static_mut_refs)]
fixed::DEVICE_MEMORY.unmap_device_pages(mapping);
}
}
@@ -136,19 +132,15 @@ unsafe fn enable_mmu() {
SCTLR_EL1.modify(SCTLR_EL1::M::Enable);
// Enable caches
unsafe {
enable_icache();
enable_dcache();
}
enable_icache();
enable_dcache();
}
pub unsafe fn init_lower(bsp: bool) {
setup_memory_attributes();
unsafe {
if bsp {
fixed::setup();
}
fixed::load();
enable_mmu();
if bsp {
fixed::setup();
}
fixed::load();
enable_mmu();
}
+4 -6
View File
@@ -14,11 +14,11 @@ use libk_mm_interface::{
};
use yggdrasil_abi::error::Error;
use crate::{KernelTableManagerImpl, mem::table::PageEntry};
use crate::{mem::table::PageEntry, KernelTableManagerImpl};
use super::{
dc_cvac, ic_iallu,
table::{L1, L2, L3, PageAttributes, PageTable},
table::{PageAttributes, PageTable, L1, L2, L3},
tlb_flush_asid, tlb_flush_vaae1,
};
@@ -97,10 +97,8 @@ impl<TA: TableAllocator> ProcessAddressSpaceManager<TA> for ProcessAddressSpaceI
}
unsafe fn clear(&mut self) {
unsafe {
self.l1
.drop_range::<TA>(0..((Self::UPPER_LIMIT_PFN * L3::SIZE).page_index::<L1>()))
};
self.l1
.drop_range::<TA>(0..((Self::UPPER_LIMIT_PFN * L3::SIZE).page_index::<L1>()));
}
}
+7 -11
View File
@@ -103,8 +103,8 @@ impl<L: EntryLevel> PageTable<L> {
}
}
pub fn new_zeroed<'a, TA: TableAllocator>()
-> Result<PhysicalRefMut<'a, Self, KernelTableManagerImpl>, Error> {
pub fn new_zeroed<'a, TA: TableAllocator>(
) -> Result<PhysicalRefMut<'a, Self, KernelTableManagerImpl>, Error> {
let physical = TA::allocate_page_table()?;
let mut table =
unsafe { PhysicalRefMut::<'a, Self, KernelTableManagerImpl>::map(physical) };
@@ -132,7 +132,7 @@ impl<L: EntryLevel> PageTable<L> {
return None;
}
let inner = unsafe { PhysicalRefMut::map(physical) };
let inner = PhysicalRefMut::map(physical);
Some(inner)
}
}
@@ -234,16 +234,12 @@ where
let entry = self[index];
if let Some(table) = entry.as_table() {
unsafe {
let mut table_ref: PhysicalRefMut<
PageTable<L::NextLevel>,
KernelTableManagerImpl,
> = PhysicalRefMut::map(table);
let mut table_ref: PhysicalRefMut<PageTable<L::NextLevel>, KernelTableManagerImpl> =
PhysicalRefMut::map(table);
table_ref.drop_all::<TA>();
table_ref.drop_all::<TA>();
TA::free_page_table(table);
}
TA::free_page_table(table);
} else if entry.is_present() {
// Memory must've been cleared beforehand, so no non-table entries must be present
panic!(
+1 -1
View File
@@ -7,12 +7,12 @@ use std::{
use device_api::dma::{DmaAllocation, DmaAllocator};
use kernel_arch_interface::{
Architecture,
cpu::{CpuData, IpiQueue},
mem::{
DeviceMemoryAttributes, KernelTableManager, PhysicalMemoryAllocator, RawDeviceMemoryMapping,
},
task::{Scheduler, TaskContext, UserContextInfo},
Architecture,
};
use libk_mm_interface::{
address::PhysicalAddress,
+1 -1
View File
@@ -7,7 +7,7 @@ use alloc::vec::Vec;
use device_api::interrupt::IpiMessage;
use crate::{
Architecture, guard::IrqGuard, sync::IrqSafeSpinlock, task::Scheduler, util::OneTimeInit,
guard::IrqGuard, sync::IrqSafeSpinlock, task::Scheduler, util::OneTimeInit, Architecture,
};
#[repr(C, align(0x10))]
+1 -1
View File
@@ -6,7 +6,7 @@ use core::{
sync::atomic::{AtomicBool, Ordering},
};
use crate::{Architecture, guard::IrqGuard};
use crate::{guard::IrqGuard, Architecture};
pub struct Spinlock<A: Architecture, T> {
value: UnsafeCell<T>,
+4 -4
View File
@@ -1,9 +1,9 @@
use core::{arch::global_asm, cell::UnsafeCell, marker::PhantomData};
use kernel_arch_interface::{
Architecture,
mem::{KernelTableManager, PhysicalMemoryAllocator},
task::{StackBuilder, TaskContext, UserContextInfo},
Architecture,
};
use libk_mm_interface::address::PhysicalAddress;
use tock_registers::{
@@ -13,9 +13,9 @@ use tock_registers::{
use yggdrasil_abi::error::Error;
use crate::{
ArchitectureImpl, PerCpuData,
mem::{self},
registers::SATP,
ArchitectureImpl, PerCpuData,
};
pub const CONTEXT_SIZE: usize = 14 * size_of::<usize>();
@@ -86,7 +86,7 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
stack.push(context.entry);
stack.push(context.argument);
setup_common_context(&mut stack, (__rv64_task_enter_user as *const ()).addr());
setup_common_context(&mut stack, __rv64_task_enter_user as _);
let sp = stack.build();
let satp = InMemoryRegister::new(0);
@@ -118,7 +118,7 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
stack.push(entry as _);
stack.push(arg);
setup_common_context(&mut stack, (__rv64_task_enter_kernel as *const ()).addr());
setup_common_context(&mut stack, __rv64_task_enter_kernel as _);
let sp = stack.build();
+2 -2
View File
@@ -11,18 +11,18 @@ use core::{
use alloc::{boxed::Box, collections::btree_map::BTreeMap, vec::Vec};
use device_api::interrupt::LocalInterruptController;
use kernel_arch_interface::{
Architecture,
cpu::{CpuData, CpuImpl, IpiQueue},
sync::IrqSafeSpinlock,
task::Scheduler,
util::OneTimeInit,
Architecture,
};
use tock_registers::interfaces::{ReadWriteable, Readable};
use registers::SSTATUS;
pub mod mem;
pub use mem::{KernelTableManagerImpl, process::ProcessAddressSpaceImpl};
pub use mem::{process::ProcessAddressSpaceImpl, KernelTableManagerImpl};
pub mod context;
pub use context::TaskContextImpl;
pub mod intrinsics;
+4 -3
View File
@@ -2,11 +2,12 @@ use kernel_arch_interface::sync::IrqSafeSpinlock;
use libk_mm_interface::{address::PhysicalAddress, table::EntryLevel};
use crate::{
ArchitectureImpl,
mem::{
KERNEL_VIRT_OFFSET, auto_lower_address,
table::{L1, PageEntry, PageTable},
auto_lower_address,
table::{PageEntry, PageTable, L1},
KERNEL_VIRT_OFFSET,
},
ArchitectureImpl,
};
pub const IDENTITY_SIZE_L1: usize = 64;
+2 -2
View File
@@ -3,13 +3,13 @@ use kernel_arch_interface::mem::{
};
use libk_mm_interface::{
address::PhysicalAddress,
table::{EntryLevel, EntryLevelExt, page_index},
table::{page_index, EntryLevel, EntryLevelExt},
};
use tock_registers::interfaces::Writeable;
use yggdrasil_abi::error::Error;
use crate::{
mem::table::{L1, L3, PageTable},
mem::table::{PageTable, L1, L3},
registers::SATP,
};
+1 -1
View File
@@ -19,8 +19,8 @@ use crate::mem::{
};
use super::{
table::{DroppableRange, PageTable, L1, L2, L3},
KernelTableManagerImpl, USER_BOUNDARY,
table::{DroppableRange, L1, L2, L3, PageTable},
};
pub struct ProcessAddressSpaceImpl<TA: TableAllocator> {
+4 -4
View File
@@ -10,8 +10,8 @@ use libk_mm_interface::{
pointer::{PhysicalRef, PhysicalRefMut},
process::PageAttributeUpdate,
table::{
EntryLevel, EntryLevelDrop, NextPageTable, NonTerminalEntryLevel, TableAllocator,
page_index,
page_index, EntryLevel, EntryLevelDrop, NextPageTable, NonTerminalEntryLevel,
TableAllocator,
},
};
use yggdrasil_abi::error::Error;
@@ -109,8 +109,8 @@ impl<L: EntryLevel> PageTable<L> {
}
}
pub fn new_zeroed<'a, TA: TableAllocator>()
-> Result<PhysicalRefMut<'a, PageTable<L>, KernelTableManagerImpl>, Error> {
pub fn new_zeroed<'a, TA: TableAllocator>(
) -> Result<PhysicalRefMut<'a, PageTable<L>, KernelTableManagerImpl>, Error> {
let physical = TA::allocate_page_table()?;
let mut table =
unsafe { PhysicalRefMut::<'a, Self, KernelTableManagerImpl>::map(physical) };
+5 -9
View File
@@ -4,8 +4,6 @@ const EXT_HSM: u64 = 0x48534D;
const EXT_TIME: u64 = 0x54494D45;
const EXT_DBCN: u64 = 0x4442434E;
const EXT_SPI: u64 = 0x735049;
const EXT_SYSTEM_SHUTDOWN: u64 = 0x53525354;
const EXT_SYSTEM_SHUTDOWN_LEGACY: u64 = 0x08;
primitive_enum! {
pub enum Status: i64 {
@@ -78,7 +76,11 @@ unsafe fn sbi_do_call(
);
}
let a0 = a0 as i64;
if a0 == 0 { Ok(a1) } else { Err(a0.into()) }
if a0 == 0 {
Ok(a1)
} else {
Err(a0.into())
}
}
pub fn sbi_hart_start(hart_id: u64, start_addr: u64, opaque: u64) -> Result<(), Error> {
@@ -106,9 +108,3 @@ pub fn sbi_debug_console_write_byte(byte: u8) {
pub fn sbi_set_timer(next_event: u64) {
unsafe { sbi_do_call(EXT_TIME, 0x00, next_event, 0, 0, 0, 0, 0) }.ok();
}
pub fn sbi_system_shutdown() -> ! {
unsafe { sbi_do_call(EXT_SYSTEM_SHUTDOWN, 0x00, 0, 0, 0, 0, 0, 0) }.ok();
unsafe { sbi_do_call(EXT_SYSTEM_SHUTDOWN_LEGACY, 0x00, 0, 0, 0, 0, 0, 0) }.ok();
unreachable!()
}
+1 -1
View File
@@ -35,7 +35,7 @@ cfg_if! {
pub use imp::{ArchitectureImpl, KernelTableManagerImpl, ProcessAddressSpaceImpl, TaskContextImpl};
pub use kernel_arch_interface::{Architecture, KERNEL_VIRT_OFFSET, guard, mem, sync, task, util};
pub use kernel_arch_interface::{guard, mem, sync, task, util, Architecture, KERNEL_VIRT_OFFSET};
pub type CpuImpl<S> = kernel_arch_interface::cpu::CpuImpl<ArchitectureImpl, S>;
pub type LocalCpuImpl<'a, S> = kernel_arch_interface::cpu::LocalCpuImpl<'a, ArchitectureImpl, S>;
+1 -1
View File
@@ -1,4 +1,4 @@
#![feature(box_as_ptr)]
#![feature(iter_chain, new_zeroed_alloc, box_as_ptr)]
#![allow(clippy::new_without_default)]
#![no_std]
+4 -4
View File
@@ -4,14 +4,14 @@ use kernel_arch_interface::{
mem::{KernelTableManager, PhysicalMemoryAllocator},
task::{ForkFrame, StackBuilder, TaskContext, TaskFrame, UserContextInfo},
};
use kernel_arch_x86::registers::{CR3, FpuContext, MSR_IA32_FS_BASE};
use kernel_arch_x86::registers::{FpuContext, CR3, MSR_IA32_FS_BASE};
use libk_mm_interface::address::PhysicalAddress;
use tock_registers::interfaces::Writeable;
use yggdrasil_abi::{arch::SavedFrame, error::Error};
use crate::{
ArchitectureImpl,
mem::{auto_lower_address, fixed},
ArchitectureImpl,
};
/// Frame saved onto the stack when taking an IRQ
@@ -445,7 +445,7 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
stack.push(entry as _);
stack.push(arg);
setup_common_context(&mut stack, (__x86_64_task_enter_kernel as *const ()).addr());
setup_common_context(&mut stack, __x86_64_task_enter_kernel as _);
let sp = stack.build();
@@ -483,7 +483,7 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
stack.push(context.argument);
stack.push(context.stack_pointer);
setup_common_context(&mut stack, (__x86_64_task_enter_user as *const ()).addr());
setup_common_context(&mut stack, __x86_64_task_enter_user as _);
let sp = stack.build();
let rsp0 = stack_base + USER_TASK_PAGES * 0x1000;
+2 -2
View File
@@ -11,10 +11,10 @@ use core::{
use alloc::{sync::Arc, vec::Vec};
use device_api::interrupt::{LocalInterruptController, MessageInterruptController};
use kernel_arch_interface::{
Architecture,
cpu::{CpuData, CpuImpl, IpiQueue},
task::Scheduler,
util::OneTimeInit,
Architecture,
};
use kernel_arch_x86::{cpuid::CpuFeatures, registers::MSR_IA32_KERNEL_GS_BASE};
use libk_mm_interface::address::PhysicalAddress;
@@ -24,7 +24,7 @@ pub mod context;
pub mod mem;
pub use context::TaskContextImpl;
pub use mem::{KernelTableManagerImpl, process::ProcessAddressSpaceImpl};
pub use mem::{process::ProcessAddressSpaceImpl, KernelTableManagerImpl};
pub struct ArchitectureImpl;
+4 -4
View File
@@ -1,19 +1,19 @@
use core::ops::Range;
use kernel_arch_interface::{Architecture, mem::DeviceMemoryAttributes, sync::IrqSafeSpinlock};
use kernel_arch_interface::{mem::DeviceMemoryAttributes, sync::IrqSafeSpinlock, Architecture};
use kernel_arch_x86::registers::CR3;
use libk_mm_interface::{
address::PhysicalAddress,
device::{DevicePageManager, DevicePageTableLevel},
table::{EntryLevel, page_index},
table::{page_index, EntryLevel},
};
use crate::{
ArchitectureImpl, KERNEL_VIRT_OFFSET,
mem::{
auto_lower_address,
table::{L0, L1, L2, L3, PageAttributes, PageEntry, PageTable},
table::{PageAttributes, PageEntry, PageTable, L0, L1, L2, L3},
},
ArchitectureImpl, KERNEL_VIRT_OFFSET,
};
pub const IDENTITY_SIZE_L1: usize = 64;
+1 -1
View File
@@ -6,7 +6,7 @@ use yggdrasil_abi::error::Error;
use crate::KERNEL_VIRT_OFFSET;
use self::table::{L0, L1, PageTable};
use self::table::{PageTable, L0, L1};
pub mod fixed;
pub mod process;
+1 -1
View File
@@ -15,7 +15,7 @@ use crate::KernelTableManagerImpl;
use super::{
clone_kernel_tables, flush_tlb_entry,
table::{L0, L1, L2, L3, PageEntry, PageTable},
table::{PageEntry, PageTable, L0, L1, L2, L3},
};
/// Represents a process or kernel address space. Because x86-64 does not have cool stuff like
+2 -2
View File
@@ -224,8 +224,8 @@ impl<L: EntryLevel> PageTable<L> {
}
/// Allocates a new page table, filling it with non-preset entries
pub fn new_zeroed<'a, TA: TableAllocator>()
-> Result<PhysicalRefMut<'a, Self, KernelTableManagerImpl>, Error> {
pub fn new_zeroed<'a, TA: TableAllocator>(
) -> Result<PhysicalRefMut<'a, Self, KernelTableManagerImpl>, Error> {
let physical = TA::allocate_page_table()?;
let mut table =
unsafe { PhysicalRefMut::<'a, Self, KernelTableManagerImpl>::map(physical) };
+2 -2
View File
@@ -6,9 +6,9 @@ use std::{
};
use abi_generator::{
TargetEnv,
abi::{AbiBuilder, ty::TypeWidth},
abi::{ty::TypeWidth, AbiBuilder},
syntax::UnwrapFancy,
TargetEnv,
};
fn build_x86_64() {
+2 -2
View File
@@ -7,7 +7,7 @@ use device_api::{
device::Device,
interrupt::{InterruptHandler, Irq, IrqVector},
};
use kernel_arch_x86::{ISA_IRQ_OFFSET, intrinsics};
use kernel_arch_x86::{intrinsics, ISA_IRQ_OFFSET};
use libk::device::external_interrupt_controller;
use libk_mm::{
address::{PhysicalAddress, Virtualize},
@@ -15,8 +15,8 @@ use libk_mm::{
};
use crate::{
ACPI_SYSTEM,
mem::{read_memory, write_memory},
ACPI_SYSTEM,
};
#[derive(Clone, Copy)]
+9 -14
View File
@@ -1,11 +1,11 @@
#![feature(allocator_api, never_type)]
#![feature(allocator_api)]
#![no_std]
use acpi::AcpiTables;
use acpi_system::{AcpiInterruptMethod, AcpiSleepState, AcpiSystem};
use acpi_system::{AcpiInterruptMethod, AcpiSystem};
use alloc::boxed::Box;
use libk::error::Error;
use libk_util::{OneTimeInit, sync::IrqSafeSpinlock};
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
extern crate alloc;
@@ -45,17 +45,6 @@ pub fn get_pci_route(
.ok()
}
pub fn power_off() -> Result<!, Error> {
let system = ACPI_SYSTEM.get();
unsafe {
system.lock().enter_sleep_state(AcpiSleepState::S5).ok();
loop {
core::arch::asm!("cli; hlt");
}
}
}
/// Initializes ACPI management
pub fn switch_to_acpi(tables: &'static AcpiTables<AcpiHandlerImpl>) -> Result<(), Error> {
// NOTE mostly broken for real HW
@@ -78,6 +67,12 @@ pub fn switch_to_acpi(tables: &'static AcpiTables<AcpiHandlerImpl>) -> Result<()
// // 6. Do something with the devices
// // 7. Actually enter the S5 state
// unsafe {
// PLATFORM
// .send_ipi(IpiDeliveryTarget::OtherCpus, IpiMessage::Shutdown)
// .unwrap();
// }
// SHUTDOWN_FENCE.signal();
// SHUTDOWN_FENCE.wait_all(CPU_COUNT.load(Ordering::Acquire));
+2 -2
View File
@@ -1,10 +1,10 @@
use core::mem::{MaybeUninit, size_of};
use core::mem::{size_of, MaybeUninit};
use device_api::dma::DmaAllocator;
use libk::dma::{BusAddress, DmaBuffer, DmaSliceMut};
use tock_registers::register_structs;
use crate::{MAX_PRD_SIZE, data::AtaString, error::AhciError};
use crate::{data::AtaString, error::AhciError, MAX_PRD_SIZE};
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[repr(u8)]
+3 -3
View File
@@ -7,9 +7,9 @@ use libk_util::{ConstAssert, IsTrue};
use static_assertions::const_assert_eq;
use crate::{
MAX_PRD_SIZE,
command::{AtaCommand, AtaIdentify, AtaIdentifyResponse},
error::AhciError,
MAX_PRD_SIZE,
};
pub const COMMAND_LIST_LENGTH: usize = 32;
@@ -20,7 +20,7 @@ const AHCI_FIS_REG_H2D: u8 = 0x27;
#[repr(C)]
pub struct AtaString<const N: usize>
where
ConstAssert<{ N.is_multiple_of(2) }>: IsTrue,
ConstAssert<{ N % 2 == 0 }>: IsTrue,
{
data: [u8; N],
}
@@ -243,7 +243,7 @@ impl AtaIdentifyResponse {
impl<const N: usize> AtaString<N>
where
ConstAssert<{ N.is_multiple_of(2) }>: IsTrue,
ConstAssert<{ N % 2 == 0 }>: IsTrue,
{
#[allow(clippy::inherent_to_string)]
pub fn to_string(&self) -> String {
+3 -3
View File
@@ -15,18 +15,18 @@ use device_api::{
use error::AhciError;
use libk::{device::manager::probe_partitions, dma::DmaBuffer, fs::devfs, task::runtime};
use libk_mm::device::DeviceMemoryIo;
use libk_util::{OneTimeInit, sync::IrqSafeSpinlock};
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
use port::AhciPort;
use regs::{PortRegs, Regs};
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
use ygg_driver_pci::{
PciCommandRegister, PciConfigurationSpace,
device::{PciDeviceInfo, PreferredInterruptMode},
macros::pci_driver,
PciCommandRegister, PciConfigurationSpace,
};
use yggdrasil_abi::{error::Error, io::FileMode};
use crate::regs::{CAP, GHC, SSTS, Version};
use crate::regs::{Version, CAP, GHC, SSTS};
mod command;
mod data;
+8 -8
View File
@@ -16,18 +16,18 @@ use libk::{
error::Error,
};
use libk_mm::{
OnDemandPage, PageProvider, VirtualPage, address::PhysicalAddress, device::DeviceMemoryIo,
table::MapAttributes,
address::PhysicalAddress, device::DeviceMemoryIo, table::MapAttributes, OnDemandPage,
PageProvider, VirtualPage,
};
use libk_util::{OneTimeInit, sync::IrqSafeSpinlock, waker::QueueWaker};
use libk_util::{sync::IrqSafeSpinlock, waker::QueueWaker, OneTimeInit};
use tock_registers::interfaces::{Readable, Writeable};
use crate::{
AhciController, MAX_COMMANDS, MAX_PRD_SIZE, SECTOR_SIZE,
command::{AtaCommand, AtaIdentify, AtaReadDmaEx},
data::{COMMAND_LIST_LENGTH, CommandListEntry, CommandTable, ReceivedFis},
data::{CommandListEntry, CommandTable, ReceivedFis, COMMAND_LIST_LENGTH},
error::AhciError,
regs::{CMD_PENDING, CMD_READY, IE, PortRegs, TFD},
regs::{PortRegs, CMD_PENDING, CMD_READY, IE, TFD},
AhciController, MAX_COMMANDS, MAX_PRD_SIZE, SECTOR_SIZE,
};
#[derive(Clone, Copy, PartialEq, Debug)]
@@ -319,11 +319,11 @@ impl BlockDevice for AhciPort {
position: u64,
buffer: DmaSliceMut<'_, MaybeUninit<u8>>,
) -> Result<(), Error> {
if !buffer.len().is_multiple_of(SECTOR_SIZE) {
if buffer.len() % SECTOR_SIZE != 0 {
log::warn!("ahci: misaligned buffer size: {}", buffer.len());
return Err(Error::InvalidOperation);
}
if !position.is_multiple_of(SECTOR_SIZE as u64) {
if position % SECTOR_SIZE as u64 != 0 {
log::warn!("ahci: misaligned read");
return Err(Error::InvalidOperation);
}
+1 -1
View File
@@ -1,7 +1,7 @@
[package]
name = "ygg_driver_nvme"
version = "0.1.0"
edition = "2024"
edition = "2021"
authors = ["Mark Poliakov <mark@alnyan.me>"]
[dependencies]
+1 -1
View File
@@ -3,7 +3,7 @@
use core::fmt::{self, Write};
use libk::dma::BusAddress;
use tock_registers::{UIntLike, interfaces::Readable, register_structs, registers::ReadOnly};
use tock_registers::{interfaces::Readable, register_structs, registers::ReadOnly, UIntLike};
use crate::queue::PhysicalRegionPage;
+7 -7
View File
@@ -9,14 +9,14 @@ use libk::{
error::Error,
};
use libk_mm::{
OnDemandPage, PageProvider, PageSlice, VirtualPage,
address::{AsPhysicalAddress, PhysicalAddress},
table::MapAttributes,
OnDemandPage, PageProvider, PageSlice, VirtualPage,
};
use crate::{IoDirection, command::IdentifyNamespaceRequest, register_nvme_namespace};
use crate::{command::IdentifyNamespaceRequest, register_nvme_namespace, IoDirection};
use super::{NvmeController, error::NvmeError};
use super::{error::NvmeError, NvmeController};
#[allow(unused)]
pub struct NvmeNamespace {
@@ -92,10 +92,10 @@ impl BlockDevice for NvmeNamespace {
position: u64,
buffer: DmaSliceMut<'_, MaybeUninit<u8>>,
) -> Result<(), Error> {
if !position.is_multiple_of(self.block_size() as u64) {
if position % self.block_size() as u64 != 0 {
return Err(Error::InvalidOperation);
}
if !buffer.len().is_multiple_of(self.block_size()) || buffer.is_empty() {
if buffer.len() % self.block_size() != 0 || buffer.is_empty() {
return Err(Error::InvalidOperation);
}
let lba = position / self.block_size() as u64;
@@ -115,10 +115,10 @@ impl BlockDevice for NvmeNamespace {
}
async fn write_aligned(&self, position: u64, buffer: DmaSlice<'_, u8>) -> Result<(), Error> {
if !position.is_multiple_of(self.block_size() as u64) {
if position % self.block_size() as u64 != 0 {
return Err(Error::InvalidOperation);
}
if !buffer.len().is_multiple_of(self.block_size()) || buffer.is_empty() {
if buffer.len() % self.block_size() != 0 || buffer.is_empty() {
return Err(Error::InvalidOperation);
}
let lba = position / self.block_size() as u64;
+7 -7
View File
@@ -1,4 +1,4 @@
#![feature(const_trait_impl, if_let_guard)]
#![feature(const_trait_impl, let_chains, if_let_guard, maybe_uninit_slice)]
#![allow(missing_docs)]
#![no_std]
// TODO
@@ -7,7 +7,7 @@
extern crate alloc;
use core::{
mem::{MaybeUninit, size_of},
mem::{size_of, MaybeUninit},
sync::atomic::{AtomicUsize, Ordering},
time::Duration,
};
@@ -27,10 +27,10 @@ use libk::{
fs::devfs,
task::{cpu_count, cpu_index, runtime},
};
use libk_mm::{L3_PAGE_SIZE, address::PhysicalAddress, device::DeviceMemoryIo};
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo, L3_PAGE_SIZE};
use libk_util::{
OneTimeInit,
sync::{IrqGuard, IrqSafeSpinlock},
OneTimeInit,
};
use queue::PrpList;
use regs::{CAP, CC};
@@ -40,9 +40,9 @@ use tock_registers::{
registers::{ReadOnly, ReadWrite, WriteOnly},
};
use ygg_driver_pci::{
PciCommandRegister, PciConfigurationSpace,
device::{PciDeviceInfo, PreferredInterruptMode},
macros::pci_driver,
PciCommandRegister, PciConfigurationSpace,
};
use yggdrasil_abi::{error::Error, io::FileMode};
@@ -284,8 +284,8 @@ impl NvmeController {
unsafe fn doorbell_pair(&self, idx: usize) -> (*mut u32, *mut u32) {
let regs = self.regs.lock();
let sq_ptr = unsafe { regs.doorbell_ptr(self.doorbell_shift, false, idx) };
let cq_ptr = unsafe { regs.doorbell_ptr(self.doorbell_shift, true, idx) };
let sq_ptr = regs.doorbell_ptr(self.doorbell_shift, false, idx);
let cq_ptr = regs.doorbell_ptr(self.doorbell_shift, true, idx);
(sq_ptr, cq_ptr)
}
}
+1 -1
View File
@@ -112,7 +112,7 @@ impl PrpList {
size: usize,
) -> Result<Self, NvmeError> {
// TODO hardcoded page size
if !base.into_u64().is_multiple_of(0x1000) {
if base.into_u64() % 0x1000 != 0 {
todo!();
}
+12 -13
View File
@@ -1,4 +1,4 @@
#![feature(generic_const_exprs)]
#![feature(generic_const_exprs, maybe_uninit_slice)]
#![allow(incomplete_features)]
#![no_std]
@@ -23,11 +23,11 @@ use libk::{
task::{runtime, sync::AsyncMutex},
};
use libk_mm::{
OnDemandPage, PageProvider, VirtualPage, address::PhysicalAddress, table::MapAttributes,
address::PhysicalAddress, table::MapAttributes, OnDemandPage, PageProvider, VirtualPage,
};
use libk_util::{
sync::{spin_rwlock::IrqSafeRwLock, IrqSafeSpinlock},
OneTimeInit,
sync::{IrqSafeSpinlock, spin_rwlock::IrqSafeRwLock},
};
use transport::{ScsiTransport, ScsiTransportWrapper};
use yggdrasil_abi::io::FileMode;
@@ -40,7 +40,7 @@ pub mod transport;
pub struct ScsiEnclosure {
transport: AsyncMutex<ScsiTransportWrapper>,
units: Vec<AsyncMutex<Option<Arc<ScsiUnit>>>>,
units: Vec<IrqSafeRwLock<Option<Arc<ScsiUnit>>>>,
index: OneTimeInit<u32>,
shutdown: AtomicBool,
}
@@ -60,7 +60,7 @@ impl ScsiEnclosure {
lun_count: usize,
) -> Result<Arc<Self>, Error> {
let transport = AsyncMutex::new(ScsiTransportWrapper::new(transport));
let units = (0..lun_count).map(|_| AsyncMutex::new(None)).collect();
let units = (0..lun_count).map(|_| IrqSafeRwLock::new(None)).collect();
let this = Arc::new(Self {
transport,
units,
@@ -74,7 +74,7 @@ impl ScsiEnclosure {
if this.probe_lun(i as u8).await
&& let Ok(unit) = ScsiUnit::setup(this.clone(), i as u8).await
{
*this.units[i].lock().await = Some(unit);
*this.units[i].write() = Some(unit);
}
}
@@ -123,7 +123,7 @@ impl ScsiEnclosure {
async fn poll(self: &Arc<Self>) {
let index = *self.index.get();
for lun in 0..self.units.len() {
let mut slot = self.units[lun].lock().await;
let mut slot = self.units[lun].write();
let present = self.probe_lun(lun as u8).await;
if let Some(unit) = slot.as_ref() {
@@ -143,12 +143,12 @@ impl ScsiEnclosure {
}
}
pub async fn detach(&self) {
pub fn detach(&self) {
self.shutdown.store(true, Ordering::Release);
let index = self.index.try_get().copied();
for unit in self.units.iter() {
if let Some(unit) = unit.lock().await.take() {
if let Some(unit) = unit.write().take() {
unit.detach();
}
}
@@ -214,11 +214,11 @@ impl BlockDevice for ScsiUnit {
position: u64,
buffer: DmaSliceMut<'_, MaybeUninit<u8>>,
) -> Result<(), Error> {
if !position.is_multiple_of(self.lba_size as u64) {
if position % self.lba_size as u64 != 0 {
log::warn!("scsi: misaligned read");
return Err(Error::InvalidArgument);
}
if !buffer.len().is_multiple_of(self.lba_size) {
if buffer.len() % self.lba_size != 0 {
log::warn!("scsi: misaligned buffer size");
return Err(Error::InvalidArgument);
}
@@ -368,11 +368,10 @@ fn register_unit(enclosure_index: u32, lun: u8, unit: Arc<ScsiUnit>) {
}
fn remove_enclosure(index: u32) {
log::info!("scsi: enclosure {index} detached");
let mut devices = SCSI_ENCLOSURES.lock();
let mut bitmap = SCSI_BITMAP.lock();
*bitmap &= !(1 << index);
devices.remove(&index);
log::info!("scsi: enclosure {index} detached");
}
-1
View File
@@ -4,5 +4,4 @@
extern crate alloc;
mod pl011;
mod pl031;
mod pl061;
+9 -7
View File
@@ -1,16 +1,16 @@
use alloc::sync::Arc;
use device_api::{
device::{Device, DeviceInitContext},
interrupt::{InterruptHandler, IrqHandle, IrqVector},
interrupt::{FullIrq, InterruptHandler, IrqVector},
};
use device_tree::driver::{Node, ProbeContext, device_tree_driver};
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
use libk::{
debug::DebugSink,
device::manager::DEVICE_REGISTRY,
device::{external_interrupt_controller, manager::DEVICE_REGISTRY},
vfs::{Terminal, TerminalInput, TerminalOutput},
};
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo};
use libk_util::{OneTimeInit, sync::IrqSafeSpinlock};
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
use tock_registers::{
interfaces::{ReadWriteable, Readable, Writeable},
register_bitfields, register_structs,
@@ -68,7 +68,7 @@ struct Pl011Inner {
pub struct Pl011 {
inner: OneTimeInit<Arc<Terminal<Pl011Inner>>>,
base: PhysicalAddress,
irq: IrqHandle,
irq: FullIrq,
}
impl Io {
@@ -164,12 +164,14 @@ impl Device for Pl011 {
}
unsafe fn init_irq(self: Arc<Self>) -> Result<(), Error> {
self.irq.register(self.clone())?;
let intc = external_interrupt_controller()?;
intc.register_irq(self.irq.irq, self.irq.options, self.clone())?;
{
let io = self.inner.get().output().io.lock();
io.regs.IMSC.modify(IMSC::RXIM::SET);
}
self.irq.enable()?;
intc.enable_irq(self.irq.irq)?;
Ok(())
}
-66
View File
@@ -1,66 +0,0 @@
use alloc::sync::Arc;
use device_api::device::{Device, DeviceInitContext};
use device_tree::driver::{Node, ProbeContext, device_tree_driver};
use libk::{
error::Error,
fs::sysfs::{self, nodes::SysfsRtcNode},
};
use libk_mm::device::DeviceMemoryIo;
use libk_util::sync::IrqSafeSpinlock;
use tock_registers::{
interfaces::Readable,
register_structs,
registers::{ReadOnly, ReadWrite, WriteOnly},
};
register_structs! {
#[allow(non_snake_case)]
Regs {
(0x00 => RTCDR: ReadOnly<u32>),
(0x04 => RTCMR: ReadWrite<u32>),
(0x08 => RTCLR: ReadWrite<u32>),
(0x0C => RTCCR: ReadWrite<u32>),
(0x10 => RTCIMSC: ReadWrite<u32>),
(0x14 => RTCRIS: ReadOnly<u32>),
(0x18 => RTCMIS: ReadOnly<u32>),
(0x1C => RTCICR: WriteOnly<u32>),
(0x20 => @END),
}
}
struct Pl031 {
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
}
impl SysfsRtcNode for Pl031 {
fn read(&self) -> Result<u64, Error> {
let regs = self.regs.lock();
Ok(regs.RTCDR.get() as _)
}
}
impl Device for Pl031 {
unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
sysfs::nodes::add_rtc_node(self.clone());
Ok(())
}
fn display_name(&self) -> &str {
"ARM PL031 RTC"
}
}
device_tree_driver! {
compatible: ["arm,pl031"],
driver: {
fn probe(&self, node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
let base = node.map_base(context, 0)?;
let regs = unsafe { DeviceMemoryIo::map(base, Default::default()) }.ok()?;
let rtc = Arc::new(Pl031 { regs: IrqSafeSpinlock::new(regs) });
Some(rtc)
}
}
}
+9 -8
View File
@@ -8,16 +8,16 @@ use device_api::{
GpioController, GpioInterruptEvent, GpioInterruptMode, GpioPinLevel, PinHandle,
SinglePinDirection,
},
interrupt::{InterruptHandler, IrqHandle, IrqVector},
interrupt::{FullIrq, InterruptHandler, IrqVector},
};
use device_tree::{
DeviceTreePropertyRead, TProp,
driver::{
DeviceTreeGpioPins, DeviceTreePinController, Node, ProbeContext, device_tree_driver,
util::generic_gpio_config,
device_tree_driver, util::generic_gpio_config, DeviceTreeGpioPins, DeviceTreePinController,
Node, ProbeContext,
},
DeviceTreePropertyRead, TProp,
};
use libk::event::signal_gpio_event;
use libk::{device::external_interrupt_controller, event::signal_gpio_event};
use libk_mm::device::DeviceMemoryIo;
use libk_util::{bit::BitField, sync::IrqSafeSpinlock};
use tock_registers::{
@@ -50,7 +50,7 @@ register_structs! {
struct Pl061 {
#[allow(unused)]
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
irq: IrqHandle,
irq: FullIrq,
clocks: Vec<ClockHandle>,
resets: Vec<ResetHandle>,
gpio_events: [AtomicU64; 8],
@@ -69,8 +69,9 @@ impl Device for Pl061 {
}
unsafe fn init_irq(self: Arc<Self>) -> Result<(), Error> {
self.irq.register(self.clone())?;
self.irq.enable()?;
let intc = external_interrupt_controller()?;
intc.register_irq(self.irq.irq, self.irq.options, self.clone())?;
intc.enable_irq(self.irq.irq)?;
Ok(())
}
+2 -2
View File
@@ -4,11 +4,11 @@ use device_api::{
device::{Device, DeviceInitContext},
};
use device_tree::{
driver::{device_tree_driver, DeviceTreeClockController, Node, ProbeContext},
DeviceTreePropertyRead, TProp,
driver::{DeviceTreeClockController, Node, ProbeContext, device_tree_driver},
};
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo};
use libk_util::{OneTimeInit, sync::IrqSafeSpinlock};
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
use tock_registers::{
interfaces::ReadWriteable,
register_bitfields, register_structs,
+8 -7
View File
@@ -2,16 +2,16 @@ use alloc::sync::Arc;
use device_api::{
clock::ClockHandle,
device::{Device, DeviceInitContext},
interrupt::{InterruptHandler, IrqHandle, IrqVector},
interrupt::{FullIrq, InterruptHandler, IrqVector},
};
use device_tree::driver::{Node, ProbeContext, device_tree_driver};
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
use libk::{
debug::DebugSink,
device::manager::DEVICE_REGISTRY,
device::{external_interrupt_controller, manager::DEVICE_REGISTRY},
vfs::{Terminal, TerminalInput, TerminalOutput},
};
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo};
use libk_util::{OneTimeInit, sync::IrqSafeSpinlock};
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
use tock_registers::{
interfaces::{ReadWriteable, Readable, Writeable},
register_bitfields, register_structs,
@@ -61,7 +61,7 @@ struct Inner {
/// Broadcom 283x mini-UART driver
pub struct Bcm2835AuxUart {
base: PhysicalAddress,
irq: IrqHandle,
irq: FullIrq,
clock: ClockHandle,
inner: OneTimeInit<Arc<Terminal<Inner>>>,
}
@@ -171,8 +171,9 @@ impl Device for Bcm2835AuxUart {
}
unsafe fn init_irq(self: Arc<Self>) -> Result<(), Error> {
self.irq.register(self.clone())?;
self.irq.enable()?;
let intc = external_interrupt_controller()?;
intc.register_irq(self.irq.irq, self.irq.options, self.clone())?;
intc.enable_irq(self.irq.irq)?;
let inner = self.inner.get().output();
let regs = inner.regs.lock();
+9 -7
View File
@@ -2,15 +2,16 @@ use alloc::sync::Arc;
use device_api::{
device::{Device, DeviceInitContext},
gpio::{GpioController, GpioInterruptEvent, PinHandle},
interrupt::{InterruptHandler, IrqHandle, IrqVector},
interrupt::{FullIrq, InterruptHandler, IrqVector},
};
use device_tree::{
DeviceTreePropertyRead, TProp,
driver::{
DeviceTreeGpioPins, DeviceTreePinController, Node, ProbeContext, device_tree_driver,
util::generic_gpio_config,
device_tree_driver, util::generic_gpio_config, DeviceTreeGpioPins, DeviceTreePinController,
Node, ProbeContext,
},
DeviceTreePropertyRead, TProp,
};
use libk::device::external_interrupt_controller;
use libk_mm::device::DeviceMemoryIo;
use libk_util::sync::IrqSafeSpinlock;
use tock_registers::{
@@ -68,7 +69,7 @@ register_structs! {
struct Bcm2711Gpio {
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
#[allow(unused)]
irqs: [IrqHandle; 2],
irqs: [FullIrq; 2],
}
impl Regs {
@@ -141,9 +142,10 @@ impl Device for Bcm2711Gpio {
regs.configure_pin_interrupts(pin, false, false, false, false);
}
let intc = external_interrupt_controller()?;
for irq in self.irqs.iter() {
irq.register(self.clone())?;
irq.enable()?;
intc.register_irq(irq.irq, irq.options, self.clone())?;
intc.enable_irq(irq.irq)?;
}
Ok(())
+2 -2
View File
@@ -2,7 +2,7 @@ use core::{cell::UnsafeCell, mem::MaybeUninit};
use alloc::sync::Arc;
use device_api::device::{Device, DeviceInitContext};
use device_tree::driver::{Node, ProbeContext, device_tree_driver};
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
use kernel_arch_aarch64::mem::table::L3;
use libk::device::{
display::{
@@ -11,10 +11,10 @@ use libk::device::{
manager::DEVICE_REGISTRY,
};
use libk_mm::{
OnDemandPage, PageBox, PageProvider, VirtualPage,
address::{AsPhysicalAddress, PhysicalAddress},
device::DeviceMemoryIo,
table::{EntryLevel, MapAttributes},
OnDemandPage, PageBox, PageProvider, VirtualPage,
};
use libk_util::sync::IrqSafeSpinlock;
use tock_registers::{
+6 -6
View File
@@ -6,11 +6,11 @@ use device_api::{
device::{Device, DeviceInitContext},
};
use device_tree::{
DeviceTreePropertyRead, TProp,
driver::{
DeviceTreeClockController, DeviceTreeResetController, DeviceTreeSyscon, Node, ProbeContext,
device_tree_driver, lookup_phandle,
device_tree_driver, lookup_phandle, DeviceTreeClockController, DeviceTreeResetController,
DeviceTreeSyscon, Node, ProbeContext,
},
DeviceTreePropertyRead, TProp,
};
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIoMut};
use libk_util::sync::IrqSafeSpinlock;
@@ -171,7 +171,7 @@ trait ClockDefinition {
const CLOCKS: &'static [Option<(&'static str, ClockDef)>];
}
const SYSCRG_CLOCKS: &[Option<(&'static str, ClockDef)>] = &const {
const SYSCRG_CLOCKS: &'static [Option<(&'static str, ClockDef)>] = &const {
use ClockDef::*;
let mut t = [const { None }; SYSCRG_CLOCK_COUNT];
@@ -230,7 +230,7 @@ const SYSCRG_CLOCKS: &[Option<(&'static str, ClockDef)>] = &const {
t
};
const AONCRG_CLOCKS: &[Option<(&'static str, ClockDef)>] = &const {
const AONCRG_CLOCKS: &'static [Option<(&'static str, ClockDef)>] = &const {
use ClockDef::*;
let mut t = [const { None }; AONCRG_CLOCK_COUNT];
@@ -262,7 +262,7 @@ const AONCRG_CLOCKS: &[Option<(&'static str, ClockDef)>] = &const {
t
};
const STGCRG_CLOCKS: &[Option<(&'static str, ClockDef)>] = &const {
const STGCRG_CLOCKS: &'static [Option<(&'static str, ClockDef)>] = &const {
use ClockDef::*;
let mut t = [const { None }; STGCRG_CLOCK_COUNT];
+1 -1
View File
@@ -1,4 +1,4 @@
#![allow(unsafe_op_in_unsafe_fn, clippy::eq_op, clippy::erasing_op)]
#![allow(unsafe_op_in_unsafe_fn)]
#![no_std]
extern crate alloc;
+5 -4
View File
@@ -8,14 +8,15 @@ use device_api::{
},
};
use device_tree::{
DeviceTreePropertyRead, TProp,
driver::{
DeviceTreeGpioPins, DeviceTreePinController, Node, ProbeContext, device_tree_driver,
util::{GenericPinctrlBiasConfig, GenericPinctrlConfig, generic_gpio_config},
device_tree_driver,
util::{generic_gpio_config, GenericPinctrlBiasConfig, GenericPinctrlConfig},
DeviceTreeGpioPins, DeviceTreePinController, Node, ProbeContext,
},
DeviceTreePropertyRead, TProp,
};
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIoMut};
use libk_util::{OneTimeInit, bit::BitField, sync::IrqSafeSpinlock};
use libk_util::{bit::BitField, sync::IrqSafeSpinlock, OneTimeInit};
use yggdrasil_abi::error::Error;
#[derive(Debug)]
@@ -1,70 +0,0 @@
use alloc::sync::Arc;
use device_api::device::{Device, DeviceInitContext};
use device_tree::driver::{Node, ProbeContext, device_tree_driver};
use libk::{
error::Error,
fs::sysfs::{self, nodes::SysfsRtcNode},
};
use libk_mm::device::DeviceMemoryIo;
use libk_util::sync::IrqSafeSpinlock;
use tock_registers::{
interfaces::Readable,
register_structs,
registers::{ReadOnly, ReadWrite},
};
use yggdrasil_abi::time::NANOSECONDS_IN_SECOND;
register_structs! {
#[allow(non_snake_case)]
Regs {
(0x00 => TIME_LOW: ReadOnly<u32>),
(0x04 => TIME_HIGH: ReadOnly<u32>),
(0x08 => ALARM_LOW: ReadWrite<u32>),
(0x0C => ALARM_HIGH: ReadWrite<u32>),
(0x10 => IRQ_ENABLED: ReadWrite<u32>),
(0x14 => CLEAR_ALARM: ReadWrite<u32>),
(0x18 => ALARM_STATUS: ReadOnly<u32>),
(0x1C => CLEAR_INTERRUPT: ReadWrite<u32>),
(0x20 => @END),
}
}
struct Rtc {
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
}
impl SysfsRtcNode for Rtc {
fn read(&self) -> Result<u64, Error> {
let regs = self.regs.lock();
let low = regs.TIME_LOW.get();
let high = regs.TIME_HIGH.get();
let t = ((high as u64) << 32) | (low as u64);
Ok(t / NANOSECONDS_IN_SECOND)
}
}
impl Device for Rtc {
unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
sysfs::nodes::add_rtc_node(self.clone());
Ok(())
}
fn display_name(&self) -> &str {
"Google Goldfish RTC"
}
}
device_tree_driver! {
compatible: ["google,goldfish-rtc"],
driver: {
fn probe(&self, node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
let base = node.map_base(context, 0)?;
let regs = unsafe { DeviceMemoryIo::map(base, Default::default()) }.ok()?;
let rtc = Arc::new(Rtc { regs: IrqSafeSpinlock::new(regs) });
Some(rtc)
}
}
}
-1
View File
@@ -3,5 +3,4 @@
extern crate alloc;
mod goldfish_rtc;
mod plic;
+7 -8
View File
@@ -2,20 +2,20 @@ use alloc::{sync::Arc, vec::Vec};
use device_api::{
device::{Device, DeviceInitContext},
interrupt::{
ExternalInterruptController, FixedInterruptTable, InterruptHandler, InterruptTable, Irq,
IrqHandle, IrqOptions, IrqVector,
ExternalInterruptController, FixedInterruptTable, FullIrq, InterruptHandler,
InterruptTable, Irq, IrqOptions, IrqVector,
},
};
use device_tree::{
DeviceTreePropertyRead, TProp,
driver::{
DeviceTreeInterruptController, Node, ProbeContext, device_tree_driver, lookup_phandle,
device_tree_driver, lookup_phandle, DeviceTreeInterruptController, Node, ProbeContext,
},
DeviceTreePropertyRead, TProp,
};
use kernel_arch_riscv64::boot_hart_id;
use libk::{arch::Cpu, device::register_external_interrupt_controller};
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo};
use libk_util::{OneTimeInit, sync::spin_rwlock::IrqSafeRwLock};
use libk_util::{sync::spin_rwlock::IrqSafeRwLock, OneTimeInit};
use tock_registers::{
interfaces::{Readable, Writeable},
register_structs,
@@ -261,12 +261,11 @@ impl Device for Plic {
}
impl DeviceTreeInterruptController for Plic {
fn map_interrupt(self: Arc<Self>, property: &TProp, offset: usize) -> Option<IrqHandle> {
fn map_interrupt(&self, property: &TProp, offset: usize) -> Option<FullIrq> {
let num = property.read_cell(offset, 1)?;
Some(IrqHandle {
Some(FullIrq {
irq: Irq::External(num as _),
options: IrqOptions::default(),
intc: self.clone(),
})
}
+1 -1
View File
@@ -1,7 +1,7 @@
[package]
name = "ygg_driver_pci"
version = "0.1.0"
edition = "2024"
edition = "2021"
authors = ["Mark Poliakov <mark@alnyan.me>"]
[dependencies]
+1 -1
View File
@@ -498,7 +498,7 @@ impl MsiXVectorTableAccess<'_> {
impl MsiXVectorTable<'_> {
unsafe fn memory_from_raw_parts(base: PhysicalAddress, len: usize) -> Result<Self, Error> {
let vectors = unsafe { DeviceMemoryIoMut::map_slice(base, len, Default::default()) }?;
let vectors = DeviceMemoryIoMut::map_slice(base, len, Default::default())?;
Ok(Self {
access: MsiXVectorTableAccess::Memory(vectors),
len,
+16 -15
View File
@@ -9,13 +9,13 @@ use device_api::{
},
};
use libk::device::external_interrupt_controller;
use libk_util::{OneTimeInit, sync::spin_rwlock::IrqSafeRwLock};
use libk_util::{sync::spin_rwlock::IrqSafeRwLock, OneTimeInit};
use yggdrasil_abi::error::Error;
use crate::{
PciAddress, PciCommandRegister, PciConfigSpace, PciConfigurationSpace, PciSegmentInfo,
capability::{MsiCapability, MsiXCapability, MsiXVectorTable},
driver::PciDriver,
PciAddress, PciCommandRegister, PciConfigSpace, PciConfigurationSpace, PciSegmentInfo,
};
/// Describes a PCI device
@@ -152,21 +152,22 @@ impl PciDeviceInfo {
let mut result = None;
if want_msix
&& let Some(mut msix) = self.config_space.capability::<MsiXCapability>()
&& let Ok(mut vt) = msix.vector_table()
{
if let Some(mut msi) = self.config_space.capability::<MsiCapability>() {
msi.set_enabled(false);
if let Ok(mut vt) = msix.vector_table() {
if let Some(mut msi) = self.config_space.capability::<MsiCapability>() {
msi.set_enabled(false);
}
vt.mask_all();
msix.set_function_mask(false);
msix.set_enabled(true);
result = Some(ConfiguredInterruptMode::MsiX(
msi_route.controller.clone(),
vt,
));
}
vt.mask_all();
msix.set_function_mask(false);
msix.set_enabled(true);
result = Some(ConfiguredInterruptMode::MsiX(
msi_route.controller.clone(),
vt,
));
}
// Fall back to MSI if MSI-x is not available or not requested
+1 -1
View File
@@ -5,8 +5,8 @@ use device_api::interrupt::MessageInterruptController;
use libk::error::Error;
use crate::{
PciAddress,
device::{PciInterrupt, PciInterruptRoute, PciMsiRoute},
PciAddress,
};
#[derive(Debug)]
+3 -3
View File
@@ -1,6 +1,6 @@
//! PCI/PCIe bus interfaces
#![no_std]
#![feature(decl_macro)]
#![feature(let_chains, decl_macro)]
#![allow(clippy::missing_transmute_annotations, clippy::identity_op)]
extern crate alloc;
@@ -20,7 +20,7 @@ use libk::{
fs::sysfs::{self, object::KObject},
};
use libk_mm::address::PhysicalAddress;
use libk_util::{OneTimeInit, sync::IrqSafeSpinlock};
use libk_util::{sync::IrqSafeSpinlock, OneTimeInit};
use space::legacy;
use yggdrasil_abi::{error::Error, primitive_enum};
@@ -36,9 +36,9 @@ mod nodes;
mod space;
pub use space::{
PciConfigSpace, PciConfigurationSpace,
ecam::PciEcam,
legacy::{LegacyPciAccess, PciLegacyConfigurationSpace},
PciConfigSpace, PciConfigurationSpace,
};
bitflags! {
+1 -1
View File
@@ -17,7 +17,7 @@ pub macro pci_driver(
matches: [$($kind:ident $match:tt),+ $(,)?],
driver: $driver:tt
) {
#[unsafe(link_section = ".init_array")]
#[link_section = ".init_array"]
#[used]
static __REGISTER_FN: extern "C" fn() = __register_fn;
+1 -1
View File
@@ -8,7 +8,7 @@ use libk::{
};
use libk_util::sync::IrqSafeSpinlock;
use crate::{PciBaseAddress, PciCapabilityId, PciConfigurationSpace, device::PciBusDevice};
use crate::{device::PciBusDevice, PciBaseAddress, PciCapabilityId, PciConfigurationSpace};
pub(crate) fn make_sysfs_object(
device: PciBusDevice,
+2 -2
View File
@@ -32,7 +32,7 @@ impl PciEcam {
/// regions. The address must be aligned to a 4KiB boundary and be valid for accesses within a
/// 4KiB-sized range.
pub unsafe fn map(phys_addr: PhysicalAddress) -> Result<Self, Error> {
let mapping = unsafe { DeviceMemoryMapping::map(phys_addr, 0x1000, Default::default()) }?;
let mapping = DeviceMemoryMapping::map(phys_addr, 0x1000, Default::default())?;
Ok(Self { mapping })
}
@@ -53,7 +53,7 @@ impl PciEcam {
+ address.function as usize)
* 0x1000,
);
let this = unsafe { Self::map(phys_addr) }?;
let this = Self::map(phys_addr)?;
Ok(if this.is_valid() { Some(this) } else { None })
}
+12 -6
View File
@@ -2,7 +2,7 @@ use alloc::sync::Arc;
use legacy::PciLegacyConfigurationSpace;
use super::{PciAddress, PciBaseAddress, PciCapability, PciCapabilityId, PciEcam};
use crate::{PciCommandRegister, PciStatusRegister, device::PciInterruptPin};
use crate::{device::PciInterruptPin, PciCommandRegister, PciStatusRegister};
pub(super) mod ecam;
pub(super) mod legacy;
@@ -26,7 +26,9 @@ macro_rules! pci_config_field_setter {
$self.write_u32($offset, $value)
};
($self:ident, u16, $offset:expr, $value:expr) => {{ $self.write_u16($offset, $value) }};
($self:ident, u16, $offset:expr, $value:expr) => {{
$self.write_u16($offset, $value)
}};
($self:ident, u8, $offset:expr, $value:expr) => {
$self.write_u8($offset, $value)
@@ -220,7 +222,11 @@ pub trait PciConfigurationSpace {
fn interrupt_line(&self) -> Option<u8> {
let value = self.read_u8(0x3C);
if value < 16 { Some(value) } else { None }
if value < 16 {
Some(value)
} else {
None
}
}
/// # Safety
@@ -242,7 +248,7 @@ pub trait PciConfigurationSpace {
PciBaseAddress::Memory32(_) => PciBaseAddress::Memory32(0xFFFFFFF0),
PciBaseAddress::Memory64(_) => PciBaseAddress::Memory64(0xFFFFFFFFFFFFFFF0),
};
unsafe { self.set_bar(index, mask_value) };
self.set_bar(index, mask_value);
let new_value = self.bar(index).unwrap();
let size = match new_value {
@@ -252,7 +258,7 @@ pub trait PciConfigurationSpace {
_ => 0,
};
unsafe { self.set_bar(index, orig_value) };
self.set_bar(index, orig_value);
self.set_command(cmd);
size
@@ -296,7 +302,7 @@ pub trait PciConfigurationSpace {
fn bar(&self, index: usize) -> Option<PciBaseAddress> {
assert!(index < 6);
if index.is_multiple_of(2) {
if index % 2 == 0 {
let w0 = self.read_u32(0x10 + index * 4);
match w0 & 1 {
+8 -13
View File
@@ -6,12 +6,13 @@ use libk_util::{queue::UnboundedMpmcQueue, sync::spin_rwlock::IrqSafeRwLock};
use crate::{
class_driver,
device::{UsbBusAddress, UsbDeviceAccess},
host::UsbHostController,
UsbHostController,
};
pub struct UsbBusManager {
busses: IrqSafeRwLock<BTreeMap<u16, Arc<dyn UsbHostController>>>,
devices: IrqSafeRwLock<BTreeMap<UsbBusAddress, Arc<UsbDeviceAccess>>>,
last_bus_address: AtomicU16,
}
@@ -32,9 +33,9 @@ impl UsbBusManager {
QUEUE.push_back(device);
}
pub async fn detach_device(address: UsbBusAddress) {
pub fn detach_device(address: UsbBusAddress) {
if let Some(device) = BUS_MANAGER.devices.write().remove(&address) {
device.handle_detach().await;
device.handle_detach();
}
}
}
@@ -44,26 +45,20 @@ pub async fn bus_handler() {
loop {
let new_device = QUEUE.pop_front().await;
let id_vendor = new_device.device_descriptor.id_vendor;
let id_product = new_device.device_descriptor.id_product;
log::info!(
"{} ({}): {:?}-speed USB device connected: {:?} {:?} ({:04x}:{:04x})",
new_device.bus_address(),
new_device.port_string(),
"New {:?}-speed USB device connected: {}",
new_device.speed(),
new_device.vendor_str,
new_device.product_str,
id_vendor,
id_product
new_device.bus_address()
);
class_driver::spawn_driver(new_device).await;
class_driver::spawn_driver(new_device).await.ok();
}
}
static BUS_MANAGER: UsbBusManager = UsbBusManager {
busses: IrqSafeRwLock::new(BTreeMap::new()),
devices: IrqSafeRwLock::new(BTreeMap::new()),
last_bus_address: AtomicU16::new(0),
};
static QUEUE: UnboundedMpmcQueue<Arc<UsbDeviceAccess>> = UnboundedMpmcQueue::new();
@@ -2,12 +2,13 @@ use core::mem::MaybeUninit;
use alloc::{boxed::Box, sync::Arc};
use async_trait::async_trait;
use yggdrasil_abi::io::{KeyboardKey, KeyboardKeyEvent, MouseEvent};
use yggdrasil_abi::io::{KeyboardKey, KeyboardKeyEvent};
use crate::{class_driver::UsbInterfaceDriver, device::UsbInterfaceAccess, error::UsbError};
use crate::{device::UsbDeviceAccess, error::UsbError, info::UsbDeviceClass};
use super::{UsbClassInfo, UsbDriver};
pub struct UsbHidKeyboardDriver;
pub struct UsbHidMouseDriver;
const MODIFIER_MAP: &[KeyboardKey] = &[
KeyboardKey::LControl,
@@ -124,25 +125,14 @@ impl KeyboardState {
}
#[async_trait]
impl UsbInterfaceDriver for UsbHidKeyboardDriver {
async fn run(self: Arc<Self>, interface: UsbInterfaceAccess) -> Result<(), UsbError> {
log::info!("{}: HID keyboard", interface.address());
impl UsbDriver for UsbHidKeyboardDriver {
async fn run(self: Arc<Self>, device: Arc<UsbDeviceAccess>) -> Result<(), UsbError> {
// TODO not sure whether to use boot protocol (easy) or GetReport
let config = device.select_configuration(|_| true).await?.unwrap();
let endpoint_infos = interface.endpoints();
if endpoint_infos.is_empty() {
log::warn!(
"{}: no available endpoints in interface description",
interface.address()
);
return Err(UsbError::InvalidConfiguration);
}
let pipe = interface
.device()
.open_interrupt_in_pipe(
endpoint_infos[0].number,
endpoint_infos[0].max_packet_size as _,
)
log::info!("Setup HID keyboard");
let pipe = device
.open_interrupt_in_pipe(1, config.endpoints[0].max_packet_size as u16)
.await?;
let mut buffer = [0; 8];
@@ -166,7 +156,7 @@ impl UsbInterfaceDriver for UsbHidKeyboardDriver {
for &event in events {
log::trace!("Generic Keyboard: {:?}", event);
ygg_driver_input::send_keyboard_event(event);
ygg_driver_input::send_event(event);
}
}
}
@@ -175,61 +165,12 @@ impl UsbInterfaceDriver for UsbHidKeyboardDriver {
"USB HID Keyboard"
}
fn probe(&self, class: u8, subclass: u8, protocol: u8) -> bool {
class == 0x03 && subclass == 0x01 && protocol == 0x01
}
}
#[async_trait]
impl UsbInterfaceDriver for UsbHidMouseDriver {
async fn run(self: Arc<Self>, interface: UsbInterfaceAccess) -> Result<(), UsbError> {
log::info!("{}: HID mouse", interface.address());
let endpoint_infos = interface.endpoints();
if endpoint_infos.is_empty() {
log::warn!(
"{}: no available endpoints in interface description",
interface.address()
);
return Err(UsbError::InvalidConfiguration);
}
let pipe = interface
.device()
.open_interrupt_in_pipe(
endpoint_infos[0].number,
endpoint_infos[0].max_packet_size as _,
)
.await?;
let mut buffer = [0; 8];
loop {
let len = pipe.read(&mut buffer).await?;
if len < 4 {
continue;
}
let data = &buffer[..len];
let buttons = data[0];
let dx = data[1] as i8;
let dy = data[2] as i8;
log::trace!("mouse {dx:+},{dy:+} {buttons:08b}");
ygg_driver_input::send_mouse_event(MouseEvent {
dx,
dy,
buttons,
unused: 0,
});
}
}
fn name(&self) -> &'static str {
"USB HID Mouse"
}
fn probe(&self, class: u8, subclass: u8, protocol: u8) -> bool {
class == 0x03 && subclass == 0x01 && protocol == 0x02
fn probe(&self, class: &UsbClassInfo, _device: &UsbDeviceAccess) -> bool {
log::info!(
"class = {:?}, subclass = {:02x}",
class.class,
class.subclass
);
class.class == UsbDeviceClass::Hid && (class.subclass == 0x00 || class.subclass == 0x01)
}
}
@@ -1,384 +0,0 @@
use core::{mem::MaybeUninit, num::NonZeroU8, time::Duration};
use alloc::{boxed::Box, sync::Arc};
use async_trait::async_trait;
use libk::{task::runtime, time::monotonic_time};
use yggdrasil_abi::bitflags;
use crate::{
class_driver::UsbDeviceDriver,
descriptor::UsbHubDescriptorHeader,
device::{UsbDeviceAccess, UsbSpeed},
error::UsbError,
pipe::control::ControlTransferSetup,
};
pub struct UsbHubDriver;
const BM_REQUEST_TYPE_GET_HUB_DESCRIPTOR: u8 = 0b10100000;
const BM_REQUEST_TYPE_GET_PORT_STATUS: u8 = 0b10100011;
const BM_REQUEST_TYPE_PORT_FEATURE: u8 = 0b00100011;
const B_REQUEST_GET_STATUS: u8 = 0x00;
const B_REQUEST_CLEAR_FEATURE: u8 = 0x01;
const B_REQUEST_SET_FEATURE: u8 = 0x03;
const B_REQUEST_GET_DESCRIPTOR: u8 = 0x06;
#[allow(unused)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u16)]
pub enum PortFeatureSelector {
PortConnection = 0,
PortEnable = 1,
PortSuspend = 2,
PortOverCurrent = 3,
PortReset = 4,
PortPower = 8,
PortLowSpeed = 9,
CPortConnection = 16,
CPortEnable = 17,
CPortSuspend = 18,
CPortOverCurrent = 19,
CPortReset = 20,
PortTest = 21,
PortIndicator = 22,
}
bitflags! {
pub struct UsbHubPortStatus: u16 {
const PORT_CONNECTION: bit 0;
const PORT_ENABLE: bit 1;
const PORT_SUSPEND: bit 2;
const PORT_OVER_CURRENT: bit 3;
const PORT_RESET: bit 4;
const PORT_POWER: bit 8;
const PORT_LOW_SPEED: bit 9;
const PORT_HIGH_SPEED: bit 10;
const PORT_TEST: bit 11;
const PORT_INDICATOR: bit 12;
}
}
bitflags! {
pub struct UsbHubPortChange: u16 {
const C_PORT_CONNECTION: bit 0;
const C_PORT_ENABLE: bit 1;
const C_PORT_SUSPEND: bit 2;
const C_PORT_OVER_CURRENT: bit 3;
const C_PORT_RESET: bit 4;
}
}
struct UsbHub {
device: Arc<UsbDeviceAccess>,
hub_descriptor: UsbHubDescriptorHeader,
children: u64,
// TODO extra info
}
impl UsbHub {
pub async fn setup(device: Arc<UsbDeviceAccess>) -> Result<Self, UsbError> {
let control_pipe = device.control_pipe();
let mut hub_descriptor = MaybeUninit::uninit();
let len = control_pipe
.control_transfer_in(
ControlTransferSetup {
bm_request_type: BM_REQUEST_TYPE_GET_HUB_DESCRIPTOR,
b_request: B_REQUEST_GET_DESCRIPTOR,
w_value: 0,
w_index: 0,
w_length: size_of::<UsbHubDescriptorHeader>() as _,
},
hub_descriptor.as_bytes_mut(),
)
.await?;
if len != size_of::<UsbHubDescriptorHeader>() {
return Err(UsbError::TruncatedDescriptor(
size_of::<UsbHubDescriptorHeader>(),
len,
));
}
let hub_descriptor: UsbHubDescriptorHeader = unsafe { hub_descriptor.assume_init() };
if hub_descriptor.b_nr_ports < 1 {
log::warn!(
"{}: ignoring hub with zero downstream ports",
device.device.bus_address()
);
return Err(UsbError::InvalidDescriptorField);
}
log::info!(
"{}: setting up {:?}-speed hub, {} downstream ports",
device.device.bus_address(),
device.device.speed(),
hub_descriptor.b_nr_ports
);
device.configure_hub(&hub_descriptor).await?;
// TODO power on the ports?
Ok(Self {
device,
hub_descriptor,
children: 0,
})
}
async fn set_port_feature(
&mut self,
port: NonZeroU8,
feature: PortFeatureSelector,
) -> Result<(), UsbError> {
self.device
.control_pipe()
.control_transfer(ControlTransferSetup {
bm_request_type: BM_REQUEST_TYPE_PORT_FEATURE,
b_request: B_REQUEST_SET_FEATURE,
w_value: feature as _,
w_index: port.get() as _,
w_length: 0,
})
.await
}
async fn clear_port_feature(
&mut self,
port: NonZeroU8,
feature: PortFeatureSelector,
) -> Result<(), UsbError> {
self.device
.control_pipe()
.control_transfer(ControlTransferSetup {
bm_request_type: BM_REQUEST_TYPE_PORT_FEATURE,
b_request: B_REQUEST_CLEAR_FEATURE,
w_value: feature as _,
w_index: port.get() as _,
w_length: 0,
})
.await
}
async fn clear_port_changes(
&mut self,
port: NonZeroU8,
change: UsbHubPortChange,
) -> Result<(), UsbError> {
if change.contains(UsbHubPortChange::C_PORT_RESET) {
self.clear_port_feature(port, PortFeatureSelector::CPortReset)
.await?;
}
if change.contains(UsbHubPortChange::C_PORT_CONNECTION) {
self.clear_port_feature(port, PortFeatureSelector::CPortConnection)
.await?;
}
if change.contains(UsbHubPortChange::C_PORT_ENABLE) {
self.clear_port_feature(port, PortFeatureSelector::CPortEnable)
.await?;
}
Ok(())
}
async fn get_port_status(
&mut self,
port: NonZeroU8,
) -> Result<(UsbHubPortStatus, UsbHubPortChange), UsbError> {
let mut buffer = [MaybeUninit::uninit(); 2];
let len = self
.device
.control_pipe()
.control_transfer_in(
ControlTransferSetup {
bm_request_type: BM_REQUEST_TYPE_GET_PORT_STATUS,
b_request: B_REQUEST_GET_STATUS,
w_value: 0,
w_index: port.get() as _,
w_length: 4,
},
buffer.as_bytes_mut(),
)
.await?;
if len != 4 {
return Err(UsbError::TruncatedDescriptor(4, len));
}
let [w0, w1] = unsafe { MaybeUninit::array_assume_init(buffer) };
let status = UsbHubPortStatus(w0);
let change = UsbHubPortChange(w1);
Ok((status, change))
}
async fn reset_port(&mut self, port: NonZeroU8) -> Result<UsbHubPortStatus, UsbError> {
self.set_port_feature(port, PortFeatureSelector::PortReset)
.await?;
// Wait for reset to be asserted
let deadline = monotonic_time() + Duration::from_secs(3);
let mut status;
let mut change;
loop {
(status, change) = self.get_port_status(port).await?;
self.clear_port_changes(port, change).await?;
if status.contains(UsbHubPortStatus::PORT_RESET)
|| status.contains(UsbHubPortStatus::PORT_ENABLE)
|| !status.contains(UsbHubPortStatus::PORT_CONNECTION)
{
// Port reset got asserted or port got enabled
break;
}
if monotonic_time() >= deadline {
log::warn!("Port reset did not assert in 3 sec");
return Ok(status);
}
}
if status.contains(UsbHubPortStatus::PORT_ENABLE)
|| !status.contains(UsbHubPortStatus::PORT_CONNECTION)
{
return Ok(status);
}
todo!()
}
async fn setup_connected_port(&mut self, port: NonZeroU8) -> Result<(), UsbError> {
let status = self.reset_port(port).await?;
if !status.contains(UsbHubPortStatus::PORT_CONNECTION) {
log::warn!(
"{}: port {} disconnected during reset",
self.device.bus_address(),
port
);
return Ok(());
}
if !status.contains(UsbHubPortStatus::PORT_ENABLE) {
log::warn!("{}: port {} did not reset", self.device.bus_address(), port);
return Ok(());
}
let usb_speed = match (
status.contains(UsbHubPortStatus::PORT_LOW_SPEED),
status.contains(UsbHubPortStatus::PORT_HIGH_SPEED),
) {
(false, false) => UsbSpeed::Full,
(true, false) => UsbSpeed::Low,
(false, true) => UsbSpeed::High,
(true, true) => todo!(),
};
log::info!(
"{}: hub port {}: {:?}-speed device connected",
self.device.bus_address(),
port,
usb_speed
);
let port_string = self.device.port_string().append(port);
if let Err(error) = self
.device
.host_controller()
.setup_hub_device(self.device.clone(), port_string, usb_speed)
.await
{
log::error!(
"{}: hub port {} ({}) setup failed: {:?}",
self.device.bus_address(),
port,
port_string,
error
);
return Ok(());
}
self.children |= 1 << (port.get() - 1);
Ok(())
}
async fn disconnect_port(&mut self, port: NonZeroU8) -> Result<(), UsbError> {
let port_string = self.device.port_string().append(port);
self.children &= !(1 << (port.get() - 1));
self.device
.host_controller()
.disconnect_device(port_string)
.await
}
async fn poll_port(&mut self, port: NonZeroU8) -> Result<(), UsbError> {
let (status, change) = self.get_port_status(port).await?;
if change.contains(UsbHubPortChange::C_PORT_CONNECTION) {
// Clear feature: C_PORT_CONNECTION
self.clear_port_feature(port, PortFeatureSelector::CPortConnection)
.await?;
if status.contains(UsbHubPortStatus::PORT_CONNECTION) {
self.setup_connected_port(port).await?;
} else if let Err(error) = self.disconnect_port(port).await {
log::warn!(
"{}: hub port {} did not disconnect cleanly: {:?}",
self.device.bus_address(),
port,
error
);
}
}
Ok(())
}
async fn poll(&mut self) -> bool {
for i in 0..self.hub_descriptor.b_nr_ports {
let port = NonZeroU8::new(i + 1).unwrap();
if let Err(error) = self.poll_port(port).await {
log::error!(
"{}: hub port {} poll error: {:?}",
self.device.bus_address(),
port,
error
);
return false;
}
}
true
}
async fn cleanup(&mut self) {
for i in 0..self.hub_descriptor.b_nr_ports {
let port = NonZeroU8::new(i + 1).unwrap();
if self.children & (1 << i) != 0 {
if let Err(error) = self.disconnect_port(port).await {
log::warn!(
"{}: downstream {} disconnect error: {:?}",
self.device.bus_address(),
port,
error
);
}
}
}
}
async fn run(mut self) -> Result<(), UsbError> {
loop {
if !self.poll().await {
self.cleanup().await;
return Ok(());
}
runtime::sleep(Duration::from_millis(100)).await;
}
}
}
#[async_trait]
impl UsbDeviceDriver for UsbHubDriver {
async fn run(self: Arc<Self>, device: Arc<UsbDeviceAccess>) -> Result<(), UsbError> {
let hub = UsbHub::setup(device).await?;
hub.run().await
}
fn name(&self) -> &'static str {
"USB Hub"
}
fn probe(&self, class: u8, subclass: u8, protocol: u8) -> bool {
let _ = protocol;
class == 0x09 && subclass == 0x00
}
}
@@ -7,25 +7,20 @@ use libk::{
dma::{DmaBuffer, DmaSliceMut},
error::Error,
};
use ygg_driver_scsi::{ScsiEnclosure, transport::ScsiTransport};
use ygg_driver_scsi::{transport::ScsiTransport, ScsiEnclosure};
use crate::{
class_driver::UsbInterfaceDriver,
communication::UsbDirection,
device::{UsbDeviceDetachHandler, UsbInterfaceAccess},
device::{UsbDeviceAccess, UsbDeviceDetachHandler},
error::UsbError,
info::UsbEndpointType,
info::{UsbDeviceClass, UsbEndpointType},
pipe::{
control::ControlTransferSetup,
control::{ControlTransferSetup, UsbClassSpecificRequest},
normal::{UsbBulkInPipeAccess, UsbBulkOutPipeAccess},
},
};
const BM_REQUEST_TYPE_BULK_ONLY_MASS_STORAGE_RESET: u8 = 0b00100001;
const BM_REQUEST_TYPE_GET_MAX_LUN: u8 = 0b10100001;
const B_REQUEST_BULK_ONLY_MASS_STORAGE_RESET: u8 = 0b11111111;
const B_REQUEST_GET_MAX_LUN: u8 = 0b11111110;
use super::{UsbClassInfo, UsbDriver};
pub struct UsbMassStorageDriverBulkOnly;
@@ -55,7 +50,7 @@ struct Csw {
struct Bbb {
#[allow(unused)]
interface: UsbInterfaceAccess,
device: Arc<UsbDeviceAccess>,
in_pipe: UsbBulkInPipeAccess,
out_pipe: UsbBulkOutPipeAccess,
last_tag: u32,
@@ -65,12 +60,12 @@ struct DetachHandler(Arc<ScsiEnclosure>);
impl Bbb {
pub fn new(
interface: UsbInterfaceAccess,
device: Arc<UsbDeviceAccess>,
in_pipe: UsbBulkInPipeAccess,
out_pipe: UsbBulkOutPipeAccess,
) -> Result<Self, UsbError> {
Ok(Self {
interface,
device,
in_pipe,
out_pipe,
last_tag: 0,
@@ -177,49 +172,60 @@ impl ScsiTransport for Bbb {
}
}
#[async_trait]
impl UsbDeviceDetachHandler for DetachHandler {
async fn handle_device_detach(&self) {
self.0.detach().await;
fn handle_device_detach(&self) {
log::info!("Mass storage detached");
self.0.detach();
}
}
#[derive(Debug, Pod, Zeroable, Clone, Copy)]
#[repr(C)]
pub struct BulkOnlyMassStorageReset;
#[derive(Debug, Pod, Zeroable, Clone, Copy)]
#[repr(C)]
pub struct GetMaxLun;
impl UsbClassSpecificRequest for BulkOnlyMassStorageReset {
const BM_REQUEST_TYPE: u8 = 0b00100001;
const B_REQUEST: u8 = 0b11111111;
}
impl UsbClassSpecificRequest for GetMaxLun {
const BM_REQUEST_TYPE: u8 = 0b10100001;
const B_REQUEST: u8 = 0b11111110;
}
#[async_trait]
impl UsbInterfaceDriver for UsbMassStorageDriverBulkOnly {
async fn run(self: Arc<Self>, interface: UsbInterfaceAccess) -> Result<(), UsbError> {
let endpoints = interface.endpoints();
let bulk_in = endpoints
.iter()
.find(|ep| ep.ty == UsbEndpointType::Bulk && ep.direction == UsbDirection::In);
let bulk_out = endpoints
.iter()
.find(|ep| ep.ty == UsbEndpointType::Bulk && ep.direction == UsbDirection::Out);
let (Some(bulk_in), Some(bulk_out)) = (bulk_in, bulk_out) else {
log::warn!(
"{}: BBB mass storage needs at least 2 bulk endpoints",
interface.address()
);
return Err(UsbError::InvalidConfiguration);
};
let control_pipe = interface.device().control_pipe();
let in_pipe = interface
.device()
.open_bulk_in_pipe(bulk_in.number, bulk_in.max_packet_size as _)
impl UsbDriver for UsbMassStorageDriverBulkOnly {
async fn run(self: Arc<Self>, device: Arc<UsbDeviceAccess>) -> Result<(), UsbError> {
// TODO filter to only accept BBB config
let config = device.select_configuration(|_| true).await?.unwrap();
// Bulk-in, bulk-out
assert_eq!(config.endpoints.len(), 2);
let control_pipe = device.control_pipe();
let (in_index, in_info) = config
.find_endpoint(|ep| ep.is(UsbEndpointType::Bulk, UsbDirection::In))
.ok_or(UsbError::InvalidConfiguration)?;
let (out_index, out_info) = config
.find_endpoint(|ep| ep.is(UsbEndpointType::Bulk, UsbDirection::Out))
.ok_or(UsbError::InvalidConfiguration)?;
let in_pipe = device
.open_bulk_in_pipe(in_index, in_info.max_packet_size as u16)
.await?;
let out_pipe = interface
.device()
.open_bulk_out_pipe(bulk_out.number, bulk_out.max_packet_size as _)
let out_pipe = device
.open_bulk_out_pipe(out_index, out_info.max_packet_size as u16)
.await?;
// Perform a Bulk-Only Mass Storage Reset
// TODO interface id?
control_pipe
.control_transfer(ControlTransferSetup {
bm_request_type: BM_REQUEST_TYPE_BULK_ONLY_MASS_STORAGE_RESET,
b_request: B_REQUEST_BULK_ONLY_MASS_STORAGE_RESET,
bm_request_type: BulkOnlyMassStorageReset::BM_REQUEST_TYPE,
b_request: BulkOnlyMassStorageReset::B_REQUEST,
w_value: 0,
w_index: interface.number() as _,
w_index: 0,
w_length: 0,
})
.await?;
@@ -230,10 +236,10 @@ impl UsbInterfaceDriver for UsbMassStorageDriverBulkOnly {
let len = control_pipe
.control_transfer_in(
ControlTransferSetup {
bm_request_type: BM_REQUEST_TYPE_GET_MAX_LUN,
b_request: B_REQUEST_GET_MAX_LUN,
bm_request_type: GetMaxLun::BM_REQUEST_TYPE,
b_request: GetMaxLun::B_REQUEST,
w_value: 0,
w_index: interface.number() as _,
w_index: 0,
w_length: 1,
},
&mut buffer,
@@ -245,13 +251,13 @@ impl UsbInterfaceDriver for UsbMassStorageDriverBulkOnly {
unsafe { buffer[0].assume_init() }
};
let bbb = Bbb::new(interface.clone(), in_pipe, out_pipe)?;
let bbb = Bbb::new(device.clone(), in_pipe, out_pipe)?;
let scsi = ScsiEnclosure::setup(Box::new(bbb), max_lun as usize + 1)
.await
.inspect_err(|error| log::error!("msc: scsi error {error:?}"))
.map_err(|_| UsbError::DriverError)?;
let detach = DetachHandler(scsi.clone());
interface.device().set_detach_handler(Arc::new(detach));
device.set_detach_handler(Arc::new(detach));
Ok(())
}
@@ -260,9 +266,8 @@ impl UsbInterfaceDriver for UsbMassStorageDriverBulkOnly {
"USB Mass Storage"
}
fn probe(&self, class: u8, subclass: u8, protocol: u8) -> bool {
fn probe(&self, class: &UsbClassInfo, _device: &UsbDeviceAccess) -> bool {
// TODO support other protocols
let _ = subclass;
class == 0x08 && protocol == 0x50
class.class == UsbDeviceClass::MassStorage && class.interface_protocol_number == 0x50
}
}
+80 -104
View File
@@ -1,141 +1,117 @@
// TODO Split drivers into device and interface drivers
use alloc::{boxed::Box, sync::Arc, vec::Vec};
use async_trait::async_trait;
use libk::task::runtime;
use libk_util::sync::spin_rwlock::IrqSafeRwLock;
use crate::{
device::{UsbDeviceAccess, UsbInterfaceAccess},
device::UsbDeviceAccess,
error::UsbError,
info::{UsbDeviceClass, UsbDeviceProtocol},
};
mod hid;
mod hub;
mod mass_storage;
pub mod hid_keyboard;
pub mod mass_storage;
#[derive(Debug)]
pub struct UsbClassInfo {
pub class: UsbDeviceClass,
pub subclass: u8,
pub protocol: UsbDeviceProtocol,
pub device_protocol_number: u8,
pub interface_protocol_number: u8,
}
#[async_trait]
pub trait UsbDeviceDriver: Send + Sync {
pub trait UsbDriver: Send + Sync {
async fn run(self: Arc<Self>, device: Arc<UsbDeviceAccess>) -> Result<(), UsbError>;
fn name(&self) -> &'static str;
fn probe(&self, class: u8, subclass: u8, protocol: u8) -> bool;
fn probe(&self, class: &UsbClassInfo, device: &UsbDeviceAccess) -> bool;
}
#[async_trait]
pub trait UsbInterfaceDriver: Send + Sync {
async fn run(self: Arc<Self>, interface: UsbInterfaceAccess) -> Result<(), UsbError>;
async fn extract_class_info(device: &UsbDeviceAccess) -> Result<Option<UsbClassInfo>, UsbError> {
if device.info.num_configurations != 1 {
return Ok(None);
}
let device_info = &device.info;
let config_info = device.query_configuration_info(0).await?;
fn name(&self) -> &'static str;
fn probe(&self, class: u8, subclass: u8, protocol: u8) -> bool;
if !config_info.interfaces.is_empty() {
let if_info = &config_info.interfaces[0];
let class = if device_info.device_class == UsbDeviceClass::FromInterface {
if_info.interface_class
} else {
device_info.device_class
};
let subclass = if device_info.device_subclass == 0 {
if_info.interface_subclass
} else {
device_info.device_subclass
};
let protocol = if device_info.device_protocol == UsbDeviceProtocol::FromInterface {
if_info.interface_protocol
} else {
device_info.device_protocol
};
Ok(Some(UsbClassInfo {
class,
subclass,
protocol,
interface_protocol_number: if_info.interface_protocol_number,
device_protocol_number: device_info.device_protocol_number,
}))
} else {
Ok(None)
}
}
async fn spawn_device_driver(device: Arc<UsbDeviceAccess>) -> Result<bool, UsbError> {
let class = device.device_descriptor.device_class;
let subclass = device.device_descriptor.device_subclass;
let protocol = device.device_descriptor.device_protocol;
let Some(driver) = USB_DEVICE_DRIVERS.read().iter().find_map(|driver| {
driver
.probe(class, subclass, protocol)
.then(|| driver.clone())
}) else {
return Ok(false);
async fn pick_driver(
device: &UsbDeviceAccess,
) -> Result<Option<Arc<dyn UsbDriver + 'static>>, UsbError> {
let Some(class) = extract_class_info(device).await? else {
return Ok(None);
};
// if let Some(driver) = pick_driver(&device)? {
runtime::spawn(async move {
let name = driver.name();
match driver.run(device).await {
e @ Err(UsbError::DeviceDisconnected) => {
log::warn!(
"Driver {:?} did not exit cleanly: device disconnected",
name,
);
e
}
e => e,
for driver in USB_DEVICE_DRIVERS.read().iter() {
if driver.probe(&class, device) {
return Ok(Some(driver.clone()));
}
})
.map_err(UsbError::SystemError)?;
Ok(true)
}
Ok(None)
}
async fn spawn_interface_driver(interface: UsbInterfaceAccess) -> Result<(), UsbError> {
let (class, subclass, protocol) = interface.class();
let Some(driver) = USB_INTERFACE_DRIVERS.read().iter().find_map(|driver| {
driver
.probe(class, subclass, protocol)
.then(|| driver.clone())
}) else {
return Ok(());
};
pub async fn spawn_driver(device: Arc<UsbDeviceAccess>) -> Result<(), UsbError> {
if let Some(driver) = pick_driver(&device).await? {
runtime::spawn(async move {
let name = driver.name();
match driver.run(device).await {
e @ Err(UsbError::DeviceDisconnected) => {
log::warn!(
"Driver {:?} did not exit cleanly: device disconnected",
name,
);
runtime::spawn(async move {
let name = driver.name();
match driver.run(interface).await {
e @ Err(UsbError::DeviceDisconnected) => {
log::warn!(
"Driver {:?} did not exit cleanly: device disconnected",
name,
);
e
e
}
e => e,
}
e => e,
}
})
.map_err(UsbError::SystemError)?;
})
.map_err(UsbError::SystemError)?;
}
Ok(())
}
pub async fn spawn_driver(device: Arc<UsbDeviceAccess>) {
match spawn_device_driver(device.clone()).await {
Ok(true) => return,
Ok(false) => (),
Err(error) => {
log::error!(
"{}: device driver probe failed: {:?}",
device.bus_address(),
error
);
}
}
// Enumerate interfaces
for index in 0..device.configuration0_info.interfaces.len() as u8 {
let access = device.interface(index);
if let Err(error) = spawn_interface_driver(access).await {
log::error!(
"{}: interface {} driver probe failed: {:?}",
device.bus_address(),
index,
error
);
}
}
}
pub fn register_device_driver(driver: Arc<dyn UsbDeviceDriver + 'static>) {
pub fn register_driver(driver: Arc<dyn UsbDriver + 'static>) {
// TODO check for duplicates
USB_DEVICE_DRIVERS.write().push(driver);
}
pub fn register_interface_driver(driver: Arc<dyn UsbInterfaceDriver + 'static>) {
USB_INTERFACE_DRIVERS.write().push(driver);
}
pub fn register_default_class_drivers() {
register_device_driver(Arc::new(hub::UsbHubDriver));
register_interface_driver(Arc::new(hid::UsbHidKeyboardDriver));
register_interface_driver(Arc::new(hid::UsbHidMouseDriver));
register_interface_driver(Arc::new(mass_storage::UsbMassStorageDriverBulkOnly));
// register_driver(Arc::new(hub::UsbHubDriver));
// register_driver(Arc::new(hid_keyboard::UsbHidKeyboardDriver));
// register_driver(Arc::new(mass_storage::UsbMassStorageDriverBulkOnly));
register_driver(Arc::new(hid_keyboard::UsbHidKeyboardDriver));
register_driver(Arc::new(mass_storage::UsbMassStorageDriverBulkOnly));
}
static USB_DEVICE_DRIVERS: IrqSafeRwLock<Vec<Arc<dyn UsbDeviceDriver + 'static>>> =
IrqSafeRwLock::new(Vec::new());
static USB_INTERFACE_DRIVERS: IrqSafeRwLock<Vec<Arc<dyn UsbInterfaceDriver + 'static>>> =
static USB_DEVICE_DRIVERS: IrqSafeRwLock<Vec<Arc<dyn UsbDriver + 'static>>> =
IrqSafeRwLock::new(Vec::new());
+18 -42
View File
@@ -4,22 +4,9 @@ use crate::{
communication::UsbDirection,
device::UsbSpeed,
error::UsbError,
info::{UsbEndpointType, UsbVersion},
// info::{UsbDeviceClass, UsbDeviceProtocol, UsbEndpointType, UsbVersion},
info::{UsbDeviceClass, UsbDeviceProtocol, UsbEndpointType, UsbVersion},
};
#[derive(Clone, Copy, Debug, Default, Pod, Zeroable)]
#[repr(C, packed)]
pub struct UsbDeviceDescriptor0 {
pub length: u8,
pub ty: u8,
pub bcd_usb: u16,
pub device_class: u8,
pub device_subclass: u8,
pub device_protocol: u8,
pub max_packet_size_0: u8,
}
#[derive(Clone, Copy, Debug, Default, Pod, Zeroable)]
#[repr(C, packed)]
pub struct UsbDeviceDescriptor {
@@ -104,27 +91,16 @@ pub struct UsbOtherSpeedConfiguration {
pub max_power: u8,
}
#[derive(Clone, Copy, Debug, Default, Pod, Zeroable)]
#[repr(C, packed)]
pub struct UsbHubDescriptorHeader {
pub b_desc_length: u8,
pub b_descriptor_type: u8,
pub b_nr_ports: u8,
pub w_hub_characteristics: u16,
pub b_pwr_on_2_pwr_good: u8,
pub b_hub_contr_current: u8,
impl UsbInterfaceDescriptor {
pub fn class(&self) -> UsbDeviceClass {
UsbDeviceClass::try_from(self.interface_class).unwrap_or(UsbDeviceClass::Unknown)
}
pub fn protocol(&self) -> UsbDeviceProtocol {
UsbDeviceProtocol::try_from(self.interface_protocol).unwrap_or(UsbDeviceProtocol::Unknown)
}
}
// impl UsbInterfaceDescriptor {
// pub fn class(&self) -> UsbDeviceClass {
// UsbDeviceClass::try_from(self.interface_class).unwrap_or(UsbDeviceClass::Unknown)
// }
//
// pub fn protocol(&self) -> UsbDeviceProtocol {
// UsbDeviceProtocol::try_from(self.interface_protocol).unwrap_or(UsbDeviceProtocol::Unknown)
// }
// }
//
impl UsbEndpointDescriptor {
pub fn direction(&self) -> UsbDirection {
match self.endpoint_address >> 7 {
@@ -149,16 +125,16 @@ impl UsbEndpointDescriptor {
}
}
}
//
impl UsbDeviceDescriptor {
// pub fn class(&self) -> UsbDeviceClass {
// UsbDeviceClass::try_from(self.device_class).unwrap_or(UsbDeviceClass::Unknown)
// }
//
// pub fn protocol(&self) -> UsbDeviceProtocol {
// UsbDeviceProtocol::try_from(self.device_protocol).unwrap_or(UsbDeviceProtocol::Unknown)
// }
//
pub fn class(&self) -> UsbDeviceClass {
UsbDeviceClass::try_from(self.device_class).unwrap_or(UsbDeviceClass::Unknown)
}
pub fn protocol(&self) -> UsbDeviceProtocol {
UsbDeviceProtocol::try_from(self.device_protocol).unwrap_or(UsbDeviceProtocol::Unknown)
}
pub fn max_packet_size(&self, version: UsbVersion, speed: UsbSpeed) -> Result<usize, UsbError> {
match (version.is_version_3(), speed, self.max_packet_size_0) {
(true, UsbSpeed::Super, 9) => Ok(1 << 9),
+127 -282
View File
@@ -1,27 +1,15 @@
use core::{any::Any, fmt, ops::Deref};
use core::{fmt, ops::Deref};
use alloc::{
boxed::Box,
string::String,
sync::{Arc, Weak},
vec::Vec,
};
use alloc::{boxed::Box, sync::Arc, vec::Vec};
use async_trait::async_trait;
use libk::{
error::Error,
fs::sysfs::{
self,
attribute::{StringAttribute, StringAttributeOps},
object::KObject,
},
};
use libk_util::OneTimeInit;
use libk_util::sync::spin_rwlock::{IrqSafeRwLock, IrqSafeRwLockReadGuard};
use crate::{
descriptor::{UsbDeviceDescriptor, UsbHubDescriptorHeader},
error::UsbError,
host::UsbHostController,
info::{PortString, UsbConfigurationInfo, UsbEndpointInfo, UsbEndpointType, UsbInterfaceInfo},
info::{
UsbConfigurationInfo, UsbDeviceInfo, UsbEndpointInfo, UsbEndpointType, UsbInterfaceInfo,
UsbVersion,
},
pipe::{
control::{ConfigurationDescriptorEntry, UsbControlPipeAccess},
normal::{
@@ -29,10 +17,10 @@ use crate::{
UsbNormalPipeOut,
},
},
UsbHostController,
};
// High-level structures for info provided through descriptors
type UsbDeviceKObject = KObject<Weak<UsbDeviceAccess>>;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct UsbBusAddress {
@@ -40,28 +28,10 @@ pub struct UsbBusAddress {
pub device: u8,
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct UsbInterfaceAddress {
pub bus: UsbBusAddress,
pub interface: u8,
}
pub struct UsbDeviceAccess {
pub device: Arc<dyn UsbDevice>,
pub device_descriptor: UsbDeviceDescriptor,
pub product_str: Option<String>,
pub vendor_str: Option<String>,
pub configuration0_info: UsbConfigurationInfo,
kobject: OneTimeInit<Arc<UsbDeviceKObject>>,
}
// USB device, limited in scope by one interface
#[derive(Clone)]
pub struct UsbInterfaceAccess {
device: Arc<UsbDeviceAccess>,
interface_index: u8,
endpoint_start_index: u8,
pub info: UsbDeviceInfo,
pub current_configuration: IrqSafeRwLock<Option<UsbConfigurationInfo>>,
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
@@ -72,9 +42,8 @@ pub enum UsbSpeed {
Super,
}
#[async_trait]
pub trait UsbDeviceDetachHandler: Send + Sync {
async fn handle_device_detach(&self);
fn handle_device_detach(&self);
}
#[async_trait]
@@ -97,231 +66,66 @@ pub trait UsbDevice: Send + Sync {
ty: UsbEndpointType,
) -> Result<Box<dyn UsbNormalPipeOut>, UsbError>;
async fn configure_hub(&self, hub_descriptor: &UsbHubDescriptorHeader) -> Result<(), UsbError>;
// fn port_number(&self) -> u8;
fn port_string(&self) -> &PortString;
fn port_number(&self) -> u8;
fn bus_address(&self) -> UsbBusAddress;
fn speed(&self) -> UsbSpeed;
fn host_controller(&self) -> Arc<dyn UsbHostController>;
fn as_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync>;
fn controller_ref(&self) -> &dyn UsbHostController;
fn set_detach_handler(&self, handler: Arc<dyn UsbDeviceDetachHandler>);
async fn handle_detach(&self);
fn handle_detach(&self);
fn debug(&self) {}
}
impl UsbDeviceAccess {
fn usb_kobject() -> Option<&'static Arc<KObject<()>>> {
static USB_KOBJECT: OneTimeInit<Arc<KObject<()>>> = OneTimeInit::new();
USB_KOBJECT.or_init_with_opt(|| {
let bus_kobject = sysfs::bus()?;
let usb_kobject = KObject::new(());
bus_kobject.add_object("usb", usb_kobject.clone()).ok()?;
Some(usb_kobject)
})
}
fn setup_kobject(self: &Arc<Self>) -> Result<(), Error> {
struct Id;
struct DeviceClass;
struct VendorString;
struct ProductString;
impl StringAttributeOps for Id {
type Data = Weak<UsbDeviceAccess>;
const NAME: &'static str = "id";
fn read(state: &Self::Data) -> Result<String, Error> {
let state = state.upgrade().ok_or(Error::InvalidOperation)?;
let id_product = state.device_descriptor.id_product;
let id_vendor = state.device_descriptor.id_vendor;
Ok(alloc::format!("{id_vendor:04x}:{id_product:04x}",))
}
}
impl StringAttributeOps for DeviceClass {
type Data = Weak<UsbDeviceAccess>;
const NAME: &'static str = "device_class";
fn read(state: &Self::Data) -> Result<String, Error> {
let state = state.upgrade().ok_or(Error::InvalidOperation)?;
Ok(alloc::format!(
"{:02x}:{:02x}:{:02x}",
state.device_descriptor.device_class,
state.device_descriptor.device_subclass,
state.device_descriptor.device_protocol
))
}
}
impl StringAttributeOps for VendorString {
type Data = Weak<UsbDeviceAccess>;
const NAME: &'static str = "vendor_str";
fn read(state: &Self::Data) -> Result<String, Error> {
let state = state.upgrade().ok_or(Error::InvalidOperation)?;
if let Some(vendor_str) = state.vendor_str.as_ref() {
Ok(vendor_str.clone())
} else {
Ok(String::new())
}
}
}
impl StringAttributeOps for ProductString {
type Data = Weak<UsbDeviceAccess>;
const NAME: &'static str = "product_str";
fn read(state: &Self::Data) -> Result<String, Error> {
let state = state.upgrade().ok_or(Error::InvalidOperation)?;
if let Some(product_str) = state.product_str.as_ref() {
Ok(product_str.clone())
} else {
Ok(String::new())
}
}
}
let usb_kobject = Self::usb_kobject().ok_or(Error::DoesNotExist)?;
let dev_kobject = KObject::new(Arc::downgrade(self));
dev_kobject.add_attribute(StringAttribute::from(Id)).ok();
dev_kobject
.add_attribute(StringAttribute::from(DeviceClass))
.ok();
dev_kobject
.add_attribute(StringAttribute::from(ProductString))
.ok();
dev_kobject
.add_attribute(StringAttribute::from(VendorString))
.ok();
let name = alloc::format!("{}", self.device.bus_address());
usb_kobject.add_object(name, dev_kobject.clone())?;
self.kobject.init(dev_kobject);
Ok(())
}
/// Expected device state:
///
/// * Link-layer stuff has been reset and established properly by the HCD
/// * Device is not yet configured
/// * Control pipe for the device has been properly set up
/// * Device has been assigned a bus address
pub async fn setup(raw: Arc<dyn UsbDevice>) -> Result<Arc<Self>, UsbError> {
let control_pipe = raw.control_pipe();
let device_descriptor = control_pipe.query_device_descriptor().await?;
if device_descriptor.num_configurations < 1 {
return Err(UsbError::InvalidDescriptorField);
}
let config_descriptor = control_pipe.query_configuration_descriptor(0).await?;
pub async fn setup(raw: Arc<dyn UsbDevice>) -> Result<Self, UsbError> {
let control = raw.control_pipe();
// Use configuration 0
control_pipe
.set_configuration(config_descriptor.configuration().config_val as _)
.await?;
let device_desc = control.query_device_descriptor().await?;
let vendor_str = control_pipe
.query_string(device_descriptor.manufacturer_str)
.await
.inspect_err(|e| {
log::warn!(
"{}: manufacturer string query error: {:?}",
let bcd_usb = device_desc.bcd_usb;
let usb_version = UsbVersion::from_bcd_usb(device_desc.bcd_usb)
.ok_or(UsbError::InvalidDescriptorField)
.inspect_err(|_| {
log::error!(
"{}: unsupported/invalid USB version: {:#x}",
raw.bus_address(),
e
bcd_usb
)
})
.ok();
let product_str = control_pipe
.query_string(device_descriptor.product_str)
.await
.inspect_err(|e| {
log::warn!("{}: product string query error: {:?}", raw.bus_address(), e)
})
.ok();
})?;
// Extract configuration 0 information
// let query = control_pipe.query_configuration_descriptor(index).await?;
let manufacturer = control.query_string(device_desc.manufacturer_str).await?;
let product = control.query_string(device_desc.product_str).await?;
let configuration_name = control_pipe
.query_string(config_descriptor.configuration().config_str)
.await
.ok();
let info = UsbDeviceInfo {
manufacturer,
product,
usb_version,
let mut endpoints = Vec::new();
let mut interfaces = Vec::new();
id_vendor: device_desc.id_vendor,
id_product: device_desc.id_product,
for desc in config_descriptor.descriptors() {
match desc {
ConfigurationDescriptorEntry::Interface(iface) => {
let name = control_pipe.query_string(iface.interface_str).await.ok();
interfaces.push(UsbInterfaceInfo {
name,
number: iface.interface_number,
num_endpoints: iface.num_endpoints,
device_class: device_desc.class(),
device_subclass: device_desc.device_subclass,
device_protocol: device_desc.protocol(),
device_protocol_number: device_desc.device_protocol,
interface_class: iface.interface_class,
interface_subclass: iface.interface_subclass,
interface_protocol: iface.interface_protocol,
});
}
ConfigurationDescriptorEntry::Endpoint(ep) => {
endpoints.push(UsbEndpointInfo {
number: ep.number(),
direction: ep.direction(),
max_packet_size: ep.max_packet_size as _,
ty: ep.transfer_type(),
});
}
_ => (),
}
}
num_configurations: device_desc.num_configurations,
interfaces.sort_by_key(|r| r.number);
endpoints.sort_by_key(|r| r.number);
let configuration0_info = UsbConfigurationInfo {
name: configuration_name,
config_value: config_descriptor.configuration().config_val,
interfaces,
endpoints,
max_packet_size: device_desc.max_packet_size(usb_version, raw.speed())?,
};
let device = Arc::new(Self {
Ok(Self {
device: raw,
device_descriptor,
product_str,
vendor_str,
configuration0_info,
kobject: OneTimeInit::new(),
});
if let Err(error) = device.setup_kobject() {
log::error!(
"{} kobject setup error: {:?}",
device.device.bus_address(),
error
);
}
Ok(device)
}
pub fn interface(self: &Arc<Self>, interface_index: u8) -> UsbInterfaceAccess {
let endpoint_start_index = self
.configuration0_info
.interfaces
.iter()
.take(interface_index as usize)
.map(|r| r.num_endpoints)
.sum();
UsbInterfaceAccess {
device: self.clone(),
interface_index,
endpoint_start_index,
}
info,
current_configuration: IrqSafeRwLock::new(None),
})
}
pub async fn open_interrupt_in_pipe(
@@ -360,6 +164,90 @@ impl UsbDeviceAccess {
Ok(UsbBulkOutPipeAccess(pipe))
}
pub fn read_current_configuration(
&self,
) -> IrqSafeRwLockReadGuard<'_, Option<UsbConfigurationInfo>> {
self.current_configuration.read()
}
pub async fn select_configuration<F: Fn(&UsbConfigurationInfo) -> bool>(
&self,
predicate: F,
) -> Result<Option<UsbConfigurationInfo>, UsbError> {
let mut current_config = self.current_configuration.write();
let control_pipe = self.control_pipe();
for i in 0..self.info.num_configurations {
let info = self.query_configuration_info(i).await?;
if predicate(&info) {
log::debug!("Selected configuration: {:#?}", info);
let config = current_config.insert(info);
control_pipe
.set_configuration(config.config_value as _)
.await?;
return Ok(Some(config.clone()));
}
}
Ok(None)
}
pub async fn query_configuration_info(
&self,
index: u8,
) -> Result<UsbConfigurationInfo, UsbError> {
if index >= self.info.num_configurations {
return Err(UsbError::InvalidConfiguration);
}
let control_pipe = self.control_pipe();
let query = control_pipe.query_configuration_descriptor(index).await?;
let configuration_name = control_pipe
.query_string(query.configuration().config_str)
.await?;
let mut endpoints = Vec::new();
let mut interfaces = Vec::new();
for desc in query.descriptors() {
match desc {
ConfigurationDescriptorEntry::Endpoint(ep) => {
endpoints.push(UsbEndpointInfo {
number: ep.number(),
direction: ep.direction(),
max_packet_size: ep.max_packet_size as _,
ty: ep.transfer_type(),
});
}
ConfigurationDescriptorEntry::Interface(iface) => {
let name = control_pipe.query_string(iface.interface_str).await?;
interfaces.push(UsbInterfaceInfo {
name,
number: iface.interface_number,
interface_class: iface.class(),
interface_subclass: iface.interface_subclass,
interface_protocol: iface.protocol(),
interface_protocol_number: iface.interface_protocol,
});
}
_ => (),
}
}
let info = UsbConfigurationInfo {
name: configuration_name,
config_value: query.configuration().config_val,
interfaces,
endpoints,
};
Ok(info)
}
pub fn set_detach_handler(&self, handler: Arc<dyn UsbDeviceDetachHandler>) {
self.device.set_detach_handler(handler);
}
@@ -378,46 +266,3 @@ impl fmt::Display for UsbBusAddress {
write!(f, "{}:{}", self.bus, self.device)
}
}
impl fmt::Display for UsbInterfaceAddress {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}.{}", self.bus, self.interface)
}
}
impl UsbInterfaceAccess {
fn interface_info(&self) -> &UsbInterfaceInfo {
&self.device.configuration0_info.interfaces[self.interface_index as usize]
}
pub fn number(&self) -> u8 {
self.interface_index
}
pub fn endpoints(&self) -> &[UsbEndpointInfo] {
let info = self.interface_info();
let start = self.endpoint_start_index as usize;
let end = start + info.num_endpoints as usize;
&self.device.configuration0_info.endpoints[start..end]
}
pub fn device(&self) -> &Arc<UsbDeviceAccess> {
&self.device
}
pub fn address(&self) -> UsbInterfaceAddress {
UsbInterfaceAddress {
bus: self.device.bus_address(),
interface: self.interface_index,
}
}
pub fn class(&self) -> (u8, u8, u8) {
let i = self.interface_info();
(
i.interface_class,
i.interface_subclass,
i.interface_protocol,
)
}
}
+1 -6
View File
@@ -7,7 +7,6 @@ pub enum TransferError {
BufferError,
UsbTransactionError,
Stall,
Shutdown,
Other(u8),
}
@@ -30,17 +29,13 @@ pub enum UsbError {
DeviceBusy,
DeviceDisconnected,
TransferFailed(TransferError),
TruncatedDescriptor(usize, usize),
// Driver errors
DriverError,
}
impl From<TransferError> for UsbError {
fn from(value: TransferError) -> Self {
match value {
TransferError::Shutdown => Self::DeviceDisconnected,
value => Self::TransferFailed(value),
}
Self::TransferFailed(value)
}
}
-20
View File
@@ -1,20 +0,0 @@
use alloc::{boxed::Box, sync::Arc};
use async_trait::async_trait;
use device_api::device::Device;
use crate::{
device::{UsbDeviceAccess, UsbSpeed},
error::UsbError,
info::PortString,
};
#[async_trait]
pub trait UsbHostController: Device + Sync + Send {
async fn setup_hub_device(
self: Arc<Self>,
hub: Arc<UsbDeviceAccess>,
port_string: PortString,
usb_speed: UsbSpeed,
) -> Result<(), UsbError>;
async fn disconnect_device(self: Arc<Self>, port_string: PortString) -> Result<(), UsbError>;
}
+42 -66
View File
@@ -1,6 +1,7 @@
use core::{fmt, num::NonZeroU8};
use core::fmt;
use alloc::{string::String, vec::Vec};
use yggdrasil_abi::primitive_enum;
use crate::communication::UsbDirection;
@@ -38,21 +39,31 @@ pub enum UsbVersion {
Usb32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct PortString(u64);
primitive_enum! {
pub enum UsbDeviceClass: u8 {
FromInterface = 0x00,
Hid = 0x03,
MassStorage = 0x08,
Unknown = 0xFF,
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PortStringIter(u64);
primitive_enum! {
pub enum UsbDeviceProtocol: u8 {
FromInterface = 0x00,
Unknown = 0xFF,
}
}
#[derive(Debug, Clone)]
pub struct UsbInterfaceInfo {
pub name: Option<String>,
pub name: String,
pub number: u8,
pub num_endpoints: u8,
pub interface_class: u8,
pub interface_class: UsbDeviceClass,
pub interface_subclass: u8,
pub interface_protocol: u8,
pub interface_protocol: UsbDeviceProtocol,
pub interface_protocol_number: u8,
}
#[derive(Debug, Clone)]
@@ -65,12 +76,33 @@ pub struct UsbEndpointInfo {
#[derive(Debug, Clone)]
pub struct UsbConfigurationInfo {
pub name: Option<String>,
pub name: String,
pub config_value: u8,
pub interfaces: Vec<UsbInterfaceInfo>,
pub endpoints: Vec<UsbEndpointInfo>,
}
#[derive(Debug, Clone)]
pub struct UsbDeviceInfo {
pub manufacturer: String,
pub product: String,
pub usb_version: UsbVersion,
pub id_vendor: u16,
pub id_product: u16,
pub device_class: UsbDeviceClass,
pub device_subclass: u8,
pub device_protocol: UsbDeviceProtocol,
pub device_protocol_number: u8,
/// Max packet size for endpoint zero
pub max_packet_size: usize,
pub num_configurations: u8,
}
impl UsbVersion {
pub fn is_version_3(&self) -> bool {
matches!(self, Self::Usb30 | Self::Usb31 | Self::Usb32)
@@ -119,59 +151,3 @@ impl UsbConfigurationInfo {
Some((index as u8 + 1, info))
}
}
impl PortString {
pub const fn new_root_port(root_hub_port_number: NonZeroU8) -> Self {
Self(root_hub_port_number.get() as u64)
}
pub const fn root_hub_port_number(&self) -> NonZeroU8 {
unsafe { NonZeroU8::new_unchecked((self.0 & 0xF) as u8) }
}
pub fn append(mut self, port: NonZeroU8) -> Self {
for i in 0..16 {
let pos = i * 4;
if (self.0 >> pos) & 0xF == 0 {
self.0 |= (port.get() as u64) << pos;
return self;
}
}
panic!("Port route string too long");
}
pub fn parent_hub_port_number(&self) -> Option<NonZeroU8> {
self.iter().last()
}
pub const fn raw(&self) -> u64 {
self.0
}
pub fn iter(&self) -> PortStringIter {
PortStringIter(self.0)
}
}
impl fmt::Display for PortString {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "<port ")?;
for (i, port) in self.iter().enumerate() {
if i != 0 {
write!(f, ".")?;
}
write!(f, "{port}")?;
}
write!(f, ">")
}
}
impl Iterator for PortStringIter {
type Item = NonZeroU8;
fn next(&mut self) -> Option<Self::Item> {
let port = NonZeroU8::new((self.0 & 0xF) as u8)?;
self.0 >>= 4;
Some(port)
}
}
+6 -5
View File
@@ -1,11 +1,11 @@
#![no_std]
#![allow(clippy::new_without_default, incomplete_features)]
#![allow(clippy::new_without_default)]
#![feature(
generic_const_exprs,
iter_array_chunks,
maybe_uninit_slice,
maybe_uninit_as_bytes,
maybe_uninit_fill,
maybe_uninit_array_assume_init
maybe_uninit_write_slice,
maybe_uninit_fill
)]
extern crate alloc;
@@ -15,7 +15,6 @@ pub mod communication;
pub mod descriptor;
pub mod device;
pub mod error;
pub mod host;
pub mod info;
pub mod pipe;
pub mod util;
@@ -25,3 +24,5 @@ pub mod class_driver;
// pub use communication::{UsbControlTransfer, UsbDirection, UsbTransferStatus, UsbTransferToken};
pub trait UsbEndpoint: Sync {}
pub trait UsbHostController: Sync + Send {}
+9 -23
View File
@@ -1,5 +1,5 @@
use core::{
mem::{MaybeUninit, size_of},
mem::{size_of, MaybeUninit},
ops::Deref,
};
@@ -10,8 +10,8 @@ use libk_mm::PageBox;
use crate::{
descriptor::{
UsbConfigurationDescriptor, UsbDeviceDescriptor, UsbDeviceDescriptor0, UsbDeviceQualifier,
UsbEndpointDescriptor, UsbInterfaceDescriptor, UsbOtherSpeedConfiguration,
UsbConfigurationDescriptor, UsbDeviceDescriptor, UsbDeviceQualifier, UsbEndpointDescriptor,
UsbInterfaceDescriptor, UsbOtherSpeedConfiguration,
},
error::UsbError,
};
@@ -34,6 +34,11 @@ pub trait UsbDeviceRequest: Sized + Pod {
const B_REQUEST: u8;
}
pub trait UsbClassSpecificRequest: Sized + Pod {
const BM_REQUEST_TYPE: u8;
const B_REQUEST: u8;
}
pub trait UsbDescriptorRequest: UsbDeviceRequest {
const DESCRIPTOR_TYPE: u8;
}
@@ -61,7 +66,7 @@ impl<U: UsbDescriptorRequest> UsbDeviceRequest for U {
}
fn decode_usb_string(bytes: &[u8]) -> Result<String, UsbError> {
if !bytes.len().is_multiple_of(2) {
if bytes.len() % 2 != 0 {
return Err(UsbError::InvalidDescriptorField);
}
@@ -172,25 +177,6 @@ impl ConfigurationDescriptorQuery {
}
impl UsbControlPipeAccess {
pub async fn query_device_descriptor_0(&self) -> Result<UsbDeviceDescriptor0, UsbError> {
assert_eq!(size_of::<UsbDeviceDescriptor0>(), 8);
let mut buffer = MaybeUninit::uninit();
self.control_transfer_in(
ControlTransferSetup {
bm_request_type: 0b10000000,
b_request: 0x06,
w_value: 0x100,
w_index: 0,
w_length: size_of::<UsbDeviceDescriptor0>() as _,
},
buffer.as_bytes_mut(),
)
.await?;
Ok(unsafe { buffer.assume_init() })
}
pub async fn query_device_descriptor(&self) -> Result<UsbDeviceDescriptor, UsbError> {
let mut buffer = MaybeUninit::uninit();
+1 -1
View File
@@ -18,7 +18,7 @@ use libk::{
use walk::{DirentIter, DirentIterMut};
use yggdrasil_abi::io::{DirectoryEntry, FileType};
use crate::{Dirent, Ext2Fs, Inode, file::RegularNode, inode::InodeAccess, symlink::SymlinkNode};
use crate::{file::RegularNode, inode::InodeAccess, symlink::SymlinkNode, Dirent, Ext2Fs, Inode};
mod walk;
+1 -1
View File
@@ -9,7 +9,7 @@ use yggdrasil_abi::{
util::FixedString,
};
use crate::{Dirent, Ext2Fs, access::InodeBlock, data::FsRequiredFeatures};
use crate::{access::InodeBlock, data::FsRequiredFeatures, Dirent, Ext2Fs};
use super::DirentName;
+1 -1
View File
@@ -8,7 +8,7 @@ use libk::{
};
use yggdrasil_abi::io::OpenOptions;
use crate::{Ext2Fs, inode::InodeAccess};
use crate::{inode::InodeAccess, Ext2Fs};
pub struct RegularNode {
fs: Arc<Ext2Fs>,
+2 -2
View File
@@ -15,8 +15,8 @@ use yggdrasil_abi::{
};
use crate::{
Ext2Fs, Inode, access::InodeBlock, data::InodeMode, dir::DirectoryNode, file::RegularNode,
symlink::SymlinkNode,
access::InodeBlock, data::InodeMode, dir::DirectoryNode, file::RegularNode,
symlink::SymlinkNode, Ext2Fs, Inode,
};
pub struct InodeHolder {
+1 -1
View File
@@ -4,8 +4,8 @@ use libk::error::Error;
use yggdrasil_abi::io::FileType;
use crate::{
data::{FsReadonlyFeatures, DIRECT_BLOCK_COUNT},
Ext2Fs, Inode,
data::{DIRECT_BLOCK_COUNT, FsReadonlyFeatures},
};
pub mod cache;
+2 -2
View File
@@ -9,12 +9,12 @@ use core::mem;
use alloc::{boxed::Box, sync::Arc};
use async_trait::async_trait;
use bytemuck::Zeroable;
use data::{DIRECT_BLOCK_COUNT, FsReadonlyFeatures, FsRequiredFeatures};
use data::{FsReadonlyFeatures, FsRequiredFeatures, DIRECT_BLOCK_COUNT};
use dir::DirectoryNode;
use file::RegularNode;
use inode::{InodeAccess, InodeCache};
use libk::{
device::block::{BlockDevice, cache::DeviceMapper},
device::block::{cache::DeviceMapper, BlockDevice},
error::Error,
vfs::{Filesystem, FilesystemMountOption, NodeRef},
};
+1 -1
View File
@@ -8,7 +8,7 @@ use libk::{
};
use libk_util::sync::spin_rwlock::IrqSafeRwLock;
use crate::{Ext2Fs, Inode, inode::InodeAccess};
use crate::{inode::InodeAccess, Ext2Fs, Inode};
pub struct SymlinkNode {
fs: Arc<Ext2Fs>,
+4 -5
View File
@@ -1,10 +1,9 @@
use core::{any::Any, fmt, mem::MaybeUninit};
use alloc::{sync::Arc, vec};
use alloc::sync::Arc;
use libk::{
block,
error::Error,
task::sync::AsyncMutex,
vfs::{
CommonImpl, CreateInfo, DirectoryImpl, DirectoryOpenPosition, Filename, Metadata, Node,
NodeFlags, NodeRef,
@@ -12,7 +11,7 @@ use libk::{
};
use libk_util::{
get_le_u16, get_le_u32,
string::{Utf16LeStr, chars_equal_ignore_case},
string::{chars_equal_ignore_case, Utf16LeStr},
};
use yggdrasil_abi::{
io::{DirectoryEntry, FileMode, GroupId, UserId},
@@ -21,9 +20,9 @@ use yggdrasil_abi::{
};
use crate::{
Fat32Fs,
data::{ClusterNumber, FatStr},
file::FileNode,
Fat32Fs,
};
pub const DIRENT_SIZE: usize = 32;
@@ -282,10 +281,10 @@ impl DirectoryNode {
} else {
let file = FileNode {
fs: self.fs.clone(),
cluster,
size_bytes: size,
parent: Some(self.cluster),
metadata,
cluster_chain_cache: AsyncMutex::new(vec![cluster]),
};
Ok(Node::regular(
+33 -18
View File
@@ -1,6 +1,6 @@
use core::any::Any;
use alloc::{sync::Arc, vec::Vec};
use alloc::{sync::Arc, vec, vec::Vec};
use libk::{
block,
error::Error,
@@ -9,26 +9,32 @@ use libk::{
};
use yggdrasil_abi::io::OpenOptions;
use crate::{Fat32Fs, data::ClusterNumber};
use crate::{data::ClusterNumber, Fat32Fs};
pub struct FileNode {
pub(crate) fs: Arc<Fat32Fs>,
pub(crate) cluster: ClusterNumber,
pub(crate) size_bytes: u32,
pub(crate) metadata: Metadata,
// Will be used when metadata needs to be updated
#[allow(unused)]
pub(crate) parent: Option<ClusterNumber>,
pub(crate) cluster_chain_cache: AsyncMutex<Vec<ClusterNumber>>,
}
impl FileNode {
async fn fetch_cluster_number(
&self,
file: &FileNode,
cluster_index: usize,
) -> Result<ClusterNumber, Error> {
let mut chain = self.cluster_chain_cache.lock().await;
// TODO use a "sliding window" to minimize memory usage when working with large files?
struct OpenedFile {
cluster_chain: AsyncMutex<Vec<ClusterNumber>>,
}
impl OpenedFile {
fn new(first_cluster: ClusterNumber) -> Self {
Self {
cluster_chain: AsyncMutex::new(vec![first_cluster]),
}
}
async fn seek(&self, file: &FileNode, cluster_index: usize) -> Result<ClusterNumber, Error> {
let mut chain = self.cluster_chain.lock().await;
if cluster_index >= chain.len() {
let last = *chain.last().unwrap();
file.fs
@@ -41,8 +47,15 @@ impl FileNode {
Ok(chain[cluster_index])
}
}
async fn read_inner(&self, mut pos: u64, buffer: &mut [u8]) -> Result<usize, Error> {
impl FileNode {
async fn read_inner(
&self,
instance: &OpenedFile,
mut pos: u64,
buffer: &mut [u8],
) -> Result<usize, Error> {
if pos >= self.size_bytes as u64 {
return Ok(0);
}
@@ -60,9 +73,7 @@ impl FileNode {
let offset_in_sector = (pos % bps) as usize;
let amount = rem.min(bps as usize - offset_in_sector);
let cluster = self
.fetch_cluster_number(self, cluster_index as usize)
.await?;
let cluster = instance.seek(self, cluster_index as usize).await?;
self.fs
.with_cluster_sector(cluster, sector_in_cluster, |data| {
@@ -108,7 +119,8 @@ impl RegularImpl for FileNode {
if opts.contains_any(OpenOptions::TRUNCATE | OpenOptions::APPEND | OpenOptions::WRITE) {
return Err(Error::ReadOnly);
}
Ok((0, None))
let instance = Arc::new(OpenedFile::new(self.cluster));
Ok((0, Some(instance)))
}
fn close(&self, _node: &NodeRef, _instance: Option<&InstanceData>) -> Result<(), Error> {
@@ -118,11 +130,14 @@ impl RegularImpl for FileNode {
fn read(
&self,
_node: &NodeRef,
_instance: Option<&InstanceData>,
instance: Option<&InstanceData>,
pos: u64,
buf: &mut [u8],
) -> Result<usize, Error> {
block!(self.read_inner(pos, buf).await)?
let instance = instance
.and_then(|p| p.downcast_ref::<OpenedFile>())
.ok_or(Error::InvalidFile)?;
block!(self.read_inner(instance, pos, buf).await)?
}
fn write(
+1 -1
View File
@@ -5,7 +5,7 @@ use async_trait::async_trait;
use data::{Bpb, ClusterNumber, Fat32Ebpb, Fat32FsInfo};
use directory::DirectoryNode;
use libk::{
device::block::{BlockDevice, cache::DeviceMapper},
device::block::{cache::DeviceMapper, BlockDevice},
error::Error,
vfs::{Filesystem, FilesystemMountOption, Metadata, Node, NodeFlags, NodeRef},
};
-1
View File
@@ -1 +0,0 @@
+1 -1
View File
@@ -1,7 +1,7 @@
//! Block management interfaces and structures
use core::{
marker::PhantomData,
mem::{MaybeUninit, size_of},
mem::{size_of, MaybeUninit},
ops::{Deref, DerefMut},
ptr::NonNull,
};
+3 -3
View File
@@ -3,12 +3,12 @@ use core::sync::atomic::Ordering;
use alloc::sync::Arc;
use libk::vfs::{
CommonImpl, CreateFileType, CreateInfo, DirectoryImpl, DirectoryOpenPosition, Metadata, Node,
NodeFlags, NodeRef, impls::fixed_path_symlink_ext,
impls::fixed_path_symlink_ext, CommonImpl, CreateFileType, CreateInfo, DirectoryImpl,
DirectoryOpenPosition, Metadata, Node, NodeFlags, NodeRef,
};
use yggdrasil_abi::error::Error;
use crate::{INO_COUNTER, MemoryFilesystem, block::BlockAllocator, file::FileNode};
use crate::{block::BlockAllocator, file::FileNode, MemoryFilesystem, INO_COUNTER};
pub(crate) struct DirectoryNode<A: BlockAllocator> {
fs: Arc<MemoryFilesystem<A>>,
+2 -2
View File
@@ -2,10 +2,10 @@ use alloc::sync::Arc;
use core::any::Any;
use libk::vfs::{CommonImpl, InstanceData, Metadata, Node, NodeFlags, NodeRef, RegularImpl};
use libk_util::sync::{IrqSafeSpinlock, spin_rwlock::IrqSafeRwLock};
use libk_util::sync::{spin_rwlock::IrqSafeRwLock, IrqSafeSpinlock};
use yggdrasil_abi::{error::Error, io::OpenOptions};
use crate::{MemoryFilesystem, block::BlockAllocator, bvec::BVec};
use crate::{block::BlockAllocator, bvec::BVec, MemoryFilesystem};
pub(crate) struct FileNode<A: BlockAllocator> {
pub(crate) data: IrqSafeSpinlock<BVec<'static, A>>,
+13 -34
View File
@@ -13,14 +13,13 @@ use alloc::sync::Arc;
use block::BlockAllocator;
use dir::DirectoryNode;
use file::FileNode;
use libk::vfs::{AccessToken, Filename, Filesystem, Metadata, NodeRef, impls::fixed_path_symlink};
use libk::vfs::{impls::fixed_path_symlink, AccessToken, Filename, Filesystem, Metadata, NodeRef};
use libk_util::sync::IrqSafeSpinlock;
use tar::TarEntry;
use yggdrasil_abi::{
error::Error,
io::{FileMode, FileType, GroupId, UserId},
path::Path,
time::SystemTime,
};
use crate::tar::TarIterator;
@@ -76,7 +75,6 @@ impl<A: BlockAllocator> MemoryFilesystem<A> {
path: &Path,
create: bool,
mode: FileMode,
mtime: SystemTime,
) -> Result<NodeRef, Error> {
let access = unsafe { AccessToken::authorized() };
if path.is_empty() {
@@ -99,18 +97,7 @@ impl<A: BlockAllocator> MemoryFilesystem<A> {
}
let ino = INO_COUNTER.fetch_add(1, Ordering::Relaxed);
let metadata = Metadata {
uid: UserId::root(),
gid: GroupId::root(),
atime: mtime,
ctime: mtime,
mode,
mtime,
inode: Some(ino),
block_size: 512,
block_count: 0,
};
let node = DirectoryNode::<A>::new(self.clone(), metadata);
let node = DirectoryNode::<A>::new(self.clone(), Metadata::now_root(mode, ino));
at.add_child(filename, node.clone())?;
node
@@ -125,7 +112,7 @@ impl<A: BlockAllocator> MemoryFilesystem<A> {
Ok(node)
} else {
assert!(node.is_directory());
self.make_path(&node, rest, create, mode, mtime)
self.make_path(&node, rest, create, mode)
}
}
@@ -133,22 +120,16 @@ impl<A: BlockAllocator> MemoryFilesystem<A> {
let kind = hdr.node_kind();
let mode = usize::from(&hdr.mode);
let mode = FileMode::new(0o777 & (mode as u32));
let mtime = SystemTime::new(usize::from(&hdr.mtime) as u64, 0);
let ino = INO_COUNTER.fetch_add(1, Ordering::Relaxed);
let metadata = Metadata {
uid: UserId::root(),
gid: GroupId::root(),
atime: mtime,
ctime: mtime,
mode,
mtime,
inode: Some(ino),
block_size: 512,
block_count: usize::from(&hdr.size).div_ceil(512) as u64,
};
match kind {
FileType::File => Ok(FileNode::<A>::new(self.clone(), metadata)),
FileType::Directory => Ok(DirectoryNode::<A>::new(self.clone(), metadata)),
FileType::File => Ok(FileNode::<A>::new(
self.clone(),
Metadata::now_root(mode, ino),
)),
FileType::Directory => Ok(DirectoryNode::<A>::new(
self.clone(),
Metadata::now_root(mode, ino),
)),
FileType::Symlink => {
let target = hdr.symlink_target()?;
Ok(fixed_path_symlink(target))
@@ -168,10 +149,9 @@ impl<A: BlockAllocator> MemoryFilesystem<A> {
};
let path = Path::from_str(hdr.name.as_str()?.trim_matches('/'));
let mtime = SystemTime::new(usize::from(&hdr.mtime) as u64, 0);
let (dirname, filename) = path.split_right();
let parent = self.make_path(&root, dirname, true, FileMode::new(0o755), mtime)?;
let parent = self.make_path(&root, dirname, true, FileMode::new(0o755))?;
let node = self.create_node_initial(hdr)?;
let filename = Filename::new(filename)?;
@@ -184,9 +164,8 @@ impl<A: BlockAllocator> MemoryFilesystem<A> {
panic!("Unreachable");
};
let mtime = SystemTime::new(usize::from(&hdr.mtime) as u64, 0);
let path = Path::from_str(hdr.name.as_str()?.trim_matches('/'));
let node = self.make_path(&root, path, false, FileMode::empty(), mtime)?;
let node = self.make_path(&root, path, false, FileMode::empty())?;
assert_eq!(node.ty(), hdr.node_kind());
let uid = unsafe { UserId::from_raw(usize::from(&hdr.uid) as u32) };
-1
View File
@@ -1 +0,0 @@
+1 -1
View File
@@ -23,7 +23,7 @@ pub(crate) struct TarEntry {
pub uid: OctalField<8>,
pub gid: OctalField<8>,
pub size: OctalField<12>,
pub mtime: OctalField<12>,
_mtime: OctalField<12>,
_checksum: OctalField<8>,
type_: u8,
link_name: TarString<100>,
+9 -83
View File
@@ -8,20 +8,15 @@ use alloc::{boxed::Box, sync::Arc};
use async_trait::async_trait;
use device_api::device::Device;
use libk::{device::char::CharDevice, vfs::FileReadiness};
use libk_util::{OneTimeInit, ring::LossyRingQueue};
use yggdrasil_abi::{
error::Error,
io::{KeyboardKeyEvent, MouseEvent},
};
use libk_util::{ring::LossyRingQueue, OneTimeInit};
use yggdrasil_abi::{error::Error, io::KeyboardKeyEvent};
#[derive(Clone, Copy)]
pub struct KeyboardDevice;
#[derive(Clone, Copy)]
pub struct MouseDevice;
impl FileReadiness for KeyboardDevice {
fn poll_read(&self, cx: &mut Context<'_>) -> Poll<Result<(), Error>> {
KEYBOARD_INPUT_QUEUE.poll_readable(cx).map(Ok)
INPUT_QUEUE.poll_readable(cx).map(Ok)
}
}
@@ -38,7 +33,7 @@ impl CharDevice for KeyboardDevice {
return Ok(0);
}
let ev = KEYBOARD_INPUT_QUEUE.read().await;
let ev = INPUT_QUEUE.read().await;
buf[..4].copy_from_slice(&ev.as_bytes());
@@ -50,7 +45,7 @@ impl CharDevice for KeyboardDevice {
return Ok(0);
}
let ev = KEYBOARD_INPUT_QUEUE.try_read().ok_or(Error::WouldBlock)?;
let ev = INPUT_QUEUE.try_read().ok_or(Error::WouldBlock)?;
buf[..4].copy_from_slice(&ev.as_bytes());
@@ -73,84 +68,15 @@ impl CharDevice for KeyboardDevice {
}
}
impl MouseDevice {
fn write_report(buf: &mut [u8], report: &MouseEvent) -> Result<usize, Error> {
buf[0] = report.dx as u8;
buf[1] = report.dy as u8;
buf[2] = report.buttons;
buf[3] = 0;
Ok(4)
}
}
impl FileReadiness for MouseDevice {
fn poll_read(&self, cx: &mut Context<'_>) -> Poll<Result<(), Error>> {
MOUSE_INPUT_QUEUE.poll_readable(cx).map(Ok)
}
}
impl Device for MouseDevice {
fn display_name(&self) -> &str {
"Mouse input pseudo-device"
}
}
#[async_trait]
impl CharDevice for MouseDevice {
async fn read(&self, buf: &mut [u8]) -> Result<usize, Error> {
if buf.len() < 4 {
return Ok(0);
}
let ev = MOUSE_INPUT_QUEUE.read().await;
Self::write_report(buf, &ev)
}
fn read_nonblocking(&self, buf: &mut [u8]) -> Result<usize, Error> {
if buf.len() < 4 {
return Ok(0);
}
let ev = MOUSE_INPUT_QUEUE.try_read().ok_or(Error::WouldBlock)?;
Self::write_report(buf, &ev)
}
fn is_writeable(&self) -> bool {
false
}
fn device_request(&self, option: u32, buffer: &mut [u8], len: usize) -> Result<usize, Error> {
let _ = option;
let _ = buffer;
let _ = len;
Err(Error::InvalidOperation)
}
fn is_terminal(&self) -> bool {
false
}
}
static KEYBOARD_INPUT_QUEUE: LossyRingQueue<KeyboardKeyEvent> = LossyRingQueue::with_capacity(32);
static MOUSE_INPUT_QUEUE: LossyRingQueue<MouseEvent> = LossyRingQueue::with_capacity(64);
static INPUT_QUEUE: LossyRingQueue<KeyboardKeyEvent> = LossyRingQueue::with_capacity(32);
static KEYBOARD_DEVICE: OneTimeInit<Arc<KeyboardDevice>> = OneTimeInit::new();
static MOUSE_DEVICE: OneTimeInit<Arc<MouseDevice>> = OneTimeInit::new();
pub fn setup_keyboard() -> Arc<KeyboardDevice> {
pub fn setup() -> Arc<KeyboardDevice> {
KEYBOARD_DEVICE
.or_init_with(|| Arc::new(KeyboardDevice))
.clone()
}
pub fn setup_mouse() -> Arc<MouseDevice> {
MOUSE_DEVICE.or_init_with(|| Arc::new(MouseDevice)).clone()
}
pub fn send_mouse_event(ev: MouseEvent) {
MOUSE_INPUT_QUEUE.write(ev);
}
pub fn send_keyboard_event(ev: KeyboardKeyEvent) {
KEYBOARD_INPUT_QUEUE.write(ev);
pub fn send_event(ev: KeyboardKeyEvent) {
INPUT_QUEUE.write(ev);
}

Some files were not shown because too many files have changed in this diff Show More