maint: sync up other architectures with mmap(file)

This commit is contained in:
Mark Poliakov 2025-02-26 16:21:56 +02:00
parent 43acdb9e13
commit 72633eb339
43 changed files with 522 additions and 262 deletions

View File

@ -7,7 +7,7 @@ use core::{
use libk_mm_interface::{ use libk_mm_interface::{
address::{AsPhysicalAddress, PhysicalAddress}, address::{AsPhysicalAddress, PhysicalAddress},
pointer::PhysicalRefMut, pointer::PhysicalRefMut,
process::ProcessAddressSpaceManager, process::{PageAttributeUpdate, ProcessAddressSpaceManager},
table::{ table::{
EntryLevel, EntryLevelDrop, EntryLevelExt, MapAttributes, NextPageTable, TableAllocator, EntryLevel, EntryLevelDrop, EntryLevelExt, MapAttributes, NextPageTable, TableAllocator,
}, },
@ -79,7 +79,15 @@ impl<TA: TableAllocator> ProcessAddressSpaceManager<TA> for ProcessAddressSpaceI
) )
} }
unsafe fn unmap_page(&mut self, address: usize) -> Result<PhysicalAddress, Error> { unsafe fn update_page_attributes(
&mut self,
address: usize,
update: &PageAttributeUpdate,
) -> Result<(), Error> {
self.update_l3_entry(address, |entry| entry.update(update))
}
unsafe fn unmap_page(&mut self, address: usize) -> Result<(PhysicalAddress, bool), Error> {
self.pop_l3_entry(address) self.pop_l3_entry(address)
} }
@ -120,7 +128,32 @@ impl<TA: TableAllocator> ProcessAddressSpaceImpl<TA> {
Ok(()) Ok(())
} }
fn pop_l3_entry(&mut self, virt: usize) -> Result<PhysicalAddress, Error> { fn update_l3_entry<F: FnOnce(&mut PageEntry<L3>) -> Result<(), Error>>(
&mut self,
virt: usize,
mapper: F,
) -> Result<(), Error> {
let l1i = virt.page_index::<L1>();
let l2i = virt.page_index::<L2>();
let l3i = virt.page_index::<L3>();
let mut l2 = self.l1.get_mut(l1i).ok_or(Error::DoesNotExist)?;
let mut l3 = l2.get_mut(l2i).ok_or(Error::DoesNotExist)?;
let entry = &mut l3[l3i];
if !entry.is_present() {
return Err(Error::DoesNotExist);
}
mapper(entry)?;
ic_iallu();
dc_cvac((&raw const l3[l3i]).addr());
tlb_flush_vaae1(virt);
Ok(())
}
fn pop_l3_entry(&mut self, virt: usize) -> Result<(PhysicalAddress, bool), Error> {
let l1i = virt.page_index::<L1>(); let l1i = virt.page_index::<L1>();
let l2i = virt.page_index::<L2>(); let l2i = virt.page_index::<L2>();
let l3i = virt.page_index::<L3>(); let l3i = virt.page_index::<L3>();
@ -129,14 +162,16 @@ impl<TA: TableAllocator> ProcessAddressSpaceImpl<TA> {
let mut l2 = self.l1.get_mut(l1i).ok_or(Error::DoesNotExist)?; let mut l2 = self.l1.get_mut(l1i).ok_or(Error::DoesNotExist)?;
let mut l3 = l2.get_mut(l2i).ok_or(Error::DoesNotExist)?; let mut l3 = l2.get_mut(l2i).ok_or(Error::DoesNotExist)?;
let page = l3[l3i].as_page().ok_or(Error::DoesNotExist)?; let entry = l3[l3i];
let page = entry.as_page().ok_or(Error::DoesNotExist)?;
let dirty = entry.is_dirty();
l3[l3i] = PageEntry::INVALID; l3[l3i] = PageEntry::INVALID;
ic_iallu(); ic_iallu();
dc_cvac((&raw const l3[l3i]).addr()); dc_cvac((&raw const l3[l3i]).addr());
tlb_flush_vaae1(virt); tlb_flush_vaae1(virt);
Ok(page) Ok((page, dirty))
} }
fn read_l3_entry(&self, virt: usize) -> Option<(PhysicalAddress, MapAttributes)> { fn read_l3_entry(&self, virt: usize) -> Option<(PhysicalAddress, MapAttributes)> {

View File

@ -9,6 +9,7 @@ use kernel_arch_interface::KERNEL_VIRT_OFFSET;
use libk_mm_interface::{ use libk_mm_interface::{
address::{AsPhysicalAddress, PhysicalAddress}, address::{AsPhysicalAddress, PhysicalAddress},
pointer::{PhysicalRef, PhysicalRefMut}, pointer::{PhysicalRef, PhysicalRefMut},
process::PageAttributeUpdate,
table::{ table::{
EntryLevel, EntryLevelDrop, MapAttributes, NextPageTable, NonTerminalEntryLevel, EntryLevel, EntryLevelDrop, MapAttributes, NextPageTable, NonTerminalEntryLevel,
TableAllocator, TableAllocator,
@ -46,6 +47,7 @@ bitflags! {
const NON_GLOBAL = 1 << 11; const NON_GLOBAL = 1 << 11;
const DIRTY = 1 << 51;
const PXN = 1 << 53; const PXN = 1 << 53;
const UXN = 1 << 54; const UXN = 1 << 54;
} }
@ -136,8 +138,32 @@ impl<L: EntryLevel> PageTable<L> {
} }
impl<L: EntryLevel> PageEntry<L> { impl<L: EntryLevel> PageEntry<L> {
const ATTR_MASK: u64 = 0xFFF | (0xFFFF << 48);
pub const INVALID: Self = Self(0, PhantomData); pub const INVALID: Self = Self(0, PhantomData);
pub fn update(&mut self, update: &PageAttributeUpdate) -> Result<(), Error> {
let mut attrs = PageAttributes::from_bits_retain(self.0);
if let Some(write) = update.user_write {
// Make writeable/non-writeable
if write {
attrs &= !PageAttributes::AP_ACCESS_MASK;
attrs |= PageAttributes::AP_BOTH_READWRITE;
} else {
todo!();
}
}
if let Some(dirty) = update.dirty {
if dirty {
attrs |= PageAttributes::DIRTY;
} else {
attrs &= !PageAttributes::DIRTY;
}
}
self.0 &= !Self::ATTR_MASK;
self.0 |= attrs.bits() & Self::ATTR_MASK;
Ok(())
}
pub const fn is_present(self) -> bool { pub const fn is_present(self) -> bool {
self.0 & PageAttributes::PRESENT.bits() != 0 self.0 & PageAttributes::PRESENT.bits() != 0
} }
@ -271,7 +297,7 @@ impl<L: NonTerminalEntryLevel> PageEntry<L> {
if self.0 & PageAttributes::PRESENT.bits() != 0 if self.0 & PageAttributes::PRESENT.bits() != 0
&& self.0 & PageAttributes::BLOCK.bits() == 0 && self.0 & PageAttributes::BLOCK.bits() == 0
{ {
Some(PhysicalAddress::from_u64(self.0 & !0xFFF)) Some(PhysicalAddress::from_u64(self.0 & !Self::ATTR_MASK))
} else { } else {
None None
} }
@ -283,7 +309,7 @@ impl<L: NonTerminalEntryLevel> PageEntry<L> {
} else if let Some(table) = self.as_table() { } else if let Some(table) = self.as_table() {
EntryType::Table(table) EntryType::Table(table)
} else { } else {
EntryType::Page(PhysicalAddress::from_u64(self.0 & !0xFFF)) EntryType::Page(PhysicalAddress::from_u64(self.0 & !Self::ATTR_MASK))
} }
} }
} }
@ -316,10 +342,14 @@ impl PageEntry<L3> {
) )
} }
pub fn is_dirty(&self) -> bool {
self.0 & PageAttributes::DIRTY.bits() != 0
}
pub fn as_page(&self) -> Option<PhysicalAddress> { pub fn as_page(&self) -> Option<PhysicalAddress> {
let mask = (PageAttributes::PRESENT | PageAttributes::PAGE).bits(); let mask = (PageAttributes::PRESENT | PageAttributes::PAGE).bits();
if self.0 & mask == mask { if self.0 & mask == mask {
Some(PhysicalAddress::from_u64(self.0 & !0xFFF)) Some(PhysicalAddress::from_u64(self.0 & !Self::ATTR_MASK))
} else { } else {
None None
} }
@ -355,6 +385,10 @@ impl From<MapAttributes> for PageAttributes {
out |= PageAttributes::AP_KERNEL_READONLY; out |= PageAttributes::AP_KERNEL_READONLY;
} }
if value.contains(MapAttributes::DIRTY) {
out |= PageAttributes::DIRTY;
}
if value.contains(MapAttributes::NON_GLOBAL) { if value.contains(MapAttributes::NON_GLOBAL) {
out |= PageAttributes::NON_GLOBAL; out |= PageAttributes::NON_GLOBAL;
} }
@ -377,6 +411,10 @@ impl From<PageAttributes> for MapAttributes {
_ => unreachable!(), _ => unreachable!(),
}; };
if value.contains(PageAttributes::DIRTY) {
out |= MapAttributes::DIRTY;
}
if value.contains(PageAttributes::NON_GLOBAL) { if value.contains(PageAttributes::NON_GLOBAL) {
out |= MapAttributes::NON_GLOBAL; out |= MapAttributes::NON_GLOBAL;
} }

View File

@ -6,7 +6,7 @@ use core::{
use libk_mm_interface::{ use libk_mm_interface::{
address::{AsPhysicalAddress, PhysicalAddress}, address::{AsPhysicalAddress, PhysicalAddress},
pointer::PhysicalRefMut, pointer::PhysicalRefMut,
process::ProcessAddressSpaceManager, process::{PageAttributeUpdate, ProcessAddressSpaceManager},
table::{ table::{
EntryLevel, EntryLevelDrop, EntryLevelExt, MapAttributes, NextPageTable, TableAllocator, EntryLevel, EntryLevelDrop, EntryLevelExt, MapAttributes, NextPageTable, TableAllocator,
}, },
@ -70,7 +70,15 @@ impl<TA: TableAllocator> ProcessAddressSpaceManager<TA> for ProcessAddressSpaceI
Ok(()) Ok(())
} }
unsafe fn unmap_page(&mut self, address: usize) -> Result<PhysicalAddress, Error> { unsafe fn update_page_attributes(
&mut self,
address: usize,
update: &PageAttributeUpdate,
) -> Result<(), Error> {
self.update_l3_entry(address, |entry| entry.update(update))
}
unsafe fn unmap_page(&mut self, address: usize) -> Result<(PhysicalAddress, bool), Error> {
self.pop_l3_entry(address) self.pop_l3_entry(address)
} }
@ -118,7 +126,11 @@ impl<TA: TableAllocator> ProcessAddressSpaceImpl<TA> {
Ok(()) Ok(())
} }
fn pop_l3_entry(&mut self, virt: usize) -> Result<PhysicalAddress, Error> { fn update_l3_entry<F: FnOnce(&mut PageEntry<L3>) -> Result<(), Error>>(
&mut self,
virt: usize,
mapper: F,
) -> Result<(), Error> {
let l1i = virt.page_index::<L1>(); let l1i = virt.page_index::<L1>();
let l2i = virt.page_index::<L2>(); let l2i = virt.page_index::<L2>();
let l3i = virt.page_index::<L3>(); let l3i = virt.page_index::<L3>();
@ -127,12 +139,33 @@ impl<TA: TableAllocator> ProcessAddressSpaceImpl<TA> {
let mut l2 = self.l1.get_mut(l1i).ok_or(Error::DoesNotExist)?; let mut l2 = self.l1.get_mut(l1i).ok_or(Error::DoesNotExist)?;
let mut l3 = l2.get_mut(l2i).ok_or(Error::DoesNotExist)?; let mut l3 = l2.get_mut(l2i).ok_or(Error::DoesNotExist)?;
let page = l3[l3i].as_page().ok_or(Error::DoesNotExist)?; let entry = &mut l3[l3i];
if !entry.is_present() {
return Err(Error::DoesNotExist);
}
mapper(entry)?;
super::tlb_flush_va_asid(virt, self.asid as usize);
Ok(())
}
fn pop_l3_entry(&mut self, virt: usize) -> Result<(PhysicalAddress, bool), Error> {
let l1i = virt.page_index::<L1>();
let l2i = virt.page_index::<L2>();
let l3i = virt.page_index::<L3>();
// TODO somehow drop tables if they're known to be empty?
let mut l2 = self.l1.get_mut(l1i).ok_or(Error::DoesNotExist)?;
let mut l3 = l2.get_mut(l2i).ok_or(Error::DoesNotExist)?;
let entry = l3[l3i];
let page = entry.as_page().ok_or(Error::DoesNotExist)?;
let dirty = entry.is_dirty();
l3[l3i] = PageEntry::INVALID; l3[l3i] = PageEntry::INVALID;
super::tlb_flush_va_asid(virt, self.asid as usize); super::tlb_flush_va_asid(virt, self.asid as usize);
Ok(page) Ok((page, dirty))
} }
fn read_l3_entry(&self, virt: usize) -> Option<(PhysicalAddress, MapAttributes)> { fn read_l3_entry(&self, virt: usize) -> Option<(PhysicalAddress, MapAttributes)> {
@ -178,6 +211,9 @@ fn to_page_attributes(src: MapAttributes) -> PageAttributes {
if src.intersects(MapAttributes::USER_READ | MapAttributes::USER_WRITE) { if src.intersects(MapAttributes::USER_READ | MapAttributes::USER_WRITE) {
result |= PageAttributes::U; result |= PageAttributes::U;
} }
if src.contains(MapAttributes::DIRTY) {
result |= PageAttributes::SW_DIRTY;
}
result result
} }
@ -192,5 +228,9 @@ fn to_map_attributes(src: PageAttributes) -> MapAttributes {
} }
} }
if src.contains(PageAttributes::SW_DIRTY) {
result |= MapAttributes::DIRTY;
}
result result
} }

View File

@ -6,6 +6,7 @@ use core::{
use libk_mm_interface::{ use libk_mm_interface::{
address::{AsPhysicalAddress, PhysicalAddress}, address::{AsPhysicalAddress, PhysicalAddress},
pointer::{PhysicalRef, PhysicalRefMut}, pointer::{PhysicalRef, PhysicalRefMut},
process::PageAttributeUpdate,
table::{ table::{
page_index, EntryLevel, EntryLevelDrop, NextPageTable, NonTerminalEntryLevel, page_index, EntryLevel, EntryLevelDrop, NextPageTable, NonTerminalEntryLevel,
TableAllocator, TableAllocator,
@ -88,6 +89,8 @@ impl<L: EntryLevel> PageTable<L> {
} }
impl<L: EntryLevel> PageEntry<L> { impl<L: EntryLevel> PageEntry<L> {
// Upper + lower 10 bits
const ATTR_MASK: u64 = 0xFFC00000000003FF;
pub const INVALID: Self = Self(0, PhantomData); pub const INVALID: Self = Self(0, PhantomData);
/// Constructs a [PageEntry] from its raw representation. /// Constructs a [PageEntry] from its raw representation.
@ -103,6 +106,23 @@ impl<L: EntryLevel> PageEntry<L> {
self.0 & PageAttributes::V.bits() != 0 self.0 & PageAttributes::V.bits() != 0
} }
pub fn update(&mut self, update: &PageAttributeUpdate) -> Result<(), Error> {
let mut attrs = self.attributes();
if let Some(write) = update.user_write {
attrs.set(PageAttributes::W, write);
}
if let Some(dirty) = update.dirty {
attrs.set(PageAttributes::SW_DIRTY, dirty);
}
self.0 &= !Self::ATTR_MASK;
self.0 |= attrs.bits() & Self::ATTR_MASK;
Ok(())
}
pub const fn is_dirty(&self) -> bool {
self.0 & PageAttributes::SW_DIRTY.bits() != 0
}
pub fn attributes(self) -> PageAttributes { pub fn attributes(self) -> PageAttributes {
PageAttributes::from_bits_retain(self.0) PageAttributes::from_bits_retain(self.0)
} }
@ -211,7 +231,7 @@ impl<L: NonTerminalEntryLevel> PageEntry<L> {
& (PageAttributes::R | PageAttributes::W | PageAttributes::X | PageAttributes::V) & (PageAttributes::R | PageAttributes::W | PageAttributes::X | PageAttributes::V)
.bits() .bits()
== PageAttributes::V.bits()) == PageAttributes::V.bits())
.then_some((self.0 << 2) & !0xFFF) .then_some((self.0 & !Self::ATTR_MASK) << 2)
.map(PhysicalAddress::from_u64) .map(PhysicalAddress::from_u64)
} }
} }
@ -232,7 +252,7 @@ impl PageEntry<L3> {
pub fn as_page(&self) -> Option<PhysicalAddress> { pub fn as_page(&self) -> Option<PhysicalAddress> {
(self.0 & PageAttributes::V.bits() != 0) (self.0 & PageAttributes::V.bits() != 0)
.then_some((self.0 << 2) & !0xFFF) .then_some((self.0 & !Self::ATTR_MASK) << 2)
.map(PhysicalAddress::from_u64) .map(PhysicalAddress::from_u64)
} }
} }

View File

@ -4,7 +4,7 @@ use core::marker::PhantomData;
use libk_mm_interface::{ use libk_mm_interface::{
address::{AsPhysicalAddress, PhysicalAddress}, address::{AsPhysicalAddress, PhysicalAddress},
pointer::PhysicalRefMut, pointer::PhysicalRefMut,
process::ProcessAddressSpaceManager, process::{PageAttributeUpdate, ProcessAddressSpaceManager},
table::{ table::{
EntryLevel, EntryLevelDrop, EntryLevelExt, MapAttributes, NextPageTable, TableAllocator, EntryLevel, EntryLevelDrop, EntryLevelExt, MapAttributes, NextPageTable, TableAllocator,
}, },
@ -61,6 +61,14 @@ impl<TA: TableAllocator> ProcessAddressSpaceManager<TA> for ProcessAddressSpaceI
self.write_l3_entry(address, PageEntry::page(physical, flags.into()), false) self.write_l3_entry(address, PageEntry::page(physical, flags.into()), false)
} }
unsafe fn update_page_attributes(
&mut self,
address: usize,
update: &PageAttributeUpdate,
) -> Result<(), Error> {
self.update_l3_entry(address, |entry| entry.update(update))
}
unsafe fn unmap_page(&mut self, address: usize) -> Result<(PhysicalAddress, bool), Error> { unsafe fn unmap_page(&mut self, address: usize) -> Result<(PhysicalAddress, bool), Error> {
self.pop_l3_entry(address) self.pop_l3_entry(address)
} }
@ -111,6 +119,32 @@ impl<TA: TableAllocator> ProcessAddressSpaceImpl<TA> {
Ok(()) Ok(())
} }
fn update_l3_entry<F: FnOnce(&mut PageEntry<L3>) -> Result<(), Error>>(
&mut self,
virt: usize,
mapper: F,
) -> Result<(), Error> {
let l0i = virt.page_index::<L0>();
let l1i = virt.page_index::<L1>();
let l2i = virt.page_index::<L2>();
let l3i = virt.page_index::<L3>();
let mut l1 = self.l0.get_mut(l0i).ok_or(Error::DoesNotExist)?;
let mut l2 = l1.get_mut(l1i).ok_or(Error::DoesNotExist)?;
let mut l3 = l2.get_mut(l2i).ok_or(Error::DoesNotExist)?;
let entry = &mut l3[l3i];
if !entry.is_present() {
return Err(Error::DoesNotExist);
}
mapper(entry)?;
unsafe {
flush_tlb_entry(virt);
}
Ok(())
}
fn pop_l3_entry(&mut self, virt: usize) -> Result<(PhysicalAddress, bool), Error> { fn pop_l3_entry(&mut self, virt: usize) -> Result<(PhysicalAddress, bool), Error> {
let l0i = virt.page_index::<L0>(); let l0i = virt.page_index::<L0>();
let l1i = virt.page_index::<L1>(); let l1i = virt.page_index::<L1>();

View File

@ -8,6 +8,7 @@ use bitflags::bitflags;
use libk_mm_interface::{ use libk_mm_interface::{
address::{AsPhysicalAddress, PhysicalAddress}, address::{AsPhysicalAddress, PhysicalAddress},
pointer::{PhysicalRef, PhysicalRefMut}, pointer::{PhysicalRef, PhysicalRefMut},
process::PageAttributeUpdate,
table::{ table::{
EntryLevel, EntryLevelDrop, MapAttributes, NextPageTable, NonTerminalEntryLevel, EntryLevel, EntryLevelDrop, MapAttributes, NextPageTable, NonTerminalEntryLevel,
TableAllocator, TableAllocator,
@ -100,7 +101,7 @@ impl PageEntry<L3> {
/// not /// not
pub fn as_page(self) -> Option<PhysicalAddress> { pub fn as_page(self) -> Option<PhysicalAddress> {
if self.0 & PageAttributes::PRESENT.bits() != 0 { if self.0 & PageAttributes::PRESENT.bits() != 0 {
Some(PhysicalAddress::from_u64(self.0 & !0xFFF)) Some(PhysicalAddress::from_u64(self.0 & !Self::ATTR_MASK))
} else { } else {
None None
} }
@ -151,7 +152,7 @@ impl<L: NonTerminalEntryLevel> PageEntry<L> {
if self.0 & PageAttributes::PRESENT.bits() != 0 if self.0 & PageAttributes::PRESENT.bits() != 0
&& self.0 & PageAttributes::BLOCK.bits() == 0 && self.0 & PageAttributes::BLOCK.bits() == 0
{ {
Some(PhysicalAddress::from_u64(self.0 & !0xFFF)) Some(PhysicalAddress::from_u64(self.0 & !Self::ATTR_MASK))
} else { } else {
None None
} }
@ -164,6 +165,8 @@ impl<L: NonTerminalEntryLevel> PageEntry<L> {
} }
impl<L: EntryLevel> PageEntry<L> { impl<L: EntryLevel> PageEntry<L> {
const ATTR_MASK: u64 = 0xFFF | (1 << 63);
/// An entry that is not mapped /// An entry that is not mapped
pub const INVALID: Self = Self(0, PhantomData); pub const INVALID: Self = Self(0, PhantomData);
@ -185,6 +188,21 @@ impl<L: EntryLevel> PageEntry<L> {
pub fn is_present(&self) -> bool { pub fn is_present(&self) -> bool {
self.0 & PageAttributes::PRESENT.bits() != 0 self.0 & PageAttributes::PRESENT.bits() != 0
} }
pub fn update(&mut self, update: &PageAttributeUpdate) -> Result<(), Error> {
let mut attrs = PageAttributes::from_bits_retain(self.0);
if let Some(write) = update.user_write {
if write {
attrs |= PageAttributes::WRITABLE;
} else {
attrs &= !PageAttributes::WRITABLE;
}
}
// Dirty is ignored, it's hardware-managed
self.0 &= !Self::ATTR_MASK;
self.0 |= attrs.bits() & Self::ATTR_MASK;
Ok(())
}
} }
impl<L: EntryLevel> PageTable<L> { impl<L: EntryLevel> PageTable<L> {

View File

@ -16,8 +16,8 @@ use libk::{
error::Error, error::Error,
}; };
use libk_mm::{ use libk_mm::{
address::PhysicalAddress, device::DeviceMemoryIo, table::MapAttributes, PageProvider, address::PhysicalAddress, device::DeviceMemoryIo, table::MapAttributes, OnDemandPage,
VirtualPage, PageProvider, VirtualPage,
}; };
use libk_util::{sync::IrqSafeSpinlock, waker::QueueWaker, OneTimeInit}; use libk_util::{sync::IrqSafeSpinlock, waker::QueueWaker, OneTimeInit};
use tock_registers::interfaces::{Readable, Writeable}; use tock_registers::interfaces::{Readable, Writeable};
@ -366,7 +366,7 @@ impl Device for AhciPort {
} }
impl PageProvider for AhciPort { impl PageProvider for AhciPort {
fn ondemand_fetch(&self, _opaque: u64) -> Result<PhysicalAddress, Error> { fn ondemand_fetch(&self, _opaque: u64) -> Result<OnDemandPage, Error> {
unimplemented!() unimplemented!()
} }

View File

@ -11,7 +11,7 @@ use libk::{
use libk_mm::{ use libk_mm::{
address::{AsPhysicalAddress, PhysicalAddress}, address::{AsPhysicalAddress, PhysicalAddress},
table::MapAttributes, table::MapAttributes,
PageProvider, PageSlice, VirtualPage, OnDemandPage, PageProvider, PageSlice, VirtualPage,
}; };
use crate::{command::IdentifyNamespaceRequest, register_nvme_namespace, IoDirection}; use crate::{command::IdentifyNamespaceRequest, register_nvme_namespace, IoDirection};
@ -151,7 +151,7 @@ impl BlockDevice for NvmeNamespace {
} }
impl PageProvider for NvmeNamespace { impl PageProvider for NvmeNamespace {
fn ondemand_fetch(&self, _opaque: u64) -> Result<PhysicalAddress, Error> { fn ondemand_fetch(&self, _opaque: u64) -> Result<OnDemandPage, Error> {
unimplemented!() unimplemented!()
} }

View File

@ -22,7 +22,9 @@ use libk::{
fs::devfs, fs::devfs,
task::{runtime, sync::AsyncMutex}, task::{runtime, sync::AsyncMutex},
}; };
use libk_mm::{address::PhysicalAddress, table::MapAttributes, PageProvider, VirtualPage}; use libk_mm::{
address::PhysicalAddress, table::MapAttributes, OnDemandPage, PageProvider, VirtualPage,
};
use libk_util::{ use libk_util::{
sync::{spin_rwlock::IrqSafeRwLock, IrqSafeSpinlock}, sync::{spin_rwlock::IrqSafeRwLock, IrqSafeSpinlock},
OneTimeInit, OneTimeInit,
@ -278,7 +280,7 @@ impl BlockDevice for ScsiUnit {
} }
impl PageProvider for ScsiUnit { impl PageProvider for ScsiUnit {
fn ondemand_fetch(&self, _opaque: u64) -> Result<PhysicalAddress, Error> { fn ondemand_fetch(&self, _opaque: u64) -> Result<OnDemandPage, Error> {
unimplemented!() unimplemented!()
} }

View File

@ -17,7 +17,9 @@ use libk::{
fs::devfs, fs::devfs,
task::runtime, task::runtime,
}; };
use libk_mm::{address::PhysicalAddress, table::MapAttributes, PageProvider, VirtualPage}; use libk_mm::{
address::PhysicalAddress, table::MapAttributes, OnDemandPage, PageProvider, VirtualPage,
};
use libk_util::sync::{spin_rwlock::IrqSafeRwLock, IrqSafeSpinlock}; use libk_util::sync::{spin_rwlock::IrqSafeRwLock, IrqSafeSpinlock};
use ygg_driver_pci::{ use ygg_driver_pci::{
device::{PciDeviceInfo, PreferredInterruptMode}, device::{PciDeviceInfo, PreferredInterruptMode},
@ -329,7 +331,7 @@ impl<T: Transport + 'static> BlockDevice for VirtioBlk<T> {
} }
impl<T: Transport + 'static> PageProvider for VirtioBlk<T> { impl<T: Transport + 'static> PageProvider for VirtioBlk<T> {
fn ondemand_fetch(&self, _opaque: u64) -> Result<PhysicalAddress, Error> { fn ondemand_fetch(&self, _opaque: u64) -> Result<OnDemandPage, Error> {
unimplemented!() unimplemented!()
} }

View File

@ -5,8 +5,7 @@ extern crate alloc;
use core::mem::MaybeUninit; use core::mem::MaybeUninit;
use alloc::{boxed::Box, sync::Arc, vec::Vec}; use alloc::{sync::Arc, vec::Vec};
use async_trait::async_trait;
use command::{CommandExecution, ScanoutInfo}; use command::{CommandExecution, ScanoutInfo};
use device_api::{ use device_api::{
device::{Device, DeviceInitContext}, device::{Device, DeviceInitContext},
@ -24,7 +23,7 @@ use libk::{
use libk_mm::{ use libk_mm::{
address::{AsPhysicalAddress, PhysicalAddress}, address::{AsPhysicalAddress, PhysicalAddress},
table::MapAttributes, table::MapAttributes,
PageProvider, VirtualPage, L3_PAGE_SIZE, OnDemandPage, PageProvider, VirtualPage, L3_PAGE_SIZE,
}; };
use libk_util::{ use libk_util::{
sync::{spin_rwlock::IrqSafeRwLock, IrqSafeSpinlock}, sync::{spin_rwlock::IrqSafeRwLock, IrqSafeSpinlock},
@ -294,52 +293,41 @@ impl<T: Transport + 'static> Device for VirtioGpu<T> {
} }
impl<T: Transport + 'static> PageProvider for VirtioGpu<T> { impl<T: Transport + 'static> PageProvider for VirtioGpu<T> {
// fn get_page(&self, offset: u64) -> Result<PhysicalAddress, Error> { fn ondemand_fetch(&self, _opaque: u64) -> Result<OnDemandPage, Error> {
// // TODO check that the page is mapped by framebuffer owner
// let config = self.config.read();
// let framebuffer = config.framebuffer.as_ref().ok_or(Error::DoesNotExist)?;
// if offset as usize + L3_PAGE_SIZE > framebuffer.dma_buffer.page_count() * L3_PAGE_SIZE {
// log::warn!(
// "virtio-gpu: offset {:#x} outside of framebuffer bounds {:#x}",
// offset,
// framebuffer.size
// );
// return Err(Error::InvalidMemoryOperation);
// }
// let phys = unsafe { framebuffer.dma_buffer.as_physical_address() }.add(offset as usize);
//
// Ok(phys)
// }
//
// fn clone_page(
// &self,
// _offset: u64,
// _src_phys: PhysicalAddress,
// _src_attrs: MapAttributes,
// ) -> Result<PhysicalAddress, Error> {
// todo!()
// }
//
// fn release_page(&self, _offset: u64, _phys: PhysicalAddress) -> Result<(), Error> {
// Ok(())
// }
fn ondemand_fetch(&self, _opaque: u64) -> Result<PhysicalAddress, Error> {
unreachable!() unreachable!()
} }
fn get_page(&self, offset: u64) -> Result<VirtualPage, Error> { fn get_page(&self, offset: u64) -> Result<VirtualPage, Error> {
unimplemented!() // TODO check that the page is mapped by framebuffer owner
let config = self.config.read();
let framebuffer = config.framebuffer.as_ref().ok_or(Error::DoesNotExist)?;
if offset as usize + L3_PAGE_SIZE > framebuffer.dma_buffer.page_count() * L3_PAGE_SIZE {
log::warn!(
"virtio-gpu: offset {:#x} outside of framebuffer bounds {:#x}",
offset,
framebuffer.size
);
return Err(Error::InvalidMemoryOperation);
}
let phys = unsafe { framebuffer.dma_buffer.as_physical_address() }.add(offset as usize);
Ok(VirtualPage::Immediate(phys))
} }
fn release_page(&self, offset: u64, phys: PhysicalAddress, _dirty: bool) -> Result<(), Error> { fn release_page(
unimplemented!() &self,
_offset: u64,
_phys: PhysicalAddress,
_dirty: bool,
) -> Result<(), Error> {
Ok(())
} }
fn clone_page( fn clone_page(
&self, &self,
offset: u64, _offset: u64,
src_phys: PhysicalAddress, _src_phys: PhysicalAddress,
src_attrs: MapAttributes, _src_attrs: MapAttributes,
) -> Result<PhysicalAddress, Error> { ) -> Result<PhysicalAddress, Error> {
unimplemented!() unimplemented!()
} }

View File

@ -140,7 +140,9 @@ impl<T: Transport + 'static> VirtioNet<T> {
(Some(msis[0].vector as u16), Some(msis[1].vector as u16)) (Some(msis[0].vector as u16), Some(msis[1].vector as u16))
} else { } else {
// TODO support non-MSI-x/non-multivec setups // TODO support non-MSI-x/non-multivec setups
todo!(); self.pci_device_info
.map_interrupt(InterruptAffinity::Any, self.clone())?;
(None, None)
}; };
// Setup a callback to remove pending buffers and pass them to the network stack // Setup a callback to remove pending buffers and pass them to the network stack
@ -245,7 +247,10 @@ impl<T: Transport + 'static> InterruptHandler for VirtioNet<T> {
true true
} }
// TODO non-multivec/legacy IRQ setup // TODO non-multivec/legacy IRQ setup
IrqVector::Irq(_) => todo!(), IrqVector::Irq(_) => {
self.softirq.signal((1 << Self::VQ_RX) | (1 << Self::VQ_TX));
true
}
} }
} }
} }

View File

@ -11,6 +11,8 @@ bitflags! {
#[derive(Clone, Copy, PartialEq, Eq, Debug)] #[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct PageAttributes: u64 { pub struct PageAttributes: u64 {
const N = 1 << 63; const N = 1 << 63;
/// Software-tracked dirty bit (RSW[0])
const SW_DIRTY = 1 << 9;
/// Dirty bit /// Dirty bit
const D = 1 << 7; const D = 1 << 7;
/// Access bit /// Access bit

View File

@ -11,6 +11,15 @@ pub mod pointer;
pub mod process; pub mod process;
pub mod table; pub mod table;
/// Describes which kind of a page fault occured
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PageFaultKind {
TranslationFault { write: bool },
WriteFault,
AccessFault,
Other,
}
/// Wrapper type to represent an object residing within the kernel /// Wrapper type to represent an object residing within the kernel
#[repr(transparent)] #[repr(transparent)]
pub struct KernelImageObject<T> { pub struct KernelImageObject<T> {

View File

@ -5,6 +5,11 @@ use crate::{
table::{MapAttributes, TableAllocator}, table::{MapAttributes, TableAllocator},
}; };
pub struct PageAttributeUpdate {
pub user_write: Option<bool>,
pub dirty: Option<bool>,
}
/// Interface for virtual memory address space management /// Interface for virtual memory address space management
pub trait ProcessAddressSpaceManager<TA: TableAllocator>: Sized { pub trait ProcessAddressSpaceManager<TA: TableAllocator>: Sized {
/// PFN of a minimum address allowed for virtual region allocation /// PFN of a minimum address allowed for virtual region allocation
@ -27,6 +32,17 @@ pub trait ProcessAddressSpaceManager<TA: TableAllocator>: Sized {
flags: MapAttributes, flags: MapAttributes,
) -> Result<(), Error>; ) -> Result<(), Error>;
/// Adds/removes attributes from a page entry in the address space.
///
/// # Safety
///
/// The caller must ensure the validity of this update.
unsafe fn update_page_attributes(
&mut self,
address: usize,
update: &PageAttributeUpdate,
) -> Result<(), Error>;
/// Removes a single PAGE_SIZE mapping from the address space. /// Removes a single PAGE_SIZE mapping from the address space.
/// ///
/// # Safety /// # Safety

View File

@ -37,6 +37,8 @@ bitflags! {
const USER_WRITE = 1 << 1; const USER_WRITE = 1 << 1;
/// The mapping is not global across the address spaces /// The mapping is not global across the address spaces
const NON_GLOBAL = 1 << 2; const NON_GLOBAL = 1 << 2;
/// The mapping is marked dirty by the OS
const DIRTY = 1 << 3;
} }
} }

View File

@ -21,8 +21,6 @@ use core::{
}; };
use address::Virtualize; use address::Virtualize;
use alloc::boxed::Box;
use async_trait::async_trait;
use kernel_arch::{mem::PhysicalMemoryAllocator, Architecture, ArchitectureImpl}; use kernel_arch::{mem::PhysicalMemoryAllocator, Architecture, ArchitectureImpl};
use libk_mm_interface::{ use libk_mm_interface::{
address::{AsPhysicalAddress, PhysicalAddress}, address::{AsPhysicalAddress, PhysicalAddress},
@ -40,7 +38,7 @@ pub mod process;
#[cfg(any(target_os = "none", rust_analyzer))] #[cfg(any(target_os = "none", rust_analyzer))]
pub mod heap; pub mod heap;
pub use libk_mm_interface::table; pub use libk_mm_interface::{table, PageFaultKind};
pub struct TableAllocatorImpl; pub struct TableAllocatorImpl;
@ -67,8 +65,13 @@ pub enum VirtualPage {
Immediate(PhysicalAddress), Immediate(PhysicalAddress),
} }
pub struct OnDemandPage {
pub physical: PhysicalAddress,
pub writeable: bool,
}
pub trait PageProvider: Send + Sync { pub trait PageProvider: Send + Sync {
fn ondemand_fetch(&self, opaque: u64) -> Result<PhysicalAddress, Error>; fn ondemand_fetch(&self, offset: u64) -> Result<OnDemandPage, Error>;
fn get_page(&self, offset: u64) -> Result<VirtualPage, Error>; fn get_page(&self, offset: u64) -> Result<VirtualPage, Error>;

View File

@ -1,15 +1,12 @@
use core::{ use core::ops::{Deref, Range};
cmp,
ops::{Deref, Range},
};
use alloc::{boxed::Box, sync::Arc}; use alloc::sync::Arc;
use async_trait::async_trait;
use kernel_arch::ProcessAddressSpaceImpl; use kernel_arch::ProcessAddressSpaceImpl;
use libk_mm_interface::{ use libk_mm_interface::{
address::PhysicalAddress, address::PhysicalAddress,
process::ProcessAddressSpaceManager, process::{PageAttributeUpdate, ProcessAddressSpaceManager},
table::{MapAttributes, TableAllocator}, table::{MapAttributes, TableAllocator},
PageFaultKind,
}; };
use libk_util::sync::{IrqSafeSpinlock, IrqSafeSpinlockGuard}; use libk_util::sync::{IrqSafeSpinlock, IrqSafeSpinlockGuard};
use vmalloc::{RangeData, VirtualMemoryAllocator}; use vmalloc::{RangeData, VirtualMemoryAllocator};
@ -18,7 +15,7 @@ use yggdrasil_abi::error::Error;
use crate::{ use crate::{
phys, phys,
pointer::{PhysicalRef, PhysicalRefMut}, pointer::{PhysicalRef, PhysicalRefMut},
PageProvider, TableAllocatorImpl, VirtualPage, L3_PAGE_SIZE, OnDemandPage, PageProvider, TableAllocatorImpl, VirtualPage, L3_PAGE_SIZE,
}; };
/// Describes how the physical memory is provided for the mapping /// Describes how the physical memory is provided for the mapping
@ -62,7 +59,7 @@ impl VirtualRangeBacking {
} }
impl PageProvider for VirtualRangeBacking { impl PageProvider for VirtualRangeBacking {
fn ondemand_fetch(&self, opaque: u64) -> Result<PhysicalAddress, Error> { fn ondemand_fetch(&self, opaque: u64) -> Result<OnDemandPage, Error> {
match self { match self {
Self::Anonymous => unreachable!(), Self::Anonymous => unreachable!(),
Self::File(f) => f.file.ondemand_fetch(f.offset + opaque), Self::File(f) => f.file.ondemand_fetch(f.offset + opaque),
@ -356,13 +353,22 @@ impl<TA: TableAllocator> Inner<TA> {
Ok(()) Ok(())
} }
fn handle_fault(&mut self, address: usize) -> Result<(), Error> { fn handle_fault(&mut self, address: usize, kind: PageFaultKind) -> Result<(), Error> {
let (ondemand, write) = match kind {
PageFaultKind::WriteFault => (false, true),
PageFaultKind::TranslationFault { write: true } => (true, true),
PageFaultKind::TranslationFault { write: false } => (true, false),
_ => return Err(Error::DoesNotExist),
};
if ondemand {
// TODO hardcoded "prefetch" hint // TODO hardcoded "prefetch" hint
const PREFETCH_HINT: usize = 16; const PREFETCH_HINT: usize = 16;
let pfn = address / L3_PAGE_SIZE; let pfn = address / L3_PAGE_SIZE;
let (pfn_range, backing) = self.allocator.get(pfn).ok_or(Error::DoesNotExist)?; let (pfn_range, backing) = self.allocator.get(pfn).ok_or(Error::DoesNotExist)?;
let remaining = (pfn_range.end - pfn).min(PREFETCH_HINT); let remaining = (pfn_range.end - pfn).min(PREFETCH_HINT);
// TODO rollback // TODO rollback
for i in 0..remaining { for i in 0..remaining {
let address = (pfn + i) * L3_PAGE_SIZE; let address = (pfn + i) * L3_PAGE_SIZE;
@ -372,17 +378,50 @@ impl<TA: TableAllocator> Inner<TA> {
continue; continue;
} }
let phys = backing.ondemand_fetch(offset as u64)?; // TODO query cpu flags to determine whether it supports hardware dirty bit
// TODO don't guess attributes // tracking. If so, just map data read-write here
match unsafe { self.table.map_page(address, phys, MapAttributes::USER_READ) } { let page = backing.ondemand_fetch(offset as u64)?;
let mut attrs = MapAttributes::USER_READ;
if page.writeable {
// Used as an indicator the page can be made writeable, used on platforms
// without hardware dirty state tracking
attrs |= MapAttributes::DIRTY;
}
match unsafe { self.table.map_page(address, page.physical, attrs) } {
Ok(()) => (), Ok(()) => (),
Err(error) => { Err(error) => {
log::warn!("Failed to map on-demand resolved page: {error:?}"); log::warn!("Failed to map on-demand resolved page: {error:?}");
backing.release_page(offset as u64, phys, false).ok(); backing
.release_page(offset as u64, page.physical, false)
.ok();
return Err(error); return Err(error);
} }
} }
} }
}
if write && !cfg!(target_arch = "x86_64") {
// TODO this will break permission architecture, need to check if the range is actually
// writeable first
let (_, attrs) = self.table.translate(address)?;
if attrs.contains(MapAttributes::DIRTY) {
unsafe {
self.table.update_page_attributes(
address & !(L3_PAGE_SIZE - 1),
&PageAttributeUpdate {
user_write: Some(true),
dirty: Some(true),
},
)?;
}
} else {
log::warn!("Write to non-demand/non-dirty page @ {address:#x}");
return Err(Error::DoesNotExist);
}
}
Ok(()) Ok(())
} }
} }
@ -523,8 +562,8 @@ impl<TA: TableAllocator> ProcessAddressSpace<TA> {
} }
/// Handles a translation fault, possibly fetching on-demand pages /// Handles a translation fault, possibly fetching on-demand pages
pub fn handle_fault(&self, address: usize) -> Result<(), Error> { pub fn handle_fault(&self, address: usize, kind: PageFaultKind) -> Result<(), Error> {
self.inner.lock().handle_fault(address) self.inner.lock().handle_fault(address, kind)
} }
} }

View File

@ -3,7 +3,9 @@ use core::mem::MaybeUninit;
use alloc::{boxed::Box, sync::Arc}; use alloc::{boxed::Box, sync::Arc};
use async_trait::async_trait; use async_trait::async_trait;
use device_api::device::Device; use device_api::device::Device;
use libk_mm::{address::PhysicalAddress, table::MapAttributes, PageProvider, VirtualPage}; use libk_mm::{
address::PhysicalAddress, table::MapAttributes, OnDemandPage, PageProvider, VirtualPage,
};
use yggdrasil_abi::error::Error; use yggdrasil_abi::error::Error;
use crate::dma::{DmaBuffer, DmaSlice, DmaSliceMut}; use crate::dma::{DmaBuffer, DmaSlice, DmaSliceMut};
@ -32,7 +34,7 @@ impl Partition {
} }
impl PageProvider for Partition { impl PageProvider for Partition {
fn ondemand_fetch(&self, _opaque: u64) -> Result<PhysicalAddress, Error> { fn ondemand_fetch(&self, _opaque: u64) -> Result<OnDemandPage, Error> {
unimplemented!() unimplemented!()
} }

View File

@ -4,7 +4,8 @@ use alloc::{boxed::Box, sync::Arc};
use async_trait::async_trait; use async_trait::async_trait;
use device_api::device::Device; use device_api::device::Device;
use libk_mm::{ use libk_mm::{
address::PhysicalAddress, table::MapAttributes, PageProvider, VirtualPage, L3_PAGE_SIZE, address::PhysicalAddress, table::MapAttributes, OnDemandPage, PageProvider, VirtualPage,
L3_PAGE_SIZE,
}; };
use yggdrasil_abi::{ use yggdrasil_abi::{
bitflags, bitflags,
@ -232,7 +233,7 @@ impl PageProvider for DisplayWrapper {
// fn release_page(&self, offset: u64, phys: PhysicalAddress) -> Result<(), Error> { // fn release_page(&self, offset: u64, phys: PhysicalAddress) -> Result<(), Error> {
// self.device.release_page(offset, phys) // self.device.release_page(offset, phys)
// } // }
fn ondemand_fetch(&self, opaque: u64) -> Result<PhysicalAddress, Error> { fn ondemand_fetch(&self, opaque: u64) -> Result<OnDemandPage, Error> {
self.device.ondemand_fetch(opaque) self.device.ondemand_fetch(opaque)
} }

View File

@ -189,7 +189,7 @@ pub fn load_elf_from_file<F: Read + Seek>(
let (image_load_base, ip_offset) = let (image_load_base, ip_offset) =
elf_load_address(aslr, elf.ehdr.e_type, vaddr_min, image_load_size); elf_load_address(aslr, elf.ehdr.e_type, vaddr_min, image_load_size);
log::debug!( log::info!(
"Loading ELF virtual {:#x?} -> real {:#x?}", "Loading ELF virtual {:#x?} -> real {:#x?}",
vaddr_min..vaddr_max, vaddr_min..vaddr_max,
image_load_base..image_load_base + image_load_size image_load_base..image_load_base + image_load_size

View File

@ -144,6 +144,8 @@ fn setup_program_env(
_ => 0, _ => 0,
}; };
placer.align(size_of::<usize>())?;
// Put ProgramArgumentInner struct // Put ProgramArgumentInner struct
let arg_address = placer.position + virt; let arg_address = placer.position + virt;
@ -180,6 +182,12 @@ where
MapAttributes::USER_WRITE | MapAttributes::USER_READ | MapAttributes::NON_GLOBAL, MapAttributes::USER_WRITE | MapAttributes::USER_READ | MapAttributes::NON_GLOBAL,
)?; )?;
log::info!(
"stack: {:#x}..{:#x}",
virt_stack_base,
virt_stack_base + USER_STACK_PAGES * 0x1000
);
let mut auxv = vec![]; let mut auxv = vec![];
if let Some(tls_image) = image.tls_image.as_ref() { if let Some(tls_image) = image.tls_image.as_ref() {
if tls_image.master_copy_base != 0 { if tls_image.master_copy_base != 0 {

View File

@ -11,7 +11,7 @@ use kernel_arch::{
task::{Scheduler, TaskContext, TaskFrame}, task::{Scheduler, TaskContext, TaskFrame},
Architecture, ArchitectureImpl, CpuImpl, Architecture, ArchitectureImpl, CpuImpl,
}; };
use libk_mm::process::ProcessAddressSpace; use libk_mm::{process::ProcessAddressSpace, PageFaultKind};
use libk_util::{ use libk_util::{
event::BoolEvent, event::BoolEvent,
sync::{spin_rwlock::IrqSafeRwLock, IrqGuard, IrqSafeSpinlock}, sync::{spin_rwlock::IrqSafeRwLock, IrqGuard, IrqSafeSpinlock},
@ -674,8 +674,8 @@ impl CurrentThread {
} }
} }
pub fn handle_page_fault(&self, address: usize) -> Result<(), Error> { pub fn handle_page_fault(&self, address: usize, kind: PageFaultKind) -> Result<(), Error> {
self.address_space().handle_fault(address) self.address_space().handle_fault(address, kind)
} }
/// Sets up a return frame to handle a pending signal, if any is present in the task's queue. /// Sets up a return frame to handle a pending signal, if any is present in the task's queue.

View File

@ -12,7 +12,9 @@ use alloc::{
}; };
use async_trait::async_trait; use async_trait::async_trait;
use device::{BlockFile, CharFile}; use device::{BlockFile, CharFile};
use libk_mm::{address::PhysicalAddress, table::MapAttributes, PageProvider, VirtualPage}; use libk_mm::{
address::PhysicalAddress, table::MapAttributes, OnDemandPage, PageProvider, VirtualPage,
};
use libk_util::{ use libk_util::{
io::{ReadAt, WriteAt}, io::{ReadAt, WriteAt},
sync::{spin_rwlock::IrqSafeRwLock, IrqSafeSpinlock}, sync::{spin_rwlock::IrqSafeRwLock, IrqSafeSpinlock},
@ -421,7 +423,7 @@ impl File {
} }
impl PageProvider for File { impl PageProvider for File {
fn ondemand_fetch(&self, opaque: u64) -> Result<PhysicalAddress, Error> { fn ondemand_fetch(&self, opaque: u64) -> Result<OnDemandPage, Error> {
self.as_page_provider()?.ondemand_fetch(opaque) self.as_page_provider()?.ondemand_fetch(opaque)
} }

View File

@ -1,14 +1,12 @@
use alloc::boxed::Box;
use async_trait::async_trait;
use libk_mm::{ use libk_mm::{
address::PhysicalAddress, phys, pointer::PhysicalRef, table::MapAttributes, PageBox, address::PhysicalAddress, phys, pointer::PhysicalRef, table::MapAttributes, OnDemandPage,
PageProvider, VirtualPage, L3_PAGE_SIZE, PageBox, PageProvider, VirtualPage, L3_PAGE_SIZE,
}; };
use libk_util::sync::IrqSafeSpinlock; use libk_util::sync::IrqSafeSpinlock;
use yggdrasil_abi::{error::Error, io::SeekFrom}; use yggdrasil_abi::{error::Error, io::SeekFrom};
use super::InstanceData; use super::InstanceData;
use crate::{debug, vfs::node::NodeRef}; use crate::vfs::node::NodeRef;
#[derive(Clone)] #[derive(Clone)]
pub struct RegularFile { pub struct RegularFile {
@ -117,7 +115,7 @@ impl Drop for RegularFile {
} }
impl PageProvider for RegularFile { impl PageProvider for RegularFile {
fn ondemand_fetch(&self, opaque: u64) -> Result<PhysicalAddress, Error> { fn ondemand_fetch(&self, opaque: u64) -> Result<OnDemandPage, Error> {
assert_eq!(opaque as usize % L3_PAGE_SIZE, 0); assert_eq!(opaque as usize % L3_PAGE_SIZE, 0);
let reg = self.node.as_regular()?; let reg = self.node.as_regular()?;
let mut page = PageBox::new_slice(0, L3_PAGE_SIZE)?; let mut page = PageBox::new_slice(0, L3_PAGE_SIZE)?;
@ -131,10 +129,13 @@ impl PageProvider for RegularFile {
page[len..].fill(0); page[len..].fill(0);
} }
let page = PageBox::into_physical_raw(page); let page = PageBox::into_physical_raw(page);
Ok(page) Ok(OnDemandPage {
physical: page,
writeable: self.write,
})
} }
fn get_page(&self, offset: u64) -> Result<VirtualPage, Error> { fn get_page(&self, _offset: u64) -> Result<VirtualPage, Error> {
Ok(VirtualPage::OnDemand) Ok(VirtualPage::OnDemand)
} }
@ -161,9 +162,9 @@ impl PageProvider for RegularFile {
fn clone_page( fn clone_page(
&self, &self,
offset: u64, _offset: u64,
src_phys: PhysicalAddress, _src_phys: PhysicalAddress,
src_attrs: MapAttributes, _src_attrs: MapAttributes,
) -> Result<PhysicalAddress, Error> { ) -> Result<PhysicalAddress, Error> {
unimplemented!() unimplemented!()
} }

View File

@ -1,11 +1,10 @@
use core::mem::MaybeUninit; use core::mem::MaybeUninit;
use alloc::{boxed::Box, vec::Vec}; use alloc::vec::Vec;
use async_trait::async_trait;
use libk_mm::{ use libk_mm::{
address::{AsPhysicalAddress, PhysicalAddress}, address::{AsPhysicalAddress, PhysicalAddress},
table::MapAttributes, table::MapAttributes,
PageBox, PageProvider, VirtualPage, L3_PAGE_SIZE, OnDemandPage, PageBox, PageProvider, VirtualPage, L3_PAGE_SIZE,
}; };
use yggdrasil_abi::error::Error; use yggdrasil_abi::error::Error;
@ -28,7 +27,7 @@ impl SharedMemory {
} }
impl PageProvider for SharedMemory { impl PageProvider for SharedMemory {
fn ondemand_fetch(&self, _opaque: u64) -> Result<PhysicalAddress, Error> { fn ondemand_fetch(&self, _opaque: u64) -> Result<OnDemandPage, Error> {
unreachable!() unreachable!()
} }
@ -52,9 +51,9 @@ impl PageProvider for SharedMemory {
fn clone_page( fn clone_page(
&self, &self,
offset: u64, _offset: u64,
src_phys: PhysicalAddress, _src_phys: PhysicalAddress,
src_attrs: MapAttributes, _src_attrs: MapAttributes,
) -> Result<PhysicalAddress, Error> { ) -> Result<PhysicalAddress, Error> {
todo!() todo!()
} }

View File

@ -42,6 +42,7 @@ unsafe fn pre_init_mmu() {
TCR_EL1.write( TCR_EL1.write(
TCR_EL1::AS::ASID8Bits + TCR_EL1::AS::ASID8Bits +
TCR_EL1::A1::TTBR0 + TCR_EL1::A1::TTBR0 +
TCR_EL1::HD::CLEAR +
// General // General
TCR_EL1::IPS::Bits_48 + TCR_EL1::IPS::Bits_48 +
// TTBR0 // TTBR0

View File

@ -19,7 +19,7 @@ use kernel_arch_aarch64::{
mem::table::{EntryType, PageTable, L1, L2, L3}, mem::table::{EntryType, PageTable, L1, L2, L3},
}; };
use libk::{device::external_interrupt_controller, task::thread::Thread}; use libk::{device::external_interrupt_controller, task::thread::Thread};
use libk_mm::{address::PhysicalAddress, table::EntryLevelExt}; use libk_mm::{address::PhysicalAddress, table::EntryLevelExt, PageFaultKind};
use tock_registers::interfaces::{Readable, Writeable}; use tock_registers::interfaces::{Readable, Writeable};
use crate::{ use crate::{
@ -82,54 +82,27 @@ fn dump_irrecoverable_exception(frame: &ExceptionFrame, ec: u64, iss: u64) {
let far = FAR_EL1.get() as usize; let far = FAR_EL1.get() as usize;
let ttbr0 = TTBR0_EL1.get(); let ttbr0 = TTBR0_EL1.get();
log::error!(target: "raw", "SYNC exception:\n"); log::error!(target: ":raw", "SYNC exception:\n");
log::error!(target: "raw", "FAR: {:#x}\n", far); log::error!(target: ":raw", "FAR: {:#x}\n", far);
log::error!(target: "raw", "ELR: {:#x}\n", ELR_EL1.get()); log::error!(target: ":raw", "ELR: {:#x}\n", ELR_EL1.get());
log::error!(target: "raw", "ESR: {:#x}\n", ESR_EL1.get()); log::error!(target: ":raw", "ESR: {:#x}\n", ESR_EL1.get());
log::error!(target: "raw", "SP_EL0: {:#x}\n", SP_EL0.get()); log::error!(target: ":raw", "SP_EL0: {:#x}\n", SP_EL0.get());
log::error!(target: "raw", "TTBR0_EL1: {:#x}\n", ttbr0); log::error!(target: ":raw", "TTBR0_EL1: {:#x}\n", ttbr0);
log::error!(target: "raw", "TTBR1_EL1: {:#x}\n", TTBR1_EL1.get()); log::error!(target: ":raw", "TTBR1_EL1: {:#x}\n", TTBR1_EL1.get());
log::error!(target: "raw", "Register dump:\n"); log::error!(target: ":raw", "Register dump:\n");
log::error!(target: "raw", "{:?}\n", frame); log::error!(target: ":raw", "{:?}\n", frame);
log::error!(target: "raw", "FAR_EL1 page table walk:\n"); log::error!(target: ":raw", "FAR_EL1 page table walk:\n");
unsafe { unsafe {
perform_ptw(far, |level, result| { perform_ptw(far, |level, result| {
log::error!(target: "raw", "[{level}] {result}\n"); log::error!(target: ":raw", "[{level}] {result}\n");
}); });
} }
// if let Some(cpu) = cpu {
// // let current = cpu.queue().current_process();
// let current = cpu.current_thread_id().and_then(Thread::get);
// if let Some(current) = current {
// log::error!(target: "raw", "In thread {}\n", current.id);
// let space = current.address_space();
// if far < KERNEL_VIRT_OFFSET && space.as_address_with_asid() == ttbr0 {
// match space.translate(far) {
// Ok(phys) => log::error!(
// target: "raw",
// "FAR translation (manual): {:#x} -> {:#x}\n",
// far,
// phys
// ),
// Err(_) => log::error!(target: "raw", "FAR does not translate\n"),
// }
// let at_s1e0r = at_s1e0r(far);
// let at_s1e1r = at_s1e1r(far);
// log::error!(target: "raw", "at s1e0r: {far:#x} -> {at_s1e0r:#x?}\n");
// log::error!(target: "raw", "at s1e1r: {far:#x} -> {at_s1e1r:#x?}\n");
// }
// }
// }
match ec { match ec {
// Data abort from lower level // Data abort from lower level
0b100100 => { 0b100100 => {
log::error!(target: "raw", "Exception kind: Data Abort from EL0\n"); log::error!(target: ":raw", "Exception kind: Data Abort from EL0\n");
let dfsc = iss & 0x3F; let dfsc = iss & 0x3F;
if iss & (1 << 24) != 0 { if iss & (1 << 24) != 0 {
@ -143,7 +116,7 @@ fn dump_irrecoverable_exception(frame: &ExceptionFrame, ec: u64, iss: u64) {
let access_type_str = if iss & (1 << 6) != 0 { "write" } else { "read" }; let access_type_str = if iss & (1 << 6) != 0 { "write" } else { "read" };
log::error!( log::error!(
target: "raw", target: ":raw",
"Invalid {} of a {} to/from {:#x}\n", "Invalid {} of a {} to/from {:#x}\n",
access_type_str, access_type_str,
access_size_str, access_size_str,
@ -151,26 +124,26 @@ fn dump_irrecoverable_exception(frame: &ExceptionFrame, ec: u64, iss: u64) {
); );
} }
log::error!(target: "raw", "DFSC = {:#x}\n", dfsc); log::error!(target: ":raw", "DFSC = {:#x}\n", dfsc);
} }
// Instruction abort from lower level // Instruction abort from lower level
0b100000 => { 0b100000 => {
log::error!( log::error!(
target: "raw", target: ":raw",
"Exception kind: Instruction Abort from EL0\n" "Exception kind: Instruction Abort from EL0\n"
); );
let ifsc = iss & 0x3F; let ifsc = iss & 0x3F;
log::error!(target: "raw", "IFSC = {:#x}\n", ifsc); log::error!(target: ":raw", "IFSC = {:#x}\n", ifsc);
} }
_ => (), _ => (),
} }
log::error!(target: "raw", "System register dump:\n"); log::error!(target: ":raw", "System register dump:\n");
log::error!(target: "raw", "SCTLR_EL1 = {:#x}\n", SCTLR_EL1.get()); log::error!(target: ":raw", "SCTLR_EL1 = {:#x}\n", SCTLR_EL1.get());
log::error!(target: "raw", "TCR_EL1 = {:#x}\n", TCR_EL1.get()); log::error!(target: ":raw", "TCR_EL1 = {:#x}\n", TCR_EL1.get());
log::error!(target: "raw", "TPIDR_EL1 = {:#x}\n", TPIDR_EL1.get()); log::error!(target: ":raw", "TPIDR_EL1 = {:#x}\n", TPIDR_EL1.get());
log::error!(target: "raw", "TPIDR_EL0 = {:#x}\n", TPIDR_EL0.get()); log::error!(target: ":raw", "TPIDR_EL0 = {:#x}\n", TPIDR_EL0.get());
} }
#[no_mangle] #[no_mangle]
@ -289,13 +262,28 @@ fn el0_sync_inner(frame: &mut ExceptionFrame) {
*thread.name.read() *thread.name.read()
); );
thread.raise_signal(Signal::Aborted); thread.raise_signal(Signal::Aborted);
true false
} }
_ => { // Data abort from a lower EL
let thread = Thread::current(); 0b100100 => {
if ec == 0b100100 {
// Data abort from lower level
let thread = Thread::current(); let thread = Thread::current();
let dfsc = esr_el1 & 0x3F;
let wnr = esr_el1 & (1 << 6) != 0;
let fnv = esr_el1 & (1 << 10) != 0;
let far = FAR_EL1.get() as usize;
let kind = match dfsc {
// Translation fault, level 3
0b000111 => Some(PageFaultKind::TranslationFault { write: wnr }),
// Permission fault, level 3
0b001111 if wnr => Some(PageFaultKind::WriteFault),
_ => None,
};
if let Some(kind) = kind
&& !fnv
&& thread.handle_page_fault(far, kind).is_ok()
{
false
} else {
log::warn!( log::warn!(
"Data abort in {} {:?} at {:#x} with address {:#x}", "Data abort in {} {:?} at {:#x} with address {:#x}",
thread.id, thread.id,
@ -303,8 +291,12 @@ fn el0_sync_inner(frame: &mut ExceptionFrame) {
ELR_EL1.get(), ELR_EL1.get(),
FAR_EL1.get() FAR_EL1.get()
); );
thread.raise_signal(Signal::MemoryAccessViolation);
true
} }
}
_ => {
let thread = Thread::current();
thread.raise_signal(Signal::MemoryAccessViolation); thread.raise_signal(Signal::MemoryAccessViolation);
true true
} }

View File

@ -232,7 +232,7 @@ impl MessageInterruptController for Gicv2m {
device_tree_driver! { device_tree_driver! {
compatible: ["arm,gic-v2m-frame"], compatible: ["arm,gic-v2m-frame"],
driver: { driver: {
fn probe(&self, node: &Arc<Node>, context: &ProbeContext) -> Option<Arc<dyn Device>> { fn probe(&self, node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
let base = node.map_base(context, 0)?; let base = node.map_base(context, 0)?;
let parent = node.parent()?.as_interrupt_controller()?; let parent = node.parent()?.as_interrupt_controller()?;

View File

@ -267,7 +267,7 @@ impl GicPerCpu {
device_tree_driver! { device_tree_driver! {
compatible: ["arm,cortex-a15-gic", "arm,gic-400"], compatible: ["arm,cortex-a15-gic", "arm,gic-400"],
driver: { driver: {
fn probe(&self, node: &Arc<Node>, context: &ProbeContext) -> Option<Arc<dyn Device>> { fn probe(&self, node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
let gicd_range = node.map_range(context, 0)?; let gicd_range = node.map_range(context, 0)?;
let gicc_range = node.map_range(context, 1)?; let gicc_range = node.map_range(context, 1)?;

View File

@ -9,7 +9,10 @@ use device_api::{
interrupt::{Irq, LocalInterruptController}, interrupt::{Irq, LocalInterruptController},
ResetDevice, ResetDevice,
}; };
use device_tree::{driver::unflatten_device_tree, DeviceTree, DeviceTreeNodeExt}; use device_tree::{
driver::{unflatten_device_tree, InitSequence},
DeviceTree, DeviceTreeNodeExt,
};
use kernel_arch_aarch64::{ use kernel_arch_aarch64::{
mem::{ mem::{
self, self,
@ -214,7 +217,7 @@ impl AArch64 {
let node = stdout_path.and_then(device_tree::driver::find_node); let node = stdout_path.and_then(device_tree::driver::find_node);
if let Some(node) = node { if let Some(node) = node {
node.force_init()?; node.force_init(InitSequence::Early)?;
} }
// No stdout // No stdout
@ -285,6 +288,7 @@ impl AArch64 {
|node, error| { |node, error| {
log::error!("{}: {error:?}", node.name().unwrap_or("<unknown>")); log::error!("{}: {error:?}", node.name().unwrap_or("<unknown>"));
}, },
InitSequence::Early,
); );
device_tree::driver::init_irqs( device_tree::driver::init_irqs(
|_| (), |_| (),
@ -294,6 +298,7 @@ impl AArch64 {
node.name().unwrap_or("<unknown>") node.name().unwrap_or("<unknown>")
); );
}, },
InitSequence::Early,
); );
PciBusManager::probe_bus_devices()?; PciBusManager::probe_bus_devices()?;

View File

@ -91,7 +91,7 @@ impl ArmTimer {
device_tree_driver! { device_tree_driver! {
compatible: ["arm,armv8-timer"], compatible: ["arm,armv8-timer"],
driver: { driver: {
fn probe(&self, node: &Arc<Node>, _context: &ProbeContext) -> Option<Arc<dyn Device>> { fn probe(&self, node: &Arc<Node>, _context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
let irq = node.interrupt(1)?; let irq = node.interrupt(1)?;
Some(Arc::new(unsafe { ArmTimer::new(irq) })) Some(Arc::new(unsafe { ArmTimer::new(irq) }))
} }

View File

@ -5,6 +5,7 @@ use abi::{bitflags, primitive_enum, process::Signal};
use kernel_arch_x86::registers::{CR2, CR3}; use kernel_arch_x86::registers::{CR2, CR3};
use kernel_arch_x86_64::context::ExceptionFrame; use kernel_arch_x86_64::context::ExceptionFrame;
use libk::task::thread::Thread; use libk::task::thread::Thread;
use libk_mm::PageFaultKind;
use libk_util::sync::spin_rwlock::IrqSafeRwLock; use libk_util::sync::spin_rwlock::IrqSafeRwLock;
use tock_registers::interfaces::Readable; use tock_registers::interfaces::Readable;
@ -146,8 +147,16 @@ fn user_exception_inner(kind: ExceptionKind, frame: &mut ExceptionFrame) {
ExceptionKind::PageFault => { ExceptionKind::PageFault => {
let cr2 = CR2.get(); let cr2 = CR2.get();
let flags = PageFaultFlags::new(frame.exc_code as usize); let flags = PageFaultFlags::new(frame.exc_code as usize);
let kind = match (
flags.contains(PageFaultFlags::P),
flags.contains(PageFaultFlags::W),
) {
(true, true) => PageFaultKind::WriteFault,
(true, false) => PageFaultKind::Other,
(false, write) => PageFaultKind::TranslationFault { write },
};
if !flags.contains(PageFaultFlags::P) && thread.handle_page_fault(cr2).is_ok() { if thread.handle_page_fault(cr2, kind).is_ok() {
false false
} else { } else {
thread.raise_signal(Signal::MemoryAccessViolation); thread.raise_signal(Signal::MemoryAccessViolation);

View File

@ -38,10 +38,10 @@ struct Bcm2835Aux {
} }
impl ClockController for Bcm2835Aux { impl ClockController for Bcm2835Aux {
fn enable_clock(&self, clock: u32) -> Result<(), Error> { fn enable_clock(&self, clock: Option<u32>) -> Result<(), Error> {
let regs = self.regs.try_get().ok_or(Error::DoesNotExist)?.lock(); let regs = self.regs.try_get().ok_or(Error::DoesNotExist)?.lock();
match clock { match clock {
0 => { Some(0) => {
regs.AUX_ENABLES.modify(AUX_ENABLES::MU_ENABLE::SET); regs.AUX_ENABLES.modify(AUX_ENABLES::MU_ENABLE::SET);
Ok(()) Ok(())
} }
@ -49,7 +49,7 @@ impl ClockController for Bcm2835Aux {
} }
} }
fn disable_clock(&self, _clock: u32) -> Result<(), Error> { fn disable_clock(&self, _clock: Option<u32>) -> Result<(), Error> {
Err(Error::NotImplemented) Err(Error::NotImplemented)
} }
} }
@ -74,7 +74,7 @@ impl Device for Bcm2835Aux {
device_tree_driver! { device_tree_driver! {
compatible: ["brcm,bcm2835-aux"], compatible: ["brcm,bcm2835-aux"],
driver: { driver: {
fn probe(&self, node: &Arc<Node>, context: &ProbeContext) -> Option<Arc<dyn Device>> { fn probe(&self, node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
let base = node.map_base(context, 0)?; let base = node.map_base(context, 0)?;
Some(Arc::new(Bcm2835Aux { Some(Arc::new(Bcm2835Aux {

View File

@ -3,8 +3,6 @@
use core::mem::MaybeUninit; use core::mem::MaybeUninit;
use abi::error::Error; use abi::error::Error;
use alloc::boxed::Box;
use async_trait::async_trait;
use device_api::device::Device; use device_api::device::Device;
use libk::device::display::{ use libk::device::display::{
DisplayDevice, DisplayMode, DisplayOwner, DriverFlags, FramebufferInfo, PixelFormat, DisplayDevice, DisplayMode, DisplayOwner, DriverFlags, FramebufferInfo, PixelFormat,
@ -13,7 +11,7 @@ use libk_mm::{
address::PhysicalAddress, address::PhysicalAddress,
device::{DeviceMemoryAttributes, DeviceMemoryCaching, RawDeviceMemoryMapping}, device::{DeviceMemoryAttributes, DeviceMemoryCaching, RawDeviceMemoryMapping},
table::{EntryLevel, MapAttributes}, table::{EntryLevel, MapAttributes},
PageProvider, VirtualPage, OnDemandPage, PageProvider, VirtualPage,
}; };
use libk_util::sync::IrqSafeSpinlock; use libk_util::sync::IrqSafeSpinlock;
@ -91,7 +89,7 @@ impl LinearFramebuffer {
} }
impl PageProvider for LinearFramebuffer { impl PageProvider for LinearFramebuffer {
fn ondemand_fetch(&self, _opaque: u64) -> Result<PhysicalAddress, Error> { fn ondemand_fetch(&self, _opaque: u64) -> Result<OnDemandPage, Error> {
unreachable!() unreachable!()
} }

View File

@ -79,7 +79,7 @@ impl Psci {
device_tree_driver! { device_tree_driver! {
compatible: ["arm,psci-1.0", "arm,psci"], compatible: ["arm,psci-1.0", "arm,psci"],
driver: { driver: {
fn probe(&self, node: &Arc<Node>, _context: &ProbeContext) -> Option<Arc<dyn Device>> { fn probe(&self, node: &Arc<Node>, _context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
let method = node.property("method")?; let method = node.property("method")?;
let method = match method.as_str()? { let method = match method.as_str()? {
"hvc" => CallMethod::Hvc, "hvc" => CallMethod::Hvc,

View File

@ -8,13 +8,11 @@ use abi::{
}; };
use alloc::sync::Arc; use alloc::sync::Arc;
use device_api::{ use device_api::{
clock::ClockHandle,
device::{Device, DeviceInitContext}, device::{Device, DeviceInitContext},
interrupt::{FullIrq, InterruptHandler, IrqVector}, interrupt::{FullIrq, InterruptHandler, IrqVector},
}; };
use device_tree::{ use device_tree::driver::{device_tree_driver, Node, ProbeContext};
driver::{device_tree_driver, lookup_phandle, Node, ProbeContext},
DeviceTreePropertyRead,
};
use libk::{ use libk::{
debug::DebugSink, debug::DebugSink,
device::{external_interrupt_controller, manager::DEVICE_REGISTRY}, device::{external_interrupt_controller, manager::DEVICE_REGISTRY},
@ -65,9 +63,9 @@ struct Inner {
} }
pub struct Bcm2835AuxUart { pub struct Bcm2835AuxUart {
node: Arc<Node>,
base: PhysicalAddress, base: PhysicalAddress,
irq: FullIrq, irq: FullIrq,
clock: ClockHandle,
inner: OneTimeInit<Arc<Terminal<Inner>>>, inner: OneTimeInit<Arc<Terminal<Inner>>>,
} }
@ -151,8 +149,7 @@ impl Device for Bcm2835AuxUart {
unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> { unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
// TODO initialize pinctrl // TODO initialize pinctrl
// NOTE: might as well make it an error if clock cannot be initialized self.clock.enable()?;
self.enable_clock();
let regs = unsafe { DeviceMemoryIo::map(self.base, Default::default()) }?; let regs = unsafe { DeviceMemoryIo::map(self.base, Default::default()) }?;
let config = TerminalOptions { let config = TerminalOptions {
@ -195,35 +192,19 @@ impl Device for Bcm2835AuxUart {
} }
} }
impl Bcm2835AuxUart {
fn enable_clock(&self) -> Option<()> {
let clocks = self.node.property("clocks")?;
let (phandle, index) = clocks.read_cells(0, (1, 1))?;
let phandle = phandle as u32;
let index = index as u32;
let clock = lookup_phandle(phandle, true)?;
let clock = clock.as_clock_controller()?;
clock.enable_clock(index).ok()?;
Some(())
}
}
// TODO handle pinctrl // TODO handle pinctrl
device_tree_driver! { device_tree_driver! {
compatible: ["brcm,bcm2835-aux-uart"], compatible: ["brcm,bcm2835-aux-uart"],
driver: { driver: {
fn probe(&self, node: &Arc<Node>, context: &ProbeContext) -> Option<Arc<dyn Device>> { fn probe(&self, node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
let base = node.map_base(context, 0)?; let base = node.map_base(context, 0)?;
let irq = node.interrupt(0)?; let irq = node.interrupt(0)?;
let clock = node.clock(0)?;
Some(Arc::new(Bcm2835AuxUart { Some(Arc::new(Bcm2835AuxUart {
node: node.clone(),
base, base,
irq, irq,
clock,
inner: OneTimeInit::new(), inner: OneTimeInit::new(),
})) }))
} }

View File

@ -181,7 +181,7 @@ impl Device for Pl011 {
device_tree_driver! { device_tree_driver! {
compatible: ["arm,pl011"], compatible: ["arm,pl011"],
driver: { driver: {
fn probe(&self, node: &Arc<Node>, context: &ProbeContext) -> Option<Arc<dyn Device>> { fn probe(&self, node: &Arc<Node>, context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
let base = node.map_base(context, 0)?; let base = node.map_base(context, 0)?;
let irq = node.interrupt(0)?; let irq = node.interrupt(0)?;

30
test.c
View File

@ -1,12 +1,32 @@
#include <sys/mman.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <dlfcn.h> #include <dlfcn.h>
#include <stdio.h> #include <stdio.h>
#include <fcntl.h>
int main(int argc, char **argv) { int main(int argc, char **argv) {
char buffer[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; int fd = open("test.dat", O_RDWR | O_CREAT, 0644);
strncpy(buffer, "abcdefghijkl", sizeof(buffer)); if (fd < 0) {
for (int i = 0; i < sizeof(buffer); ++i) { perror("open()");
printf("[%d] 0x%hhx\n", i, buffer[i]); return EXIT_FAILURE;
} }
return 0; if (ftruncate(fd, 0x1000 * 4) != 0) {
perror("ftruncate()");
return EXIT_FAILURE;
}
void *data;
if ((data = mmap(NULL, 0x1000 * 4, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
perror("mmap()");
return EXIT_FAILURE;
}
memset(data + 0x1000 * 0, 'a', 0x1000);
memset(data + 0x1000 * 1, 'b', 0x1000);
memset(data + 0x1000 * 2, 'c', 0x1000);
memset(data + 0x1000 * 3, 'd', 0x1000);
close(fd);
return EXIT_SUCCESS;
} }

View File

@ -1,7 +1,10 @@
use std::{ use std::{
collections::BTreeMap, collections::BTreeMap,
process::ExitCode, process::ExitCode,
sync::{atomic::{AtomicBool, Ordering}, Arc, Mutex}, sync::{
atomic::{AtomicBool, Ordering},
Arc, Mutex,
},
}; };
use cross::signal::set_sigint_handler; use cross::signal::set_sigint_handler;

View File

@ -1,6 +1,6 @@
use core::{ use core::{
cmp::Ordering, cmp::Ordering,
ffi::{c_char, c_int, CStr}, ffi::{c_char, c_int},
}; };
use super::locale::locale_t; use super::locale::locale_t;

View File

@ -72,13 +72,6 @@ unsafe extern "C" fn __ygglibc_entry(
signal::init(true); signal::init(true);
init::init(); init::init();
let sp = unsafe {
let sp: usize;
core::arch::asm!("mov %rsp, {0}", out(reg) sp, options(att_syntax));
sp
};
log::info!("sp = {sp:#x}");
// Setup args // Setup args
let args = env::handle_kernel_argument(arg); let args = env::handle_kernel_argument(arg);
let mut c_args = Vec::new(); let mut c_args = Vec::new();

View File

@ -1,4 +1,3 @@
#![allow(unused)]
use std::{ use std::{
fs, fs,
path::{Path, PathBuf}, path::{Path, PathBuf},
@ -127,25 +126,19 @@ fn build_test_c_program(
fn install_ygglibc(env: &BuildEnv, ygglibc: &Ygglibc) -> Result<(), Error> { fn install_ygglibc(env: &BuildEnv, ygglibc: &Ygglibc) -> Result<(), Error> {
log::info!("Installing ygglibc into LLVM sysroot"); log::info!("Installing ygglibc into LLVM sysroot");
// let dst_lib_dir = env.llvm_sysroot.join("lib"); let dst_lib_dir = env.llvm_sysroot.join("lib");
// let dst_include_dir = env.llvm_sysroot.join("usr/include"); let dst_include_dir = env.llvm_sysroot.join("usr/include");
let _ = env;
let _ = ygglibc.crt0_file;
// fs::create_dir_all(&dst_lib_dir)?; fs::create_dir_all(&dst_lib_dir)?;
// fs::create_dir_all(&dst_include_dir)?; fs::create_dir_all(&dst_include_dir)?;
// fs::copy(&ygglibc.static_lib_file, dst_lib_dir.join("libygglibc.a"))?; fs::copy(&ygglibc.static_lib_file, dst_lib_dir.join("libygglibc.a"))?;
// fs::copy(&ygglibc.shared_lib_file, dst_lib_dir.join("libygglibc.so"))?; fs::copy(&ygglibc.shared_lib_file, dst_lib_dir.join("libygglibc.so"))?;
// fs::copy(&ygglibc.crt0_file, dst_lib_dir.join("crt0.o"))?; fs::copy(&ygglibc.crt0_file, dst_lib_dir.join("crt0.o"))?;
let _ = ygglibc.static_lib_file; for path in ygglibc.include_paths.iter() {
let _ = ygglibc.shared_lib_file; util::copy_dir_recursive(path, &dst_include_dir)?;
let _ = ygglibc.include_paths; }
// for path in ygglibc.include_paths.iter() {
// util::copy_dir_recursive(path, &dst_include_dir)?;
// }
Ok(()) Ok(())
} }
@ -219,8 +212,7 @@ fn install_openlibm(env: &BuildEnv, libm: &Openlibm) -> Result<(), Error> {
fs::copy(&libm.static_lib_file, env.llvm_sysroot.join("lib/libm.a"))?; fs::copy(&libm.static_lib_file, env.llvm_sysroot.join("lib/libm.a"))?;
fs::copy(&libm.shared_lib_file, env.llvm_sysroot.join("lib/libm.so"))?; fs::copy(&libm.shared_lib_file, env.llvm_sysroot.join("lib/libm.so"))?;
let _ = libm.include_path; util::copy_dir_recursive(&libm.include_path, env.llvm_sysroot.join("usr/include"))?;
// util::copy_dir_recursive(&libm.include_path, env.llvm_sysroot.join("usr/include"))?;
Ok(()) Ok(())
} }