Skip to content

Commit

Permalink
feat: GICR
Browse files Browse the repository at this point in the history
Signed-off-by: Zone.N <[email protected]>
  • Loading branch information
MRNIU committed Feb 7, 2025
1 parent e669a5f commit ca5d05f
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 94 deletions.
35 changes: 23 additions & 12 deletions src/kernel/arch/aarch64/interrupt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,31 @@
// 1 if other device,
// 0 if not recognized.
int devintr() {
uint32_t iar = cpu_io::ICC_IAR1_EL1::Read();
uint32_t irq = Singleton<Gic>::GetInstance().gic_iar_irq(iar);
int dev = 0;

if (irq == TIMER0_IRQ) {
// if (cpuid() == 0) {
// clockintr();
// }
// timerintr();
klog::Info("Timer interrupt\n");
dev = 2;
auto irq = cpu_io::ICC_IAR1_EL1::INTID::Get();
auto dev = 0;

switch (irq) {
case TIMER0_IRQ: {
// if (cpuid() == 0) {
// clockintr();
// }
// timerintr();
klog::Info("Timer interrupt\n");
dev = 2;
break;
}
case UART0_IRQ: {
// uartintr();
klog::Info("Uart interrupt\n");
break;
}
default: {
break;
}
}

if (dev) {
cpu_io::ICC_EOIR1_EL1::Write(iar);
cpu_io::ICC_EOIR1_EL1::Write(irq);
cpu_io::DisableInterrupt();
// cpu_io::EnableInterrupt();

Expand Down
38 changes: 19 additions & 19 deletions src/kernel/driver/gic/gic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,65 +20,65 @@
#include "kernel_log.hpp"

Gic::Gic(uint64_t dist_addr, uint64_t redist_addr)
: dist_base_addr_(dist_addr), redist_base_addr_(redist_addr) {
if (dist_base_addr_ == 0 || redist_base_addr_ == 0) {
: gicd_base_addr_(dist_addr), gicr_base_addr_(redist_addr) {
if (gicd_base_addr_ == 0 || gicr_base_addr_ == 0) {
klog::Err("GIC base address is invalid. gicd [0x%X], gicc [0x%X]\n",
dist_base_addr_, redist_base_addr_);
gicd_base_addr_, gicr_base_addr_);
throw;
}

klog::Info("dist 0x%X, redist 0x%X\n", dist_base_addr_, redist_base_addr_);
klog::Info("dist 0x%X, redist 0x%X\n", gicd_base_addr_, gicr_base_addr_);

gicv3init();
gicv3inithart();
}

void Gic::Enable(uint32_t intid) const {
auto is = gicd_read(GICD_ISENABLERn(intid / kGICD_ISENABLERn_SIZE));
auto is = GICDRead(GICD_ISENABLERn(intid / kGICD_ISENABLERn_SIZE));
is |= 1 << (intid % kGICD_ISENABLERn_SIZE);
gicd_write(GICD_ISENABLERn(intid / kGICD_ISENABLERn_SIZE), is);
GICDWrite(GICD_ISENABLERn(intid / kGICD_ISENABLERn_SIZE), is);
}

void Gic::Disable(uint32_t intid) const {
auto ic = gicd_read(GICD_ICENABLERn(intid / kGICD_ICENABLERn_SIZE));
auto ic = GICDRead(GICD_ICENABLERn(intid / kGICD_ICENABLERn_SIZE));
ic |= 1 << (intid % kGICD_ICENABLERn_SIZE);
gicd_write(GICD_ICENABLERn(intid / kGICD_ICENABLERn_SIZE), ic);
GICDWrite(GICD_ICENABLERn(intid / kGICD_ICENABLERn_SIZE), ic);
}

void Gic::Clear(uint32_t intid) const {
auto ic = gicd_read(GICD_ICPENDRn(intid / kGICD_ICPENDRn_SIZE));
auto ic = GICDRead(GICD_ICPENDRn(intid / kGICD_ICPENDRn_SIZE));
ic |= 1 << (intid % kGICD_ICPENDRn_SIZE);
gicd_write(GICD_ICPENDRn(intid / kGICD_ICPENDRn_SIZE), ic);
GICDWrite(GICD_ICPENDRn(intid / kGICD_ICPENDRn_SIZE), ic);
}

auto Gic::IsEnable(uint32_t intid) const -> bool {
auto is = gicd_read(GICD_ISENABLERn(intid / kGICD_ISENABLERn_SIZE));
auto is = GICDRead(GICD_ISENABLERn(intid / kGICD_ISENABLERn_SIZE));
return is & (1 << (intid % kGICD_ISENABLERn_SIZE));
}

void Gic::SetPrio(uint32_t intid, uint32_t prio) const {
auto shift = (intid % kGICD_IPRIORITYRn_SIZE) * kGICD_IPRIORITYRn_BITS;
auto ip = gicd_read(GICD_IPRIORITYRn(intid / kGICD_IPRIORITYRn_SIZE));
auto ip = GICDRead(GICD_IPRIORITYRn(intid / kGICD_IPRIORITYRn_SIZE));
ip &= ~(kGICD_IPRIORITYRn_BITS_MASK << shift);
ip |= prio << shift;
gicd_write(GICD_IPRIORITYRn(intid / kGICD_IPRIORITYRn_SIZE), ip);
GICDWrite(GICD_IPRIORITYRn(intid / kGICD_IPRIORITYRn_SIZE), ip);
}

void Gic::SetConfig(uint32_t intid, uint32_t config) const {
auto shift = (intid % kGICD_ICFGRn_SIZE) * kGICD_ICFGRn_BITS;
auto ic = gicd_read(GICD_ICFGRn(intid / kGICD_ICFGRn_SIZE));
auto ic = GICDRead(GICD_ICFGRn(intid / kGICD_ICFGRn_SIZE));
ic &= ~(kGICD_ICFGRn_BITS_MASK << shift);
ic |= config << shift;
gicd_write(GICD_ICFGRn(intid / kGICD_ICFGRn_SIZE), ic);
GICDWrite(GICD_ICFGRn(intid / kGICD_ICFGRn_SIZE), ic);
}

void Gic::SetTarget(uint32_t intid, uint32_t cpuid) const {
auto target = gicd_read(GICD_ITARGETSRn(intid / kGICD_ITARGETSRn_SIZE));
auto target = GICDRead(GICD_ITARGETSRn(intid / kGICD_ITARGETSRn_SIZE));
target &= ~(kGICD_ICFGRn_BITS_MASK
<< ((intid % kGICD_ITARGETSRn_SIZE) * kGICD_ITARGETSRn_BITS));
gicd_write(GICD_ITARGETSRn(intid / kGICD_ITARGETSRn_SIZE),
target | ((1 << cpuid) << ((intid % kGICD_ITARGETSRn_SIZE) *
kGICD_ITARGETSRn_BITS)));
GICDWrite(GICD_ITARGETSRn(intid / kGICD_ITARGETSRn_SIZE),
target | ((1 << cpuid) << ((intid % kGICD_ITARGETSRn_SIZE) *
kGICD_ITARGETSRn_BITS)));
}

void Gic::SetupSPI(uint32_t intid) const {
Expand Down
84 changes: 21 additions & 63 deletions src/kernel/driver/gic/include/gic.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,43 +52,6 @@ class Gic {
public:
static constexpr const char* kCompatibleName = "arm,gic-v3";

/// GICC Register offsets
/// CPU Interface Control Register, RW
static constexpr const uint64_t kGICC_CTLR = 0x0000;
/// 使能 gicc
static constexpr const uint32_t kGICC_CTLR_Enable = 1;
/// 禁用 gicc
static constexpr const uint32_t kGICC_CTLR_Disable = 0;

/// Interrupt Priority Mask Register, RW
static constexpr const uint64_t kGICC_PMR = 0x0004;
/// Binary Point Register, RW
static constexpr const uint64_t kGICC_BPR = 0x0008;
/// Interrupt Acknowledge Register, RO
static constexpr const uint64_t kGICC_IAR = 0x000C;
/// End Of Interrupt Register, WO
static constexpr const uint64_t kGICC_EOIR = 0x0010;
/// Running Priority Register, RO
static constexpr const uint64_t kGICC_RPR = 0x0014;
/// Highest Priority Pending Interrupt Register, RO
static constexpr const uint64_t kGICC_HPPIR = 0x0018;
/// Aliased Binary Point Register, RW
static constexpr const uint64_t kGICC_ABPR = 0x001C;
/// Aliased Interrupt Acknowledge Register, RO
static constexpr const uint64_t kGICC_AIAR = 0x0020;
/// Aliased End of Interrupt Register, WO
static constexpr const uint64_t kGICC_AEOIR = 0x0024;
/// Aliased Highest Priority Pending Interrupt Register, RO
static constexpr const uint64_t kGICC_AHPPIR = 0x0028;
/// Active Priority Register, RW
static constexpr const uint64_t kGICC_APR0 = 0x00D0;
/// Non-secure Active Priority Register, RW
static constexpr const uint64_t kGICC_NSAPR0 = 0x00E0;
/// CPU Interface Identification Register, RO
static constexpr const uint64_t kGICC_IIDR = 0x00FC;
/// Deactivate Interrupt Register, WO
static constexpr const uint64_t kGICC_DIR = 0x1000;

/// @see
/// https://developer.arm.com/documentation/101206/0003/Programmers-model/Distributor-registers--GICD-GICDA--summary
/// GICD Register offsets
Expand Down Expand Up @@ -322,6 +285,9 @@ class Gic {
/// Component ID 3 Register, RO
static constexpr const uint32_t kGICD_CIDR3 = 0xFFFC;

/// 每个 GICR 长度
static constexpr const uint32_t kGICR_STRIDE = 0x20000;

/**
* 构造函数
* @param dev_addr 设备地址
Expand Down Expand Up @@ -418,62 +384,58 @@ class Gic {
gicr_enable_int(cpuid, intid);
}

// irq from iar
int gic_iar_irq(uint32_t iar) { return iar & 0x3ff; }

private:
uint64_t dist_base_addr_ = 0;
uint64_t redist_base_addr_ = 0;
char* rdist_addrs_[PerCpu::kMaxCoreCount];
uint64_t gicd_base_addr_ = 0;
uint64_t gicr_base_addr_ = 0;

__always_inline void gicd_write(uint32_t off, uint32_t val) const {
io::Out<uint32_t>(dist_base_addr_ + off, val);
__always_inline void GICDWrite(uint32_t off, uint32_t val) const {
io::Out<uint32_t>(gicd_base_addr_ + off, val);
}

__always_inline auto gicd_read(uint32_t off) const -> uint32_t {
return io::In<uint32_t>(dist_base_addr_ + off);
__always_inline auto GICDRead(uint32_t off) const -> uint32_t {
return io::In<uint32_t>(gicd_base_addr_ + off);
}

__always_inline void gicr_write(uint32_t cpuid, uint32_t off,
uint32_t val) const {
io::Out<uint32_t>((uint64_t)rdist_addrs_[cpuid] + off, val);
io::Out<uint32_t>(gicr_base_addr_ + cpuid * kGICR_STRIDE + off, val);
}

__always_inline auto gicr_read(uint32_t cpuid, uint32_t off) const
-> uint32_t {
return io::In<uint32_t>((uint64_t)rdist_addrs_[cpuid] + off);
return io::In<uint32_t>(gicr_base_addr_ + cpuid * kGICR_STRIDE + off);
}

/**
* 允许 no-sec group1 中断
*/
void EnableGrp1NS() const {
gicd_write(kGICD_CTLR, kGICD_CTLR_EnableGrp1NS);
GICDWrite(kGICD_CTLR, kGICD_CTLR_EnableGrp1NS);
cpu_io::ICC_IGRPEN1_EL1::Enable::Set();
}

void giccinit() {
void GICCInit() const {
cpu_io::ICC_IGRPEN1_EL1::Enable::Clear();
cpu_io::ICC_PMR_EL1::Priority::Set();
}

void gicdinit() const {
void GICDInit() const {
// 将 GICD_CTLR 清零
gicd_write(kGICD_CTLR, 0);
GICDWrite(kGICD_CTLR, 0);

// 读取 ITLinesNumber 数量
auto it_lines_number =
gicd_read(kGICD_TYPER) & kGICD_TYPER_ITLinesNumberMask;
GICDRead(kGICD_TYPER) & kGICD_TYPER_ITLinesNumberMask;

klog::Info("it_lines_number %d\n", it_lines_number);

// 设置中断为 Non-secure Group 1
for (uint32_t i = 0; i < it_lines_number; i++) {
gicd_write(GICD_IGROUPRn(i), UINT32_MAX);
GICDWrite(GICD_IGROUPRn(i), UINT32_MAX);
}
}

void gicrinit(uint32_t cpuid) {
void GICRInit(uint32_t cpuid) const {
gicr_write(cpuid, R_CTLR, 0);

cpu_io::ICC_SRE_EL1::SRE::Set();
Expand All @@ -488,11 +450,7 @@ class Gic {
}

void gicv3init() {
for (size_t i = 0; i < PerCpu::kMaxCoreCount; i++) {
rdist_addrs_[i] = (char*)(redist_base_addr_ + (i)*0x20000);
}

gicdinit();
GICDInit();

SetupSPI(UART0_IRQ);
SetupSPI(VIRTIO0_IRQ);
Expand All @@ -501,8 +459,8 @@ class Gic {
void gicv3inithart() {
int cpu = cpu_io::GetCurrentCoreId();

giccinit();
gicrinit(cpu);
GICCInit();
GICRInit(cpu);

gic_setup_ppi(cpu, TIMER0_IRQ);

Expand Down

0 comments on commit ca5d05f

Please sign in to comment.