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
128
129
130
131
132
133
134
135
136
137
|
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()
}
static PART_TYPES: Mutex<Vec<(String, &'static str)>> = Mutex::new(Vec::new());
pub fn partition_type(name: &str) -> Option<&'static str> {
PART_TYPES.lock().iter().find(|(n, _)| n == name).map(|(_, t)| *t)
}
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)));
PART_TYPES.lock().push((pname, p.type_name));
}
}
Err(e) => log.push(format!("{}: no partition table ({:?})", name, e)),
}
}
Err(e) => log.push(format!("{}: virtio-blk init failed: {:?}", name, e)),
}
letter += 1;
}
log
}
|