From 7c0e7aced1c51534fecf1b2cc232f273d82a6c4a Mon Sep 17 00:00:00 2001 From: Bryan Bayerdorffer Date: Wed, 3 Jun 2026 10:08:52 -0500 Subject: [PATCH 1/9] Fix stmode test WIP. Signed-off-by: Bryan Bayerdorffer --- kernel/util/spinlock/test/test.c | 1 - kernel/util/stmode/test/Makefile | 5 +++-- kernel/util/stmode/test/test.c | 10 +++++++--- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/kernel/util/spinlock/test/test.c b/kernel/util/spinlock/test/test.c index 0a83fda9e..8d90a54cf 100644 --- a/kernel/util/spinlock/test/test.c +++ b/kernel/util/spinlock/test/test.c @@ -7,7 +7,6 @@ #include #include #include -#include void FAIL(const char *str) { diff --git a/kernel/util/stmode/test/Makefile b/kernel/util/stmode/test/Makefile index 71b74048c..a3661b5bb 100644 --- a/kernel/util/stmode/test/Makefile +++ b/kernel/util/stmode/test/Makefile @@ -1,7 +1,8 @@ -STANDALONE=1 OBJS+=test.o EXEC=test.elf include Makefile.inc -OSLIB= +KERNEL_BUILD_DIR := $(INSTALLPATH)/../build/kernel +CFLAGS += -ffixed-r28 -I$(KERNEL_BUILD_DIR)/include +ASFLAGS += -ffixed-r28 -I$(KERNEL_BUILD_DIR)/include diff --git a/kernel/util/stmode/test/test.c b/kernel/util/stmode/test/test.c index 2f9182552..aca9164f0 100644 --- a/kernel/util/stmode/test/test.c +++ b/kernel/util/stmode/test/test.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include void FAIL(const char *str) { @@ -48,6 +48,10 @@ void test2(void *unused) int main() { u32_t tmp; + + h2_init(NULL); + h2_hwconfig_hwthreads_mask(-1); + asm volatile (" %0 = #-1; imask=%0 " : "=r"(tmp)); H2K_set_gie(); @@ -57,7 +61,7 @@ int main() H2K_stmode_end(); if ((H2K_get_syscfg() & 0x10) == 0) FAIL("stmode_end didn't ensable gie"); - thread_create(&test1,stack1+STACK_SIZE,1,(void *)1); + h2_thread_create(test1, &stack1[STACK_SIZE], (void *)1, 0); while (handshake == 0) /* SPIN */; for (tmp = 0; tmp < 100; tmp++) { asm volatile ("nop"); } @@ -69,7 +73,7 @@ int main() handshake = 0; - thread_create(&test2,stack2+STACK_SIZE,2,(void *)2); + h2_thread_create(test2, &stack2[STACK_SIZE], (void *)2, 0); while (handshake == 0) /* SPIN */; for (tmp = 0; tmp < 100; tmp++) { asm volatile ("nop"); } From af213939db5c7ecd3126baa3e8b19bd410594655 Mon Sep 17 00:00:00 2001 From: Zeev Belinsky Date: Mon, 8 Jun 2026 06:15:14 -0700 Subject: [PATCH 2/9] stmode test: fix privilege mismatch for monitor-space threads h2_thread_create() hardcodes ssr_um=1 (guest-user mode) for created threads, but this test runs in monitor space (no BOOT/booter) where code pages are supervisor-execute-only. Guest-user threads fault with Hexagon cause 0x11 (user/guest execute to page with no execute permission) at their first instruction. Fix by providing a local override of H2K_thread_create_no_squash that inherits ssr_guest/ssr_um from the caller (main runs ssr_um=0, ssr_guest=1) instead of hardcoding 1. Add linking flag --allow-multiple-definition so the linker picks test.o over libh2kernel.a for this symbol. Also: - Add stmode_extend_bootvm_contexts() to pre-allocate NUM_TEST_THREADS extra H2K_thread_context slots into the boot VM free list, so the test is self-contained and does not require MAX_BOOT_CONTEXTS=3 at kernel build time. - Add wait_for_threads_to_sleep() using MODECTL_W_BITS to quiesce all hw threads into WAIT after h2_hwconfig_hwthreads_mask(-1) before calling stmode_begin(); without this, stmode_begin races threads coming online and spuriously reports >1 active thread. - Add MODECTL_E_MASK/MODECTL_W_BITS/MODECTL_W_MASK to max.h. Signed-off-by: Zeev Belinsky --- kernel/util/max/max.h | 4 + kernel/util/stmode/test/Makefile | 11 ++- kernel/util/stmode/test/test.c | 143 ++++++++++++++++++++++++++++++- 3 files changed, 152 insertions(+), 6 deletions(-) diff --git a/kernel/util/max/max.h b/kernel/util/max/max.h index 2c2cf2b63..9c187bf9b 100644 --- a/kernel/util/max/max.h +++ b/kernel/util/max/max.h @@ -87,6 +87,10 @@ #define MAX_ASIDS (1<<(ASID_BITS)) +#define MODECTL_E_MASK 0x0000ffff +#define MODECTL_W_BITS 16 +#define MODECTL_W_MASK 0xffff0000 + /* QDSP6SS_PRIV_BASE is the subsystem base value read from cfg_table, but we map QDSP6SS_PUB_BASE to Q6_SS_BASE_VA so we can get at the public registers. FIXME? Is the QDSP6SS_PUB_PRIV_OFFSET the same for all subsystems? */ diff --git a/kernel/util/stmode/test/Makefile b/kernel/util/stmode/test/Makefile index a3661b5bb..24ac02f64 100644 --- a/kernel/util/stmode/test/Makefile +++ b/kernel/util/stmode/test/Makefile @@ -1,8 +1,13 @@ +INC_KERNEL=1 + OBJS+=test.o EXEC=test.elf +EXTRA_CFLAGS += -ffixed-r28 +EXTRA_ASFLAGS += -ffixed-r28 + include Makefile.inc -KERNEL_BUILD_DIR := $(INSTALLPATH)/../build/kernel -CFLAGS += -ffixed-r28 -I$(KERNEL_BUILD_DIR)/include -ASFLAGS += -ffixed-r28 -I$(KERNEL_BUILD_DIR)/include + +# allow local override of H2K_thread_create_no_squash to inherit caller privilege +LDFLAGS += -Wl,--allow-multiple-definition diff --git a/kernel/util/stmode/test/test.c b/kernel/util/stmode/test/test.c index aca9164f0..d5486d412 100644 --- a/kernel/util/stmode/test/test.c +++ b/kernel/util/stmode/test/test.c @@ -10,6 +10,107 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include + +void H2K_interrupt_restore(); + +/* Local override of H2K_thread_create_no_squash: identical to the kernel version + except ssr_guest/ssr_um are inherited from me instead of hardcoded to 1. + This is needed because this test runs in monitor space (no BOOT/booter), so pages + are supervisor-execute-only. Created threads must run at the same privilege as + main (ssr_um=0, ssr_guest=1) to be able to execute them without cause-0x11. */ +IN_SECTION(".text.misc.create") s32_t H2K_thread_create_no_squash(u32_t pc, u32_t sp, u32_t arg1, u32_t prio, H2K_vmblock_t *vmblock, H2K_thread_context *me) +{ + H2K_thread_context *tmp; + u32_t bestprio; + u32_t trapmask; + u32_t ptb; + u32_t extra; + translation_type type; + s32_t asid; + void *guest_evb; + H2K_offset_t identity_offset = { + .pages = 0, + .cccc = 7, + .size = 6, + .xwru = 0xf, + }; + + bestprio = vmblock->bestprio; + trapmask = vmblock->trapmask; + + if (vmblock->num_cpus == 0) { + guest_evb = NULL; + type = H2K_ASID_TRANS_TYPE_OFFSET; + ptb = identity_offset.raw; + extra = 0; + } else { + guest_evb = me->gevb; + ptb = H2K_gp->asid_table[me->ssr_asid].ptb; + type = H2K_gp->asid_table[me->ssr_asid].fields.type; + extra = H2K_gp->asid_table[me->ssr_asid].fields.extra; + } + + if (prio > MAX_PRIO) return -1; + if (prio < bestprio) return -1; + if ((sp & 7) != 0) return -1; + if ((pc & 3) != 0) return -1; + + BKL_LOCK(&H2K_bkl); + if (vmblock->free_threads == NULL) { + BKL_UNLOCK(&H2K_bkl); + return -1; + } + tmp = vmblock->free_threads; + vmblock->free_threads = vmblock->free_threads->next; + tmp->base_prio = tmp->prio = (u8_t)prio; + tmp->gp = H2K_get_gp(); + tmp->usr = me->usr; + tmp->ssr = me->ssr; +#if ARCHV >= 73 + tmp->vwctrl = me->vwctrl; +#endif + tmp->elr = pc; + tmp->r29 = sp; + tmp->r0100 = arg1; + tmp->ccr = H2K_get_ccr(); + tmp->trapmask = trapmask; + tmp->tlbidxmask = vmblock->tlbidxmask; + tmp->continuation = H2K_interrupt_restore; + tmp->vmstatus = 0x0; + tmp->gevb = guest_evb; + + asid = H2K_asid_table_inc(ptb, type, H2K_ASID_TLB_INVALIDATE_FALSE, extra, vmblock); + if (asid == -1) { + vmblock->free_threads = tmp; + BKL_UNLOCK(&H2K_bkl); + return -1; + } + + /* inherit caller's privilege instead of hardcoding ssr_um=1/ssr_guest=1 */ + tmp->ssr_guest = me->ssr_guest; + tmp->ssr_um = me->ssr_um; + tmp->ssr_asid = (u8_t)asid; +#ifdef HAVE_EXTENSIONS + tmp->ssr_xa = EXT_NO_EXT; + tmp->ssr_xe = 0; + tmp->ssr_xe2 = 0; + tmp->ccr_xe3 = 0; +#endif + + vmblock->num_cpus++; + tmp->vmblock = vmblock; + + H2K_ready_append(tmp); + return (s32_t)H2K_check_sanity_unlock(H2K_id_from_context(tmp).raw); +} void FAIL(const char *str) { @@ -21,10 +122,40 @@ void FAIL(const char *str) volatile int handshake = 0; #define STACK_SIZE 16 +#define NUM_TEST_THREADS 2 /* test1 + test2 */ unsigned long long int stack1[STACK_SIZE]; unsigned long long int stack2[STACK_SIZE]; +/* Extra thread contexts for test1/test2. The boot VM is created with + MAX_BOOT_CONTEXTS=1 (just main), leaving no free slots. We extend + the free list with two statically-allocated contexts before creating + any threads. */ +static H2K_thread_context extra_contexts[NUM_TEST_THREADS] __attribute__((aligned(32))); + +static void stmode_extend_bootvm_contexts(H2K_thread_context *me) +{ + H2K_vmblock_t *vm = me->vmblock; + int i; + for (i = 0; i < NUM_TEST_THREADS; i++) { + H2K_thread_context_clear(&extra_contexts[i]); + extra_contexts[i].id.raw = 0; + extra_contexts[i].id.vmidx = vm->vmidx; + extra_contexts[i].id.cpuidx = vm->max_cpus++; + extra_contexts[i].vmblock = vm; + extra_contexts[i].next = vm->free_threads; + vm->free_threads = &extra_contexts[i]; + } +} + +static void wait_for_threads_to_sleep(void) +{ + u32_t mc; + do { + mc = H2K_get_modectl(); + } while ((mc & ((~mc) >> MODECTL_W_BITS)) & ~0x1u); +} + void test1(void *unused) { u32_t tmp; @@ -47,12 +178,19 @@ void test2(void *unused) int main() { + H2K_thread_context *me; u32_t tmp; h2_init(NULL); +#if ARCHV <= 3 + asm (" %0 = sgp\n" : "=r"(me)); +#else + asm (" %0 = sgp0\n" : "=r"(me)); +#endif + stmode_extend_bootvm_contexts(me); h2_hwconfig_hwthreads_mask(-1); - - asm volatile (" %0 = #-1; imask=%0 " : "=r"(tmp)); + wait_for_threads_to_sleep(); + H2K_set_gie(); tmp = H2K_stmode_begin(); @@ -84,4 +222,3 @@ int main() puts("TEST PASSED"); return 0; } - From 1de41308be270ea564d3105d7a92e44a3297e8ae Mon Sep 17 00:00:00 2001 From: zbelinsk Date: Mon, 8 Jun 2026 18:11:05 +0300 Subject: [PATCH 3/9] Update test.c Signed-off-by: zbelinsk --- kernel/util/stmode/test/test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/util/stmode/test/test.c b/kernel/util/stmode/test/test.c index d5486d412..bfabec9b5 100644 --- a/kernel/util/stmode/test/test.c +++ b/kernel/util/stmode/test/test.c @@ -188,7 +188,7 @@ int main() asm (" %0 = sgp0\n" : "=r"(me)); #endif stmode_extend_bootvm_contexts(me); - h2_hwconfig_hwthreads_mask(-1); + H2K_trap_hwconfig_hwthreads_mask(0, NULL, (u32_t)-1, 0, me); wait_for_threads_to_sleep(); H2K_set_gie(); From 3d1a0a0f117071af5e5d73625b7de0d9c612927e Mon Sep 17 00:00:00 2001 From: zbelinsk Date: Mon, 8 Jun 2026 18:20:53 +0300 Subject: [PATCH 4/9] Update test.c Signed-off-by: zbelinsk --- kernel/util/stmode/test/test.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/util/stmode/test/test.c b/kernel/util/stmode/test/test.c index bfabec9b5..a4deea70e 100644 --- a/kernel/util/stmode/test/test.c +++ b/kernel/util/stmode/test/test.c @@ -18,6 +18,7 @@ #include #include #include +#include void H2K_interrupt_restore(); From c6acbbe92503809b530d0400ea72dee30439fe56 Mon Sep 17 00:00:00 2001 From: Zeev Belinsky Date: Tue, 9 Jun 2026 00:58:01 -0700 Subject: [PATCH 5/9] hw.h: add H2K_get_sgp(); use it in tests instead of raw sgp0 asm Add H2K_get_sgp() to kernel/util/hw/hw.h to return the current thread context pointer from sgp/sgp0. Also make stmode_extend_bootvm_contexts(), wait_for_threads_to_sleep() static inlines. Signed-off-by: Zeev Belinsky --- kernel/event/error/test/test.c | 7 ++----- kernel/event/fastint/test/test.c | 17 +++++------------ kernel/thread/state/state.ref.c | 5 ++--- kernel/util/hw/hw.h | 11 +++++++++++ kernel/util/stmode/test/test.c | 13 ++++--------- 5 files changed, 24 insertions(+), 29 deletions(-) diff --git a/kernel/event/error/test/test.c b/kernel/event/error/test/test.c index b02fb1068..95dd1402a 100644 --- a/kernel/event/error/test/test.c +++ b/kernel/event/error/test/test.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -106,11 +107,7 @@ void TH_call_error() int main() { h2_init(NULL); -#if ARCHV <= 3 - asm (" %0 = sgp\n" : "=r"(me)); -#else - asm (" %0 = sgp0\n" : "=r"(me)); -#endif + me = H2K_get_sgp(); /* * Put ourselves in guest mode, but don't have an EVB registered. * We expect this to call thread_fatal diff --git a/kernel/event/fastint/test/test.c b/kernel/event/fastint/test/test.c index 110ae33dd..d2c7b56d8 100644 --- a/kernel/event/fastint/test/test.c +++ b/kernel/event/fastint/test/test.c @@ -12,6 +12,7 @@ #include #include #include +#include H2K_thread_context *TH_me; u32_t TH_intno; @@ -59,12 +60,8 @@ int TH_good_interrupt(u32_t intno) if ((u32_t)(sp_check - ((u32_t)(&H2K_fastint_contexts[0]))) > ((u32_t)FASTINT_CONTEXT_SIZE)) { FAIL("Not fastint context sp"); } -#if ARCHV <= 3 - asm ( " %0 = sgp " : "=r"(sgp_check)); -#else - asm ( " %0 = sgp0 " : "=r"(sgp_check)); -#endif - if ((u32_t)(sgp_check) != ((u32_t)(&H2K_fastint_contexts[0]))) { + sgp_check = (u32_t)H2K_get_sgp(); + if (sgp_check != ((u32_t)(&H2K_fastint_contexts[0]))) { FAIL("Not fastint context sgp"); } return 0; @@ -79,12 +76,8 @@ int TH_good_interrupt_ackl2(u32_t intno) if ((u32_t)(sp_check - ((u32_t)(&H2K_fastint_contexts[0]))) > ((u32_t)FASTINT_CONTEXT_SIZE)) { FAIL("Not fastint context sp"); } -#if ARCHV <= 3 - asm ( " %0 = sgp " : "=r"(sgp_check)); -#else - asm ( " %0 = sgp0 " : "=r"(sgp_check)); -#endif - if ((u32_t)(sgp_check) != ((u32_t)(&H2K_fastint_contexts[0]))) { + sgp_check = (u32_t)H2K_get_sgp(); + if (sgp_check != ((u32_t)(&H2K_fastint_contexts[0]))) { FAIL("Not fastint context sgp"); } return 1; diff --git a/kernel/thread/state/state.ref.c b/kernel/thread/state/state.ref.c index eac50c4df..6cd547f0c 100644 --- a/kernel/thread/state/state.ref.c +++ b/kernel/thread/state/state.ref.c @@ -7,6 +7,7 @@ #include #include #include +#include IN_SECTION(".text.core.state") u64_t H2K_thread_state(H2K_id_t id, u32_t offset, H2K_thread_context *me) { u64_t val; @@ -15,9 +16,7 @@ IN_SECTION(".text.core.state") u64_t H2K_thread_state(H2K_id_t id, u32_t offset, // Special case, return SGP0 register if (offset == CONTEXT_PSEUDO_SGP0) { - void *sgp; - asm (" %0 = sgp0" : "=r"(sgp)); - return (u64_t)sgp; + return (u64_t)H2K_get_sgp(); } // Special case, return IMASK register diff --git a/kernel/util/hw/hw.h b/kernel/util/hw/hw.h index 5e3386f69..bdcc6b5cb 100644 --- a/kernel/util/hw/hw.h +++ b/kernel/util/hw/hw.h @@ -125,6 +125,17 @@ static inline u32_t H2K_get_ssr() return ret; } +static inline H2K_thread_context *H2K_get_sgp() +{ + H2K_thread_context *me; +#if ARCHV <= 3 + asm volatile (" %0 = sgp\n" : "=r"(me)); +#else + asm volatile (" %0 = sgp0\n" : "=r"(me)); +#endif + return me; +} + static inline void H2K_set_ssr(u32_t val) { asm volatile (" ssr = %0 // set ssr" : : "r"(val)); diff --git a/kernel/util/stmode/test/test.c b/kernel/util/stmode/test/test.c index a4deea70e..cd4160e9f 100644 --- a/kernel/util/stmode/test/test.c +++ b/kernel/util/stmode/test/test.c @@ -134,7 +134,7 @@ unsigned long long int stack2[STACK_SIZE]; any threads. */ static H2K_thread_context extra_contexts[NUM_TEST_THREADS] __attribute__((aligned(32))); -static void stmode_extend_bootvm_contexts(H2K_thread_context *me) +static inline void stmode_extend_bootvm_contexts(H2K_thread_context *me) { H2K_vmblock_t *vm = me->vmblock; int i; @@ -149,7 +149,7 @@ static void stmode_extend_bootvm_contexts(H2K_thread_context *me) } } -static void wait_for_threads_to_sleep(void) +static inline void wait_for_threads_to_sleep(void) { u32_t mc; do { @@ -179,15 +179,10 @@ void test2(void *unused) int main() { - H2K_thread_context *me; + h2_init(NULL); + H2K_thread_context *me = H2K_get_sgp(); u32_t tmp; - h2_init(NULL); -#if ARCHV <= 3 - asm (" %0 = sgp\n" : "=r"(me)); -#else - asm (" %0 = sgp0\n" : "=r"(me)); -#endif stmode_extend_bootvm_contexts(me); H2K_trap_hwconfig_hwthreads_mask(0, NULL, (u32_t)-1, 0, me); wait_for_threads_to_sleep(); From cb9d100cf25b72d1db1f3e29892ad280ef6bdd46 Mon Sep 17 00:00:00 2001 From: Zeev Belinsky Date: Tue, 9 Jun 2026 04:13:08 -0700 Subject: [PATCH 6/9] hwconfig: add traps; clean up booter Add hwconfig trap handlers and user-facing wrappers for registers that booter was accessing directly via H2K_* kernel functions: CCR, SYSCFG, livelock (s35), turkey (s61), duck (s62), chicken (s63), rgdr (s60). Replace all H2K_get_*/H2K_set_* calls in booter/booter.c with the new h2_hwconfig_* trap wrappers. Remove include of hw.h from booter since it no longer needs kernel-internal register access. Add SSR_UM_BIT (bit 16) to max.h as a named constant. Simplify stmode test: remove local H2K_thread_create_no_squash override and --allow-multiple-definition now that create.ref.c inherits ssr_um from the caller. Use H2K_get_sgp() instead of raw sgp0 asm. Replace h2_hwconfig_hwthreads_mask() with H2K_trap_hwconfig_hwthreads_mask(). Signed-off-by: Zeev Belinsky --- booter/booter.c | 51 ++++++------ kernel/traps/hwconfig/hwconfig.h | 14 ++++ kernel/traps/hwconfig/hwconfig.ref.c | 79 ++++++++++++++++++- kernel/util/max/max.h | 1 + kernel/util/stmode/test/Makefile | 4 - kernel/util/stmode/test/test.c | 98 ----------------------- libs/h2/common/h2_common_hwconfig.h | 16 +++- libs/h2/hwconfig/h2_hwconfig.h | 105 +++++++++++++++++++++++++ libs/h2/hwconfig/h2_hwconfig_imp.ref.c | 70 +++++++++++++++++ 9 files changed, 308 insertions(+), 130 deletions(-) diff --git a/booter/booter.c b/booter/booter.c index 071702bc6..d704aeb9d 100644 --- a/booter/booter.c +++ b/booter/booter.c @@ -23,7 +23,6 @@ #include #include -#include #include #define VM_BEST_PRIO 0 @@ -797,7 +796,7 @@ void clade_setup(unsigned int idx, long offset) { h2_hwconfig_clade_set_reg(CLADE_REG_REGION, region_hi); clade_region = region_hi; - H2K_set_syscfg(h2_info(INFO_SYSCFG) | SYSCFG_CLADEN); // enable clade + h2_hwconfig_syscfg_set(h2_info(INFO_SYSCFG) | SYSCFG_CLADEN); // enable clade } else if (region_hi != clade_region) { // has to be identical for all concurrent clade guests FAIL("\tCLADE region address mismatch", ""); } @@ -1157,10 +1156,10 @@ void boot_vm(unsigned int idx) { BOOTER_PRINTF("Boot VM index %d, ID %d\n", idx, vm_params[idx].id); if (~0L != vm_params[idx].ccr) { - regval = H2K_get_ccr(); + regval = h2_hwconfig_ccr_get(); BOOTER_PRINTF("\told value for ccr: 0x%08x\n",regval); - H2K_set_ccr(vm_params[idx].ccr); - regval = H2K_get_ccr(); + h2_hwconfig_ccr_set(vm_params[idx].ccr); + regval = h2_hwconfig_ccr_get(); BOOTER_PRINTF("\tnew value for ccr: 0x%08x\n",regval); } #if ARCHV >= 73 // FIXME: Make this 79 if there is a separate build @@ -1389,7 +1388,7 @@ void run(unsigned int idx) { } } while (!done); - H2K_set_syscfg(h2_info(INFO_SYSCFG) & ~SYSCFG_CLADEN); // disable clade + h2_hwconfig_syscfg_set(h2_info(INFO_SYSCFG) & ~SYSCFG_CLADEN); // disable clade pd_num = 0; // reset h2_galloc_reset(&tcm_alloc, 0); @@ -1692,9 +1691,9 @@ typedef struct { } syscfg_field; syscfg_field syscfg[] = { - {"BQ", SYSCFG_BQ_BIT, SYSCFG_BQ_LEN, H2K_set_syscfg}, - {"DMT", SYSCFG_DMT_BIT, SYSCFG_DMT_LEN, H2K_set_syscfg}, - {"CLADEN", SYSCFG_CLADEN_BIT, SYSCFG_CLADEN_LEN, H2K_set_syscfg}, + {"BQ", SYSCFG_BQ_BIT, SYSCFG_BQ_LEN, (void (*)(unsigned int))h2_hwconfig_syscfg_set}, + {"DMT", SYSCFG_DMT_BIT, SYSCFG_DMT_LEN, (void (*)(unsigned int))h2_hwconfig_syscfg_set}, + {"CLADEN", SYSCFG_CLADEN_BIT, SYSCFG_CLADEN_LEN, (void (*)(unsigned int))h2_hwconfig_syscfg_set}, {"L2WB", SYSCFG_L2WB_BIT, SYSCFG_L2WB_LEN, set_l2wb}, {NULL, 0, 0} }; @@ -1784,7 +1783,7 @@ unsigned int process_line(int argc, char **argv, unsigned int idx) { regval = h2_info(INFO_SYSCFG); BOOTER_PRINTF("Old value for syscfg: 0x%08x\n",regval); regval = strtoul(argv[1],NULL,0); - H2K_set_syscfg(regval); + h2_hwconfig_syscfg_set(regval); regval = h2_info(INFO_SYSCFG); BOOTER_PRINTF("New value for syscfg: 0x%08x\n",regval); argc -= 2; argv += 2; @@ -1795,7 +1794,7 @@ unsigned int process_line(int argc, char **argv, unsigned int idx) { regval = h2_info(INFO_LIVELOCK); BOOTER_PRINTF("Old value for livelock: 0x%08x\n",regval); regval = strtoul(argv[1],NULL,0); - H2K_set_livelock(regval); + h2_hwconfig_livelock_set(regval); regval = h2_info(INFO_LIVELOCK); BOOTER_PRINTF("New value for livelock: 0x%08x\n",regval); argc -= 2; argv += 2; @@ -1803,55 +1802,55 @@ unsigned int process_line(int argc, char **argv, unsigned int idx) { } else if (0 == strcmp(argv[0],"--turkey")) { if (argc < 2) die_usage(); - regval = H2K_get_turkey(); + regval = h2_hwconfig_turkey_get(); BOOTER_PRINTF("Old value for turkey: 0x%08x\n",regval); regval = strtoul(argv[1],NULL,0); - H2K_set_turkey(regval); - regval = H2K_get_turkey(); + h2_hwconfig_turkey_set(regval); + regval = h2_hwconfig_turkey_get(); BOOTER_PRINTF("New value for turkey: 0x%08x\n",regval); argc -= 2; argv += 2; continue; } else if (0 == strcmp(argv[0],"--turkey")) { if (argc < 2) die_usage(); - regval = H2K_get_turkey(); + regval = h2_hwconfig_turkey_get(); printf("Old value for turkey: 0x%08x\n",regval); regval = strtoul(argv[1],NULL,0); - H2K_set_turkey(regval); - regval = H2K_get_turkey(); + h2_hwconfig_turkey_set(regval); + regval = h2_hwconfig_turkey_get(); printf("New value for turkey: 0x%08x\n",regval); argc -= 2; argv += 2; continue; } else if (0 == strcmp(argv[0],"--duck")) { if (argc < 2) die_usage(); - regval = H2K_get_duck(); + regval = h2_hwconfig_duck_get(); BOOTER_PRINTF("Old value for duck: 0x%08x\n",regval); regval = strtoul(argv[1],NULL,0); - H2K_set_duck(regval); - regval = H2K_get_duck(); + h2_hwconfig_duck_set(regval); + regval = h2_hwconfig_duck_get(); BOOTER_PRINTF("New value for duck: 0x%08x\n",regval); argc -= 2; argv += 2; continue; } else if (0 == strcmp(argv[0],"--chicken")) { if (argc < 2) die_usage(); - regval = H2K_get_chicken(); + regval = h2_hwconfig_chicken_get(); BOOTER_PRINTF("Old value for chicken: 0x%08x\n",regval); regval = strtoul(argv[1],NULL,0); - H2K_set_chicken(regval); - regval = H2K_get_chicken(); + h2_hwconfig_chicken_set(regval); + regval = h2_hwconfig_chicken_get(); BOOTER_PRINTF("New value for chicken: 0x%08x\n",regval); argc -= 2; argv += 2; continue; } else if (0 == strcmp(argv[0],"--rgdr")) { if (argc < 2) die_usage(); - regval = H2K_get_rgdr(); + regval = h2_hwconfig_rgdr_get(); BOOTER_PRINTF("Old value for rgdr: 0x%08x\n",regval); regval = strtoul(argv[1],NULL,0); - H2K_set_rgdr(regval); - regval = H2K_get_rgdr(); + h2_hwconfig_rgdr_set(regval); + regval = h2_hwconfig_rgdr_get(); BOOTER_PRINTF("New value for rgdr: 0x%08x\n",regval); argc -= 2; argv += 2; continue; diff --git a/kernel/traps/hwconfig/hwconfig.h b/kernel/traps/hwconfig/hwconfig.h index 10e8562ed..1515ca37f 100644 --- a/kernel/traps/hwconfig/hwconfig.h +++ b/kernel/traps/hwconfig/hwconfig.h @@ -46,6 +46,20 @@ u32_t H2K_trap_hwconfig_getvwctrl(u32_t unused, void *unusedp, u32_t unused2, u3 u32_t H2K_trap_hwconfig_setvwctrl(u32_t unused, void *unusedp, u32_t val, u32_t unused3, H2K_thread_context *me) IN_SECTION(".text.config.hwconfig"); u32_t H2K_trap_hwconfig_get_dpm_voltlimitmgmt_reg(u32_t unused, void *unusedp, u32_t offset, u32_t unused3, H2K_thread_context *me)IN_SECTION(".text.config.hwconfig"); u32_t H2K_trap_hwconfig_set_dpm_voltlimitmgmt_reg(u32_t unused, void *unusedp, u32_t offset, u32_t val, H2K_thread_context *me)IN_SECTION(".text.config.hwconfig"); +u32_t H2K_trap_hwconfig_getccr(u32_t unused, void *unusedp, u32_t unused2, u32_t unused3, H2K_thread_context *me) IN_SECTION(".text.config.hwconfig"); +u32_t H2K_trap_hwconfig_setccr(u32_t unused, void *unusedp, u32_t val, u32_t unused3, H2K_thread_context *me) IN_SECTION(".text.config.hwconfig"); +u32_t H2K_trap_hwconfig_getsyscfg(u32_t unused, void *unusedp, u32_t unused2, u32_t unused3, H2K_thread_context *me) IN_SECTION(".text.config.hwconfig"); +u32_t H2K_trap_hwconfig_setsyscfg(u32_t unused, void *unusedp, u32_t val, u32_t unused3, H2K_thread_context *me) IN_SECTION(".text.config.hwconfig"); +u32_t H2K_trap_hwconfig_getlivelock(u32_t unused, void *unusedp, u32_t unused2, u32_t unused3, H2K_thread_context *me) IN_SECTION(".text.config.hwconfig"); +u32_t H2K_trap_hwconfig_setlivelock(u32_t unused, void *unusedp, u32_t val, u32_t unused3, H2K_thread_context *me) IN_SECTION(".text.config.hwconfig"); +u32_t H2K_trap_hwconfig_getturkey(u32_t unused, void *unusedp, u32_t unused2, u32_t unused3, H2K_thread_context *me) IN_SECTION(".text.config.hwconfig"); +u32_t H2K_trap_hwconfig_setturkey(u32_t unused, void *unusedp, u32_t val, u32_t unused3, H2K_thread_context *me) IN_SECTION(".text.config.hwconfig"); +u32_t H2K_trap_hwconfig_getduck(u32_t unused, void *unusedp, u32_t unused2, u32_t unused3, H2K_thread_context *me) IN_SECTION(".text.config.hwconfig"); +u32_t H2K_trap_hwconfig_setduck(u32_t unused, void *unusedp, u32_t val, u32_t unused3, H2K_thread_context *me) IN_SECTION(".text.config.hwconfig"); +u32_t H2K_trap_hwconfig_getchicken(u32_t unused, void *unusedp, u32_t unused2, u32_t unused3, H2K_thread_context *me) IN_SECTION(".text.config.hwconfig"); +u32_t H2K_trap_hwconfig_setchicken(u32_t unused, void *unusedp, u32_t val, u32_t unused3, H2K_thread_context *me) IN_SECTION(".text.config.hwconfig"); +u32_t H2K_trap_hwconfig_getrgdr(u32_t unused, void *unusedp, u32_t unused2, u32_t unused3, H2K_thread_context *me) IN_SECTION(".text.config.hwconfig"); +u32_t H2K_trap_hwconfig_setrgdr(u32_t unused, void *unusedp, u32_t val, u32_t unused3, H2K_thread_context *me) IN_SECTION(".text.config.hwconfig"); #endif diff --git a/kernel/traps/hwconfig/hwconfig.ref.c b/kernel/traps/hwconfig/hwconfig.ref.c index 2b26fe9ab..76503e87b 100644 --- a/kernel/traps/hwconfig/hwconfig.ref.c +++ b/kernel/traps/hwconfig/hwconfig.ref.c @@ -65,7 +65,21 @@ static const configptr_t H2K_hwconfigtab[HWCONFIG_MAX] IN_SECTION(".data.config. H2K_trap_hwconfig_get_dpm_voltlimitmgmt_reg, H2K_trap_hwconfig_set_dpm_voltlimitmgmt_reg, H2K_trap_hwconfig_hlxbits, - H2K_trap_hwconfig_coproc_bits + H2K_trap_hwconfig_coproc_bits, + H2K_trap_hwconfig_getccr, + H2K_trap_hwconfig_setccr, + H2K_trap_hwconfig_getsyscfg, + H2K_trap_hwconfig_setsyscfg, + H2K_trap_hwconfig_getlivelock, + H2K_trap_hwconfig_setlivelock, + H2K_trap_hwconfig_getturkey, + H2K_trap_hwconfig_setturkey, + H2K_trap_hwconfig_getduck, + H2K_trap_hwconfig_setduck, + H2K_trap_hwconfig_getchicken, + H2K_trap_hwconfig_setchicken, + H2K_trap_hwconfig_getrgdr, + H2K_trap_hwconfig_setrgdr, }; typedef struct { @@ -801,3 +815,66 @@ u32_t H2K_trap_hwconfig_set_dpm_voltlimitmgmt_reg(u32_t unused, void *unusedp, u return 0; } } + +u32_t H2K_trap_hwconfig_getccr(u32_t unused, void *unusedp, u32_t unused2, u32_t unused3, H2K_thread_context *me) { + return H2K_get_ccr(); +} + +u32_t H2K_trap_hwconfig_setccr(u32_t unused, void *unusedp, u32_t val, u32_t unused3, H2K_thread_context *me) { + H2K_set_ccr(val); + return 0; +} + +u32_t H2K_trap_hwconfig_getsyscfg(u32_t unused, void *unusedp, u32_t unused2, u32_t unused3, H2K_thread_context *me) { + return H2K_get_syscfg(); +} + +u32_t H2K_trap_hwconfig_setsyscfg(u32_t unused, void *unusedp, u32_t val, u32_t unused3, H2K_thread_context *me) { + H2K_set_syscfg(val); + return 0; +} + +u32_t H2K_trap_hwconfig_getlivelock(u32_t unused, void *unusedp, u32_t unused2, u32_t unused3, H2K_thread_context *me) { + return H2K_get_livelock(); +} + +u32_t H2K_trap_hwconfig_setlivelock(u32_t unused, void *unusedp, u32_t val, u32_t unused3, H2K_thread_context *me) { + H2K_set_livelock(val); + return 0; +} + +u32_t H2K_trap_hwconfig_getturkey(u32_t unused, void *unusedp, u32_t unused2, u32_t unused3, H2K_thread_context *me) { + return H2K_get_turkey(); +} + +u32_t H2K_trap_hwconfig_setturkey(u32_t unused, void *unusedp, u32_t val, u32_t unused3, H2K_thread_context *me) { + H2K_set_turkey(val); + return 0; +} + +u32_t H2K_trap_hwconfig_getduck(u32_t unused, void *unusedp, u32_t unused2, u32_t unused3, H2K_thread_context *me) { + return H2K_get_duck(); +} + +u32_t H2K_trap_hwconfig_setduck(u32_t unused, void *unusedp, u32_t val, u32_t unused3, H2K_thread_context *me) { + H2K_set_duck(val); + return 0; +} + +u32_t H2K_trap_hwconfig_getchicken(u32_t unused, void *unusedp, u32_t unused2, u32_t unused3, H2K_thread_context *me) { + return H2K_get_chicken(); +} + +u32_t H2K_trap_hwconfig_setchicken(u32_t unused, void *unusedp, u32_t val, u32_t unused3, H2K_thread_context *me) { + H2K_set_chicken(val); + return 0; +} + +u32_t H2K_trap_hwconfig_getrgdr(u32_t unused, void *unusedp, u32_t unused2, u32_t unused3, H2K_thread_context *me) { + return H2K_get_rgdr(); +} + +u32_t H2K_trap_hwconfig_setrgdr(u32_t unused, void *unusedp, u32_t val, u32_t unused3, H2K_thread_context *me) { + H2K_set_rgdr(val); + return 0; +} diff --git a/kernel/util/max/max.h b/kernel/util/max/max.h index 9c187bf9b..2980f4904 100644 --- a/kernel/util/max/max.h +++ b/kernel/util/max/max.h @@ -237,6 +237,7 @@ #define H2K_PAGESIZE (1 << ((PAGE_BITS) + ((H2K_KERNEL_PGSIZE) * 2))) #define SSR_IE_BIT 18 +#define SSR_UM_BIT 16 #if ARCHV <= 3 #define RESCHED_INT_INTMASK (0x80000000 >> RESCHED_INT) diff --git a/kernel/util/stmode/test/Makefile b/kernel/util/stmode/test/Makefile index 24ac02f64..8da090ae4 100644 --- a/kernel/util/stmode/test/Makefile +++ b/kernel/util/stmode/test/Makefile @@ -1,4 +1,3 @@ - INC_KERNEL=1 OBJS+=test.o @@ -8,6 +7,3 @@ EXTRA_CFLAGS += -ffixed-r28 EXTRA_ASFLAGS += -ffixed-r28 include Makefile.inc - -# allow local override of H2K_thread_create_no_squash to inherit caller privilege -LDFLAGS += -Wl,--allow-multiple-definition diff --git a/kernel/util/stmode/test/test.c b/kernel/util/stmode/test/test.c index cd4160e9f..079cc993c 100644 --- a/kernel/util/stmode/test/test.c +++ b/kernel/util/stmode/test/test.c @@ -12,107 +12,9 @@ #include #include #include -#include #include -#include -#include -#include -#include #include -void H2K_interrupt_restore(); - -/* Local override of H2K_thread_create_no_squash: identical to the kernel version - except ssr_guest/ssr_um are inherited from me instead of hardcoded to 1. - This is needed because this test runs in monitor space (no BOOT/booter), so pages - are supervisor-execute-only. Created threads must run at the same privilege as - main (ssr_um=0, ssr_guest=1) to be able to execute them without cause-0x11. */ -IN_SECTION(".text.misc.create") s32_t H2K_thread_create_no_squash(u32_t pc, u32_t sp, u32_t arg1, u32_t prio, H2K_vmblock_t *vmblock, H2K_thread_context *me) -{ - H2K_thread_context *tmp; - u32_t bestprio; - u32_t trapmask; - u32_t ptb; - u32_t extra; - translation_type type; - s32_t asid; - void *guest_evb; - H2K_offset_t identity_offset = { - .pages = 0, - .cccc = 7, - .size = 6, - .xwru = 0xf, - }; - - bestprio = vmblock->bestprio; - trapmask = vmblock->trapmask; - - if (vmblock->num_cpus == 0) { - guest_evb = NULL; - type = H2K_ASID_TRANS_TYPE_OFFSET; - ptb = identity_offset.raw; - extra = 0; - } else { - guest_evb = me->gevb; - ptb = H2K_gp->asid_table[me->ssr_asid].ptb; - type = H2K_gp->asid_table[me->ssr_asid].fields.type; - extra = H2K_gp->asid_table[me->ssr_asid].fields.extra; - } - - if (prio > MAX_PRIO) return -1; - if (prio < bestprio) return -1; - if ((sp & 7) != 0) return -1; - if ((pc & 3) != 0) return -1; - - BKL_LOCK(&H2K_bkl); - if (vmblock->free_threads == NULL) { - BKL_UNLOCK(&H2K_bkl); - return -1; - } - tmp = vmblock->free_threads; - vmblock->free_threads = vmblock->free_threads->next; - tmp->base_prio = tmp->prio = (u8_t)prio; - tmp->gp = H2K_get_gp(); - tmp->usr = me->usr; - tmp->ssr = me->ssr; -#if ARCHV >= 73 - tmp->vwctrl = me->vwctrl; -#endif - tmp->elr = pc; - tmp->r29 = sp; - tmp->r0100 = arg1; - tmp->ccr = H2K_get_ccr(); - tmp->trapmask = trapmask; - tmp->tlbidxmask = vmblock->tlbidxmask; - tmp->continuation = H2K_interrupt_restore; - tmp->vmstatus = 0x0; - tmp->gevb = guest_evb; - - asid = H2K_asid_table_inc(ptb, type, H2K_ASID_TLB_INVALIDATE_FALSE, extra, vmblock); - if (asid == -1) { - vmblock->free_threads = tmp; - BKL_UNLOCK(&H2K_bkl); - return -1; - } - - /* inherit caller's privilege instead of hardcoding ssr_um=1/ssr_guest=1 */ - tmp->ssr_guest = me->ssr_guest; - tmp->ssr_um = me->ssr_um; - tmp->ssr_asid = (u8_t)asid; -#ifdef HAVE_EXTENSIONS - tmp->ssr_xa = EXT_NO_EXT; - tmp->ssr_xe = 0; - tmp->ssr_xe2 = 0; - tmp->ccr_xe3 = 0; -#endif - - vmblock->num_cpus++; - tmp->vmblock = vmblock; - - H2K_ready_append(tmp); - return (s32_t)H2K_check_sanity_unlock(H2K_id_from_context(tmp).raw); -} - void FAIL(const char *str) { puts("FAIL"); diff --git a/libs/h2/common/h2_common_hwconfig.h b/libs/h2/common/h2_common_hwconfig.h index 3d193e3bd..0bb0d1bf6 100644 --- a/libs/h2/common/h2_common_hwconfig.h +++ b/libs/h2/common/h2_common_hwconfig.h @@ -40,9 +40,23 @@ typedef enum { HWCONFIG_GETVWCTRL, HWCONFIG_SETVWCTRL, HWCONFIG_GET_DPM_VOLTLMTMGMT_REG, - HWCONFIG_SET_DPM_VOLTLMTMGMT_REG, + HWCONFIG_SET_DPM_VOLTLMTMGMT_REG, HWCONFIG_HLXBITS, HWCONFIG_COPROCBITS, + HWCONFIG_GETCCR, + HWCONFIG_SETCCR, + HWCONFIG_GETSYSCFG, + HWCONFIG_SETSYSCFG, + HWCONFIG_GETLIVELOCK, + HWCONFIG_SETLIVELOCK, + HWCONFIG_GETTURKEY, + HWCONFIG_SETTURKEY, + HWCONFIG_GETDUCK, + HWCONFIG_SETDUCK, + HWCONFIG_GETCHICKEN, + HWCONFIG_SETCHICKEN, + HWCONFIG_GETRGDR, + HWCONFIG_SETRGDR, HWCONFIG_MAX } hwconfig_type_t; diff --git a/libs/h2/hwconfig/h2_hwconfig.h b/libs/h2/hwconfig/h2_hwconfig.h index 00e799dd2..b79db4363 100644 --- a/libs/h2/hwconfig/h2_hwconfig.h +++ b/libs/h2/hwconfig/h2_hwconfig.h @@ -318,6 +318,111 @@ Set DPM volt limits management register. */ int h2_hwconfig_dpm_voltlmtmgmt_set_reg(unsigned int offset, unsigned int val); +/** +Get CCR (Compute Code Register). +@returns register value +@dependencies None +*/ +unsigned int h2_hwconfig_ccr_get(void); + +/** +Set CCR (Compute Code Register). +@param[in] val Value to write +@returns 0 on success +@dependencies None +*/ +int h2_hwconfig_ccr_set(unsigned int val); + +/** +Get SYSCFG register. +@returns register value +@dependencies None +*/ +unsigned int h2_hwconfig_syscfg_get(void); + +/** +Set SYSCFG register. +@param[in] val Value to write +@returns 0 on success +@dependencies None +*/ +int h2_hwconfig_syscfg_set(unsigned int val); + +/** +Get livelock detection register (s35). +@returns register value +@dependencies None +*/ +unsigned int h2_hwconfig_livelock_get(void); + +/** +Set livelock detection register (s35). +@param[in] val Value to write +@returns 0 on success +@dependencies None +*/ +int h2_hwconfig_livelock_set(unsigned int val); + +/** +Get turkey register (s61). +@returns register value +@dependencies None +*/ +unsigned int h2_hwconfig_turkey_get(void); + +/** +Set turkey register (s61). +@param[in] val Value to write +@returns 0 on success +@dependencies None +*/ +int h2_hwconfig_turkey_set(unsigned int val); + +/** +Get duck register (s62). +@returns register value +@dependencies None +*/ +unsigned int h2_hwconfig_duck_get(void); + +/** +Set duck register (s62). +@param[in] val Value to write +@returns 0 on success +@dependencies None +*/ +int h2_hwconfig_duck_set(unsigned int val); + +/** +Get chicken register (s63). +@returns register value +@dependencies None +*/ +unsigned int h2_hwconfig_chicken_get(void); + +/** +Set chicken register (s63). +@param[in] val Value to write +@returns 0 on success +@dependencies None +*/ +int h2_hwconfig_chicken_set(unsigned int val); + +/** +Get RGDR register (s60). +@returns register value +@dependencies None +*/ +unsigned int h2_hwconfig_rgdr_get(void); + +/** +Set RGDR register (s60). +@param[in] val Value to write +@returns 0 on success +@dependencies None +*/ +int h2_hwconfig_rgdr_set(unsigned int val); + #endif /** @} */ diff --git a/libs/h2/hwconfig/h2_hwconfig_imp.ref.c b/libs/h2/hwconfig/h2_hwconfig_imp.ref.c index 600bc42e0..b9eca2a38 100644 --- a/libs/h2/hwconfig/h2_hwconfig_imp.ref.c +++ b/libs/h2/hwconfig/h2_hwconfig_imp.ref.c @@ -180,3 +180,73 @@ int h2_hwconfig_dpm_voltlmtmgmt_set_reg(unsigned int offset, unsigned int val) { return h2_hwconfig_trap(HWCONFIG_SET_DPM_VOLTLMTMGMT_REG, NULL, offset, val); } + +unsigned int h2_hwconfig_ccr_get(void) +{ + return h2_hwconfig_trap(HWCONFIG_GETCCR, NULL, 0, 0); +} + +int h2_hwconfig_ccr_set(unsigned int val) +{ + return h2_hwconfig_trap(HWCONFIG_SETCCR, NULL, val, 0); +} + +unsigned int h2_hwconfig_syscfg_get(void) +{ + return h2_hwconfig_trap(HWCONFIG_GETSYSCFG, NULL, 0, 0); +} + +int h2_hwconfig_syscfg_set(unsigned int val) +{ + return h2_hwconfig_trap(HWCONFIG_SETSYSCFG, NULL, val, 0); +} + +unsigned int h2_hwconfig_livelock_get(void) +{ + return h2_hwconfig_trap(HWCONFIG_GETLIVELOCK, NULL, 0, 0); +} + +int h2_hwconfig_livelock_set(unsigned int val) +{ + return h2_hwconfig_trap(HWCONFIG_SETLIVELOCK, NULL, val, 0); +} + +unsigned int h2_hwconfig_turkey_get(void) +{ + return h2_hwconfig_trap(HWCONFIG_GETTURKEY, NULL, 0, 0); +} + +int h2_hwconfig_turkey_set(unsigned int val) +{ + return h2_hwconfig_trap(HWCONFIG_SETTURKEY, NULL, val, 0); +} + +unsigned int h2_hwconfig_duck_get(void) +{ + return h2_hwconfig_trap(HWCONFIG_GETDUCK, NULL, 0, 0); +} + +int h2_hwconfig_duck_set(unsigned int val) +{ + return h2_hwconfig_trap(HWCONFIG_SETDUCK, NULL, val, 0); +} + +unsigned int h2_hwconfig_chicken_get(void) +{ + return h2_hwconfig_trap(HWCONFIG_GETCHICKEN, NULL, 0, 0); +} + +int h2_hwconfig_chicken_set(unsigned int val) +{ + return h2_hwconfig_trap(HWCONFIG_SETCHICKEN, NULL, val, 0); +} + +unsigned int h2_hwconfig_rgdr_get(void) +{ + return h2_hwconfig_trap(HWCONFIG_GETRGDR, NULL, 0, 0); +} + +int h2_hwconfig_rgdr_set(unsigned int val) +{ + return h2_hwconfig_trap(HWCONFIG_SETRGDR, NULL, val, 0); +} From 277445d284176ad33c4110b6c8c4ea8bdf51d765 Mon Sep 17 00:00:00 2001 From: Zeev Belinsky Date: Tue, 9 Jun 2026 05:00:24 -0700 Subject: [PATCH 7/9] create: inherit ssr_um from caller; set BOOT_THREAD_SSR ssr_um=1 H2K_thread_create_no_squash: change tmp->ssr_um from hardcoded 1 to me->ssr_um so created threads inherit the caller's user mode bit. Set SSR_UM_BIT in BOOT_THREAD_SSR so the booter boot thread starts as guest-user (ssr_um=1), which is required for the inheritance to work correctly for booter-created VMs. NOTE: h2_compat/error test is currently failing - needs adaptation. Signed-off-by: Zeev Belinsky --- kernel/thread/create/create.ref.c | 2 +- kernel/util/max/max.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/thread/create/create.ref.c b/kernel/thread/create/create.ref.c index fa716d75b..be7e3afb1 100644 --- a/kernel/thread/create/create.ref.c +++ b/kernel/thread/create/create.ref.c @@ -94,7 +94,7 @@ IN_SECTION(".text.misc.create") s32_t H2K_thread_create_no_squash(u32_t pc, u32_ } tmp->ssr_guest = 1; // start in guest mode - tmp->ssr_um = 1; + tmp->ssr_um = me->ssr_um; // inherit caller's user mode bit tmp->ssr_asid = (u8_t)asid; #ifdef HAVE_EXTENSIONS tmp->ssr_xa = EXT_NO_EXT; diff --git a/kernel/util/max/max.h b/kernel/util/max/max.h index 2980f4904..2ac302dfb 100644 --- a/kernel/util/max/max.h +++ b/kernel/util/max/max.h @@ -301,7 +301,7 @@ #define BOOT_THREAD_USR 0x00057c00 #endif -#define BOOT_THREAD_SSR (0x01c60000 | (1< Date: Tue, 9 Jun 2026 15:24:43 +0300 Subject: [PATCH 8/9] Update max.h Signed-off-by: zbelinsk --- kernel/util/max/max.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/util/max/max.h b/kernel/util/max/max.h index 2ac302dfb..2980f4904 100644 --- a/kernel/util/max/max.h +++ b/kernel/util/max/max.h @@ -301,7 +301,7 @@ #define BOOT_THREAD_USR 0x00057c00 #endif -#define BOOT_THREAD_SSR (0x01c60000 | (1< Date: Sun, 28 Jun 2026 06:03:39 -0700 Subject: [PATCH 9/9] h2_compat/error: fix test to use trap1(#7) instead of SSR read The real issue this test exposed: the booter runs as supervisor guest (ssr_um=0, gm=1), so threads it creates inherit ssr_um=0. This causes these instructions to have unexpected behaviour: - SSR read: works cleanly - syscfg write: hangs The correct long-term fix is to make BOOT_THREAD_SSR include SSR_UM_BIT so the booter and its guest VMs run as true user-mode guests. However: - Kernel-level tests (e.g. kernel/util/stmode/test) run at monitor privilege reusing BOOT_THREAD_SSR, and would hang before reaching main() with ssr_um=1. For now, use trap1(#7) which unconditionally routes to H2K_vmtrap_bad -> H2K_vm_event(cause=0x1B) regardless of ssr_um, fixing the test. Signed-off-by: Zeev Belinsky --- libs/h2_compat/error/test/simple/test.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/libs/h2_compat/error/test/simple/test.c b/libs/h2_compat/error/test/simple/test.c index 3665e6c8f..8f7d7cbb8 100644 --- a/libs/h2_compat/error/test/simple/test.c +++ b/libs/h2_compat/error/test/simple/test.c @@ -4,20 +4,21 @@ */ #include -#include #include /* FIXME: need to check that we actually dumped the right state. Also need to check h2_handle_errors(1), i.e. check that we call exit(). */ int main() { - unsigned int x; + unsigned int ssr; + asm volatile ("%0 = ssr \n" : "=r"(ssr)); + printf("ssr=0x%08x ssr_um=%d\n", ssr, (ssr >> 16) & 1); - // h2_handle_errors(0) should be set by default + // h2_handle_errors(0); - // do something bad - // *p++; - asm volatile ("%0 = ssr \n" : "=r"(x)); + // do something bad - trap1 with invalid number triggers H2K_vmtrap_bad -> H2K_vm_event + printf("about to do bad trap\n"); + asm volatile ("trap1(#7) \n"); /* Shouldn't reach here */ puts("FAIL\n");