Skip to content

Commit ab02644

Browse files
committed
kernel: add optional syscall WCET cycle instrumentation
- Opt-in via ULMK_CONFIG_SYSCALL_WCET; publish deltas in a user-visible slot - Arch cycle counters: TriCore CCNT, RISC-V mcycle, ARM DWT CYCCNT
1 parent 3b90c1b commit ab02644

13 files changed

Lines changed: 173 additions & 0 deletions

File tree

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ execute_process(
7777
--board-config "${ULMK_CHIP_DIR}/board_config.h"
7878
--set "ULMK_CONFIG_MAX_IRQ_BINDINGS=${ULMK_CONFIG_MAX_IRQ_BINDINGS}"
7979
--set "ULMK_CONFIG_DEBUG_PRINTK=${ULMK_CONFIG_DEBUG_PRINTK}"
80+
--set "ULMK_CONFIG_SYSCALL_WCET=${ULMK_CONFIG_SYSCALL_WCET}"
8081
RESULT_VARIABLE _ulmk_gen_rc)
8182
if(NOT _ulmk_gen_rc EQUAL 0)
8283
message(FATAL_ERROR "gen_config.py failed (rc=${_ulmk_gen_rc})")
@@ -104,6 +105,7 @@ add_library(ulmk_kernel STATIC
104105
kernel/mem/mem.c
105106
kernel/mem/tlsf.c
106107
kernel/irq/irq.c
108+
kernel/syscall/syscall_wcet.c
107109
${ULMK_ARCH_KERNEL_SOURCES})
108110

109111
if(EXISTS "${ULMK_CHIP_DIR}/qemu_printk_hook.c")

arch/arm/arch.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,35 @@ uint32_t ulmk_arch_cpu_clz(uint32_t val)
8989
return (uint32_t)__builtin_clz(val);
9090
}
9191

92+
#if ULMK_CONFIG_SYSCALL_WCET
93+
#define DEMCR 0xE000EDFCu
94+
#define DWT_CTRL 0xE0001000u
95+
#define DWT_CYCCNT 0xE0001004u
96+
#define DEMCR_TRCENA (1u << 24)
97+
#define DWT_CYCCNTENA (1u << 0)
98+
99+
void ulmk_arch_cycle_enable(void)
100+
{
101+
REG32(DEMCR) |= DEMCR_TRCENA;
102+
REG32(DWT_CYCCNT) = 0u;
103+
REG32(DWT_CTRL) |= DWT_CYCCNTENA;
104+
}
105+
106+
uint32_t ulmk_arch_cycle_read(void)
107+
{
108+
return REG32(DWT_CYCCNT);
109+
}
110+
#else
111+
void ulmk_arch_cycle_enable(void)
112+
{
113+
}
114+
115+
uint32_t ulmk_arch_cycle_read(void)
116+
{
117+
return 0u;
118+
}
119+
#endif
120+
92121
/* =========================================================================
93122
* Context management
94123
* ========================================================================= */
@@ -289,6 +318,11 @@ void ulmk_arch_trap_dump(uint8_t trap_class, uint8_t tin)
289318

290319
void ulmk_arch_trap_entry(uint8_t trap_class, uint8_t tin)
291320
{
321+
/*
322+
* HardFault / unexpected paths: policy is panic. MemManage / Bus /
323+
* Usage from Thread+PSP are recovered in _arm_fault_dispatch before
324+
* reaching here (kill via ulmk_user_thread_entry / thread_exit).
325+
*/
292326
dump_puts("TRAP class=");
293327
dump_hex8((uint32_t)trap_class);
294328
dump_puts(" exc=");

arch/arm/include/ulmk_arch.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ void ulmk_arch_cpu_idle(void);
6666
void ulmk_arch_cpu_halt(void);
6767
uint32_t ulmk_arch_cpu_clz(uint32_t val);
6868

69+
void ulmk_arch_cycle_enable(void);
70+
uint32_t ulmk_arch_cycle_read(void);
71+
6972
void ulmk_arch_csa_pool_init(uintptr_t pool_base, size_t pool_size);
7073

7174
void ulmk_arch_ctx_init(ulmk_arch_ctx_t *ctx,

arch/riscv/arch.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <stddef.h>
88
#include <stdbool.h>
99
#include <ulmk/microkernel.h>
10+
#include <ulmk/config.h>
1011
#include <ulmk_arch.h>
1112
#include "irq_internal.h"
1213

@@ -240,6 +241,30 @@ uint32_t ulmk_arch_cpu_clz(uint32_t val)
240241
return (uint32_t)__builtin_clz(val);
241242
}
242243

244+
#if ULMK_CONFIG_SYSCALL_WCET
245+
void ulmk_arch_cycle_enable(void)
246+
{
247+
/* mcycle is free-running from reset; nothing to unlock in M-mode. */
248+
}
249+
250+
uint32_t ulmk_arch_cycle_read(void)
251+
{
252+
uint32_t v;
253+
254+
__asm__ volatile("csrr %0, mcycle" : "=r"(v));
255+
return v;
256+
}
257+
#else
258+
void ulmk_arch_cycle_enable(void)
259+
{
260+
}
261+
262+
uint32_t ulmk_arch_cycle_read(void)
263+
{
264+
return 0u;
265+
}
266+
#endif
267+
243268
/* =========================================================================
244269
* Context management
245270
* ========================================================================= */

arch/riscv/include/ulmk_arch.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ void ulmk_arch_cpu_idle(void);
4141
void ulmk_arch_cpu_halt(void);
4242
uint32_t ulmk_arch_cpu_clz(uint32_t val);
4343

44+
void ulmk_arch_cycle_enable(void);
45+
uint32_t ulmk_arch_cycle_read(void);
46+
4447
void ulmk_arch_csa_pool_init(uintptr_t pool_base, size_t pool_size);
4548

4649
void ulmk_arch_ctx_init(ulmk_arch_ctx_t *ctx,

arch/tricore/arch.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,38 @@ uint32_t ulmk_arch_cpu_clz(uint32_t val)
7171
return result;
7272
}
7373

74+
#if ULMK_CONFIG_SYSCALL_WCET
75+
/* CCTRL: CM=bit0, CE=bit1 (TC1.6 Vol1 §12.11). Normal free-run: CE=1. */
76+
#define CCTRL_CE (1u << 1)
77+
78+
void ulmk_arch_cycle_enable(void)
79+
{
80+
uint32_t cctrl;
81+
82+
__asm__ volatile("mfcr %0, 0xFC00" : "=d"(cctrl));
83+
cctrl |= CCTRL_CE;
84+
__asm__ volatile("mtcr 0xFC00, %0" :: "d"(cctrl));
85+
__asm__ volatile("isync" ::: "memory");
86+
}
87+
88+
uint32_t ulmk_arch_cycle_read(void)
89+
{
90+
uint32_t v;
91+
92+
__asm__ volatile("mfcr %0, 0xFC04" : "=d"(v));
93+
return v;
94+
}
95+
#else
96+
void ulmk_arch_cycle_enable(void)
97+
{
98+
}
99+
100+
uint32_t ulmk_arch_cycle_read(void)
101+
{
102+
return 0u;
103+
}
104+
#endif
105+
74106
/* =========================================================================
75107
* CSA helpers — used by context init only; not part of the public API.
76108
*

arch/tricore/include/ulmk_arch.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ void ulmk_arch_cpu_idle(void);
7272
void ulmk_arch_cpu_halt(void);
7373
uint32_t ulmk_arch_cpu_clz(uint32_t val);
7474

75+
void ulmk_arch_cycle_enable(void);
76+
uint32_t ulmk_arch_cycle_read(void);
77+
7578
/* =========================================================================
7679
* Context management (arch_api_spec.md §6)
7780
* ========================================================================= */

cmake/config.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,5 @@
66

77
set(ULMK_CONFIG_MAX_IRQ_BINDINGS 16 CACHE STRING "Max IRQ-to-notification bindings")
88
set(ULMK_CONFIG_DEBUG_PRINTK 1 CACHE STRING "Enable kernel printk (0 = production no-op)")
9+
set(ULMK_CONFIG_SYSCALL_WCET 0 CACHE STRING
10+
"Syscall cycle-counter slot (0=off, 1=WCET HIL / silicon_wcet)")

include/ulmk/syscall_wcet.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/* SPDX-License-Identifier: MIT */
2+
/*
3+
* Syscall WCET slot — filled by the kernel when ULMK_CONFIG_SYSCALL_WCET=1.
4+
*
5+
* Lives in .user_bss so driver threads may read it without mem_map.
6+
* After each syscall the kernel updates nr/delta/begin/end and increments seq.
7+
*/
8+
9+
#ifndef ULMK_SYSCALL_WCET_H
10+
#define ULMK_SYSCALL_WCET_H
11+
12+
#include <stdint.h>
13+
14+
#define ULMK_SYSCALL_WCET_MAGIC 0x57434554u /* 'WCET' */
15+
16+
struct ulmk_syscall_wcet_slot {
17+
uint32_t magic;
18+
uint32_t seq;
19+
uint32_t nr;
20+
uint32_t delta;
21+
uint32_t begin;
22+
uint32_t end;
23+
};
24+
25+
extern volatile struct ulmk_syscall_wcet_slot g_ulmk_syscall_wcet;
26+
27+
#endif /* ULMK_SYSCALL_WCET_H */

kernel/kernel_main.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <stdint.h>
1111
#include <ulmk/microkernel.h>
1212
#include <ulmk/config.h>
13+
#include <ulmk/syscall_wcet.h>
1314
#include <ulmk_arch.h>
1415
#include <kernel/include/ulmk_sched.h>
1516
#include <kernel/include/ulmk_thread_internal.h>
@@ -44,7 +45,25 @@ void ulmk_kern_trap_mpu_restore(void)
4445

4546
uint32_t ulmk_kern_trap_syscall(uint8_t tin, uint32_t args[4])
4647
{
48+
#if ULMK_CONFIG_SYSCALL_WCET
49+
uint32_t begin;
50+
uint32_t end;
51+
uint32_t ret;
52+
53+
begin = ulmk_arch_cycle_read();
54+
ret = ulmk_syscall_router(tin, args[0], args[1], args[2], args[3]);
55+
end = ulmk_arch_cycle_read();
56+
57+
g_ulmk_syscall_wcet.magic = ULMK_SYSCALL_WCET_MAGIC;
58+
g_ulmk_syscall_wcet.nr = tin;
59+
g_ulmk_syscall_wcet.begin = begin;
60+
g_ulmk_syscall_wcet.end = end;
61+
g_ulmk_syscall_wcet.delta = end - begin;
62+
g_ulmk_syscall_wcet.seq++;
63+
return ret;
64+
#else
4765
return ulmk_syscall_router(tin, args[0], args[1], args[2], args[3]);
66+
#endif
4867
}
4968

5069
void ulmk_kern_trap_recoverable(void)
@@ -124,6 +143,12 @@ void ulmk_kern_main(const ulmk_boot_info_t *info)
124143
ulmk_irq_table_init();
125144
UL_LOG_DBG("irq table init done");
126145

146+
#if ULMK_CONFIG_SYSCALL_WCET
147+
ulmk_arch_cycle_enable();
148+
g_ulmk_syscall_wcet.magic = ULMK_SYSCALL_WCET_MAGIC;
149+
g_ulmk_syscall_wcet.seq = 0u;
150+
#endif
151+
127152
ulmk_arch_mpu_init();
128153
ulmk_arch_cpu_irq_enable();
129154

0 commit comments

Comments
 (0)