Skip to content
Merged
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
76 changes: 68 additions & 8 deletions gic-driver/src/version/v3/gicd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,68 @@ register_structs! {
}

impl DistributorReg {
#[inline(never)]
unsafe fn write32(&self, offset: usize, val: u32) {
let base = self as *const _ as *mut u8;
let addr = base.add(offset) as *mut u32;
core::ptr::write_volatile(addr, val);
}

#[inline(never)]
unsafe fn write8(&self, offset: usize, val: u8) {
let base = self as *const _ as *mut u8;
core::ptr::write_volatile(base.add(offset), val);
}

#[inline(always)]
fn write_icpendr(&self, n: usize, val: u32) {
unsafe {
self.write32(0x280 + n * 4, val);
}
}

#[inline(always)]
fn write_icactiver(&self, n: usize, val: u32) {
unsafe {
self.write32(0x380 + n * 4, val);
}
}

#[inline(always)]
fn write_igroupr(&self, n: usize, val: u32) {
unsafe {
self.write32(0x80 + n * 4, val);
}
}

#[inline(always)]
fn write_isenabler(&self, n: usize, val: u32) {
unsafe {
self.write32(0x100 + n * 4, val);
}
}

#[inline(always)]
fn write_icenabler(&self, n: usize, val: u32) {
unsafe {
self.write32(0x180 + n * 4, val);
}
}

#[inline(always)]
fn write_ipriorityr(&self, n: usize, val: u8) {
unsafe {
self.write8(0x400 + n, val);
}
}

#[inline(always)]
fn write_icfgr(&self, n: usize, val: u32) {
unsafe {
self.write32(0xc00 + n * 4, val);
}
}

pub fn get_security_state(&self) -> SecurityState {
if self.is_single_security_state() || !self.has_security_extensions() {
SecurityState::Single
Expand Down Expand Up @@ -184,7 +246,7 @@ impl DistributorReg {
let num_regs = num_regs.min(self.ICENABLER.len());

for i in 0..num_regs {
self.ICENABLER[i].set(u32::MAX);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

感谢这个 PR,这里有一个潜在问题:

black_box 本质是 best-effort 的优化屏障
Rust / LLVM 没有保证它一定会阻止某种特定的 codegen(比如 post-index addressing)
不同编译器版本 / 优化级别 / backend 组合下,行为可能变化
从长期来看不太稳。
我比较推荐的方式是:不要让编译器从“数组索引”推导寻址模式,而是显式表达 MMIO 写操作

具体来说,可以考虑:
建议改为统一的寄存器访问 helper,例如:

impl Gicd {
    #[inline(always)]
    unsafe fn write32(&self, offset: usize, val: u32) {
        core::ptr::write_volatile(
            self.base.add(offset).cast::<u32>(),
            val,
        );
    }

    #[inline(always)]
    unsafe fn write_icenabler(&self, n: usize, val: u32) {
        self.write32(0x180 + n * 4, val);
    }
}

然后初始化代码变成:

for i in 0..num {
    self.write_icenabler(i, u32::MAX);
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

感谢建议,已经按照建议进行修改,virtcca环境测试可以正常通过初始化。不过有一点不同的是,write32函数使用了inline never。如果使用inline always,在我的编译环境下测试仍然会使用post-index addressing方式寻址。

self.write_icenabler(i, u32::MAX);
}
}

Expand Down Expand Up @@ -242,7 +304,7 @@ impl DistributorReg {
let num_regs = num_regs.min(self.ICPENDR.len());

for i in 0..num_regs {
self.ICPENDR[i].set(u32::MAX);
self.write_icpendr(i, u32::MAX);
}
}

Expand All @@ -252,7 +314,7 @@ impl DistributorReg {
let num_regs = num_regs.min(self.ICACTIVER.len());

for i in 0..num_regs {
self.ICACTIVER[i].set(u32::MAX);
self.write_icactiver(i, u32::MAX);
}
}

Expand All @@ -278,8 +340,7 @@ impl DistributorReg {

// Set default priority (0xA0 - middle priority) for all interrupts
for i in 32..num_priorities {
// Skip SGIs and PPIs
self.IPRIORITYR[i as usize].set(0xA0);
self.write_ipriorityr(i as usize, 0xA0);
}
}

Expand All @@ -289,7 +350,7 @@ impl DistributorReg {
let num_regs = num_regs.min(self.IGROUPR.len());

for i in 0..num_regs {
self.IGROUPR[i].set(u32::MAX);
self.write_igroupr(i, u32::MAX);
}
}

Expand Down Expand Up @@ -349,7 +410,7 @@ impl DistributorReg {

// Configure all interrupts as level-sensitive (0x0) by default
for i in 0..num_regs {
self.ICFGR[i].set(0);
self.write_icfgr(i, 0);
}
}

Expand Down Expand Up @@ -510,7 +571,6 @@ impl DistributorReg {
fn set_all_routing_to_current(&self, max_interrupts: u32) {
let current = Affinity::current();
for i in SPI_RANGE.start..max_interrupts {
// Set all SPIs to route to current CPU
self.set_interrupt_route(i, Some(current));
}
}
Expand Down
Loading