GIC and Interrupt Reset #55
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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) };
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {}
|
||||
|
|
|
@ -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");
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue