* [Qemu-devel] [PATCH 1/3] target-mips: add exception base to MIPS CPU
2016-06-09 9:46 [Qemu-devel] [PATCH 0/3] mips: support configurable exception vector base Leon Alrae
@ 2016-06-09 9:46 ` Leon Alrae
2016-06-09 9:46 ` [Qemu-devel] [PATCH 2/3] hw/mips_cpc: make VP correctly start from the reset vector Leon Alrae
2016-06-09 9:46 ` [Qemu-devel] [PATCH 3/3] hw/mips_cmgcr: implement RESET_BASE register in CM GCR Leon Alrae
2 siblings, 0 replies; 4+ messages in thread
From: Leon Alrae @ 2016-06-09 9:46 UTC (permalink / raw)
To: qemu-devel; +Cc: aurelien
Replace hardcoded 0xbfc00000 with exception_base which is initialized with
this default address so there is no functional change here.
However, it is now exposed and consequently it will be possible to modify
it from outside of the CPU.
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
---
target-mips/cpu.h | 2 ++
target-mips/helper.c | 6 +++---
target-mips/translate.c | 9 ++++++++-
3 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index 4ce9d47..2db010f 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -614,6 +614,7 @@ struct CPUMIPSState {
void *irq[8];
QEMUTimer *timer; /* Internal timer */
MemoryRegion *itc_tag; /* ITC Configuration Tags */
+ target_ulong exception_base; /* ExceptionBase input to the core */
};
/**
@@ -807,6 +808,7 @@ int cpu_mips_signal_handler(int host_signum, void *pinfo, void *puc);
#define cpu_init(cpu_model) CPU(cpu_mips_init(cpu_model))
bool cpu_supports_cps_smp(const char *cpu_model);
+void cpu_set_exception_base(int vp_index, target_ulong address);
/* TODO QOM'ify CPU reset and remove */
void cpu_state_reset(CPUMIPSState *s);
diff --git a/target-mips/helper.c b/target-mips/helper.c
index 65fbef0..1402ff0 100644
--- a/target-mips/helper.c
+++ b/target-mips/helper.c
@@ -640,7 +640,7 @@ void mips_cpu_do_interrupt(CPUState *cs)
/* EJTAG probe trap enable is not implemented... */
if (!(env->CP0_Status & (1 << CP0St_EXL)))
env->CP0_Cause &= ~(1U << CP0Ca_BD);
- env->active_tc.PC = (int32_t)0xBFC00480;
+ env->active_tc.PC = env->exception_base + 0x480;
set_hflags_for_handler(env);
break;
case EXCP_RESET:
@@ -667,7 +667,7 @@ void mips_cpu_do_interrupt(CPUState *cs)
env->hflags &= ~(MIPS_HFLAG_KSU);
if (!(env->CP0_Status & (1 << CP0St_EXL)))
env->CP0_Cause &= ~(1U << CP0Ca_BD);
- env->active_tc.PC = (int32_t)0xBFC00000;
+ env->active_tc.PC = env->exception_base;
set_hflags_for_handler(env);
break;
case EXCP_EXT_INTERRUPT:
@@ -849,7 +849,7 @@ void mips_cpu_do_interrupt(CPUState *cs)
}
env->hflags &= ~MIPS_HFLAG_BMASK;
if (env->CP0_Status & (1 << CP0St_BEV)) {
- env->active_tc.PC = (int32_t)0xBFC00200;
+ env->active_tc.PC = env->exception_base + 0x200;
} else {
env->active_tc.PC = (int32_t)(env->CP0_EBase & ~0x3ff);
}
diff --git a/target-mips/translate.c b/target-mips/translate.c
index f420680..c0aec42 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -20068,6 +20068,7 @@ MIPSCPU *cpu_mips_init(const char *cpu_model)
cpu = MIPS_CPU(object_new(TYPE_MIPS_CPU));
env = &cpu->env;
env->cpu_model = def;
+ env->exception_base = (int32_t)0xBFC00000;
#ifndef CONFIG_USER_ONLY
mmu_init(env, def);
@@ -20090,6 +20091,12 @@ bool cpu_supports_cps_smp(const char *cpu_model)
return (def->CP0_Config3 & (1 << CP0C3_CMGCR)) != 0;
}
+void cpu_set_exception_base(int vp_index, target_ulong address)
+{
+ MIPSCPU *vp = MIPS_CPU(qemu_get_cpu(vp_index));
+ vp->env.exception_base = address;
+}
+
void cpu_state_reset(CPUMIPSState *env)
{
MIPSCPU *cpu = mips_env_get_cpu(env);
@@ -20179,7 +20186,7 @@ void cpu_state_reset(CPUMIPSState *env)
} else {
env->CP0_ErrorEPC = env->active_tc.PC;
}
- env->active_tc.PC = (int32_t)0xBFC00000;
+ env->active_tc.PC = env->exception_base;
env->CP0_Random = env->tlb->nb_tlb - 1;
env->tlb->tlb_in_use = env->tlb->nb_tlb;
env->CP0_Wired = 0;
--
2.7.4
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [Qemu-devel] [PATCH 2/3] hw/mips_cpc: make VP correctly start from the reset vector
2016-06-09 9:46 [Qemu-devel] [PATCH 0/3] mips: support configurable exception vector base Leon Alrae
2016-06-09 9:46 ` [Qemu-devel] [PATCH 1/3] target-mips: add exception base to MIPS CPU Leon Alrae
@ 2016-06-09 9:46 ` Leon Alrae
2016-06-09 9:46 ` [Qemu-devel] [PATCH 3/3] hw/mips_cmgcr: implement RESET_BASE register in CM GCR Leon Alrae
2 siblings, 0 replies; 4+ messages in thread
From: Leon Alrae @ 2016-06-09 9:46 UTC (permalink / raw)
To: qemu-devel; +Cc: aurelien
When VP enters the Run state it starts execution from the reset vector.
Currently used CPU_INTERRUPT_WAKE does not do that if reset exception
base has been modified. Therefore fix that by simply resetting given VP.
Drop the usage of CPU_INTERRUPT_WAKE also in VP_STOP and instead raise
the CPU_INTERRUPT_HALT to halt a VP.
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
---
hw/misc/mips_cpc.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/hw/misc/mips_cpc.c b/hw/misc/mips_cpc.c
index e6a35dd..6d34574 100644
--- a/hw/misc/mips_cpc.c
+++ b/hw/misc/mips_cpc.c
@@ -37,7 +37,7 @@ static void cpc_run_vp(MIPSCPCState *cpc, uint64_t vp_run)
CPU_FOREACH(cs) {
uint64_t i = 1ULL << cs->cpu_index;
if (i & vp_run & ~cpc->vp_running) {
- cpu_interrupt(cs, CPU_INTERRUPT_WAKE);
+ cpu_reset(cs);
cpc->vp_running |= i;
}
}
@@ -50,8 +50,7 @@ static void cpc_stop_vp(MIPSCPCState *cpc, uint64_t vp_stop)
CPU_FOREACH(cs) {
uint64_t i = 1ULL << cs->cpu_index;
if (i & vp_stop & cpc->vp_running) {
- cs->halted = 1;
- cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE);
+ cpu_interrupt(cs, CPU_INTERRUPT_HALT);
cpc->vp_running &= ~i;
}
}
--
2.7.4
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [Qemu-devel] [PATCH 3/3] hw/mips_cmgcr: implement RESET_BASE register in CM GCR
2016-06-09 9:46 [Qemu-devel] [PATCH 0/3] mips: support configurable exception vector base Leon Alrae
2016-06-09 9:46 ` [Qemu-devel] [PATCH 1/3] target-mips: add exception base to MIPS CPU Leon Alrae
2016-06-09 9:46 ` [Qemu-devel] [PATCH 2/3] hw/mips_cpc: make VP correctly start from the reset vector Leon Alrae
@ 2016-06-09 9:46 ` Leon Alrae
2 siblings, 0 replies; 4+ messages in thread
From: Leon Alrae @ 2016-06-09 9:46 UTC (permalink / raw)
To: qemu-devel; +Cc: aurelien
Implement RESET_BASE register which is local to each VP and a write to
it changes VP's reset exception base. Also, add OTHER register to
allow a software running on one VP to access other VP's local registers.
Guest can use this mechanism to specify custom address from which a VP
will start execution.
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
---
hw/misc/mips_cmgcr.c | 54 +++++++++++++++++++++++++++++++++++++++++++-
include/hw/misc/mips_cmgcr.h | 18 +++++++++++++++
2 files changed, 71 insertions(+), 1 deletion(-)
diff --git a/hw/misc/mips_cmgcr.c b/hw/misc/mips_cmgcr.c
index e6cf17d..b3ba166 100644
--- a/hw/misc/mips_cmgcr.c
+++ b/hw/misc/mips_cmgcr.c
@@ -59,6 +59,8 @@ static inline void update_gic_base(MIPSGCRState *gcr, uint64_t val)
static uint64_t gcr_read(void *opaque, hwaddr addr, unsigned size)
{
MIPSGCRState *gcr = (MIPSGCRState *) opaque;
+ MIPSGCRVPState *current_vps = &gcr->vps[current_cpu->cpu_index];
+ MIPSGCRVPState *other_vps = &gcr->vps[current_vps->other];
switch (addr) {
/* Global Control Block Register */
@@ -85,8 +87,14 @@ static uint64_t gcr_read(void *opaque, hwaddr addr, unsigned size)
case MIPS_COCB_OFS + GCR_CL_CONFIG_OFS:
/* Set PVP to # of VPs - 1 */
return gcr->num_vps - 1;
+ case MIPS_CLCB_OFS + GCR_CL_RESETBASE_OFS:
+ return current_vps->reset_base;
+ case MIPS_COCB_OFS + GCR_CL_RESETBASE_OFS:
+ return other_vps->reset_base;
case MIPS_CLCB_OFS + GCR_CL_OTHER_OFS:
- return 0;
+ return current_vps->other;
+ case MIPS_COCB_OFS + GCR_CL_OTHER_OFS:
+ return other_vps->other;
default:
qemu_log_mask(LOG_UNIMP, "Read %d bytes at GCR offset 0x%" HWADDR_PRIx
"\n", size, addr);
@@ -95,10 +103,18 @@ static uint64_t gcr_read(void *opaque, hwaddr addr, unsigned size)
return 0;
}
+static inline target_ulong get_exception_base(MIPSGCRVPState *vps)
+{
+ /* TODO: BEV_BASE and SELECT_BEV */
+ return (int32_t)(vps->reset_base & GCR_CL_RESET_BASE_RESETBASE_MSK);
+}
+
/* Write GCR registers */
static void gcr_write(void *opaque, hwaddr addr, uint64_t data, unsigned size)
{
MIPSGCRState *gcr = (MIPSGCRState *)opaque;
+ MIPSGCRVPState *current_vps = &gcr->vps[current_cpu->cpu_index];
+ MIPSGCRVPState *other_vps = &gcr->vps[current_vps->other];
switch (addr) {
case GCR_GIC_BASE_OFS:
@@ -107,6 +123,26 @@ static void gcr_write(void *opaque, hwaddr addr, uint64_t data, unsigned size)
case GCR_CPC_BASE_OFS:
update_cpc_base(gcr, data);
break;
+ case MIPS_CLCB_OFS + GCR_CL_RESETBASE_OFS:
+ current_vps->reset_base = data & GCR_CL_RESET_BASE_MSK;
+ cpu_set_exception_base(current_cpu->cpu_index,
+ get_exception_base(current_vps));
+ break;
+ case MIPS_COCB_OFS + GCR_CL_RESETBASE_OFS:
+ other_vps->reset_base = data & GCR_CL_RESET_BASE_MSK;
+ cpu_set_exception_base(current_vps->other,
+ get_exception_base(other_vps));
+ break;
+ case MIPS_CLCB_OFS + GCR_CL_OTHER_OFS:
+ if ((data & GCR_CL_OTHER_MSK) < gcr->num_vps) {
+ current_vps->other = data & GCR_CL_OTHER_MSK;
+ }
+ break;
+ case MIPS_COCB_OFS + GCR_CL_OTHER_OFS:
+ if ((data & GCR_CL_OTHER_MSK) < gcr->num_vps) {
+ other_vps->other = data & GCR_CL_OTHER_MSK;
+ }
+ break;
default:
qemu_log_mask(LOG_UNIMP, "Write %d bytes at GCR offset 0x%" HWADDR_PRIx
" 0x%" PRIx64 "\n", size, addr, data);
@@ -148,9 +184,16 @@ static void mips_gcr_init(Object *obj)
static void mips_gcr_reset(DeviceState *dev)
{
MIPSGCRState *s = MIPS_GCR(dev);
+ int i;
update_gic_base(s, 0);
update_cpc_base(s, 0);
+
+ for (i = 0; i < s->num_vps; i++) {
+ s->vps[i].other = 0;
+ s->vps[i].reset_base = 0xBFC00000 & GCR_CL_RESET_BASE_MSK;
+ cpu_set_exception_base(i, get_exception_base(&s->vps[i]));
+ }
}
static const VMStateDescription vmstate_mips_gcr = {
@@ -170,12 +213,21 @@ static Property mips_gcr_properties[] = {
DEFINE_PROP_END_OF_LIST(),
};
+static void mips_gcr_realize(DeviceState *dev, Error **errp)
+{
+ MIPSGCRState *s = MIPS_GCR(dev);
+
+ /* Create local set of registers for each VP */
+ s->vps = g_new(MIPSGCRVPState, s->num_vps);
+}
+
static void mips_gcr_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->props = mips_gcr_properties;
dc->vmsd = &vmstate_mips_gcr;
dc->reset = mips_gcr_reset;
+ dc->realize = mips_gcr_realize;
}
static const TypeInfo mips_gcr_info = {
diff --git a/include/hw/misc/mips_cmgcr.h b/include/hw/misc/mips_cmgcr.h
index 5b90e94..690e1d6 100644
--- a/include/hw/misc/mips_cmgcr.h
+++ b/include/hw/misc/mips_cmgcr.h
@@ -35,6 +35,7 @@
/* Core Local and Core Other Block Register Map */
#define GCR_CL_CONFIG_OFS 0x0010
#define GCR_CL_OTHER_OFS 0x0018
+#define GCR_CL_RESETBASE_OFS 0x0020
/* GCR_L2_CONFIG register fields */
#define GCR_L2_CONFIG_BYPASS_SHF 20
@@ -50,6 +51,20 @@
#define GCR_CPC_BASE_CPCBASE_MSK 0xFFFFFFFF8000ULL
#define GCR_CPC_BASE_MSK (GCR_CPC_BASE_CPCEN_MSK | GCR_CPC_BASE_CPCBASE_MSK)
+/* GCR_CL_OTHER_OFS register fields */
+#define GCR_CL_OTHER_VPOTHER_MSK 0x7
+#define GCR_CL_OTHER_MSK GCR_CL_OTHER_VPOTHER_MSK
+
+/* GCR_CL_RESETBASE_OFS register fields */
+#define GCR_CL_RESET_BASE_RESETBASE_MSK 0xFFFFF000U
+#define GCR_CL_RESET_BASE_MSK GCR_CL_RESET_BASE_RESETBASE_MSK
+
+typedef struct MIPSGCRVPState MIPSGCRVPState;
+struct MIPSGCRVPState {
+ uint32_t other;
+ uint64_t reset_base;
+};
+
typedef struct MIPSGCRState MIPSGCRState;
struct MIPSGCRState {
SysBusDevice parent_obj;
@@ -63,6 +78,9 @@ struct MIPSGCRState {
uint64_t cpc_base;
uint64_t gic_base;
+
+ /* VP Local/Other Registers */
+ MIPSGCRVPState *vps;
};
#endif /* _MIPS_GCR_H */
--
2.7.4
^ permalink raw reply related [flat|nested] 4+ messages in thread