Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduction of arm_boards crate & GIC driver fixes #915

Merged
merged 23 commits into from
Apr 4, 2023
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
b29102a
Bump vte dependency from 0.10.1 to 0.11.0
NathanRoyer Mar 31, 2023
6fac3fb
Make CpuId conversions and constructions `const`
NathanRoyer Mar 31, 2023
3bb3d3c
Introduce arm_boards crate
NathanRoyer Mar 31, 2023
19b8c66
Use arm_boards in GIC driver
NathanRoyer Mar 31, 2023
dfac795
Use arm_boards in multicore_bringup instead of CpuId bruteforcing
NathanRoyer Mar 31, 2023
f9ab052
Assert that the GIC distributor is allowed to pick a core that is asl…
NathanRoyer Mar 31, 2023
0bc3b7f
Introduce AffinityShift for safer affinity level readings from an Mpi…
NathanRoyer Mar 31, 2023
e7cc06c
Dedicated Offset Types to prevent confusion between 32b & 64b registers
NathanRoyer Mar 31, 2023
e153838
Assert PE selectability policy for "1 of N" interrupts in redistribut…
NathanRoyer Mar 31, 2023
03f05c5
Revert "Introduce AffinityShift for safer affinity level readings fro…
NathanRoyer Mar 31, 2023
d9cfc4e
Fix missing import in gic
NathanRoyer Mar 31, 2023
d7f9267
Fix doc builds
NathanRoyer Mar 31, 2023
d8bf0c6
Remove `arrayvec` dep of `gic` in favor of `core::array::try_from_fn`
NathanRoyer Apr 4, 2023
2903a98
Rename `current_redist_index` as `get_current_cpu_redist_index` and d…
NathanRoyer Apr 4, 2023
0cabe63
Rename default arm_boards file
NathanRoyer Apr 4, 2023
77f5052
Introduce arm_boards::BoardConfig
NathanRoyer Apr 4, 2023
aed9ac0
Rename default arm_boards file to `unselected.rs`
NathanRoyer Apr 4, 2023
baba04c
Introduce `arm_boards::mpidr::DefinedMpidrValue`, a hardcoded equival…
NathanRoyer Apr 4, 2023
76d8678
Fix unselected board file path
NathanRoyer Apr 4, 2023
5f83734
Doc & x86 builds fix
NathanRoyer Apr 4, 2023
605f93a
Fix doc builds by removing the gic crate from them
NathanRoyer Apr 4, 2023
1eb0588
clean up
kevinaboos Apr 4, 2023
f7de8b1
fix gic redistributor timeout
kevinaboos Apr 4, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 18 additions & 0 deletions kernel/arm_boards/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[package]
authors = ["Nathan Royer <nathan.royer.pro@gmail.com>"]
name = "arm_boards"
description = "Board-specific configuration and definitions for aarch64 systems"
version = "0.1.0"
edition = "2021"

[dependencies]
cfg-if = "1.0.0"
memory_structs = { path = "../memory_structs" }
derive_more = "0.99.0"

[features]
default = [ "qemu_virt" ]
qemu_virt = []

[lib]
crate-type = ["rlib"]
36 changes: 36 additions & 0 deletions kernel/arm_boards/src/boards/qemu_virt.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//! Board configuration for QEMU's basic `virt` machine with 4 CPUs.

use super::{
InterruptControllerConfig::GicV3, GicV3InterruptControllerConfig,
BoardConfig, mpidr::DefinedMpidrValue,
};
use memory_structs::PhysicalAddress;

/// Generates an MPIDR value from a CPU's 0th affinity level.
const fn cpu_id(aff0: u8) -> DefinedMpidrValue {
DefinedMpidrValue::new(0, 0, 0, aff0)
}

/// Generates a Redistributor base address from a CPU's 0th affinity level.
const fn redist(aff0: usize) -> PhysicalAddress {
PhysicalAddress::new_canonical(0x080A0000 + 0x20000 * aff0)
}

pub const NUM_CPUS: usize = 4;
pub static BOARD_CONFIG: BoardConfig = BoardConfig {
cpu_ids: [
cpu_id(0),
cpu_id(1),
cpu_id(2),
cpu_id(3),
],
interrupt_controller: GicV3(GicV3InterruptControllerConfig {
distributor_base_address: PhysicalAddress::new_canonical(0x08000000),
redistributor_base_addresses: [
redist(0),
redist(1),
redist(2),
redist(3),
],
}),
};
3 changes: 3 additions & 0 deletions kernel/arm_boards/src/boards/unselected.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
//! Invalid board config file that throws a compile error if a board config wasn't selected.

compile_error!("Please select a board config feature in the arm_boards crate");
53 changes: 53 additions & 0 deletions kernel/arm_boards/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//! Configuration and definitions for specific boards on aarch64 systems.
//!
//! | Board Name | Num CPUs | Interrupt Controller | Secondary CPU Startup Method |
//! | ---------- | --------- | -------------------- | ---------------------------- |
//! | qemu_virt | 4 | GICv3 | PSCI |
//!

#![no_std]
#![feature(const_trait_impl)]

cfg_if::cfg_if! {
if #[cfg(target_arch = "aarch64")] {

use memory_structs::PhysicalAddress;

#[derive(Debug, Copy, Clone)]
pub struct GicV3InterruptControllerConfig {
pub distributor_base_address: PhysicalAddress,
pub redistributor_base_addresses: [PhysicalAddress; board::NUM_CPUS],
}

#[derive(Debug, Copy, Clone)]
pub enum InterruptControllerConfig {
GicV3(GicV3InterruptControllerConfig),
}

/*
TODO: multicore_bringup: wake secondary cores based on this:
pub enum SecondaryCoresStartup {
Psci,
}
*/

#[derive(Debug, Clone)]
pub struct BoardConfig {
pub cpu_ids: [mpidr::DefinedMpidrValue; board::NUM_CPUS],
pub interrupt_controller: InterruptControllerConfig,
}

// by default & on x86_64, the default.rs file is used
#[cfg_attr(feature = "qemu_virt", path = "boards/qemu_virt.rs")]
#[cfg_attr(not(any(
feature = "qemu_virt",
)), path = "boards/unselected.rs")]
mod board;

pub mod mpidr;

pub use board::{NUM_CPUS, BOARD_CONFIG};


} // end of cfg(target_arch = "aarch64")
} // end of cfg_if
25 changes: 25 additions & 0 deletions kernel/arm_boards/src/mpidr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use derive_more::{Display, Binary, Octal, LowerHex, UpperHex};

/// A unique identifier for a CPU, hardcoded in `arm_boards`.
#[derive(
Clone, Copy, Debug, Display, PartialEq, Eq, PartialOrd, Ord,
Hash, Binary, Octal, LowerHex, UpperHex,
)]
#[repr(transparent)]
pub struct DefinedMpidrValue(u64);

impl DefinedMpidrValue {
/// Returns the contained value
pub fn value(self) -> u64 {
self.0
}

/// Create an `MpidrValue` from its four affinity numbers
pub(crate) const fn new(aff3: u8, aff2: u8, aff1: u8, aff0: u8) -> Self {
let aff3 = (aff3 as u64) << 32;
let aff2 = (aff2 as u64) << 16;
let aff1 = (aff1 as u64) << 8;
let aff0 = (aff0 as u64) << 0;
Self(aff3 | aff2 | aff1 | aff0)
}
}
4 changes: 2 additions & 2 deletions kernel/cpu/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ edition = "2021"
[dependencies]
derive_more = "0.99.0"


[target.'cfg(target_arch = "x86_64")'.dependencies]
apic = { path = "../apic" }

[target.'cfg(target_arch = "aarch64")'.dependencies]
irq_safety = { git = "https://github.com/theseus-os/irq_safety" }
arm_boards = { path = "../arm_boards" }
tock-registers = "0.7.0"
cortex-a = "7.5.0"
irq_safety = { git = "https://github.com/theseus-os/irq_safety" }

[lib]
crate-type = ["rlib"]
18 changes: 11 additions & 7 deletions kernel/cpu/src/aarch64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use derive_more::{Display, Binary, Octal, LowerHex, UpperHex};
use irq_safety::RwLockIrqSafe;
use core::fmt;
use alloc::vec::Vec;
use arm_boards::mpidr::DefinedMpidrValue;

use super::CpuId;

Expand Down Expand Up @@ -89,14 +90,17 @@ impl MpidrValue {
};
(self.0 >> shift) as u8
}
}

impl From<DefinedMpidrValue> for MpidrValue {
fn from(def_mpidr: DefinedMpidrValue) -> Self {
Self(def_mpidr.value())
}
}

/// Create an `MpidrValue` from its four affinity numbers
pub fn new(aff3: u8, aff2: u8, aff1: u8, aff0: u8) -> Self {
let aff3 = (aff3 as u64) << 32;
let aff2 = (aff2 as u64) << 16;
let aff1 = (aff1 as u64) << 8;
let aff0 = (aff0 as u64) << 0;
Self(aff3 | aff2 | aff1 | aff0)
impl From<DefinedMpidrValue> for CpuId {
fn from(def_mpidr: DefinedMpidrValue) -> Self {
Self::from(MpidrValue::from(def_mpidr))
}
}

Expand Down
2 changes: 2 additions & 0 deletions kernel/gic/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ zerocopy = "0.5.0"
log = "0.4.8"

memory = { path = "../memory" }
cpu = { path = "../cpu" }
arm_boards = { path = "../arm_boards" }
13 changes: 6 additions & 7 deletions kernel/gic/src/gic/cpu_interface_gicv2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,16 @@
//! - Sending End-Of-Interrupts signals

use super::GicRegisters;
use super::U32BYTES;
use super::Priority;
use super::InterruptNumber;

mod offset {
use super::U32BYTES;
pub const CTLR: usize = 0x00 / U32BYTES;
pub const PMR: usize = 0x04 / U32BYTES;
pub const IAR: usize = 0x0C / U32BYTES;
pub const RPR: usize = 0x14 / U32BYTES;
pub const EOIR: usize = 0x10 / U32BYTES;
use crate::Offset32;
pub(crate) const CTLR: Offset32 = Offset32::from_byte_offset(0x00);
pub(crate) const PMR: Offset32 = Offset32::from_byte_offset(0x04);
pub(crate) const IAR: Offset32 = Offset32::from_byte_offset(0x0C);
pub(crate) const RPR: Offset32 = Offset32::from_byte_offset(0x14);
pub(crate) const EOIR: Offset32 = Offset32::from_byte_offset(0x10);
}

// enable group 0
Expand Down
33 changes: 19 additions & 14 deletions kernel/gic/src/gic/dist_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,21 @@
//! - Generating software interrupts (GICv2 style)

use super::GicRegisters;
use super::U32BYTES;
use super::TargetCpu;
use super::InterruptNumber;
use super::Enabled;
use super::TargetList;

mod offset {
use super::U32BYTES;
pub const CTLR: usize = 0x000 / U32BYTES;
pub const IGROUPR: usize = 0x080 / U32BYTES;
pub const ISENABLER: usize = 0x100 / U32BYTES;
pub const ICENABLER: usize = 0x180 / U32BYTES;
pub const ITARGETSR: usize = 0x800 / U32BYTES;
pub const SGIR: usize = 0xf00 / U32BYTES;
use crate::{Offset32, Offset64};
pub(crate) const CTLR: Offset32 = Offset32::from_byte_offset(0x000);
pub(crate) const IGROUPR: Offset32 = Offset32::from_byte_offset(0x080);
pub(crate) const ISENABLER: Offset32 = Offset32::from_byte_offset(0x100);
pub(crate) const ICENABLER: Offset32 = Offset32::from_byte_offset(0x180);
pub(crate) const ITARGETSR: Offset32 = Offset32::from_byte_offset(0x800);
pub(crate) const SGIR: Offset32 = Offset32::from_byte_offset(0xf00);
/// This one is on the 6th page
pub const P6IROUTER: usize = 0x100 / U32BYTES;
pub(crate) const P6IROUTER: Offset64 = Offset64::from_byte_offset(0x100);
}

// enable group 0
Expand All @@ -37,6 +36,9 @@ mod offset {
// enable group 1
const CTLR_ENGRP1: u32 = 0b10;

// enable 1 of N wakeup functionality
const CTLR_E1NWF: u32 = 1 << 7;

// Affinity Routing Enable, Non-secure state.
const CTLR_ARE_NS: u32 = 1 << 5;

Expand All @@ -48,7 +50,7 @@ const SGIR_TARGET_ALL_OTHER_PE: u32 = 1 << 24;
// bit 31: SPI routing
// 1 = any available PE
// 0 = route to specific PE
const P6IROUTER_ANY_AVAILABLE_PE: u32 = 1 << 31;
const P6IROUTER_ANY_AVAILABLE_PE: u64 = 1 << 31;

// const GROUP_0: u32 = 0;
const GROUP_1: u32 = 1;
Expand All @@ -63,14 +65,16 @@ fn assert_cpu_bounds(target: &TargetCpu) {
}

/// Initializes the distributor by enabling forwarding
/// of group 1 interrupts
/// of group 1 interrupts and allowing the GIC to pick
/// a core that is asleep for "1 of N" interrupts.
///
/// Return value: whether or not affinity routing is
/// currently enabled for both secure and non-secure
/// states.
pub fn init(registers: &mut GicRegisters) -> Enabled {
let mut reg = registers.read_volatile(offset::CTLR);
reg |= CTLR_ENGRP1;
reg |= CTLR_E1NWF;
registers.write_volatile(offset::CTLR, reg);

// Return value: whether or not affinity routing is
Expand Down Expand Up @@ -157,7 +161,7 @@ impl super::ArmGic {
let list = TargetList::from_bits_truncate(flags as u8);
TargetCpu::GICv2TargetList(list)
} else if let Self::V3(v3) = self {
let reg = v3.dist_extended.read_volatile(offset::P6IROUTER);
let reg = v3.dist_extended.read_volatile_64(offset::P6IROUTER);

// bit 31: Interrupt Routing Mode
// value of 1 to target any available cpu
Expand All @@ -167,7 +171,7 @@ impl super::ArmGic {
} else {
let aff3 = (reg >> 8) & 0xff000000;
let aff012 = reg & 0xffffff;
TargetCpu::Specific(aff3 | aff012)
TargetCpu::Specific((aff3 | aff012) as u32)
}
} else {
// If we're on gicv2 then affinity routing is off
Expand Down Expand Up @@ -196,6 +200,7 @@ impl super::ArmGic {
} else if let Self::V3(v3) = self {
let value = match target {
TargetCpu::Specific(cpu) => {
let cpu = cpu as u64;
// shift aff3 8 bits to the left
let aff3 = (cpu & 0xff000000) << 8;
// keep aff 0, 1 & 2 where they are
Expand All @@ -212,7 +217,7 @@ impl super::ArmGic {
},
};

v3.dist_extended.write_volatile(offset::P6IROUTER, value);
v3.dist_extended.write_volatile_64(offset::P6IROUTER, value);
}

// If we're on gicv2 then affinity routing is off
Expand Down
Loading