Skip to content

Commit

Permalink
Emulate GICv3 on macos
Browse files Browse the repository at this point in the history
Signed-off-by: Djordje Lukic <[email protected]>
Signed-off-by: David Gageot <[email protected]>
Signed-off-by: Piotr Stankiewicz <[email protected]>
  • Loading branch information
rumpl authored and slp committed Dec 7, 2024
1 parent d0ac954 commit 0e166f2
Show file tree
Hide file tree
Showing 37 changed files with 1,294 additions and 689 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions src/arch/src/aarch64/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ pub const GTIMER_HYP: u32 = 14;
pub const GTIMER_VIRT: u32 = 11;
pub const GTIMER_PHYS: u32 = 12;

pub const VTIMER_IRQ: u32 = GTIMER_VIRT + 16;

/// Below this address will reside the GIC, above this address will reside the MMIO devices.
#[cfg(not(feature = "efi"))]
pub const MAPPED_IO_START: u64 = 1 << 30; // 1 GB
Expand Down
9 changes: 3 additions & 6 deletions src/arch/src/aarch64/macos/gic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

use std::{boxed::Box, result};

use super::gicv2::GICv2;
use super::gicv3::GICv3;

/// Errors thrown while setting up the GIC.
#[derive(Debug)]
Expand Down Expand Up @@ -70,10 +70,7 @@ pub trait GICDevice: Send {
}
}

/// Create a GIC device.
///
/// It will try to create by default a GICv3 device. If that fails it will try
/// to fall-back to a GICv2 device.
/// Create a GICv3 device.
pub fn create_gic(vcpu_count: u64) -> Result<Box<dyn GICDevice>> {
GICv2::new(vcpu_count)
GICv3::new(vcpu_count)
}
94 changes: 94 additions & 0 deletions src/arch/src/aarch64/macos/gicv3.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
use std::{boxed::Box, result};

use super::gic::{Error, GICDevice};

type Result<T> = result::Result<T, Error>;

/// This is just a placeholder for building the FDT entry.
/// The actual emulated GICv3 is in devices/legacy.
pub struct GICv3 {
/// GIC device properties, to be used for setting up the fdt entry
properties: [u64; 4],

/// Number of CPUs handled by the device
vcpu_count: u64,
}

impl GICv3 {
const SZ_64K: u64 = 0x0001_0000;

// Device trees specific constants
const GIC_V3_MAINT_IRQ: u32 = 8;

/// Get the address of the GICv3 distributor.
pub fn get_dist_addr() -> u64 {
super::super::layout::MAPPED_IO_START - 3 * GICv3::SZ_64K
}

/// Get the size of the GIC_v3 distributor.
pub const fn get_dist_size() -> u64 {
GICv3::SZ_64K
}

/// Get the address of the GIC redistributors.
pub const fn compute_redists_addr(vcpu_count: u64) -> u64 {
super::super::layout::MAPPED_IO_START
- 3 * GICv3::SZ_64K
- GICv3::compute_redists_size(vcpu_count)
}

pub fn get_redists_addr(&self) -> u64 {
Self::compute_redists_addr(self.vcpu_count)
}

/// Get the size of the GIC redistributors.
pub const fn compute_redists_size(vcpu_count: u64) -> u64 {
vcpu_count * GICv3::get_redist_size()
}

pub fn get_redists_size(&self) -> u64 {
GICv3::compute_redists_size(self.vcpu_count)
}

pub const fn get_redist_size() -> u64 {
2 * GICv3::SZ_64K
}
}

impl GICDevice for GICv3 {
fn device_properties(&self) -> &[u64] {
&self.properties
}

fn vcpu_count(&self) -> u64 {
self.vcpu_count
}

fn fdt_compatibility(&self) -> &str {
"arm,gic-v3"
}

fn fdt_maint_irq(&self) -> u32 {
GICv3::GIC_V3_MAINT_IRQ
}

fn version() -> u32 {
0
}

fn create_device(vcpu_count: u64) -> Box<dyn GICDevice> {
Box::new(GICv3 {
properties: [
GICv3::get_dist_addr(),
GICv3::get_dist_size(),
GICv3::compute_redists_addr(vcpu_count),
GICv3::compute_redists_size(vcpu_count),
],
vcpu_count,
})
}

fn init_device_attributes(_gic_device: &Box<dyn GICDevice>) -> Result<()> {
Ok(())
}
}
2 changes: 2 additions & 0 deletions src/arch/src/aarch64/macos/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#[allow(clippy::new_ret_no_self)]
pub mod gic;
pub mod gicv2;
pub mod gicv3;
pub mod regs;
pub mod sysreg;
122 changes: 122 additions & 0 deletions src/arch/src/aarch64/macos/sysreg.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
pub const SYSREG_OP0_SHIFT: u32 = 20;
pub const SYSREG_OP0_MASK: u32 = 0x3;
pub const SYSREG_OP1_SHIFT: u32 = 14;
pub const SYSREG_OP1_MASK: u32 = 0x7;
pub const SYSREG_CRN_SHIFT: u32 = 10;
pub const SYSREG_CRN_MASK: u32 = 0xf;
pub const SYSREG_CRM_SHIFT: u32 = 1;
pub const SYSREG_CRM_MASK: u32 = 0xf;
pub const SYSREG_OP2_SHIFT: u32 = 17;
pub const SYSREG_OP2_MASK: u32 = 0x7;

#[macro_export]
macro_rules! arm64_sys_reg {
($name: tt, $op0: tt, $op1: tt, $op2: tt, $crn: tt, $crm: tt) => {
pub const $name: u32 = ($op0 as u32) << SYSREG_OP0_SHIFT
| ($op2 as u32) << SYSREG_OP2_SHIFT
| ($op1 as u32) << SYSREG_OP1_SHIFT
| ($crn as u32) << SYSREG_CRN_SHIFT
| ($crm as u32) << SYSREG_CRM_SHIFT;
};
}

arm64_sys_reg!(
SYSREG_MASK,
SYSREG_OP0_MASK,
SYSREG_OP1_MASK,
SYSREG_OP2_MASK,
SYSREG_CRN_MASK,
SYSREG_CRM_MASK
);

arm64_sys_reg!(SYSREG_OSLAR_EL1, 2, 0, 4, 1, 0);
arm64_sys_reg!(SYSREG_OSDLR_EL1, 2, 0, 4, 1, 3);

arm64_sys_reg!(SYSREG_ICC_AP0R0_EL1, 3, 0, 4, 12, 8);
arm64_sys_reg!(SYSREG_ICC_AP0R1_EL1, 3, 0, 5, 12, 8);
arm64_sys_reg!(SYSREG_ICC_AP0R2_EL1, 3, 0, 6, 12, 8);
arm64_sys_reg!(SYSREG_ICC_AP0R3_EL1, 3, 0, 7, 12, 8);
arm64_sys_reg!(SYSREG_ICC_AP1R0_EL1, 3, 0, 0, 12, 9);
arm64_sys_reg!(SYSREG_ICC_AP1R1_EL1, 3, 0, 1, 12, 9);
arm64_sys_reg!(SYSREG_ICC_AP1R2_EL1, 3, 0, 2, 12, 9);
arm64_sys_reg!(SYSREG_ICC_AP1R3_EL1, 3, 0, 3, 12, 9);
arm64_sys_reg!(SYSREG_ICC_ASGI1R_EL1, 3, 0, 6, 12, 11);
arm64_sys_reg!(SYSREG_ICC_BPR0_EL1, 3, 0, 3, 12, 8);
arm64_sys_reg!(SYSREG_ICC_BPR1_EL1, 3, 0, 3, 12, 12);
arm64_sys_reg!(SYSREG_ICC_CTLR_EL1, 3, 0, 4, 12, 12);
arm64_sys_reg!(SYSREG_ICC_DIR_EL1, 3, 0, 1, 12, 11);
arm64_sys_reg!(SYSREG_ICC_EOIR0_EL1, 3, 0, 1, 12, 8);
arm64_sys_reg!(SYSREG_ICC_EOIR1_EL1, 3, 0, 1, 12, 12);
arm64_sys_reg!(SYSREG_ICC_HPPIR0_EL1, 3, 0, 2, 12, 8);
arm64_sys_reg!(SYSREG_ICC_HPPIR1_EL1, 3, 0, 2, 12, 12);
arm64_sys_reg!(SYSREG_ICC_IAR0_EL1, 3, 0, 0, 12, 8);
arm64_sys_reg!(SYSREG_ICC_IAR1_EL1, 3, 0, 0, 12, 12);
arm64_sys_reg!(SYSREG_ICC_IGRPEN0_EL1, 3, 0, 6, 12, 12);
arm64_sys_reg!(SYSREG_ICC_IGRPEN1_EL1, 3, 0, 7, 12, 12);
arm64_sys_reg!(SYSREG_ICC_PMR_EL1, 3, 0, 0, 4, 6);
arm64_sys_reg!(SYSREG_ICC_SGI1R_EL1, 3, 0, 5, 12, 11);
arm64_sys_reg!(SYSREG_ICC_SRE_EL1, 3, 0, 5, 12, 12);

// ICC_CTLR_EL1 (https://developer.arm.com/documentation/ddi0595/2021-06/AArch64-Registers/ICC-CTLR-EL1--Interrupt-Controller-Control-Register--EL1-)
pub const ICC_CTLR_EL1_RSS_SHIFT: u32 = 18;
pub const ICC_CTLR_EL1_A3V_SHIFT: u32 = 15;
pub const ICC_CTLR_EL1_ID_BITS_SHIFT: u32 = 11;
pub const ICC_CTLR_EL1_PRI_BITS_SHIFT: u32 = 8;

pub fn icc_reg_name(addr: u32) -> Option<&'static str> {
match addr {
SYSREG_ICC_IAR0_EL1 => Some("SYSREG_ICC_IAR0_EL1"),
SYSREG_ICC_IAR1_EL1 => Some("SYSREG_ICC_IAR1_EL1"),
SYSREG_ICC_EOIR0_EL1 => Some("SYSREG_ICC_EOIR0_EL1"),
SYSREG_ICC_EOIR1_EL1 => Some("SYSREG_ICC_EOIR1_EL1"),
SYSREG_ICC_AP0R0_EL1 => Some("SYSREG_ICC_AP0R0_EL1"),
SYSREG_ICC_AP0R1_EL1 => Some("SYSREG_ICC_AP0R1_EL1"),
SYSREG_ICC_AP0R2_EL1 => Some("SYSREG_ICC_AP0R2_EL1"),
SYSREG_ICC_AP0R3_EL1 => Some("SYSREG_ICC_AP0R3_EL1"),
SYSREG_ICC_AP1R0_EL1 => Some("SYSREG_ICC_AP1R0_EL1"),
SYSREG_ICC_AP1R1_EL1 => Some("SYSREG_ICC_AP1R1_EL1"),
SYSREG_ICC_AP1R2_EL1 => Some("SYSREG_ICC_AP1R2_EL1"),
SYSREG_ICC_AP1R3_EL1 => Some("SYSREG_ICC_AP1R3_EL1"),
SYSREG_ICC_ASGI1R_EL1 => Some("SYSREG_ICC_ASGI1R_EL1"),
SYSREG_ICC_BPR0_EL1 => Some("SYSREG_ICC_BPR0_EL1"),
SYSREG_ICC_BPR1_EL1 => Some("SYSREG_ICC_BPR1_EL1"),
SYSREG_ICC_CTLR_EL1 => Some("SYSREG_ICC_CTLR_EL1"),
SYSREG_ICC_DIR_EL1 => Some("SYSREG_ICC_DIR_EL1"),
SYSREG_ICC_HPPIR0_EL1 => Some("SYSREG_ICC_HPPIR0_EL1"),
SYSREG_ICC_HPPIR1_EL1 => Some("SYSREG_ICC_HPPIR1_EL1"),
SYSREG_ICC_IGRPEN0_EL1 => Some("SYSREG_ICC_IGRPEN0_EL1"),
SYSREG_ICC_IGRPEN1_EL1 => Some("SYSREG_ICC_IGRPEN1_EL1"),
SYSREG_ICC_PMR_EL1 => Some("SYSREG_ICC_PMR_EL1"),
SYSREG_ICC_SGI1R_EL1 => Some("SYSREG_ICC_SGI1R_EL1"),
SYSREG_ICC_SRE_EL1 => Some("SYSREG_ICC_SRE_EL1"),
_ => None,
}
}

pub fn sysreg_op0(sysreg: u32) -> u32 {
(sysreg >> SYSREG_OP0_SHIFT) & SYSREG_OP0_MASK
}

pub fn sysreg_op1(sysreg: u32) -> u32 {
(sysreg >> SYSREG_OP1_SHIFT) & SYSREG_OP1_MASK
}

pub fn sysreg_op2(sysreg: u32) -> u32 {
(sysreg >> SYSREG_OP2_SHIFT) & SYSREG_OP2_MASK
}

pub fn sysreg_crn(sysreg: u32) -> u32 {
(sysreg >> SYSREG_CRN_SHIFT) & SYSREG_CRN_MASK
}

pub fn sysreg_crm(sysreg: u32) -> u32 {
(sysreg >> SYSREG_CRM_SHIFT) & SYSREG_CRM_MASK
}

pub fn is_id_sysreg(reg: u32) -> bool {
sysreg_op0(reg) == 3
&& sysreg_op1(reg) == 0
&& sysreg_crn(reg) == 0
&& sysreg_crm(reg) >= 1
&& sysreg_crm(reg) < 8
}
10 changes: 5 additions & 5 deletions src/devices/src/legacy/aarch64/gpio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,14 @@
use std::fmt;
use std::os::fd::AsRawFd;
use std::result;
use std::sync::{Arc, Mutex};

use polly::event_manager::{EventManager, Subscriber};
use utils::byte_order::{read_le_u32, write_le_u32};
use utils::epoll::{EpollEvent, EventSet};
use utils::eventfd::EventFd;

use crate::bus::BusDevice;
use crate::legacy::Gic;
use crate::legacy::GicV3;

const OFS_DATA: u64 = 0x400; // Data Register
const GPIODIR: u64 = 0x400; // Direction Register
Expand Down Expand Up @@ -74,7 +73,7 @@ pub struct Gpio {
afsel: u32,
// GPIO irq_field
interrupt_evt: EventFd,
intc: Option<Arc<Mutex<Gic>>>,
intc: Option<GicV3>,
irq_line: Option<u32>,
shutdown_efd: EventFd,
}
Expand All @@ -98,11 +97,12 @@ impl Gpio {
}
}

pub fn set_intc(&mut self, intc: Arc<Mutex<Gic>>) {
pub fn set_intc(&mut self, intc: GicV3) {
self.intc = Some(intc);
}

pub fn set_irq_line(&mut self, irq: u32) {
debug!("SET_IRQ_LINE (GPIO)={}", irq);
self.irq_line = Some(irq);
}

Expand Down Expand Up @@ -166,7 +166,7 @@ impl Gpio {

fn trigger_gpio_interrupt(&self) {
if let Some(intc) = &self.intc {
intc.lock().unwrap().set_irq(self.irq_line.unwrap());
intc.set_irq(self.irq_line.unwrap());
} else if let Err(e) = self.interrupt_evt.write(1) {
error!("Failed to signal used queue: {:?}", e);
}
Expand Down
11 changes: 5 additions & 6 deletions src/devices/src/legacy/aarch64/serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
use std::collections::VecDeque;
use std::fmt;
use std::sync::{Arc, Mutex};
use std::{io, result};

use polly::event_manager::{EventManager, Subscriber};
Expand All @@ -17,8 +16,7 @@ use utils::epoll::{EpollEvent, EventSet};
use utils::eventfd::EventFd;

use crate::bus::BusDevice;
use crate::legacy::Gic;
use crate::legacy::ReadableFd;
use crate::legacy::{GicV3, ReadableFd};

/* Registers */
const UARTDR: u64 = 0;
Expand Down Expand Up @@ -91,7 +89,7 @@ pub struct Serial {
read_trigger: u32,
out: Option<Box<dyn io::Write + Send>>,
input: Option<Box<dyn ReadableFd + Send>>,
intc: Option<Arc<Mutex<Gic>>>,
intc: Option<GicV3>,
irq_line: Option<u32>,
}

Expand Down Expand Up @@ -179,11 +177,12 @@ impl Serial {
Self::new(interrupt_evt, None, None)
}

pub fn set_intc(&mut self, intc: Arc<Mutex<Gic>>) {
pub fn set_intc(&mut self, intc: GicV3) {
self.intc = Some(intc);
}

pub fn set_irq_line(&mut self, irq: u32) {
debug!("SET_IRQ_LINE (SERIAL)={}", irq);
self.irq_line = Some(irq);
}

Expand Down Expand Up @@ -308,7 +307,7 @@ impl Serial {

fn trigger_interrupt(&mut self) -> result::Result<(), io::Error> {
if let Some(intc) = &self.intc {
intc.lock().unwrap().set_irq(self.irq_line.unwrap());
intc.set_irq(self.irq_line.unwrap());
Ok(())
} else {
self.interrupt_evt.write(1)
Expand Down
Loading

0 comments on commit 0e166f2

Please sign in to comment.