1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
pub mod partition;
pub mod virtio_blk;
use crate::errno::Errno;
use alloc::{string::String, sync::Arc, vec, vec::Vec};
use spin::Mutex;
pub const SECTOR_SIZE: usize = 512;
pub trait BlockDevice: Send + Sync {
fn sector_count(&self) -> u64;
fn read_sectors(&self, lba: u64, buf: &mut [u8]) -> Result<(), Errno>;
fn write_sectors(&self, lba: u64, buf: &[u8]) -> Result<(), Errno>;
}
pub fn check_range(dev: &dyn BlockDevice, lba: u64, len: usize) -> Result<u64, Errno> {
if len % SECTOR_SIZE != 0 {
return Err(Errno::EINVAL);
}
let count = (len / SECTOR_SIZE) as u64;
match lba.checked_add(count) {
Some(end) if end <= dev.sector_count() => Ok(count),
_ => Err(Errno::EIO), }
}
pub struct RamDisk {
data: Mutex<Vec<u8>>,
}
impl RamDisk {
pub fn new(sectors: usize) -> Self {
RamDisk { data: Mutex::new(vec![0; sectors * SECTOR_SIZE]) }
}
}
impl BlockDevice for RamDisk {
fn sector_count(&self) -> u64 {
(self.data.lock().len() / SECTOR_SIZE) as u64
}
fn read_sectors(&self, lba: u64, buf: &mut [u8]) -> Result<(), Errno> {
check_range(self, lba, buf.len())?;
let start = lba as usize * SECTOR_SIZE;
buf.copy_from_slice(&self.data.lock()[start..start + buf.len()]);
Ok(())
}
fn write_sectors(&self, lba: u64, buf: &[u8]) -> Result<(), Errno> {
check_range(self, lba, buf.len())?;
let start = lba as usize * SECTOR_SIZE;
self.data.lock()[start..start + buf.len()].copy_from_slice(buf);
Ok(())
}
}
static DEVICES: Mutex<Vec<(String, Arc<dyn BlockDevice>)>> = Mutex::new(Vec::new());
pub fn register(name: &str, dev: Arc<dyn BlockDevice>) {
DEVICES.lock().push((String::from(name), dev));
}
pub fn devices() -> Vec<(String, Arc<dyn BlockDevice>)> {
DEVICES.lock().clone()
}
pub fn get(name: &str) -> Option<Arc<dyn BlockDevice>> {
DEVICES.lock().iter().find(|(n, _)| n == name).map(|(_, d)| d.clone())
}
pub fn init(pci_devices: &[crate::pci::PciDevice]) -> Vec<String> {
use alloc::format;
let mut log = Vec::new();
let mut letter = b'a';
for pci in pci_devices.iter().filter(|d| virtio_blk::is_virtio_blk(d)) {
let name = format!("vd{}", letter as char);
match virtio_blk::VirtioBlk::new(pci) {
Ok(disk) => {
let disk: Arc<dyn BlockDevice> = Arc::new(disk);
log.push(format!(
"{}: virtio-blk, {} sectors ({} MiB)",
name,
disk.sector_count(),
disk.sector_count() * SECTOR_SIZE as u64 / (1024 * 1024)
));
register(&name, disk.clone());
match partition::scan(&disk) {
Ok((scheme, parts)) => {
log.push(format!("{}: {} partition table, {} partition(s)", name, scheme, parts.len()));
for (i, p) in parts.into_iter().enumerate() {
let pname = format!("{}{}", name, i + 1);
log.push(format!(
"{}: start {} sectors {} type {}{}",
pname, p.start, p.sectors, p.type_name,
if p.name.is_empty() { String::new() } else { format!(" name \"{}\"", p.name) }
));
register(&pname, Arc::new(partition::Partition::new(disk.clone(), p.start, p.sectors)));
}
}
Err(e) => log.push(format!("{}: no partition table ({:?})", name, e)),
}
}
Err(e) => log.push(format!("{}: virtio-blk init failed: {:?}", name, e)),
}
letter += 1;
}
log
}
|