use core::arch::global_asm;
use core::ffi::c_void;
use crate::config::*;
use crate::types::*;
pub const portSTACK_GROWTH: BaseType_t = -1;
pub const portBYTE_ALIGNMENT: usize = 16;
pub const portARCH_NAME: &str = "ARM Cortex-A53 (AArch64)";
const portINITIAL_PSTATE: StackType_t = 0x04;
const portNO_CRITICAL_NESTING: u64 = 0;
const portNO_FLOATING_POINT_CONTEXT: StackType_t = 0;
const portUNMASK_VALUE: u32 = 0xFF;
const portFPU_REGISTER_WORDS: usize = 64;
const portICCPMR_PRIORITY_MASK_OFFSET: usize = 0x04;
const portICCIAR_INTERRUPT_ACKNOWLEDGE_OFFSET: usize = 0x0C;
const portICCEOIR_END_OF_INTERRUPT_OFFSET: usize = 0x10;
const portICCBPR_BINARY_POINT_OFFSET: usize = 0x08;
pub const configUNIQUE_INTERRUPT_PRIORITIES: u32 = 32;
const portPRIORITY_SHIFT: u32 = 3;
const portMAX_BINARY_POINT_VALUE: u32 = 2;
pub const portLOWEST_INTERRUPT_PRIORITY: u32 = configUNIQUE_INTERRUPT_PRIORITIES - 1;
#[no_mangle]
pub static mut ulGICDistributorBase: u64 = 0x0800_0000;
#[no_mangle]
pub static mut ulGICCPUInterfaceBase: u64 = 0x0801_0000;
#[no_mangle]
pub static mut ulMaxAPIPriority: u32 = 18;
fn get_max_api_priority_mask() -> u32 {
unsafe { ulMaxAPIPriority << portPRIORITY_SHIFT }
}
fn get_iccpmr_address() -> *mut u32 {
unsafe { (ulGICCPUInterfaceBase as usize + portICCPMR_PRIORITY_MASK_OFFSET) as *mut u32 }
}
fn get_icciar_address() -> *const u32 {
unsafe {
(ulGICCPUInterfaceBase as usize + portICCIAR_INTERRUPT_ACKNOWLEDGE_OFFSET) as *const u32
}
}
fn get_icceoir_address() -> *mut u32 {
unsafe { (ulGICCPUInterfaceBase as usize + portICCEOIR_END_OF_INTERRUPT_OFFSET) as *mut u32 }
}
#[no_mangle]
pub static mut ullICCPMR: u64 = 0;
#[no_mangle]
pub static mut ullICCIAR: u64 = 0;
#[no_mangle]
pub static mut ullICCEOIR: u64 = 0;
#[no_mangle]
pub static mut ullMaxAPIPriorityMask: u64 = 0;
#[no_mangle]
pub extern "C" fn vPortConfigureGIC(gic_dist_base: u64, gic_cpu_base: u64, max_api_priority: u32) {
configASSERT(max_api_priority > configUNIQUE_INTERRUPT_PRIORITIES / 2);
configASSERT(max_api_priority <= configUNIQUE_INTERRUPT_PRIORITIES);
unsafe {
ulGICDistributorBase = gic_dist_base;
ulGICCPUInterfaceBase = gic_cpu_base;
ulMaxAPIPriority = max_api_priority;
ullICCPMR = gic_cpu_base + portICCPMR_PRIORITY_MASK_OFFSET as u64;
ullICCIAR = gic_cpu_base + portICCIAR_INTERRUPT_ACKNOWLEDGE_OFFSET as u64;
ullICCEOIR = gic_cpu_base + portICCEOIR_END_OF_INTERRUPT_OFFSET as u64;
ullMaxAPIPriorityMask = (max_api_priority << portPRIORITY_SHIFT) as u64;
}
}
#[no_mangle]
pub static mut ullCriticalNesting: u64 = 9999;
#[no_mangle]
pub static mut ullPortTaskHasFPUContext: u64 = 0;
#[no_mangle]
pub static mut ullPortYieldRequired: u64 = 0;
#[no_mangle]
pub static mut ullPortInterruptNesting: u64 = 0;
#[inline(always)]
pub fn portENTER_CRITICAL() {
vPortEnterCritical();
}
#[inline(always)]
pub fn portEXIT_CRITICAL() {
vPortExitCritical();
}
#[no_mangle]
pub extern "C" fn vPortEnterCritical() {
ulPortSetInterruptMask();
unsafe {
ullCriticalNesting += 1;
if ullCriticalNesting == 1 {
configASSERT(ullPortInterruptNesting == 0);
}
}
}
#[no_mangle]
pub extern "C" fn vPortExitCritical() {
unsafe {
if ullCriticalNesting > portNO_CRITICAL_NESTING {
ullCriticalNesting -= 1;
if ullCriticalNesting == portNO_CRITICAL_NESTING {
portCLEAR_INTERRUPT_MASK();
}
}
}
}
#[inline(always)]
pub fn portDISABLE_INTERRUPTS() {
unsafe {
core::arch::asm!("msr daifset, #2", options(nostack));
core::arch::asm!("dsb sy", options(nomem, nostack));
core::arch::asm!("isb sy", options(nomem, nostack));
}
}
#[inline(always)]
pub fn portENABLE_INTERRUPTS() {
unsafe {
core::arch::asm!("msr daifclr, #2", options(nostack));
core::arch::asm!("dsb sy", options(nomem, nostack));
core::arch::asm!("isb sy", options(nomem, nostack));
}
}
#[no_mangle]
pub extern "C" fn ulPortSetInterruptMask() -> u64 {
let ulReturn: u64;
unsafe {
portDISABLE_INTERRUPTS();
let iccpmr = get_iccpmr_address();
let mask_value = get_max_api_priority_mask();
let current = core::ptr::read_volatile(iccpmr);
if current == mask_value {
ulReturn = pdTRUE as u64;
} else {
ulReturn = pdFALSE as u64;
core::ptr::write_volatile(iccpmr, mask_value);
core::arch::asm!("dsb sy", options(nomem, nostack));
core::arch::asm!("isb sy", options(nomem, nostack));
}
portENABLE_INTERRUPTS();
}
ulReturn
}
#[no_mangle]
pub extern "C" fn vPortClearInterruptMask(ulNewMaskValue: u64) {
if ulNewMaskValue == pdFALSE as u64 {
portCLEAR_INTERRUPT_MASK();
}
}
#[inline(always)]
fn portCLEAR_INTERRUPT_MASK() {
unsafe {
portDISABLE_INTERRUPTS();
let iccpmr = get_iccpmr_address();
core::ptr::write_volatile(iccpmr, portUNMASK_VALUE);
core::arch::asm!("dsb sy", options(nomem, nostack));
core::arch::asm!("isb sy", options(nomem, nostack));
portENABLE_INTERRUPTS();
}
}
#[inline(always)]
pub fn portSET_INTERRUPT_MASK_FROM_ISR() -> UBaseType_t {
ulPortSetInterruptMask() as UBaseType_t
}
#[inline(always)]
pub fn portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus: UBaseType_t) {
vPortClearInterruptMask(uxSavedInterruptStatus as u64);
}
#[inline(always)]
pub fn portYIELD() {
unsafe {
core::arch::asm!("svc 0", options(nostack));
}
}
#[inline(always)]
pub fn portYIELD_FROM_ISR(xSwitchRequired: BaseType_t) {
if xSwitchRequired != pdFALSE {
unsafe {
ullPortYieldRequired = pdTRUE as u64;
}
}
}
#[inline(always)]
pub fn portEND_SWITCHING_ISR(xSwitchRequired: BaseType_t) {
portYIELD_FROM_ISR(xSwitchRequired);
}
pub unsafe fn pxPortInitialiseStack(
pxTopOfStack: *mut StackType_t,
pxCode: TaskFunction_t,
pvParameters: *mut c_void,
) -> *mut StackType_t {
unsafe {
let mut pxStack = pxTopOfStack;
pxStack = pxStack.wrapping_sub(1);
*pxStack = 0x0101010101010101u64;
pxStack = pxStack.wrapping_sub(1);
*pxStack = pvParameters as StackType_t;
pxStack = pxStack.wrapping_sub(1);
*pxStack = 0x0303030303030303u64;
pxStack = pxStack.wrapping_sub(1);
*pxStack = 0x0202020202020202u64;
pxStack = pxStack.wrapping_sub(1);
*pxStack = 0x0505050505050505u64;
pxStack = pxStack.wrapping_sub(1);
*pxStack = 0x0404040404040404u64;
pxStack = pxStack.wrapping_sub(1);
*pxStack = 0x0707070707070707u64;
pxStack = pxStack.wrapping_sub(1);
*pxStack = 0x0606060606060606u64;
pxStack = pxStack.wrapping_sub(1);
*pxStack = 0x0909090909090909u64;
pxStack = pxStack.wrapping_sub(1);
*pxStack = 0x0808080808080808u64;
pxStack = pxStack.wrapping_sub(1);
*pxStack = 0x1111111111111111u64;
pxStack = pxStack.wrapping_sub(1);
*pxStack = 0x1010101010101010u64;
pxStack = pxStack.wrapping_sub(1);
*pxStack = 0x1313131313131313u64;
pxStack = pxStack.wrapping_sub(1);
*pxStack = 0x1212121212121212u64;
pxStack = pxStack.wrapping_sub(1);
*pxStack = 0x1515151515151515u64;
pxStack = pxStack.wrapping_sub(1);
*pxStack = 0x1414141414141414u64;
pxStack = pxStack.wrapping_sub(1);
*pxStack = 0x1717171717171717u64;
pxStack = pxStack.wrapping_sub(1);
*pxStack = 0x1616161616161616u64;
pxStack = pxStack.wrapping_sub(1);
*pxStack = 0x1919191919191919u64;
pxStack = pxStack.wrapping_sub(1);
*pxStack = 0x1818181818181818u64;
pxStack = pxStack.wrapping_sub(1);
*pxStack = 0x2121212121212121u64;
pxStack = pxStack.wrapping_sub(1);
*pxStack = 0x2020202020202020u64;
pxStack = pxStack.wrapping_sub(1);
*pxStack = 0x2323232323232323u64;
pxStack = pxStack.wrapping_sub(1);
*pxStack = 0x2222222222222222u64;
pxStack = pxStack.wrapping_sub(1);
*pxStack = 0x2525252525252525u64;
pxStack = pxStack.wrapping_sub(1);
*pxStack = 0x2424242424242424u64;
pxStack = pxStack.wrapping_sub(1);
*pxStack = 0x2727272727272727u64;
pxStack = pxStack.wrapping_sub(1);
*pxStack = 0x2626262626262626u64;
pxStack = pxStack.wrapping_sub(1);
*pxStack = 0x2929292929292929u64;
pxStack = pxStack.wrapping_sub(1);
*pxStack = 0x2828282828282828u64;
pxStack = pxStack.wrapping_sub(1);
*pxStack = 0x00;
pxStack = pxStack.wrapping_sub(1);
*pxStack = prvTaskExitError as StackType_t;
pxStack = pxStack.wrapping_sub(1);
*pxStack = portINITIAL_PSTATE;
pxStack = pxStack.wrapping_sub(1);
*pxStack = pxCode as StackType_t;
pxStack = pxStack.wrapping_sub(1);
*pxStack = portNO_CRITICAL_NESTING;
pxStack = pxStack.wrapping_sub(1);
*pxStack = portNO_FLOATING_POINT_CONTEXT;
pxStack
}
}
fn prvTaskExitError() -> ! {
configASSERT(false);
portDISABLE_INTERRUPTS();
loop {
unsafe {
core::arch::asm!("wfi", options(nomem, nostack));
}
}
}
#[no_mangle]
pub extern "C" fn xPortStartScheduler() -> BaseType_t {
unsafe {
let current_el: u64;
core::arch::asm!("mrs {}, CurrentEL", out(reg) current_el);
configASSERT((current_el & 0x0c) == 0x04);
configASSERT(ullICCPMR != 0 && ullICCIAR != 0 && ullICCEOIR != 0);
let binary_point = core::ptr::read_volatile(
(ulGICCPUInterfaceBase as usize + portICCBPR_BINARY_POINT_OFFSET) as *const u32,
);
configASSERT((binary_point & 0x03) <= portMAX_BINARY_POINT_VALUE);
portDISABLE_INTERRUPTS();
vPortRestoreTaskContext();
}
0
}
pub fn vPortEndScheduler() {
configASSERT(false);
loop {
unsafe {
core::arch::asm!("wfi", options(nomem, nostack));
}
}
}
#[no_mangle]
pub extern "C" fn FreeRTOS_Tick_Handler() {
unsafe {
let iccpmr = get_iccpmr_address();
core::ptr::write_volatile(iccpmr, get_max_api_priority_mask());
core::arch::asm!("dsb sy", "isb sy", options(nomem, nostack));
}
if unsafe { crate::kernel::tasks::xTaskIncrementTick() } != pdFALSE {
unsafe {
ullPortYieldRequired = pdTRUE as u64;
}
}
portCLEAR_INTERRUPT_MASK();
}
#[no_mangle]
pub extern "C" fn vPortTaskUsesFPU() {
unsafe {
ullPortTaskHasFPUContext = pdTRUE as u64;
}
}
#[inline(always)]
pub fn xPortIsInsideInterrupt() -> BaseType_t {
unsafe {
if ullPortInterruptNesting > 0 {
pdTRUE
} else {
pdFALSE
}
}
}
#[inline(always)]
pub fn portNOP() {
unsafe {
core::arch::asm!("nop", options(nomem, nostack));
}
}
#[inline(always)]
pub fn portMEMORY_BARRIER() {
unsafe {
core::arch::asm!("dmb sy", options(nostack));
}
}
#[cfg(feature = "generate-run-time-stats")]
static mut ullRunTimeCounterStart: u64 = 0;
#[cfg(feature = "generate-run-time-stats")]
#[inline(always)]
fn prvReadRunTimeCounter() -> u64 {
let counter: u64;
unsafe {
core::arch::asm!("mrs {}, cntpct_el0", out(reg) counter, options(nomem, nostack));
}
counter
}
#[cfg(feature = "generate-run-time-stats")]
#[inline(always)]
pub fn portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() {
unsafe {
ullRunTimeCounterStart = prvReadRunTimeCounter();
}
}
#[cfg(feature = "generate-run-time-stats")]
#[inline(always)]
pub fn portGET_RUN_TIME_COUNTER_VALUE() -> crate::config::configRUN_TIME_COUNTER_TYPE {
prvReadRunTimeCounter().wrapping_sub(unsafe { ullRunTimeCounterStart })
as crate::config::configRUN_TIME_COUNTER_TYPE
}
#[cfg(feature = "generate-run-time-stats")]
#[inline(always)]
pub fn portINCREMENT_RUN_TIME_COUNTER() {
}
#[cfg(feature = "tickless-idle")]
static mut ulTimerFrequency: u64 = 0;
#[cfg(feature = "tickless-idle")]
static mut ulTimerCountsForOneTick: u64 = 0;
#[cfg(feature = "tickless-idle")]
static mut ulMaximumPossibleSuppressedTicks: TickType_t = 0;
#[cfg(feature = "tickless-idle")]
#[no_mangle]
pub extern "C" fn vPortConfigureTicklessIdle(tick_rate_hz: u32) {
unsafe {
core::arch::asm!("mrs {}, cntfrq_el0", out(reg) ulTimerFrequency);
if ulTimerFrequency > 0 && tick_rate_hz > 0 {
ulTimerCountsForOneTick = ulTimerFrequency / tick_rate_hz as u64;
ulMaximumPossibleSuppressedTicks = 0xFFFF_FFFF as TickType_t;
}
}
}
#[cfg(feature = "tickless-idle")]
pub fn vPortSuppressTicksAndSleep(xExpectedIdleTime: TickType_t) {
use crate::types::eSleepModeStatus;
unsafe {
if ulTimerCountsForOneTick == 0 || xExpectedIdleTime < 2 {
return;
}
let mut xExpectedIdleTime = xExpectedIdleTime;
if xExpectedIdleTime > ulMaximumPossibleSuppressedTicks {
xExpectedIdleTime = ulMaximumPossibleSuppressedTicks;
}
core::arch::asm!("msr daifset, #2", options(nostack));
core::arch::asm!("dsb sy", options(nomem, nostack));
core::arch::asm!("isb sy", options(nomem, nostack));
if crate::kernel::tasks::eTaskConfirmSleepModeStatus() == eSleepModeStatus::eAbortSleep {
core::arch::asm!("msr daifclr, #2", options(nostack));
return;
}
let ulCurrentCompare: u64;
core::arch::asm!("mrs {}, cntp_cval_el0", out(reg) ulCurrentCompare);
let ulCurrentCount: u64;
core::arch::asm!("mrs {}, cntpct_el0", out(reg) ulCurrentCount);
let ulCountsRemaining = if ulCurrentCompare > ulCurrentCount {
ulCurrentCompare - ulCurrentCount
} else {
0 };
let ulNewCompare = ulCurrentCount
+ ulCountsRemaining
+ (ulTimerCountsForOneTick * (xExpectedIdleTime as u64 - 1));
core::arch::asm!("msr cntp_cval_el0, {}", in(reg) ulNewCompare);
core::arch::asm!("dsb sy", options(nomem, nostack));
core::arch::asm!("isb sy", options(nomem, nostack));
core::arch::asm!("wfi", options(nomem, nostack));
core::arch::asm!("isb sy", options(nomem, nostack));
let ulTimerCountAtWake: u64;
core::arch::asm!("mrs {}, cntpct_el0", out(reg) ulTimerCountAtWake);
core::arch::asm!("msr daifclr, #2", options(nostack));
core::arch::asm!("dsb sy", options(nomem, nostack));
core::arch::asm!("isb sy", options(nomem, nostack));
core::arch::asm!("msr daifset, #2", options(nostack));
core::arch::asm!("dsb sy", options(nomem, nostack));
core::arch::asm!("isb sy", options(nomem, nostack));
let ulElapsedCounts = if ulTimerCountAtWake > ulCurrentCount {
ulTimerCountAtWake - ulCurrentCount
} else {
0
};
let ulCompletedTicks = core::cmp::min(
ulElapsedCounts / ulTimerCountsForOneTick,
xExpectedIdleTime.saturating_sub(1) as u64,
);
if ulCompletedTicks > 0 {
crate::kernel::tasks::vTaskStepTick(ulCompletedTicks as TickType_t);
}
let ulRemainingCounts =
ulTimerCountsForOneTick - (ulElapsedCounts % ulTimerCountsForOneTick);
let ulNextCompare = ulTimerCountAtWake + ulRemainingCounts;
core::arch::asm!("msr cntp_cval_el0, {}", in(reg) ulNextCompare);
core::arch::asm!("dsb sy", options(nomem, nostack));
core::arch::asm!("isb sy", options(nomem, nostack));
core::arch::asm!("msr daifclr, #2", options(nostack));
}
}
#[cfg(not(feature = "tickless-idle"))]
pub fn vPortSuppressTicksAndSleep(_xExpectedIdleTime: TickType_t) {
}
extern "C" {
fn vPortRestoreTaskContext();
}
global_asm!(
".align 8",
".macro portSAVE_CONTEXT",
"msr spsel, #0",
"stp x0, x1, [sp, #-0x10]!",
"stp x2, x3, [sp, #-0x10]!",
"stp x4, x5, [sp, #-0x10]!",
"stp x6, x7, [sp, #-0x10]!",
"stp x8, x9, [sp, #-0x10]!",
"stp x10, x11, [sp, #-0x10]!",
"stp x12, x13, [sp, #-0x10]!",
"stp x14, x15, [sp, #-0x10]!",
"stp x16, x17, [sp, #-0x10]!",
"stp x18, x19, [sp, #-0x10]!",
"stp x20, x21, [sp, #-0x10]!",
"stp x22, x23, [sp, #-0x10]!",
"stp x24, x25, [sp, #-0x10]!",
"stp x26, x27, [sp, #-0x10]!",
"stp x28, x29, [sp, #-0x10]!",
"stp x30, xzr, [sp, #-0x10]!",
"mrs x3, spsr_el1",
"mrs x2, elr_el1",
"stp x2, x3, [sp, #-0x10]!",
"ldr x0, =ullCriticalNesting",
"ldr x3, [x0]",
"ldr x0, =ullPortTaskHasFPUContext",
"ldr x2, [x0]",
"cmp x2, #0",
"b.eq 1f",
"stp q0, q1, [sp, #-0x20]!",
"stp q2, q3, [sp, #-0x20]!",
"stp q4, q5, [sp, #-0x20]!",
"stp q6, q7, [sp, #-0x20]!",
"stp q8, q9, [sp, #-0x20]!",
"stp q10, q11, [sp, #-0x20]!",
"stp q12, q13, [sp, #-0x20]!",
"stp q14, q15, [sp, #-0x20]!",
"stp q16, q17, [sp, #-0x20]!",
"stp q18, q19, [sp, #-0x20]!",
"stp q20, q21, [sp, #-0x20]!",
"stp q22, q23, [sp, #-0x20]!",
"stp q24, q25, [sp, #-0x20]!",
"stp q26, q27, [sp, #-0x20]!",
"stp q28, q29, [sp, #-0x20]!",
"stp q30, q31, [sp, #-0x20]!",
"1:",
"stp x2, x3, [sp, #-0x10]!",
"ldr x0, =pxCurrentTCB",
"ldr x1, [x0]",
"mov x0, sp",
"str x0, [x1]",
"msr spsel, #1",
".endm",
".macro portRESTORE_CONTEXT",
"msr spsel, #0",
"ldr x0, =pxCurrentTCB",
"ldr x1, [x0]",
"ldr x0, [x1]",
"mov sp, x0",
"ldp x2, x3, [sp], #0x10",
"ldr x0, =ullCriticalNesting",
"mov x1, #255",
"ldr x4, =ullICCPMR",
"cmp x3, #0",
"ldr x5, [x4]",
"b.eq 2f",
"ldr x6, =ullMaxAPIPriorityMask",
"ldr x1, [x6]",
"2:",
"str w1, [x5]",
"dsb sy",
"isb sy",
"str x3, [x0]",
"ldr x0, =ullPortTaskHasFPUContext",
"str x2, [x0]",
"cmp x2, #0",
"b.eq 3f",
"ldp q30, q31, [sp], #0x20",
"ldp q28, q29, [sp], #0x20",
"ldp q26, q27, [sp], #0x20",
"ldp q24, q25, [sp], #0x20",
"ldp q22, q23, [sp], #0x20",
"ldp q20, q21, [sp], #0x20",
"ldp q18, q19, [sp], #0x20",
"ldp q16, q17, [sp], #0x20",
"ldp q14, q15, [sp], #0x20",
"ldp q12, q13, [sp], #0x20",
"ldp q10, q11, [sp], #0x20",
"ldp q8, q9, [sp], #0x20",
"ldp q6, q7, [sp], #0x20",
"ldp q4, q5, [sp], #0x20",
"ldp q2, q3, [sp], #0x20",
"ldp q0, q1, [sp], #0x20",
"3:",
"ldp x2, x3, [sp], #0x10",
"msr spsr_el1, x3",
"msr elr_el1, x2",
"ldp x30, xzr, [sp], #0x10",
"ldp x28, x29, [sp], #0x10",
"ldp x26, x27, [sp], #0x10",
"ldp x24, x25, [sp], #0x10",
"ldp x22, x23, [sp], #0x10",
"ldp x20, x21, [sp], #0x10",
"ldp x18, x19, [sp], #0x10",
"ldp x16, x17, [sp], #0x10",
"ldp x14, x15, [sp], #0x10",
"ldp x12, x13, [sp], #0x10",
"ldp x10, x11, [sp], #0x10",
"ldp x8, x9, [sp], #0x10",
"ldp x6, x7, [sp], #0x10",
"ldp x4, x5, [sp], #0x10",
"ldp x2, x3, [sp], #0x10",
"ldp x0, x1, [sp], #0x10",
"msr spsel, #1",
"eret",
".endm",
".global FreeRTOS_SWI_Handler",
".align 8",
"FreeRTOS_SWI_Handler:",
"portSAVE_CONTEXT",
"mrs x0, esr_el1",
"lsr x1, x0, #26",
"cmp x1, #0x15",
"b.ne FreeRTOS_Abort",
"bl vTaskSwitchContext",
"portRESTORE_CONTEXT",
"FreeRTOS_Abort:",
"b FreeRTOS_Abort",
".global vPortRestoreTaskContext",
".align 8",
"vPortRestoreTaskContext:",
"ldr x1, =_freertos_vector_table",
"msr vbar_el1, x1",
"dsb sy",
"isb sy",
"portRESTORE_CONTEXT",
".global FreeRTOS_IRQ_Handler",
".align 8",
"FreeRTOS_IRQ_Handler:",
"stp x0, x1, [sp, #-0x10]!",
"stp x2, x3, [sp, #-0x10]!",
"stp x4, x5, [sp, #-0x10]!",
"stp x6, x7, [sp, #-0x10]!",
"stp x8, x9, [sp, #-0x10]!",
"stp x10, x11, [sp, #-0x10]!",
"stp x12, x13, [sp, #-0x10]!",
"stp x14, x15, [sp, #-0x10]!",
"stp x16, x17, [sp, #-0x10]!",
"stp x18, x19, [sp, #-0x10]!",
"stp x29, x30, [sp, #-0x10]!",
"mrs x3, spsr_el1",
"mrs x2, elr_el1",
"stp x2, x3, [sp, #-0x10]!",
"ldr x5, =ullPortInterruptNesting",
"ldr x1, [x5]",
"add x6, x1, #1",
"str x6, [x5]",
"stp x1, x5, [sp, #-0x10]!",
"ldr x2, =ullICCIAR",
"ldr x3, [x2]",
"ldr w0, [x3]",
"stp x0, x1, [sp, #-0x10]!",
"bl vApplicationIRQHandler",
"msr daifset, #2",
"dsb sy",
"isb sy",
"ldp x0, x1, [sp], #0x10",
"ldr x4, =ullICCEOIR",
"ldr x4, [x4]",
"str w0, [x4]",
"ldp x1, x5, [sp], #0x10",
"str x1, [x5]",
"cmp x1, #0",
"b.ne 4f",
"ldr x0, =ullPortYieldRequired",
"ldr x1, [x0]",
"cmp x1, #0",
"b.eq 4f",
"mov x2, #0",
"str x2, [x0]",
"ldp x4, x5, [sp], #0x10",
"msr spsr_el1, x5",
"msr elr_el1, x4",
"dsb sy",
"isb sy",
"ldp x29, x30, [sp], #0x10",
"ldp x18, x19, [sp], #0x10",
"ldp x16, x17, [sp], #0x10",
"ldp x14, x15, [sp], #0x10",
"ldp x12, x13, [sp], #0x10",
"ldp x10, x11, [sp], #0x10",
"ldp x8, x9, [sp], #0x10",
"ldp x6, x7, [sp], #0x10",
"ldp x4, x5, [sp], #0x10",
"ldp x2, x3, [sp], #0x10",
"ldp x0, x1, [sp], #0x10",
"portSAVE_CONTEXT",
"bl vTaskSwitchContext",
"portRESTORE_CONTEXT",
"4:",
"ldp x4, x5, [sp], #0x10",
"msr spsr_el1, x5",
"msr elr_el1, x4",
"dsb sy",
"isb sy",
"ldp x29, x30, [sp], #0x10",
"ldp x18, x19, [sp], #0x10",
"ldp x16, x17, [sp], #0x10",
"ldp x14, x15, [sp], #0x10",
"ldp x12, x13, [sp], #0x10",
"ldp x10, x11, [sp], #0x10",
"ldp x8, x9, [sp], #0x10",
"ldp x6, x7, [sp], #0x10",
"ldp x4, x5, [sp], #0x10",
"ldp x2, x3, [sp], #0x10",
"ldp x0, x1, [sp], #0x10",
"eret",
);
extern "C" {
fn vApplicationIRQHandler(ulICCIAR: u32);
}
global_asm!(
".section .vectors, \"ax\"",
".global _freertos_vector_table",
".balign 2048",
"_freertos_vector_table:",
".balign 128",
"curr_el_sp0_sync:",
"b FreeRTOS_SWI_Handler",
".balign 128",
"curr_el_sp0_irq:",
"b FreeRTOS_IRQ_Handler",
".balign 128",
"curr_el_sp0_fiq:",
"b .",
".balign 128",
"curr_el_sp0_serror:",
"b .",
".balign 128",
"curr_el_spx_sync:",
"b .",
".balign 128",
"curr_el_spx_irq:",
"b .",
".balign 128",
"curr_el_spx_fiq:",
"b .",
".balign 128",
"curr_el_spx_serror:",
"b .",
".balign 128",
"lower_el_aarch64_sync:",
"b .",
".balign 128",
"lower_el_aarch64_irq:",
"b .",
".balign 128",
"lower_el_aarch64_fiq:",
"b .",
".balign 128",
"lower_el_aarch64_serror:",
"b .",
".balign 128",
"lower_el_aarch32_sync:",
"b .",
".balign 128",
"lower_el_aarch32_irq:",
"b .",
".balign 128",
"lower_el_aarch32_fiq:",
"b .",
".balign 128",
"lower_el_aarch32_serror:",
"b .",
);