Skip to content

Commit 222a5ad

Browse files
committed
cortex-r82: Add Non-MPU SMP FVP Example
This example shows how to bring-up FreeRTOS-SMP on an Arm Cortex-R82 multiprocessor system using the BaseR AEMv8R Architecture Envelope Model (AEM) Fixed Virtual Platform (FVP). Signed-off-by: Ahmed Ismail <Ahmed.Ismail@arm.com>
1 parent 681423f commit 222a5ad

File tree

17 files changed

+1806
-0
lines changed

17 files changed

+1806
-0
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Copyright 2023-2025 Arm Limited and/or its affiliates <open-source-office@arm.com>
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
cmake_minimum_required(VERSION 3.15)
6+
7+
add_library(bsp INTERFACE)
8+
9+
target_sources(bsp
10+
INTERFACE
11+
${CMAKE_CURRENT_SOURCE_DIR}/Source/port_asm_vectors.S
12+
${CMAKE_CURRENT_SOURCE_DIR}/Source/boot.S
13+
${CMAKE_CURRENT_SOURCE_DIR}/Source/xil-crt0.S
14+
${CMAKE_CURRENT_SOURCE_DIR}/Source/gic.c
15+
)
16+
17+
target_include_directories(bsp
18+
INTERFACE
19+
${CMAKE_CURRENT_SOURCE_DIR}/Include
20+
)
21+
22+
target_link_libraries(bsp
23+
INTERFACE
24+
freertos_kernel
25+
)
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/* Copyright 2025 Arm Limited and/or its affiliates <open-source-office@arm.com>
2+
* SPDX-License-Identifier: MIT
3+
*/
4+
5+
#define GICD_BASE ( 0xAF000000UL ) /* Base of GIC Distributor on BaseR FVP */
6+
#define GICR_BASE_PER_CORE( core ) ( 0xAF100000 + (0x20000 * ( core ) ) ) /* Base of GIC Redistributor per core on BaseR FVP */
7+
#define SGI_BASE ( 0x10000 ) /* SGI Base */
8+
#define GICD_CTLR ( 0x000 ) /* Distributor Control Register */
9+
#define GICR_WAKER ( 0x14 ) /* ReDistributor Wake Register */
10+
#define GICR_PWRR ( 0x24 ) /* ReDistributor Power Register */
11+
#define GICR_IGROUPR0 ( SGI_BASE + 0x80 ) /* Interrupt Group Registers */
12+
#define GICR_ISENABLER0 ( SGI_BASE + 0x100 ) /* Interrupt Set-Enable Registers */
13+
#define GICR_IPRIORITYR( n ) ( SGI_BASE + ( 0x400 + ( 4 * n ) ) ) /* Interrupt Priority Registers */
14+
#define GICR_IGRPMODR0 ( SGI_BASE + 0xD00 ) /* Distributor Interrupt group modifier Register */
15+
16+
#define GICD_CTLR_ENABLEGRP1NS_BIT ( 1U ) /* GICD_CTRL.EnableGrp1NS bit */
17+
#define GICD_CTLR_ENABLEGRP1S_BIT ( 2U ) /* GICD_CTRL.EnableGrp1S bit */
18+
#define GICD_CTLR_ARES_BIT ( 4U ) /* GICD_CTRL.ARE_S bit */
19+
#define GICD_CTLR_DS_BIT ( 6U ) /* GICD_CTRL.DS bit */
20+
21+
#define GICR_PWRR_RDPD_BIT ( 0U ) /* GICR_PWRR.RDPD bit */
22+
23+
#define GICR_WAKER_PS_BIT ( 1U ) /* GICR_WAKER.PS bit */
24+
#define GICR_WAKER_CA_BIT ( 2U ) /* GICR_WAKER.CA bit */
25+
26+
#define GIC_MAX_INTERRUPT_ID ( 31UL ) /* Maximum Interrupt ID for PPIs and SGIs */
27+
#define GIC_WAIT_TIMEOUT ( 1000000U ) /* Timeout for waiting on GIC operations */
28+
29+
/**
30+
* Assigns the specified interrupt to Group 1 and enables it
31+
* in the Redistributor for the local core.
32+
*/
33+
void vGIC_EnableIRQ( uint32_t ulInterruptID );
34+
35+
/**
36+
* Enables signaling of Group-1 interrupts at EL1 via ICC_IGRPEN1_EL1.
37+
*/
38+
void vGIC_EnableCPUInterface( void );
39+
40+
/**
41+
* Initializes the GIC Distributor:
42+
* - Enables Group-1 Non-Secure and Group-1 Secure interrupts
43+
* - Enables Affinity Routing (ARE_S) and Disable Security (DS) bits
44+
*/
45+
void vGIC_InitDist( void );
46+
47+
/**
48+
* Powers up and wakes the Redistributor for the current core:
49+
* 1. Clears the Redistributor power-down bit and waits for RDPD=0
50+
* 2. Clears the Processor-Sleep bit and waits for Children-Asleep=0
51+
*/
52+
void vGIC_PowerUpRedistributor( void );
53+
54+
/**
55+
* Sets the priority of the specified SGI/PPI (INTID 0‑31) in the local
56+
* Redistributor bank via GICR_IPRIORITYR.
57+
* For shared peripheral interrupts (SPI, INTID ≥ 32) use the GICD_IPRIORITYR path.
58+
*
59+
* @param ulInterruptID The ID of the interrupt to set the priority for.
60+
* @param ulPriority The priority value to set.
61+
*/
62+
void vGIC_SetPriority( uint32_t ulInterruptID, uint32_t ulPriority );
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
/******************************************************************************
2+
* Copyright (c) 2014 - 2020 Xilinx, Inc. All rights reserved.
3+
* Copyright 2025 Arm Limited and/or its affiliates <open-source-office@arm.com>
4+
* SPDX-License-Identifier: MIT
5+
******************************************************************************/
6+
.global secondary_cores_release_flag
7+
8+
.section .bss
9+
secondary_cores_release_flag:
10+
.skip 8
11+
12+
#if defined(__ARMCC_VERSION)
13+
/* Externs needed by the MPU setup code. These are defined in Scatter-Loading
14+
* description file (armclang.sct). */
15+
.set __el1_stack, Image$$ARM_LIB_STACK$$Base
16+
.set _el1_stack_end, Image$$ARM_LIB_HEAP$$Base
17+
#endif
18+
19+
#include "FreeRTOSConfig.h"
20+
21+
.global _prestart
22+
.global _boot
23+
24+
.global __el1_stack
25+
.global _vector_table
26+
27+
.set EL1_stack, __el1_stack
28+
29+
.set EL1_stack_end, _el1_stack_end
30+
31+
.set vector_base, _vector_table
32+
33+
/*
34+
* N_CPUS_SHIFT must equal log2(configNUMBER_OF_CORES). It represents the
35+
* number of bits required to index the core that owns a particular slice
36+
* of the shared EL1 stack pool.
37+
*
38+
* To avoid overlapping stack regions, the code assumes
39+
* configNUMBER_OF_CORES is a power‑of‑two. The static check below forces
40+
* a build‑time error if that assumption is broken.
41+
*/
42+
#if ( (configNUMBER_OF_CORES & (configNUMBER_OF_CORES - 1)) != 0 )
43+
#error "configNUMBER_OF_CORES must be a power‑of‑two"
44+
#endif
45+
46+
/* Compute log2(configNUMBER_OF_CORES). */
47+
#if (configNUMBER_OF_CORES == 1)
48+
.set N_CPUS_SHIFT, 0
49+
#elif (configNUMBER_OF_CORES == 2)
50+
.set N_CPUS_SHIFT, 1
51+
#elif (configNUMBER_OF_CORES == 4)
52+
.set N_CPUS_SHIFT, 2
53+
#else
54+
#error "Unsupported configNUMBER_OF_CORES value — must be a power‑of‑two up to 4"
55+
#endif
56+
57+
.section .boot,"ax"
58+
59+
_prestart:
60+
_boot:
61+
#if configNUMBER_OF_CORES > 1
62+
/* Get CPU Id */
63+
mrs x0, MPIDR_EL1
64+
and x0, x0, #0xFF
65+
cbz x0, start
66+
secondary_cores_hold:
67+
ldr x0, =secondary_cores_release_flag
68+
ldr w1, [x0] /* Has core 0 set the flag? */
69+
cbnz w1, start /* Non-zero → Secondary cores released */
70+
wfe /* Sleep until any event */
71+
b secondary_cores_hold /* Re-test the flag */
72+
#endif
73+
start:
74+
/* Clear all GP registers (x0–x30) for a known initial state */
75+
mov x0, #0
76+
mov x1, #0
77+
mov x2, #0
78+
mov x3, #0
79+
mov x4, #0
80+
mov x5, #0
81+
mov x6, #0
82+
mov x7, #0
83+
mov x8, #0
84+
mov x9, #0
85+
mov x10, #0
86+
mov x11, #0
87+
mov x12, #0
88+
mov x13, #0
89+
mov x14, #0
90+
mov x15, #0
91+
mov x16, #0
92+
mov x17, #0
93+
mov x18, #0
94+
mov x19, #0
95+
mov x20, #0
96+
mov x21, #0
97+
mov x22, #0
98+
mov x23, #0
99+
mov x24, #0
100+
mov x25, #0
101+
mov x26, #0
102+
mov x27, #0
103+
mov x28, #0
104+
mov x29, #0
105+
mov x30, #0
106+
107+
mrs x0, currentEL
108+
cmp x0, #0x4
109+
beq InitEL1
110+
111+
b error /* Check we’ve come from EL1 (currentEL==0x4), otherwise fault */
112+
InitEL1:
113+
/* Set vector table base address */
114+
ldr x1, =vector_base
115+
msr VBAR_EL1,x1
116+
117+
mrs x0, CPACR_EL1
118+
orr x0, x0, #(0x1 << 20)
119+
msr CPACR_EL1, x0 /* Enable FP/SIMD access at EL1 */
120+
isb
121+
122+
/* Clear FP status flags (FPSR) to avoid spurious exceptions on first use */
123+
mov x0, 0x0
124+
msr FPSR, x0
125+
126+
/* Define stack pointer for current exception level */
127+
#if configNUMBER_OF_CORES > 1
128+
/* Divide the EL1 stack region equally among all cores, then set SP based on MPIDR_EL1[7:0] */
129+
/* x0 = log2(N_CPUS) is assumed to be a build-time constant */
130+
mov x0, N_CPUS_SHIFT /* log2(#cores) */
131+
/* load overall stack limits */
132+
ldr x2, =EL1_stack /* low address of the shared stack pool */
133+
ldr x3, =EL1_stack_end /* high address (one past the pool) */
134+
/* x1 = total size of the pool, x1 >> N_CPUS_SHIFT = size per core */
135+
sub x1, x3, x2 /* total_stack_size */
136+
lsr x1, x1, x0 /* slice_size = total/#cores */
137+
/* x4 = this CPU’s index (Aff0 field of MPIDR_EL1) */
138+
mrs x4, MPIDR_EL1
139+
and x4, x4, #0xFF /* core_id ∈ {0 … N_CPUS-1} */
140+
cmp x4, #configNUMBER_OF_CORES
141+
b.hs error
142+
/* x0 = slice_size * core_id → how far to step back from the top */
143+
mul x0, x1, x4
144+
/* sp = top_of_pool – offset (so core 0 gets the very top) */
145+
sub x3, x3, x0 /* x3 = initial SP for this core */
146+
bic x3, x3, #0xF /* keep the mandated 16-byte alignment */
147+
mov sp, x3
148+
#else
149+
ldr x2, =EL1_stack_end
150+
mov sp, x2
151+
#endif
152+
153+
/* Enable ICC system-register interface (SRE=1) and disable FIQ/IRQ bypass (DFB/DIB) */
154+
mov x0, #0x7
155+
msr ICC_SRE_EL1, x0
156+
157+
/* Invalidate I and D caches */
158+
ic IALLU
159+
bl invalidate_dcaches
160+
dsb sy
161+
isb
162+
163+
/* Unmask SError interrupts (clear DAIF.A bit) */
164+
mrs x1,DAIF
165+
bic x1,x1,#(0x1<<8)
166+
msr DAIF,x1
167+
168+
mrs x1, SCTLR_EL1
169+
orr x1, x1, #(1 << 2) /* Set SCTLR_EL1.C caching enable bit */
170+
msr SCTLR_EL1, x1
171+
172+
/* Branch to C-level startup (zero BSS, init data, etc.) */
173+
bl _startup
174+
175+
/* If we ever get here, something went wrong—hang forever */
176+
error:
177+
b error
178+
179+
invalidate_dcaches:
180+
181+
dmb ISH
182+
mrs x0, CLIDR_EL1 /* x0 = CLIDR */
183+
ubfx w2, w0, #24, #3 /* w2 = CLIDR.LoC */
184+
cmp w2, #0 /* LoC is 0? */
185+
b.eq invalidateCaches_end /* No cleaning required */
186+
mov w1, #0 /* w1 = level iterator */
187+
188+
invalidateCaches_flush_level:
189+
add w3, w1, w1, lsl #1 /* w3 = w1 * 3 (right-shift for cache type) */
190+
lsr w3, w0, w3 /* w3 = w0 >> w3 */
191+
ubfx w3, w3, #0, #3 /* w3 = cache type of this level */
192+
cmp w3, #2 /* No cache at this level? */
193+
b.lt invalidateCaches_next_level
194+
195+
lsl w4, w1, #1
196+
msr CSSELR_EL1, x4 /* Select current cache level in CSSELR */
197+
isb /* ISB required to reflect new CSIDR */
198+
mrs x4, CCSIDR_EL1 /* w4 = CSIDR */
199+
200+
ubfx w3, w4, #0, #3
201+
add w3, w3, #2 /* w3 = log2(line size) */
202+
ubfx w5, w4, #13, #15
203+
ubfx w4, w4, #3, #10 /* w4 = Way number */
204+
clz w6, w4 /* w6 = 32 - log2(number of ways) */
205+
206+
invalidateCaches_flush_set:
207+
mov w8, w4 /* w8 = Way number */
208+
invalidateCaches_flush_way:
209+
lsl w7, w1, #1 /* Fill level field */
210+
lsl w9, w5, w3
211+
orr w7, w7, w9 /* Fill level field */
212+
lsl w9, w8, w6
213+
orr w7, w7, w9 /* Fill way field */
214+
dc CISW, x7 /* Invalidate by set/way to point of coherency */
215+
subs w8, w8, #1 /* Decrement way */
216+
b.ge invalidateCaches_flush_way
217+
subs w5, w5, #1 /* Descrement set */
218+
b.ge invalidateCaches_flush_set
219+
220+
invalidateCaches_next_level:
221+
add w1, w1, #1 /* Next level */
222+
cmp w2, w1
223+
b.gt invalidateCaches_flush_level
224+
225+
invalidateCaches_end:
226+
ret
227+
228+
.end

0 commit comments

Comments
 (0)