Skip to content

Commit 4d92c92

Browse files
committed
arch/tricore: enter threads via user_runtime and fix CPXE map
- Point fabricated CSA PC at ulmk_user_thread_entry (CPR 1) so PRS 1 driver/user threads never fetch .kernel_text (class-1 MPX tin=4) - Program CPXE at 0xE000 (no phantom CPRE); 0xE040 is Safety RGNLA - Use exclusive DPR/CPR upper bounds; ALIGN(MPU) at kernel_text end
1 parent 339e5f3 commit 4d92c92

4 files changed

Lines changed: 82 additions & 90 deletions

File tree

arch/tricore/arch.c

Lines changed: 63 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ void ulmk_arch_csa_pool_init(uintptr_t pool_base, size_t pool_size)
203203
*/
204204
}
205205

206-
extern void _ulmk_thread_trampoline(void);
206+
extern void ulmk_user_thread_entry(void (*entry)(void *arg), void *arg);
207207

208208
/*
209209
* Fabricate the initial two-frame CSA chain for a new thread.
@@ -212,22 +212,24 @@ extern void _ulmk_thread_trampoline(void);
212212
* Upper context (CALL/RFE): PCXI PSW A10 A11 D8-D11 A12-A15 D12-D15
213213
* Lower context (SVLCX/RSLCX): PCXI A11 A2 A3 D0-D3 A4-A7 D4-D7
214214
*
215-
* RFE restores the upper context; PC is taken from A11 pre-restore.
216-
* lower_csa[1] = trampoline sets the jump target for the first RFE.
215+
* First PC after RSLCX+RFE is upper A11. That must be
216+
* ulmk_user_thread_entry in .user_runtime (CPR 1): driver/user threads run
217+
* with PSW.PRS=1 and cannot fetch from .kernel_text (CPR 0). A kernel-side
218+
* trampoline here causes class-1 MPX (tin=4) on the first instruction.
217219
*
218220
* Fabricated frames:
219221
*
220222
* Upper CSA (UL=1):
221223
* [0] PCXI = 0 (terminal)
222-
* [1] PSW (privilege)
224+
* [1] PSW (privilege + PRS)
223225
* [2] A10 (stack_top)
224-
* [3] A11 (trampoline — restored into A11 register by RFE)
225-
* [10] A14 (entry function address — loaded by RFE into A14)
226+
* [3] A11 (ulmk_user_thread_entry — RFE PC)
226227
*
227228
* Lower CSA (UL=0):
228-
* [0] PCXI (upper_link | UL_FLAG)
229-
* [1] A11 (trampoline — RFE uses this for PC before restore)
230-
* [8] A4 (arg pointer — restored by RSLCX, ABI-correct)
229+
* [0] PCXI (upper_link | UL_FLAG | PIE)
230+
* [1] A11 (same entry; consistent with RSLCX restore)
231+
* [8] A4 (thread entry fn — ABI arg0)
232+
* [9] A5 (thread arg — ABI arg1)
231233
*
232234
* ctx->pcxi = lower_link (UL=0).
233235
*/
@@ -241,6 +243,7 @@ void ulmk_arch_ctx_init(ulmk_arch_ctx_t *ctx,
241243
uint32_t *lower_csa;
242244
uint32_t psw;
243245
uint32_t i;
246+
uint32_t entry_pc;
244247

245248
/*
246249
* Build the initial PSW from the current kernel PSW, overriding the
@@ -266,14 +269,15 @@ void ulmk_arch_ctx_init(ulmk_arch_ctx_t *ctx,
266269
if (priv != ULMK_PRIV_KERNEL)
267270
psw |= (uint32_t)ULMK_ARCH_PRS_USER << 12;
268271

272+
entry_pc = (uint32_t)(uintptr_t)ulmk_user_thread_entry;
273+
269274
upper_link = csa_alloc();
270275
upper_csa = csa_link_to_addr(upper_link);
271276
for (i = 0u; i < 16u; i++)
272277
upper_csa[i] = 0u;
273-
upper_csa[1] = psw;
274-
upper_csa[2] = (uint32_t)stack_top;
275-
upper_csa[3] = (uint32_t)(uintptr_t)_ulmk_thread_trampoline;
276-
upper_csa[10] = (uint32_t)(uintptr_t)entry; /* A14: entry fn */
278+
upper_csa[1] = psw;
279+
upper_csa[2] = (uint32_t)stack_top;
280+
upper_csa[3] = entry_pc;
277281

278282
lower_link = csa_alloc();
279283
lower_csa = csa_link_to_addr(lower_link);
@@ -285,8 +289,9 @@ void ulmk_arch_ctx_init(ulmk_arch_ctx_t *ctx,
285289
* are left disabled in every new thread, blocking timer preemption.
286290
*/
287291
lower_csa[0] = upper_link | UL_CSA_UL_FLAG | (1u << 21);
288-
lower_csa[1] = (uint32_t)(uintptr_t)_ulmk_thread_trampoline;
289-
lower_csa[8] = (uint32_t)(uintptr_t)arg; /* A4: pointer arg */
292+
lower_csa[1] = entry_pc;
293+
lower_csa[8] = (uint32_t)(uintptr_t)entry; /* A4 */
294+
lower_csa[9] = (uint32_t)(uintptr_t)arg; /* A5 */
290295

291296
ctx->pcxi = lower_link;
292297
}
@@ -493,15 +498,17 @@ static void mpu_write_cpr(uint8_t slot, uint32_t lower, uint32_t upper)
493498
}
494499

495500
/*
496-
* Write DPRE, DPWE, CPRE, CPXE enable registers for a given PRS.
501+
* Write DPRE, DPWE, CPXE enable registers for a given PRS.
497502
* ISYNC is issued at the end to flush the pipeline.
503+
*
504+
* TC2xx/TC3xx have no separate CPRE CSFR — only CPXE at 0xE000+prs*4.
505+
* Writing a phantom "CPXE" at 0xE040 hits Safety RGNLA on TC27x.
498506
*/
499507
static void mpu_write_enables(uint8_t prs, uint32_t dpre, uint32_t dpwe,
500-
uint32_t cpre, uint32_t cpxe)
508+
uint32_t cpxe)
501509
{
502510
mpu_mtcr(ULMK_ARCH_CSFR_DPRE_0 + (uint32_t)prs * 4u, dpre);
503511
mpu_mtcr(ULMK_ARCH_CSFR_DPWE_0 + (uint32_t)prs * 4u, dpwe);
504-
mpu_mtcr(ULMK_ARCH_CSFR_CPRE_0 + (uint32_t)prs * 4u, cpre);
505512
mpu_mtcr(ULMK_ARCH_CSFR_CPXE_0 + (uint32_t)prs * 4u, cpxe);
506513
__asm__ volatile("isync" ::: "memory");
507514
}
@@ -532,9 +539,15 @@ static uint8_t g_mpu_count;
532539
static uint8_t g_mpu_prs = 0xFFu;
533540
static uint8_t g_mpu_live;
534541

542+
/*
543+
* AURIX CPR/DPR: address belongs to the range iff
544+
* lower <= addr < upper
545+
* (`end` is the exclusive linker symbol). Bits [2:0] of the bound registers
546+
* are ignored; keep an 8-byte aligned exclusive upper.
547+
*/
535548
static uint32_t mpu_range_upper(uintptr_t end)
536549
{
537-
return (uint32_t)end - 8u;
550+
return (uint32_t)end & ~7u;
538551
}
539552

540553
void ulmk_arch_mpu_init(void)
@@ -549,7 +562,6 @@ void ulmk_arch_mpu_init(void)
549562
uintptr_t kram_hi;
550563
uintptr_t uram_lo;
551564
uintptr_t uram_hi;
552-
uint32_t prs1_cpre;
553565
uint32_t prs1_cpxe;
554566
uint32_t prs0_cpr;
555567

@@ -562,10 +574,12 @@ void ulmk_arch_mpu_init(void)
562574
extern uint8_t _ulmk_user_ram_start[];
563575
extern uint8_t _ulmk_user_pool_end[];
564576

565-
/* Disable protection during reconfiguration */
577+
/* Disable protection during reconfiguration (SYSCON is EndInit). */
578+
ulmk_board_cpu_endinit_clear();
566579
__asm__ volatile("mfcr %0, 0xFE14" : "=d"(syscon));
567580
mpu_mtcr(ULMK_ARCH_CSFR_SYSCON, syscon & ~ULMK_ARCH_SYSCON_PROTEN);
568581
__asm__ volatile("isync" ::: "memory");
582+
ulmk_board_cpu_endinit_set();
569583

570584
g_mpu_regions = NULL;
571585
g_mpu_count = 0u;
@@ -580,7 +594,7 @@ void ulmk_arch_mpu_init(void)
580594

581595
/* Zero all PRS enable registers */
582596
for (i = 0u; i < ULMK_ARCH_NUM_PRS; i++)
583-
mpu_write_enables(i, 0u, 0u, 0u, 0u);
597+
mpu_write_enables(i, 0u, 0u, 0u);
584598

585599
kexec_lo = (uintptr_t)_ulmk_kernel_exec_start;
586600
kexec_hi = (uintptr_t)_ulmk_kernel_exec_end;
@@ -624,20 +638,17 @@ void ulmk_arch_mpu_init(void)
624638

625639
__asm__ volatile("isync" ::: "memory");
626640

627-
prs1_cpre = 0u;
628641
prs1_cpxe = 0u;
629-
if (utext_hi > utext_lo) {
630-
prs1_cpre = (1u << ULMK_ARCH_MPU_CPR_USER);
642+
if (utext_hi > utext_lo)
631643
prs1_cpxe = (1u << ULMK_ARCH_MPU_CPR_USER);
632-
}
633644

634645
/*
635646
* PRS 0 (kernel): all static DPR slots + kernel CPR execute.
636647
* DPR 0 already covers the full address space. The kernel also needs
637-
* execute over the userspace CPR: the thread trampoline and the common
638-
* userspace entry live in user text, and kernel-privileged threads
639-
* (e.g. idle) start there too. Granting the trusted kernel execute of
640-
* user text keeps isolation intact (PRS 1 still cannot reach CPR 0).
648+
* execute over the userspace CPR: ulmk_user_thread_entry lives in user
649+
* text, and kernel-privileged threads (e.g. idle) start there too.
650+
* Granting the trusted kernel execute of user text keeps isolation
651+
* intact (PRS 1 still cannot reach CPR 0).
641652
*/
642653
prs0_cpr = (1u << ULMK_ARCH_MPU_CPR_KERNEL);
643654
if (utext_hi > utext_lo)
@@ -646,7 +657,6 @@ void ulmk_arch_mpu_init(void)
646657
mpu_write_enables(0u,
647658
(1u << ULMK_ARCH_MPU_NUM_DPR) - 1u,
648659
(1u << ULMK_ARCH_MPU_NUM_DPR) - 1u,
649-
prs0_cpr,
650660
prs0_cpr);
651661

652662
/*
@@ -658,7 +668,6 @@ void ulmk_arch_mpu_init(void)
658668
(1u << ULMK_ARCH_MPU_MMIO_DPR),
659669
(1u << ULMK_ARCH_MPU_URAM_DPR) |
660670
(1u << ULMK_ARCH_MPU_MMIO_DPR),
661-
prs1_cpre,
662671
prs1_cpxe);
663672

664673
/* PRS 2, 3: remain zeroed (unused) */
@@ -668,22 +677,26 @@ void ulmk_arch_mpu_enable(void)
668677
{
669678
uint32_t syscon;
670679

680+
ulmk_board_cpu_endinit_clear();
671681
__asm__ volatile("mfcr %0, 0xFE14" : "=d"(syscon));
672682
mpu_mtcr(ULMK_ARCH_CSFR_SYSCON, syscon | ULMK_ARCH_SYSCON_PROTEN);
673683
__asm__ volatile("isync" ::: "memory");
684+
ulmk_board_cpu_endinit_set();
674685
}
675686

676687
void ulmk_arch_mpu_disable(void)
677688
{
678689
uint32_t syscon;
679690

691+
ulmk_board_cpu_endinit_clear();
680692
__asm__ volatile("mfcr %0, 0xFE14" : "=d"(syscon));
681693
mpu_mtcr(ULMK_ARCH_CSFR_SYSCON, syscon & ~ULMK_ARCH_SYSCON_PROTEN);
682694
__asm__ volatile("isync" ::: "memory");
695+
ulmk_board_cpu_endinit_set();
683696
}
684697

685698
static void mpu_prs1_static_enables(uint32_t *dpre, uint32_t *dpwe,
686-
uint32_t *cpre, uint32_t *cpxe)
699+
uint32_t *cpxe)
687700
{
688701
uintptr_t utext_lo;
689702
uintptr_t utext_hi;
@@ -698,12 +711,9 @@ static void mpu_prs1_static_enables(uint32_t *dpre, uint32_t *dpwe,
698711
(1u << ULMK_ARCH_MPU_MMIO_DPR);
699712
*dpwe = (1u << ULMK_ARCH_MPU_URAM_DPR) |
700713
(1u << ULMK_ARCH_MPU_MMIO_DPR);
701-
*cpre = 0u;
702714
*cpxe = 0u;
703-
if (utext_hi > utext_lo) {
704-
*cpre = (1u << ULMK_ARCH_MPU_CPR_USER);
715+
if (utext_hi > utext_lo)
705716
*cpxe = (1u << ULMK_ARCH_MPU_CPR_USER);
706-
}
707717
}
708718

709719
static void mpu_write_user_slot(uint8_t idx, const ulmk_arch_region_t *r,
@@ -750,7 +760,6 @@ static void mpu_program_regions(uint8_t prs, const ulmk_arch_region_t *regions,
750760
{
751761
uint32_t dpre;
752762
uint32_t dpwe;
753-
uint32_t cpre;
754763
uint32_t cpxe;
755764
uint8_t i;
756765
uint8_t prog;
@@ -774,7 +783,6 @@ static void mpu_program_regions(uint8_t prs, const ulmk_arch_region_t *regions,
774783
mpu_write_enables(0u,
775784
(1u << ULMK_ARCH_MPU_NUM_DPR) - 1u,
776785
(1u << ULMK_ARCH_MPU_NUM_DPR) - 1u,
777-
prs0_cpr,
778786
prs0_cpr);
779787
g_mpu_prs = 0u;
780788
g_mpu_regions = NULL;
@@ -804,7 +812,7 @@ static void mpu_program_regions(uint8_t prs, const ulmk_arch_region_t *regions,
804812
return;
805813
}
806814

807-
mpu_prs1_static_enables(&dpre, &dpwe, &cpre, &cpxe);
815+
mpu_prs1_static_enables(&dpre, &dpwe, &cpxe);
808816

809817
/*
810818
* Fast append: mem_map grew the table by one non-STACK region and the
@@ -826,7 +834,7 @@ static void mpu_program_regions(uint8_t prs, const ulmk_arch_region_t *regions,
826834
if (regions[i].perms & ULMK_PERM_WRITE)
827835
dpwe |= (1u << d_slot);
828836
}
829-
mpu_write_enables(prs, dpre, dpwe, cpre, cpxe);
837+
mpu_write_enables(prs, dpre, dpwe, cpxe);
830838
g_mpu_count = count;
831839
g_mpu_live = count;
832840
return;
@@ -848,7 +856,7 @@ static void mpu_program_regions(uint8_t prs, const ulmk_arch_region_t *regions,
848856
mpu_write_dpr(d_slot, 0u, 0u);
849857
}
850858

851-
mpu_write_enables(prs, dpre, dpwe, cpre, cpxe);
859+
mpu_write_enables(prs, dpre, dpwe, cpxe);
852860

853861
g_mpu_prs = prs;
854862
g_mpu_regions = regions;
@@ -951,11 +959,13 @@ void ulmk_arch_irq_vectors_init(uintptr_t btv, uintptr_t biv, uintptr_t isp_top)
951959
uint32_t biv32 = (uint32_t)biv;
952960
uint32_t isp32 = (uint32_t)isp_top;
953961

962+
ulmk_board_cpu_endinit_clear();
954963
__asm__ volatile("dsync" ::: "memory");
955964
__asm__ volatile("mtcr 0xFE24, %0" :: "d"(btv32)); /* BTV */
956965
__asm__ volatile("mtcr 0xFE20, %0" :: "d"(biv32)); /* BIV, VSS=0 → 32-byte slots */
957966
__asm__ volatile("mtcr 0xFE28, %0" :: "d"(isp32)); /* ISP */
958967
__asm__ volatile("isync" ::: "memory");
968+
ulmk_board_cpu_endinit_set();
959969
}
960970

961971
void ulmk_arch_irq_src_configure(uint8_t srpn, uint8_t priority, uint8_t cpu_id)
@@ -1454,3 +1464,14 @@ void ulmk_arch_spin_unlock_irqrestore(ulmk_spinlock_t *lock,
14541464
}
14551465

14561466
/* send_ipi / secondary / park — arch/tricore/smp.c */
1467+
1468+
/*
1469+
* Weak no-ops: QEMU and boards without CPU EndInit. tc275_lite overrides.
1470+
*/
1471+
__attribute__((weak)) void ulmk_board_cpu_endinit_clear(void)
1472+
{
1473+
}
1474+
1475+
__attribute__((weak)) void ulmk_board_cpu_endinit_set(void)
1476+
{
1477+
}

arch/tricore/ctx_switch.S

Lines changed: 6 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -38,33 +38,18 @@
3838
* Lower (SVLCX/RSLCX): PCXI A11 A2 A3 D0-D3 A4-A7 D4-D7
3939
*
4040
* For a freshly fabricated thread "to", ulmk_arch_ctx_init() builds:
41-
* lower_csa[0] = upper_link | UL_FLAG (→ upper frame)
42-
* lower_csa[1] = _ulmk_thread_trampoline (A11 after RSLCX; RFE uses
43-
* this for PC before restoring upper)
44-
* lower_csa[8] = arg pointer (A4 after RSLCX, ABI pointer arg)
41+
* lower_csa[0] = upper_link | UL_FLAG | PIE
42+
* lower_csa[1] = ulmk_user_thread_entry (A11 after RSLCX)
43+
* lower_csa[8] = thread entry fn (A4 — ABI arg0)
44+
* lower_csa[9] = thread arg (A5 — ABI arg1)
4545
* upper_csa[1] = PSW
4646
* upper_csa[2] = stack_top (A10)
47-
* upper_csa[3] = _ulmk_thread_trampoline (A11 register after RFE)
48-
* upper_csa[10] = entry function (A14 after RFE, trampoline calls it)
47+
* upper_csa[3] = ulmk_user_thread_entry (RFE PC; must be in CPR 1)
4948
*
50-
* -------------------------------------------------------------------------
51-
* _ulmk_thread_trampoline — first instruction of every new thread
52-
* -------------------------------------------------------------------------
53-
*
54-
* After RSLCX + RFE:
55-
* A10 = stack_top (upper_csa[2] via RFE)
56-
* A14 = entry function (upper_csa[10] via RFE)
57-
* A4 = arg pointer (lower_csa[8] via RSLCX)
58-
*
59-
* The trampoline JUMPS (JI, no CALL) to the common userspace entry
60-
* ulmk_user_thread_entry(entry, arg): A4 = entry, A5 = arg (TriCore ABI
61-
* pointer args A4-A7). Jumping keeps the CSA chain depth identical to a
62-
* direct entry call; that shim runs the entry and, if it returns, issues
63-
* ulmk_thread_exit() so the thread is reaped cleanly.
49+
* PC lands directly in .user_runtime so PRS 1 threads never fetch CPR 0.
6450
*/
6551

6652
.extern ulmk_arch_cpu_halt
67-
.extern ulmk_user_thread_entry
6853

6954
/* ---------------------------------------------------------------------------
7055
* ulmk_arch_ctx_switch
@@ -111,19 +96,3 @@ ulmk_arch_ctx_switch:
11196
* jump to A11 (entry or return address) */
11297

11398
.size ulmk_arch_ctx_switch, . - ulmk_arch_ctx_switch
114-
115-
/* ---------------------------------------------------------------------------
116-
* _ulmk_thread_trampoline
117-
* ------------------------------------------------------------------------ */
118-
119-
.global _ulmk_thread_trampoline
120-
.type _ulmk_thread_trampoline, @function
121-
122-
_ulmk_thread_trampoline:
123-
mov.aa %a5, %a4 /* a5 = arg (2nd param) */
124-
mov.aa %a4, %a14 /* a4 = entry (1st param) */
125-
movh.a %a15, hi:ulmk_user_thread_entry
126-
lea %a15, [%a15] lo:ulmk_user_thread_entry
127-
ji %a15 /* jump: ulmk_user_thread_entry(entry,arg)*/
128-
129-
.size _ulmk_thread_trampoline, . - _ulmk_thread_trampoline

arch/tricore/include/arch_config.h

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -120,10 +120,15 @@
120120
#define ULMK_ARCH_CSFR_CPR_L(n) (0xD000u + (n) * 8u)
121121
#define ULMK_ARCH_CSFR_CPR_U(n) (0xD004u + (n) * 8u)
122122

123-
#define ULMK_ARCH_CSFR_CPRE_0 0xE000u
124-
#define ULMK_ARCH_CSFR_CPRE_1 0xE004u
125-
#define ULMK_ARCH_CSFR_CPRE_2 0xE008u
126-
#define ULMK_ARCH_CSFR_CPRE_3 0xE00Cu
123+
/*
124+
* TC2xx/TC3xx MPU enables (UM): CPXE @ E000, DPRE @ E010, DPWE @ E020.
125+
* There is no CPRE register. Older internal docs listed CPXE @ E040; on
126+
* TC27x that address is Safety RGNLA — never program it as CPXE.
127+
*/
128+
#define ULMK_ARCH_CSFR_CPXE_0 0xE000u
129+
#define ULMK_ARCH_CSFR_CPXE_1 0xE004u
130+
#define ULMK_ARCH_CSFR_CPXE_2 0xE008u
131+
#define ULMK_ARCH_CSFR_CPXE_3 0xE00Cu
127132
#define ULMK_ARCH_CSFR_DPRE_0 0xE010u
128133
#define ULMK_ARCH_CSFR_DPRE_1 0xE014u
129134
#define ULMK_ARCH_CSFR_DPRE_2 0xE018u
@@ -132,10 +137,6 @@
132137
#define ULMK_ARCH_CSFR_DPWE_1 0xE024u
133138
#define ULMK_ARCH_CSFR_DPWE_2 0xE028u
134139
#define ULMK_ARCH_CSFR_DPWE_3 0xE02Cu
135-
#define ULMK_ARCH_CSFR_CPXE_0 0xE040u
136-
#define ULMK_ARCH_CSFR_CPXE_1 0xE044u
137-
#define ULMK_ARCH_CSFR_CPXE_2 0xE048u
138-
#define ULMK_ARCH_CSFR_CPXE_3 0xE04Cu
139140

140141
#define ULMK_ARCH_CSFR_SYSCON 0xFE14u
141142
#define ULMK_ARCH_SYSCON_PROTEN (1u << 1)

0 commit comments

Comments
 (0)