Skip to content

Commit aa1a4ba

Browse files
committed
device/block: Add ramdisk device
1 parent c529caa commit aa1a4ba

4 files changed

Lines changed: 115 additions & 4 deletions

File tree

kernel/src/device/block/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
pub mod gpt;
22
pub mod io;
33
pub mod partition;
4+
pub mod ram;
45

56
use crate::device::Device;
67
use crate::{

kernel/src/device/block/ram.rs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
//! A block device backed entirely by a region of physical memory.
2+
3+
use super::{BlockCompletion, BlockDevice, BlockIo, BlockOp};
4+
use crate::{
5+
device::Device,
6+
memory::PhysAddr,
7+
posix::errno::{EResult, Errno},
8+
vfs::file::{FileOps, OpenFlags},
9+
};
10+
use alloc::sync::Arc;
11+
use core::sync::atomic::{AtomicU32, Ordering};
12+
13+
const RAM_MAJOR: u32 = 1;
14+
const LBA_SIZE: usize = 512;
15+
16+
static NEXT_MINOR: AtomicU32 = AtomicU32::new(0);
17+
18+
pub struct RamDisk {
19+
base: PhysAddr,
20+
lba_count: u64,
21+
minor: u32,
22+
}
23+
24+
impl RamDisk {
25+
/// Creates a RAM disk over `len` bytes of physical memory starting at `base`.
26+
/// Any trailing bytes that don't make up a whole sector are ignored.
27+
pub fn new(base: PhysAddr, len: usize) -> Self {
28+
Self {
29+
base,
30+
lba_count: (len / LBA_SIZE) as u64,
31+
minor: NEXT_MINOR.fetch_add(1, Ordering::Relaxed),
32+
}
33+
}
34+
}
35+
36+
impl BlockDevice for RamDisk {
37+
fn get_lba_size(&self) -> usize {
38+
LBA_SIZE
39+
}
40+
41+
fn lba_count(&self) -> u64 {
42+
self.lba_count
43+
}
44+
45+
fn submit_io(&self, io: &mut BlockIo) -> EResult<BlockCompletion> {
46+
let Some(end_lba) = io.lba().checked_add(io.num_lbas() as u64) else {
47+
return Err(Errno::EOVERFLOW);
48+
};
49+
50+
if end_lba > self.lba_count {
51+
return match io.op() {
52+
BlockOp::Read => Ok(BlockCompletion { lbas: 0 }),
53+
BlockOp::Write => Err(Errno::ENOSPC),
54+
};
55+
}
56+
57+
let bytes = io.num_lbas() * LBA_SIZE;
58+
let segment = io.first_segment();
59+
60+
let store = (self.base + io.lba() as usize * LBA_SIZE).as_hhdm::<u8>();
61+
let buffer = segment.phys().as_hhdm::<u8>();
62+
63+
// The backing store and the I/O buffer never overlap.
64+
unsafe {
65+
match io.op() {
66+
BlockOp::Read => core::ptr::copy_nonoverlapping(store, buffer, bytes),
67+
BlockOp::Write => core::ptr::copy_nonoverlapping(buffer, store, bytes),
68+
}
69+
}
70+
71+
Ok(BlockCompletion {
72+
lbas: io.num_lbas(),
73+
})
74+
}
75+
}
76+
77+
impl Device for RamDisk {
78+
fn open(self: Arc<Self>, _flags: OpenFlags) -> EResult<Arc<dyn FileOps>> {
79+
Ok(self.clone())
80+
}
81+
82+
fn major(&self) -> u32 {
83+
RAM_MAJOR
84+
}
85+
86+
fn minor(&self) -> u32 {
87+
self.minor
88+
}
89+
}

kernel/src/lib.rs

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ pub mod util;
5454
pub mod vfs;
5555

5656
use crate::{
57+
device::block::ram::RamDisk,
5758
irq::lock::IrqLock,
5859
percpu::CpuData,
5960
process::{Identity, Process},
@@ -94,11 +95,27 @@ pub extern "C" fn main(_: usize, _: usize) {
9495
{
9596
let kernel_proc = Process::get_kernel();
9697
let root_dir = kernel_proc.root_dir.lock().clone();
98+
let mut ramdisk_index = 0;
99+
97100
for file in BootInfo::get().files {
98-
initramfs::load(root_dir.clone(), root_dir.clone(), unsafe {
99-
core::slice::from_raw_parts(file.data.as_hhdm(), file.length)
100-
})
101-
.expect("Failed to load one of the provided initramfs archives");
101+
let data =
102+
unsafe { core::slice::from_raw_parts(file.data.as_hhdm::<u8>(), file.length) };
103+
104+
if initramfs::is_initramfs(data) {
105+
initramfs::load(root_dir.clone(), root_dir.clone(), data)
106+
.expect("Failed to load one of the provided initramfs archives");
107+
} else {
108+
let name = format!("ram{ramdisk_index}");
109+
let disk = Arc::new(RamDisk::new(file.data, file.length));
110+
device::block::register_block_device(&name, disk)
111+
.expect("Failed to register RAM disk block device");
112+
log!(
113+
"Exposed module \"{}\" as RAM disk /dev/block/{}",
114+
file.name,
115+
name
116+
);
117+
ramdisk_index += 1;
118+
}
102119
}
103120
}
104121

kernel/src/vfs/fs/initramfs.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,10 @@ pub fn create_dirs(
105105
return Ok((current, file_name));
106106
}
107107

108+
pub fn is_initramfs(data: &[u8]) -> bool {
109+
data.len() >= size_of::<FileHeader>() && &data[257..262] == b"ustar"
110+
}
111+
108112
pub fn load(root: PathNode, target: PathNode, data: &[u8]) -> EResult<()> {
109113
let mut offset = 0;
110114
let mut name_override = None;

0 commit comments

Comments
 (0)