From 540731810b3202ec55a809048212d7e57ded48b1 Mon Sep 17 00:00:00 2001 From: hangqi-ren <2572131118@qq.com> Date: Thu, 26 Jun 2025 00:57:41 +0800 Subject: [PATCH 1/7] Optimized the parameter expression structure of the interrupt controller. --- platform/aarch64/imx8mp/board.rs | 22 ++--- platform/aarch64/ok6254-c/board.rs | 22 ++--- platform/aarch64/qemu-gicv2/board.rs | 32 +++--- platform/aarch64/qemu-gicv3/board.rs | 29 +++--- platform/aarch64/rk3568/board.rs | 38 ++------ platform/aarch64/rk3588/board.rs | 22 ++--- platform/aarch64/zcu102/board.rs | 26 ++--- src/arch/aarch64/zone.rs | 33 ++++++- src/device/irqchip/gicv2/gic.rs | 25 +++-- src/device/irqchip/gicv2/gic_ref.rs | 6 +- src/device/irqchip/gicv2/gicc.rs | 34 ++++--- src/device/irqchip/gicv2/gicd.rs | 18 ++-- src/device/irqchip/gicv2/gich.rs | 17 +++- src/device/irqchip/gicv2/gicv.rs | 16 ++- src/device/irqchip/gicv2/mod.rs | 58 +++++++---- src/device/irqchip/gicv2/vgic.rs | 65 +++++++----- src/device/irqchip/gicv3/mod.rs | 141 ++++++++++++++++++++------- src/device/irqchip/gicv3/vgic.rs | 64 ++++++------ 18 files changed, 394 insertions(+), 274 deletions(-) diff --git a/platform/aarch64/imx8mp/board.rs b/platform/aarch64/imx8mp/board.rs index 555001f0..a33004ca 100644 --- a/platform/aarch64/imx8mp/board.rs +++ b/platform/aarch64/imx8mp/board.rs @@ -90,19 +90,15 @@ pub const ROOT_ZONE_IRQS: [u32; 28] = [ ]; pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { - gicd_base: 0x38800000, - gicd_size: 0x10000, - gicr_base: 0x38880000, - gicr_size: 0xc0000, - gicc_base: 0, - gicc_size: 0, - gicc_offset: 0x0, - gich_base: 0, - gich_size: 0, - gicv_base: 0, - gicv_size: 0, - gits_base: 0, - gits_size: 0, + gic_version: 3, + gic_config: GicConfig::Gicv3(Gicv3Config { + gicd_base: 0x38800000, + gicd_size: 0x10000, + gicr_base: 0x38880000, + gicr_size: 0xc0000, + gits_base: 0x0, + gits_size: 0x0, + }), }; pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; diff --git a/platform/aarch64/ok6254-c/board.rs b/platform/aarch64/ok6254-c/board.rs index 862f0292..2a7e0a4f 100644 --- a/platform/aarch64/ok6254-c/board.rs +++ b/platform/aarch64/ok6254-c/board.rs @@ -106,19 +106,15 @@ pub const ROOT_ZONE_IRQS: [u32; 13] = [ ]; pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { - gicd_base: 0x1800000, - gicd_size: 0x10000, - gicr_base: 0x1880000, - gicr_size: 0xc0000, - gicc_base: 0x0, - gicc_size: 0x0, - gicc_offset: 0x0, - gich_base: 0x0, - gich_size: 0x0, - gicv_base: 0x0, - gicv_size: 0x00000, - gits_base: 0x1820000, - gits_size: 0x10000, + gic_version: 3, + gic_config: GicConfig::Gicv3(Gicv3Config { + gicd_base: 0x1800000, + gicd_size: 0x10000, + gicr_base: 0x1880000, + gicr_size: 0xc0000, + gits_base: 0x1820000, + gits_size: 0x10000, + }), }; pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; diff --git a/platform/aarch64/qemu-gicv2/board.rs b/platform/aarch64/qemu-gicv2/board.rs index c9d6f8f8..2d223255 100644 --- a/platform/aarch64/qemu-gicv2/board.rs +++ b/platform/aarch64/qemu-gicv2/board.rs @@ -12,13 +12,10 @@ // https://www.syswonder.org // // Authors: -// -use crate::{arch::zone::HvArchZoneConfig, config::*}; - +// Hangqi Ren <2572131118@qq.com> +use crate::{arch::zone::{HvArchZoneConfig,GicConfig,Gicv2Config}, config::*}; pub const BOARD_NAME: &str = "qemu-gicv2"; -pub const BOARD_NCPUS: usize = 4; - pub const ROOT_ZONE_DTB_ADDR: u64 = 0xa0000000; pub const ROOT_ZONE_KERNEL_ADDR: u64 = 0xa0400000; pub const ROOT_ZONE_ENTRY: u64 = 0xa0400000; @@ -52,19 +49,18 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 3] = [ pub const ROOT_ZONE_IRQS: [u32; 9] = [33, 64, 77, 79, 35, 36, 37, 38, 65]; pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { - gicd_base: 0x8000000, - gicd_size: 0x10000, - gicr_base: 0x80a0000, - gicr_size: 0xf60000, - gicc_base: 0x8010000, - gicc_size: 0x10000, - gicc_offset: 0x0, - gich_base: 0x8030000, - gich_size: 0x10000, - gicv_base: 0x8040000, - gicv_size: 0x10000, - gits_base: 0x8080000, - gits_size: 0x20000, + gic_version: 2, + gic_config: GicConfig::Gicv2(Gicv2Config { + gicd_base: 0x8000000, + gicd_size: 0x10000, + gicc_base: 0x8010000, + gicc_size: 0x10000, + gicc_offset: 0x0, + gich_base: 0x8030000, + gich_size: 0x10000, + gicv_base: 0x8040000, + gicv_size: 0x10000, + }), }; pub const ROOT_PCI_CONFIG: HvPciConfig = HvPciConfig { diff --git a/platform/aarch64/qemu-gicv3/board.rs b/platform/aarch64/qemu-gicv3/board.rs index 9ff4be52..16e75866 100644 --- a/platform/aarch64/qemu-gicv3/board.rs +++ b/platform/aarch64/qemu-gicv3/board.rs @@ -13,12 +13,9 @@ // // Authors: // -use crate::{arch::zone::HvArchZoneConfig, config::*}; - -pub const BOARD_NAME: &str = "qemu-gicv3"; - +use crate::{arch::zone::{HvArchZoneConfig,GicConfig,Gicv3Config}, config::*}; +pub const BOARD_NAME: &str = "qemu-givc3"; pub const BOARD_NCPUS: usize = 4; - pub const ROOT_ZONE_DTB_ADDR: u64 = 0xa0000000; pub const ROOT_ZONE_KERNEL_ADDR: u64 = 0xa0400000; pub const ROOT_ZONE_ENTRY: u64 = 0xa0400000; @@ -52,19 +49,15 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 3] = [ pub const ROOT_ZONE_IRQS: [u32; 9] = [33, 64, 77, 79, 35, 36, 37, 38, 65]; pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { - gicd_base: 0x8000000, - gicd_size: 0x10000, - gicr_base: 0x80a0000, - gicr_size: 0xf60000, - gicc_base: 0x8010000, - gicc_size: 0x10000, - gicc_offset: 0x0, - gich_base: 0x8030000, - gich_size: 0x10000, - gicv_base: 0x8040000, - gicv_size: 0x10000, - gits_base: 0x8080000, - gits_size: 0x20000, + gic_version: 3, + gic_config: GicConfig::Gicv3(Gicv3Config { + gicd_base: 0x8000000, + gicd_size: 0x10000, + gicr_base: 0x80a0000, + gicr_size: 0xf60000, + gits_base: 0x8080000, + gits_size: 0x20000, + }), }; pub const ROOT_PCI_CONFIG: HvPciConfig = HvPciConfig { diff --git a/platform/aarch64/rk3568/board.rs b/platform/aarch64/rk3568/board.rs index 12845b62..5c4b2d8f 100644 --- a/platform/aarch64/rk3568/board.rs +++ b/platform/aarch64/rk3568/board.rs @@ -1,19 +1,3 @@ -// Copyright (c) 2025 Syswonder -// hvisor is licensed under Mulan PSL v2. -// You can use this software according to the terms and conditions of the Mulan PSL v2. -// You may obtain a copy of Mulan PSL v2 at: -// http://license.coscl.org.cn/MulanPSL2 -// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR -// FIT FOR A PARTICULAR PURPOSE. -// See the Mulan PSL v2 for more details. -// -// Syswonder Website: -// https://www.syswonder.org -// -// Authors: -// - use crate::{arch::zone::HvArchZoneConfig, config::*}; pub const BOARD_NAME: &str = "rk3568"; @@ -166,19 +150,15 @@ pub const ROOT_ZONE_IRQS: [u32; 20] = [ 0x84, 0x98, 0x40, 0x104, 0x105, 0x106, 0x107, 0x2d, 0x2e, 0x2b, 0x2a, 0x29, 0x33, 0x96, 0x11c, 0x44, 0x43, 0x42, 0x41, 0x8d]; pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { - gicd_base: 0xfd400000, - gicd_size: 0x10000, - gicr_base: 0xfd460000, - gicr_size: 0xc0000, - gicc_base: 0, - gicc_size: 0, - gicc_offset: 0x0, - gich_base: 0, - gich_size: 0, - gicv_base: 0, - gicv_size: 0, - gits_base: 0, - gits_size: 0, + gic_version: 3, + gic_config: GicConfig::Gicv3(Gicv3Config { + gicd_base: 0xfd400000, + gicd_size: 0x10000, + gicr_base: 0xfd460000, + gicr_size: 0xc0000, + gits_base: 0x0, + gits_size: 0x0, + }), }; pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; diff --git a/platform/aarch64/rk3588/board.rs b/platform/aarch64/rk3588/board.rs index 95680030..3c274e22 100644 --- a/platform/aarch64/rk3588/board.rs +++ b/platform/aarch64/rk3588/board.rs @@ -146,19 +146,15 @@ pub const ROOT_ZONE_IRQS: [u32; 29] = [ ]; pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { - gicd_base: 0xfe600000, - gicd_size: 0x10000, - gicr_base: 0xfe680000, - gicr_size: 0x100000, - gicc_base: 0x8010000, - gicc_size: 0x10000, - gicc_offset: 0x0, - gich_base: 0x8030000, - gich_size: 0x10000, - gicv_base: 0x8040000, - gicv_size: 0x10000, - gits_base: 0x8080000, - gits_size: 0x20000, + gic_version: 3, + gic_config: GicConfig::Gicv3(Gicv3Config { + gicd_base: 0xfe600000, + gicd_size: 0x10000, + gicr_base: 0xfe680000, + gicr_size: 0x100000, + gits_base: 0x8080000, + gits_size: 0x20000, + }), }; pub const ROOT_PCI_CONFIG: HvPciConfig = HvPciConfig { diff --git a/platform/aarch64/zcu102/board.rs b/platform/aarch64/zcu102/board.rs index 54049234..e6edab15 100644 --- a/platform/aarch64/zcu102/board.rs +++ b/platform/aarch64/zcu102/board.rs @@ -69,19 +69,19 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 5] = [ pub const ROOT_ZONE_IRQS: [u32; 8] = [53, 81, 67, 175, 176, 177, 178, 64]; pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { - gicd_base: 0xf9010000, - gicd_size: 0x10000, - gicr_base: 0x80a0000, - gicr_size: 0xf60000, - gits_base: 0x20000, - gits_size: 0x20000, - gicc_base: 0xf9020000, - gicc_size: 0x20000, - gicc_offset: 0xf000, - gich_base: 0xf9040000, - gich_size: 0x20000, - gicv_base: 0xf9060000, - gicv_size: 0x20000, + gic_version: 2, + gic_config: GicConfig::Gicv2(Gicv2Config { + gicd_base: 0xf9010000, + gicd_size: 0x10000, + gicc_base: 0xf9020000, + gicc_size: 0x20000, + gicc_offset: 0xf000, + gich_base: 0xf9040000, + gich_size: 0x20000, + gicv_base: 0xf9060000, + gicv_size: 0x20000, + }), }; + pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; diff --git a/src/arch/aarch64/zone.rs b/src/arch/aarch64/zone.rs index 037750e4..81bb9f5a 100644 --- a/src/arch/aarch64/zone.rs +++ b/src/arch/aarch64/zone.rs @@ -64,17 +64,40 @@ impl Zone { #[repr(C)] #[derive(Debug, Clone)] pub struct HvArchZoneConfig { + pub gic_version: usize, + pub gic_config: GicConfig, +} + + +#[repr(C, usize)] +#[derive(Debug, Clone)] +pub enum GicConfig { + Gicv2(Gicv2Config), + Gicv3(Gicv3Config), +} + +#[repr(C)] +#[derive(Debug, Clone)] +pub struct Gicv2Config { pub gicd_base: usize, pub gicd_size: usize, - pub gicr_base: usize, - pub gicr_size: usize, - pub gits_base: usize, - pub gits_size: usize, pub gicc_base: usize, - pub gicc_offset: usize, pub gicc_size: usize, + pub gicc_offset: usize, pub gich_base: usize, pub gich_size: usize, pub gicv_base: usize, pub gicv_size: usize, } + +#[repr(C)] +#[derive(Debug, Clone)] +pub struct Gicv3Config { + pub gicd_base: usize, + pub gicd_size: usize, + pub gicr_base: usize, + pub gicr_size: usize, + pub gits_base: usize, + pub gits_size: usize, +} + diff --git a/src/device/irqchip/gicv2/gic.rs b/src/device/irqchip/gicv2/gic.rs index 50356341..91719e52 100644 --- a/src/device/irqchip/gicv2/gic.rs +++ b/src/device/irqchip/gicv2/gic.rs @@ -12,9 +12,8 @@ // https://www.syswonder.org // // Authors: -// +// Hangqi Ren <2572131118@qq.com> use crate::arch::cpu::this_cpu_id; -use crate::consts; use crate::device::irqchip::gicv2::gicc::GICC; use crate::device::irqchip::gicv2::gicd::GICV2_SGIS_NUM; use crate::device::irqchip::gicv2::gich::{ @@ -31,7 +30,7 @@ use alloc::collections::VecDeque; use alloc::vec::Vec; use spin::{Mutex, Once}; -pub const MAX_CPU_NUM: usize = consts::MAX_CPU_NUM; +pub const MAX_CPU_NUM: usize = 8; pub const MAINTENACE_INTERRUPT: u64 = 25; pub fn gicv2_handle_irq() { @@ -57,7 +56,7 @@ pub fn gicv2_handle_irq() { } pub fn get_pending_irq() -> Option { - let iar = GICC.get_iar() as usize; + let iar = GICC.get().unwrap().get_iar() as usize; let irq = iar & 0x3ff; if irq >= 1023 { None @@ -68,22 +67,22 @@ pub fn get_pending_irq() -> Option { // deactivate irq: GIC doesn't care CPU ID. pub fn deactivate_irq(irq_id: usize) { - GICC.set_eoir(irq_id as u32); + GICC.get().unwrap().set_eoir(irq_id as u32); if irq_id < GICV2_SGIS_NUM { - GICC.set_dir(irq_id as u32); + GICC.get().unwrap().set_dir(irq_id as u32); } } pub fn change_underflow_maintenance(is_enable: bool) { trace!("enable_maintenace_interrupt, is_enable is {}", is_enable); - let mut hcr = GICH.get_hcr(); + let mut hcr = GICH.get().unwrap().get_hcr(); trace!("hcr is {}", hcr); if is_enable { hcr |= GICV2_GICH_HCR_UIE; } else { hcr &= !GICV2_GICH_HCR_UIE; } - GICH.set_hcr(hcr); + GICH.get().unwrap().set_hcr(hcr); } fn handle_maintenace_interrupt() { @@ -103,8 +102,8 @@ fn handle_maintenace_interrupt() { } pub fn inject_irq(irq_id: usize, is_sgi: bool) -> bool { - let elrsr: u64 = (GICH.get_elrsr(1) as u64) << 32 | GICH.get_elrsr(0) as u64; - let lr_num: isize = GICH.get_lr_num() as isize; + let elrsr: u64 = (GICH.get().unwrap().get_elrsr(1) as u64) << 32 | GICH.get().unwrap().get_elrsr(0) as u64; + let lr_num: isize = GICH.get().unwrap().get_lr_num() as isize; let lr_pint_mask: usize = 0x3ff << 10; let mut free_lr: isize = -1; for i in 0..lr_num { @@ -112,7 +111,7 @@ pub fn inject_irq(irq_id: usize, is_sgi: bool) -> bool { free_lr = i; continue; } - let lr = GICH.get_lr(i as usize) as usize; + let lr = GICH.get().unwrap().get_lr(i as usize) as usize; let pint = (lr & lr_pint_mask) >> 10; if pint == irq_id { trace!("virtual irq {} enables again", irq_id); @@ -122,7 +121,7 @@ pub fn inject_irq(irq_id: usize, is_sgi: bool) -> bool { if free_lr == -1 { warn!("no free lr"); for i in 0..lr_num { - let lr = GICH.get_lr(i as usize) as usize; + let lr = GICH.get().unwrap().get_lr(i as usize) as usize; warn!("lr[{}]: {:#x}", i, lr); } PENDING_VIRQS @@ -147,7 +146,7 @@ pub fn inject_irq(irq_id: usize, is_sgi: bool) -> bool { // config hw bit 31 val = val | GICV2_GICH_LR_HW; } - GICH.set_lr(free_lr as usize, val as u32); + GICH.get().unwrap().set_lr(free_lr as usize, val as u32); true } } diff --git a/src/device/irqchip/gicv2/gic_ref.rs b/src/device/irqchip/gicv2/gic_ref.rs index b86f2f92..833d7e48 100644 --- a/src/device/irqchip/gicv2/gic_ref.rs +++ b/src/device/irqchip/gicv2/gic_ref.rs @@ -12,12 +12,8 @@ // https://www.syswonder.org // // Authors: -// +// Hangqi Ren <2572131118@qq.com> use core::marker::PhantomData; -/// A struct definition that wraps around a bare pointer -/// author: ForeverYolo -/// references: -/// rust_shyper: https://gitee.com/openeuler/rust_shyper use core::ops::Deref; use core::ptr::NonNull; diff --git a/src/device/irqchip/gicv2/gicc.rs b/src/device/irqchip/gicv2/gicc.rs index 41a9f0c7..20dab61c 100644 --- a/src/device/irqchip/gicv2/gicc.rs +++ b/src/device/irqchip/gicv2/gicc.rs @@ -12,9 +12,11 @@ // https://www.syswonder.org // // Authors: -// +// Hangqi Ren <2572131118@qq.com> #![allow(unused_variables)] #![allow(dead_code)] + +use spin::Once; use crate::device::irqchip::gicv2::gic_ref::GicRef; use crate::device::irqchip::gicv2::gicd::GICD; use crate::device::irqchip::gicv2::gich::{ @@ -83,14 +85,22 @@ register_structs! { unsafe impl Sync for GicCpuInterface {} // Each CPU holds one GICC. -pub static GICC: GicRef = - unsafe { GicRef::new(GICV2.gicc_base as *const GicCpuInterface) }; +pub static GICC: Once> = Once::new(); + // unsafe { GicRef::new(GICV2.gicc_base as *const GicCpuInterface) }; + +pub fn gicc_init(gicc_base: usize) { + unsafe { + GICC.call_once(|| { + GicRef::new(gicc_base as *const GicCpuInterface) + }); + } +} impl GicCpuInterface { // init GICC for each CPU. pub fn init(&self) { // Ensure all SGIs disabled. - GICD.set_icenabler(0, 0x0000FFFF); + GICD.get().unwrap().set_icenabler(0, 0x0000FFFF); // get ctrl and pmr value let gicc_ctrl = self.CTLR.get(); let gicc_pmr = self.PMR.get(); @@ -108,18 +118,18 @@ impl GicCpuInterface { if gicc_ctrl & GICV2_GICC_CTRL_EOIMODES != 0 { vmcr |= GICV2_GICH_VMCR_VEM; } - GICH.set_vmcr(vmcr); + GICH.get().unwrap().set_vmcr(vmcr); // Enable virtual CPU interface operation. - GICH.set_hcr(GICV2_GICH_HCR_EN); + GICH.get().unwrap().set_hcr(GICV2_GICH_HCR_EN); // Clear all lr registers in GICH. - GICH.clear_all_lr(); + GICH.get().unwrap().clear_all_lr(); // Deactivate all active and pending SGIS - let gicd_isactive = GICD.get_isactiver(0); - let gicd_ispend = GICD.get_spendsgir(0); - GICD.set_icactiver(0, gicd_isactive & 0xffff); - GICD.set_cpendsgir(0, gicd_ispend & 0xffff); + let gicd_isactive = GICD.get().unwrap().get_isactiver(0); + let gicd_ispend = GICD.get().unwrap().get_spendsgir(0); + GICD.get().unwrap().set_icactiver(0, gicd_isactive & 0xffff); + GICD.get().unwrap().set_cpendsgir(0, gicd_ispend & 0xffff); // re-enable all SGIs - GICD.set_isenabler(0, 0x0000FFFF); + GICD.get().unwrap().set_isenabler(0, 0x0000FFFF); info!("GICV2: GICC init done."); } diff --git a/src/device/irqchip/gicv2/gicd.rs b/src/device/irqchip/gicv2/gicd.rs index bc8fab22..c7ea652c 100644 --- a/src/device/irqchip/gicv2/gicd.rs +++ b/src/device/irqchip/gicv2/gicd.rs @@ -12,7 +12,7 @@ // https://www.syswonder.org // // Authors: -// +// Hangqi Ren <2572131118@qq.com> #![allow(unused_variables)] #![allow(dead_code)] use crate::device::irqchip::gicv2::gic_ref::GicRef; @@ -21,7 +21,7 @@ use crate::device::irqchip::gicv2::GICV2; /// author : ForeverYolo /// reference: /// 1. gicv2 spec : https://www.cl.cam.ac.uk/research/srg/han/ACS-P35/zynq/arm_gic_architecture_specification.pdf -use spin::Mutex; +use spin::{Mutex, Once}; use tock_registers::interfaces::{Readable, Writeable}; use tock_registers::register_structs; use tock_registers::registers::{ReadOnly, ReadWrite}; @@ -100,10 +100,14 @@ register_structs! { unsafe impl Sync for GicDistributer {} // GICD is globally unique. -pub static GICD: GicRef = - unsafe { GicRef::new(GICV2.gicd_base as *const GicDistributer) }; +pub static GICD: Once> = Once::new(); + // unsafe { GicRef::new(GICV2.gicd_base as *const GicDistributer) }; pub static GICD_LOCK: Mutex<()> = Mutex::new(()); +pub fn gicd_init(gicd_base: usize) { + GICD.call_once(|| unsafe { GicRef::new(gicd_base as *const GicDistributer) }); +} + impl GicDistributer { // init GICD globally and enable it. pub fn global_init(&self) { @@ -187,7 +191,7 @@ impl GicDistributer { // Get the maximum number of interrupt IDs that the GIC supports. pub fn get_max_int_num() -> usize { - let value = (GICD.TYPER.get() & 0b11111) as usize; + let value = (GICD.get().unwrap().TYPER.get() & 0b11111) as usize; (value + 1) * 32 } @@ -198,9 +202,9 @@ pub fn is_spi(irqn: usize) -> bool { // Get the base address of GICD. pub fn host_gicd_base() -> usize { - GICV2.gicd_base + GICV2.get().unwrap().gicd_base } pub fn set_ispender(index: usize, value: u32) { - GICD.set_ispender(index, value); + GICD.get().unwrap().set_ispender(index, value); } diff --git a/src/device/irqchip/gicv2/gich.rs b/src/device/irqchip/gicv2/gich.rs index e1dc2bae..95a2e6f9 100644 --- a/src/device/irqchip/gicv2/gich.rs +++ b/src/device/irqchip/gicv2/gich.rs @@ -12,7 +12,7 @@ // https://www.syswonder.org // // Authors: -// +// Hangqi Ren <2572131118@qq.com> #![allow(unused_variables)] #![allow(dead_code)] use crate::device::irqchip::gicv2::gic_ref::GicRef; @@ -22,6 +22,7 @@ use crate::device::irqchip::gicv2::GICV2; use tock_registers::interfaces::{Readable, Writeable}; use tock_registers::register_structs; use tock_registers::registers::{ReadOnly, ReadWrite}; +use spin::Once; pub const GICV2_MAX_LIST_REGS_NUM: usize = 64; pub const GICV2_GICH_HCR_EN: u32 = 0x1; pub const GICV2_GICH_VMCR_VEM: u32 = 0x1 << 9; @@ -67,8 +68,18 @@ register_structs! { } unsafe impl Sync for GicHypervisorInterface {} // Each CPU holds one GICH. -pub static GICH: GicRef = - unsafe { GicRef::new(GICV2.gich_base as *const GicHypervisorInterface) }; +pub static GICH: Once> = Once::new(); + // unsafe { GicRef::new(GICV2.gich_base as *const GicHypervisorInterface) }; + +pub fn gich_init(gich_base: usize) { + unsafe { + GICH.call_once(|| { + GicRef::new(gich_base as *const GicHypervisorInterface) + }); + } + +} + impl GicHypervisorInterface { // init GICH for each CPU. diff --git a/src/device/irqchip/gicv2/gicv.rs b/src/device/irqchip/gicv2/gicv.rs index 6f408f5e..a2ea44cb 100644 --- a/src/device/irqchip/gicv2/gicv.rs +++ b/src/device/irqchip/gicv2/gicv.rs @@ -12,7 +12,7 @@ // https://www.syswonder.org // // Authors: -// +// Hangqi Ren <2572131118@qq.com> #![allow(unused_variables)] #![allow(dead_code)] /// gicv layout definition and functions for gicv operations. @@ -23,7 +23,15 @@ use crate::device::irqchip::gicv2::gic_ref::GicRef; use crate::device::irqchip::gicv2::gicc::GicCpuInterface; use crate::device::irqchip::gicv2::GICV2; - +use spin::Once; // Each CPU holds one GICV, and it has the same register layout as GICC. -pub static GICV: GicRef = - unsafe { GicRef::new(GICV2.gicv_base as *const GicCpuInterface) }; +pub static GICV: Once> = Once::new(); + // unsafe { GicRef::new(GICV2.gicv_base as *const GicCpuInterface) }; + +pub fn gicv_init(gicv_base: usize) { + unsafe { + GICV.call_once(|| { + GicRef::new(gicv_base as *const GicCpuInterface) + }); + } +} \ No newline at end of file diff --git a/src/device/irqchip/gicv2/mod.rs b/src/device/irqchip/gicv2/mod.rs index ea1760f8..dc71c59f 100644 --- a/src/device/irqchip/gicv2/mod.rs +++ b/src/device/irqchip/gicv2/mod.rs @@ -12,7 +12,8 @@ // https://www.syswonder.org // // Authors: -// +// Hangqi Ren <2572131118@qq.com> +use spin::Once; use crate::device::irqchip::gicv2::gic::MAX_CPU_NUM; /// The outer layer is defined using gicv2. /// author: ForeverYolo @@ -20,9 +21,13 @@ use crate::device::irqchip::gicv2::gic::MAX_CPU_NUM; /// 1. gicv2 spec : https://www.cl.cam.ac.uk/research/srg/han/ACS-P35/zynq/arm_gic_architecture_specification.pdf use crate::device::irqchip::gicv2::gicc::GICC; use crate::device::irqchip::gicv2::gicd::GICD; +use crate::device::irqchip::gicv2::gicd::gicd_init; +use crate::device::irqchip::gicv2::gicc::gicc_init; +use crate::device::irqchip::gicv2::gich::gich_init; +use crate::device::irqchip::gicv2::gicv::gicv_init; use crate::platform::ROOT_ARCH_ZONE_CONFIG; use crate::zone::Zone; - +use crate::arch::zone::{HvArchZoneConfig,GicConfig,Gicv2Config}; // GIC Distributor Definition. pub mod gicd; @@ -51,33 +56,46 @@ pub struct Gicv2 { gicv_base: usize, } -pub static GICV2: Gicv2 = Gicv2 { - gicd_base: ROOT_ARCH_ZONE_CONFIG.gicd_base, - /* - * Some boards have the GIC CPU interface registers alias, which will overlap DIR register, so we need to add an offset to - * find the last gic cpu alias region. - * ref: https://github.com/Xilinx/qemu-devicetrees/commit/09d4c3200538dc90082fbda9289e2af9794b9a28 - */ - gicc_base: ROOT_ARCH_ZONE_CONFIG.gicc_base + ROOT_ARCH_ZONE_CONFIG.gicc_offset, - gich_base: ROOT_ARCH_ZONE_CONFIG.gich_base, - gicv_base: ROOT_ARCH_ZONE_CONFIG.gicv_base, -}; - +pub static GICV2: Once = Once::new(); // get base address of GIC and initialize GIC Structs. pub fn primary_init_early() { - info!("GicDistributer = {:#x?}", GICV2.gicd_base); - info!("GicCpuInterface = {:#x?}", GICV2.gicc_base); - info!("GicHypervisorInterface = {:#x?}", GICV2.gich_base); - info!("GicVCpuInterface = {:#x?}", GICV2.gicv_base); + match ROOT_ARCH_ZONE_CONFIG.gic_config { + GicConfig::Gicv3(_) => { + panic!("GICv3 is not supported in this version of hvisor"); + } + GicConfig::Gicv2(ref gicv2_config) => { + if ROOT_ARCH_ZONE_CONFIG.gic_version != 2 { + panic!("GIC version mismatch, expected 2, got {}", ROOT_ARCH_ZONE_CONFIG.gic_version); + } + info!("GICv2 detected"); + GICV2.call_once(|| { + Gicv2 { + gicd_base: gicv2_config.gicd_base, + gicc_base: gicv2_config.gicc_base + gicv2_config.gicc_offset, + gich_base: gicv2_config.gich_base, + gicv_base: gicv2_config.gicv_base, + } + }); + gicd_init(gicv2_config.gicd_base); + gicc_init(gicv2_config.gicc_base + gicv2_config.gicc_offset); + gich_init(gicv2_config.gich_base); + gicv_init(gicv2_config.gicv_base); + info!("GIC Distributor base: {:#x}, size: {:#x}", GICV2.get().unwrap().gicd_base, gicv2_config.gicd_size); + info!("GIC CPU Interface base: {:#x}, size: {:#x}", GICV2.get().unwrap().gicc_base, gicv2_config.gicc_size); + info!("GIC CPU Interface offset: {:#x}", gicv2_config.gicc_offset); + info!("GIC Hypervisor Interface base: {:#x}, size: {:#x}", GICV2.get().unwrap().gich_base, gicv2_config.gich_size); + info!("GIC Virtual CPU Interface base: {:#x}, size: {:#x}", GICV2.get().unwrap().gicv_base, gicv2_config.gicv_size); + } + }; gic::PENDING_VIRQS.call_once(|| gic::PendingIrqs::new(MAX_CPU_NUM)); } pub fn percpu_init() { - GICC.init(); + GICC.get().unwrap().init(); } pub fn primary_init_late() { - GICD.global_init(); + GICD.get().unwrap().global_init(); } impl Zone { diff --git a/src/device/irqchip/gicv2/vgic.rs b/src/device/irqchip/gicv2/vgic.rs index eddfcb90..f66aa1bc 100644 --- a/src/device/irqchip/gicv2/vgic.rs +++ b/src/device/irqchip/gicv2/vgic.rs @@ -12,8 +12,8 @@ // https://www.syswonder.org // // Authors: -// -use crate::arch::zone::HvArchZoneConfig; +// Hangqi Ren <2572131118@qq.com> +use crate::arch::zone::{HvArchZoneConfig,GicConfig,Gicv2Config}; use crate::device::irqchip::gicv2::gicd::{ get_max_int_num, GICD, GICD_CTRL_REG_OFFSET, GICD_ICACTIVER_REG_OFFSET, GICD_ICENABLER_REG_OFFSET, GICD_ICFGR_REG_OFFSET, GICD_ICPENDR_REG_OFFSET, @@ -33,36 +33,51 @@ use crate::percpu::this_zone; /// reference: /// 1. gicv2 spec : https://www.cl.cam.ac.uk/research/srg/han/ACS-P35/zynq/arm_gic_architecture_specification.pdf use crate::zone::Zone; - const GICV2_REG_WIDTH: usize = 4; impl Zone { // trap all Guest OS accesses to the GIC Distributor registers. pub fn vgicv2_mmio_init(&mut self, arch: &HvArchZoneConfig) { - if arch.gicd_base == 0 { - panic!("vgicv2_mmio_init: gicd_base is null"); + match arch.gic_config { + GicConfig::Gicv3(_) => { + panic!("GICv3 is not supported in this version of hvisor"); + } + GicConfig::Gicv2(ref gicv2_config) => { + if gicv2_config.gicd_base == 0 { + panic!("vgicv2_mmio_init: gicd_base is null"); + } + info!("Initializing GICv2 MMIO regions for zone {}", self.id); + self.mmio_region_register(gicv2_config.gicd_base, gicv2_config.gicd_size, vgicv2_dist_handler, 0); + } } - self.mmio_region_register(arch.gicd_base, arch.gicd_size, vgicv2_dist_handler, 0); } // remap the GIC CPU interface register address space to point to the GIC virtual CPU interface registers. pub fn vgicv2_remap_init(&mut self, arch: &HvArchZoneConfig) { - if arch.gicc_base == 0 || arch.gicv_base == 0 || arch.gicc_size == 0 || arch.gicv_size == 0 - { - panic!("vgicv2_remap_init: gic related address is null"); - } - if arch.gicv_size != arch.gicc_size { - panic!("vgicv2_remap_init: gicv_size not equal to gicc_size"); + match arch.gic_config { + GicConfig::Gicv3(_) => { + panic!("GICv3 is not supported in this version of hvisor"); + } + GicConfig::Gicv2(ref gicv2_config) => { + if gicv2_config.gicc_base == 0 || gicv2_config.gicv_base == 0 || gicv2_config.gicc_size == 0 || gicv2_config.gicv_size == 0 + { + panic!("vgicv2_remap_init: gic related address is null"); + } + if gicv2_config.gicv_size != gicv2_config.gicc_size { + panic!("vgicv2_remap_init: gicv_size not equal to gicc_size"); + } + info!("Remaping GICv2 GICV MMIO regions to GICC MMIO regions for zone {}", self.id); + // map gicv memory region to gicc memory region. + self.gpm + .insert(MemoryRegion::new_with_offset_mapper( + gicv2_config.gicc_base, + gicv2_config.gicv_base, + gicv2_config.gicc_size, + MemFlags::READ | MemFlags::WRITE, + )) + .unwrap(); + } } - // map gicv memory region to gicc memory region. - self.gpm - .insert(MemoryRegion::new_with_offset_mapper( - arch.gicc_base, - arch.gicv_base, - arch.gicc_size, - MemFlags::READ | MemFlags::WRITE, - )) - .unwrap(); } // store the interrupt number in the irq_bitmap. @@ -95,7 +110,7 @@ impl Zone { } pub fn reg_range(base: usize, n: usize, size: usize) -> core::ops::Range { - base..(base + n * size) + base..(base + (n - 1) * size) } // extend from gicv3, support half-word and byte access. @@ -229,13 +244,13 @@ pub fn set_sgi_irq(irq_id: usize, target_list: usize, routing_mode: usize) { target_list, routing_mode ); - trace!("ISENABLER: {:#x}", GICD.get_isenabler(0)); - GICD.set_sgir(val as u32); + trace!("ISENABLER: {:#x}", GICD.get().unwrap().get_isenabler(0)); + GICD.get().unwrap().set_sgir(val as u32); } // Handle GIC Distributor register accesses. pub fn vgicv2_dist_handler(mmio: &mut MMIOAccess, _arg: usize) -> HvResult { - let gicd_base = GICV2.gicd_base; + let gicd_base = GICV2.get().unwrap().gicd_base; let reg = mmio.address; match reg { diff --git a/src/device/irqchip/gicv3/mod.rs b/src/device/irqchip/gicv3/mod.rs index 3d0969a4..02fb3b18 100644 --- a/src/device/irqchip/gicv3/mod.rs +++ b/src/device/irqchip/gicv3/mod.rs @@ -1,19 +1,80 @@ -// Copyright (c) 2025 Syswonder -// hvisor is licensed under Mulan PSL v2. -// You can use this software according to the terms and conditions of the Mulan PSL v2. -// You may obtain a copy of Mulan PSL v2 at: -// http://license.coscl.org.cn/MulanPSL2 -// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR -// FIT FOR A PARTICULAR PURPOSE. -// See the Mulan PSL v2 for more details. +// SPDX-License-Identifier: MIT OR Apache-2.0 // -// Syswonder Website: -// https://www.syswonder.org -// -// Authors: -// - +// Copyright (c) 2020-2022 Andre Richter + +//! GICv2 Driver - ARM Generic Interrupt Controller v2. +//! +//! The following is a collection of excerpts with useful information from +//! - `Programmer's Guide for ARMv8-A` +//! - `ARM Generic Interrupt Controller Architecture Specification` +//! +//! # Programmer's Guide - 10.6.1 Configuration +//! +//! The GIC is accessed as a memory-mapped peripheral. +//! +//! All cores can access the common Distributor, but the CPU interface is banked, that is, each core +//! uses the same address to access its own private CPU interface. +//! +//! It is not possible for a core to access the CPU interface of another core. +//! +//! # Architecture Specification - 10.6.2 Initialization +//! +//! Both the Distributor and the CPU interfaces are disabled at reset. The GIC must be initialized +//! after reset before it can deliver interrupts to the core. +//! +//! In the Distributor, software must configure the priority, target, security and enable individual +//! interrupts. The Distributor must subsequently be enabled through its control register +//! (GICD_CTLR). For each CPU interface, software must program the priority mask and preemption +//! settings. +//! +//! Each CPU interface block itself must be enabled through its control register (GICD_CTLR). This +//! prepares the GIC to deliver interrupts to the core. +//! +//! Before interrupts are expected in the core, software prepares the core to take interrupts by +//! setting a valid interrupt vector in the vector table, and clearing interrupt mask bits in +//! PSTATE, and setting the routing controls. +//! +//! The entire interrupt mechanism in the system can be disabled by disabling the Distributor. +//! Interrupt delivery to an individual core can be disabled by disabling its CPU interface. +//! Individual interrupts can also be disabled (or enabled) in the distributor. +//! +//! For an interrupt to reach the core, the individual interrupt, Distributor and CPU interface must +//! all be enabled. The interrupt also needs to be of sufficient priority, that is, higher than the +//! core's priority mask. +//! +//! # Architecture Specification - 1.4.2 Interrupt types +//! +//! - Peripheral interrupt +//! - Private Peripheral Interrupt (PPI) +//! - This is a peripheral interrupt that is specific to a single processor. +//! - Shared Peripheral Interrupt (SPI) +//! - This is a peripheral interrupt that the Distributor can route to any of a specified +//! combination of processors. +//! +//! - Software-generated interrupt (SGI) +//! - This is an interrupt generated by software writing to a GICD_SGIR register in the GIC. The +//! system uses SGIs for interprocessor communication. +//! - An SGI has edge-triggered properties. The software triggering of the interrupt is +//! equivalent to the edge transition of the interrupt request signal. +//! - When an SGI occurs in a multiprocessor implementation, the CPUID field in the Interrupt +//! Acknowledge Register, GICC_IAR, or the Aliased Interrupt Acknowledge Register, GICC_AIAR, +//! identifies the processor that requested the interrupt. +//! +//! # Architecture Specification - 2.2.1 Interrupt IDs +//! +//! Interrupts from sources are identified using ID numbers. Each CPU interface can see up to 1020 +//! interrupts. The banking of SPIs and PPIs increases the total number of interrupts supported by +//! the Distributor. +//! +//! The GIC assigns interrupt ID numbers ID0-ID1019 as follows: +//! - Interrupt numbers 32..1019 are used for SPIs. +//! - Interrupt numbers 0..31 are used for interrupts that are private to a CPU interface. These +//! interrupts are banked in the Distributor. +//! - A banked interrupt is one where the Distributor can have multiple interrupts with the +//! same ID. A banked interrupt is identified uniquely by its ID number and its associated +//! CPU interface number. Of the banked interrupt IDs: +//! - 00..15 SGIs +//! - 16..31 PPIs #![allow(dead_code)] pub mod gicd; pub mod gicr; @@ -24,9 +85,10 @@ use core::arch::asm; use core::ptr::write_volatile; use core::sync::atomic::AtomicU64; +use alloc::collections::btree_map::BTreeMap; use alloc::collections::vec_deque::VecDeque; use alloc::vec::Vec; -use gicr::init_lpi_prop; +use gicr::{init_lpi_prop, GICR_ISENABLER, GICR_SGI_BASE}; use gits::gits_init; use spin::{Mutex, Once}; @@ -35,12 +97,12 @@ use self::gicr::enable_ipi; use crate::arch::aarch64::sysreg::{read_sysreg, smc_arg1, write_sysreg}; use crate::arch::cpu::this_cpu_id; use crate::config::root_zone_config; -use crate::consts::{self, MAX_CPU_NUM}; +use crate::consts::MAX_CPU_NUM; use crate::event::check_events; use crate::hypercall::SGI_IPI_ID; use crate::zone::Zone; - +use crate::arch::zone::{HvArchZoneConfig,GicConfig,Gicv2Config}; const ICH_HCR_UIE: u64 = 1 << 1; //TODO: add Distributor init pub fn gicc_init() { @@ -88,12 +150,11 @@ fn gicv3_clear_pending_irqs() { static TIMER_INTERRUPT_COUNTER: AtomicU64 = AtomicU64::new(0); // how often to print timer interrupt counter -const TIMER_INTERRUPT_PRINT_INTERVAL: u64 = 50; +const TIMER_INTERRUPT_PRINT_TIMES: u64 = 50; pub fn gicv3_handle_irq_el1() { while let Some(irq_id) = pending_irq() { if irq_id < 8 { - trace!("sgi get {}, try to handle...", irq_id); deactivate_irq(irq_id); let mut ipi_handled = false; if irq_id == SGI_IPI_ID as _ { @@ -111,10 +172,10 @@ pub fn gicv3_handle_irq_el1() { // virtual timer interrupt TIMER_INTERRUPT_COUNTER.fetch_add(1, core::sync::atomic::Ordering::SeqCst); if TIMER_INTERRUPT_COUNTER.load(core::sync::atomic::Ordering::SeqCst) - % TIMER_INTERRUPT_PRINT_INTERVAL + % TIMER_INTERRUPT_PRINT_TIMES == 0 { - trace!( + debug!( "Virtual timer interrupt, counter = {}", TIMER_INTERRUPT_COUNTER.load(core::sync::atomic::Ordering::SeqCst) ); @@ -124,7 +185,7 @@ pub fn gicv3_handle_irq_el1() { handle_maintenace_interrupt(); } else if irq_id > 31 { //inject phy irq - trace!("*** get spi_irq id = {}", irq_id); + debug!("*** get spi_irq id = {}", irq_id); } else { warn!("not konw irq id = {}", irq_id); } @@ -346,7 +407,7 @@ pub fn host_gicd_base() -> usize { } pub fn host_gicr_base(id: usize) -> usize { - assert!(id < consts::MAX_CPU_NUM); + assert!(id < MAX_CPU_NUM); GIC.get().unwrap().gicr_base + id * PER_GICR_SIZE } @@ -384,16 +445,28 @@ pub fn disable_irqs() { pub fn primary_init_early() { let root_config = root_zone_config(); - - GIC.call_once(|| Gic { - gicd_base: root_config.arch_config.gicd_base, - gicr_base: root_config.arch_config.gicr_base, - gicd_size: root_config.arch_config.gicd_size, - gicr_size: root_config.arch_config.gicr_size, - gits_base: root_config.arch_config.gits_base, - gits_size: root_config.arch_config.gits_size, - }); - + match root_config.arch_config.gic_config { + GicConfig::Gicv2(_) => { + panic!("GICv2 is not supported in this version of hvisor"); + } + GicConfig::Gicv3(ref gicv3_config) => { + if root_config.arch_config.gic_version != 3 { + panic!("GIC version mismatch, expected 3, got {}", root_config.arch_config.gic_version); + } + info!("GICv3 detected"); + GIC.call_once(|| Gic { + gicd_base: gicv3_config.gicd_base, + gicr_base: gicv3_config.gicr_base, + gicd_size: gicv3_config.gicd_size, + gicr_size: gicv3_config.gicr_size, + gits_base: gicv3_config.gits_base, + gits_size: gicv3_config.gits_size, + }); + info!("GIC Distributor base: {:#x}, size: {:#x}", GIC.get().unwrap().gicd_base, GIC.get().unwrap().gicd_size); + info!("GIC Redistributor base: {:#x}, size: {:#x}", GIC.get().unwrap().gicr_base, GIC.get().unwrap().gicr_size); + info!("GIC ITS base: {:#x}, size: {:#x}", GIC.get().unwrap().gits_base, GIC.get().unwrap().gits_size); + } + } init_lpi_prop(); if host_gits_base() != 0 && host_gits_size() != 0 { diff --git a/src/device/irqchip/gicv3/vgic.rs b/src/device/irqchip/gicv3/vgic.rs index c4924e1c..7f55455c 100644 --- a/src/device/irqchip/gicv3/vgic.rs +++ b/src/device/irqchip/gicv3/vgic.rs @@ -17,7 +17,7 @@ use alloc::sync::Arc; use super::{gicd::GICD_LOCK, is_spi}; use crate::{ - arch::zone::HvArchZoneConfig, + arch::zone::{HvArchZoneConfig, GicConfig, Gicv2Config, Gicv3Config}, consts::MAX_CPU_NUM, device::irqchip::gicv3::{ gicd::*, gicr::*, gits::*, host_gicd_base, host_gicr_base, host_gits_base, @@ -31,22 +31,31 @@ use crate::{ }; pub fn reg_range(base: usize, n: usize, size: usize) -> core::ops::Range { - base..(base + n * size) + base..(base + (n - 1) * size) } impl Zone { pub fn vgicv3_mmio_init(&mut self, arch: &HvArchZoneConfig) { - if arch.gicd_base == 0 || arch.gicr_base == 0 { - panic!("vgicv3_mmio_init: gicd_base or gicr_base is null"); - } + match arch.gic_config { + GicConfig::Gicv2(_) => { + panic!("vgicv3_mmio_init: GICv2 is not supported in this function"); + } + GicConfig::Gicv3(ref gicv3_config) => { + // GICv3 specific initialization + info!("Initializing GICv3 MMIO regions for zone {}", self.id); + if gicv3_config.gicd_base == 0 || gicv3_config.gicr_base == 0 { + panic!("vgicv3_mmio_init: gicd_base or gicr_base is null"); + } - self.mmio_region_register(arch.gicd_base, arch.gicd_size, vgicv3_dist_handler, 0); - self.mmio_region_register(arch.gits_base, arch.gits_size, vgicv3_its_handler, 0); + self.mmio_region_register(gicv3_config.gicd_base, gicv3_config.gicd_size, vgicv3_dist_handler, 0); + self.mmio_region_register(gicv3_config.gits_base, gicv3_config.gits_size, vgicv3_its_handler, 0); - for cpu in 0..MAX_CPU_NUM { - let gicr_base = arch.gicr_base + cpu * PER_GICR_SIZE; - debug!("registering gicr {} at {:#x?}", cpu, gicr_base); - self.mmio_region_register(gicr_base, PER_GICR_SIZE, vgicv3_redist_handler, cpu); + for cpu in 0..MAX_CPU_NUM { + let gicr_base = gicv3_config.gicr_base + cpu * PER_GICR_SIZE; + debug!("registering gicr {} at {:#x?}", cpu, gicr_base); + self.mmio_region_register(gicr_base, PER_GICR_SIZE, vgicv3_redist_handler, cpu); + } + } } } @@ -205,19 +214,19 @@ pub fn vgicv3_redist_handler(mmio: &mut MMIOAccess, cpu: usize) -> HvResult { || reg == GICR_SGI_BASE + GICR_ICACTIVER || reg_range(GICR_SGI_BASE + GICR_IPRIORITYR, 8, 4).contains(®) || reg_range(GICR_SGI_BASE + GICR_ICFGR, 2, 4).contains(®) => - { - if Arc::ptr_eq(&this_zone(), get_cpu_data(cpu).zone.as_ref().unwrap()) { - // avoid linux disable maintenance interrupt - if reg == GICR_SGI_BASE + GICR_ICENABLER { - mmio.value &= !(1 << MAINTENACE_INTERRUPT); - mmio.value &= !(1 << SGI_IPI_ID); + { + if Arc::ptr_eq(&this_zone(), get_cpu_data(cpu).zone.as_ref().unwrap()) { + // avoid linux disable maintenance interrupt + if reg == GICR_SGI_BASE + GICR_ICENABLER { + mmio.value &= !(1 << MAINTENACE_INTERRUPT); + mmio.value &= !(1 << SGI_IPI_ID); + } + // ignore access to foreign redistributors + mmio_perform_access(gicr_base, mmio); + } else { + trace!("*** gicv3_gicr_mmio_handler: ignore access to foreign redistributors ***"); } - // ignore access to foreign redistributors - mmio_perform_access(gicr_base, mmio); - } else { - trace!("*** gicv3_gicr_mmio_handler: ignore access to foreign redistributors ***"); } - } _ => {} } HvResult::Ok(()) @@ -256,7 +265,7 @@ fn vgicv3_dist_misc_access(mmio: &mut MMIOAccess, gicd_base: usize) -> HvResult mmio_perform_access(gicd_base, mmio); } } else { - todo!("vgicv3_dist_misc_access: MMIO.Address = {:#x?}", reg) + todo!() } Ok(()) @@ -280,9 +289,9 @@ pub fn vgicv3_dist_handler(mmio: &mut MMIOAccess, _arg: usize) -> HvResult { || reg_range(GICD_ISPENDR, 32, 4).contains(®) || reg_range(GICD_ICACTIVER, 32, 4).contains(®) || reg_range(GICD_ISACTIVER, 32, 4).contains(®) => - { - restrict_bitmask_access(mmio, (reg & 0x7f) / 4, 1, true, gicd_base) - } + { + restrict_bitmask_access(mmio, (reg & 0x7f) / 4, 1, true, gicd_base) + } reg if reg_range(GICD_IGROUPR, 32, 4).contains(®) => { restrict_bitmask_access(mmio, (reg & 0x7f) / 4, 1, false, gicd_base) } @@ -312,9 +321,6 @@ pub fn vgicv3_its_handler(mmio: &mut MMIOAccess, _arg: usize) -> HvResult { } GITS_CBASER => { if mmio.is_write { - if this_zone_id() == 0 { - mmio_perform_access(gits_base, mmio); - } set_cbaser(mmio.value); trace!("write GITS_CBASER: {:#x}", mmio.value); } else { From 71b85e105ce99cb71722277d4974d3ff716dfa7e Mon Sep 17 00:00:00 2001 From: hangqi-ren <2572131118@qq.com> Date: Thu, 26 Jun 2025 01:14:23 +0800 Subject: [PATCH 2/7] fix compile bugs. --- platform/aarch64/imx8mp/board.rs | 18 +++++++-------- platform/aarch64/ok6254-c/board.rs | 4 ++-- platform/aarch64/qemu-gicv2/board.rs | 6 ++++- platform/aarch64/qemu-gicv3/board.rs | 7 ++++-- platform/aarch64/rk3568/board.rs | 33 +++++++++++++++++++++------- platform/aarch64/rk3588/board.rs | 4 ++-- platform/aarch64/zcu102/board.rs | 7 +++--- 7 files changed, 51 insertions(+), 28 deletions(-) diff --git a/platform/aarch64/imx8mp/board.rs b/platform/aarch64/imx8mp/board.rs index a33004ca..4e094ca2 100644 --- a/platform/aarch64/imx8mp/board.rs +++ b/platform/aarch64/imx8mp/board.rs @@ -13,7 +13,7 @@ // // Authors: // -use crate::{arch::zone::HvArchZoneConfig, config::*}; +use crate::{arch::zone::{HvArchZoneConfig,GicConfig,Gicv3Config}, config::*}; pub const BOARD_NAME: &str = "imx8mp"; @@ -75,13 +75,13 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 8] = [ virtual_start: 0x32c00000, size: 0x400000, }, // hdmi - // bus@30800000 - // HvConfigMemoryRegion { - // mem_type: MEM_TYPE_IO, - // physical_start: 0x30890000, - // virtual_start: 0x30890000, - // size: 0x1000, - // }, // serial + // bus@30800000 + // HvConfigMemoryRegion { + // mem_type: MEM_TYPE_IO, + // physical_start: 0x30890000, + // virtual_start: 0x30890000, + // size: 0x1000, + // }, // serial ]; pub const ROOT_ZONE_IRQS: [u32; 28] = [ @@ -101,4 +101,4 @@ pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { }), }; -pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; +pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; \ No newline at end of file diff --git a/platform/aarch64/ok6254-c/board.rs b/platform/aarch64/ok6254-c/board.rs index 2a7e0a4f..68697405 100644 --- a/platform/aarch64/ok6254-c/board.rs +++ b/platform/aarch64/ok6254-c/board.rs @@ -14,7 +14,7 @@ // Authors: // -use crate::{arch::zone::HvArchZoneConfig, config::*}; +use crate::{arch::zone::{HvArchZoneConfig,GicConfig,Gicv3Config}, config::*}; pub const BOARD_NAME: &str = "ok6254"; pub const BOARD_NCPUS: usize = 4; @@ -117,4 +117,4 @@ pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { }), }; -pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; +pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; \ No newline at end of file diff --git a/platform/aarch64/qemu-gicv2/board.rs b/platform/aarch64/qemu-gicv2/board.rs index 2d223255..5bf74cdc 100644 --- a/platform/aarch64/qemu-gicv2/board.rs +++ b/platform/aarch64/qemu-gicv2/board.rs @@ -14,8 +14,11 @@ // Authors: // Hangqi Ren <2572131118@qq.com> use crate::{arch::zone::{HvArchZoneConfig,GicConfig,Gicv2Config}, config::*}; + pub const BOARD_NAME: &str = "qemu-gicv2"; +pub const BOARD_NCPUS: usize = 4; + pub const ROOT_ZONE_DTB_ADDR: u64 = 0xa0000000; pub const ROOT_ZONE_KERNEL_ADDR: u64 = 0xa0400000; pub const ROOT_ZONE_ENTRY: u64 = 0xa0400000; @@ -63,6 +66,7 @@ pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { }), }; + pub const ROOT_PCI_CONFIG: HvPciConfig = HvPciConfig { ecam_base: 0x4010000000, ecam_size: 0x10000000, @@ -79,4 +83,4 @@ pub const ROOT_PCI_CONFIG: HvPciConfig = HvPciConfig { pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; -pub const ROOT_PCI_DEVS: [u64; 2] = [0, 1 << 3]; +pub const ROOT_PCI_DEVS: [u64; 2] = [0, 1 << 3]; \ No newline at end of file diff --git a/platform/aarch64/qemu-gicv3/board.rs b/platform/aarch64/qemu-gicv3/board.rs index 16e75866..e171eb02 100644 --- a/platform/aarch64/qemu-gicv3/board.rs +++ b/platform/aarch64/qemu-gicv3/board.rs @@ -14,8 +14,11 @@ // Authors: // use crate::{arch::zone::{HvArchZoneConfig,GicConfig,Gicv3Config}, config::*}; -pub const BOARD_NAME: &str = "qemu-givc3"; + +pub const BOARD_NAME: &str = "qemu-gicv3"; + pub const BOARD_NCPUS: usize = 4; + pub const ROOT_ZONE_DTB_ADDR: u64 = 0xa0000000; pub const ROOT_ZONE_KERNEL_ADDR: u64 = 0xa0400000; pub const ROOT_ZONE_ENTRY: u64 = 0xa0400000; @@ -76,4 +79,4 @@ pub const ROOT_PCI_CONFIG: HvPciConfig = HvPciConfig { pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; -pub const ROOT_PCI_DEVS: [u64; 2] = [0, 1 << 3]; +pub const ROOT_PCI_DEVS: [u64; 2] = [0, 1 << 3]; \ No newline at end of file diff --git a/platform/aarch64/rk3568/board.rs b/platform/aarch64/rk3568/board.rs index 5c4b2d8f..ce6cf718 100644 --- a/platform/aarch64/rk3568/board.rs +++ b/platform/aarch64/rk3568/board.rs @@ -1,4 +1,20 @@ -use crate::{arch::zone::HvArchZoneConfig, config::*}; +// Copyright (c) 2025 Syswonder +// hvisor is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +// FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. +// +// Syswonder Website: +// https://www.syswonder.org +// +// Authors: +// + +use crate::{arch::zone::{HvArchZoneConfig,GicConfig,Gicv3Config}, config::*}; pub const BOARD_NAME: &str = "rk3568"; @@ -147,19 +163,20 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 19] = [ ]; pub const ROOT_ZONE_IRQS: [u32; 20] = [ - 0x84, 0x98, 0x40, 0x104, 0x105, 0x106, 0x107, 0x2d, 0x2e, 0x2b, 0x2a, 0x29, 0x33, 0x96, 0x11c, 0x44, 0x43, 0x42, 0x41, 0x8d]; + 0x84, 0x98, 0x40, 0x104, 0x105, 0x106, 0x107, 0x2d, 0x2e, 0x2b, 0x2a, 0x29, 0x33, 0x96, 0x11c, 0x44, 0x43, 0x42, 0x41, 0x8d]; pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { gic_version: 3, gic_config: GicConfig::Gicv3(Gicv3Config { - gicd_base: 0xfd400000, + gicd_base: 0xfe600000, gicd_size: 0x10000, - gicr_base: 0xfd460000, - gicr_size: 0xc0000, - gits_base: 0x0, - gits_size: 0x0, + gicr_base: 0xfe680000, + gicr_size: 0x100000, + gits_base: 0x8080000, + gits_size: 0x20000, }), }; + pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; -pub const ROOT_PCI_DEVS: [u64; 0] = []; +pub const ROOT_PCI_DEVS: [u64; 0] = []; \ No newline at end of file diff --git a/platform/aarch64/rk3588/board.rs b/platform/aarch64/rk3588/board.rs index 3c274e22..bbedd76c 100644 --- a/platform/aarch64/rk3588/board.rs +++ b/platform/aarch64/rk3588/board.rs @@ -13,7 +13,7 @@ // // Authors: // -use crate::{arch::zone::HvArchZoneConfig, config::*}; +use crate::{arch::zone::{HvArchZoneConfig,GicConfig,Gicv3Config}, config::*}; // [ 17.796762] node 0: [mem 0x0000000000200000-0x000000000047ffff] // [ 17.797335] node 0: [mem 0x0000000000480000-0x000000000087ffff] @@ -173,4 +173,4 @@ pub const ROOT_PCI_CONFIG: HvPciConfig = HvPciConfig { pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; -pub const ROOT_PCI_DEVS: [u64; 2] = [0, 1 << 3]; +pub const ROOT_PCI_DEVS: [u64; 2] = [0, 1 << 3]; \ No newline at end of file diff --git a/platform/aarch64/zcu102/board.rs b/platform/aarch64/zcu102/board.rs index e6edab15..e331365e 100644 --- a/platform/aarch64/zcu102/board.rs +++ b/platform/aarch64/zcu102/board.rs @@ -12,9 +12,9 @@ // https://www.syswonder.org // // Authors: -// +// Hangqi Ren <2572131118@qq.com> use crate::config::HvConfigMemoryRegion; -use crate::{arch::zone::HvArchZoneConfig, config::*}; +use crate::{arch::zone::{HvArchZoneConfig,GicConfig,Gicv2Config}, config::*}; pub const BOARD_NAME: &str = "zcu102"; @@ -83,5 +83,4 @@ pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { }), }; - -pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; +pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; \ No newline at end of file From 212ac737763a96615650d9d6a41606ccfe0a416d Mon Sep 17 00:00:00 2001 From: hangqi-ren <2572131118@qq.com> Date: Thu, 26 Jun 2025 01:20:55 +0800 Subject: [PATCH 3/7] fix errors in rk3568 config. --- platform/aarch64/rk3568/board.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/platform/aarch64/rk3568/board.rs b/platform/aarch64/rk3568/board.rs index ce6cf718..f0989bbe 100644 --- a/platform/aarch64/rk3568/board.rs +++ b/platform/aarch64/rk3568/board.rs @@ -168,12 +168,12 @@ pub const ROOT_ZONE_IRQS: [u32; 20] = [ pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { gic_version: 3, gic_config: GicConfig::Gicv3(Gicv3Config { - gicd_base: 0xfe600000, + gicd_base: 0xfd400000, gicd_size: 0x10000, - gicr_base: 0xfe680000, - gicr_size: 0x100000, - gits_base: 0x8080000, - gits_size: 0x20000, + gicr_base: 0xfd460000, + gicr_size: 0xc0000, + gits_base: 0x0, + gits_size: 0x0, }), }; From 88def495e49b9a5e9f50b1ef1382dbcc14808992 Mon Sep 17 00:00:00 2001 From: hangqi-ren <2572131118@qq.com> Date: Thu, 26 Jun 2025 01:41:09 +0800 Subject: [PATCH 4/7] Manual syncing. --- src/device/irqchip/gicv2/vgic.rs | 2 +- src/device/irqchip/gicv3/mod.rs | 11 +++++------ src/device/irqchip/gicv3/vgic.rs | 7 +++++-- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/device/irqchip/gicv2/vgic.rs b/src/device/irqchip/gicv2/vgic.rs index f66aa1bc..726d8570 100644 --- a/src/device/irqchip/gicv2/vgic.rs +++ b/src/device/irqchip/gicv2/vgic.rs @@ -110,7 +110,7 @@ impl Zone { } pub fn reg_range(base: usize, n: usize, size: usize) -> core::ops::Range { - base..(base + (n - 1) * size) + base..(base + n * size) } // extend from gicv3, support half-word and byte access. diff --git a/src/device/irqchip/gicv3/mod.rs b/src/device/irqchip/gicv3/mod.rs index 02fb3b18..b4a608ef 100644 --- a/src/device/irqchip/gicv3/mod.rs +++ b/src/device/irqchip/gicv3/mod.rs @@ -85,10 +85,9 @@ use core::arch::asm; use core::ptr::write_volatile; use core::sync::atomic::AtomicU64; -use alloc::collections::btree_map::BTreeMap; use alloc::collections::vec_deque::VecDeque; use alloc::vec::Vec; -use gicr::{init_lpi_prop, GICR_ISENABLER, GICR_SGI_BASE}; +use gicr::init_lpi_prop; use gits::gits_init; use spin::{Mutex, Once}; @@ -150,7 +149,7 @@ fn gicv3_clear_pending_irqs() { static TIMER_INTERRUPT_COUNTER: AtomicU64 = AtomicU64::new(0); // how often to print timer interrupt counter -const TIMER_INTERRUPT_PRINT_TIMES: u64 = 50; +const TIMER_INTERRUPT_PRINT_INTERVAL: u64 = 50; pub fn gicv3_handle_irq_el1() { while let Some(irq_id) = pending_irq() { @@ -172,10 +171,10 @@ pub fn gicv3_handle_irq_el1() { // virtual timer interrupt TIMER_INTERRUPT_COUNTER.fetch_add(1, core::sync::atomic::Ordering::SeqCst); if TIMER_INTERRUPT_COUNTER.load(core::sync::atomic::Ordering::SeqCst) - % TIMER_INTERRUPT_PRINT_TIMES + % TIMER_INTERRUPT_PRINT_INTERVAL == 0 { - debug!( + trace!( "Virtual timer interrupt, counter = {}", TIMER_INTERRUPT_COUNTER.load(core::sync::atomic::Ordering::SeqCst) ); @@ -185,7 +184,7 @@ pub fn gicv3_handle_irq_el1() { handle_maintenace_interrupt(); } else if irq_id > 31 { //inject phy irq - debug!("*** get spi_irq id = {}", irq_id); + trace!("*** get spi_irq id = {}", irq_id); } else { warn!("not konw irq id = {}", irq_id); } diff --git a/src/device/irqchip/gicv3/vgic.rs b/src/device/irqchip/gicv3/vgic.rs index 7f55455c..9cdfd276 100644 --- a/src/device/irqchip/gicv3/vgic.rs +++ b/src/device/irqchip/gicv3/vgic.rs @@ -31,7 +31,7 @@ use crate::{ }; pub fn reg_range(base: usize, n: usize, size: usize) -> core::ops::Range { - base..(base + (n - 1) * size) + base..(base + n * size) } impl Zone { @@ -265,7 +265,7 @@ fn vgicv3_dist_misc_access(mmio: &mut MMIOAccess, gicd_base: usize) -> HvResult mmio_perform_access(gicd_base, mmio); } } else { - todo!() + todo!("vgicv3_dist_misc_access: MMIO.Address = {:#x?}", reg) } Ok(()) @@ -321,6 +321,9 @@ pub fn vgicv3_its_handler(mmio: &mut MMIOAccess, _arg: usize) -> HvResult { } GITS_CBASER => { if mmio.is_write { + if this_zone_id() == 0 { + mmio_perform_access(gits_base, mmio); + } set_cbaser(mmio.value); trace!("write GITS_CBASER: {:#x}", mmio.value); } else { From aec85a77fb5b86ba149618f592a6e24a6657c108 Mon Sep 17 00:00:00 2001 From: hangqi-ren <2572131118@qq.com> Date: Thu, 26 Jun 2025 01:46:52 +0800 Subject: [PATCH 5/7] Manual syncing. --- src/device/irqchip/gicv2/mod.rs | 5 +++++ src/device/irqchip/gicv3/mod.rs | 1 + 2 files changed, 6 insertions(+) diff --git a/src/device/irqchip/gicv2/mod.rs b/src/device/irqchip/gicv2/mod.rs index dc71c59f..df7dd06b 100644 --- a/src/device/irqchip/gicv2/mod.rs +++ b/src/device/irqchip/gicv2/mod.rs @@ -71,6 +71,11 @@ pub fn primary_init_early() { GICV2.call_once(|| { Gicv2 { gicd_base: gicv2_config.gicd_base, + /* + * Some boards have the GIC CPU interface registers alias, which will overlap DIR register, so we need to add an offset to + * find the last gic cpu alias region. + * ref: https://github.com/Xilinx/qemu-devicetrees/commit/09d4c3200538dc90082fbda9289e2af9794b9a28 + */ gicc_base: gicv2_config.gicc_base + gicv2_config.gicc_offset, gich_base: gicv2_config.gich_base, gicv_base: gicv2_config.gicv_base, diff --git a/src/device/irqchip/gicv3/mod.rs b/src/device/irqchip/gicv3/mod.rs index b4a608ef..99e22183 100644 --- a/src/device/irqchip/gicv3/mod.rs +++ b/src/device/irqchip/gicv3/mod.rs @@ -154,6 +154,7 @@ const TIMER_INTERRUPT_PRINT_INTERVAL: u64 = 50; pub fn gicv3_handle_irq_el1() { while let Some(irq_id) = pending_irq() { if irq_id < 8 { + trace!("sgi get {}, try to handle...", irq_id); deactivate_irq(irq_id); let mut ipi_handled = false; if irq_id == SGI_IPI_ID as _ { From 918bc63bbf5d4787973257e55b15d51003197618 Mon Sep 17 00:00:00 2001 From: hangqi-ren <2572131118@qq.com> Date: Thu, 26 Jun 2025 02:22:15 +0800 Subject: [PATCH 6/7] Fix license check. --- src/device/irqchip/gicv3/mod.rs | 91 ++++++--------------------------- 1 file changed, 15 insertions(+), 76 deletions(-) diff --git a/src/device/irqchip/gicv3/mod.rs b/src/device/irqchip/gicv3/mod.rs index 99e22183..5ab7596a 100644 --- a/src/device/irqchip/gicv3/mod.rs +++ b/src/device/irqchip/gicv3/mod.rs @@ -1,80 +1,19 @@ -// SPDX-License-Identifier: MIT OR Apache-2.0 +// Copyright (c) 2025 Syswonder +// hvisor is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +// FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. // -// Copyright (c) 2020-2022 Andre Richter - -//! GICv2 Driver - ARM Generic Interrupt Controller v2. -//! -//! The following is a collection of excerpts with useful information from -//! - `Programmer's Guide for ARMv8-A` -//! - `ARM Generic Interrupt Controller Architecture Specification` -//! -//! # Programmer's Guide - 10.6.1 Configuration -//! -//! The GIC is accessed as a memory-mapped peripheral. -//! -//! All cores can access the common Distributor, but the CPU interface is banked, that is, each core -//! uses the same address to access its own private CPU interface. -//! -//! It is not possible for a core to access the CPU interface of another core. -//! -//! # Architecture Specification - 10.6.2 Initialization -//! -//! Both the Distributor and the CPU interfaces are disabled at reset. The GIC must be initialized -//! after reset before it can deliver interrupts to the core. -//! -//! In the Distributor, software must configure the priority, target, security and enable individual -//! interrupts. The Distributor must subsequently be enabled through its control register -//! (GICD_CTLR). For each CPU interface, software must program the priority mask and preemption -//! settings. -//! -//! Each CPU interface block itself must be enabled through its control register (GICD_CTLR). This -//! prepares the GIC to deliver interrupts to the core. -//! -//! Before interrupts are expected in the core, software prepares the core to take interrupts by -//! setting a valid interrupt vector in the vector table, and clearing interrupt mask bits in -//! PSTATE, and setting the routing controls. -//! -//! The entire interrupt mechanism in the system can be disabled by disabling the Distributor. -//! Interrupt delivery to an individual core can be disabled by disabling its CPU interface. -//! Individual interrupts can also be disabled (or enabled) in the distributor. -//! -//! For an interrupt to reach the core, the individual interrupt, Distributor and CPU interface must -//! all be enabled. The interrupt also needs to be of sufficient priority, that is, higher than the -//! core's priority mask. -//! -//! # Architecture Specification - 1.4.2 Interrupt types -//! -//! - Peripheral interrupt -//! - Private Peripheral Interrupt (PPI) -//! - This is a peripheral interrupt that is specific to a single processor. -//! - Shared Peripheral Interrupt (SPI) -//! - This is a peripheral interrupt that the Distributor can route to any of a specified -//! combination of processors. -//! -//! - Software-generated interrupt (SGI) -//! - This is an interrupt generated by software writing to a GICD_SGIR register in the GIC. The -//! system uses SGIs for interprocessor communication. -//! - An SGI has edge-triggered properties. The software triggering of the interrupt is -//! equivalent to the edge transition of the interrupt request signal. -//! - When an SGI occurs in a multiprocessor implementation, the CPUID field in the Interrupt -//! Acknowledge Register, GICC_IAR, or the Aliased Interrupt Acknowledge Register, GICC_AIAR, -//! identifies the processor that requested the interrupt. -//! -//! # Architecture Specification - 2.2.1 Interrupt IDs -//! -//! Interrupts from sources are identified using ID numbers. Each CPU interface can see up to 1020 -//! interrupts. The banking of SPIs and PPIs increases the total number of interrupts supported by -//! the Distributor. -//! -//! The GIC assigns interrupt ID numbers ID0-ID1019 as follows: -//! - Interrupt numbers 32..1019 are used for SPIs. -//! - Interrupt numbers 0..31 are used for interrupts that are private to a CPU interface. These -//! interrupts are banked in the Distributor. -//! - A banked interrupt is one where the Distributor can have multiple interrupts with the -//! same ID. A banked interrupt is identified uniquely by its ID number and its associated -//! CPU interface number. Of the banked interrupt IDs: -//! - 00..15 SGIs -//! - 16..31 PPIs +// Syswonder Website: +// https://www.syswonder.org +// +// Authors: +// + #![allow(dead_code)] pub mod gicd; pub mod gicr; From d00a973d8cf5509e63a85840a640e4445ea7a7be Mon Sep 17 00:00:00 2001 From: hangqi-ren <2572131118@qq.com> Date: Thu, 26 Jun 2025 02:46:05 +0800 Subject: [PATCH 7/7] Fix style check. --- platform/aarch64/qemu-gicv3/board.rs | 7 +++-- src/arch/aarch64/zone.rs | 2 -- src/device/irqchip/gicv2/gic.rs | 3 +- src/device/irqchip/gicv2/gicc.rs | 7 ++--- src/device/irqchip/gicv2/gicd.rs | 1 - src/device/irqchip/gicv2/gich.rs | 9 ++---- src/device/irqchip/gicv2/gicv.rs | 7 ++--- src/device/irqchip/gicv2/mod.rs | 37 +++++++++++++++++------ src/device/irqchip/gicv2/vgic.rs | 19 +++++++++--- src/device/irqchip/gicv3/mod.rs | 27 +++++++++++++---- src/device/irqchip/gicv3/vgic.rs | 44 +++++++++++++++++----------- 11 files changed, 104 insertions(+), 59 deletions(-) diff --git a/platform/aarch64/qemu-gicv3/board.rs b/platform/aarch64/qemu-gicv3/board.rs index e171eb02..c8ea830a 100644 --- a/platform/aarch64/qemu-gicv3/board.rs +++ b/platform/aarch64/qemu-gicv3/board.rs @@ -13,7 +13,10 @@ // // Authors: // -use crate::{arch::zone::{HvArchZoneConfig,GicConfig,Gicv3Config}, config::*}; +use crate::{ + arch::zone::{GicConfig, Gicv3Config, HvArchZoneConfig}, + config::*, +}; pub const BOARD_NAME: &str = "qemu-gicv3"; @@ -79,4 +82,4 @@ pub const ROOT_PCI_CONFIG: HvPciConfig = HvPciConfig { pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; -pub const ROOT_PCI_DEVS: [u64; 2] = [0, 1 << 3]; \ No newline at end of file +pub const ROOT_PCI_DEVS: [u64; 2] = [0, 1 << 3]; diff --git a/src/arch/aarch64/zone.rs b/src/arch/aarch64/zone.rs index 81bb9f5a..a404126e 100644 --- a/src/arch/aarch64/zone.rs +++ b/src/arch/aarch64/zone.rs @@ -68,7 +68,6 @@ pub struct HvArchZoneConfig { pub gic_config: GicConfig, } - #[repr(C, usize)] #[derive(Debug, Clone)] pub enum GicConfig { @@ -100,4 +99,3 @@ pub struct Gicv3Config { pub gits_base: usize, pub gits_size: usize, } - diff --git a/src/device/irqchip/gicv2/gic.rs b/src/device/irqchip/gicv2/gic.rs index 91719e52..ffe491e2 100644 --- a/src/device/irqchip/gicv2/gic.rs +++ b/src/device/irqchip/gicv2/gic.rs @@ -102,7 +102,8 @@ fn handle_maintenace_interrupt() { } pub fn inject_irq(irq_id: usize, is_sgi: bool) -> bool { - let elrsr: u64 = (GICH.get().unwrap().get_elrsr(1) as u64) << 32 | GICH.get().unwrap().get_elrsr(0) as u64; + let elrsr: u64 = + (GICH.get().unwrap().get_elrsr(1) as u64) << 32 | GICH.get().unwrap().get_elrsr(0) as u64; let lr_num: isize = GICH.get().unwrap().get_lr_num() as isize; let lr_pint_mask: usize = 0x3ff << 10; let mut free_lr: isize = -1; diff --git a/src/device/irqchip/gicv2/gicc.rs b/src/device/irqchip/gicv2/gicc.rs index 20dab61c..a5f14df3 100644 --- a/src/device/irqchip/gicv2/gicc.rs +++ b/src/device/irqchip/gicv2/gicc.rs @@ -16,7 +16,6 @@ #![allow(unused_variables)] #![allow(dead_code)] -use spin::Once; use crate::device::irqchip::gicv2::gic_ref::GicRef; use crate::device::irqchip::gicv2::gicd::GICD; use crate::device::irqchip::gicv2::gich::{ @@ -24,6 +23,7 @@ use crate::device::irqchip::gicv2::gich::{ GICV2_GICH_VMCR_VMGRP0EN, }; use crate::device::irqchip::gicv2::GICV2; +use spin::Once; /// gicc layout definition and functions for gicc operations. /// author : ForeverYolo /// reference: @@ -86,13 +86,10 @@ unsafe impl Sync for GicCpuInterface {} // Each CPU holds one GICC. pub static GICC: Once> = Once::new(); - // unsafe { GicRef::new(GICV2.gicc_base as *const GicCpuInterface) }; pub fn gicc_init(gicc_base: usize) { unsafe { - GICC.call_once(|| { - GicRef::new(gicc_base as *const GicCpuInterface) - }); + GICC.call_once(|| GicRef::new(gicc_base as *const GicCpuInterface)); } } diff --git a/src/device/irqchip/gicv2/gicd.rs b/src/device/irqchip/gicv2/gicd.rs index c7ea652c..dd9f3283 100644 --- a/src/device/irqchip/gicv2/gicd.rs +++ b/src/device/irqchip/gicv2/gicd.rs @@ -101,7 +101,6 @@ unsafe impl Sync for GicDistributer {} // GICD is globally unique. pub static GICD: Once> = Once::new(); - // unsafe { GicRef::new(GICV2.gicd_base as *const GicDistributer) }; pub static GICD_LOCK: Mutex<()> = Mutex::new(()); pub fn gicd_init(gicd_base: usize) { diff --git a/src/device/irqchip/gicv2/gich.rs b/src/device/irqchip/gicv2/gich.rs index 95a2e6f9..982ff7ad 100644 --- a/src/device/irqchip/gicv2/gich.rs +++ b/src/device/irqchip/gicv2/gich.rs @@ -17,12 +17,12 @@ #![allow(dead_code)] use crate::device::irqchip::gicv2::gic_ref::GicRef; use crate::device::irqchip::gicv2::GICV2; +use spin::Once; /// gich layout definition and functions for gich operations. /// author : ForeverYolo use tock_registers::interfaces::{Readable, Writeable}; use tock_registers::register_structs; use tock_registers::registers::{ReadOnly, ReadWrite}; -use spin::Once; pub const GICV2_MAX_LIST_REGS_NUM: usize = 64; pub const GICV2_GICH_HCR_EN: u32 = 0x1; pub const GICV2_GICH_VMCR_VEM: u32 = 0x1 << 9; @@ -69,18 +69,13 @@ register_structs! { unsafe impl Sync for GicHypervisorInterface {} // Each CPU holds one GICH. pub static GICH: Once> = Once::new(); - // unsafe { GicRef::new(GICV2.gich_base as *const GicHypervisorInterface) }; pub fn gich_init(gich_base: usize) { unsafe { - GICH.call_once(|| { - GicRef::new(gich_base as *const GicHypervisorInterface) - }); + GICH.call_once(|| GicRef::new(gich_base as *const GicHypervisorInterface)); } - } - impl GicHypervisorInterface { // init GICH for each CPU. pub fn get_lrs_num(&self) -> u32 { diff --git a/src/device/irqchip/gicv2/gicv.rs b/src/device/irqchip/gicv2/gicv.rs index a2ea44cb..6309364a 100644 --- a/src/device/irqchip/gicv2/gicv.rs +++ b/src/device/irqchip/gicv2/gicv.rs @@ -26,12 +26,9 @@ use crate::device::irqchip::gicv2::GICV2; use spin::Once; // Each CPU holds one GICV, and it has the same register layout as GICC. pub static GICV: Once> = Once::new(); - // unsafe { GicRef::new(GICV2.gicv_base as *const GicCpuInterface) }; pub fn gicv_init(gicv_base: usize) { unsafe { - GICV.call_once(|| { - GicRef::new(gicv_base as *const GicCpuInterface) - }); + GICV.call_once(|| GicRef::new(gicv_base as *const GicCpuInterface)); } -} \ No newline at end of file +} diff --git a/src/device/irqchip/gicv2/mod.rs b/src/device/irqchip/gicv2/mod.rs index df7dd06b..516df11e 100644 --- a/src/device/irqchip/gicv2/mod.rs +++ b/src/device/irqchip/gicv2/mod.rs @@ -13,21 +13,21 @@ // // Authors: // Hangqi Ren <2572131118@qq.com> -use spin::Once; +use crate::arch::zone::{GicConfig, Gicv2Config, HvArchZoneConfig}; use crate::device::irqchip::gicv2::gic::MAX_CPU_NUM; +use crate::device::irqchip::gicv2::gicc::gicc_init; /// The outer layer is defined using gicv2. /// author: ForeverYolo /// reference: /// 1. gicv2 spec : https://www.cl.cam.ac.uk/research/srg/han/ACS-P35/zynq/arm_gic_architecture_specification.pdf use crate::device::irqchip::gicv2::gicc::GICC; -use crate::device::irqchip::gicv2::gicd::GICD; use crate::device::irqchip::gicv2::gicd::gicd_init; -use crate::device::irqchip::gicv2::gicc::gicc_init; +use crate::device::irqchip::gicv2::gicd::GICD; use crate::device::irqchip::gicv2::gich::gich_init; use crate::device::irqchip::gicv2::gicv::gicv_init; use crate::platform::ROOT_ARCH_ZONE_CONFIG; use crate::zone::Zone; -use crate::arch::zone::{HvArchZoneConfig,GicConfig,Gicv2Config}; +use spin::Once; // GIC Distributor Definition. pub mod gicd; @@ -65,7 +65,10 @@ pub fn primary_init_early() { } GicConfig::Gicv2(ref gicv2_config) => { if ROOT_ARCH_ZONE_CONFIG.gic_version != 2 { - panic!("GIC version mismatch, expected 2, got {}", ROOT_ARCH_ZONE_CONFIG.gic_version); + panic!( + "GIC version mismatch, expected 2, got {}", + ROOT_ARCH_ZONE_CONFIG.gic_version + ); } info!("GICv2 detected"); GICV2.call_once(|| { @@ -85,11 +88,27 @@ pub fn primary_init_early() { gicc_init(gicv2_config.gicc_base + gicv2_config.gicc_offset); gich_init(gicv2_config.gich_base); gicv_init(gicv2_config.gicv_base); - info!("GIC Distributor base: {:#x}, size: {:#x}", GICV2.get().unwrap().gicd_base, gicv2_config.gicd_size); - info!("GIC CPU Interface base: {:#x}, size: {:#x}", GICV2.get().unwrap().gicc_base, gicv2_config.gicc_size); + info!( + "GIC Distributor base: {:#x}, size: {:#x}", + GICV2.get().unwrap().gicd_base, + gicv2_config.gicd_size + ); + info!( + "GIC CPU Interface base: {:#x}, size: {:#x}", + GICV2.get().unwrap().gicc_base, + gicv2_config.gicc_size + ); info!("GIC CPU Interface offset: {:#x}", gicv2_config.gicc_offset); - info!("GIC Hypervisor Interface base: {:#x}, size: {:#x}", GICV2.get().unwrap().gich_base, gicv2_config.gich_size); - info!("GIC Virtual CPU Interface base: {:#x}, size: {:#x}", GICV2.get().unwrap().gicv_base, gicv2_config.gicv_size); + info!( + "GIC Hypervisor Interface base: {:#x}, size: {:#x}", + GICV2.get().unwrap().gich_base, + gicv2_config.gich_size + ); + info!( + "GIC Virtual CPU Interface base: {:#x}, size: {:#x}", + GICV2.get().unwrap().gicv_base, + gicv2_config.gicv_size + ); } }; gic::PENDING_VIRQS.call_once(|| gic::PendingIrqs::new(MAX_CPU_NUM)); diff --git a/src/device/irqchip/gicv2/vgic.rs b/src/device/irqchip/gicv2/vgic.rs index 726d8570..2b4a4158 100644 --- a/src/device/irqchip/gicv2/vgic.rs +++ b/src/device/irqchip/gicv2/vgic.rs @@ -13,7 +13,7 @@ // // Authors: // Hangqi Ren <2572131118@qq.com> -use crate::arch::zone::{HvArchZoneConfig,GicConfig,Gicv2Config}; +use crate::arch::zone::{GicConfig, Gicv2Config, HvArchZoneConfig}; use crate::device::irqchip::gicv2::gicd::{ get_max_int_num, GICD, GICD_CTRL_REG_OFFSET, GICD_ICACTIVER_REG_OFFSET, GICD_ICENABLER_REG_OFFSET, GICD_ICFGR_REG_OFFSET, GICD_ICPENDR_REG_OFFSET, @@ -47,7 +47,12 @@ impl Zone { panic!("vgicv2_mmio_init: gicd_base is null"); } info!("Initializing GICv2 MMIO regions for zone {}", self.id); - self.mmio_region_register(gicv2_config.gicd_base, gicv2_config.gicd_size, vgicv2_dist_handler, 0); + self.mmio_region_register( + gicv2_config.gicd_base, + gicv2_config.gicd_size, + vgicv2_dist_handler, + 0, + ); } } } @@ -59,14 +64,20 @@ impl Zone { panic!("GICv3 is not supported in this version of hvisor"); } GicConfig::Gicv2(ref gicv2_config) => { - if gicv2_config.gicc_base == 0 || gicv2_config.gicv_base == 0 || gicv2_config.gicc_size == 0 || gicv2_config.gicv_size == 0 + if gicv2_config.gicc_base == 0 + || gicv2_config.gicv_base == 0 + || gicv2_config.gicc_size == 0 + || gicv2_config.gicv_size == 0 { panic!("vgicv2_remap_init: gic related address is null"); } if gicv2_config.gicv_size != gicv2_config.gicc_size { panic!("vgicv2_remap_init: gicv_size not equal to gicc_size"); } - info!("Remaping GICv2 GICV MMIO regions to GICC MMIO regions for zone {}", self.id); + info!( + "Remaping GICv2 GICV MMIO regions to GICC MMIO regions for zone {}", + self.id + ); // map gicv memory region to gicc memory region. self.gpm .insert(MemoryRegion::new_with_offset_mapper( diff --git a/src/device/irqchip/gicv3/mod.rs b/src/device/irqchip/gicv3/mod.rs index 5ab7596a..590b1f17 100644 --- a/src/device/irqchip/gicv3/mod.rs +++ b/src/device/irqchip/gicv3/mod.rs @@ -34,13 +34,13 @@ use self::gicd::{enable_gic_are_ns, GICD_ICACTIVER, GICD_ICENABLER}; use self::gicr::enable_ipi; use crate::arch::aarch64::sysreg::{read_sysreg, smc_arg1, write_sysreg}; use crate::arch::cpu::this_cpu_id; +use crate::arch::zone::{GicConfig, Gicv2Config, HvArchZoneConfig}; use crate::config::root_zone_config; use crate::consts::MAX_CPU_NUM; - use crate::event::check_events; use crate::hypercall::SGI_IPI_ID; use crate::zone::Zone; -use crate::arch::zone::{HvArchZoneConfig,GicConfig,Gicv2Config}; + const ICH_HCR_UIE: u64 = 1 << 1; //TODO: add Distributor init pub fn gicc_init() { @@ -390,7 +390,10 @@ pub fn primary_init_early() { } GicConfig::Gicv3(ref gicv3_config) => { if root_config.arch_config.gic_version != 3 { - panic!("GIC version mismatch, expected 3, got {}", root_config.arch_config.gic_version); + panic!( + "GIC version mismatch, expected 3, got {}", + root_config.arch_config.gic_version + ); } info!("GICv3 detected"); GIC.call_once(|| Gic { @@ -401,9 +404,21 @@ pub fn primary_init_early() { gits_base: gicv3_config.gits_base, gits_size: gicv3_config.gits_size, }); - info!("GIC Distributor base: {:#x}, size: {:#x}", GIC.get().unwrap().gicd_base, GIC.get().unwrap().gicd_size); - info!("GIC Redistributor base: {:#x}, size: {:#x}", GIC.get().unwrap().gicr_base, GIC.get().unwrap().gicr_size); - info!("GIC ITS base: {:#x}, size: {:#x}", GIC.get().unwrap().gits_base, GIC.get().unwrap().gits_size); + info!( + "GIC Distributor base: {:#x}, size: {:#x}", + GIC.get().unwrap().gicd_base, + GIC.get().unwrap().gicd_size + ); + info!( + "GIC Redistributor base: {:#x}, size: {:#x}", + GIC.get().unwrap().gicr_base, + GIC.get().unwrap().gicr_size + ); + info!( + "GIC ITS base: {:#x}, size: {:#x}", + GIC.get().unwrap().gits_base, + GIC.get().unwrap().gits_size + ); } } init_lpi_prop(); diff --git a/src/device/irqchip/gicv3/vgic.rs b/src/device/irqchip/gicv3/vgic.rs index 9cdfd276..c5734382 100644 --- a/src/device/irqchip/gicv3/vgic.rs +++ b/src/device/irqchip/gicv3/vgic.rs @@ -17,7 +17,7 @@ use alloc::sync::Arc; use super::{gicd::GICD_LOCK, is_spi}; use crate::{ - arch::zone::{HvArchZoneConfig, GicConfig, Gicv2Config, Gicv3Config}, + arch::zone::{GicConfig, Gicv2Config, Gicv3Config, HvArchZoneConfig}, consts::MAX_CPU_NUM, device::irqchip::gicv3::{ gicd::*, gicr::*, gits::*, host_gicd_base, host_gicr_base, host_gits_base, @@ -47,8 +47,18 @@ impl Zone { panic!("vgicv3_mmio_init: gicd_base or gicr_base is null"); } - self.mmio_region_register(gicv3_config.gicd_base, gicv3_config.gicd_size, vgicv3_dist_handler, 0); - self.mmio_region_register(gicv3_config.gits_base, gicv3_config.gits_size, vgicv3_its_handler, 0); + self.mmio_region_register( + gicv3_config.gicd_base, + gicv3_config.gicd_size, + vgicv3_dist_handler, + 0, + ); + self.mmio_region_register( + gicv3_config.gits_base, + gicv3_config.gits_size, + vgicv3_its_handler, + 0, + ); for cpu in 0..MAX_CPU_NUM { let gicr_base = gicv3_config.gicr_base + cpu * PER_GICR_SIZE; @@ -214,19 +224,19 @@ pub fn vgicv3_redist_handler(mmio: &mut MMIOAccess, cpu: usize) -> HvResult { || reg == GICR_SGI_BASE + GICR_ICACTIVER || reg_range(GICR_SGI_BASE + GICR_IPRIORITYR, 8, 4).contains(®) || reg_range(GICR_SGI_BASE + GICR_ICFGR, 2, 4).contains(®) => - { - if Arc::ptr_eq(&this_zone(), get_cpu_data(cpu).zone.as_ref().unwrap()) { - // avoid linux disable maintenance interrupt - if reg == GICR_SGI_BASE + GICR_ICENABLER { - mmio.value &= !(1 << MAINTENACE_INTERRUPT); - mmio.value &= !(1 << SGI_IPI_ID); - } - // ignore access to foreign redistributors - mmio_perform_access(gicr_base, mmio); - } else { - trace!("*** gicv3_gicr_mmio_handler: ignore access to foreign redistributors ***"); + { + if Arc::ptr_eq(&this_zone(), get_cpu_data(cpu).zone.as_ref().unwrap()) { + // avoid linux disable maintenance interrupt + if reg == GICR_SGI_BASE + GICR_ICENABLER { + mmio.value &= !(1 << MAINTENACE_INTERRUPT); + mmio.value &= !(1 << SGI_IPI_ID); } + // ignore access to foreign redistributors + mmio_perform_access(gicr_base, mmio); + } else { + trace!("*** gicv3_gicr_mmio_handler: ignore access to foreign redistributors ***"); } + } _ => {} } HvResult::Ok(()) @@ -289,9 +299,9 @@ pub fn vgicv3_dist_handler(mmio: &mut MMIOAccess, _arg: usize) -> HvResult { || reg_range(GICD_ISPENDR, 32, 4).contains(®) || reg_range(GICD_ICACTIVER, 32, 4).contains(®) || reg_range(GICD_ISACTIVER, 32, 4).contains(®) => - { - restrict_bitmask_access(mmio, (reg & 0x7f) / 4, 1, true, gicd_base) - } + { + restrict_bitmask_access(mmio, (reg & 0x7f) / 4, 1, true, gicd_base) + } reg if reg_range(GICD_IGROUPR, 32, 4).contains(®) => { restrict_bitmask_access(mmio, (reg & 0x7f) / 4, 1, false, gicd_base) }