Skip to content

Commit 24cfd4a

Browse files
block: GPT
* GPT * NVME make use of PRP2 when the content cannot fit in 1 page (4096 bytes) * NVME Completion Queue - make sure to return an error if has had one * EXT2 framework Signed-off-by: Andy-Python-Programmer <andypythonappdeveloper@gmail.com>
1 parent 54513bc commit 24cfd4a

File tree

11 files changed

+492
-227
lines changed

11 files changed

+492
-227
lines changed

src/aero_kernel/src/drivers/block/ide/mod.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
mod channel;
2121
mod registers;
2222

23+
use core::mem::MaybeUninit;
24+
2325
use channel::*;
2426

2527
use alloc::sync::Arc;
@@ -50,14 +52,15 @@ impl IdeDrive {
5052
}
5153

5254
impl BlockDeviceInterface for IdeDrive {
53-
fn read(&self, sector: usize, dest: &mut [u8]) -> Option<usize> {
55+
fn read(&self, sector: usize, dest: &mut [MaybeUninit<u8>]) -> Option<usize> {
5456
let count = dest.len().ceil_div(512);
5557
let request = Arc::new(DmaRequest::new(sector, count));
5658

5759
let res = self.channel.run_request(request.clone(), self.slave);
5860

5961
if res.is_some() {
60-
request.copy_into(dest);
62+
todo!()
63+
// request.copy_into(dest);
6164
}
6265

6366
res

src/aero_kernel/src/drivers/block/nvme/command.rs

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@
1717
* along with Aero. If not, see <https://www.gnu.org/licenses/>.
1818
*/
1919

20-
use bit_field::BitField;
21-
2220
#[repr(u8)]
2321
#[derive(Default, Copy, Clone)]
2422
pub enum IdentifyCns {
@@ -58,7 +56,7 @@ pub enum AdminOpcode {
5856
Unknown = u8::MAX,
5957
}
6058

61-
#[derive(Default, Copy, Clone)]
59+
#[derive(Debug, Default, Copy, Clone)]
6260
#[repr(C)]
6361
pub struct DataPointer {
6462
pub prp1: u64,
@@ -272,7 +270,7 @@ pub struct IdentifyNamespace {
272270
const_assert_eq!(core::mem::size_of::<IdentifyNamespace>(), 0x1000);
273271

274272
#[repr(C)]
275-
#[derive(Default, Copy, Clone)]
273+
#[derive(Debug, Default, Copy, Clone)]
276274
pub struct ReadWriteCommand {
277275
pub opcode: u8,
278276
pub flags: u8,
@@ -343,16 +341,12 @@ impl Into<Command> for CreateCQCommand {
343341
#[derive(Clone, Copy, Debug)]
344342
#[repr(C)]
345343
pub struct CompletionEntry {
346-
dw0: u32,
347-
dw1: u32,
348-
dw2: u32,
349-
dw3: u32,
350-
}
351-
352-
impl CompletionEntry {
353-
pub fn get_phase_tag(&self) -> bool {
354-
self.dw3.get_bit(16)
355-
}
344+
pub result: u32, // Used by admin commands to return data.
345+
pub reserved: u32,
346+
pub sq_head: u16, // Portion of the queue that may be reclaimed
347+
pub sq_id: u16, // Submission Queue that generated this entry.
348+
pub command_id: u16, // Command ID of the command that was completed.
349+
pub status: u16, // Reason why the command failed, if it did.
356350
}
357351

358352
#[repr(C)]

src/aero_kernel/src/drivers/block/nvme/dma.rs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,22 +35,26 @@ pub struct DmaAllocator;
3535
unsafe impl Allocator for DmaAllocator {
3636
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
3737
// XXX: The DMA buffer must be aligned to a page boundary.
38-
let size = align_up(layout.size() as u64, Size2MiB::SIZE);
38+
let size_bytes = layout.size() as u64;
3939

40-
let pages = size / Size2MiB::SIZE;
41-
assert!(pages == 1);
40+
let phys = if size_bytes <= Size4KiB::SIZE {
41+
let frame: PhysFrame<Size4KiB> = FRAME_ALLOCATOR.allocate_frame().ok_or(AllocError)?;
42+
frame.start_address()
43+
} else {
44+
assert!(size_bytes <= Size2MiB::SIZE);
4245

43-
let frame: PhysFrame<Size2MiB> = FRAME_ALLOCATOR.allocate_frame().ok_or(AllocError)?;
44-
let virt = frame.start_address().as_hhdm_virt();
46+
let frame: PhysFrame<Size2MiB> = FRAME_ALLOCATOR.allocate_frame().ok_or(AllocError)?;
47+
frame.start_address()
48+
};
49+
50+
let virt = phys.as_hhdm_virt();
4551

4652
// SAFETY: The frame is aligned and non-null.
4753
let ptr = unsafe { NonNull::new_unchecked(virt.as_mut_ptr() as *mut u8) };
48-
Ok(NonNull::slice_from_raw_parts(ptr, size as _))
54+
Ok(NonNull::slice_from_raw_parts(ptr, size_bytes as _))
4955
}
5056

51-
unsafe fn deallocate(&self, _ptr: NonNull<u8>, _layout: Layout) {
52-
log::warn!("DMA memory deallocation is not *yet* implemented :) Enjoy the leaks :)")
53-
}
57+
unsafe fn deallocate(&self, _ptr: NonNull<u8>, _layout: Layout) {}
5458
}
5559

5660
pub type DmaBuffer<T> = Box<T, DmaAllocator>;

src/aero_kernel/src/drivers/block/nvme/mod.rs

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ mod command;
2121
mod dma;
2222
mod queue;
2323

24+
use core::mem::MaybeUninit;
25+
2426
use command::*;
2527
use dma::*;
2628
use queue::*;
@@ -36,7 +38,7 @@ use crate::fs::block::{install_block_device, BlockDevice, BlockDeviceInterface};
3638
use crate::mem::paging::*;
3739

3840
use crate::utils::sync::Mutex;
39-
use crate::utils::VolatileCell;
41+
use crate::utils::{CeilDiv, VolatileCell};
4042

4143
#[derive(Copy, Clone, Debug)]
4244
enum Error {
@@ -78,7 +80,8 @@ bitflags::bitflags! {
7880
struct Capability(VolatileCell<u64>);
7981

8082
impl Capability {
81-
/// Returns maximum individual queue size that the controller supports.
83+
/// Returns maximum individual queue size that the controller
84+
/// supports.
8285
fn max_queue_entries(&self) -> u16 {
8386
self.0.get().get_bits(0..16) as u16
8487
}
@@ -88,10 +91,17 @@ impl Capability {
8891
self.0.get().get_bits(32..36)
8992
}
9093

91-
/// Returns the command sets that are supported by the controller.
94+
/// Returns the command sets that are supported by the
95+
/// controller.
9296
fn get_css(&self) -> CommandSetsSupported {
9397
CommandSetsSupported::from_bits_truncate(self.0.get().get_bits(37..45) as u8)
9498
}
99+
100+
/// Returns the the minimum host memory page size that the
101+
/// controller supports.
102+
fn mpsmin(&self) -> u64 {
103+
self.0.get().get_bits(48..52)
104+
}
95105
}
96106

97107
#[repr(u32)]
@@ -215,27 +225,48 @@ struct Namespace<'a> {
215225
blocks: usize,
216226
block_size: usize,
217227
size: usize,
228+
max_prps: usize,
229+
prps: Mutex<Dma<[MaybeUninit<u64>]>>,
218230
controller: Arc<Controller<'a>>,
219231
}
220232

221233
impl<'a> Namespace<'a> {
222-
fn read(&self, sector: usize, dest: &mut [u8]) {
223-
let length = ((dest.len() / self.block_size) - 1) as u16;
234+
fn read(&self, sector: usize, dest: &mut [MaybeUninit<u8>]) {
235+
let size_bytes = dest.len();
236+
let blocks = size_bytes.ceil_div(self.block_size);
224237

225238
let buffer = Dma::<u8>::new_uninit_slice(dest.len());
226239
let mut read_cmd = ReadWriteCommand::default();
227240

228241
read_cmd.opcode = CommandOpcode::Read as u8;
229242
read_cmd.nsid = self.nsid;
230243
read_cmd.start_lba = sector as u64;
231-
read_cmd.length = length;
232-
read_cmd.data_ptr.prp1 = buffer.addr().as_u64();
244+
read_cmd.length = (blocks - 1) as u16;
245+
246+
if size_bytes > Size4KiB::SIZE as usize {
247+
// The data cannot fit in 8KiB frames, so we need to use
248+
// a PRP list.
249+
let prp_num = ((blocks - 1) * self.block_size) / Size4KiB::SIZE as usize;
250+
assert!(prp_num < self.max_prps);
251+
252+
let mut prps = self.prps.lock();
253+
254+
for i in 0..prp_num {
255+
prps[i]
256+
.write((buffer.addr().as_u64() + Size4KiB::SIZE) + (Size4KiB::SIZE * i as u64));
257+
}
258+
259+
read_cmd.data_ptr.prp1 = buffer.addr().as_u64();
260+
read_cmd.data_ptr.prp2 = prps.addr().as_u64();
261+
} else {
262+
read_cmd.data_ptr.prp1 = buffer.addr().as_u64();
263+
}
233264

234265
self.controller.io_queue.lock().submit_command(read_cmd);
235266

236267
// SAFETY: The buffer is initialized above.
237268
let buffer = unsafe { buffer.assume_init() };
238-
dest.copy_from_slice(&*buffer);
269+
MaybeUninit::write_slice(dest, &*buffer);
239270
}
240271
}
241272

@@ -356,6 +387,13 @@ impl<'a> Controller<'a> {
356387

357388
admin.submit_command(io_sq_cmd);
358389

390+
let shift = 12 + registers.capability.mpsmin() as usize;
391+
let max_transfer_shift = if identity.mdts != 0 {
392+
shift + identity.mdts as usize
393+
} else {
394+
20
395+
};
396+
359397
let this = Arc::new(Self {
360398
identity,
361399
namespaces: Mutex::new(alloc::vec![]),
@@ -396,12 +434,19 @@ impl<'a> Controller<'a> {
396434
let blocks = identity.nsze as usize;
397435
let block_size = 1 << identity.lbaf[(identity.flbas & 0b11111) as usize].ds;
398436

437+
// The maximum transfer size is in units of 2^(min page size)
438+
let lba_shift = identity.lbaf[(identity.flbas & 0xf) as usize].ds;
439+
let max_lbas = 1 << (max_transfer_shift - lba_shift as usize);
440+
let max_prps = (max_lbas * (1 << lba_shift)) / Size4KiB::SIZE as usize;
441+
399442
Namespace {
400443
controller: this.clone(),
401444
nsid: *nsid,
402445
blocks,
403446
block_size,
404447
size: blocks * block_size,
448+
max_prps,
449+
prps: Mutex::new(Dma::new_uninit_slice(max_prps)),
405450
}
406451
})
407452
.collect::<Vec<_>>();
@@ -423,7 +468,7 @@ impl<'a> Controller<'a> {
423468
}
424469

425470
impl<'a> BlockDeviceInterface for Controller<'a> {
426-
fn read(&self, sector: usize, dest: &mut [u8]) -> Option<usize> {
471+
fn read(&self, sector: usize, dest: &mut [MaybeUninit<u8>]) -> Option<usize> {
427472
self.namespaces.lock()[0].read(sector, dest);
428473
Some(dest.len())
429474
}

src/aero_kernel/src/drivers/block/nvme/queue.rs

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use core::mem::MaybeUninit;
1+
use core::cell::UnsafeCell;
22
use core::sync::atomic::{AtomicU16, Ordering};
33

44
use crate::mem::paging::PhysAddr;
@@ -38,7 +38,7 @@ unsafe impl Sync for DoorBell {}
3838
pub(super) struct Queue<'bell, T: QueueType> {
3939
doorbell: &'bell DoorBell,
4040
index: usize,
41-
queue: Dma<[MaybeUninit<T::Type>]>,
41+
queue: Dma<[UnsafeCell<T::Type>]>,
4242
phase: bool,
4343
}
4444

@@ -53,7 +53,7 @@ impl<'bell, T: QueueType> Queue<'bell, T> {
5353

5454
Ok(Self {
5555
doorbell,
56-
queue: Dma::new_uninit_slice(size),
56+
queue: unsafe { Dma::new_uninit_slice(size).assume_init() },
5757
index: 0,
5858
phase: true,
5959
})
@@ -66,20 +66,30 @@ impl<'bell, T: QueueType> Queue<'bell, T> {
6666

6767
impl Queue<'_, Completion> {
6868
pub fn next_cmd_result(&mut self) -> Option<CompletionEntry> {
69-
let cur_completion = unsafe { self.queue[self.index].assume_init() };
70-
if cur_completion.get_phase_tag() != self.phase {
71-
self.index += 1;
72-
self.doorbell.0.set(self.index as u32);
73-
Some(cur_completion.clone())
74-
} else {
75-
None
69+
let cmd = &mut self.queue[self.index];
70+
71+
while (cmd.get_mut().status & 0x1) != self.phase as u16 {
72+
core::hint::spin_loop();
73+
}
74+
75+
let cmd = cmd.get_mut();
76+
let status = cmd.status >> 1;
77+
78+
if status != 0 {
79+
log::error!("nvme: command error {status:#x}");
80+
return None;
7681
}
82+
83+
self.index += 1;
84+
self.doorbell.0.set(self.index as u32);
85+
86+
Some(cmd.clone())
7787
}
7888
}
7989

8090
impl Queue<'_, Submisson> {
8191
pub fn submit_command(&mut self, command: Command) {
82-
self.queue[self.index] = MaybeUninit::new(command);
92+
self.queue[self.index] = UnsafeCell::new(command);
8393

8494
self.index += 1;
8595
self.doorbell.0.set(self.index as u32); // ring ring!

0 commit comments

Comments
 (0)