mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2025-01-18 19:26:12 +00:00
kern: use common GIC implementation for arm/arm64
This commit is contained in:
parent
f07bd0e337
commit
48e8562033
7 changed files with 364 additions and 253 deletions
|
@ -0,0 +1,279 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <mesosphere/kern_select_cpu.hpp>
|
||||||
|
#include <mesosphere/kern_k_typed_address.hpp>
|
||||||
|
|
||||||
|
namespace ams::kern::arch::arm {
|
||||||
|
|
||||||
|
struct GicDistributor {
|
||||||
|
u32 ctlr;
|
||||||
|
u32 typer;
|
||||||
|
u32 iidr;
|
||||||
|
u32 reserved_0x0c;
|
||||||
|
u32 statusr;
|
||||||
|
u32 reserved_0x14[3];
|
||||||
|
u32 impldef_0x20[8];
|
||||||
|
u32 setspi_nsr;
|
||||||
|
u32 reserved_0x44;
|
||||||
|
u32 clrspi_nsr;
|
||||||
|
u32 reserved_0x4c;
|
||||||
|
u32 setspi_sr;
|
||||||
|
u32 reserved_0x54;
|
||||||
|
u32 clrspi_sr;
|
||||||
|
u32 reserved_0x5c[9];
|
||||||
|
u32 igroupr[32];
|
||||||
|
u32 isenabler[32];
|
||||||
|
u32 icenabler[32];
|
||||||
|
u32 ispendr[32];
|
||||||
|
u32 icpendr[32];
|
||||||
|
u32 isactiver[32];
|
||||||
|
u32 icactiver[32];
|
||||||
|
union {
|
||||||
|
u8 bytes[1020];
|
||||||
|
u32 words[255];
|
||||||
|
} ipriorityr;
|
||||||
|
u32 _0x7fc;
|
||||||
|
union {
|
||||||
|
u8 bytes[1020];
|
||||||
|
u32 words[255];
|
||||||
|
} itargetsr;
|
||||||
|
u32 _0xbfc;
|
||||||
|
u32 icfgr[64];
|
||||||
|
u32 igrpmodr[32];
|
||||||
|
u32 _0xd80[32];
|
||||||
|
u32 nsacr[64];
|
||||||
|
u32 sgir;
|
||||||
|
u32 _0xf04[3];
|
||||||
|
u32 cpendsgir[4];
|
||||||
|
u32 spendsgir[4];
|
||||||
|
u32 reserved_0xf30[52];
|
||||||
|
|
||||||
|
static constexpr size_t SgirCpuTargetListShift = 16;
|
||||||
|
|
||||||
|
enum SgirTargetListFilter : u32 {
|
||||||
|
SgirTargetListFilter_CpuTargetList = (0 << 24),
|
||||||
|
SgirTargetListFilter_Others = (1 << 24),
|
||||||
|
SgirTargetListFilter_Self = (2 << 24),
|
||||||
|
SgirTargetListFilter_Reserved = (3 << 24),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
static_assert(util::is_pod<GicDistributor>::value);
|
||||||
|
static_assert(sizeof(GicDistributor) == 0x1000);
|
||||||
|
|
||||||
|
struct GicCpuInterface {
|
||||||
|
u32 ctlr;
|
||||||
|
u32 pmr;
|
||||||
|
u32 bpr;
|
||||||
|
u32 iar;
|
||||||
|
u32 eoir;
|
||||||
|
u32 rpr;
|
||||||
|
u32 hppir;
|
||||||
|
u32 abpr;
|
||||||
|
u32 aiar;
|
||||||
|
u32 aeoir;
|
||||||
|
u32 ahppir;
|
||||||
|
u32 statusr;
|
||||||
|
u32 reserved_30[4];
|
||||||
|
u32 impldef_40[36];
|
||||||
|
u32 apr[4];
|
||||||
|
u32 nsapr[4];
|
||||||
|
u32 reserved_f0[3];
|
||||||
|
u32 iidr;
|
||||||
|
u32 reserved_100[960];
|
||||||
|
u32 dir;
|
||||||
|
u32 _0x1004[1023];
|
||||||
|
};
|
||||||
|
static_assert(util::is_pod<GicCpuInterface>::value);
|
||||||
|
static_assert(sizeof(GicCpuInterface) == 0x2000);
|
||||||
|
|
||||||
|
struct KInterruptController {
|
||||||
|
NON_COPYABLE(KInterruptController);
|
||||||
|
NON_MOVEABLE(KInterruptController);
|
||||||
|
public:
|
||||||
|
static constexpr s32 NumSoftwareInterrupts = 16;
|
||||||
|
static constexpr s32 NumLocalInterrupts = NumSoftwareInterrupts + 16;
|
||||||
|
static constexpr s32 NumGlobalInterrupts = 988;
|
||||||
|
static constexpr s32 NumInterrupts = NumLocalInterrupts + NumGlobalInterrupts;
|
||||||
|
static constexpr s32 NumPriorityLevels = 4;
|
||||||
|
public:
|
||||||
|
struct LocalState {
|
||||||
|
u32 isenabler[NumLocalInterrupts / 32];
|
||||||
|
u32 ipriorityr[NumLocalInterrupts / 4];
|
||||||
|
u32 itargetsr[NumLocalInterrupts / 4];
|
||||||
|
u32 icfgr[NumLocalInterrupts / 16];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GlobalState {
|
||||||
|
u32 isenabler[NumGlobalInterrupts / 32];
|
||||||
|
u32 ipriorityr[NumGlobalInterrupts / 4];
|
||||||
|
u32 itargetsr[NumGlobalInterrupts / 4];
|
||||||
|
u32 icfgr[NumGlobalInterrupts / 16];
|
||||||
|
};
|
||||||
|
|
||||||
|
enum PriorityLevel : u8 {
|
||||||
|
PriorityLevel_High = 0,
|
||||||
|
PriorityLevel_Low = NumPriorityLevels - 1,
|
||||||
|
|
||||||
|
PriorityLevel_Timer = 1,
|
||||||
|
PriorityLevel_Scheduler = 2,
|
||||||
|
};
|
||||||
|
private:
|
||||||
|
static inline u32 s_mask[cpu::NumCores];
|
||||||
|
private:
|
||||||
|
volatile GicDistributor *gicd;
|
||||||
|
volatile GicCpuInterface *gicc;
|
||||||
|
public:
|
||||||
|
constexpr KInterruptController() : gicd(nullptr), gicc(nullptr) { /* ... */ }
|
||||||
|
|
||||||
|
void Initialize(s32 core_id);
|
||||||
|
void Finalize(s32 core_id);
|
||||||
|
|
||||||
|
void SaveCoreLocal(LocalState *state) const;
|
||||||
|
void SaveGlobal(GlobalState *state) const;
|
||||||
|
void RestoreCoreLocal(const LocalState *state) const;
|
||||||
|
void RestoreGlobal(const GlobalState *state) const;
|
||||||
|
public:
|
||||||
|
u32 GetIrq() const {
|
||||||
|
return this->gicc->iar;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr s32 ConvertRawIrq(u32 irq) {
|
||||||
|
return (irq == 0x3FF) ? -1 : (irq & 0x3FF);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Enable(s32 irq) const {
|
||||||
|
this->gicd->isenabler[irq / BITSIZEOF(u32)] = (1u << (irq % BITSIZEOF(u32)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Disable(s32 irq) const {
|
||||||
|
this->gicd->icenabler[irq / BITSIZEOF(u32)] = (1u << (irq % BITSIZEOF(u32)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clear(s32 irq) const {
|
||||||
|
this->gicd->icpendr[irq / BITSIZEOF(u32)] = (1u << (irq % BITSIZEOF(u32)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetTarget(s32 irq, s32 core_id) const {
|
||||||
|
this->gicd->itargetsr.bytes[irq] = this->gicd->itargetsr.bytes[irq] | GetGicMask(core_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearTarget(s32 irq, s32 core_id) const {
|
||||||
|
this->gicd->itargetsr.bytes[irq] = this->gicd->itargetsr.bytes[irq] & ~GetGicMask(core_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetPriorityLevel(s32 irq, s32 level) const {
|
||||||
|
MESOSPHERE_ASSERT(PriorityLevel_High <= level && level <= PriorityLevel_Low);
|
||||||
|
this->gicd->ipriorityr.bytes[irq] = ToGicPriorityValue(level);
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 GetPriorityLevel(s32 irq) const {
|
||||||
|
return FromGicPriorityValue(this->gicd->ipriorityr.bytes[irq]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetPriorityLevel(s32 level) const {
|
||||||
|
MESOSPHERE_ASSERT(PriorityLevel_High <= level && level <= PriorityLevel_Low);
|
||||||
|
this->gicc->pmr = ToGicPriorityValue(level);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetEdge(s32 irq) const {
|
||||||
|
u32 cfg = this->gicd->icfgr[irq / (BITSIZEOF(u32) / 2)];
|
||||||
|
cfg &= ~(0x3 << (2 * (irq % (BITSIZEOF(u32) / 2))));
|
||||||
|
cfg |= (0x2 << (2 * (irq % (BITSIZEOF(u32) / 2))));
|
||||||
|
this->gicd->icfgr[irq / (BITSIZEOF(u32) / 2)] = cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetLevel(s32 irq) const {
|
||||||
|
u32 cfg = this->gicd->icfgr[irq / (BITSIZEOF(u32) / 2)];
|
||||||
|
cfg &= ~(0x3 << (2 * (irq % (BITSIZEOF(u32) / 2))));
|
||||||
|
cfg |= (0x0 << (2 * (irq % (BITSIZEOF(u32) / 2))));
|
||||||
|
this->gicd->icfgr[irq / (BITSIZEOF(u32) / 2)] = cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SendInterProcessorInterrupt(s32 irq, u64 core_mask) {
|
||||||
|
MESOSPHERE_ASSERT(IsSoftware(irq));
|
||||||
|
this->gicd->sgir = GetCpuTargetListMask(irq, core_mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SendInterProcessorInterrupt(s32 irq) {
|
||||||
|
MESOSPHERE_ASSERT(IsSoftware(irq));
|
||||||
|
this->gicd->sgir = GicDistributor::SgirTargetListFilter_Others | irq;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndOfInterrupt(u32 irq) const {
|
||||||
|
this->gicc->eoir = irq;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsInterruptDefined(s32 irq) const {
|
||||||
|
const s32 num_interrupts = std::min(32 + 32 * (this->gicd->typer & 0x1F), static_cast<u32>(NumInterrupts));
|
||||||
|
return (0 <= irq && irq < num_interrupts);
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
static constexpr ALWAYS_INLINE bool IsSoftware(s32 id) {
|
||||||
|
MESOSPHERE_ASSERT(0 <= id && id < NumInterrupts);
|
||||||
|
return id < NumSoftwareInterrupts;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr ALWAYS_INLINE bool IsLocal(s32 id) {
|
||||||
|
MESOSPHERE_ASSERT(0 <= id && id < NumInterrupts);
|
||||||
|
return id < NumLocalInterrupts;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr ALWAYS_INLINE bool IsGlobal(s32 id) {
|
||||||
|
MESOSPHERE_ASSERT(0 <= id && id < NumInterrupts);
|
||||||
|
return NumLocalInterrupts <= id;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr size_t GetGlobalInterruptIndex(s32 id) {
|
||||||
|
MESOSPHERE_ASSERT(IsGlobal(id));
|
||||||
|
return id - NumLocalInterrupts;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr size_t GetLocalInterruptIndex(s32 id) {
|
||||||
|
MESOSPHERE_ASSERT(IsLocal(id));
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
static constexpr size_t PriorityShift = BITSIZEOF(u8) - __builtin_ctz(NumPriorityLevels);
|
||||||
|
static_assert(PriorityShift < BITSIZEOF(u8));
|
||||||
|
|
||||||
|
static constexpr ALWAYS_INLINE u8 ToGicPriorityValue(s32 level) {
|
||||||
|
return (level << PriorityShift) | ((1 << PriorityShift) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr ALWAYS_INLINE s32 FromGicPriorityValue(u8 priority) {
|
||||||
|
return (priority >> PriorityShift) & (NumPriorityLevels - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr ALWAYS_INLINE s32 GetCpuTargetListMask(s32 irq, u64 core_mask) {
|
||||||
|
MESOSPHERE_ASSERT(IsSoftware(irq));
|
||||||
|
MESOSPHERE_ASSERT(core_mask < (1ul << cpu::NumCores));
|
||||||
|
return GicDistributor::SgirTargetListFilter_CpuTargetList | irq | (static_cast<u16>(core_mask) << GicDistributor::SgirCpuTargetListShift);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ALWAYS_INLINE s32 GetGicMask(s32 core_id) {
|
||||||
|
return s_mask[core_id];
|
||||||
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE void SetGicMask(s32 core_id) const {
|
||||||
|
s_mask[core_id] = this->gicd->itargetsr.bytes[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
NOINLINE void SetupInterruptLines(s32 core_id) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <mesosphere/kern_select_cpu.hpp>
|
||||||
|
#include <mesosphere/kern_k_typed_address.hpp>
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
|
||||||
|
#include <mesosphere/arch/arm/kern_generic_interrupt_controller.hpp>
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#error "Unknown board for KInterruptController"
|
||||||
|
|
||||||
|
#endif
|
|
@ -18,261 +18,19 @@
|
||||||
#include <mesosphere/kern_select_cpu.hpp>
|
#include <mesosphere/kern_select_cpu.hpp>
|
||||||
#include <mesosphere/kern_k_typed_address.hpp>
|
#include <mesosphere/kern_k_typed_address.hpp>
|
||||||
|
|
||||||
namespace ams::kern::arch::arm64 {
|
#if 1
|
||||||
|
|
||||||
struct GicDistributor {
|
#include <mesosphere/arch/arm/kern_generic_interrupt_controller.hpp>
|
||||||
u32 ctlr;
|
namespace ams::kern::arch::arm64 {
|
||||||
u32 typer;
|
|
||||||
u32 iidr;
|
|
||||||
u32 reserved_0x0c;
|
|
||||||
u32 statusr;
|
|
||||||
u32 reserved_0x14[3];
|
|
||||||
u32 impldef_0x20[8];
|
|
||||||
u32 setspi_nsr;
|
|
||||||
u32 reserved_0x44;
|
|
||||||
u32 clrspi_nsr;
|
|
||||||
u32 reserved_0x4c;
|
|
||||||
u32 setspi_sr;
|
|
||||||
u32 reserved_0x54;
|
|
||||||
u32 clrspi_sr;
|
|
||||||
u32 reserved_0x5c[9];
|
|
||||||
u32 igroupr[32];
|
|
||||||
u32 isenabler[32];
|
|
||||||
u32 icenabler[32];
|
|
||||||
u32 ispendr[32];
|
|
||||||
u32 icpendr[32];
|
|
||||||
u32 isactiver[32];
|
|
||||||
u32 icactiver[32];
|
|
||||||
union {
|
|
||||||
u8 bytes[1020];
|
|
||||||
u32 words[255];
|
|
||||||
} ipriorityr;
|
|
||||||
u32 _0x7fc;
|
|
||||||
union {
|
|
||||||
u8 bytes[1020];
|
|
||||||
u32 words[255];
|
|
||||||
} itargetsr;
|
|
||||||
u32 _0xbfc;
|
|
||||||
u32 icfgr[64];
|
|
||||||
u32 igrpmodr[32];
|
|
||||||
u32 _0xd80[32];
|
|
||||||
u32 nsacr[64];
|
|
||||||
u32 sgir;
|
|
||||||
u32 _0xf04[3];
|
|
||||||
u32 cpendsgir[4];
|
|
||||||
u32 spendsgir[4];
|
|
||||||
u32 reserved_0xf30[52];
|
|
||||||
|
|
||||||
static constexpr size_t SgirCpuTargetListShift = 16;
|
using ams::kern::arch::arm::GicDistributor;
|
||||||
|
using ams::kern::arch::arm::GicCpuInterface;
|
||||||
|
using ams::kern::arch::arm::KInterruptController;
|
||||||
|
|
||||||
enum SgirTargetListFilter : u32 {
|
|
||||||
SgirTargetListFilter_CpuTargetList = (0 << 24),
|
|
||||||
SgirTargetListFilter_Others = (1 << 24),
|
|
||||||
SgirTargetListFilter_Self = (2 << 24),
|
|
||||||
SgirTargetListFilter_Reserved = (3 << 24),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
static_assert(util::is_pod<GicDistributor>::value);
|
|
||||||
static_assert(sizeof(GicDistributor) == 0x1000);
|
|
||||||
|
|
||||||
struct GicCpuInterface {
|
|
||||||
u32 ctlr;
|
|
||||||
u32 pmr;
|
|
||||||
u32 bpr;
|
|
||||||
u32 iar;
|
|
||||||
u32 eoir;
|
|
||||||
u32 rpr;
|
|
||||||
u32 hppir;
|
|
||||||
u32 abpr;
|
|
||||||
u32 aiar;
|
|
||||||
u32 aeoir;
|
|
||||||
u32 ahppir;
|
|
||||||
u32 statusr;
|
|
||||||
u32 reserved_30[4];
|
|
||||||
u32 impldef_40[36];
|
|
||||||
u32 apr[4];
|
|
||||||
u32 nsapr[4];
|
|
||||||
u32 reserved_f0[3];
|
|
||||||
u32 iidr;
|
|
||||||
u32 reserved_100[960];
|
|
||||||
u32 dir;
|
|
||||||
u32 _0x1004[1023];
|
|
||||||
};
|
|
||||||
static_assert(util::is_pod<GicCpuInterface>::value);
|
|
||||||
static_assert(sizeof(GicCpuInterface) == 0x2000);
|
|
||||||
|
|
||||||
struct KInterruptController {
|
|
||||||
NON_COPYABLE(KInterruptController);
|
|
||||||
NON_MOVEABLE(KInterruptController);
|
|
||||||
public:
|
|
||||||
static constexpr s32 NumSoftwareInterrupts = 16;
|
|
||||||
static constexpr s32 NumLocalInterrupts = NumSoftwareInterrupts + 16;
|
|
||||||
static constexpr s32 NumGlobalInterrupts = 988;
|
|
||||||
static constexpr s32 NumInterrupts = NumLocalInterrupts + NumGlobalInterrupts;
|
|
||||||
static constexpr s32 NumPriorityLevels = 4;
|
|
||||||
public:
|
|
||||||
struct LocalState {
|
|
||||||
u32 isenabler[NumLocalInterrupts / 32];
|
|
||||||
u32 ipriorityr[NumLocalInterrupts / 4];
|
|
||||||
u32 itargetsr[NumLocalInterrupts / 4];
|
|
||||||
u32 icfgr[NumLocalInterrupts / 16];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct GlobalState {
|
|
||||||
u32 isenabler[NumGlobalInterrupts / 32];
|
|
||||||
u32 ipriorityr[NumGlobalInterrupts / 4];
|
|
||||||
u32 itargetsr[NumGlobalInterrupts / 4];
|
|
||||||
u32 icfgr[NumGlobalInterrupts / 16];
|
|
||||||
};
|
|
||||||
|
|
||||||
enum PriorityLevel : u8 {
|
|
||||||
PriorityLevel_High = 0,
|
|
||||||
PriorityLevel_Low = NumPriorityLevels - 1,
|
|
||||||
|
|
||||||
PriorityLevel_Timer = 1,
|
|
||||||
PriorityLevel_Scheduler = 2,
|
|
||||||
};
|
|
||||||
private:
|
|
||||||
static inline u32 s_mask[cpu::NumCores];
|
|
||||||
private:
|
|
||||||
volatile GicDistributor *gicd;
|
|
||||||
volatile GicCpuInterface *gicc;
|
|
||||||
public:
|
|
||||||
constexpr KInterruptController() : gicd(nullptr), gicc(nullptr) { /* ... */ }
|
|
||||||
|
|
||||||
void Initialize(s32 core_id);
|
|
||||||
void Finalize(s32 core_id);
|
|
||||||
|
|
||||||
void SaveCoreLocal(LocalState *state) const;
|
|
||||||
void SaveGlobal(GlobalState *state) const;
|
|
||||||
void RestoreCoreLocal(const LocalState *state) const;
|
|
||||||
void RestoreGlobal(const GlobalState *state) const;
|
|
||||||
public:
|
|
||||||
u32 GetIrq() const {
|
|
||||||
return this->gicc->iar;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr s32 ConvertRawIrq(u32 irq) {
|
#else
|
||||||
return (irq == 0x3FF) ? -1 : (irq & 0x3FF);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Enable(s32 irq) const {
|
#error "Unknown board for KInterruptController"
|
||||||
this->gicd->isenabler[irq / BITSIZEOF(u32)] = (1u << (irq % BITSIZEOF(u32)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Disable(s32 irq) const {
|
#endif
|
||||||
this->gicd->icenabler[irq / BITSIZEOF(u32)] = (1u << (irq % BITSIZEOF(u32)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Clear(s32 irq) const {
|
|
||||||
this->gicd->icpendr[irq / BITSIZEOF(u32)] = (1u << (irq % BITSIZEOF(u32)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetTarget(s32 irq, s32 core_id) const {
|
|
||||||
this->gicd->itargetsr.bytes[irq] = this->gicd->itargetsr.bytes[irq] | GetGicMask(core_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClearTarget(s32 irq, s32 core_id) const {
|
|
||||||
this->gicd->itargetsr.bytes[irq] = this->gicd->itargetsr.bytes[irq] & ~GetGicMask(core_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetPriorityLevel(s32 irq, s32 level) const {
|
|
||||||
MESOSPHERE_ASSERT(PriorityLevel_High <= level && level <= PriorityLevel_Low);
|
|
||||||
this->gicd->ipriorityr.bytes[irq] = ToGicPriorityValue(level);
|
|
||||||
}
|
|
||||||
|
|
||||||
s32 GetPriorityLevel(s32 irq) const {
|
|
||||||
return FromGicPriorityValue(this->gicd->ipriorityr.bytes[irq]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetPriorityLevel(s32 level) const {
|
|
||||||
MESOSPHERE_ASSERT(PriorityLevel_High <= level && level <= PriorityLevel_Low);
|
|
||||||
this->gicc->pmr = ToGicPriorityValue(level);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetEdge(s32 irq) const {
|
|
||||||
u32 cfg = this->gicd->icfgr[irq / (BITSIZEOF(u32) / 2)];
|
|
||||||
cfg &= ~(0x3 << (2 * (irq % (BITSIZEOF(u32) / 2))));
|
|
||||||
cfg |= (0x2 << (2 * (irq % (BITSIZEOF(u32) / 2))));
|
|
||||||
this->gicd->icfgr[irq / (BITSIZEOF(u32) / 2)] = cfg;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetLevel(s32 irq) const {
|
|
||||||
u32 cfg = this->gicd->icfgr[irq / (BITSIZEOF(u32) / 2)];
|
|
||||||
cfg &= ~(0x3 << (2 * (irq % (BITSIZEOF(u32) / 2))));
|
|
||||||
cfg |= (0x0 << (2 * (irq % (BITSIZEOF(u32) / 2))));
|
|
||||||
this->gicd->icfgr[irq / (BITSIZEOF(u32) / 2)] = cfg;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SendInterProcessorInterrupt(s32 irq, u64 core_mask) {
|
|
||||||
MESOSPHERE_ASSERT(IsSoftware(irq));
|
|
||||||
this->gicd->sgir = GetCpuTargetListMask(irq, core_mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SendInterProcessorInterrupt(s32 irq) {
|
|
||||||
MESOSPHERE_ASSERT(IsSoftware(irq));
|
|
||||||
this->gicd->sgir = GicDistributor::SgirTargetListFilter_Others | irq;
|
|
||||||
}
|
|
||||||
|
|
||||||
void EndOfInterrupt(u32 irq) const {
|
|
||||||
this->gicc->eoir = irq;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsInterruptDefined(s32 irq) const {
|
|
||||||
const s32 num_interrupts = std::min(32 + 32 * (this->gicd->typer & 0x1F), static_cast<u32>(NumInterrupts));
|
|
||||||
return (0 <= irq && irq < num_interrupts);
|
|
||||||
}
|
|
||||||
public:
|
|
||||||
static constexpr ALWAYS_INLINE bool IsSoftware(s32 id) {
|
|
||||||
MESOSPHERE_ASSERT(0 <= id && id < NumInterrupts);
|
|
||||||
return id < NumSoftwareInterrupts;
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr ALWAYS_INLINE bool IsLocal(s32 id) {
|
|
||||||
MESOSPHERE_ASSERT(0 <= id && id < NumInterrupts);
|
|
||||||
return id < NumLocalInterrupts;
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr ALWAYS_INLINE bool IsGlobal(s32 id) {
|
|
||||||
MESOSPHERE_ASSERT(0 <= id && id < NumInterrupts);
|
|
||||||
return NumLocalInterrupts <= id;
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr size_t GetGlobalInterruptIndex(s32 id) {
|
|
||||||
MESOSPHERE_ASSERT(IsGlobal(id));
|
|
||||||
return id - NumLocalInterrupts;
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr size_t GetLocalInterruptIndex(s32 id) {
|
|
||||||
MESOSPHERE_ASSERT(IsLocal(id));
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
static constexpr size_t PriorityShift = BITSIZEOF(u8) - __builtin_ctz(NumPriorityLevels);
|
|
||||||
static_assert(PriorityShift < BITSIZEOF(u8));
|
|
||||||
|
|
||||||
static constexpr ALWAYS_INLINE u8 ToGicPriorityValue(s32 level) {
|
|
||||||
return (level << PriorityShift) | ((1 << PriorityShift) - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr ALWAYS_INLINE s32 FromGicPriorityValue(u8 priority) {
|
|
||||||
return (priority >> PriorityShift) & (NumPriorityLevels - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr ALWAYS_INLINE s32 GetCpuTargetListMask(s32 irq, u64 core_mask) {
|
|
||||||
MESOSPHERE_ASSERT(IsSoftware(irq));
|
|
||||||
MESOSPHERE_ASSERT(core_mask < (1ul << cpu::NumCores));
|
|
||||||
return GicDistributor::SgirTargetListFilter_CpuTargetList | irq | (static_cast<u16>(core_mask) << GicDistributor::SgirCpuTargetListShift);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ALWAYS_INLINE s32 GetGicMask(s32 core_id) {
|
|
||||||
return s_mask[core_id];
|
|
||||||
}
|
|
||||||
|
|
||||||
ALWAYS_INLINE void SetGicMask(s32 core_id) const {
|
|
||||||
s_mask[core_id] = this->gicd->itargetsr.bytes[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
NOINLINE void SetupInterruptLines(s32 core_id) const;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
|
@ -24,6 +24,13 @@
|
||||||
using ams::kern::arch::arm64::KInterruptController;
|
using ams::kern::arch::arm64::KInterruptController;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#elif defined(ATMOSPHERE_ARCH_ARM)
|
||||||
|
|
||||||
|
#include <mesosphere/arch/arm/kern_k_interrupt_controller.hpp>
|
||||||
|
namespace ams::kern {
|
||||||
|
using ams::kern::arch::arm::KInterruptController;
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#error "Unknown architecture for KInterruptController"
|
#error "Unknown architecture for KInterruptController"
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
#include <mesosphere.hpp>
|
#include <mesosphere.hpp>
|
||||||
|
|
||||||
namespace ams::kern::arch::arm64 {
|
namespace ams::kern::arch::arm {
|
||||||
|
|
||||||
void KInterruptController::SetupInterruptLines(s32 core_id) const {
|
void KInterruptController::SetupInterruptLines(s32 core_id) const {
|
||||||
const size_t ITLines = (core_id == 0) ? 32 * ((this->gicd->typer & 0x1F) + 1) : NumLocalInterrupts;
|
const size_t ITLines = (core_id == 0) ? 32 * ((this->gicd->typer & 0x1F) + 1) : NumLocalInterrupts;
|
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <mesosphere.hpp>
|
||||||
|
|
||||||
|
/* Include the common implementation. */
|
||||||
|
#include "../arm/kern_generic_interrupt_controller.inc"
|
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <mesosphere.hpp>
|
||||||
|
|
||||||
|
/* Include the common implementation. */
|
||||||
|
#include "../arm/kern_generic_interrupt_controller.inc"
|
Loading…
Reference in a new issue