diff --git a/Makefile b/Makefile index 0a23bf8..7b4e165 100644 --- a/Makefile +++ b/Makefile @@ -24,6 +24,7 @@ all: $(KBUILD)/harddrive.bin clean: cargo clean cargo clean --manifest-path libstd/Cargo.toml + cargo clean --manifest-path drivers/ahcid/Cargo.toml cargo clean --manifest-path drivers/ps2d/Cargo.toml cargo clean --manifest-path drivers/pcid/Cargo.toml cargo clean --manifest-path drivers/vesad/Cargo.toml @@ -39,7 +40,7 @@ FORCE: # Emulation QEMU=qemu-system-$(ARCH) -QEMUFLAGS=-serial mon:stdio -d guest_errors +QEMUFLAGS=-serial mon:stdio -d cpu_reset -d guest_errors ifeq ($(ARCH),arm) LD=$(ARCH)-none-eabi-ld QEMUFLAGS+=-cpu arm1176 -machine integratorcp @@ -55,7 +56,7 @@ qemu: $(KBUILD)/harddrive.bin $(QEMU) $(QEMUFLAGS) -kernel $< else LD=ld - QEMUFLAGS+=-machine q35 -smp 4 + QEMUFLAGS+=-machine q35 -smp 4 -m 256 ifeq ($(kvm),yes) QEMUFLAGS+=-enable-kvm -cpu host endif @@ -168,6 +169,7 @@ coreutils: \ initfs/bin/realpath $(BUILD)/initfs.rs: \ + initfs/bin/ahcid \ initfs/bin/pcid \ initfs/bin/ps2d \ initfs/bin/vesad \ diff --git a/arch/x86_64/src/memory/area_frame_allocator.rs b/arch/x86_64/src/memory/area_frame_allocator.rs index 15f21a2..6367d06 100644 --- a/arch/x86_64/src/memory/area_frame_allocator.rs +++ b/arch/x86_64/src/memory/area_frame_allocator.rs @@ -43,11 +43,14 @@ impl AreaFrameAllocator { } impl FrameAllocator for AreaFrameAllocator { - fn allocate_frame(&mut self) -> Option { - if let Some(area) = self.current_area { + fn allocate_frames(&mut self, count: usize) -> Option { + if count == 0 { + None + } else if let Some(area) = self.current_area { // "Clone" the frame to return it if it's free. Frame doesn't // implement Clone, but we can construct an identical frame. - let frame = Frame{ number: self.next_free_frame.number }; + let start_frame = Frame{ number: self.next_free_frame.number }; + let end_frame = Frame { number: self.next_free_frame.number + (count - 1) }; // the last frame of the current area let current_area_last_frame = { @@ -55,27 +58,28 @@ impl FrameAllocator for AreaFrameAllocator { Frame::containing_address(PhysicalAddress::new(address as usize)) }; - if frame > current_area_last_frame { + if end_frame > current_area_last_frame { // all frames of current area are used, switch to next area self.choose_next_area(); - } else if frame >= self.kernel_start && frame <= self.kernel_end { + } else if (start_frame >= self.kernel_start && start_frame <= self.kernel_end) + || (end_frame >= self.kernel_start && end_frame <= self.kernel_end) { // `frame` is used by the kernel self.next_free_frame = Frame { number: self.kernel_end.number + 1 }; } else { // frame is unused, increment `next_free_frame` and return it - self.next_free_frame.number += 1; - return Some(frame); + self.next_free_frame.number += count; + return Some(start_frame); } // `frame` was not valid, try it again with the updated `next_free_frame` - self.allocate_frame() + self.allocate_frames(count) } else { None // no free frames left } } - fn deallocate_frame(&mut self, frame: Frame) { + fn deallocate_frames(&mut self, frame: Frame, count: usize) { //panic!("AreaFrameAllocator::deallocate_frame: not supported: {:?}", frame); } } diff --git a/arch/x86_64/src/memory/mod.rs b/arch/x86_64/src/memory/mod.rs index 02c6c2b..f7f5048 100644 --- a/arch/x86_64/src/memory/mod.rs +++ b/arch/x86_64/src/memory/mod.rs @@ -69,17 +69,27 @@ pub unsafe fn init(kernel_start: usize, kernel_end: usize) { /// Allocate a frame pub fn allocate_frame() -> Option { + allocate_frames(1) +} + +/// Deallocate a frame +pub fn deallocate_frame(frame: Frame) { + deallocate_frames(frame, 1) +} + +/// Allocate a range of frames +pub fn allocate_frames(count: usize) -> Option { if let Some(ref mut allocator) = *ALLOCATOR.lock() { - allocator.allocate_frame() + allocator.allocate_frames(count) } else { panic!("frame allocator not initialized"); } } -/// Deallocate a frame -pub fn deallocate_frame(frame: Frame) { +/// Deallocate a range of frames frame +pub fn deallocate_frames(frame: Frame, count: usize) { if let Some(ref mut allocator) = *ALLOCATOR.lock() { - allocator.deallocate_frame(frame) + allocator.deallocate_frames(frame, count) } else { panic!("frame allocator not initialized"); } @@ -151,6 +161,6 @@ impl Iterator for FrameIter { } pub trait FrameAllocator { - fn allocate_frame(&mut self) -> Option; - fn deallocate_frame(&mut self, frame: Frame); + fn allocate_frames(&mut self, size: usize) -> Option; + fn deallocate_frames(&mut self, frame: Frame, size: usize); } diff --git a/drivers/ahcid/Cargo.toml b/drivers/ahcid/Cargo.toml new file mode 100644 index 0000000..2bc8fa8 --- /dev/null +++ b/drivers/ahcid/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "ahcid" +version = "0.1.0" + +[dependencies] +bitflags = "*" +io = { path = "../io/" } +spin = "*" +syscall = { path = "../../syscall/" } diff --git a/drivers/ahcid/src/ahci/disk.rs b/drivers/ahcid/src/ahci/disk.rs new file mode 100644 index 0000000..fbef726 --- /dev/null +++ b/drivers/ahcid/src/ahci/disk.rs @@ -0,0 +1,116 @@ +use std::ptr; + +use syscall::error::{Error, EIO, Result}; + +use super::dma::Dma; +use super::hba::{HbaPort, HbaCmdTable, HbaCmdHeader}; + +pub struct Disk { + id: usize, + port: &'static mut HbaPort, + size: u64, + clb: Dma<[HbaCmdHeader; 32]>, + ctbas: [Dma; 32], + fb: Dma<[u8; 256]>, + buf: Dma<[u8; 256 * 512]> +} + +impl Disk { + pub fn new(id: usize, port: &'static mut HbaPort) -> Result { + let mut clb = Dma::zeroed()?; + let mut ctbas = [ + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + ]; + let mut fb = Dma::zeroed()?; + let buf = Dma::zeroed()?; + + port.init(&mut clb, &mut ctbas, &mut fb); + + let size = unsafe { port.identify(&mut clb, &mut ctbas).unwrap_or(0) }; + + Ok(Disk { + id: id, + port: port, + size: size, + clb: clb, + ctbas: ctbas, + fb: fb, + buf: buf + }) + } + + pub fn id(&self) -> usize { + self.id + } + + pub fn size(&self) -> u64 { + self.size + } + + pub fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result { + let sectors = buffer.len()/512; + if sectors > 0 { + let mut sector: usize = 0; + while sectors - sector >= 255 { + if let Err(err) = self.port.ata_dma(block + sector as u64, 255, false, &mut self.clb, &mut self.ctbas, &mut self.buf) { + return Err(err); + } + + unsafe { ptr::copy(self.buf.as_ptr(), buffer.as_mut_ptr().offset(sector as isize * 512), 255 * 512); } + + sector += 255; + } + if sector < sectors { + if let Err(err) = self.port.ata_dma(block + sector as u64, sectors - sector, false, &mut self.clb, &mut self.ctbas, &mut self.buf) { + return Err(err); + } + + unsafe { ptr::copy(self.buf.as_ptr(), buffer.as_mut_ptr().offset(sector as isize * 512), (sectors - sector) * 512); } + + sector += sectors - sector; + } + + Ok(sector * 512) + } else { + println!("Invalid request"); + Err(Error::new(EIO)) + } + } + + pub fn write(&mut self, block: u64, buffer: &[u8]) -> Result { + let sectors = (buffer.len() + 511)/512; + if sectors > 0 { + let mut sector: usize = 0; + while sectors - sector >= 255 { + unsafe { ptr::copy(buffer.as_ptr().offset(sector as isize * 512), self.buf.as_mut_ptr(), 255 * 512); } + + if let Err(err) = self.port.ata_dma(block + sector as u64, 255, true, &mut self.clb, &mut self.ctbas, &mut self.buf) { + return Err(err); + } + + sector += 255; + } + if sector < sectors { + unsafe { ptr::copy(buffer.as_ptr().offset(sector as isize * 512), self.buf.as_mut_ptr(), (sectors - sector) * 512); } + + if let Err(err) = self.port.ata_dma(block + sector as u64, sectors - sector, true, &mut self.clb, &mut self.ctbas, &mut self.buf) { + return Err(err); + } + + sector += sectors - sector; + } + + Ok(sector * 512) + } else { + println!("Invalid request"); + Err(Error::new(EIO)) + } + } +} diff --git a/drivers/ahcid/src/ahci/dma.rs b/drivers/ahcid/src/ahci/dma.rs new file mode 100644 index 0000000..91258b8 --- /dev/null +++ b/drivers/ahcid/src/ahci/dma.rs @@ -0,0 +1,76 @@ +use std::{mem, ptr}; +use std::ops::{Deref, DerefMut}; + +use syscall::{self, Result}; + +struct PhysBox { + address: usize, + size: usize +} + +impl PhysBox { + fn new(size: usize) -> Result { + let address = unsafe { syscall::physalloc(size)? }; + Ok(PhysBox { + address: address, + size: size + }) + } +} + +impl Drop for PhysBox { + fn drop(&mut self) { + let _ = unsafe { syscall::physfree(self.address, self.size) }; + } +} + +pub struct Dma { + phys: PhysBox, + virt: *mut T +} + +impl Dma { + pub fn new(value: T) -> Result> { + let phys = PhysBox::new(mem::size_of::())?; + let virt = unsafe { syscall::physmap(phys.address, phys.size, syscall::MAP_WRITE)? } as *mut T; + unsafe { ptr::write(virt, value); } + Ok(Dma { + phys: phys, + virt: virt + }) + } + + pub fn zeroed() -> Result> { + let phys = PhysBox::new(mem::size_of::())?; + let virt = unsafe { syscall::physmap(phys.address, phys.size, syscall::MAP_WRITE)? } as *mut T; + unsafe { ptr::write_bytes(virt as *mut u8, 0, phys.size); } + Ok(Dma { + phys: phys, + virt: virt + }) + } + + pub fn physical(&self) -> usize { + self.phys.address + } +} + +impl Deref for Dma { + type Target = T; + fn deref(&self) -> &T { + unsafe { &*self.virt } + } +} + +impl DerefMut for Dma { + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.virt } + } +} + +impl Drop for Dma { + fn drop(&mut self) { + unsafe { drop(ptr::read(self.virt)); } + let _ = unsafe { syscall::physunmap(self.virt as usize) }; + } +} diff --git a/drivers/ahcid/src/ahci/fis.rs b/drivers/ahcid/src/ahci/fis.rs new file mode 100644 index 0000000..7dbe33c --- /dev/null +++ b/drivers/ahcid/src/ahci/fis.rs @@ -0,0 +1,155 @@ +use io::Mmio; + +#[repr(u8)] +pub enum FisType { + /// Register FIS - host to device + RegH2D = 0x27, + /// Register FIS - device to host + RegD2H = 0x34, + /// DMA activate FIS - device to host + DmaAct = 0x39, + /// DMA setup FIS - bidirectional + DmaSetup = 0x41, + /// Data FIS - bidirectional + Data = 0x46, + /// BIST activate FIS - bidirectional + Bist = 0x58, + /// PIO setup FIS - device to host + PioSetup = 0x5F, + /// Set device bits FIS - device to host + DevBits = 0xA1 +} + +#[repr(packed)] +pub struct FisRegH2D { + // DWORD 0 + pub fis_type: Mmio, // FIS_TYPE_REG_H2D + + pub pm: Mmio, // Port multiplier, 1: Command, 0: Control + + pub command: Mmio, // Command register + pub featurel: Mmio, // Feature register, 7:0 + + // DWORD 1 + pub lba0: Mmio, // LBA low register, 7:0 + pub lba1: Mmio, // LBA mid register, 15:8 + pub lba2: Mmio, // LBA high register, 23:16 + pub device: Mmio, // Device register + + // DWORD 2 + pub lba3: Mmio, // LBA register, 31:24 + pub lba4: Mmio, // LBA register, 39:32 + pub lba5: Mmio, // LBA register, 47:40 + pub featureh: Mmio, // Feature register, 15:8 + + // DWORD 3 + pub countl: Mmio, // Count register, 7:0 + pub counth: Mmio, // Count register, 15:8 + pub icc: Mmio, // Isochronous command completion + pub control: Mmio, // Control register + + // DWORD 4 + pub rsv1: [Mmio; 4], // Reserved +} + +#[repr(packed)] +pub struct FisRegD2H { + // DWORD 0 + pub fis_type: Mmio, // FIS_TYPE_REG_D2H + + pub pm: Mmio, // Port multiplier, Interrupt bit: 2 + + pub status: Mmio, // Status register + pub error: Mmio, // Error register + + // DWORD 1 + pub lba0: Mmio, // LBA low register, 7:0 + pub lba1: Mmio, // LBA mid register, 15:8 + pub lba2: Mmio, // LBA high register, 23:16 + pub device: Mmio, // Device register + + // DWORD 2 + pub lba3: Mmio, // LBA register, 31:24 + pub lba4: Mmio, // LBA register, 39:32 + pub lba5: Mmio, // LBA register, 47:40 + pub rsv2: Mmio, // Reserved + + // DWORD 3 + pub countl: Mmio, // Count register, 7:0 + pub counth: Mmio, // Count register, 15:8 + pub rsv3: [Mmio; 2], // Reserved + + // DWORD 4 + pub rsv4: [Mmio; 4], // Reserved +} + +#[repr(packed)] +pub struct FisData { + // DWORD 0 + pub fis_type: Mmio, // FIS_TYPE_DATA + + pub pm: Mmio, // Port multiplier + + pub rsv1: [Mmio; 2], // Reserved + + // DWORD 1 ~ N + pub data: [Mmio; 252], // Payload +} + +#[repr(packed)] +pub struct FisPioSetup { + // DWORD 0 + pub fis_type: Mmio, // FIS_TYPE_PIO_SETUP + + pub pm: Mmio, // Port multiplier, direction: 4 - device to host, interrupt: 2 + + pub status: Mmio, // Status register + pub error: Mmio, // Error register + + // DWORD 1 + pub lba0: Mmio, // LBA low register, 7:0 + pub lba1: Mmio, // LBA mid register, 15:8 + pub lba2: Mmio, // LBA high register, 23:16 + pub device: Mmio, // Device register + + // DWORD 2 + pub lba3: Mmio, // LBA register, 31:24 + pub lba4: Mmio, // LBA register, 39:32 + pub lba5: Mmio, // LBA register, 47:40 + pub rsv2: Mmio, // Reserved + + // DWORD 3 + pub countl: Mmio, // Count register, 7:0 + pub counth: Mmio, // Count register, 15:8 + pub rsv3: Mmio, // Reserved + pub e_status: Mmio, // New value of status register + + // DWORD 4 + pub tc: Mmio, // Transfer count + pub rsv4: [Mmio; 2], // Reserved +} + +#[repr(packed)] +pub struct FisDmaSetup { + // DWORD 0 + pub fis_type: Mmio, // FIS_TYPE_DMA_SETUP + + pub pm: Mmio, // Port multiplier, direction: 4 - device to host, interrupt: 2, auto-activate: 1 + + pub rsv1: [Mmio; 2], // Reserved + + // DWORD 1&2 + pub dma_buffer_id: Mmio, /* DMA Buffer Identifier. Used to Identify DMA buffer in host memory. SATA Spec says host specific and not in Spec. Trying AHCI spec might work. */ + + // DWORD 3 + pub rsv3: Mmio, // More reserved + + // DWORD 4 + pub dma_buffer_offset: Mmio, // Byte offset into buffer. First 2 bits must be 0 + + // DWORD 5 + pub transfer_count: Mmio, // Number of bytes to transfer. Bit 0 must be 0 + + // DWORD 6 + pub rsv6: Mmio, // Reserved +} diff --git a/drivers/ahcid/src/ahci/hba.rs b/drivers/ahcid/src/ahci/hba.rs new file mode 100644 index 0000000..015b733 --- /dev/null +++ b/drivers/ahcid/src/ahci/hba.rs @@ -0,0 +1,351 @@ +use io::{Io, Mmio}; + +use std::mem::size_of; +use std::ops::DerefMut; +use std::{ptr, u32}; + +use syscall::error::{Error, Result, EIO}; + +use super::dma::Dma; +use super::fis::{FisType, FisRegH2D}; + +const ATA_CMD_READ_DMA_EXT: u8 = 0x25; +const ATA_CMD_WRITE_DMA_EXT: u8 = 0x35; +const ATA_CMD_IDENTIFY: u8 = 0xEC; +const ATA_DEV_BUSY: u8 = 0x80; +const ATA_DEV_DRQ: u8 = 0x08; + +const HBA_PORT_CMD_CR: u32 = 1 << 15; +const HBA_PORT_CMD_FR: u32 = 1 << 14; +const HBA_PORT_CMD_FRE: u32 = 1 << 4; +const HBA_PORT_CMD_ST: u32 = 1; +const HBA_PORT_IS_TFES: u32 = 1 << 30; +const HBA_SSTS_PRESENT: u32 = 0x3; +const HBA_SIG_ATA: u32 = 0x00000101; +const HBA_SIG_ATAPI: u32 = 0xEB140101; +const HBA_SIG_PM: u32 = 0x96690101; +const HBA_SIG_SEMB: u32 = 0xC33C0101; + +#[derive(Debug)] +pub enum HbaPortType { + None, + Unknown(u32), + SATA, + SATAPI, + PM, + SEMB, +} + +#[repr(packed)] +pub struct HbaPort { + pub clb: Mmio, // 0x00, command list base address, 1K-byte aligned + pub fb: Mmio, // 0x08, FIS base address, 256-byte aligned + pub is: Mmio, // 0x10, interrupt status + pub ie: Mmio, // 0x14, interrupt enable + pub cmd: Mmio, // 0x18, command and status + pub rsv0: Mmio, // 0x1C, Reserved + pub tfd: Mmio, // 0x20, task file data + pub sig: Mmio, // 0x24, signature + pub ssts: Mmio, // 0x28, SATA status (SCR0:SStatus) + pub sctl: Mmio, // 0x2C, SATA control (SCR2:SControl) + pub serr: Mmio, // 0x30, SATA error (SCR1:SError) + pub sact: Mmio, // 0x34, SATA active (SCR3:SActive) + pub ci: Mmio, // 0x38, command issue + pub sntf: Mmio, // 0x3C, SATA notification (SCR4:SNotification) + pub fbs: Mmio, // 0x40, FIS-based switch control + pub rsv1: [Mmio; 11], // 0x44 ~ 0x6F, Reserved + pub vendor: [Mmio; 4], // 0x70 ~ 0x7F, vendor specific +} + +impl HbaPort { + pub fn probe(&self) -> HbaPortType { + if self.ssts.readf(HBA_SSTS_PRESENT) { + let sig = self.sig.read(); + match sig { + HBA_SIG_ATA => HbaPortType::SATA, + HBA_SIG_ATAPI => HbaPortType::SATAPI, + HBA_SIG_PM => HbaPortType::PM, + HBA_SIG_SEMB => HbaPortType::SEMB, + _ => HbaPortType::Unknown(sig), + } + } else { + HbaPortType::None + } + } + + pub fn init(&mut self, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32], fb: &mut Dma<[u8; 256]>) { + self.stop(); + + self.clb.write(clb.physical() as u64); + self.fb.write(fb.physical() as u64); + + for i in 0..32 { + let cmdheader = &mut clb[i]; + cmdheader.ctba.write(ctbas[i].physical() as u64); + cmdheader.prdtl.write(0); + } + + self.start(); + } + + pub unsafe fn identify(&mut self, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32]) -> Option { + self.is.write(u32::MAX); + + let dest: Dma<[u16; 256]> = Dma::new([0; 256]).unwrap(); + + if let Some(slot) = self.slot() { + let cmdheader = &mut clb[slot as usize]; + cmdheader.cfl.write(((size_of::() / size_of::()) as u8)); + cmdheader.prdtl.write(1); + + { + let cmdtbl = &mut ctbas[slot as usize]; + ptr::write_bytes(cmdtbl.deref_mut() as *mut HbaCmdTable as *mut u8, 0, size_of::()); + + let prdt_entry = &mut cmdtbl.prdt_entry[0]; + prdt_entry.dba.write(dest.physical() as u64); + prdt_entry.dbc.write(512 | 1); + } + + { + let cmdfis = &mut *(ctbas[slot as usize].cfis.as_mut_ptr() as *mut FisRegH2D); + + cmdfis.fis_type.write(FisType::RegH2D as u8); + cmdfis.pm.write(1 << 7); + cmdfis.command.write(ATA_CMD_IDENTIFY); + cmdfis.device.write(0); + cmdfis.countl.write(1); + cmdfis.counth.write(0); + } + + while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) {} + + self.ci.writef(1 << slot, true); + + while self.ci.readf(1 << slot) { + if self.is.readf(HBA_PORT_IS_TFES) { + return None; + } + } + + if self.is.readf(HBA_PORT_IS_TFES) { + return None; + } + + let mut serial = String::new(); + for word in 10..20 { + let d = dest[word]; + let a = ((d >> 8) as u8) as char; + if a != '\0' { + serial.push(a); + } + let b = (d as u8) as char; + if b != '\0' { + serial.push(b); + } + } + + let mut firmware = String::new(); + for word in 23..27 { + let d = dest[word]; + let a = ((d >> 8) as u8) as char; + if a != '\0' { + firmware.push(a); + } + let b = (d as u8) as char; + if b != '\0' { + firmware.push(b); + } + } + + let mut model = String::new(); + for word in 27..47 { + let d = dest[word]; + let a = ((d >> 8) as u8) as char; + if a != '\0' { + model.push(a); + } + let b = (d as u8) as char; + if b != '\0' { + model.push(b); + } + } + + let mut sectors = (dest[100] as u64) | + ((dest[101] as u64) << 16) | + ((dest[102] as u64) << 32) | + ((dest[103] as u64) << 48); + + let lba_bits = if sectors == 0 { + sectors = (dest[60] as u64) | ((dest[61] as u64) << 16); + 28 + } else { + 48 + }; + + println!(" + Serial: {} Firmware: {} Model: {} {}-bit LBA Size: {} MB", + serial.trim(), firmware.trim(), model.trim(), lba_bits, sectors / 2048); + + Some(sectors * 512) + } else { + None + } + } + + pub fn start(&mut self) { + while self.cmd.readf(HBA_PORT_CMD_CR) {} + + self.cmd.writef(HBA_PORT_CMD_FRE, true); + self.cmd.writef(HBA_PORT_CMD_ST, true); + } + + pub fn stop(&mut self) { + self.cmd.writef(HBA_PORT_CMD_ST, false); + + while self.cmd.readf(HBA_PORT_CMD_FR | HBA_PORT_CMD_CR) {} + + self.cmd.writef(HBA_PORT_CMD_FRE, false); + } + + pub fn slot(&self) -> Option { + let slots = self.sact.read() | self.ci.read(); + for i in 0..32 { + if slots & 1 << i == 0 { + return Some(i); + } + } + None + } + + pub fn ata_dma(&mut self, block: u64, sectors: usize, write: bool, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32], buf: &mut Dma<[u8; 256 * 512]>) -> Result { + println!("AHCI {:X} DMA BLOCK: {:X} SECTORS: {} WRITE: {}", (self as *mut HbaPort) as usize, block, sectors, write); + + assert!(sectors > 0 && sectors < 256); + + self.is.write(u32::MAX); + + if let Some(slot) = self.slot() { + println!("Slot {}", slot); + + let cmdheader = &mut clb[slot as usize]; + + cmdheader.cfl.write(((size_of::() / size_of::()) as u8)); + cmdheader.cfl.writef(1 << 6, write); + + cmdheader.prdtl.write(1); + + { + let cmdtbl = &mut ctbas[slot as usize]; + unsafe { ptr::write_bytes(cmdtbl.deref_mut() as *mut HbaCmdTable as *mut u8, 0, size_of::()) }; + + let prdt_entry = &mut cmdtbl.prdt_entry[0]; + prdt_entry.dba.write(buf.physical() as u64); + prdt_entry.dbc.write(((sectors * 512) as u32) | 1); + } + + { + let cmdfis = unsafe { &mut *(ctbas[slot as usize].cfis.as_mut_ptr() as *mut FisRegH2D) }; + + cmdfis.fis_type.write(FisType::RegH2D as u8); + cmdfis.pm.write(1 << 7); + if write { + cmdfis.command.write(ATA_CMD_WRITE_DMA_EXT); + } else { + cmdfis.command.write(ATA_CMD_READ_DMA_EXT); + } + + cmdfis.lba0.write(block as u8); + cmdfis.lba1.write((block >> 8) as u8); + cmdfis.lba2.write((block >> 16) as u8); + + cmdfis.device.write(1 << 6); + + cmdfis.lba3.write((block >> 24) as u8); + cmdfis.lba4.write((block >> 32) as u8); + cmdfis.lba5.write((block >> 40) as u8); + + cmdfis.countl.write(sectors as u8); + cmdfis.counth.write((sectors >> 8) as u8); + } + + println!("Busy Wait"); + while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) {} + + self.ci.writef(1 << slot, true); + + println!("Completion Wait"); + while self.ci.readf(1 << slot) { + if self.is.readf(HBA_PORT_IS_TFES) { + return Err(Error::new(EIO)); + } + } + + if self.is.readf(HBA_PORT_IS_TFES) { + return Err(Error::new(EIO)); + } + + Ok(sectors * 512) + } else { + println!("No Command Slots"); + Err(Error::new(EIO)) + } + } +} + +#[repr(packed)] +pub struct HbaMem { + pub cap: Mmio, // 0x00, Host capability + pub ghc: Mmio, // 0x04, Global host control + pub is: Mmio, // 0x08, Interrupt status + pub pi: Mmio, // 0x0C, Port implemented + pub vs: Mmio, // 0x10, Version + pub ccc_ctl: Mmio, // 0x14, Command completion coalescing control + pub ccc_pts: Mmio, // 0x18, Command completion coalescing ports + pub em_loc: Mmio, // 0x1C, Enclosure management location + pub em_ctl: Mmio, // 0x20, Enclosure management control + pub cap2: Mmio, // 0x24, Host capabilities extended + pub bohc: Mmio, // 0x28, BIOS/OS handoff control and status + pub rsv: [Mmio; 116], // 0x2C - 0x9F, Reserved + pub vendor: [Mmio; 96], // 0xA0 - 0xFF, Vendor specific registers + pub ports: [HbaPort; 32], // 0x100 - 0x10FF, Port control registers +} + +#[repr(packed)] +pub struct HbaPrdtEntry { + dba: Mmio, // Data base address + rsv0: Mmio, // Reserved + dbc: Mmio, // Byte count, 4M max, interrupt = 1 +} + +#[repr(packed)] +pub struct HbaCmdTable { + // 0x00 + cfis: [Mmio; 64], // Command FIS + + // 0x40 + acmd: [Mmio; 16], // ATAPI command, 12 or 16 bytes + + // 0x50 + rsv: [Mmio; 48], // Reserved + + // 0x80 + prdt_entry: [HbaPrdtEntry; 65536], // Physical region descriptor table entries, 0 ~ 65535 +} + +#[repr(packed)] +pub struct HbaCmdHeader { + // DW0 + cfl: Mmio, /* Command FIS length in DWORDS, 2 ~ 16, atapi: 4, write - host to device: 2, prefetchable: 1 */ + pm: Mmio, // Reset - 0x80, bist: 0x40, clear busy on ok: 0x20, port multiplier + + prdtl: Mmio, // Physical region descriptor table length in entries + + // DW1 + prdbc: Mmio, // Physical region descriptor byte count transferred + + // DW2, 3 + ctba: Mmio, // Command table descriptor base address + + // DW4 - 7 + rsv1: [Mmio; 4], // Reserved +} diff --git a/drivers/ahcid/src/ahci/mod.rs b/drivers/ahcid/src/ahci/mod.rs new file mode 100644 index 0000000..9d594de --- /dev/null +++ b/drivers/ahcid/src/ahci/mod.rs @@ -0,0 +1,37 @@ +use io::Io; + +use self::disk::Disk; +use self::hba::{HbaMem, HbaPortType}; + +pub mod disk; +pub mod dma; +pub mod fis; +pub mod hba; + +pub fn disks(base: usize, irq: u8) -> Vec { + println!(" + AHCI on: {:X} IRQ: {}", base as usize, irq); + + let pi = unsafe { &mut *(base as *mut HbaMem) }.pi.read(); + let ret: Vec = (0..32) + .filter(|&i| pi & 1 << i as i32 == 1 << i as i32) + .filter_map(|i| { + let port = &mut unsafe { &mut *(base as *mut HbaMem) }.ports[i]; + let port_type = port.probe(); + println!("{}: {:?}", i, port_type); + match port_type { + HbaPortType::SATA => { + match Disk::new(i, port) { + Ok(disk) => Some(disk), + Err(err) => { + println!("{}: {}", i, err); + None + } + } + } + _ => None, + } + }) + .collect(); + + ret +} diff --git a/drivers/ahcid/src/main.rs b/drivers/ahcid/src/main.rs new file mode 100644 index 0000000..07ca38e --- /dev/null +++ b/drivers/ahcid/src/main.rs @@ -0,0 +1,48 @@ +#![feature(asm)] +#![feature(question_mark)] + +#[macro_use] +extern crate bitflags; +extern crate io; +extern crate spin; +extern crate syscall; + +use std::fs::File; +use std::io::{Read, Write}; +use std::{env, thread, usize}; +use syscall::{iopl, physmap, physunmap, MAP_WRITE, Packet, Scheme}; + +use scheme::DiskScheme; + +pub mod ahci; +pub mod scheme; + +fn main() { + let mut args = env::args().skip(1); + + 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 irq_str = args.next().expect("ahcid: no irq provided"); + let irq = irq_str.parse::().expect("ahcid: failed to parse irq"); + + thread::spawn(move || { + unsafe { + iopl(3).expect("ahcid: failed to get I/O permission"); + asm!("cli" :::: "intel", "volatile"); + } + + let address = unsafe { physmap(bar, 4096, MAP_WRITE).expect("ahcid: failed to map address") }; + { + let mut socket = File::create(":disk").expect("ahcid: failed to create disk scheme"); + let scheme = DiskScheme::new(ahci::disks(address, irq)); + loop { + let mut packet = Packet::default(); + socket.read(&mut packet).expect("ahcid: failed to read disk scheme"); + scheme.handle(&mut packet); + socket.write(&mut packet).expect("ahcid: failed to read disk scheme"); + } + } + unsafe { let _ = physunmap(address); } + }); +} diff --git a/drivers/ahcid/src/scheme.rs b/drivers/ahcid/src/scheme.rs new file mode 100644 index 0000000..76b8b8a --- /dev/null +++ b/drivers/ahcid/src/scheme.rs @@ -0,0 +1,85 @@ +use std::collections::BTreeMap; +use std::{cmp, str}; +use std::sync::Arc; +use std::sync::atomic::{AtomicUsize, Ordering}; +use spin::Mutex; +use syscall::{Error, EBADF, EINVAL, ENOENT, Result, Scheme, SEEK_CUR, SEEK_END, SEEK_SET}; + +use ahci::disk::Disk; + +pub struct DiskScheme { + disks: Box<[Arc>]>, + handles: Mutex>, usize)>>, + next_id: AtomicUsize +} + +impl DiskScheme { + pub fn new(disks: Vec) -> DiskScheme { + let mut disk_arcs = vec![]; + for disk in disks { + disk_arcs.push(Arc::new(Mutex::new(disk))); + } + + DiskScheme { + disks: disk_arcs.into_boxed_slice(), + handles: Mutex::new(BTreeMap::new()), + next_id: AtomicUsize::new(0) + } + } +} + +impl Scheme for DiskScheme { + fn open(&self, path: &[u8], _flags: usize) -> Result { + let path_str = str::from_utf8(path).or(Err(Error::new(ENOENT)))?; + + let i = path_str.parse::().or(Err(Error::new(ENOENT)))?; + + if let Some(disk) = self.disks.get(i) { + let id = self.next_id.fetch_add(1, Ordering::SeqCst); + self.handles.lock().insert(id, (disk.clone(), 0)); + Ok(id) + } else { + Err(Error::new(ENOENT)) + } + } + + fn read(&self, id: usize, buf: &mut [u8]) -> Result { + let mut handles = self.handles.lock(); + let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; + + let mut disk = handle.0.lock(); + let count = disk.read((handle.1 as u64)/512, buf)?; + handle.1 += count; + Ok(count) + } + + fn write(&self, id: usize, buf: &[u8]) -> Result { + let mut handles = self.handles.lock(); + let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; + + let mut disk = handle.0.lock(); + let count = disk.write((handle.1 as u64)/512, buf)?; + handle.1 += count; + Ok(count) + } + + fn seek(&self, id: usize, pos: usize, whence: usize) -> Result { + let mut handles = self.handles.lock(); + let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; + + let len = handle.0.lock().size() as usize; + handle.1 = match whence { + SEEK_SET => cmp::min(len, pos), + SEEK_CUR => cmp::max(0, cmp::min(len as isize, handle.1 as isize + pos as isize)) as usize, + SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize, + _ => return Err(Error::new(EINVAL)) + }; + + Ok(handle.1) + } + + fn close(&self, id: usize) -> Result { + let mut handles = self.handles.lock(); + handles.remove(&id).ok_or(Error::new(EBADF)).and(Ok(0)) + } +} diff --git a/drivers/pcid/Cargo.toml b/drivers/pcid/Cargo.toml index e6b6318..222032c 100644 --- a/drivers/pcid/Cargo.toml +++ b/drivers/pcid/Cargo.toml @@ -2,5 +2,12 @@ name = "pcid" version = "0.1.0" +[dependencies] +rustc-serialize = { git = "https://github.com/redox-os/rustc-serialize.git" } +toml = "*" + [dependencies.syscall] path = "../../syscall/" + +[replace] +"rustc-serialize:0.3.19" = { git = "https://github.com/redox-os/rustc-serialize.git" } diff --git a/drivers/pcid/src/config.rs b/drivers/pcid/src/config.rs new file mode 100644 index 0000000..3bc4dba --- /dev/null +++ b/drivers/pcid/src/config.rs @@ -0,0 +1,14 @@ +#[derive(Debug, Default, RustcDecodable)] +pub struct Config { + pub drivers: Vec +} + +#[derive(Debug, Default, RustcDecodable)] +pub struct DriverConfig { + pub name: Option, + pub class: Option, + pub subclass: Option, + pub vendor: Option, + pub device: Option, + pub command: Option> +} diff --git a/drivers/pcid/src/main.rs b/drivers/pcid/src/main.rs index 0886bef..a34ff17 100644 --- a/drivers/pcid/src/main.rs +++ b/drivers/pcid/src/main.rs @@ -1,79 +1,152 @@ #![feature(asm)] +extern crate rustc_serialize; extern crate syscall; +extern crate toml; +use std::env; +use std::fs::File; +use std::io::Read; +use std::process::Command; use std::thread; use syscall::iopl; +use config::Config; use pci::{Pci, PciBar, PciClass}; +mod config; mod pci; -fn enumerate_pci() { - println!("PCI BS/DV/FN VEND:DEVI CL.SC.IN.RV"); +fn main() { + thread::spawn(|| { + let mut config = Config::default(); - let pci = Pci::new(); - for bus in pci.buses() { - for dev in bus.devs() { - for func in dev.funcs() { - if let Some(header) = func.header() { - print!("PCI {:>02X}/{:>02X}/{:>02X} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X}", - bus.num, dev.num, func.num, - header.vendor_id, header.device_id, - header.class, header.subclass, header.interface, header.revision); + let mut args = env::args().skip(1); + if let Some(config_path) = args.next() { + if let Ok(mut config_file) = File::open(&config_path) { + let mut config_data = String::new(); + if let Ok(_) = config_file.read_to_string(&mut config_data) { + config = toml::decode_str(&config_data).unwrap_or(Config::default()); + } + } + } - let pci_class = PciClass::from(header.class); - print!(" {:?}", pci_class); - match pci_class { - PciClass::Storage => match header.subclass { - 0x01 => { - print!(" IDE"); + println!("{:?}", config); + + unsafe { iopl(3).unwrap() }; + + println!("PCI BS/DV/FN VEND:DEVI CL.SC.IN.RV"); + + let pci = Pci::new(); + for bus in pci.buses() { + for dev in bus.devs() { + for func in dev.funcs() { + if let Some(header) = func.header() { + print!("PCI {:>02X}/{:>02X}/{:>02X} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X}", + bus.num, dev.num, func.num, + header.vendor_id, header.device_id, + header.class, header.subclass, header.interface, header.revision); + + let pci_class = PciClass::from(header.class); + print!(" {:?}", pci_class); + match pci_class { + PciClass::Storage => match header.subclass { + 0x01 => { + print!(" IDE"); + }, + 0x06 => { + print!(" SATA"); + }, + _ => () }, - 0x06 => { - print!(" SATA"); - }, - _ => () - }, - PciClass::SerialBus => match header.subclass { - 0x03 => match header.interface { - 0x00 => { - print!(" UHCI"); - }, - 0x10 => { - print!(" OHCI"); - }, - 0x20 => { - print!(" EHCI"); - }, - 0x30 => { - print!(" XHCI"); + PciClass::SerialBus => match header.subclass { + 0x03 => match header.interface { + 0x00 => { + print!(" UHCI"); + }, + 0x10 => { + print!(" OHCI"); + }, + 0x20 => { + print!(" EHCI"); + }, + 0x30 => { + print!(" XHCI"); + }, + _ => () }, _ => () }, _ => () - }, - _ => () - } + } - for i in 0..header.bars.len() { - match PciBar::from(header.bars[i]) { - PciBar::None => (), - PciBar::Memory(address) => print!(" {}={:>08X}", i, address), - PciBar::Port(address) => print!(" {}={:>04X}", i, address) + for i in 0..header.bars.len() { + match PciBar::from(header.bars[i]) { + PciBar::None => (), + PciBar::Memory(address) => print!(" {}={:>08X}", i, address), + PciBar::Port(address) => print!(" {}={:>04X}", i, address) + } + } + + print!("\n"); + + for driver in config.drivers.iter() { + if let Some(class) = driver.class { + if class != header.class { continue; } + } + + if let Some(subclass) = driver.subclass { + if subclass != header.subclass { continue; } + } + + if let Some(vendor) = driver.vendor { + if vendor != header.vendor_id { continue; } + } + + if let Some(device) = driver.device { + if device != header.device_id { continue; } + } + + if let Some(ref args) = driver.command { + let mut args = args.iter(); + if let Some(program) = args.next() { + let mut command = Command::new(program); + for arg in args { + let bar_arg = |i| -> String { + match PciBar::from(header.bars[i]) { + PciBar::None => String::new(), + PciBar::Memory(address) => format!("{:>08X}", address), + PciBar::Port(address) => format!("{:>04X}", address) + } + }; + let arg = match arg.as_str() { + "$BAR0" => bar_arg(0), + "$BAR1" => bar_arg(1), + "$BAR2" => bar_arg(2), + "$BAR3" => bar_arg(3), + "$BAR4" => bar_arg(4), + "$BAR5" => bar_arg(5), + "$IRQ" => format!("{}", header.interrupt_line), + _ => arg.clone() + }; + command.arg(&arg); + } + + match command.spawn() { + Ok(mut child) => match child.wait() { + Ok(_status) => (), //println!("pcid: waited for {}: {:?}", line, status.code()), + Err(err) => println!("pcid: failed to wait for {:?}: {}", command, err) + }, + Err(err) => println!("pcid: failed to execute {:?}: {}", command, err) + } + } + } + + println!("Driver: {:?}", driver); } } - - print!("\n"); } } } - } -} - -fn main() { - thread::spawn(||{ - unsafe { iopl(3).unwrap() }; - - enumerate_pci(); }); } diff --git a/drivers/vesad/src/main.rs b/drivers/vesad/src/main.rs index f022a74..cb45f39 100644 --- a/drivers/vesad/src/main.rs +++ b/drivers/vesad/src/main.rs @@ -13,7 +13,7 @@ use std::fs::File; use std::io::{Read, Write}; use std::{slice, thread}; use ransid::{Console, Event}; -use syscall::{physmap, physunmap, Packet, Result, Scheme, MAP_WRITE, MAP_WRITE_COMBINE}; +use syscall::{physmap, physunmap, Packet, Result, Scheme, EVENT_READ, MAP_WRITE, MAP_WRITE_COMBINE}; use display::Display; use mode_info::VBEModeInfo; @@ -26,7 +26,8 @@ pub mod primitive; struct DisplayScheme { console: RefCell, display: RefCell, - input: RefCell> + input: RefCell>, + requested: RefCell } impl Scheme for DisplayScheme { @@ -42,6 +43,12 @@ impl Scheme for DisplayScheme { Ok(id) } + fn fevent(&self, _id: usize, flags: usize) -> Result { + *self.requested.borrow_mut() = flags; + println!("fevent {:X}", flags); + Ok(0) + } + fn fsync(&self, _id: usize) -> Result { Ok(0) } @@ -121,7 +128,8 @@ fn main() { unsafe { slice::from_raw_parts_mut(onscreen as *mut u32, size) }, unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) } )), - input: RefCell::new(VecDeque::new()) + input: RefCell::new(VecDeque::new()), + requested: RefCell::new(0) }; let mut blocked = VecDeque::new(); @@ -129,18 +137,36 @@ fn main() { let mut packet = Packet::default(); socket.read(&mut packet).expect("vesad: failed to read display scheme"); //println!("vesad: {:?}", packet); + + // If it is a read packet, and there is no data, block it. Otherwise, handle packet if packet.a == syscall::number::SYS_READ && packet.d > 0 && scheme.input.borrow().is_empty() { blocked.push_back(packet); } else { scheme.handle(&mut packet); socket.write(&packet).expect("vesad: failed to write display scheme"); } + + // If there are blocked readers, and data is available, handle them while ! scheme.input.borrow().is_empty() { if let Some(mut packet) = blocked.pop_front() { scheme.handle(&mut packet); socket.write(&packet).expect("vesad: failed to write display scheme"); + } else { + break; } } + + // If there are requested events, and data is available, send a notification + if ! scheme.input.borrow().is_empty() && *scheme.requested.borrow() & EVENT_READ == EVENT_READ { + let event_packet = Packet { + id: 0, + a: syscall::number::SYS_FEVENT, + b: 0, + c: EVENT_READ, + d: scheme.input.borrow().len() + }; + socket.write(&event_packet).expect("vesad: failed to write display scheme"); + } } }); } diff --git a/initfs/etc/init.rc b/initfs/etc/init.rc index 374b4ab..e46d40d 100644 --- a/initfs/etc/init.rc +++ b/initfs/etc/init.rc @@ -1,5 +1,5 @@ initfs:bin/vesad initfs:bin/ps2d -#initfs:bin/pcid +initfs:bin/pcid initfs:etc/pcid.toml #initfs:bin/example initfs:bin/login display: initfs:bin/ion diff --git a/initfs/etc/pcid.toml b/initfs/etc/pcid.toml new file mode 100644 index 0000000..996b9a8 --- /dev/null +++ b/initfs/etc/pcid.toml @@ -0,0 +1,5 @@ +[[drivers]] +name = "AHCI storage" +class = 1 +subclass = 6 +command = ["initfs:bin/ahcid", "$BAR5", "$IRQ"] diff --git a/kernel/context/context.rs b/kernel/context/context.rs index 504b5e4..a2ab64b 100644 --- a/kernel/context/context.rs +++ b/kernel/context/context.rs @@ -1,9 +1,10 @@ use alloc::arc::Arc; use alloc::boxed::Box; -use collections::{BTreeMap, Vec}; +use collections::{BTreeMap, Vec, VecDeque}; use spin::Mutex; use arch; +use syscall::data::Event; use super::file::File; use super::memory::{Grant, Memory, SharedMemory}; @@ -39,6 +40,8 @@ pub struct Context { pub grants: Arc>>, /// The current working directory pub cwd: Arc>>, + /// Kernel events + pub events: Arc>>, /// The process environment pub env: Arc, Arc>>>>>, /// The open files in the scheme @@ -60,6 +63,7 @@ impl Context { stack: None, grants: Arc::new(Mutex::new(Vec::new())), cwd: Arc::new(Mutex::new(Vec::new())), + events: Arc::new(Mutex::new(VecDeque::new())), env: Arc::new(Mutex::new(BTreeMap::new())), files: Arc::new(Mutex::new(Vec::new())) } diff --git a/kernel/context/event.rs b/kernel/context/event.rs new file mode 100644 index 0000000..06fea60 --- /dev/null +++ b/kernel/context/event.rs @@ -0,0 +1,80 @@ +use alloc::arc::{Arc, Weak}; +use collections::{BTreeMap, VecDeque}; +use spin::{Mutex, Once, RwLock, RwLockReadGuard, RwLockWriteGuard}; + +use context; +use syscall::data::Event; + +type EventList = Weak>>; + +type Registry = BTreeMap<(usize, usize), BTreeMap<(usize, usize), EventList>>; + +static REGISTRY: Once> = Once::new(); + +/// Initialize registry, called if needed +fn init_registry() -> RwLock { + RwLock::new(Registry::new()) +} + +/// Get the global schemes list, const +fn registry() -> RwLockReadGuard<'static, Registry> { + REGISTRY.call_once(init_registry).read() +} + +/// Get the global schemes list, mutable +pub fn registry_mut() -> RwLockWriteGuard<'static, Registry> { + REGISTRY.call_once(init_registry).write() +} + +pub fn register(fd: usize, scheme_id: usize, id: usize) -> bool { + let (context_id, events) = { + let contexts = context::contexts(); + let context_lock = contexts.current().expect("event::register: No context"); + let context = context_lock.read(); + (context.id, Arc::downgrade(&context.events)) + }; + + let mut registry = registry_mut(); + let entry = registry.entry((scheme_id, id)).or_insert_with(|| { + BTreeMap::new() + }); + if entry.contains_key(&(context_id, fd)) { + false + } else { + entry.insert((context_id, fd), events); + true + } +} + +pub fn unregister(fd: usize, scheme_id: usize, id: usize) { + let mut registry = registry_mut(); + + let mut remove = false; + if let Some(entry) = registry.get_mut(&(scheme_id, id)) { + entry.remove(&(context::context_id(), fd)); + + if entry.is_empty() { + remove = true; + } + } + + if remove { + registry.remove(&(scheme_id, id)); + } +} + +pub fn trigger(scheme_id: usize, id: usize, flags: usize, data: usize) { + let registry = registry(); + if let Some(event_lists) = registry.get(&(scheme_id, id)) { + for entry in event_lists.iter() { + if let Some(event_list_lock) = entry.1.upgrade() { + let mut event_list = event_list_lock.lock(); + event_list.push_back(Event { + id: (entry.0).1, + flags: flags, + data: data + }); + } + } + } +} diff --git a/kernel/context/mod.rs b/kernel/context/mod.rs index 597c301..9da1259 100644 --- a/kernel/context/mod.rs +++ b/kernel/context/mod.rs @@ -16,6 +16,9 @@ mod list; /// Context switch function mod switch; +/// Event handling +pub mod event; + /// File struct - defines a scheme and a file number pub mod file; diff --git a/kernel/context/switch.rs b/kernel/context/switch.rs index 2e16727..9065530 100644 --- a/kernel/context/switch.rs +++ b/kernel/context/switch.rs @@ -8,7 +8,7 @@ use super::{contexts, Context, Status, CONTEXT_ID}; /// # Safety /// /// Do not call this while holding locks! -pub unsafe fn switch() { +pub unsafe fn switch() -> bool { use core::ops::DerefMut; // Set the global lock to avoid the unsafe operations below from causing issues @@ -48,10 +48,9 @@ pub unsafe fn switch() { } if to_ptr as usize == 0 { - // TODO: Sleep, wait for interrupt // Unset global lock if no context found arch::context::CONTEXT_SWITCH_LOCK.store(false, Ordering::SeqCst); - return; + return false; } //println!("Switch {} to {}", (&*from_ptr).id, (&*to_ptr).id); @@ -64,4 +63,6 @@ pub unsafe fn switch() { CONTEXT_ID.store((&mut *to_ptr).id, Ordering::SeqCst); (&mut *from_ptr).arch.switch_to(&mut (&mut *to_ptr).arch); + + true } diff --git a/kernel/lib.rs b/kernel/lib.rs index d7a1fc8..fee417c 100644 --- a/kernel/lib.rs +++ b/kernel/lib.rs @@ -129,7 +129,7 @@ pub fn cpu_id() -> usize { } pub extern fn userspace_init() { - assert_eq!(syscall::chdir(b"initfs:bin/"), Ok(0)); + assert_eq!(syscall::chdir(b"initfs:bin"), Ok(0)); assert_eq!(syscall::open(b"debug:", 0), Ok(0)); assert_eq!(syscall::open(b"debug:", 0), Ok(1)); @@ -162,8 +162,11 @@ pub extern fn kmain() { loop { unsafe { interrupt::disable(); - context::switch(); - interrupt::enable_and_nop(); + if context::switch() { + interrupt::enable_and_nop(); + } else { + interrupt::enable_and_halt(); + } } } } diff --git a/kernel/scheme/debug.rs b/kernel/scheme/debug.rs index 70459e7..eed44ed 100644 --- a/kernel/scheme/debug.rs +++ b/kernel/scheme/debug.rs @@ -1,11 +1,15 @@ use collections::VecDeque; use core::str; +use core::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; use spin::{Mutex, Once}; use context; use syscall::error::*; +use syscall::flag::EVENT_READ; use syscall::scheme::Scheme; +pub static DEBUG_SCHEME_ID: AtomicUsize = ATOMIC_USIZE_INIT; + /// Input static INPUT: Once>> = Once::new(); @@ -17,7 +21,13 @@ fn init_input() -> Mutex> { /// Get the global schemes list, const #[no_mangle] pub extern fn debug_input(b: u8) { - INPUT.call_once(init_input).lock().push_back(b) + let len = { + let mut input = INPUT.call_once(init_input).lock(); + input.push_back(b); + input.len() + }; + + context::event::trigger(DEBUG_SCHEME_ID.load(Ordering::SeqCst), 0, EVENT_READ, len); } pub struct DebugScheme; @@ -48,7 +58,7 @@ impl Scheme for DebugScheme { if i > 0 { return Ok(i); } else { - unsafe { context::switch(); } + unsafe { context::switch(); } //TODO: Block } } } @@ -62,6 +72,10 @@ impl Scheme for DebugScheme { Ok(buffer.len()) } + fn fevent(&self, _file: usize, _flags: usize) -> Result { + Ok(0) + } + fn fsync(&self, _file: usize) -> Result { Ok(0) } diff --git a/kernel/scheme/event.rs b/kernel/scheme/event.rs new file mode 100644 index 0000000..2dead8d --- /dev/null +++ b/kernel/scheme/event.rs @@ -0,0 +1,94 @@ +use alloc::arc::{Arc, Weak}; +use collections::{BTreeMap, VecDeque}; +use core::mem; +use core::sync::atomic::{AtomicUsize, Ordering}; +use spin::{Mutex, RwLock}; + +use context; +use syscall::data::Event; +use syscall::error::*; +use syscall::scheme::Scheme; + +pub struct EventScheme { + next_id: AtomicUsize, + handles: RwLock>>>> +} + +impl EventScheme { + pub fn new() -> EventScheme { + EventScheme { + next_id: AtomicUsize::new(0), + handles: RwLock::new(BTreeMap::new()) + } + } +} + +impl Scheme for EventScheme { + fn open(&self, _path: &[u8], _flags: usize) -> Result { + let handle = { + let contexts = context::contexts(); + let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; + let context = context_lock.read(); + context.events.clone() + }; + + let id = self.next_id.fetch_add(1, Ordering::SeqCst); + self.handles.write().insert(id, Arc::downgrade(&handle)); + + Ok(id) + } + + fn dup(&self, id: usize) -> Result { + let handle = { + let handles = self.handles.read(); + let handle_weak = handles.get(&id).ok_or(Error::new(EBADF))?; + handle_weak.upgrade().ok_or(Error::new(EBADF))? + }; + + let new_id = self.next_id.fetch_add(1, Ordering::SeqCst); + self.handles.write().insert(new_id, Arc::downgrade(&handle)); + Ok(new_id) + } + + fn read(&self, id: usize, buf: &mut [u8]) -> Result { + let handle = { + let handles = self.handles.read(); + let handle_weak = handles.get(&id).ok_or(Error::new(EBADF))?; + handle_weak.upgrade().ok_or(Error::new(EBADF))? + }; + + let event_size = mem::size_of::(); + let len = buf.len()/event_size; + if len > 0 { + loop { + let mut i = 0; + { + let mut events = handle.lock(); + while ! events.is_empty() && i < len { + let event = events.pop_front().unwrap(); + unsafe { *(buf.as_mut_ptr() as *mut Event).offset(i as isize) = event; } + i += 1; + } + } + + if i > 0 { + return Ok(i * event_size); + } else { + unsafe { context::switch(); } //TODO: Block + } + } + } else { + Ok(0) + } + } + + fn fsync(&self, id: usize) -> Result { + let handles = self.handles.read(); + let handle_weak = handles.get(&id).ok_or(Error::new(EBADF))?; + handle_weak.upgrade().ok_or(Error::new(EBADF)).and(Ok(0)) + } + + fn close(&self, id: usize) -> Result { + self.handles.write().remove(&id).ok_or(Error::new(EBADF)).and(Ok(0)) + } +} diff --git a/kernel/scheme/mod.rs b/kernel/scheme/mod.rs index 4d0580a..7d3e25e 100644 --- a/kernel/scheme/mod.rs +++ b/kernel/scheme/mod.rs @@ -8,15 +8,15 @@ use alloc::arc::Arc; use alloc::boxed::Box; - use collections::BTreeMap; - +use core::sync::atomic::Ordering; use spin::{Once, RwLock, RwLockReadGuard, RwLockWriteGuard}; use syscall::error::*; use syscall::scheme::Scheme; -use self::debug::DebugScheme; +use self::debug::{DEBUG_SCHEME_ID, DebugScheme}; +use self::event::EventScheme; use self::env::EnvScheme; use self::initfs::InitFsScheme; use self::irq::IrqScheme; @@ -25,6 +25,9 @@ use self::root::RootScheme; /// Debug scheme pub mod debug; +/// Kernel events +pub mod event; + /// Environmental variables pub mod env; @@ -74,7 +77,7 @@ impl SchemeList { } /// Create a new scheme. - pub fn insert(&mut self, name: Box<[u8]>, scheme: Arc>) -> Result<&Arc>> { + pub fn insert(&mut self, name: Box<[u8]>, scheme: Arc>) -> Result { if self.names.contains_key(&name) { return Err(Error::new(EEXIST)); } @@ -97,7 +100,7 @@ impl SchemeList { assert!(self.map.insert(id, scheme).is_none()); assert!(self.names.insert(name, id).is_none()); - Ok(self.map.get(&id).expect("Failed to insert new scheme. ID is out of bounds.")) + Ok(id) } } @@ -108,7 +111,8 @@ static SCHEMES: Once> = Once::new(); fn init_schemes() -> RwLock { let mut list: SchemeList = SchemeList::new(); list.insert(Box::new(*b""), Arc::new(Box::new(RootScheme::new()))).expect("failed to insert root scheme"); - list.insert(Box::new(*b"debug"), Arc::new(Box::new(DebugScheme))).expect("failed to insert debug scheme"); + DEBUG_SCHEME_ID.store(list.insert(Box::new(*b"debug"), Arc::new(Box::new(DebugScheme))).expect("failed to insert debug scheme"), Ordering::SeqCst); + list.insert(Box::new(*b"event"), Arc::new(Box::new(EventScheme::new()))).expect("failed to insert event scheme"); list.insert(Box::new(*b"env"), Arc::new(Box::new(EnvScheme::new()))).expect("failed to insert env scheme"); list.insert(Box::new(*b"initfs"), Arc::new(Box::new(InitFsScheme::new()))).expect("failed to insert initfs scheme"); list.insert(Box::new(*b"irq"), Arc::new(Box::new(IrqScheme))).expect("failed to insert irq scheme"); diff --git a/kernel/scheme/root.rs b/kernel/scheme/root.rs index a2e0060..e982c8f 100644 --- a/kernel/scheme/root.rs +++ b/kernel/scheme/root.rs @@ -38,7 +38,8 @@ impl Scheme for RootScheme { return Err(Error::new(EEXIST)); } let inner = Arc::new(UserInner::new(context)); - schemes.insert(path.to_vec().into_boxed_slice(), Arc::new(Box::new(UserScheme::new(Arc::downgrade(&inner))))).expect("failed to insert user scheme"); + let id = schemes.insert(path.to_vec().into_boxed_slice(), Arc::new(Box::new(UserScheme::new(Arc::downgrade(&inner))))).expect("failed to insert user scheme"); + inner.scheme_id.store(id, Ordering::SeqCst); inner }; diff --git a/kernel/scheme/user.rs b/kernel/scheme/user.rs index ba8fd95..a02b2b7 100644 --- a/kernel/scheme/user.rs +++ b/kernel/scheme/user.rs @@ -15,6 +15,7 @@ use syscall::number::*; use syscall::scheme::Scheme; pub struct UserInner { + pub scheme_id: AtomicUsize, next_id: AtomicUsize, context: Weak>, todo: Mutex>, @@ -24,7 +25,8 @@ pub struct UserInner { impl UserInner { pub fn new(context: Weak>) -> UserInner { UserInner { - next_id: AtomicUsize::new(0), + scheme_id: AtomicUsize::new(0), + next_id: AtomicUsize::new(1), context: context, todo: Mutex::new(VecDeque::new()), done: Mutex::new(BTreeMap::new()) @@ -52,7 +54,7 @@ impl UserInner { } } - unsafe { context::switch(); } + unsafe { context::switch(); } //TODO: Block } } @@ -163,7 +165,7 @@ impl UserInner { if i > 0 { return Ok(i * packet_size); } else { - unsafe { context::switch(); } + unsafe { context::switch(); } //TODO: Block } } } else { @@ -177,7 +179,14 @@ impl UserInner { let mut i = 0; while i < len { let packet = unsafe { *(buf.as_ptr() as *const Packet).offset(i as isize) }; - self.done.lock().insert(packet.id, packet.a); + if packet.id == 0 { + match packet.a { + SYS_FEVENT => context::event::trigger(self.scheme_id.load(Ordering::SeqCst), packet.b, packet.c, packet.d), + _ => println!("Unknown scheme -> kernel message {}", packet.a) + } + } else { + self.done.lock().insert(packet.id, packet.a); + } i += 1; } @@ -230,7 +239,12 @@ impl Scheme for UserScheme { fn seek(&self, file: usize, position: usize, whence: usize) -> Result { let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; - inner.call(SYS_FSYNC, file, position, whence) + inner.call(SYS_LSEEK, file, position, whence) + } + + fn fevent(&self, file: usize, flags: usize) -> Result { + let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; + inner.call(SYS_FEVENT, file, flags, 0) } fn fstat(&self, file: usize, stat: &mut Stat) -> Result { diff --git a/kernel/syscall/fs.rs b/kernel/syscall/fs.rs index 2fef6f6..91c36e4 100644 --- a/kernel/syscall/fs.rs +++ b/kernel/syscall/fs.rs @@ -72,6 +72,8 @@ pub fn close(fd: usize) -> Result { file }; + context::event::unregister(fd, file.scheme, file.number); + let scheme = { let schemes = scheme::schemes(); let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; @@ -98,6 +100,26 @@ pub fn dup(fd: usize) -> Result { scheme.dup(file.number) } +/// Register events for file +pub fn fevent(fd: usize, flags: usize) -> Result { + let file = { + let contexts = context::contexts(); + let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; + let context = context_lock.read(); + let file = context.get_file(fd).ok_or(Error::new(EBADF))?; + file + }; + + let scheme = { + let schemes = scheme::schemes(); + let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; + scheme.clone() + }; + scheme.fevent(file.number, flags)?; + context::event::register(fd, file.scheme, file.number); + Ok(0) +} + /// Get the canonical path of the file pub fn fpath(fd: usize, buf: &mut [u8]) -> Result { let file = { diff --git a/kernel/syscall/mod.rs b/kernel/syscall/mod.rs index c4ed06b..2815091 100644 --- a/kernel/syscall/mod.rs +++ b/kernel/syscall/mod.rs @@ -45,9 +45,13 @@ pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize SYS_CLONE => clone(b, stack), SYS_YIELD => sched_yield(), SYS_GETCWD => getcwd(validate_slice_mut(b as *mut u8, c)?), + SYS_FEVENT => fevent(b, c), SYS_FPATH => fpath(b, validate_slice_mut(c as *mut u8, d)?), + SYS_PHYSALLOC => physalloc(b), + SYS_PHYSFREE => physfree(b, c), SYS_PHYSMAP => physmap(b, c, d), SYS_PHYSUNMAP => physunmap(b), + SYS_VIRTTOPHYS => virttophys(b), _ => { println!("Unknown syscall {}", a); Err(Error::new(ENOSYS)) diff --git a/kernel/syscall/process.rs b/kernel/syscall/process.rs index 0da2d00..d953e42 100644 --- a/kernel/syscall/process.rs +++ b/kernel/syscall/process.rs @@ -8,7 +8,7 @@ use spin::Mutex; use arch; use arch::externs::memcpy; -use arch::memory::allocate_frame; +use arch::memory::{allocate_frame, allocate_frames, deallocate_frames, Frame}; use arch::paging::{ActivePageTable, InactivePageTable, Page, PhysicalAddress, VirtualAddress, entry}; use arch::paging::temporary_page::TemporaryPage; use arch::start::usermode; @@ -535,6 +535,16 @@ pub fn iopl(_level: usize) -> Result { Ok(0) } +pub fn physalloc(size: usize) -> Result { + allocate_frames((size + 4095)/4096).ok_or(Error::new(ENOMEM)).map(|frame| frame.start_address().get()) +} + +pub fn physfree(physical_address: usize, size: usize) -> Result { + deallocate_frames(Frame::containing_address(PhysicalAddress::new(physical_address)), (size + 4095)/4096); + //TODO: Check that no double free occured + Ok(0) +} + //TODO: verify exlusive access to physical memory pub fn physmap(physical_address: usize, size: usize, flags: usize) -> Result { if size == 0 { @@ -617,8 +627,15 @@ pub fn sched_yield() -> Result { Ok(0) } +pub fn virttophys(virtual_address: usize) -> Result { + let active_table = unsafe { ActivePageTable::new() }; + match active_table.translate(VirtualAddress::new(virtual_address)) { + Some(physical_address) => Ok(physical_address.get()), + None => Err(Error::new(EFAULT)) + } +} + pub fn waitpid(pid: usize, status_ptr: usize, flags: usize) -> Result { - //TODO: Implement status_ptr and options loop { { let mut exited = false; @@ -644,6 +661,6 @@ pub fn waitpid(pid: usize, status_ptr: usize, flags: usize) -> Result { } } - unsafe { context::switch(); } + unsafe { context::switch(); } //TODO: Block } } diff --git a/libstd b/libstd index 9f7687e..29a6cab 160000 --- a/libstd +++ b/libstd @@ -1 +1 @@ -Subproject commit 9f7687ec7cf09945b8d832e4777b6c521f408754 +Subproject commit 29a6cab11d6e84c422917724ef0eca2bcc2c6589 diff --git a/programs/login/src/main.rs b/programs/login/src/main.rs index 6bd6ba4..1e0ca13 100644 --- a/programs/login/src/main.rs +++ b/programs/login/src/main.rs @@ -25,10 +25,10 @@ pub fn main() { for arg in sh_args.iter() { command.arg(arg); } - + command.env("HOME", "initfs:"); - command.env("PWD", "initfs:bin/"); - command.env("PATH", "initfs:bin/"); + command.env("PWD", "initfs:bin"); + command.env("PATH", "initfs:bin"); command.env("COLUMNS", "80"); command.env("LINES", "30"); command.env("TTY", &tty); diff --git a/schemes/example/src/main.rs b/schemes/example/src/main.rs index 84fb345..d854ced 100644 --- a/schemes/example/src/main.rs +++ b/schemes/example/src/main.rs @@ -25,6 +25,27 @@ impl Scheme for ExampleScheme { } fn main(){ + { + let events = syscall::open("event:", 0).unwrap(); + + let a = syscall::open("display:", 0).unwrap(); + syscall::fevent(a, syscall::EVENT_READ).unwrap(); + let b = syscall::open("debug:", 0).unwrap(); + syscall::fevent(b, syscall::EVENT_READ).unwrap(); + + loop { + let mut event = syscall::Event::default(); + syscall::read(events, &mut event).unwrap(); + println!("{:?}", event); + + let mut buf = vec![0; event.data]; + syscall::read(event.id, &mut buf).unwrap(); + println!("{}", unsafe { ::std::str::from_utf8_unchecked(&buf) }); + } + + let _ = syscall::close(events); + } + thread::spawn(move || { let mut socket = File::create(":example").expect("example: failed to create example scheme"); let scheme = ExampleScheme; diff --git a/syscall/src/data.rs b/syscall/src/data.rs index 399950b..5ed4cd4 100644 --- a/syscall/src/data.rs +++ b/syscall/src/data.rs @@ -1,6 +1,30 @@ use core::ops::{Deref, DerefMut}; use core::{mem, slice}; +#[derive(Copy, Clone, Debug, Default)] +pub struct Event { + pub id: usize, + pub flags: usize, + pub data: usize +} + +impl Deref for Event { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const Event as *const u8, mem::size_of::()) as &[u8] + } + } +} + +impl DerefMut for Event { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut Event as *mut u8, mem::size_of::()) as &mut [u8] + } + } +} + #[derive(Copy, Clone, Debug, Default)] #[repr(packed)] pub struct Packet { diff --git a/syscall/src/flag.rs b/syscall/src/flag.rs index 52db74c..73b4dd8 100644 --- a/syscall/src/flag.rs +++ b/syscall/src/flag.rs @@ -14,6 +14,10 @@ pub const CLONE_SUPERVISE: usize = 0x400000; pub const CLOCK_REALTIME: usize = 1; pub const CLOCK_MONOTONIC: usize = 4; +pub const EVENT_NONE: usize = 0; +pub const EVENT_READ: usize = 1; +pub const EVENT_WRITE: usize = 2; + pub const FUTEX_WAIT: usize = 0; pub const FUTEX_WAKE: usize = 1; pub const FUTEX_REQUEUE: usize = 2; diff --git a/syscall/src/lib.rs b/syscall/src/lib.rs index 3acc70a..15ac101 100644 --- a/syscall/src/lib.rs +++ b/syscall/src/lib.rs @@ -58,6 +58,10 @@ pub fn exit(status: usize) -> Result { unsafe { syscall1(SYS_EXIT, status) } } +pub fn fevent(fd: usize, flags: usize) -> Result { + unsafe { syscall2(SYS_FEVENT, fd, flags) } +} + pub fn fpath(fd: usize, buf: &mut [u8]) -> Result { unsafe { syscall3(SYS_FPATH, fd, buf.as_mut_ptr() as usize, buf.len()) } } @@ -110,6 +114,14 @@ pub fn open(path: &str, flags: usize) -> Result { unsafe { syscall3(SYS_OPEN, path.as_ptr() as usize, path.len(), flags) } } +pub unsafe fn physalloc(size: usize) -> Result { + syscall1(SYS_PHYSALLOC, size) +} + +pub unsafe fn physfree(physical_address: usize, size: usize) -> Result { + syscall2(SYS_PHYSFREE, physical_address, size) +} + pub unsafe fn physmap(physical_address: usize, size: usize, flags: usize) -> Result { syscall3(SYS_PHYSMAP, physical_address, size, flags) } @@ -134,6 +146,10 @@ pub fn unlink(path: &str) -> Result { unsafe { syscall2(SYS_UNLINK, path.as_ptr() as usize, path.len()) } } +pub unsafe fn virttophys(virtual_address: usize) -> Result { + syscall1(SYS_VIRTTOPHYS, virtual_address) +} + pub fn waitpid(pid: usize, status: &mut usize, options: usize) -> Result { unsafe { syscall3(SYS_WAITPID, pid, status as *mut usize as usize, options) } } diff --git a/syscall/src/number.rs b/syscall/src/number.rs index 80e7065..b0d41c0 100644 --- a/syscall/src/number.rs +++ b/syscall/src/number.rs @@ -6,6 +6,7 @@ pub const SYS_CLOCK_GETTIME: usize = 265; pub const SYS_DUP: usize = 41; pub const SYS_EXECVE: usize = 11; pub const SYS_EXIT: usize = 1; +pub const SYS_FEVENT: usize = 927; pub const SYS_FPATH: usize = 928; pub const SYS_FSTAT: usize = 28; pub const SYS_FSYNC: usize = 118; @@ -19,8 +20,11 @@ pub const SYS_LSEEK: usize = 19; pub const SYS_MKDIR: usize = 39; pub const SYS_NANOSLEEP: usize = 162; pub const SYS_OPEN: usize = 5; -pub const SYS_PHYSMAP: usize = 945; -pub const SYS_PHYSUNMAP: usize = 946; +pub const SYS_PHYSALLOC: usize = 945; +pub const SYS_PHYSFREE: usize = 946; +pub const SYS_PHYSMAP: usize = 947; +pub const SYS_PHYSUNMAP: usize = 948; +pub const SYS_VIRTTOPHYS: usize = 949; pub const SYS_PIPE2: usize = 331; pub const SYS_READ: usize = 3; pub const SYS_RMDIR: usize = 84; diff --git a/syscall/src/scheme.rs b/syscall/src/scheme.rs index 6a857d1..43d1899 100644 --- a/syscall/src/scheme.rs +++ b/syscall/src/scheme.rs @@ -14,6 +14,7 @@ pub trait Scheme { SYS_READ => self.read(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), SYS_WRITE => self.write(packet.b, unsafe { slice::from_raw_parts(packet.c as *const u8, packet.d) }), SYS_LSEEK => self.seek(packet.b, packet.c, packet.d), + SYS_FEVENT => self.fevent(packet.b, packet.c), SYS_FPATH => self.fpath(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), SYS_FSTAT => self.fstat(packet.b, unsafe { &mut *(packet.c as *mut Stat) }), SYS_FSYNC => self.fsync(packet.b), @@ -67,6 +68,11 @@ pub trait Scheme { Err(Error::new(EBADF)) } + #[allow(unused_variables)] + fn fevent(&self, id: usize, flags: usize) -> Result { + Err(Error::new(EBADF)) + } + #[allow(unused_variables)] fn fpath(&self, id: usize, buf: &mut [u8]) -> Result { Err(Error::new(EBADF))