diff mbox

[4/7] target/openrisc: implement shadow registers

Message ID b1be5af9a1d304f55847efeab706e88e3b9b1afa.1492384862.git.shorne@gmail.com
State New
Headers show

Commit Message

Stafford Horne April 16, 2017, 11:23 p.m. UTC
Shadow registers are part of the openrisc spec along with sr[cid], as
part of the fast context switching feature.  When exceptions occur,
instead of having to save registers to the stack if enabled the CID will
increment and a new set of registers will be available.

This patch only implements shadow registers which can be used as extra
scratch registers via the mfspr and mtspr if required.  This is
implemented in a way where it would be easy to add on the fast context
switching, currently cid is hardcoded to 0.

This is need for openrisc linux smp kernels to boot correctly.

Signed-off-by: Stafford Horne <shorne@gmail.com>
---
 target/openrisc/cpu.c        |  5 ++++-
 target/openrisc/cpu.h        |  4 +++-
 target/openrisc/machine.c    | 16 +++++++++++++---
 target/openrisc/sys_helper.c |  9 +++++++++
 target/openrisc/translate.c  |  3 ++-
 5 files changed, 31 insertions(+), 6 deletions(-)

Comments

Richard Henderson April 18, 2017, 8:11 a.m. UTC | #1
On 04/16/2017 04:23 PM, Stafford Horne wrote:
> Shadow registers are part of the openrisc spec along with sr[cid], as
> part of the fast context switching feature.  When exceptions occur,
> instead of having to save registers to the stack if enabled the CID will
> increment and a new set of registers will be available.
>
> This patch only implements shadow registers which can be used as extra
> scratch registers via the mfspr and mtspr if required.  This is
> implemented in a way where it would be easy to add on the fast context
> switching, currently cid is hardcoded to 0.

I'm not especially keen on this half-conversion.
If CID cannot be changed, then

> -    target_ulong gpr[32];     /* General registers */
> +    target_ulong shadow_gpr[16][32]; /* Shadow registers */
> +    target_ulong * gpr;       /* General registers (backed by shadow) */

this pointer should not be necessary.  Just use a union, or even just

     target_ulong gpr[32];
     target_ulong shadow_gpr[15][32];

for now.

Alternately, add accessor functions that take the whole ENV (which would be 
able to read CID, when needed).  C.f.

     uint64_t cpu_alpha_load_gr(CPUAlphaState *env, unsigned reg);
     void cpu_alpha_store_gr(CPUAlphaState *env, unsigned reg, uint64_t val);

If/when CID can be changed, then we can talk about various ways
that this can be modeled within TCG.


r~
Stafford Horne April 18, 2017, 2:26 p.m. UTC | #2
On Tue, Apr 18, 2017 at 01:11:53AM -0700, Richard Henderson wrote:
> On 04/16/2017 04:23 PM, Stafford Horne wrote:
> > Shadow registers are part of the openrisc spec along with sr[cid], as
> > part of the fast context switching feature.  When exceptions occur,
> > instead of having to save registers to the stack if enabled the CID will
> > increment and a new set of registers will be available.
> > 
> > This patch only implements shadow registers which can be used as extra
> > scratch registers via the mfspr and mtspr if required.  This is
> > implemented in a way where it would be easy to add on the fast context
> > switching, currently cid is hardcoded to 0.
> 
> I'm not especially keen on this half-conversion.
> If CID cannot be changed, then
> 
> > -    target_ulong gpr[32];     /* General registers */
> > +    target_ulong shadow_gpr[16][32]; /* Shadow registers */
> > +    target_ulong * gpr;       /* General registers (backed by shadow) */
> 
> this pointer should not be necessary.  Just use a union, or even just
> 
>     target_ulong gpr[32];
>     target_ulong shadow_gpr[15][32];
> 
> for now.
> 
> Alternately, add accessor functions that take the whole ENV (which would be
> able to read CID, when needed).  C.f.
> 
>     uint64_t cpu_alpha_load_gr(CPUAlphaState *env, unsigned reg);
>     void cpu_alpha_store_gr(CPUAlphaState *env, unsigned reg, uint64_t val);

Actually, I started off writing it this way, but there were a lot of places
that used env->gpr.  I had some regex's to replace everything, but in the
end I thought using the gpr pointer was just easier.

Using the union would work as well, but it wouldnt help to allow switching
of cid.  My idea with the pointer was that if cid was updates I could
update the pointer at that time.

Ill rework this to use the accessor functions.

-Stafford

> If/when CID can be changed, then we can talk about various ways
> that this can be modeled within TCG.
> 
> 
> r~
diff mbox

Patch

diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c
index 7fd2b9a..dc8be21 100644
--- a/target/openrisc/cpu.c
+++ b/target/openrisc/cpu.c
@@ -46,13 +46,14 @@  static void openrisc_cpu_reset(CPUState *s)
 
     memset(&cpu->env, 0, offsetof(CPUOpenRISCState, end_reset_fields));
 
+    cpu->env.gpr = cpu->env.shadow_gpr[0];
     cpu->env.pc = 0x100;
     cpu->env.sr = SR_FO | SR_SM;
     cpu->env.lock_addr = -1;
     s->exception_index = -1;
 
     cpu->env.upr = UPR_UP | UPR_DMP | UPR_IMP | UPR_PICP | UPR_TTP;
-    cpu->env.cpucfgr = CPUCFGR_OB32S | CPUCFGR_OF32S;
+    cpu->env.cpucfgr = CPUCFGR_OB32S | CPUCFGR_OF32S | CPUCFGR_NSGF;
     cpu->env.dmmucfgr = (DMMUCFGR_NTW & (0 << 2)) | (DMMUCFGR_NTS & (6 << 2));
     cpu->env.immucfgr = (IMMUCFGR_NTW & (0 << 2)) | (IMMUCFGR_NTS & (6 << 2));
 
@@ -132,6 +133,7 @@  static void or1200_initfn(Object *obj)
 {
     OpenRISCCPU *cpu = OPENRISC_CPU(obj);
 
+    set_feature(cpu, OPENRISC_FEATURE_NSGF);
     set_feature(cpu, OPENRISC_FEATURE_OB32S);
     set_feature(cpu, OPENRISC_FEATURE_OF32S);
 }
@@ -140,6 +142,7 @@  static void openrisc_any_initfn(Object *obj)
 {
     OpenRISCCPU *cpu = OPENRISC_CPU(obj);
 
+    set_feature(cpu, OPENRISC_FEATURE_NSGF);
     set_feature(cpu, OPENRISC_FEATURE_OB32S);
 }
 
diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h
index 418a0e6..78675e0 100644
--- a/target/openrisc/cpu.h
+++ b/target/openrisc/cpu.h
@@ -269,7 +269,9 @@  typedef struct CPUOpenRISCTLBContext {
 #endif
 
 typedef struct CPUOpenRISCState {
-    target_ulong gpr[32];     /* General registers */
+    target_ulong shadow_gpr[16][32]; /* Shadow registers */
+    target_ulong * gpr;       /* General registers (backed by shadow) */
+
     target_ulong pc;          /* Program counter */
     target_ulong ppc;         /* Prev PC */
     target_ulong jmp_pc;      /* Jump PC */
diff --git a/target/openrisc/machine.c b/target/openrisc/machine.c
index 686eaa3..27cc751 100644
--- a/target/openrisc/machine.c
+++ b/target/openrisc/machine.c
@@ -24,6 +24,15 @@ 
 #include "hw/boards.h"
 #include "migration/cpu.h"
 
+static int env_post_load(void *opaque, int version_id)
+{
+    CPUOpenRISCState *env = opaque;
+
+    env->gpr = env->shadow_gpr[0];
+
+    return 0;
+}
+
 static int get_sr(QEMUFile *f, void *opaque, size_t size, VMStateField *field)
 {
     CPUOpenRISCState *env = opaque;
@@ -47,10 +56,11 @@  static const VMStateInfo vmstate_sr = {
 
 static const VMStateDescription vmstate_env = {
     .name = "env",
-    .version_id = 4,
-    .minimum_version_id = 4,
+    .version_id = 5,
+    .minimum_version_id = 5,
+    .post_load = env_post_load,
     .fields = (VMStateField[]) {
-        VMSTATE_UINTTL_ARRAY(gpr, CPUOpenRISCState, 32),
+        VMSTATE_UINTTL_2DARRAY(shadow_gpr, CPUOpenRISCState, 16, 32),
         VMSTATE_UINTTL(pc, CPUOpenRISCState),
         VMSTATE_UINTTL(ppc, CPUOpenRISCState),
         VMSTATE_UINTTL(jmp_pc, CPUOpenRISCState),
diff --git a/target/openrisc/sys_helper.c b/target/openrisc/sys_helper.c
index bd5051b..04ff302 100644
--- a/target/openrisc/sys_helper.c
+++ b/target/openrisc/sys_helper.c
@@ -89,6 +89,11 @@  void HELPER(mtspr)(CPUOpenRISCState *env,
     case TO_SPR(0, 64): /* ESR */
         env->esr = rb;
         break;
+
+    case TO_SPR(0, 1024) ... TO_SPR(0, 1024 + (16 * 32)): /* Shadow GPRs */
+        idx = (spr - 1024);
+        env->shadow_gpr[idx / 32][idx % 32] = rb;
+
     case TO_SPR(1, 512) ... TO_SPR(1, 512+DTLB_SIZE-1): /* DTLBW0MR 0-127 */
         idx = spr - TO_SPR(1, 512);
         if (!(rb & 1)) {
@@ -233,6 +238,10 @@  target_ulong HELPER(mfspr)(CPUOpenRISCState *env,
     case TO_SPR(0, 129): /* NUMCORES */
         return 1;
 
+    case TO_SPR(0, 1024) ... TO_SPR(0, 1024 + (16 * 32)): /* Shadow GPRs */
+        idx = (spr - 1024);
+        return env->shadow_gpr[idx / 32][idx % 32];
+
     case TO_SPR(1, 512) ... TO_SPR(1, 512+DTLB_SIZE-1): /* DTLBW0MR 0-127 */
         idx = spr - TO_SPR(1, 512);
         return env->tlb->dtlb[0][idx].mr;
diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c
index 74df245..c7261cb 100644
--- a/target/openrisc/translate.c
+++ b/target/openrisc/translate.c
@@ -107,7 +107,8 @@  void openrisc_translate_init(void)
                                      "mac");
     for (i = 0; i < 32; i++) {
         cpu_R[i] = tcg_global_mem_new(cpu_env,
-                                      offsetof(CPUOpenRISCState, gpr[i]),
+                                      offsetof(CPUOpenRISCState,
+                                               shadow_gpr[0][i]),
                                       regnames[i]);
     }
     cpu_R0 = cpu_R[0];