From a23305afc0a5d4f166fb54a5be202c651d214d70 Mon Sep 17 00:00:00 2001 From: Denis Drakhnya Date: Sun, 15 Nov 2020 18:39:30 +0200 Subject: [PATCH] target: e2k: Add pcs_{push,pop}. --- target/e2k/cpu.h | 35 +++++++++++++++++++++- target/e2k/helper.c | 71 ++++++++++++++++++++++++++++++--------------- 2 files changed, 82 insertions(+), 24 deletions(-) diff --git a/target/e2k/cpu.h b/target/e2k/cpu.h index 17af5f7749..26b009d3dd 100644 --- a/target/e2k/cpu.h +++ b/target/e2k/cpu.h @@ -17,7 +17,7 @@ void e2k_tcg_initialize(void); #define SET_FIELD(v, f, s, l) \ ( \ ((v) & ~GEN_MASK_LEN((s), (l))) | \ - ((((typeof(v)) (f)) << (s)) & GEN_MASK_LEN((s), (l))) \ + ((((typeof((v))) (f)) << (s)) & GEN_MASK_LEN((s), (l))) \ ) #define MMU_USER_IDX 1 @@ -229,6 +229,39 @@ int e2k_cpu_signal_handler(int host_signum, void *pinfo, void *puc); #define cpu_signal_handler e2k_cpu_signal_handler +static inline target_ulong e2k_state_pcs_base_get(CPUE2KState *env) +{ + return GET_FIELD(env->pcsp_lo, PCSP_LO_BASE_OFF, PCSP_LO_BASE_END); +} + +static inline void e2k_state_pcs_base_set(CPUE2KState *env, target_ulong pcsp) +{ + env->pcsp_lo = SET_FIELD(env->pcsp_lo, pcsp, PCSP_LO_BASE_OFF, + PCSP_LO_BASE_LEN); +} + +static inline size_t e2k_state_pcs_index_get(CPUE2KState *env) +{ + return GET_FIELD(env->pcsp_hi, PCSP_HI_IND_OFF, PCSP_HI_IND_END); +} + +static inline void e2k_state_pcs_index_set(CPUE2KState *env, size_t ind) +{ + env->pcsp_hi = SET_FIELD(env->pcsp_hi, ind, PCSP_HI_IND_OFF, + PCSP_HI_IND_LEN); +} + +static inline size_t e2k_state_pcs_size_get(CPUE2KState *env) +{ + return GET_FIELD(env->pcsp_hi, PCSP_HI_SIZE_OFF, PCSP_HI_SIZE_END); +} + +static inline void e2k_state_pcs_size_set(CPUE2KState *env, size_t size) +{ + env->pcsp_hi = SET_FIELD(env->pcsp_hi, size, PCSP_HI_SIZE_OFF, + PCSP_HI_SIZE_LEN); +} + static inline int e2k_state_wbs_get(CPUE2KState *env) { return GET_FIELD(env->cr1_lo, CR1_LO_WBS_OFF, CR1_LO_WBS_END); diff --git a/target/e2k/helper.c b/target/e2k/helper.c index 1dd8266112..7b5635e39f 100644 --- a/target/e2k/helper.c +++ b/target/e2k/helper.c @@ -14,48 +14,73 @@ void helper_raise_exception(CPUE2KState *env, int tt) cpu_loop_exit(cs); } +static void pcs_push(CPUE2KState *env) +{ + size_t size = e2k_state_pcs_size_get(env); + size_t offset = e2k_state_pcs_index_get(env); + uint64_t *pcsp = (uint64_t *) (e2k_state_pcs_base_get(env) + offset); + + if (offset + 32 > size) { + /* TODO: allocate more memory */ + abort(); + } + + memcpy(pcsp, &env->pf, 8); + memcpy(pcsp + 1, &env->nip, 8); + memcpy(pcsp + 2, &env->cr1_lo, 8); + memcpy(pcsp + 3, &env->cr1_hi, 8); + + e2k_state_pcs_index_set(env, offset + 32); +} + +static void pcs_pop(CPUE2KState *env) +{ + size_t offset = e2k_state_pcs_index_get(env); + uint64_t *pcsp = (uint64_t *) (e2k_state_pcs_base_get(env) + offset - 32); + + if (offset < 32) { + /* TODO: SIGKILL */ + abort(); + } + + memcpy(&env->pf, pcsp, 8); + memcpy(&env->ip, pcsp + 1, 8); + memcpy(&env->cr1_lo, pcsp + 2, 8); + memcpy(&env->cr1_hi, pcsp + 3, 8); + + e2k_state_pcs_index_set(env, offset - 32); +} + static inline void do_call(CPUE2KState *env, target_ulong ctpr) { - unsigned int offset, wbs, wsz, new_wbs, new_wsz; - uint64_t *pcsp = (uint64_t *) - GET_FIELD(env->pcsp_lo, PCSP_LO_BASE_OFF, PCSP_LO_BASE_END); + int wbs, wsz, new_wbs, new_wsz; wbs = e2k_state_wbs_get(env); wsz = e2k_state_wsz_get(env); new_wbs = (wbs + env->call_wbs) % WREGS_SIZE; new_wsz = wsz - env->call_wbs; - /* save procedure chain */ - offset = (env->pcsp_hi & GEN_MASK(0, 31)) / 8; - pcsp[offset + 0] = env->pf; - pcsp[offset + 1] = env->nip; - pcsp[offset + 2] = env->cr1_lo; - pcsp[offset + 3] = env->cr1_hi; - /* TODO: check stack overflow */ - env->pcsp_hi = env->pcsp_hi + 32; + if (wsz < 0) { + /* TODO: SIGSEGV */ + abort(); + } + + /* save procedure chain info */ + pcs_push(env); - /* TODO: check if call_wbs is less or equal then wsz */ e2k_state_wbs_set(env, new_wbs); e2k_state_wsz_set(env, new_wsz); - /* TODO: check rbs/rsz after call */ + env->ip = GET_FIELD(ctpr, CTPR_BASE_OFF, CTPR_BASE_END); } static void do_return(CPUE2KState *env) { - unsigned int offset = env->pcsp_hi & GEN_MASK(0, 31); - uint64_t *pcsp = (uint64_t *) (GET_FIELD(env->pcsp_lo, PCSP_LO_BASE_OFF, - PCSP_LO_BASE_END) + offset - 32); // uint64_t *psp = (uint64_t *) GET_FIELD(env->psp_lo, PSP_LO_BASE_OFF, // PSP_LO_BASE_END); - env->pf = pcsp[0]; - env->ip = pcsp[1]; - env->nip = env->ip + 8; - env->cr1_lo = pcsp[2]; - env->cr1_hi = pcsp[3]; - /* TODO: check stack overflow */ - env->pcsp_hi = env->pcsp_hi - 32; + /* restore procedure chain info */ + pcs_pop(env); // TODO: restore regs }