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))