diff --git a/crates/display-server/src/main.rs b/crates/display-server/src/main.rs index 5d2cb5fd..8d0da9e2 100644 --- a/crates/display-server/src/main.rs +++ b/crates/display-server/src/main.rs @@ -29,7 +29,7 @@ fn handle_incoming(_msg: ulib::sys::Message, _buf: &[u8], resp_socket: FileDesc) // TODO: proper listen + connect sockets // (this just broadcasts a response to all listeners and hopes that there aren't race conditions) - let buffer = init_buffer(); + let buffer = init_buffer(640, 480); let fds = [buffer.fd, buffer.present_sem_fd]; let handle = unsafe { proto::BufferHandle::new(buffer.mapped, &fds) }; @@ -55,10 +55,9 @@ fn handle_incoming(_msg: ulib::sys::Message, _buf: &[u8], resp_socket: FileDesc) handle } -fn init_buffer() -> BufferInfo { +fn init_buffer(width: usize, height: usize) -> BufferInfo { println!("init_buffer"); - let screen_size = (640, 480); - let vmem_size = screen_size.0 * screen_size.1 * 4; + let vmem_size = width * height * 4; let header_size = size_of::().next_multiple_of(4096); let total_size = header_size + vmem_size; @@ -87,9 +86,9 @@ fn init_buffer() -> BufferInfo { server_to_client_queue: proto::EventQueue::new(), video_meta: proto::VideoMeta { - width: screen_size.0 as u16, - height: screen_size.1 as u16, - row_stride: (screen_size.0 as u16 * 4), + width: width as u16, + height: height as u16, + row_stride: (width as u16 * 4), bytes_per_pixel: 4, bit_layout: 0, present_ts: 0, diff --git a/crates/kernel/.gitignore b/crates/kernel/.gitignore new file mode 100644 index 00000000..84650ba7 --- /dev/null +++ b/crates/kernel/.gitignore @@ -0,0 +1 @@ +*.pcap diff --git a/crates/kernel/examples/timer.rs b/crates/kernel/examples/timer.rs index 7cb4adcb..51b50df6 100644 --- a/crates/kernel/examples/timer.rs +++ b/crates/kernel/examples/timer.rs @@ -6,7 +6,7 @@ extern crate kernel; use kernel::*; -fn test_irq_handler(_ctx: &mut event::context::Context) { +fn test_irq_handler(_ctx: &mut event::context::Context, _irq: usize) { //Reset the timer to ping again device::system_timer::ARM_GENERIC_TIMERS.with_current(|timer| { timer.reset_timer(); diff --git a/crates/kernel/examples/user.rs b/crates/kernel/examples/user.rs index 0959cf4d..05404cd4 100644 --- a/crates/kernel/examples/user.rs +++ b/crates/kernel/examples/user.rs @@ -42,6 +42,8 @@ async fn main() { let user_region = user_region as *mut u8; let ttbr0 = process.get_ttbr0(); + println!("init ttbr0={:#x}", ttbr0); + let callback = || { println!("User ptr: {:p}", user_region); println!( @@ -65,6 +67,13 @@ async fn main() { let end = sync::get_time(); println!("Done copying user data, took {:4}µs", end - start); + + unsafe { + crate::arch::memory::flush_range( + user_region.addr(), + user_region.addr() + INIT_CODE.len(), + ) + }; }; unsafe { with_user_vmem(ttbr0, callback) }; diff --git a/crates/kernel/scripts/run-usb-passthrough.sh b/crates/kernel/scripts/run-usb-passthrough.sh new file mode 100755 index 00000000..77828d77 --- /dev/null +++ b/crates/kernel/scripts/run-usb-passthrough.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -ex +QEMU_DISPLAY=${QEMU_DISPLAY-"default"} \ +QEMU_DEVICES="-usb -device usb-host,hostbus=3,hostport=4.3" "$(dirname "$0")/run.sh" +#QEMU_DEVICES="-usb -device usb-host,vendorid=0x1532,productid=0x025e" "$(dirname "$0")/run.sh" +#QEMU_DEVICES="-usb -device usb-host,vendorid=0x2109,productid=0x2817" "$(dirname "$0")/run.sh" + diff --git a/crates/kernel/scripts/run-usb.sh b/crates/kernel/scripts/run-usb.sh index 6572aacd..b3ce68fb 100755 --- a/crates/kernel/scripts/run-usb.sh +++ b/crates/kernel/scripts/run-usb.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash set -ex -QEMU_DISPLAY="default" QEMU_DEVICES="-usb -device usb-kbd -device usb-mouse -device usb-net,netdev=net0 -netdev user,id=net0,hostfwd=tcp::2222-:22 -object filter-dump,id=f1,netdev=net0,file=net0.pcap" "$(dirname "$0")/run.sh" +QEMU_DISPLAY=${QEMU_DISPLAY-"default"} QEMU_DEVICES="-device usb-hub,id=hub1 -device usb-kbd -device usb-mouse" "$(dirname "$0")/run.sh" +# QEMU_DISPLAY=${QEMU_DISPLAY-"default"} QEMU_DEVICES="-usb -device usb-kbd -device usb-mouse,pcap=usb-mouse.pcap -device usb-net,netdev=net0 -netdev user,id=net0,hostfwd=tcp::2222-:22 -object filter-dump,id=f1,netdev=net0,file=net0.pcap" "$(dirname "$0")/run.sh" diff --git a/crates/kernel/src/arch/aarch64/boot.rs b/crates/kernel/src/arch/aarch64/boot.rs index d425b182..2de715c7 100644 --- a/crates/kernel/src/arch/aarch64/boot.rs +++ b/crates/kernel/src/arch/aarch64/boot.rs @@ -83,16 +83,20 @@ kernel_entry_alt: b kernel_entry_rust_alt - // TODO: somehow this sometimes gets triggered twice on core 0? - // Taking exception 1 [Undefined Instruction] on CPU 0 - // ...from EL1 to EL1 - // ...with ESR 0x0/0x2000000 - // ...with ELR 0x8005c - // ...to EL1 PC 0x80a00 PSTATE 0x3c5 drop_to_el1: + // Init core ids? TODO: probably unneeded + mrs x5, midr_el1 + mrs x6, mpidr_el1 + msr vpidr_el2, x5 + msr vmpidr_el2, x6 + + // Init timers on core zero??? + mrs x5, cnthctl_el2 + orr x5, x5, #0x3 + msr cnthctl_el2, x5 + msr cntvoff_el2, xzr - mov x5, #(1 << 31) - // orr x5, x5, #0x38 + ldr x5, ={HCR_EL2} msr hcr_el2, x5 // Enable FPU @@ -114,7 +118,7 @@ drop_to_el1: ldr x5, ={MAIR_EL1} msr MAIR_EL1, x5 - mov x5, #0b0101 + mov x5, #0x3c5 // EL1_SP1, DAIF masked msr SPSR_EL2, x5 // Enable FPU @@ -163,6 +167,7 @@ switch_kernel_vmem: mrs x3, TTBR1_EL1 msr TTBR0_EL1, x3 + isb dsb sy tlbi vmalle1is dsb sy @@ -173,6 +178,7 @@ switch_kernel_vmem: msr TTBR0_EL1, x4 + isb dsb sy tlbi vmalle1is dsb sy @@ -187,6 +193,7 @@ switch_kernel_vmem_in_phys: msr TCR_EL1, x1 msr TTBR1_EL1, x0 + isb dsb sy tlbi vmalle1is dsb sy @@ -198,6 +205,7 @@ switch_kernel_vmem_in_phys: switch_user_tcr_el1: msr TCR_EL1, x0 + isb dsb sy tlbi vmalle1is dsb sy @@ -207,8 +215,19 @@ switch_user_tcr_el1: STACK_SIZE_LOG2 = const STACK_SIZE_LOG2, TCR_EL1 = const INIT_TCR_EL1, TRANSLATION_ENTRY = const INIT_TRANSLATION, + HCR_EL2 = const ( + (1 << 31) | // 64 bit mode in EL1 + // orr x5, x5, #0x38 (???) + 0 + ), SCTLR_EL1 = const ( - (1 << 11) | // enable instruction caching + (1 << 29) | // ??? + (1 << 28) | + (1 << 23) | + (1 << 22) | + (1 << 20) | + (1 << 12) | // enable instruction caching + (1 << 11) | // exceptions as sync point? (1 << 4) | // enable EL0 stack pointer alignment (1 << 3) | // enable EL1 stack pointer alignment (1 << 2) | // enable data caching @@ -216,8 +235,8 @@ switch_user_tcr_el1: 1 // enable EL1&0 virtual memory ), MAIR_EL1 = const ( - (0b01000100 << 16) | // Entry 2: normal noncacheable memory - (0b00000000 << 8) | // Entry 1: device memory - (0b11111111 << 0) // Entry 0: normal memory + (0x44 << 16) | // Entry 2: normal noncacheable memory + (0x00 << 8) | // Entry 1: device memory + (0xFF << 0) // Entry 0: normal memory ) ); diff --git a/crates/kernel/src/arch/aarch64/memory/mod.rs b/crates/kernel/src/arch/aarch64/memory/mod.rs index 5927eefd..49567c26 100644 --- a/crates/kernel/src/arch/aarch64/memory/mod.rs +++ b/crates/kernel/src/arch/aarch64/memory/mod.rs @@ -97,42 +97,55 @@ pub unsafe fn clean_physical_buffer_for_device(va: *mut (), bytes: usize) { for ptr in va..(va + bytes) { // clean each byte // TODO: only invoke the cleaning once per cache line by using the cache registers to find line width - unsafe { - asm! { - "dc cvac, {ptr}", - ptr = in(reg) ptr, - options(readonly, nostack, preserves_flags) - } - } + unsafe { asm!("dc cvac, {ptr}",ptr = in(reg) ptr,options(nostack, preserves_flags)) }; } // enforce memory barrier between this and subsequent memory operations // must be inserted at some point before the device access, and this is a reasonable point - unsafe { - asm! { - "dmb sy", - options(readonly, nostack, preserves_flags) - } - } + unsafe { asm!("dmb sy", options(nostack, preserves_flags)) }; } pub unsafe fn invalidate_physical_buffer_for_device(va: *mut (), bytes: usize) { // enforce memory barrier between this and prior memory operations // probably needs to be inserted (?) at some point after the device work completes, and this is a reasonable point - unsafe { - asm! { - "dmb sy", - options(readonly, nostack, preserves_flags) - } - } + unsafe { asm!("dmb sy", options(nostack, preserves_flags)) }; let va = va.addr(); for ptr in va..(va + bytes) { // invalidate each byte // TODO: only invoke the invalidating once per cache line by using the cache registers to find line width - unsafe { - asm! { - "dc ivac, {ptr}", - ptr = in(reg) ptr, - options(readonly, nostack, preserves_flags) - } - } + unsafe { asm!("dc ivac, {ptr}",ptr = in(reg) ptr,options(nostack, preserves_flags)) }; + } +} + +pub unsafe fn flush_range(start: usize, end: usize) { + use core::arch::asm; + + // might not be needed + unsafe { asm!("dsb sy", "isb", options(nostack, preserves_flags)) }; + + let ctr_el0: usize; + unsafe { asm!("mrs {0}, CTR_EL0", out(reg) ctr_el0, options(nomem, nostack, preserves_flags)) }; + + let d_cacheline = 4 << ((ctr_el0 >> 16) & 0x0F); + let i_cacheline = 4 << ((ctr_el0 >> 0) & 0x0F); + + let start_line = (start / d_cacheline) * d_cacheline; + let end_line = end.next_multiple_of(d_cacheline); + for line in (start_line..end_line).step_by(d_cacheline) { + // TODO: figure out what subset of cache flushing is needed here + // unsafe { asm!("dc cvau, {0}", in(reg) line, options(nostack, preserves_flags)) }; + unsafe { asm!("dc cvac, {0}", in(reg) line, options(nostack, preserves_flags)) }; + unsafe { asm!("dc ivac, {0}", in(reg) line, options(nostack, preserves_flags)) }; + } + + unsafe { asm!("dsb ish", options(nostack, preserves_flags)) }; + + let start_line = (start / i_cacheline) * i_cacheline; + let end_line = end.next_multiple_of(i_cacheline); + for line in (start_line..end_line).step_by(i_cacheline) { + unsafe { asm!("ic ivau, {0}", in(reg) line, options(nostack, preserves_flags)) }; } + + unsafe { asm!("dsb ish", "isb", options(nostack, preserves_flags)) }; + + // might not be needed + unsafe { asm!("dsb sy", "isb", options(nostack, preserves_flags)) }; } diff --git a/crates/kernel/src/device.rs b/crates/kernel/src/device.rs index 00d74042..b03965da 100644 --- a/crates/kernel/src/device.rs +++ b/crates/kernel/src/device.rs @@ -14,7 +14,7 @@ pub mod watchdog; use crate::device::usb::usbd::device::UsbBus; use crate::memory; use crate::memory::{map_device, map_device_block}; -use crate::sync::{SpinLock, UnsafeInit}; +use crate::sync::{InterruptSpinLock, UnsafeInit}; use alloc::boxed::Box; use alloc::vec::Vec; use device_tree::format::StructEntry; @@ -92,14 +92,15 @@ pub fn find_device_addr(iter: MappingIterator) -> Result, Ok(None) } -pub static WATCHDOG: UnsafeInit> = +pub static WATCHDOG: UnsafeInit> = unsafe { UnsafeInit::uninit() }; type InitTask = Box; pub static PER_CORE_INIT: UnsafeInit> = unsafe { UnsafeInit::uninit() }; -pub static GPIO: UnsafeInit> = unsafe { UnsafeInit::uninit() }; -pub static MAILBOX: UnsafeInit> = +pub static GPIO: UnsafeInit> = + unsafe { UnsafeInit::uninit() }; +pub static MAILBOX: UnsafeInit> = unsafe { UnsafeInit::uninit() }; pub static BOX: UnsafeInit> = unsafe { UnsafeInit::uninit() }; @@ -107,6 +108,33 @@ pub static BOX: UnsafeInit> = unsafe { UnsafeInit::uninit() }; pub fn init_devices(tree: &DeviceTree<'_>) { let mut init_fns: Vec = Vec::new(); + { + let watchdog = discover_compatible(tree, b"brcm,bcm2835-pm-wdt") + .unwrap() + .next() + .unwrap(); + let (watchdog_addr, _) = find_device_addr(watchdog).unwrap().unwrap(); + let watchdog_base = unsafe { map_device(watchdog_addr) }.as_ptr(); + + unsafe { + let watchdog = watchdog::bcm2835_wdt_driver::init(watchdog_base); + WATCHDOG.init(InterruptSpinLock::new(watchdog)); + } + // println!("| initialized power managment watchdog"); + // println!("| last reset: {:#010x}", WATCHDOG.get().lock().last_reset()); + } + + { + let gpio = discover_compatible(tree, b"brcm,bcm2711-gpio") + .unwrap() + .next() + .unwrap(); + let (gpio_addr, _) = find_device_addr(gpio).unwrap().unwrap(); + let gpio_base = unsafe { map_device(gpio_addr) }.as_ptr(); + let gpio = unsafe { gpio::bcm2711_gpio_driver::init_with_defaults(gpio_base, true) }; + unsafe { GPIO.init(InterruptSpinLock::new(gpio)) }; + } + let mut uarts = discover_compatible(tree, b"arm,pl011").unwrap(); { let uart = uarts.next().unwrap(); @@ -127,22 +155,6 @@ pub fn init_devices(tree: &DeviceTree<'_>) { println!("| initialized Mini UART"); } - { - let watchdog = discover_compatible(tree, b"brcm,bcm2835-pm-wdt") - .unwrap() - .next() - .unwrap(); - let (watchdog_addr, _) = find_device_addr(watchdog).unwrap().unwrap(); - let watchdog_base = unsafe { map_device(watchdog_addr) }.as_ptr(); - - unsafe { - let watchdog = watchdog::bcm2835_wdt_driver::init(watchdog_base); - WATCHDOG.init(SpinLock::new(watchdog)); - } - println!("| initialized power managment watchdog"); - println!("| last reset: {:#010x}", WATCHDOG.get().lock().last_reset()); - } - { let mailbox = discover_compatible(&tree, b"brcm,bcm2835-mbox") .unwrap() @@ -151,17 +163,50 @@ pub fn init_devices(tree: &DeviceTree<'_>) { let (mailbox_addr, _) = find_device_addr(mailbox).unwrap().unwrap(); let mailbox_base = unsafe { memory::map_device(mailbox_addr) }.as_ptr(); unsafe { - MAILBOX.init(SpinLock::new(mailbox::VideoCoreMailbox::init(mailbox_base))); + MAILBOX.init(InterruptSpinLock::new(mailbox::VideoCoreMailbox::init( + mailbox_base, + ))); } } + { + let mut guard = MAILBOX.get().lock(); + // TODO: this freezes after clock 11? + // for clock in 0x01..=0x0E { + // // let state = unsafe { guard.get_property(mailbox::PropGetClockState { id: clock }).unwrap() }; + // let rate = unsafe { guard.get_property(mailbox::PropGetClockRate { id: clock }).unwrap() }; + // // let measured = unsafe { guard.get_property(mailbox::PropGetClockRateMeasured { id: clock }).unwrap() }; + // let min = unsafe { guard.get_property(mailbox::PropGetMinClockRate { id: clock }).unwrap() }; + // let max = unsafe { guard.get_property(mailbox::PropGetMaxClockRate { id: clock }).unwrap() }; + // println!("Clock {clock}: state = {}, rate = {}, measured = {}, min = {}, max = {}", 0, rate.rate, 0, min.rate, max.rate); + // } + + let clock_rate_req = mailbox::PropGetClockRate { + id: mailbox::CLOCK_ARM, + }; + let cur_rate = unsafe { guard.get_property(clock_rate_req).unwrap() }.rate; + let max_rate_req = mailbox::PropGetMaxClockRate { + id: mailbox::CLOCK_ARM, + }; + let _max_rate = unsafe { guard.get_property(max_rate_req).unwrap() }.rate; + let target_rate = 1_500_000_000; + + let set_rate_req = mailbox::PropSetClockRate { + id: mailbox::CLOCK_ARM, + rate: target_rate, + skip_setting_turbo: 0, + }; + println!("| Changing arm clock from {cur_rate} to {target_rate}"); + let new_rate = unsafe { guard.get_property(set_rate_req).unwrap() }; + println!("| Set clock rate; new rate = {}", new_rate.rate); + } + if let Some(gic) = discover_compatible(tree, b"arm,gic-400").unwrap().next() { println!("| initializing GIC-400 interrupt controller"); let (gic_addr, _) = find_device_addr(gic).unwrap().unwrap(); let gic_base = unsafe { map_device_block(gic_addr, 0x8000) }.as_ptr(); println!("| GIC-400 addr: {:#010x}", gic_addr); - println!("| GIC-400 base: {:#010x}", gic_base as usize); let gic = unsafe { gic::Gic400Driver::init(gic_base) }; unsafe { gic::GIC.init(gic) }; @@ -190,6 +235,35 @@ pub fn init_devices(tree: &DeviceTree<'_>) { } } + // println!("| acquiring framebuffer"); + // let mut surface = unsafe { MAILBOX.get().lock().map_framebuffer_kernel(640, 480) }; + // println!("| surface constructed"); + // let (width, height) = surface.dimensions(); + + // for i in 0.. { + // println!("| drawing frame"); + // let color = 0xFFFF0000 | (i as i32 % 512 - 256).abs().min(255) as u32; + // let color2 = 0xFF0000FF | (((i as i32 % 512 - 256).abs().min(255) as u32) << 16); + // let stripe_width = width / 20; + // let offset = i * (120 / surface.framerate()); + // for r in 0..height { + // for c in 0..width { + // let cluster = (c + offset % (2 * stripe_width)) / stripe_width; + // let color = if cluster % 2 == 0 { color } else { color2 }; + // surface[(r, c)] = color; + // } + // } + + // surface.present(); + // } + // let console = console::init(); + // unsafe { CONSOLE.init(InterruptSpinLock::new(console)) }; + // for i in 0.. { + // println!("Line {i}"); + // console.input(alloc::format!("Line {i}\n").as_bytes()); + // console.render(); + // } + { println!("| initializing timer"); let timer_iter = discover_compatible(tree, b"brcm,bcm2835-system-timer") @@ -204,25 +278,16 @@ pub fn init_devices(tree: &DeviceTree<'_>) { println!("| timer initialized, time: {time}"); } - { - let gpio = discover_compatible(tree, b"brcm,bcm2711-gpio") - .unwrap() - .next() - .unwrap(); - let (gpio_addr, _) = find_device_addr(gpio).unwrap().unwrap(); - let gpio_base = unsafe { map_device(gpio_addr) }.as_ptr(); - println!("| GPIO controller addr: {:#010x}", gpio_addr); - println!("| GPIO controller base: {:#010x}", gpio_base as usize); - let gpio = unsafe { gpio::bcm2711_gpio_driver::init_with_defaults(gpio_base, true) }; - unsafe { GPIO.init(SpinLock::new(gpio)) }; - println!("| initialized GPIO"); - } - if ENABLE_USB { println!("| Initializing USB"); - let usb = discover_compatible(tree, b"brcm,bcm2708-usb") + let usb = discover_compatible(tree, b"brcm,bcm2835-usb") .unwrap() .next() + .or_else(|| { + discover_compatible(tree, b"brcm,bcm2708-usb") + .unwrap() + .next() + }) .unwrap(); let (usb_addr, _) = find_device_addr(usb).unwrap().unwrap(); @@ -327,6 +392,7 @@ pub fn enable_cpus(tree: &device_tree::DeviceTree<'_>, start_fn: unsafe extern " let start = unsafe { map_physical(release_addr, 8).cast::() }; unsafe { core::ptr::write_volatile(start.as_ptr(), physical_start) }; + unsafe { memory::invalidate_physical_buffer_for_device(start.as_ptr().cast(), 8) }; core_count += 1; } diff --git a/crates/kernel/src/device/gic.rs b/crates/kernel/src/device/gic.rs index ebd06ad2..e11dff91 100644 --- a/crates/kernel/src/device/gic.rs +++ b/crates/kernel/src/device/gic.rs @@ -112,12 +112,13 @@ fn isb() { unsafe { asm!("isb", options(nostack, nomem, preserves_flags)) } } -pub fn irq_not_handled(_ctx: &mut Context) { - panic!("IRQ not handled"); +pub fn irq_not_handled(_ctx: &mut Context, irq: usize) { + println!("spurious irq: {irq}"); } /// Handles the interrupt and asks handler to handle it /// Level-triggered interrupts must be cleared by associaetd irq handler or else it will be called again +#[unsafe(no_mangle)] pub unsafe extern "C" fn gic_irq_handler( ctx: &mut Context, _elr: u64, @@ -168,7 +169,7 @@ pub unsafe extern "C" fn gic_irq_handler( // Level-triggered interrupts must be cleared by associated irq // handler or else it will be called again let irq_handler = gic.isr_table.get(irq as usize); - irq_handler(ctx); + irq_handler(ctx, irq as usize); //TODO: HAndle level-triggered interrupts? // GICC_DIR is not necessary, Security Extensions are not enabled @@ -177,7 +178,7 @@ pub unsafe extern "C" fn gic_irq_handler( ctx } -type Isr = fn(&mut Context); +type Isr = fn(&mut Context, usize); pub struct IsrTable(HandlerTableInner); @@ -322,7 +323,7 @@ impl Gic400Driver { unsafe { self.reg_write_cpui(GICC_PMR, old_pmr) }; } - pub fn register_isr(&self, irq: usize, isr: fn(&mut Context)) { + pub fn register_isr(&self, irq: usize, isr: Isr) { self.register_isr_detailed(irq, isr, 0xf, false, 0xa0); } @@ -336,7 +337,7 @@ impl Gic400Driver { pub fn register_isr_detailed( &self, irq: usize, - isr: fn(&mut Context), + isr: Isr, target_cpus: u8, int_type: bool, priority: u8, diff --git a/crates/kernel/src/device/gpio.rs b/crates/kernel/src/device/gpio.rs index d742eb73..9106090a 100644 --- a/crates/kernel/src/device/gpio.rs +++ b/crates/kernel/src/device/gpio.rs @@ -153,8 +153,8 @@ impl bcm2711_gpio_driver { val &= !(0b111 << shift); // Clear current function bits val |= (function as u32) << shift; reg_fsel.write(val); - #[cfg(debug_assertions)] - print!("| GPIO -- Wrote {:#010b}, to register GPFSEL{index}, function: {:?} for pin {pin}\n", val, function); + // #[cfg(debug_assertions)] + // print!("| GPIO -- Wrote {:#010b}, to register GPFSEL{index}, function: {:?} for pin {pin}\n", val, function); } } @@ -167,8 +167,8 @@ impl bcm2711_gpio_driver { unsafe { reg_set.write(1 << shift); } - #[cfg(debug_assertions)] - println!("| GPIO -- Set HIGH: pin {}", pin); + // #[cfg(debug_assertions)] + // println!("| GPIO -- Set HIGH: pin {}", pin); } /// Set a GPIO pin LOW @@ -180,8 +180,8 @@ impl bcm2711_gpio_driver { unsafe { reg_clr.write(1 << shift); } - #[cfg(debug_assertions)] - println!("| GPIO -- Set LOW: pin {}", pin); + // #[cfg(debug_assertions)] + // println!("| GPIO -- Set LOW: pin {}", pin); } /// Read a GPIO pin value diff --git a/crates/kernel/src/device/mailbox.rs b/crates/kernel/src/device/mailbox.rs index a6052894..ec14d43d 100644 --- a/crates/kernel/src/device/mailbox.rs +++ b/crates/kernel/src/device/mailbox.rs @@ -104,9 +104,150 @@ unsafe impl PropertyRequest for PropSetPowerState { } } +macro_rules! define_property { + ($tag:literal => + struct $req_name:ident { $($req_field:ident : $req_field_ty:ty),* $(,)? } + -> struct $resp_name:ident { $($resp_field:ident : $resp_field_ty:ty),* $(,)? }) => + { + + #[repr(C, align(4))] + #[derive(Copy, Clone)] + pub struct $req_name { + $(pub $req_field : $req_field_ty,)* + } + unsafe impl bytemuck::Zeroable for $req_name {} + unsafe impl bytemuck::Pod for $req_name {} + + #[repr(C, align(4))] + #[derive(Copy, Clone)] + pub struct $resp_name { + $(pub $resp_field : $resp_field_ty,)* + } + unsafe impl bytemuck::Zeroable for $resp_name {} + unsafe impl bytemuck::Pod for $resp_name {} + + unsafe impl PropertyRequest for $req_name { + const TAG: u32 = $tag; + type Output = $resp_name; + unsafe fn parse_response(data: &[u8]) -> Self::Output { + *bytemuck::from_bytes(&data[..size_of::()]) + } + } + } +} + +pub const CLOCK_EMMC: u32 = 0x000000001; +pub const CLOCK_UART: u32 = 0x000000002; +pub const CLOCK_ARM: u32 = 0x000000003; +pub const CLOCK_CORE: u32 = 0x000000004; +pub const CLOCK_V3D: u32 = 0x000000005; +pub const CLOCK_H264: u32 = 0x000000006; +pub const CLOCK_ISP: u32 = 0x000000007; +pub const CLOCK_SDRAM: u32 = 0x000000008; +pub const CLOCK_PIXEL: u32 = 0x000000009; +pub const CLOCK_PWM: u32 = 0x00000000a; +pub const CLOCK_HEVC: u32 = 0x00000000b; +pub const CLOCK_EMMC2: u32 = 0x00000000c; +pub const CLOCK_M2MC: u32 = 0x00000000d; +pub const CLOCK_PIXEL_BVB: u32 = 0x00000000e; + +define_property!(0x00030041 => struct PropGetStatusLED {} -> struct PropGetStatusLEDResponse { + pin: u32, + state: u32, +}); + +define_property!(0x00038041 => struct PropSetStatusLED { + pin: u32, + state: u32, +} -> struct PropSetStatusLEDResponse { + pin: u32, + state: u32, +}); + +define_property!(0x00030001 => struct PropGetClockState { + id: u32, +} -> struct PropGetClockStateResponse { + id: u32, + state: u32, +}); + +define_property!(0x00030002 => struct PropGetClockRate { + id: u32, +} -> struct PropGetClockRateResponse { + id: u32, + rate: u32, +}); + +define_property!(0x00030047 => struct PropGetClockRateMeasured { + id: u32, +} -> struct PropGetClockRateMeasuredResponse { + id: u32, + rate: u32, +}); + +define_property!(0x00038002 => struct PropSetClockRate { + id: u32, + rate: u32, + skip_setting_turbo: u32, +} -> struct PropSetClockRateResponse { + id: u32, + rate: u32, +}); + +define_property!(0x00030004 => struct PropGetMaxClockRate { + id: u32, +} -> struct PropGetMaxClockRateResponse { + id: u32, + rate: u32, +}); + +define_property!(0x00030007 => struct PropGetMinClockRate { + id: u32, +} -> struct PropGetMinClockRateResponse { + id: u32, + rate: u32, +}); + +define_property!(0x00030009 => struct PropGetTurbo { + id: u32, +} -> struct PropGetTurboResponse { + id: u32, + level: u32, +}); + +define_property!(0x00038009 => struct PropSetTurbo { + id: u32, + level: u32, +} -> struct PropSetTurboResponse { + id: u32, + level: u32, +}); + #[derive(Debug)] pub struct MailboxError; +struct HexDisplay<'a, T>(&'a [T]); + +impl core::fmt::LowerHex for HexDisplay<'_, T> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let mut list = f.debug_list(); + for i in self.0 { + list.entry(&format_args!("{:#x}", i)); + } + list.finish() + } +} + +impl core::fmt::UpperHex for HexDisplay<'_, T> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let mut list = f.debug_list(); + for i in self.0 { + list.entry(&format_args!("{:#X}", i)); + } + list.finish() + } +} + impl VideoCoreMailbox { const MBOX_READ: usize = 0x00; const MBOX_POLL: usize = 0x10; @@ -137,18 +278,27 @@ impl VideoCoreMailbox { let read_reg = Volatile(self.base.wrapping_byte_add(Self::MBOX_READ)); let write_reg = Volatile(self.base.wrapping_byte_add(Self::MBOX_WRITE)); + let mut i = 0; + unsafe { while (status_reg.read() & Self::STATUS_FULL) != 0 { - crate::arch::wfe(); + core::hint::spin_loop(); + i = i + 1; + if i % 100 == 0 { + // println!("mailbox full..."); + } } } + unsafe { core::arch::asm!("dsb sy") }; // TODO let buffer_bytes = size_of_val(buffer); let buffer_ptr = buffer.as_mut_ptr(); + let addr = physical_addr(buffer_ptr.addr()).unwrap(); assert!(addr <= u32::MAX as u64 && addr % 16 == 0); assert!(channel as u32 <= Self::CHANNEL_MASK); + let addr = addr | 0xC0000000; // Tell the GPU to treat it as non-cacheable let value = (addr as u32 & !Self::CHANNEL_MASK) | (channel as u32 & Self::CHANNEL_MASK); // TODO: are mailbox messages 1-to-1, or can there be spurious @@ -164,26 +314,34 @@ impl VideoCoreMailbox { // TODO: translate buffer addresses for non-property calls // (GPU memory and CPU memory may have different virtual addresses) + // println!( + // "mailbox_call({channel}, {value:#x}, {:x})", + // HexDisplay(bytemuck::cast_slice::<_, u32>(buffer)) + // ); + unsafe { - memory::clean_physical_buffer_for_device(buffer_ptr.cast(), buffer_bytes); + memory::invalidate_physical_buffer_for_device(buffer_ptr.cast(), buffer_bytes); } unsafe { write_reg.write(value) }; + // TODO: why is this load-bearing... + // crate::sync::spin_sleep(20_000); + loop { unsafe { while (status_reg.read() & Self::STATUS_EMPTY) != 0 { - crate::arch::wfe(); + core::hint::spin_loop(); } } let message = unsafe { read_reg.read() }; if (message & Self::CHANNEL_MASK) == channel as u32 { unsafe { - memory::invalidate_physical_buffer_for_device(buffer_ptr.cast(), buffer_bytes); + memory::clean_physical_buffer_for_device(buffer_ptr.cast(), buffer_bytes); } break; } else { - println!("Warning: received mailbox message from wrong channel?"); + // println!("Warning: received mailbox message from wrong channel?"); } } @@ -208,7 +366,7 @@ impl VideoCoreMailbox { 0x00000000, // request tag, data_words * size_of::() as u32, - 0, + request_data.len() as u32, // Documented as reserved, but must be data length ]; assert!( @@ -218,12 +376,16 @@ impl VideoCoreMailbox { words[..data.len()].copy_from_slice(&data); words[data.len()..][..request_data.len()].copy_from_slice(request_data); - words[data.len() - 1] = 0; + words[data.len() + data_words as usize] = 0; // end tag unsafe { self.mailbox_call(8, &mut *buffer).unwrap(); } + // let debug = crate::device::LED_OUT.get(); + // debug.put(0b11111111); + // debug.sleep(250_000); + let words: &[u32] = bytemuck::cast_slice::<_, u32>(&*buffer); let response = words[1]; @@ -231,12 +393,20 @@ impl VideoCoreMailbox { let response_code = words[4]; let mut response_size = response_code & 0x7FFFFFFF; + // for b in u32::to_be_bytes(response_code) { + // debug.put(b); + // debug.sleep(250_000); + // } + // debug.sleep(250_000); + // debug.put(0b11111111); + // debug.sleep(250_000); + if (response_code & 0x80000000) == 0 { return Err(MailboxError); } - if response_size == 0 && [PropGetPowerState::TAG, PropGetPowerWaitTime::TAG].contains(&tag) - { + // if response_size == 0 && [PropGetPowerState::TAG, PropGetPowerWaitTime::TAG].contains(&tag) + if response_size == 0 { // TODO: Unsupported in qemu response_size = 8; } @@ -279,6 +449,7 @@ impl VideoCoreMailbox { const TAG_BLANK_SCREEN: u32 = 0x00040002; const TAG_SET_PHYS_DIMS: u32 = 0x00048003; const TAG_SET_VIRT_DIMS: u32 = 0x00048004; + const TAG_SET_VIRT_OFF: u32 = 0x00048009; const TAG_SET_DEPTH: u32 = 0x00048005; const TAG_SET_PIXEL_ORDER: u32 = 0x00048006; const TAG_GET_PITCH: u32 = 0x00040008; @@ -304,6 +475,11 @@ impl VideoCoreMailbox { 0, width as u32, height as u32, + TAG_SET_VIRT_OFF, + 8, + 0, + 0, + 0, TAG_SET_DEPTH, 4, 0, @@ -332,15 +508,19 @@ impl VideoCoreMailbox { let words: &[u32; BUFFER_WORDS] = bytemuck::cast_slice::<_, u32>(&buffer).try_into().unwrap(); - let response = words[1]; + let _response = words[1]; - let buffer_ptr = words[23]; - let buffer_size = words[24] as usize; - let pitch = words[28] as usize; + // TODO: parse the output to get these, rather than assuming their locations + let width = words[10] as usize; + let height = words[11] as usize; + let _pixel_order = words[24]; + let buffer_ptr = words[28] & 0x3FFFFFFF; + let buffer_size = words[29] as usize; + let pitch = words[33] as usize; assert!(pitch == width * 4); // println!("{:?}", bytemuck::cast_slice_mut::<_, u32>(&mut buffer)); - println!("Response: {response:#010x}\nbuffer: {buffer_ptr:#010x}, {buffer_size:#010x}, {pitch:#010x}"); + // println!("Response: {response:#010x}\nbuffer: {buffer_ptr:#010x}, {buffer_size:#010x}, {pitch:#010x}"); assert!(buffer_ptr % 4096 == 0); RawFB { @@ -375,12 +555,12 @@ pub struct RawFB { pub struct Surface { alternate: alloc::boxed::Box<[u128]>, - buffer: &'static mut [u128], + pub buffer: &'static mut [u128], framerate: usize, time_step: usize, width: usize, height: usize, - pitch_elems: usize, + pub pitch_elems: usize, } #[cfg(target_arch = "aarch64")] diff --git a/crates/kernel/src/device/system_timer.rs b/crates/kernel/src/device/system_timer.rs index 6bf2bb69..c670c340 100644 --- a/crates/kernel/src/device/system_timer.rs +++ b/crates/kernel/src/device/system_timer.rs @@ -38,12 +38,13 @@ pub fn micro_delay(delay: u32) { } pub unsafe fn initialize_system_timer(base: *mut ()) { - unsafe { SYSTEM_TIMER.init(Bcm2835SysTmr::new(base)) }; if super::gic::GIC.is_initialized() { // TODO: support local timer on rpi3b interrupt controller let gic = super::gic::GIC.get(); register_system_timer_irqs(gic); } + + unsafe { SYSTEM_TIMER.init(Bcm2835SysTmr::new(base)) }; } fn register_system_timer_irqs(gic: &super::gic::Gic400Driver) { @@ -54,8 +55,8 @@ fn register_system_timer_irqs(gic: &super::gic::Gic400Driver) { gic.register_isr(99, system_timer_irq_handler); } -fn system_timer_irq_handler(_ctx: &mut Context) { - panic!("System timer IRQ handler not implemented"); +fn system_timer_irq_handler(_ctx: &mut Context, _irq: usize) { + // panic!("System timer IRQ handler not implemented"); } #[derive(PartialEq)] @@ -224,7 +225,7 @@ impl Bcm2835SysTmr { } } -pub fn timer_scheduler_handler(ctx: &mut Context) { +pub fn timer_scheduler_handler(ctx: &mut Context, _irq: usize) { let time = ARM_GENERIC_TIMERS.with_current(|timer| timer.get_time()); let mut preemption_flag = false; TIMER_SCHEDULER.with_current(|timer_scheduler| { diff --git a/crates/kernel/src/device/uart.rs b/crates/kernel/src/device/uart.rs index af8ca5ac..32f80910 100644 --- a/crates/kernel/src/device/uart.rs +++ b/crates/kernel/src/device/uart.rs @@ -105,6 +105,10 @@ impl UARTInner { (unsafe { self.reg(Self::UART_FR).read() } & (1 << 4) > 0) } pub fn writec(&mut self, c: u8) { + // if super::LED_OUT.is_initialized() { + // super::LED_OUT.get().put(c); + // // crate::sync::spin_sleep(33 * 1000); + // } unsafe { while self.transmit_fifo_full() {} self.reg(Self::UART_DR).write(c as u32); @@ -125,6 +129,21 @@ impl UARTInner { } } } + + pub fn write_bytes(&mut self, bytes: &[u8]) { + for b in bytes { + self.writec(*b); + } + // if super::CONSOLE.is_initialized() { + // let mut console = super::CONSOLE.get().lock(); + // console.input(bytes); + // if bytes.contains(&b'\n') { + // console.render(); + // } + // drop(console); + // spin_sleep(3000); + // } + } } unsafe impl Send for UARTInner {} diff --git a/crates/kernel/src/device/usb/device/hid/mouse.rs b/crates/kernel/src/device/usb/device/hid/mouse.rs index 1872e553..ba36190f 100644 --- a/crates/kernel/src/device/usb/device/hid/mouse.rs +++ b/crates/kernel/src/device/usb/device/hid/mouse.rs @@ -6,8 +6,8 @@ use crate::SpinLock; #[derive(Debug)] pub enum MouseEvent { Move { - x: i8, - y: i8, + x: i16, + y: i16, }, Button { button: MouseButton, @@ -67,11 +67,21 @@ pub static LAST_BUTTONS: AtomicU8 = AtomicU8::new(0); pub unsafe fn MouseAnalyze(buffer: *mut u8, buffer_length: u32) { let buffer = unsafe { core::slice::from_raw_parts(buffer, buffer_length as usize) }; - if buffer.is_empty() { - return; - } + let (buttons, x, y, wheel) = match buffer { + &[] => return, + &[buttons, x, y, wheel] => (buttons, x as i8 as i16, y as i8 as i16, wheel as i8), + &[buttons, _, xa, xb, ya, yb, wheel, _] => ( + buttons, + i16::from_le_bytes([xa, xb]), + i16::from_le_bytes([ya, yb]), + wheel as i8, + ), + _ => { + println!("Not enough data in MouseAnalyze: {:?}", buffer); + return; + } + }; - let [buttons, x, y, wheel] = buffer.try_into().unwrap(); let old_buttons = LAST_BUTTONS.swap(buttons, Ordering::SeqCst); let send = |ev| unsafe { MOUSE_EVENTS.buffer.send_overwrite(ev) }; @@ -95,12 +105,9 @@ pub unsafe fn MouseAnalyze(buffer: *mut u8, buffer_length: u32) { }); if x != 0 || y != 0 { - send(MouseEvent::Move { - x: x as i8, - y: y as i8, - }); + send(MouseEvent::Move { x, y }); } if wheel != 0 { - send(MouseEvent::Wheel { delta: wheel as i8 }); + send(MouseEvent::Wheel { delta: wheel }); } } diff --git a/crates/kernel/src/device/usb/device/hub.rs b/crates/kernel/src/device/usb/device/hub.rs index 57de2214..38450078 100644 --- a/crates/kernel/src/device/usb/device/hub.rs +++ b/crates/kernel/src/device/usb/device/hub.rs @@ -21,6 +21,7 @@ use crate::device::usb::hcd::hub::*; use crate::device::usb::types::*; use crate::device::usb::usbd::pipe::*; use crate::device::usb::usbd::request::*; +use crate::device::usb::DwcUpdateHostFrameInterval; use alloc::boxed::Box; pub fn HubLoad(bus: &mut UsbBus) { @@ -165,7 +166,7 @@ fn HubPowerOn(device: &mut UsbDevice) -> ResultCode { let hub = device.driver_data.downcast::().unwrap(); let hub_desc = hub.Descriptor.as_mut().unwrap().as_mut(); //unsafe { &mut *(.as_mut_ptr() as *mut HubDescriptor) }; let max_children = hub.MaxChildren; - let delay = hub_desc.PowerGoodDelay as u32; + let mut delay = hub_desc.PowerGoodDelay as u32; for i in 0..max_children { if HubChangePortFeature(device, HubPortFeature::FeaturePower, i as u8, true) @@ -175,7 +176,12 @@ fn HubPowerOn(device: &mut UsbDevice) -> ResultCode { } } - micro_delay(delay); + if delay == 0 { + delay = 50; //100 ms + } + + // println!("| HUB: powering on hub, waiting for {}ms", 2 * delay); + micro_delay(delay * 2000); return ResultCode::OK; } @@ -221,6 +227,59 @@ fn HubPortGetStatus(device: &mut UsbDevice, port: u8) -> ResultCode { return ResultCode::OK; } +fn HubPortReset2(device: &mut UsbDevice, port: u8) -> ResultCode { + /* clear any leftover port reset changes first */ + HubChangePortFeature(device, HubPortFeature::FeatureResetChange, port, false); + let mut result = HubChangePortFeature(device, HubPortFeature::FeatureReset, port, true); + + if result != ResultCode::OK { + println!("| HUB: failed to reset port (1) {}", port + 1); + return result; + } + + let mut n = 0; + loop { + /* wait for the device to recover from reset */ + micro_delay(50000); //50ms + n += 50; + + result = HubPortGetStatus(device, port); + + if result != ResultCode::OK { + println!("| HUB: failed to get status (2) for port {}", port + 1); + return result; + } + + let data = device.driver_data.downcast::().unwrap(); + let status = &data.PortStatus[port as usize]; + let port_changed = status.Change; + + if port_changed.contains(HubPortStatusChange::ResetChanged) { + break; + } + + if n > 1000 { + n = 0; + break; + } + } + + result = HubChangePortFeature(device, HubPortFeature::FeatureResetChange, port, false); + if result != ResultCode::OK { + println!("| HUB: failed to clear reset change for port {}", port + 1); + return result; + } + + if n == 0 { + println!("| HUB: timeout waiting for reset on port {}", port + 1); + return ResultCode::ErrorTimeout; + } + + micro_delay(10000); + return result; +} + +#[allow(dead_code)] fn HubPortReset(device: &mut UsbDevice, port: u8) -> ResultCode { let mut result; let mut retry_max = 0; @@ -284,6 +343,11 @@ fn HubPortReset(device: &mut UsbDevice, port: u8) -> ResultCode { println!("| HUB: failed to clear reset for port {}", port + 1); } + result = HubChangePortFeature(device, HubPortFeature::FeatureResetChange, port, false); + if result != ResultCode::OK { + println!("| HUB: failed to clear reset change for port {}", port + 1); + } + return ResultCode::OK; } @@ -294,7 +358,7 @@ fn HubChildReset(device: &mut UsbDevice, child: &mut UsbDevice) -> ResultCode { && child.port_number < data.MaxChildren as u8 && data.Children[child.port_number as usize] == child { - return HubPortReset(device, child.port_number); + return HubPortReset2(device, child.port_number); } else { println!("| HUB: child reset failed"); return ResultCode::ErrorArgument; @@ -302,6 +366,8 @@ fn HubChildReset(device: &mut UsbDevice, child: &mut UsbDevice) -> ResultCode { } fn HubPortConnectionChanged(device: &mut UsbDevice, port: u8) -> ResultCode { + DwcUpdateHostFrameInterval(); + let mut result = HubPortGetStatus(device, port); if result != ResultCode::OK { @@ -320,6 +386,13 @@ fn HubPortConnectionChanged(device: &mut UsbDevice, port: u8) -> ResultCode { ); return result; } + + result = HubPortGetStatus(device, port); + if result != ResultCode::OK { + println!("| HUB: failed to get status (3) for port {}", port + 1); + return result; + } + let data = device.driver_data.downcast::().unwrap(); let port_status = data.PortStatus[port as usize].Status; if (!(port_status.contains(HubPortStatus::Connected)) @@ -332,7 +405,15 @@ fn HubPortConnectionChanged(device: &mut UsbDevice, port: u8) -> ResultCode { return ResultCode::ErrorIncompatible; } - result = HubPortReset(device, port); + if !port_status.contains(HubPortStatus::Power) { + println!("| WWARNING: HUB: PORT {} has no power", port + 1); + } + + //wait for maximum device powerup time + //300ms + micro_delay(300000); + + result = HubPortReset2(device, port); if result != ResultCode::OK { println!("| HUB: count not reset port {} for new device", port + 1); return result; @@ -365,9 +446,12 @@ fn HubPortConnectionChanged(device: &mut UsbDevice, port: u8) -> ResultCode { child_dev.speed = UsbSpeed::Full; } + println!("| HUB: new device speed {:?}", child_dev.speed); + child_dev.parent = Some(device); child_dev.port_number = port; + println!("| HUB: attach device {}", child_dev.number); result = UsbAttachDevice(child_dev); if result != ResultCode::OK { println!("| HUB: Could not connect to new device"); @@ -404,9 +488,14 @@ fn HubCheckConnection(device: &mut UsbDevice, port: u8) -> ResultCode { } } - if port_change.contains(HubPortStatusChange::ConnectedChanged) { - // println!("| HUB: Port {} connected changed", port + 1); - HubPortConnectionChanged(device, port); + //freebsd + if port_change.contains(HubPortStatusChange::OverCurrentChanged) { + if HubChangePortFeature(device, HubPortFeature::FeatureOverCurrent, port, false) + != ResultCode::OK + { + println!("| HUB: failed to clear over current for port {}", port + 1); + } + HubPowerOn(device); } if port_change.contains(HubPortStatusChange::EnabledChanged) { @@ -427,28 +516,24 @@ fn HubCheckConnection(device: &mut UsbDevice, port: u8) -> ResultCode { } } - if port_status.contains(HubPortStatus::Suspended) { - if HubChangePortFeature(device, HubPortFeature::FeatureSuspend, port, false) - != ResultCode::OK - { - println!("| HUB: failed to clear suspend for port {}", port + 1); - } + if port_change.contains(HubPortStatusChange::ConnectedChanged) { + // println!("| HUB: Port {} connected changed", port + 1); + HubPortConnectionChanged(device, port); } - if port_change.contains(HubPortStatusChange::OverCurrentChanged) { - if HubChangePortFeature(device, HubPortFeature::FeatureOverCurrent, port, false) + if port_status.contains(HubPortStatus::Suspended) { + if HubChangePortFeature(device, HubPortFeature::FeatureSuspend, port, false) != ResultCode::OK { - println!("| HUB: failed to clear over current for port {}", port + 1); + panic!("| HUB: failed to clear suspend for port {}", port + 1); } - HubPowerOn(device); } if port_change.contains(HubPortStatusChange::ResetChanged) { if HubChangePortFeature(device, HubPortFeature::FeatureResetChange, port, false) != ResultCode::OK { - println!("| HUB: failed to clear reset change for port {}", port + 1); + panic!("| HUB: failed to clear reset change for port {}", port + 1); } } @@ -564,6 +649,7 @@ fn HubAttach(device: &mut UsbDevice, interface_number: u32) -> ResultCode { } // println!("| Hub Read Descriptor"); let mut result = HubReadDescriptor(device); + // println!("| Hub Read Descriptor done: {:?}", result); if result != ResultCode::OK { return result; } @@ -578,6 +664,9 @@ fn HubAttach(device: &mut UsbDevice, interface_number: u32) -> ResultCode { hub.MaxChildren = HubDescriptor.PortCount as u32; } + //print HubDescriptor info + println!("| HUB: Hub descriptor {:?}", HubDescriptor); + //TODO: Hope HubDescriptor.Attributes is correct // println!("| HUB: hub has {} children", hub.MaxChildren); diff --git a/crates/kernel/src/device/usb/hcd/dwc/dwc_otg.rs b/crates/kernel/src/device/usb/hcd/dwc/dwc_otg.rs index 5d249dfa..a0ab8a13 100644 --- a/crates/kernel/src/device/usb/hcd/dwc/dwc_otg.rs +++ b/crates/kernel/src/device/usb/hcd/dwc/dwc_otg.rs @@ -78,7 +78,7 @@ fn schedule_next_transfer(channel: u8) { } } -pub fn dwc_otg_interrupt_handler(_ctx: &mut Context) { +pub fn dwc_otg_interrupt_handler(_ctx: &mut Context, _irq: usize) { let mut hcint_channels = [0u32; ChannelCount]; { //read interrupt status @@ -108,8 +108,9 @@ pub fn dwc_otg_interrupt_handler(_ctx: &mut Context) { if let Some(callback) = unsafe { DWC_CHANNEL_CALLBACK.callback[i] } { let hcint = hcint_channels[i]; schedule_rt(move || { - callback(endpoint_descriptor, hcint, i as u8); - schedule_next_transfer(i as u8); + if callback(endpoint_descriptor, hcint, i as u8) { + schedule_next_transfer(i as u8); + } }); } else { println!("| DWC: No callback for channel {}.\n", i); @@ -124,6 +125,19 @@ pub fn dwc_otg_interrupt_handler(_ctx: &mut Context) { } } +pub fn DwcUpdateHostFrameInterval() { + let hfir = read_volatile(DOTG_HFIR); + println!("| DWC: HFIR: {:#x}", hfir); +} + +pub fn UpdateDwcOddFrame(channel: u8) { + let frame = read_volatile(DOTG_HFNUM); + let mut hcchar = read_volatile(DOTG_HCCHAR(channel as usize)); + hcchar &= !HCCHAR_ODDFRM; + hcchar |= (!(frame & 1)) << 29 | HCCHAR_CHENA; + write_volatile(DOTG_HCCHAR(channel as usize), hcchar); +} + /** \brief Prepares a channel to communicated with a device. @@ -175,6 +189,12 @@ fn HcdPrepareChannel( dwc_sc.channel[channel as usize].characteristics.Enable = false; dwc_sc.channel[channel as usize].characteristics.Disable = false; dwc_sc.channel[channel as usize].characteristics.OddFrame = false; + if pipe.transfer_type == UsbTransfer::Interrupt { + //TODO: handling for isochronous + let frame = read_volatile(DOTG_HFNUM); + dwc_sc.channel[channel as usize].characteristics.OddFrame = frame & 1 == 0; + } + dwc_sc.channel[channel as usize] .characteristics .PacketsPerFrame = 1; @@ -188,8 +208,14 @@ fn HcdPrepareChannel( dwc_sc.channel[channel as usize].split_control.XactPos = 0; dwc_sc.channel[channel as usize].split_control.CompleteSplit = false; dwc_sc.channel[channel as usize].split_control.SplitEnable = false; - // if pipe.speed != UsbSpeed::High && device.parent.is_some() && unsafe { (*device.parent.unwrap()).speed == UsbSpeed::High && (*device.parent.unwrap()).parent.is_some() }{ - if pipe.speed != UsbSpeed::High { + if pipe.speed != UsbSpeed::High + && device.parent.is_some() + && unsafe { + (*device.parent.unwrap()).speed == UsbSpeed::High + && (*device.parent.unwrap()).parent.is_some() + } + { + // if pipe.speed != UsbSpeed::High { dwc_sc.channel[channel as usize].split_control.SplitEnable = true; if let Some(parent) = device.parent { unsafe { @@ -251,11 +277,15 @@ pub unsafe fn HcdTransmitChannel(device: &UsbDevice, channel: u8, buffer: *mut u ); } - let dma_address = 0x2FF0000 + 0x1000 * channel as usize; + let dma_base_phys = 0x2FF0000; + let dma_base_gpu = dma_base_phys | 0xC0000000; + let dma_address = dma_base_gpu + 0x1000 * channel as usize; let dma_loc = dwc_sc.dma_loc + 0x1000 * channel as usize; //copy from buffer to dma_loc for 32 bytes memory_copy(dma_loc as *mut u8, buffer, 100); + crate::arch::memory::invalidate_physical_buffer_for_device(dma_loc as *mut (), 128); + //print out the first 8 bytes stored in buffer // unsafe { // println!("Buffer: {:#x} {:#x} {:#x} {:#x} {:#x} {:#x} {:#x} {:#x}", *(buffer), *((buffer as *const u8).offset(1)), *((buffer as *const u8).offset(2)), *((buffer as *const u8).offset(3)), *((buffer as *const u8).offset(4)), *((buffer as *const u8).offset(5)), *((buffer as *const u8).offset(6)), *((buffer as *const u8).offset(7))); @@ -406,6 +436,7 @@ pub fn HcdChannelSendWaitOne( loop { if timeout == RequestTimeout { println!("| HCD: Request to device has timed out."); + printDWCErrors(channel as u32); device.error = UsbTransferError::ConnectionError; return ResultCode::ErrorTimeout; } @@ -430,7 +461,7 @@ pub fn HcdChannelSendWaitOne( if hcint & HCINT_ACK != 0 && dwc_sc.channel[channel as usize].split_control.SplitEnable { // Try to complete the split up to 3 times. - println!("| HCD: Completing split to device with ACK\n"); + // println!("| HCD: Completing split to device with ACK"); for tries_i in 0..3 { tries = tries_i; write_volatile(DOTG_HCINT(channel as usize), 0x3fff); @@ -459,7 +490,7 @@ pub fn HcdChannelSendWaitOne( timeout = 0; loop { if timeout == RequestTimeout { - println!("| HCD: Request split completion to ss has timed out.\n"); + println!("| HCD: Request split completion to ss has timed out."); device.error = UsbTransferError::ConnectionError; return ResultCode::ErrorTimeout; } @@ -475,16 +506,22 @@ pub fn HcdChannelSendWaitOne( if hcint & HCINT_NYET == 0 { break; } + // println!("| HCD: Request split completion failed, retrying."); } + // println!("| HCD: Request split completion made progress; hcint: {:#x}", hcint); + if tries == 3 { micro_delay(25000); continue; } else if hcint & HCINT_NAK != 0 { + // println!("| HCD: Request split completion NAK"); globalTries = globalTries.wrapping_sub(1); micro_delay(25000); continue; } else if hcint & HCINT_XACTERR != 0 { + // println!("| HCD: Request split completion XACTERR"); + printDWCErrors(channel as u32); micro_delay(25000); continue; } @@ -513,18 +550,6 @@ pub fn HcdChannelSendWaitOne( result = HcdChannelInterruptToError(device, hcint, false); if result != ResultCode::OK { - // LOG_DEBUGF( - // "HCD: Control message to %#x: %02x%02x%02x%02x %02x%02x%02x%02x.\n", - // *(pipe as *const u32), - // *((request as *const u8).offset(0)), - // *((request as *const u8).offset(1)), - // *((request as *const u8).offset(2)), - // *((request as *const u8).offset(3)), - // *((request as *const u8).offset(4)), - // *((request as *const u8).offset(5)), - // *((request as *const u8).offset(6)), - // *((request as *const u8).offset(7)), - // ); println!("| HCD: Request split completion to failed.\n"); return result; } @@ -543,20 +568,7 @@ pub fn HcdChannelSendWaitOne( !dwc_sc.channel[channel as usize].split_control.SplitEnable, ); if result != ResultCode::OK { - // LOG_DEBUGF( - // "HCD: Control message to %#x: %02x%02x%02x%02x %02x%02x%02x%02x.\n", - // *(pipe as *const u32), - // *((request as *const u8).offset(0)), - // *((request as *const u8).offset(1)), - // *((request as *const u8).offset(2)), - // *((request as *const u8).offset(3)), - // *((request as *const u8).offset(4)), - // *((request as *const u8).offset(5)), - // *((request as *const u8).offset(6)), - // *((request as *const u8).offset(7)), - // ); println!("HCD: Request to failed.\n"); - // shutdown(); return ResultCode::ErrorRetry; } } @@ -572,18 +584,6 @@ pub fn HcdChannelSendWaitOne( !dwc_sc.channel[channel as usize].split_control.SplitEnable, ); if result != ResultCode::OK { - // LOG_DEBUGF( - // "HCD: Control message to %#x: %02x%02x%02x%02x %02x%02x%02x%02x.\n", - // *(pipe as *const u32), - // *((request as *const u8).offset(0)), - // *((request as *const u8).offset(1)), - // *((request as *const u8).offset(2)), - // *((request as *const u8).offset(3)), - // *((request as *const u8).offset(4)), - // *((request as *const u8).offset(5)), - // *((request as *const u8).offset(6)), - // *((request as *const u8).offset(7)), - // ); println!("| HCD: Request to failed.\n"); return result; } @@ -663,6 +663,8 @@ fn HcdChannelSendWait( transfer = buffer_length - dwc_sc.channel[channel as usize].transfer_size.TransferSize; // println!("| HCD: Transfer to packet progress: {}/{} with packets {} from {}\n", transfer, buffer_length, dwc_sc.channel[channel as usize].transfer_size.PacketCount, packets); + // printDWCErrors(channel as u32); + // If the packet count hasn’t changed, break out of the loop. if packets == dwc_sc.channel[channel as usize].transfer_size.PacketCount { // println!("| HCD: Transfer to packet got stuck."); @@ -689,7 +691,7 @@ fn HcdChannelSendWait( } else { device.error = UsbTransferError::ConnectionError; } - + // println!("| HCD: Transfer to packet got stuck."); return ResultCode::ErrorDevice; } @@ -876,7 +878,7 @@ pub unsafe fn HcdSubmitBulkMessage( device, &mut tempPipe, channel, - dwc_sc.dma_phys[channel as usize] as *mut u8, + dwc_sc.dma_gpu_addr[channel as usize] as *mut u8, buffer_length, packet_id, ); @@ -910,7 +912,7 @@ pub unsafe fn HcdSubmitInterruptMessage( _reserved: 0, }; - let data_buffer = dwc_sc.dma_phys[channel as usize] as *mut u8; + let data_buffer = dwc_sc.dma_gpu_addr[channel as usize] as *mut u8; let result = HcdChannelSend( device, &mut tempPipe, @@ -928,6 +930,23 @@ pub unsafe fn HcdSubmitInterruptMessage( return ResultCode::OK; } +pub fn printDWCErrors(channel: u32) { + let hprt = read_volatile(DOTG_HPRT); + let gintsts = read_volatile(DOTG_GINTSTS); + let haint = read_volatile(DOTG_HAINT); + let hcint = read_volatile(DOTG_HCINT(channel as usize)); + let hcchar = read_volatile(DOTG_HCCHAR(channel as usize)); + let hctsiz = read_volatile(DOTG_HCTSIZ(channel as usize)); + + println!("| HCD hprt: {:#x}", hprt); + println!("| HCD gintsts: {:#x}", gintsts); + println!("| HCD haint: {:#x}", haint); + println!("| HCD hcint: {:#x}", hcint); + println!("| HCD hcchar: {:#x}", hcchar); + println!("| HCD hctsiz: {:#x}", hctsiz); + println!("| HCD channel: {:#x}\n", channel); +} + pub unsafe fn HcdSubmitControlMessage( device: &mut UsbDevice, pipe: UsbPipeAddress, @@ -935,6 +954,7 @@ pub unsafe fn HcdSubmitControlMessage( buffer_length: u32, request: &mut UsbDeviceRequest, ) -> ResultCode { + // println!("| HcdSubmitControlMessage for device {}", pipe.device); let roothub_device_number = unsafe { (*device.bus).roothub_device_number }; if pipe.device == roothub_device_number as u8 { return unsafe { HcdProcessRootHubMessage(device, pipe, buffer, buffer_length, request) }; @@ -957,6 +977,7 @@ pub unsafe fn HcdSubmitControlMessage( let request_buffer = request as *mut UsbDeviceRequest as *mut u8; // dwc_sc.channel[0].characteristics.MaximumPacketSize = 8; + let mut result; result = HcdChannelSendWait( device, @@ -973,6 +994,8 @@ pub unsafe fn HcdSubmitControlMessage( return result; } + let mut is_data1 = true; + if !buffer.is_null() { if pipe.direction == UsbDirection::Out { unsafe { @@ -991,7 +1014,12 @@ pub unsafe fn HcdSubmitControlMessage( tempPipe.direction = pipe.direction; let data_buffer = dwc_sc.databuffer.as_mut_ptr(); - + let pid = if is_data1 { + PacketId::Data1 + } else { + PacketId::Data0 + }; + is_data1 = !is_data1; result = HcdChannelSendWait( device, &mut tempPipe, @@ -999,10 +1027,13 @@ pub unsafe fn HcdSubmitControlMessage( data_buffer, buffer_length, request, - PacketId::Data1, + pid, ); if result != ResultCode::OK { println!("| HCD: Coult not send data to device\n"); + + printDWCErrors(0); + return result; } @@ -1045,6 +1076,12 @@ pub unsafe fn HcdSubmitControlMessage( tempPipe.direction = UsbDirection::Out; } + let pid = if is_data1 { + PacketId::Data1 + } else { + PacketId::Data0 + }; + // tempPipe.direction = UsbDirection::In; //TODO: This is necessary in Real hardware I think but QEMU doesn't fully handle it //https://elixir.bootlin.com/qemu/v9.0.2/source/hw/usb/hcd-dwc2.c#L346 @@ -1055,7 +1092,7 @@ pub unsafe fn HcdSubmitControlMessage( dwc_sc.databuffer.as_mut_ptr(), 0, request, - PacketId::Data1, + pid, ); if result != ResultCode::OK { // println!("| HCD: Could not send STATUS to device."); @@ -1120,7 +1157,8 @@ pub fn HcdReset() -> ResultCode { grstcl = read_volatile(DOTG_GRSTCTL); } - grstcl |= GRSTCTL_CSFTRST; + // grstcl |= GRSTCTL_CSFTRST; + grstcl = GRSTCTL_CSFTRST; write_volatile(DOTG_GRSTCTL, grstcl); count = 0; @@ -1185,31 +1223,186 @@ fn HcdReceiveFifoFlush() -> ResultCode { return ResultCode::OK; } -pub fn HcdStart(bus: &mut UsbBus) -> ResultCode { +pub fn ms_to_micro(ms: u32) -> u32 { + return ms * 1000; +} + +pub fn init_fifo() -> ResultCode { + let cfg3 = read_volatile(DOTG_GHWCFG3); + let mut fifo_size = 4 * (cfg3 >> 16); + + let fifo_regs = 4 * 16; + if fifo_size < fifo_regs { + panic!("| HCD ERROR: FIFO size is too small"); + } + + fifo_size -= fifo_regs; + fifo_size /= 2; + fifo_size &= !3; + + write_volatile(DOTG_GRXFSIZ, fifo_size); + let mut tx_start = fifo_size; + fifo_size /= 2; + + write_volatile(DOTG_GNPTXFSIZ, ((fifo_size / 4) << 16) | (tx_start / 4)); + tx_start += fifo_size; + + write_volatile(DOTG_HPTXFSIZ, ((fifo_size / 4) << 16) | (tx_start / 4)); + + write_volatile(DOTG_GINTMSK, GINTMSK_HCHINTMSK); + + if HcdTransmitFifoFlush(CoreFifoFlush::FlushAll) != ResultCode::OK { + return ResultCode::ErrorDevice; + } + + if HcdReceiveFifoFlush() != ResultCode::OK { + return ResultCode::ErrorDevice; + } + + ResultCode::OK +} + +pub fn DwcInit(bus: &mut UsbBus, base_addr: *mut ()) -> ResultCode { + unsafe { + dwc_otg_driver = DWC_OTG::init(base_addr); + } + + if mbox_set_power_on() != ResultCode::OK { + return ResultCode::ErrorDevice; + } + let dwc_sc: &mut dwc_hub = &mut *bus.dwc_sc; unsafe { - let dma_address = 0x2FF0000; - use crate::memory::map_physical_noncacheable; - let dma_loc = - map_physical_noncacheable(dma_address, 0x1000 * ChannelCount).as_ptr() as usize; + let dma_address_phys = 0x2FF0000; + let dma_address_gpu = dma_address_phys | 0xC0000000; + use crate::memory::map_device_block; + let dma_loc = map_device_block(dma_address_phys, 0x1000 * ChannelCount).as_ptr() as usize; + // map_device_block(dma_address, 0x1000 * ChannelCount).as_ptr() as usize; dwc_sc.dma_loc = dma_loc; //TODO: Temporay, move to somwhere elses println!( "| HCD: DMA address {:#x} mapped from {:#x} to {:#x}", - dma_address, + dma_address_gpu, dma_loc, dma_loc + 0x1000 * ChannelCount ); for i in 0..ChannelCount { dwc_sc.dma_addr[i as usize] = dma_loc + (i * 0x1000); - dwc_sc.dma_phys[i as usize] = dma_address + (i * 0x1000); + dwc_sc.dma_gpu_addr[i as usize] = dma_address_gpu + (i * 0x1000); } } - // println!("| HCD: Starting"); + dwc_otg_register_interrupt_handler(); + + let vendor_id = read_volatile(DOTG_GSNPSID); + let user_id = read_volatile(DOTG_GUID); + + println!("| HCD: Vendor ID: {:#x} User ID: {:#x}", vendor_id, user_id); + + let version = read_volatile(DOTG_GSNPSID); + println!("| HCD: Version: {:#x}", version); + + //disconnect + write_volatile(DOTG_DCTL, DCTL_SFTDISCON); + + //wait for disconnect + micro_delay(ms_to_micro(32)); + + write_volatile(DOTG_GRSTCTL, GRSTCTL_CSFTRST); + + //wait for reset + micro_delay(ms_to_micro(10)); + + write_volatile(DOTG_GUSBCFG, GUSBCFG_FORCEHOSTMODE); + write_volatile(DOTG_GOTGCTL, 0); + + //clear global NAK + write_volatile(DOTG_DCTL, DCTL_CGOUTNAK | DCTL_CGNPINNAK); + + //disable usb port + write_volatile(DOTG_PCGCCTL, 0xFFFFFFFF); + + micro_delay(ms_to_micro(10)); + + //enable usb port + write_volatile(DOTG_PCGCCTL, 0); + micro_delay(ms_to_micro(10)); + + if init_fifo() != ResultCode::OK { + println!("| HCD ERROR: Failed to init FIFO"); + return ResultCode::ErrorDevice; + } + + //setup clock + let mut hcfg = read_volatile(DOTG_HCFG); + hcfg &= !(HCFG_FSLSSUPP | HCFG_FSLSPCLKSEL_MASK); + hcfg |= (1 << HCFG_FSLSPCLKSEL_SHIFT) | HCFG_FSLSSUPP; + //Host clock: 30-60Mhz + write_volatile(DOTG_HCFG, hcfg); + + let hfir = 0xBB80; + write_volatile(DOTG_HFIR, hfir); + + write_volatile(DOTG_GAHBCFG, GAHBCFG_GLBLINTRMSK); + + let mut hport = read_volatile(DOTG_HPRT); + if (hport & HPRT_PRTPWR) == 0 { + println!("| HCD Powering on port"); + hport |= HPRT_PRTPWR; + write_volatile(DOTG_HPRT, hport); + micro_delay(10000); + } + + //Enable DMA + let mut gahbcfg = read_volatile(DOTG_GAHBCFG); + gahbcfg |= GAHBCFG_DMAEN | GAHBCFG_GLBLINTRMSK; + gahbcfg &= !(1 << 23); + write_volatile(DOTG_GAHBCFG, gahbcfg); + + let hcfg = read_volatile(DOTG_HCFG); + let h_dmaen = hcfg & (1 << 23); + let cfg4 = read_volatile(DOTG_GHWCFG4); + let c_dmad = cfg4 & (1 << 31); + let c_dmaen = cfg4 & (1 << 30); + let gahbcfg = read_volatile(DOTG_GAHBCFG); + let g_dmaen = gahbcfg & GAHBCFG_DMAEN; + let gsnpsid = read_volatile(DOTG_GSNPSID); + + println!( + "| HCD: DMA enabled: {}, DMA description: {}, dma en {}, gdmaen {}, GSNPSID: {:#x}", + h_dmaen, + c_dmad, + c_dmaen, + g_dmaen, + gsnpsid & 0xfff + ); + + ResultCode::OK +} + +pub fn HcdStart(bus: &mut UsbBus) -> ResultCode { + let dwc_sc: &mut dwc_hub = &mut *bus.dwc_sc; + + unsafe { + let dma_address_phys = 0x2FF0000; + let dma_address_gpu = dma_address_phys | 0xC0000000; + use crate::memory::map_device_block; + let dma_loc = map_device_block(dma_address_phys, 0x1000 * ChannelCount).as_ptr() as usize; + dwc_sc.dma_loc = dma_loc; //TODO: Temporay, move to somwhere elses + println!( + "| HCD: DMA address {:#x} mapped from {:#x} to {:#x}", + dma_address_gpu, + dma_loc, + dma_loc + 0x1000 * ChannelCount + ); + for i in 0..ChannelCount { + dwc_sc.dma_addr[i as usize] = dma_loc + (i * 0x1000); + dwc_sc.dma_gpu_addr[i as usize] = dma_address_gpu + (i * 0x1000); + } + } write_volatile(DOTG_DCTL, 1 << 1); - micro_delay(1000); + micro_delay(32000); let mut gusbcfg = read_volatile(DOTG_GUSBCFG); gusbcfg &= !(GUSBCFG_ULPIEXTVBUSDRV | GUSBCFG_TERMSELDLPULSE); @@ -1228,6 +1421,7 @@ pub fn HcdStart(bus: &mut UsbBus) -> ResultCode { gusbcfg &= !GUSBCFG_PHYIF; write_volatile(DOTG_GUSBCFG, gusbcfg); HcdReset(); + println!("| HCD: Reset PHY"); } gusbcfg = read_volatile(DOTG_GUSBCFG); @@ -1268,18 +1462,25 @@ pub fn HcdStart(bus: &mut UsbBus) -> ResultCode { } write_volatile(DOTG_GUSBCFG, gusbcfg); + write_volatile(DOTG_PCGCCTL, 0xFFFFFFFF); + + micro_delay(30000); + write_volatile(DOTG_PCGCCTL, 0); + micro_delay(30000); + let mut hcfg = read_volatile(DOTG_HCFG); //FSPhyType = Dedicated full-speed interface 2'b01 //HSPhyType = UTMI+ 2'b01 - hcfg &= !HCFG_FSLSPCLKSEL_MASK; + hcfg &= !(HCFG_FSLSSUPP | HCFG_FSLSPCLKSEL_MASK); + hcfg |= (1 << HCFG_FSLSPCLKSEL_SHIFT) | HCFG_FSLSSUPP; //Host clock: 30-60Mhz write_volatile(DOTG_HCFG, hcfg); - hcfg = read_volatile(DOTG_HCFG); - hcfg |= HCFG_FSLSSUPP; //Sets speed for FS/LS devices, no HS devices - write_volatile(DOTG_HCFG, hcfg); + // hcfg = read_volatile(DOTG_HCFG); + // hcfg |= HCFG_FSLSSUPP; //Sets speed for FS/LS devices, no HS devices + // write_volatile(DOTG_HCFG, hcfg); let h_dmaen = hcfg & (1 << 23); let cfg4 = read_volatile(DOTG_GHWCFG4); @@ -1328,6 +1529,7 @@ pub fn HcdStart(bus: &mut UsbBus) -> ResultCode { (read_volatile(DOTG_GHWCFG2) & GHWCFG2_NUMHSTCHNL_MASK) >> GHWCFG2_NUMHSTCHNL_SHIFT; for channel in 0..num_hst_chans { + write_volatile(DOTG_HCINT(channel as usize), 0xFFFFFFFF); let mut chan = read_volatile(DOTG_HCCHAR(channel as usize)); chan |= HCCHAR_EPDIR_IN | HCCHAR_CHDIS; chan &= !HCCHAR_CHENA; @@ -1341,37 +1543,59 @@ pub fn HcdStart(bus: &mut UsbBus) -> ResultCode { write_volatile(DOTG_HCCHAR(channel as usize), chan); let mut timeout = 0; - chan = read_volatile(DOTG_HCCHAR(channel as usize)); - while (chan & HCCHAR_CHENA) != 0 { + // chan = read_volatile(DOTG_HCCHAR(channel as usize)); + let mut chan_int = read_volatile(DOTG_HCINT(channel as usize)); + while (chan_int & HCINT_CHHLTD) == 0 { timeout += 1; if timeout > 0x100000 { println!("| HCD Start ERROR: Channel {} failed to halt", channel); } - chan = read_volatile(DOTG_HCCHAR(channel as usize)); + chan_int = read_volatile(DOTG_HCINT(channel as usize)); } + // while (chan & HCCHAR_CHENA) != 0 { + // timeout += 1; + // if timeout > 0x100000 { + // println!("| HCD Start ERROR: Channel {} failed to halt", channel); + // } + // chan = read_volatile(DOTG_HCCHAR(channel as usize)); + // } } } let mut hport = read_volatile(DOTG_HPRT); - if (hport & HPRT_PRTCONNSTS) == 0 { + if (hport & HPRT_PRTPWR) == 0 { println!("| HCD Powering on port"); hport |= HPRT_PRTPWR; write_volatile(DOTG_HPRT, hport & (0x1f140 | 0x1000)); + micro_delay(10000); + } + + // Wait for device connection (optional debounce) + for _ in 0..100 { + let h = read_volatile(DOTG_HPRT); + if (h & HPRT_PRTCONNSTS) != 0 { + break; + } + micro_delay(1000); // wait 1ms } write_volatile(DOTG_GINTSTS, 0xFFFFFFFF); - dwc_otg_register_interrupt_handler(); + + micro_delay(10000); write_volatile(DOTG_GINTMSK, GINTMSK_HCHINTMSK); write_volatile(DOTG_GINTSTS, 1); write_volatile(DOTG_GAHBCFG, GAHBCFG_GLBLINTRMSK); + // hport = read_volatile(DOTG_HPRT); // hport |= HPRT_PRTRST; - // write_volatile(DOTG_HPRT, hport & (0x1f140 | 0x100)); + // write_volatile(DOTG_HPRT, hport); // micro_delay(50000); // hport &= !HPRT_PRTRST; - // write_volatile(DOTG_HPRT, hport & (0x1f140 | 0x100)); + // write_volatile(DOTG_HPRT, hport); + // micro_delay(50000); + return ResultCode::OK; } @@ -1433,10 +1657,13 @@ pub fn HcdInitialize(_bus: &mut UsbBus, base_addr: *mut ()) -> ResultCode { } pub fn read_volatile(reg: usize) -> u32 { - unsafe { core::ptr::read_volatile((dwc_otg_driver.base_addr + reg) as *mut u32) } + let ptr = unsafe { (dwc_otg_driver.base_addr + reg) as *mut u32 }; + let val = unsafe { core::ptr::read_volatile(ptr) }; + val } pub fn write_volatile(reg: usize, val: u32) { - unsafe { core::ptr::write_volatile((dwc_otg_driver.base_addr + reg) as *mut u32, val) } + let ptr = unsafe { (dwc_otg_driver.base_addr + reg) as *mut u32 }; + unsafe { core::ptr::write_volatile(ptr, val) }; } pub fn get_dwc_ptr(offset: usize) -> *mut u32 { @@ -1489,7 +1716,7 @@ pub fn dwc_otg_free_channel(channel: u32) { } pub struct DwcChannelCallback { - pub callback: [Option; ChannelCount], + pub callback: [Option bool>; ChannelCount], pub endpoint_descriptors: [Option; ChannelCount], } @@ -1526,7 +1753,7 @@ pub struct dwc_hub { pub databuffer: [u8; 1024], pub phy_initialised: bool, pub dma_loc: usize, - pub dma_phys: [usize; ChannelCount], + pub dma_gpu_addr: [usize; ChannelCount], pub dma_addr: [usize; ChannelCount], pub channel: [host_channel; ChannelCount], } @@ -1641,7 +1868,7 @@ impl dwc_hub { databuffer: [0; 1024], phy_initialised: false, dma_loc: 0, - dma_phys: [0; ChannelCount], + dma_gpu_addr: [0; ChannelCount], dma_addr: [0; ChannelCount], channel: [host_channel::default(); ChannelCount], } diff --git a/crates/kernel/src/device/usb/hcd/dwc/roothub.rs b/crates/kernel/src/device/usb/hcd/dwc/roothub.rs index c85ae43c..2f22250b 100644 --- a/crates/kernel/src/device/usb/hcd/dwc/roothub.rs +++ b/crates/kernel/src/device/usb/hcd/dwc/roothub.rs @@ -58,12 +58,12 @@ const DeviceDescriptor: UsbDeviceDescriptor = UsbDeviceDescriptor { class: DeviceClass::DeviceClassHub, subclass: 0, protocol: 0, - max_packet_size0: 8, + max_packet_size0: 64, vendor_id: 0, product_id: 0, version: 0x0100, - manufacturer: 0, - product: 1, + manufacturer: 1, + product: 2, serial_number: 0, configuration_count: 1, }; @@ -129,7 +129,7 @@ const HUB_DESCRIPTOR: HubDescriptor = HubDescriptor { DescriptorType: DescriptorType::Hub, PortCount: 1, Attributes: 0, - PowerGoodDelay: 0, + PowerGoodDelay: 50, MaximumHubPower: 0, Data: [0x01, 0xff], }; @@ -278,22 +278,33 @@ pub unsafe fn HcdProcessRootHubMessage( 0x23 => { match request.value { 4 => { - //FeatureReset - let mut pwr = read_volatile(DOTG_PCGCCTL); - pwr &= !(1 << 5); - pwr &= !(1 << 0); - write_volatile(DOTG_PCGCCTL, pwr); - write_volatile(DOTG_PCGCCTL, 0); + // println!("Roothub Exec: Port Reset"); - let mut hprt = read_volatile(DOTG_HPRT); - hprt &= !HPRT_PRTSUSP; - hprt |= HPRT_PRTRST; - hprt |= HPRT_PRTPWR; - write_volatile(DOTG_HPRT, hprt & (0x1f140 | 0x1180)); - micro_delay(60000); + let hprt = read_volatile(DOTG_HPRT); + write_volatile(DOTG_HPRT, hprt | HPRT_PRTRST); - hprt &= !HPRT_PRTRST; - write_volatile(DOTG_HPRT, hprt & (0x1f140 | 0x1000)); + micro_delay(ms_to_micro(63)); + + write_volatile(DOTG_HPRT, hprt); + micro_delay(ms_to_micro(63)); + + init_fifo(); + // //FeatureReset + // let mut pwr = read_volatile(DOTG_PCGCCTL); + // pwr &= !(1 << 5); + // pwr &= !(1 << 0); + // write_volatile(DOTG_PCGCCTL, pwr); + // write_volatile(DOTG_PCGCCTL, 0); + + // let mut hprt = read_volatile(DOTG_HPRT); + // hprt &= !HPRT_PRTSUSP; + // hprt |= HPRT_PRTRST; + // hprt |= HPRT_PRTPWR; + // write_volatile(DOTG_HPRT, hprt & (0x1f140 | 0x1180)); + // micro_delay(60000); + + // hprt &= !HPRT_PRTRST; + // write_volatile(DOTG_HPRT, hprt & (0x1f140 | 0x1000)); } 8 => { //FeaturePower diff --git a/crates/kernel/src/device/usb/hcd/hub.rs b/crates/kernel/src/device/usb/hcd/hub.rs index ac48bf60..888b4775 100644 --- a/crates/kernel/src/device/usb/hcd/hub.rs +++ b/crates/kernel/src/device/usb/hcd/hub.rs @@ -23,7 +23,7 @@ use bitflags::bitflags; 11.23.2.1. */ #[repr(C, packed)] -#[derive(Default)] +#[derive(Default, Debug)] pub struct HubDescriptor { pub DescriptorLength: u8, // +0x0 pub DescriptorType: DescriptorType, // +0x1 diff --git a/crates/kernel/src/device/usb/usbd/device.rs b/crates/kernel/src/device/usb/usbd/device.rs index 2e39947e..e9965d21 100644 --- a/crates/kernel/src/device/usb/usbd/device.rs +++ b/crates/kernel/src/device/usb/usbd/device.rs @@ -97,7 +97,7 @@ impl UsbDevice { pub unsafe fn new(bus: *mut UsbBus, num: u32) -> Self { Self { number: num, - speed: UsbSpeed::Low, + speed: UsbSpeed::Full, status: UsbDeviceStatus::Attached, error: UsbTransferError::NoError, port_number: 0, diff --git a/crates/kernel/src/device/usb/usbd/endpoint.rs b/crates/kernel/src/device/usb/usbd/endpoint.rs index 57707c97..b1c65340 100644 --- a/crates/kernel/src/device/usb/usbd/endpoint.rs +++ b/crates/kernel/src/device/usb/usbd/endpoint.rs @@ -8,10 +8,12 @@ */ use crate::device::usb; +use crate::device::usb::hcd::dwc::dwc_otg::UpdateDwcOddFrame; +use crate::device::usb::hcd::dwc::dwc_otgreg::HCINT_FRMOVRUN; use crate::device::usb::UsbSendInterruptMessage; use usb::dwc_hub; use usb::hcd::dwc::dwc_otg::HcdUpdateTransferSize; -use usb::hcd::dwc::dwc_otgreg::{HCINT_CHHLTD, HCINT_NAK, HCINT_XFERCOMPL}; +use usb::hcd::dwc::dwc_otgreg::{HCINT_ACK, HCINT_CHHLTD, HCINT_NAK, HCINT_XFERCOMPL}; use usb::types::*; use usb::usbd::device::*; use usb::usbd::pipe::*; @@ -23,7 +25,11 @@ use crate::sync::time::{interval, MissedTicks}; use alloc::boxed::Box; -pub fn finish_bulk_endpoint_callback_in(endpoint: endpoint_descriptor, hcint: u32, channel: u8) { +pub fn finish_bulk_endpoint_callback_in( + endpoint: endpoint_descriptor, + hcint: u32, + channel: u8, +) -> bool { let device = unsafe { &mut *endpoint.device }; let transfer_size = HcdUpdateTransferSize(device, channel); @@ -65,9 +71,14 @@ pub fn finish_bulk_endpoint_callback_in(endpoint: endpoint_descriptor, hcint: u3 endpoint.device_endpoint_number ); } + return true; } -pub fn finish_bulk_endpoint_callback_out(endpoint: endpoint_descriptor, hcint: u32, channel: u8) { +pub fn finish_bulk_endpoint_callback_out( + endpoint: endpoint_descriptor, + hcint: u32, + channel: u8, +) -> bool { let device = unsafe { &mut *endpoint.device }; let transfer_size = HcdUpdateTransferSize(device, channel); device.last_transfer = endpoint.buffer_length - transfer_size; @@ -91,9 +102,15 @@ pub fn finish_bulk_endpoint_callback_out(endpoint: endpoint_descriptor, hcint: u endpoint.device_endpoint_number ); } + + return true; } -pub fn finish_interrupt_endpoint_callback(endpoint: endpoint_descriptor, hcint: u32, channel: u8) { +pub fn finish_interrupt_endpoint_callback( + endpoint: endpoint_descriptor, + hcint: u32, + channel: u8, +) -> bool { let device = unsafe { &mut *endpoint.device }; let transfer_size = HcdUpdateTransferSize(device, channel); device.last_transfer = endpoint.buffer_length - transfer_size; @@ -115,6 +132,10 @@ pub fn finish_interrupt_endpoint_callback(endpoint: endpoint_descriptor, hcint: let buffer_length = device.last_transfer.clamp(0, 8); let mut buffer = Box::new_uninit_slice(buffer_length as usize); + if hcint & HCINT_ACK != 0 { + endpoint_device.endpoint_pid[endpoint.device_endpoint_number as usize] += 1; + } + if hcint & HCINT_NAK != 0 { //NAK received, do nothing assert_eq!(buffer_length, 0); @@ -128,8 +149,17 @@ pub fn finish_interrupt_endpoint_callback(endpoint: endpoint_descriptor, hcint: buffer_length as usize, ); } + } else if hcint & HCINT_FRMOVRUN != 0 { + //Frame overrun + UpdateDwcOddFrame(channel); + + return false; } else { - panic!("| Endpoint {}: Unknown interrupt, aborting.", channel); + println!( + "| Endpoint {}: Unknown interrupt, ignoring {}.", + channel, hcint + ); + return true; } let mut buffer = unsafe { buffer.assume_init() }; @@ -142,6 +172,7 @@ pub fn finish_interrupt_endpoint_callback(endpoint: endpoint_descriptor, hcint: endpoint.device_endpoint_number ); } + return true; } pub fn interrupt_endpoint_callback(endpoint: endpoint_descriptor) { @@ -156,12 +187,19 @@ pub fn interrupt_endpoint_callback(endpoint: endpoint_descriptor) { _reserved: 0, }; + let endpoint_device = device.driver_data.downcast::().unwrap(); + let pid = if endpoint_device.endpoint_pid[endpoint.device_endpoint_number as usize] % 2 == 0 { + PacketId::Data0 + } else { + PacketId::Data1 + }; + let result = unsafe { UsbSendInterruptMessage( device, pipe, 8, - PacketId::Data0, + pid, endpoint.timeout, finish_interrupt_endpoint_callback, endpoint, @@ -245,6 +283,7 @@ impl UsbEndpointDevice { pub fn new() -> Self { UsbEndpointDevice { endpoints: [None; 5], + endpoint_pid: [0; 5], } } } @@ -252,4 +291,5 @@ impl UsbEndpointDevice { pub struct UsbEndpointDevice { //TODO: update for better?: The 5 is an arbitrary number pub endpoints: [Option; 5], + pub endpoint_pid: [usize; 5], } diff --git a/crates/kernel/src/device/usb/usbd/request.rs b/crates/kernel/src/device/usb/usbd/request.rs index a497edf9..3308e94f 100644 --- a/crates/kernel/src/device/usb/usbd/request.rs +++ b/crates/kernel/src/device/usb/usbd/request.rs @@ -18,7 +18,7 @@ /// parameters, and so are best implemented with a structure. As per usual, /// since this structure is arbitrary, we shall match Linux in the hopes of /// achieving some compatibility. -#[repr(C, packed)] +#[repr(C, align(8))] #[derive(Debug, Clone, Copy)] pub struct UsbDeviceRequest { pub request_type: u8, // +0x0 diff --git a/crates/kernel/src/device/usb/usbd/transfer.rs b/crates/kernel/src/device/usb/usbd/transfer.rs index c3d57e93..283d1ab7 100644 --- a/crates/kernel/src/device/usb/usbd/transfer.rs +++ b/crates/kernel/src/device/usb/usbd/transfer.rs @@ -70,7 +70,7 @@ pub struct UsbXfer { pub endpoint_descriptor: endpoint_descriptor, pub buffer: Option>, pub buffer_length: u32, - pub callback: Option, + pub callback: Option bool>, pub packet_id: PacketId, pub pipe: UsbPipeAddress, } diff --git a/crates/kernel/src/device/usb/usbd/usbd.rs b/crates/kernel/src/device/usb/usbd/usbd.rs index 6df6bae7..e0f0b575 100644 --- a/crates/kernel/src/device/usb/usbd/usbd.rs +++ b/crates/kernel/src/device/usb/usbd/usbd.rs @@ -55,13 +55,8 @@ pub fn UsbInitialise(bus: &mut UsbBus, base_addr: *mut ()) -> ResultCode { return ResultCode::ErrorCompiler; } - if HcdInitialize(bus, base_addr) != ResultCode::OK { - println!("Error: HcdInitialize failed"); - return ResultCode::ErrorDevice; - } - - if HcdStart(bus) != ResultCode::OK { - println!("Error: HcdStart failed"); + if DwcInit(bus, base_addr) != ResultCode::OK { + println!("Error: DwcInit failed"); return ResultCode::ErrorDevice; } @@ -170,7 +165,7 @@ pub unsafe fn UsbSendInterruptMessage( buffer_length: u32, packet_id: PacketId, _timeout_: u32, - callback: fn(endpoint_descriptor, u32, u8), + callback: fn(endpoint_descriptor, u32, u8) -> bool, endpoint: endpoint_descriptor, ) -> ResultCode { let b = Box::new(UsbXfer { @@ -306,12 +301,19 @@ pub unsafe fn UsbGetDescriptor( }; if result != ResultCode::OK { - println!("| USBD: Failed to get descriptor"); + println!( + "| USBD: Failed to get descriptor {} {}", + device.last_transfer, minimumLength + ); return result; } if device.last_transfer < minimumLength { - println!("| USBD: Descriptor too short"); + println!( + "| USBD: Descriptor too short {} {}", + device.last_transfer, minimumLength + ); + printDWCErrors(0); return ResultCode::ErrorDevice; } @@ -356,7 +358,6 @@ fn UsbReadDeviceDescriptor(device: &mut UsbDevice) -> ResultCode { }; } else if device.speed == UsbSpeed::Full { device.descriptor.max_packet_size0 = 64; - // device.descriptor.max_packet_size0 = 8; result = unsafe { UsbGetDescriptor( device, @@ -370,6 +371,8 @@ fn UsbReadDeviceDescriptor(device: &mut UsbDevice) -> ResultCode { ) }; if result != ResultCode::OK { + //print the device descriptor + println!("| USBD: failed device descriptor {:?}", device.descriptor); return result; } @@ -390,7 +393,6 @@ fn UsbReadDeviceDescriptor(device: &mut UsbDevice) -> ResultCode { }; } else { device.descriptor.max_packet_size0 = 64; - // device.descriptor.max_packet_size0 = 8; return unsafe { UsbGetDescriptor( device, @@ -407,7 +409,6 @@ fn UsbReadDeviceDescriptor(device: &mut UsbDevice) -> ResultCode { } fn UsbSetAddress(device: &mut UsbDevice, address: u8) -> ResultCode { - // println!("| USBD: Set device address to {}", address); if device.status != UsbDeviceStatus::Default { println!("| USBD: Device not in default state"); return ResultCode::ErrorDevice; @@ -624,33 +625,32 @@ fn UsbConfigure(device: &mut UsbDevice, configuration: u8) -> ResultCode { pub fn UsbAttachDevice(device: &mut UsbDevice) -> ResultCode { let bus = unsafe { &mut *(device.bus) }; - // println!("| USBD: Attaching device {}", device.number); - let address = device.number; device.number = 0; let mut result = UsbReadDeviceDescriptor(device); - //print USB device descriptor - // println!("| USBD: Device descriptor:\n {:#?}", device.descriptor); + if result != ResultCode::OK { println!("| USBD: Failed to read device descriptor"); + return result; } + device.status = UsbDeviceStatus::Default; - if let Some(parent) = device.parent { - unsafe { - if let Some(device_child_reset) = (*parent).device_child_reset { - result = device_child_reset(&mut *parent, device); - if result != ResultCode::OK { - println!("| USBD: Failed to reset parent device"); - return result; - } - } - } - } else { - // println!("| USBD: No parent device"); - } + // if let Some(parent) = device.parent { + // unsafe { + // if let Some(device_child_reset) = (*parent).device_child_reset { + // result = device_child_reset(&mut *parent, device); + // if result != ResultCode::OK { + // println!("| USBD: Failed to reset parent device"); + // return result; + // } + // } + // } + // } else { + // println!("| USBD: No parent device"); + // } result = UsbSetAddress(device, address as u8); if result != ResultCode::OK { @@ -661,11 +661,12 @@ pub fn UsbAttachDevice(device: &mut UsbDevice) -> ResultCode { device.number = address; result = UsbReadDeviceDescriptor(device); + if result != ResultCode::OK { println!("| USBD: Failed to read device descriptor"); return result; } - // println!("| USBD: Device descriptor:\n {:#?}", device.descriptor); + println!("| USBD: Device descriptor: {:?}", device.descriptor); let vendor_id = device.descriptor.vendor_id; let product_id = device.descriptor.product_id; @@ -680,10 +681,10 @@ pub fn UsbAttachDevice(device: &mut UsbDevice) -> ResultCode { return result; } - // println!( - // "\n Device interface class: {} at device number {}\n", - // device.interfaces[0].class as u16, device.number - // ); + println!( + "\n Device interface class: {} at device number {}\n", + device.interfaces[0].class as u16, device.number + ); if (device.interfaces[0].class as usize) < INTERFACE_CLASS_ATTACH_COUNT { // for j in 0..device.configuration.interface_count { @@ -698,7 +699,6 @@ pub fn UsbAttachDevice(device: &mut UsbDevice) -> ResultCode { // ); // } // } - if let Some(class_attach) = bus.interface_class_attach[device.interfaces[0].class as usize] { result = class_attach(device, 0); @@ -724,11 +724,35 @@ pub fn UsbAllocateDevice(mut devices: Box) -> ResultCode { device.error = UsbTransferError::NoError; device.port_number = 0; device.configuration_index = 0xff; + device.descriptor.max_packet_size0 = 8; for number in 0..MaximumDevices { if bus.devices[number].is_none() { // println!("| USBD: Allocating device {}", number); device.number = number as u32 + 1; + if device.number == 1 { + //Roothub -> get speed + use crate::device::usb::hcd::dwc::dwc_otgreg::DOTG_HPRT; + let hprt = read_volatile(DOTG_HPRT); + let _ = match (hprt >> 17) & 0b11 { + 0b00 => { + device.speed = UsbSpeed::High; + // device.speed = UsbSpeed::Full; + "High-Speed" + } + 0b01 => { + device.speed = UsbSpeed::Full; + "Full-Speed" + } + 0b10 => { + device.speed = UsbSpeed::Low; + "Low-Speed" + } + _ => { + panic!("| USBD: Unknown speed") + } + }; + } bus.devices[number] = Some(devices); break; } diff --git a/crates/kernel/src/event/async_handler.rs b/crates/kernel/src/event/async_handler.rs index 315e6a08..af9ae3d4 100644 --- a/crates/kernel/src/event/async_handler.rs +++ b/crates/kernel/src/event/async_handler.rs @@ -112,6 +112,11 @@ where let thread = unsafe { &mut *future.data.thread.get() }.take().unwrap(); CORES.with_current(|core| core.thread.set(Some(thread))); + let woken = task::TASKS.return_task(task_id, task::Task::new(future, priority)); + if woken { + event::SCHEDULER.add_task(event::Event::async_task(task_id, priority)); + } + // Return back to the user context ctx.as_ptr() } else { @@ -377,9 +382,13 @@ where let inner = unsafe { Pin::new_unchecked(this.inner.assume_init_mut()) }; let _context = core::task::ready!(inner.poll(ctx)); + + // Finished running the task; if the thread wasn't detatched / resumed + // separately, schedule it now. if !this.data.in_handler.get() { - let thread = unsafe { &mut *this.data.thread.get() }.take().unwrap(); - event::SCHEDULER.add_task(event::Event::schedule_thread(thread)); + if let Some(thread) = unsafe { &mut *this.data.thread.get() }.take() { + event::SCHEDULER.add_task(event::Event::schedule_thread(thread)); + } } ().into() } diff --git a/crates/kernel/src/event/exceptions.rs b/crates/kernel/src/event/exceptions.rs index e0e5b8ea..25a7fa03 100644 --- a/crates/kernel/src/event/exceptions.rs +++ b/crates/kernel/src/event/exceptions.rs @@ -1,8 +1,9 @@ use core::arch::{asm, global_asm}; -use super::context::{deschedule_thread, Context, DescheduleAction, CORES}; +use super::context::Context; use crate::arch::halt; use crate::sync::HandlerTableInner; +use crate::syscall::proc::exit_current_user_thread; use crate::uart; global_asm!( @@ -263,6 +264,8 @@ unsafe extern "C" fn exception_handler_example( println!("{:#?}", ctx); } + // crate::device::LED_OUT.get().put(exception_class as u8); + match exception_class { _ => halt(), } @@ -276,6 +279,7 @@ unsafe extern "C" fn exception_handler_unhandled( _esr: u64, _arg: u64, ) -> *mut Context { + // crate::device::LED_OUT.get().put(0b11100111); halt(); } @@ -311,10 +315,7 @@ unsafe extern "C" fn exception_handler_user( } println!("Unknown syscall number {arg:#x}; stopping user thread"); - let thread = CORES.with_current(|core| core.thread.take()); - let mut thread = thread.expect("usermode syscall without active thread"); - unsafe { thread.save_context(ctx.into(), false) }; - unsafe { deschedule_thread(DescheduleAction::FreeThread, Some(thread)) } + unsafe { exit_current_user_thread(ctx, (-1i32) as u32) } } } 0x24 => { @@ -328,9 +329,8 @@ unsafe extern "C" fn exception_handler_user( println!("ttbr0={ttbr0:#010x}"); println!("{:#?}", ctx); } - let thread = CORES.with_current(|core| core.thread.take()); - let thread = thread.expect("usermode exception without active thread"); - unsafe { crate::syscall::proc::exit_exception(thread, ctx, u32::MAX) } + + unsafe { exit_current_user_thread(ctx, (-2i32) as u32) } } } } diff --git a/crates/kernel/src/event/mod.rs b/crates/kernel/src/event/mod.rs index 645fff64..1b5d5daa 100644 --- a/crates/kernel/src/event/mod.rs +++ b/crates/kernel/src/event/mod.rs @@ -149,6 +149,10 @@ pub unsafe fn timer_handler(ctx: &mut Context) -> *mut Context { ); } + // if thread.is_user_thread() { + // println!("Preempting user at elr: {:x}", ctx.elr); + // } + unsafe { thread.save_context(ctx.into(), thread.is_kernel_thread()) }; unsafe { deschedule_thread(DescheduleAction::Yield, Some(thread)) }; } diff --git a/crates/kernel/src/event/thread.rs b/crates/kernel/src/event/thread.rs index 4a8dfe6d..a0591488 100644 --- a/crates/kernel/src/event/thread.rs +++ b/crates/kernel/src/event/thread.rs @@ -220,6 +220,13 @@ impl Thread { ctx.kernel_sp = core_sp; } } + + pub fn set_exited(&mut self, status: u32) { + let exit_code = &self.process.as_ref().unwrap().exit_code; + exit_code.set(crate::process::ExitStatus { + status: status as u32, + }); + } } impl Drop for Thread { diff --git a/crates/kernel/src/lib.rs b/crates/kernel/src/lib.rs index 4ba1742d..854b9187 100644 --- a/crates/kernel/src/lib.rs +++ b/crates/kernel/src/lib.rs @@ -45,6 +45,7 @@ unsafe extern "Rust" { pub unsafe extern "C" fn kernel_entry_rust(x0: u32, _x1: u64, _x2: u64, _x3: u64, x4: u32) -> ! { unsafe { memory::init() }; let id = arch::core_id() & 3; + unsafe { sync::enable_interrupts() }; // TODO: proper heap allocator, and physical memory allocation for heap space let heap_base = &raw mut arch::memory::vmm::__rpi_virt_binary_end_addr; @@ -108,6 +109,8 @@ pub unsafe extern "C" fn kernel_entry_rust(x0: u32, _x1: u64, _x2: u64, _x3: u64 #[unsafe(no_mangle)] pub unsafe extern "C" fn kernel_entry_rust_alt(_x0: u32, _x1: u64, _x2: u64, _x3: u64) -> ! { + unsafe { sync::enable_interrupts() }; + unsafe { crate::arch::memory::vmm::switch_to_kernel_48bit() }; let id = arch::core_id() & 3; diff --git a/crates/kernel/src/process/mem.rs b/crates/kernel/src/process/mem.rs index 093cc187..313821c4 100644 --- a/crates/kernel/src/process/mem.rs +++ b/crates/kernel/src/process/mem.rs @@ -9,8 +9,9 @@ use crate::arch::memory::vmm::{ PAGE_SIZE, USER_PG_SZ, }; use crate::event::async_handler::{run_async_handler, HandlerContext}; -use crate::event::context::{deschedule_thread, Context, DescheduleAction}; +use crate::event::context::Context; use crate::event::exceptions::DataAbortISS; +use crate::syscall::proc::exit_user_thread; use super::fd::ArcFd; @@ -72,7 +73,7 @@ impl UserAddrSpace { unsafe { asm!("mrs {0}, TTBR0_EL1", out(reg) active_page_dir); if active_page_dir != old_page_dir { - asm!("msr TTBR0_EL1, {0}", "dsb sy", "tlbi vmalle1is", "dsb sy", in(reg) old_page_dir); + asm!("msr TTBR0_EL1, {0}", "isb", "dsb sy", "tlbi vmalle1is", "dsb sy", in(reg) old_page_dir); } } @@ -98,16 +99,16 @@ impl UserAddrSpace { let buf_ptr: *mut u8 = buffer.as_mut_ptr().cast(); unsafe { copy_nonoverlapping(src_data.byte_add(offset), buf_ptr, chunk_size); - asm!("msr TTBR0_EL1, {0}", "dsb sy", "tlbi vmalle1is", "dsb sy", in(reg) new_page_dir); + asm!("msr TTBR0_EL1, {0}", "isb", "dsb sy", "tlbi vmalle1is", "dsb sy", in(reg) new_page_dir); copy_nonoverlapping(buf_ptr, dst_data.byte_add(offset), chunk_size); - asm!("msr TTBR0_EL1, {0}", "dsb sy", "tlbi vmalle1is", "dsb sy", in(reg) old_page_dir); + asm!("msr TTBR0_EL1, {0}", "isb", "dsb sy", "tlbi vmalle1is", "dsb sy", in(reg) old_page_dir); } } } if active_page_dir != old_page_dir { unsafe { - asm!("msr TTBR0_EL1, {0}", "dsb sy", "tlbi vmalle1is", "dsb sy", in(reg) active_page_dir); + asm!("msr TTBR0_EL1, {0}", "isb", "dsb sy", "tlbi vmalle1is", "dsb sy", in(reg) active_page_dir); } } @@ -327,7 +328,7 @@ pub fn page_fault_handler(ctx: &mut Context, far: usize, _iss: DataAbortISS) -> println!("{:#?}", &*context.regs()); let thread = context.detach_thread(); - unsafe { deschedule_thread(DescheduleAction::FreeThread, Some(thread)) } + unsafe { exit_user_thread(thread, -4i32 as u32) } } Some(vme) => { mem.populate_page(vme, page_addr).await.unwrap(); // TODO: errors? diff --git a/crates/kernel/src/runtime.rs b/crates/kernel/src/runtime.rs index b85148ef..7c3e224f 100644 --- a/crates/kernel/src/runtime.rs +++ b/crates/kernel/src/runtime.rs @@ -36,9 +36,10 @@ fn panic_handler(info: &core::panic::PanicInfo) -> ! { // TODO: write error message to a fixed location in memory and reset? if crate::device::WATCHDOG.is_initialized() { + // crate::device::LED_OUT.get().put(0b00011000); // Shut down the system let mut watchdog = crate::device::WATCHDOG.get().lock(); - unsafe { watchdog.reset(63) }; + unsafe { watchdog.reset(0) }; } halt(); } diff --git a/crates/kernel/src/syscall/exec.rs b/crates/kernel/src/syscall/exec.rs index d2fde316..4c147f37 100644 --- a/crates/kernel/src/syscall/exec.rs +++ b/crates/kernel/src/syscall/exec.rs @@ -139,6 +139,15 @@ pub unsafe fn sys_execve_fd(ctx: &mut Context) -> *mut Context { mapping[..data.len()].copy_from_slice(data); // TODO: make sure anonymous pages are zeroed mapping[data.len()..].fill(0); + + // if phdr.p_flags.execute() { + // TODO: figure out proper cache flush subset; this shouldn't + // be needed (except maybe for the executable parts) + let range = mapping.as_ptr_range(); + unsafe { + crate::arch::memory::flush_range(range.start.addr(), range.end.addr()) + }; + // } } } }; @@ -146,7 +155,7 @@ pub unsafe fn sys_execve_fd(ctx: &mut Context) -> *mut Context { let stack_size = 0x20_0000; let stack_start = 0x100_0000; - new_mem + let base = new_mem .mmap( Some(stack_start - stack_size), stack_size, @@ -159,9 +168,9 @@ pub unsafe fn sys_execve_fd(ctx: &mut Context) -> *mut Context { let mut argv = 0; let setup_stack = async { // println!("In stack callback"); - let stack_vme = new_mem.get_vme(stack_start - stack_size).unwrap(); + let stack_vme = new_mem.get_vme(base).unwrap(); new_mem - .populate_range(stack_vme, stack_start - stack_size, stack_size) + .populate_range(stack_vme, stack_vme.start, stack_vme.size) .await .unwrap(); @@ -214,6 +223,16 @@ pub unsafe fn sys_execve_fd(ctx: &mut Context) -> *mut Context { let user_entry = elf.elf_header().e_entry(); + // println!("Exec returning to new process with ttbr0: {ttbr0:#x}, sp: {user_sp:#x}, entry: {user_entry:#x}"); + // print!("A"); + // crate::sync::spin_sleep(500_000); + // { + // let mut console = crate::device::CONSOLE.get().lock(); + // // console.surface.present(); + // core::hint::black_box(&mut *console.surface.buffer); + // } + // unsafe { core::arch::asm!("isb", "dsb sy", "tlbi vmalle1is", "dsb sy") }; + { let mut regs = context.regs(); regs.regs = [0; 31]; @@ -225,7 +244,6 @@ pub unsafe fn sys_execve_fd(ctx: &mut Context) -> *mut Context { context.user_regs().as_mut().unwrap().ttbr0_el1 = ttbr0; } - // println!("Jumping to user entry point: {user_entry:#x}"); context.resume_final() }) } diff --git a/crates/kernel/src/syscall/proc.rs b/crates/kernel/src/syscall/proc.rs index cc701dd3..315fb0c8 100644 --- a/crates/kernel/src/syscall/proc.rs +++ b/crates/kernel/src/syscall/proc.rs @@ -2,25 +2,43 @@ use alloc::boxed::Box; use alloc::sync::Arc; use crate::event::async_handler::{run_async_handler, run_event_handler, HandlerContext}; -use crate::event::context::{deschedule_thread, Context, DescheduleAction}; +use crate::event::context::{deschedule_thread, Context, DescheduleAction, CORES}; use crate::event::thread::Thread; use crate::process::fd::{self, FileDescriptor}; use crate::process::ExitStatus; use crate::sync::once_cell::BlockingOnceCell; use crate::{event, shutdown}; +const SHUTDOWN_ENABLED: bool = false; + pub unsafe fn sys_shutdown(ctx: &mut Context) -> *mut Context { - run_event_handler(ctx, move |_context: HandlerContext<'_>| { - shutdown(); + run_event_handler(ctx, move |context: HandlerContext<'_>| { + if SHUTDOWN_ENABLED { + shutdown(); + } else { + println!("Not shutting down..."); + let thread = context.detach_thread(); + let exit_code = &thread.process.as_ref().unwrap().exit_code; + exit_code.set(crate::process::ExitStatus { status: 0 as u32 }); + unsafe { deschedule_thread(DescheduleAction::FreeThread, Some(thread)) } + } }) } -pub unsafe fn exit_exception(mut thread: Box, ctx: &mut Context, status: u32) -> ! { - let exit_code = &thread.process.as_ref().unwrap().exit_code; - exit_code.set(crate::process::ExitStatus { - status: status as u32, - }); +pub unsafe fn exit_current_user_thread(ctx: &mut Context, status: u32) -> ! { + let thread = CORES.with_current(|core| core.thread.take()); + let mut thread = thread.expect("usermode syscall without active thread"); + + thread.last_context = core::ptr::NonNull::from(&mut *ctx); + unsafe { thread.save_user_regs() }; unsafe { thread.save_context(ctx.into(), false) }; + + unsafe { crate::sync::enable_interrupts() }; + unsafe { exit_user_thread(thread, status) } +} + +pub unsafe fn exit_user_thread(mut thread: Box, status: u32) -> ! { + thread.set_exited(status); unsafe { deschedule_thread(DescheduleAction::FreeThread, Some(thread)) } } @@ -68,7 +86,7 @@ pub unsafe fn sys_spawn(ctx: &mut Context) -> *mut Context { } println!( - "Creating new process with page dir {:#010x}", + "Creating new process with page dir {:#010x}, initial sp {user_sp:#x}, entry {user_entry:#x}", process.get_ttbr0() ); let mut user_thread = unsafe { Thread::new_user(process, user_sp, user_entry) };