2023-07-18 18:03:45 +03:00
|
|
|
//! AArch64 architecture and platforms implementation
|
|
|
|
|
2024-12-13 23:35:17 +02:00
|
|
|
use core::sync::atomic::{self, Ordering};
|
2023-07-18 18:03:45 +03:00
|
|
|
|
2024-12-15 15:20:09 +02:00
|
|
|
use aarch64_cpu::registers::{CNTP_CTL_EL0, CNTP_TVAL_EL0};
|
2023-07-18 18:03:45 +03:00
|
|
|
use abi::error::Error;
|
2024-12-10 11:52:26 +02:00
|
|
|
use alloc::sync::Arc;
|
2023-08-13 21:23:58 +03:00
|
|
|
use device_api::{
|
2024-11-30 23:51:02 +02:00
|
|
|
interrupt::{Irq, LocalInterruptController},
|
2023-08-18 22:53:58 +03:00
|
|
|
ResetDevice,
|
2023-08-13 21:23:58 +03:00
|
|
|
};
|
2024-12-16 12:56:05 +02:00
|
|
|
use device_tree::{driver::unflatten_device_tree, DeviceTree, DeviceTreeNodeExt};
|
2024-02-08 15:50:25 +02:00
|
|
|
use kernel_arch_aarch64::{
|
|
|
|
mem::{
|
2024-12-15 15:20:09 +02:00
|
|
|
self,
|
2024-06-09 13:43:56 +03:00
|
|
|
table::{L1, L3},
|
|
|
|
EarlyMapping, MEMORY_LIMIT, RAM_MAPPING_L1_COUNT,
|
2024-02-08 15:50:25 +02:00
|
|
|
},
|
|
|
|
ArchitectureImpl, PerCpuData,
|
2024-02-06 12:27:02 +02:00
|
|
|
};
|
2024-12-17 19:12:39 +02:00
|
|
|
use libk::{arch::Cpu, config, debug, device::external_interrupt_controller};
|
2024-02-05 11:55:50 +02:00
|
|
|
use libk_mm::{
|
2024-07-25 11:58:47 +03:00
|
|
|
address::PhysicalAddress,
|
2024-12-13 23:35:17 +02:00
|
|
|
phys::{self, reserved::reserve_region, PhysicalMemoryRegion},
|
2024-02-05 11:55:50 +02:00
|
|
|
pointer::PhysicalRef,
|
2024-06-09 13:43:56 +03:00
|
|
|
table::EntryLevelExt,
|
2024-01-04 23:04:34 +02:00
|
|
|
};
|
2024-02-05 12:35:09 +02:00
|
|
|
use libk_util::OneTimeInit;
|
2024-12-15 15:20:09 +02:00
|
|
|
use tock_registers::interfaces::Writeable;
|
2024-02-03 20:44:04 +02:00
|
|
|
use ygg_driver_pci::PciBusManager;
|
2023-07-18 18:03:45 +03:00
|
|
|
|
|
|
|
use crate::{
|
2024-12-13 23:35:17 +02:00
|
|
|
// device::power::arm_psci::Psci,
|
2024-12-16 14:24:46 +02:00
|
|
|
device::{power::arm_psci::Psci, MACHINE_NAME},
|
2023-12-05 10:27:56 +02:00
|
|
|
fs::{Initrd, INITRD_DATA},
|
2024-12-13 23:35:17 +02:00
|
|
|
util::call_init_array,
|
2023-07-18 18:03:45 +03:00
|
|
|
};
|
|
|
|
|
2024-02-08 15:50:25 +02:00
|
|
|
use self::gic::Gic;
|
|
|
|
|
2024-02-07 13:06:17 +02:00
|
|
|
use super::Platform;
|
2023-07-18 18:03:45 +03:00
|
|
|
|
|
|
|
pub mod boot;
|
|
|
|
pub mod exception;
|
|
|
|
pub mod gic;
|
|
|
|
pub mod smp;
|
|
|
|
pub mod timer;
|
|
|
|
|
2023-11-16 00:16:38 +02:00
|
|
|
const BOOT_STACK_SIZE: usize = 4096 * 32;
|
2023-07-18 18:03:45 +03:00
|
|
|
|
|
|
|
#[derive(Clone, Copy)]
|
|
|
|
#[repr(C, align(0x20))]
|
2024-07-27 14:37:46 +03:00
|
|
|
struct BootStack<const SIZE: usize> {
|
|
|
|
data: [u8; SIZE],
|
2023-07-18 18:03:45 +03:00
|
|
|
}
|
|
|
|
|
2023-12-07 12:50:54 +02:00
|
|
|
/// AArch64 architecture implementation
|
2023-07-18 18:03:45 +03:00
|
|
|
pub struct AArch64 {
|
|
|
|
dt: OneTimeInit<DeviceTree<'static>>,
|
2023-08-13 21:23:58 +03:00
|
|
|
|
2023-12-07 12:50:54 +02:00
|
|
|
/// Optional instance of PSCI on this platform
|
2024-12-16 14:24:46 +02:00
|
|
|
pub psci: OneTimeInit<Arc<Psci>>,
|
2024-12-10 11:52:26 +02:00
|
|
|
reset: OneTimeInit<Arc<dyn ResetDevice>>,
|
2023-11-16 00:16:38 +02:00
|
|
|
initrd: OneTimeInit<PhysicalRef<'static, [u8]>>,
|
2024-12-16 14:24:46 +02:00
|
|
|
machine_compatible: OneTimeInit<&'static str>,
|
2023-11-16 00:16:38 +02:00
|
|
|
}
|
2023-08-21 17:26:44 +03:00
|
|
|
|
2024-07-27 14:37:46 +03:00
|
|
|
impl<const SIZE: usize> BootStack<SIZE> {
|
|
|
|
pub const fn zeroed() -> Self {
|
|
|
|
Self { data: [0; SIZE] }
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn top_addr(&self) -> usize {
|
|
|
|
unsafe { self.data.as_ptr().add(SIZE).addr() }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-05 13:44:21 +02:00
|
|
|
impl Platform for AArch64 {
|
2023-07-18 18:03:45 +03:00
|
|
|
const KERNEL_VIRT_OFFSET: usize = 0xFFFFFF8000000000;
|
|
|
|
|
2024-01-04 23:04:34 +02:00
|
|
|
type L3 = L3;
|
|
|
|
|
2023-08-18 22:53:58 +03:00
|
|
|
unsafe fn start_application_processors(&self) {
|
2024-12-16 14:24:46 +02:00
|
|
|
if let Some(compatible) = self.machine_compatible.try_get() {
|
|
|
|
if *compatible == "raspberrypi,4-model-b" {
|
|
|
|
log::warn!("raspi4b: cache workaround disable SMP");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-18 22:53:58 +03:00
|
|
|
let dt = self.dt.get();
|
2023-11-16 00:16:38 +02:00
|
|
|
if let Err(error) = smp::start_ap_cores(dt) {
|
2024-11-30 23:51:02 +02:00
|
|
|
log::error!("Could not initialize AP CPUs: {:?}", error);
|
2023-08-18 22:53:58 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-10 11:52:26 +02:00
|
|
|
fn register_reset_device(&self, reset: Arc<dyn ResetDevice>) -> Result<(), Error> {
|
2023-11-16 00:16:38 +02:00
|
|
|
self.reset.init(reset);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2023-08-13 21:23:58 +03:00
|
|
|
unsafe fn reset(&self) -> ! {
|
2024-12-16 14:24:46 +02:00
|
|
|
if let Some(reset) = self.reset.try_get() {
|
|
|
|
reset.reset()
|
|
|
|
} else {
|
|
|
|
let psci = self.psci.get();
|
|
|
|
psci.reset()
|
|
|
|
}
|
2023-08-13 21:23:58 +03:00
|
|
|
}
|
2023-07-18 18:03:45 +03:00
|
|
|
}
|
|
|
|
|
2024-12-10 11:52:26 +02:00
|
|
|
static GIC: OneTimeInit<Arc<Gic>> = OneTimeInit::new();
|
2024-02-08 15:50:25 +02:00
|
|
|
|
2023-07-18 18:03:45 +03:00
|
|
|
impl AArch64 {
|
2024-12-10 11:52:26 +02:00
|
|
|
fn set_gic(gic: Arc<Gic>) {
|
2024-02-08 15:50:25 +02:00
|
|
|
GIC.init(gic);
|
|
|
|
}
|
|
|
|
|
2024-02-05 14:45:17 +02:00
|
|
|
fn map_physical_memory<I: Iterator<Item = PhysicalMemoryRegion> + Clone>(
|
|
|
|
_it: I,
|
|
|
|
_memory_start: PhysicalAddress,
|
|
|
|
memory_end: PhysicalAddress,
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
let end_l1i = memory_end.page_align_up::<L1>().page_index::<L1>();
|
2024-02-06 12:27:02 +02:00
|
|
|
if end_l1i > RAM_MAPPING_L1_COUNT {
|
2024-11-05 22:00:10 +02:00
|
|
|
panic!("TODO: partial physical memory mapping");
|
2024-02-05 14:45:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Map 1GiB chunks
|
|
|
|
for index in 0..end_l1i {
|
|
|
|
unsafe {
|
2024-02-06 12:27:02 +02:00
|
|
|
kernel_arch_aarch64::mem::map_ram_l1(index);
|
2024-02-05 14:45:17 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-25 11:58:47 +03:00
|
|
|
MEMORY_LIMIT.store(memory_end.into_usize(), Ordering::Release);
|
2024-02-05 14:45:17 +02:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2023-11-16 00:16:38 +02:00
|
|
|
unsafe fn init_memory_management(&'static self, dtb: PhysicalAddress) -> Result<(), Error> {
|
|
|
|
// Initialize the runtime mappings
|
2024-02-06 12:27:02 +02:00
|
|
|
kernel_arch_aarch64::mem::init_fixed_tables();
|
2023-11-16 00:16:38 +02:00
|
|
|
|
|
|
|
// Extract the size of the device tree
|
|
|
|
let dtb_size = {
|
2024-02-04 15:18:34 +02:00
|
|
|
let dtb_header = EarlyMapping::<u8>::map_slice(dtb, DeviceTree::MIN_HEADER_SIZE)?;
|
2024-12-13 23:35:17 +02:00
|
|
|
DeviceTree::read_totalsize(dtb_header.as_ref()).map_err(|_| Error::InvalidArgument)?
|
2023-11-16 00:16:38 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
reserve_region(
|
|
|
|
"dtb",
|
|
|
|
PhysicalMemoryRegion {
|
|
|
|
base: dtb,
|
|
|
|
size: (dtb_size + 0xFFF) & !0xFFF,
|
|
|
|
},
|
|
|
|
);
|
|
|
|
|
|
|
|
let dtb_slice = EarlyMapping::<u8>::map_slice(dtb, dtb_size)?;
|
2024-12-16 12:56:05 +02:00
|
|
|
let dt = DeviceTree::from_raw(dtb_slice.as_ptr() as usize)?;
|
2023-11-16 00:16:38 +02:00
|
|
|
|
|
|
|
// Setup initrd from the dt
|
2024-12-13 23:35:17 +02:00
|
|
|
let initrd = dt.chosen_initrd();
|
2023-07-18 18:03:45 +03:00
|
|
|
|
2023-11-16 00:16:38 +02:00
|
|
|
if let Some((start, end)) = initrd {
|
|
|
|
let aligned_start = start.page_align_down::<L3>();
|
|
|
|
let aligned_end = end.page_align_up::<L3>();
|
|
|
|
|
|
|
|
let size = aligned_end - aligned_start;
|
2023-07-19 21:58:59 +03:00
|
|
|
reserve_region(
|
|
|
|
"initrd",
|
|
|
|
PhysicalMemoryRegion {
|
2023-11-16 00:16:38 +02:00
|
|
|
base: aligned_start,
|
|
|
|
size,
|
2023-07-19 21:58:59 +03:00
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2023-11-16 00:16:38 +02:00
|
|
|
// Initialize the physical memory
|
2024-12-16 12:56:05 +02:00
|
|
|
phys::init_from_iter(dt.memory_regions(), Self::map_physical_memory)?;
|
2023-08-08 20:00:24 +03:00
|
|
|
|
2023-11-16 00:16:38 +02:00
|
|
|
// EarlyMapping for DTB no longer needed, it lives in physical memory and can be obtained
|
|
|
|
// through PhysicalRef
|
|
|
|
let dtb_slice: PhysicalRef<'static, [u8]> = PhysicalRef::map_slice(dtb, dtb_size);
|
2024-12-16 12:56:05 +02:00
|
|
|
let dt = DeviceTree::from_raw(dtb_slice.as_ptr().addr())?;
|
2023-11-16 00:16:38 +02:00
|
|
|
|
|
|
|
self.dt.init(dt);
|
|
|
|
|
|
|
|
// Setup initrd
|
|
|
|
if let Some((initrd_start, initrd_end)) = initrd {
|
|
|
|
let aligned_start = initrd_start.page_align_down::<L3>();
|
|
|
|
let aligned_end = initrd_end.page_align_up::<L3>();
|
|
|
|
let len = initrd_end - initrd_start;
|
|
|
|
|
|
|
|
let data = unsafe { PhysicalRef::map_slice(initrd_start, len) };
|
|
|
|
self.initrd.init(data);
|
|
|
|
|
2023-12-05 10:27:56 +02:00
|
|
|
INITRD_DATA.init(Initrd {
|
|
|
|
phys_page_start: aligned_start,
|
|
|
|
phys_page_len: aligned_end - aligned_start,
|
|
|
|
data: self.initrd.get().as_ref(),
|
|
|
|
});
|
2023-11-16 00:16:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
2023-08-13 21:23:58 +03:00
|
|
|
}
|
|
|
|
|
2024-12-13 23:35:17 +02:00
|
|
|
#[inline(never)]
|
2024-12-16 00:23:23 +02:00
|
|
|
unsafe fn setup_chosen_stdout(dt: &'static DeviceTree) -> Result<(), Error> {
|
2024-12-13 23:35:17 +02:00
|
|
|
// Get /chosen.stdout-path to get early debug printing
|
|
|
|
// TODO honor defined configuration value
|
|
|
|
let stdout = dt.chosen_stdout();
|
|
|
|
let stdout_path = stdout.map(|(p, _)| p);
|
2024-12-16 00:23:23 +02:00
|
|
|
let node = stdout_path.and_then(device_tree::driver::find_node);
|
2024-12-13 23:35:17 +02:00
|
|
|
|
2024-12-16 00:23:23 +02:00
|
|
|
if let Some(node) = node {
|
|
|
|
node.force_init()?;
|
2024-12-13 23:35:17 +02:00
|
|
|
}
|
2024-12-16 00:23:23 +02:00
|
|
|
|
|
|
|
// No stdout
|
|
|
|
Ok(())
|
2024-12-13 23:35:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fn machine_name(dt: &'static DeviceTree) -> (Option<&'static str>, Option<&'static str>) {
|
2024-12-16 12:56:05 +02:00
|
|
|
(
|
|
|
|
dt.root().prop_string("compatible"),
|
|
|
|
dt.root().prop_string("model"),
|
|
|
|
)
|
2024-12-13 23:35:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fn apply_machine_workarounds(compatible: &str) {
|
|
|
|
#[allow(clippy::single_match)]
|
|
|
|
match compatible {
|
|
|
|
"raspberrypi,4-model-b" => {
|
|
|
|
// XXX Workaround for Raspberry Pi 4B:
|
|
|
|
// Instruction cache totally freaks out at EL0 and I don't know why
|
2024-12-15 15:20:09 +02:00
|
|
|
unsafe { mem::disable_icache() };
|
2024-12-13 23:35:17 +02:00
|
|
|
}
|
|
|
|
_ => (),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe fn init_platform(&'static self, is_bsp: bool) -> Result<(), Error> {
|
2024-02-08 15:50:25 +02:00
|
|
|
let per_cpu = PerCpuData {
|
|
|
|
gic: OneTimeInit::new(),
|
|
|
|
};
|
2024-02-12 12:09:53 +02:00
|
|
|
Cpu::init_local(None, per_cpu);
|
2023-11-16 00:16:38 +02:00
|
|
|
|
|
|
|
if is_bsp {
|
2024-12-16 00:23:23 +02:00
|
|
|
// Will register drivers
|
2024-12-13 23:35:17 +02:00
|
|
|
call_init_array();
|
|
|
|
|
|
|
|
atomic::compiler_fence(Ordering::SeqCst);
|
|
|
|
|
|
|
|
debug::init();
|
|
|
|
|
2023-11-16 00:16:38 +02:00
|
|
|
let dt = self.dt.get();
|
2024-12-17 19:12:39 +02:00
|
|
|
let bootargs = dt.chosen_bootargs().unwrap_or("");
|
|
|
|
config::parse_boot_arguments(bootargs);
|
2023-08-13 21:23:58 +03:00
|
|
|
|
2024-12-17 16:42:21 +02:00
|
|
|
// Create device tree sysfs nodes
|
|
|
|
device_tree::util::create_sysfs_nodes(dt);
|
|
|
|
|
2024-12-13 23:35:17 +02:00
|
|
|
let (machine_compatible, machine_name) = Self::machine_name(dt);
|
2023-08-13 21:23:58 +03:00
|
|
|
|
2024-12-13 23:35:17 +02:00
|
|
|
if let Some(compatible) = machine_compatible {
|
2024-12-16 14:24:46 +02:00
|
|
|
self.machine_compatible.init(compatible);
|
2024-12-13 23:35:17 +02:00
|
|
|
Self::apply_machine_workarounds(compatible);
|
|
|
|
}
|
2023-08-13 21:23:58 +03:00
|
|
|
|
2024-12-16 00:23:23 +02:00
|
|
|
unflatten_device_tree(dt);
|
|
|
|
|
|
|
|
Self::setup_chosen_stdout(dt).ok();
|
2023-08-13 21:23:58 +03:00
|
|
|
|
2024-12-13 23:35:17 +02:00
|
|
|
if let Some(machine) = machine_name {
|
|
|
|
log::info!("Running on {machine:?}");
|
|
|
|
MACHINE_NAME.init(machine.into());
|
2023-11-16 00:16:38 +02:00
|
|
|
}
|
2024-12-17 19:12:39 +02:00
|
|
|
log::info!("Boot arguments: {bootargs:?}");
|
2023-08-13 21:23:58 +03:00
|
|
|
|
2024-11-30 23:51:02 +02:00
|
|
|
log::info!("Initializing aarch64 platform");
|
2023-08-13 21:23:58 +03:00
|
|
|
|
2024-12-16 00:23:23 +02:00
|
|
|
device_tree::driver::lazy_init(
|
|
|
|
|_| (),
|
|
|
|
|node, error| {
|
|
|
|
log::error!("{}: {error:?}", node.name().unwrap_or("<unknown>"));
|
|
|
|
},
|
|
|
|
);
|
|
|
|
device_tree::driver::init_irqs(
|
|
|
|
|_| (),
|
|
|
|
|node, error| {
|
|
|
|
log::error!(
|
|
|
|
"{}: irq init error: {error:?}",
|
|
|
|
node.name().unwrap_or("<unknown>")
|
|
|
|
);
|
|
|
|
},
|
|
|
|
);
|
2024-02-03 20:44:04 +02:00
|
|
|
|
|
|
|
PciBusManager::setup_bus_devices()?;
|
2023-08-13 21:23:58 +03:00
|
|
|
} else {
|
|
|
|
// BSP already initialized everything needed
|
|
|
|
// Setup timer and local interrupt controller
|
2024-02-08 15:50:25 +02:00
|
|
|
if let Some(gic) = GIC.try_get() {
|
|
|
|
unsafe {
|
|
|
|
gic.init_ap().unwrap();
|
|
|
|
}
|
2023-08-13 21:23:58 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO device-tree initialization for this
|
|
|
|
CNTP_CTL_EL0.write(CNTP_CTL_EL0::ENABLE::SET + CNTP_CTL_EL0::IMASK::CLEAR);
|
|
|
|
CNTP_TVAL_EL0.set(10000000);
|
2024-02-08 13:11:29 +02:00
|
|
|
external_interrupt_controller()
|
2024-12-10 11:52:26 +02:00
|
|
|
.unwrap()
|
2024-02-08 13:11:29 +02:00
|
|
|
.enable_irq(Irq::Private(14))
|
|
|
|
.unwrap();
|
2023-08-13 21:23:58 +03:00
|
|
|
}
|
2023-11-16 00:16:38 +02:00
|
|
|
|
2024-02-08 15:50:25 +02:00
|
|
|
if let Some(gic) = GIC.try_get() {
|
|
|
|
let cpu_data = ArchitectureImpl::local_cpu_data().unwrap();
|
2024-12-10 11:52:26 +02:00
|
|
|
cpu_data.gic.init(gic.clone());
|
2024-02-08 15:50:25 +02:00
|
|
|
}
|
|
|
|
|
2023-11-16 00:16:38 +02:00
|
|
|
Ok(())
|
2023-08-13 21:23:58 +03:00
|
|
|
}
|
2023-07-18 18:03:45 +03:00
|
|
|
}
|
|
|
|
|
2023-12-07 12:50:54 +02:00
|
|
|
/// AArch64 implementation value
|
2024-02-05 13:44:21 +02:00
|
|
|
pub static PLATFORM: AArch64 = AArch64 {
|
2023-11-16 00:16:38 +02:00
|
|
|
dt: OneTimeInit::new(),
|
|
|
|
initrd: OneTimeInit::new(),
|
|
|
|
|
2024-12-16 14:24:46 +02:00
|
|
|
psci: OneTimeInit::new(),
|
2023-11-16 00:16:38 +02:00
|
|
|
reset: OneTimeInit::new(),
|
2024-12-16 14:24:46 +02:00
|
|
|
machine_compatible: OneTimeInit::new(),
|
2023-11-16 00:16:38 +02:00
|
|
|
};
|