GIC and Interrupt Reset #55

Merged
sb10q merged 7 commits from pca006132/zynq-rs:gic-clean into master 2020-08-03 12:35:18 +08:00
8 changed files with 500 additions and 85 deletions

View File

@ -15,7 +15,8 @@ use libboard_zynq::{
clocks::source::{ArmPll, ClockSource, IoPll},
clocks::Clocks,
print, println,
sdio::sd_card::SdCard,
mpcore,
gic,
smoltcp::{
iface::{EthernetInterfaceBuilder, NeighborCache, Routes},
time::Instant,
@ -23,10 +24,9 @@ use libboard_zynq::{
},
time::Milliseconds,
};
#[cfg(feature = "target_zc706")]
use libboard_zynq::ps7_init;
use libcortex_a9::{
mutex::Mutex,
sync_channel::{Sender, Receiver},
sync_channel,
};
use libregister::RegisterR;
@ -37,6 +37,9 @@ use log::{info, warn};
const HWADDR: [u8; 6] = [0, 0x23, 0xde, 0xea, 0xbe, 0xef];
static mut CORE1_REQ: (Sender<usize>, Receiver<usize>) = sync_channel!(usize, 10);
static mut CORE1_RES: (Sender<usize>, Receiver<usize>) = sync_channel!(usize, 10);
#[no_mangle]
pub fn main_core0() {
// zynq::clocks::CpuClocks::enable_io(1_250_000_000);
@ -83,26 +86,6 @@ pub fn main_core0() {
clocks.cpu_1x()
);
// commented out due to OCM full
// let sd = libboard_zynq::sdio::SDIO::sdio0(true);
// // only test SD card if it is inserted
// if sd.is_card_inserted() {
// let result = SdCard::from_sdio(sd);
// match &result {
// Ok(_) => info!("OK!"),
// Err(a) => info!("{}", a),
// };
// const SIZE: usize = 512 * 2 + 1;
// let mut sd_card = result.unwrap();
// if false {
// let buffer: [u8; SIZE] = [5; SIZE];
// sd_card.write_block(0x0, 2, &buffer).unwrap();
// }
// let mut buffer: [u8; SIZE] = [0; SIZE];
// sd_card.read_block(0 /*0x1*/, 2, &mut buffer[1..]).unwrap();
// info!("buffer = {:?}", &buffer[..]);
// }
let mut flash = zynq::flash::Flash::new(200_000_000).linear_addressing_mode();
let flash_ram: &[u8] = unsafe { core::slice::from_raw_parts(flash.ptr(), flash.size()) };
for i in 0..=1 {
@ -160,20 +143,21 @@ pub fn main_core0() {
flash = flash_io.stop();
}
let core1 = boot::Core1::start(false);
boot::Core1::start(false);
let (mut core1_req, rx) = sync_channel!(usize, 10);
*CORE1_REQ.lock() = Some(rx);
let (tx, mut core1_res) = sync_channel!(usize, 10);
*CORE1_RES.lock() = Some(tx);
let core1_req = unsafe { &mut CORE1_REQ.0 };
let core1_res = unsafe { &mut CORE1_RES.1 };
let mut interrupt_controller = gic::InterruptController::new(mpcore::RegisterBlock::new());
interrupt_controller.enable_interrupts();
task::block_on(async {
for i in 0..10 {
// this interrupt would cause core1 to reset.
interrupt_controller.send_sgi(gic::InterruptId(0), gic::CPUCore::Core1.into());
core1_req.async_send(i).await;
let j = core1_res.async_recv().await;
println!("{} -> {}", i, j);
}
});
core1.disable();
let eth = zynq::eth::Eth::default(HWADDR.clone());
println!("Eth on");
@ -198,9 +182,6 @@ pub fn main_core0() {
.neighbor_cache(neighbor_cache)
.finalize();
#[cfg(feature = "target_zc706")]
ps7_init::report_differences();
Sockets::init(32);
const TCP_PORT: u16 = 19;
@ -267,24 +248,15 @@ pub fn main_core0() {
})
}
static CORE1_REQ: Mutex<Option<sync_channel::Receiver<usize>>> = Mutex::new(None);
static CORE1_RES: Mutex<Option<sync_channel::Sender<usize>>> = Mutex::new(None);
static DONE: Mutex<bool> = Mutex::new(false);
#[no_mangle]
pub fn main_core1() {
println!("Hello from core1!");
let mut req = None;
while req.is_none() {
req = CORE1_REQ.lock().take();
}
let req = req.unwrap();
let mut res = None;
while res.is_none() {
res = CORE1_RES.lock().take();
}
let mut res = res.unwrap();
let mut interrupt_controller = gic::InterruptController::new(mpcore::RegisterBlock::new());
interrupt_controller.enable_interrupts();
let req = unsafe { &mut CORE1_REQ.1 };
let res = unsafe { &mut CORE1_RES.0 };
for i in req {
res.send(i * i);

150
libboard_zynq/src/gic.rs Normal file
View File

@ -0,0 +1,150 @@
//! ARM Generic Interrupt Controller
use bit_field::BitField;
use libregister::{RegisterW, RegisterRW, RegisterR};
use super::mpcore;
#[derive(Debug, Clone, Copy)]
pub struct InterruptId(pub u8);
#[derive(Debug, Clone, Copy)]
#[repr(u8)]
pub enum CPUCore {
Core0 = 0b01,
Core1 = 0b10
}
#[derive(Debug, Clone, Copy)]
pub struct TargetCPU(u8);
impl TargetCPU {
pub const fn none() -> TargetCPU {
TargetCPU(0)
}
pub const fn and(self, other: TargetCPU) -> TargetCPU {
TargetCPU(self.0 | other.0)
}
}
impl From<CPUCore> for TargetCPU {
fn from(core: CPUCore) -> Self {
TargetCPU(core as u8)
}
}
pub enum TargetList {
CPUList(TargetCPU),
Others,
This
}
impl From<CPUCore> for TargetList {
fn from(core: CPUCore) -> Self {
TargetList::CPUList(TargetCPU(core as u8))
}
}
impl From<TargetCPU> for TargetList {
fn from(cpu: TargetCPU) -> Self {
TargetList::CPUList(cpu)
}
}
#[derive(Debug, Clone, Copy)]
pub enum InterruptSensitivity {
Level,
Edge,
}
pub struct InterruptController {
mpcore: &'static mut mpcore::RegisterBlock,
}
impl InterruptController {
pub fn new(mpcore: &'static mut mpcore::RegisterBlock) -> Self {
InterruptController { mpcore }
}
pub fn disable_interrupts(&mut self) {
self.mpcore.iccicr.modify(|_, w| w.enable_ns(false)
.enable_s(false));
// FIXME: Should we disable the distributor globally when we disable interrupt (for a single
// core)?
// self.mpcore.icddcr.modify(|_, w| w.enable_secure(false)
// .enable_non_secure(false));
}
/// enable interrupt signaling
pub fn enable_interrupts(&mut self) {
self.mpcore.iccicr.modify(|_, w| w.enable_ns(true)
.enable_s(true));
self.mpcore.icddcr.modify(|_, w| w.enable_secure(true));
// Enable all interrupts except those of the lowest priority.
self.mpcore.iccpmr.write(mpcore::ICCPMR::zeroed().priority(0xFF));
}
/// send software generated interrupt
pub fn send_sgi(&mut self, id: InterruptId, targets: TargetList) {
assert!(id.0 < 16);
self.mpcore.icdsgir.modify(|_, w| match targets {
TargetList::CPUList(list) => w.target_list_filter(0).cpu_target_list(list.0),
TargetList::Others => w.target_list_filter(0b01),
TargetList::This => w.target_list_filter(0b10)
}.sgiintid(id.0).satt(false));
}
/// enable the interrupt *for this core*.
/// Not needed for SGI.
pub fn enable(&mut self, id: InterruptId, target_cpu: CPUCore, sensitivity: InterruptSensitivity, priority: u8) {
// only 5 bits of the priority is useful
assert!(priority < 32);
self.disable_interrupts();
// enable
let m = (id.0 >> 5) as usize;
let n = (id.0 & 0x1F) as usize;
assert!(m < 3);
unsafe {
self.mpcore.icdiser[m].modify(|mut icdiser| *icdiser.set_bit(n, true));
}
// target cpu
let m = (id.0 >> 2) as usize;
let n = (8 * (id.0 & 3)) as usize;
unsafe {
self.mpcore.icdiptr[m].modify(|mut icdiptr| *icdiptr.set_bits(n..=n+1, target_cpu as u32 + 1));
}
// sensitivity
let m = (id.0 >> 4) as usize;
let n = (2 * (id.0 & 0xF)) as usize;
unsafe {
self.mpcore.icdicfr[m].modify(|mut icdicfr| *icdicfr.set_bits(n..=n+1, match sensitivity {
InterruptSensitivity::Level => 0b00,
InterruptSensitivity::Edge => 0b10,
}));
}
// priority
let offset = (id.0 % 4) * 8;
let priority: u32 = (priority as u32) << (offset + 3);
let mask: u32 = 0xFFFFFFFF ^ (0xFF << offset);
unsafe {
self.mpcore.icdipr[id.0 as usize / 4].modify(|v| (v & mask) | priority);
}
self.enable_interrupts();
}
pub fn end_interrupt(&mut self, id: InterruptId) {
self.mpcore.icceoir.modify(|_, w| w.eoiintid(id.0 as u32));
}
pub fn get_interrupt_id(&self) -> InterruptId {
InterruptId(self.mpcore.icciar.read().ackintid() as u8)
}
}

View File

@ -15,6 +15,7 @@ pub mod axi_hp;
pub mod axi_gp;
pub mod ddr;
pub mod mpcore;
pub mod gic;
pub mod flash;
pub mod time;
pub mod timer;

View File

@ -8,48 +8,141 @@ use libregister::{
#[repr(C)]
pub struct RegisterBlock {
/// SCU Control Register
pub scu_control: ScuControl,
pub scu_config: RO<u32>,
pub scu_cpu_power: RW<u32>,
/// SCU Configuration Register
pub scu_config: ScuConfig,
/// SCU CPU Power Status Register
pub scu_cpu_power_status: SCUCPUPowerStatusRegister,
/// SCU Invalidate All Registers in Secure State
pub scu_invalidate: ScuInvalidate,
reserved0: [u32; 12],
pub filter_start: RW<u32>,
pub filter_end: RW<u32>,
reserved1: [u32; 2],
pub scu_access_control: RW<u32>,
pub scu_non_secure_access_control: RW<u32>,
reserved2: [u32; 42],
pub iccicr: RW<u32>,
pub iccpmw: RW<u32>,
pub iccbpr: RW<u32>,
pub icciar: RW<u32>,
pub icceoir: RW<u32>,
pub iccrpr: RW<u32>,
pub icchpir: RW<u32>,
pub iccabpr: RW<u32>,
reserved3: [u32; 55],
pub iccidr: RW<u32>,
unused0: [u32; 12],
/// Filtering Start Address Register
pub filtering_start_address: FilteringStartAddressRegister,
/// Defined by FILTEREND input
pub filtering_end_address: FilteringEndAddressRegister,
unused1: [u32; 2],
/// SCU Access Control (SAC) Register
pub scu_access_control_sac: SCUAccessControlRegisterSAC,
/// SCU Non-secure Access Control Register SNSAC
pub scu_non_secure_access_control: SCUNonSecureAccessControlRegister,
unused2: [u32; 42],
/// CPU Interface Control Register
pub iccicr: ICCICR,
/// Interrupt Priority Mask Register
pub iccpmr: ICCPMR,
/// Binary Point Register
pub iccbpr: ICCBPR,
/// Interrupt Acknowledge Register
pub icciar: ICCIAR,
/// End Of Interrupt Register
pub icceoir: ICCEOIR,
/// Running Priority Register
pub iccrpr: ICCRPR,
/// Highest Pending Interrupt Register
pub icchpir: ICCHPIR,
/// Aliased Non-secure Binary Point Register
pub iccabpr: ICCABPR,
unused3: [u32; 55],
/// CPU Interface Implementer Identification Register
pub iccidr: ICCIDR,
/// Global Timer Counter Register 0
pub global_timer_counter0: ValueRegister,
pub global_timer_counter1: ValueRegister,
/// Global Timer Control Register
pub global_timer_control: GlobalTimerControl,
pub global_timer_interrupt_status: RW<u32>,
/// Global Timer Interrupt Status Register
pub global_timer_interrupt_status: GlobalTimerInterruptStatusRegister,
/// Comparator Value Register_0
pub comparator_value0: ValueRegister,
pub comparator_value1: ValueRegister,
pub auto_increment: ValueRegister,
reserved4: [u32; 249],
pub private_timer_load: ValueRegister,
pub private_timer_counter: ValueRegister,
pub private_timer_control: RW<u32>,
pub private_timer_interrupt_status: RW<u32>,
reserved5: [u32; 4],
pub watchdog_load: ValueRegister,
pub watchdog_counter: ValueRegister,
pub watchdog_control: RW<u32>,
pub watchdog_interrupt_status: RW<u32>,
// there is plenty more (unimplemented)
/// Auto-increment Register
pub auto_increment: RW<u32>,
unused4: [u32; 249],
/// Private Timer Load Register
pub private_timer_load: RW<u32>,
/// Private Timer Counter Register
pub private_timer_counter: RW<u32>,
/// Private Timer Control Register
pub private_timer_control: PrivateTimerControlRegister,
/// Private Timer Interrupt Status Register
pub private_timer_interrupt_status: PrivateTimerInterruptStatusRegister,
unused5: [u32; 4],
/// Watchdog Load Register
pub watchdog_load: RW<u32>,
/// Watchdog Counter Register
pub watchdog_counter: RW<u32>,
/// Watchdog Control Register
pub watchdog_control: WatchdogControlRegister,
/// Watchdog Interrupt Status Register
pub watchdog_interrupt_status: WatchdogInterruptStatusRegister,
/// Watchdog Reset Status Register
pub watchdog_reset_status: WatchdogResetStatusRegister,
/// Watchdog Disable Register
pub watchdog_disable: RW<u32>,
unused6: [u32; 626],
/// Distributor Control Register
pub icddcr: ICDDCR,
/// Interrupt Controller Type Register
pub icdictr: ICDICTR,
/// Distributor Implementer Identification Register
pub icdiidr: ICDIIDR,
unused7: [u32; 29],
/// Interrupt Security Register
pub icdisr0: RW<u32>,
pub icdisr1: RW<u32>,
pub icdisr2: RW<u32>,
unused8: [u32; 29],
/// Interrupt Set-enable Registers
pub icdiser: [RW<u32>; 3],
unused9: [u32; 29],
/// Interrupt Clear-Enable Register 0
pub icdicer0: RW<u32>,
/// Interrupt Clear-Enable Register 1
pub icdicer1: RW<u32>,
/// Interrupt Clear-Enable Register 2
pub icdicer2: RW<u32>,
unused10: [u32; 29],
/// Interrupt Set-pending Register
pub icdispr0: RW<u32>,
pub icdispr1: RW<u32>,
pub icdispr2: RW<u32>,
unused11: [u32; 29],
/// Interrupt Clear-Pending Register
pub icdicpr0: RW<u32>,
pub icdicpr1: RW<u32>,
pub icdicpr2: RW<u32>,
unused12: [u32; 29],
/// Active Bit register
pub icdabr0: RW<u32>,
pub icdabr1: RW<u32>,
pub icdabr2: RW<u32>,
unused13: [u32; 61],
/// Interrupt Priority Register
pub icdipr: [RW<u32>; 24],
unused14: [u32; 232],
/// Interrupt Processor Targets Registers
pub icdiptr: [RW<u32>; 24],
unused15: [u32; 232],
/// Interrupt Configuration Registers
pub icdicfr: [RW<u32>; 6],
unused16: [u32; 58],
/// PPI Status Register
pub ppi_status: PpiStatus,
/// SPI Status Register 0
pub spi_status_0: RO<u32>,
/// SPI Status Register 1
pub spi_status_1: RO<u32>,
unused17: [u32; 125],
/// Software Generated Interrupt Register
pub icdsgir: ICDSGIR,
}
register_at!(RegisterBlock, 0xF8F00000, new);
register!(value_register, ValueRegister, RW, u32);
register_bits!(value_register, value, u32, 0, 31);
register!(scu_control, ScuControl, RW, u32);
register_bit!(scu_control, ic_standby_enable, 6);
register_bit!(scu_control, scu_standby_enable, 5);
@ -65,6 +158,17 @@ impl ScuControl {
}
}
register!(scu_config, ScuConfig, RO, u32);
register_bits!(scu_config, tag_ram_sizes, u8, 8, 15);
register_bits!(scu_config, cpus_smp, u8, 4, 7);
register_bits!(scu_config, cpu_number, u8, 0, 1);
register!(scu_cpu_power_status, SCUCPUPowerStatusRegister, RW, u32);
register_bits!(scu_cpu_power_status, cpu3_status, u8, 24, 25);
register_bits!(scu_cpu_power_status, cpu2_status, u8, 16, 17);
register_bits!(scu_cpu_power_status, cpu1_status, u8, 8, 9);
register_bits!(scu_cpu_power_status, cpu0_status, u8, 0, 1);
register!(scu_invalidate, ScuInvalidate, WO, u32);
register_bits!(scu_invalidate, cpu0_ways, u8, 0, 3);
register_bits!(scu_invalidate, cpu1_ways, u8, 4, 7);
@ -88,8 +192,71 @@ impl ScuInvalidate {
}
}
register!(value_register, ValueRegister, RW, u32);
register_bits!(value_register, value, u32, 0, 31);
register!(filtering_start_address, FilteringStartAddressRegister, RW, u32);
register_bits!(filtering_start_address, filtering_start_address, u32, 20, 31);
register_bits!(filtering_start_address, sbz, u32, 0, 19);
register!(filtering_end_address, FilteringEndAddressRegister, RW, u32);
register_bits!(filtering_end_address, filtering_end_address, u32, 20, 31);
register_bits!(filtering_end_address, sbz, u32, 0, 19);
register!(scu_access_control_sac, SCUAccessControlRegisterSAC, RW, u32);
register_bit!(scu_access_control_sac, cp_u3, 3);
register_bit!(scu_access_control_sac, cp_u2, 2);
register_bit!(scu_access_control_sac, cp_u1, 1);
register_bit!(scu_access_control_sac, cp_u0, 0);
register!(scu_non_secure_access_control, SCUNonSecureAccessControlRegister, RO, u32);
register_bits!(scu_non_secure_access_control, sbz, u32, 12, 31);
register_bit!(scu_non_secure_access_control, cpu3_global_timer, 11);
register_bit!(scu_non_secure_access_control, cpu2_global_timer, 10);
register_bit!(scu_non_secure_access_control, cpu1_global_timer, 9);
register_bit!(scu_non_secure_access_control, cpu0_global_timer, 8);
register_bit!(scu_non_secure_access_control, private_timers_for_cpu3, 7);
register_bit!(scu_non_secure_access_control, private_timers_for_cpu2, 6);
register_bit!(scu_non_secure_access_control, private_timers_for_cpu1, 5);
register_bit!(scu_non_secure_access_control, private_timers_for_cpu0, 4);
register_bit!(scu_non_secure_access_control, component_access_for_cpu3, 3);
register_bit!(scu_non_secure_access_control, component_access_for_cpu2, 2);
register_bit!(scu_non_secure_access_control, component_access_for_cpu1, 1);
register_bit!(scu_non_secure_access_control, component_access_for_cpu0, 0);
register!(iccicr, ICCICR, RW, u32);
register_bit!(iccicr, sbpr, 4);
register_bit!(iccicr, fiq_en, 3);
register_bit!(iccicr, ack_ctl, 2);
register_bit!(iccicr, enable_ns, 1);
register_bit!(iccicr, enable_s, 0);
register!(iccpmr, ICCPMR, RW, u32);
register_bits!(iccpmr, priority, u8, 0, 7);
register!(iccbpr, ICCBPR, RW, u32);
register_bits!(iccbpr, binary_point, u8, 0, 2);
register!(icciar, ICCIAR, RW, u32);
register_bits!(icciar, cpuid, u8, 10, 12);
register_bits!(icciar, ackintid, u32, 0, 9);
register!(icceoir, ICCEOIR, RW, u32);
register_bits!(icceoir, cpuid, u8, 10, 12);
register_bits!(icceoir, eoiintid, u32, 0, 9);
register!(iccrpr, ICCRPR, RW, u32);
register_bits!(iccrpr, priority, u8, 0, 7);
register!(icchpir, ICCHPIR, RW, u32);
register_bits!(icchpir, cpuid, u8, 10, 12);
register_bits!(icchpir, pendintid, u32, 0, 9);
register!(iccabpr, ICCABPR, RW, u32);
register_bits!(iccabpr, binary_point, u8, 0, 2);
register!(iccidr, ICCIDR, RO, u32);
register_bits!(iccidr, part_number, u32, 20, 31);
register_bits!(iccidr, architecture_version, u8, 16, 19);
register_bits!(iccidr, revision_number, u8, 12, 15);
register_bits!(iccidr, implementer, u32, 0, 11);
register!(global_timer_control, GlobalTimerControl, RW, u32);
register_bits!(global_timer_control, prescaler, u8, 8, 15);
@ -97,3 +264,58 @@ register_bit!(global_timer_control, auto_increment_mode, 3);
register_bit!(global_timer_control, irq_enable, 2);
register_bit!(global_timer_control, comp_enablea, 1);
register_bit!(global_timer_control, timer_enable, 0);
register!(global_timer_interrupt_status, GlobalTimerInterruptStatusRegister, RW, u32);
register_bit!(global_timer_interrupt_status, event_flag, 0);
register!(private_timer_control, PrivateTimerControlRegister, RW, u32);
register_bits!(private_timer_control, sbzp, u32, 16, 31);
register_bits!(private_timer_control, prescaler, u8, 8, 15);
register_bits!(private_timer_control, unk_sbzp, u8, 3, 7);
register_bit!(private_timer_control, irq_enable, 2);
register_bit!(private_timer_control, auto_reload, 1);
register_bit!(private_timer_control, timer_enable, 0);
register!(private_timer_interrupt_status, PrivateTimerInterruptStatusRegister, RW, u32);
register_bits!(private_timer_interrupt_status, unk_sbzp, u32, 1, 31);
register!(watchdog_control, WatchdogControlRegister, RW, u32);
register_bits!(watchdog_control, prescaler, u8, 8, 15);
register_bit!(watchdog_control, watchdog_mode, 3);
register_bit!(watchdog_control, it_enable, 2);
register_bit!(watchdog_control, auto_reload, 1);
register_bit!(watchdog_control, watchdog_enable, 0);
register!(watchdog_interrupt_status, WatchdogInterruptStatusRegister, RW, u32);
register_bit!(watchdog_interrupt_status, event_flag, 0);
register!(watchdog_reset_status, WatchdogResetStatusRegister, RW, u32);
register_bit!(watchdog_reset_status, reset_flag, 0);
register!(icddcr, ICDDCR, RW, u32);
register_bit!(icddcr, enable_non_secure, 1);
register_bit!(icddcr, enable_secure, 0);
register!(icdictr, ICDICTR, RO, u32);
register_bits!(icdictr, lspi, u8, 11, 15);
register_bit!(icdictr, security_extn, 10);
register_bits!(icdictr, sbz, u8, 8, 9);
register_bits!(icdictr, cpu_number, u8, 5, 7);
register_bits!(icdictr, it_lines_number, u8, 0, 4);
register!(icdiidr, ICDIIDR, RO, u32);
register_bits!(icdiidr, implementation_version, u8, 24, 31);
register_bits!(icdiidr, revision_number, u32, 12, 23);
register_bits!(icdiidr, implementer, u32, 0, 11);
register!(ppi_status, PpiStatus, RO, u32);
register_bits!(ppi_status, ppi_status, u8, 11, 15);
register_bits!(ppi_status, sbz, u32, 0, 10);
register!(icdsgir, ICDSGIR, RW, u32);
register_bits!(icdsgir, target_list_filter, u8, 24, 25);
register_bits!(icdsgir, cpu_target_list, u8, 16, 23);
register_bit!(icdsgir, satt, 15);
register_bits!(icdsgir, sbz, u32, 4, 14);
register_bits!(icdsgir, sgiintid, u8, 0, 3);

View File

@ -33,3 +33,44 @@ pub fn dsb() {
pub fn isb() {
unsafe { llvm_asm!("isb" :::: "volatile") }
}
/// Enable IRQ
#[inline]
pub unsafe fn enable_irq() {
llvm_asm!("cpsie i":::: "volatile");
}
/// Disable IRQ, return if IRQ was originally enabled.
#[inline]
pub unsafe fn enter_critical() -> bool {
let mut cpsr: u32;
llvm_asm!(
"mrs $0, cpsr
cpsid i"
: "=r"(cpsr) ::: "volatile");
(cpsr & (1 << 7)) == 0
}
#[inline]
pub unsafe fn exit_critical(enable: bool) {
// https://stackoverflow.com/questions/40019929/temporarily-disable-interrupts-on-arm
let mask: u32 = if enable {
1 << 7
} else {
0
};
llvm_asm!(
"mrs r1, cpsr
bic r1, r1, $0
msr cpsr_c, r1"
:: "r"(mask) : "r1");
}
/// Exiting IRQ
#[inline]
pub unsafe fn exit_irq() {
llvm_asm!("
mrs r0, SPSR
msr CPSR, r0
" ::: "r0");
}

View File

@ -41,19 +41,26 @@ impl<T> Mutex<T> {
/// Lock the Mutex, blocks when already locked
pub fn lock(&self) -> MutexGuard<T> {
let mut irq = unsafe { enter_critical() };
while self.locked.compare_and_swap(UNLOCKED, LOCKED, Ordering::Acquire) != UNLOCKED {
wait_for_update();
unsafe {
exit_critical(irq);
wait_for_update();
irq = enter_critical();
}
}
dmb();
MutexGuard { mutex: self }
MutexGuard { mutex: self, irq }
}
pub fn try_lock(&self) -> Option<MutexGuard<T>> {
let irq = unsafe { enter_critical() };
if self.locked.compare_and_swap(UNLOCKED, LOCKED, Ordering::Acquire) != UNLOCKED {
unsafe { exit_critical(irq) };
None
} else {
dmb();
Some(MutexGuard { mutex: self })
Some(MutexGuard { mutex: self, irq })
}
}
@ -69,6 +76,7 @@ impl<T> Mutex<T> {
/// `Deref`/`DerefMutx`
pub struct MutexGuard<'a, T> {
mutex: &'a Mutex<T>,
irq: bool,
}
impl<'a, T> Deref for MutexGuard<'a, T> {
@ -88,5 +96,6 @@ impl<'a, T> DerefMut for MutexGuard<'a, T> {
impl<'a, T> Drop for MutexGuard<'a, T> {
fn drop(&mut self) {
self.mutex.unlock();
unsafe { exit_critical(self.irq) };
}
}

View File

@ -1,6 +1,12 @@
use libregister::RegisterR;
use libcortex_a9::regs::{DFSR, MPIDR};
use libboard_zynq::{println, stdio};
use libregister::{RegisterR, RegisterW};
use libcortex_a9::regs::{DFSR, MPIDR, SP};
use libcortex_a9::asm;
use libboard_zynq::{println, stdio, gic, mpcore};
extern "C" {
fn main_core1();
static mut __stack1_start: u32;
}
#[link_section = ".text.boot"]
#[no_mangle]
@ -54,6 +60,18 @@ pub unsafe extern "C" fn ReservedException() {
#[no_mangle]
#[naked]
pub unsafe extern "C" fn IRQ() {
if MPIDR.read().cpu_id() == 1{
let mpcore = mpcore::RegisterBlock::new();
let mut gic = gic::InterruptController::new(mpcore);
let id = gic.get_interrupt_id();
if id.0 == 0 {
gic.end_interrupt(id);
asm::exit_irq();
SP.write(&mut __stack1_start as *mut _ as u32);
asm::enable_irq();
main_core1();
}
}
stdio::drop_uart();
println!("IRQ");
loop {}

View File

@ -57,6 +57,7 @@ unsafe fn boot_core0() -> ! {
asm::dmb();
asm::dsb();
asm::enable_irq();
main_core0();
panic!("return from main");
});
@ -77,6 +78,7 @@ unsafe fn boot_core1() -> ! {
asm::dmb();
asm::dsb();
asm::enable_irq();
main_core1();
panic!("return from main_core1");
});