From eda6bc6f92bd2f72f95f1ca6c0cd7f0444d00afb Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 4 Sep 2019 20:38:08 -0600 Subject: [PATCH] Calculate and use PCI BAR memory sizes in most drivers. --- ahcid/src/main.rs | 10 +++++-- e1000d/config.toml | 3 +-- e1000d/src/main.rs | 7 +++-- initfs.toml | 4 +-- nvmed/src/main.rs | 11 +++++--- pcid/src/main.rs | 62 +++++++++++++++++++++++++++++++++++--------- rtl8168d/config.toml | 3 +-- rtl8168d/src/main.rs | 7 +++-- 8 files changed, 80 insertions(+), 27 deletions(-) diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 9522634593..9cc8857992 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -23,14 +23,20 @@ fn main() { let bar_str = args.next().expect("ahcid: no address provided"); let bar = usize::from_str_radix(&bar_str, 16).expect("ahcid: failed to parse address"); + let bar_size_str = args.next().expect("ahcid: no address size provided"); + let bar_size = usize::from_str_radix(&bar_str, 16).expect("ahcid: failed to parse address size"); + let irq_str = args.next().expect("ahcid: no irq provided"); let irq = irq_str.parse::().expect("ahcid: failed to parse irq"); - print!("{}", format!(" + AHCI {} on: {:X} IRQ: {}\n", name, bar, irq)); + print!("{}", format!(" + AHCI {} on: {:X} size: {} IRQ: {}\n", name, bar, bar_size, irq)); // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { - let address = unsafe { syscall::physmap(bar, 4096, PHYSMAP_WRITE | PHYSMAP_NO_CACHE).expect("ahcid: failed to map address") }; + let address = unsafe { + syscall::physmap(bar, bar_size, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) + .expect("ahcid: failed to map address") + }; { let scheme_name = format!("disk/{}", name); let socket_fd = syscall::open( diff --git a/e1000d/config.toml b/e1000d/config.toml index 0f5f3339b3..19d0b57f84 100644 --- a/e1000d/config.toml +++ b/e1000d/config.toml @@ -2,5 +2,4 @@ name = "E1000 NIC" class = 2 ids = { 0x8086 = [0x1004, 0x100e, 0x100f, 0x1503] } -command = ["e1000d", "$NAME", "$BAR0", "$IRQ"] - +command = ["e1000d", "$NAME", "$BAR0", "$BARSIZE0", "$IRQ"] diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index 6518764fc2..98e924259f 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -68,10 +68,13 @@ fn main() { let bar_str = args.next().expect("e1000d: no address provided"); let bar = usize::from_str_radix(&bar_str, 16).expect("e1000d: failed to parse address"); + let bar_size_str = args.next().expect("e1000d: no address size provided"); + let bar_size = usize::from_str_radix(&bar_str, 16).expect("e1000d: failed to parse address size"); + let irq_str = args.next().expect("e1000d: no irq provided"); let irq = irq_str.parse::().expect("e1000d: failed to parse irq"); - println!(" + E1000 {} on: {:X} IRQ: {}", name, bar, irq); + println!(" + E1000 {} on: {:X} size: {} IRQ: {}", name, bar, bar_size, irq); // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { @@ -91,7 +94,7 @@ fn main() { let mut irq_file = unsafe { File::from_raw_fd(irq_fd as RawFd) }; let address = unsafe { - syscall::physmap(bar, 128 * 1024, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) + syscall::physmap(bar, bar_size, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) .expect("e1000d: failed to map address") }; { diff --git a/initfs.toml b/initfs.toml index 15b49d522f..a6eb2dddd6 100644 --- a/initfs.toml +++ b/initfs.toml @@ -5,7 +5,7 @@ name = "AHCI storage" class = 1 subclass = 6 -command = ["ahcid", "$NAME", "$BAR5", "$IRQ"] +command = ["ahcid", "$NAME", "$BAR5", "$BARSIZE5", "$IRQ"] # bgad [[drivers]] @@ -27,7 +27,7 @@ command = ["bgad", "$NAME", "$BAR0"] name = "NVME storage" class = 1 subclass = 8 -command = ["nvmed", "$NAME", "$BAR0", "$IRQ"] +command = ["nvmed", "$NAME", "$BAR0", "$BARSIZE0", "$IRQ"] # vboxd [[drivers]] diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index daaa633fe7..5939430b8e 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -26,15 +26,20 @@ fn main() { let bar_str = args.next().expect("nvmed: no address provided"); let bar = usize::from_str_radix(&bar_str, 16).expect("nvmed: failed to parse address"); + let bar_size_str = args.next().expect("nvmed: no address size provided"); + let bar_size = usize::from_str_radix(&bar_str, 16).expect("nvmed: failed to parse address size"); + let irq_str = args.next().expect("nvmed: no irq provided"); let irq = irq_str.parse::().expect("nvmed: failed to parse irq"); - print!("{}", format!(" + NVME {} on: {:X} IRQ: {}\n", name, bar, irq)); + print!("{}", format!(" + NVME {} on: {:X} size: {} IRQ: {}\n", name, bar, bar_size, irq)); // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { - //TODO: Figure out correct size of mapping, not just 256 * 1024 - let address = unsafe { syscall::physmap(bar, 256 * 1024, PHYSMAP_WRITE | PHYSMAP_NO_CACHE).expect("nvmed: failed to map address") }; + let address = unsafe { + syscall::physmap(bar, bar_size, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) + .expect("nvmed: failed to map address") + }; { let event_fd = syscall::open("event:", syscall::O_RDWR | syscall::O_CLOEXEC) .expect("nvmed: failed to open event queue"); diff --git a/pcid/src/main.rs b/pcid/src/main.rs index a977e0fcfb..340eb6dbcb 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -13,7 +13,7 @@ use std::process::Command; use syscall::iopl; use crate::config::Config; -use crate::pci::{Pci, PciClass, PciHeader, PciHeaderError, PciHeaderType}; +use crate::pci::{Pci, PciBar, PciClass, PciHeader, PciHeaderError, PciHeaderType}; mod config; mod pci; @@ -82,7 +82,7 @@ fn handle_parsed_header(config: &Config, pci: &Pci, bus_num: u8, if let Some(ref ids) = driver.ids { let mut device_found = false; for (vendor, devices) in ids { - let vendor_without_prefix = vendor.trim_left_matches("0x"); + let vendor_without_prefix = vendor.trim_start_matches("0x"); let vendor = i64::from_str_radix(vendor_without_prefix, 16).unwrap() as u16; if vendor != header.vendor_id() { continue; } @@ -130,6 +130,42 @@ fn handle_parsed_header(config: &Config, pci: &Pci, bus_num: u8, pci.write(bus_num, dev_num, func_num, 0x3C, data); } + // Find BAR sizes + let mut bars = [PciBar::None; 6]; + let mut bar_sizes = [0; 6]; + unsafe { + let count = match header.header_type() { + PciHeaderType::GENERAL => 6, + PciHeaderType::PCITOPCI => 2, + _ => 0, + }; + + for i in 0..count { + bars[i] = header.get_bar(i); + + let offset = 0x10 + (i as u8) * 4; + + let original = pci.read(bus_num, dev_num, func_num, offset); + pci.write(bus_num, dev_num, func_num, offset, 0xFFFFFFFF); + + let new = pci.read(bus_num, dev_num, func_num, offset); + pci.write(bus_num, dev_num, func_num, offset, original); + + let masked = if new & 1 == 1 { + new & 0xFFFFFFFC + } else { + new & 0xFFFFFFF0 + }; + + let size = !masked + 1; + bar_sizes[i] = if size <= 1 { + 0 + } else { + size + }; + } + } + // TODO: find a better way to pass the header data down to the // device driver, making passing the capabilities list etc // posible. @@ -142,16 +178,18 @@ fn handle_parsed_header(config: &Config, pci: &Pci, bus_num: u8, "$DEV" => format!("{:>02X}", dev_num), "$FUNC" => format!("{:>02X}", func_num), "$NAME" => format!("pci-{:>02X}.{:>02X}.{:>02X}", bus_num, dev_num, func_num), - "$BAR0" => format!("{}", header.get_bar(0)), - "$BAR1" => format!("{}", header.get_bar(1)), - "$BAR2" if header.header_type() == PciHeaderType::GENERAL => - format!("{}", header.get_bar(2)), - "$BAR3" if header.header_type() == PciHeaderType::GENERAL => - format!("{}", header.get_bar(3)), - "$BAR4" if header.header_type() == PciHeaderType::GENERAL => - format!("{}", header.get_bar(4)), - "$BAR5" if header.header_type() == PciHeaderType::GENERAL => - format!("{}", header.get_bar(5)), + "$BAR0" => format!("{}", bars[0]), + "$BAR1" => format!("{}", bars[1]), + "$BAR2" => format!("{}", bars[2]), + "$BAR3" => format!("{}", bars[3]), + "$BAR4" => format!("{}", bars[4]), + "$BAR5" => format!("{}", bars[5]), + "$BARSIZE0" => format!("{:>08X}", bar_sizes[0]), + "$BARSIZE1" => format!("{:>08X}", bar_sizes[1]), + "$BARSIZE2" => format!("{:>08X}", bar_sizes[2]), + "$BARSIZE3" => format!("{:>08X}", bar_sizes[3]), + "$BARSIZE4" => format!("{:>08X}", bar_sizes[4]), + "$BARSIZE5" => format!("{:>08X}", bar_sizes[5]), "$IRQ" => format!("{}", irq), "$VENID" => format!("{:>04X}", header.vendor_id()), "$DEVID" => format!("{:>04X}", header.device_id()), diff --git a/rtl8168d/config.toml b/rtl8168d/config.toml index 04a3626044..72660448ff 100644 --- a/rtl8168d/config.toml +++ b/rtl8168d/config.toml @@ -2,5 +2,4 @@ name = "RTL8168 NIC" class = 2 ids = { 0x10ec = [0x8168] } -command = ["rtl8168d", "$NAME", "$BAR2", "$IRQ"] - +command = ["rtl8168d", "$NAME", "$BAR2", "$BARSIZE2", "$IRQ"] diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index 9abaf31648..ddc7cbe4e4 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -68,10 +68,13 @@ fn main() { let bar_str = args.next().expect("rtl8168d: no address provided"); let bar = usize::from_str_radix(&bar_str, 16).expect("rtl8168d: failed to parse address"); + let bar_size_str = args.next().expect("rtl8168d: no address size provided"); + let bar_size = usize::from_str_radix(&bar_str, 16).expect("rtl8168d: failed to parse address size"); + let irq_str = args.next().expect("rtl8168d: no irq provided"); let irq = irq_str.parse::().expect("rtl8168d: failed to parse irq"); - println!(" + RTL8168 {} on: {:X}, IRQ: {}", name, bar, irq); + println!(" + RTL8168 {} on: {:X} size: {} IRQ: {}", name, bar, bar_size, irq); // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { @@ -91,7 +94,7 @@ fn main() { let mut irq_file = unsafe { File::from_raw_fd(irq_fd as RawFd) }; let address = unsafe { - syscall::physmap(bar, 256, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) + syscall::physmap(bar, bar_size, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) .expect("rtl8168d: failed to map address") }; {