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

Emulate GICv3 on macos #229

Merged
merged 1 commit into from
Dec 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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
Loading