From 197bebb1d2703aaef4f5c4c982115394ed9f3463 Mon Sep 17 00:00:00 2001 From: Jiajie Chen Date: Mon, 25 Feb 2019 19:12:41 +0800 Subject: [PATCH] Implement pci bus probing and fix a bug in virtio_mmio --- kernel/Makefile | 14 +++- kernel/src/arch/x86_64/mod.rs | 2 + kernel/src/drivers/bus/mod.rs | 4 +- kernel/src/drivers/bus/pci.rs | 98 +++++++++++++++++++++++++++ kernel/src/drivers/bus/virtio_mmio.rs | 3 +- kernel/src/drivers/mod.rs | 6 ++ kernel/src/drivers/net/virtio_net.rs | 3 +- 7 files changed, 123 insertions(+), 7 deletions(-) create mode 100644 kernel/src/drivers/bus/pci.rs diff --git a/kernel/Makefile b/kernel/Makefile index 33d2fc2..cd14aa8 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -61,6 +61,8 @@ endif ### qemu options ### qemu_opts := \ -smp cores=$(smp) +qemu_net_opts := \ + -netdev type=tap,id=net0,script=no,downscript=no ifeq ($(arch), x86_64) qemu_opts += \ @@ -68,6 +70,8 @@ qemu_opts += \ -drive format=raw,file=$(SFSIMG),media=disk,cache=writeback \ -serial mon:stdio \ -device isa-debug-exit +qemu_net_opts += \ + -device virtio-net-pci,netdev=net0 else ifeq ($(arch), riscv32) qemu_opts += \ @@ -75,6 +79,9 @@ qemu_opts += \ -kernel $(bin) \ -drive file=$(SFSIMG),format=raw,id=sfs \ -device virtio-blk-device,drive=sfs +qemu_net_opts += \ + -device virtio-net-device,netdev=net0 + ifdef m_mode qemu_opts += -cpu rv32imacu-nommu endif @@ -85,6 +92,9 @@ qemu_opts += \ -kernel $(bin) \ -drive file=$(SFSIMG),format=raw,id=sfs \ -device virtio-blk-device,drive=sfs +qemu_net_opts += \ + -device virtio-net-device,netdev=net0 + ifdef m_mode qemu_opts += -cpu rv64imacu-nommu endif @@ -182,9 +192,7 @@ justrun: @qemu-system-$(arch) $(qemu_opts) justrunnet: build - @sudo qemu-system-$(arch) $(qemu_opts) \ - -netdev type=tap,id=net0,script=no,downscript=no \ - -device virtio-net-device,netdev=net0 \ + @sudo qemu-system-$(arch) $(qemu_opts) $(qemu_net_opts) justrunui: build @qemu-system-$(arch) $(qemu_opts) \ diff --git a/kernel/src/arch/x86_64/mod.rs b/kernel/src/arch/x86_64/mod.rs index eb070f5..2a9aee6 100644 --- a/kernel/src/arch/x86_64/mod.rs +++ b/kernel/src/arch/x86_64/mod.rs @@ -43,6 +43,8 @@ pub extern "C" fn _start(boot_info: &'static BootInfo) -> ! { driver::init(); + crate::drivers::init(); + crate::process::init(); AP_CAN_INIT.store(true, Ordering::Relaxed); diff --git a/kernel/src/drivers/bus/mod.rs b/kernel/src/drivers/bus/mod.rs index 08d5c84..c9d93c6 100644 --- a/kernel/src/drivers/bus/mod.rs +++ b/kernel/src/drivers/bus/mod.rs @@ -1 +1,3 @@ -pub mod virtio_mmio; \ No newline at end of file +pub mod virtio_mmio; +#[cfg(target_arch = "x86_64")] +pub mod pci; \ No newline at end of file diff --git a/kernel/src/drivers/bus/pci.rs b/kernel/src/drivers/bus/pci.rs new file mode 100644 index 0000000..2bafe12 --- /dev/null +++ b/kernel/src/drivers/bus/pci.rs @@ -0,0 +1,98 @@ +use x86_64::instructions::port::Port; +use crate::logging::*; + +const VENDOR: u32 = 0x00; +const DEVICE: u32 = 0x02; +const STATUS: u32 = 0x06; +const SUBCLASS: u32 = 0x0a; +const CLASS: u32 = 0x0b; +const HEADER: u32 = 0x0e; + +const PCI_ADDR_PORT: u16 = 0xcf8; +const PCI_DATA_PORT: u16 = 0xcfc; + +struct PciTag(u32); + +impl PciTag { + pub fn new(bus: u32, dev: u32, func: u32) -> PciTag { + PciTag(bus << 16 | dev << 11 | func << 8) + } + + pub fn bus(&self) -> u32 { + (self.0 >> 16) & 0xFF + } + + pub fn dev(&self) -> u32 { + (self.0 >> 11) & 0x1F + } + + pub fn func(&self) -> u32 { + (self.0 >> 8) & 0x7 + } + + // biscuit/src/pci/pci.go + pub unsafe fn read(&self, reg: u32, width: u32) -> u32 { + // spans in one reg + assert_eq!(reg / 4, (reg + width - 1) / 4); + + let enable = 1 << 31; + let rsh = reg % 4; + let r = reg - rsh; + let t = enable | self.0 | r; + + let mut pci_addr: Port = Port::new(PCI_ADDR_PORT); + let mut pci_data: Port = Port::new(PCI_DATA_PORT); + + pci_addr.write(t); + let d = pci_data.read(); + pci_addr.write(0); + + let ret = d >> (rsh * 8); + let m = (1 << (8 * width)) - 1; + return ret & m; + } + + pub unsafe fn write(&self, reg: u32, val: u32) { + assert_eq!(reg & 3, 0); + + let enable = 1 << 31; + let t = enable | self.0 | reg; + + let mut pci_addr: Port = Port::new(PCI_ADDR_PORT); + let mut pci_data: Port = Port::new(PCI_DATA_PORT); + + pci_addr.write(t); + pci_data.write(val); + pci_addr.write(0); + } + + pub fn describe(&self) -> bool { + unsafe { + let v = self.read(VENDOR, 2); + if v == 0xffff { + return false; + } + let d = self.read(DEVICE, 2); + let mf = self.read(HEADER, 1); + let cl = self.read(CLASS, 1); + let scl = self.read(SUBCLASS, 1); + info!("{}: {}: {}: {:#X} {:#X} ({} {})", self.bus(), self.dev(), self.func(), v, d, cl, scl); + return mf & 0x80 != 0; + } + } +} + +pub fn init() { + for bus in 0..256 { + for dev in 0..32 { + let tag = PciTag::new(bus, dev, 0); + if tag.describe() { + for func in 1..8 { + let tag = PciTag::new(bus, dev, func); + tag.describe(); + } + } + } + } + info!("Init pci"); +} \ No newline at end of file diff --git a/kernel/src/drivers/bus/virtio_mmio.rs b/kernel/src/drivers/bus/virtio_mmio.rs index 0624d9b..e579da1 100644 --- a/kernel/src/drivers/bus/virtio_mmio.rs +++ b/kernel/src/drivers/bus/virtio_mmio.rs @@ -208,7 +208,8 @@ impl VirtIOVirtqueue { let mut output = Vec::new(); loop { let flags = VirtIOVirtqueueFlag::from_bits_truncate(desc[cur].flags.read()); - let buffer = unsafe { slice::from_raw_parts(desc[cur].addr.read() as *const u8, desc[cur].len.read() as usize) }; + let addr = desc[cur].addr.read() as u64 - MEMORY_OFFSET as u64 + KERNEL_OFFSET as u64; + let buffer = unsafe { slice::from_raw_parts(addr as *const u8, desc[cur].len.read() as usize) }; if flags.contains(VirtIOVirtqueueFlag::WRITE) { input.push(buffer); } else { diff --git a/kernel/src/drivers/mod.rs b/kernel/src/drivers/mod.rs index d5a3743..232183e 100644 --- a/kernel/src/drivers/mod.rs +++ b/kernel/src/drivers/mod.rs @@ -54,6 +54,12 @@ lazy_static! { pub static ref NET_DRIVERS: SpinNoIrqLock>> = SpinNoIrqLock::new(Vec::new()); } +#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] pub fn init(dtb: usize) { device_tree::init(dtb); +} + +#[cfg(target_arch = "x86_64")] +pub fn init() { + bus::pci::init(); } \ No newline at end of file diff --git a/kernel/src/drivers/net/virtio_net.rs b/kernel/src/drivers/net/virtio_net.rs index eef326d..0cf42c4 100644 --- a/kernel/src/drivers/net/virtio_net.rs +++ b/kernel/src/drivers/net/virtio_net.rs @@ -168,9 +168,8 @@ impl phy::TxToken for VirtIONetTxToken { unsafe { slice::from_raw_parts_mut(page as *mut u8, PAGE_SIZE) } } }; - let output_buffer = &mut output[size_of::()..(size_of::() +len)]; + let output_buffer = &mut output[size_of::()..(size_of::() + len)]; let result = f(output_buffer); - println!("output {:?}", output_buffer); let mut driver = (self.0).0.lock(); assert!(driver.queues[VIRTIO_QUEUE_TRANSMIT].add_and_notify(&[], &[output], 0));