Merge branch 'unify_storage_drivers' into 'master'
Reduce code duplication between disk drivers See merge request redox-os/drivers!146
This commit is contained in:
Generated
+13
-12
@@ -42,11 +42,10 @@ name = "ahcid"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"block-io-wrapper",
|
||||
"byteorder",
|
||||
"common",
|
||||
"driver-block",
|
||||
"log",
|
||||
"partitionlib",
|
||||
"pcid",
|
||||
"redox-daemon",
|
||||
"redox-log",
|
||||
@@ -149,10 +148,9 @@ checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
|
||||
name = "bcm2835-sdhcid"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"block-io-wrapper",
|
||||
"common",
|
||||
"driver-block",
|
||||
"fdt",
|
||||
"partitionlib",
|
||||
"redox-daemon",
|
||||
"redox_syscall 0.4.1",
|
||||
]
|
||||
@@ -206,10 +204,6 @@ dependencies = [
|
||||
"wyz",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-io-wrapper"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.13.0"
|
||||
@@ -350,6 +344,14 @@ dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "driver-block"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"partitionlib",
|
||||
"redox_syscall 0.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "driver-network"
|
||||
version = "0.1.0"
|
||||
@@ -570,10 +572,9 @@ dependencies = [
|
||||
name = "ided"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"block-io-wrapper",
|
||||
"common",
|
||||
"driver-block",
|
||||
"log",
|
||||
"partitionlib",
|
||||
"pcid",
|
||||
"redox-daemon",
|
||||
"redox-log",
|
||||
@@ -758,9 +759,9 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bitflags 1.3.2",
|
||||
"block-io-wrapper",
|
||||
"common",
|
||||
"crossbeam-channel",
|
||||
"driver-block",
|
||||
"futures",
|
||||
"log",
|
||||
"partitionlib",
|
||||
@@ -1591,8 +1592,8 @@ name = "virtio-blkd"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"block-io-wrapper",
|
||||
"common",
|
||||
"driver-block",
|
||||
"futures",
|
||||
"log",
|
||||
"partitionlib",
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ members = [
|
||||
|
||||
"storage/ahcid",
|
||||
"storage/bcm2835-sdhcid",
|
||||
"storage/block-io-wrapper",
|
||||
"storage/driver-block",
|
||||
"storage/ided",
|
||||
"storage/lived", # TODO: not really a driver...
|
||||
"storage/nvmed",
|
||||
|
||||
@@ -50,7 +50,7 @@ impl<T: NetworkAdapter> NetworkScheme<T> {
|
||||
format!(":{scheme_name}"),
|
||||
syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK,
|
||||
)
|
||||
.expect("e1000d: failed to create network scheme");
|
||||
.expect("failed to create network scheme");
|
||||
let scheme = unsafe { File::from_raw_fd(scheme_fd as RawFd) };
|
||||
|
||||
NetworkScheme {
|
||||
|
||||
@@ -7,11 +7,10 @@ edition = "2018"
|
||||
bitflags = "1.2"
|
||||
byteorder = "1.2"
|
||||
log = "0.4"
|
||||
partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" }
|
||||
redox-daemon = "0.1"
|
||||
redox-log = "0.1"
|
||||
redox_syscall = "0.4"
|
||||
|
||||
block-io-wrapper = { path = "../block-io-wrapper" }
|
||||
common = { path = "../../common" }
|
||||
driver-block = { path = "../driver-block" }
|
||||
pcid = { path = "../../pcid" }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use driver_block::Disk;
|
||||
use log::{error, info};
|
||||
use syscall::io::Io;
|
||||
use syscall::error::Result;
|
||||
|
||||
use self::disk_ata::DiskATA;
|
||||
use self::disk_atapi::DiskATAPI;
|
||||
@@ -11,14 +11,6 @@ pub mod disk_atapi;
|
||||
pub mod fis;
|
||||
pub mod hba;
|
||||
|
||||
pub trait Disk {
|
||||
fn id(&self) -> usize;
|
||||
fn size(&mut self) -> u64;
|
||||
fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result<Option<usize>>;
|
||||
fn write(&mut self, block: u64, buffer: &[u8]) -> Result<Option<usize>>;
|
||||
fn block_length(&mut self) -> Result<u32>;
|
||||
}
|
||||
|
||||
pub fn disks(base: usize, name: &str) -> (&'static mut HbaMem, Vec<Box<dyn Disk>>) {
|
||||
let hba_mem = unsafe { &mut *(base as *mut HbaMem) };
|
||||
hba_mem.init();
|
||||
|
||||
@@ -3,19 +3,15 @@ use std::{cmp, str};
|
||||
use std::convert::{TryFrom};
|
||||
use std::fmt::Write;
|
||||
use std::io::prelude::*;
|
||||
use std::io::SeekFrom;
|
||||
use std::io;
|
||||
|
||||
use driver_block::{Disk, DiskWrapper};
|
||||
use syscall::{
|
||||
Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOVERFLOW, Result,
|
||||
Io, SchemeBlockMut, Stat, MODE_DIR, MODE_FILE, O_DIRECTORY,
|
||||
O_STAT, SEEK_CUR, SEEK_END, SEEK_SET};
|
||||
|
||||
use crate::ahci::Disk;
|
||||
use crate::ahci::hba::HbaMem;
|
||||
|
||||
use partitionlib::{LogicalBlockSize, PartitionTable};
|
||||
|
||||
#[derive(Clone)]
|
||||
enum Handle {
|
||||
List(Vec<u8>, usize), // Dir contents buffer, position
|
||||
@@ -23,89 +19,6 @@ enum Handle {
|
||||
Partition(usize, u32, usize), // Disk index, partition index, position
|
||||
}
|
||||
|
||||
pub struct DiskWrapper {
|
||||
disk: Box<dyn Disk>,
|
||||
pt: Option<PartitionTable>,
|
||||
}
|
||||
|
||||
impl DiskWrapper {
|
||||
fn pt(disk: &mut dyn Disk) -> Option<PartitionTable> {
|
||||
let bs = match disk.block_length() {
|
||||
Ok(512) => LogicalBlockSize::Lb512,
|
||||
Ok(4096) => LogicalBlockSize::Lb4096,
|
||||
_ => return None,
|
||||
};
|
||||
struct Device<'a, 'b> { disk: &'a mut dyn Disk, offset: u64, block_bytes: &'b mut [u8] }
|
||||
|
||||
impl<'a, 'b> Seek for Device<'a, 'b> {
|
||||
fn seek(&mut self, from: SeekFrom) -> io::Result<u64> {
|
||||
let size = i64::try_from(self.disk.size()).or(Err(io::Error::new(io::ErrorKind::Other, "Disk larger than 2^63 - 1 bytes")))?;
|
||||
|
||||
self.offset = match from {
|
||||
SeekFrom::Start(new_pos) => cmp::min(self.disk.size(), new_pos),
|
||||
SeekFrom::Current(new_pos) => cmp::max(0, cmp::min(size, self.offset as i64 + new_pos)) as u64,
|
||||
SeekFrom::End(new_pos) => cmp::max(0, cmp::min(size + new_pos, size)) as u64,
|
||||
};
|
||||
|
||||
Ok(self.offset)
|
||||
}
|
||||
}
|
||||
// TODO: Perhaps this impl should be used in the rest of the scheme.
|
||||
impl<'a, 'b> Read for Device<'a, 'b> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
let blksize = self.disk.block_length().map_err(|err| io::Error::from_raw_os_error(err.errno))?;
|
||||
let size_in_blocks = self.disk.size() / u64::from(blksize);
|
||||
|
||||
let disk = &mut self.disk;
|
||||
|
||||
let read_block = |block: u64, block_bytes: &mut [u8]| {
|
||||
if block >= size_in_blocks {
|
||||
return Err(io::Error::from_raw_os_error(syscall::EOVERFLOW));
|
||||
}
|
||||
loop {
|
||||
match disk.read(block, block_bytes) {
|
||||
Ok(Some(bytes)) => {
|
||||
assert_eq!(bytes, block_bytes.len());
|
||||
assert_eq!(bytes, blksize as usize);
|
||||
return Ok(());
|
||||
}
|
||||
Ok(None) => { std::thread::yield_now(); continue }
|
||||
Err(err) => return Err(io::Error::from_raw_os_error(err.errno)),
|
||||
}
|
||||
}
|
||||
};
|
||||
let bytes_read = block_io_wrapper::read(self.offset, blksize, buf, self.block_bytes, read_block)?;
|
||||
|
||||
self.offset += bytes_read as u64;
|
||||
Ok(bytes_read)
|
||||
}
|
||||
}
|
||||
|
||||
let mut block_bytes = [0u8; 4096];
|
||||
|
||||
partitionlib::get_partitions(&mut Device { disk, offset: 0, block_bytes: &mut block_bytes[..bs.into()] }, bs).ok().flatten()
|
||||
}
|
||||
fn new(mut disk: Box<dyn Disk>) -> Self {
|
||||
Self {
|
||||
pt: Self::pt(&mut *disk),
|
||||
disk,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for DiskWrapper {
|
||||
type Target = dyn Disk;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&*self.disk
|
||||
}
|
||||
}
|
||||
impl std::ops::DerefMut for DiskWrapper {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut *self.disk
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DiskScheme {
|
||||
scheme_name: String,
|
||||
hba_mem: &'static mut HbaMem,
|
||||
|
||||
@@ -8,8 +8,7 @@ edition = "2021"
|
||||
[dependencies]
|
||||
fdt = "0.1.5"
|
||||
redox_syscall = "0.4"
|
||||
partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" }
|
||||
block-io-wrapper = { path = "../block-io-wrapper" }
|
||||
common = { path = "../../common" }
|
||||
driver-block = { path = "../driver-block" }
|
||||
|
||||
redox-daemon = "0.1"
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
use std::{fs::File, io::{Read, Write}, process};
|
||||
|
||||
use driver_block::Disk;
|
||||
use fdt::{Fdt, node::FdtNode};
|
||||
use syscall::{Packet, SchemeBlockMut};
|
||||
|
||||
use crate::sd::Disk;
|
||||
use crate::scheme::DiskScheme;
|
||||
|
||||
mod sd;
|
||||
mod scheme;
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
#[cfg(target_os = "redox")]
|
||||
fn get_dtb() -> Vec<u8> {
|
||||
std::fs::read("kernel.dtb:").unwrap()
|
||||
}
|
||||
@@ -48,7 +48,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! {
|
||||
};
|
||||
println!("ioremap 0x{:08x} to 0x{:08x} 2222", reg.starting_address as usize, addr);
|
||||
let mut sdhci = sd::SdHostCtrl::new(addr);
|
||||
unsafe {
|
||||
unsafe {
|
||||
sdhci.init();
|
||||
/*
|
||||
let mut buf1 = [0u32; 512];
|
||||
|
||||
@@ -3,19 +3,14 @@ use std::{cmp, str};
|
||||
use std::convert::{TryFrom};
|
||||
use std::fmt::Write;
|
||||
use std::io::prelude::*;
|
||||
use std::io::SeekFrom;
|
||||
use std::io;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use driver_block::{Disk, DiskWrapper};
|
||||
use syscall::{
|
||||
Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOVERFLOW, Result,
|
||||
Io, SchemeBlockMut, Stat, MODE_DIR, MODE_FILE, O_DIRECTORY,
|
||||
O_STAT, SEEK_CUR, SEEK_END, SEEK_SET};
|
||||
|
||||
use crate::sd::Disk;
|
||||
|
||||
use partitionlib::{LogicalBlockSize, PartitionTable};
|
||||
|
||||
#[derive(Clone)]
|
||||
enum Handle {
|
||||
List(Vec<u8>, usize), // Dir contents buffer, position
|
||||
@@ -23,88 +18,6 @@ enum Handle {
|
||||
Partition(usize, u32, usize), // Disk index, partition index, position
|
||||
}
|
||||
|
||||
pub struct DiskWrapper {
|
||||
disk: Box<dyn Disk>,
|
||||
pt: Option<PartitionTable>,
|
||||
}
|
||||
|
||||
impl DiskWrapper {
|
||||
fn pt(disk: &mut dyn Disk) -> Option<PartitionTable> {
|
||||
let bs = match disk.block_length() {
|
||||
Ok(512) => LogicalBlockSize::Lb512,
|
||||
_ => return None,
|
||||
};
|
||||
struct Device<'a, 'b> { disk: &'a mut dyn Disk, offset: u64, block_bytes: &'b mut [u8] }
|
||||
|
||||
impl<'a, 'b> Seek for Device<'a, 'b> {
|
||||
fn seek(&mut self, from: SeekFrom) -> io::Result<u64> {
|
||||
let size = i64::try_from(self.disk.size()).or(Err(io::Error::new(io::ErrorKind::Other, "Disk larger than 2^63 - 1 bytes")))?;
|
||||
|
||||
self.offset = match from {
|
||||
SeekFrom::Start(new_pos) => cmp::min(self.disk.size(), new_pos),
|
||||
SeekFrom::Current(new_pos) => cmp::max(0, cmp::min(size, self.offset as i64 + new_pos)) as u64,
|
||||
SeekFrom::End(new_pos) => cmp::max(0, cmp::min(size + new_pos, size)) as u64,
|
||||
};
|
||||
|
||||
Ok(self.offset)
|
||||
}
|
||||
}
|
||||
// TODO: Perhaps this impl should be used in the rest of the scheme.
|
||||
impl<'a, 'b> Read for Device<'a, 'b> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
let blksize = self.disk.block_length().map_err(|err| io::Error::from_raw_os_error(err.errno))?;
|
||||
let size_in_blocks = self.disk.size() / u64::from(blksize);
|
||||
|
||||
let disk = &mut self.disk;
|
||||
|
||||
let read_block = |block: u64, block_bytes: &mut [u8]| {
|
||||
if block >= size_in_blocks {
|
||||
return Err(io::Error::from_raw_os_error(syscall::EOVERFLOW));
|
||||
}
|
||||
loop {
|
||||
match disk.read(block, block_bytes) {
|
||||
Ok(Some(bytes)) => {
|
||||
assert_eq!(bytes, block_bytes.len());
|
||||
assert_eq!(bytes, blksize as usize);
|
||||
return Ok(());
|
||||
}
|
||||
Ok(None) => { std::thread::yield_now(); continue }
|
||||
Err(err) => return Err(io::Error::from_raw_os_error(err.errno)),
|
||||
}
|
||||
}
|
||||
};
|
||||
let bytes_read = block_io_wrapper::read(self.offset, blksize, buf, self.block_bytes, read_block)?;
|
||||
|
||||
self.offset += bytes_read as u64;
|
||||
Ok(bytes_read)
|
||||
}
|
||||
}
|
||||
|
||||
let mut block_bytes = [0u8; 4096];
|
||||
|
||||
partitionlib::get_partitions(&mut Device { disk, offset: 0, block_bytes: &mut block_bytes[..bs.into()] }, bs).ok().flatten()
|
||||
}
|
||||
fn new(mut disk: Box<dyn Disk>) -> Self {
|
||||
Self {
|
||||
pt: Self::pt(&mut *disk),
|
||||
disk,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for DiskWrapper {
|
||||
type Target = dyn Disk;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&*self.disk
|
||||
}
|
||||
}
|
||||
impl std::ops::DerefMut for DiskWrapper {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut *self.disk
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DiskScheme {
|
||||
scheme_name: String,
|
||||
disks: Box<[DiskWrapper]>,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::{sync::{Mutex, RwLock}, time::{self, Duration}, thread};
|
||||
use syscall::{io::Mmio, Io, Error, Result, EINVAL};
|
||||
use core::ptr::{read_volatile, write_volatile};
|
||||
use driver_block::Disk;
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
#[inline(always)]
|
||||
@@ -17,7 +17,7 @@ pub(crate) unsafe fn wait_cycles(mut n: usize) {
|
||||
#[inline(always)]
|
||||
pub(crate) unsafe fn wait_msec(mut n: usize) {
|
||||
use core::arch::asm;
|
||||
|
||||
|
||||
let mut f: usize;
|
||||
let mut t: usize;
|
||||
let mut r: usize;
|
||||
@@ -185,7 +185,7 @@ pub struct SdHostCtrl {
|
||||
impl SdHostCtrl {
|
||||
pub fn new(address: usize) -> Self {
|
||||
SdHostCtrl {
|
||||
regs: RwLock::new(unsafe { &mut *(address as *mut SdHostCtrlRegs)}),
|
||||
regs: RwLock::new(unsafe { &mut *(address as *mut SdHostCtrlRegs)}),
|
||||
host_spec_ver: 0,
|
||||
cid: [0; 4],
|
||||
csd: [0; 4],
|
||||
@@ -228,7 +228,7 @@ impl SdHostCtrl {
|
||||
return ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let regs = self.regs.get_mut().unwrap();
|
||||
regs.irpt_en.write(0xffff_ffff);
|
||||
regs.irpt_mask.write(0xffff_ffff);
|
||||
@@ -518,7 +518,7 @@ impl SdHostCtrl {
|
||||
self.cid[1] = regs.resp1.read();
|
||||
self.cid[2] = regs.resp2.read();
|
||||
self.cid[3] = regs.resp3.read();
|
||||
|
||||
|
||||
//FIXME: wrong implement, see CMD_SEND_CSD for detail
|
||||
return Ok(reg_val);
|
||||
} else if code == CMD_SEND_CSD {
|
||||
@@ -526,7 +526,7 @@ impl SdHostCtrl {
|
||||
let tmp1 = regs.resp1.read();
|
||||
let tmp2 = regs.resp2.read();
|
||||
let tmp3 = regs.resp3.read();
|
||||
|
||||
|
||||
self.csd[0] = tmp3 << 8 | tmp2 >> 24;
|
||||
self.csd[1] = tmp2 << 8 | tmp1 >> 24;
|
||||
self.csd[2] = tmp1 << 8 | tmp0 >> 24;
|
||||
@@ -713,14 +713,6 @@ impl SdHostCtrl {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Disk {
|
||||
fn id(&self) -> usize;
|
||||
fn size(&mut self) -> u64;
|
||||
fn read(&mut self, block:u64, buffer: &mut [u8]) -> syscall::error::Result<Option<usize>>;
|
||||
fn write(&mut self, block:u64, buffer: &[u8]) -> syscall::error::Result<Option<usize>>;
|
||||
fn block_length(&mut self) -> syscall::error::Result<u32>;
|
||||
}
|
||||
|
||||
impl Disk for SdHostCtrl {
|
||||
fn id(&self) -> usize {
|
||||
0xdead_dead
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
/target
|
||||
@@ -1,9 +0,0 @@
|
||||
[package]
|
||||
name = "block-io-wrapper"
|
||||
version = "0.1.0"
|
||||
authors = ["4lDO2 <4lDO2@protonmail.com>"]
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
@@ -1,49 +0,0 @@
|
||||
use std::cmp::min;
|
||||
use std::io::Error;
|
||||
|
||||
/// Split the read operation into a series of block reads.
|
||||
/// `read_fn` will be called with a block number to be read, and a buffer to be filled.
|
||||
/// The buffer must be large enough to hold `blksize` of data.
|
||||
/// `read_fn` must return a full block of data.
|
||||
/// Result will be the number of bytes read.
|
||||
pub fn read(
|
||||
offset: u64,
|
||||
blksize: u32,
|
||||
buf: &mut [u8],
|
||||
block_bytes: &mut [u8],
|
||||
mut read_fn: impl FnMut(u64, &mut [u8]) -> Result<(), Error>,
|
||||
) -> Result<usize, Error> {
|
||||
// TODO: Yield sometimes, perhaps after a few blocks or something.
|
||||
|
||||
if buf.len() == 0 {
|
||||
return Ok(0);
|
||||
}
|
||||
let to_copy = usize::try_from(
|
||||
offset.saturating_add(u64::try_from(buf.len()).expect("buf.len() larger than u64"))
|
||||
- offset,
|
||||
)
|
||||
.expect("bytes to copy larger than usize");
|
||||
let mut curr_buf = &mut buf[..to_copy];
|
||||
let mut curr_offset = offset;
|
||||
let blk_size = usize::try_from(blksize).expect("blksize larger than usize");
|
||||
let mut total_read = 0;
|
||||
|
||||
while curr_buf.len() > 0 {
|
||||
// TODO: Async/await? I mean, shouldn't AHCI be async?
|
||||
|
||||
let blk_offset =
|
||||
usize::try_from(curr_offset % u64::from(blksize)).expect("usize smaller than blksize");
|
||||
let to_copy = min(curr_buf.len(), blk_size - blk_offset);
|
||||
assert!(blk_offset + to_copy <= blk_size);
|
||||
|
||||
read_fn(curr_offset / u64::from(blksize), block_bytes)?;
|
||||
|
||||
let src_buf = &block_bytes[blk_offset..];
|
||||
|
||||
curr_buf[..to_copy].copy_from_slice(&src_buf[..to_copy]);
|
||||
curr_buf = &mut curr_buf[to_copy..];
|
||||
curr_offset += u64::try_from(to_copy).expect("bytes to copy larger than u64");
|
||||
total_read += to_copy;
|
||||
}
|
||||
Ok(total_read)
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "driver-block"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" }
|
||||
|
||||
redox_syscall = "0.4"
|
||||
@@ -0,0 +1,175 @@
|
||||
use std::cmp;
|
||||
use std::io::Error;
|
||||
use std::io::{self, Read, Seek, SeekFrom};
|
||||
|
||||
use partitionlib::{LogicalBlockSize, PartitionTable};
|
||||
|
||||
/// Split the read operation into a series of block reads.
|
||||
/// `read_fn` will be called with a block number to be read, and a buffer to be filled.
|
||||
/// The buffer must be large enough to hold `blksize` of data.
|
||||
/// `read_fn` must return a full block of data.
|
||||
/// Result will be the number of bytes read.
|
||||
// FIXME make private once nvmed uses the DiskWrapper defined in this crate
|
||||
pub fn block_read(
|
||||
offset: u64,
|
||||
blksize: u32,
|
||||
buf: &mut [u8],
|
||||
block_bytes: &mut [u8],
|
||||
mut read_fn: impl FnMut(u64, &mut [u8]) -> Result<(), Error>,
|
||||
) -> Result<usize, Error> {
|
||||
// TODO: Yield sometimes, perhaps after a few blocks or something.
|
||||
|
||||
if buf.len() == 0 {
|
||||
return Ok(0);
|
||||
}
|
||||
let to_copy = usize::try_from(
|
||||
offset.saturating_add(u64::try_from(buf.len()).expect("buf.len() larger than u64"))
|
||||
- offset,
|
||||
)
|
||||
.expect("bytes to copy larger than usize");
|
||||
let mut curr_buf = &mut buf[..to_copy];
|
||||
let mut curr_offset = offset;
|
||||
let blk_size = usize::try_from(blksize).expect("blksize larger than usize");
|
||||
let mut total_read = 0;
|
||||
|
||||
while curr_buf.len() > 0 {
|
||||
// TODO: Async/await? I mean, shouldn't AHCI be async?
|
||||
|
||||
let blk_offset =
|
||||
usize::try_from(curr_offset % u64::from(blksize)).expect("usize smaller than blksize");
|
||||
let to_copy = cmp::min(curr_buf.len(), blk_size - blk_offset);
|
||||
assert!(blk_offset + to_copy <= blk_size);
|
||||
|
||||
read_fn(curr_offset / u64::from(blksize), block_bytes)?;
|
||||
|
||||
let src_buf = &block_bytes[blk_offset..];
|
||||
|
||||
curr_buf[..to_copy].copy_from_slice(&src_buf[..to_copy]);
|
||||
curr_buf = &mut curr_buf[to_copy..];
|
||||
curr_offset += u64::try_from(to_copy).expect("bytes to copy larger than u64");
|
||||
total_read += to_copy;
|
||||
}
|
||||
Ok(total_read)
|
||||
}
|
||||
|
||||
pub trait Disk {
|
||||
fn id(&self) -> usize;
|
||||
fn block_length(&mut self) -> syscall::error::Result<u32>;
|
||||
fn size(&mut self) -> u64;
|
||||
|
||||
fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result<Option<usize>>;
|
||||
fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result<Option<usize>>;
|
||||
}
|
||||
|
||||
pub struct DiskWrapper {
|
||||
pub disk: Box<dyn Disk>,
|
||||
pub pt: Option<PartitionTable>,
|
||||
}
|
||||
|
||||
impl DiskWrapper {
|
||||
fn pt(disk: &mut dyn Disk) -> Option<PartitionTable> {
|
||||
let bs = match disk.block_length() {
|
||||
Ok(512) => LogicalBlockSize::Lb512,
|
||||
_ => return None,
|
||||
};
|
||||
struct Device<'a, 'b> {
|
||||
disk: &'a mut dyn Disk,
|
||||
offset: u64,
|
||||
block_bytes: &'b mut [u8],
|
||||
}
|
||||
|
||||
impl<'a, 'b> Seek for Device<'a, 'b> {
|
||||
fn seek(&mut self, from: SeekFrom) -> io::Result<u64> {
|
||||
let size = i64::try_from(self.disk.size()).or(Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
"Disk larger than 2^63 - 1 bytes",
|
||||
)))?;
|
||||
|
||||
self.offset = match from {
|
||||
SeekFrom::Start(new_pos) => cmp::min(self.disk.size(), new_pos),
|
||||
SeekFrom::Current(new_pos) => {
|
||||
cmp::max(0, cmp::min(size, self.offset as i64 + new_pos)) as u64
|
||||
}
|
||||
SeekFrom::End(new_pos) => cmp::max(0, cmp::min(size + new_pos, size)) as u64,
|
||||
};
|
||||
|
||||
Ok(self.offset)
|
||||
}
|
||||
}
|
||||
// TODO: Perhaps this impl should be used in the rest of the scheme.
|
||||
impl<'a, 'b> Read for Device<'a, 'b> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
let blksize = self
|
||||
.disk
|
||||
.block_length()
|
||||
.map_err(|err| io::Error::from_raw_os_error(err.errno))?;
|
||||
let size_in_blocks = self.disk.size() / u64::from(blksize);
|
||||
|
||||
let disk = &mut self.disk;
|
||||
|
||||
let read_block = |block: u64, block_bytes: &mut [u8]| {
|
||||
if block >= size_in_blocks {
|
||||
return Err(io::Error::from_raw_os_error(syscall::EOVERFLOW));
|
||||
}
|
||||
loop {
|
||||
match disk.read(block, block_bytes) {
|
||||
Ok(Some(bytes)) => {
|
||||
assert_eq!(bytes, block_bytes.len());
|
||||
assert_eq!(bytes, blksize as usize);
|
||||
return Ok(());
|
||||
}
|
||||
Ok(None) => {
|
||||
std::thread::yield_now();
|
||||
continue;
|
||||
}
|
||||
Err(err) => return Err(io::Error::from_raw_os_error(err.errno)),
|
||||
}
|
||||
}
|
||||
};
|
||||
let bytes_read = block_read(
|
||||
self.offset,
|
||||
blksize,
|
||||
buf,
|
||||
self.block_bytes,
|
||||
read_block,
|
||||
)?;
|
||||
|
||||
self.offset += bytes_read as u64;
|
||||
Ok(bytes_read)
|
||||
}
|
||||
}
|
||||
|
||||
let mut block_bytes = [0u8; 4096];
|
||||
|
||||
partitionlib::get_partitions(
|
||||
&mut Device {
|
||||
disk,
|
||||
offset: 0,
|
||||
block_bytes: &mut block_bytes[..bs.into()],
|
||||
},
|
||||
bs,
|
||||
)
|
||||
.ok()
|
||||
.flatten()
|
||||
}
|
||||
|
||||
pub fn new(mut disk: Box<dyn Disk>) -> Self {
|
||||
Self {
|
||||
pt: Self::pt(&mut *disk),
|
||||
disk,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for DiskWrapper {
|
||||
type Target = dyn Disk;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&*self.disk
|
||||
}
|
||||
}
|
||||
impl std::ops::DerefMut for DiskWrapper {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut *self.disk
|
||||
}
|
||||
}
|
||||
@@ -4,10 +4,9 @@ version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
block-io-wrapper = { path = "../block-io-wrapper" }
|
||||
common = { path = "../../common" }
|
||||
driver-block = { path = "../driver-block" }
|
||||
log = "0.4"
|
||||
partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" }
|
||||
pcid = { path = "../../pcid" }
|
||||
redox-daemon = "0.1"
|
||||
redox-log = "0.1"
|
||||
|
||||
@@ -5,6 +5,7 @@ use std::{
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
use driver_block::Disk;
|
||||
use syscall::{
|
||||
error::{Error, Result, EIO},
|
||||
io::{Io, Pio, ReadOnly, WriteOnly},
|
||||
@@ -153,14 +154,6 @@ impl Channel {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Disk {
|
||||
fn id(&self) -> usize;
|
||||
fn size(&mut self) -> u64;
|
||||
fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result<Option<usize>>;
|
||||
fn write(&mut self, block: u64, buffer: &[u8]) -> Result<Option<usize>>;
|
||||
fn block_length(&mut self) -> Result<u32>;
|
||||
}
|
||||
|
||||
pub struct AtaDisk {
|
||||
pub chan: Arc<Mutex<Channel>>,
|
||||
pub chan_i: usize,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use driver_block::Disk;
|
||||
use log::{error, info};
|
||||
use pcid_interface::{PciBar, PcidServerHandle};
|
||||
use redox_log::{OutputBuilder, RedoxLogger};
|
||||
@@ -18,7 +19,7 @@ use syscall::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
ide::{AtaCommand, AtaDisk, Channel, Disk},
|
||||
ide::{AtaCommand, AtaDisk, Channel},
|
||||
scheme::DiskScheme,
|
||||
};
|
||||
|
||||
|
||||
@@ -3,18 +3,15 @@ use std::{cmp, str};
|
||||
use std::convert::{TryFrom};
|
||||
use std::fmt::Write;
|
||||
use std::io::prelude::*;
|
||||
use std::io::SeekFrom;
|
||||
use std::io;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use driver_block::{Disk, DiskWrapper};
|
||||
use syscall::{
|
||||
Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOVERFLOW, Result,
|
||||
Io, SchemeBlockMut, Stat, MODE_DIR, MODE_FILE, O_DIRECTORY,
|
||||
O_STAT, SEEK_CUR, SEEK_END, SEEK_SET};
|
||||
|
||||
use crate::ide::{Channel, Disk};
|
||||
|
||||
use partitionlib::{LogicalBlockSize, PartitionTable};
|
||||
use crate::ide::Channel;
|
||||
|
||||
#[derive(Clone)]
|
||||
enum Handle {
|
||||
@@ -23,89 +20,6 @@ enum Handle {
|
||||
Partition(usize, u32, usize), // Disk index, partition index, position
|
||||
}
|
||||
|
||||
pub struct DiskWrapper {
|
||||
disk: Box<dyn Disk>,
|
||||
pt: Option<PartitionTable>,
|
||||
}
|
||||
|
||||
impl DiskWrapper {
|
||||
fn pt(disk: &mut dyn Disk) -> Option<PartitionTable> {
|
||||
let bs = match disk.block_length() {
|
||||
Ok(512) => LogicalBlockSize::Lb512,
|
||||
Ok(4096) => LogicalBlockSize::Lb4096,
|
||||
_ => return None,
|
||||
};
|
||||
struct Device<'a, 'b> { disk: &'a mut dyn Disk, offset: u64, block_bytes: &'b mut [u8] }
|
||||
|
||||
impl<'a, 'b> Seek for Device<'a, 'b> {
|
||||
fn seek(&mut self, from: SeekFrom) -> io::Result<u64> {
|
||||
let size = i64::try_from(self.disk.size()).or(Err(io::Error::new(io::ErrorKind::Other, "Disk larger than 2^63 - 1 bytes")))?;
|
||||
|
||||
self.offset = match from {
|
||||
SeekFrom::Start(new_pos) => cmp::min(self.disk.size(), new_pos),
|
||||
SeekFrom::Current(new_pos) => cmp::max(0, cmp::min(size, self.offset as i64 + new_pos)) as u64,
|
||||
SeekFrom::End(new_pos) => cmp::max(0, cmp::min(size + new_pos, size)) as u64,
|
||||
};
|
||||
|
||||
Ok(self.offset)
|
||||
}
|
||||
}
|
||||
// TODO: Perhaps this impl should be used in the rest of the scheme.
|
||||
impl<'a, 'b> Read for Device<'a, 'b> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
let blksize = self.disk.block_length().map_err(|err| io::Error::from_raw_os_error(err.errno))?;
|
||||
let size_in_blocks = self.disk.size() / u64::from(blksize);
|
||||
|
||||
let disk = &mut self.disk;
|
||||
|
||||
let read_block = |block: u64, block_bytes: &mut [u8]| {
|
||||
if block >= size_in_blocks {
|
||||
return Err(io::Error::from_raw_os_error(syscall::EOVERFLOW));
|
||||
}
|
||||
loop {
|
||||
match disk.read(block, block_bytes) {
|
||||
Ok(Some(bytes)) => {
|
||||
assert_eq!(bytes, block_bytes.len());
|
||||
assert_eq!(bytes, blksize as usize);
|
||||
return Ok(());
|
||||
}
|
||||
Ok(None) => { std::thread::yield_now(); continue }
|
||||
Err(err) => return Err(io::Error::from_raw_os_error(err.errno)),
|
||||
}
|
||||
}
|
||||
};
|
||||
let bytes_read = block_io_wrapper::read(self.offset, blksize, buf, self.block_bytes, read_block)?;
|
||||
|
||||
self.offset += bytes_read as u64;
|
||||
Ok(bytes_read)
|
||||
}
|
||||
}
|
||||
|
||||
let mut block_bytes = [0u8; 4096];
|
||||
|
||||
partitionlib::get_partitions(&mut Device { disk, offset: 0, block_bytes: &mut block_bytes[..bs.into()] }, bs).ok().flatten()
|
||||
}
|
||||
fn new(mut disk: Box<dyn Disk>) -> Self {
|
||||
Self {
|
||||
pt: Self::pt(&mut *disk),
|
||||
disk,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for DiskWrapper {
|
||||
type Target = dyn Disk;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&*self.disk
|
||||
}
|
||||
}
|
||||
impl std::ops::DerefMut for DiskWrapper {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut *self.disk
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DiskScheme {
|
||||
scheme_name: String,
|
||||
chans: Box<[Arc<Mutex<Channel>>]>,
|
||||
|
||||
@@ -15,8 +15,8 @@ redox_syscall = "0.4"
|
||||
partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" }
|
||||
smallvec = "1"
|
||||
|
||||
block-io-wrapper = { path = "../block-io-wrapper" }
|
||||
common = { path = "../../common" }
|
||||
driver-block = { path = "../driver-block" }
|
||||
pcid = { path = "../../pcid" }
|
||||
|
||||
[features]
|
||||
|
||||
@@ -96,7 +96,7 @@ impl DiskWrapper {
|
||||
}
|
||||
}
|
||||
};
|
||||
let bytes_read = block_io_wrapper::read(
|
||||
let bytes_read = driver_block::block_read(
|
||||
self.offset,
|
||||
blksize
|
||||
.try_into()
|
||||
|
||||
@@ -17,7 +17,7 @@ redox-log = "0.1"
|
||||
redox_syscall = "0.4"
|
||||
partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" }
|
||||
|
||||
block-io-wrapper = { path = "../block-io-wrapper" }
|
||||
common = { path = "../../common" }
|
||||
driver-block = { path = "../driver-block" }
|
||||
pcid = { path = "../../pcid" }
|
||||
virtio-core = { path = "../../virtio-core" }
|
||||
|
||||
@@ -148,7 +148,7 @@ impl<'a> DiskScheme<'a> {
|
||||
};
|
||||
|
||||
let bytes_read =
|
||||
block_io_wrapper::read(self.offset, 512, buf, self.block_bytes, read_block)
|
||||
driver_block::block_read(self.offset, 512, buf, self.block_bytes, read_block)
|
||||
.unwrap();
|
||||
self.offset += bytes_read as u64;
|
||||
Ok(bytes_read)
|
||||
|
||||
@@ -71,7 +71,7 @@ pub fn probe_device(pcid_handle: &mut PcidServerHandle) -> Result<Device, Error>
|
||||
let mut notify_addr = None;
|
||||
let mut device_addr = None;
|
||||
|
||||
for capability in pcid_handle
|
||||
for raw_capability in pcid_handle
|
||||
.get_capabilities()?
|
||||
.iter()
|
||||
.filter_map(|capability| {
|
||||
@@ -83,7 +83,7 @@ pub fn probe_device(pcid_handle: &mut PcidServerHandle) -> Result<Device, Error>
|
||||
})
|
||||
{
|
||||
// SAFETY: We have verified that the length of the data is correct.
|
||||
let capability = unsafe { &*(capability.data.as_ptr() as *const PciCapability) };
|
||||
let capability = unsafe { &*(raw_capability.data.as_ptr() as *const PciCapability) };
|
||||
|
||||
match capability.cfg_type {
|
||||
CfgType::Common | CfgType::Notify | CfgType::Device => {}
|
||||
@@ -123,7 +123,7 @@ pub fn probe_device(pcid_handle: &mut PcidServerHandle) -> Result<Device, Error>
|
||||
// SAFETY: The capability type is `Notify`, so its safe to access
|
||||
// the `notify_multiplier` field.
|
||||
let multiplier = unsafe {
|
||||
(&*(capability as *const PciCapability as *const PciCapabilityNotify))
|
||||
(&*(raw_capability.data.as_ptr() as *const PciCapability as *const PciCapabilityNotify))
|
||||
.notify_off_multiplier()
|
||||
};
|
||||
notify_addr = Some((address, multiplier));
|
||||
|
||||
Reference in New Issue
Block a user