Merge pull request #8 from redox-os/pci_drivers
Create a PCI driver daemon, which starts up AHCI driver
This commit is contained in:
		
						commit
						b527fc3c99
					
				
					 38 changed files with 1458 additions and 104 deletions
				
			
		
							
								
								
									
										6
									
								
								Makefile
									
										
									
									
									
								
							
							
						
						
									
										6
									
								
								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 \
 | ||||
|  |  | |||
|  | @ -43,11 +43,14 @@ impl AreaFrameAllocator { | |||
| } | ||||
| 
 | ||||
| impl FrameAllocator for AreaFrameAllocator { | ||||
|     fn allocate_frame(&mut self) -> Option<Frame> { | ||||
|         if let Some(area) = self.current_area { | ||||
|     fn allocate_frames(&mut self, count: usize) -> Option<Frame> { | ||||
|         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);
 | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -69,17 +69,27 @@ pub unsafe fn init(kernel_start: usize, kernel_end: usize) { | |||
| 
 | ||||
| /// Allocate a frame
 | ||||
| pub fn allocate_frame() -> Option<Frame> { | ||||
|     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<Frame> { | ||||
|     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<Frame>; | ||||
|     fn deallocate_frame(&mut self, frame: Frame); | ||||
|     fn allocate_frames(&mut self, size: usize) -> Option<Frame>; | ||||
|     fn deallocate_frames(&mut self, frame: Frame, size: usize); | ||||
| } | ||||
|  |  | |||
							
								
								
									
										9
									
								
								drivers/ahcid/Cargo.toml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								drivers/ahcid/Cargo.toml
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,9 @@ | |||
| [package] | ||||
| name = "ahcid" | ||||
| version = "0.1.0" | ||||
| 
 | ||||
| [dependencies] | ||||
| bitflags = "*" | ||||
| io = { path = "../io/" } | ||||
| spin = "*" | ||||
| syscall = { path = "../../syscall/" } | ||||
							
								
								
									
										116
									
								
								drivers/ahcid/src/ahci/disk.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								drivers/ahcid/src/ahci/disk.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -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<HbaCmdTable>; 32], | ||||
|     fb: Dma<[u8; 256]>, | ||||
|     buf: Dma<[u8; 256 * 512]> | ||||
| } | ||||
| 
 | ||||
| impl Disk { | ||||
|     pub fn new(id: usize, port: &'static mut HbaPort) -> Result<Self> { | ||||
|         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<usize> { | ||||
|         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<usize> { | ||||
|         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)) | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										76
									
								
								drivers/ahcid/src/ahci/dma.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								drivers/ahcid/src/ahci/dma.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -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<PhysBox> { | ||||
|         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<T> { | ||||
|     phys: PhysBox, | ||||
|     virt: *mut T | ||||
| } | ||||
| 
 | ||||
| impl<T> Dma<T> { | ||||
|     pub fn new(value: T) -> Result<Dma<T>> { | ||||
|         let phys = PhysBox::new(mem::size_of::<T>())?; | ||||
|         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<Dma<T>> { | ||||
|         let phys = PhysBox::new(mem::size_of::<T>())?; | ||||
|         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<T> Deref for Dma<T> { | ||||
|     type Target = T; | ||||
|     fn deref(&self) -> &T { | ||||
|         unsafe { &*self.virt } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<T> DerefMut for Dma<T> { | ||||
|     fn deref_mut(&mut self) -> &mut T { | ||||
|         unsafe { &mut *self.virt } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<T> Drop for Dma<T> { | ||||
|     fn drop(&mut self) { | ||||
|         unsafe { drop(ptr::read(self.virt)); } | ||||
|         let _ = unsafe { syscall::physunmap(self.virt as usize) }; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										155
									
								
								drivers/ahcid/src/ahci/fis.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								drivers/ahcid/src/ahci/fis.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -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<u8>, // FIS_TYPE_REG_H2D
 | ||||
| 
 | ||||
|     pub pm: Mmio<u8>, // Port multiplier, 1: Command, 0: Control
 | ||||
| 
 | ||||
|     pub command: Mmio<u8>, // Command register
 | ||||
|     pub featurel: Mmio<u8>, // Feature register, 7:0
 | ||||
| 
 | ||||
|     // DWORD 1
 | ||||
|     pub lba0: Mmio<u8>, // LBA low register, 7:0
 | ||||
|     pub lba1: Mmio<u8>, // LBA mid register, 15:8
 | ||||
|     pub lba2: Mmio<u8>, // LBA high register, 23:16
 | ||||
|     pub device: Mmio<u8>, // Device register
 | ||||
| 
 | ||||
|     // DWORD 2
 | ||||
|     pub lba3: Mmio<u8>, // LBA register, 31:24
 | ||||
|     pub lba4: Mmio<u8>, // LBA register, 39:32
 | ||||
|     pub lba5: Mmio<u8>, // LBA register, 47:40
 | ||||
|     pub featureh: Mmio<u8>, // Feature register, 15:8
 | ||||
| 
 | ||||
|     // DWORD 3
 | ||||
|     pub countl: Mmio<u8>, // Count register, 7:0
 | ||||
|     pub counth: Mmio<u8>, // Count register, 15:8
 | ||||
|     pub icc: Mmio<u8>, // Isochronous command completion
 | ||||
|     pub control: Mmio<u8>, // Control register
 | ||||
| 
 | ||||
|     // DWORD 4
 | ||||
|     pub rsv1: [Mmio<u8>; 4], // Reserved
 | ||||
| } | ||||
| 
 | ||||
| #[repr(packed)] | ||||
| pub struct FisRegD2H { | ||||
|     // DWORD 0
 | ||||
|     pub fis_type: Mmio<u8>, // FIS_TYPE_REG_D2H
 | ||||
| 
 | ||||
|     pub pm: Mmio<u8>, // Port multiplier, Interrupt bit: 2
 | ||||
| 
 | ||||
|     pub status: Mmio<u8>, // Status register
 | ||||
|     pub error: Mmio<u8>, // Error register
 | ||||
| 
 | ||||
|     // DWORD 1
 | ||||
|     pub lba0: Mmio<u8>, // LBA low register, 7:0
 | ||||
|     pub lba1: Mmio<u8>, // LBA mid register, 15:8
 | ||||
|     pub lba2: Mmio<u8>, // LBA high register, 23:16
 | ||||
|     pub device: Mmio<u8>, // Device register
 | ||||
| 
 | ||||
|     // DWORD 2
 | ||||
|     pub lba3: Mmio<u8>, // LBA register, 31:24
 | ||||
|     pub lba4: Mmio<u8>, // LBA register, 39:32
 | ||||
|     pub lba5: Mmio<u8>, // LBA register, 47:40
 | ||||
|     pub rsv2: Mmio<u8>, // Reserved
 | ||||
| 
 | ||||
|     // DWORD 3
 | ||||
|     pub countl: Mmio<u8>, // Count register, 7:0
 | ||||
|     pub counth: Mmio<u8>, // Count register, 15:8
 | ||||
|     pub rsv3: [Mmio<u8>; 2], // Reserved
 | ||||
| 
 | ||||
|     // DWORD 4
 | ||||
|     pub rsv4: [Mmio<u8>; 4], // Reserved
 | ||||
| } | ||||
| 
 | ||||
| #[repr(packed)] | ||||
| pub struct FisData { | ||||
|     // DWORD 0
 | ||||
|     pub fis_type: Mmio<u8>, // FIS_TYPE_DATA
 | ||||
| 
 | ||||
|     pub pm: Mmio<u8>, // Port multiplier
 | ||||
| 
 | ||||
|     pub rsv1: [Mmio<u8>; 2], // Reserved
 | ||||
| 
 | ||||
|     // DWORD 1 ~ N
 | ||||
|     pub data: [Mmio<u8>; 252], // Payload
 | ||||
| } | ||||
| 
 | ||||
| #[repr(packed)] | ||||
| pub struct FisPioSetup { | ||||
|     // DWORD 0
 | ||||
|     pub fis_type: Mmio<u8>, // FIS_TYPE_PIO_SETUP
 | ||||
| 
 | ||||
|     pub pm: Mmio<u8>, // Port multiplier, direction: 4 - device to host, interrupt: 2
 | ||||
| 
 | ||||
|     pub status: Mmio<u8>, // Status register
 | ||||
|     pub error: Mmio<u8>, // Error register
 | ||||
| 
 | ||||
|     // DWORD 1
 | ||||
|     pub lba0: Mmio<u8>, // LBA low register, 7:0
 | ||||
|     pub lba1: Mmio<u8>, // LBA mid register, 15:8
 | ||||
|     pub lba2: Mmio<u8>, // LBA high register, 23:16
 | ||||
|     pub device: Mmio<u8>, // Device register
 | ||||
| 
 | ||||
|     // DWORD 2
 | ||||
|     pub lba3: Mmio<u8>, // LBA register, 31:24
 | ||||
|     pub lba4: Mmio<u8>, // LBA register, 39:32
 | ||||
|     pub lba5: Mmio<u8>, // LBA register, 47:40
 | ||||
|     pub rsv2: Mmio<u8>, // Reserved
 | ||||
| 
 | ||||
|     // DWORD 3
 | ||||
|     pub countl: Mmio<u8>, // Count register, 7:0
 | ||||
|     pub counth: Mmio<u8>, // Count register, 15:8
 | ||||
|     pub rsv3: Mmio<u8>, // Reserved
 | ||||
|     pub e_status: Mmio<u8>, // New value of status register
 | ||||
| 
 | ||||
|     // DWORD 4
 | ||||
|     pub tc: Mmio<u16>, // Transfer count
 | ||||
|     pub rsv4: [Mmio<u8>; 2], // Reserved
 | ||||
| } | ||||
| 
 | ||||
| #[repr(packed)] | ||||
| pub struct FisDmaSetup { | ||||
|     // DWORD 0
 | ||||
|     pub fis_type: Mmio<u8>, // FIS_TYPE_DMA_SETUP
 | ||||
| 
 | ||||
|     pub pm: Mmio<u8>, // Port multiplier, direction: 4 - device to host, interrupt: 2, auto-activate: 1
 | ||||
| 
 | ||||
|     pub rsv1: [Mmio<u8>; 2], // Reserved
 | ||||
| 
 | ||||
|     // DWORD 1&2
 | ||||
|     pub dma_buffer_id: Mmio<u64>, /* 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<u32>, // More reserved
 | ||||
| 
 | ||||
|     // DWORD 4
 | ||||
|     pub dma_buffer_offset: Mmio<u32>, // Byte offset into buffer. First 2 bits must be 0
 | ||||
| 
 | ||||
|     // DWORD 5
 | ||||
|     pub transfer_count: Mmio<u32>, // Number of bytes to transfer. Bit 0 must be 0
 | ||||
| 
 | ||||
|     // DWORD 6
 | ||||
|     pub rsv6: Mmio<u32>, // Reserved
 | ||||
| } | ||||
							
								
								
									
										351
									
								
								drivers/ahcid/src/ahci/hba.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										351
									
								
								drivers/ahcid/src/ahci/hba.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -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<u64>, // 0x00, command list base address, 1K-byte aligned
 | ||||
|     pub fb: Mmio<u64>, // 0x08, FIS base address, 256-byte aligned
 | ||||
|     pub is: Mmio<u32>, // 0x10, interrupt status
 | ||||
|     pub ie: Mmio<u32>, // 0x14, interrupt enable
 | ||||
|     pub cmd: Mmio<u32>, // 0x18, command and status
 | ||||
|     pub rsv0: Mmio<u32>, // 0x1C, Reserved
 | ||||
|     pub tfd: Mmio<u32>, // 0x20, task file data
 | ||||
|     pub sig: Mmio<u32>, // 0x24, signature
 | ||||
|     pub ssts: Mmio<u32>, // 0x28, SATA status (SCR0:SStatus)
 | ||||
|     pub sctl: Mmio<u32>, // 0x2C, SATA control (SCR2:SControl)
 | ||||
|     pub serr: Mmio<u32>, // 0x30, SATA error (SCR1:SError)
 | ||||
|     pub sact: Mmio<u32>, // 0x34, SATA active (SCR3:SActive)
 | ||||
|     pub ci: Mmio<u32>, // 0x38, command issue
 | ||||
|     pub sntf: Mmio<u32>, // 0x3C, SATA notification (SCR4:SNotification)
 | ||||
|     pub fbs: Mmio<u32>, // 0x40, FIS-based switch control
 | ||||
|     pub rsv1: [Mmio<u32>; 11], // 0x44 ~ 0x6F, Reserved
 | ||||
|     pub vendor: [Mmio<u32>; 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<HbaCmdTable>; 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<HbaCmdTable>; 32]) -> Option<u64> { | ||||
|         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::<FisRegH2D>() / size_of::<u32>()) 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::<HbaCmdTable>()); | ||||
| 
 | ||||
|                 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<u32> { | ||||
|         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<HbaCmdTable>; 32], buf: &mut Dma<[u8; 256 * 512]>) -> Result<usize> { | ||||
|         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::<FisRegH2D>() / size_of::<u32>()) 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::<HbaCmdTable>()) }; | ||||
| 
 | ||||
|                 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<u32>, // 0x00, Host capability
 | ||||
|     pub ghc: Mmio<u32>, // 0x04, Global host control
 | ||||
|     pub is: Mmio<u32>, // 0x08, Interrupt status
 | ||||
|     pub pi: Mmio<u32>, // 0x0C, Port implemented
 | ||||
|     pub vs: Mmio<u32>, // 0x10, Version
 | ||||
|     pub ccc_ctl: Mmio<u32>, // 0x14, Command completion coalescing control
 | ||||
|     pub ccc_pts: Mmio<u32>, // 0x18, Command completion coalescing ports
 | ||||
|     pub em_loc: Mmio<u32>, // 0x1C, Enclosure management location
 | ||||
|     pub em_ctl: Mmio<u32>, // 0x20, Enclosure management control
 | ||||
|     pub cap2: Mmio<u32>, // 0x24, Host capabilities extended
 | ||||
|     pub bohc: Mmio<u32>, // 0x28, BIOS/OS handoff control and status
 | ||||
|     pub rsv: [Mmio<u8>; 116], // 0x2C - 0x9F, Reserved
 | ||||
|     pub vendor: [Mmio<u8>; 96], // 0xA0 - 0xFF, Vendor specific registers
 | ||||
|     pub ports: [HbaPort; 32], // 0x100 - 0x10FF, Port control registers
 | ||||
| } | ||||
| 
 | ||||
| #[repr(packed)] | ||||
| pub struct HbaPrdtEntry { | ||||
|     dba: Mmio<u64>, // Data base address
 | ||||
|     rsv0: Mmio<u32>, // Reserved
 | ||||
|     dbc: Mmio<u32>, // Byte count, 4M max, interrupt = 1
 | ||||
| } | ||||
| 
 | ||||
| #[repr(packed)] | ||||
| pub struct HbaCmdTable { | ||||
|     // 0x00
 | ||||
|     cfis: [Mmio<u8>; 64], // Command FIS
 | ||||
| 
 | ||||
|     // 0x40
 | ||||
|     acmd: [Mmio<u8>; 16], // ATAPI command, 12 or 16 bytes
 | ||||
| 
 | ||||
|     // 0x50
 | ||||
|     rsv: [Mmio<u8>; 48], // Reserved
 | ||||
| 
 | ||||
|     // 0x80
 | ||||
|     prdt_entry: [HbaPrdtEntry; 65536], // Physical region descriptor table entries, 0 ~ 65535
 | ||||
| } | ||||
| 
 | ||||
| #[repr(packed)] | ||||
| pub struct HbaCmdHeader { | ||||
|     // DW0
 | ||||
|     cfl: Mmio<u8>, /* Command FIS length in DWORDS, 2 ~ 16, atapi: 4, write - host to device: 2, prefetchable: 1 */ | ||||
|     pm: Mmio<u8>, // Reset - 0x80, bist: 0x40, clear busy on ok: 0x20, port multiplier
 | ||||
| 
 | ||||
|     prdtl: Mmio<u16>, // Physical region descriptor table length in entries
 | ||||
| 
 | ||||
|     // DW1
 | ||||
|     prdbc: Mmio<u32>, // Physical region descriptor byte count transferred
 | ||||
| 
 | ||||
|     // DW2, 3
 | ||||
|     ctba: Mmio<u64>, // Command table descriptor base address
 | ||||
| 
 | ||||
|     // DW4 - 7
 | ||||
|     rsv1: [Mmio<u32>; 4], // Reserved
 | ||||
| } | ||||
							
								
								
									
										37
									
								
								drivers/ahcid/src/ahci/mod.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								drivers/ahcid/src/ahci/mod.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -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<Disk> { | ||||
|     println!(" + AHCI on: {:X} IRQ: {}", base as usize, irq); | ||||
| 
 | ||||
|     let pi = unsafe { &mut *(base as *mut HbaMem) }.pi.read(); | ||||
|     let ret: Vec<Disk> = (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 | ||||
| } | ||||
							
								
								
									
										48
									
								
								drivers/ahcid/src/main.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								drivers/ahcid/src/main.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -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::<u8>().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); } | ||||
|     }); | ||||
| } | ||||
							
								
								
									
										85
									
								
								drivers/ahcid/src/scheme.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								drivers/ahcid/src/scheme.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -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<Mutex<Disk>>]>, | ||||
|     handles: Mutex<BTreeMap<usize, (Arc<Mutex<Disk>>, usize)>>, | ||||
|     next_id: AtomicUsize | ||||
| } | ||||
| 
 | ||||
| impl DiskScheme { | ||||
|     pub fn new(disks: Vec<Disk>) -> 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<usize> { | ||||
|         let path_str = str::from_utf8(path).or(Err(Error::new(ENOENT)))?; | ||||
| 
 | ||||
|         let i = path_str.parse::<usize>().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<usize> { | ||||
|         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<usize> { | ||||
|         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<usize> { | ||||
|         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<usize> { | ||||
|         let mut handles = self.handles.lock(); | ||||
|         handles.remove(&id).ok_or(Error::new(EBADF)).and(Ok(0)) | ||||
|     } | ||||
| } | ||||
|  | @ -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" } | ||||
|  |  | |||
							
								
								
									
										14
									
								
								drivers/pcid/src/config.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								drivers/pcid/src/config.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | |||
| #[derive(Debug, Default, RustcDecodable)] | ||||
| pub struct Config { | ||||
|     pub drivers: Vec<DriverConfig> | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Default, RustcDecodable)] | ||||
| pub struct DriverConfig { | ||||
|     pub name: Option<String>, | ||||
|     pub class: Option<u8>, | ||||
|     pub subclass: Option<u8>, | ||||
|     pub vendor: Option<u16>, | ||||
|     pub device: Option<u16>, | ||||
|     pub command: Option<Vec<String>> | ||||
| } | ||||
|  | @ -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(); | ||||
|     }); | ||||
| } | ||||
|  |  | |||
|  | @ -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<Console>, | ||||
|     display: RefCell<Display>, | ||||
|     input: RefCell<VecDeque<u8>> | ||||
|     input: RefCell<VecDeque<u8>>, | ||||
|     requested: RefCell<usize> | ||||
| } | ||||
| 
 | ||||
| impl Scheme for DisplayScheme { | ||||
|  | @ -42,6 +43,12 @@ impl Scheme for DisplayScheme { | |||
|         Ok(id) | ||||
|     } | ||||
| 
 | ||||
|     fn fevent(&self, _id: usize, flags: usize) -> Result<usize> { | ||||
|         *self.requested.borrow_mut() = flags; | ||||
|         println!("fevent {:X}", flags); | ||||
|         Ok(0) | ||||
|     } | ||||
| 
 | ||||
|     fn fsync(&self, _id: usize) -> Result<usize> { | ||||
|         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"); | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
							
								
								
									
										5
									
								
								initfs/etc/pcid.toml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								initfs/etc/pcid.toml
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,5 @@ | |||
| [[drivers]] | ||||
| name = "AHCI storage" | ||||
| class = 1 | ||||
| subclass = 6 | ||||
| command = ["initfs:bin/ahcid", "$BAR5", "$IRQ"] | ||||
|  | @ -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<Mutex<Vec<Grant>>>, | ||||
|     /// The current working directory
 | ||||
|     pub cwd: Arc<Mutex<Vec<u8>>>, | ||||
|     /// Kernel events
 | ||||
|     pub events: Arc<Mutex<VecDeque<Event>>>, | ||||
|     /// The process environment
 | ||||
|     pub env: Arc<Mutex<BTreeMap<Box<[u8]>, Arc<Mutex<Vec<u8>>>>>>, | ||||
|     /// 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())) | ||||
|         } | ||||
|  |  | |||
							
								
								
									
										80
									
								
								kernel/context/event.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								kernel/context/event.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -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<Mutex<VecDeque<Event>>>; | ||||
| 
 | ||||
| type Registry = BTreeMap<(usize, usize), BTreeMap<(usize, usize), EventList>>; | ||||
| 
 | ||||
| static REGISTRY: Once<RwLock<Registry>> = Once::new(); | ||||
| 
 | ||||
| /// Initialize registry, called if needed
 | ||||
| fn init_registry() -> RwLock<Registry> { | ||||
|     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 | ||||
|                 }); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -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; | ||||
| 
 | ||||
|  |  | |||
|  | @ -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 | ||||
| } | ||||
|  |  | |||
|  | @ -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(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -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<Mutex<VecDeque<u8>>> = Once::new(); | ||||
| 
 | ||||
|  | @ -17,7 +21,13 @@ fn init_input() -> Mutex<VecDeque<u8>> { | |||
| /// 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<usize> { | ||||
|         Ok(0) | ||||
|     } | ||||
| 
 | ||||
|     fn fsync(&self, _file: usize) -> Result<usize> { | ||||
|         Ok(0) | ||||
|     } | ||||
|  |  | |||
							
								
								
									
										94
									
								
								kernel/scheme/event.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								kernel/scheme/event.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -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<BTreeMap<usize, Weak<Mutex<VecDeque<Event>>>>> | ||||
| } | ||||
| 
 | ||||
| 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<usize> { | ||||
|         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<usize> { | ||||
|         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<usize> { | ||||
|         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::<Event>(); | ||||
|         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<usize> { | ||||
|         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<usize> { | ||||
|         self.handles.write().remove(&id).ok_or(Error::new(EBADF)).and(Ok(0)) | ||||
|     } | ||||
| } | ||||
|  | @ -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<Box<Scheme + Send + Sync>>) -> Result<&Arc<Box<Scheme + Send + Sync>>> { | ||||
|     pub fn insert(&mut self, name: Box<[u8]>, scheme: Arc<Box<Scheme + Send + Sync>>) -> Result<usize> { | ||||
|         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<RwLock<SchemeList>> = Once::new(); | |||
| fn init_schemes() -> RwLock<SchemeList> { | ||||
|     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"); | ||||
|  |  | |||
|  | @ -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 | ||||
|         }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -15,6 +15,7 @@ use syscall::number::*; | |||
| use syscall::scheme::Scheme; | ||||
| 
 | ||||
| pub struct UserInner { | ||||
|     pub scheme_id: AtomicUsize, | ||||
|     next_id: AtomicUsize, | ||||
|     context: Weak<RwLock<Context>>, | ||||
|     todo: Mutex<VecDeque<Packet>>, | ||||
|  | @ -24,7 +25,8 @@ pub struct UserInner { | |||
| impl UserInner { | ||||
|     pub fn new(context: Weak<RwLock<Context>>) -> 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<usize> { | ||||
|         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<usize> { | ||||
|         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<usize> { | ||||
|  |  | |||
|  | @ -72,6 +72,8 @@ pub fn close(fd: usize) -> Result<usize> { | |||
|         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<usize> { | |||
|     scheme.dup(file.number) | ||||
| } | ||||
| 
 | ||||
| /// Register events for file
 | ||||
| pub fn fevent(fd: usize, flags: usize) -> Result<usize> { | ||||
|     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<usize> { | ||||
|     let file = { | ||||
|  |  | |||
|  | @ -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)) | ||||
|  |  | |||
|  | @ -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<usize> { | |||
|     Ok(0) | ||||
| } | ||||
| 
 | ||||
| pub fn physalloc(size: usize) -> Result<usize> { | ||||
|     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<usize> { | ||||
|     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<usize> { | ||||
|     if size == 0 { | ||||
|  | @ -617,8 +627,15 @@ pub fn sched_yield() -> Result<usize> { | |||
|     Ok(0) | ||||
| } | ||||
| 
 | ||||
| pub fn virttophys(virtual_address: usize) -> Result<usize> { | ||||
|     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<usize> { | ||||
|     //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<usize> { | |||
|             } | ||||
|         } | ||||
| 
 | ||||
|         unsafe { context::switch(); } | ||||
|         unsafe { context::switch(); } //TODO: Block
 | ||||
|     } | ||||
| } | ||||
|  |  | |||
							
								
								
									
										2
									
								
								libstd
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								libstd
									
										
									
									
									
								
							|  | @ -1 +1 @@ | |||
| Subproject commit 9f7687ec7cf09945b8d832e4777b6c521f408754 | ||||
| Subproject commit 29a6cab11d6e84c422917724ef0eca2bcc2c6589 | ||||
|  | @ -27,8 +27,8 @@ pub fn main() { | |||
|             } | ||||
| 
 | ||||
|             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); | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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::<Event>()) 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::<Event>()) as &mut [u8] | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Copy, Clone, Debug, Default)] | ||||
| #[repr(packed)] | ||||
| pub struct Packet { | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -58,6 +58,10 @@ pub fn exit(status: usize) -> Result<usize> { | |||
|     unsafe { syscall1(SYS_EXIT, status) } | ||||
| } | ||||
| 
 | ||||
| pub fn fevent(fd: usize, flags: usize) -> Result<usize> { | ||||
|     unsafe { syscall2(SYS_FEVENT, fd, flags) } | ||||
| } | ||||
| 
 | ||||
| pub fn fpath(fd: usize, buf: &mut [u8]) -> Result<usize> { | ||||
|     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<usize> { | |||
|     unsafe { syscall3(SYS_OPEN, path.as_ptr() as usize, path.len(), flags) } | ||||
| } | ||||
| 
 | ||||
| pub unsafe fn physalloc(size: usize) -> Result<usize> { | ||||
|     syscall1(SYS_PHYSALLOC, size) | ||||
| } | ||||
| 
 | ||||
| pub unsafe fn physfree(physical_address: usize, size: usize) -> Result<usize> { | ||||
|     syscall2(SYS_PHYSFREE, physical_address, size) | ||||
| } | ||||
| 
 | ||||
| pub unsafe fn physmap(physical_address: usize, size: usize, flags: usize) -> Result<usize> { | ||||
|     syscall3(SYS_PHYSMAP, physical_address, size, flags) | ||||
| } | ||||
|  | @ -134,6 +146,10 @@ pub fn unlink(path: &str) -> Result<usize> { | |||
|     unsafe { syscall2(SYS_UNLINK, path.as_ptr() as usize, path.len()) } | ||||
| } | ||||
| 
 | ||||
| pub unsafe fn virttophys(virtual_address: usize) -> Result<usize> { | ||||
|     syscall1(SYS_VIRTTOPHYS, virtual_address) | ||||
| } | ||||
| 
 | ||||
| pub fn waitpid(pid: usize, status: &mut usize, options: usize) -> Result<usize> { | ||||
|     unsafe { syscall3(SYS_WAITPID, pid, status as *mut usize as usize, options) } | ||||
| } | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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<usize> { | ||||
|         Err(Error::new(EBADF)) | ||||
|     } | ||||
| 
 | ||||
|     #[allow(unused_variables)] | ||||
|     fn fpath(&self, id: usize, buf: &mut [u8]) -> Result<usize> { | ||||
|         Err(Error::new(EBADF)) | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Jeremy Soller
						Jeremy Soller