diff --git a/examples/.cargo/config b/examples/.cargo/config new file mode 100644 index 0000000..b7cde2d --- /dev/null +++ b/examples/.cargo/config @@ -0,0 +1,7 @@ +[build] +target = "riscv64gc-unknown-none-elf" + +[target.riscv64gc-unknown-none-elf] +rustflags = [ + "-C", "link-arg=-Tsrc/boot/linker64.ld", +] diff --git a/examples/.gitignore b/examples/.gitignore new file mode 100644 index 0000000..96ef6c0 --- /dev/null +++ b/examples/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock diff --git a/examples/Cargo.toml b/examples/Cargo.toml new file mode 100644 index 0000000..328a606 --- /dev/null +++ b/examples/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "e1000-driver-test" +version = "0.2.0" +authors = ["Luoyuan Xiao "] + +[dependencies] +log = "0.4" +cfg-if = "1.0" +riscv = "0.8" +buddy_system_allocator = "0.6" +# linked_list_allocator = "0.10.5" +lazy_static = { version = "1.4", features = ["spin_no_std"] } +device_tree = { git = "https://github.com/rcore-os/device_tree-rs", rev = "2f2e55fb" } +pci = { git = "https://github.com/elliott10/pci-rs.git", rev = "583a15bf" } +e1000-driver = { path = "../" } + +[features] +board-fu740 = [] \ No newline at end of file diff --git a/examples/Makefile b/examples/Makefile new file mode 100644 index 0000000..b5981dd --- /dev/null +++ b/examples/Makefile @@ -0,0 +1,57 @@ +arch ?= riscv64 +board ?= qemu +target := $(arch)gc-unknown-none-elf +# target := $(arch)imac-unknown-none-elf +# when using new toolchain after 2024-04, release mode get stuck +# mode := release +mode := debug +kernel := target/$(target)/$(mode)/e1000-driver-test +bin := target/$(target)/$(mode)/e1000-driver-test.bin +img := target/$(target)/$(mode)/ext4.img + +sysroot := $(shell rustc --print sysroot) +objdump := $(shell find $(sysroot) -name llvm-objdump) --arch-name=$(arch) +objcopy := $(shell find $(sysroot) -name llvm-objcopy) + +BUILD_ARGS += --target $(target) +ifeq ($(mode), release) + BUILD_ARGS += --release +endif +ifeq ($(board), fu740) + BUILD_ARGS += --features board-fu740 +endif + +.PHONY: kernel build clean qemu run + +build: kernel $(bin) + +kernel: + cargo build $(BUILD_ARGS) + +$(bin): kernel + $(objcopy) $(kernel) --strip-all -O binary $(bin) + +asm: + $(objdump) -d $(kernel) | less + +sym: + $(objdump) -t $(kernel) | less + +header: + $(objdump) -x $(kernel) | less + +clean: + cargo clean + +qemu: + qemu-system-$(arch) \ + -machine virt \ + -no-reboot \ + -serial mon:stdio \ + -display none \ + -bios default \ + -kernel $(kernel) \ + -netdev user,id=net0 \ + -device e1000,netdev=net0 + +run: build qemu diff --git a/examples/rust-toolchain.toml b/examples/rust-toolchain.toml new file mode 100644 index 0000000..e35c314 --- /dev/null +++ b/examples/rust-toolchain.toml @@ -0,0 +1,6 @@ +[toolchain] +channel = "nightly-2024-01-31" +components = [ "rustfmt", "llvm-tools-preview" ] +targets = [ "riscv64gc-unknown-none-elf" ] +profile = "minimal" + diff --git a/examples/src/boot/entry64.asm b/examples/src/boot/entry64.asm new file mode 100644 index 0000000..01e060a --- /dev/null +++ b/examples/src/boot/entry64.asm @@ -0,0 +1,38 @@ + .section .text.entry + .globl _start +_start: + #OpenSBI将DTB地址保存在a1寄存器 + + #关中断 + csrw sie, zero + + #关闭mmu + csrw satp, zero + + #BSS节清零 + la t0, sbss + la t1, ebss + bgeu t0, t1, 2f + +1: + # sd: store double word (64 bits) + sd zero, (t0) + addi t0, t0, 8 + bltu t0, t1, 1b + +2: + la sp, bootstacktop + call rust_main + +4: + wfi + j 4b + +# stack栈空间 + .section .bss.stack + .align 12 + .global bootstack +bootstack: + .space 1024 * 256 + .global bootstacktop +bootstacktop: diff --git a/examples/src/boot/lang_items.rs b/examples/src/boot/lang_items.rs new file mode 100644 index 0000000..bbd2607 --- /dev/null +++ b/examples/src/boot/lang_items.rs @@ -0,0 +1,14 @@ +use core::panic::PanicInfo; + +#[panic_handler] +fn panic(info: &PanicInfo) -> !{ + println!("{}", info); + crate::boot::sbi::shutdown(); + unreachable!() +} + +#[no_mangle] +pub extern "C" fn abort() -> !{ + panic!("abort!"); +} + diff --git a/examples/src/boot/linker64.ld b/examples/src/boot/linker64.ld new file mode 100644 index 0000000..4f5381f --- /dev/null +++ b/examples/src/boot/linker64.ld @@ -0,0 +1,48 @@ +OUTPUT_ARCH(riscv) +ENTRY(_start) + +/* Qemu, fu740 */ +BASE_ADDRESS = 0x80200000; + +SECTIONS +{ + /* Load the kernel at this address: "." means the current address */ + . = BASE_ADDRESS; + start = .; + + .text : { + stext = .; + *(.text.entry) + *(.text .text.*) + . = ALIGN(4K); + etext = .; + } + + .rodata : { + srodata = .; + *(.rodata .rodata.*) + . = ALIGN(4K); + erodata = .; + } + + .data : { + sdata = .; + *(.data .data.*) + edata = .; + } + + .stack : { + *(.bss.stack) + . = ALIGN(4K); + } + + /* .sbss 会存放为0的static变量,系统启动时需要清0 */ + .bss : { + sbss = .; + *(.bss .bss.* .sbss .sbss.*) + ebss = .; + } + + . = ALIGN(4K); + PROVIDE(end = .); +} diff --git a/examples/src/boot/logger.rs b/examples/src/boot/logger.rs new file mode 100644 index 0000000..e5ee453 --- /dev/null +++ b/examples/src/boot/logger.rs @@ -0,0 +1,89 @@ +use core::fmt::{self, Write}; +use log::*; + +pub fn getchar() -> Option { + let c = super::sbi::console_getchar(); + if c < 0 { + None + } else { + Some(c as u8) + } +} + +pub fn putchar(ch: char) { + super::sbi::console_putchar(ch as u8 as usize); +} + +pub fn puts(s: &str) { + for ch in s.chars() { + putchar(ch); + } +} + +struct Stdout; + +impl fmt::Write for Stdout { + fn write_str(&mut self, s: &str) -> fmt::Result { + puts(s); + Ok(()) + } +} + +pub fn _print(args: fmt::Arguments) { + Stdout.write_fmt(args).unwrap(); +} + +#[macro_export] +macro_rules! print { + ($($arg:tt)*) => ({ + $crate::boot::logger::_print(format_args!($($arg)*)); + }); +} + +#[macro_export] +macro_rules! println { + () => ($crate::print!("\n")); + ($($arg:tt)*) => ($crate::print!("{}\n", format_args!($($arg)*))); +} + +static LOGGER: SimpleLogger = SimpleLogger; + +pub fn init(level: &str) -> Result<(), SetLoggerError> { + use core::str::FromStr; + + set_logger(&LOGGER) + .map(|()| set_max_level(LevelFilter::from_str(level).unwrap_or(LevelFilter::Debug))) +} + +struct SimpleLogger; + +impl Log for SimpleLogger { + fn enabled(&self, metadata: &Metadata) -> bool { + metadata.level() <= Level::Trace + } + + fn log(&self, record: &Record) { + if self.enabled(record.metadata()) { + println!( + "\x1b[{}m {:5} - {} \x1b[0m", + level_to_color_code(record.level()), + record.level(), + record.args() + ); + } + } + + fn flush(&self) {} +} + +// (16进制) \x1b == \033 (8进制) + +fn level_to_color_code(level: Level) -> u8 { + match level { + Level::Error => 31, // Red + Level::Warn => 33, // Yellow + Level::Info => 32, // Green + Level::Debug => 36, // SkyBlue + Level::Trace => 90, // BrightBlack + } +} diff --git a/examples/src/boot/mod.rs b/examples/src/boot/mod.rs new file mode 100644 index 0000000..9f85430 --- /dev/null +++ b/examples/src/boot/mod.rs @@ -0,0 +1,32 @@ +core::arch::global_asm!(include_str!("entry64.asm")); + +extern crate buddy_system_allocator; +//extern crate linked_list_allocator; + +pub mod sbi; + +#[macro_use] +pub mod logger; +use log::*; + +pub mod lang_items; + +//use self::linked_list_allocator::LockedHeap; +//pub static HEAP_ALLOCATOR: LockedHeap = LockedHeap::empty(); + + +use self::buddy_system_allocator::*; +#[global_allocator] +pub static HEAP_ALLOCATOR: LockedHeap = LockedHeap::new(); + +pub const KERNEL_HEAP_SIZE: usize = 1024 * 1024 * 4; + +pub fn init_heap() { + static mut HEAP: [u8; KERNEL_HEAP_SIZE] = [0; KERNEL_HEAP_SIZE]; + unsafe { + HEAP_ALLOCATOR + .lock() + .init(HEAP.as_mut_ptr() as usize, KERNEL_HEAP_SIZE); + } + info!("heap init end"); +} diff --git a/examples/src/boot/sbi.rs b/examples/src/boot/sbi.rs new file mode 100644 index 0000000..d7b740f --- /dev/null +++ b/examples/src/boot/sbi.rs @@ -0,0 +1,69 @@ +use core::arch::asm; + +pub fn console_putchar(ch: usize){ + sbi_call(SBI_CONSOLE_PUTCHAR, ch, 0, 0); +} + +pub fn console_getchar() -> isize { + return sbi_call(SBI_CONSOLE_GETCHAR, 0, 0, 0); +} + +pub fn console_putchar_u8(ch: u8){ + let ret: isize; + //let arg0: char = ch as char; + let arg0: u8 = ch; + let arg1: usize = 0; + let arg2: usize = 0; + let which: usize = 1; //SBI_ECALL_CONSOLE_PUTCHAR + unsafe{ + asm!("ecall", + lateout("x10") ret, + in("x10") arg0, in("x11") arg1, in("x12") arg2, in("x17") which + ); + } +} + +fn sbi_call(which: usize, arg0: usize, arg1: usize, arg2: usize) -> isize{ + let ret: isize; + unsafe{ + asm!("ecall", + lateout("x10") ret, + in("x10") arg0, in("x11") arg1, in("x12") arg2, in("x17") which + ); + } + ret +} + +pub fn set_timer(stime_value: u64){ + #[cfg(target_pointer_width = "32")] + sbi_call(SBI_SET_TIMER, stime_value as usize, (stime_value >> 32), 0); + + #[cfg(target_pointer_width = "64")] + sbi_call(SBI_SET_TIMER, stime_value as usize, 0, 0); +} +pub fn clear_ipi(){ + sbi_call(SBI_CLEAR_IPI, 0, 0, 0); +} + +pub fn send_ipi(sipi_value: usize){ + sbi_call(SBI_SEND_IPI, sipi_value, 0, 0); +} + +pub fn set_s_insn(entry: usize){ + sbi_call(SBI_SET_SINSN, entry, 0, 0); +} + +pub fn shutdown(){ + sbi_call(SBI_SHUTDOWN, 0, 0, 0); +} + +const SBI_SET_TIMER: usize = 0; +const SBI_CONSOLE_PUTCHAR: usize = 1; +const SBI_CONSOLE_GETCHAR: usize = 2; +const SBI_CLEAR_IPI: usize = 3; +const SBI_SEND_IPI: usize = 4; +const SBI_REMOTE_FENCE_I: usize = 5; +const SBI_REMOTE_SFENCE_VMA: usize = 6; +const SBI_REMOTE_SFENCE_VMA_ASID: usize = 7; +const SBI_SHUTDOWN: usize = 8; +const SBI_SET_SINSN: usize = 100; diff --git a/examples/src/e1000.rs b/examples/src/e1000.rs new file mode 100644 index 0000000..0ff0ba6 --- /dev/null +++ b/examples/src/e1000.rs @@ -0,0 +1,125 @@ +use alloc::{boxed::Box, vec}; +use log::*; + +use crate::{print, println}; + +pub struct Kernfn; +impl e1000_driver::e1000::KernelFunc for Kernfn { + const PAGE_SIZE: usize = 1 << 12; + + fn dma_alloc_coherent(&mut self, pages: usize) -> (usize, usize) { + let paddr: Box<[u32]> = if pages == 1 { + Box::new([0; 1024]) // 4096 + } else if pages == 8 { + Box::new([0; 1024 * 8]) // 4096 + } else { + info!("Alloc {} pages failed", pages); + Box::new([0; 1024]) + }; + + let len = paddr.len(); + + let paddr = Box::into_raw(paddr) as *const u32 as usize; + let vaddr = paddr; + println!("alloc paddr: {:#x}, len={}", paddr, len); + + (vaddr, paddr) + } + + fn dma_free_coherent(&mut self, vaddr: usize, pages: usize) { + trace!("dealloc_dma {} @ {:#x} unimplemented!", pages, vaddr); + } +} + +pub fn e1000_init() { + e1000_driver::pci::pci_init(); + + let mut e1000_device = e1000_driver::e1000::E1000Device::::new( + Kernfn, + e1000_driver::pci::E1000_REGS as usize, + ) + .unwrap(); + + // MAC 52:54:00:12:34:56 + let ping_frame: Box<[u8]> = Box::new([ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x52, 0x54, 0x00, 0x12, 0x34, 0x56, 0x08, 0x06, 0x00, + 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0x52, 0x54, 0x00, 0x12, 0x34, 0x56, 0x0a, 0x00, + 0x02, 0x0f, //10.0.2.15 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x02, 0x02, + ]); //ping 10.0.2.2 + + msdelay(500); + e1000_device.e1000_transmit(&ping_frame); + e1000_device.e1000_transmit(&ping_frame); + e1000_device.e1000_transmit(&ping_frame); + e1000_device.e1000_transmit(&ping_frame); + + let mut c = 12; + loop { + let rx_buf = e1000_device.e1000_recv(); + if let Some(vecdeque) = rx_buf { + debug!("e1000 recv num {}", vecdeque.len()); + for v in vecdeque.iter() { + print_hex_dump(v, v.len()); + } + } + c -= 1; + if c <= 0 { + break; + } + msdelay(100); + } +} + +pub fn print_hex_dump(buf: &[u8], len: usize) { + //let mut linebuf: [char; 16] = [0 as char; 16]; + + use alloc::string::String; + let mut linebuf = String::with_capacity(32); + let buf_len = buf.len(); + + for i in 0..len { + if (i % 16) == 0 { + print!("\t{:?}\nHEX DUMP: ", linebuf); + //linebuf.fill(0 as char); + linebuf.clear(); + } + + if i >= buf_len { + print!(" {:02x}", 0); + } else { + print!(" {:02x}", buf[i]); + //linebuf[i%16] = buf[i] as char; + linebuf.push(buf[i] as char); + } + } + print!("\t{:?}\n", linebuf); +} + +pub fn get_cycle() -> u64 { + use core::arch::asm; + let mut cycle: u64 = 0; + unsafe { + asm!("csrr {}, time", out(reg) cycle); + } + cycle +} + +// qemu +pub const TIMER_CLOCK: u64 = 10000000; + +// 微秒(us) +pub fn usdelay(us: u64) { + let mut t1: u64 = get_cycle(); + let t2 = t1 + us * (TIMER_CLOCK / 1000000); + + while t2 >= t1 { + t1 = get_cycle(); + } +} + +// 毫秒(ms) +#[allow(unused)] +pub fn msdelay(ms: u64) { + usdelay(ms * 1000); +} \ No newline at end of file diff --git a/examples/src/main.rs b/examples/src/main.rs new file mode 100644 index 0000000..f5c3728 --- /dev/null +++ b/examples/src/main.rs @@ -0,0 +1,240 @@ +#![no_std] +#![no_main] +//#![deny(warnings)] +#![allow(unused_variables)] +#![allow(dead_code)] + +extern crate alloc; +extern crate device_tree; +extern crate lazy_static; +extern crate log; +extern crate pci; + +mod boot; +mod e1000; +mod pci_impl; + +use alloc::{boxed::Box, format, vec, vec::Vec}; +use device_tree::util::SliceRead; +use device_tree::{DeviceTree, Node}; +pub use log::*; +use pci::{scan_bus, Location, PCIDevice, BAR}; +use pci_impl::*; + +use crate::boot::{init_heap, logger}; +use crate::e1000::Kernfn; + +#[no_mangle] +extern "C" fn rust_main(_hartid: usize, device_tree_paddr: usize) { + println!("\nHi\nTEST START"); + + logger::init("DEBUG"); + + info!("log initialized"); + + init_heap(); + + //init_dt(device_tree_paddr); + + e1000::e1000_init(); + + println!("TEST END"); + boot::lang_items::abort(); +} + +fn init_dt(dtb: usize) { + info!("device tree @ {:#x}", dtb); + #[repr(C)] + struct DtbHeader { + be_magic: u32, + be_size: u32, + } + let header = unsafe { &*(dtb as *const DtbHeader) }; + let magic = u32::from_be(header.be_magic); + const DEVICE_TREE_MAGIC: u32 = 0xd00dfeed; + assert_eq!(magic, DEVICE_TREE_MAGIC); + let size = u32::from_be(header.be_size); + let dtb_data = unsafe { core::slice::from_raw_parts(dtb as *const u8, size as usize) }; + let dt = DeviceTree::load(dtb_data).expect("failed to parse device tree"); + walk_dt_node(&dt.root); +} + +fn walk_dt_node(dt: &Node) { + if let Ok(compatible) = dt.prop_str("compatible") { + if compatible == "pci-host-ecam-generic" || compatible == "sifive,fu740-pcie" { + if let Some(reg) = dt.prop_raw("reg") { + let paddr = reg.as_slice().read_be_u64(0).unwrap_or(0); + let size = reg + .as_slice() + .read_be_u64(2 * core::mem::size_of::()) + .unwrap_or(0); + + let address_cells = dt.prop_u32("#address-cells").unwrap_or(0) as usize; + let size_cells = dt.prop_u32("#size-cells").unwrap_or(0) as usize; + let ranges = dt.prop_cells("ranges").unwrap(); + info!( + "pci ranges: bus_addr@[{:x?}], cpu_paddr@[{:x?}], size@[{:x?}]", + ranges[0]..ranges[address_cells - 1], + ranges[address_cells]..ranges[address_cells + 2 - 1], + ranges[address_cells + 2]..ranges[address_cells + 2 + size_cells - 1] + ); + + info!("{:?} addr={:#x}, size={:#x}", compatible, paddr, size); + pci_scan().unwrap(); + } + } + + if compatible == "virtio,mmio" { + if let Some(reg) = dt.prop_raw("reg") { + let paddr = reg.as_slice().read_be_u64(0).unwrap_or(0); + let size = reg + .as_slice() + .read_be_u64(2 * core::mem::size_of::()) + .unwrap_or(0); + + info!( + "walk dt: {}, addr={:#x}, size={:#x}", + compatible, paddr, size + ); + //virtio_probe(paddr, size); + } + } + } + for child in dt.children.iter() { + walk_dt_node(child); + } +} + +pub fn pci_scan() -> Option { + let mut dev_list = Vec::new(); + let pci_iter = unsafe { scan_bus(&PortOpsImpl, PCI_ACCESS) }; + info!("--------- PCI bus:device:function ---------"); + for dev in pci_iter { + info!( + "PCI: {}:{}:{} {:04x}:{:04x} ({} {}) irq: {}:{:?}", + dev.loc.bus, + dev.loc.device, + dev.loc.function, + dev.id.vendor_id, + dev.id.device_id, + dev.id.class, + dev.id.subclass, + dev.pic_interrupt_line, + dev.interrupt_pin, + ); + init_driver(&dev); + dev_list.push(dev.loc); + } + info!("---------"); + + let pci_num = dev_list.len(); + + info!("Found PCI number is {}", pci_num); + Some(pci_num as u32) +} + +pub fn init_driver(dev: &PCIDevice) { + let name = format!("enp{}s{}f{}", dev.loc.bus, dev.loc.device, dev.loc.function); + match (dev.id.vendor_id, dev.id.device_id) { + (0x8086, 0x100e) | (0x8086, 0x100f) | (0x8086, 0x10d3) => { + if let Some(BAR::Memory(addr, _len, _, _)) = dev.bars[0] { + info!( + "Found Intel E1000 {:?} dev {:?} BAR0 {:#x?}", + name, dev, addr + ); + #[cfg(target_arch = "riscv64")] + let addr = if addr == 0 { E1000_BASE as u64 } else { addr }; + + let irq = unsafe { enable(dev.loc, addr) }; + let vaddr = addr as usize; + + let mut e1000_device = + e1000_driver::e1000::E1000Device::::new(Kernfn, vaddr).unwrap(); + + // e1000_device.e1000_transmit(&ping_frame); + // let rx_buf = e1000_device.e1000_recv(); + } + } + + _ => {} + } + if dev.id.class == 0x01 && dev.id.subclass == 0x06 { + // Mass storage class + // SATA subclass + if let Some(BAR::Memory(addr, _len, _, _)) = dev.bars[5] { + info!("Found AHCI dev {:?} BAR5 {:x?}", dev, addr); + } + } +} + +/// Enable the pci device and its interrupt +/// Return assigned MSI interrupt number when applicable +unsafe fn enable(loc: Location, paddr: u64) -> Option { + let ops = &PortOpsImpl; + let am = PCI_ACCESS; + + if paddr != 0 { + // reveal PCI regs by setting paddr + let bar0_raw = am.read32(ops, loc, BAR0); + am.write32(ops, loc, BAR0, (paddr & !0xfff) as u32); //Only for 32-bit decoding + debug!( + "BAR0 set from {:#x} to {:#x}", + bar0_raw, + am.read32(ops, loc, BAR0) + ); + } + + // 23 and lower are used + static mut MSI_IRQ: u32 = 23; + + let _orig = am.read16(ops, loc, PCI_COMMAND); + // IO Space | MEM Space | Bus Mastering | Special Cycles | PCI Interrupt Disable + // am.write32(ops, loc, PCI_COMMAND, (orig | 0x40f) as u32); + + // find MSI cap + let mut msi_found = false; + let mut cap_ptr = am.read8(ops, loc, PCI_CAP_PTR) as u16; + let mut assigned_irq = None; + while cap_ptr > 0 { + let cap_id = am.read8(ops, loc, cap_ptr); + if cap_id == PCI_CAP_ID_MSI { + let orig_ctrl = am.read32(ops, loc, cap_ptr + PCI_MSI_CTRL_CAP); + // The manual Volume 3 Chapter 10.11 Message Signalled Interrupts + // 0 is (usually) the apic id of the bsp. + //am.write32(ops, loc, cap_ptr + PCI_MSI_ADDR, 0xfee00000 | (0 << 12)); + am.write32(ops, loc, cap_ptr + PCI_MSI_ADDR, 0xfee00000); + MSI_IRQ += 1; + let irq = MSI_IRQ; + assigned_irq = Some(irq as usize); + // we offset all our irq numbers by 32 + if (orig_ctrl >> 16) & (1 << 7) != 0 { + // 64bit + am.write32(ops, loc, cap_ptr + PCI_MSI_DATA_64, irq + 32); + } else { + // 32bit + am.write32(ops, loc, cap_ptr + PCI_MSI_DATA_32, irq + 32); + } + + // enable MSI interrupt, assuming 64bit for now + am.write32(ops, loc, cap_ptr + PCI_MSI_CTRL_CAP, orig_ctrl | 0x10000); + debug!( + "MSI control {:#b}, enabling MSI interrupt {}", + orig_ctrl >> 16, + irq + ); + msi_found = true; + } + debug!("PCI device has cap id {} at {:#X}", cap_id, cap_ptr); + cap_ptr = am.read8(ops, loc, cap_ptr + 1) as u16; + } + + if !msi_found { + // am.write16(ops, loc, PCI_COMMAND, (0x2) as u16); + am.write16(ops, loc, PCI_COMMAND, 0x6); + am.write32(ops, loc, PCI_INTERRUPT_LINE, 33); + debug!("MSI not found, using PCI interrupt"); + } + + debug!("pci device enable done"); + assigned_irq +} diff --git a/examples/src/pci_impl.rs b/examples/src/pci_impl.rs new file mode 100644 index 0000000..1979980 --- /dev/null +++ b/examples/src/pci_impl.rs @@ -0,0 +1,142 @@ +#![allow(unused_variables)] +use pci::{PortOps, CSpaceAccessMethod}; + +pub const PCI_COMMAND: u16 = 0x04; +pub const BAR0: u16 = 0x10; +pub const PCI_CAP_PTR: u16 = 0x34; +pub const PCI_INTERRUPT_LINE: u16 = 0x3c; +pub const PCI_INTERRUPT_PIN: u16 = 0x3d; +pub const PCI_COMMAND_INTX_DISABLE:u16 = 0x400; + +pub const PCI_MSI_CTRL_CAP: u16 = 0x00; +pub const PCI_MSI_ADDR: u16 = 0x04; +pub const PCI_MSI_UPPER_ADDR: u16 = 0x08; +pub const PCI_MSI_DATA_32: u16 = 0x08; +pub const PCI_MSI_DATA_64: u16 = 0x0C; + +pub const PCI_CAP_ID_MSI: u8 = 0x05; + +pub struct PortOpsImpl; + +cfg_if::cfg_if! { + if #[cfg(target_arch = "x86_64")] { + +use x86_64::instructions::port::Port; +impl PortOps for PortOpsImpl { + unsafe fn read8(&self, port: u16) -> u8 { + Port::new(port).read() + } + unsafe fn read16(&self, port: u16) -> u16 { + Port::new(port).read() + } + unsafe fn read32(&self, port: u32) -> u32 { + Port::new(port as u16).read() + } + unsafe fn write8(&self, port: u16, val: u8) { + Port::new(port).write(val); + } + unsafe fn write16(&self, port: u16, val: u16) { + Port::new(port).write(val); + } + unsafe fn write32(&self, port: u32, val: u32) { + Port::new(port as u16).write(val); + } +} + +// fix me +pub const PCI_BASE: usize = 0; +pub const PCI_ACCESS: CSpaceAccessMethod = CSpaceAccessMethod::IO; + +} else if #[cfg(target_arch = "riscv64")] { + +use core::ptr::{read_volatile, write_volatile}; + +pub fn phys_to_virt(paddr: usize) -> usize { + paddr +} +pub fn virt_to_phys(vaddr: usize) -> usize { + vaddr +} + +#[inline(always)] +pub fn writev(addr: usize, content: T) { + let cell = (addr) as *mut T; + unsafe { + write_volatile(cell, content); + } +} +#[inline(always)] +pub fn readv(addr: usize) -> T { + let cell = (addr) as *const T; + unsafe { read_volatile(cell) } +} + +pub const E1000_BASE: usize = 0x40000000; +pub const PCI_ACCESS: CSpaceAccessMethod = CSpaceAccessMethod::MemoryMapped(PCI_BASE as *mut u8); + +cfg_if::cfg_if! { +if #[cfg(feature = "board-fu740")] { + +use super::error; +use pci::{pcie_dw_read_config, pcie_dw_write_config, PciSize}; + +pub const PCI_BASE: usize = 0xe00000000; +impl PortOps for PortOpsImpl { + unsafe fn read8(&self, port: u16) -> u8 { + error!("unimplemented read8!"); + 0 + } + unsafe fn read16(&self, port: u16) -> u16 { + error!("unimplemented read16!"); + 0 + } + unsafe fn read32(&self, port: u32) -> u32 { + let mut valuep: u64 = 0; + let bdf = port; + let offset = port & 0xfc; + pcie_dw_read_config(bdf, offset, &mut valuep, PciSize::Pci32).unwrap(); + + valuep as u32 + } + + unsafe fn write8(&self, port: u16, val: u8) { + error!("unimplemented write8!"); + } + unsafe fn write16(&self, port: u16, val: u16) { + error!("unimplemented write16!"); + } + unsafe fn write32(&self, port: u32, val: u32) { + let bdf = port; + let offset = port & 0xfc; + pcie_dw_write_config(bdf, offset, val as u64, PciSize::Pci32).unwrap(); + } +} + +} else { + +/// riscv64 qemu +pub const PCI_BASE: usize = 0x30000000; +impl PortOps for PortOpsImpl { + unsafe fn read8(&self, port: u16) -> u8 { + readv(PCI_BASE + port as usize) + } + unsafe fn read16(&self, port: u16) -> u16 { + readv(PCI_BASE + port as usize) + } + unsafe fn read32(&self, port: u32) -> u32 { + readv(PCI_BASE + port as usize) + } + unsafe fn write8(&self, port: u16, val: u8) { + writev(PCI_BASE + port as usize, val); + } + unsafe fn write16(&self, port: u16, val: u16) { + writev(PCI_BASE + port as usize, val); + } + unsafe fn write32(&self, port: u32, val: u32) { + writev(PCI_BASE + port as usize, val); + } +} +}} + +} +} // cfg_if