arch/aarch64: fix aarch64 build
This commit is contained in:
parent
b760a5bad9
commit
0e8860c719
@ -19,9 +19,6 @@ vmalloc = { path = "lib/vmalloc" }
|
|||||||
device-api-macros = { path = "lib/device-api/macros" }
|
device-api-macros = { path = "lib/device-api/macros" }
|
||||||
|
|
||||||
# Drivers
|
# Drivers
|
||||||
ygg_driver_pci = { path = "driver/bus/pci" }
|
|
||||||
ygg_driver_nvme = { path = "driver/block/nvme" }
|
|
||||||
ygg_driver_ahci = { path = "driver/block/ahci" }
|
|
||||||
ygg_driver_block = { path = "driver/block/core" }
|
ygg_driver_block = { path = "driver/block/core" }
|
||||||
kernel-fs = { path = "driver/fs/kernel-fs" }
|
kernel-fs = { path = "driver/fs/kernel-fs" }
|
||||||
memfs = { path = "driver/fs/memfs" }
|
memfs = { path = "driver/fs/memfs" }
|
||||||
@ -57,6 +54,9 @@ acpi_lib = { git = "https://github.com/alnyan/acpi.git", package = "acpi", branc
|
|||||||
acpi-system = { git = "https://github.com/alnyan/acpi-system.git" }
|
acpi-system = { git = "https://github.com/alnyan/acpi-system.git" }
|
||||||
# TODO currently only supported here
|
# TODO currently only supported here
|
||||||
xhci_lib = { git = "https://github.com/rust-osdev/xhci.git", package = "xhci" }
|
xhci_lib = { git = "https://github.com/rust-osdev/xhci.git", package = "xhci" }
|
||||||
|
ygg_driver_pci = { path = "driver/bus/pci" }
|
||||||
|
ygg_driver_nvme = { path = "driver/block/nvme" }
|
||||||
|
ygg_driver_ahci = { path = "driver/block/ahci" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["fb_console"]
|
default = ["fb_console"]
|
||||||
|
@ -5,6 +5,14 @@ use aarch64_cpu::{
|
|||||||
asm::barrier,
|
asm::barrier,
|
||||||
registers::{CPACR_EL1, ID_AA64MMFR0_EL1, MAIR_EL1, SCTLR_EL1, TCR_EL1, TTBR0_EL1},
|
registers::{CPACR_EL1, ID_AA64MMFR0_EL1, MAIR_EL1, SCTLR_EL1, TCR_EL1, TTBR0_EL1},
|
||||||
};
|
};
|
||||||
|
use kernel_fs::devfs;
|
||||||
|
use kernel_util::{
|
||||||
|
mem::{
|
||||||
|
address::{IntoRaw, PhysicalAddress},
|
||||||
|
table::EntryLevel,
|
||||||
|
},
|
||||||
|
runtime,
|
||||||
|
};
|
||||||
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
|
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
@ -13,10 +21,8 @@ use super::{
|
|||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::{aarch64::mem::table::L3, Architecture},
|
arch::{aarch64::mem::table::L3, Architecture},
|
||||||
fs::devfs,
|
|
||||||
kernel_main, kernel_secondary_main,
|
kernel_main, kernel_secondary_main,
|
||||||
mem::{address::IntoRaw, phys, table::EntryLevel, PhysicalAddress, KERNEL_VIRT_OFFSET},
|
mem::{phys, KERNEL_VIRT_OFFSET},
|
||||||
task::runtime,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
unsafe fn pre_init_mmu() {
|
unsafe fn pre_init_mmu() {
|
||||||
|
@ -1,12 +1,22 @@
|
|||||||
//! Per-CPU data structures
|
//! Per-CPU data structures
|
||||||
use core::sync::atomic::Ordering;
|
use core::{
|
||||||
|
ops::{Deref, DerefMut},
|
||||||
|
sync::atomic::Ordering,
|
||||||
|
};
|
||||||
|
|
||||||
use aarch64_cpu::registers::{MPIDR_EL1, TPIDR_EL1};
|
use aarch64_cpu::registers::{MPIDR_EL1, TPIDR_EL1};
|
||||||
use alloc::{boxed::Box, vec::Vec};
|
use alloc::{boxed::Box, vec::Vec};
|
||||||
use kernel_util::{sync::IrqSafeSpinlock, util::OneTimeInit};
|
use kernel_util::{
|
||||||
|
sync::{IrqGuard, IrqSafeSpinlock},
|
||||||
|
util::OneTimeInit,
|
||||||
|
};
|
||||||
use tock_registers::interfaces::{Readable, Writeable};
|
use tock_registers::interfaces::{Readable, Writeable};
|
||||||
|
|
||||||
use crate::{arch::CpuMessage, panic, task::sched::CpuQueue};
|
use crate::{
|
||||||
|
arch::{CpuAccess, CpuMessage, LocalCpuAccess},
|
||||||
|
panic,
|
||||||
|
task::{sched::CpuQueue, thread::ThreadId},
|
||||||
|
};
|
||||||
|
|
||||||
use super::smp::CPU_COUNT;
|
use super::smp::CPU_COUNT;
|
||||||
|
|
||||||
@ -18,8 +28,17 @@ pub struct Cpu {
|
|||||||
id: u32,
|
id: u32,
|
||||||
|
|
||||||
queue: OneTimeInit<&'static CpuQueue>,
|
queue: OneTimeInit<&'static CpuQueue>,
|
||||||
|
thread_id: Option<ThreadId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Handle allowing safe access to the local CPU.
|
||||||
|
///
|
||||||
|
/// # Note
|
||||||
|
///
|
||||||
|
/// Obtaining this handle prevents IRQs from being delivered to ensure the context having this
|
||||||
|
/// struct cannot be interrupted by another (which could obtain it as well).
|
||||||
|
pub struct LocalCpu(&'static mut Cpu, IrqGuard);
|
||||||
|
|
||||||
struct IpiQueue {
|
struct IpiQueue {
|
||||||
data: IrqSafeSpinlock<Option<CpuMessage>>,
|
data: IrqSafeSpinlock<Option<CpuMessage>>,
|
||||||
}
|
}
|
||||||
@ -47,17 +66,11 @@ impl IpiQueue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Cpu {
|
impl Cpu {
|
||||||
/// Returns a safe reference to the local CPU's private data structure
|
/// Sets up global list of interprocessor message queues
|
||||||
#[inline(always)]
|
pub fn init_ipi_queues() {
|
||||||
pub fn local<'a>() -> &'a Self {
|
IPI_QUEUES.init(Vec::from_iter(
|
||||||
Self::get_local().unwrap()
|
(0..CPU_COUNT.load(Ordering::Acquire)).map(|_| IpiQueue::new()),
|
||||||
}
|
));
|
||||||
|
|
||||||
/// Returns the local CPU data structure reference, if it was set up
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn get_local<'a>() -> Option<&'a Self> {
|
|
||||||
let tpidr = TPIDR_EL1.get() as *mut Cpu;
|
|
||||||
unsafe { tpidr.as_ref() }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets up the local CPU's private data structure.
|
/// Sets up the local CPU's private data structure.
|
||||||
@ -69,60 +82,81 @@ impl Cpu {
|
|||||||
let this = Box::new(Cpu {
|
let this = Box::new(Cpu {
|
||||||
id: Self::local_id(),
|
id: Self::local_id(),
|
||||||
queue: OneTimeInit::new(),
|
queue: OneTimeInit::new(),
|
||||||
|
thread_id: None,
|
||||||
});
|
});
|
||||||
TPIDR_EL1.set(Box::into_raw(this) as _);
|
TPIDR_EL1.set(Box::into_raw(this) as _);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Sets up the local CPU's execution queue.
|
impl CpuAccess for Cpu {
|
||||||
pub fn init_queue(&self, queue: &'static CpuQueue) {
|
type Local = LocalCpu;
|
||||||
self.queue.init(queue);
|
|
||||||
|
fn id(&self) -> u32 {
|
||||||
|
self.id
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the local CPU's execution queue.
|
fn local_id() -> u32 {
|
||||||
pub fn queue(&self) -> &'static CpuQueue {
|
|
||||||
self.queue.get()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the index of the local CPU
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn local_id() -> u32 {
|
|
||||||
(MPIDR_EL1.get() & 0xFF) as _
|
(MPIDR_EL1.get() & 0xFF) as _
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inserts an IPI message to the back of the target CPU's message queue
|
fn try_local() -> Option<Self::Local> {
|
||||||
pub fn push_ipi_queue(cpu_id: u32, msg: CpuMessage) {
|
let guard = IrqGuard::acquire();
|
||||||
let ipi_queue = &IPI_QUEUES.get()[cpu_id as usize];
|
let tpidr = TPIDR_EL1.get() as *mut Cpu;
|
||||||
ipi_queue.push(msg);
|
unsafe { tpidr.as_mut() }.map(|cpu| LocalCpu(cpu, guard))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pops the first IPI message received for this CPU.
|
fn get_queue(&self) -> Option<&'static CpuQueue> {
|
||||||
///
|
self.queue.try_get().copied()
|
||||||
/// # Note
|
|
||||||
///
|
|
||||||
/// Currently the queue consists of only one entry, so the CPU will only receive the last one.
|
|
||||||
pub fn get_ipi(&self) -> Option<CpuMessage> {
|
|
||||||
let ipi_queue = &IPI_QUEUES.get()[self.id as usize];
|
|
||||||
ipi_queue.pop()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets up global list of interprocessor message queues
|
fn init_queue(&mut self, queue: &'static CpuQueue) {
|
||||||
pub fn init_ipi_queues() {
|
self.queue.init(queue);
|
||||||
IPI_QUEUES.init(Vec::from_iter(
|
|
||||||
(0..CPU_COUNT.load(Ordering::Acquire)).map(|_| IpiQueue::new()),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets an IPI message from the processor's queue and takes corresponding actions. If there is
|
unsafe fn set_current_thread_id(&mut self, id: Option<ThreadId>) {
|
||||||
/// none, this is treated as a spurious IPI and ignored. See [CpuMessage].
|
self.thread_id = id;
|
||||||
pub fn handle_ipi(&self) {
|
}
|
||||||
let Some(msg) = self.get_ipi() else {
|
|
||||||
warnln!("Spurious IPI in cpu{}", self.id);
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
match msg {
|
fn current_thread_id(&self) -> Option<ThreadId> {
|
||||||
CpuMessage::Panic => panic::panic_secondary(),
|
self.thread_id
|
||||||
CpuMessage::Shutdown => todo!(),
|
}
|
||||||
|
|
||||||
|
fn push_ipi(id: u32, msg: CpuMessage) {
|
||||||
|
if let Some(q) = IPI_QUEUES.try_get().and_then(|q| q.get(id as usize)) {
|
||||||
|
q.push(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_ipi(&mut self) {
|
||||||
|
if let Some(ipi) = IPI_QUEUES
|
||||||
|
.try_get()
|
||||||
|
.and_then(|q| q.get(self.id() as usize))
|
||||||
|
.and_then(|q| q.pop())
|
||||||
|
{
|
||||||
|
match ipi {
|
||||||
|
CpuMessage::Panic => panic::panic_secondary(),
|
||||||
|
CpuMessage::Shutdown => todo!(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl LocalCpuAccess<Cpu> for LocalCpu {
|
||||||
|
fn into_guard(self) -> IrqGuard {
|
||||||
|
self.1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for LocalCpu {
|
||||||
|
type Target = Cpu;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for LocalCpu {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -323,11 +323,7 @@ fn el0_sync_inner(frame: &mut ExceptionFrame) {
|
|||||||
// BRK in AArch64
|
// BRK in AArch64
|
||||||
0b111100 => {
|
0b111100 => {
|
||||||
let thread = Thread::current();
|
let thread = Thread::current();
|
||||||
warnln!(
|
warnln!("Thread {} {:?} hit a breakpoint", thread.id, thread.name);
|
||||||
"Thread {} {:?} hit a breakpoint",
|
|
||||||
thread.id(),
|
|
||||||
thread.name()
|
|
||||||
);
|
|
||||||
thread.raise_signal(Signal::Aborted);
|
thread.raise_signal(Signal::Aborted);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@ -337,8 +333,8 @@ fn el0_sync_inner(frame: &mut ExceptionFrame) {
|
|||||||
let thread = Thread::current();
|
let thread = Thread::current();
|
||||||
warnln!(
|
warnln!(
|
||||||
"Data abort in {} {:?} at {:#x} with address {:#x}",
|
"Data abort in {} {:?} at {:#x} with address {:#x}",
|
||||||
thread.id(),
|
thread.id,
|
||||||
thread.name(),
|
thread.name,
|
||||||
ELR_EL1.get(),
|
ELR_EL1.get(),
|
||||||
FAR_EL1.get()
|
FAR_EL1.get()
|
||||||
);
|
);
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
//! ARM GICv2 CPU registers
|
//! ARM GICv2 CPU registers
|
||||||
|
use kernel_util::mem::device::DeviceMemoryIo;
|
||||||
use tock_registers::{
|
use tock_registers::{
|
||||||
interfaces::{Readable, Writeable},
|
interfaces::{Readable, Writeable},
|
||||||
register_bitfields, register_structs,
|
register_bitfields, register_structs,
|
||||||
registers::ReadWrite,
|
registers::ReadWrite,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::mem::device::DeviceMemoryIo;
|
|
||||||
|
|
||||||
register_bitfields! {
|
register_bitfields! {
|
||||||
u32,
|
u32,
|
||||||
CTLR [
|
CTLR [
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
//! ARM GICv2 Distributor registers
|
//! ARM GICv2 Distributor registers
|
||||||
use device_api::interrupt::IpiDeliveryTarget;
|
use device_api::interrupt::IpiDeliveryTarget;
|
||||||
|
use kernel_util::mem::device::DeviceMemoryIo;
|
||||||
use spinning_top::Spinlock;
|
use spinning_top::Spinlock;
|
||||||
use tock_registers::{
|
use tock_registers::{
|
||||||
interfaces::{ReadWriteable, Readable, Writeable},
|
interfaces::{ReadWriteable, Readable, Writeable},
|
||||||
@ -7,8 +8,6 @@ use tock_registers::{
|
|||||||
registers::{ReadOnly, ReadWrite, WriteOnly},
|
registers::{ReadOnly, ReadWrite, WriteOnly},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::mem::device::DeviceMemoryIo;
|
|
||||||
|
|
||||||
register_bitfields! {
|
register_bitfields! {
|
||||||
u32,
|
u32,
|
||||||
CTLR [
|
CTLR [
|
||||||
|
@ -12,17 +12,19 @@ use device_api::{
|
|||||||
},
|
},
|
||||||
Device,
|
Device,
|
||||||
};
|
};
|
||||||
use kernel_util::{sync::IrqSafeSpinlock, util::OneTimeInit};
|
use kernel_util::{
|
||||||
|
mem::{
|
||||||
|
address::{FromRaw, PhysicalAddress},
|
||||||
|
device::{DeviceMemoryIo, RawDeviceMemoryMapping},
|
||||||
|
},
|
||||||
|
sync::IrqSafeSpinlock,
|
||||||
|
util::OneTimeInit,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::{aarch64::IrqNumber, Architecture, CpuMessage},
|
arch::{aarch64::IrqNumber, Architecture, CpuAccess, CpuMessage},
|
||||||
device::devtree::{self, DevTreeIndexPropExt},
|
device::devtree::{self, DevTreeIndexPropExt},
|
||||||
device_tree_driver,
|
device_tree_driver,
|
||||||
mem::{
|
|
||||||
address::FromRaw,
|
|
||||||
device::{DeviceMemoryIo, RawDeviceMemoryMapping},
|
|
||||||
PhysicalAddress,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use self::{gicc::Gicc, gicd::Gicd};
|
use self::{gicc::Gicc, gicd::Gicd};
|
||||||
@ -141,7 +143,7 @@ impl LocalInterruptController for Gic {
|
|||||||
let local = Cpu::local_id();
|
let local = Cpu::local_id();
|
||||||
for i in 0..CPU_COUNT.load(Ordering::Acquire) {
|
for i in 0..CPU_COUNT.load(Ordering::Acquire) {
|
||||||
if i != local as usize {
|
if i != local as usize {
|
||||||
Cpu::push_ipi_queue(i as u32, msg);
|
Cpu::push_ipi(i as u32, msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,19 +6,21 @@ use core::{
|
|||||||
|
|
||||||
use abi::error::Error;
|
use abi::error::Error;
|
||||||
use cfg_if::cfg_if;
|
use cfg_if::cfg_if;
|
||||||
use kernel_util::util::OneTimeInit;
|
use kernel_util::{
|
||||||
|
mem::{
|
||||||
|
address::{FromRaw, PhysicalAddress},
|
||||||
|
device::RawDeviceMemoryMapping,
|
||||||
|
table::{EntryLevel, EntryLevelExt},
|
||||||
|
},
|
||||||
|
util::OneTimeInit,
|
||||||
|
};
|
||||||
use memtables::aarch64::{FixedTables, KERNEL_L3_COUNT};
|
use memtables::aarch64::{FixedTables, KERNEL_L3_COUNT};
|
||||||
|
|
||||||
use aarch64_cpu::registers::{TTBR0_EL1, TTBR1_EL1};
|
use aarch64_cpu::registers::{TTBR0_EL1, TTBR1_EL1};
|
||||||
use static_assertions::const_assert_eq;
|
use static_assertions::const_assert_eq;
|
||||||
use tock_registers::interfaces::Writeable;
|
use tock_registers::interfaces::Writeable;
|
||||||
|
|
||||||
use crate::mem::{
|
use crate::mem::{address::KernelImageObject, KERNEL_VIRT_OFFSET};
|
||||||
address::{FromRaw, IntoRaw, KernelImageObject},
|
|
||||||
device::RawDeviceMemoryMapping,
|
|
||||||
table::EntryLevel,
|
|
||||||
PhysicalAddress, KERNEL_VIRT_OFFSET,
|
|
||||||
};
|
|
||||||
|
|
||||||
use self::table::{PageAttributes, PageEntry, PageTable, L1, L2, L3};
|
use self::table::{PageAttributes, PageEntry, PageTable, L1, L2, L3};
|
||||||
|
|
||||||
@ -36,8 +38,8 @@ cfg_if! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Precomputed mappings
|
// Precomputed mappings
|
||||||
const KERNEL_L1_INDEX: usize = L1::index(KERNEL_VIRT_OFFSET + KERNEL_PHYS_BASE);
|
const KERNEL_L1_INDEX: usize = (KERNEL_VIRT_OFFSET + KERNEL_PHYS_BASE).page_index::<L1>();
|
||||||
const KERNEL_START_L2_INDEX: usize = L2::index(KERNEL_VIRT_OFFSET + KERNEL_PHYS_BASE);
|
const KERNEL_START_L2_INDEX: usize = (KERNEL_VIRT_OFFSET + KERNEL_PHYS_BASE).page_index::<L2>();
|
||||||
const KERNEL_END_L2_INDEX: usize = KERNEL_START_L2_INDEX + KERNEL_L3_COUNT;
|
const KERNEL_END_L2_INDEX: usize = KERNEL_START_L2_INDEX + KERNEL_L3_COUNT;
|
||||||
|
|
||||||
// Must not be zero, should be at 4MiB
|
// Must not be zero, should be at 4MiB
|
||||||
@ -177,7 +179,7 @@ unsafe fn unmap_early_page(address: usize) {
|
|||||||
panic!("Tried to unmap invalid early mapping: {:#x}", address);
|
panic!("Tried to unmap invalid early mapping: {:#x}", address);
|
||||||
}
|
}
|
||||||
|
|
||||||
let l3i = L3::index(address - EARLY_MAPPING_OFFSET);
|
let l3i = (address - EARLY_MAPPING_OFFSET).page_index::<L3>();
|
||||||
|
|
||||||
assert!(EARLY_MAPPING_L3[l3i].is_present());
|
assert!(EARLY_MAPPING_L3[l3i].is_present());
|
||||||
EARLY_MAPPING_L3[l3i] = PageEntry::INVALID;
|
EARLY_MAPPING_L3[l3i] = PageEntry::INVALID;
|
||||||
@ -262,14 +264,14 @@ pub(super) unsafe fn map_device_memory(
|
|||||||
) -> Result<RawDeviceMemoryMapping, Error> {
|
) -> Result<RawDeviceMemoryMapping, Error> {
|
||||||
// debugln!("Map {}B @ {:#x}", size, base);
|
// debugln!("Map {}B @ {:#x}", size, base);
|
||||||
let l3_aligned = base.page_align_down::<L3>();
|
let l3_aligned = base.page_align_down::<L3>();
|
||||||
let l3_offset = L3::page_offset(base.into_raw());
|
let l3_offset = base.page_offset::<L3>();
|
||||||
let page_count = (l3_offset + size + L3::SIZE - 1) / L3::SIZE;
|
let page_count = (l3_offset + size).page_count::<L3>();
|
||||||
|
|
||||||
if page_count > 256 {
|
if page_count > 256 {
|
||||||
// Large mapping, use L2 mapping instead
|
// Large mapping, use L2 mapping instead
|
||||||
let l2_aligned = base.page_align_down::<L2>();
|
let l2_aligned = base.page_align_down::<L2>();
|
||||||
let l2_offset = L2::page_offset(base.into_raw());
|
let l2_offset = base.page_offset::<L2>();
|
||||||
let page_count = (l2_offset + size + L2::SIZE - 1) / L2::SIZE;
|
let page_count = (l2_offset + size).page_count::<L2>();
|
||||||
|
|
||||||
let base_address = map_device_memory_l2(l2_aligned, page_count)?;
|
let base_address = map_device_memory_l2(l2_aligned, page_count)?;
|
||||||
let address = base_address + l2_offset;
|
let address = base_address + l2_offset;
|
||||||
@ -304,8 +306,8 @@ pub(super) unsafe fn unmap_device_memory(map: &RawDeviceMemoryMapping) {
|
|||||||
L3::SIZE => {
|
L3::SIZE => {
|
||||||
for i in 0..map.page_count {
|
for i in 0..map.page_count {
|
||||||
let page = map.base_address + i * L3::SIZE;
|
let page = map.base_address + i * L3::SIZE;
|
||||||
let l2i = L2::index(page);
|
let l2i = page.page_index::<L2>();
|
||||||
let l3i = L3::index(page);
|
let l3i = page.page_index::<L3>();
|
||||||
assert!(DEVICE_MAPPING_L3S[l2i][l3i].is_present());
|
assert!(DEVICE_MAPPING_L3S[l2i][l3i].is_present());
|
||||||
DEVICE_MAPPING_L3S[l2i][l3i] = PageEntry::INVALID;
|
DEVICE_MAPPING_L3S[l2i][l3i] = PageEntry::INVALID;
|
||||||
|
|
||||||
|
@ -2,14 +2,16 @@
|
|||||||
use core::sync::atomic::{AtomicU8, Ordering};
|
use core::sync::atomic::{AtomicU8, Ordering};
|
||||||
|
|
||||||
use abi::error::Error;
|
use abi::error::Error;
|
||||||
|
use kernel_util::mem::{
|
||||||
|
address::{AsPhysicalAddress, PhysicalAddress},
|
||||||
|
pointer::PhysicalRefMut,
|
||||||
|
table::{EntryLevel, EntryLevelExt},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::mem::{
|
use crate::mem::{
|
||||||
address::AsPhysicalAddress,
|
|
||||||
phys,
|
phys,
|
||||||
pointer::PhysicalRefMut,
|
|
||||||
process::ProcessAddressSpaceManager,
|
process::ProcessAddressSpaceManager,
|
||||||
table::{EntryLevel, MapAttributes, NextPageTable},
|
table::{MapAttributes, NextPageTable},
|
||||||
PhysicalAddress,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::table::{PageEntry, PageTable, L1, L2, L3};
|
use super::table::{PageEntry, PageTable, L1, L2, L3};
|
||||||
@ -75,9 +77,9 @@ impl ProcessAddressSpaceImpl {
|
|||||||
entry: PageEntry<L3>,
|
entry: PageEntry<L3>,
|
||||||
overwrite: bool,
|
overwrite: bool,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let l1i = L1::index(virt);
|
let l1i = virt.page_index::<L1>();
|
||||||
let l2i = L2::index(virt);
|
let l2i = virt.page_index::<L2>();
|
||||||
let l3i = L3::index(virt);
|
let l3i = virt.page_index::<L3>();
|
||||||
|
|
||||||
let mut l2 = self.l1.get_mut_or_alloc(l1i)?;
|
let mut l2 = self.l1.get_mut_or_alloc(l1i)?;
|
||||||
let mut l3 = l2.get_mut_or_alloc(l2i)?;
|
let mut l3 = l2.get_mut_or_alloc(l2i)?;
|
||||||
@ -93,9 +95,9 @@ impl ProcessAddressSpaceImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn pop_l3_entry(&mut self, virt: usize) -> Result<PhysicalAddress, Error> {
|
fn pop_l3_entry(&mut self, virt: usize) -> Result<PhysicalAddress, Error> {
|
||||||
let l1i = L1::index(virt);
|
let l1i = virt.page_index::<L1>();
|
||||||
let l2i = L2::index(virt);
|
let l2i = virt.page_index::<L2>();
|
||||||
let l3i = L3::index(virt);
|
let l3i = virt.page_index::<L3>();
|
||||||
|
|
||||||
// TODO somehow drop tables if they're known to be empty?
|
// 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 l2 = self.l1.get_mut(l1i).ok_or(Error::DoesNotExist)?;
|
||||||
@ -110,9 +112,9 @@ impl ProcessAddressSpaceImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn read_l3_entry(&self, virt: usize) -> Option<(PhysicalAddress, MapAttributes)> {
|
fn read_l3_entry(&self, virt: usize) -> Option<(PhysicalAddress, MapAttributes)> {
|
||||||
let l1i = L1::index(virt);
|
let l1i = virt.page_index::<L1>();
|
||||||
let l2i = L2::index(virt);
|
let l2i = virt.page_index::<L2>();
|
||||||
let l3i = L3::index(virt);
|
let l3i = virt.page_index::<L3>();
|
||||||
|
|
||||||
let l2 = self.l1.get(l1i)?;
|
let l2 = self.l1.get(l1i)?;
|
||||||
let l3 = l2.get(l2i)?;
|
let l3 = l2.get(l2i)?;
|
||||||
|
@ -5,13 +5,15 @@ use core::{
|
|||||||
|
|
||||||
use abi::error::Error;
|
use abi::error::Error;
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
|
use kernel_util::mem::{
|
||||||
|
address::{AsPhysicalAddress, FromRaw, IntoRaw, PhysicalAddress},
|
||||||
|
pointer::{PhysicalRef, PhysicalRefMut},
|
||||||
|
table::EntryLevel,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::mem::{
|
use crate::mem::{
|
||||||
address::{AsPhysicalAddress, FromRaw, IntoRaw},
|
|
||||||
phys,
|
phys,
|
||||||
pointer::{PhysicalRef, PhysicalRefMut},
|
table::{MapAttributes, NextPageTable, NonTerminalEntryLevel},
|
||||||
table::{EntryLevel, MapAttributes, NextPageTable, NonTerminalEntryLevel},
|
|
||||||
PhysicalAddress,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
@ -60,23 +62,23 @@ pub struct L2;
|
|||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct L3;
|
pub struct L3;
|
||||||
|
|
||||||
impl const EntryLevel for L1 {
|
|
||||||
const SHIFT: usize = 30;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NonTerminalEntryLevel for L1 {
|
impl NonTerminalEntryLevel for L1 {
|
||||||
type NextLevel = L2;
|
type NextLevel = L2;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl const EntryLevel for L2 {
|
|
||||||
const SHIFT: usize = 21;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NonTerminalEntryLevel for L2 {
|
impl NonTerminalEntryLevel for L2 {
|
||||||
type NextLevel = L3;
|
type NextLevel = L3;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl const EntryLevel for L3 {
|
impl EntryLevel for L1 {
|
||||||
|
const SHIFT: usize = 30;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EntryLevel for L2 {
|
||||||
|
const SHIFT: usize = 21;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EntryLevel for L3 {
|
||||||
const SHIFT: usize = 12;
|
const SHIFT: usize = 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,15 @@ use device_api::{
|
|||||||
};
|
};
|
||||||
use fdt_rs::base::DevTree;
|
use fdt_rs::base::DevTree;
|
||||||
use git_version::git_version;
|
use git_version::git_version;
|
||||||
use kernel_util::util::OneTimeInit;
|
use kernel_util::{
|
||||||
|
mem::{
|
||||||
|
address::{FromRaw, IntoRaw, PhysicalAddress},
|
||||||
|
device::RawDeviceMemoryMapping,
|
||||||
|
pointer::PhysicalRef,
|
||||||
|
table::{EntryLevel, EntryLevelExt},
|
||||||
|
},
|
||||||
|
util::OneTimeInit,
|
||||||
|
};
|
||||||
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
|
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -29,13 +37,8 @@ use crate::{
|
|||||||
},
|
},
|
||||||
fs::{Initrd, INITRD_DATA},
|
fs::{Initrd, INITRD_DATA},
|
||||||
mem::{
|
mem::{
|
||||||
address::{FromRaw, IntoRaw},
|
|
||||||
device::RawDeviceMemoryMapping,
|
|
||||||
heap,
|
heap,
|
||||||
phys::{self, reserved::reserve_region, PhysicalMemoryRegion},
|
phys::{self, reserved::reserve_region, PhysicalMemoryRegion},
|
||||||
pointer::PhysicalRef,
|
|
||||||
table::EntryLevel,
|
|
||||||
PhysicalAddress,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -80,6 +83,8 @@ impl Architecture for AArch64 {
|
|||||||
|
|
||||||
type IrqNumber = IrqNumber;
|
type IrqNumber = IrqNumber;
|
||||||
|
|
||||||
|
type L3 = L3;
|
||||||
|
|
||||||
unsafe fn start_application_processors(&self) {
|
unsafe fn start_application_processors(&self) {
|
||||||
let dt = self.dt.get();
|
let dt = self.dt.get();
|
||||||
if let Err(error) = smp::start_ap_cores(dt) {
|
if let Err(error) = smp::start_ap_cores(dt) {
|
||||||
@ -125,7 +130,7 @@ impl Architecture for AArch64 {
|
|||||||
_memory_start: PhysicalAddress,
|
_memory_start: PhysicalAddress,
|
||||||
memory_end: PhysicalAddress,
|
memory_end: PhysicalAddress,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let end_l1i = L1::index(memory_end.page_align_up::<L1>().into_raw());
|
let end_l1i = memory_end.page_align_up::<L1>().page_index::<L1>();
|
||||||
if end_l1i > mem::RAM_MAPPING_L1_COUNT {
|
if end_l1i > mem::RAM_MAPPING_L1_COUNT {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
@ -142,25 +147,23 @@ impl Architecture for AArch64 {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn virtualize(address: PhysicalAddress) -> Result<usize, Error> {
|
fn virtualize(address: u64) -> usize {
|
||||||
let raw: usize = address.into_raw();
|
let address = address as usize;
|
||||||
if raw < *mem::MEMORY_LIMIT.get() {
|
if address < *mem::MEMORY_LIMIT.get() {
|
||||||
Ok(raw + mem::RAM_MAPPING_OFFSET)
|
address + mem::RAM_MAPPING_OFFSET
|
||||||
} else {
|
} else {
|
||||||
errorln!("Invalid physical address: {:#x}", address);
|
panic!("Invalid physical address: {:#x}", address);
|
||||||
Err(Error::InvalidMemoryOperation)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn physicalize(address: usize) -> Result<PhysicalAddress, Error> {
|
fn physicalize(address: usize) -> u64 {
|
||||||
if address < mem::RAM_MAPPING_OFFSET
|
if address < mem::RAM_MAPPING_OFFSET
|
||||||
|| address - mem::RAM_MAPPING_OFFSET >= *mem::MEMORY_LIMIT.get()
|
|| address - mem::RAM_MAPPING_OFFSET >= *mem::MEMORY_LIMIT.get()
|
||||||
{
|
{
|
||||||
errorln!("Not a virtualized physical address: {:#x}", address);
|
panic!("Not a virtualized physical address: {:#x}", address);
|
||||||
return Err(Error::InvalidMemoryOperation);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(PhysicalAddress::from_raw(address - mem::RAM_MAPPING_OFFSET))
|
(address - mem::RAM_MAPPING_OFFSET) as _
|
||||||
}
|
}
|
||||||
|
|
||||||
fn local_interrupt_controller(
|
fn local_interrupt_controller(
|
||||||
@ -362,23 +365,22 @@ impl AArch64 {
|
|||||||
infoln!("Initializing aarch64 platform");
|
infoln!("Initializing aarch64 platform");
|
||||||
|
|
||||||
let nodes = dt.root().children();
|
let nodes = dt.root().children();
|
||||||
if let Err(error) = devtree::enumerate_dt(
|
if let Err(error) =
|
||||||
address_cells,
|
devtree::enumerate_dt(address_cells, size_cells, nodes, |_, probe| {
|
||||||
size_cells,
|
|
||||||
nodes,
|
|
||||||
|_, probe| {
|
|
||||||
// Skip chosen-stdout, already initialized
|
// Skip chosen-stdout, already initialized
|
||||||
if let Some(ref chosen_stdout) = chosen_stdout && chosen_stdout.name() == probe.node.name() {
|
if let Some(ref chosen_stdout) = chosen_stdout
|
||||||
return Ok(());
|
&& chosen_stdout.name() == probe.node.name()
|
||||||
}
|
{
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
if let Some((device, _)) = devtree::probe_dt_node(&probe) {
|
if let Some((device, _)) = devtree::probe_dt_node(&probe) {
|
||||||
device.init()?;
|
device.init()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
})
|
||||||
) {
|
{
|
||||||
warnln!(
|
warnln!(
|
||||||
"{} errors encountered when initializing platform devices",
|
"{} errors encountered when initializing platform devices",
|
||||||
error
|
error
|
||||||
|
@ -6,12 +6,12 @@ use aarch64_cpu::registers::{CNTFRQ_EL0, CNTPCT_EL0, CNTP_CTL_EL0, CNTP_TVAL_EL0
|
|||||||
use abi::error::Error;
|
use abi::error::Error;
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
use device_api::{interrupt::InterruptHandler, timer::MonotonicTimestampProviderDevice, Device};
|
use device_api::{interrupt::InterruptHandler, timer::MonotonicTimestampProviderDevice, Device};
|
||||||
|
use kernel_util::runtime;
|
||||||
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
|
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::{aarch64::IrqNumber, Architecture, ARCHITECTURE},
|
arch::{aarch64::IrqNumber, Architecture, CpuAccess, ARCHITECTURE},
|
||||||
device_tree_driver,
|
device_tree_driver,
|
||||||
task::runtime,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::cpu::Cpu;
|
use super::cpu::Cpu;
|
||||||
|
@ -251,7 +251,9 @@ pub trait CpuAccess: Sized {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the ID of the local processor or 0 if the processor has not yet been initialized
|
/// Returns the ID of the local processor or 0 if the processor has not yet been initialized
|
||||||
fn local_id() -> u32;
|
fn local_id() -> u32 {
|
||||||
|
Self::try_local().map(|cpu| cpu.id()).unwrap_or(0)
|
||||||
|
}
|
||||||
|
|
||||||
/// Initializes the CPU's scheduling queue.
|
/// Initializes the CPU's scheduling queue.
|
||||||
///
|
///
|
||||||
@ -281,6 +283,18 @@ pub trait CpuAccess: Sized {
|
|||||||
///
|
///
|
||||||
/// Only meant to be called from within the scheduler.
|
/// Only meant to be called from within the scheduler.
|
||||||
unsafe fn set_current_thread_id(&mut self, id: Option<ThreadId>);
|
unsafe fn set_current_thread_id(&mut self, id: Option<ThreadId>);
|
||||||
|
|
||||||
|
/// Push an IPI message to the CPU's queue
|
||||||
|
fn push_ipi(id: u32, msg: CpuMessage) {
|
||||||
|
let _ = id;
|
||||||
|
let _ = msg;
|
||||||
|
// Not implemented by default
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pops an IPI message (if any is present) from the CPU's queue and handles it
|
||||||
|
fn handle_ipi(&mut self) {
|
||||||
|
// Not implemented by default
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// External API for architecture specifics
|
// External API for architecture specifics
|
||||||
|
@ -9,11 +9,9 @@ use fdt_rs::{
|
|||||||
index::{iters::DevTreeIndexNodeSiblingIter, DevTreeIndex, DevTreeIndexNode, DevTreeIndexProp},
|
index::{iters::DevTreeIndexNodeSiblingIter, DevTreeIndex, DevTreeIndexNode, DevTreeIndexProp},
|
||||||
prelude::PropReader,
|
prelude::PropReader,
|
||||||
};
|
};
|
||||||
|
use kernel_util::mem::address::{FromRaw, PhysicalAddress};
|
||||||
|
|
||||||
use crate::{
|
use crate::{debug::LogLevel, mem::phys::PhysicalMemoryRegion};
|
||||||
debug::LogLevel,
|
|
||||||
mem::{address::FromRaw, phys::PhysicalMemoryRegion, PhysicalAddress},
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::register_device;
|
use super::register_device;
|
||||||
|
|
||||||
|
@ -2,25 +2,32 @@
|
|||||||
use abi::{error::Error, io::DeviceRequest};
|
use abi::{error::Error, io::DeviceRequest};
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
use device_api::{interrupt::InterruptHandler, serial::SerialDevice, Device};
|
use device_api::{interrupt::InterruptHandler, serial::SerialDevice, Device};
|
||||||
use kernel_util::{sync::IrqSafeSpinlock, util::OneTimeInit};
|
use futures_util::task::{Context, Poll};
|
||||||
|
use kernel_fs::devfs::{self, CharDeviceType};
|
||||||
|
use kernel_util::{
|
||||||
|
block,
|
||||||
|
mem::{
|
||||||
|
address::{FromRaw, PhysicalAddress},
|
||||||
|
device::DeviceMemoryIo,
|
||||||
|
},
|
||||||
|
sync::IrqSafeSpinlock,
|
||||||
|
util::OneTimeInit,
|
||||||
|
};
|
||||||
use tock_registers::{
|
use tock_registers::{
|
||||||
interfaces::{ReadWriteable, Readable, Writeable},
|
interfaces::{ReadWriteable, Readable, Writeable},
|
||||||
register_bitfields, register_structs,
|
register_bitfields, register_structs,
|
||||||
registers::{ReadOnly, ReadWrite, WriteOnly},
|
registers::{ReadOnly, ReadWrite, WriteOnly},
|
||||||
};
|
};
|
||||||
use vfs::CharDevice;
|
use vfs::{CharDevice, FileReadiness};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::{aarch64::IrqNumber, Architecture, ARCHITECTURE},
|
arch::{aarch64::IrqNumber, Architecture, ARCHITECTURE},
|
||||||
block,
|
|
||||||
debug::{self, DebugSink, LogLevel},
|
debug::{self, DebugSink, LogLevel},
|
||||||
device::{
|
device::{
|
||||||
devtree::{self, DevTreeIndexPropExt},
|
devtree::{self, DevTreeIndexPropExt},
|
||||||
tty::{TtyContext, TtyDevice},
|
tty::{TtyContext, TtyDevice},
|
||||||
},
|
},
|
||||||
device_tree_driver,
|
device_tree_driver,
|
||||||
fs::devfs::{self, CharDeviceType},
|
|
||||||
mem::{address::FromRaw, device::DeviceMemoryIo, PhysicalAddress},
|
|
||||||
task::process::ProcessId,
|
task::process::ProcessId,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -108,6 +115,12 @@ impl TtyDevice for Pl011 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FileReadiness for Pl011 {
|
||||||
|
fn poll_read(&self, _cx: &mut Context<'_>) -> Poll<Result<(), Error>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// impl CharDevice for Pl011 {
|
// impl CharDevice for Pl011 {
|
||||||
// fn write(&self, blocking: bool, data: &[u8]) -> Result<usize, Error> {
|
// fn write(&self, blocking: bool, data: &[u8]) -> Result<usize, Error> {
|
||||||
// assert!(blocking);
|
// assert!(blocking);
|
||||||
|
@ -214,5 +214,6 @@ static QUEUES: OneTimeInit<Vec<CpuQueue>> = OneTimeInit::new();
|
|||||||
|
|
||||||
/// Initializes the global queue list
|
/// Initializes the global queue list
|
||||||
pub fn init_queues(queues: Vec<CpuQueue>) {
|
pub fn init_queues(queues: Vec<CpuQueue>) {
|
||||||
|
debugln!("init_queues!!!");
|
||||||
QUEUES.init(queues);
|
QUEUES.init(queues);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user