mem: implement PageBox<T>
This commit is contained in:
parent
4d23cc5c74
commit
6aa18a1fa2
@ -7,3 +7,4 @@ edition = "2021"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
yggdrasil-abi = { git = "https://git.alnyan.me/yggdrasil/yggdrasil-abi.git" }
|
yggdrasil-abi = { git = "https://git.alnyan.me/yggdrasil/yggdrasil-abi.git" }
|
||||||
|
log = "0.4.20"
|
||||||
|
@ -6,9 +6,10 @@ extern "Rust" {
|
|||||||
pub fn __acquire_irq_guard() -> bool;
|
pub fn __acquire_irq_guard() -> bool;
|
||||||
pub fn __release_irq_guard(mask: bool);
|
pub fn __release_irq_guard(mask: bool);
|
||||||
|
|
||||||
pub fn __allocate_2m_page() -> u64;
|
pub fn __allocate_2m_page() -> Result<PhysicalAddress, Error>;
|
||||||
pub fn __allocate_page() -> u64;
|
pub fn __allocate_page() -> Result<PhysicalAddress, Error>;
|
||||||
pub fn __free_page(page: u64);
|
pub fn __allocate_contiguous_pages(count: usize) -> Result<PhysicalAddress, Error>;
|
||||||
|
pub fn __free_page(page: PhysicalAddress);
|
||||||
|
|
||||||
pub fn __virtualize(phys: u64) -> usize;
|
pub fn __virtualize(phys: u64) -> usize;
|
||||||
pub fn __physicalize(virt: usize) -> u64;
|
pub fn __physicalize(virt: usize) -> u64;
|
||||||
|
@ -1,5 +1,12 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![feature(maybe_uninit_slice, step_trait, const_trait_impl, effects)]
|
#![feature(
|
||||||
|
maybe_uninit_slice,
|
||||||
|
step_trait,
|
||||||
|
const_trait_impl,
|
||||||
|
effects,
|
||||||
|
slice_ptr_get,
|
||||||
|
strict_provenance
|
||||||
|
)]
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
|
@ -1,3 +1,221 @@
|
|||||||
|
use core::{
|
||||||
|
alloc::Layout,
|
||||||
|
fmt,
|
||||||
|
mem::{size_of, MaybeUninit},
|
||||||
|
ops::{Deref, DerefMut},
|
||||||
|
};
|
||||||
|
|
||||||
|
use yggdrasil_abi::error::Error;
|
||||||
|
|
||||||
|
use crate::api::{__allocate_contiguous_pages, __free_page, __physicalize};
|
||||||
|
|
||||||
|
use self::address::{AsPhysicalAddress, PhysicalAddress};
|
||||||
|
|
||||||
pub mod address;
|
pub mod address;
|
||||||
pub mod device;
|
pub mod device;
|
||||||
|
pub mod pointer;
|
||||||
pub mod table;
|
pub mod table;
|
||||||
|
|
||||||
|
pub struct PageBox<T: ?Sized> {
|
||||||
|
value: *mut T,
|
||||||
|
page_count: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> PageBox<T> {
|
||||||
|
#[inline]
|
||||||
|
fn alloc_slice(count: usize) -> Result<(PhysicalAddress, usize), Error> {
|
||||||
|
// TODO hardcoded page sizes
|
||||||
|
let layout = Layout::array::<T>(count).unwrap();
|
||||||
|
let page_count = (layout.size() + 0xFFF) / 0x1000;
|
||||||
|
Ok((
|
||||||
|
unsafe { __allocate_contiguous_pages(page_count) }?,
|
||||||
|
page_count,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn alloc() -> Result<(PhysicalAddress, usize), Error> {
|
||||||
|
let page_count = (size_of::<T>() + 0xFFF) / 0x1000;
|
||||||
|
Ok((
|
||||||
|
unsafe { __allocate_contiguous_pages(page_count) }?,
|
||||||
|
page_count,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(init: T) -> Result<PageBox<T>, Error> {
|
||||||
|
let (base, page_count) = Self::alloc()?;
|
||||||
|
let value = base.virtualize_raw() as *mut T;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
value.write(init);
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = PageBox { value, page_count };
|
||||||
|
result.trace_created();
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_slice(item: T, count: usize) -> Result<PageBox<[T]>, Error>
|
||||||
|
where
|
||||||
|
T: Copy,
|
||||||
|
{
|
||||||
|
let (base, page_count) = Self::alloc_slice(count)?;
|
||||||
|
let base_virt_ptr = base.virtualize_raw() as *mut T;
|
||||||
|
let value = core::ptr::slice_from_raw_parts_mut(base_virt_ptr, count);
|
||||||
|
|
||||||
|
for i in 0..count {
|
||||||
|
unsafe {
|
||||||
|
value.get_unchecked_mut(i).write(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = PageBox { value, page_count };
|
||||||
|
result.trace_created();
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_uninit() -> Result<PageBox<MaybeUninit<T>>, Error> {
|
||||||
|
let (base, page_count) = PageBox::<MaybeUninit<T>>::alloc()?;
|
||||||
|
let value = base.virtualize_raw() as *mut MaybeUninit<T>;
|
||||||
|
let result = PageBox { value, page_count };
|
||||||
|
result.trace_created();
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_uninit_slice(count: usize) -> Result<PageBox<[MaybeUninit<T>]>, Error> {
|
||||||
|
let (base, page_count) = PageBox::<MaybeUninit<T>>::alloc_slice(count)?;
|
||||||
|
let base_virt_ptr = base.virtualize_raw() as *mut MaybeUninit<T>;
|
||||||
|
let value = core::ptr::slice_from_raw_parts_mut(base_virt_ptr, count);
|
||||||
|
let result = PageBox { value, page_count };
|
||||||
|
result.trace_created();
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized> PageBox<T> {
|
||||||
|
#[inline]
|
||||||
|
pub fn as_ptr(&self) -> *const T {
|
||||||
|
self.value as _
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn trace_created(&self) {
|
||||||
|
log::trace!(
|
||||||
|
"Alloc PageBox<{}> @ {:p}, {}",
|
||||||
|
core::any::type_name::<T>(),
|
||||||
|
self.value,
|
||||||
|
self.page_count
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn trace_dropped(&self) {
|
||||||
|
log::trace!(
|
||||||
|
"Free PageBox<{}> @ {:p}, {}",
|
||||||
|
core::any::type_name::<T>(),
|
||||||
|
self.value,
|
||||||
|
self.page_count
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> PageBox<MaybeUninit<T>> {
|
||||||
|
pub unsafe fn assume_init(self) -> PageBox<T> {
|
||||||
|
// SAFETY: Memory-safe, as:
|
||||||
|
// 1. MaybeUninit<T> is transparent
|
||||||
|
// 2. self.value still points to the same memory and is not deallocated
|
||||||
|
let page_count = self.page_count;
|
||||||
|
let value = MaybeUninit::assume_init_mut(&mut *self.value);
|
||||||
|
|
||||||
|
// Prevent deallocation of the PageBox with MaybeUninit
|
||||||
|
core::mem::forget(self);
|
||||||
|
|
||||||
|
PageBox { value, page_count }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> PageBox<[MaybeUninit<T>]> {
|
||||||
|
pub unsafe fn assume_init_slice(self) -> PageBox<[T]> {
|
||||||
|
// SAFETY: Memory-safe, as:
|
||||||
|
// 1. MaybeUninit<T> is transparent
|
||||||
|
// 2. self.value still points to the same memory and is not deallocated
|
||||||
|
let page_count = self.page_count;
|
||||||
|
let value = MaybeUninit::slice_assume_init_mut(&mut *self.value);
|
||||||
|
|
||||||
|
core::mem::forget(self);
|
||||||
|
|
||||||
|
PageBox { value, page_count }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn assume_init_slice_ref(&self) -> &[T] {
|
||||||
|
MaybeUninit::slice_assume_init_ref(self.deref())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn assume_init_slice_mut(&mut self) -> &mut [T] {
|
||||||
|
MaybeUninit::slice_assume_init_mut(self.deref_mut())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized> AsPhysicalAddress for PageBox<T> {
|
||||||
|
#[inline]
|
||||||
|
unsafe fn as_physical_address(&self) -> PhysicalAddress {
|
||||||
|
PhysicalAddress(__physicalize(self.value.addr()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized> Deref for PageBox<T> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
unsafe { &*self.value }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized> DerefMut for PageBox<T> {
|
||||||
|
#[inline(always)]
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
unsafe { &mut *self.value }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized> Drop for PageBox<T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.trace_dropped();
|
||||||
|
unsafe {
|
||||||
|
core::ptr::drop_in_place(self.value);
|
||||||
|
}
|
||||||
|
// SAFETY: Safe, pointer obtained through "virtualize"
|
||||||
|
let base = PhysicalAddress(unsafe { __physicalize(self.value.addr()) });
|
||||||
|
for i in 0..self.page_count {
|
||||||
|
// SAFETY: Safe, page allocated only by this PageBox
|
||||||
|
unsafe {
|
||||||
|
__free_page(base.add(0x1000 * i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized> fmt::Pointer for PageBox<T> {
|
||||||
|
#[inline]
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
self.value.fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized + fmt::Debug> fmt::Debug for PageBox<T> {
|
||||||
|
#[inline]
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
fmt::Debug::fmt(self.deref(), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized + fmt::Display> fmt::Display for PageBox<T> {
|
||||||
|
#[inline]
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
fmt::Display::fmt(self.deref(), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<T: ?Sized + Send> Send for PageBox<T> {}
|
||||||
|
unsafe impl<T: ?Sized + Sync> Sync for PageBox<T> {}
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
//! Pointer utilities and interfaces
|
|
||||||
|
|
||||||
use core::{
|
use core::{
|
||||||
fmt,
|
fmt,
|
||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
};
|
};
|
||||||
|
|
||||||
use kernel_util::mem::address::{AsPhysicalAddress, PhysicalAddress};
|
use super::address::{AsPhysicalAddress, PhysicalAddress};
|
||||||
|
|
||||||
/// Wrapper for immutably accessing a value at a physical address
|
/// Wrapper for immutably accessing a value at a physical address
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
@ -3,13 +3,7 @@
|
|||||||
#![cfg_attr(not(test), no_std)]
|
#![cfg_attr(not(test), no_std)]
|
||||||
#![allow(clippy::new_ret_no_self)]
|
#![allow(clippy::new_ret_no_self)]
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
#![feature(
|
#![feature(if_let_guard, maybe_uninit_slice, trait_alias, let_chains)]
|
||||||
trait_upcasting,
|
|
||||||
if_let_guard,
|
|
||||||
maybe_uninit_slice,
|
|
||||||
trait_alias,
|
|
||||||
let_chains
|
|
||||||
)]
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
extern crate hosted_tests;
|
extern crate hosted_tests;
|
||||||
|
@ -16,7 +16,10 @@ use device_api::{
|
|||||||
Device,
|
Device,
|
||||||
};
|
};
|
||||||
use kernel_util::{
|
use kernel_util::{
|
||||||
mem::address::{FromRaw, PhysicalAddress},
|
mem::{
|
||||||
|
address::{FromRaw, PhysicalAddress},
|
||||||
|
pointer::PhysicalRef,
|
||||||
|
},
|
||||||
sync::IrqSafeSpinlock,
|
sync::IrqSafeSpinlock,
|
||||||
util::OneTimeInit,
|
util::OneTimeInit,
|
||||||
};
|
};
|
||||||
@ -27,7 +30,7 @@ use crate::{
|
|||||||
x86_64::{smp::CPU_COUNT, IrqNumber, SHUTDOWN_FENCE},
|
x86_64::{smp::CPU_COUNT, IrqNumber, SHUTDOWN_FENCE},
|
||||||
Architecture, CpuMessage, ARCHITECTURE,
|
Architecture, CpuMessage, ARCHITECTURE,
|
||||||
},
|
},
|
||||||
mem::{heap::GLOBAL_HEAP, pointer::PhysicalRef, read_memory, write_memory},
|
mem::{heap::GLOBAL_HEAP, read_memory, write_memory},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::intrinsics;
|
use super::intrinsics;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
//! x86-64-specific process address space management functions
|
//! x86-64-specific process address space management functions
|
||||||
use kernel_util::mem::{
|
use kernel_util::mem::{
|
||||||
address::{AsPhysicalAddress, IntoRaw, PhysicalAddress},
|
address::{AsPhysicalAddress, IntoRaw, PhysicalAddress},
|
||||||
|
pointer::PhysicalRefMut,
|
||||||
table::EntryLevelExt,
|
table::EntryLevelExt,
|
||||||
};
|
};
|
||||||
use yggdrasil_abi::error::Error;
|
use yggdrasil_abi::error::Error;
|
||||||
@ -9,7 +10,6 @@ use crate::{
|
|||||||
arch::x86_64::intrinsics,
|
arch::x86_64::intrinsics,
|
||||||
mem::{
|
mem::{
|
||||||
phys,
|
phys,
|
||||||
pointer::PhysicalRefMut,
|
|
||||||
process::ProcessAddressSpaceManager,
|
process::ProcessAddressSpaceManager,
|
||||||
table::{EntryLevel, MapAttributes, NextPageTable},
|
table::{EntryLevel, MapAttributes, NextPageTable},
|
||||||
},
|
},
|
||||||
|
@ -6,11 +6,13 @@ use core::{
|
|||||||
|
|
||||||
use abi::error::Error;
|
use abi::error::Error;
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use kernel_util::mem::address::{AsPhysicalAddress, FromRaw, PhysicalAddress};
|
use kernel_util::mem::{
|
||||||
|
address::{AsPhysicalAddress, FromRaw, PhysicalAddress},
|
||||||
|
pointer::{PhysicalRef, PhysicalRefMut},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::mem::{
|
use crate::mem::{
|
||||||
phys,
|
phys,
|
||||||
pointer::{PhysicalRef, PhysicalRefMut},
|
|
||||||
table::{EntryLevel, MapAttributes, NextPageTable, NonTerminalEntryLevel},
|
table::{EntryLevel, MapAttributes, NextPageTable, NonTerminalEntryLevel},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2,7 +2,10 @@
|
|||||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
use core::sync::atomic::{AtomicUsize, Ordering};
|
||||||
|
|
||||||
use acpi_lib::platform::{ProcessorInfo, ProcessorState};
|
use acpi_lib::platform::{ProcessorInfo, ProcessorState};
|
||||||
use kernel_util::mem::address::{AsPhysicalAddress, FromRaw, IntoRaw, PhysicalAddress};
|
use kernel_util::mem::{
|
||||||
|
address::{AsPhysicalAddress, FromRaw, IntoRaw, PhysicalAddress},
|
||||||
|
pointer::PhysicalRefMut,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::{
|
arch::{
|
||||||
@ -16,7 +19,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
Architecture, ArchitectureImpl,
|
Architecture, ArchitectureImpl,
|
||||||
},
|
},
|
||||||
mem::{phys, pointer::PhysicalRefMut},
|
mem::phys,
|
||||||
task::Cpu,
|
task::Cpu,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ impl NvmeDrive {
|
|||||||
nsid: u32,
|
nsid: u32,
|
||||||
) -> Result<&'static NvmeDrive, NvmeError> {
|
) -> Result<&'static NvmeDrive, NvmeError> {
|
||||||
let admin_q = controller.admin_q.get();
|
let admin_q = controller.admin_q.get();
|
||||||
let identify = admin_q.request(IdentifyNamespaceRequest { nsid })?.await?;
|
let identify = admin_q.request(IdentifyNamespaceRequest { nsid }).await?;
|
||||||
|
|
||||||
let current_lba_format_idx = identify.current_lba_fmt_idx();
|
let current_lba_format_idx = identify.current_lba_fmt_idx();
|
||||||
let current_lba_format = identify.lba_fmt(current_lba_format_idx).unwrap();
|
let current_lba_format = identify.lba_fmt(current_lba_format_idx).unwrap();
|
||||||
@ -49,23 +49,6 @@ impl NvmeDrive {
|
|||||||
|
|
||||||
Ok(dev)
|
Ok(dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO proper interface for reading/writing blocks
|
|
||||||
// pub async fn read_block(
|
|
||||||
// &self,
|
|
||||||
// lba: u64,
|
|
||||||
// block: &mut PhysicalRefMut<'_, [u8]>,
|
|
||||||
// ) -> Result<(), NvmeError> {
|
|
||||||
// self.controller.read_block(self.nsid, lba, block).await
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pub async fn write_block(
|
|
||||||
// &self,
|
|
||||||
// lba: u64,
|
|
||||||
// block: &PhysicalRefMut<'_, [u8]>,
|
|
||||||
// ) -> Result<(), NvmeError> {
|
|
||||||
// self.controller.write_block(self.nsid, lba, block).await
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BlockDevice for NvmeDrive {
|
impl BlockDevice for NvmeDrive {
|
||||||
|
@ -6,7 +6,7 @@ use alloc::{collections::BTreeMap, vec::Vec};
|
|||||||
use device_api::{interrupt::MsiHandler, Device};
|
use device_api::{interrupt::MsiHandler, Device};
|
||||||
use kernel_util::{
|
use kernel_util::{
|
||||||
mem::{
|
mem::{
|
||||||
address::{AsPhysicalAddress, FromRaw, IntoRaw, PhysicalAddress},
|
address::{FromRaw, IntoRaw, PhysicalAddress},
|
||||||
device::{DeviceMemoryIo, DeviceMemoryIoMut},
|
device::{DeviceMemoryIo, DeviceMemoryIoMut},
|
||||||
},
|
},
|
||||||
sync::IrqSafeSpinlock,
|
sync::IrqSafeSpinlock,
|
||||||
@ -32,7 +32,6 @@ use crate::{
|
|||||||
queue::{CompletionQueueEntry, SubmissionQueueEntry},
|
queue::{CompletionQueueEntry, SubmissionQueueEntry},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mem::pointer::PhysicalRefMut,
|
|
||||||
task::runtime,
|
task::runtime,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -117,8 +116,8 @@ register_structs! {
|
|||||||
|
|
||||||
pub struct NvmeController {
|
pub struct NvmeController {
|
||||||
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
|
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
|
||||||
admin_q: OneTimeInit<QueuePair<'static>>,
|
admin_q: OneTimeInit<QueuePair>,
|
||||||
ioqs: OneTimeInit<Vec<QueuePair<'static>>>,
|
ioqs: OneTimeInit<Vec<QueuePair>>,
|
||||||
vector_table: IrqSafeSpinlock<DeviceMemoryIoMut<'static, [MsiXEntry]>>,
|
vector_table: IrqSafeSpinlock<DeviceMemoryIoMut<'static, [MsiXEntry]>>,
|
||||||
drive_table: IrqSafeSpinlock<BTreeMap<u32, &'static NvmeDrive>>,
|
drive_table: IrqSafeSpinlock<BTreeMap<u32, &'static NvmeDrive>>,
|
||||||
controller_id: OneTimeInit<usize>,
|
controller_id: OneTimeInit<usize>,
|
||||||
@ -126,6 +125,12 @@ pub struct NvmeController {
|
|||||||
doorbell_shift: usize,
|
doorbell_shift: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
|
pub enum IoDirection {
|
||||||
|
Read,
|
||||||
|
Write,
|
||||||
|
}
|
||||||
|
|
||||||
impl Regs {
|
impl Regs {
|
||||||
unsafe fn doorbell_ptr(&self, shift: usize, completion: bool, queue_index: usize) -> *mut u32 {
|
unsafe fn doorbell_ptr(&self, shift: usize, completion: bool, queue_index: usize) -> *mut u32 {
|
||||||
let doorbell_base = (self as *const Regs as *mut Regs).addr() + 0x1000;
|
let doorbell_base = (self as *const Regs as *mut Regs).addr() + 0x1000;
|
||||||
@ -141,7 +146,7 @@ impl NvmeController {
|
|||||||
let admin_q = self.admin_q.get();
|
let admin_q = self.admin_q.get();
|
||||||
|
|
||||||
// Identify the controller
|
// Identify the controller
|
||||||
let _identify = admin_q.request(IdentifyControllerRequest)?.await?;
|
let _identify = admin_q.request(IdentifyControllerRequest).await?;
|
||||||
|
|
||||||
// TODO do something with identify_controller
|
// TODO do something with identify_controller
|
||||||
|
|
||||||
@ -185,7 +190,7 @@ impl NvmeController {
|
|||||||
let admin_q = self.admin_q.get();
|
let admin_q = self.admin_q.get();
|
||||||
|
|
||||||
let namespaces = admin_q
|
let namespaces = admin_q
|
||||||
.request(IdentifyActiveNamespaceIdListRequest { start_id: 0 })?
|
.request(IdentifyActiveNamespaceIdListRequest { start_id: 0 })
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let count = namespaces.entries.iter().position(|&x| x == 0).unwrap();
|
let count = namespaces.entries.iter().position(|&x| x == 0).unwrap();
|
||||||
@ -205,17 +210,19 @@ impl NvmeController {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn read_block(
|
// TODO sane methods for IO
|
||||||
|
pub async fn perform_io(
|
||||||
&'static self,
|
&'static self,
|
||||||
nsid: u32,
|
nsid: u32,
|
||||||
lba: u64,
|
lba: u64,
|
||||||
buffer: &mut PhysicalRefMut<'_, [u8]>,
|
buffer_address: PhysicalAddress,
|
||||||
|
direction: IoDirection,
|
||||||
) -> Result<(), NvmeError> {
|
) -> Result<(), NvmeError> {
|
||||||
let ioq = &self.ioqs.get()[0];
|
let ioq = &self.ioqs.get()[0];
|
||||||
let buffer_address = unsafe { buffer.as_physical_address() };
|
|
||||||
|
|
||||||
debugln!("read nsid={}, lba={:#x}", nsid, lba);
|
debugln!("{:?} nsid={}, lba={:#x}", direction, nsid, lba);
|
||||||
let cmd_id = ioq.submit(
|
let cmd_id = match direction {
|
||||||
|
IoDirection::Read => ioq.submit(
|
||||||
IoRead {
|
IoRead {
|
||||||
nsid,
|
nsid,
|
||||||
lba,
|
lba,
|
||||||
@ -223,24 +230,8 @@ impl NvmeController {
|
|||||||
},
|
},
|
||||||
&[buffer_address],
|
&[buffer_address],
|
||||||
true,
|
true,
|
||||||
);
|
),
|
||||||
|
IoDirection::Write => ioq.submit(
|
||||||
ioq.wait_for_completion(cmd_id, ()).await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn write_block(
|
|
||||||
&'static self,
|
|
||||||
nsid: u32,
|
|
||||||
lba: u64,
|
|
||||||
buffer: &PhysicalRefMut<'_, [u8]>,
|
|
||||||
) -> Result<(), NvmeError> {
|
|
||||||
let ioq = &self.ioqs.get()[0];
|
|
||||||
let buffer_address = unsafe { buffer.as_physical_address() };
|
|
||||||
|
|
||||||
debugln!("write nsid={}, lba={:#x}", nsid, lba);
|
|
||||||
let cmd_id = ioq.submit(
|
|
||||||
IoWrite {
|
IoWrite {
|
||||||
nsid,
|
nsid,
|
||||||
lba,
|
lba,
|
||||||
@ -248,7 +239,8 @@ impl NvmeController {
|
|||||||
},
|
},
|
||||||
&[buffer_address],
|
&[buffer_address],
|
||||||
true,
|
true,
|
||||||
);
|
),
|
||||||
|
};
|
||||||
|
|
||||||
ioq.wait_for_completion(cmd_id, ()).await?;
|
ioq.wait_for_completion(cmd_id, ()).await?;
|
||||||
|
|
||||||
|
@ -14,18 +14,14 @@ use bytemuck::{Pod, Zeroable};
|
|||||||
use futures_util::Future;
|
use futures_util::Future;
|
||||||
use kernel_util::{
|
use kernel_util::{
|
||||||
mem::{
|
mem::{
|
||||||
address::{IntoRaw, PhysicalAddress},
|
address::{AsPhysicalAddress, IntoRaw, PhysicalAddress},
|
||||||
table::EntryLevelExt,
|
PageBox,
|
||||||
},
|
},
|
||||||
sync::IrqSafeSpinlock,
|
sync::IrqSafeSpinlock,
|
||||||
};
|
};
|
||||||
use static_assertions::const_assert;
|
use static_assertions::const_assert;
|
||||||
|
|
||||||
use crate::{
|
use crate::task::runtime::QueueWaker;
|
||||||
arch::L3,
|
|
||||||
mem::{phys, pointer::PhysicalRefMut},
|
|
||||||
task::runtime::QueueWaker,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
command::{Command, Request},
|
command::{Command, Request},
|
||||||
@ -74,9 +70,8 @@ pub struct CompletionQueueEntry {
|
|||||||
dw: [u32; 4],
|
dw: [u32; 4],
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Queue<'a, T> {
|
pub struct Queue<T> {
|
||||||
data: PhysicalRefMut<'a, [T]>,
|
data: PageBox<[T]>,
|
||||||
|
|
||||||
mask: usize,
|
mask: usize,
|
||||||
head: usize,
|
head: usize,
|
||||||
tail: usize,
|
tail: usize,
|
||||||
@ -86,28 +81,26 @@ pub struct Queue<'a, T> {
|
|||||||
tail_doorbell: *mut u32,
|
tail_doorbell: *mut u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Inner<'a> {
|
struct Inner {
|
||||||
sq: Queue<'a, SubmissionQueueEntry>,
|
sq: Queue<SubmissionQueueEntry>,
|
||||||
cq: Queue<'a, CompletionQueueEntry>,
|
cq: Queue<CompletionQueueEntry>,
|
||||||
|
|
||||||
completed: BTreeMap<u32, CompletionQueueEntry>,
|
completed: BTreeMap<u32, CompletionQueueEntry>,
|
||||||
pending: BTreeSet<u32>,
|
pending: BTreeSet<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO PageBox<T>?
|
pub struct QueuePair {
|
||||||
#[allow(unused)]
|
|
||||||
pub struct QueuePair<'a> {
|
|
||||||
base: PhysicalAddress,
|
|
||||||
page_count: usize,
|
|
||||||
id: u32,
|
id: u32,
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
vector: usize,
|
vector: usize,
|
||||||
|
|
||||||
sq_base: PhysicalAddress,
|
sq_base: PhysicalAddress,
|
||||||
cq_base: PhysicalAddress,
|
cq_base: PhysicalAddress,
|
||||||
|
|
||||||
completion_notify: QueueWaker,
|
completion_notify: QueueWaker,
|
||||||
|
|
||||||
inner: IrqSafeSpinlock<Inner<'a>>,
|
inner: IrqSafeSpinlock<Inner>,
|
||||||
}
|
}
|
||||||
|
|
||||||
const_assert!(size_of::<CompletionQueueEntry>().is_power_of_two());
|
const_assert!(size_of::<CompletionQueueEntry>().is_power_of_two());
|
||||||
@ -166,25 +159,23 @@ impl CompletionQueueEntry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> Queue<'a, T> {
|
impl<T> Queue<T> {
|
||||||
pub unsafe fn from_raw_parts(
|
pub fn new(
|
||||||
base: PhysicalAddress,
|
data: PageBox<[T]>,
|
||||||
len: usize,
|
|
||||||
head_doorbell: *mut u32,
|
head_doorbell: *mut u32,
|
||||||
tail_doorbell: *mut u32,
|
tail_doorbell: *mut u32,
|
||||||
phase: bool,
|
phase: bool,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
// Submission queues have tail doorbells, completion queues have head doorbells
|
|
||||||
assert!(
|
assert!(
|
||||||
(head_doorbell.is_null() && !tail_doorbell.is_null())
|
(head_doorbell.is_null() && !tail_doorbell.is_null())
|
||||||
|| (!head_doorbell.is_null() && tail_doorbell.is_null())
|
|| (!head_doorbell.is_null() && tail_doorbell.is_null())
|
||||||
);
|
);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
data: PhysicalRefMut::map_slice(base, len),
|
mask: data.len() - 1,
|
||||||
mask: len - 1,
|
|
||||||
head: 0,
|
head: 0,
|
||||||
tail: 0,
|
tail: 0,
|
||||||
|
data,
|
||||||
head_doorbell,
|
head_doorbell,
|
||||||
tail_doorbell,
|
tail_doorbell,
|
||||||
phase,
|
phase,
|
||||||
@ -246,13 +237,9 @@ impl<'a, T> Queue<'a, T> {
|
|||||||
|
|
||||||
wrapped
|
wrapped
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn is_empty(&self) -> bool {
|
|
||||||
// self.head == self.tail
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> QueuePair<'a> {
|
impl QueuePair {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
id: u32,
|
id: u32,
|
||||||
vector: usize,
|
vector: usize,
|
||||||
@ -260,24 +247,16 @@ impl<'a> QueuePair<'a> {
|
|||||||
sq_doorbell: *mut u32,
|
sq_doorbell: *mut u32,
|
||||||
cq_doorbell: *mut u32,
|
cq_doorbell: *mut u32,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
let sq_size = capacity * size_of::<SubmissionQueueEntry>();
|
let sq_data = PageBox::new_slice(SubmissionQueueEntry::zeroed(), capacity)?;
|
||||||
let cq_size = capacity * size_of::<CompletionQueueEntry>();
|
let cq_data = PageBox::new_slice(CompletionQueueEntry::zeroed(), capacity)?;
|
||||||
|
|
||||||
let page_count = sq_size.page_count::<L3>() + cq_size.page_count::<L3>();
|
let sq_base = unsafe { sq_data.as_physical_address() };
|
||||||
let base = phys::alloc_pages_contiguous(page_count)?;
|
let cq_base = unsafe { cq_data.as_physical_address() };
|
||||||
|
|
||||||
let sq_base = base;
|
debugln!("Allocated queue pair: sq={:p}, cq={:p}", sq_data, cq_data);
|
||||||
let cq_base = base.add(sq_size.page_align_up::<L3>());
|
|
||||||
|
|
||||||
debugln!(
|
let sq = Queue::new(sq_data, null_mut(), sq_doorbell, true);
|
||||||
"Allocated queue pair: sq={:x?}, cq={:x?} ({} pages)",
|
let cq = Queue::new(cq_data, cq_doorbell, null_mut(), true);
|
||||||
sq_base..sq_base.add(sq_size),
|
|
||||||
cq_base..cq_base.add(cq_size),
|
|
||||||
page_count
|
|
||||||
);
|
|
||||||
|
|
||||||
let sq = unsafe { Queue::from_raw_parts(sq_base, capacity, null_mut(), sq_doorbell, true) };
|
|
||||||
let cq = unsafe { Queue::from_raw_parts(cq_base, capacity, cq_doorbell, null_mut(), true) };
|
|
||||||
|
|
||||||
let inner = IrqSafeSpinlock::new(Inner {
|
let inner = IrqSafeSpinlock::new(Inner {
|
||||||
sq,
|
sq,
|
||||||
@ -291,8 +270,6 @@ impl<'a> QueuePair<'a> {
|
|||||||
|
|
||||||
id,
|
id,
|
||||||
vector,
|
vector,
|
||||||
base,
|
|
||||||
page_count,
|
|
||||||
sq_base,
|
sq_base,
|
||||||
cq_base,
|
cq_base,
|
||||||
inner,
|
inner,
|
||||||
@ -313,12 +290,9 @@ impl<'a> QueuePair<'a> {
|
|||||||
&'r self,
|
&'r self,
|
||||||
command_id: u32,
|
command_id: u32,
|
||||||
result: T,
|
result: T,
|
||||||
) -> impl Future<Output = Result<T, CommandError>> + 'r
|
) -> impl Future<Output = Result<T, CommandError>> + 'r {
|
||||||
where
|
|
||||||
'r: 'a,
|
|
||||||
{
|
|
||||||
struct Fut<'r, R: Unpin + 'r> {
|
struct Fut<'r, R: Unpin + 'r> {
|
||||||
this: &'r QueuePair<'r>,
|
this: &'r QueuePair,
|
||||||
response: Option<R>,
|
response: Option<R>,
|
||||||
command_id: u32,
|
command_id: u32,
|
||||||
}
|
}
|
||||||
@ -386,34 +360,22 @@ impl<'a> QueuePair<'a> {
|
|||||||
pub fn request_no_data<'r, C: Command>(
|
pub fn request_no_data<'r, C: Command>(
|
||||||
&'r self,
|
&'r self,
|
||||||
req: C,
|
req: C,
|
||||||
) -> impl Future<Output = Result<(), CommandError>> + 'r
|
) -> impl Future<Output = Result<(), CommandError>> + 'r {
|
||||||
where
|
|
||||||
'r: 'a,
|
|
||||||
{
|
|
||||||
let command_id = self.submit(req, &[], true);
|
let command_id = self.submit(req, &[], true);
|
||||||
self.wait_for_completion(command_id, ())
|
self.wait_for_completion(command_id, ())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn request<'r, R: Request>(
|
pub async fn request<'r, R: Request>(
|
||||||
&'r self,
|
&'r self,
|
||||||
req: R,
|
req: R,
|
||||||
) -> Result<
|
) -> Result<PageBox<R::Response>, NvmeError>
|
||||||
impl Future<Output = Result<PhysicalRefMut<'r, R::Response>, CommandError>>,
|
|
||||||
NvmeError,
|
|
||||||
>
|
|
||||||
where
|
where
|
||||||
R::Response: 'r,
|
R::Response: 'r,
|
||||||
'r: 'a,
|
|
||||||
{
|
{
|
||||||
assert_ne!(size_of::<R::Response>(), 0);
|
let response = PageBox::new_uninit().map_err(NvmeError::MemoryError)?;
|
||||||
assert!(size_of::<R::Response>() <= 0x1000);
|
let command_id = self.submit(req, &[unsafe { response.as_physical_address() }], true);
|
||||||
|
let result = self.wait_for_completion(command_id, response).await?;
|
||||||
let page = phys::alloc_page().map_err(NvmeError::MemoryError)?;
|
Ok(unsafe { result.assume_init() })
|
||||||
// TODO PageBox
|
|
||||||
let response = unsafe { PhysicalRefMut::map(page) };
|
|
||||||
|
|
||||||
let command_id = self.submit(req, &[page], true);
|
|
||||||
Ok(self.wait_for_completion(command_id, response))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_completions(&self) -> usize {
|
pub fn process_completions(&self) -> usize {
|
||||||
|
@ -14,7 +14,6 @@ use crate::arch::{Architecture, ArchitectureImpl};
|
|||||||
pub mod address;
|
pub mod address;
|
||||||
pub mod heap;
|
pub mod heap;
|
||||||
pub mod phys;
|
pub mod phys;
|
||||||
pub mod pointer;
|
|
||||||
pub mod process;
|
pub mod process;
|
||||||
pub mod table;
|
pub mod table;
|
||||||
|
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
//! Physical memory manager implementation
|
//! Physical memory manager implementation
|
||||||
use abi::error::Error;
|
use abi::error::Error;
|
||||||
use kernel_util::mem::address::{FromRaw, IntoRaw, PhysicalAddress};
|
use kernel_util::mem::{
|
||||||
|
address::{FromRaw, IntoRaw, PhysicalAddress},
|
||||||
use crate::mem::pointer::PhysicalRefMut;
|
pointer::PhysicalRefMut,
|
||||||
|
};
|
||||||
|
|
||||||
pub type BitmapWord = u64;
|
pub type BitmapWord = u64;
|
||||||
|
|
||||||
|
@ -208,3 +208,13 @@ fn kernel_physical_memory_region() -> PhysicalMemoryRegion {
|
|||||||
|
|
||||||
PhysicalMemoryRegion { base, size }
|
PhysicalMemoryRegion { base, size }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
fn __allocate_contiguous_pages(count: usize) -> Result<PhysicalAddress, Error> {
|
||||||
|
alloc_pages_contiguous(count)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
unsafe fn __free_page(page: PhysicalAddress) {
|
||||||
|
free_page(page)
|
||||||
|
}
|
||||||
|
@ -7,16 +7,12 @@ use elf::{
|
|||||||
segment::ProgramHeader,
|
segment::ProgramHeader,
|
||||||
ElfStream, ParseError,
|
ElfStream, ParseError,
|
||||||
};
|
};
|
||||||
|
use kernel_util::mem::pointer::{PhysicalRef, PhysicalRefMut};
|
||||||
use vfs::{FileRef, Read, Seek};
|
use vfs::{FileRef, Read, Seek};
|
||||||
use yggdrasil_abi::{error::Error, io::SeekFrom};
|
use yggdrasil_abi::{error::Error, io::SeekFrom};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
mem::{
|
mem::{phys, process::ProcessAddressSpace, table::MapAttributes},
|
||||||
phys,
|
|
||||||
pointer::{PhysicalRef, PhysicalRefMut},
|
|
||||||
process::ProcessAddressSpace,
|
|
||||||
table::MapAttributes,
|
|
||||||
},
|
|
||||||
task::process::{ProcessImage, ProcessTlsInfo, ProcessTlsLayout},
|
task::process::{ProcessImage, ProcessTlsInfo, ProcessTlsLayout},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -9,13 +9,11 @@ use abi::{
|
|||||||
process::ProgramArgumentInner,
|
process::ProgramArgumentInner,
|
||||||
};
|
};
|
||||||
use alloc::{string::String, sync::Arc, vec::Vec};
|
use alloc::{string::String, sync::Arc, vec::Vec};
|
||||||
|
use kernel_util::mem::pointer::PhysicalRefMut;
|
||||||
use vfs::{FileRef, IoContext, Read, Seek};
|
use vfs::{FileRef, IoContext, Read, Seek};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
mem::{
|
mem::{phys, process::ProcessAddressSpace, table::MapAttributes, ForeignPointer},
|
||||||
phys, pointer::PhysicalRefMut, process::ProcessAddressSpace, table::MapAttributes,
|
|
||||||
ForeignPointer,
|
|
||||||
},
|
|
||||||
proc,
|
proc,
|
||||||
task::{
|
task::{
|
||||||
context::TaskContextImpl,
|
context::TaskContextImpl,
|
||||||
@ -190,7 +188,9 @@ pub fn load<P: AsRef<Path>>(
|
|||||||
let count = file.read(&mut head)?;
|
let count = file.read(&mut head)?;
|
||||||
let head = &head[..count];
|
let head = &head[..count];
|
||||||
|
|
||||||
if let Some(shebang) = head.strip_prefix(b"#!") && let Some((shebang, _)) = shebang.split_once(|&ch| ch == b'\n') {
|
if let Some(shebang) = head.strip_prefix(b"#!")
|
||||||
|
&& let Some((shebang, _)) = shebang.split_once(|&ch| ch == b'\n')
|
||||||
|
{
|
||||||
let shebang = core::str::from_utf8(shebang).map_err(|_| Error::InvalidFile)?;
|
let shebang = core::str::from_utf8(shebang).map_err(|_| Error::InvalidFile)?;
|
||||||
let mut shebang_args = shebang.split(' ').collect::<Vec<_>>();
|
let mut shebang_args = shebang.split(' ').collect::<Vec<_>>();
|
||||||
if shebang_args.is_empty() || shebang_args.len() >= 8 {
|
if shebang_args.is_empty() || shebang_args.len() >= 8 {
|
||||||
|
@ -5,12 +5,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use bytemuck::Zeroable;
|
use elf::{abi::PT_LOAD, endian::AnyEndian, ElfStream};
|
||||||
use elf::{
|
|
||||||
abi::{PF_W, PF_X, PT_LOAD},
|
|
||||||
endian::AnyEndian,
|
|
||||||
ElfStream,
|
|
||||||
};
|
|
||||||
use memtables::x86_64::{FixedTables, KERNEL_L3_COUNT};
|
use memtables::x86_64::{FixedTables, KERNEL_L3_COUNT};
|
||||||
|
|
||||||
use crate::{GenData, GenError};
|
use crate::{GenData, GenError};
|
||||||
@ -36,7 +31,7 @@ pub struct X8664Builder<F: Seek + Read> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PageFlags {
|
impl PageFlags {
|
||||||
fn from_elf(flags: u32) -> Self {
|
fn from_elf(_flags: u32) -> Self {
|
||||||
let mut out = Self::empty();
|
let mut out = Self::empty();
|
||||||
// if flags & PF_W != 0 {
|
// if flags & PF_W != 0 {
|
||||||
out |= Self::WRITABLE;
|
out |= Self::WRITABLE;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user