mirror of https://github.com/xqemu/xqemu.git
hw/mips_cmgcr: implement RESET_BASE register in CM GCR
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>
This commit is contained in:
parent
dff94251f0
commit
c09199fe73
|
@ -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)
|
static uint64_t gcr_read(void *opaque, hwaddr addr, unsigned size)
|
||||||
{
|
{
|
||||||
MIPSGCRState *gcr = (MIPSGCRState *) opaque;
|
MIPSGCRState *gcr = (MIPSGCRState *) opaque;
|
||||||
|
MIPSGCRVPState *current_vps = &gcr->vps[current_cpu->cpu_index];
|
||||||
|
MIPSGCRVPState *other_vps = &gcr->vps[current_vps->other];
|
||||||
|
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
/* Global Control Block Register */
|
/* 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:
|
case MIPS_COCB_OFS + GCR_CL_CONFIG_OFS:
|
||||||
/* Set PVP to # of VPs - 1 */
|
/* Set PVP to # of VPs - 1 */
|
||||||
return gcr->num_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:
|
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:
|
default:
|
||||||
qemu_log_mask(LOG_UNIMP, "Read %d bytes at GCR offset 0x%" HWADDR_PRIx
|
qemu_log_mask(LOG_UNIMP, "Read %d bytes at GCR offset 0x%" HWADDR_PRIx
|
||||||
"\n", size, addr);
|
"\n", size, addr);
|
||||||
|
@ -95,10 +103,18 @@ static uint64_t gcr_read(void *opaque, hwaddr addr, unsigned size)
|
||||||
return 0;
|
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 */
|
/* Write GCR registers */
|
||||||
static void gcr_write(void *opaque, hwaddr addr, uint64_t data, unsigned size)
|
static void gcr_write(void *opaque, hwaddr addr, uint64_t data, unsigned size)
|
||||||
{
|
{
|
||||||
MIPSGCRState *gcr = (MIPSGCRState *)opaque;
|
MIPSGCRState *gcr = (MIPSGCRState *)opaque;
|
||||||
|
MIPSGCRVPState *current_vps = &gcr->vps[current_cpu->cpu_index];
|
||||||
|
MIPSGCRVPState *other_vps = &gcr->vps[current_vps->other];
|
||||||
|
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
case GCR_GIC_BASE_OFS:
|
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:
|
case GCR_CPC_BASE_OFS:
|
||||||
update_cpc_base(gcr, data);
|
update_cpc_base(gcr, data);
|
||||||
break;
|
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:
|
default:
|
||||||
qemu_log_mask(LOG_UNIMP, "Write %d bytes at GCR offset 0x%" HWADDR_PRIx
|
qemu_log_mask(LOG_UNIMP, "Write %d bytes at GCR offset 0x%" HWADDR_PRIx
|
||||||
" 0x%" PRIx64 "\n", size, addr, data);
|
" 0x%" PRIx64 "\n", size, addr, data);
|
||||||
|
@ -148,9 +184,16 @@ static void mips_gcr_init(Object *obj)
|
||||||
static void mips_gcr_reset(DeviceState *dev)
|
static void mips_gcr_reset(DeviceState *dev)
|
||||||
{
|
{
|
||||||
MIPSGCRState *s = MIPS_GCR(dev);
|
MIPSGCRState *s = MIPS_GCR(dev);
|
||||||
|
int i;
|
||||||
|
|
||||||
update_gic_base(s, 0);
|
update_gic_base(s, 0);
|
||||||
update_cpc_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 = {
|
static const VMStateDescription vmstate_mips_gcr = {
|
||||||
|
@ -170,12 +213,21 @@ static Property mips_gcr_properties[] = {
|
||||||
DEFINE_PROP_END_OF_LIST(),
|
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)
|
static void mips_gcr_class_init(ObjectClass *klass, void *data)
|
||||||
{
|
{
|
||||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
dc->props = mips_gcr_properties;
|
dc->props = mips_gcr_properties;
|
||||||
dc->vmsd = &vmstate_mips_gcr;
|
dc->vmsd = &vmstate_mips_gcr;
|
||||||
dc->reset = mips_gcr_reset;
|
dc->reset = mips_gcr_reset;
|
||||||
|
dc->realize = mips_gcr_realize;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo mips_gcr_info = {
|
static const TypeInfo mips_gcr_info = {
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
/* Core Local and Core Other Block Register Map */
|
/* Core Local and Core Other Block Register Map */
|
||||||
#define GCR_CL_CONFIG_OFS 0x0010
|
#define GCR_CL_CONFIG_OFS 0x0010
|
||||||
#define GCR_CL_OTHER_OFS 0x0018
|
#define GCR_CL_OTHER_OFS 0x0018
|
||||||
|
#define GCR_CL_RESETBASE_OFS 0x0020
|
||||||
|
|
||||||
/* GCR_L2_CONFIG register fields */
|
/* GCR_L2_CONFIG register fields */
|
||||||
#define GCR_L2_CONFIG_BYPASS_SHF 20
|
#define GCR_L2_CONFIG_BYPASS_SHF 20
|
||||||
|
@ -50,6 +51,20 @@
|
||||||
#define GCR_CPC_BASE_CPCBASE_MSK 0xFFFFFFFF8000ULL
|
#define GCR_CPC_BASE_CPCBASE_MSK 0xFFFFFFFF8000ULL
|
||||||
#define GCR_CPC_BASE_MSK (GCR_CPC_BASE_CPCEN_MSK | GCR_CPC_BASE_CPCBASE_MSK)
|
#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;
|
typedef struct MIPSGCRState MIPSGCRState;
|
||||||
struct MIPSGCRState {
|
struct MIPSGCRState {
|
||||||
SysBusDevice parent_obj;
|
SysBusDevice parent_obj;
|
||||||
|
@ -63,6 +78,9 @@ struct MIPSGCRState {
|
||||||
|
|
||||||
uint64_t cpc_base;
|
uint64_t cpc_base;
|
||||||
uint64_t gic_base;
|
uint64_t gic_base;
|
||||||
|
|
||||||
|
/* VP Local/Other Registers */
|
||||||
|
MIPSGCRVPState *vps;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _MIPS_GCR_H */
|
#endif /* _MIPS_GCR_H */
|
||||||
|
|
Loading…
Reference in New Issue