Moved proj up

This commit is contained in:
Timo Niemann
2026-06-04 10:21:56 +02:00
parent aea013305e
commit 99fb345151
949 changed files with 0 additions and 0 deletions
@@ -0,0 +1 @@
The bsp_patches contains the xlinx bsp modifications needed to port FreeRTOS-SMP to the ZynqMPOSC(A53*4) platform, see details bsp_patches/ReadMe.txt
@@ -0,0 +1,14 @@
boot.S:
Added CPU ID determination and stack initialization code after multicore startup.
xil-crt0.S:
Initialize the C runtime environment only on the primary core
Start the secondary cores
cpu.c / cpu.h:
APIs of secondary cores power up and reset
xscugic.c:
Added CPU interface initialization of the GIC for secondary cores
scugic_v4_2_diff.png:
standalone_v7_2_diff.png:
Xlinx bsp libaray modification details
@@ -0,0 +1,501 @@
/******************************************************************************
* Copyright (c) 2014 - 2020 Xilinx, Inc. All rights reserved.
* SPDX-License-Identifier: MIT
******************************************************************************/
/*****************************************************************************/
/**
* @file boot.S
*
* @addtogroup a53_64_boot_code Cortex A53 64bit Processor Boot Code
* @{
* <h2> boot.S </h2>
*
* The boot code performs minimum configuration which is required for an
* application. Cortex-A53 starts by checking current exception level. If the
* current exception level is EL3 and BSP is built for EL3, it will do
* initialization required for application execution at EL3. Below is a
* sequence illustrating what all configuration is performed before control
* reaches to main function for EL3 execution.
*
* 1. Program vector table base for exception handling
* 2. Set reset vector table base address
* 3. Program stack pointer for EL3
* 4. Routing of interrupts to EL3
* 5. Enable ECC protection
* 6. Program generic counter frequency
* 7. Invalidate instruction cache, data cache and TLBs
* 8. Configure MMU registers and program base address of translation table
* 9. Transfer control to _start which clears BSS sections and runs global
* constructor before jumping to main application
*
* If the current exception level is EL1 and BSP is also built for EL1_NONSECURE
* it will perform initialization required for application execution at EL1
* non-secure. For all other combination, the execution will go into infinite
* loop. Below is a sequence illustrating what all configuration is performed
* before control reaches to main function for EL1 execution.
*
* 1. Program vector table base for exception handling
* 2. Program stack pointer for EL1
* 3. Invalidate instruction cache, data cache and TLBs
* 4. Configure MMU registers and program base address of translation table
* 5. Transfer control to _start which clears BSS sections and runs global
* constructor before jumping to main application
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ------- -------- ---------------------------------------------------
* 5.00 pkp 05/21/14 Initial version
* 6.00 pkp 07/25/16 Program the counter frequency
* 6.02 pkp 01/22/17 Added support for EL1 non-secure
* 6.02 pkp 01/24/17 Clearing status of FPUStatus variable to ensure it
* holds correct value.
* 6.3 mus 04/20/17 CPU Cache protection bit in the L2CTLR_EL1 will be in
* set state on reset. So, setting that bit through boot
* code is redundant, hence removed the code which sets
* CPU cache protection bit.
* 6.4 mus 08/11/17 Implemented ARM erratum 855873.It fixes
* CR#982209.
* 6.6 mus 01/19/18 Added isb after writing to the cpacr_el1/cptr_el3,
* to ensure floating-point unit is disabled, before
* any subsequent instruction.
* 7.0 mus 03/26/18 Updated TCR_EL3/TCR_EL1 as per versal address map
*
*
******************************************************************************/
#include "xparameters.h"
#include "bspconfig.h"
#include "xil_errata.h"
#define FREERTOS_SMP
.globl MMUTableL0
.globl MMUTableL1
.globl MMUTableL2
.global _prestart
.global _boot
.global __el3_stack
.global __el2_stack
.global __el1_stack
.global __el0_stack
.global _vector_table
.set EL3_stack, __el3_stack
.set EL2_stack, __el2_stack
.set EL1_stack, __el1_stack
.set EL0_stack, __el0_stack
.set EL3_stack_end, _el3_stack_end
.set EL2_stack_end, _el2_stack_end
.set EL1_stack_end, _el1_stack_end
.set EL0_stack_end, _el0_stack_end
.set N_CPUS_SHIFT, 0x2
.set TT_S1_FAULT, 0x0
.set TT_S1_TABLE, 0x3
.set L0Table, MMUTableL0
.set L1Table, MMUTableL1
.set L2Table, MMUTableL2
.set vector_base, _vector_table
.set rvbar_base, 0xFD5C0040
#if defined (versal)
.set counterfreq, XPAR_CPU_CORTEXA72_0_TIMESTAMP_CLK_FREQ
#else
.set counterfreq, XPAR_CPU_CORTEXA53_0_TIMESTAMP_CLK_FREQ
#endif
.set MODE_EL1, 0x5
.set DAIF_BIT, 0x1C0
.section .boot,"ax"
/* this initializes the various processor modes */
_prestart:
_boot:
mov x0, #0
mov x1, #0
mov x2, #0
mov x3, #0
mov x4, #0
mov x5, #0
mov x6, #0
mov x7, #0
mov x8, #0
mov x9, #0
mov x10, #0
mov x11, #0
mov x12, #0
mov x13, #0
mov x14, #0
mov x15, #0
mov x16, #0
mov x17, #0
mov x18, #0
mov x19, #0
mov x20, #0
mov x21, #0
mov x22, #0
mov x23, #0
mov x24, #0
mov x25, #0
mov x26, #0
mov x27, #0
mov x28, #0
mov x29, #0
mov x30, #0
#if 0 //don't put other a53 cpus in wfi
//Which core am I
// ----------------
mrs x0, MPIDR_EL1
and x0, x0, #0xFF //Mask off to leave Aff0
cbz x0, OKToRun //If core 0, run the primary init code
EndlessLoop0:
wfi
b EndlessLoop0
#endif
OKToRun:
mrs x0, currentEL
cmp x0, #0xC
beq InitEL3
cmp x0, #0x4
beq InitEL1
b error // go to error if current exception level is neither EL3 nor EL1
InitEL3:
.if (EL3 == 1)
/*Set vector table base address*/
ldr x1, =vector_base
msr VBAR_EL3,x1
/* Set reset vector address */
/* Get the cpu ID */
mrs x0, MPIDR_EL1
and x0, x0, #0xFF
/* Save cpu ID for future use */
mov x4, x0
mov w0, w0
ldr w2, =rvbar_base
/* calculate the rvbar base address for particular CPU core */
mov w3, #0x8
mul w0, w0, w3
add w2, w2, w0
/* store vector base address to RVBAR */
str x1, [x2]
/*Define stack pointer for current exception level*/
#ifdef FREERTOS_SMP
/*EL3_stack_end */
/*------------*/
/* CPU0 stack */
/*------------*/
/* CPU1 stack */
/*------------*/
/* CPU2 stack */
/*------------*/
/* CPU3 stack */
/*------------*/
/* EL3_stack */
mov x0, N_CPUS_SHIFT
ldr x1, =EL3_stack_end
ldr x2, =EL3_stack
subs x1, x2, x1
lsr x1, x1, x0
mul x0, x1, x4
add x2, x2, x0
mov sp, x2
#else
ldr x2, =EL3_stack
mov sp, x2
#endif
/* Enable Trapping of SIMD/FPU register for standalone BSP */
mov x0, #0
#ifndef FREERTOS_BSP
orr x0, x0, #(0x1 << 10)
#endif
msr CPTR_EL3, x0
isb
/*
* Clear FPUStatus variable to make sure that it contains current
* status of FPU i.e. disabled. In case of a warm restart execution
* when bss sections are not cleared, it may contain previously updated
* value which does not hold true now.
*/
#ifndef FREERTOS_BSP
ldr x0,=FPUStatus
str xzr, [x0]
#endif
/* Configure SCR_EL3 */
mov w1, #0 //; Initial value of register is unknown
orr w1, w1, #(1 << 11) //; Set ST bit (Secure EL1 can access CNTPS_TVAL_EL1, CNTPS_CTL_EL1 & CNTPS_CVAL_EL1)
orr w1, w1, #(1 << 10) //; Set RW bit (EL1 is AArch64, as this is the Secure world)
orr w1, w1, #(1 << 3) //; Set EA bit (SError routed to EL3)
orr w1, w1, #(1 << 2) //; Set FIQ bit (FIQs routed to EL3)
orr w1, w1, #(1 << 1) //; Set IRQ bit (IRQs routed to EL3)
msr SCR_EL3, x1
/*configure cpu auxiliary control register EL1 */
ldr x0,=0x80CA000 // L1 Data prefetch control - 5, Enable device split throttle, 2 independent data prefetch streams
#if CONFIG_ARM_ERRATA_855873
/*
* Set ENDCCASCI bit in CPUACTLR_EL1 register, to execute data
* cache clean operations as data cache clean and invalidate
*
*/
orr x0, x0, #(1 << 44) //; Set ENDCCASCI bit
#endif
msr S3_1_C15_C2_0, x0 //CPUACTLR_EL1
/* program the counter frequency */
ldr x0,=counterfreq
msr CNTFRQ_EL0, x0
/*Enable hardware coherency between cores*/
mrs x0, S3_1_c15_c2_1 //Read EL1 CPU Extended Control Register
orr x0, x0, #(1 << 6) //Set the SMPEN bit
msr S3_1_c15_c2_1, x0 //Write EL1 CPU Extended Control Register
isb
tlbi ALLE3
ic IALLU //; Invalidate I cache to PoU
bl invalidate_dcaches
dsb sy
isb
ldr x1, =L0Table //; Get address of level 0 for TTBR0_EL3
msr TTBR0_EL3, x1 //; Set TTBR0_EL3
/**********************************************
* Set up memory attributes
* This equates to:
* 0 = b01000100 = Normal, Inner/Outer Non-Cacheable
* 1 = b11111111 = Normal, Inner/Outer WB/WA/RA
* 2 = b00000000 = Device-nGnRnE
* 3 = b00000100 = Device-nGnRE
* 4 = b10111011 = Normal, Inner/Outer WT/WA/RA
**********************************************/
ldr x1, =0x000000BB0400FF44
msr MAIR_EL3, x1
#if defined (versal)
/**********************************************
* Set up TCR_EL3
* Physical Address Size PS = 100 -> 44bits 16 TB
* Granual Size TG0 = 00 -> 4KB
* size offset of the memory region T0SZ = 20 -> (region size 2^(64-20) = 2^44)
***************************************************/
ldr x1,=0x80843514
#else
/**********************************************
* Set up TCR_EL3
* Physical Address Size PS = 010 -> 40bits 1TB
* Granual Size TG0 = 00 -> 4KB
* size offset of the memory region T0SZ = 24 -> (region size 2^(64-24) = 2^40)
***************************************************/
ldr x1,=0x80823518
#endif
msr TCR_EL3, x1
isb
/* Enable SError Exception for asynchronous abort */
mrs x1,DAIF
bic x1,x1,#(0x1<<8)
msr DAIF,x1
/* Configure SCTLR_EL3 */
mov x1, #0 //Most of the SCTLR_EL3 bits are unknown at reset
orr x1, x1, #(1 << 12) //Enable I cache
orr x1, x1, #(1 << 3) //Enable SP alignment check
orr x1, x1, #(1 << 2) //Enable caches
orr x1, x1, #(1 << 0) //Enable MMU
msr SCTLR_EL3, x1
dsb sy
isb
b _startup //jump to start
.else
b error // present exception level and selected exception level mismatch
.endif
InitEL1:
.if (EL1_NONSECURE == 1)
/*Set vector table base address*/
ldr x1, =vector_base
msr VBAR_EL1,x1
mrs x0, CPACR_EL1
bic x0, x0, #(0x3 << 0x20)
msr CPACR_EL1, x0
isb
/*
* Clear FPUStatus variable to make sure that it contains current
* status of FPU i.e. disabled. In case of a warm restart execution
* when bss sections are not cleared, it may contain previously updated
* value which does not hold true now.
*/
#ifndef FREERTOS_BSP
ldr x0,=FPUStatus
str xzr, [x0]
#endif
/*Define stack pointer for current exception level*/
#ifdef FREERTOS_SMP
/*EL3_stack_end */
/*------------*/
/* CPU0 stack */
/*------------*/
/* CPU1 stack */
/*------------*/
/* CPU2 stack */
/*------------*/
/* CPU3 stack */
/*------------*/
/* EL3_stack */
mov x0, N_CPUS_SHIFT
ldr x1, =EL1_stack_end
ldr x2, =EL1_stack
subs x1, x2, x1
lsr x1, x1, x0
mul x0, x1, x4
add x2, x2, x0
mov sp, x2
#else
ldr x2, =EL1_stack
mov sp, x2
#endif
/* Disable MMU first */
mov x1,#0x0
msr SCTLR_EL1, x1
isb
TLBI VMALLE1
ic IALLU //; Invalidate I cache to PoU
bl invalidate_dcaches
dsb sy
isb
ldr x1, =L0Table //; Get address of level 0 for TTBR0_EL1
msr TTBR0_EL1, x1 //; Set TTBR0_EL1
/**********************************************
* Set up memory attributes
* This equates to:
* 0 = b01000100 = Normal, Inner/Outer Non-Cacheable
* 1 = b11111111 = Normal, Inner/Outer WB/WA/RA
* 2 = b00000000 = Device-nGnRnE
* 3 = b00000100 = Device-nGnRE
* 4 = b10111011 = Normal, Inner/Outer WT/WA/RA
**********************************************/
ldr x1, =0x000000BB0400FF44
msr MAIR_EL1, x1
#if defined (versal)
/**********************************************
* Set up TCR_EL1
* Physical Address Size PS = 100 -> 44bits 16TB
* Granual Size TG0 = 00 -> 4KB
* size offset of the memory region T0SZ = 20 -> (region size 2^(64-20) = 2^44)
***************************************************/
ldr x1,=0x485800514
#else
/**********************************************
* Set up TCR_EL1
* Physical Address Size PS = 010 -> 44bits 16TB
* Granual Size TG0 = 00 -> 4KB
* size offset of the memory region T0SZ = 24 -> (region size 2^(64-24) = 2^40)
***************************************************/
ldr x1,=0x285800518
#endif
msr TCR_EL1, x1
isb
/* Enable SError Exception for asynchronous abort */
mrs x1,DAIF
bic x1,x1,#(0x1<<8)
msr DAIF,x1
//; Enable MMU
mov x1,#0x0
orr x1, x1, #(1 << 18) // ; Set WFE non trapping
orr x1, x1, #(1 << 17) // ; Set WFI non trapping
orr x1, x1, #(1 << 5) // ; Set CP15 barrier enabled
orr x1, x1, #(1 << 12) // ; Set I bit
orr x1, x1, #(1 << 2) // ; Set C bit
orr x1, x1, #(1 << 0) // ; Set M bit
msr SCTLR_EL1, x1
isb
bl _startup //jump to start
.else
b error // present exception level and selected exception level mismatch
.endif
error:
b error
invalidate_dcaches:
dmb ISH
mrs x0, CLIDR_EL1 //; x0 = CLIDR
ubfx w2, w0, #24, #3 //; w2 = CLIDR.LoC
cmp w2, #0 //; LoC is 0?
b.eq invalidateCaches_end //; No cleaning required and enable MMU
mov w1, #0 //; w1 = level iterator
invalidateCaches_flush_level:
add w3, w1, w1, lsl #1 //; w3 = w1 * 3 (right-shift for cache type)
lsr w3, w0, w3 //; w3 = w0 >> w3
ubfx w3, w3, #0, #3 //; w3 = cache type of this level
cmp w3, #2 //; No cache at this level?
b.lt invalidateCaches_next_level
lsl w4, w1, #1
msr CSSELR_EL1, x4 //; Select current cache level in CSSELR
isb //; ISB required to reflect new CSIDR
mrs x4, CCSIDR_EL1 //; w4 = CSIDR
ubfx w3, w4, #0, #3
add w3, w3, #2 //; w3 = log2(line size)
ubfx w5, w4, #13, #15
ubfx w4, w4, #3, #10 //; w4 = Way number
clz w6, w4 //; w6 = 32 - log2(number of ways)
invalidateCaches_flush_set:
mov w8, w4 //; w8 = Way number
invalidateCaches_flush_way:
lsl w7, w1, #1 //; Fill level field
lsl w9, w5, w3
orr w7, w7, w9 //; Fill index field
lsl w9, w8, w6
orr w7, w7, w9 //; Fill way field
dc CISW, x7 //; Invalidate by set/way to point of coherency
subs w8, w8, #1 //; Decrement way
b.ge invalidateCaches_flush_way
subs w5, w5, #1 //; Descrement set
b.ge invalidateCaches_flush_set
invalidateCaches_next_level:
add w1, w1, #1 //; Next level
cmp w2, w1
b.gt invalidateCaches_flush_level
invalidateCaches_end:
ret
.end
/**
* @} End of "addtogroup a53_64_boot_code".
*/
@@ -0,0 +1,240 @@
/******************************************************************************
* Copyright (c) 2024 - 2028 MindCurise, Inc. All rights reserved.
* SPDX-License-Identifier: MIT
* Ver Who Date Changes
* ----- ---- -------- -------------------------------------------------------
* 1.00 yafeng.yun 5/31/24 Initial version
******************************************************************************/
#include "cpu.h"
#define CPU_OK 0
#define CPU_FAIL 1
#define CPU_A53_0 (uint32_t)(0x0u)
#define CPU_A53_1 (uint32_t)(0x1u)
#define CPU_A53_2 (uint32_t)(0x2u)
#define CPU_A53_3 (uint32_t)(0x3u)
static uint32_t PowerUpIsland(uint32_t PwrIslandMask)
{
uint32_t RegVal;
uint32_t Status = CPU_OK;
/* Power up request enable */
Xil_Out32(PMU_GLOBAL_REQ_PWRUP_INT_EN, PwrIslandMask);
/* Trigger power up request */
Xil_Out32(PMU_GLOBAL_REQ_PWRUP_TRIG, PwrIslandMask);
/* Poll for Power up complete */
do {
RegVal = Xil_In32(PMU_GLOBAL_REQ_PWRUP_STATUS) & PwrIslandMask;
} while (RegVal != 0x0U);
return Status;
}
static uint32_t ReleaseReset_A53 (uint32_t CpuID)
{
uint32_t RegValue;
uint32_t Status;
uint32_t PwrStateMask;
switch(CpuID)
{
case CPU_A53_0:
PwrStateMask = PMU_GLOBAL_PWR_STATE_ACPU0_MASK | PMU_GLOBAL_PWR_STATE_FP_MASK | PMU_GLOBAL_PWR_STATE_L2_BANK0_MASK;
Status = PowerUpIsland(PwrStateMask);
if (Status != CPU_OK) {
goto END;
}
/**
* Enable the clock
*/
RegValue = Xil_In32(CRF_APB_ACPU_CTRL);
RegValue |= (CRF_APB_ACPU_CTRL_CLKACT_FULL_MASK | CRF_APB_ACPU_CTRL_CLKACT_HALF_MASK);
Xil_Out32(CRF_APB_ACPU_CTRL, RegValue);
/**
* Release reset
*/
RegValue = Xil_In32(CRF_APB_RST_FPD_APU);
RegValue &= ~(CRF_APB_RST_FPD_APU_ACPU0_RESET_MASK | CRF_APB_RST_FPD_APU_APU_L2_RESET_MASK | CRF_APB_RST_FPD_APU_ACPU0_PWRON_RESET_MASK);
Xil_Out32(CRF_APB_RST_FPD_APU, RegValue);
break;
case CPU_A53_1:
PwrStateMask = PMU_GLOBAL_PWR_STATE_ACPU1_MASK | PMU_GLOBAL_PWR_STATE_FP_MASK | PMU_GLOBAL_PWR_STATE_L2_BANK0_MASK;
Status = PowerUpIsland(PwrStateMask);
if (Status != CPU_OK) {
goto END;
}
/**
* Enable the clock
*/
RegValue = Xil_In32(CRF_APB_ACPU_CTRL);
RegValue |= (CRF_APB_ACPU_CTRL_CLKACT_FULL_MASK | CRF_APB_ACPU_CTRL_CLKACT_HALF_MASK);
Xil_Out32(CRF_APB_ACPU_CTRL, RegValue);
/**
* Release reset
*/
RegValue = Xil_In32(CRF_APB_RST_FPD_APU);
RegValue &= ~(CRF_APB_RST_FPD_APU_ACPU1_RESET_MASK | CRF_APB_RST_FPD_APU_APU_L2_RESET_MASK | CRF_APB_RST_FPD_APU_ACPU1_PWRON_RESET_MASK);
Xil_Out32(CRF_APB_RST_FPD_APU, RegValue);
break;
case CPU_A53_2:
PwrStateMask = PMU_GLOBAL_PWR_STATE_ACPU2_MASK | PMU_GLOBAL_PWR_STATE_FP_MASK | PMU_GLOBAL_PWR_STATE_L2_BANK0_MASK;
Status = PowerUpIsland(PwrStateMask);
if (Status != CPU_OK) {
goto END;
}
/**
* Enable the clock
*/
RegValue = Xil_In32(CRF_APB_ACPU_CTRL);
RegValue |= (CRF_APB_ACPU_CTRL_CLKACT_FULL_MASK | CRF_APB_ACPU_CTRL_CLKACT_HALF_MASK);
Xil_Out32(CRF_APB_ACPU_CTRL, RegValue);
/**
* Release reset
*/
RegValue = Xil_In32(CRF_APB_RST_FPD_APU);
RegValue &= ~(CRF_APB_RST_FPD_APU_ACPU2_RESET_MASK | CRF_APB_RST_FPD_APU_APU_L2_RESET_MASK | CRF_APB_RST_FPD_APU_ACPU2_PWRON_RESET_MASK);
Xil_Out32(CRF_APB_RST_FPD_APU, RegValue);
break;
case CPU_A53_3:
PwrStateMask = PMU_GLOBAL_PWR_STATE_ACPU3_MASK | PMU_GLOBAL_PWR_STATE_FP_MASK | PMU_GLOBAL_PWR_STATE_L2_BANK0_MASK;
Status = PowerUpIsland(PwrStateMask);
if (Status != CPU_OK) {
goto END;
}
/**
* Enable the clock
*/
RegValue = Xil_In32(CRF_APB_ACPU_CTRL);
RegValue |= (CRF_APB_ACPU_CTRL_CLKACT_FULL_MASK | CRF_APB_ACPU_CTRL_CLKACT_HALF_MASK);
Xil_Out32(CRF_APB_ACPU_CTRL, RegValue);
/**
* Release reset
*/
RegValue = Xil_In32(CRF_APB_RST_FPD_APU);
RegValue &= ~(CRF_APB_RST_FPD_APU_ACPU3_RESET_MASK | CRF_APB_RST_FPD_APU_APU_L2_RESET_MASK | CRF_APB_RST_FPD_APU_ACPU3_PWRON_RESET_MASK);
Xil_Out32(CRF_APB_RST_FPD_APU, RegValue);
break;
default:
Status = CPU_FAIL;
break;
}
END:
return Status;
}
static void SetCoreResetVector_A53 (uint32_t CpuID, uint64_t VectorAddr)
{
uint32_t VectorAddrLow;
uint32_t VectorAddrHigh;
uint32_t LowAddressReg;
uint32_t HighAddressReg;
/**
* for A53 cpu, write 64bit handoff address
* to the RVBARADDR in APU
*/
VectorAddrLow = (uint32_t )(VectorAddr & 0xFFFFFFFFU);
VectorAddrHigh = (uint32_t )((VectorAddr>>32) & 0xFFFFFFFFU);
switch (CpuID)
{
case CPU_A53_0:
LowAddressReg = APU_RVBARADDR0L;
HighAddressReg = APU_RVBARADDR0H;
break;
case CPU_A53_1:
LowAddressReg = APU_RVBARADDR1L;
HighAddressReg = APU_RVBARADDR1H;
break;
case CPU_A53_2:
LowAddressReg = APU_RVBARADDR2L;
HighAddressReg = APU_RVBARADDR2H;
break;
case CPU_A53_3:
LowAddressReg = APU_RVBARADDR3L;
HighAddressReg = APU_RVBARADDR3H;
break;
default:
/**
* error can be triggered here
*/
LowAddressReg = 0U;
HighAddressReg = 0U;
break;
}
Xil_Out32(LowAddressReg, VectorAddrLow);
Xil_Out32(HighAddressReg, VectorAddrHigh);
return;
}
uint32_t CpuUp_A53(uint32_t CpuID, uint64_t ResetAddress)
{
Xil_DCacheDisable();
// Step 1: Setup Reset vector of the core
SetCoreResetVector_A53(CpuID, ResetAddress);
// Step 2: Take the core out of reset
ReleaseReset_A53(CpuID);
Xil_DCacheEnable();
return 0;
}
void StartAndWaitSecondaryCpuUp(uint64_t CpuID, uint64_t ResetAddr)
{
static volatile uint32_t CpuUpFlags[4] = {0};
if (CpuID == 0)
{
CpuUpFlags[CpuID] = 1;
for (CpuID = 1; CpuID < 4; ++CpuID)
{
extern void Xil_Assert(const char *File, int32_t Line);
if (CpuUp_A53((uint32_t)CpuID, ResetAddr) != 0)
{
Xil_Assert(__FILE__, __LINE__);
}
}
// Wait for secondary CPUs up
int CpuIndx = 0;
while (CpuIndx < 4)
{
if (CpuUpFlags[CpuIndx] != 0)
{
CpuIndx++;
}
}
}
else
{
CpuUpFlags[CpuID] = 1;
}
}
@@ -0,0 +1,979 @@
/******************************************************************************
* Copyright (c) 2015 - 2020 Xilinx, Inc. All rights reserved.
* SPDX-License-Identifier: MIT
******************************************************************************/
/*****************************************************************************/
/**
*
* @file portZynqHW.h
*
* This is the header file which contains definitions for the hardware
* registers.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -------- -------------------------------------------------------
* 1.00 kc 10/21/13 Initial release
* 2.0 bv 12/05/16 Made compliance to MISRAC 2012 guidelines
* 3.0 vns 09/08/17 Added eFUSE secure control register masks for PPK revoke
* 4.0 vns 02/02/18 Added warning message to notify SHA2 support
* deprecation in future releases.
* vns 03/07/18 Added ENC_ONLY mask
* 4.0 vns 03/14/19 Added AES reset offset and Mask values.
*
* </pre>
*
* @note Copied from xfsbl_hw.h of 'zynqmp_fsbl'
*
******************************************************************************/
#ifndef CPU_H
#define CPU_H
#ifdef __cplusplus
extern "C" {
#endif
/***************************** Include Files *********************************/
#include "xil_io.h"
/************************** Constant Definitions *****************************/
/* csu */
/**
* CSU Base Address
*/
#define CSU_BASEADDR 0XFFCA0000U
/**
* Register: CSU_CSU_SSS_CFG
*/
#define CSU_CSU_SSS_CFG ( ( CSU_BASEADDR ) + 0X00000008U )
#define CSU_CSU_SSS_CFG_PCAP_SSS_MASK 0X0000000FU
#define CSU_CSU_SSS_CFG_PCAP_SSS_SHIFT 0U
#define CSU_CSU_SSS_CFG_DMA_SSS_SHIFT 1U
/**
* Register: CSU AES RESET
*/
#define CSU_AES_RESET ( ( CSU_BASEADDR ) + 0X00001010U )
#define CSU_AES_RESET_RESET_MASK 0X00000001U
/**
* Register: CSU_PCAP_STATUS
*/
#define CSU_PCAP_STATUS ( ( CSU_BASEADDR ) + 0X00003010U )
#define CSU_PCAP_STATUS_PL_INIT_SHIFT 2U
#define CSU_PCAP_STATUS_PL_INIT_MASK 0X00000004U
#define CSU_PCAP_STATUS_PCAP_WR_IDLE_MASK 0X00000001U
#define CSU_PCAP_STATUS_PL_DONE_MASK 0X00000008U
#define CSU_PCAP_STATUS_PL_CFG_RST_MASK 0x00000040U
/**
* Register: CSU_PCAP_RDWR
*/
#define CSU_PCAP_RDWR ( ( CSU_BASEADDR ) + 0X00003004U )
#define CSU_PCAP_RDWR_PCAP_RDWR_B_SHIFT 0U
/* Register: CSU_PCAP_PROG */
#define CSU_PCAP_PROG ( ( CSU_BASEADDR ) + 0X00003000U )
#define CSU_PCAP_PROG_PCFG_PROG_B_MASK 0X00000001U
#define CSU_PCAP_PROG_PCFG_PROG_B_SHIFT 0U
/**
* Register: CSU_VERSION
*/
#define CSU_VERSION ( ( CSU_BASEADDR ) + 0X00000044U )
#define CSU_VERSION_PLATFORM_MASK 0X0000F000U
/**
* Register: CSU_CSU_MULTI_BOOT
*/
#define CSU_CSU_MULTI_BOOT ( ( CSU_BASEADDR ) + 0X00000010U )
/**
* Register: CSU_SHA_RESET
*/
#define CSU_SHA_RESET ( ( CSU_BASEADDR ) + 0X00002004U )
#define CSU_SHA_RESET_RESET_MASK 0X00000001U
/**
* Register: CSU_SHA_START
*/
#define CSU_SHA_START ( ( CSU_BASEADDR ) + 0X00002000U )
#define CSU_SHA_START_START_MSG_MASK 0X00000001U
/**
* Register: CSU_SHA_DONE
*/
#define CSU_SHA_DONE ( ( CSU_BASEADDR ) + 0X00002008U )
#define CSU_SHA_DONE_SHA_DONE_MASK 0X00000001U
/**
* Register: CSU_SHA_DIGEST_0
*/
#define CSU_SHA_DIGEST_0 ( ( CSU_BASEADDR ) + 0X00002010U )
/* Register: CSU_PCAP_RESET */
#define CSU_PCAP_RESET ( ( CSU_BASEADDR ) + 0X0000300CU )
#define CSU_PCAP_RESET_RESET_MASK 0X00000001U
/* Register: CSU_PCAP_CTRL */
#define CSU_PCAP_CTRL ( ( CSU_BASEADDR ) + 0X00003008U )
#define CSU_PCAP_CTRL_PCAP_PR_MASK 0X00000001U
/* Register: CSU_IDCODE */
#define CSU_IDCODE ( ( CSU_BASEADDR ) + 0X00000040U )
#define CSU_IDCODE_SVD_SHIFT 12U
#define CSU_IDCODE_SVD_MASK (0x7U << CSU_IDCODE_SVD_SHIFT)
#define CSU_IDCODE_DEVICE_CODE_SHIFT 15U
#define CSU_IDCODE_DEVICE_CODE_MASK (0xFU << CSU_IDCODE_DEVICE_CODE_SHIFT)
/* efuse */
/**
* EFUSE Base Address
*/
#define EFUSE_BASEADDR 0XFFCC0000U
/**
* Register: EFUSE_SEC_CTRL
*/
#define EFUSE_SEC_CTRL ( ( EFUSE_BASEADDR ) + 0X00001058U )
#define EFUSE_SEC_CTRL_ENC_ONLY_MASK 0x00000004U
#define EFUSE_SEC_CTRL_RSA_EN_MASK 0x03FFF800U
#define EFUSE_SEC_CTRL_PPK0_RVK_MASK 0x18000000U
#define EFUSE_SEC_CTRL_PPK1_RVK_MASK 0xC0000000U
/* Register: EFUSE_IPDISABLE */
#define EFUSE_IPDISABLE ( ( EFUSE_BASEADDR ) + 0X00001018U )
#define EFUSE_IPDISABLE_GPU_DIS_MASK 0X00000020U
#define EFUSE_IPDISABLE_APU3_DIS_MASK 0X00000008U
#define EFUSE_IPDISABLE_APU2_DIS_MASK 0X00000004U
#define EFUSE_IPDISABLE_VCU_DIS_MASK 0x00000100U
/* Register PPK0_0 */
#define EFUSE_PPK0 (EFUSE_BASEADDR + 0x000010A0U)
/* Register PPK1_0 */
#define EFUSE_PPK1 (EFUSE_BASEADDR + 0x000010D0U)
/* Register SPK ID */
#define EFUSE_SPKID (EFUSE_BASEADDR + 0x0000105CU)
/* csudma */
/**
* CSUDMA Base Address
*/
#define CSUDMA_BASEADDR 0XFFC80000U
/* crf_apb */
/**
* CRF_APB Base Address
*/
#define CRF_APB_BASEADDR 0XFD1A0000U
/**
* Register: CRF_APB_RST_FPD_APU
*/
#define CRF_APB_RST_FPD_APU ( ( CRF_APB_BASEADDR ) + 0X00000104U )
#define CRF_APB_RST_FPD_APU_ACPU0_RESET_MASK (u32)0X00000001U
#define CRF_APB_RST_FPD_APU_APU_L2_RESET_MASK (u32)0X00000100U
/**
* Register: CRF_APB_ACPU_CTRL
*/
#define CRF_APB_ACPU_CTRL ( ( CRF_APB_BASEADDR ) + 0X00000060U )
#define CRF_APB_ACPU_CTRL_CLKACT_FULL_MASK 0X01000000U
#define CRF_APB_ACPU_CTRL_CLKACT_HALF_MASK 0X02000000U
#define CRF_APB_RST_FPD_APU_ACPU1_RESET_MASK (u32)0X00000002U
#define CRF_APB_RST_FPD_APU_ACPU2_RESET_MASK (u32)0X00000004U
#define CRF_APB_RST_FPD_APU_ACPU3_RESET_MASK (u32) 0X00000008U
#define CRF_APB_RST_FPD_APU_ACPU3_PWRON_RESET_MASK (u32)0X00002000U
#define CRF_APB_RST_FPD_APU_ACPU2_PWRON_RESET_MASK (u32)0X00001000U
#define CRF_APB_RST_FPD_APU_ACPU1_PWRON_RESET_MASK (u32)0X00000800U
#define CRF_APB_RST_FPD_APU_ACPU0_PWRON_RESET_MASK (u32)0X00000400U
/* crl_apb */
/**
* CRL_APB Base Address
*/
#define CRL_APB_BASEADDR 0XFF5E0000U
/**
* Register: CRL_APB_CPU_R5_CTRL
*/
#define CRL_APB_CPU_R5_CTRL ( ( CRL_APB_BASEADDR ) + 0X00000090U )
#define CRL_APB_CPU_R5_CTRL_CLKACT_MASK 0X01000000U
/**
* Register: CRL_APB_RST_LPD_TOP
*/
#define CRL_APB_RST_LPD_TOP ( ( CRL_APB_BASEADDR ) + 0X0000023CU )
#define CRL_APB_RST_LPD_TOP_RPU_R50_RESET_MASK (u32)0X00000001U
#define CRL_APB_RST_LPD_TOP_RPU_AMBA_RESET_MASK (u32)0X00000004U
#define CRL_APB_RST_LPD_TOP_RPU_R51_RESET_MASK (u32)0X00000002U
/**
* Register: CRL_APB_BOOT_MODE_USER
*/
#define CRL_APB_BOOT_MODE_USER ( ( CRL_APB_BASEADDR ) + 0X00000200U )
#define CRL_APB_BOOT_MODE_USER_BOOT_MODE_MASK 0X0000000FU
/**
* Register: CRL_APB_RESET_CTRL
*/
#define CRL_APB_RESET_CTRL ( ( CRL_APB_BASEADDR ) + 0X00000218U )
#define CRL_APB_RESET_CTRL_SOFT_RESET_MASK 0X00000010U
/* Register: CRL_APB_PCAP_CTRL */
#define CRL_APB_PCAP_CTRL ( ( CRL_APB_BASEADDR ) + 0X000000A4U )
#define CRL_APB_PCAP_CTRL_DIVISOR0_SHIFT 8U
#define CRL_APB_PCAP_CTRL_DIVISOR0_MASK 0X00003F00U
#define CRL_APB_PCAP_CTRL_CLKACT_MASK 0X01000000U
/* Register: CRL_APB_RESET_REASON */
#define CRL_APB_RESET_REASON ( ( CRL_APB_BASEADDR ) + 0X00000220U )
#define CRL_APB_RESET_REASON_PMU_SYS_RESET_MASK 0X00000004U
#define CRL_APB_RESET_REASON_PSONLY_RESET_REQ_MASK 0x00000008U
/**
* Register: CRL_APB_RPLL_CTRL
*/
#define CRL_APB_RPLL_CTRL ( ( CRL_APB_BASEADDR ) + 0X00000030U )
#define CRL_APB_RPLL_CTRL_BYPASS_MASK 0X00000008U
/* apu */
/**
* APU Base Address
*/
#define APU_BASEADDR 0XFD5C0000U
/**
* Register: APU_CONFIG_0
*/
#define APU_CONFIG_0 ( ( APU_BASEADDR ) + 0X00000020U )
#define APU_CONFIG_0_VINITHI_MASK 0x000000F0
/**
* Register: APU_RVBARADDR0L
*/
#define APU_RVBARADDR0L ( ( APU_BASEADDR ) + 0X00000040U )
/**
* Register: APU_RVBARADDR0H
*/
#define APU_RVBARADDR0H ( ( APU_BASEADDR ) + 0X00000044U )
/**
* Register: APU_RVBARADDR1L
*/
#define APU_RVBARADDR1L ( ( APU_BASEADDR ) + 0X00000048U )
/**
* Register: APU_RVBARADDR1H
*/
#define APU_RVBARADDR1H ( ( APU_BASEADDR ) + 0X0000004CU )
/**
* Register: APU_RVBARADDR2L
*/
#define APU_RVBARADDR2L ( ( APU_BASEADDR ) + 0X00000050U )
/**
* Register: APU_RVBARADDR2H
*/
#define APU_RVBARADDR2H ( ( APU_BASEADDR ) + 0X00000054U )
/**
* Register: APU_RVBARADDR3L
*/
#define APU_RVBARADDR3L ( ( APU_BASEADDR ) + 0X00000058U )
/**
* Register: APU_RVBARADDR3H
*/
#define APU_RVBARADDR3H ( ( APU_BASEADDR ) + 0X0000005CU )
/* pmu_global */
#define PMU_GLOBAL_GLOB_GEN_STORAGE6 ( ( PMU_GLOBAL_BASEADDR ) + 0X48U )
#define PMU_GLOBAL_GLOB_GEN_STORAGE5 ( ( PMU_GLOBAL_BASEADDR ) + 0x44U )
#define PMU_GLOBAL_GLOB_GEN_STORAGE4 ( ( PMU_GLOBAL_BASEADDR ) + 0X40U )
#define PMU_GLOBAL_GLOB_GEN_STORAGE1 ( ( PMU_GLOBAL_BASEADDR ) + 0X34U )
#define PMU_GLOBAL_GLOB_GEN_STORAGE2 ( ( PMU_GLOBAL_BASEADDR ) + 0X38U )
/**
* Register: PMU_GLOBAL_PERS_GLOB_GEN_STORAGE4
*/
#define PMU_GLOBAL_PERS_GLOB_GEN_STORAGE4 ( ( PMU_GLOBAL_BASEADDR ) + 0X00000060U )
/**
* Register: PMU_GLOBAL_PERS_GLOB_GEN_STORAGE5
*/
#define PMU_GLOBAL_PERS_GLOB_GEN_STORAGE5 ( ( PMU_GLOBAL_BASEADDR ) + 0X00000064U )
/*
* Register: PMU_GLOBAL_PERS_GLOB_GEN_STORAGE7
*/
#define PMU_GLOBAL_PERS_GLOB_GEN_STORAGE7 ( ( PMU_GLOBAL_BASEADDR ) + 0X0000006CU )
/**
* PMU_GLOBAL Base Address
*/
#define PMU_GLOBAL_BASEADDR 0XFFD80000U
#define PMU_GLOBAL_GLOBAL_CNTRL ( ( PMU_GLOBAL_BASEADDR ) + 0X00000000U )
#define PMU_GLOBAL_GLOBAL_CNTRL_MB_SLEEP_MASK 0X00010000U
#define PMU_GLOBAL_GLOBAL_CNTRL_FW_IS_PRESENT_MASK 0X00000010U
#define PMU_GLOBAL_PS_CNTRL ( (PMU_GLOBAL_BASEADDR ) + 0x4U)
#define PMU_GLOBAL_PS_CNTRL_PROG_ENABLE_MASK 0x2U
#define PMU_GLOBAL_PS_CNTRL_PROG_GATE_MASK 0x1U
#define PMU_GLOBAL_AIB_CNTRL ( ( PMU_GLOBAL_BASEADDR ) + 0X600U )
#define PMU_GLOBAL_AIB_STATUS ( ( PMU_GLOBAL_BASEADDR ) + 0X604U )
/* Register: PMU_GLOBAL_REQ_PWRUP_INT_EN */
#define PMU_GLOBAL_REQ_PWRUP_INT_EN ( ( PMU_GLOBAL_BASEADDR ) + 0X00000118U )
#define PMU_GLOBAL_REQ_PWRUP_INT_EN_PL_MASK 0X00800000U
/* Register: PMU_GLOBAL_REQ_PWRUP_TRIG */
#define PMU_GLOBAL_REQ_PWRUP_TRIG ( ( PMU_GLOBAL_BASEADDR ) + 0X00000120U )
#define PMU_GLOBAL_REQ_PWRUP_TRIG_PL_MASK 0X00800000U
/* Register: PMU_GLOBAL_REQ_PWRUP_STATUS */
#define PMU_GLOBAL_REQ_PWRUP_STATUS ( ( PMU_GLOBAL_BASEADDR ) + 0X00000110U )
#define PMU_GLOBAL_REQ_PWRUP_STATUS_PL_SHIFT 23U
#define PMU_GLOBAL_REQ_PWRUP_STATUS_PL_MASK 0X00800000U
/* Register: PMU_GLOBAL_PWR_STATE */
#define PMU_GLOBAL_PWR_STATE ( ( PMU_GLOBAL_BASEADDR ) + 0X00000100U )
#define PMU_GLOBAL_PWR_STATE_PL_MASK 0X00800000U
#define PMU_GLOBAL_PWR_STATE_FP_MASK 0X00400000U
#define PMU_GLOBAL_PWR_STATE_USB1_MASK 0X00200000U
#define PMU_GLOBAL_PWR_STATE_USB0_MASK 0X00100000U
#define PMU_GLOBAL_PWR_STATE_OCM_BANK3_MASK 0X00080000U
#define PMU_GLOBAL_PWR_STATE_OCM_BANK2_MASK 0X00040000U
#define PMU_GLOBAL_PWR_STATE_OCM_BANK1_MASK 0X00020000U
#define PMU_GLOBAL_PWR_STATE_OCM_BANK0_MASK 0X00010000U
#define PMU_GLOBAL_PWR_STATE_TCM1B_MASK (u32)0X00008000U
#define PMU_GLOBAL_PWR_STATE_TCM1A_MASK (u32)0X00004000U
#define PMU_GLOBAL_PWR_STATE_TCM0B_MASK (u32)0X00002000U
#define PMU_GLOBAL_PWR_STATE_TCM0A_MASK (u32)0X00001000U
#define PMU_GLOBAL_PWR_STATE_R5_1_MASK (u32)0X00000800U
#define PMU_GLOBAL_PWR_STATE_R5_0_MASK (u32)0X00000400U
#define PMU_GLOBAL_PWR_STATE_L2_BANK0_MASK 0X00000080U
#define PMU_GLOBAL_PWR_STATE_PP1_MASK 0X00000020U
#define PMU_GLOBAL_PWR_STATE_PP0_MASK 0X00000010U
#define PMU_GLOBAL_PWR_STATE_ACPU3_MASK 0X00000008U
#define PMU_GLOBAL_PWR_STATE_ACPU2_MASK 0X00000004U
#define PMU_GLOBAL_PWR_STATE_ACPU1_MASK 0X00000002U
#define PMU_GLOBAL_PWR_STATE_ACPU0_MASK 0X00000001U
/* Register: PMU_GLOBAL_ERROR_STATUS_1 */
#define PMU_GLOBAL_ERROR_STATUS_1 ( ( PMU_GLOBAL_BASEADDR ) + 0X00000530U )
#define PMU_GLOBAL_ERROR_STATUS_1_LPD_SWDT_MASK 0X00001000U
/* Register: PMU_GLOBAL_ERROR_SRST_EN_1 */
#define PMU_GLOBAL_ERROR_SRST_EN_1 ( ( PMU_GLOBAL_BASEADDR ) + 0X0000056CU )
#define PMU_GLOBAL_ERROR_SRST_EN_1_LPD_SWDT_MASK 0X00001000U
#define PMU_GLOBAL_ERROR_SRST_EN_1_FPD_SWDT_MASK 0X00002000U
/* Register: PMU_GLOBAL_ERROR_SRST_DIS_1 */
#define PMU_GLOBAL_ERROR_SRST_DIS_1 ( ( PMU_GLOBAL_BASEADDR ) + 0X00000570U )
#define PMU_GLOBAL_ERROR_SRST_DIS_1_LPD_SWDT_MASK 0X00001000U
#define PMU_GLOBAL_ERROR_SRST_DIS_1_FPD_SWDT_MASK 0X00002000U
/* Register: PMU_GLOBAL_ERROR_EN_1 */
#define PMU_GLOBAL_ERROR_EN_1 ( ( PMU_GLOBAL_BASEADDR ) + 0X000005A0U )
#define PMU_GLOBAL_ERROR_EN_1_LPD_SWDT_MASK 0X00001000U
/* Register: PMU_GLOBAL_REQ_ISO_INT_EN */
#define PMU_GLOBAL_REQ_ISO_INT_EN ( ( PMU_GLOBAL_BASEADDR ) + 0X00000318U )
#define PMU_GLOBAL_REQ_ISO_INT_EN_PL_NONPCAP_MASK 0X00000004U
/* Register: PMU_GLOBAL_REQ_ISO_TRIG */
#define PMU_GLOBAL_REQ_ISO_TRIG ( ( PMU_GLOBAL_BASEADDR ) + 0X00000320U )
/* Register: PMU_GLOBAL_REQ_ISO_STATUS */
#define PMU_GLOBAL_REQ_ISO_STATUS ( ( PMU_GLOBAL_BASEADDR ) + 0X00000310U )
/* rpu */
/**
* RPU Base Address
*/
#define RPU_BASEADDR 0XFF9A0000U
/**
* Register: RPU_RPU_GLBL_CNTL
*/
#define RPU_RPU_GLBL_CNTL ( ( RPU_BASEADDR ) + 0X00000000U )
#define RPU_RPU_GLBL_CNTL_SLSPLIT_MASK 0X00000008U
#define RPU_RPU_GLBL_CNTL_TCM_COMB_MASK 0X00000040U
#define RPU_RPU_GLBL_CNTL_SLCLAMP_MASK 0X00000010U
/**
* Register: RPU_RPU_0_CFG
*/
#define RPU_RPU_0_CFG ( ( RPU_BASEADDR ) + 0X00000100U )
#define RPU_RPU_0_CFG_VINITHI_SHIFT 2U
#define RPU_RPU_0_CFG_VINITHI_MASK 0x00000004U
#define RPU_RPU_0_CFG_NCPUHALT_MASK 0X00000001U
/**
* Register: RPU_RPU_1_CFG
*/
#define RPU_RPU_1_CFG ( ( RPU_BASEADDR ) + 0X00000200U )
#define RPU_RPU_1_CFG_VINITHI_SHIFT 2U
#define RPU_RPU_1_CFG_VINITHI_MASK 0x00000004U
#define RPU_RPU_1_CFG_NCPUHALT_MASK 0X00000001U
/* rsa */
/**
* RSA Base Address
*/
#define RSA_BASEADDR 0XFFCE002CU
/**
* Register: RSA_WR_DATA_0
*/
#define RSA_WR_DATA_0 ( ( RSA_BASEADDR ) + 0X00000000U )
/**
* Register: RSA_WR_ADDR
*/
#define RSA_WR_ADDR ( ( RSA_BASEADDR ) + 0X00000018U )
/**
* Register: RSA_RD_ADDR
*/
#define RSA_RD_ADDR ( ( RSA_BASEADDR ) + 0X00000034U )
/**
* Register: RSA_RD_DATA_0
*/
#define RSA_RD_DATA_0 ( ( RSA_BASEADDR ) + 0X0000001CU )
/* rsa_core */
/**
* RSA_CORE Base Address
*/
#define RSA_CORE_BASEADDR 0XFFCE0000U
/**
* Register: RSA_CORE_MINV0
*/
#define RSA_CORE_MINV0 ( ( RSA_CORE_BASEADDR ) + 0X00000018U )
/**
* Register: RSA_CORE_MINV1
*/
#define RSA_CORE_MINV1 ( ( RSA_CORE_BASEADDR ) + 0X0000001CU )
/**
* Register: RSA_CORE_MINV2
*/
#define RSA_CORE_MINV2 ( ( RSA_CORE_BASEADDR ) + 0X00000020U )
/**
* Register: RSA_CORE_MINV3
*/
#define RSA_CORE_MINV3 ( ( RSA_CORE_BASEADDR ) + 0X00000024U )
/**
* Register: RSA_CORE_STATUS
*/
#define RSA_CORE_STATUS ( ( RSA_CORE_BASEADDR ) + 0X00000014U )
#define RSA_CORE_STATUS_ERROR_MASK 0X00000004U
#define RSA_CORE_STATUS_DONE_MASK 0X00000001U
/**
* Register: RSA_CORE_CTRL
*/
#define RSA_CORE_CTRL ( ( RSA_CORE_BASEADDR ) + 0X00000010U )
/* LPD_SLCR Base Address */
#define LPD_SLCR_BASEADDR 0XFF410000U
/* Register: LPD_SLCR_PERSISTENT4 */
#define LPD_SLCR_PERSISTENT4 ( ( LPD_SLCR_BASEADDR ) + 0X00000030U )
/* Register: LPD_SLCR_PERSISTENT5 */
#define LPD_SLCR_PERSISTENT5 ( ( LPD_SLCR_BASEADDR ) + 0X00000034U )
/* IPI Base Address */
#define IPI_BASEADDR 0XFF300000U
/* Register: IPI_PMU_0_TRIG */
#define IPI_PMU_0_TRIG ( ( IPI_BASEADDR ) + 0X00030000U )
#define IPI_PMU_0_TRIG_PMU_0_MASK 0X00010000U
#define IPI_PMU_0_IER ( ( IPI_BASEADDR ) + 0X00030018U )
#define IPI_PMU_0_IER_PMU_0_MASK 0X00010000U
/* serdes */
/* SERDES Base Address */
#define SERDES_BASEADDR 0XFD400000U
#define SERDES_ICM_CFG0 ( ( SERDES_BASEADDR ) + 0X00010010U )
#define SERDES_ICM_CFG0_L1_ICM_CFG_SHIFT 4U
#define SERDES_ICM_CFG0_L1_ICM_CFG_MASK 0X00000070U
#define SERDES_ICM_CFG0_L0_ICM_CFG_MASK 0X00000007U
#define SERDES_ICM_CFG1 ( ( SERDES_BASEADDR ) + 0X00010014U )
#define SERDES_ICM_CFG1_L3_ICM_CFG_SHIFT 4U
#define SERDES_ICM_CFG1_L3_ICM_CFG_MASK 0X00000070U
#define SERDES_ICM_CFG1_L2_ICM_CFG_MASK 0X00000007U
/* gpio */
/* GPIO Base Address */
#define GPIO_BASEADDR 0XFF0A0000U
#define GPIO_DATA_1 ( ( GPIO_BASEADDR ) + 0X00000044U )
#define GPIO_DIRM_1 ( ( GPIO_BASEADDR ) + 0X00000244U )
#define GPIO_OEN_1 ( ( GPIO_BASEADDR ) + 0X00000248U )
/* IOU_SLCR Base Address */
#define IOU_SLCR_BASEADDR 0XFF180000U
/* Register: IOU_SLCR_SD_CDN_CTRL */
#define IOU_SLCR_SD_CDN_CTRL ( ( IOU_SLCR_BASEADDR ) + 0X0000035CU )
#define IOU_SLCR_SD_CDN_CTRL_SD1_CDN_CTRL_MASK 0X00010000U
#define IOU_SLCR_SD_CDN_CTRL_SD0_CDN_CTRL_MASK 0X00000001U
/* Register: ADMA_CH0 Base Address */
#define ADMA_CH0_BASEADDR 0XFFA80000U
/* Register: ADMA_CH0_ZDMA_CH_STATUS */
#define ADMA_CH0_ZDMA_CH_STATUS ( ( ADMA_CH0_BASEADDR ) + 0X0000011CU )
#define ADMA_CH0_ZDMA_CH_STATUS_STATE_MASK 0X00000003U
#define ADMA_CH0_ZDMA_CH_STATUS_STATE_DONE 0X00000000U
#define ADMA_CH0_ZDMA_CH_STATUS_STATE_ERR 0X00000003U
/* Register: ADMA_CH0_ZDMA_CH_CTRL0 */
#define ADMA_CH0_ZDMA_CH_CTRL0 ( ( ADMA_CH0_BASEADDR ) + 0X00000110U )
#define ADMA_CH0_ZDMA_CH_CTRL0_POINT_TYPE_MASK (u32)0X00000040U
#define ADMA_CH0_ZDMA_CH_CTRL0_POINT_TYPE_NORMAL (u32)0X00000000U
#define ADMA_CH0_ZDMA_CH_CTRL0_MODE_MASK (u32)0X00000030U
#define ADMA_CH0_ZDMA_CH_CTRL0_MODE_WR_ONLY (u32)0X00000010U
#define ADMA_CH0_ZDMA_CH_CTRL0_TOTAL_BYTE_COUNT ( ( ADMA_CH0_BASEADDR ) + 0X00000188U )
/* Register: ADMA_CH0_ZDMA_CH_WR_ONLY_WORD0 */
#define ADMA_CH0_ZDMA_CH_WR_ONLY_WORD0 ( ( ADMA_CH0_BASEADDR ) + 0X00000148U )
/* Register: ADMA_CH0_ZDMA_CH_WR_ONLY_WORD1 */
#define ADMA_CH0_ZDMA_CH_WR_ONLY_WORD1 ( ( ADMA_CH0_BASEADDR ) + 0X0000014CU )
/* Register: ADMA_CH0_ZDMA_CH_WR_ONLY_WORD2 */
#define ADMA_CH0_ZDMA_CH_WR_ONLY_WORD2 ( ( ADMA_CH0_BASEADDR ) + 0X00000150U )
/* Register: ADMA_CH0_ZDMA_CH_WR_ONLY_WORD3 */
#define ADMA_CH0_ZDMA_CH_WR_ONLY_WORD3 ( ( ADMA_CH0_BASEADDR ) + 0X00000154U )
/* Register: ADMA_CH0_ZDMA_CH_DST_DSCR_WORD0 */
#define ADMA_CH0_ZDMA_CH_DST_DSCR_WORD0 ( ( ADMA_CH0_BASEADDR ) + 0X00000138U )
#define ADMA_CH0_ZDMA_CH_DST_DSCR_WORD0_LSB_MASK 0XFFFFFFFFU
/* Register: ADMA_CH0_ZDMA_CH_DST_DSCR_WORD1 */
#define ADMA_CH0_ZDMA_CH_DST_DSCR_WORD1 ( ( ADMA_CH0_BASEADDR ) + 0X0000013CU )
#define ADMA_CH0_ZDMA_CH_DST_DSCR_WORD1_MSB_MASK 0X0001FFFFU
/* Register: ADMA_CH0_ZDMA_CH_SRC_DSCR_WORD2 */
#define ADMA_CH0_ZDMA_CH_SRC_DSCR_WORD2 ( ( ADMA_CH0_BASEADDR ) + 0X00000130U )
/* Register: ADMA_CH0_ZDMA_CH_DST_DSCR_WORD2 */
#define ADMA_CH0_ZDMA_CH_DST_DSCR_WORD2 ( ( ADMA_CH0_BASEADDR ) + 0X00000140U )
/* Register: ADMA_CH0_ZDMA_CH_SRC_DSCR_WORD1 */
#define ADMA_CH0_ZDMA_CH_SRC_DSCR_WORD1 ( ( ADMA_CH0_BASEADDR ) + 0X0000012CU )
/* Register: ADMA_CH0_ZDMA_CH_SRC_DSCR_WORD0 */
#define ADMA_CH0_ZDMA_CH_SRC_DSCR_WORD0 ( ( ADMA_CH0_BASEADDR ) + 0X00000128U )
/* Register: ADMA_CH0_ZDMA_CH_SRC_DSCR_WORD3 */
#define ADMA_CH0_ZDMA_CH_SRC_DSCR_WORD3 ( ( ADMA_CH0_BASEADDR ) + 0X00000134U )
/* Register: ADMA_CH0_ZDMA_CH_DST_DSCR_WORD3 */
#define ADMA_CH0_ZDMA_CH_DST_DSCR_WORD3 ( ( ADMA_CH0_BASEADDR ) + 0X00000144U )
/* Register: ADMA_CH0_ZDMA_CH_CTRL2 */
#define ADMA_CH0_ZDMA_CH_CTRL2 ( ( ADMA_CH0_BASEADDR ) + 0X00000200U )
#define ADMA_CH0_ZDMA_CH_CTRL2_EN_MASK 0X00000001U
/* Register: ADMA_CH0_ZDMA_CH_ISR */
#define ADMA_CH0_ZDMA_CH_ISR ( ( ADMA_CH0_BASEADDR ) + 0X00000100U )
#define ADMA_CH0_ZDMA_CH_ISR_DMA_DONE_MASK 0X00000400U
/* AMS_PS_SYSMON Base Address */
#define AMS_PS_SYSMON_BASEADDR 0XFFA50800U
#define XFSBL_PS_SYSMON_CONFIGREG1 0XFFA50904U
#define XFSBL_PS_SYSMON_CONFIGREG3 0XFFA5090CU
#define XFSBL_PS_SYSMON_CFGREG1_ALRM_DISBL_MASK 0X0F0EU
#define XFSBL_PS_SYSMON_CFGREG3_ALRM_DISBL_MASK 0X3FU
/* Register: AMS_PS_SYSMON_ANALOG_BUS */
#define AMS_PS_SYSMON_ANALOG_BUS ( ( AMS_PS_SYSMON_BASEADDR ) + 0X00000114U )
/* Register: ACPU_GIC_GICD_ISPENDR0 */
#define ACPU_GIC_BASEADDR 0xF9000000U
/* Register: ACPU_GIC_GICD_ICENBLR0 */
#define ACPU_GIC_GICD_ICENBLR0 ( ( ACPU_GIC_BASEADDR ) + 0X00010180U )
/* Register: ACPU_GIC_GICD_ICENBLR1 */
#define ACPU_GIC_GICD_ICENBLR1 ( ( ACPU_GIC_BASEADDR ) + 0X00010184U )
/* Register: ACPU_GIC_GICD_ICENBLR2 */
#define ACPU_GIC_GICD_ICENBLR2 ( ( ACPU_GIC_BASEADDR ) + 0X00010188U )
/* Register: ACPU_GIC_GICD_ICENBLR3 */
#define ACPU_GIC_GICD_ICENBLR3 ( ( ACPU_GIC_BASEADDR ) + 0X0001018CU )
/* Register: ACPU_GIC_GICD_ICENBLR4 */
#define ACPU_GIC_GICD_ICENBLR4 ( ( ACPU_GIC_BASEADDR ) + 0X00010190U )
/* Register: ACPU_GIC_GICD_ICENBLR5 */
#define ACPU_GIC_GICD_ICENBLR5 ( ( ACPU_GIC_BASEADDR ) + 0X00010194U )
/* Register: ACPU_GIC_GICD_ICPENDR0 */
#define ACPU_GIC_GICD_ICPENDR0 ( ( ACPU_GIC_BASEADDR ) + 0X00010280U )
/* Register: ACPU_GIC_GICD_ICPENDR1 */
#define ACPU_GIC_GICD_ICPENDR1 ( ( ACPU_GIC_BASEADDR ) + 0X00010284U )
/* Register: ACPU_GIC_GICD_ICPENDR2 */
#define ACPU_GIC_GICD_ICPENDR2 ( ( ACPU_GIC_BASEADDR ) + 0X00010288U )
/* Register: ACPU_GIC_GICD_ICPENDR3 */
#define ACPU_GIC_GICD_ICPENDR3 ( ( ACPU_GIC_BASEADDR ) + 0X0001028CU )
/* Register: ACPU_GIC_GICD_ICPENDR4 */
#define ACPU_GIC_GICD_ICPENDR4 ( ( ACPU_GIC_BASEADDR ) + 0X00010290U )
/* Register: ACPU_GIC_GICD_ICPENDR5 */
#define ACPU_GIC_GICD_ICPENDR5 ( ( ACPU_GIC_BASEADDR ) + 0X00010294U )
/* Register: ACPU_GIC_GICD_ICACTIVER0 */
#define ACPU_GIC_GICD_ICACTIVER0 ( ( ACPU_GIC_BASEADDR ) + 0X00010380U )
/* Register: ACPU_GIC_GICD_ICACTIVER1 */
#define ACPU_GIC_GICD_ICACTIVER1 ( ( ACPU_GIC_BASEADDR ) + 0X00010384U )
/* Register: ACPU_GIC_GICD_ICACTIVER2 */
#define ACPU_GIC_GICD_ICACTIVER2 ( ( ACPU_GIC_BASEADDR ) + 0X00010388U )
/* Register: ACPU_GIC_GICD_ICACTIVER3 */
#define ACPU_GIC_GICD_ICACTIVER3 ( ( ACPU_GIC_BASEADDR ) + 0X0001038CU )
/* Register: ACPU_GIC_GICD_ICACTIVER4 */
#define ACPU_GIC_GICD_ICACTIVER4 ( ( ACPU_GIC_BASEADDR ) + 0X00010390U )
/* Register: ACPU_GIC_GICD_ICACTIVER5 */
#define ACPU_GIC_GICD_ICACTIVER5 ( ( ACPU_GIC_BASEADDR ) + 0X00010394U )
/* Register: ACPU_GIC_GICD_CPENDSGIR0 */
#define ACPU_GIC_GICD_CPENDSGIR0 ( ( ACPU_GIC_BASEADDR ) + 0X00010F10U )
/* Register: ACPU_GIC_GICD_CPENDSGIR1 */
#define ACPU_GIC_GICD_CPENDSGIR1 ( ( ACPU_GIC_BASEADDR ) + 0X00010F14U )
/* Register: ACPU_GIC_GICD_CPENDSGIR2 */
#define ACPU_GIC_GICD_CPENDSGIR2 ( ( ACPU_GIC_BASEADDR ) + 0X00010F18U )
/* Register: ACPU_GIC_GICD_CPENDSGIR3 */
#define ACPU_GIC_GICD_CPENDSGIR3 ( ( ACPU_GIC_BASEADDR ) + 0X00010F1CU )
/* Register: ACPU_GIC_GICD_INTR_ACK_REG */
#define ACPU_GIC_GICD_INTR_ACK_REG ( ( ACPU_GIC_BASEADDR ) + 0X0002000CU )
/* Register: ACPU_GIC_GICD_END_INTR_REG */
#define ACPU_GIC_GICD_END_INTR_REG ( ( ACPU_GIC_BASEADDR ) + 0X00020010U )
/* Register: ACPU_GIC_GICD_CACTIVESGIR0 */
#define ACPU_GIC_GICD_CACTIVESGIR0 ( ( ACPU_GIC_BASEADDR ) + 0X00010F10U )
/* Register: ACPU_GIC_GICD_CACTIVESGIR1 */
#define ACPU_GIC_GICD_CACTIVESGIR1 ( ( ACPU_GIC_BASEADDR ) + 0X00010F14U )
/* Register: ACPU_GIC_GICD_CACTIVESGIR2 */
#define ACPU_GIC_GICD_CACTIVESGIR2 ( ( ACPU_GIC_BASEADDR ) + 0X00010F18U )
/* Register: ACPU_GIC_GICD_CACTIVESGIR3 */
#define ACPU_GIC_GICD_CACTIVESGIR3 ( ( ACPU_GIC_BASEADDR ) + 0X00010F1CU )
/**************************** Type Definitions *******************************/
/***************** Macros (Inline Functions) Definitions *********************/
/**
* For error reporting PMU_GLOBAL_PERS_GLOB_GEN_STORAGE4 is used
*/
#define XFSBL_ERROR_STATUS_REGISTER_OFFSET (PMU_GLOBAL_PERS_GLOB_GEN_STORAGE4)
/* PMU RAM address for PMU FW */
#define XFSBL_PMU_RAM_START_ADDRESS (0xFFDC0000U)
#define XFSBL_PMU_RAM_END_ADDRESS (0xFFDDFFFFU)
/**
* If address where bitstream need to be copied is not configured, below will
* be the default address to indicate it is invalid address. In such cases,
* XFSBL_DDR_TEMP_ADDRESS is used as load address.
*/
#define XFSBL_DUMMY_PL_ADDR (0xFFFFFFFFU)
/**
* ARM Processor defines
*/
#define XFSBL_CLUSTER_ID_MASK (0x00000F00U)
#define XFSBL_A53_PROCESSOR (0x00000000U)
#define XFSBL_R5_PROCESSOR (0x00000100U)
/**
* Other FSBL defines
* this can defined in xfsbl_main.h
*/
#define XFSBL_R5_0 (0x1U)
#define XFSBL_R5_L (0x2U)
/**
* To indicate usage of RPU cores to PMU, PMU_GLOBAL_GLOB_GEN_STORAGE4 is used
*/
#define XFSBL_R5_USAGE_STATUS_REG (PMU_GLOBAL_GLOB_GEN_STORAGE4)
/* Bit 1 of rpu uasge status register is used for R50 status */
#define XFSBL_R5_0_STATUS_MASK (1U << 1)
/* Bit 2 of rpu usage status register is used for R51 status */
#define XFSBL_R5_1_STATUS_MASK (1U << 2)
/**
* TCM address for R5
*/
#define XFSBL_R5_TCM_START_ADDRESS (u32)(0x0U)
#define XFSBL_R5_BTCM_START_ADDRESS (0x20000U)
#define XFSBL_R50_HIGH_ATCM_START_ADDRESS (0xFFE00000U)
#define XFSBL_R50_HIGH_BTCM_START_ADDRESS (0xFFE20000U)
#define XFSBL_R51_HIGH_ATCM_START_ADDRESS (0xFFE90000U)
#define XFSBL_R51_HIGH_BTCM_START_ADDRESS (0xFFEB0000U)
#define XFSBL_R5_TCM_BANK_LENGTH (0x10000U)
/**
* defines for the FSBL peripherals present
*/
/**
* Definition for WDT to be included
*/
#if (!defined(FSBL_WDT_EXCLUDE) && defined(XPAR_PSU_WDT_0_DEVICE_ID))
#define XFSBL_WDT_PRESENT
#define XFSBL_WDT_DEVICE_ID XPAR_PSU_WDT_0_DEVICE_ID
#define XFSBL_WDT_MASK PMU_GLOBAL_ERROR_SRST_EN_1_LPD_SWDT_MASK
#elif (!defined(FSBL_WDT_EXCLUDE) && defined(XPAR_PSU_WDT_1_DEVICE_ID))
#define XFSBL_WDT_PRESENT
#define XFSBL_WDT_DEVICE_ID XPAR_PSU_WDT_1_DEVICE_ID
#define XFSBL_WDT_MASK PMU_GLOBAL_ERROR_SRST_EN_1_FPD_SWDT_MASK
#endif
/**
* Definitions for SD to be included
*/
#if (!defined(FSBL_SD_EXCLUDE) && (XPAR_XSDPS_0_BASEADDR == 0xFF160000))
#define XFSBL_SD_0
#endif
#if (!defined(FSBL_SD_EXCLUDE) && (XPAR_XSDPS_0_BASEADDR == 0xFF170000) ||\
(XPAR_XSDPS_1_BASEADDR == 0xFF170000))
#define XFSBL_SD_1
#endif
/**
* Definition for QSPI to be included
*/
#if (!defined(FSBL_QSPI_EXCLUDE) && defined(XPAR_XQSPIPSU_0_DEVICE_ID))
#define XFSBL_QSPI
#define XFSBL_QSPI_BASEADDRESS XPAR_XQSPIPS_0_BASEADDR
#define XFSBL_QSPI_BUSWIDTH_ONE 0U
#define XFSBL_QSPI_BUSWIDTH_TWO 1U
#define XFSBL_QSPI_BUSWIDTH_FOUR 2U
#endif
/**
* Definition for NAND to be included
*/
#if (!defined(FSBL_NAND_EXCLUDE) && defined(XPAR_XNANDPSU_0_DEVICE_ID))
#define XFSBL_NAND
#endif
/**
* Definition for SECURE to be included
*/
#if !defined(FSBL_SECURE_EXCLUDE)
#define XFSBL_SECURE
#endif
/**
* Definition for PL bitsream feature to be included
*/
#if !defined(FSBL_BS_EXCLUDE)
#define XFSBL_BS
#endif
/**
* Definition for early handoff feature to be included
*/
#if !defined(FSBL_EARLY_HANDOFF_EXCLUDE)
#define XFSBL_EARLY_HANDOFF
#endif
#if !defined(FSBL_PERF_EXCLUDE) && (!defined(ARMR5) || (defined(ARMR5) && defined(SLEEP_TIMER_BASEADDR)))
#define XFSBL_PERF
#endif
/* Definition for TCM ECC Enable for A53 to be included */
#if !defined(FSBL_A53_TCM_ECC_EXCLUDE)
#define XFSBL_A53_TCM_ECC
#endif
/* Definition for PL clear include irrespective of boot image has bitstream or not */
#if !defined(FSBL_PL_CLEAR_EXCLUDE)
#define XFSBL_PL_CLEAR
#endif
/*
* Definition for forcing encryption for each partition
* when ENC_ONLY FUSE bit is blown
*/
#if !defined(FSBL_FORCE_ENC_EXCLUDE)
#define XFSBL_FORCE_ENC
#endif
#define XFSBL_QSPI_LINEAR_BASE_ADDRESS_START (0xC0000000U)
#define XFSBL_QSPI_LINEAR_BASE_ADDRESS_END (0xDFFFFFFFU)
#if defined(XPAR_PSU_DDR_0_S_AXI_BASEADDR) \
|| defined(XPAR_PSU_R5_DDR_0_S_AXI_BASEADDR)
#define XFSBL_PS_DDR
#endif
#define XFSBL_PS_DDR_START_ADDRESS (0x0U)
#define XFSBL_PS_DDR_START_ADDRESS_R5 (0x100000U)
#if (!defined(FSBL_USB_EXCLUDE) && defined(XPAR_XUSBPSU_0_DEVICE_ID) && (XPAR_XUSBPSU_0_BASEADDR == 0xFE200000) && defined(XFSBL_PS_DDR))
#define XFSBL_USB
#endif
#if !defined(FSBL_PROT_BYPASS_EXCLUDE)
#define XFSBL_PROT_BYPASS
#endif
#ifdef ARMR5
#define XFSBL_PS_DDR_INIT_START_ADDRESS XFSBL_PS_DDR_START_ADDRESS_R5
#if defined(XPAR_PSU_R5_DDR_1_S_AXI_BASEADDR)
#define XFSBL_PS_HI_DDR_START_ADDRESS XPAR_PSU_R5_DDR_1_S_AXI_BASEADDR
#define XFSBL_PS_HI_DDR_END_ADDRESS XPAR_PSU_R5_DDR_1_S_AXI_HIGHADDR
#endif
#else
#define XFSBL_PS_DDR_INIT_START_ADDRESS XFSBL_PS_DDR_START_ADDRESS
#if defined(XPAR_PSU_DDR_1_S_AXI_BASEADDR)
#define XFSBL_PS_HI_DDR_START_ADDRESS XPAR_PSU_DDR_1_S_AXI_BASEADDR
#define XFSBL_PS_HI_DDR_END_ADDRESS XPAR_PSU_DDR_1_S_AXI_HIGHADDR
#endif
#endif
#ifdef XFSBL_PS_DDR
#ifdef ARMR5
#define XFSBL_PS_DDR_END_ADDRESS (XPAR_PSU_R5_DDR_0_S_AXI_HIGHADDR)
#else
#define XFSBL_PS_DDR_END_ADDRESS (XPAR_PSU_DDR_0_S_AXI_HIGHADDR)
#endif
#endif
#ifdef XFSBL_ENABLE_DDR_SR
/*
* For DDR status PMU_GLOBAL_PERS_GLOB_GEN_STORAGE7 is used
*/
#define XFSBL_DDR_STATUS_REGISTER_OFFSET (PMU_GLOBAL_PERS_GLOB_GEN_STORAGE7)
/*
* DDR controller initialization flag mask
*
* This flag signals whether DDR controller have been initialized or not. It is
* used by FSBL to inform PMU that DDR controller is initialized. When booting
* with DDR in self refresh mode, PMU must wait until DDR controller have been
* initialized by the FSBL before it can bring the DDR out of self refresh mode.
*/
#define DDRC_INIT_FLAG_MASK (1U << 4)
/*
* DDR self refresh mode indication flag mask
*
* This flag indicates whether DDR is in self refresh mode or not. It is used
* by PMU to signal FSBL in order to skip over DDR phy and ECC initialization
* at boot time.
*/
#define DDR_STATUS_FLAG_MASK (1U << 3)
#endif
/* The number of bytes transferred per cycle of DMA should be
* 64 bit aligned to avoid any ECC errors. Hence, even though the maximum
* number of bytes that can be sent per cycle is 1GB -1, only 1GB -8 bytes
* are sent to preserve the 64 bit alignment.
*/
#define ZDMA_TRANSFER_MAX_LEN (0x3FFFFFFFU - 7U)
#define EFUSE_IPDISABLE_CG_MASK ((EFUSE_IPDISABLE_GPU_DIS_MASK) | \
(EFUSE_IPDISABLE_APU2_DIS_MASK) | (EFUSE_IPDISABLE_APU3_DIS_MASK))
#define XFSBL_OCM
#define XFSBL_OCM_START_ADDRESS (0xFFFEA000U)
#define XFSBL_OCM_END_ADDRESS (0xFFFFFFFFU)
/* Different Memory types */
#define XFSBL_R5_0_TCM (0x1U)
#define XFSBL_R5_1_TCM (0x2U)
#define XFSBL_R5_L_TCM (0x3U)
#define PTRSIZE UINTPTR
/* Reset Reason */
#define XFSBL_SYSTEM_RESET 0U
#define XFSBL_PS_ONLY_RESET 1U
#define XFSBL_MASTER_ONLY_RESET 2U
/* AMS PS Sysmon ANALOG_BUS value */
#define PS_SYSMON_ANALOG_BUS_VAL 0X00003210U
/************************** Function Prototypes ******************************/
/************************** Variable Definitions *****************************/
#ifdef __cplusplus
}
#endif
#endif /* CPU_H */
@@ -0,0 +1,149 @@
/******************************************************************************
* Copyright (C) 2014 - 2020 Xilinx, Inc. All rights reserved.
* SPDX-License-Identifier: MIT
******************************************************************************/
/*****************************************************************************/
/**
* @file xil-crt0.S
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -------- ---------------------------------------------------
* 5.00 pkp 05/21/14 Initial version
* 5.04 pkp 12/18/15 Initialized global constructor for C++ applications
* 5.04 pkp 01/05/16 Set the reset vector register RVBAR equivalent to
* vector table base address
* 6.02 pkp 01/22/17 Added support for EL1 non-secure
* 6.6 srm 10/18/17 Added timer configuration using XTime_StartTTCTimer API.
* Now the TTC instance as specified by the user will be
* started.
* 6.6 mus 01/29/18 Initialized the xen PV console for Cortexa53 64 bit
* EL1 NS BSP.
* 7.2 sd 02/23/20 Clock Init is called
* 7.2 sd 02/23/20 Clock code added under XCLOCKING flag
* </pre>
*
* @note
*
* None.
*
******************************************************************************/
#include "xparameters.h"
#include "bspconfig.h"
.file "xil-crt0.S"
.section ".got2","aw"
.align 2
.globl _vector_table
#define FREERTOS_SMP
#ifdef FREERTOS_SMP
.set secondary_cpu_reset_vector, _vector_table
#endif
.text
.Lsbss_start:
.quad __sbss_start
.Lsbss_end:
.quad __sbss_end
.Lbss_start:
.quad __bss_start__
.Lbss_end:
.quad __bss_end__
.extern StartAndWaitSecondaryCpuUp
.set APU_PWRCTL, 0xFD5C0090
.globl _startup
_startup:
#ifdef FREERTOS_SMP
/* Get CPU Id */
mrs x0, MPIDR_EL1
and x0, x0, #0xFF
cmp x0, #0
bne c_init_end
#endif
mov x0, #0
.if (EL3 == 1)
/* Check whether the clearing of bss sections shall be skipped */
ldr x10, =APU_PWRCTL /* Load PWRCTRL address */
ldr w11, [x10] /* Read PWRCTRL register */
mrs x2, MPIDR_EL1 /* Read MPIDR_EL1 */
ubfx x2, x2, #0, #8 /* Extract CPU ID (affinity level 0) */
mov w1, #1
lsl w2, w1, w2 /* Shift CPU ID to get one-hot ID */
ands w11, w11, w2 /* Get PWRCTRL bit for this core */
bne .Lenclbss /* Skip BSS and SBSS clearing */
.endif
/* clear sbss */
ldr x1,.Lsbss_start /* calculate beginning of the SBSS */
ldr x2,.Lsbss_end /* calculate end of the SBSS */
.Lloop_sbss:
cmp x1,x2
bge .Lenclsbss /* If no SBSS, no clearing required */
str x0, [x1], #8
b .Lloop_sbss
.Lenclsbss:
/* clear bss */
ldr x1,.Lbss_start /* calculate beginning of the BSS */
ldr x2,.Lbss_end /* calculate end of the BSS */
.Lloop_bss:
cmp x1,x2
bge .Lenclbss /* If no BSS, no clearing required */
str x0, [x1], #8
b .Lloop_bss
.Lenclbss:
/* run global constructors */
bl __libc_init_array
c_init_end:
/* Reset and start Triple Timer Counter */
#if defined (SLEEP_TIMER_BASEADDR)
bl XTime_StartTTCTimer
#endif
.if (EL1_NONSECURE == 1 && HYP_GUEST == 1 && \
XEN_USE_PV_CONSOLE == 1)
bl XPVXenConsole_Init
.endif
#ifdef FREERTOS_SMP
/* Get CPU Id */
mrs x0, MPIDR_EL1
and x0, x0, #0xFF
ldr x1, =secondary_cpu_reset_vector
/* void StartAndWaitSecondaryCpuUp(uint64_t CpuID, uint64_t ResetAddr) */
bl StartAndWaitSecondaryCpuUp
#endif
/* make sure argc and argv are valid */
mov x0, #0
mov x1, #0
#ifdef XCLOCKING
bl Xil_ClockInit
#endif
bl main /* Jump to main C code */
/* Cleanup global constructors */
bl __libc_fini_array
bl exit
.Lexit: /* should never get here */
b .Lexit
.Lstart:
.size _startup,.Lstart-_startup
@@ -0,0 +1,927 @@
/*
* FreeRTOS Kernel V10.3.0
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Copyright (C) 2014 - 2020 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
/* Standard includes. */
#include <stdlib.h>
/* Scheduler includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "xpseudo_asm.h"
/* Xilinx includes. */
#include "xscugic.h"
#ifndef configINTERRUPT_CONTROLLER_BASE_ADDRESS
#error configINTERRUPT_CONTROLLER_BASE_ADDRESS must be defined. See http://www.freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html
#endif
#ifndef configINTERRUPT_CONTROLLER_CPU_INTERFACE_OFFSET
#error configINTERRUPT_CONTROLLER_CPU_INTERFACE_OFFSET must be defined. See http://www.freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html
#endif
#ifndef configUNIQUE_INTERRUPT_PRIORITIES
#error configUNIQUE_INTERRUPT_PRIORITIES must be defined. See http://www.freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html
#endif
#ifndef configSETUP_TICK_INTERRUPT
#error configSETUP_TICK_INTERRUPT() must be defined. See http://www.freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html
#endif /* configSETUP_TICK_INTERRUPT */
#ifndef configMAX_API_CALL_INTERRUPT_PRIORITY
#error configMAX_API_CALL_INTERRUPT_PRIORITY must be defined. See http://www.freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html
#endif
#if configMAX_API_CALL_INTERRUPT_PRIORITY == 0
#error configMAX_API_CALL_INTERRUPT_PRIORITY must not be set to 0
#endif
#if configMAX_API_CALL_INTERRUPT_PRIORITY > configUNIQUE_INTERRUPT_PRIORITIES
#error configMAX_API_CALL_INTERRUPT_PRIORITY must be less than or equal to configUNIQUE_INTERRUPT_PRIORITIES as the lower the numeric priority value the higher the logical interrupt priority
#endif
#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1
/* Check the configuration. */
#if( configMAX_PRIORITIES > 32 )
#error configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32. It is very rare that a system requires more than 10 to 15 difference priorities as tasks that share a priority will time slice.
#endif
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
/* In case security extensions are implemented. */
#if configMAX_API_CALL_INTERRUPT_PRIORITY <= ( configUNIQUE_INTERRUPT_PRIORITIES / 2 )
#error configMAX_API_CALL_INTERRUPT_PRIORITY must be greater than ( configUNIQUE_INTERRUPT_PRIORITIES / 2 )
#endif
/* Some vendor specific files default configCLEAR_TICK_INTERRUPT() in
portmacro.h. */
#ifndef configCLEAR_TICK_INTERRUPT
#define configCLEAR_TICK_INTERRUPT()
#endif
/* A critical section is exited when the critical section nesting count reaches
this value. */
#define portNO_CRITICAL_NESTING ( ( size_t ) 0 )
/* In all GICs 255 can be written to the priority mask register to unmask all
(but the lowest) interrupt priority. */
#define portUNMASK_VALUE ( 0xFFUL )
/* Tasks are not created with a floating point context, but can be given a
floating point context after they have been created. A variable is stored as
part of the tasks context that holds portNO_FLOATING_POINT_CONTEXT if the task
does not have an FPU context, or any other value if the task does have an FPU
context. */
#define portNO_FLOATING_POINT_CONTEXT ( ( StackType_t ) 0 )
/* Constants required to setup the initial task context. */
#define portSP_ELx ( ( StackType_t ) 0x01 )
#define portSP_EL0 ( ( StackType_t ) 0x00 )
#if defined( GUEST )
#define portEL1 ( ( StackType_t ) 0x04 )
#define portINITIAL_PSTATE ( portEL1 | portSP_EL0 )
#else
#define portEL3 ( ( StackType_t ) 0x0c )
/* At the time of writing, the BSP only supports EL3. */
#define portINITIAL_PSTATE ( portEL3 | portSP_EL0 )
#endif
/* Used by portASSERT_IF_INTERRUPT_PRIORITY_INVALID() when ensuring the binary
point is zero. */
#define portBINARY_POINT_BITS ( ( uint8_t ) 0x03 )
/* Masks all bits in the APSR other than the mode bits. */
#define portAPSR_MODE_BITS_MASK ( 0x0C )
/* The I bit in the DAIF bits. */
#define portDAIF_I ( 0x80 )
#if defined (GICv2)
/* Macro to unmask all interrupt priorities. */
#define portCLEAR_INTERRUPT_MASK_P() \
{ \
portDISABLE_INTERRUPTS(); \
portICCPMR_PRIORITY_MASK_REGISTER = portUNMASK_VALUE; \
__asm volatile ( "DSB SY \n" \
"ISB SY \n" ); \
portENABLE_INTERRUPTS(); \
}
#else
#define portCLEAR_INTERRUPT_MASK_P() \
{ \
portDISABLE_INTERRUPTS(); \
mtcp(S3_0_C4_C6_0, portUNMASK_VALUE); \
__asm volatile ( "DSB SY \n" \
"ISB SY \n" ); \
portENABLE_INTERRUPTS(); \
}
#endif
/* Hardware specifics used when sanity checking the configuration. */
#define portINTERRUPT_PRIORITY_REGISTER_OFFSET 0x400UL
#define portMAX_8_BIT_VALUE ( ( uint8_t ) 0xff )
#define portBIT_0_SET ( ( uint8_t ) 0x01 )
/*-----------------------------------------------------------*/
/*
* Starts the first task executing. This function is necessarily written in
* assembly code so is implemented in portASM.s.
*/
extern void vPortRestoreTaskContext( void );
/*-----------------------------------------------------------*/
/* A variable is used to keep track of the critical section nesting. This
variable has to be stored as part of the task context and must be initialised to
a non zero value to ensure interrupts don't inadvertently become unmasked before
the scheduler starts. As it is stored as part of the task context it will
automatically be set to 0 when the first task is started. */
volatile uint64_t ullCriticalNesting = 9999ULL;
/*
* The instance of the interrupt controller used by this port. This is required
* by the Xilinx library API functions.
*/
extern XScuGic xInterruptController;
/* Saved as part of the task context. If ullPortTaskHasFPUContext is non-zero
then floating point context must be saved and restored for the task. */
uint64_t ullPortTaskHasFPUContext = pdFALSE;
/* Set to 1 to pend a context switch from an ISR. */
uint64_t ullPortYieldRequired[configNUMBER_OF_CORES] = { pdFALSE };
/* Counts the interrupt nesting depth. A context switch is only performed if
if the nesting depth is 0. */
uint64_t ullPortInterruptNesting[configNUMBER_OF_CORES] = { 0 };
/* Used for check IN ISR */
volatile uint64_t uxCoreInIsr[configNUMBER_OF_CORES] = {0};
/*
* Global counter used for calculation of run time statistics of tasks.
* Defined only when the relevant option is turned on
*/
#if (configGENERATE_RUN_TIME_STATS==1)
volatile uint32_t ulHighFrequencyTimerTicks;
#endif
/* The space on the stack required to hold the FPU registers. This is 32 128-bit
* registers */
#define portFPU_REGISTER_WORDS ( 2 * 32 )
#if defined(GICv2)
/* Used in the ASM code. */
__attribute__(( used )) const uint64_t ullICCEOIR = portICCEOIR_END_OF_INTERRUPT_REGISTER_ADDRESS;
__attribute__(( used )) const uint64_t ullICCIAR = portICCIAR_INTERRUPT_ACKNOWLEDGE_REGISTER_ADDRESS;
__attribute__(( used )) const uint64_t ullICCPMR = portICCPMR_PRIORITY_MASK_REGISTER_ADDRESS;
#endif
__attribute__(( used )) const uint64_t ullMaxAPIPriorityMask = ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT );
/*-----------------------------------------------------------*/
/*
* Initialise the interrupt controller instance.
*/
static int32_t prvInitialiseInterruptController( void );
/* Ensure the interrupt controller instance variable is initialised before it is
* used, and that the initialisation only happens once.
*/
static int32_t prvEnsureInterruptControllerIsInitialised( void );
int32_t lInterruptControllerInitialised[configNUMBER_OF_CORES] = {0};
/*
* See header file for description.
*/
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
{
/* Setup the initial stack of the task. The stack is set exactly as
expected by the portRESTORE_CONTEXT() macro. */
/* First all the general purpose registers. */
pxTopOfStack--;
*pxTopOfStack = 0x0101010101010101ULL; /* R1 */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */
pxTopOfStack--;
*pxTopOfStack = 0x0303030303030303ULL; /* R3 */
pxTopOfStack--;
*pxTopOfStack = 0x0202020202020202ULL; /* R2 */
pxTopOfStack--;
*pxTopOfStack = 0x0505050505050505ULL; /* R5 */
pxTopOfStack--;
*pxTopOfStack = 0x0404040404040404ULL; /* R4 */
pxTopOfStack--;
*pxTopOfStack = 0x0707070707070707ULL; /* R7 */
pxTopOfStack--;
*pxTopOfStack = 0x0606060606060606ULL; /* R6 */
pxTopOfStack--;
*pxTopOfStack = 0x0909090909090909ULL; /* R9 */
pxTopOfStack--;
*pxTopOfStack = 0x0808080808080808ULL; /* R8 */
pxTopOfStack--;
*pxTopOfStack = 0x1111111111111111ULL; /* R11 */
pxTopOfStack--;
*pxTopOfStack = 0x1010101010101010ULL; /* R10 */
pxTopOfStack--;
*pxTopOfStack = 0x1313131313131313ULL; /* R13 */
pxTopOfStack--;
*pxTopOfStack = 0x1212121212121212ULL; /* R12 */
pxTopOfStack--;
*pxTopOfStack = 0x1515151515151515ULL; /* R15 */
pxTopOfStack--;
*pxTopOfStack = 0x1414141414141414ULL; /* R14 */
pxTopOfStack--;
*pxTopOfStack = 0x1717171717171717ULL; /* R17 */
pxTopOfStack--;
*pxTopOfStack = 0x1616161616161616ULL; /* R16 */
pxTopOfStack--;
*pxTopOfStack = 0x1919191919191919ULL; /* R19 */
pxTopOfStack--;
*pxTopOfStack = 0x1818181818181818ULL; /* R18 */
pxTopOfStack--;
*pxTopOfStack = 0x2121212121212121ULL; /* R21 */
pxTopOfStack--;
*pxTopOfStack = 0x2020202020202020ULL; /* R20 */
pxTopOfStack--;
*pxTopOfStack = 0x2323232323232323ULL; /* R23 */
pxTopOfStack--;
*pxTopOfStack = 0x2222222222222222ULL; /* R22 */
pxTopOfStack--;
*pxTopOfStack = 0x2525252525252525ULL; /* R25 */
pxTopOfStack--;
*pxTopOfStack = 0x2424242424242424ULL; /* R24 */
pxTopOfStack--;
*pxTopOfStack = 0x2727272727272727ULL; /* R27 */
pxTopOfStack--;
*pxTopOfStack = 0x2626262626262626ULL; /* R26 */
pxTopOfStack--;
*pxTopOfStack = 0x2929292929292929ULL; /* R29 */
pxTopOfStack--;
*pxTopOfStack = 0x2828282828282828ULL; /* R28 */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 0x00; /* XZR - has no effect, used so there are an even number of registers. */
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 0x00; /* R30 - procedure call link register. */
pxTopOfStack--;
*pxTopOfStack = portINITIAL_PSTATE;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) pxCode; /* Exception return address. */
#if( configUSE_TASK_FPU_SUPPORT == 1 )
{
/* The task will start without a floating point context. A task that uses
the floating point hardware must call vPortTaskUsesFPU() before executing
any floating point instructions. */
/* The task will start with a critical nesting count of 0 as interrupts are
enabled. */
pxTopOfStack--
*pxTopOfStack = portNO_CRITICAL_NESTING;
pxTopOfStack--;
*pxTopOfStack = portNO_FLOATING_POINT_CONTEXT;
}
#elif( configUSE_TASK_FPU_SUPPORT == 2 )
{
/* The task will start with a floating point context. Leave enough
* space for the registers - and ensure they are initialised to 0. */
pxTopOfStack -= portFPU_REGISTER_WORDS;
BaseType_t i = 0;
for (i = 0; i < portFPU_REGISTER_WORDS; ++i)
{
pxTopOfStack[i] = 0ULL;
}
pxTopOfStack--;
*pxTopOfStack = portNO_CRITICAL_NESTING;
pxTopOfStack--;
*pxTopOfStack = pdTRUE;
ullPortTaskHasFPUContext = pdTRUE;
}
#else
{
#error Invalid configUSE_TASK_FPU_SUPPORT setting - configUSE_TASK_FPU_SUPPORT must be set to 1, 2, or left undefined.
}
#endif
return pxTopOfStack;
}
/*-----------------------------------------------------------*/
BaseType_t xPortInstallInterruptHandler( uint8_t ucInterruptID, XInterruptHandler pxHandler, void *pvCallBackRef )
{
int32_t lReturn;
/* An API function is provided to install an interrupt handler */
lReturn = prvEnsureInterruptControllerIsInitialised();
if( lReturn == pdPASS )
{
lReturn = XScuGic_Connect( &xInterruptController, ucInterruptID, pxHandler, pvCallBackRef );
}
if( lReturn == XST_SUCCESS )
{
lReturn = pdPASS;
}
configASSERT( lReturn == pdPASS );
return lReturn;
}
/*-----------------------------------------------------------*/
static int32_t prvEnsureInterruptControllerIsInitialised( void )
{
int32_t lReturn;
/* Ensure the interrupt controller instance variable is initialised before
it is used, and that the initialisation only happens once. */
uint32_t ulCoreID = portGET_CORE_ID();
if( lInterruptControllerInitialised[ulCoreID] != pdTRUE )
{
lReturn = prvInitialiseInterruptController();
if( lReturn == pdPASS )
{
lInterruptControllerInitialised[ulCoreID] = pdTRUE;
}
}
else
{
lReturn = pdPASS;
}
return lReturn;
}
/*-----------------------------------------------------------*/
uint32_t TSCIsrCnt[4] = {0, 0, 0, 0};
void vTaskSwitchContextISR(void* arg)
{
portEND_SWITCHING_ISR(pdTRUE);
TSCIsrCnt[portGET_CORE_ID()]++;
}
uint32_t IntCoreCnt[4] = {0, 0, 0, 0};
void vInterruptCore(uint32_t ulInterruptID, uint32_t ulCoreID)
{
configASSERT(ulCoreID < configNUMBER_OF_CORES);
configASSERT(ulInterruptID < 16);
uint32_t ulRegVal = 0;
uint32_t ulCoreMask = (1 << ulCoreID);
ulRegVal |= ulInterruptID & 0xFu;
ulRegVal |= (ulCoreMask << 16U);
*((volatile uint32_t*)portICD_SGIR_ADDRESS) = ulRegVal;
IntCoreCnt[ulCoreID] ++;
}
static int32_t prvInitialiseInterruptController( void )
{
BaseType_t xulStatus;
XScuGic_Config *pxGICConfig;
BaseType_t xCoreID = portGET_CORE_ID();
if (xCoreID == 0)
{
pxGICConfig = XScuGic_LookupConfig( configINTERRUPT_CONTROLLER_DEVICE_ID );
xulStatus = XScuGic_CfgInitialize( &xInterruptController, pxGICConfig, pxGICConfig->CpuBaseAddress );
/* Connect the interrupt controller interrupt handler to the hardware
interrupt handling logic in the ARM processor. */
Xil_ExceptionRegisterHandler( XIL_EXCEPTION_ID_IRQ_INT,
( Xil_ExceptionHandler ) XScuGic_InterruptHandler,
&xInterruptController);
XScuGic_SetPPI_SGI_Priority(&xInterruptController, portYIELD_CORE_INT_ID, portLOWEST_USABLE_INTERRUPT_PRIORITY << portPRIORITY_SHIFT);
XScuGic_Connect(&xInterruptController, portYIELD_CORE_INT_ID, vTaskSwitchContextISR, NULL);
}
else
{
// Secondary COREs only handle the portYIELD_CORE interrrupt, any other interrupts should be handled by CORE 0
extern s32 XScuGic_CpuIfInitialize(XScuGic *InstancePtr);
xulStatus = XScuGic_CpuIfInitialize(&xInterruptController);
XScuGic_SetPPI_SGI_Priority(&xInterruptController, portYIELD_CORE_INT_ID, portLOWEST_USABLE_INTERRUPT_PRIORITY << portPRIORITY_SHIFT);
XScuGic_Connect(&xInterruptController, portYIELD_CORE_INT_ID, vTaskSwitchContextISR, NULL);
}
/* For FreeRTOS SMP port, Exception will be enable at the end of vPortRestoreTaskContext */
// Xil_ExceptionEnable();
if( xulStatus == XST_SUCCESS )
{
xulStatus = pdPASS;
}
else
{
xulStatus = pdFAIL;
}
configASSERT( xulStatus == pdPASS );
return xulStatus;
}
/*-----------------------------------------------------------*/
void vPortEnableInterrupt( uint8_t ucInterruptID )
{
int32_t lReturn;
/* An API function is provided to enable an interrupt in the interrupt
controller. */
lReturn = prvEnsureInterruptControllerIsInitialised();
if( lReturn == pdPASS )
{
XScuGic_Enable( &xInterruptController, ucInterruptID );
}
configASSERT( lReturn );
}
/*-----------------------------------------------------------*/
void vPortDisableInterrupt( uint8_t ucInterruptID )
{
int32_t lReturn;
/* An API function is provided to disable an interrupt in the interrupt
controller. */
lReturn = prvEnsureInterruptControllerIsInitialised();
if( lReturn == pdPASS )
{
XScuGic_Disable( &xInterruptController, ucInterruptID );
}
configASSERT( lReturn );
}
/*-----------------------------------------------------------*/
/* flag to control tick ISR handling, this is made true just before schedular start */
volatile uint64_t uxPortSchedularRunning = pdFALSE;
BaseType_t xPortStartScheduler( void )
{
uint32_t ulAPSR;
#if defined(GICv3)
uint32_t ulBpr;
#endif
prvEnsureInterruptControllerIsInitialised();
#if( configASSERT_DEFINED == 1 )
{
if (portGET_CORE_ID() == 0)
{
volatile uint32_t ulOriginalPriority;
#if defined(GICv2)
volatile uint8_t * const pucFirstUserPriorityRegister = ( volatile uint8_t * const ) ( configINTERRUPT_CONTROLLER_BASE_ADDRESS + portINTERRUPT_PRIORITY_REGISTER_OFFSET );
#else
volatile uint8_t * const pucFirstUserPriorityRegister = ( volatile uint8_t * const ) ( configINTERRUPT_CONTROLLER_BASE_ADDRESS + 0x420 );
#endif
volatile uint8_t ucMaxPriorityValue;
/* Determine how many priority bits are implemented in the GIC.
Save the interrupt priority value that is about to be clobbered. */
ulOriginalPriority = *pucFirstUserPriorityRegister;
/* Determine the number of priority bits available. First write to
all possible bits. */
*pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE;
/* Read the value back to see how many bits stuck. */
ucMaxPriorityValue = *pucFirstUserPriorityRegister;
/* Shift to the least significant bits. */
while( ( ucMaxPriorityValue & portBIT_0_SET ) != portBIT_0_SET )
{
ucMaxPriorityValue >>= ( uint8_t ) 0x01;
}
/* Sanity check configUNIQUE_INTERRUPT_PRIORITIES matches the read
value. */
configASSERT( ucMaxPriorityValue >= portLOWEST_INTERRUPT_PRIORITY );
/* Restore the clobbered interrupt priority register to its original
value. */
*pucFirstUserPriorityRegister = ulOriginalPriority;
}
}
#endif /* conifgASSERT_DEFINED */
/* At the time of writing, the BSP only supports EL3. */
__asm volatile ( "MRS %0, CurrentEL" : "=r" ( ulAPSR ) );
ulAPSR &= portAPSR_MODE_BITS_MASK;
#if defined( GUEST )
#warning Building for execution as a guest under XEN. THIS IS NOT A FULLY TESTED PATH.
configASSERT( ulAPSR == portEL1 );
if( ulAPSR == portEL1 )
#else
configASSERT( ulAPSR == portEL3 );
if( ulAPSR == portEL3 )
#endif
{
/* Only continue if the binary point value is set to its lowest possible
setting. See the comments in vPortValidateInterruptPriority() below for
more information. */
#if defined(GICv2)
configASSERT( ( portICCBPR_BINARY_POINT_REGISTER & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE );
if( ( portICCBPR_BINARY_POINT_REGISTER & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE )
#else
ulBpr = mfcp(S3_0_C12_C8_3);
configASSERT( ( ulBpr & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE );
if( ( ulBpr & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE )
#endif
{
/* Interrupts are turned off in the CPU itself to ensure a tick does
not execute while the scheduler is being started. Interrupts are
automatically turned back on in the CPU when the first task starts
executing. */
portDISABLE_INTERRUPTS();
if (portGET_CORE_ID() == 0)
{
/* Start the timer that generates the tick ISR. */
configSETUP_TICK_INTERRUPT();
uxPortSchedularRunning = pdTRUE;
}
/* Start the first task executing. */
vPortRestoreTaskContext();
}
}
return 0;
}
/*-----------------------------------------------------------*/
void vPortEndScheduler( void )
{
/* Not implemented in ports where there is nothing to return to.
Artificially force an assert. */
configASSERT( 0 );
}
/*-----------------------------------------------------------*/
void FreeRTOS_Tick_Handler( void )
{
#if defined(GICv3)
unsigned int ulRpr;
#endif
/*
* The Xilinx implementation of generating run time task stats uses the same timer used for generating
* FreeRTOS ticks. In case user decides to generate run time stats the tick handler is called more
* frequently (10 times faster). The timer/tick handler uses logic to handle the same. It handles
* the FreeRTOS tick once per 10 interrupts.
* For handling generation of run time stats, it increments a pre-defined counter every time the
* interrupt handler executes.
*/
#if (configGENERATE_RUN_TIME_STATS == 1)
ulHighFrequencyTimerTicks++;
if (!(ulHighFrequencyTimerTicks % 10))
#endif
{
/* Must be the lowest possible priority. */
#if !defined( QEMU )
{
#if defined(GICv2)
configASSERT( portICCRPR_RUNNING_PRIORITY_REGISTER == ( uint32_t ) ( portLOWEST_USABLE_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) );
#else
ulRpr = mfcp(S3_0_C12_C11_3);
configASSERT( ulRpr == ( uint32_t ) ( portLOWEST_USABLE_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) );
#endif
}
#endif
/* Interrupts should not be enabled before this point. */
#if( configASSERT_DEFINED == 1 )
{
uint32_t ulMaskBits;
__asm volatile( "mrs %0, daif" : "=r"( ulMaskBits ) :: "memory" );
configASSERT( ( ulMaskBits & portDAIF_I ) != 0 );
}
#endif /* configASSERT_DEFINED */
/* Set interrupt mask before altering scheduler structures. The tick
handler runs at the lowest priority, so interrupts cannot already be masked,
so there is no need to save and restore the current mask value. It is
necessary to turn off interrupts in the CPU itself while the ICCPMR is being
updated. */
#if defined(GICv2)
portICCPMR_PRIORITY_MASK_REGISTER = ( uint32_t ) ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT );
#else
mtcp(S3_0_C4_C6_0, ( uint32_t ) ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ));
#endif
__asm volatile ( "dsb sy \n"
"isb sy \n" ::: "memory" );
/* Ok to enable interrupts after the interrupt source has been cleared. */
configCLEAR_TICK_INTERRUPT();
portENABLE_INTERRUPTS();
UBaseType_t x = portENTER_CRITICAL_FROM_ISR();
/* Increment the RTOS tick. */
if( xTaskIncrementTick() != pdFALSE )
{
ullPortYieldRequired[portGET_CORE_ID()] = pdTRUE;
}
portEXIT_CRITICAL_FROM_ISR(x);
}
/* Ensure all interrupt priorities are active again. */
portCLEAR_INTERRUPT_MASK_P();
}
/*-----------------------------------------------------------*/
#if( configUSE_TASK_FPU_SUPPORT != 2 )
void vPortTaskUsesFPU( void )
{
/* A task is registering the fact that it needs an FPU context. Set the
FPU flag (which is saved as part of the task context). */
ullPortTaskHasFPUContext = pdTRUE;
/* Consider initialising the FPSR here - but probably not necessary in
AArch64. */
}
#endif /* configUSE_TASK_FPU_SUPPORT */
/*-----------------------------------------------------------*/
void vPortClearInterruptMask( UBaseType_t uxNewMaskValue )
{
if( uxNewMaskValue == pdFALSE )
{
portCLEAR_INTERRUPT_MASK_P();
}
}
/*-----------------------------------------------------------*/
UBaseType_t uxPortSetInterruptMask( void )
{
uint32_t ulReturn;
uint32_t mask;
if (lInterruptControllerInitialised[portGET_CORE_ID()] == pdTRUE) {
/* Interrupt in the CPU must be turned off while the ICCPMR is being
updated. */
portDISABLE_INTERRUPTS();
#if defined(GICv2)
mask = portICCPMR_PRIORITY_MASK_REGISTER;
#else
mask = mfcp(S3_0_C4_C6_0);
#endif
if( mask == ( uint32_t ) ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) )
{
/* Interrupts were already masked. */
ulReturn = pdTRUE;
}
else
{
ulReturn = pdFALSE;
#if defined(GICv2)
portICCPMR_PRIORITY_MASK_REGISTER = ( uint32_t ) ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT );
#else
mtcp(S3_0_C4_C6_0, ( uint32_t ) ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ));
#endif
__asm volatile ( "dsb sy \n"
"isb sy \n" ::: "memory" );
}
portENABLE_INTERRUPTS();
} else {
ulReturn = pdTRUE;
}
return ulReturn;
}
/*-----------------------------------------------------------*/
#if( configASSERT_DEFINED == 1 )
void vPortValidateInterruptPriority( void )
{
#if defined(GICv3)
unsigned int ulRpr;
unsigned int ulBpr;
#endif
/* The following assertion will fail if a service routine (ISR) for
an interrupt that has been assigned a priority above
configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API
function. ISR safe FreeRTOS API functions must *only* be called
from interrupts that have been assigned a priority at or below
configMAX_SYSCALL_INTERRUPT_PRIORITY.
Numerically low interrupt priority numbers represent logically high
interrupt priorities, therefore the priority of the interrupt must
be set to a value equal to or numerically *higher* than
configMAX_SYSCALL_INTERRUPT_PRIORITY.
FreeRTOS maintains separate thread and ISR API functions to ensure
interrupt entry is as fast and simple as possible. */
#if defined(GICv2)
configASSERT( portICCRPR_RUNNING_PRIORITY_REGISTER >= ( uint32_t ) ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) );
#else
ulRpr = mfcp(S3_0_C12_C11_3);
configASSERT( ulRpr >= ( uint32_t ) ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) );
#endif
/* Priority grouping: The interrupt controller (GIC) allows the bits
that define each interrupt's priority to be split between bits that
define the interrupt's pre-emption priority bits and bits that define
the interrupt's sub-priority. For simplicity all bits must be defined
to be pre-emption priority bits. The following assertion will fail if
this is not the case (if some bits represent a sub-priority).
The priority grouping is configured by the GIC's binary point register
(ICCBPR). Writing 0 to ICCBPR will ensure it is set to its lowest
possible value (which may be above 0). */
#if defined(GICv2)
configASSERT( ( portICCBPR_BINARY_POINT_REGISTER & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE );
#else
ulBpr = mfcp(S3_0_C12_C8_3);
configASSERT( ( ulBpr & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE );
#endif
}
#endif /* configASSERT_DEFINED */
/*-----------------------------------------------------------*/
void vIRQHandler( uint32_t ulICCIAR )
{
BaseType_t xCoreId = portGET_CORE_ID();
uxCoreInIsr[xCoreId]++;
extern void vApplicationIRQHandler( uint32_t ulICCIAR );
vApplicationIRQHandler(ulICCIAR);
uxCoreInIsr[xCoreId]--;
}
#define portRTOS_LOCK_COUNT (2u)
#define portMAX_CORE_COUNT configNUMBER_OF_CORES
/* Which core owns the lock */
volatile uint64_t ucOwnedByCore[ portMAX_CORE_COUNT ];
/* Lock count a core owns */
volatile uint64_t ucRecursionCountByLock[ portRTOS_LOCK_COUNT ];
/* Index 0 is used for ISR lock and Index 1 is used for task lock */
uint32_t ulGateWord[ portRTOS_LOCK_COUNT ];
static inline void vSpinUnlock(uint32_t* ulLock)
{
__asm volatile(
"dmb sy\n"
"mov w1, #0\n"
"str w1, [%x0]\n"
"dsb sy\n"
"sev\n"
:
:"r" (ulLock)
: "memory", "w1"
);
}
static inline int32_t lSpinTrylock(uint32_t* ulLock)
{
register int32_t lRet;
__asm volatile(
"1:\n"
"ldxr w1, [%x1]\n"
"cmp w1, #1\n"
"beq 2f\n"
"mov w2, #1\n"
"stxr w1, w2, [%x1]\n"
"cmp w1, #0\n"
"bne 1b\n"
"2:\n"
"mov %w0, w1\n"
:"=r" (lRet)
:"r" (ulLock)
: "memory", "w1", "w2"
);
return lRet;
}
/* Read 64b value shared between cores */
static inline uint64_t uxGet64(volatile uint64_t* x)
{
__asm("dsb sy");
return *x;
}
/* Write 64b value shared between cores */
static inline void vSet64(volatile uint64_t* x, uint64_t value)
{
*x = value;
__asm("dsb sy");
}
void vPortRecursiveLock(BaseType_t xCoreID, uint32_t ulLockNum, BaseType_t uxAcquire)
{
uint32_t ulLockBit = 1u << ulLockNum;
/* Lock acquire */
if (uxAcquire)
{
/* Check if spinlock is available */
/* If spinlock is not available check if the core owns the lock */
/* If the core owns the lock wait increment the lock count by the core */
/* If core does not own the lock wait for the spinlock */
if( lSpinTrylock(&ulGateWord[ulLockNum]) != 0)
{
/* Check if the core owns the spinlock */
if( uxGet64(&ucOwnedByCore[xCoreID]) & ulLockBit )
{
configASSERT( uxGet64(&ucRecursionCountByLock[ulLockNum]) != 255u);
vSet64(&ucRecursionCountByLock[ulLockNum], (uxGet64(&ucRecursionCountByLock[ulLockNum])+1));
return;
}
/* Preload the gate word into the cache */
uint32_t dummy = ulGateWord[ulLockNum];
dummy++;
while (lSpinTrylock(&ulGateWord[ulLockNum]) != 0)
__asm volatile ("wfe");
}
/* Add barrier to ensure lock is taken before we proceed */
__asm__ __volatile__ ( "dmb sy" ::: "memory" );
/* Assert the lock count is 0 when the spinlock is free and is acquired */
configASSERT(uxGet64(&ucRecursionCountByLock[ulLockNum]) == 0);
/* Set lock count as 1 */
vSet64(&ucRecursionCountByLock[ulLockNum], 1);
/* Set ucOwnedByCore */
vSet64(&ucOwnedByCore[xCoreID], (uxGet64(&ucOwnedByCore[xCoreID]) | ulLockBit));
}
/* Lock release */
else
{
/* Assert the lock is not free already */
configASSERT( (uxGet64(&ucOwnedByCore[xCoreID]) & ulLockBit) != 0 );
configASSERT( uxGet64(&ucRecursionCountByLock[ulLockNum]) != 0 );
/* Reduce ucRecursionCountByLock by 1 */
vSet64(&ucRecursionCountByLock[ulLockNum], (uxGet64(&ucRecursionCountByLock[ulLockNum]) - 1) );
if( !uxGet64(&ucRecursionCountByLock[ulLockNum]) )
{
vSet64(&ucOwnedByCore[xCoreID], (uxGet64(&ucOwnedByCore[xCoreID]) & ~ulLockBit));
vSpinUnlock(&ulGateWord[ulLockNum]);
__asm volatile("sev");
/* Add barrier to ensure lock is taken before we proceed */
__asm__ __volatile__ ( "dmb sy" ::: "memory" );
}
}
}
#if( configGENERATE_RUN_TIME_STATS == 1 )
/*
* For Xilinx implementation this is a dummy function that does a redundant operation
* of zeroing out the global counter.
* It is called by FreeRTOS kernel.
*/
void xCONFIGURE_TIMER_FOR_RUN_TIME_STATS (void)
{
ulHighFrequencyTimerTicks = 0;
}
/*
* For Xilinx implementation this function returns the global counter used for
* run time task stats calculation.
* It is called by FreeRTOS kernel task handling logic.
*/
uint32_t xGET_RUN_TIME_COUNTER_VALUE (void)
{
return ulHighFrequencyTimerTicks;
}
#endif
@@ -0,0 +1,533 @@
/*
* FreeRTOS Kernel V10.3.0
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Copyright (C) 2014 - 2020 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software AND associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, AND/or sell copies of
* the Software, AND to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice AND this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#if defined (versal) && !defined(ARMR5)
#define GICv3
#else
#define GICv2
#endif
.text
/* Variables AND functions. */
.extern ullMaxAPIPriorityMask
.extern pxCurrentTCBs
.extern vTaskSwitchContext
.extern vIRQHandler
.extern ullPortInterruptNesting
.extern ullPortTaskHasFPUContext
.extern ullCriticalNesting
.extern ullPortYieldRequired
.extern ullICCEOIR
.extern ullICCIAR
.extern _freertos_vector_table
.global FreeRTOS_IRQ_Handler
.global FreeRTOS_SWI_Handler
.global vPortRestoreTaskContext
.macro portSAVE_CONTEXT
/* Switch to use the EL0 stack pointer. */
MSR SPSEL, #0
/* Save the entire context. */
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]!
/* Save the SPSR. */
#if defined( GUEST )
MRS X3, SPSR_EL1
MRS X2, ELR_EL1
#else
MRS X3, SPSR_EL3
/* Save the ELR. */
MRS X2, ELR_EL3
#endif
STP X2, X3, [SP, #-0x10]!
/* Save the FPU context indicator. */
LDR X0, ullPortTaskHasFPUContextConst
LDR X2, [X0]
/* Save the FPU context, if any (32 128-bit registers). */
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:
/* Store the critical nesting count AND FPU context indicator. */
STR X2, [SP, #-0x10]!
LDR X0, pxCurrentTCBConst
/* Get coreId AND choose the corresponding index for core in pxCurrentTCB */
MRS X1, MPIDR_EL1
AND X1, X1, #0xff
LSL X1, X1, #3 /* X1 = X1 * 8 */
ADD X0, X0, X1
LDR X1, [X0]
MOV X0, SP /* Move SP into X0 for saving. */
STR X0, [X1]
/* Switch to use the ELx stack pointer. */
MSR SPSEL, #1
.endm
; /**********************************************************************/
.macro portRESTORE_CONTEXT
/* Switch to use the EL0 stack pointer. */
MSR SPSEL, #0
/* Set the SP to point to the stack of the task being restored. */
LDR X0, pxCurrentTCBConst
/* Get coreId AND choose the corresponding index for core in pxCurrentTCB */
MRS X1, MPIDR_EL1
AND X1, X1, #0xff
LSL X1, X1, #3 /* X1 = X1 * 8 */
ADD X0, X0, X1
LDR X1, [X0]
LDR X0, [X1]
MOV SP, X0
LDR X2, [SP], #0x10 /* FPU context. */
/* Set the PMR register to be correct for the current critical nesting
depth. */
MOV X1, #255 /* X1 holds the unmask value. */
#if defined(GICv2)
LDR X4, ullICCPMRConst /* X4 holds the address of the ICCPMR constant. */
/* CMP X3, #0 */
LDR X5, [X4] /* X5 holds the address of the ICCPMR register. */
/* B.EQ 1f */ /* Jump to Label 1 Forward */
/* LDR X6, ullMaxAPIPriorityMaskConst */
/* LDR X1, [X6] */ /* X1 holds the mask value. */
1:
STR W1, [X5] /* Write the mask value to ICCPMR. */
#else
CMP X3, #0
B.EQ 2f
LDR X6, ullMaxAPIPriorityMaskConst
LDR X1, [X6] /* X1 holds the mask value. */
2:
MSR S3_0_C4_C6_0, X1
#endif
DSB SY /* _RB_Barriers probably not required here. */
ISB SY
/* Restore the FPU context indicator. */
LDR X0, ullPortTaskHasFPUContextConst
STR X2, [X0]
/* Restore the FPU context, if any. */
CMP X2, #0
B.EQ 1f
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
1:
LDP X2, X3, [SP], #0x10 /* SPSR AND ELR. */
#if defined( GUEST )
/* Restore the SPSR. */
MSR SPSR_EL1, X3
/* Restore the ELR. */
MSR ELR_EL1, X2
#else
/* Restore the SPSR. */
MSR SPSR_EL3, X3 /*_RB_ Assumes started in EL3. */
/* Restore the ELR. */
MSR ELR_EL3, X2
#endif
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
/* Switch to use the ELx stack pointer. _RB_ Might not be required. */
MSR SPSEL, #1
ERET
.endm
/******************************************************************************
* vPortRestoreTaskContext is used to start the scheduler.
*****************************************************************************/
.align 8
.type vPortRestoreTaskContext, %function
vPortRestoreTaskContext:
.set freertos_vector_base, _freertos_vector_table
/* Install the FreeRTOS interrupt handlers. */
LDR X1, =freertos_vector_base
#if defined( GUEST )
MSR VBAR_EL1, X1
#else
MSR VBAR_EL3, X1
#endif
/* Enable IRQ */
MSR DAIFCLR, #2
DSB SY
ISB SY
/* Start the first task. */
portRESTORE_CONTEXT
/******************************************************************************
* FreeRTOS_SWI_Handler handler is used to perform a context switch.
*****************************************************************************/
.align 8
.type FreeRTOS_SWI_Handler, %function
FreeRTOS_SWI_Handler:
/* Save the context of the current task AND select a new task to run. */
portSAVE_CONTEXT
#if defined( GUEST )
MRS X0, ESR_EL1
#else
MRS X0, ESR_EL3
#endif
LSR X1, X0, #26
#if defined( GUEST )
CMP X1, #0x15 /* 0x15 = SVC instruction. */
#else
CMP X1, #0x17 /* 0x17 = SMC instruction. */
#endif
B.NE FreeRTOS_Abort
MRS x0, MPIDR_EL1 /* Get CoreID */
AND x0, x0, #0xff
BL vTaskSwitchContext
portRESTORE_CONTEXT
FreeRTOS_Abort:
/* Full ESR is in X0, exception class code is in X1. */
B .
/******************************************************************************
* FreeRTOS_IRQ_Handler handles IRQ entry AND exit.
*****************************************************************************/
.align 8
.type FreeRTOS_IRQ_Handler, %function
FreeRTOS_IRQ_Handler:
/* Save volatile registers. */
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]!
/* Save FPU registers */
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]!
/* Save the SPSR AND ELR. */
#if defined( GUEST )
MRS X3, SPSR_EL1
MRS X2, ELR_EL1
#else
MRS X3, SPSR_EL3
MRS X2, ELR_EL3
#endif
STP X2, X3, [SP, #-0x10]!
/* Increment the interrupt nesting counter. */
LDR X5, ullPortInterruptNestingConst
/* Get coreId AND choose the corresponding index for core in ullPortInterruptNesting */
MRS X1, MPIDR_EL1
AND X1, X1, #0xff
LSL X1, X1, #3 /* X1 = X1 * 8 */
ADD X5, X5, X1
LDR X1, [X5] /* Old nesting count in X1. */
ADD X6, X1, #1
STR X6, [X5] /* Address of nesting count variable in X5. */
/* Maintain the interrupt nesting information across the function call. */
STP X1, X5, [SP, #-0x10]!
/* Read value from the interrupt acknowledge register, which is stored in W0
for future parameter AND interrupt clearing use. */
#if defined(GICv2)
LDR X2, ullICCIARConst
LDR X3, [X2]
LDR W0, [X3] /* ICCIAR in W0 as parameter. */
#else
MRS X0, S3_0_C12_C8_0
#endif
/* ICCIAR in W0 as parameter. */
/* Maintain the ICCIAR value across the function call. */
STP X0, X1, [SP, #-0x10]!
/* Call the C handler. */
BL vIRQHandler
/* Disable interrupts. */
#if defined(GICv2)
MSR DAIFSET, #3
#else
MSR DAIFSET, #2
#endif
DSB SY
ISB SY
/* Restore the ICCIAR value. */
LDP X0, X1, [SP], #0x10
/* End IRQ processing by writing ICCIAR to the EOI register. */
#if defined(GICv2)
LDR X4, ullICCEOIRConst
LDR X4, [X4]
STR W0, [X4]
#else
MSR S3_0_C12_C8_1, X0
#endif
/* Restore the critical nesting count. */
LDP X1, X5, [SP], #0x10
STR X1, [X5]
/* Has interrupt nesting unwound? */
CMP X1, #0
B.NE Exit_IRQ_No_Context_Switch
/* Is a context switch required? */
LDR X0, ullPortYieldRequiredConst
/* Choose the corresponding index for core in ullPortYieldRequired */
MRS X1, MPIDR_EL1
AND X1, X1, #0xff
LSL X1, X1, #3 /* X1 = X1 * 8 */
ADD X0, X0, X1
LDR X1, [X0]
CMP X1, #0
B.EQ Exit_IRQ_No_Context_Switch
/* Reset ullPortYieldRequired to 0. */
MOV X2, #0
STR X2, [X0]
/* Restore volatile registers. */
LDP X4, X5, [SP], #0x10 /* SPSR AND ELR. */
#if defined( GUEST )
MSR SPSR_EL1, X5
MSR ELR_EL1, X4
#else
MSR SPSR_EL3, X5 /*_RB_ Assumes started in EL3. */
MSR ELR_EL3, X4
#endif
DSB SY
ISB SY
/* Restore FPU registers */
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
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
/* Save the context of the current task AND select a new task to run. */
portSAVE_CONTEXT
MRS X0, MPIDR_EL1 /* Get CoreID */
AND X0, X0, #0xff
BL vTaskSwitchContext
portRESTORE_CONTEXT
Exit_IRQ_No_Context_Switch:
/* Restore volatile registers. */
LDP X4, X5, [SP], #0x10 /* SPSR AND ELR. */
#if defined( GUEST )
MSR SPSR_EL1, X5
MSR ELR_EL1, X4
#else
MSR SPSR_EL3, X5 /*_RB_ Assumes started in EL3. */
MSR ELR_EL3, X4
#endif
DSB SY
ISB SY
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
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
pxCurrentTCBConst: .dword pxCurrentTCBs
ullPortTaskHasFPUContextConst: .dword ullPortTaskHasFPUContext
ullMaxAPIPriorityMaskConst: .dword ullMaxAPIPriorityMask
vIRQHandlerConst: .dword vIRQHandler
ullPortInterruptNestingConst: .dword ullPortInterruptNesting
ullPortYieldRequiredConst: .dword ullPortYieldRequired
#if defined(GICv2)
ullICCPMRConst: .dword ullICCPMR
ullICCIARConst: .dword ullICCIAR
ullICCEOIRConst: .dword ullICCEOIR
#endif
.end
@@ -0,0 +1,211 @@
/*
* FreeRTOS Kernel V10.3.0
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Copyright (C) 2014 - 2020 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
/* Xilinx includes. */
#include "xttcps.h"
#include "xscugic.h"
void vApplicationAssert( const char *pcFileName, uint32_t ulLine )
__attribute__((weak));
/* Timer used to generate the tick interrupt. */
XTtcPs xTimerInstance;
XScuGic xInterruptController;
/*-----------------------------------------------------------*/
void FreeRTOS_SetupTickInterrupt( void )
{
BaseType_t xStatus;
XTtcPs_Config *pxTimerConfiguration;
XInterval usInterval;
uint8_t ucPrescale;
const uint8_t ucLevelSensitive = 1;
pxTimerConfiguration = XTtcPs_LookupConfig( configTIMER_ID );
/* Initialise the device. */
xStatus = XTtcPs_CfgInitialize( &xTimerInstance, pxTimerConfiguration, pxTimerConfiguration->BaseAddress );
if( xStatus != XST_SUCCESS )
{
/* Not sure how to do this before XTtcPs_CfgInitialize is called as
*xRTOSTickTimerInstance is set within XTtcPs_CfgInitialize(). */
XTtcPs_Stop( &xTimerInstance );
xStatus = XTtcPs_CfgInitialize( &xTimerInstance, pxTimerConfiguration, pxTimerConfiguration->BaseAddress );
configASSERT( xStatus == XST_SUCCESS );
}
/* Set the options. */
XTtcPs_SetOptions( &xTimerInstance, ( XTTCPS_OPTION_INTERVAL_MODE | XTTCPS_OPTION_WAVE_DISABLE ) );
/*
* The Xilinx implementation of generating run time task stats uses the same timer used for generating
* FreeRTOS ticks. In case user decides to generate run time stats the timer time out interval is changed
* as "configured tick rate * 10". The multiplying factor of 10 is hard coded for Xilinx FreeRTOS ports.
*/
#if (configGENERATE_RUN_TIME_STATS == 1)
XTtcPs_CalcIntervalFromFreq( &xTimerInstance, configTICK_RATE_HZ*10, &usInterval, &ucPrescale );
#else
XTtcPs_CalcIntervalFromFreq( &xTimerInstance, configTICK_RATE_HZ, &( usInterval ), &( ucPrescale ) );
#endif
/* Set the interval and prescale. */
XTtcPs_SetInterval( &xTimerInstance, usInterval );
XTtcPs_SetPrescaler( &xTimerInstance, ucPrescale );
xPortInstallInterruptHandler(configTIMER_INTERRUPT_ID,
( Xil_InterruptHandler ) FreeRTOS_Tick_Handler,
( void * ) &xTimerInstance);
/* The priority must be the lowest possible. */
XScuGic_SetPriorityTriggerType( &xInterruptController, configTIMER_INTERRUPT_ID, portLOWEST_USABLE_INTERRUPT_PRIORITY << portPRIORITY_SHIFT, ucLevelSensitive );
vPortEnableInterrupt(configTIMER_INTERRUPT_ID);
/* Enable the interrupts in the timer. */
XTtcPs_EnableInterrupts( &xTimerInstance, XTTCPS_IXR_INTERVAL_MASK );
/* Start the timer. */
XTtcPs_Start( &xTimerInstance );
}
/*-----------------------------------------------------------*/
void FreeRTOS_ClearTickInterrupt( void )
{
XTtcPs_ClearInterruptStatus( &xTimerInstance, XTtcPs_GetInterruptStatus( &xTimerInstance ) );
__asm volatile( "DSB SY" );
__asm volatile( "ISB SY" );
}
/*-----------------------------------------------------------*/
void vApplicationIRQHandler( uint32_t ulICCIAR )
{
extern const XScuGic_Config XScuGic_ConfigTable[];
static const XScuGic_VectorTableEntry *pxVectorTable = XScuGic_ConfigTable[ XPAR_SCUGIC_SINGLE_DEVICE_ID ].HandlerTable;
uint32_t ulInterruptID;
const XScuGic_VectorTableEntry *pxVectorEntry;
/* Interrupts cannot be re-enabled until the source of the interrupt is
cleared. The ID of the interrupt is obtained by bitwise ANDing the ICCIAR
value with 0x3FF. */
ulInterruptID = ulICCIAR & 0x3FFUL;
if( ulInterruptID < XSCUGIC_MAX_NUM_INTR_INPUTS )
{
/* Call the function installed in the array of installed handler
functions. */
pxVectorEntry = &( pxVectorTable[ ulInterruptID ] );
configASSERT( pxVectorEntry );
pxVectorEntry->Handler( pxVectorEntry->CallBackRef );
}
}
/*-----------------------------------------------------------*/
/* This version of vApplicationAssert() is declared as a weak symbol to allow it
to be overridden by a version implemented within the application that is using
this BSP. */
void vApplicationAssert( const char *pcFileName, uint32_t ulLine )
{
volatile uint32_t ul = 0;
volatile const char *pcLocalFileName = pcFileName; /* To prevent pcFileName being optimized away. */
volatile uint32_t ulLocalLine = ulLine; /* To prevent ulLine being optimized away. */
/* Prevent compile warnings about the following two variables being set but
not referenced. They are intended for viewing in the debugger. */
( void ) pcLocalFileName;
( void ) ulLocalLine;
xil_printf( "Assert failed in file %s, line %lu\r\n", pcLocalFileName, ulLocalLine );
/* If this function is entered then a call to configASSERT() failed in the
FreeRTOS code because of a fatal error. The pcFileName and ulLine
parameters hold the file name and line number in that file of the assert
that failed. Additionally, if using the debugger, the function call stack
can be viewed to find which line failed its configASSERT() test. Finally,
the debugger can be used to set ul to a non-zero value, then step out of
this function to find where the assert function was entered. */
taskENTER_CRITICAL();
{
while( ul == 0 )
{
__asm volatile( "NOP" );
}
}
taskEXIT_CRITICAL();
}
/*-----------------------------------------------------------*/
#if 0
/* This default tick hook does nothing and is declared as a weak symbol to allow
the application writer to override this default by providing their own
implementation in the application code. */
void vApplicationTickHook( void )
{
}
/*-----------------------------------------------------------*/
/* This default idle hook does nothing and is declared as a weak symbol to allow
the application writer to override this default by providing their own
implementation in the application code. */
void vApplicationIdleHook( void )
{
}
/*-----------------------------------------------------------*/
/* This default malloc failed hook does nothing and is declared as a weak symbol
to allow the application writer to override this default by providing their own
implementation in the application code. */
void vApplicationMallocFailedHook( void )
{
xil_printf( "vApplicationMallocFailedHook() called\n" );
}
/*-----------------------------------------------------------*/
/* This default stack overflow hook will stop the application for executing. It
is declared as a weak symbol to allow the application writer to override this
default by providing their own implementation in the application code. */
void vApplicationStackOverflowHook( TaskHandle_t xTask, char *pcTaskName )
{
/* Attempt to prevent the handle and name of the task that overflowed its stack
from being optimised away because they are not used. */
volatile TaskHandle_t xOverflowingTaskHandle = xTask;
volatile char *pcOverflowingTaskName = pcTaskName;
( void ) xOverflowingTaskHandle;
( void ) pcOverflowingTaskName;
xil_printf( "HALT: Task %s overflowed its stack.", pcOverflowingTaskName );
portDISABLE_INTERRUPTS();
for( ;; );
}
#endif
@@ -0,0 +1,312 @@
/******************************************************************************
*
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Copyright (C) 2014 - 2020 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*
******************************************************************************/
/*****************************************************************************/
/**
* @file asm_vectors.s
*
* This file contains the initial vector table for the Cortex A53 processor
* Currently NEON registers are not saved on stack if interrupt is taken.
* It will be implemented.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ------- -------- ---------------------------------------------------
* 5.00 pkp 5/21/14 Initial version
* </pre>
*
* @note
*
* None.
*
******************************************************************************/
#if defined (versal) && !defined(ARMR5)
#define GICv3
#else
#define GICv2
#endif
.org 0
.text
.globl _boot
.globl _vector_table
.globl _freertos_vector_table
.globl FIQInterrupt
.globl IRQInterrupt
.globl SErrorInterrupt
.globl SynchronousInterrupt
.org 0
.section .vectors, "a"
_vector_table:
.set VBAR, _vector_table
.org VBAR
b _boot
.org (VBAR + 0x80)
b .
.org (VBAR + 0x100)
b .
.org (VBAR + 0x180)
b .
.org (VBAR + 0x200)
b .
.org (VBAR + 0x280)
b .
.org (VBAR + 0x300)
b .
.org (VBAR + 0x380)
b .
.org (VBAR + 0x400)
b .
.org (VBAR + 0x480)
b .
.org (VBAR + 0x500)
b .
.org (VBAR + 0x580)
b .
.org (VBAR + 0x600)
b .
.org (VBAR + 0x680)
b .
.org (VBAR + 0x700)
b .
.org (VBAR + 0x780)
b .
/******************************************************************************
* Vector table to use when FreeRTOS is running.
*****************************************************************************/
.set FREERTOS_VBAR, (VBAR+0x1000)
.org(FREERTOS_VBAR)
_freertos_vector_table:
b FreeRTOS_SWI_Handler
.org (FREERTOS_VBAR + 0x80)
b FreeRTOS_IRQ_Handler
.org (FREERTOS_VBAR + 0x100)
#if defined(GICv3)
b FreeRTOS_IRQ_Handler
#else
b .
#endif
.org (FREERTOS_VBAR + 0x180)
b .
.org (FREERTOS_VBAR + 0x200)
b FreeRTOS_SWI_Handler
.org (FREERTOS_VBAR + 0x280)
b FreeRTOS_IRQ_Handler
.org (FREERTOS_VBAR + 0x300)
b FreeRTOS_IRQ_Handler
.org (FREERTOS_VBAR + 0x380)
b .
.org (FREERTOS_VBAR + 0x400)
b .
.org (FREERTOS_VBAR + 0x480)
b .
.org (FREERTOS_VBAR + 0x500)
b .
.org (FREERTOS_VBAR + 0x580)
b .
.org (FREERTOS_VBAR + 0x600)
b .
.org (FREERTOS_VBAR + 0x680)
b .
.org (FREERTOS_VBAR + 0x700)
b .
.org (FREERTOS_VBAR + 0x780)
b .
.org (FREERTOS_VBAR + 0x800)
SynchronousInterruptHandler:
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]!
bl SynchronousInterrupt
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
IRQInterruptHandler:
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]!
bl IRQInterrupt
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
FIQInterruptHandler:
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]!
bl FIQInterrupt
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
SErrorInterruptHandler:
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]!
bl SErrorInterrupt
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
.end
@@ -0,0 +1,365 @@
/*
* FreeRTOS Kernel V10.3.0
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Copyright (C) 2014 - 2020 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#ifndef PORTMACRO_H
#define PORTMACRO_H
#ifdef __cplusplus
extern "C" {
#endif
/* BSP includes. */
#include "xil_types.h"
#include "xpseudo_asm.h"
#include "FreeRTOSConfig.h"
#if defined (versal) && !defined(ARMR5)
#define GICv3
#else
#define GICv2
#endif
/*-----------------------------------------------------------
* Port specific definitions.
*
* The settings in this file configure FreeRTOS correctly for the given hardware
* and compiler.
*
* These settings should not be altered.
*-----------------------------------------------------------
*/
/* Type definitions. */
#define portCHAR char
#define portFLOAT float
#define portDOUBLE double
#define portLONG long
#define portSHORT short
#define portSTACK_TYPE size_t
#define portBASE_TYPE long
typedef portSTACK_TYPE StackType_t;
typedef portBASE_TYPE BaseType_t;
typedef uint64_t UBaseType_t;
typedef uint64_t TickType_t;
#define portMAX_DELAY ( ( TickType_t ) 0xffffffffffffffff )
/*-----------------------------------------------------------*/
/* Hardware specifics. */
#define portSTACK_GROWTH ( -1 )
#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
#define portBYTE_ALIGNMENT 16
#define portPOINTER_SIZE_TYPE uint64_t
#define portCRITICAL_NESTING_IN_TCB 1
/* Task utilities. */
extern uint64_t ullPortYieldRequired[];
/* Called at the end of an ISR that can cause a context switch. */
#define portEND_SWITCHING_ISR( xSwitchRequired )\
{ \
\
if( xSwitchRequired != pdFALSE ) \
{ \
ullPortYieldRequired[portGET_CORE_ID()] = pdTRUE; \
} \
}
#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )
#if defined( GUEST )
#define portYIELD() __asm volatile ( "SVC 0" ::: "memory" )
#else
#define portYIELD() __asm volatile ( "SMC 0" ::: "memory" )
#endif
static inline UBaseType_t uxDisableInterrupts()
{
unsigned long flags;
__asm volatile (
"mrs %0, daif\n"
"msr daifset, #2\n"
: "=r" (flags)
:
: "memory"
);
return flags;
}
static inline void vEnableInterrupts()
{
__asm volatile (
"msr daifclr, #2\n"
:
:
: "memory"
);
}
static inline void vRestoreInterrupts(UBaseType_t flags)
{
__asm volatile (
"and x2, %0, #128\n"
"mrs x1, daif\n"
"bic x1, x1, #128\n"
"orr x1, x1, x2\n"
"msr daif, x1\n"
:
: "r" (flags)
: "x0","x1","x2","memory"
);
}
static inline BaseType_t xPortGetCoreID()
{
register BaseType_t xCoreID;
__asm volatile (
"mrs x0, mpidr_el1\n"
"and %0, x0, #0xff\n"
: "=r" (xCoreID)
:
: "memory", "x0"
);
return xCoreID;
}
/*-----------------------------------------------------------
* Critical section control
*----------------------------------------------------------*/
extern void vTaskEnterCritical( void );
extern void vTaskExitCritical( void );
extern UBaseType_t vTaskEnterCriticalFromISR( void );
extern void vTaskExitCriticalFromISR( UBaseType_t uxSavedInterruptStatus );
#define portENTER_CRITICAL() vTaskEnterCritical();
#define portEXIT_CRITICAL() vTaskExitCritical();
#define portENTER_CRITICAL_FROM_ISR() vTaskEnterCriticalFromISR()
#define portEXIT_CRITICAL_FROM_ISR( x ) vTaskExitCriticalFromISR( x )
#define portDISABLE_INTERRUPTS() uxDisableInterrupts()
#define portENABLE_INTERRUPTS() vEnableInterrupts()
#define portSET_INTERRUPT_MASK() uxDisableInterrupts()
#define portCLEAR_INTERRUPT_MASK(x) vRestoreInterrupts(x)
#define portHAS_NESTED_INTERRUPTS 1
UBaseType_t uxPortSetInterruptMask( void );
void vPortClearInterruptMask( UBaseType_t );
#define portSET_INTERRUPT_MASK_FROM_ISR() uxPortSetInterruptMask()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortClearInterruptMask(x)
/* Task function macros as described on the FreeRTOS.org WEB site. These are
not required for this port but included in case common demo code that uses these
macros is used. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
/* Prototype of the FreeRTOS tick handler. This must be installed as the
handler for whichever peripheral is used to generate the RTOS tick. */
void FreeRTOS_Tick_Handler( void );
/*
* Installs pxHandler as the interrupt handler for the peripheral specified by
* the ucInterruptID parameter.
*
* ucInterruptID:
*
* The ID of the peripheral that will have pxHandler assigned as its interrupt
* handler. Peripheral IDs are defined in the xparameters.h header file, which
* is itself part of the BSP project.
*
* pxHandler:
*
* A pointer to the interrupt handler function itself. This must be a void
* function that takes a (void *) parameter.
*
* pvCallBackRef:
*
* The parameter passed into the handler function. In many cases this will not
* be used and can be NULL. Some times it is used to pass in a reference to
* the peripheral instance variable, so it can be accessed from inside the
* handler function.
*
* pdPASS is returned if the function executes successfully. Any other value
* being returned indicates that the function did not execute correctly.
*/
BaseType_t xPortInstallInterruptHandler( uint8_t ucInterruptID, XInterruptHandler pxHandler, void *pvCallBackRef );
/*
* Enables the interrupt, within the interrupt controller, for the peripheral
* specified by the ucInterruptID parameter.
*
* ucInterruptID:
*
* The ID of the peripheral that will have its interrupt enabled in the
* interrupt controller. Peripheral IDs are defined in the xparameters.h header
* file, which is itself part of the BSP project.
*/
void vPortEnableInterrupt( uint8_t ucInterruptID );
/*
* Disables the interrupt, within the interrupt controller, for the peripheral
* specified by the ucInterruptID parameter.
*
* ucInterruptID:
*
* The ID of the peripheral that will have its interrupt disabled in the
* interrupt controller. Peripheral IDs are defined in the xparameters.h header
* file, which is itself part of the BSP project.
*/
void vPortDisableInterrupt( uint8_t ucInterruptID );
/* Any task that uses the floating point unit MUST call vPortTaskUsesFPU()
before any floating point instructions are executed. */
#if( configUSE_TASK_FPU_SUPPORT != 2 )
void vPortTaskUsesFPU( void );
#else
/* Each task has an FPU context already, so define this function away to
* nothing to prevent it being called accidentally. */
#define vPortTaskUsesFPU()
#endif
#define portTASK_USES_FLOATING_POINT() vPortTaskUsesFPU()
#define portLOWEST_INTERRUPT_PRIORITY ( ( ( uint32_t ) configUNIQUE_INTERRUPT_PRIORITIES ) - 1UL )
#define portLOWEST_USABLE_INTERRUPT_PRIORITY ( portLOWEST_INTERRUPT_PRIORITY - 1UL )
/* Architecture specific optimisations. */
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
#endif
#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1
/* Store/clear the ready priorities in a bit map. */
#define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) )
#define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )
/*-----------------------------------------------------------*/
#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31 - __builtin_clz( uxReadyPriorities ) )
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
#ifdef configASSERT
void vPortValidateInterruptPriority( void );
#define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() vPortValidateInterruptPriority()
#endif /* configASSERT */
#define portNOP() __asm volatile( "NOP" )
#define portMEMORY_BARRIER() __asm volatile( "" ::: "memory" )
/* port for SMP */
#define portGET_CORE_ID() xPortGetCoreID()
static inline void vAssertIfInIsr()
{
extern volatile uint64_t uxCoreInIsr[configNUMBER_OF_CORES];
UBaseType_t x = uxDisableInterrupts();
BaseType_t xCoreId = xPortGetCoreID();
configASSERT(uxCoreInIsr[xCoreId] == 0);
vRestoreInterrupts(x);
}
#define portASSERT_IF_IN_ISR() vAssertIfInIsr()
/*-----------------------------------------------------------
* Critical section locks
*----------------------------------------------------------*/
#define ISR_LOCK (0u)
#define TASK_LOCK (1u)
extern void vPortRecursiveLock(BaseType_t xCoreID, uint32_t ulLockNum, BaseType_t uxAcquire);
#define portRELEASE_ISR_LOCK( xCoreID ) vPortRecursiveLock(( xCoreID ), ISR_LOCK, pdFALSE)
#define portGET_ISR_LOCK( xCoreID ) vPortRecursiveLock(( xCoreID ), ISR_LOCK, pdTRUE)
#define portRELEASE_TASK_LOCK( xCoreID ) vPortRecursiveLock(( xCoreID ), TASK_LOCK, pdFALSE)
#define portGET_TASK_LOCK( xCoreID ) vPortRecursiveLock(( xCoreID ), TASK_LOCK, pdTRUE)
extern void vInterruptCore(uint32_t ulInterruptID, uint32_t ulCoreID);
/* Use PPI 0 as the yield core interrupt. */
#define portYIELD_CORE_INT_ID 0
#define portYIELD_CORE( xCoreID ) vInterruptCore(portYIELD_CORE_INT_ID, (uint32_t)xCoreID)
/* The number of bits to shift for an interrupt priority is dependent on the
number of bits implemented by the interrupt controller. */
#if configUNIQUE_INTERRUPT_PRIORITIES == 16
#define portPRIORITY_SHIFT 4
#define portMAX_BINARY_POINT_VALUE 3
#elif configUNIQUE_INTERRUPT_PRIORITIES == 32
#define portPRIORITY_SHIFT 3
#define portMAX_BINARY_POINT_VALUE 2
#elif configUNIQUE_INTERRUPT_PRIORITIES == 64
#define portPRIORITY_SHIFT 2
#define portMAX_BINARY_POINT_VALUE 1
#elif configUNIQUE_INTERRUPT_PRIORITIES == 128
#define portPRIORITY_SHIFT 1
#define portMAX_BINARY_POINT_VALUE 0
#elif configUNIQUE_INTERRUPT_PRIORITIES == 256
#define portPRIORITY_SHIFT 0
#define portMAX_BINARY_POINT_VALUE 0
#else
#error Invalid configUNIQUE_INTERRUPT_PRIORITIES setting. configUNIQUE_INTERRUPT_PRIORITIES must be set to the number of unique priorities implemented by the target hardware
#endif
#if defined(GICv2)
/* Interrupt controller access addresses. */
#define portICCPMR_PRIORITY_MASK_OFFSET ( 0x04 )
#define portICCIAR_INTERRUPT_ACKNOWLEDGE_OFFSET ( 0x0C )
#define portICCEOIR_END_OF_INTERRUPT_OFFSET ( 0x10 )
#define portICCBPR_BINARY_POINT_OFFSET ( 0x08 )
#define portICCRPR_RUNNING_PRIORITY_OFFSET ( 0x14 )
#define portICD_SGIR_OFFSET ( 0xF00 )
#define portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS ( configINTERRUPT_CONTROLLER_BASE_ADDRESS + configINTERRUPT_CONTROLLER_CPU_INTERFACE_OFFSET )
#define portICCPMR_PRIORITY_MASK_REGISTER ( *( ( volatile uint32_t * ) ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCPMR_PRIORITY_MASK_OFFSET ) ) )
#define portICCIAR_INTERRUPT_ACKNOWLEDGE_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCIAR_INTERRUPT_ACKNOWLEDGE_OFFSET )
#define portICCEOIR_END_OF_INTERRUPT_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCEOIR_END_OF_INTERRUPT_OFFSET )
#define portICCPMR_PRIORITY_MASK_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCPMR_PRIORITY_MASK_OFFSET )
#define portICCBPR_BINARY_POINT_REGISTER ( *( ( const volatile uint32_t * ) ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCBPR_BINARY_POINT_OFFSET ) ) )
#define portICCRPR_RUNNING_PRIORITY_REGISTER ( *( ( const volatile uint32_t * ) ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCRPR_RUNNING_PRIORITY_OFFSET ) ) )
#define portICD_SGIR_ADDRESS ( configINTERRUPT_CONTROLLER_BASE_ADDRESS + portICD_SGIR_OFFSET )
#endif
#endif /* PORTMACRO_H */
#ifdef __cplusplus
} /* extern C */
#endif
@@ -0,0 +1,317 @@
/*
* FreeRTOS Kernel V10.4.2
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/* Standard includes. */
#include <stdlib.h>
#include <signal.h>
#include <msp430.h>
/* Scheduler includes. */
#include "FreeRTOS.h"
#include "task.h"
/*-----------------------------------------------------------
* Implementation of functions defined in portable.h for the MSP430 port.
*----------------------------------------------------------*/
/* Constants required for hardware setup. The tick ISR runs off the ACLK,
not the MCLK. */
#define portACLK_FREQUENCY_HZ ( ( TickType_t ) 32768 )
#define portINITIAL_CRITICAL_NESTING ( ( uint16_t ) 10 )
#define portFLAGS_INT_ENABLED ( ( StackType_t ) 0x08 )
/* We require the address of the pxCurrentTCB variable, but don't want to know
any details of its type. */
typedef void TCB_t;
extern volatile TCB_t * volatile pxCurrentTCB;
/* Most ports implement critical sections by placing the interrupt flags on
the stack before disabling interrupts. Exiting the critical section is then
simply a case of popping the flags from the stack. As mspgcc does not use
a frame pointer this cannot be done as modifying the stack will clobber all
the stack variables. Instead each task maintains a count of the critical
section nesting depth. Each time a critical section is entered the count is
incremented. Each time a critical section is left the count is decremented -
with interrupts only being re-enabled if the count is zero.
usCriticalNesting will get set to zero when the scheduler starts, but must
not be initialised to zero as this will cause problems during the startup
sequence. */
volatile uint16_t usCriticalNesting = portINITIAL_CRITICAL_NESTING;
/*-----------------------------------------------------------*/
/*
* Macro to save a task context to the task stack. This simply pushes all the
* general purpose msp430 registers onto the stack, followed by the
* usCriticalNesting value used by the task. Finally the resultant stack
* pointer value is saved into the task control block so it can be retrieved
* the next time the task executes.
*/
#ifdef __LARGE_DATA_MODEL__
#define portSAVE_CONTEXT() \
asm volatile ( "pushm.a #12, r15 \n\t" \
"movx.w &usCriticalNesting, r14 \n\t" \
"pushm.a #1, r14 \n\t" \
"movx.a &pxCurrentTCB, r12 \n\t" \
"movx.a sp, 0(r12) \n\t" \
);
#else
#define portSAVE_CONTEXT() \
asm volatile ( "pushm.w #12, r15 \n\t" \
"mov.w &usCriticalNesting, r14 \n\t" \
"push.w r14 \n\t" \
"mov.w &pxCurrentTCB, r12 \n\t" \
"mov.w sp, 0(r12) \r\t" \
);
#endif
/*
* Macro to restore a task context from the task stack. This is effectively
* the reverse of portSAVE_CONTEXT(). First the stack pointer value is
* loaded from the task control block. Next the value for usCriticalNesting
* used by the task is retrieved from the stack - followed by the value of all
* the general purpose msp430 registers.
*
*/
#ifdef __LARGE_DATA_MODEL__
#define portRESTORE_CONTEXT() \
asm volatile ( "movx.a &pxCurrentTCB, r12 \n\t" \
"movx.a @r12, sp \n\t" \
"popm.a #1, r15 \n\t" \
"movx.w r15, &usCriticalNesting \n\t" \
"popm.a #12, r15 \n\t" \
"nop \n\t" \
"pop.w sr \n\t" \
"nop \n\t" \
"reta \n\t" \
);
#else
#define portRESTORE_CONTEXT() \
asm volatile ( "mov.w &pxCurrentTCB, r12 \n\t" \
"mov.w @r12, sp \n\t" \
"pop.w r15 \n\t" \
"mov.w r15, &usCriticalNesting \n\t" \
"popm.w #12, r15 \n\t" \
"nop \n\t" \
"pop.w sr \n\t" \
"nop \n\t" \
"ret \n\t" \
);
#endif
/*-----------------------------------------------------------*/
/*
* Sets up the periodic ISR used for the RTOS tick. This uses timer 0, but
* could have alternatively used the watchdog timer or timer 1.
*/
static void prvSetupTimerInterrupt( void );
/*-----------------------------------------------------------*/
/*
* Initialise the stack of a task to look exactly as if a call to
* portSAVE_CONTEXT had been called.
*
* See the header file portable.h.
*/
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
{
uint16_t *pusTopOfStack;
uint32_t *pulTopOfStack, ulTemp;
/*
Place a few bytes of known values on the bottom of the stack.
This is just useful for debugging and can be included if required.
*pxTopOfStack = ( StackType_t ) 0x1111;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 0x2222;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 0x3333;
pxTopOfStack--;
*/
/* Data types are need either 16 bits or 32 bits depending on the data
and code model used. */
if( sizeof( pxCode ) == sizeof( uint16_t ) )
{
pusTopOfStack = ( uint16_t * ) pxTopOfStack;
ulTemp = ( uint32_t ) pxCode;
*pusTopOfStack = ( uint16_t ) ulTemp;
}
else
{
/* Make room for a 20 bit value stored as a 32 bit value. */
pusTopOfStack = ( uint16_t * ) pxTopOfStack;
pusTopOfStack--;
pulTopOfStack = ( uint32_t * ) pusTopOfStack;
*pulTopOfStack = ( uint32_t ) pxCode;
}
pusTopOfStack--;
*pusTopOfStack = portFLAGS_INT_ENABLED;
pusTopOfStack -= ( sizeof( StackType_t ) / 2 );
/* From here on the size of stacked items depends on the memory model. */
pxTopOfStack = ( StackType_t * ) pusTopOfStack;
/* Next the general purpose registers. */
#ifdef PRELOAD_REGISTER_VALUES
*pxTopOfStack = ( StackType_t ) 0xffff;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 0xeeee;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 0xdddd;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) pvParameters;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 0xbbbb;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 0xaaaa;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 0x9999;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 0x8888;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 0x7777;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 0x6666;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 0x5555;
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) 0x4444;
pxTopOfStack--;
#else
pxTopOfStack -= 3;
*pxTopOfStack = ( StackType_t ) pvParameters;
pxTopOfStack -= 9;
#endif
/* A variable is used to keep track of the critical section nesting.
This variable has to be stored as part of the task context and is
initially set to zero. */
*pxTopOfStack = ( StackType_t ) portNO_CRITICAL_SECTION_NESTING;
/* Return a pointer to the top of the stack we have generated so this can
be stored in the task control block for the task. */
return pxTopOfStack;
}
/*-----------------------------------------------------------*/
BaseType_t xPortStartScheduler( void )
{
/* Setup the hardware to generate the tick. Interrupts are disabled when
this function is called. */
prvSetupTimerInterrupt();
/* Restore the context of the first task that is going to run. */
portRESTORE_CONTEXT();
/* Should not get here as the tasks are now running! */
return pdTRUE;
}
/*-----------------------------------------------------------*/
void vPortEndScheduler( void )
{
/* It is unlikely that the MSP430 port will get stopped. If required simply
disable the tick interrupt here. */
}
/*-----------------------------------------------------------*/
/*
* Manual context switch called by portYIELD or taskYIELD.
*
* The first thing we do is save the registers so we can use a naked attribute.
*/
void vPortYield( void ) __attribute__ ( ( naked ) );
void vPortYield( void )
{
asm volatile ( "push.w sr" );
portDISABLE_INTERRUPTS();
portSAVE_CONTEXT();
vTaskSwitchContext();
portRESTORE_CONTEXT();
}
/*-----------------------------------------------------------*/
/*
* Hardware initialisation to generate the RTOS tick. This uses timer 0
* but could alternatively use the watchdog timer or timer 1.
*/
static void prvSetupTimerInterrupt( void )
{
vApplicationSetupTimerInterrupt();
}
/*-----------------------------------------------------------*/
/*
* The interrupt service routine used depends on whether the pre-emptive
* scheduler is being used or not.
*/
#if configUSE_PREEMPTION == 1
void vPortPreemptiveTickISR(void)
{
asm volatile("push.w sr");
portSAVE_CONTEXT();
if(xTaskIncrementTick() != pdFALSE)
{
vTaskSwitchContext();
}
portRESTORE_CONTEXT();
}
__attribute__((interrupt(configTICK_VECTOR))) void prvTickISR(void)
{
__bic_SR_register_on_exit( SCG1 + SCG0 + OSCOFF + CPUOFF );
vPortPreemptiveTickISR();
}
#else
void vPortCooperativeTickISR(void)
{
asm volatile("push.w sr");
portSAVE_CONTEXT();
xTaskIncrementTick();
portRESTORE_CONTEXT();
}
__attribute__((interrupt(configTICK_VECTOR))) void prvTickISR(void)
{
__bic_SR_register_on_exit( SCG1 + SCG0 + OSCOFF + CPUOFF );
vPortCooperativeTickISR();
}
#endif
@@ -0,0 +1,132 @@
/*
* FreeRTOS Kernel V10.4.2
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
#ifndef PORTMACRO_H
#define PORTMACRO_H
/*-----------------------------------------------------------
* Port specific definitions.
*
* The settings in this file configure FreeRTOS correctly for the
* given hardware and compiler.
*
* These settings should not be altered.
*-----------------------------------------------------------
*/
/* Hardware includes. */
#include <msp430.h>
/* Type definitions. */
#define portCHAR char
#define portFLOAT float
#define portDOUBLE double
#define portLONG long
#define portSHORT int
#define portBASE_TYPE short
/* The stack type changes depending on the data model. */
#ifdef __LARGE_DATA_MODEL__
#define portSTACK_TYPE uint32_t
#else
#define portSTACK_TYPE uint16_t
#define portPOINTER_SIZE_TYPE uint16_t
#endif
typedef portSTACK_TYPE StackType_t;
typedef short BaseType_t;
typedef unsigned short UBaseType_t;
#if( configUSE_16_BIT_TICKS == 1 )
typedef uint16_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffff
#else
typedef uint32_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
#endif
/*-----------------------------------------------------------*/
/* Interrupt control macros. */
#define portDISABLE_INTERRUPTS() asm volatile ( "NOP" ); asm volatile ( "DINT" ); asm volatile ( "NOP" )
#define portENABLE_INTERRUPTS() asm volatile ( "NOP" ); asm volatile ( "EINT" ); asm volatile ( "NOP" )
/*-----------------------------------------------------------*/
/* Critical section control macros. */
#define portNO_CRITICAL_SECTION_NESTING ( ( uint16_t ) 0 )
#define portENTER_CRITICAL() \
{ \
extern volatile uint16_t usCriticalNesting; \
\
portDISABLE_INTERRUPTS(); \
\
/* Now interrupts are disabled ulCriticalNesting can be accessed */ \
/* directly. Increment ulCriticalNesting to keep a count of how many */ \
/* times portENTER_CRITICAL() has been called. */ \
usCriticalNesting++; \
}
#define portEXIT_CRITICAL() \
{ \
extern volatile uint16_t usCriticalNesting; \
\
if( usCriticalNesting > portNO_CRITICAL_SECTION_NESTING ) \
{ \
/* Decrement the nesting count as we are leaving a critical section. */ \
usCriticalNesting--; \
\
/* If the nesting level has reached zero then interrupts should be */ \
/* re-enabled. */ \
if( usCriticalNesting == portNO_CRITICAL_SECTION_NESTING ) \
{ \
portENABLE_INTERRUPTS(); \
} \
} \
}
/*-----------------------------------------------------------*/
/* Task utilities. */
extern void vPortYield( void ) __attribute__ ( ( naked ) );
#define portYIELD() vPortYield()
#define portNOP() asm volatile ( "NOP" )
/*-----------------------------------------------------------*/
/* Hardware specifics. */
#define portBYTE_ALIGNMENT 2
#define portSTACK_GROWTH ( -1 )
#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
/*-----------------------------------------------------------*/
/* Task function macros as described on the FreeRTOS.org WEB site. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
extern void vTaskSwitchContext(void);
#define portYIELD_FROM_ISR( x ) if( x ) vPortYield()
void vApplicationSetupTimerInterrupt( void );
#endif /* PORTMACRO_H */
@@ -0,0 +1,210 @@
/*
* FreeRTOS Kernel V10.4.0
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
* 1 tab == 4 spaces!
*/
/*
* The FreeRTOS kernel's RISC-V port is split between the the code that is
* common across all currently supported RISC-V chips (implementations of the
* RISC-V ISA), and code that tailors the port to a specific RISC-V chip:
*
* + FreeRTOS\Source\portable\GCC\RISC-V-RV32\portASM.S contains the code that
* is common to all currently supported RISC-V chips. There is only one
* portASM.S file because the same file is built for all RISC-V target chips.
*
* + Header files called freertos_risc_v_chip_specific_extensions.h contain the
* code that tailors the FreeRTOS kernel's RISC-V port to a specific RISC-V
* chip. There are multiple freertos_risc_v_chip_specific_extensions.h files
* as there are multiple RISC-V chip implementations.
*
* !!!NOTE!!!
* TAKE CARE TO INCLUDE THE CORRECT freertos_risc_v_chip_specific_extensions.h
* HEADER FILE FOR THE CHIP IN USE. This is done using the assembler's (not the
* compiler's!) include path. For example, if the chip in use includes a core
* local interrupter (CLINT) and does not include any chip specific register
* extensions then add the path below to the assembler's include path:
* FreeRTOS\Source\portable\GCC\RISC-V-RV32\chip_specific_extensions\RV32I_CLINT_no_extensions
*
*/
#ifndef __FREERTOS_RISC_V_EXTENSIONS_H__
#define __FREERTOS_RISC_V_EXTENSIONS_H__
#define portasmHANDLE_INTERRUPT Default_IRQHandler
#define portasmHAS_SIFIVE_CLINT 1
#define portasmHAS_MTIME 0
#define portasmADDITIONAL_CONTEXT_SIZE 0 /* Must be even number on 32-bit cores. */
.macro portasmSAVE_ADDITIONAL_REGISTERS
/* save float registers */
#if __riscv_flen == 64
addi sp, sp, -(128+128)
fsd f31, (0 + 0 )(sp)
fsd f30, (4 + 4 )(sp)
fsd f29, (8 + 8 )(sp)
fsd f28, (12 + 12)(sp)
fsd f27, (16 + 16)(sp)
fsd f26, (20 + 20)(sp)
fsd f25, (24 + 24)(sp)
fsd f24, (28 + 28)(sp)
fsd f23, (32 + 32)(sp)
fsd f22, (36 + 36)(sp)
fsd f21, (40 + 40)(sp)
fsd f20, (44 + 44)(sp)
fsd f19, (48 + 48)(sp)
fsd f18, (52 + 52)(sp)
fsd f17, (56 + 56)(sp)
fsd f16, (60 + 60)(sp)
fsd f15, (64 + 64)(sp)
fsd f14, (68 + 68)(sp)
fsd f13, (72 + 72)(sp)
fsd f12, (76 + 76)(sp)
fsd f11, (80 + 80)(sp)
fsd f10, (84 + 84)(sp)
fsd f9, (88 + 88)(sp)
fsd f8, (92 + 92)(sp)
fsd f7, (96 + 96)(sp)
fsd f6, (100+100)(sp)
fsd f5, (104+104)(sp)
fsd f4, (108+108)(sp)
fsd f3, (112+112)(sp)
fsd f2, (116+116)(sp)
fsd f1, (120+120)(sp)
fsd f0, (124+124)(sp)
#elif __riscv_flen == 32
addi sp, sp, -(128)
fsw f31, (0 )(sp)
fsw f30, (4 )(sp)
fsw f29, (8 )(sp)
fsw f28, (12 )(sp)
fsw f27, (16 )(sp)
fsw f26, (20 )(sp)
fsw f25, (24 )(sp)
fsw f24, (28 )(sp)
fsw f23, (32 )(sp)
fsw f22, (36 )(sp)
fsw f21, (40 )(sp)
fsw f20, (44 )(sp)
fsw f19, (48 )(sp)
fsw f18, (52 )(sp)
fsw f17, (56 )(sp)
fsw f16, (60 )(sp)
fsw f15, (64 )(sp)
fsw f14, (68 )(sp)
fsw f13, (72 )(sp)
fsw f12, (76 )(sp)
fsw f11, (80 )(sp)
fsw f10, (84 )(sp)
fsw f9, (88 )(sp)
fsw f8, (92 )(sp)
fsw f7, (96 )(sp)
fsw f6, (100)(sp)
fsw f5, (104)(sp)
fsw f4, (108)(sp)
fsw f3, (112)(sp)
fsw f2, (116)(sp)
fsw f1, (120)(sp)
fsw f0, (124)(sp)
#endif
.endm
.macro portasmRESTORE_ADDITIONAL_REGISTERS
/* load float registers */
#if __riscv_flen == 64
fld f31, (0 + 0 )(sp)
fld f30, (4 + 4 )(sp)
fld f29, (8 + 8 )(sp)
fld f28, (12 + 12)(sp)
fld f27, (16 + 16)(sp)
fld f26, (20 + 20)(sp)
fld f25, (24 + 24)(sp)
fld f24, (28 + 28)(sp)
fld f23, (32 + 32)(sp)
fld f22, (36 + 36)(sp)
fld f21, (40 + 40)(sp)
fld f20, (44 + 44)(sp)
fld f19, (48 + 48)(sp)
fld f18, (52 + 52)(sp)
fld f17, (56 + 56)(sp)
fld f16, (60 + 60)(sp)
fld f15, (64 + 64)(sp)
fld f14, (68 + 68)(sp)
fld f13, (72 + 72)(sp)
fld f12, (76 + 76)(sp)
fld f11, (80 + 80)(sp)
fld f10, (84 + 84)(sp)
fld f9, (88 + 88)(sp)
fld f8, (92 + 92)(sp)
fld f7, (96 + 96)(sp)
fld f6, (100+100)(sp)
fld f5, (104+104)(sp)
fld f4, (108+108)(sp)
fld f3, (112+112)(sp)
fld f2, (116+116)(sp)
fld f1, (120+120)(sp)
fld f0, (124+124)(sp)
addi sp, sp, (128+128)
#elif __riscv_flen == 32
flw f31, (0 )(sp)
flw f30, (4 )(sp)
flw f29, (8 )(sp)
flw f28, (12 )(sp)
flw f27, (16 )(sp)
flw f26, (20 )(sp)
flw f25, (24 )(sp)
flw f24, (28 )(sp)
flw f23, (32 )(sp)
flw f22, (36 )(sp)
flw f21, (40 )(sp)
flw f20, (44 )(sp)
flw f19, (48 )(sp)
flw f18, (52 )(sp)
flw f17, (56 )(sp)
flw f16, (60 )(sp)
flw f15, (64 )(sp)
flw f14, (68 )(sp)
flw f13, (72 )(sp)
flw f12, (76 )(sp)
flw f11, (80 )(sp)
flw f10, (84 )(sp)
flw f9, (88 )(sp)
flw f8, (92 )(sp)
flw f7, (96 )(sp)
flw f6, (100)(sp)
flw f5, (104)(sp)
flw f4, (108)(sp)
flw f3, (112)(sp)
flw f2, (116)(sp)
flw f1, (120)(sp)
flw f0, (124)(sp)
addi sp, sp, (128)
#endif
.endm
#endif /* __FREERTOS_RISC_V_EXTENSIONS_H__ */
@@ -0,0 +1,50 @@
cmake_minimum_required(VERSION 3.13)
if (NOT TARGET _FreeRTOS_kernel_inclusion_marker)
add_library(_FreeRTOS_kernel_inclusion_marker INTERFACE)
# Pull in PICO SDK (must be before project)
include(pico_sdk_import.cmake)
if (PICO_SDK_VERSION_STRING VERSION_LESS "2.0.0")
message(FATAL_ERROR "Require at least Raspberry Pi Pico SDK version 2.0.0")
endif()
if (NOT FREERTOS_KERNEL_PATH)
get_filename_component(FREERTOS_KERNEL_PATH ${CMAKE_CURRENT_LIST_DIR}/../../../.. REALPATH)
endif ()
message(DEBUG "FREERTOS_KERNEL_PATH is ${FREERTOS_KERNEL_PATH}")
project(FreeRTOS-Kernel C CXX)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
pico_is_top_level_project(FREERTOS_KERNEL_TOP_LEVEL_PROJECT)
# if the SDK has already been initialized, then just add our libraries now - this allows
# this FreeRTOS port to just be added as a sub-directory or include within another project, rather than
# having to include it at the top level before pico_sdk_init()
if (TARGET _pico_sdk_inclusion_marker)
if (PICO_SDK_VERSION_STRING VERSION_LESS "1.3.2")
message(FATAL_ERROR "Require at least Raspberry Pi Pico SDK version 1.3.2 to include FreeRTOS after pico_sdk_init()")
endif()
include(${CMAKE_CURRENT_LIST_DIR}/library.cmake)
else()
# The real work gets done in library.cmake which is called at the end of pico_sdk_init
list(APPEND PICO_SDK_POST_LIST_FILES ${CMAKE_CURRENT_LIST_DIR}/library.cmake)
if (PICO_SDK_VERSION_STRING VERSION_LESS "1.3.2")
# We need to inject the following header file into ALL SDK files (which we do via the config header)
list(APPEND PICO_CONFIG_HEADER_FILES ${CMAKE_CURRENT_LIST_DIR}/include/freertos_sdk_config.h)
endif()
if (FREERTOS_KERNEL_TOP_LEVEL_PROJECT)
message("FreeRTOS: initialize SDK since we're the top-level")
# Initialize the SDK
pico_sdk_init()
else()
set(FREERTOS_KERNEL_PATH ${FREERTOS_KERNEL_PATH} PARENT_SCOPE)
set(PICO_CONFIG_HEADER_FILES ${PICO_CONFIG_HEADER_FILES} PARENT_SCOPE)
set(PICO_SDK_POST_LIST_FILES ${PICO_SDK_POST_LIST_FILES} PARENT_SCOPE)
endif()
endif()
endif()
@@ -0,0 +1,91 @@
# This is a copy of <FREERTOS_KERNEL_PATH>/portable/ThirdParty/GCC/RP2040/FREERTOS_KERNEL_import.cmake
# This can be dropped into an external project to help locate the FreeRTOS kernel
# It should be include()ed prior to project(). Alternatively this file may
# or the CMakeLists.txt in this directory may be included or added via add_subdirectory
# respectively.
if (DEFINED ENV{FREERTOS_KERNEL_PATH} AND (NOT FREERTOS_KERNEL_PATH))
set(FREERTOS_KERNEL_PATH $ENV{FREERTOS_KERNEL_PATH})
message("Using FREERTOS_KERNEL_PATH from environment ('${FREERTOS_KERNEL_PATH}')")
endif ()
# first pass we look in old tree; second pass we look in new tree
foreach(SEARCH_PASS RANGE 0 1)
if (SEARCH_PASS)
# ports may be moving to submodule in the future
set(FREERTOS_KERNEL_RP2040_RELATIVE_PATH "portable/ThirdParty/Community-Supported-Ports/GCC")
set(FREERTOS_KERNEL_RP2040_BACK_PATH "../../../../..")
else()
set(FREERTOS_KERNEL_RP2040_RELATIVE_PATH "portable/ThirdParty/GCC")
set(FREERTOS_KERNEL_RP2040_BACK_PATH "../../../..")
endif()
if(PICO_PLATFORM STREQUAL "rp2040")
set(FREERTOS_KERNEL_RP2040_RELATIVE_PATH "${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}/RP2040")
else()
if (PICO_PLATFORM STREQUAL "rp2350-riscv")
set(FREERTOS_KERNEL_RP2040_RELATIVE_PATH "${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}/RP2350_RISC-V")
else()
set(FREERTOS_KERNEL_RP2040_RELATIVE_PATH "${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}/RP2350_ARM_NTZ")
endif()
endif()
if (NOT FREERTOS_KERNEL_PATH)
# check if we are inside the FreeRTOS kernel tree (i.e. this file has been included directly)
get_filename_component(_ACTUAL_PATH ${CMAKE_CURRENT_LIST_DIR} REALPATH)
get_filename_component(_POSSIBLE_PATH ${CMAKE_CURRENT_LIST_DIR}/${FREERTOS_KERNEL_RP2040_BACK_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH} REALPATH)
if (_ACTUAL_PATH STREQUAL _POSSIBLE_PATH)
get_filename_component(FREERTOS_KERNEL_PATH ${CMAKE_CURRENT_LIST_DIR}/${FREERTOS_KERNEL_RP2040_BACK_PATH} REALPATH)
endif()
if (_ACTUAL_PATH STREQUAL _POSSIBLE_PATH)
get_filename_component(FREERTOS_KERNEL_PATH ${CMAKE_CURRENT_LIST_DIR}/${FREERTOS_KERNEL_RP2040_BACK_PATH} REALPATH)
message("Setting FREERTOS_KERNEL_PATH to ${FREERTOS_KERNEL_PATH} based on location of FreeRTOS-Kernel-import.cmake")
break()
elseif (PICO_SDK_PATH AND EXISTS "${PICO_SDK_PATH}/../FreeRTOS-Kernel")
set(FREERTOS_KERNEL_PATH ${PICO_SDK_PATH}/../FreeRTOS-Kernel)
message("Defaulting FREERTOS_KERNEL_PATH as sibling of PICO_SDK_PATH: ${FREERTOS_KERNEL_PATH}")
break()
endif()
endif ()
if (NOT FREERTOS_KERNEL_PATH)
foreach(POSSIBLE_SUFFIX Source FreeRTOS-Kernel FreeRTOS/Source)
# check if FreeRTOS-Kernel exists under directory that included us
set(SEARCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR})
get_filename_component(_POSSIBLE_PATH ${SEARCH_ROOT}/${POSSIBLE_SUFFIX} REALPATH)
if (EXISTS ${_POSSIBLE_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}/CMakeLists.txt)
get_filename_component(FREERTOS_KERNEL_PATH ${_POSSIBLE_PATH} REALPATH)
message("Setting FREERTOS_KERNEL_PATH to '${FREERTOS_KERNEL_PATH}' found relative to enclosing project")
break()
endif()
endforeach()
if (FREERTOS_KERNEL_PATH)
break()
endif()
endif()
# user must have specified
if (FREERTOS_KERNEL_PATH)
if (EXISTS "${FREERTOS_KERNEL_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}")
break()
endif()
endif()
endforeach ()
if (NOT FREERTOS_KERNEL_PATH)
message(FATAL_ERROR "FreeRTOS location was not specified. Please set FREERTOS_KERNEL_PATH.")
endif()
set(FREERTOS_KERNEL_PATH "${FREERTOS_KERNEL_PATH}" CACHE PATH "Path to the FreeRTOS Kernel")
get_filename_component(FREERTOS_KERNEL_PATH "${FREERTOS_KERNEL_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
if (NOT EXISTS ${FREERTOS_KERNEL_PATH})
message(FATAL_ERROR "Directory '${FREERTOS_KERNEL_PATH}' not found")
endif()
if (NOT EXISTS ${FREERTOS_KERNEL_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}/CMakeLists.txt)
message(FATAL_ERROR "Directory '${FREERTOS_KERNEL_PATH}' does not contain a '${PICO_PLATFORM}' port here: ${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}")
endif()
set(FREERTOS_KERNEL_PATH ${FREERTOS_KERNEL_PATH} CACHE PATH "Path to the FreeRTOS_KERNEL" FORCE)
add_subdirectory(${FREERTOS_KERNEL_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH} FREERTOS_KERNEL)
@@ -0,0 +1,23 @@
BSD-3-Clause License
Copyright (c) 2020-2021 Raspberry Pi (Trading) Ltd.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,67 @@
## Overview
This directory provides an SMP FreeRTOS-Kernel port that can be used with the Raspberry Pi Pico SDK on RP2350. It supports:
* Simple CMake INTERFACE libraries, to provide the FreeRTOS-Kernel and also the individual allocator types, without copying code into the user's project.
* Running the FreeRTOS-Kernel and tasks on either core 0 or core 1, or both.
* Use of SDK synchronization primitives (such as mutexes, semaphores, queues from pico_sync) between FreeRTOS tasks and code executing on a non FreeRTOS core, or in IRQ handlers.
Note that whilst this SMP version can be run on just a single (either) core, it is probably
more efficient to use the non SMP version in the main FreeRTOS-Kernel branch in that case.
## Using this port
You can copy [FreeRTOS_Kernel_import.cmake](FreeRTOS_Kernel_import.cmake) into your project, and
add the following in your `CMakeLists.txt`:
```cmake
include(FreeRTOS_Kernel_import.cmake)
```
This will locate the FreeRTOS kernel if it is a direct sub-module of your project, or if you provide the
`FREERTOS_KERNEL_PATH` variable in your environment or via `-DFREERTOS_KERNEL_PATH=/path/to/FreeRTOS-Kernel` on the CMake command line.
**NOTE:** If you are using version 1.3.1 or older of the Raspberry Pi Pico SDK then this line must appear before the
`pico_sdk_init()` and will cause FreeRTOS to be included/required in all RP2040 targets in your project. After this SDK
version, you can include the FreeRTOS-Kernel support later in your CMake build (possibly in a subdirectory) and the
FreeRTOS-Kernel support will only apply to those targets which explicitly include FreeRTOS support.
As an alternative to the `import` statement above, you can just add this directory directly via thw following (with
the same placement restrictions related to the Raspberry Pi Pico SDK version above):
```cmake
add_subdirectory(path/to/this/directory FreeRTOS-Kernel)
```
## FreeRTOS configuration for Armv8-M
The following standard FreeRTOS ARM options are required for RP2350"
These three options must be specified as follows, as only RP2040-like FreeRTOS implementation only is supported currently; running in at a single privilege level in the secure statea.
```c
#define configENABLE_MPU 0
#define configENABLE_TRUSTZONE 0
#define configRUN_FREERTOS_SECURE_ONLY 1
```
You can set the following to enable save/restore of FPU state (you should set this is you are using floating point operations)
```c
#define configENABLE_FPU 1
```
As of right now this is the only value of configMAX_SYSCALL_INTERRUPT_PRIORITY that has been tested
```c
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 16
```
## Advanced Configuration
Some additional `config` options are defined [here](include/rp2040_config.h) which control some low level implementation details.
## Known Limitations
- Tickless idle has not currently been tested, and is likely non-functiona
- There is no TrustZone version
- There is no support for enabling MPU for user/handler mode within FreeRTOS
@@ -0,0 +1,73 @@
# Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
#
# SPDX-License-Identifier: BSD-3-Clause
# Called after the Raspberry Pi Pico SDK has been initialized to add our libraries
add_library(FreeRTOS-Kernel-Core INTERFACE)
target_sources(FreeRTOS-Kernel-Core INTERFACE
${FREERTOS_KERNEL_PATH}/croutine.c
${FREERTOS_KERNEL_PATH}/event_groups.c
${FREERTOS_KERNEL_PATH}/list.c
${FREERTOS_KERNEL_PATH}/queue.c
${FREERTOS_KERNEL_PATH}/stream_buffer.c
${FREERTOS_KERNEL_PATH}/tasks.c
${FREERTOS_KERNEL_PATH}/timers.c
)
target_include_directories(FreeRTOS-Kernel-Core INTERFACE ${FREERTOS_KERNEL_PATH}/include)
if (PICO_SDK_VERSION_STRING VERSION_GREATER_EQUAL "1.3.2")
target_compile_definitions(FreeRTOS-Kernel-Core INTERFACE
PICO_CONFIG_RTOS_ADAPTER_HEADER=${CMAKE_CURRENT_LIST_DIR}/non_secure/freertos_sdk_config.h)
endif()
add_library(FreeRTOS-Kernel INTERFACE)
target_sources(FreeRTOS-Kernel INTERFACE
${CMAKE_CURRENT_LIST_DIR}/non_secure/port.c
${CMAKE_CURRENT_LIST_DIR}/non_secure/portasm.c
)
target_include_directories(FreeRTOS-Kernel INTERFACE
${CMAKE_CURRENT_LIST_DIR}/non_secure
${FREERTOS_CONFIG_FILE_DIRECTORY})
target_link_libraries(FreeRTOS-Kernel INTERFACE
FreeRTOS-Kernel-Core
pico_base_headers
hardware_clocks
hardware_exception
pico_multicore
)
target_compile_definitions(FreeRTOS-Kernel INTERFACE
LIB_FREERTOS_KERNEL=1
FREE_RTOS_KERNEL_SMP=1
)
add_library(FreeRTOS-Kernel-Static INTERFACE)
target_compile_definitions(FreeRTOS-Kernel-Static INTERFACE
configSUPPORT_STATIC_ALLOCATION=1
configKERNEL_PROVIDED_STATIC_MEMORY=1
)
target_link_libraries(FreeRTOS-Kernel-Static INTERFACE FreeRTOS-Kernel)
add_library(FreeRTOS-Kernel-Heap1 INTERFACE)
target_sources(FreeRTOS-Kernel-Heap1 INTERFACE ${FREERTOS_KERNEL_PATH}/portable/MemMang/heap_1.c)
target_link_libraries(FreeRTOS-Kernel-Heap1 INTERFACE FreeRTOS-Kernel)
add_library(FreeRTOS-Kernel-Heap2 INTERFACE)
target_sources(FreeRTOS-Kernel-Heap2 INTERFACE ${FREERTOS_KERNEL_PATH}/portable/MemMang/heap_2.c)
target_link_libraries(FreeRTOS-Kernel-Heap2 INTERFACE FreeRTOS-Kernel)
add_library(FreeRTOS-Kernel-Heap3 INTERFACE)
target_sources(FreeRTOS-Kernel-Heap3 INTERFACE ${FREERTOS_KERNEL_PATH}/portable/MemMang/heap_3.c)
target_link_libraries(FreeRTOS-Kernel-Heap3 INTERFACE FreeRTOS-Kernel)
add_library(FreeRTOS-Kernel-Heap4 INTERFACE)
target_sources(FreeRTOS-Kernel-Heap4 INTERFACE ${FREERTOS_KERNEL_PATH}/portable/MemMang/heap_4.c)
target_link_libraries(FreeRTOS-Kernel-Heap4 INTERFACE FreeRTOS-Kernel)
add_library(FreeRTOS-Kernel-Heap5 INTERFACE)
target_sources(FreeRTOS-Kernel-Heap5 INTERFACE ${FREERTOS_KERNEL_PATH}/portable/MemMang/heap_5.c)
target_link_libraries(FreeRTOS-Kernel-Heap5 INTERFACE FreeRTOS-Kernel)
@@ -0,0 +1,77 @@
/*
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*/
#ifndef FREERTOS_SDK_CONFIG_H
#define FREERTOS_SDK_CONFIG_H
#ifndef __ASSEMBLER__
#include "FreeRTOSConfig.h"
#include "rp2040_config.h"
#ifndef PICO_USE_MALLOC_MUTEX
/* malloc needs to be made thread safe */
#define PICO_USE_MALLOC_MUTEX 1
#endif /* PICO_USE_MALLOC_MUTEX */
#if ( configSUPPORT_PICO_SYNC_INTEROP == 1 )
/* increase the amount of time it may reasonably take to wake us up */
#ifndef PICO_TIME_SLEEP_OVERHEAD_ADJUST_US
#define PICO_TIME_SLEEP_OVERHEAD_ADJUST_US 150
#endif
#define lock_owner_id_t uint32_t
extern uint32_t ulPortLockGetCurrentOwnerId( void );
#define lock_get_caller_owner_id() ulPortLockGetCurrentOwnerId()
#define LOCK_INVALID_OWNER_ID ( ( uint32_t ) -1 )
struct lock_core;
#ifndef lock_internal_spin_unlock_with_wait
extern void vPortLockInternalSpinUnlockWithWait( struct lock_core * pxLock,
uint32_t ulSave );
#define lock_internal_spin_unlock_with_wait( lock, save ) vPortLockInternalSpinUnlockWithWait( lock, save )
#endif
#ifndef lock_internal_spin_unlock_with_notify
extern void vPortLockInternalSpinUnlockWithNotify( struct lock_core * pxLock,
uint32_t save );
#define lock_internal_spin_unlock_with_notify( lock, save ) vPortLockInternalSpinUnlockWithNotify( lock, save );
#endif
#ifndef lock_internal_spin_unlock_with_best_effort_wait_or_timeout
extern bool xPortLockInternalSpinUnlockWithBestEffortWaitOrTimeout( struct lock_core * pxLock,
uint32_t ulSave,
absolute_time_t uxUntil );
#define lock_internal_spin_unlock_with_best_effort_wait_or_timeout( lock, save, until ) \
xPortLockInternalSpinUnlockWithBestEffortWaitOrTimeout( lock, save, until )
#endif
#endif /* configSUPPORT_PICO_SYNC_INTEROP */
#if ( configSUPPORT_PICO_TIME_INTEROP == 1 )
extern void xPortSyncInternalYieldUntilBefore( absolute_time_t t );
#define sync_internal_yield_until_before( t ) xPortSyncInternalYieldUntilBefore( t )
#endif /* configSUPPORT_PICO_TIME_INTEROP */
#endif /* __ASSEMBLER__ */
#endif /* ifndef FREERTOS_SDK_CONFIG_H */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,526 @@
/*
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/* Standard includes. */
#include <stdint.h>
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE ensures that PRIVILEGED_FUNCTION
* is defined correctly and privileged functions are placed in correct sections. */
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
/* Portasm includes. */
#include "portasm.h"
#include "hardware/address_mapped.h"
/* System call numbers includes. */
#include "mpu_syscall_numbers.h"
/* MPU_WRAPPERS_INCLUDED_FROM_API_FILE is needed to be defined only for the
* header files. */
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#if ( configENABLE_MPU == 1 )
void vRestoreContextOfFirstTask( void ) /* __attribute__ (( naked )) PRIVILEGED_FUNCTION */
{
__asm volatile
(
" .syntax unified \n"
" \n"
" program_mpu_first_task: \n"
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
" ldr r0, [r2] \n" /* r0 = pxCurrentTCB. */
" \n"
" dmb \n" /* Complete outstanding transfers before disabling MPU. */
" ldr r1, =0xe000ed94 \n" /* r1 = 0xe000ed94 [Location of MPU_CTRL]. */
" ldr r2, [r1] \n" /* Read the value of MPU_CTRL. */
" bic r2, #1 \n" /* r2 = r2 & ~1 i.e. Clear the bit 0 in r2. */
" str r2, [r1] \n" /* Disable MPU. */
" \n"
" adds r0, #4 \n" /* r0 = r0 + 4. r0 now points to MAIR0 in TCB. */
" ldr r1, [r0] \n" /* r1 = *r0 i.e. r1 = MAIR0. */
" ldr r2, =0xe000edc0 \n" /* r2 = 0xe000edc0 [Location of MAIR0]. */
" str r1, [r2] \n" /* Program MAIR0. */
" \n"
" adds r0, #4 \n" /* r0 = r0 + 4. r0 now points to first RBAR in TCB. */
" ldr r1, =0xe000ed98 \n" /* r1 = 0xe000ed98 [Location of RNR]. */
" ldr r2, =0xe000ed9c \n" /* r2 = 0xe000ed9c [Location of RBAR]. */
" \n"
" movs r3, #4 \n" /* r3 = 4. */
" str r3, [r1] \n" /* Program RNR = 4. */
" ldmia r0!, {r4-r11} \n" /* Read 4 sets of RBAR/RLAR registers from TCB. */
" stmia r2, {r4-r11} \n" /* Write 4 set of RBAR/RLAR registers using alias registers. */
" \n"
#if ( configTOTAL_MPU_REGIONS == 16 )
" movs r3, #8 \n" /* r3 = 8. */
" str r3, [r1] \n" /* Program RNR = 8. */
" ldmia r0!, {r4-r11} \n" /* Read 4 sets of RBAR/RLAR registers from TCB. */
" stmia r2, {r4-r11} \n" /* Write 4 set of RBAR/RLAR registers using alias registers. */
" movs r3, #12 \n" /* r3 = 12. */
" str r3, [r1] \n" /* Program RNR = 12. */
" ldmia r0!, {r4-r11} \n" /* Read 4 sets of RBAR/RLAR registers from TCB. */
" stmia r2, {r4-r11} \n" /* Write 4 set of RBAR/RLAR registers using alias registers. */
#endif /* configTOTAL_MPU_REGIONS == 16 */
" \n"
" ldr r1, =0xe000ed94 \n" /* r1 = 0xe000ed94 [Location of MPU_CTRL]. */
" ldr r2, [r1] \n" /* Read the value of MPU_CTRL. */
" orr r2, #1 \n" /* r2 = r2 | 1 i.e. Set the bit 0 in r2. */
" str r2, [r1] \n" /* Enable MPU. */
" dsb \n" /* Force memory writes before continuing. */
" \n"
" restore_context_first_task: \n"
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
" ldr r0, [r2] \n" /* r0 = pxCurrentTCB.*/
" ldr r1, [r0] \n" /* r1 = Location of saved context in TCB. */
" \n"
" restore_special_regs_first_task: \n"
" ldmdb r1!, {r2-r4, lr} \n" /* r2 = original PSP, r3 = PSPLIM, r4 = CONTROL, LR restored. */
" msr psp, r2 \n"
" msr psplim, r3 \n"
" msr control, r4 \n"
" \n"
" restore_general_regs_first_task: \n"
" ldmdb r1!, {r4-r11} \n" /* r4-r11 contain hardware saved context. */
" stmia r2!, {r4-r11} \n" /* Copy the hardware saved context on the task stack. */
" ldmdb r1!, {r4-r11} \n" /* r4-r11 restored. */
" \n"
" restore_context_done_first_task: \n"
" str r1, [r0] \n" /* Save the location where the context should be saved next as the first member of TCB. */
" mov r0, #0 \n"
" msr basepri, r0 \n" /* Ensure that interrupts are enabled when the first task starts. */
" bx lr \n"
);
}
#else /* configENABLE_MPU */
void vRestoreContextOfFirstTask( void ) /* __attribute__ (( naked )) PRIVILEGED_FUNCTION */
{
__asm volatile
(
" .syntax unified \n"
" \n"
#if ( configNUMBER_OF_CORES == 1)
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
#else /* if ( configNUMBER_OF_CORES == 1) */
" adr r1, ulAsmLocals \n" /* Get the location of the current TCB for the current core. */
" ldmia r1!, {r2, r3} \n"
" ldr r2, [r2] \n" /* r2 = Core number */
" ldr r1, [r3, r2, LSL #2] \n" /* r1 = pxCurrentTCBs[get_core_num()] */
#endif /* if ( configNUMBER_OF_CORES == 1) */
" ldr r0, [r1] \n" /* Read top of stack from TCB - The first item in pxCurrentTCB is the task top of stack. */
" \n"
" ldm r0!, {r1-r2} \n" /* Read from stack - r1 = PSPLIM and r2 = EXC_RETURN. */
" msr psplim, r1 \n" /* Set this task's PSPLIM value. */
" movs r1, #2 \n" /* r1 = 2. */
" msr CONTROL, r1 \n" /* Switch to use PSP in the thread mode. */
" adds r0, #32 \n" /* Discard everything up to r0. */
" msr psp, r0 \n" /* This is now the new top of stack to use in the task. */
" isb \n"
" mov r0, #0 \n"
" msr basepri, r0 \n" /* Ensure that interrupts are enabled when the first task starts. */
" bx r2 \n" /* Finally, branch to EXC_RETURN. */
#if ( configNUMBER_OF_CORES != 1 )
" \n"
" .align 4 \n"
"ulAsmLocals: \n"
" .word %c0 \n" /* SIO */
" .word pxCurrentTCBs \n"
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
:: "i" (SIO_BASE)
);
}
#endif /* configENABLE_MPU */
/*-----------------------------------------------------------*/
BaseType_t xIsPrivileged( void ) /* __attribute__ (( naked )) */
{
__asm volatile
(
" .syntax unified \n"
" \n"
" mrs r0, control \n" /* r0 = CONTROL. */
" tst r0, #1 \n" /* Perform r0 & 1 (bitwise AND) and update the conditions flag. */
" ite ne \n"
" movne r0, #0 \n" /* CONTROL[0]!=0. Return false to indicate that the processor is not privileged. */
" moveq r0, #1 \n" /* CONTROL[0]==0. Return true to indicate that the processor is privileged. */
" bx lr \n" /* Return. */
::: "r0", "memory"
);
}
/*-----------------------------------------------------------*/
void vRaisePrivilege( void ) /* __attribute__ (( naked )) PRIVILEGED_FUNCTION */
{
__asm volatile
(
" .syntax unified \n"
" \n"
" mrs r0, control \n" /* Read the CONTROL register. */
" bic r0, #1 \n" /* Clear the bit 0. */
" msr control, r0 \n" /* Write back the new CONTROL value. */
" bx lr \n" /* Return to the caller. */
::: "r0", "memory"
);
}
/*-----------------------------------------------------------*/
void vResetPrivilege( void ) /* __attribute__ (( naked )) */
{
__asm volatile
(
" .syntax unified \n"
" \n"
" mrs r0, control \n" /* r0 = CONTROL. */
" orr r0, #1 \n" /* r0 = r0 | 1. */
" msr control, r0 \n" /* CONTROL = r0. */
" bx lr \n" /* Return to the caller. */
::: "r0", "memory"
);
}
/*-----------------------------------------------------------*/
void vStartFirstTask( void ) /* __attribute__ (( naked )) PRIVILEGED_FUNCTION */
{
__asm volatile
(
" .syntax unified \n"
" \n"
/* Note this config is not really supported; it breaks running on core 1 */
#if configRESET_STACK_POINTER
" ldr r0, =0xe000ed08 \n" /* Use the NVIC offset register to locate the stack. */
" ldr r0, [r0] \n" /* Read the VTOR register which gives the address of vector table. */
" ldr r0, [r0] \n" /* The first entry in vector table is stack pointer. */
" msr msp, r0 \n" /* Set the MSP back to the start of the stack. */
#endif
" cpsie i \n" /* Globally enable interrupts. */
" cpsie f \n"
" dsb \n"
" isb \n"
" svc %0 \n" /* System call to start the first task. */
" nop \n"
::"i" ( portSVC_START_SCHEDULER ) : "memory"
);
}
/*-----------------------------------------------------------*/
uint32_t ulSetInterruptMask( void ) /* __attribute__(( naked )) PRIVILEGED_FUNCTION */
{
__asm volatile
(
" .syntax unified \n"
" \n"
" mrs r0, basepri \n" /* r0 = basepri. Return original basepri value. */
" mov r1, %0 \n" /* r1 = configMAX_SYSCALL_INTERRUPT_PRIORITY. */
" msr basepri, r1 \n" /* Disable interrupts upto configMAX_SYSCALL_INTERRUPT_PRIORITY. */
" dsb \n"
" isb \n"
" bx lr \n" /* Return. */
::"i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) : "memory"
);
}
/*-----------------------------------------------------------*/
void vClearInterruptMask( __attribute__( ( unused ) ) uint32_t ulMask ) /* __attribute__(( naked )) PRIVILEGED_FUNCTION */
{
__asm volatile
(
" .syntax unified \n"
" \n"
" msr basepri, r0 \n" /* basepri = ulMask. */
" dsb \n"
" isb \n"
" bx lr \n" /* Return. */
::: "memory"
);
}
/*-----------------------------------------------------------*/
#if ( configENABLE_MPU == 1 )
void PendSV_Handler( void ) /* __attribute__ (( naked )) PRIVILEGED_FUNCTION */
{
__asm volatile
(
" .syntax unified \n"
" \n"
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
" ldr r0, [r2] \n" /* r0 = pxCurrentTCB. */
" ldr r1, [r0] \n" /* r1 = Location in TCB where the context should be saved. */
" mrs r2, psp \n" /* r2 = PSP. */
" \n"
" save_general_regs: \n"
#if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) )
" add r2, r2, #0x20 \n" /* Move r2 to location where s0 is saved. */
" tst lr, #0x10 \n"
" ittt eq \n"
" vstmiaeq r1!, {s16-s31} \n" /* Store s16-s31. */
" vldmiaeq r2, {s0-s16} \n" /* Copy hardware saved FP context into s0-s16. */
" vstmiaeq r1!, {s0-s16} \n" /* Store hardware saved FP context. */
" sub r2, r2, #0x20 \n" /* Set r2 back to the location of hardware saved context. */
#endif /* configENABLE_FPU || configENABLE_MVE */
" \n"
" stmia r1!, {r4-r11} \n" /* Store r4-r11. */
" ldmia r2, {r4-r11} \n" /* Copy the hardware saved context into r4-r11. */
" stmia r1!, {r4-r11} \n" /* Store the hardware saved context. */
" \n"
" save_special_regs: \n"
" mrs r3, psplim \n" /* r3 = PSPLIM. */
" mrs r4, control \n" /* r4 = CONTROL. */
" stmia r1!, {r2-r4, lr} \n" /* Store original PSP (after hardware has saved context), PSPLIM, CONTROL and LR. */
" str r1, [r0] \n" /* Save the location from where the context should be restored as the first member of TCB. */
" \n"
" select_next_task: \n"
" mov r0, %0 \n" /* r0 = configMAX_SYSCALL_INTERRUPT_PRIORITY */
" msr basepri, r0 \n" /* Disable interrupts upto configMAX_SYSCALL_INTERRUPT_PRIORITY. */
" dsb \n"
" isb \n"
" bl vTaskSwitchContext \n"
" mov r0, #0 \n" /* r0 = 0. */
" msr basepri, r0 \n" /* Enable interrupts. */
" \n"
" program_mpu: \n"
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
" ldr r0, [r2] \n" /* r0 = pxCurrentTCB. */
" \n"
" dmb \n" /* Complete outstanding transfers before disabling MPU. */
" ldr r1, =0xe000ed94 \n" /* r1 = 0xe000ed94 [Location of MPU_CTRL]. */
" ldr r2, [r1] \n" /* Read the value of MPU_CTRL. */
" bic r2, #1 \n" /* r2 = r2 & ~1 i.e. Clear the bit 0 in r2. */
" str r2, [r1] \n" /* Disable MPU. */
" \n"
" adds r0, #4 \n" /* r0 = r0 + 4. r0 now points to MAIR0 in TCB. */
" ldr r1, [r0] \n" /* r1 = *r0 i.e. r1 = MAIR0. */
" ldr r2, =0xe000edc0 \n" /* r2 = 0xe000edc0 [Location of MAIR0]. */
" str r1, [r2] \n" /* Program MAIR0. */
" \n"
" adds r0, #4 \n" /* r0 = r0 + 4. r0 now points to first RBAR in TCB. */
" ldr r1, =0xe000ed98 \n" /* r1 = 0xe000ed98 [Location of RNR]. */
" ldr r2, =0xe000ed9c \n" /* r2 = 0xe000ed9c [Location of RBAR]. */
" \n"
" movs r3, #4 \n" /* r3 = 4. */
" str r3, [r1] \n" /* Program RNR = 4. */
" ldmia r0!, {r4-r11} \n" /* Read 4 sets of RBAR/RLAR registers from TCB. */
" stmia r2, {r4-r11} \n" /* Write 4 set of RBAR/RLAR registers using alias registers. */
" \n"
#if ( configTOTAL_MPU_REGIONS == 16 )
" movs r3, #8 \n" /* r3 = 8. */
" str r3, [r1] \n" /* Program RNR = 8. */
" ldmia r0!, {r4-r11} \n" /* Read 4 sets of RBAR/RLAR registers from TCB. */
" stmia r2, {r4-r11} \n" /* Write 4 set of RBAR/RLAR registers using alias registers. */
" movs r3, #12 \n" /* r3 = 12. */
" str r3, [r1] \n" /* Program RNR = 12. */
" ldmia r0!, {r4-r11} \n" /* Read 4 sets of RBAR/RLAR registers from TCB. */
" stmia r2, {r4-r11} \n" /* Write 4 set of RBAR/RLAR registers using alias registers. */
#endif /* configTOTAL_MPU_REGIONS == 16 */
" \n"
" ldr r1, =0xe000ed94 \n" /* r1 = 0xe000ed94 [Location of MPU_CTRL]. */
" ldr r2, [r1] \n" /* Read the value of MPU_CTRL. */
" orr r2, #1 \n" /* r2 = r2 | 1 i.e. Set the bit 0 in r2. */
" str r2, [r1] \n" /* Enable MPU. */
" dsb \n" /* Force memory writes before continuing. */
" \n"
" restore_context: \n"
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
" ldr r0, [r2] \n" /* r0 = pxCurrentTCB.*/
" ldr r1, [r0] \n" /* r1 = Location of saved context in TCB. */
" \n"
" restore_special_regs: \n"
" ldmdb r1!, {r2-r4, lr} \n" /* r2 = original PSP, r3 = PSPLIM, r4 = CONTROL, LR restored. */
" msr psp, r2 \n"
" msr psplim, r3 \n"
" msr control, r4 \n"
" \n"
" restore_general_regs: \n"
" ldmdb r1!, {r4-r11} \n" /* r4-r11 contain hardware saved context. */
" stmia r2!, {r4-r11} \n" /* Copy the hardware saved context on the task stack. */
" ldmdb r1!, {r4-r11} \n" /* r4-r11 restored. */
#if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) )
" tst lr, #0x10 \n"
" ittt eq \n"
" vldmdbeq r1!, {s0-s16} \n" /* s0-s16 contain hardware saved FP context. */
" vstmiaeq r2!, {s0-s16} \n" /* Copy hardware saved FP context on the task stack. */
" vldmdbeq r1!, {s16-s31} \n" /* Restore s16-s31. */
#endif /* configENABLE_FPU || configENABLE_MVE */
" \n"
" restore_context_done: \n"
" str r1, [r0] \n" /* Save the location where the context should be saved next as the first member of TCB. */
" bx lr \n"
::"i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY )
);
}
#else /* configENABLE_MPU */
void PendSV_Handler( void ) /* __attribute__ (( naked )) PRIVILEGED_FUNCTION */
{
__asm volatile
(
" .syntax unified \n"
" \n"
" mrs r1, psp \n" /* Read PSP in r1. */
" \n"
#if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) )
" tst lr, #0x10 \n" /* Test Bit[4] in LR. Bit[4] of EXC_RETURN is 0 if the Extended Stack Frame is in use. */
" it eq \n"
" vstmdbeq r1!, {s16-s31} \n" /* Store the additional FP context registers which are not saved automatically. */
#endif /* configENABLE_FPU || configENABLE_MVE */
" \n"
" mrs r2, psplim \n" /* r2 = PSPLIM. */
" mov r3, lr \n" /* r3 = LR/EXC_RETURN. */
" stmdb r1!, {r2-r11} \n" /* Store on the stack - PSPLIM, LR and registers that are not automatically saved. */
" \n"
#if portUSE_DCP_SAVE_RESTORE
" mrrc2 p4,#0,r4,r5,c8 \n" /* PXMD r4, r5 */
" mrrc2 p4,#0,r6,r7,c9 \n" /* PYMD r6, r7 */
" mrrc2 p4,#0,r8,r9,c10 \n" /* REFD r8, r9 */
" stmdb r1, {r4-r9} \n" /* Store DCP state on the stack; don't update r1 as we want the stack frame to be normal for smart debuggers */
#endif /* portUSE_DIVIDER_SAVE_RESTORE */
#if ( configNUMBER_OF_CORES == 1)
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
" ldr r3, [r2] \n" /* Read pxCurrentTCB. */
#else /* if ( configNUMBER_OF_CORES == 1) */
" adr r0, ulAsmLocals2 \n" /* Get the location of the current TCB for the current core. */
" ldmia r0!, {r2, r3} \n"
" ldr r0, [r2] \n" /* r0 = Core number */
" ldr r3, [r3, r0, LSL #2] \n" /* r3 = pxCurrentTCBs[get_core_num()] */
#endif /* if ( configNUMBER_OF_CORES == 1) */
" str r1, [r3] \n" /* Save the new top of stack in TCB. */
" \n"
" mov r1, %0 \n" /* r1 = configMAX_SYSCALL_INTERRUPT_PRIORITY */
" msr basepri, r1 \n" /* Disable interrupts upto configMAX_SYSCALL_INTERRUPT_PRIORITY. */
" dsb \n"
" isb \n"
/* Note: in configNUMBER_OF_CORES != 1 r0 holds core number from above */
" bl vTaskSwitchContext \n"
" mov r0, #0 \n" /* r0 = 0. */
" msr basepri, r0 \n" /* Enable interrupts. */
" \n"
#if ( configNUMBER_OF_CORES == 1)
" ldr r2, =pxCurrentTCB \n" /* Read the location of pxCurrentTCB i.e. &( pxCurrentTCB ). */
" ldr r1, [r2] \n" /* Read pxCurrentTCB. */
#else /* if ( configNUMBER_OF_CORES == 1) */
" adr r1, ulAsmLocals2 \n" /* Get the location of the current TCB for the current core. */
" ldmia r1!, {r2, r3} \n"
" ldr r2, [r2] \n" /* r2 = Core number */
" ldr r1, [r3, r2, LSL #2] \n" /* r1 = pxCurrentTCBs[get_core_num()] */
#endif /* if ( configNUMBER_OF_CORES == 1) */
" ldr r0, [r1] \n" /* The first item in pxCurrentTCB is the task top of stack. r0 now points to the top of stack. */
" \n"
#if portUSE_DCP_SAVE_RESTORE
" subs r0, r0, #24 \n" /* the DCP state is below the stored stack pointer */
" ldmia r0!, {r4-r9} \n" /* Read DCP state from stack */
" mcrr p4,#0,r4,r5,c0 \n" /* WXMD r4, r5 */
" mcrr p4,#0,r6,r7,c1 \n" /* WYMD r6, r7 */
" mcrr p4,#0,r8,r9,c2 \n" /* WEFD r8, r9 */
#endif /* portUSE_DIVIDER_SAVE_RESTORE */
" ldmia r0!, {r2-r11} \n" /* Read from stack - r2 = PSPLIM, r3 = LR and r4-r11 restored. */
" \n"
#if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) )
" tst r3, #0x10 \n" /* Test Bit[4] in LR. Bit[4] of EXC_RETURN is 0 if the Extended Stack Frame is in use. */
" it eq \n"
" vldmiaeq r0!, {s16-s31} \n" /* Restore the additional FP context registers which are not restored automatically. */
#endif /* configENABLE_FPU || configENABLE_MVE */
" \n"
" msr psplim, r2 \n" /* Restore the PSPLIM register value for the task. */
" msr psp, r0 \n" /* Remember the new top of stack for the task. */
" bx r3 \n"
#if ( configNUMBER_OF_CORES != 1 )
" .align 4 \n"
"ulAsmLocals2: \n"
" .word %c1 \n" /* SIO */
" .word pxCurrentTCBs \n"
#endif /* #if ( configNUMBER_OF_CORES > 1 ) */
::"i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY ), "i" ( SIO_BASE )
);
}
#endif /* configENABLE_MPU */
/*-----------------------------------------------------------*/
#if ( ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) )
void SVC_Handler( void ) /* __attribute__ (( naked )) PRIVILEGED_FUNCTION */
{
__asm volatile
(
".syntax unified \n"
".extern vPortSVCHandler_C \n"
".extern vSystemCallEnter \n"
".extern vSystemCallExit \n"
" \n"
"tst lr, #4 \n"
"ite eq \n"
"mrseq r0, msp \n"
"mrsne r0, psp \n"
" \n"
"ldr r1, [r0, #24] \n"
"ldrb r2, [r1, #-2] \n"
"cmp r2, %0 \n"
"blt syscall_enter \n"
"cmp r2, %1 \n"
"beq syscall_exit \n"
"b vPortSVCHandler_C \n"
" \n"
"syscall_enter: \n"
" mov r1, lr \n"
" b vSystemCallEnter \n"
" \n"
"syscall_exit: \n"
" mov r1, lr \n"
" b vSystemCallExit \n"
" \n"
: /* No outputs. */
: "i" ( NUM_SYSTEM_CALLS ), "i" ( portSVC_SYSTEM_CALL_EXIT )
: "r0", "r1", "r2", "memory"
);
}
#else /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
void SVC_Handler( void ) /* __attribute__ (( naked )) PRIVILEGED_FUNCTION */
{
__asm volatile
(
" .syntax unified \n"
" \n"
" tst lr, #4 \n"
" ite eq \n"
" mrseq r0, msp \n"
" mrsne r0, psp \n"
" ldr r1, =vPortSVCHandler_C \n"
" bx r1 \n"
);
}
#endif /* ( configENABLE_MPU == 1 ) && ( configUSE_MPU_WRAPPERS_V1 == 0 ) */
/*-----------------------------------------------------------*/
@@ -0,0 +1,114 @@
/*
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
#ifndef __PORT_ASM_H__
#define __PORT_ASM_H__
/* Scheduler includes. */
#include "FreeRTOS.h"
/* MPU wrappers includes. */
#include "mpu_wrappers.h"
/**
* @brief Restore the context of the first task so that the first task starts
* executing.
*/
void vRestoreContextOfFirstTask( void ) __attribute__( ( naked ) ) PRIVILEGED_FUNCTION;
/**
* @brief Checks whether or not the processor is privileged.
*
* @return 1 if the processor is already privileged, 0 otherwise.
*/
BaseType_t xIsPrivileged( void ) __attribute__( ( naked ) );
/**
* @brief Raises the privilege level by clearing the bit 0 of the CONTROL
* register.
*
* @note This is a privileged function and should only be called from the kenrel
* code.
*
* Bit 0 of the CONTROL register defines the privilege level of Thread Mode.
* Bit[0] = 0 --> The processor is running privileged
* Bit[0] = 1 --> The processor is running unprivileged.
*/
void vRaisePrivilege( void ) __attribute__( ( naked ) ) PRIVILEGED_FUNCTION;
/**
* @brief Lowers the privilege level by setting the bit 0 of the CONTROL
* register.
*
* Bit 0 of the CONTROL register defines the privilege level of Thread Mode.
* Bit[0] = 0 --> The processor is running privileged
* Bit[0] = 1 --> The processor is running unprivileged.
*/
void vResetPrivilege( void ) __attribute__( ( naked ) );
/**
* @brief Starts the first task.
*/
void vStartFirstTask( void ) __attribute__( ( naked ) ) PRIVILEGED_FUNCTION;
/**
* @brief Disables interrupts.
*/
uint32_t ulSetInterruptMask( void ) __attribute__( ( naked ) ) PRIVILEGED_FUNCTION;
/**
* @brief Enables interrupts.
*/
void vClearInterruptMask( uint32_t ulMask ) __attribute__( ( naked ) ) PRIVILEGED_FUNCTION;
/**
* @brief PendSV Exception handler.
*/
void PendSV_Handler( void ) __attribute__( ( naked ) ) PRIVILEGED_FUNCTION;
/**
* @brief SVC Handler.
*/
void SVC_Handler( void ) __attribute__( ( naked ) ) PRIVILEGED_FUNCTION;
/**
* @brief Allocate a Secure context for the calling task.
*
* @param[in] ulSecureStackSize The size of the stack to be allocated on the
* secure side for the calling task.
*/
void vPortAllocateSecureContext( uint32_t ulSecureStackSize ) __attribute__( ( naked ) );
/**
* @brief Free the task's secure context.
*
* @param[in] pulTCB Pointer to the Task Control Block (TCB) of the task.
*/
void vPortFreeSecureContext( uint32_t * pulTCB ) __attribute__( ( naked ) ) PRIVILEGED_FUNCTION;
#endif /* __PORT_ASM_H__ */
@@ -0,0 +1,230 @@
/*
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Copyright (c) 2024 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: MIT AND BSD-3-Clause
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
#ifndef PORTMACRO_H
#define PORTMACRO_H
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
#include "pico.h"
#include "hardware/sync.h"
/*-----------------------------------------------------------
* Port specific definitions.
*
* The settings in this file configure FreeRTOS correctly for the given hardware
* and compiler.
*
* These settings should not be altered.
*------------------------------------------------------------------------------
*/
/**
* Architecture specifics.
*/
#define portARCH_NAME "Cortex-M33"
#define portHAS_ARMV8M_MAIN_EXTENSION 1
#define portARMV8M_MINOR_VERSION 0
#define portDONT_DISCARD __attribute__( ( used ) )
/*-----------------------------------------------------------*/
/* ARMv8-M common port configurations. */
#include "portmacrocommon.h"
/*-----------------------------------------------------------*/
#ifndef configENABLE_MVE
#define configENABLE_MVE 0
#elif( configENABLE_MVE != 0 )
#error configENABLE_MVE must be left undefined, or defined to 0 for the Cortex-M33.
#endif
/*-----------------------------------------------------------*/
/**
* @brief Critical section management.
*/
#define portSET_INTERRUPT_MASK() ulSetInterruptMask()
#define portCLEAR_INTERRUPT_MASK(state) vClearInterruptMask( state )
#define portDISABLE_INTERRUPTS() portSET_INTERRUPT_MASK()
#define portENABLE_INTERRUPTS() portCLEAR_INTERRUPT_MASK( 0 )
#if ( configNUMBER_OF_CORES == 1 )
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
#define portENTER_CRITICAL() vPortEnterCritical()
#define portEXIT_CRITICAL() vPortExitCritical()
#else /* ( configNUMBER_OF_CORES == 1 ) */
/* SMP enabled */
#undef portENTER_CRITICAL
#undef portEXIT_CRITICAL
extern void vTaskEnterCritical( void );
extern void vTaskExitCritical( void );
extern UBaseType_t vTaskEnterCriticalFromISR( void );
extern void vTaskExitCriticalFromISR( UBaseType_t uxSavedInterruptStatus );
#define portENTER_CRITICAL() vTaskEnterCritical()
#define portEXIT_CRITICAL() vTaskExitCritical()
#define portENTER_CRITICAL_FROM_ISR() vTaskEnterCriticalFromISR()
#define portEXIT_CRITICAL_FROM_ISR( x ) vTaskExitCriticalFromISR( x )
#endif /* if ( configNUMBER_OF_CORES != 1 ) */
/*-----------------------------------------------------------*/
#ifdef configUSE_DCP_SAVE_RESTORE
#define portUSE_DCP_SAVE_RESTORE configUSE_DCP_SAVE_RESTORE
#elif (LIB_PICO_DOUBLE_PICO/* || LIB_PICO_FLOAT_PICO*/) // todo we don't use DCP in float yet
#define portUSE_DCP_SAVE_RESTORE 1
#endif
#if portUSE_DCP_SAVE_RESTORE
#define portSTACK_LIMIT_PADDING 6
#endif
/*-----------------------------------------------------------*/
/* Exception handlers */
#if ( configUSE_DYNAMIC_EXCEPTION_HANDLERS == 0 )
/* We only need to override the SDK's weak functions if we want to replace them at compile time */
#define SVC_Handler isr_svcall
#define PendSV_Handler isr_pendsv
#define SysTick_Handler isr_systick
#endif
/*-----------------------------------------------------------*/
/* Multi-core */
#define portMAX_CORE_COUNT 2
/* Check validity of number of cores specified in config */
#if ( configNUMBER_OF_CORES < 1 || portMAX_CORE_COUNT < configNUMBER_OF_CORES )
#error "Invalid number of cores specified in config!"
#endif
#if ( configTICK_CORE < 0 || configTICK_CORE > configNUMBER_OF_CORES )
#error "Invalid tick core specified in config!"
#endif
/* FreeRTOS core id is always zero based, so always 0 if we're running on only one core */
#if configNUMBER_OF_CORES != 1
#define portGET_CORE_ID() get_core_num()
#else
#define portGET_CORE_ID() 0
#endif
#define portCHECK_IF_IN_ISR() \
( { \
uint32_t ulIPSR; \
__asm volatile ( "mrs %0, IPSR" : "=r" ( ulIPSR )::); \
( ( uint8_t ) ulIPSR ) > 0; } )
void vYieldCore( int xCoreID );
#define portYIELD_CORE( a ) vYieldCore( a )
/*-----------------------------------------------------------*/
/* Critical nesting count management. */
#if configNUMBER_OF_CORES == 1
#define portGET_CRITICAL_NESTING_COUNT( xCoreID ) ulCriticalNesting
#else
extern volatile uint32_t ulCriticalNestings[ configNUMBER_OF_CORES ];
#define portGET_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( xCoreID ) ] )
#define portSET_CRITICAL_NESTING_COUNT( xCoreID, x ) ( ulCriticalNestings[ ( xCoreID ) ] = ( x ) )
#define portINCREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( xCoreID ) ]++ )
#define portDECREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ulCriticalNestings[ ( xCoreID ) ]-- )
#endif
/*-----------------------------------------------------------*/
/* Critical section management. */
#define portCRITICAL_NESTING_IN_TCB 0
#define portRTOS_SPINLOCK_COUNT 2
/* Note this is a single method with uxAcquire parameter since we have
* static vars, the method is always called with a compile time constant for
* uxAcquire, and the compiler should do the right thing! */
static inline void vPortRecursiveLock( BaseType_t xCoreID,
uint32_t ulLockNum,
spin_lock_t * pxSpinLock,
BaseType_t uxAcquire )
{
static volatile uint8_t ucOwnedByCore[ portMAX_CORE_COUNT ][portRTOS_SPINLOCK_COUNT];
static volatile uint8_t ucRecursionCountByLock[ portRTOS_SPINLOCK_COUNT ];
configASSERT( ulLockNum < portRTOS_SPINLOCK_COUNT );
if( uxAcquire )
{
if (!spin_try_lock_unsafe(pxSpinLock)) {
if( ucOwnedByCore[ xCoreID ][ ulLockNum ] )
{
configASSERT( ucRecursionCountByLock[ ulLockNum ] != 255u );
ucRecursionCountByLock[ ulLockNum ]++;
return;
}
spin_lock_unsafe_blocking(pxSpinLock);
}
configASSERT( ucRecursionCountByLock[ ulLockNum ] == 0 );
ucRecursionCountByLock[ ulLockNum ] = 1;
ucOwnedByCore[ xCoreID ][ ulLockNum ] = 1;
}
else
{
configASSERT( ( ucOwnedByCore[ xCoreID ] [ulLockNum ] ) != 0 );
configASSERT( ucRecursionCountByLock[ ulLockNum ] != 0 );
if( !--ucRecursionCountByLock[ ulLockNum ] )
{
ucOwnedByCore[ xCoreID ] [ ulLockNum ] = 0;
spin_unlock_unsafe(pxSpinLock);
}
}
}
#if ( configNUMBER_OF_CORES == 1 )
#define portGET_ISR_LOCK( xCoreID )
#define portRELEASE_ISR_LOCK( xCoreID )
#define portGET_TASK_LOCK( xCoreID )
#define portRELEASE_TASK_LOCK( xCoreID )
#else /* configNUMBER_OF_CORES == 1 */
#define portGET_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( xCoreID ), 0, spin_lock_instance( configSMP_SPINLOCK_0 ), pdTRUE )
#define portRELEASE_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( xCoreID ), 0, spin_lock_instance( configSMP_SPINLOCK_0 ), pdFALSE )
#define portGET_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( xCoreID ), 1, spin_lock_instance( configSMP_SPINLOCK_1 ), pdTRUE )
#define portRELEASE_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( xCoreID ), 1, spin_lock_instance( configSMP_SPINLOCK_1 ), pdFALSE )
#endif /* configNUMBER_OF_CORES == 1 */
/* *INDENT-OFF* */
#ifdef __cplusplus
}
#endif
/* *INDENT-ON* */
#endif /* PORTMACRO_H */
@@ -0,0 +1,516 @@
/*
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
#ifndef PORTMACROCOMMON_H
#define PORTMACROCOMMON_H
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
/*------------------------------------------------------------------------------
* Port specific definitions.
*
* The settings in this file configure FreeRTOS correctly for the given hardware
* and compiler.
*
* These settings should not be altered.
*------------------------------------------------------------------------------
*/
#ifndef configENABLE_FPU
#error configENABLE_FPU must be defined in FreeRTOSConfig.h. Set configENABLE_FPU to 1 to enable the FPU or 0 to disable the FPU.
#endif /* configENABLE_FPU */
#ifndef configENABLE_MPU
#error configENABLE_MPU must be defined in FreeRTOSConfig.h. Set configENABLE_MPU to 1 to enable the MPU or 0 to disable the MPU.
#endif /* configENABLE_MPU */
#ifndef configENABLE_TRUSTZONE
#error configENABLE_TRUSTZONE must be defined in FreeRTOSConfig.h. Set configENABLE_TRUSTZONE to 1 to enable TrustZone or 0 to disable TrustZone.
#endif /* configENABLE_TRUSTZONE */
/*-----------------------------------------------------------*/
/**
* @brief Type definitions.
*/
#define portCHAR char
#define portFLOAT float
#define portDOUBLE double
#define portLONG long
#define portSHORT short
#define portSTACK_TYPE uint32_t
#define portBASE_TYPE long
typedef portSTACK_TYPE StackType_t;
typedef long BaseType_t;
typedef unsigned long UBaseType_t;
#if ( configTICK_TYPE_WIDTH_IN_BITS == TICK_TYPE_WIDTH_16_BITS )
typedef uint16_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffff
#elif ( configTICK_TYPE_WIDTH_IN_BITS == TICK_TYPE_WIDTH_32_BITS )
typedef uint32_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
/* 32-bit tick type on a 32-bit architecture, so reads of the tick count do
* not need to be guarded with a critical section. */
#define portTICK_TYPE_IS_ATOMIC 1
#else
#error configTICK_TYPE_WIDTH_IN_BITS set to unsupported tick type width.
#endif
/*-----------------------------------------------------------*/
/**
* Architecture specifics.
*/
#define portSTACK_GROWTH ( -1 )
#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
#define portBYTE_ALIGNMENT 8
#define portNOP()
#define portINLINE __inline
#ifndef portFORCE_INLINE
#define portFORCE_INLINE inline __attribute__( ( always_inline ) )
#endif
#define portHAS_STACK_OVERFLOW_CHECKING 1
/*-----------------------------------------------------------*/
/**
* @brief Extern declarations.
*/
extern BaseType_t xPortIsInsideInterrupt( void );
extern void vPortYield( void ) /* PRIVILEGED_FUNCTION */;
extern void vPortEnterCritical( void ) /* PRIVILEGED_FUNCTION */;
extern void vPortExitCritical( void ) /* PRIVILEGED_FUNCTION */;
extern uint32_t ulSetInterruptMask( void ) /* __attribute__(( naked )) PRIVILEGED_FUNCTION */;
extern void vClearInterruptMask( uint32_t ulMask ) /* __attribute__(( naked )) PRIVILEGED_FUNCTION */;
#if ( configENABLE_TRUSTZONE == 1 )
extern void vPortAllocateSecureContext( uint32_t ulSecureStackSize ); /* __attribute__ (( naked )) */
extern void vPortFreeSecureContext( uint32_t * pulTCB ) /* __attribute__ (( naked )) PRIVILEGED_FUNCTION */;
#endif /* configENABLE_TRUSTZONE */
#if ( configENABLE_MPU == 1 )
extern BaseType_t xIsPrivileged( void ) /* __attribute__ (( naked )) */;
extern void vResetPrivilege( void ) /* __attribute__ (( naked )) */;
#endif /* configENABLE_MPU */
/*-----------------------------------------------------------*/
/**
* @brief MPU specific constants.
*/
#if ( configENABLE_MPU == 1 )
#define portUSING_MPU_WRAPPERS 1
#define portPRIVILEGE_BIT ( 0x80000000UL )
#else
#define portPRIVILEGE_BIT ( 0x0UL )
#endif /* configENABLE_MPU */
/* MPU settings that can be overriden in FreeRTOSConfig.h. */
#ifndef configTOTAL_MPU_REGIONS
/* Define to 8 for backward compatibility. */
#define configTOTAL_MPU_REGIONS ( 8UL )
#endif
/* MPU regions. */
#define portPRIVILEGED_FLASH_REGION ( 0UL )
#define portUNPRIVILEGED_FLASH_REGION ( 1UL )
#define portUNPRIVILEGED_SYSCALLS_REGION ( 2UL )
#define portPRIVILEGED_RAM_REGION ( 3UL )
#define portSTACK_REGION ( 4UL )
#define portFIRST_CONFIGURABLE_REGION ( 5UL )
#define portLAST_CONFIGURABLE_REGION ( configTOTAL_MPU_REGIONS - 1UL )
#define portNUM_CONFIGURABLE_REGIONS ( ( portLAST_CONFIGURABLE_REGION - portFIRST_CONFIGURABLE_REGION ) + 1 )
#define portTOTAL_NUM_REGIONS ( portNUM_CONFIGURABLE_REGIONS + 1 ) /* Plus one to make space for the stack region. */
/* Device memory attributes used in MPU_MAIR registers.
*
* 8-bit values encoded as follows:
* Bit[7:4] - 0000 - Device Memory
* Bit[3:2] - 00 --> Device-nGnRnE
* 01 --> Device-nGnRE
* 10 --> Device-nGRE
* 11 --> Device-GRE
* Bit[1:0] - 00, Reserved.
*/
#define portMPU_DEVICE_MEMORY_nGnRnE ( 0x00 ) /* 0000 0000 */
#define portMPU_DEVICE_MEMORY_nGnRE ( 0x04 ) /* 0000 0100 */
#define portMPU_DEVICE_MEMORY_nGRE ( 0x08 ) /* 0000 1000 */
#define portMPU_DEVICE_MEMORY_GRE ( 0x0C ) /* 0000 1100 */
/* Normal memory attributes used in MPU_MAIR registers. */
#define portMPU_NORMAL_MEMORY_NON_CACHEABLE ( 0x44 ) /* Non-cacheable. */
#define portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE ( 0xFF ) /* Non-Transient, Write-back, Read-Allocate and Write-Allocate. */
/* Attributes used in MPU_RBAR registers. */
#define portMPU_REGION_NON_SHAREABLE ( 0UL << 3UL )
#define portMPU_REGION_INNER_SHAREABLE ( 1UL << 3UL )
#define portMPU_REGION_OUTER_SHAREABLE ( 2UL << 3UL )
#define portMPU_REGION_PRIVILEGED_READ_WRITE ( 0UL << 1UL )
#define portMPU_REGION_READ_WRITE ( 1UL << 1UL )
#define portMPU_REGION_PRIVILEGED_READ_ONLY ( 2UL << 1UL )
#define portMPU_REGION_READ_ONLY ( 3UL << 1UL )
#define portMPU_REGION_EXECUTE_NEVER ( 1UL )
/*-----------------------------------------------------------*/
#if ( configENABLE_MPU == 1 )
/**
* @brief Settings to define an MPU region.
*/
typedef struct MPURegionSettings
{
uint32_t ulRBAR; /**< RBAR for the region. */
uint32_t ulRLAR; /**< RLAR for the region. */
} MPURegionSettings_t;
#if ( configUSE_MPU_WRAPPERS_V1 == 0 )
#ifndef configSYSTEM_CALL_STACK_SIZE
#error configSYSTEM_CALL_STACK_SIZE must be defined to the desired size of the system call stack in words for using MPU wrappers v2.
#endif
/**
* @brief System call stack.
*/
typedef struct SYSTEM_CALL_STACK_INFO
{
uint32_t ulSystemCallStackBuffer[ configSYSTEM_CALL_STACK_SIZE ];
uint32_t * pulSystemCallStack;
uint32_t * pulSystemCallStackLimit;
uint32_t * pulTaskStack;
uint32_t ulLinkRegisterAtSystemCallEntry;
uint32_t ulStackLimitRegisterAtSystemCallEntry;
} xSYSTEM_CALL_STACK_INFO;
#endif /* configUSE_MPU_WRAPPERS_V1 == 0 */
/**
* @brief MPU settings as stored in the TCB.
*/
#if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) )
#if ( configENABLE_TRUSTZONE == 1 )
/*
* +-----------+---------------+----------+-----------------+------------------------------+-----+
* | s16-s31 | s0-s15, FPSCR | r4-r11 | r0-r3, r12, LR, | xSecureContext, PSP, PSPLIM, | |
* | | | | PC, xPSR | CONTROL, EXC_RETURN | |
* +-----------+---------------+----------+-----------------+------------------------------+-----+
*
* <-----------><--------------><---------><----------------><-----------------------------><---->
* 16 16 8 8 5 1
*/
#define MAX_CONTEXT_SIZE 54
#else /* #if( configENABLE_TRUSTZONE == 1 ) */
/*
* +-----------+---------------+----------+-----------------+----------------------+-----+
* | s16-s31 | s0-s15, FPSCR | r4-r11 | r0-r3, r12, LR, | PSP, PSPLIM, CONTROL | |
* | | | | PC, xPSR | EXC_RETURN | |
* +-----------+---------------+----------+-----------------+----------------------+-----+
*
* <-----------><--------------><---------><----------------><---------------------><---->
* 16 16 8 8 4 1
*/
#define MAX_CONTEXT_SIZE 53
#endif /* #if( configENABLE_TRUSTZONE == 1 ) */
#else /* #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) */
#if ( configENABLE_TRUSTZONE == 1 )
/*
* +----------+-----------------+------------------------------+-----+
* | r4-r11 | r0-r3, r12, LR, | xSecureContext, PSP, PSPLIM, | |
* | | PC, xPSR | CONTROL, EXC_RETURN | |
* +----------+-----------------+------------------------------+-----+
*
* <---------><----------------><------------------------------><---->
* 8 8 5 1
*/
#define MAX_CONTEXT_SIZE 22
#else /* #if( configENABLE_TRUSTZONE == 1 ) */
/*
* +----------+-----------------+----------------------+-----+
* | r4-r11 | r0-r3, r12, LR, | PSP, PSPLIM, CONTROL | |
* | | PC, xPSR | EXC_RETURN | |
* +----------+-----------------+----------------------+-----+
*
* <---------><----------------><----------------------><---->
* 8 8 4 1
*/
#define MAX_CONTEXT_SIZE 21
#endif /* #if( configENABLE_TRUSTZONE == 1 ) */
#endif /* #if ( ( configENABLE_FPU == 1 ) || ( configENABLE_MVE == 1 ) ) */
/* Flags used for xMPU_SETTINGS.ulTaskFlags member. */
#define portSTACK_FRAME_HAS_PADDING_FLAG ( 1UL << 0UL )
#define portTASK_IS_PRIVILEGED_FLAG ( 1UL << 1UL )
/* Size of an Access Control List (ACL) entry in bits. */
#define portACL_ENTRY_SIZE_BITS ( 32U )
typedef struct MPU_SETTINGS
{
uint32_t ulMAIR0; /**< MAIR0 for the task containing attributes for all the 4 per task regions. */
MPURegionSettings_t xRegionsSettings[ portTOTAL_NUM_REGIONS ]; /**< Settings for 4 per task regions. */
uint32_t ulContext[ MAX_CONTEXT_SIZE ];
uint32_t ulTaskFlags;
#if ( configUSE_MPU_WRAPPERS_V1 == 0 )
xSYSTEM_CALL_STACK_INFO xSystemCallStackInfo;
#if ( configENABLE_ACCESS_CONTROL_LIST == 1 )
uint32_t ulAccessControlList[ ( configPROTECTED_KERNEL_OBJECT_POOL_SIZE / portACL_ENTRY_SIZE_BITS ) + 1 ];
#endif
#endif
} xMPU_SETTINGS;
#endif /* configENABLE_MPU == 1 */
/*-----------------------------------------------------------*/
/**
* @brief Validate priority of ISRs that are allowed to call FreeRTOS
* system calls.
*/
#ifdef configASSERT
#if ( portHAS_ARMV8M_MAIN_EXTENSION == 1 )
void vPortValidateInterruptPriority( void );
#define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() vPortValidateInterruptPriority()
#endif
#endif
/**
* @brief SVC numbers.
*/
#define portSVC_ALLOCATE_SECURE_CONTEXT 100
#define portSVC_FREE_SECURE_CONTEXT 101
#define portSVC_START_SCHEDULER 102
#define portSVC_RAISE_PRIVILEGE 103
#define portSVC_SYSTEM_CALL_EXIT 104
#define portSVC_YIELD 105
/*-----------------------------------------------------------*/
/**
* @brief Scheduler utilities.
*/
#if ( configENABLE_MPU == 1 )
#define portYIELD() __asm volatile ( "svc %0" ::"i" ( portSVC_YIELD ) : "memory" )
#define portYIELD_WITHIN_API() vPortYield()
#else
#define portYIELD() vPortYield()
#define portYIELD_WITHIN_API() vPortYield()
#endif
#define portNVIC_INT_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000ed04 ) )
#define portNVIC_PENDSVSET_BIT ( 1UL << 28UL )
#define portEND_SWITCHING_ISR( xSwitchRequired ) \
do \
{ \
if( xSwitchRequired ) \
{ \
traceISR_EXIT_TO_SCHEDULER(); \
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \
} \
else \
{ \
traceISR_EXIT(); \
} \
} while( 0 )
#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )
/*-----------------------------------------------------------*/
/**
* @brief Critical section management.
*/
#define portSET_INTERRUPT_MASK_FROM_ISR() ulSetInterruptMask()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( x ) vClearInterruptMask( x )
#define portENTER_CRITICAL() vPortEnterCritical()
#define portEXIT_CRITICAL() vPortExitCritical()
/*-----------------------------------------------------------*/
/**
* @brief Tickless idle/low power functionality.
*/
#ifndef portSUPPRESS_TICKS_AND_SLEEP
extern void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime );
#define portSUPPRESS_TICKS_AND_SLEEP( xExpectedIdleTime ) vPortSuppressTicksAndSleep( xExpectedIdleTime )
#endif
/*-----------------------------------------------------------*/
/**
* @brief Task function macros as described on the FreeRTOS.org WEB site.
*/
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void * pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void * pvParameters )
/*-----------------------------------------------------------*/
#if ( configENABLE_TRUSTZONE == 1 )
/**
* @brief Allocate a secure context for the task.
*
* Tasks are not created with a secure context. Any task that is going to call
* secure functions must call portALLOCATE_SECURE_CONTEXT() to allocate itself a
* secure context before it calls any secure function.
*
* @param[in] ulSecureStackSize The size of the secure stack to be allocated.
*/
#define portALLOCATE_SECURE_CONTEXT( ulSecureStackSize ) vPortAllocateSecureContext( ulSecureStackSize )
/**
* @brief Called when a task is deleted to delete the task's secure context,
* if it has one.
*
* @param[in] pxTCB The TCB of the task being deleted.
*/
#define portCLEAN_UP_TCB( pxTCB ) vPortFreeSecureContext( ( uint32_t * ) pxTCB )
#endif /* configENABLE_TRUSTZONE */
/*-----------------------------------------------------------*/
#if ( configENABLE_MPU == 1 )
/**
* @brief Checks whether or not the processor is privileged.
*
* @return 1 if the processor is already privileged, 0 otherwise.
*/
#define portIS_PRIVILEGED() xIsPrivileged()
/**
* @brief Raise an SVC request to raise privilege.
*
* The SVC handler checks that the SVC was raised from a system call and only
* then it raises the privilege. If this is called from any other place,
* the privilege is not raised.
*/
#define portRAISE_PRIVILEGE() __asm volatile ( "svc %0 \n" ::"i" ( portSVC_RAISE_PRIVILEGE ) : "memory" );
/**
* @brief Lowers the privilege level by setting the bit 0 of the CONTROL
* register.
*/
#define portRESET_PRIVILEGE() vResetPrivilege()
#else
#define portIS_PRIVILEGED()
#define portRAISE_PRIVILEGE()
#define portRESET_PRIVILEGE()
#endif /* configENABLE_MPU */
/*-----------------------------------------------------------*/
#if ( configENABLE_MPU == 1 )
extern BaseType_t xPortIsTaskPrivileged( void );
/**
* @brief Checks whether or not the calling task is privileged.
*
* @return pdTRUE if the calling task is privileged, pdFALSE otherwise.
*/
#define portIS_TASK_PRIVILEGED() xPortIsTaskPrivileged()
#endif /* configENABLE_MPU == 1 */
/*-----------------------------------------------------------*/
/**
* @brief Barriers.
*/
#define portMEMORY_BARRIER() __asm volatile ( "" ::: "memory" )
/*-----------------------------------------------------------*/
/* Select correct value of configUSE_PORT_OPTIMISED_TASK_SELECTION
* based on whether or not Mainline extension is implemented. */
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
#if ( portHAS_ARMV8M_MAIN_EXTENSION == 1 && !( configNUMBER_OF_CORES > 1 ))
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
#else
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0
#endif
#endif /* #ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION */
/**
* @brief Port-optimised task selection.
*/
#if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 )
/**
* @brief Count the number of leading zeros in a 32-bit value.
*/
static portFORCE_INLINE uint32_t ulPortCountLeadingZeros( uint32_t ulBitmap )
{
uint32_t ulReturn;
__asm volatile ( "clz %0, %1" : "=r" ( ulReturn ) : "r" ( ulBitmap ) : "memory" );
return ulReturn;
}
/* Check the configuration. */
#if ( configMAX_PRIORITIES > 32 )
#error configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32. It is very rare that a system requires more than 10 to 15 different priorities as tasks that share a priority will time slice.
#endif
#if ( portHAS_ARMV8M_MAIN_EXTENSION == 0 )
#error ARMv8-M baseline implementations (such as Cortex-M23) do not support port-optimised task selection. Please set configUSE_PORT_OPTIMISED_TASK_SELECTION to 0 or leave it undefined.
#endif
/**
* @brief Store/clear the ready priorities in a bit map.
*/
#define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) )
#define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )
/**
* @brief Get the priority of the highest-priority task that is ready to execute.
*/
#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31UL - ulPortCountLeadingZeros( ( uxReadyPriorities ) ) )
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
/*-----------------------------------------------------------*/
/* *INDENT-OFF* */
#ifdef __cplusplus
}
#endif
/* *INDENT-ON* */
#endif /* PORTMACROCOMMON_H */
@@ -0,0 +1,96 @@
/*
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: MIT AND BSD-3-Clause
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*/
#ifndef RP2040_CONFIG_H
#define RP2040_CONFIG_H
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
/* configUSE_DYNAMIC_EXCEPTION_HANDLERS == 1 means set the exception handlers dynamically on cores
* that need them in case the user has set up distinct vector table offsets per core
*/
#ifndef configUSE_DYNAMIC_EXCEPTION_HANDLERS
#if defined( PICO_NO_RAM_VECTOR_TABLE ) && ( PICO_NO_RAM_VECTOR_TABLE == 1 )
#define configUSE_DYNAMIC_EXCEPTION_HANDLERS 0
#else
#define configUSE_DYNAMIC_EXCEPTION_HANDLERS 1
#endif
#endif
/* configSUPPORT_PICO_SYNC_INTEROP == 1 means that SDK pico_sync
* sem/mutex/queue etc. will work correctly when called from FreeRTOS tasks
*/
#ifndef configSUPPORT_PICO_SYNC_INTEROP
#if LIB_PICO_SYNC
#define configSUPPORT_PICO_SYNC_INTEROP 1
#endif
#endif
/* configSUPPORT_PICO_SYNC_INTEROP == 1 means that SDK pico_time
* sleep_ms/sleep_us/sleep_until will work correctly when called from FreeRTOS
* tasks, and will actually block at the FreeRTOS level
*/
#ifndef configSUPPORT_PICO_TIME_INTEROP
#if LIB_PICO_TIME
#define configSUPPORT_PICO_TIME_INTEROP 1
#endif
#endif
#if ( configNUMBER_OF_CORES > 1 )
/* configTICK_CORE indicates which core should handle the SysTick
* interrupts */
#ifndef configTICK_CORE
#define configTICK_CORE 0
#endif
#endif
#if (configNUMBER_OF_CORES != 1)
/* This SMP port requires two spin locks, which are claimed from the SDK.
* the spin lock numbers to be used are defined statically and defaulted here
* to the values nominally set aside for RTOS by the SDK */
#ifndef configSMP_SPINLOCK_0
#define configSMP_SPINLOCK_0 PICO_SPINLOCK_ID_OS1
#endif
#ifndef configSMP_SPINLOCK_1
#define configSMP_SPINLOCK_1 PICO_SPINLOCK_ID_OS2
#endif
#endif
/* *INDENT-OFF* */
#ifdef __cplusplus
}
#endif
/* *INDENT-ON* */
#endif /* ifndef RP2040_CONFIG_H */
@@ -0,0 +1,66 @@
# Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
#
# SPDX-License-Identifier: BSD-3-Clause
# This is a copy of <PICO_SDK_PATH>/external/pico_sdk_import.cmake
# This can be dropped into an external project to help locate this SDK
# It should be include()ed prior to project()
if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH))
set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')")
endif ()
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT))
set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT})
message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')")
endif ()
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH))
set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH})
message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')")
endif ()
set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK")
set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable")
set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK")
if (NOT PICO_SDK_PATH)
if (PICO_SDK_FETCH_FROM_GIT)
include(FetchContent)
set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR})
if (PICO_SDK_FETCH_FROM_GIT_PATH)
get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}")
endif ()
FetchContent_Declare(
pico_sdk
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
GIT_TAG master
)
if (NOT pico_sdk)
message("Downloading Raspberry Pi Pico SDK")
FetchContent_Populate(pico_sdk)
set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR})
endif ()
set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE})
else ()
message(FATAL_ERROR
"SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git."
)
endif ()
endif ()
get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
if (NOT EXISTS ${PICO_SDK_PATH})
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found")
endif ()
set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake)
if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE})
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK")
endif ()
set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE)
include(${PICO_SDK_INIT_CMAKE_FILE})
@@ -0,0 +1,50 @@
cmake_minimum_required(VERSION 3.13)
if (NOT TARGET _FreeRTOS_kernel_inclusion_marker)
add_library(_FreeRTOS_kernel_inclusion_marker INTERFACE)
# Pull in PICO SDK (must be before project)
include(pico_sdk_import.cmake)
if (PICO_SDK_VERSION_STRING VERSION_LESS "2.0.0")
message(FATAL_ERROR "Require at least Raspberry Pi Pico SDK version 2.0.0")
endif()
if (NOT FREERTOS_KERNEL_PATH)
get_filename_component(FREERTOS_KERNEL_PATH ${CMAKE_CURRENT_LIST_DIR}/../../../.. REALPATH)
endif ()
message(DEBUG "FREERTOS_KERNEL_PATH is ${FREERTOS_KERNEL_PATH}")
project(FreeRTOS-Kernel C CXX)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
pico_is_top_level_project(FREERTOS_KERNEL_TOP_LEVEL_PROJECT)
# if the SDK has already been initialized, then just add our libraries now - this allows
# this FreeRTOS port to just be added as a sub-directory or include within another project, rather than
# having to include it at the top level before pico_sdk_init()
if (TARGET _pico_sdk_inclusion_marker)
if (PICO_SDK_VERSION_STRING VERSION_LESS "1.3.2")
message(FATAL_ERROR "Require at least Raspberry Pi Pico SDK version 1.3.2 to include FreeRTOS after pico_sdk_init()")
endif()
include(${CMAKE_CURRENT_LIST_DIR}/library.cmake)
else()
# The real work gets done in library.cmake which is called at the end of pico_sdk_init
list(APPEND PICO_SDK_POST_LIST_FILES ${CMAKE_CURRENT_LIST_DIR}/library.cmake)
if (PICO_SDK_VERSION_STRING VERSION_LESS "1.3.2")
# We need to inject the following header file into ALL SDK files (which we do via the config header)
list(APPEND PICO_CONFIG_HEADER_FILES ${CMAKE_CURRENT_LIST_DIR}/include/freertos_sdk_config.h)
endif()
if (FREERTOS_KERNEL_TOP_LEVEL_PROJECT)
message("FreeRTOS: initialize SDK since we're the top-level")
# Initialize the SDK
pico_sdk_init()
else()
set(FREERTOS_KERNEL_PATH ${FREERTOS_KERNEL_PATH} PARENT_SCOPE)
set(PICO_CONFIG_HEADER_FILES ${PICO_CONFIG_HEADER_FILES} PARENT_SCOPE)
set(PICO_SDK_POST_LIST_FILES ${PICO_SDK_POST_LIST_FILES} PARENT_SCOPE)
endif()
endif()
endif()
@@ -0,0 +1,5 @@
[{000214A0-0000-0000-C000-000000000046}]
Prop3=19,11
[InternetShortcut]
IDList=
URL=https://www.FreeRTOS.org/Using-FreeRTOS-on-RISC-V.html
@@ -0,0 +1,91 @@
# This is a copy of <FREERTOS_KERNEL_PATH>/portable/ThirdParty/GCC/RP2040/FREERTOS_KERNEL_import.cmake
# This can be dropped into an external project to help locate the FreeRTOS kernel
# It should be include()ed prior to project(). Alternatively this file may
# or the CMakeLists.txt in this directory may be included or added via add_subdirectory
# respectively.
if (DEFINED ENV{FREERTOS_KERNEL_PATH} AND (NOT FREERTOS_KERNEL_PATH))
set(FREERTOS_KERNEL_PATH $ENV{FREERTOS_KERNEL_PATH})
message("Using FREERTOS_KERNEL_PATH from environment ('${FREERTOS_KERNEL_PATH}')")
endif ()
# first pass we look in old tree; second pass we look in new tree
foreach(SEARCH_PASS RANGE 0 1)
if (SEARCH_PASS)
# ports may be moving to submodule in the future
set(FREERTOS_KERNEL_RP2040_RELATIVE_PATH "portable/ThirdParty/Community-Supported-Ports/GCC")
set(FREERTOS_KERNEL_RP2040_BACK_PATH "../../../../..")
else()
set(FREERTOS_KERNEL_RP2040_RELATIVE_PATH "portable/ThirdParty/GCC")
set(FREERTOS_KERNEL_RP2040_BACK_PATH "../../../..")
endif()
if(PICO_PLATFORM STREQUAL "rp2040")
set(FREERTOS_KERNEL_RP2040_RELATIVE_PATH "${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}/RP2040")
else()
if (PICO_PLATFORM STREQUAL "rp2350-riscv")
set(FREERTOS_KERNEL_RP2040_RELATIVE_PATH "${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}/RP2350_RISC-V")
else()
set(FREERTOS_KERNEL_RP2040_RELATIVE_PATH "${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}/RP2350_ARM_NTZ")
endif()
endif()
if (NOT FREERTOS_KERNEL_PATH)
# check if we are inside the FreeRTOS kernel tree (i.e. this file has been included directly)
get_filename_component(_ACTUAL_PATH ${CMAKE_CURRENT_LIST_DIR} REALPATH)
get_filename_component(_POSSIBLE_PATH ${CMAKE_CURRENT_LIST_DIR}/${FREERTOS_KERNEL_RP2040_BACK_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH} REALPATH)
if (_ACTUAL_PATH STREQUAL _POSSIBLE_PATH)
get_filename_component(FREERTOS_KERNEL_PATH ${CMAKE_CURRENT_LIST_DIR}/${FREERTOS_KERNEL_RP2040_BACK_PATH} REALPATH)
endif()
if (_ACTUAL_PATH STREQUAL _POSSIBLE_PATH)
get_filename_component(FREERTOS_KERNEL_PATH ${CMAKE_CURRENT_LIST_DIR}/${FREERTOS_KERNEL_RP2040_BACK_PATH} REALPATH)
message("Setting FREERTOS_KERNEL_PATH to ${FREERTOS_KERNEL_PATH} based on location of FreeRTOS-Kernel-import.cmake")
break()
elseif (PICO_SDK_PATH AND EXISTS "${PICO_SDK_PATH}/../FreeRTOS-Kernel")
set(FREERTOS_KERNEL_PATH ${PICO_SDK_PATH}/../FreeRTOS-Kernel)
message("Defaulting FREERTOS_KERNEL_PATH as sibling of PICO_SDK_PATH: ${FREERTOS_KERNEL_PATH}")
break()
endif()
endif ()
if (NOT FREERTOS_KERNEL_PATH)
foreach(POSSIBLE_SUFFIX Source FreeRTOS-Kernel FreeRTOS/Source)
# check if FreeRTOS-Kernel exists under directory that included us
set(SEARCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR})
get_filename_component(_POSSIBLE_PATH ${SEARCH_ROOT}/${POSSIBLE_SUFFIX} REALPATH)
if (EXISTS ${_POSSIBLE_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}/CMakeLists.txt)
get_filename_component(FREERTOS_KERNEL_PATH ${_POSSIBLE_PATH} REALPATH)
message("Setting FREERTOS_KERNEL_PATH to '${FREERTOS_KERNEL_PATH}' found relative to enclosing project")
break()
endif()
endforeach()
if (FREERTOS_KERNEL_PATH)
break()
endif()
endif()
# user must have specified
if (FREERTOS_KERNEL_PATH)
if (EXISTS "${FREERTOS_KERNEL_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}")
break()
endif()
endif()
endforeach ()
if (NOT FREERTOS_KERNEL_PATH)
message(FATAL_ERROR "FreeRTOS location was not specified. Please set FREERTOS_KERNEL_PATH.")
endif()
set(FREERTOS_KERNEL_PATH "${FREERTOS_KERNEL_PATH}" CACHE PATH "Path to the FreeRTOS Kernel")
get_filename_component(FREERTOS_KERNEL_PATH "${FREERTOS_KERNEL_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
if (NOT EXISTS ${FREERTOS_KERNEL_PATH})
message(FATAL_ERROR "Directory '${FREERTOS_KERNEL_PATH}' not found")
endif()
if (NOT EXISTS ${FREERTOS_KERNEL_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}/CMakeLists.txt)
message(FATAL_ERROR "Directory '${FREERTOS_KERNEL_PATH}' does not contain a '${PICO_PLATFORM}' port here: ${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}")
endif()
set(FREERTOS_KERNEL_PATH ${FREERTOS_KERNEL_PATH} CACHE PATH "Path to the FreeRTOS_KERNEL" FORCE)
add_subdirectory(${FREERTOS_KERNEL_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH} FREERTOS_KERNEL)
@@ -0,0 +1,23 @@
BSD-3-Clause License
Copyright (c) 2020-2021 Raspberry Pi (Trading) Ltd.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,65 @@
## Overview
This directory provides an SMP FreeRTOS-Kernel port that can be used with the Raspberry Pi Pico SDK on RP2350. It supports:
* Simple CMake INTERFACE libraries, to provide the FreeRTOS-Kernel and also the individual allocator types, without copying code into the user's project.
* Running the FreeRTOS-Kernel and tasks on either core 0 or core 1, or both.
* Use of SDK synchronization primitives (such as mutexes, semaphores, queues from pico_sync) between FreeRTOS tasks and code executing on a non FreeRTOS core, or in IRQ handlers.
Note that whilst this SMP version can be run on just a single (either) core, it is probably
more efficient to use the non SMP version in the main FreeRTOS-Kernel branch in that case.
## Using this port
You can copy [FreeRTOS_Kernel_import.cmake](FreeRTOS_Kernel_import.cmake) into your project, and
add the following in your `CMakeLists.txt`:
```cmake
include(FreeRTOS_Kernel_import.cmake)
```
This will locate the FreeRTOS kernel if it is a direct sub-module of your project, or if you provide the
`FREERTOS_KERNEL_PATH` variable in your environment or via `-DFREERTOS_KERNEL_PATH=/path/to/FreeRTOS-Kernel` on the CMake command line.
**NOTE:** If you are using version 1.3.1 or older of the Raspberry Pi Pico SDK then this line must appear before the
`pico_sdk_init()` and will cause FreeRTOS to be included/required in all RP2040 targets in your project. After this SDK
version, you can include the FreeRTOS-Kernel support later in your CMake build (possibly in a subdirectory) and the
FreeRTOS-Kernel support will only apply to those targets which explicitly include FreeRTOS support.
As an alternative to the `import` statement above, you can just add this directory directly via thw following (with
the same placement restrictions related to the Raspberry Pi Pico SDK version above):
```cmake
add_subdirectory(path/to/this/directory FreeRTOS-Kernel)
```
## FreeRTOS configuration for Armv8-M
The following standard FreeRTOS ARM options are required for RP2350"
These three options must be specified as follows, as only RP2040-like FreeRTOS implementation only is supported currently; running in at a single privilege level in the secure statea.
```c
#define configENABLE_MPU 0
#define configENABLE_TRUSTZONE 0
#define configRUN_FREERTOS_SECURE_ONLY 1
```
You can set the following to enable save/restore of FPU state (you should set this is you are using floating point operations)
```c
#define configENABLE_FPU 1
```
As of right now this is the only value of configMAX_SYSCALL_INTERRUPT_PRIORITY that has been tested
```c
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 16
```
## Advanced Configuration
Some additional `config` options are defined [here](include/rp2040_config.h) which control some low level implementation details.
## Known Limitations
- Hazard3 IRQ premption is not currently supported on either core even if only one core is running FreeRTOS
@@ -0,0 +1,68 @@
/*
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/*
* The FreeRTOS kernel's RISC-V port is split between the the code that is
* common across all currently supported RISC-V chips (implementations of the
* RISC-V ISA), and code that tailors the port to a specific RISC-V chip:
*
* + FreeRTOS\Source\portable\GCC\RISC-V\portASM.S contains the code that
* is common to all currently supported RISC-V chips. There is only one
* portASM.S file because the same file is built for all RISC-V target chips.
*
* + Header files called freertos_risc_v_chip_specific_extensions.h contain the
* code that tailors the FreeRTOS kernel's RISC-V port to a specific RISC-V
* chip. There are multiple freertos_risc_v_chip_specific_extensions.h files
* as there are multiple RISC-V chip implementations.
*
* !!!NOTE!!!
* TAKE CARE TO INCLUDE THE CORRECT freertos_risc_v_chip_specific_extensions.h
* HEADER FILE FOR THE CHIP IN USE. This is done using the assembler's (not the
* compiler's!) include path. For example, if the chip in use includes a core
* local interrupter (CLINT) and does not include any chip specific register
* extensions then add the path below to the assembler's include path:
* FreeRTOS\Source\portable\GCC\RISC-V\chip_specific_extensions\RISCV_MTIME_CLINT_no_extensions
*
*/
#ifndef __FREERTOS_RISC_V_EXTENSIONS_H__
#define __FREERTOS_RISC_V_EXTENSIONS_H__
#define portasmHAS_MTIME 1
#define portasmADDITIONAL_CONTEXT_SIZE 0
.macro portasmSAVE_ADDITIONAL_REGISTERS
/* No additional registers to save, so this macro does nothing. */
.endm
.macro portasmRESTORE_ADDITIONAL_REGISTERS
/* No additional registers to restore, so this macro does nothing. */
.endm
#endif /* __FREERTOS_RISC_V_EXTENSIONS_H__ */
@@ -0,0 +1,77 @@
/*
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*/
#ifndef FREERTOS_SDK_CONFIG_H
#define FREERTOS_SDK_CONFIG_H
#ifndef __ASSEMBLER__
#include "FreeRTOSConfig.h"
#include "rp2040_config.h"
#ifndef PICO_USE_MALLOC_MUTEX
/* malloc needs to be made thread safe */
#define PICO_USE_MALLOC_MUTEX 1
#endif /* PICO_USE_MALLOC_MUTEX */
#if ( configSUPPORT_PICO_SYNC_INTEROP == 1 )
/* increase the amount of time it may reasonably take to wake us up */
#ifndef PICO_TIME_SLEEP_OVERHEAD_ADJUST_US
#define PICO_TIME_SLEEP_OVERHEAD_ADJUST_US 150
#endif
#define lock_owner_id_t uint32_t
extern uint32_t ulPortLockGetCurrentOwnerId( void );
#define lock_get_caller_owner_id() ulPortLockGetCurrentOwnerId()
#define LOCK_INVALID_OWNER_ID ( ( uint32_t ) -1 )
struct lock_core;
#ifndef lock_internal_spin_unlock_with_wait
extern void vPortLockInternalSpinUnlockWithWait( struct lock_core * pxLock,
uint32_t ulSave );
#define lock_internal_spin_unlock_with_wait( lock, save ) vPortLockInternalSpinUnlockWithWait( lock, save )
#endif
#ifndef lock_internal_spin_unlock_with_notify
extern void vPortLockInternalSpinUnlockWithNotify( struct lock_core * pxLock,
uint32_t save );
#define lock_internal_spin_unlock_with_notify( lock, save ) vPortLockInternalSpinUnlockWithNotify( lock, save );
#endif
#ifndef lock_internal_spin_unlock_with_best_effort_wait_or_timeout
extern bool xPortLockInternalSpinUnlockWithBestEffortWaitOrTimeout( struct lock_core * pxLock,
uint32_t ulSave,
absolute_time_t uxUntil );
#define lock_internal_spin_unlock_with_best_effort_wait_or_timeout( lock, save, until ) \
xPortLockInternalSpinUnlockWithBestEffortWaitOrTimeout( lock, save, until )
#endif
#endif /* configSUPPORT_PICO_SYNC_INTEROP */
#if ( configSUPPORT_PICO_TIME_INTEROP == 1 )
extern void xPortSyncInternalYieldUntilBefore( absolute_time_t t );
#define sync_internal_yield_until_before( t ) xPortSyncInternalYieldUntilBefore( t )
#endif /* configSUPPORT_PICO_TIME_INTEROP */
#endif /* __ASSEMBLER__ */
#endif /* ifndef FREERTOS_SDK_CONFIG_H */
@@ -0,0 +1,264 @@
/*
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
#ifndef PORTCONTEXT_H
#define PORTCONTEXT_H
#include "pico.h"
#include "hardware/regs/rvcsr.h"
#include "hardware/regs/intctrl.h"
/*
* todo this is currently disabled; as it certainly breaks
* the RP2 on_core_zero & on_core_one interrupt tests in FreeRTOS
*/
#ifndef portcontextALLOW_NESTED_IRQs
#define portcontextALLOW_NESTED_IRQs 0
#endif
#if __riscv_xlen == 64
#define portWORD_SIZE 8
#define store_x sd
#define load_x ld
#elif __riscv_xlen == 32
#define store_x sw
#define load_x lw
#define portWORD_SIZE 4
#else
#error Assembler did not define __riscv_xlen
#endif
#include "freertos_risc_v_chip_specific_extensions.h"
/* Only the standard core registers are stored by default. Any additional
* registers must be saved by the portasmSAVE_ADDITIONAL_REGISTERS and
* portasmRESTORE_ADDITIONAL_REGISTERS macros - which can be defined in a chip
* specific version of freertos_risc_v_chip_specific_extensions.h. See the
* notes at the top of portASM.S file. */
#ifdef __riscv_32e
#define portCONTEXT_SIZE ( 15 * portWORD_SIZE )
#define portCRITICAL_NESTING_OFFSET 13
#define portMSTATUS_OFFSET 14
#else
#define portCONTEXT_SIZE ( 31 * portWORD_SIZE )
#define portCRITICAL_NESTING_OFFSET 29
#define portMSTATUS_OFFSET 30
#endif
/*-----------------------------------------------------------*/
/*
* OK this is ugly; we cannot use configNUMBER_OF_CORES because FreeRTOSConfig.h is not required to be ASM includable;
* So we have a global pointer that is either to a value 0 for configNUMBER_OF_CORES == 1, or points to the SIO
* reg on configNUMBER_OF_CORES == 1
*/
.extern pxCurrentCoreID
/*
* Note also we must use our own symbol, because pxCurrentTCB is defined by tasks.c for configNUMBER_OF_CORES == 1
* vs pCurrentTCBs for configNUMBER_OF_CORES != 1
*/
.extern pxCurrentTCBArray
.extern xCriticalNestingArray
.extern xISRStackTop
/*-----------------------------------------------------------*/
.macro portcontextGET_CORE_ID out_reg
load_x \out_reg, pxCurrentCoreID
load_x \out_reg, 0 ( \out_reg )
.endm
.macro portcontextGET_CURRENT_TCB_FOR_CORE core_reg, out_reg
/* todo wasteful indirections here because we don't have configNUMBER_OF_CORES */
la \out_reg, pxCurrentTCBArray
load_x \out_reg, 0 ( \out_reg )
sh2add \out_reg, \core_reg, \out_reg
load_x \out_reg, 0 ( \out_reg )
.endm
.macro portcontextGET_CRITICAL_NESTING_PTR_FOR_CORE core_reg, out_reg
load_x \out_reg, xCriticalNestingArray
sh2add \out_reg, \core_reg, \out_reg
.endm
.macro portcontextSWITCH_TO_ISR_STACK reg_pISRStackTop, reg_ISRStackTop
la \reg_pISRStackTop, SIO_BASE
load_x \reg_pISRStackTop, 0 ( \reg_pISRStackTop )
la \reg_ISRStackTop, xISRStackTops
sh2add \reg_pISRStackTop, \reg_pISRStackTop, \reg_ISRStackTop
load_x \reg_ISRStackTop, 0 ( \reg_pISRStackTop )
beqz \reg_ISRStackTop, no_isr_stack\@
mv sp, \reg_ISRStackTop
no_isr_stack\@:
.endm
/*-----------------------------------------------------------*/
.macro portcontextSAVE_CONTEXT_INTERNAL
addi sp, sp, -portCONTEXT_SIZE
store_x x1, 1 * portWORD_SIZE( sp )
store_x x5, 2 * portWORD_SIZE( sp )
store_x x6, 3 * portWORD_SIZE( sp )
store_x x7, 4 * portWORD_SIZE( sp )
store_x x8, 5 * portWORD_SIZE( sp )
store_x x9, 6 * portWORD_SIZE( sp )
store_x x10, 7 * portWORD_SIZE( sp )
store_x x11, 8 * portWORD_SIZE( sp )
store_x x12, 9 * portWORD_SIZE( sp )
store_x x13, 10 * portWORD_SIZE( sp )
store_x x14, 11 * portWORD_SIZE( sp )
store_x x15, 12 * portWORD_SIZE( sp )
#ifndef __riscv_32e
store_x x16, 13 * portWORD_SIZE( sp )
store_x x17, 14 * portWORD_SIZE( sp )
store_x x18, 15 * portWORD_SIZE( sp )
store_x x19, 16 * portWORD_SIZE( sp )
store_x x20, 17 * portWORD_SIZE( sp )
store_x x21, 18 * portWORD_SIZE( sp )
store_x x22, 19 * portWORD_SIZE( sp )
store_x x23, 20 * portWORD_SIZE( sp )
store_x x24, 21 * portWORD_SIZE( sp )
store_x x25, 22 * portWORD_SIZE( sp )
store_x x26, 23 * portWORD_SIZE( sp )
store_x x27, 24 * portWORD_SIZE( sp )
store_x x28, 25 * portWORD_SIZE( sp )
store_x x29, 26 * portWORD_SIZE( sp )
store_x x30, 27 * portWORD_SIZE( sp )
store_x x31, 28 * portWORD_SIZE( sp )
#endif /* ifndef __riscv_32e */
portcontextGET_CORE_ID t1
portcontextGET_CRITICAL_NESTING_PTR_FOR_CORE t1, t0
load_x t0, 0 ( t0 )
store_x t0, portCRITICAL_NESTING_OFFSET * portWORD_SIZE( sp ) /* Store the critical nesting value to the stack. */
csrr t0, mstatus /* Required for MPIE bit. */
store_x t0, portMSTATUS_OFFSET * portWORD_SIZE( sp )
portasmSAVE_ADDITIONAL_REGISTERS /* Defined in freertos_risc_v_chip_specific_extensions.h to save any registers unique to the RISC-V implementation. */
portcontextGET_CORE_ID t1
portcontextGET_CURRENT_TCB_FOR_CORE t1, t0
store_x sp, 0 ( t0 ) /* Write sp to first TCB member. */
.endm
/*-----------------------------------------------------------*/
.macro portcontextSAVE_EXCEPTION_CONTEXT
portcontextSAVE_CONTEXT_INTERNAL
csrr a0, mcause
csrr a1, mepc
addi a1, a1, 4 /* Synchronous so update exception return address to the instruction after the instruction that generated the exception. */
store_x a1, 0 ( sp ) /* Save updated exception return address. */
portcontextSWITCH_TO_ISR_STACK t0, t1
.endm
/*-----------------------------------------------------------*/
.macro portcontextSAVE_INTERRUPT_CONTEXT
portcontextSAVE_CONTEXT_INTERNAL
csrr a0, mcause
csrr a1, mepc
store_x a1, 0 ( sp ) /* Asynchronous interrupt so save unmodified exception return address. */
portcontextSWITCH_TO_ISR_STACK s10, s11
/*
* s10 is now pISRStackTop for the current core
* s11 is the old value of ISRStackTop
* we expect them to remain saved, and we overwrite the
* pISRStackTop with zero, so we don't overwrite again if nesting is enabled
*/
sw zero, 0 (s10)
.endm
/*-----------------------------------------------------------*/
.macro portcontextRESTORE_CONTEXT
portcontextGET_CORE_ID t0
portcontextGET_CURRENT_TCB_FOR_CORE t0, t1
load_x sp, 0 ( t1 ) /* Read sp from first TCB member. */
/* Load mepc with the address of the instruction in the task to run next. */
load_x t0, 0 ( sp )
csrw mepc, t0
/* Defined in freertos_risc_v_chip_specific_extensions.h to restore any registers unique to the RISC-V implementation. */
portasmRESTORE_ADDITIONAL_REGISTERS
/* Load mstatus with the interrupt enable bits used by the task. */
load_x t0, portMSTATUS_OFFSET * portWORD_SIZE( sp )
csrw mstatus, t0 /* Required for MPIE bit. */
/* Load the address of xCriticalNesting into t1. */
portcontextGET_CORE_ID t0
portcontextGET_CRITICAL_NESTING_PTR_FOR_CORE t0, t1
load_x t0, portCRITICAL_NESTING_OFFSET * portWORD_SIZE( sp ) /* Obtain xCriticalNesting value for this task from task's stack. */
store_x t0, 0 ( t1 ) /* Restore the critical nesting value for this task. */
load_x x1, 1 * portWORD_SIZE( sp )
load_x x5, 2 * portWORD_SIZE( sp )
load_x x6, 3 * portWORD_SIZE( sp )
load_x x7, 4 * portWORD_SIZE( sp )
load_x x8, 5 * portWORD_SIZE( sp )
load_x x9, 6 * portWORD_SIZE( sp )
load_x x10, 7 * portWORD_SIZE( sp )
load_x x11, 8 * portWORD_SIZE( sp )
load_x x12, 9 * portWORD_SIZE( sp )
load_x x13, 10 * portWORD_SIZE( sp )
load_x x14, 11 * portWORD_SIZE( sp )
load_x x15, 12 * portWORD_SIZE( sp )
#ifndef __riscv_32e
load_x x16, 13 * portWORD_SIZE( sp )
load_x x17, 14 * portWORD_SIZE( sp )
load_x x18, 15 * portWORD_SIZE( sp )
load_x x19, 16 * portWORD_SIZE( sp )
load_x x20, 17 * portWORD_SIZE( sp )
load_x x21, 18 * portWORD_SIZE( sp )
load_x x22, 19 * portWORD_SIZE( sp )
load_x x23, 20 * portWORD_SIZE( sp )
load_x x24, 21 * portWORD_SIZE( sp )
load_x x25, 22 * portWORD_SIZE( sp )
load_x x26, 23 * portWORD_SIZE( sp )
load_x x27, 24 * portWORD_SIZE( sp )
load_x x28, 25 * portWORD_SIZE( sp )
load_x x29, 26 * portWORD_SIZE( sp )
load_x x30, 27 * portWORD_SIZE( sp )
load_x x31, 28 * portWORD_SIZE( sp )
#endif /* ifndef __riscv_32e */
addi sp, sp, portCONTEXT_SIZE
mret
.endm
/*-----------------------------------------------------------*/
.macro portcontextRESTORE_INTERUUPT_CONTEXT
/* restore old ISRStackTop */
sw s11, 0 (s10)
portcontextRESTORE_CONTEXT
.endm
#endif /* PORTCONTEXT_H */
@@ -0,0 +1,314 @@
/*
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Copyright (c) 2024 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: MIT AND BSD-3-Clause
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
#ifndef PORTMACRO_H
#define PORTMACRO_H
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
#include "pico.h"
#include "hardware/sync.h"
/*-----------------------------------------------------------
* Port specific definitions.
*
* The settings in this file configure FreeRTOS correctly for the
* given hardware and compiler.
*
* These settings should not be altered.
*-----------------------------------------------------------
*/
/* Type definitions. */
#if __riscv_xlen == 64
#define portSTACK_TYPE uint64_t
#define portBASE_TYPE int64_t
#define portUBASE_TYPE uint64_t
#define portMAX_DELAY ( TickType_t ) 0xffffffffffffffffUL
#define portPOINTER_SIZE_TYPE uint64_t
#elif __riscv_xlen == 32
#define portSTACK_TYPE uint32_t
// todo amy; these cause compilation failure in the RP2040 FreeRTOS examples; need to go look what the "full" tests do on RISC-V
//#define portBASE_TYPE int32_t
//#define portUBASE_TYPE uint32_t
#define portBASE_TYPE long
#define portUBASE_TYPE unsigned long
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
#else /* if __riscv_xlen == 64 */
#error "Assembler did not define __riscv_xlen"
#endif /* if __riscv_xlen == 64 */
typedef portSTACK_TYPE StackType_t;
typedef portBASE_TYPE BaseType_t;
typedef portUBASE_TYPE UBaseType_t;
typedef portUBASE_TYPE TickType_t;
/* Legacy type definitions. */
#define portCHAR char
#define portFLOAT float
#define portDOUBLE double
#define portLONG long
#define portSHORT short
/* 32-bit tick type on a 32-bit architecture, so reads of the tick count do
* not need to be guarded with a critical section. */
#define portTICK_TYPE_IS_ATOMIC 1
/*-----------------------------------------------------------*/
/* Architecture specifics. */
#define portSTACK_GROWTH ( -1 )
#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
#ifdef __riscv_32e
#define portBYTE_ALIGNMENT 8 /* RV32E uses RISC-V EABI with reduced stack alignment requirements */
#else
#define portBYTE_ALIGNMENT 16
#endif
/* Multi-core */
#define portMAX_CORE_COUNT 2
/* Check validity of number of cores specified in config */
#if ( configNUMBER_OF_CORES < 1 || portMAX_CORE_COUNT < configNUMBER_OF_CORES )
#error "Invalid number of cores specified in config!"
#endif
#if ( configTICK_CORE < 0 || configTICK_CORE > configNUMBER_OF_CORES )
#error "Invalid tick core specified in config!"
#endif
/* FreeRTOS core id is always zero based, so always 0 if we're running on only one core */
#if configNUMBER_OF_CORES != 1
#define portGET_CORE_ID() get_core_num()
#else
#define portGET_CORE_ID() 0
#endif
#define portCHECK_IF_IN_ISR() \
( { \
uint32_t meicontext; \
__asm volatile ( "csrr %0, %1" : "=r" ( meicontext ): "i" ( RVCSR_MEICONTEXT_OFFSET ):); \
!( meicontext & RVCSR_MEICONTEXT_NOIRQ_BITS ); } )
void vYieldCore( int xCoreID );
#define portYIELD_CORE( a ) vYieldCore( a )
/*-----------------------------------------------------------*/
/* Scheduler utilities. */
#if configNUMBER_OF_CORES == 1
#define portTASK_SWITCH_CONTEXT() vTaskSwitchContext()
#else
#define portTASK_SWITCH_CONTEXT() vTaskSwitchContext(portGET_CORE_ID())
#endif
#if ( configSUPPORT_PICO_SYNC_INTEROP == 1 )
/* extra assertion */
extern void vPortYield(void);
#define portYIELD() vPortYield();
#else
#define portYIELD() __asm volatile ( "ecall" );
#endif /* configSUPPORT_PICO_SYNC_INTEROP */
#define portEND_SWITCHING_ISR( xSwitchRequired ) \
do \
{ \
if( xSwitchRequired != pdFALSE ) \
{ \
traceISR_EXIT_TO_SCHEDULER(); \
portTASK_SWITCH_CONTEXT(); \
} \
else \
{ \
traceISR_EXIT(); \
} \
} while( 0 )
#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )
/*-----------------------------------------------------------*/
#define portSET_INTERRUPT_MASK() save_and_disable_interrupts()
#define portCLEAR_INTERRUPT_MASK(state) restore_interrupts( state )
#define portDISABLE_INTERRUPTS() save_and_disable_interrupts()
#define portENABLE_INTERRUPTS() restore_interrupts( RVCSR_MIE_MSIE_BITS )
#if ( configNUMBER_OF_CORES == 1 )
extern size_t xCriticalNesting;
#define portGET_CRITICAL_NESTING_COUNT( xCoreID ) xCriticalNesting
#define portENTER_CRITICAL() \
{ \
portDISABLE_INTERRUPTS(); \
xCriticalNesting++; \
}
#define portEXIT_CRITICAL() \
{ \
xCriticalNesting--; \
if( xCriticalNesting == 0 ) \
{ \
portENABLE_INTERRUPTS(); \
} \
}
#else /* ( configNUMBER_OF_CORES == 1 ) */
extern size_t xCriticalNestings[ configNUMBER_OF_CORES ];
/*
* SMP enabled
*/
extern void vTaskEnterCritical( void );
extern void vTaskExitCritical( void );
extern UBaseType_t vTaskEnterCriticalFromISR( void );
extern void vTaskExitCriticalFromISR( UBaseType_t uxSavedInterruptStatus );
#define portENTER_CRITICAL() vTaskEnterCritical()
#define portEXIT_CRITICAL() vTaskExitCritical()
#define portENTER_CRITICAL_FROM_ISR() vTaskEnterCriticalFromISR()
#define portEXIT_CRITICAL_FROM_ISR( x ) vTaskExitCriticalFromISR( x )
#define portGET_CRITICAL_NESTING_COUNT( xCoreID ) ( xCriticalNestings[ ( xCoreID ) ] )
#define portSET_CRITICAL_NESTING_COUNT( xCoreID, x ) ( xCriticalNestings[ ( xCoreID ) ] = ( x ) )
#define portINCREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( xCriticalNestings[ ( xCoreID ) ]++ )
#define portDECREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( xCriticalNestings[ ( xCoreID ) ]-- )
#endif /* if ( configNUMBER_OF_CORES == 1 ) */
/*-----------------------------------------------------------*/
/* Architecture specific optimisations. */
#ifndef configUSE_PORT_OPTIMISED_TASK_SELECTION
/* Not supported on SMP */
#if ( configNUMBER_OF_CORES == 1 )
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
#endif
#endif
#if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 )
/* Check the configuration. */
#if ( configMAX_PRIORITIES > 32 )
#error "configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32. It is very rare that a system requires more than 10 to 15 difference priorities as tasks that share a priority will time slice."
#endif
/* Store/clear the ready priorities in a bit map. */
#define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) )
#define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )
/*-----------------------------------------------------------*/
#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31UL - __builtin_clz( uxReadyPriorities ) )
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
/*-----------------------------------------------------------*/
/* Task function macros as described on the FreeRTOS.org WEB site. These are
* not necessary for to use this port. They are defined so the common demo
* files (which build with all the ports) will build. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void * pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void * pvParameters )
/*-----------------------------------------------------------*/
#define portNOP() __asm volatile ( " nop " )
#define portINLINE __inline
#ifndef portFORCE_INLINE
#define portFORCE_INLINE inline __attribute__( ( always_inline ) )
#endif
#define portMEMORY_BARRIER() __asm volatile ( "" ::: "memory" )
/*-----------------------------------------------------------*/
/* Critical section management. */
#define portCRITICAL_NESTING_IN_TCB 0
#define portRTOS_SPINLOCK_COUNT 2
/* Note this is a single method with uxAcquire parameter since we have
* static vars, the method is always called with a compile time constant for
* uxAcquire, and the compiler should do the right thing! */
static inline void vPortRecursiveLock( BaseType_t xCoreID,
uint32_t ulLockNum,
spin_lock_t * pxSpinLock,
BaseType_t uxAcquire )
{
static volatile uint8_t ucOwnedByCore[ portMAX_CORE_COUNT ][portRTOS_SPINLOCK_COUNT];
static volatile uint8_t ucRecursionCountByLock[ portRTOS_SPINLOCK_COUNT ];
configASSERT( ulLockNum < portRTOS_SPINLOCK_COUNT );
if( uxAcquire )
{
if (!spin_try_lock_unsafe(pxSpinLock)) {
if( ucOwnedByCore[ xCoreID ][ ulLockNum ] )
{
configASSERT( ucRecursionCountByLock[ ulLockNum ] != 255u );
ucRecursionCountByLock[ ulLockNum ]++;
return;
}
spin_lock_unsafe_blocking(pxSpinLock);
}
configASSERT( ucRecursionCountByLock[ ulLockNum ] == 0 );
ucRecursionCountByLock[ ulLockNum ] = 1;
ucOwnedByCore[ xCoreID ][ ulLockNum ] = 1;
}
else
{
configASSERT( ( ucOwnedByCore[ xCoreID ] [ulLockNum ] ) != 0 );
configASSERT( ucRecursionCountByLock[ ulLockNum ] != 0 );
if( !--ucRecursionCountByLock[ ulLockNum ] )
{
ucOwnedByCore[ xCoreID ] [ ulLockNum ] = 0;
spin_unlock_unsafe(pxSpinLock);
}
}
}
#if ( configNUMBER_OF_CORES == 1 )
#define portGET_ISR_LOCK( xCoreID )
#define portRELEASE_ISR_LOCK( xCoreID )
#define portGET_TASK_LOCK( xCoreID )
#define portRELEASE_TASK_LOCK( xCoreID )
#else /* configNUMBER_OF_CORES == 1 */
#define portGET_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( xCoreID ), 0, spin_lock_instance( configSMP_SPINLOCK_0 ), pdTRUE )
#define portRELEASE_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( xCoreID ), 0, spin_lock_instance( configSMP_SPINLOCK_0 ), pdFALSE )
#define portGET_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( xCoreID ), 1, spin_lock_instance( configSMP_SPINLOCK_1 ), pdTRUE )
#define portRELEASE_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( xCoreID ), 1, spin_lock_instance( configSMP_SPINLOCK_1 ), pdFALSE )
#endif /* configNUMBER_OF_CORES == 1 */
/* *INDENT-OFF* */
#ifdef __cplusplus
}
#endif
/* *INDENT-ON* */
#endif /* PORTMACRO_H */
@@ -0,0 +1,96 @@
/*
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: MIT AND BSD-3-Clause
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*/
#ifndef RP2040_CONFIG_H
#define RP2040_CONFIG_H
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
/* configUSE_DYNAMIC_EXCEPTION_HANDLERS == 1 means set the exception handlers dynamically on cores
* that need them in case the user has set up distinct vector table offsets per core
*/
#ifndef configUSE_DYNAMIC_EXCEPTION_HANDLERS
#if defined( PICO_NO_RAM_VECTOR_TABLE ) && ( PICO_NO_RAM_VECTOR_TABLE == 1 )
#define configUSE_DYNAMIC_EXCEPTION_HANDLERS 0
#else
#define configUSE_DYNAMIC_EXCEPTION_HANDLERS 1
#endif
#endif
/* configSUPPORT_PICO_SYNC_INTEROP == 1 means that SDK pico_sync
* sem/mutex/queue etc. will work correctly when called from FreeRTOS tasks
*/
#ifndef configSUPPORT_PICO_SYNC_INTEROP
#if LIB_PICO_SYNC
#define configSUPPORT_PICO_SYNC_INTEROP 1
#endif
#endif
/* configSUPPORT_PICO_SYNC_INTEROP == 1 means that SDK pico_time
* sleep_ms/sleep_us/sleep_until will work correctly when called from FreeRTOS
* tasks, and will actually block at the FreeRTOS level
*/
#ifndef configSUPPORT_PICO_TIME_INTEROP
#if LIB_PICO_TIME
#define configSUPPORT_PICO_TIME_INTEROP 1
#endif
#endif
#if ( configNUMBER_OF_CORES > 1 )
/* configTICK_CORE indicates which core should handle the SysTick
* interrupts */
#ifndef configTICK_CORE
#define configTICK_CORE 0
#endif
#endif
#if (configNUMBER_OF_CORES != 1)
/* This SMP port requires two spin locks, which are claimed from the SDK.
* the spin lock numbers to be used are defined statically and defaulted here
* to the values nominally set aside for RTOS by the SDK */
#ifndef configSMP_SPINLOCK_0
#define configSMP_SPINLOCK_0 PICO_SPINLOCK_ID_OS1
#endif
#ifndef configSMP_SPINLOCK_1
#define configSMP_SPINLOCK_1 PICO_SPINLOCK_ID_OS2
#endif
#endif
/* *INDENT-OFF* */
#ifdef __cplusplus
}
#endif
/* *INDENT-ON* */
#endif /* ifndef RP2040_CONFIG_H */
@@ -0,0 +1,74 @@
# Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
#
# SPDX-License-Identifier: BSD-3-Clause
# Called after the Raspberry Pi Pico SDK has been initialized to add our libraries
add_library(FreeRTOS-Kernel-Core INTERFACE)
target_sources(FreeRTOS-Kernel-Core INTERFACE
${FREERTOS_KERNEL_PATH}/croutine.c
${FREERTOS_KERNEL_PATH}/event_groups.c
${FREERTOS_KERNEL_PATH}/list.c
${FREERTOS_KERNEL_PATH}/queue.c
${FREERTOS_KERNEL_PATH}/stream_buffer.c
${FREERTOS_KERNEL_PATH}/tasks.c
${FREERTOS_KERNEL_PATH}/timers.c
)
target_include_directories(FreeRTOS-Kernel-Core INTERFACE ${FREERTOS_KERNEL_PATH}/include)
if (PICO_SDK_VERSION_STRING VERSION_GREATER_EQUAL "1.3.2")
target_compile_definitions(FreeRTOS-Kernel-Core INTERFACE
PICO_CONFIG_RTOS_ADAPTER_HEADER=${CMAKE_CURRENT_LIST_DIR}/include/freertos_sdk_config.h)
endif()
add_library(FreeRTOS-Kernel INTERFACE)
target_sources(FreeRTOS-Kernel INTERFACE
${CMAKE_CURRENT_LIST_DIR}/port.c
${CMAKE_CURRENT_LIST_DIR}/portASM.S
)
target_include_directories(FreeRTOS-Kernel INTERFACE
${CMAKE_CURRENT_LIST_DIR}/include
${FREERTOS_CONFIG_FILE_DIRECTORY})
target_link_libraries(FreeRTOS-Kernel INTERFACE
FreeRTOS-Kernel-Core
pico_base_headers
hardware_clocks
hardware_exception
hardware_riscv_platform_timer
pico_multicore
)
target_compile_definitions(FreeRTOS-Kernel INTERFACE
LIB_FREERTOS_KERNEL=1
FREE_RTOS_KERNEL_SMP=1
)
add_library(FreeRTOS-Kernel-Static INTERFACE)
target_compile_definitions(FreeRTOS-Kernel-Static INTERFACE
configSUPPORT_STATIC_ALLOCATION=1
configKERNEL_PROVIDED_STATIC_MEMORY=1
)
target_link_libraries(FreeRTOS-Kernel-Static INTERFACE FreeRTOS-Kernel)
add_library(FreeRTOS-Kernel-Heap1 INTERFACE)
target_sources(FreeRTOS-Kernel-Heap1 INTERFACE ${FREERTOS_KERNEL_PATH}/portable/MemMang/heap_1.c)
target_link_libraries(FreeRTOS-Kernel-Heap1 INTERFACE FreeRTOS-Kernel)
add_library(FreeRTOS-Kernel-Heap2 INTERFACE)
target_sources(FreeRTOS-Kernel-Heap2 INTERFACE ${FREERTOS_KERNEL_PATH}/portable/MemMang/heap_2.c)
target_link_libraries(FreeRTOS-Kernel-Heap2 INTERFACE FreeRTOS-Kernel)
add_library(FreeRTOS-Kernel-Heap3 INTERFACE)
target_sources(FreeRTOS-Kernel-Heap3 INTERFACE ${FREERTOS_KERNEL_PATH}/portable/MemMang/heap_3.c)
target_link_libraries(FreeRTOS-Kernel-Heap3 INTERFACE FreeRTOS-Kernel)
add_library(FreeRTOS-Kernel-Heap4 INTERFACE)
target_sources(FreeRTOS-Kernel-Heap4 INTERFACE ${FREERTOS_KERNEL_PATH}/portable/MemMang/heap_4.c)
target_link_libraries(FreeRTOS-Kernel-Heap4 INTERFACE FreeRTOS-Kernel)
add_library(FreeRTOS-Kernel-Heap5 INTERFACE)
target_sources(FreeRTOS-Kernel-Heap5 INTERFACE ${FREERTOS_KERNEL_PATH}/portable/MemMang/heap_5.c)
target_link_libraries(FreeRTOS-Kernel-Heap5 INTERFACE FreeRTOS-Kernel)
@@ -0,0 +1,4 @@
- IRQ premption is currently disabled; this might be easy enough to fix by stacking the core local ISRStackTop, and using 0
for recursing, since that just uses the current one - of course the whole code may not be happy with nested IRQs
- Right now mtvec table and irq handlers are installed on both cores, since the SDK doesn't currently treat them separately.
- Q: Why is critical_nestings stored in TCB on RISC-V?
@@ -0,0 +1,66 @@
# Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
#
# SPDX-License-Identifier: BSD-3-Clause
# This is a copy of <PICO_SDK_PATH>/external/pico_sdk_import.cmake
# This can be dropped into an external project to help locate this SDK
# It should be include()ed prior to project()
if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH))
set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')")
endif ()
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT))
set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT})
message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')")
endif ()
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH))
set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH})
message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')")
endif ()
set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK")
set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable")
set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK")
if (NOT PICO_SDK_PATH)
if (PICO_SDK_FETCH_FROM_GIT)
include(FetchContent)
set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR})
if (PICO_SDK_FETCH_FROM_GIT_PATH)
get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}")
endif ()
FetchContent_Declare(
pico_sdk
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
GIT_TAG master
)
if (NOT pico_sdk)
message("Downloading Raspberry Pi Pico SDK")
FetchContent_Populate(pico_sdk)
set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR})
endif ()
set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE})
else ()
message(FATAL_ERROR
"SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git."
)
endif ()
endif ()
get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
if (NOT EXISTS ${PICO_SDK_PATH})
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found")
endif ()
set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake)
if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE})
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK")
endif ()
set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE)
include(${PICO_SDK_INIT_CMAKE_FILE})
@@ -0,0 +1,714 @@
/*
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Copyright (c) 2024 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: MIT AND BSD-3-Clause
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/*-----------------------------------------------------------
* Implementation of functions defined in portable.h for the RISC-V port.
*----------------------------------------------------------*/
/* Scheduler includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "rp2040_config.h"
#include "hardware/clocks.h"
#include "hardware/exception.h"
#include "hardware/irq.h"
#include "portmacro.h"
/* Standard includes. */
#include "string.h"
/* Let the user override the pre-loading of the initial RA. */
#ifdef configTASK_RETURN_ADDRESS
#define portTASK_RETURN_ADDRESS configTASK_RETURN_ADDRESS
#else
#define portTASK_RETURN_ADDRESS 0
#endif
/*
* LIB_PICO_MULTICORE == 1, if we are linked with pico_multicore (note that
* the non SMP FreeRTOS_Kernel is not linked with pico_multicore itself). We
* use this flag to determine if we need multi-core functionality.
*/
#if ( LIB_PICO_MULTICORE == 1 )
#include "pico/multicore.h"
#endif /* LIB_PICO_MULTICORE */
#ifndef configUSE_ISR_STACK
#define configUSE_ISR_STACK 1
#endif
/* The stack used by interrupt service routines. Set configISR_STACK_SIZE_WORDS
* to use a statically allocated array as the interrupt stack. Alternative leave
* configISR_STACK_SIZE_WORDS undefined and update the linker script so that a
* linker variable names __freertos_irq_stack_top has the same value as the top
* of the stack used by main. Using the linker script method will repurpose the
* stack that was used by main before the scheduler was started for use as the
* interrupt stack after the scheduler has started. */
#ifdef configISR_STACK_SIZE_WORDS
#error configISR_STACK_SIZE_WORDS not yet supported; we need per core ones
static __attribute__( ( aligned( 16 ) ) ) StackType_t xISRStack[ configISR_STACK_SIZE_WORDS ] = { 0 };
const StackType_t xISRStackTop = ( StackType_t ) &( xISRStack[ configISR_STACK_SIZE_WORDS & ~portBYTE_ALIGNMENT_MASK ] );
/* Don't use 0xa5 as the stack fill bytes as that is used by the kernel for
* the task stacks, and so will legitimately appear in many positions within
* the ISR stack. */
#define portISR_STACK_FILL_BYTE 0xee
#else
/*
* If these are 0, then no stack switch is performed.
*
* Note: if configUSE_ISR_STACK == 0, then this is never initialized,
* but we keep this array around, because portASM.S / portContext.h does not
* have access to config variables
*/
StackType_t xISRStackTops[NUM_CORES] = {0};
#endif
#if ( configSUPPORT_PICO_SYNC_INTEROP == 1 || configNUMBER_OF_CORES > 1 )
#include "hardware/irq.h"
#endif /* ( configSUPPORT_PICO_SYNC_INTEROP == 1 || configNUMBER_OF_CORES > 1 ) */
#if ( configSUPPORT_PICO_SYNC_INTEROP == 1 )
#include "pico/lock_core.h"
#include "event_groups.h"
#if configSUPPORT_STATIC_ALLOCATION
static StaticEventGroup_t xStaticEventGroup;
#define pEventGroup ( &xStaticEventGroup )
#endif /* configSUPPORT_STATIC_ALLOCATION */
static EventGroupHandle_t xEventGroup;
#if ( configNUMBER_OF_CORES == 1 )
static EventBits_t uxCrossCoreEventBits;
static spin_lock_t * pxCrossCoreSpinLock; /* protects uxCrossCoreEventBits */
#endif
#endif /* configSUPPORT_PICO_SYNC_INTEROP */
/* Note this is an SDK IRQ priority which use the ARM convention */
#define portMIN_INTERRUPT_PRIORITY ( 255UL )
/*
* Setup the timer to generate the tick interrupts. The implementation in this
* file is weak to allow application writers to change the timer used to
* generate the tick interrupt.
*/
void vPortSetupTimerInterrupt( void ) __attribute__( ( weak ) );
/*-----------------------------------------------------------*/
/* Used to program the machine timer compare register. */
uint64_t ullNextTime = 0ULL;
const uint64_t * pullNextTime = &ullNextTime; /* used by ASM code */
size_t uxTimerIncrementsForOneTick;
volatile uint64_t * pullMachineTimerCompareRegister = NULL;
/* Holds the critical nesting value - deliberately non-zero at start up to
* ensure interrupts are not accidentally enabled before the scheduler starts. */
typedef struct tskTaskControlBlock TCB_t;
#if configNUMBER_OF_CORES == 1
size_t xCriticalNesting = ( size_t ) 0xaaaaaaaa;
size_t *xCriticalNestingArray = &xCriticalNesting;
extern portDONT_DISCARD PRIVILEGED_DATA TCB_t * volatile pxCurrentTCB;
TCB_t * volatile * pxCurrentTCBArray = &pxCurrentTCB;
static uint32_t zero; /* todo we could use a pre-existing zero elsewhere! */
uint32_t * pxCurrentCoreID = &zero;
#else
size_t xCriticalNestings[ configNUMBER_OF_CORES ] = { 0 };
size_t *xCriticalNestingArray = &xCriticalNestings[0];
extern portDONT_DISCARD PRIVILEGED_DATA TCB_t * volatile pxCurrentTCBs[ configNUMBER_OF_CORES ];
TCB_t * volatile * pxCurrentTCBArray = pxCurrentTCBs;
const volatile uint32_t * pxCurrentCoreID = &sio_hw->cpuid;
#endif
/* Used to catch tasks that attempt to return from their implementing function. */
size_t xTaskReturnAddress = ( size_t ) portTASK_RETURN_ADDRESS;
/* Set configCHECK_FOR_STACK_OVERFLOW to 3 to add ISR stack checking to task
* stack checking. A problem in the ISR stack will trigger an assert, not call
* the stack overflow hook function (because the stack overflow hook is specific
* to a task stack, not the ISR stack). */
#if defined( configISR_STACK_SIZE_WORDS ) && ( configCHECK_FOR_STACK_OVERFLOW > 2 )
#warning "This path not tested, or even compiled yet."
static const uint8_t ucExpectedStackBytes[] =
{
portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, \
portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, \
portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, \
portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, \
portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE, portISR_STACK_FILL_BYTE
}; \
#define portCHECK_ISR_STACK() configASSERT( ( memcmp( ( void * ) xISRStack, ( void * ) ucExpectedStackBytes, sizeof( ucExpectedStackBytes ) ) == 0 ) )
#else /* if defined( configISR_STACK_SIZE_WORDS ) && ( configCHECK_FOR_STACK_OVERFLOW > 2 ) */
/* Define the function away. */
#define portCHECK_ISR_STACK()
#endif /* configCHECK_FOR_STACK_OVERFLOW > 2 */
#define INVALID_PRIMARY_CORE_NUM 0xffu
/* The primary core number (the own which has the SysTick handler) */
static uint8_t ucPrimaryCoreNum = INVALID_PRIMARY_CORE_NUM;
/* Initialize to -1 so that when using INTEROP with SDK and running on one core only, we can tell if this is initialized yet */
static int8_t cDoorbellNum = -1;
/* Note: portIS_FREE_RTOS_CORE() also returns false until the scheduler is started */
#if ( configNUMBER_OF_CORES != 1 )
#define portIS_FREE_RTOS_CORE() ( ucPrimaryCoreNum != INVALID_PRIMARY_CORE_NUM )
#else
#define portIS_FREE_RTOS_CORE() ( ucPrimaryCoreNum == get_core_num() )
#endif
/*-----------------------------------------------------------*/
#include "hardware/riscv_platform_timer.h"
void vPortSetupTimerInterrupt( void )
{
riscv_timer_set_fullspeed(true);
uint64_t ullCurrentTime = riscv_timer_get_mtime();
uxTimerIncrementsForOneTick = ( size_t ) ( ( clock_get_hz( clk_sys ) ) / ( configTICK_RATE_HZ ) ); /* Assumes increment won't go over 32-bits. */
pullMachineTimerCompareRegister = ( volatile uint64_t * ) &sio_hw->mtimecmp;
ullNextTime = ullCurrentTime + uxTimerIncrementsForOneTick;
*pullMachineTimerCompareRegister = ullNextTime;
/* Prepare the time to use after the next tick interrupt. */
ullNextTime += uxTimerIncrementsForOneTick;
extern void freertos_risc_v_mtimer_interrupt_handler(void);
#if 1
irq_set_exclusive_handler(SIO_IRQ_MTIMECMP, freertos_risc_v_mtimer_interrupt_handler);
irq_set_enabled(SIO_IRQ_MTIMECMP, true);
#else
riscv_set_csr(mie, RVCSR_MIE_MTIE_BITS);
#endif
}
void vPortInstallVectorTableHandlers(void) {
extern void freertos_risc_v_trap_handler(void);
extern void freertos_risc_v_interrupt_handler(void);
irq_set_riscv_vector_handler(RISCV_VEC_MACHINE_EXCEPTION, freertos_risc_v_trap_handler);
irq_set_riscv_vector_handler(RISCV_VEC_MACHINE_EXTERNAL_IRQ, freertos_risc_v_interrupt_handler);
}
StackType_t xPortInitISRStack(void) {
StackType_t xISRStackTop;
//( StackType_t ) /*__freertos_irq_stack_top*/__StackTop;
// todo fixup for allocated stacks
if (get_core_num())
{
extern const uint32_t __StackOneTop[];
xISRStackTop = ( StackType_t ) __StackOneTop;
}
else
{
extern const uint32_t __StackTop[];
xISRStackTop = ( StackType_t ) __StackTop;
}
xISRStackTops[get_core_num()] = xISRStackTop;
return xISRStackTop;
}
/*-----------------------------------------------------------*/
#if ( LIB_PICO_MULTICORE == 1 ) && ( configSUPPORT_PICO_SYNC_INTEROP == 1 || configNUMBER_OF_CORES > 1)
static void prvDoorbellInterruptHandler()
{
if (cDoorbellNum >= 0 && multicore_doorbell_is_set_current_core(cDoorbellNum))
{
multicore_doorbell_clear_current_core(cDoorbellNum);
#if ( configNUMBER_OF_CORES != 1 )
portYIELD_FROM_ISR( pdTRUE );
#elif ( configSUPPORT_PICO_SYNC_INTEROP == 1 )
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
uint32_t ulSave = spin_lock_blocking( pxCrossCoreSpinLock );
EventBits_t ulBits = uxCrossCoreEventBits;
uxCrossCoreEventBits &= ~ulBits;
spin_unlock( pxCrossCoreSpinLock, ulSave );
xEventGroupSetBitsFromISR( xEventGroup, ulBits, &xHigherPriorityTaskWoken );
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
#endif /* configNUMBER_OF_CORES != 1 */
}
}
#endif /* ( LIB_PICO_MULTICORE == 1 ) && ( configSUPPORT_PICO_SYNC_INTEROP == 1 || configNUMBER_OF_CORES > 1) */
/*-----------------------------------------------------------*/
#if ( configNUMBER_OF_CORES != 1 )
static BaseType_t xPortStartSchedulerOnCore( void )
{
extern void xPortStartFirstTask( void );
#if ( configUSE_ISR_STACK == 1)
StackType_t xISRStackTop = xPortInitISRStack();
#if ( configASSERT_DEFINED == 1 )
{
/* Check alignment of the interrupt stack - which is the same as the
* stack that was being used by main() prior to the scheduler being
* started. */
configASSERT( ( xISRStackTop & portBYTE_ALIGNMENT_MASK ) == 0 );
#ifdef configISR_STACK_SIZE_WORDS
{
memset( ( void * ) xISRStack, portISR_STACK_FILL_BYTE, sizeof( xISRStack ) );
}
#endif /* configISR_STACK_SIZE_WORDS */
}
#endif /* configASSERT_DEFINED */
#endif /* configUSE_ISR_STACK */
if( ucPrimaryCoreNum == get_core_num() ) {
/* If there is a CLINT then it is ok to use the default implementation
* in this file, otherwise vPortSetupTimerInterrupt() must be implemented to
* configure whichever clock is to be used to generate the tick interrupt. */
vPortSetupTimerInterrupt();
// extern void freertos_risc_v_trap_handler(void);
// exception_set_exclusive_handler(0, freertos_risc_v_trap_handler);
#if ((configMTIME_BASE_ADDRESS != 0) && (configMTIMECMP_BASE_ADDRESS != 0))
{
/* Enable mtime and external interrupts. 1<<7 for timer interrupt,
* 1<<11 for external interrupt. _RB_ What happens here when mtime is
* not present as with pulpino? */
__asm volatile ( "csrs mie, %0" ::"r" ( 0x880 ) );
}
#endif /* ( configMTIME_BASE_ADDRESS != 0 ) && ( configMTIMECMP_BASE_ADDRESS != 0 ) */
}
/* Install Doorbell handler to receive interrupt from other core */
uint32_t irq_num = multicore_doorbell_irq_num(cDoorbellNum);
irq_set_priority( irq_num, portMIN_INTERRUPT_PRIORITY );
irq_set_exclusive_handler( irq_num, prvDoorbellInterruptHandler );
irq_set_enabled( irq_num, 1 );
xPortStartFirstTask();
/* Should not get here as after calling xPortStartFirstTask() only tasks
* should be executing. */
return pdFAIL;
}
static void prvDisableInterruptsAndPortStartSchedulerOnCore( void )
{
portDISABLE_INTERRUPTS();
xPortStartSchedulerOnCore();
}
BaseType_t xPortStartScheduler( void )
{
configASSERT( ucPrimaryCoreNum == INVALID_PRIMARY_CORE_NUM );
vPortInstallVectorTableHandlers();
/* No one else should use these! */
spin_lock_claim( configSMP_SPINLOCK_0 );
spin_lock_claim( configSMP_SPINLOCK_1 );
// claim same number of both cores for simplicity
cDoorbellNum = (int8_t)multicore_doorbell_claim_unused(0b11, true);
multicore_doorbell_clear_current_core(cDoorbellNum);
multicore_doorbell_clear_other_core(cDoorbellNum);
ucPrimaryCoreNum = configTICK_CORE;
configASSERT( get_core_num() == 0 ); /* we must be started on core 0 */
multicore_reset_core1();
multicore_launch_core1( prvDisableInterruptsAndPortStartSchedulerOnCore );
xPortStartSchedulerOnCore();
/* Should not get here! */
return 0;
}
#else /* if ( configNUMBER_OF_CORES != 1 ) */
BaseType_t xPortStartScheduler( void )
{
extern void xPortStartFirstTask( void );
vPortInstallVectorTableHandlers();
#if ( configUSE_ISR_STACK == 1)
StackType_t xISRStackTop = xPortInitISRStack();
#if ( configASSERT_DEFINED == 1 )
{
/* Check alignment of the interrupt stack - which is the same as the
* stack that was being used by main() prior to the scheduler being
* started. */
configASSERT( ( xISRStackTop & portBYTE_ALIGNMENT_MASK ) == 0 );
#ifdef configISR_STACK_SIZE_WORDS
{
memset( ( void * ) xISRStack, portISR_STACK_FILL_BYTE, sizeof( xISRStack ) );
}
#endif /* configISR_STACK_SIZE_WORDS */
}
#endif /* configASSERT_DEFINED */
#endif /* configUSE_ISR_STACK */
/* If there is a CLINT then it is ok to use the default implementation
* in this file, otherwise vPortSetupTimerInterrupt() must be implemented to
* configure whichever clock is to be used to generate the tick interrupt. */
vPortSetupTimerInterrupt();
// extern void freertos_risc_v_trap_handler(void);
// exception_set_exclusive_handler(0, freertos_risc_v_trap_handler);
#if ( ( configMTIME_BASE_ADDRESS != 0 ) && ( configMTIMECMP_BASE_ADDRESS != 0 ) )
{
/* Enable mtime and external interrupts. 1<<7 for timer interrupt,
* 1<<11 for external interrupt. _RB_ What happens here when mtime is
* not present as with pulpino? */
__asm volatile ( "csrs mie, %0" ::"r" ( 0x880 ) );
}
#endif /* ( configMTIME_BASE_ADDRESS != 0 ) && ( configMTIMECMP_BASE_ADDRESS != 0 ) */
ucPrimaryCoreNum = get_core_num();
#if ( LIB_PICO_MULTICORE == 1 )
#if ( configSUPPORT_PICO_SYNC_INTEROP == 1 )
// claim same number of both cores for simplicity
cDoorbellNum = (int8_t) multicore_doorbell_claim_unused(0b11, true);
multicore_doorbell_clear_current_core(cDoorbellNum);
multicore_doorbell_clear_other_core(cDoorbellNum);
uint32_t irq_num = multicore_doorbell_irq_num(cDoorbellNum);
irq_set_priority( irq_num, portMIN_INTERRUPT_PRIORITY );
irq_set_exclusive_handler( irq_num, prvDoorbellInterruptHandler );
irq_set_enabled( irq_num, 1 );
#endif
#endif
xPortStartFirstTask();
/* Should not get here as after calling xPortStartFirstTask() only tasks
* should be executing. */
return pdFAIL;
}
#endif /* ( configNUMBER_OF_CORES != 1 ) */
/*-----------------------------------------------------------*/
void vPortEndScheduler( void )
{
/* Not implemented. */
for( ; ; )
{
}
}
/*-----------------------------------------------------------*/
#if ( configSUPPORT_PICO_SYNC_INTEROP == 1 )
void vPortYield( void )
{
__asm volatile ( "ecall" );
}
#endif /* configSUPPORT_PICO_SYNC_INTEROP */
/*-----------------------------------------------------------*/
#if ( configSUPPORT_PICO_SYNC_INTEROP == 1 ) || ( configSUPPORT_PICO_TIME_INTEROP == 1 )
static TickType_t prvGetTicksToWaitBefore( absolute_time_t t )
{
int64_t xDelay = absolute_time_diff_us( get_absolute_time(), t );
const uint32_t ulTickPeriod = 1000000 / configTICK_RATE_HZ;
xDelay += ulTickPeriod - 1;
if( xDelay >= ulTickPeriod )
{
return xDelay / ulTickPeriod;
}
return 0;
}
#endif /* if ( configSUPPORT_PICO_SYNC_INTEROP == 1 ) || ( configSUPPORT_PICO_TIME_INTEROP == 1 ) */
#if ( configSUPPORT_PICO_SYNC_INTEROP == 1 )
uint32_t ulPortLockGetCurrentOwnerId()
{
if( portIS_FREE_RTOS_CORE() )
{
uint32_t exception = __get_current_exception();
if( !exception )
{
return ( uintptr_t ) xTaskGetCurrentTaskHandle();
}
/* Note: since ROM as at 0x00000000, these can't be confused with
* valid task handles (pointers) in RAM */
/* We make all exception handler/core combinations distinct owners */
return get_core_num() + exception * 2;
}
/* Note: since ROM as at 0x00000000, this can't be confused with
* valid task handles (pointers) in RAM */
return get_core_num();
}
static inline EventBits_t prvGetEventGroupBit( spin_lock_t * spinLock )
{
uint32_t ulBit;
#if ( configTICK_TYPE_WIDTH_IN_BITS == TICK_TYPE_WIDTH_16_BITS )
ulBit = 1u << ( spin_lock_get_num( spinLock ) & 0x7u );
#elif ( configTICK_TYPE_WIDTH_IN_BITS == TICK_TYPE_WIDTH_32_BITS )
ulBit = 1u << ( spin_lock_get_num( spinLock ) % 24 );
#endif /* configTICK_TYPE_WIDTH_IN_BITS */
return ( EventBits_t ) ulBit;
}
static inline EventBits_t prvGetAllEventGroupBits()
{
#if ( configTICK_TYPE_WIDTH_IN_BITS == TICK_TYPE_WIDTH_16_BITS )
return ( EventBits_t ) 0xffu;
#elif ( configTICK_TYPE_WIDTH_IN_BITS == TICK_TYPE_WIDTH_32_BITS )
return ( EventBits_t ) 0xffffffu;
#endif /* configTICK_TYPE_WIDTH_IN_BITS */
}
void vPortLockInternalSpinUnlockWithWait( struct lock_core * pxLock,
uint32_t ulSave )
{
configASSERT( !portCHECK_IF_IN_ISR() );
configASSERT( pxLock->spin_lock );
if( !portIS_FREE_RTOS_CORE() )
{
spin_unlock( pxLock->spin_lock, ulSave );
__wfe();
}
else
{
/* The requirement (from the SDK) on this implementation is that this method
* should always wake up from a corresponding call to vPortLockInternalSpinUnlockWithNotify
* that happens after this method is called.
*
* The moment that we unlock the spin lock, we need to be sure that
* there is no way that we end up blocking in xEventGroupWaitBits,
* despite the fact that other tasks can now run, if the corresponding
* unlock has occurred.
*
* Previously the RP2xxx ports used to attempt to disable IRQs until the
* task actually (potentially) became blocked by hooking the IRQ re-enable
* when xEventGroupWaitBits completes (or switches tasks), but this
* was a broken hack, in that IRQs are re-enabled at other points during
* that call.
*
* This deferred IRQ enable is not actually needed, because all we
* care about is that:
*
* Even in the presence of other tasks acquiring then releasing
* the lock, between the interrupt_enable and the xEventGroupWaitBits,
* the corresponding bit will still be set.
*
* This is the case, even any intervening blocked lock (which
* clears the event bit) will need to unlock it before we proceed,
* which will set the event bit again.
*
* The multiplexing down of multiple spin lock numbers to fewer
* event bits does not cause a possible race condition,
* but it does mean that a task waiting for lock A can be
* blocked by a task B which owns another lock.
*
* This could be fixed by using an array of event groups, however
* since the SDK spin locks are generally intended for very short
* term usage anyway, and rarely nested except in exotic cases
* like video output, we'll leave it as one event group for now
*/
spin_unlock( pxLock->spin_lock, ulSave);
xEventGroupWaitBits( xEventGroup, prvGetEventGroupBit( pxLock->spin_lock ),
pdTRUE, pdFALSE, portMAX_DELAY );
}
}
void vPortLockInternalSpinUnlockWithNotify( struct lock_core * pxLock,
uint32_t ulSave )
{
EventBits_t uxBits = prvGetEventGroupBit( pxLock->spin_lock );
if( portIS_FREE_RTOS_CORE() )
{
#if LIB_PICO_MULTICORE
/* signal an event in case a regular core is waiting */
__sev();
#endif
spin_unlock( pxLock->spin_lock, ulSave );
if( !portCHECK_IF_IN_ISR() )
{
xEventGroupSetBits( xEventGroup, uxBits );
}
else
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xEventGroupSetBitsFromISR( xEventGroup, uxBits, &xHigherPriorityTaskWoken );
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
}
else
{
__sev();
#if ( configNUMBER_OF_CORES == 1 )
if( pxCrossCoreSpinLock != pxLock->spin_lock )
{
spin_lock_unsafe_blocking( pxCrossCoreSpinLock );
uxCrossCoreEventBits |= uxBits;
spin_unlock_unsafe( pxCrossCoreSpinLock );
}
else
{
uxCrossCoreEventBits |= uxBits;
}
/* This causes doorbell irq on the other (FreeRTOS) core which will do the set the event bits */
if ( cDoorbellNum >= 0 )
{
multicore_doorbell_set_other_core(cDoorbellNum);
}
#endif /* configNUMBER_OF_CORES == 1 */
spin_unlock( pxLock->spin_lock, ulSave );
}
}
bool xPortLockInternalSpinUnlockWithBestEffortWaitOrTimeout( struct lock_core * pxLock,
uint32_t ulSave,
absolute_time_t uxUntil )
{
configASSERT( !portCHECK_IF_IN_ISR() );
configASSERT( pxLock->spin_lock );
/* note no need to check LIB_PICO_MULTICORE, as this is always returns true if that is not defined */
if( !portIS_FREE_RTOS_CORE() )
{
spin_unlock( pxLock->spin_lock, ulSave );
return best_effort_wfe_or_timeout( uxUntil );
}
else
{
configASSERT( portIS_FREE_RTOS_CORE() );
TickType_t uxTicksToWait = prvGetTicksToWaitBefore( uxUntil );
if( uxTicksToWait )
{
/* See comment in vPortLockInternalSpinUnlockWithWait for detail
* about possible race conditions */
spin_unlock( pxLock->spin_lock, ulSave );
xEventGroupWaitBits( xEventGroup,
prvGetEventGroupBit( pxLock->spin_lock ), pdTRUE,
pdFALSE, uxTicksToWait );
}
else
{
spin_unlock( pxLock->spin_lock, ulSave );
}
if( time_reached( uxUntil ) )
{
return true;
}
else
{
/* We do not want to hog the core */
portYIELD();
/* We aren't sure if we've reached the timeout yet; the caller will check */
return false;
}
}
}
#if ( configSUPPORT_PICO_SYNC_INTEROP == 1 )
/* runs before main */
static void __attribute__( ( constructor ) ) prvRuntimeInitializer( void )
{
/* This must be done even before the scheduler is started, as the spin lock
* is used by the overrides of the SDK wait/notify primitives */
#if ( configNUMBER_OF_CORES == 1 )
pxCrossCoreSpinLock = spin_lock_instance( next_striped_spin_lock_num() );
#endif /* configNUMBER_OF_CORES == 1 */
/* The event group is not used prior to scheduler init, but is initialized
* here to since it logically belongs with the spin lock */
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
xEventGroup = xEventGroupCreateStatic( &xStaticEventGroup );
#else
/* Note that it is slightly dubious calling this here before the scheduler is initialized,
* however the only thing it touches is the allocator which then calls vPortEnterCritical
* and vPortExitCritical, and allocating here saves us checking the one time initialized variable in
* some rather critical code paths */
xEventGroup = xEventGroupCreate();
#endif /* configSUPPORT_STATIC_ALLOCATION */
}
#endif /* if ( configSUPPORT_PICO_SYNC_INTEROP == 1 ) */
#endif /* configSUPPORT_PICO_SYNC_INTEROP */
#if ( configSUPPORT_PICO_TIME_INTEROP == 1 )
void xPortSyncInternalYieldUntilBefore( absolute_time_t t )
{
TickType_t uxTicksToWait = prvGetTicksToWaitBefore( t );
if( uxTicksToWait )
{
vTaskDelay( uxTicksToWait );
}
}
#endif /* configSUPPORT_PICO_TIME_INTEROP */
/*-----------------------------------------------------------*/
#if ( configNUMBER_OF_CORES != 1 )
void vYieldCore( int xCoreID )
{
/* Remove warning if configASSERT is not defined.
* xCoreID is not used in this function due to this is a dual-core system. The yielding core must be different from the current core. */
( void ) xCoreID;
configASSERT( xCoreID != ( int ) portGET_CORE_ID() );
#if ( configNUMBER_OF_CORES != 1 )
/* will cause interrupt on other core if not already pending */
configASSERT( cDoorbellNum >= 0);
multicore_doorbell_set_other_core(cDoorbellNum);
#endif
}
#endif // ( configNUMBER_OF_CORES != 1 )
/*-----------------------------------------------------------*/
/* todo need to move portASM.s back into portasm.c so we can inline this */
UBaseType_t callTaskEnterCriticalFromISR(void) {
/** todo note on ARM port we call this anyway for single core, but it seems unnecessary */
#if ( configNUMBER_OF_CORES > 1 )
return taskENTER_CRITICAL_FROM_ISR();
#else
return 0;
#endif
}
/* todo need to move portASM.s back into portasm.c so we can inline this */
void callTaskExitCriticalFromISR(UBaseType_t uxSavedInterruptStatus) {
/** todo note on ARM port we call this anyway for single core, but it seems unnecessary */
#if ( configNUMBER_OF_CORES > 1 )
taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
#endif
}
@@ -0,0 +1,461 @@
/*
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/*
* The FreeRTOS kernel's RISC-V port is split between the the code that is
* common across all currently supported RISC-V chips (implementations of the
* RISC-V ISA), and code which tailors the port to a specific RISC-V chip:
*
* + The code that is common to all RISC-V chips is implemented in
* FreeRTOS\Source\portable\GCC\RISC-V-RV32\portASM.S. There is only one
* portASM.S file because the same file is used no matter which RISC-V chip is
* in use.
*
* + The code that tailors the kernel's RISC-V port to a specific RISC-V
* chip is implemented in freertos_risc_v_chip_specific_extensions.h. There
* is one freertos_risc_v_chip_specific_extensions.h that can be used with any
* RISC-V chip that both includes a standard CLINT and does not add to the
* base set of RISC-V registers. There are additional
* freertos_risc_v_chip_specific_extensions.h files for RISC-V implementations
* that do not include a standard CLINT or do add to the base set of RISC-V
* registers.
*
* CARE MUST BE TAKEN TO INCLDUE THE CORRECT
* freertos_risc_v_chip_specific_extensions.h HEADER FILE FOR THE CHIP
* IN USE. To include the correct freertos_risc_v_chip_specific_extensions.h
* header file ensure the path to the correct header file is in the assembler's
* include path.
*
* This freertos_risc_v_chip_specific_extensions.h is for use on RISC-V chips
* that include a standard CLINT and do not add to the base set of RISC-V
* registers.
*
*/
#include "portContext.h"
/* Check the freertos_risc_v_chip_specific_extensions.h and/or command line
definitions. */
#if defined( portasmHAS_CLINT ) && defined( portasmHAS_MTIME )
#error The portasmHAS_CLINT constant has been deprecated. Please replace it with portasmHAS_MTIME. portasmHAS_CLINT and portasmHAS_MTIME cannot both be defined at once. See https://www.FreeRTOS.org/Using-FreeRTOS-on-RISC-V.html
#endif
#ifdef portasmHAS_CLINT
#warning The portasmHAS_CLINT constant has been deprecated. Please replace it with portasmHAS_MTIME and portasmHAS_SIFIVE_CLINT. For now portasmHAS_MTIME and portasmHAS_SIFIVE_CLINT are derived from portasmHAS_CLINT. See https://www.FreeRTOS.org/Using-FreeRTOS-on-RISC-V.html
#define portasmHAS_MTIME portasmHAS_CLINT
#define portasmHAS_SIFIVE_CLINT portasmHAS_CLINT
#endif
#ifndef portasmHAS_MTIME
#error freertos_risc_v_chip_specific_extensions.h must define portasmHAS_MTIME to either 1 (MTIME clock present) or 0 (MTIME clock not present). See https://www.FreeRTOS.org/Using-FreeRTOS-on-RISC-V.html
#endif
#ifndef portasmHAS_SIFIVE_CLINT
#define portasmHAS_SIFIVE_CLINT 0
#endif
.global xPortStartFirstTask
.global pxPortInitialiseStack
.global freertos_risc_v_trap_handler
.global freertos_risc_v_exception_handler
.global freertos_risc_v_interrupt_handler
.global freertos_risc_v_mtimer_interrupt_handler
.extern vTaskSwitchContext
.extern xTaskIncrementTick
.extern pullMachineTimerCompareRegister
.extern pullNextTime
.extern uxTimerIncrementsForOneTick /* size_t type so 32-bit on 32-bit core and 64-bits on 64-bit core. */
.extern xTaskReturnAddress
.weak freertos_risc_v_application_exception_handler
.weak freertos_risc_v_application_interrupt_handler
/*-----------------------------------------------------------*/
.macro portUPDATE_MTIMER_COMPARE_REGISTER
load_x a0, pullMachineTimerCompareRegister /* Load address of compare register into a0. */
load_x a1, pullNextTime /* Load the address of ullNextTime into a1. */
#if( __riscv_xlen == 32 )
/* Update the 64-bit mtimer compare match value in two 32-bit writes. */
li a4, -1
lw a2, 0(a1) /* Load the low word of ullNextTime into a2. */
lw a3, 4(a1) /* Load the high word of ullNextTime into a3. */
sw a4, 0(a0) /* Low word no smaller than old value to start with - will be overwritten below. */
sw a3, 4(a0) /* Store high word of ullNextTime into compare register. No smaller than new value. */
sw a2, 0(a0) /* Store low word of ullNextTime into compare register. */
lw t0, uxTimerIncrementsForOneTick /* Load the value of ullTimerIncrementForOneTick into t0 (could this be optimized by storing in an array next to pullNextTime?). */
add a4, t0, a2 /* Add the low word of ullNextTime to the timer increments for one tick (assumes timer increment for one tick fits in 32-bits). */
sltu t1, a4, a2 /* See if the sum of low words overflowed (what about the zero case?). */
add t2, a3, t1 /* Add overflow to high word of ullNextTime. */
sw a4, 0(a1) /* Store new low word of ullNextTime. */
sw t2, 4(a1) /* Store new high word of ullNextTime. */
#endif /* __riscv_xlen == 32 */
#if( __riscv_xlen == 64 )
/* Update the 64-bit mtimer compare match value. */
ld t2, 0(a1) /* Load ullNextTime into t2. */
sd t2, 0(a0) /* Store ullNextTime into compare register. */
ld t0, uxTimerIncrementsForOneTick /* Load the value of ullTimerIncrementForOneTick into t0 (could this be optimized by storing in an array next to pullNextTime?). */
add t4, t0, t2 /* Add ullNextTime to the timer increments for one tick. */
sd t4, 0(a1) /* Store ullNextTime. */
#endif /* __riscv_xlen == 64 */
.endm
/*-----------------------------------------------------------*/
/*
* Unlike other ports pxPortInitialiseStack() is written in assembly code as it
* needs access to the portasmADDITIONAL_CONTEXT_SIZE constant. The prototype
* for the function is as per the other ports:
* StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters );
*
* As per the standard RISC-V ABI pxTopOfStack is passed in in a0, pxCode in
* a1, and pvParameters in a2. The new top of stack is passed out in a0.
*
* RISC-V maps registers to ABI names as follows (X1 to X31 integer registers
* for the 'I' profile, X1 to X15 for the 'E' profile, currently I assumed).
*
* Register ABI Name Description Saver
* x0 zero Hard-wired zero -
* x1 ra Return address Caller
* x2 sp Stack pointer Callee
* x3 gp Global pointer -
* x4 tp Thread pointer -
* x5-7 t0-2 Temporaries Caller
* x8 s0/fp Saved register/Frame pointer Callee
* x9 s1 Saved register Callee
* x10-11 a0-1 Function Arguments/return values Caller
* x12-17 a2-7 Function arguments Caller
* x18-27 s2-11 Saved registers Callee
* x28-31 t3-6 Temporaries Caller
*
* The RISC-V context is saved to FreeRTOS tasks in the following stack frame,
* where the global and thread pointers are currently assumed to be constant so
* are not saved:
*
* mstatus
* xCriticalNesting
* x31
* x30
* x29
* x28
* x27
* x26
* x25
* x24
* x23
* x22
* x21
* x20
* x19
* x18
* x17
* x16
* x15
* x14
* x13
* x12
* x11
* pvParameters
* x9
* x8
* x7
* x6
* x5
* portTASK_RETURN_ADDRESS
* [chip specific registers go here]
* pxCode
*/
pxPortInitialiseStack:
csrr t0, mstatus /* Obtain current mstatus value. */
andi t0, t0, ~0x8 /* Ensure interrupts are disabled when the stack is restored within an ISR. Required when a task is created after the schedulre has been started, otherwise interrupts would be disabled anyway. */
addi t1, x0, 0x188 /* Generate the value 0x1880, which are the MPIE and MPP bits to set in mstatus. */
slli t1, t1, 4
or t0, t0, t1 /* Set MPIE and MPP bits in mstatus value. */
addi a0, a0, -portWORD_SIZE
store_x t0, 0(a0) /* mstatus onto the stack. */
addi a0, a0, -portWORD_SIZE /* Space for critical nesting count. */
store_x x0, 0(a0) /* Critical nesting count starts at 0 for every task. */
#ifdef __riscv_32e
addi a0, a0, -(6 * portWORD_SIZE) /* Space for registers x10-x15. */
#else
addi a0, a0, -(22 * portWORD_SIZE) /* Space for registers x10-x31. */
#endif
store_x a2, 0(a0) /* Task parameters (pvParameters parameter) goes into register X10/a0 on the stack. */
addi a0, a0, -(6 * portWORD_SIZE) /* Space for registers x5-x9 + taskReturnAddress. */
load_x t0, xTaskReturnAddress
store_x t0, 0(a0) /* Return address onto the stack. */
addi t0, x0, portasmADDITIONAL_CONTEXT_SIZE /* The number of chip specific additional registers. */
chip_specific_stack_frame: /* First add any chip specific registers to the stack frame being created. */
beq t0, x0, 1f /* No more chip specific registers to save. */
addi a0, a0, -portWORD_SIZE /* Make space for chip specific register. */
store_x x0, 0(a0) /* Give the chip specific register an initial value of zero. */
addi t0, t0, -1 /* Decrement the count of chip specific registers remaining. */
j chip_specific_stack_frame /* Until no more chip specific registers. */
1:
addi a0, a0, -portWORD_SIZE
store_x a1, 0(a0) /* mret value (pxCode parameter) onto the stack. */
ret
/*-----------------------------------------------------------*/
xPortStartFirstTask:
portcontextGET_CORE_ID x7
portcontextGET_CURRENT_TCB_FOR_CORE x7, sp
load_x sp, 0( sp ) /* Read sp from first TCB member. */
load_x x1, 0( sp ) /* Note for starting the scheduler the exception return address is used as the function return address. */
portasmRESTORE_ADDITIONAL_REGISTERS /* Defined in freertos_risc_v_chip_specific_extensions.h to restore any registers unique to the RISC-V implementation. */
load_x x7, 4 * portWORD_SIZE( sp ) /* t2 */
load_x x8, 5 * portWORD_SIZE( sp ) /* s0/fp */
load_x x9, 6 * portWORD_SIZE( sp ) /* s1 */
load_x x10, 7 * portWORD_SIZE( sp ) /* a0 */
load_x x11, 8 * portWORD_SIZE( sp ) /* a1 */
load_x x12, 9 * portWORD_SIZE( sp ) /* a2 */
load_x x13, 10 * portWORD_SIZE( sp ) /* a3 */
load_x x14, 11 * portWORD_SIZE( sp ) /* a4 */
load_x x15, 12 * portWORD_SIZE( sp ) /* a5 */
#ifndef __riscv_32e
load_x x16, 13 * portWORD_SIZE( sp ) /* a6 */
load_x x17, 14 * portWORD_SIZE( sp ) /* a7 */
load_x x18, 15 * portWORD_SIZE( sp ) /* s2 */
load_x x19, 16 * portWORD_SIZE( sp ) /* s3 */
load_x x20, 17 * portWORD_SIZE( sp ) /* s4 */
load_x x21, 18 * portWORD_SIZE( sp ) /* s5 */
load_x x22, 19 * portWORD_SIZE( sp ) /* s6 */
load_x x23, 20 * portWORD_SIZE( sp ) /* s7 */
load_x x24, 21 * portWORD_SIZE( sp ) /* s8 */
load_x x25, 22 * portWORD_SIZE( sp ) /* s9 */
load_x x26, 23 * portWORD_SIZE( sp ) /* s10 */
load_x x27, 24 * portWORD_SIZE( sp ) /* s11 */
load_x x28, 25 * portWORD_SIZE( sp ) /* t3 */
load_x x29, 26 * portWORD_SIZE( sp ) /* t4 */
load_x x30, 27 * portWORD_SIZE( sp ) /* t5 */
load_x x31, 28 * portWORD_SIZE( sp ) /* t6 */
#endif
/* Load the address of xCriticalNesting into x6. */
portcontextGET_CORE_ID x5
portcontextGET_CRITICAL_NESTING_PTR_FOR_CORE x5, x6
load_x x5, portCRITICAL_NESTING_OFFSET * portWORD_SIZE( sp ) /* Obtain xCriticalNesting value for this task from task's stack. */
store_x x5, 0( x6 ) /* Restore the critical nesting value for this task. */
load_x x5, portMSTATUS_OFFSET * portWORD_SIZE( sp ) /* Initial mstatus into x5 (t0). */
addi x5, x5, 0x08 /* Set MIE bit so the first task starts with interrupts enabled - required as returns with ret not eret. */
csrrw x0, mstatus, x5 /* Interrupts enabled from here! */
load_x x5, 2 * portWORD_SIZE( sp ) /* Initial x5 (t0) value. */
load_x x6, 3 * portWORD_SIZE( sp ) /* Initial x6 (t1) value. */
addi sp, sp, portCONTEXT_SIZE
ret
/*-----------------------------------------------------------*/
freertos_risc_v_application_exception_handler:
csrr t0, mcause /* For viewing in the debugger only. */
csrr t1, mepc /* For viewing in the debugger only */
csrr t2, mstatus /* For viewing in the debugger only */
j .
/*-----------------------------------------------------------*/
freertos_risc_v_application_interrupt_handler:
csrr t0, mcause /* For viewing in the debugger only. */
csrr t1, mepc /* For viewing in the debugger only */
csrr t2, mstatus /* For viewing in the debugger only */
j .
/*-----------------------------------------------------------*/
.section .text.freertos_risc_v_exception_handler
freertos_risc_v_exception_handler:
portcontextSAVE_EXCEPTION_CONTEXT
/* a0 now contains mcause. */
li t0, 11 /* 11 == environment call. */
bne a0, t0, other_exception /* Not an M environment call, so some other exception. */
#if configNUMBER_OF_CORES != 1
portcontextGET_CORE_ID a0
#endif
call vTaskSwitchContext
portcontextRESTORE_CONTEXT
other_exception:
call freertos_risc_v_application_exception_handler
portcontextRESTORE_CONTEXT
/*-----------------------------------------------------------*/
.section .time_critical.freertos_risc_v_interrupt_handler
freertos_risc_v_interrupt_handler:
portcontextSAVE_INTERRUPT_CONTEXT // note this macro requires s10, s11 to be preserved here
// note we replace/recreate the SDK's IRQ mechansim here, since we want to control the exception stacking
save_meicontext:
// Make sure to set meicontext.clearts to clear+save mie.msie/mtie along
// with ext IRQ context. We don't let these preempt ext IRQs because they
// clear meicontext.mreteirq, which breaks __get_current_exception().
csrrsi s2, RVCSR_MEICONTEXT_OFFSET, RVCSR_MEICONTEXT_CLEARTS_BITS
get_first_irq:
// Sample the current highest-priority active IRQ (left-shifted by 2) from
// meinext, and write 1 to meinext.update to update meicontext with the
// preemption priority and IRQ number of this IRQ
csrrsi a0, RVCSR_MEINEXT_OFFSET, RVCSR_MEINEXT_UPDATE_BITS
// MSB will be set if there is no active IRQ at the current priority level
bltz a0, no_more_irqs
dispatch_irq:
#if portcontextALLOW_NESTED_IRQs
// Preemption priority was configured by meinext update, so enable preemption:
csrsi mstatus, 0x8
#endif
// <- from this point we can be preempted by a higher-priority interrupt.
// meinext is pre-shifted by 2, so only an add is required to index table
lui a1, %hi(__soft_vector_table)
add a1, a1, a0
lw a1, %lo(__soft_vector_table)(a1)
jalr ra, a1
// note: beware: freertos_risc_v_mtimer_interrupt_handler trashes s0 and s1, but
// we require s2, s10, s11 saved.
#if portcontextALLOW_NESTED_IRQs
// Disable IRQs on returning so we can sample the next IRQ
csrci mstatus, 0x8
#endif
get_next_irq:
// Get the next-highest-priority IRQ that is active at this level. If
// there is such an IRQ, update meicontext with new preemption priority.
csrrsi a0, RVCSR_MEINEXT_OFFSET, RVCSR_MEINEXT_UPDATE_BITS
// MSB will be set if there is no active IRQ at the current priority level
bgez a0, dispatch_irq
no_more_irqs:
csrw RVCSR_MEICONTEXT_OFFSET, s2
portcontextRESTORE_INTERUUPT_CONTEXT
/*-----------------------------------------------------------*/
.section .time_critical.freertos_risc_v_mtimer_interrupt_handler
freertos_risc_v_mtimer_interrupt_handler:
// we know we are called from freertos_risc_v_interrupt_handler which saves ALL registers
// already, and doesn't care about us trashing s0, so we used it instead of stack
// to save ra across the calls in this function
mv s0, ra
// Clear the interrupt force array bit for the timer IRQ, in case this IRQ
// was forced locally rather than actually coming from the timer.
//li a0, (1 << ((SIO_IRQ_MTIMECMP % 16) + 16) | (SIO_IRQ_MTIMECMP / 16)
//csrc 0xbe2, a0 // 0xbe2: meifa (external interrupt force array)
// TODO Graham: the above code is probably unnecessary because the meifa
// bit should already have been cleared when we sampled the timer IRQ
// from meinext. Suggest to delete it once confirmed to work without.
portUPDATE_MTIMER_COMPARE_REGISTER
call callTaskEnterCriticalFromISR
// we are also allowed to trash s1 by the caller
mv s1, a0
call xTaskIncrementTick
mv a0, s1
call callTaskExitCriticalFromISR
beqz a0, exit_without_context_switch /* Don't switch context if incrementing tick didn't unblock a task. */
#if configNUMBER_OF_CORES != 1
portcontextGET_CORE_ID a0 // vtTaskSwitch context takes coreID in SMP
#endif
call vTaskSwitchContext
exit_without_context_switch:
jr s0
/*-----------------------------------------------------------*/
.section .time_critical.freertos_risc_v_trap_handler
.align 8
freertos_risc_v_trap_handler:
portcontextSAVE_CONTEXT_INTERNAL
csrr a0, mcause
csrr a1, mepc
bge a0, x0, synchronous_exception
asynchronous_interrupt:
store_x a1, 0( sp ) /* Asynchronous interrupt so save unmodified exception return address. */
portcontextSWITCH_TO_ISR_STACK t0, t1
j handle_interrupt
synchronous_exception:
addi a1, a1, 4 /* Synchronous so update exception return address to the instruction after the instruction that generated the exeption. */
store_x a1, 0( sp ) /* Save updated exception return address. */
portcontextSWITCH_TO_ISR_STACK t0, t1
j handle_exception
handle_interrupt:
#if( portasmHAS_MTIME != 0 )
test_if_mtimer: /* If there is a CLINT then the mtimer is used to generate the tick interrupt. */
addi t0, x0, 1
slli t0, t0, __riscv_xlen - 1 /* LSB is already set, shift into MSB. Shift 31 on 32-bit or 63 on 64-bit cores. */
addi t1, t0, 7 /* 0x8000[]0007 == machine timer interrupt. */
bne a0, t1, application_interrupt_handler
portUPDATE_MTIMER_COMPARE_REGISTER
call xTaskIncrementTick
beqz a0, processed_source /* Don't switch context if incrementing tick didn't unblock a task. */
#if configNUMBER_OF_CORES != 1
portcontextGET_CORE_ID a0
#endif
call vTaskSwitchContext
j processed_source
#endif /* portasmHAS_MTIME */
application_interrupt_handler:
call freertos_risc_v_application_interrupt_handler
j processed_source
handle_exception:
/* a0 contains mcause. */
li t0, 11 /* 11 == environment call. */
bne a0, t0, application_exception_handler /* Not an M environment call, so some other exception. */
#if configNUMBER_OF_CORES != 1
portcontextGET_CORE_ID a0
#endif
call vTaskSwitchContext
j processed_source
application_exception_handler:
call freertos_risc_v_application_exception_handler
j processed_source /* No other exceptions handled yet. */
processed_source:
portcontextRESTORE_CONTEXT
/*-----------------------------------------------------------*/
@@ -0,0 +1,23 @@
/*
* The FreeRTOS kernel's RISC-V port is split between the the code that is
* common across all currently supported RISC-V chips (implementations of the
* RISC-V ISA), and code that tailors the port to a specific RISC-V chip:
*
* + FreeRTOS\Source\portable\GCC\RISC-V-RV32\portASM.S contains the code that
* is common to all currently supported RISC-V chips. There is only one
* portASM.S file because the same file is built for all RISC-V target chips.
*
* + Header files called freertos_risc_v_chip_specific_extensions.h contain the
* code that tailors the FreeRTOS kernel's RISC-V port to a specific RISC-V
* chip. There are multiple freertos_risc_v_chip_specific_extensions.h files
* as there are multiple RISC-V chip implementations.
*
* !!!NOTE!!!
* TAKE CARE TO INCLUDE THE CORRECT freertos_risc_v_chip_specific_extensions.h
* HEADER FILE FOR THE CHIP IN USE. This is done using the assembler's (not the
* compiler's!) include path. For example, if the chip in use includes a core
* local interrupter (CLINT) and does not include any chip specific register
* extensions then add the path below to the assembler's include path:
* FreeRTOS\Source\portable\GCC\RISC-V-RV32\chip_specific_extensions\RV32I_CLINT_no_extensions
*
*/
@@ -0,0 +1,573 @@
/*
* FreeRTOS Kernel V10.4.1
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
* 1 tab == 4 spaces!
*/
#include "port.h"
/* Standard includes. */
#include <stdlib.h>
#include <string.h>
/* TriCore specific includes. */
#include <machine/intrinsics.h>
#include <machine/cint.h>
#include <machine/wdtcon.h>
#include <tc38xa/Ifx_reg.h>
#include <tc38xa/IfxScu_reg.h>
#include "interrupts.h"
/* Kernel includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "list.h"
#if configCHECK_FOR_STACK_OVERFLOW > 0
#error "Stack checking cannot be used with this port, as, unlike most ports, the pxTopOfStack member of the TCB is consumed CSA. CSA starvation, loosely equivalent to stack overflow, will result in a trap exception."
/* The stack pointer is accessible using portCSA_TO_ADDRESS( portCSA_TO_ADDRESS( pxCurrentTCB->pxTopOfStack )[ 0 ] )[ 2 ]; */
#endif /* configCHECK_FOR_STACK_OVERFLOW */
#define CPU_ID (_mfcr(CPU_CORE_ID) & 0x0f)
static volatile Ifx_STM* STMs[4] = {&MODULE_STM0, &MODULE_STM1, &MODULE_STM2, &MODULE_STM3};
static const unsigned short STM_SRCs[4] = {SRC_ID_STM0SR0, SRC_ID_STM1SR0, SRC_ID_STM2SR0, SRC_ID_STM3SR0};
static volatile Ifx_INT_SRB* SRBs[4] = {&INT_SRB0, &INT_SRB1, &INT_SRB2, &INT_SRB3};
static const unsigned short GPSRs[4] = {SRC_ID_GPSR00, SRC_ID_GPSR10, SRC_ID_GPSR20, SRC_ID_GPSR30};
typedef struct
{
unsigned int PCXI, PSW, A10, A11, D8, D9, D10, D11, A12, A13, A14, A15, D12, D13, D14, D15;
} UPPER_CONTEXT;
/*-----------------------------------------------------------*/
/* System register Definitions. */
#define portSYSTEM_PROGRAM_STATUS_WORD ( 0x000008FFUL ) /* Supervisor Mode, MPU Register Set 0 and Call Depth Counting disabled. */
#define portINITIAL_PRIVILEGED_PROGRAM_STATUS_WORD ( 0x000014FFUL ) /* IO Level 1, MPU Register Set 1 and Call Depth Counting disabled. */
#define portINITIAL_UNPRIVILEGED_PROGRAM_STATUS_WORD ( 0x000010FFUL ) /* IO Level 0, MPU Register Set 1 and Call Depth Counting disabled. */
//#define portINITIAL_PCXI_UPPER_CONTEXT_WORD ( 0x00C00000UL ) /* The lower 20 bits identify the CSA address. */
//#define portINITIAL_PCXI_UPPER_CONTEXT_WORD ( 0x10300000UL ) // ATENlower 20 bits identify the CSA address. */
#define portINITIAL_PCXI_UPPER_CONTEXT_WORD ( 0x00300000UL ) // ATEN, default value as read from the CPU after init
#define portINITIAL_SYSCON ( 0x00000000UL ) /* MPU Disable. */
/* CSA manipulation macros. */
#define portCSA_FCX_MASK ( 0x000FFFFFUL )
/* OS Interrupt and Trap mechanisms. */
#define portRESTORE_PSW_MASK ( ~( 0x000000FFUL ) )
#define portSYSCALL_TRAP ( 6 )
/* Each CSA contains 16 words of data. */
#define portNUM_WORDS_IN_CSA ( 16 )
/* The interrupt enable bit in the PCP_SRC register. */
#define portENABLE_CPU_INTERRUPT ( 1U << 12U )
/*-----------------------------------------------------------*/
/*
* Perform any hardware configuration necessary to generate the tick interrupt.
*/
static void prvSystemTickHandler( int ) __attribute__((longcall));
static void prvERUISRHandler( int ) __attribute__((longcall));
static void prvSetupTimerInterrupt( void );
#define ERUInterruptCoreID 0
static void prvSetupERUInterrupt(void);
/*
* Priority 1 interrupt handler for yields pended from an interrupt.
*/
static void prvInterruptYield( int iTrapIdentification );
/*-----------------------------------------------------------*/
/* This reference is required by the save/restore context macros. */
extern volatile uint32_t *pxCurrentTCB;
extern TaskHandle_t xTaskHandle0[E_TASKS_CPU0_SIZE];
/* Precalculate the compare match value at compile time. */
static const uint32_t ulCompareMatchValue = ( configPERIPHERAL_CLOCK_HZ / configTICK_RATE_HZ );
/*-----------------------------------------------------------*/
StackType_t *pxPortInitialiseStack( StackType_t * pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
{
uint32_t *pulUpperCSA = NULL;
uint32_t *pulLowerCSA = NULL;
/* 16 Address Registers (4 Address registers are global), 16 Data
Registers, and 3 System Registers.
There are 3 registers that track the CSAs.
FCX points to the head of globally free set of CSAs.
PCX for the task needs to point to Lower->Upper->NULL arrangement.
LCX points to the last free CSA so that corrective action can be taken.
Need two CSAs to store the context of a task.
The upper context contains D8-D15, A10-A15, PSW and PCXI->NULL.
The lower context contains D0-D7, A2-A7, A11 and PCXI->UpperContext.
The pxCurrentTCB->pxTopOfStack points to the Lower Context RSLCX matching the initial BISR.
The Lower Context points to the Upper Context ready for the return from the interrupt handler.
The Real stack pointer for the task is stored in the A10 which is restored
with the upper context. */
/* Have to disable interrupts here because the CSAs are going to be
manipulated. */
portENTER_CRITICAL();
{
/* DSync to ensure that buffering is not a problem. */
_dsync();
/* Consume two free CSAs. */
pulLowerCSA = portCSA_TO_ADDRESS( __MFCR( $FCX ) );
if( NULL != pulLowerCSA )
{
/* The Lower Links to the Upper. */
pulUpperCSA = portCSA_TO_ADDRESS( pulLowerCSA[ 0 ] );
}
/* Check that we have successfully reserved two CSAs. */
if( ( NULL != pulLowerCSA ) && ( NULL != pulUpperCSA ) )
{
/* Remove the two consumed CSAs from the free CSA list. */
_disable();
_dsync();
_mtcr( $FCX, pulUpperCSA[ 0 ] );
_isync();
_enable();
}
else
{
/* Simply trigger a context list depletion trap. */
_svlcx();
}
}
portEXIT_CRITICAL();
/* Clear the upper CSA. */
memset( pulUpperCSA, 0, portNUM_WORDS_IN_CSA * sizeof( uint32_t ) );
/* Upper Context. */
pulUpperCSA[ 2 ] = ( uint32_t )pxTopOfStack; /* A10; Stack Return aka Stack Pointer */
pulUpperCSA[ 1 ] = portSYSTEM_PROGRAM_STATUS_WORD; /* PSW */
/* Clear the lower CSA. */
memset( pulLowerCSA, 0, portNUM_WORDS_IN_CSA * sizeof( uint32_t ) );
/* Lower Context. */
pulLowerCSA[ 8 ] = ( uint32_t ) pvParameters; /* A4; Address Type Parameter Register */
pulLowerCSA[ 1 ] = ( uint32_t ) pxCode; /* A11; Return Address aka RA */
/* PCXI pointing to the Upper context. */
pulLowerCSA[ 0 ] = ( portINITIAL_PCXI_UPPER_CONTEXT_WORD | ( uint32_t ) portADDRESS_TO_CSA( pulUpperCSA ) );
/* Save the link to the CSA in the top of stack. */
pxTopOfStack = (uint32_t * ) portADDRESS_TO_CSA( pulLowerCSA );
/* DSync to ensure that buffering is not a problem. */
_dsync();
return pxTopOfStack;
}
/*-----------------------------------------------------------*/
int32_t xPortStartScheduler( void )
{
extern void vTrapInstallHandlers( void );
uint32_t ulMFCR = 0UL;
uint32_t *pulUpperCSA = NULL;
uint32_t *pulLowerCSA = NULL;
/* prevent compiler warnings */
(void)pulUpperCSA;
/* Interrupts at or below configMAX_SYSCALL_INTERRUPT_PRIORITY are disable
when this function is called. */
/* Set-up the ERU interrupt. */
prvSetupERUInterrupt();
/* Set-up the timer interrupt. */
prvSetupTimerInterrupt();
/* Install the Trap Handlers. */
// vTrapInstallHandlers();
/* Install the Syscall Handler for yield calls. */
// if( 0 == _install_trap_handler( portSYSCALL_TRAP, prvTrapYield ) )
// {
// /* Failed to install the yield handler, force an assert. */
// configASSERT( ( ( volatile void * ) NULL ) );
// }
/* Enable and install the priority 1 interrupt for pending context switches from an ISR. */
InterruptInstall(GPSRs[CPU_ID], prvInterruptYield, configKERNEL_YIELD_PRIORITY, 0); //ATEN
_disable();
/* Load the initial SYSCON. */
_mtcr( $SYSCON, portINITIAL_SYSCON );
_isync();
/* ENDINIT has already been applied in the 'cstart.c' code. */
/* Clear the PSW.CDC to enable the use of an RFE without it generating an
exception because this code is not genuinely in an exception. */
ulMFCR = __MFCR( $PSW );
ulMFCR &= portRESTORE_PSW_MASK;
_dsync();
_mtcr( $PSW, ulMFCR );
_isync();
/* Finally, perform the equivalent of a portRESTORE_CONTEXT() */
pulLowerCSA = portCSA_TO_ADDRESS( ( *pxCurrentTCB ) );
pulUpperCSA = portCSA_TO_ADDRESS( pulLowerCSA[0] );
_dsync();
_mtcr( $PCXI, *pxCurrentTCB );
_isync();
_nop();
_rslcx();
_nop();
/* Return to the first task selected to execute. */
__asm volatile( "rfe" );
/* Will not get here. */
return 0;
}
/*-----------------------------------------------------------*/
static void prvSetupTimerInterrupt( void )
{
unsigned short cpuid = CPU_ID;
// Install handler for timer interrupt & reset interrupt flag
STMs[cpuid]->ISCR.U = 1;
InterruptInstall(STM_SRCs[cpuid], prvSystemTickHandler, configKERNEL_INTERRUPT_PRIORITY, 0);
// prepare compare register for first interrupt
STMs[cpuid]->CMP[0].U = STMs[cpuid]->TIM0.U + ulCompareMatchValue;
STMs[cpuid]->CMCON.U = 31;
STMs[cpuid]->OCS.B.SUS = 2;
STMs[cpuid]->ICR.B.CMP0EN = 1;
}
/*-----------------------------------------------------------*/
/*****************************************************************/
static void prvSetupERUInterrupt(void)
{
unsigned short cpuid = CPU_ID;
if(cpuid == ERUInterruptCoreID)
{
SCU_FMR.B.FC0 = 1; //Clear the interrupt flag
InterruptInstall(SRC_ID_SCUERU0, prvERUISRHandler, 3, 0); //Load the interrupt routine and priortiy
}
}
/*****************************************************************/
static void prvSystemTickHandler( int iArg )
{
uint32_t ulSavedInterruptMask;
uint32_t *pxUpperCSA = NULL;
uint32_t xUpperCSA = 0UL;
extern volatile uint32_t *pxCurrentTCB;
int32_t lYieldRequired;
unsigned short cpuid = CPU_ID;
/* Just to avoid compiler warnings about unused parameters. */
( void ) iArg;
/* Clear the interrupt source. */
//STM_ISRR.reg = 1UL; //ATEN
/* Reload the Compare Match register for X ticks into the future.
If critical section or interrupt nesting budgets are exceeded, then
it is possible that the calculated next compare match value is in the
past. If this occurs (unlikely), it is possible that the resulting
time slippage will exceed a single tick period. Any adverse effect of
this is time bounded by the fact that only the first n bits of the 56 bit
STM timer are being used for a compare match, so another compare match
will occur after an overflow in just those n bits (not the entire 56 bits).
As an example, if the peripheral clock is 75MHz, and the tick rate is 1KHz,
a missed tick could result in the next tick interrupt occurring within a
time that is 1.7 times the desired period. The fact that this is greater
than a single tick period is an effect of using a timer that cannot be
automatically reset, in hardware, by the occurrence of a tick interrupt.
Changing the tick source to a timer that has an automatic reset on compare
match (such as a GPTA timer) will reduce the maximum possible additional
period to exactly 1 times the desired period. */
STMs[cpuid]->CMP[0].U = STMs[cpuid]->TIM0.U + ulCompareMatchValue; //ATEN
STMs[cpuid]->ISCR.B.CMP0IRR = 1;
//STM_CMP0.reg += ulCompareMatchValue;
/* Kernel API calls require Critical Sections. */
ulSavedInterruptMask = portSET_INTERRUPT_MASK_FROM_ISR();
{
/* Increment the Tick. */
lYieldRequired = xTaskIncrementTick();
}
portCLEAR_INTERRUPT_MASK_FROM_ISR( ulSavedInterruptMask );
if( lYieldRequired != pdFALSE )
{
/* Save the context of a task.
The upper context is automatically saved when entering a trap or interrupt.
Need to save the lower context as well and copy the PCXI CSA ID into
pxCurrentTCB->pxTopOfStack. Only Lower Context CSA IDs may be saved to the
TCB of a task.
Call vTaskSwitchContext to select the next task, note that this changes the
value of pxCurrentTCB so that it needs to be reloaded.
Call vPortSetMPURegisterSetOne to change the MPU mapping for the task
that has just been switched in.
Load the context of the task.
Need to restore the lower context by loading the CSA from
pxCurrentTCB->pxTopOfStack into PCXI (effectively changing the call stack).
In the Interrupt handler post-amble, RSLCX will restore the lower context
of the task. RFE will restore the upper context of the task, jump to the
return address and restore the previous state of interrupts being
enabled/disabled. */
_disable();
_dsync();
xUpperCSA = __MFCR( $PCXI );
pxUpperCSA = portCSA_TO_ADDRESS( xUpperCSA );
*pxCurrentTCB = pxUpperCSA[ 0 ];
vTaskSwitchContext();
pxUpperCSA[ 0 ] = *pxCurrentTCB;
SRBs[cpuid]->B.TRIG0 = 0; //ATEN
//CPU_SRC0.bits.SETR = 0;
_isync();
}
}
/*-----------------------------------------------------------*/
static void prvERUISRHandler( int iArg )
{
BaseType_t checkIfYieldRequired;
/* Just to avoid compiler warnings about unused parameters. */
( void ) iArg;
SCU_FMR.B.FC0 = 1; //Clear the interrupt flag
checkIfYieldRequired = xTaskResumeFromISR(xTaskHandle0[E_FPGA_TASK]); //Check the state of the FPGA task
portYIELD_FROM_ISR(checkIfYieldRequired); //Yield the FPGA task if it was suspended
}
/*
* When a task is deleted, it is yielded permanently until the IDLE task
* has an opportunity to reclaim the memory that that task was using.
* Typically, the memory used by a task is the TCB and Stack but in the
* TriCore this includes the CSAs that were consumed as part of the Call
* Stack. These CSAs can only be returned to the Globally Free Pool when
* they are not part of the current Call Stack, hence, delaying the
* reclamation until the IDLE task is freeing the task's other resources.
* This function uses the head of the linked list of CSAs (from when the
* task yielded for the last time) and finds the tail (the very bottom of
* the call stack) and inserts this list at the head of the Free list,
* attaching the existing Free List to the tail of the reclaimed call stack.
*
* NOTE: the IDLE task needs processing time to complete this function
* and in heavily loaded systems, the Free CSAs may be consumed faster
* than they can be freed assuming that tasks are being spawned and
* deleted frequently.
*/
void vPortReclaimCSA( uint32_t *pxTCB )
{
uint32_t pxHeadCSA, pxTailCSA, pxFreeCSA;
uint32_t *pulNextCSA;
/* A pointer to the first CSA in the list of CSAs consumed by the task is
stored in the first element of the tasks TCB structure (where the stack
pointer would be on a traditional stack based architecture). */
pxHeadCSA = ( *pxTCB ) & portCSA_FCX_MASK;
/* Mask off everything in the CSA link field other than the address. If
the address is NULL, then the CSA is not linking anywhere and there is
nothing to do. */
pxTailCSA = pxHeadCSA;
/* Convert the link value to contain just a raw address and store this
in a local variable. */
pulNextCSA = portCSA_TO_ADDRESS( pxTailCSA );
/* Iterate over the CSAs that were consumed as part of the task. The
first field in the CSA is the pointer to then next CSA. Mask off
everything in the pointer to the next CSA, other than the link address.
If this is NULL, then the CSA currently being pointed to is the last in
the chain. */
while( 0UL != ( pulNextCSA[ 0 ] & portCSA_FCX_MASK ) )
{
/* Clear all bits of the pointer to the next in the chain, other
than the address bits themselves. */
pulNextCSA[ 0 ] = pulNextCSA[ 0 ] & portCSA_FCX_MASK;
/* Move the pointer to point to the next CSA in the list. */
pxTailCSA = pulNextCSA[ 0 ];
/* Update the local pointer to the CSA. */
pulNextCSA = portCSA_TO_ADDRESS( pxTailCSA );
}
_disable();
{
/* Look up the current free CSA head. */
_dsync();
pxFreeCSA = __MFCR( $FCX );
/* Join the current Free onto the Tail of what is being reclaimed. */
portCSA_TO_ADDRESS( pxTailCSA )[ 0 ] = pxFreeCSA;
/* Move the head of the reclaimed into the Free. */
_dsync();
_mtcr( $FCX, pxHeadCSA );
_isync();
}
_enable();
}
/*-----------------------------------------------------------*/
void vPortEndScheduler( void )
{
/* Nothing to do. Unlikely to want to end. */
}
/*-----------------------------------------------------------*/
void vTrapSysCallYield( int iTrapIdentification )
{
uint32_t *pxUpperCSA = NULL;
uint32_t xUpperCSA = 0UL;
extern volatile uint32_t *pxCurrentTCB;
switch( iTrapIdentification )
{
case portSYSCALL_TASK_YIELD:
/* Save the context of a task.
The upper context is automatically saved when entering a trap or interrupt.
Need to save the lower context as well and copy the PCXI CSA ID into
pxCurrentTCB->pxTopOfStack. Only Lower Context CSA IDs may be saved to the
TCB of a task.
Call vTaskSwitchContext to select the next task, note that this changes the
value of pxCurrentTCB so that it needs to be reloaded.
Call vPortSetMPURegisterSetOne to change the MPU mapping for the task
that has just been switched in.
Load the context of the task.
Need to restore the lower context by loading the CSA from
pxCurrentTCB->pxTopOfStack into PCXI (effectively changing the call stack).
In the Interrupt handler post-amble, RSLCX will restore the lower context
of the task. RFE will restore the upper context of the task, jump to the
return address and restore the previous state of interrupts being
enabled/disabled. */
_disable();
_dsync();
xUpperCSA = __MFCR( $PCXI );
pxUpperCSA = portCSA_TO_ADDRESS( xUpperCSA );
*pxCurrentTCB = pxUpperCSA[ 0 ];
vTaskSwitchContext();
pxUpperCSA[ 0 ] = *pxCurrentTCB;
SRBs[CPU_ID]->B.TRIG0 = 0; //ATEN
// CPU_SRC0.bits.SETR = 0;
_isync();
break;
default:
/* Unimplemented trap called. */
configASSERT( ( ( volatile void * ) NULL ) );
break;
}
}
/*-----------------------------------------------------------*/
static void prvInterruptYield( int iId )
{
uint32_t *pxUpperCSA = NULL;
uint32_t xUpperCSA = 0UL;
extern volatile uint32_t *pxCurrentTCB;
/* Just to remove compiler warnings. */
( void ) iId;
/* Save the context of a task.
The upper context is automatically saved when entering a trap or interrupt.
Need to save the lower context as well and copy the PCXI CSA ID into
pxCurrentTCB->pxTopOfStack. Only Lower Context CSA IDs may be saved to the
TCB of a task.
Call vTaskSwitchContext to select the next task, note that this changes the
value of pxCurrentTCB so that it needs to be reloaded.
Call vPortSetMPURegisterSetOne to change the MPU mapping for the task
that has just been switched in.
Load the context of the task.
Need to restore the lower context by loading the CSA from
pxCurrentTCB->pxTopOfStack into PCXI (effectively changing the call stack).
In the Interrupt handler post-amble, RSLCX will restore the lower context
of the task. RFE will restore the upper context of the task, jump to the
return address and restore the previous state of interrupts being
enabled/disabled. */
_disable();
_dsync();
xUpperCSA = __MFCR( $PCXI );
pxUpperCSA = portCSA_TO_ADDRESS( xUpperCSA );
*pxCurrentTCB = pxUpperCSA[ 0 ];
vTaskSwitchContext();
pxUpperCSA[ 0 ] = *pxCurrentTCB;
SRBs[CPU_ID]->B.TRIG0 = 0; //ATEN
//CPU_SRC0.bits.SETR = 0;
_isync();
}
/*-----------------------------------------------------------*/
uint32_t uxPortSetInterruptMaskFromISR( void )
{
uint32_t uxReturn = 0UL;
_disable();
uxReturn = __MFCR( $ICR );
_mtcr( $ICR, ( ( uxReturn & ~portCCPN_MASK ) | configMAX_SYSCALL_INTERRUPT_PRIORITY ) );
_isync();
_enable();
/* Return just the interrupt mask bits. */
return ( uxReturn & portCCPN_MASK );
}
/*-----------------------------------------------------------*/
@@ -0,0 +1,42 @@
/*
* FreeRTOS Kernel V10.4.1
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
* 1 tab == 4 spaces!
*/
#ifndef _PORTABLE_GCC_TRICORE_PORT_H_
#define _PORTABLE_GCC_TRICORE_PORT_H_
//These definitions seem to be missing within the TC3xx include files
//Compile the project with the "-fdollars-in-identifiers" option!!
#define $FCX 0xFE38
#define $ICR 0xFE2C
#define $PCXI 0xFE00
#define $PSW 0xFE04
#define $SYSCON 0xFE14
extern void vTrapSysCallYield( int iTrapIdentification );
#endif /* _PORTABLE_GCC_TRICORE_PORT_H_ */
@@ -0,0 +1,179 @@
/*
* FreeRTOS Kernel V10.4.1
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
* 1 tab == 4 spaces!
*/
#ifndef _PORTABLE_GCC_TRICORE_PORTMACRO_H_
#define _PORTABLE_GCC_TRICORE_PORTMACRO_H_
/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C" {
#endif
/* *INDENT-ON* */
#include "port.h"
/* System Includes. */
#include <machine/intrinsics.h>
#include <tc38xaIfx_reg.h>
/*-----------------------------------------------------------
* Port specific definitions.
*
* The settings in this file configure FreeRTOS correctly for the
* given hardware and compiler.
*
* These settings should not be altered.
*-----------------------------------------------------------
*/
/* Type definitions. */
#define portCHAR char
#define portFLOAT float
#define portDOUBLE double
#define portLONG long
#define portSHORT short
#define portSTACK_TYPE uint32_t
#define portBASE_TYPE unsigned long
typedef portSTACK_TYPE StackType_t;
typedef long BaseType_t;
typedef unsigned long UBaseType_t;
#if( configUSE_16_BIT_TICKS == 1 )
typedef uint16_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffff
#else
typedef uint32_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
/* 32-bit tick type on a 32-bit architecture, so reads of the tick count do
not need to be guarded with a critical section. */
#define portTICK_TYPE_IS_ATOMIC 1
#endif
/*---------------------------------------------------------------------------*/
/* Architecture specifics. */
#define portSTACK_GROWTH ( -1 )
#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ )
#define portBYTE_ALIGNMENT 4
#define portNOP() __asm volatile( " nop " )
#define portCRITICAL_NESTING_IN_TCB 1
#define portRESTORE_FIRST_TASK_PRIORITY_LEVEL 1
/*---------------------------------------------------------------------------*/
typedef struct MPU_SETTINGS { uint32_t ulNotUsed; } xMPU_SETTINGS;
/* Define away the instruction from the Restore Context Macro. */
#define portPRIVILEGE_BIT 0x0UL
#define portCCPN_MASK ( 0x000000FFUL )
extern void vTaskEnterCritical( void );
extern void vTaskExitCritical( void );
#define portENTER_CRITICAL() vTaskEnterCritical()
#define portEXIT_CRITICAL() vTaskExitCritical()
/*---------------------------------------------------------------------------*/
/* CSA Manipulation. */
#define portCSA_TO_ADDRESS( pCSA ) ( ( uint32_t * )( ( ( ( pCSA ) & 0x000F0000 ) << 12 ) | ( ( ( pCSA ) & 0x0000FFFF ) << 6 ) ) )
#define portADDRESS_TO_CSA( pAddress ) ( ( uint32_t )( ( ( ( (uint32_t)( pAddress ) ) & 0xF0000000 ) >> 12 ) | ( ( ( uint32_t )( pAddress ) & 0x003FFFC0 ) >> 6 ) ) )
/*---------------------------------------------------------------------------*/
#define portYIELD() _syscall( 0 )
/* Port Restore is implicit in the platform when the function is returned from the original PSW is automatically replaced. */
#define portSYSCALL_TASK_YIELD 0
#define portSYSCALL_RAISE_PRIORITY 1
/*---------------------------------------------------------------------------*/
/* Critical section management. */
/* Set ICR.CCPN to configMAX_SYSCALL_INTERRUPT_PRIORITY. */
#define portDISABLE_INTERRUPTS() { \
uint32_t ulICR; \
_disable(); \
ulICR = __MFCR( $ICR ); /* Get current ICR value. */ \
ulICR &= ~portCCPN_MASK; /* Clear down mask bits. */ \
ulICR |= configMAX_SYSCALL_INTERRUPT_PRIORITY; /* Set mask bits to required priority mask. */ \
_mtcr( $ICR, ulICR ); /* Write back updated ICR. */ \
_isync(); \
_enable(); \
}
/* Clear ICR.CCPN to allow all interrupt priorities. */
#define portENABLE_INTERRUPTS() { \
uint32_t ulICR; \
_disable(); \
ulICR = __MFCR( $ICR ); /* Get current ICR value. */ \
ulICR &= ~portCCPN_MASK; /* Clear down mask bits. */ \
_mtcr( $ICR, ulICR ); /* Write back updated ICR. */ \
_isync(); \
_enable(); \
}
/* Set ICR.CCPN to uxSavedMaskValue. */
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedMaskValue ) { \
uint32_t ulICR; \
_disable(); \
ulICR = __MFCR( $ICR ); /* Get current ICR value. */ \
ulICR &= ~portCCPN_MASK; /* Clear down mask bits. */ \
ulICR |= uxSavedMaskValue; /* Set mask bits to previously saved mask value. */ \
_mtcr( $ICR, ulICR ); /* Write back updated ICR. */ \
_isync(); \
_enable(); \
}
/* Set ICR.CCPN to configMAX_SYSCALL_INTERRUPT_PRIORITY */
extern uint32_t uxPortSetInterruptMaskFromISR( void );
#define portSET_INTERRUPT_MASK_FROM_ISR() uxPortSetInterruptMaskFromISR()
/* Pend a priority 1 interrupt, which will take care of the context switch. */
#define portYIELD_FROM_ISR( xHigherPriorityTaskWoken ) if( xHigherPriorityTaskWoken != pdFALSE ) { _isync(); }
/*---------------------------------------------------------------------------*/
/* Task function macros as described on the FreeRTOS.org WEB site. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
/*---------------------------------------------------------------------------*/
/*
* Port specific clean up macro required to free the CSAs that were consumed by
* a task that has since been deleted.
*/
void vPortReclaimCSA( uint32_t *pxTCB );
#define portCLEAN_UP_TCB( pxTCB ) vPortReclaimCSA( ( uint32_t * ) ( pxTCB ) )
/* *INDENT-OFF* */
#ifdef __cplusplus
}
#endif
/* *INDENT-ON* */
#endif /* _PORTABLE_GCC_TRICORE_PORTMACRO_H_ */
@@ -0,0 +1,281 @@
/*
* FreeRTOS Kernel V10.4.1
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
* 1 tab == 4 spaces!
*/
/* Kernel includes. */
#include "FreeRTOS.h"
/* Machine includes */
#include <machine/intrinsics.h>
#include <machine/cint.h>
#include <tc38xa/Ifx_reg.h>
/*---------------------------------------------------------------------------*/
/*
* This reference is required by the Save/Restore Context Macros.
*/
extern volatile uint32_t *pxCurrentTCB;
/*-----------------------------------------------------------*/
/*
* This file contains base definitions for all of the possible traps in the system.
* It is suggested to provide implementations for all of the traps but for
* the time being they simply trigger a DEBUG instruction so that it is easy
* to see what caused a particular trap.
*
* Trap Class 6, the SYSCALL, is used exclusively by the operating system.
*/
/* The Trap Classes. */
#define portMMU_TRAP 0
#define portIPT_TRAP 1
#define portIE_TRAP 2
#define portCM_TRAP 3
#define portSBP_TRAP 4
#define portASSERT_TRAP 5
#define portNMI_TRAP 7
/* MMU Trap Identifications. */
#define portTIN_MMU_VIRTUAL_ADDRESS_FILL 0
#define portTIN_MMU_VIRTUAL_ADDRESS_PROTECTION 1
/* Internal Protection Trap Identifications. */
#define portTIN_IPT_PRIVILIGED_INSTRUCTION 1
#define portTIN_IPT_MEMORY_PROTECTION_READ 2
#define portTIN_IPT_MEMORY_PROTECTION_WRITE 3
#define portTIN_IPT_MEMORY_PROTECTION_EXECUTION 4
#define portTIN_IPT_MEMORY_PROTECTION_PERIPHERAL_ACCESS 5
#define portTIN_IPT_MEMORY_PROTECTION_NULL_ADDRESS 6
#define portTIN_IPT_MEMORY_PROTECTION_GLOBAL_REGISTER_WRITE_PROTECTION 7
/* Instruction Error Trap Identifications. */
#define portTIN_IE_ILLEGAL_OPCODE 1
#define portTIN_IE_UNIMPLEMENTED_OPCODE 2
#define portTIN_IE_INVALID_OPERAND 3
#define portTIN_IE_DATA_ADDRESS_ALIGNMENT 4
#define portTIN_IE_INVALID_LOCAL_MEMORY_ADDRESS 5
/* Context Management Trap Identifications. */
#define portTIN_CM_FREE_CONTEXT_LIST_DEPLETION 1
#define portTIN_CM_CALL_DEPTH_OVERFLOW 2
#define portTIN_CM_CALL_DEPTH_UNDEFLOW 3
#define portTIN_CM_FREE_CONTEXT_LIST_UNDERFLOW 4
#define portTIN_CM_CALL_STACK_UNDERFLOW 5
#define portTIN_CM_CONTEXT_TYPE 6
#define portTIN_CM_NESTING_ERROR 7
/* System Bus and Peripherals Trap Identifications. */
#define portTIN_SBP_PROGRAM_FETCH_SYNCHRONOUS_ERROR 1
#define portTIN_SBP_DATA_ACCESS_SYNCHRONOUS_ERROR 2
#define portTIN_SBP_DATA_ACCESS_ASYNCHRONOUS_ERROR 3
#define portTIN_SBP_COPROCESSOR_TRAP_ASYNCHRONOUS_ERROR 4
#define portTIN_SBP_PROGRAM_MEMORY_INTEGRITY_ERROR 5
#define portTIN_SBP_DATA_MEMORY_INTEGRITY_ERROR 6
/* Assertion Trap Identifications. */
#define portTIN_ASSERT_ARITHMETIC_OVERFLOW 1
#define portTIN_ASSERT_STICKY_ARITHMETIC_OVERFLOW 2
/* Non-maskable Interrupt Trap Identifications. */
#define portTIN_NMI_NON_MASKABLE_INTERRUPT 0
/*---------------------------------------------------------------------------*/
void vMMUTrap( int iTrapIdentification ) __attribute__( ( longcall, weak ) );
void vInternalProtectionTrap( int iTrapIdentification ) __attribute__( ( longcall, weak ) );
void vInstructionErrorTrap( int iTrapIdentification ) __attribute__( ( longcall, weak ) );
void vContextManagementTrap( int iTrapIdentification ) __attribute__( ( longcall, weak ) );
void vSystemBusAndPeripheralsTrap( int iTrapIdentification ) __attribute__( ( longcall, weak ) );
void vAssertionTrap( int iTrapIdentification ) __attribute__( ( longcall, weak ) );
void vNonMaskableInterruptTrap( int iTrapIdentification ) __attribute__( ( longcall, weak ) );
/*---------------------------------------------------------------------------*/
void vTrapInstallHandlers( void )
{
if( 0 == _install_trap_handler ( portMMU_TRAP, vMMUTrap ) )
{
_debug();
}
if( 0 == _install_trap_handler ( portIPT_TRAP, vInternalProtectionTrap ) )
{
_debug();
}
if( 0 == _install_trap_handler ( portIE_TRAP, vInstructionErrorTrap ) )
{
_debug();
}
if( 0 == _install_trap_handler ( portCM_TRAP, vContextManagementTrap ) )
{
_debug();
}
if( 0 == _install_trap_handler ( portSBP_TRAP, vSystemBusAndPeripheralsTrap ) )
{
_debug();
}
if( 0 == _install_trap_handler ( portASSERT_TRAP, vAssertionTrap ) )
{
_debug();
}
if( 0 == _install_trap_handler ( portNMI_TRAP, vNonMaskableInterruptTrap ) )
{
_debug();
}
}
/*-----------------------------------------------------------*/
void vMMUTrap( int iTrapIdentification )
{
switch( iTrapIdentification )
{
case portTIN_MMU_VIRTUAL_ADDRESS_FILL:
case portTIN_MMU_VIRTUAL_ADDRESS_PROTECTION:
default:
_debug();
break;
}
}
/*---------------------------------------------------------------------------*/
void vInternalProtectionTrap( int iTrapIdentification )
{
/* Deliberate fall through to default. */
switch( iTrapIdentification )
{
case portTIN_IPT_PRIVILIGED_INSTRUCTION:
/* Instruction is not allowed at current execution level, eg DISABLE at User-0. */
case portTIN_IPT_MEMORY_PROTECTION_READ:
/* Load word using invalid address. */
case portTIN_IPT_MEMORY_PROTECTION_WRITE:
/* Store Word using invalid address. */
case portTIN_IPT_MEMORY_PROTECTION_EXECUTION:
/* PC jumped to an address outside of the valid range. */
case portTIN_IPT_MEMORY_PROTECTION_PERIPHERAL_ACCESS:
/* Access to a peripheral denied at current execution level. */
case portTIN_IPT_MEMORY_PROTECTION_NULL_ADDRESS:
/* NULL Pointer. */
case portTIN_IPT_MEMORY_PROTECTION_GLOBAL_REGISTER_WRITE_PROTECTION:
/* Tried to modify a global address pointer register. */
default:
pxCurrentTCB[ 0 ] = __MFCR( $PCXI );
_debug();
break;
}
}
/*---------------------------------------------------------------------------*/
void vInstructionErrorTrap( int iTrapIdentification )
{
/* Deliberate fall through to default. */
switch( iTrapIdentification )
{
case portTIN_IE_ILLEGAL_OPCODE:
case portTIN_IE_UNIMPLEMENTED_OPCODE:
case portTIN_IE_INVALID_OPERAND:
case portTIN_IE_DATA_ADDRESS_ALIGNMENT:
case portTIN_IE_INVALID_LOCAL_MEMORY_ADDRESS:
default:
_debug();
break;
}
}
/*---------------------------------------------------------------------------*/
void vContextManagementTrap( int iTrapIdentification )
{
/* Deliberate fall through to default. */
switch( iTrapIdentification )
{
case portTIN_CM_FREE_CONTEXT_LIST_DEPLETION:
case portTIN_CM_CALL_DEPTH_OVERFLOW:
case portTIN_CM_CALL_DEPTH_UNDEFLOW:
case portTIN_CM_FREE_CONTEXT_LIST_UNDERFLOW:
case portTIN_CM_CALL_STACK_UNDERFLOW:
case portTIN_CM_CONTEXT_TYPE:
case portTIN_CM_NESTING_ERROR:
default:
_debug();
break;
}
}
/*---------------------------------------------------------------------------*/
void vSystemBusAndPeripheralsTrap( int iTrapIdentification )
{
/* Deliberate fall through to default. */
switch( iTrapIdentification )
{
case portTIN_SBP_PROGRAM_FETCH_SYNCHRONOUS_ERROR:
case portTIN_SBP_DATA_ACCESS_SYNCHRONOUS_ERROR:
case portTIN_SBP_DATA_ACCESS_ASYNCHRONOUS_ERROR:
case portTIN_SBP_COPROCESSOR_TRAP_ASYNCHRONOUS_ERROR:
case portTIN_SBP_PROGRAM_MEMORY_INTEGRITY_ERROR:
case portTIN_SBP_DATA_MEMORY_INTEGRITY_ERROR:
default:
_debug();
break;
}
}
/*---------------------------------------------------------------------------*/
void vAssertionTrap( int iTrapIdentification )
{
/* Deliberate fall through to default. */
switch( iTrapIdentification )
{
case portTIN_ASSERT_ARITHMETIC_OVERFLOW:
case portTIN_ASSERT_STICKY_ARITHMETIC_OVERFLOW:
default:
_debug();
break;
}
}
/*---------------------------------------------------------------------------*/
void vNonMaskableInterruptTrap( int iTrapIdentification )
{
/* Deliberate fall through to default. */
switch( iTrapIdentification )
{
case portTIN_NMI_NON_MASKABLE_INTERRUPT:
default:
_debug();
break;
}
}
/*---------------------------------------------------------------------------*/
@@ -0,0 +1 @@
Compile the project with the "-fdollars-in-identifiers" option!!