Skip to content

Commit

Permalink
add dependency to Send for the implementation of spinlock (#97)
Browse files Browse the repository at this point in the history
* add requirement to use only types T for spin lock, where the behavior Send is specified
* remove obsolete implementation of a irqsave refcell
* replace DoubleLinkedList by LinkedList of the alloc library
* using of the core collection library to handle memory and tasks
* the vector of PCI adapters aren't longer protected by a lock because these adapter are initialized at boot time. Afterwards, we have only read-access.
* Freelist: add check if a reunion with the previous slot is possible
  • Loading branch information
stlankes authored Sep 7, 2020
1 parent 15b44c0 commit f105ba8
Show file tree
Hide file tree
Showing 17 changed files with 296 additions and 673 deletions.
67 changes: 42 additions & 25 deletions src/arch/x86_64/kernel/fuse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use crate::arch::kernel::pci::get_filesystem_driver;
use crate::syscalls::fs::{FileError, FilePerms, PosixFile, PosixFileSystem, SeekWhence};
use alloc::boxed::Box;
use alloc::rc::Rc;
use alloc::vec::Vec;
use core::cell::RefCell;
use core::{fmt, u32, u8};

// response out layout eg @ https://github.com/zargony/fuse-rs/blob/bf6d1cf03f3277e35b580f3c7b9999255d72ecf3/src/ll/request.rs#L44
Expand All @@ -27,14 +26,11 @@ pub trait FuseInterface {
T: FuseOut + core::fmt::Debug;
}

pub struct Fuse<T: FuseInterface> {
driver: Rc<RefCell<T>>,
}
pub struct Fuse;

impl<T: FuseInterface + 'static> PosixFileSystem for Fuse<T> {
fn open(&self, path: &str, perms: FilePerms) -> Result<Box<dyn PosixFile>, FileError> {
impl PosixFileSystem for Fuse {
fn open(&self, path: &str, perms: FilePerms) -> Result<Box<dyn PosixFile + Send>, FileError> {
let mut file = FuseFile {
driver: self.driver.clone(),
fuse_nid: None,
fuse_fh: None,
offset: 0,
Expand All @@ -54,15 +50,19 @@ impl<T: FuseInterface + 'static> PosixFileSystem for Fuse<T> {

// 3.FUSE_OPEN(nodeid, O_RDONLY) -> fh
let (cmd, rsp) = create_open(file.fuse_nid.unwrap(), perms.raw);
let rsp = self.driver.borrow_mut().send_command(cmd, Some(rsp));
let rsp = get_filesystem_driver()
.ok_or(FileError::ENOSYS())?
.lock()
.send_command(cmd, Some(rsp))
.unwrap();
trace!("Open answer {:?}", rsp);
file.fuse_fh = Some(rsp.unwrap().rsp.fh);
file.fuse_fh = Some(rsp.rsp.fh);
} else {
// Create file (opens implicitly, returns results from both lookup and open calls)
let (cmd, rsp) = create_create(path, perms.raw, perms.mode);
let rsp = self
.driver
.borrow_mut()
let rsp = get_filesystem_driver()
.ok_or(FileError::ENOSYS())?
.lock()
.send_command(cmd, Some(rsp))
.unwrap();
trace!("Create answer {:?}", rsp);
Expand All @@ -76,42 +76,53 @@ impl<T: FuseInterface + 'static> PosixFileSystem for Fuse<T> {

fn unlink(&self, path: &str) -> core::result::Result<(), FileError> {
let (cmd, rsp) = create_unlink(path);
let rsp = self.driver.borrow_mut().send_command(cmd, Some(rsp));
let rsp = get_filesystem_driver()
.ok_or(FileError::ENOSYS())?
.lock()
.send_command(cmd, Some(rsp));
trace!("unlink answer {:?}", rsp);

Ok(())
}
}

impl<T: FuseInterface + 'static> Fuse<T> {
pub fn new(driver: Rc<RefCell<T>>) -> Self {
Self { driver }
impl Fuse {
pub fn new() -> Self {
Self {}
}

pub fn send_init(&self) {
let (cmd, rsp) = create_init();
let rsp = self.driver.borrow_mut().send_command(cmd, Some(rsp));
let rsp = get_filesystem_driver()
.unwrap()
.lock()
.send_command(cmd, Some(rsp));
trace!("fuse init answer: {:?}", rsp);
}

pub fn lookup(&self, name: &str) -> Option<u64> {
let (cmd, rsp) = create_lookup(name);
let rsp = self.driver.borrow_mut().send_command(cmd, Some(rsp));
let rsp = get_filesystem_driver()
.unwrap()
.lock()
.send_command(cmd, Some(rsp));
Some(rsp.unwrap().rsp.nodeid)
}
}

struct FuseFile<T: FuseInterface> {
driver: Rc<RefCell<T>>,
struct FuseFile {
fuse_nid: Option<u64>,
fuse_fh: Option<u64>,
offset: usize,
}

impl<T: FuseInterface> PosixFile for FuseFile<T> {
impl PosixFile for FuseFile {
fn close(&mut self) -> Result<(), FileError> {
let (cmd, rsp) = create_release(self.fuse_nid.unwrap(), self.fuse_fh.unwrap());
self.driver.borrow_mut().send_command(cmd, Some(rsp));
get_filesystem_driver()
.ok_or(FileError::ENOSYS())?
.lock()
.send_command(cmd, Some(rsp));

Ok(())
}
Expand All @@ -124,7 +135,10 @@ impl<T: FuseInterface> PosixFile for FuseFile<T> {
}
if let Some(fh) = self.fuse_fh {
let (cmd, rsp) = create_read(fh, len, self.offset as u64);
let rsp = self.driver.borrow_mut().send_command(cmd, Some(rsp));
let rsp = get_filesystem_driver()
.ok_or(FileError::ENOSYS())?
.lock()
.send_command(cmd, Some(rsp));
let rsp = rsp.unwrap();
let len = rsp.header.len as usize - ::core::mem::size_of::<fuse_out_header>();
self.offset += len;
Expand Down Expand Up @@ -152,7 +166,10 @@ impl<T: FuseInterface> PosixFile for FuseFile<T> {
}
if let Some(fh) = self.fuse_fh {
let (cmd, rsp) = create_write(fh, &buf[..len], self.offset as u64);
let rsp = self.driver.borrow_mut().send_command(cmd, Some(rsp));
let rsp = get_filesystem_driver()
.ok_or(FileError::ENOSYS())?
.lock()
.send_command(cmd, Some(rsp));
trace!("write response: {:?}", rsp);
let rsp = rsp.unwrap();

Expand Down
64 changes: 37 additions & 27 deletions src/arch/x86_64/kernel/pci.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ use crate::arch::x86_64::kernel::virtio_net::VirtioNetDriver;
use crate::arch::x86_64::mm::{PhysAddr, VirtAddr};
use crate::synch::spinlock::SpinlockIrqSave;
use crate::x86::io::*;
use alloc::rc::Rc;
use alloc::vec::Vec;
use core::cell::RefCell;
use core::convert::TryInto;
use core::{fmt, u32, u8};

Expand Down Expand Up @@ -50,8 +48,8 @@ pub const PCI_MULTIFUNCTION_MASK: u32 = 0x0080_0000;

pub const PCI_CAP_ID_VNDR: u32 = 0x09;

static PCI_ADAPTERS: SpinlockIrqSave<Vec<PciAdapter>> = SpinlockIrqSave::new(Vec::new());
static PCI_DRIVERS: SpinlockIrqSave<Vec<PciDriver>> = SpinlockIrqSave::new(Vec::new());
static mut PCI_ADAPTERS: Vec<PciAdapter> = Vec::new();
static mut PCI_DRIVERS: Vec<PciDriver> = Vec::new();

/// Classes of PCI nodes.
#[allow(dead_code)]
Expand Down Expand Up @@ -126,27 +124,41 @@ pub struct MemoryBar {
}

pub enum PciDriver<'a> {
VirtioFs(Rc<RefCell<VirtioFsDriver<'a>>>),
VirtioNet(Rc<RefCell<VirtioNetDriver<'a>>>),
VirtioFs(SpinlockIrqSave<VirtioFsDriver<'a>>),
VirtioNet(SpinlockIrqSave<VirtioNetDriver<'a>>),
}

pub fn register_driver(drv: PciDriver<'static>) {
let mut drivers = PCI_DRIVERS.lock();
drivers.push(drv);
}
impl<'a> PciDriver<'a> {
fn get_network_driver(&self) -> Option<&SpinlockIrqSave<VirtioNetDriver<'a>>> {
match self {
Self::VirtioNet(drv) => Some(drv),
_ => None,
}
}

pub fn get_network_driver() -> Option<Rc<RefCell<VirtioNetDriver<'static>>>> {
let drivers = PCI_DRIVERS.lock();
for i in drivers.iter() {
match &*i {
PciDriver::VirtioNet(nic_driver) => {
return Some(nic_driver.clone());
}
_ => {}
fn get_filesystem_driver(&self) -> Option<&SpinlockIrqSave<VirtioFsDriver<'a>>> {
match self {
Self::VirtioFs(drv) => Some(drv),
_ => None,
}
}
}
pub fn register_driver(drv: PciDriver<'static>) {
unsafe {
PCI_DRIVERS.push(drv);
}
}

None
pub fn get_network_driver() -> Option<&'static SpinlockIrqSave<VirtioNetDriver<'static>>> {
unsafe { PCI_DRIVERS.iter().find_map(|drv| drv.get_network_driver()) }
}

pub fn get_filesystem_driver() -> Option<&'static SpinlockIrqSave<VirtioFsDriver<'static>>> {
unsafe {
PCI_DRIVERS
.iter()
.find_map(|drv| drv.get_filesystem_driver())
}
}

/// Reads all bar registers of specified device and returns vector of PciBar's containing addresses and sizes.
Expand Down Expand Up @@ -451,8 +463,7 @@ pub fn write_config(bus: u8, device: u8, register: u32, data: u32) {
}

pub fn get_adapter(vendor_id: u16, device_id: u16) -> Option<PciAdapter> {
let adapters = PCI_ADAPTERS.lock();
for adapter in adapters.iter() {
for adapter in unsafe { PCI_ADAPTERS.iter() } {
if adapter.vendor_id == vendor_id && adapter.device_id == device_id {
return Some(adapter.clone());
}
Expand All @@ -463,7 +474,6 @@ pub fn get_adapter(vendor_id: u16, device_id: u16) -> Option<PciAdapter> {

pub fn init() {
debug!("Scanning PCI Busses 0 to {}", PCI_MAX_BUS_NUMBER - 1);
let mut adapters = PCI_ADAPTERS.lock();

// HermitCore only uses PCI for network devices.
// Therefore, multifunction devices as well as additional bridges are not scanned.
Expand All @@ -476,17 +486,18 @@ pub fn init() {
let vendor_id = device_vendor_id as u16;
let adapter = PciAdapter::new(bus, device, vendor_id, device_id);
if let Some(adapter) = adapter {
adapters.push(adapter);
unsafe {
PCI_ADAPTERS.push(adapter);
}
}
}
}
}
}

pub fn init_drivers() {
let adapters = PCI_ADAPTERS.lock();
// virtio: 4.1.2 PCI Device Discovery
for adapter in adapters.iter() {
for adapter in unsafe { PCI_ADAPTERS.iter() } {
if adapter.vendor_id == 0x1AF4 && adapter.device_id >= 0x1000 && adapter.device_id <= 0x107F
{
info!(
Expand All @@ -501,8 +512,7 @@ pub fn init_drivers() {
pub fn print_information() {
infoheader!(" PCI BUS INFORMATION ");

let adapters = PCI_ADAPTERS.lock();
for adapter in adapters.iter() {
for adapter in unsafe { PCI_ADAPTERS.iter() } {
info!("{}", adapter);
}

Expand Down
8 changes: 5 additions & 3 deletions src/arch/x86_64/kernel/virtio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use crate::arch::x86_64::kernel::virtio_net;
use crate::arch::x86_64::mm::paging;
use crate::arch::x86_64::mm::VirtAddr;
use crate::config::VIRTIO_MAX_QUEUE_SIZE;
use crate::synch::spinlock::SpinlockIrqSave;

use alloc::boxed::Box;
use alloc::rc::Rc;
Expand Down Expand Up @@ -834,7 +835,7 @@ pub fn init_virtio_device(adapter: &pci::PciAdapter) {
PciNetworkControllerSubclass::EthernetController => {
// TODO: proper error handling on driver creation fail
let drv = virtio_net::create_virtionet_driver(adapter).unwrap();
pci::register_driver(PciDriver::VirtioNet(drv));
pci::register_driver(PciDriver::VirtioNet(SpinlockIrqSave::new(drv)));
}
_ => {
warn!("Virtio device is NOT supported, skipping!");
Expand All @@ -852,7 +853,8 @@ pub fn init_virtio_device(adapter: &pci::PciAdapter) {
info!("Found Virtio-FS device!");
// TODO: check subclass
// TODO: proper error handling on driver creation fail
virtio_fs::create_virtiofs_driver(adapter).unwrap();
let drv = virtio_fs::create_virtiofs_driver(adapter).unwrap();
pci::register_driver(PciDriver::VirtioFs(SpinlockIrqSave::new(drv)));
}
_ => {
warn!("Virtio device is NOT supported, skipping!");
Expand All @@ -878,7 +880,7 @@ extern "x86-interrupt" fn virtio_irqhandler(_stack_frame: &mut ExceptionStackFra
increment_irq_counter((32 + unsafe { VIRTIO_IRQ_NO }).into());

let check_scheduler = match get_network_driver() {
Some(driver) => driver.borrow_mut().handle_interrupt(),
Some(driver) => driver.lock().handle_interrupt(),
_ => false,
};

Expand Down
14 changes: 5 additions & 9 deletions src/arch/x86_64/kernel/virtio_fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@ use crate::syscalls::fs;
use crate::util;

use alloc::boxed::Box;
use alloc::rc::Rc;
use alloc::vec::Vec;
use core::cell::RefCell;
use core::{fmt, u32, u8};

#[repr(C)]
Expand Down Expand Up @@ -236,9 +234,7 @@ impl FuseInterface for VirtioFsDriver<'_> {
*/
}

pub fn create_virtiofs_driver(
adapter: &pci::PciAdapter,
) -> Option<Rc<RefCell<VirtioFsDriver<'static>>>> {
pub fn create_virtiofs_driver(adapter: &pci::PciAdapter) -> Option<VirtioFsDriver<'static>> {
// Scan capabilities to get common config, which we need to reset the device and get basic info.
// also see https://elixir.bootlin.com/linux/latest/source/drivers/virtio/virtio_pci_modern.c#L581 (virtio_pci_modern_probe)
// Read status register
Expand Down Expand Up @@ -299,19 +295,19 @@ pub fn create_virtiofs_driver(
// TODO: also load the other 2 cap types (?).

// Instanciate driver on heap, so it outlives this function
let drv = Rc::new(RefCell::new(VirtioFsDriver {
let mut drv = VirtioFsDriver {
common_cfg,
device_cfg,
notify_cfg,
vqueues: None,
}));
};

trace!("Driver before init: {:?}", drv);
drv.borrow_mut().init();
drv.init();
trace!("Driver after init: {:?}", drv);

// Instanciate global fuse object
let fuse = fuse::Fuse::new(drv.clone());
let fuse = fuse::Fuse::new();

// send FUSE_INIT to create session
fuse.send_init();
Expand Down
15 changes: 5 additions & 10 deletions src/arch/x86_64/kernel/virtio_net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -452,9 +452,7 @@ impl<'a> VirtioNetDriver<'a> {
}
}

pub fn create_virtionet_driver(
adapter: &pci::PciAdapter,
) -> Option<Rc<RefCell<VirtioNetDriver<'static>>>> {
pub fn create_virtionet_driver(adapter: &pci::PciAdapter) -> Option<VirtioNetDriver<'static>> {
// Scan capabilities to get common config, which we need to reset the device and get basic info.
// also see https://elixir.bootlin.com/linux/latest/source/drivers/virtio/virtio_pci_modern.c#L581 (virtio_pci_modern_probe)
// Read status register
Expand Down Expand Up @@ -523,29 +521,26 @@ pub fn create_virtionet_driver(
// TODO: also load the other cap types (?).

// Instanciate driver on heap, so it outlives this function
let drv = Rc::new(RefCell::new(VirtioNetDriver {
let mut drv = VirtioNetDriver {
tx_buffers: Vec::new(),
rx_buffers: Vec::new(),
common_cfg,
device_cfg,
isr_cfg,
notify_cfg,
vqueues: None,
}));
};

trace!("Driver before init: {:?}", drv);
drv.borrow_mut().init();
drv.init();
trace!("Driver after init: {:?}", drv);

if device_cfg.status & VIRTIO_NET_S_LINK_UP == VIRTIO_NET_S_LINK_UP {
info!("Virtio-Net link is up");
} else {
info!("Virtio-Net link is down");
}
info!(
"Virtio-Net status: 0x{:x}",
drv.borrow().common_cfg.device_status
);
info!("Virtio-Net status: 0x{:x}", drv.common_cfg.device_status);

Some(drv)
}
Loading

0 comments on commit f105ba8

Please sign in to comment.