mirror of https://github.com/vinc/moros.git
Add drive device (#555)
* Add drive device * Add TODO comments * Add specific information to device files * Handle invalid drive * Create device file for each possible drive * Change error messages on read failures * Replace From with TryFrom for Device * Refactor Device::try_from * Add TODO comment * Handle drive end of file * Fix merge issue
This commit is contained in:
parent
10d9ba5833
commit
6f1de4edf4
|
@ -98,10 +98,10 @@ pub fn open_device(path: &str) -> Option<usize> {
|
|||
syscall::open(path, flags)
|
||||
}
|
||||
|
||||
pub fn create_device(path: &str, kind: DeviceType) -> Option<usize> {
|
||||
pub fn create_device(path: &str, buf: &[u8]) -> Option<usize> {
|
||||
let flags = OpenFlag::Create as usize | OpenFlag::Device as usize;
|
||||
if let Some(handle) = syscall::open(path, flags) {
|
||||
syscall::write(handle, &kind.buf());
|
||||
syscall::write(handle, buf);
|
||||
return Some(handle);
|
||||
}
|
||||
None
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
use crate::sys;
|
||||
use crate::api::fs::{FileIO, IO};
|
||||
|
||||
use alloc::string::String;
|
||||
use alloc::vec::Vec;
|
||||
use bit_field::BitField;
|
||||
|
@ -316,33 +318,40 @@ pub fn init() {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Drive {
|
||||
pub bus: u8,
|
||||
pub dsk: u8,
|
||||
blocks: u32,
|
||||
model: String,
|
||||
serial: String,
|
||||
block_count: u32,
|
||||
block_index: u32,
|
||||
}
|
||||
|
||||
impl Drive {
|
||||
pub fn size() -> usize {
|
||||
BLOCK_SIZE
|
||||
}
|
||||
|
||||
pub fn open(bus: u8, dsk: u8) -> Option<Self> {
|
||||
let mut buses = BUSES.lock();
|
||||
let res = buses[bus as usize].identify_drive(dsk);
|
||||
if let Ok(IdentifyResponse::Ata(res)) = res {
|
||||
let buf = res.map(u16::to_be_bytes).concat();
|
||||
let serial = String::from_utf8_lossy(&buf[20..40]).trim().into();
|
||||
let model = String::from_utf8_lossy(&buf[54..94]).trim().into();
|
||||
|
||||
let blocks = u32::from_be_bytes(buf[120..124].try_into().unwrap()).
|
||||
rotate_left(16);
|
||||
let serial = String::from_utf8_lossy(&buf[20..40]).trim().into();
|
||||
let block_count = u32::from_be_bytes(
|
||||
buf[120..124].try_into().unwrap()
|
||||
).rotate_left(16);
|
||||
let block_index = 0;
|
||||
|
||||
Some(Self {
|
||||
bus,
|
||||
dsk,
|
||||
model,
|
||||
serial,
|
||||
blocks,
|
||||
block_count,
|
||||
block_index,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
|
@ -354,7 +363,7 @@ impl Drive {
|
|||
}
|
||||
|
||||
pub fn block_count(&self) -> u32 {
|
||||
self.blocks
|
||||
self.block_count
|
||||
}
|
||||
|
||||
fn humanized_size(&self) -> (usize, String) {
|
||||
|
@ -369,6 +378,34 @@ impl Drive {
|
|||
}
|
||||
}
|
||||
|
||||
impl FileIO for Drive {
|
||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize, ()> {
|
||||
if self.block_index == self.block_count {
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
let mut buses = BUSES.lock();
|
||||
let _ = buses[self.bus as usize].read(self.dsk, self.block_index, buf);
|
||||
let n = buf.len();
|
||||
self.block_index += 1;
|
||||
Ok(n)
|
||||
}
|
||||
|
||||
fn write(&mut self, _buf: &[u8]) -> Result<usize, ()> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn close(&mut self) {
|
||||
}
|
||||
|
||||
fn poll(&mut self, event: IO) -> bool {
|
||||
match event {
|
||||
IO::Read => true,
|
||||
IO::Write => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Drive {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let (size, unit) = self.humanized_size();
|
||||
|
|
|
@ -3,6 +3,7 @@ use super::dir::Dir;
|
|||
use super::file::File;
|
||||
use super::{dirname, filename, realpath, FileIO, IO};
|
||||
|
||||
use crate::sys::ata::Drive;
|
||||
use crate::sys::clock::{Realtime, Uptime};
|
||||
use crate::sys::cmos::RTC;
|
||||
use crate::sys::console::Console;
|
||||
|
@ -12,6 +13,8 @@ use crate::sys::random::Random;
|
|||
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
use core::convert::TryFrom;
|
||||
use core::convert::TryInto;
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Copy)]
|
||||
#[repr(u8)]
|
||||
|
@ -25,10 +28,33 @@ pub enum DeviceType {
|
|||
RTC = 6,
|
||||
TcpSocket = 7,
|
||||
UdpSocket = 8,
|
||||
Drive = 9,
|
||||
}
|
||||
|
||||
impl TryFrom<&[u8]> for DeviceType {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(buf: &[u8]) -> Result<Self, Self::Error> {
|
||||
match buf.get(0) {
|
||||
Some(i) if *i == DeviceType::Null as u8 => Ok(DeviceType::Null),
|
||||
Some(i) if *i == DeviceType::File as u8 => Ok(DeviceType::File),
|
||||
Some(i) if *i == DeviceType::Console as u8 => Ok(DeviceType::Console),
|
||||
Some(i) if *i == DeviceType::Random as u8 => Ok(DeviceType::Random),
|
||||
Some(i) if *i == DeviceType::Uptime as u8 => Ok(DeviceType::Uptime),
|
||||
Some(i) if *i == DeviceType::Realtime as u8 => Ok(DeviceType::Realtime),
|
||||
Some(i) if *i == DeviceType::RTC as u8 => Ok(DeviceType::RTC),
|
||||
Some(i) if *i == DeviceType::TcpSocket as u8 => Ok(DeviceType::TcpSocket),
|
||||
Some(i) if *i == DeviceType::UdpSocket as u8 => Ok(DeviceType::UdpSocket),
|
||||
Some(i) if *i == DeviceType::Drive as u8 => Ok(DeviceType::Drive),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Used when creating a device
|
||||
impl DeviceType {
|
||||
// Return a buffer for the file representing the device in the filesystem.
|
||||
// The first byte is the device type. The remaining bytes can be used to
|
||||
// store specific device informations.
|
||||
pub fn buf(self) -> Vec<u8> {
|
||||
let len = match self {
|
||||
DeviceType::RTC => RTC::size(),
|
||||
|
@ -37,10 +63,11 @@ impl DeviceType {
|
|||
DeviceType::Console => Console::size(),
|
||||
DeviceType::TcpSocket => TcpSocket::size(),
|
||||
DeviceType::UdpSocket => UdpSocket::size(),
|
||||
_ => 1,
|
||||
DeviceType::Drive => Drive::size(),
|
||||
_ => 1,
|
||||
};
|
||||
let mut res = vec![0; len];
|
||||
res[0] = self as u8;
|
||||
res[0] = self as u8; // Device type
|
||||
res
|
||||
}
|
||||
}
|
||||
|
@ -56,39 +83,51 @@ pub enum Device {
|
|||
RTC(RTC),
|
||||
TcpSocket(TcpSocket),
|
||||
UdpSocket(UdpSocket),
|
||||
Drive(Drive),
|
||||
}
|
||||
|
||||
impl From<u8> for Device {
|
||||
fn from(i: u8) -> Self {
|
||||
match i {
|
||||
i if i == DeviceType::Null as u8 => {
|
||||
Device::Null
|
||||
impl TryFrom<&[u8]> for Device {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(buf: &[u8]) -> Result<Self, Self::Error> {
|
||||
match buf.try_into() {
|
||||
Ok(DeviceType::Null) => {
|
||||
Ok(Device::Null)
|
||||
}
|
||||
i if i == DeviceType::File as u8 => {
|
||||
Device::File(File::new())
|
||||
Ok(DeviceType::File) => {
|
||||
Ok(Device::File(File::new()))
|
||||
}
|
||||
i if i == DeviceType::Console as u8 => {
|
||||
Device::Console(Console::new())
|
||||
Ok(DeviceType::Console) => {
|
||||
Ok(Device::Console(Console::new()))
|
||||
}
|
||||
i if i == DeviceType::Random as u8 => {
|
||||
Device::Random(Random::new())
|
||||
Ok(DeviceType::Random) => {
|
||||
Ok(Device::Random(Random::new()))
|
||||
}
|
||||
i if i == DeviceType::Uptime as u8 => {
|
||||
Device::Uptime(Uptime::new())
|
||||
Ok(DeviceType::Uptime) => {
|
||||
Ok(Device::Uptime(Uptime::new()))
|
||||
}
|
||||
i if i == DeviceType::Realtime as u8 => {
|
||||
Device::Realtime(Realtime::new())
|
||||
Ok(DeviceType::Realtime) => {
|
||||
Ok(Device::Realtime(Realtime::new()))
|
||||
}
|
||||
i if i == DeviceType::RTC as u8 => {
|
||||
Device::RTC(RTC::new())
|
||||
Ok(DeviceType::RTC) => {
|
||||
Ok(Device::RTC(RTC::new()))
|
||||
}
|
||||
i if i == DeviceType::TcpSocket as u8 => {
|
||||
Device::TcpSocket(TcpSocket::new())
|
||||
Ok(DeviceType::TcpSocket) => {
|
||||
Ok(Device::TcpSocket(TcpSocket::new()))
|
||||
}
|
||||
i if i == DeviceType::UdpSocket as u8 => {
|
||||
Device::UdpSocket(UdpSocket::new())
|
||||
Ok(DeviceType::UdpSocket) => {
|
||||
Ok(Device::UdpSocket(UdpSocket::new()))
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
Ok(DeviceType::Drive) if buf.len() > 2 => {
|
||||
let bus = buf[1];
|
||||
let dsk = buf[2];
|
||||
if let Some(drive) = Drive::open(bus, dsk) {
|
||||
Ok(Device::Drive(drive))
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -115,7 +154,7 @@ impl Device {
|
|||
if dir_entry.is_device() {
|
||||
let block = LinkedBlock::read(dir_entry.addr());
|
||||
let data = block.data();
|
||||
return Some(data[0].into());
|
||||
return data.try_into().ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -137,6 +176,7 @@ impl FileIO for Device {
|
|||
Device::RTC(io) => io.read(buf),
|
||||
Device::TcpSocket(io) => io.read(buf),
|
||||
Device::UdpSocket(io) => io.read(buf),
|
||||
Device::Drive(io) => io.read(buf),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -151,6 +191,7 @@ impl FileIO for Device {
|
|||
Device::RTC(io) => io.write(buf),
|
||||
Device::TcpSocket(io) => io.write(buf),
|
||||
Device::UdpSocket(io) => io.write(buf),
|
||||
Device::Drive(io) => io.write(buf),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -165,6 +206,7 @@ impl FileIO for Device {
|
|||
Device::RTC(io) => io.close(),
|
||||
Device::TcpSocket(io) => io.close(),
|
||||
Device::UdpSocket(io) => io.close(),
|
||||
Device::Drive(io) => io.close(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -179,6 +221,7 @@ impl FileIO for Device {
|
|||
Device::RTC(io) => io.poll(event),
|
||||
Device::TcpSocket(io) => io.poll(event),
|
||||
Device::UdpSocket(io) => io.poll(event),
|
||||
Device::Drive(io) => io.poll(event),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> {
|
|||
Err(ExitCode::Failure)
|
||||
}
|
||||
} else {
|
||||
error!("Could not find file '{}'", source);
|
||||
error!("Could not read file '{}'", source);
|
||||
Err(ExitCode::Failure)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> {
|
|||
Err(ExitCode::Failure)
|
||||
}
|
||||
} else {
|
||||
error!("Could not find file '{}'", pathname);
|
||||
error!("Could not read file '{}'", pathname);
|
||||
Err(ExitCode::Failure)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> {
|
|||
print_hex(&buf);
|
||||
Ok(())
|
||||
} else {
|
||||
error!("Could not find file '{}'", pathname);
|
||||
error!("Could not read file '{}'", pathname);
|
||||
Err(ExitCode::Failure)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,13 @@ pub fn copy_files(verbose: bool) {
|
|||
);
|
||||
copy_file("/bin/sleep", include_bytes!("../../dsk/bin/sleep"), verbose);
|
||||
|
||||
create_dir("/dev/ata", verbose); // Drives
|
||||
create_dir("/dev/ata/0", verbose);
|
||||
create_dev("/dev/ata/0/0", DeviceType::Drive, verbose);
|
||||
create_dev("/dev/ata/0/1", DeviceType::Drive, verbose);
|
||||
create_dir("/dev/ata/1", verbose);
|
||||
create_dev("/dev/ata/1/0", DeviceType::Drive, verbose);
|
||||
create_dev("/dev/ata/1/1", DeviceType::Drive, verbose);
|
||||
create_dir("/dev/clk", verbose); // Clock
|
||||
create_dev("/dev/clk/uptime", DeviceType::Uptime, verbose);
|
||||
create_dev("/dev/clk/realtime", DeviceType::Realtime, verbose);
|
||||
|
@ -336,7 +343,16 @@ fn create_dir(pathname: &str, verbose: bool) {
|
|||
|
||||
fn create_dev(pathname: &str, dev: DeviceType, verbose: bool) {
|
||||
if syscall::info(pathname).is_none() {
|
||||
if let Some(handle) = fs::create_device(pathname, dev) {
|
||||
let mut buf = dev.buf();
|
||||
// NOTE: The first byte of `buf` contains the device type
|
||||
match pathname {
|
||||
"/dev/ata/0/0" => { buf[1] = 0; buf[2] = 0 },
|
||||
"/dev/ata/0/1" => { buf[1] = 0; buf[2] = 1 },
|
||||
"/dev/ata/1/0" => { buf[1] = 1; buf[2] = 0 },
|
||||
"/dev/ata/1/1" => { buf[1] = 1; buf[2] = 1 },
|
||||
_ => {},
|
||||
}
|
||||
if let Some(handle) = fs::create_device(pathname, &buf) {
|
||||
syscall::close(handle);
|
||||
if verbose {
|
||||
println!("Created '{}'", pathname);
|
||||
|
|
|
@ -176,7 +176,7 @@ fn eval_load_args(
|
|||
ensure_length_eq!(args, 1);
|
||||
let path = string(&eval(&args[0], env)?)?;
|
||||
let mut input = fs::read_to_string(&path).
|
||||
or(could_not!("find file '{}'", path))?;
|
||||
or(could_not!("read file '{}'", path))?;
|
||||
loop {
|
||||
let (rest, _) = parse_eval(&input, env)?;
|
||||
if rest.is_empty() {
|
||||
|
|
|
@ -356,7 +356,27 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> {
|
|||
if args[1] == "-h" || args[1] == "--help" {
|
||||
return help();
|
||||
}
|
||||
exec(env, args[1])
|
||||
let path = args[1];
|
||||
if let Ok(mut input) = fs::read_to_string(path) {
|
||||
loop {
|
||||
match parse_eval(&input, env) {
|
||||
Ok((rest, _)) => {
|
||||
if rest.is_empty() {
|
||||
break;
|
||||
}
|
||||
input = rest;
|
||||
}
|
||||
Err(Err::Reason(msg)) => {
|
||||
error!("{}", msg);
|
||||
return Err(ExitCode::Failure);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
error!("Could not read file '{}'", path);
|
||||
Err(ExitCode::Failure)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -85,10 +85,15 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> {
|
|||
} else if info.is_dir() {
|
||||
usr::list::main(args)
|
||||
} else if info.is_device() {
|
||||
// TODO: Improve device file usage
|
||||
let is_char_device = info.size() == 4;
|
||||
let is_float_device = info.size() == 8;
|
||||
let is_eof_device = info.size() > 8;
|
||||
// TODO: Add a way to read the device file to get its type directly
|
||||
// instead of relying on the various device file sizes. We could
|
||||
// maybe allow `sys::fs::file::File::open()` to open a Device file
|
||||
// as a regular file and read the type in the first byte of the
|
||||
// file.
|
||||
let n = info.size();
|
||||
let is_char_device = n == 4;
|
||||
let is_float_device = n == 8;
|
||||
let is_block_device = n > 8;
|
||||
loop {
|
||||
if console::end_of_text() || console::end_of_transmission() {
|
||||
println!();
|
||||
|
@ -117,7 +122,7 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> {
|
|||
for b in bytes {
|
||||
print!("{}", b as char);
|
||||
}
|
||||
if is_eof_device {
|
||||
if is_block_device {
|
||||
println!();
|
||||
return Ok(());
|
||||
}
|
||||
|
|
|
@ -681,7 +681,7 @@ pub fn main(args: &[&str]) -> Result<(), ExitCode> {
|
|||
}
|
||||
Ok(())
|
||||
} else {
|
||||
error!("Could not find file '{}'", path);
|
||||
error!("Could not read file '{}'", path);
|
||||
Err(ExitCode::Failure)
|
||||
}
|
||||
}
|
||||
|
@ -723,7 +723,7 @@ fn test_shell() {
|
|||
// Redirect standard error explicitely
|
||||
exec("hex /nope 2=> /tmp/test3").ok();
|
||||
assert!(api::fs::read_to_string("/tmp/test3").unwrap().
|
||||
contains("Could not find file '/nope'"));
|
||||
contains("Could not read file '/nope'"));
|
||||
|
||||
let mut config = Config::new();
|
||||
exec_with_config("set b 42", &mut config).ok();
|
||||
|
|
Loading…
Reference in New Issue