qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] RFC: Implement emulation of pSeries logical partitions (v2)
@ 2011-02-15  4:56 qemu
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 01/28] Add TAGS and *~ to .gitignore qemu
                   ` (27 more replies)
  0 siblings, 28 replies; 29+ messages in thread
From: qemu @ 2011-02-15  4:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: paulus, agraf, anton

This patch series adds a "pseries" machine to qemu, allowing it to
emulate IBM pSeries logical partitions.  Along the way we add a bunch
of support for more modern ppc CPUs than are currently supported.  It
also makes some significant cleanups to the translation code for hash
page table based ppc MMUs.

Changes since v1 of this series:
 * numerous coding style fixups
 * incorporated most review comments from initial version
 * moved to a wholly dynamic hypercall registration scheme
 * assorted other cleanups
 * many more patches implementing VIO devices and basic partition firmware

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 01/28] Add TAGS and *~ to .gitignore
  2011-02-15  4:56 [Qemu-devel] RFC: Implement emulation of pSeries logical partitions (v2) qemu
@ 2011-02-15  4:56 ` qemu
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 02/28] Clean up PowerPC SLB handling code qemu
                   ` (26 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: qemu @ 2011-02-15  4:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: paulus, agraf, anton

From: David Gibson <david@gibson.dropbear.id.au>

Add the etags generated output file and editor backup files to
.gitignore.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 .gitignore |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore
index 26703e1..1d79680 100644
--- a/.gitignore
+++ b/.gitignore
@@ -63,3 +63,5 @@ pc-bios/optionrom/multiboot.raw
 .stgit-*
 cscope.*
 tags
+TAGS
+*~
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 02/28] Clean up PowerPC SLB handling code
  2011-02-15  4:56 [Qemu-devel] RFC: Implement emulation of pSeries logical partitions (v2) qemu
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 01/28] Add TAGS and *~ to .gitignore qemu
@ 2011-02-15  4:56 ` qemu
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 03/28] Allow qemu_devtree_setprop() to take arbitrary values qemu
                   ` (25 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: qemu @ 2011-02-15  4:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: paulus, agraf, anton

From: David Gibson <david@gibson.dropbear.id.au>

Currently the SLB information when emulating a PowerPC 970 is
storeed in a structure with the unhelpfully named fields 'tmp'
and 'tmp64'.  While the layout in these fields does match the
description of the SLB in the architecture document, it is not
convenient either for looking up the SLB, or for emulating the
slbmte instruction.

This patch, therefore, reorganizes the SLB entry structure to be
divided in the the "ESID related" and "VSID related" fields as
they are divided in instructions accessing the SLB.

In addition to making the code smaller and more readable, this will
make it easier to implement for the 1TB segments used in more
recent PowerPC chips.

Signed-off-by: David Gibson <dwg@au1.ibm.com>
---
 target-ppc/cpu.h       |   29 +++++++-
 target-ppc/helper.c    |  178 ++++++++++++++----------------------------------
 target-ppc/helper.h    |    1 -
 target-ppc/op_helper.c |    9 +--
 4 files changed, 80 insertions(+), 137 deletions(-)

diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index deb8d7c..a20c132 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -43,6 +43,8 @@
 # define TARGET_VIRT_ADDR_SPACE_BITS 64
 #endif
 
+#define TARGET_PAGE_BITS_16M 24
+
 #else /* defined (TARGET_PPC64) */
 /* PowerPC 32 definitions */
 #define TARGET_LONG_BITS 32
@@ -359,10 +361,31 @@ union ppc_tlb_t {
 
 typedef struct ppc_slb_t ppc_slb_t;
 struct ppc_slb_t {
-    uint64_t tmp64;
-    uint32_t tmp;
+    uint64_t esid;
+    uint64_t vsid;
 };
 
+/* Bits in the SLB ESID word */
+#define SLB_ESID_ESID           0xFFFFFFFFF0000000ULL
+#define SLB_ESID_V              0x0000000008000000ULL /* valid */
+
+/* Bits in the SLB VSID word */
+#define SLB_VSID_SHIFT          12
+#define SLB_VSID_SSIZE_SHIFT    62
+#define SLB_VSID_B              0xc000000000000000ULL
+#define SLB_VSID_B_256M         0x0000000000000000ULL
+#define SLB_VSID_VSID           0x3FFFFFFFFFFFF000ULL
+#define SLB_VSID_KS             0x0000000000000800ULL
+#define SLB_VSID_KP             0x0000000000000400ULL
+#define SLB_VSID_N              0x0000000000000200ULL /* no-execute */
+#define SLB_VSID_L              0x0000000000000100ULL
+#define SLB_VSID_C              0x0000000000000080ULL /* class */
+#define SLB_VSID_LP             0x0000000000000030ULL
+#define SLB_VSID_ATTR           0x0000000000000FFFULL
+
+#define SEGMENT_SHIFT_256M      28
+#define SEGMENT_MASK_256M       ~((1ULL << SEGMENT_SHIFT_256M) - 1)
+
 /*****************************************************************************/
 /* Machine state register bits definition                                    */
 #define MSR_SF   63 /* Sixty-four-bit mode                            hflags */
@@ -755,7 +778,7 @@ void ppc_store_sdr1 (CPUPPCState *env, target_ulong value);
 void ppc_store_asr (CPUPPCState *env, target_ulong value);
 target_ulong ppc_load_slb (CPUPPCState *env, int slb_nr);
 target_ulong ppc_load_sr (CPUPPCState *env, int sr_nr);
-void ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs);
+int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs);
 #endif /* defined(TARGET_PPC64) */
 void ppc_store_sr (CPUPPCState *env, int srnum, target_ulong value);
 #endif /* !defined(CONFIG_USER_ONLY) */
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 4b49101..2094ca3 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -672,85 +672,36 @@ static inline int find_pte(CPUState *env, mmu_ctx_t *ctx, int h, int rw,
 }
 
 #if defined(TARGET_PPC64)
-static ppc_slb_t *slb_get_entry(CPUPPCState *env, int nr)
-{
-    ppc_slb_t *retval = &env->slb[nr];
-
-#if 0 // XXX implement bridge mode?
-    if (env->spr[SPR_ASR] & 1) {
-        target_phys_addr_t sr_base;
-
-        sr_base = env->spr[SPR_ASR] & 0xfffffffffffff000;
-        sr_base += (12 * nr);
-
-        retval->tmp64 = ldq_phys(sr_base);
-        retval->tmp = ldl_phys(sr_base + 8);
-    }
-#endif
-
-    return retval;
-}
-
-static void slb_set_entry(CPUPPCState *env, int nr, ppc_slb_t *slb)
-{
-    ppc_slb_t *entry = &env->slb[nr];
-
-    if (slb == entry)
-        return;
-
-    entry->tmp64 = slb->tmp64;
-    entry->tmp = slb->tmp;
-}
-
-static inline int slb_is_valid(ppc_slb_t *slb)
-{
-    return (int)(slb->tmp64 & 0x0000000008000000ULL);
-}
-
-static inline void slb_invalidate(ppc_slb_t *slb)
-{
-    slb->tmp64 &= ~0x0000000008000000ULL;
-}
-
 static inline int slb_lookup(CPUPPCState *env, target_ulong eaddr,
                              target_ulong *vsid, target_ulong *page_mask,
                              int *attr, int *target_page_bits)
 {
-    target_ulong mask;
-    int n, ret;
+    uint64_t esid;
+    int n;
 
-    ret = -5;
     LOG_SLB("%s: eaddr " TARGET_FMT_lx "\n", __func__, eaddr);
-    mask = 0x0000000000000000ULL; /* Avoid gcc warning */
+
+    esid = (eaddr & SEGMENT_MASK_256M) | SLB_ESID_V;
+
     for (n = 0; n < env->slb_nr; n++) {
-        ppc_slb_t *slb = slb_get_entry(env, n);
-
-        LOG_SLB("%s: seg %d %016" PRIx64 " %08"
-                    PRIx32 "\n", __func__, n, slb->tmp64, slb->tmp);
-        if (slb_is_valid(slb)) {
-            /* SLB entry is valid */
-            mask = 0xFFFFFFFFF0000000ULL;
-            if (slb->tmp & 0x8) {
-                /* 16 MB PTEs */
-                if (target_page_bits)
-                    *target_page_bits = 24;
-            } else {
-                /* 4 KB PTEs */
-                if (target_page_bits)
-                    *target_page_bits = TARGET_PAGE_BITS;
-            }
-            if ((eaddr & mask) == (slb->tmp64 & mask)) {
-                /* SLB match */
-                *vsid = ((slb->tmp64 << 24) | (slb->tmp >> 8)) & 0x0003FFFFFFFFFFFFULL;
-                *page_mask = ~mask;
-                *attr = slb->tmp & 0xFF;
-                ret = n;
-                break;
+        ppc_slb_t *slb = &env->slb[n];
+
+        LOG_SLB("%s: slot %d %016" PRIx64 " %016"
+                    PRIx64 "\n", __func__, n, slb->esid, slb->vsid);
+        if (slb->esid == esid) {
+            *vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT;
+            *page_mask = ~SEGMENT_MASK_256M;
+            *attr = slb->vsid & SLB_VSID_ATTR;
+            if (target_page_bits) {
+                *target_page_bits = (slb->vsid & SLB_VSID_L)
+                    ? TARGET_PAGE_BITS_16M
+                    : TARGET_PAGE_BITS;
             }
+            return n;
         }
     }
 
-    return ret;
+    return -5;
 }
 
 void ppc_slb_invalidate_all (CPUPPCState *env)
@@ -760,11 +711,10 @@ void ppc_slb_invalidate_all (CPUPPCState *env)
     do_invalidate = 0;
     /* XXX: Warning: slbia never invalidates the first segment */
     for (n = 1; n < env->slb_nr; n++) {
-        ppc_slb_t *slb = slb_get_entry(env, n);
+        ppc_slb_t *slb = &env->slb[n];
 
-        if (slb_is_valid(slb)) {
-            slb_invalidate(slb);
-            slb_set_entry(env, n, slb);
+        if (slb->esid & SLB_ESID_V) {
+            slb->esid &= ~SLB_ESID_V;
             /* XXX: given the fact that segment size is 256 MB or 1TB,
              *      and we still don't have a tlb_flush_mask(env, n, mask)
              *      in Qemu, we just invalidate all TLBs
@@ -781,68 +731,44 @@ void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0)
     target_ulong vsid, page_mask;
     int attr;
     int n;
+    ppc_slb_t *slb;
 
     n = slb_lookup(env, T0, &vsid, &page_mask, &attr, NULL);
-    if (n >= 0) {
-        ppc_slb_t *slb = slb_get_entry(env, n);
-
-        if (slb_is_valid(slb)) {
-            slb_invalidate(slb);
-            slb_set_entry(env, n, slb);
-            /* XXX: given the fact that segment size is 256 MB or 1TB,
-             *      and we still don't have a tlb_flush_mask(env, n, mask)
-             *      in Qemu, we just invalidate all TLBs
-             */
-            tlb_flush(env, 1);
-        }
+    if (n < 0) {
+        return;
     }
-}
 
-target_ulong ppc_load_slb (CPUPPCState *env, int slb_nr)
-{
-    target_ulong rt;
-    ppc_slb_t *slb = slb_get_entry(env, slb_nr);
+    slb = &env->slb[n];
 
-    if (slb_is_valid(slb)) {
-        /* SLB entry is valid */
-        /* Copy SLB bits 62:88 to Rt 37:63 (VSID 23:49) */
-        rt = slb->tmp >> 8;             /* 65:88 => 40:63 */
-        rt |= (slb->tmp64 & 0x7) << 24; /* 62:64 => 37:39 */
-        /* Copy SLB bits 89:92 to Rt 33:36 (KsKpNL) */
-        rt |= ((slb->tmp >> 4) & 0xF) << 27;
-    } else {
-        rt = 0;
-    }
-    LOG_SLB("%s: %016" PRIx64 " %08" PRIx32 " => %d "
-            TARGET_FMT_lx "\n", __func__, slb->tmp64, slb->tmp, slb_nr, rt);
+    if (slb->esid & SLB_ESID_V) {
+        slb->esid &= ~SLB_ESID_V;
 
-    return rt;
+        /* XXX: given the fact that segment size is 256 MB or 1TB,
+         *      and we still don't have a tlb_flush_mask(env, n, mask)
+         *      in Qemu, we just invalidate all TLBs
+         */
+        tlb_flush(env, 1);
+    }
 }
 
-void ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs)
+int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs)
 {
-    ppc_slb_t *slb;
-
-    uint64_t vsid;
-    uint64_t esid;
-    int flags, valid, slb_nr;
-
-    vsid = rs >> 12;
-    flags = ((rs >> 8) & 0xf);
+    int slot = rb & 0xfff;
+    uint64_t esid = rb & ~0xfff;
+    ppc_slb_t *slb = &env->slb[slot];
 
-    esid = rb >> 28;
-    valid = (rb & (1 << 27));
-    slb_nr = rb & 0xfff;
+    if (slot >= env->slb_nr) {
+        return -1;
+    }
 
-    slb = slb_get_entry(env, slb_nr);
-    slb->tmp64 = (esid << 28) | valid | (vsid >> 24);
-    slb->tmp = (vsid << 8) | (flags << 3);
+    slb->esid = esid;
+    slb->vsid = rs;
 
     LOG_SLB("%s: %d " TARGET_FMT_lx " - " TARGET_FMT_lx " => %016" PRIx64
-            " %08" PRIx32 "\n", __func__, slb_nr, rb, rs, slb->tmp64,
-            slb->tmp);
+            " %016" PRIx64 "\n", __func__, slot, rb, rs,
+            slb->esid, slb->vsid);
 
-    slb_set_entry(env, slb_nr, slb);
+    return 0;
 }
 #endif /* defined(TARGET_PPC64) */
 
@@ -860,24 +786,22 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx,
 {
     target_phys_addr_t sdr, hash, mask, sdr_mask, htab_mask;
     target_ulong sr, vsid, vsid_mask, pgidx, page_mask;
-#if defined(TARGET_PPC64)
-    int attr;
-#endif
     int ds, vsid_sh, sdr_sh, pr, target_page_bits;
     int ret, ret2;
 
     pr = msr_pr;
 #if defined(TARGET_PPC64)
     if (env->mmu_model & POWERPC_MMU_64) {
+        int attr;
+
         LOG_MMU("Check SLBs\n");
         ret = slb_lookup(env, eaddr, &vsid, &page_mask, &attr,
                          &target_page_bits);
         if (ret < 0)
             return ret;
-        ctx->key = ((attr & 0x40) && (pr != 0)) ||
-            ((attr & 0x80) && (pr == 0)) ? 1 : 0;
+        ctx->key = !!(pr ? (attr & SLB_VSID_KP) : (attr & SLB_VSID_KS));
         ds = 0;
-        ctx->nx = attr & 0x10 ? 1 : 0;
+        ctx->nx = !!(attr & SLB_VSID_N);
         ctx->eaddr = eaddr;
         vsid_mask = 0x00003FFFFFFFFF80ULL;
         vsid_sh = 7;
diff --git a/target-ppc/helper.h b/target-ppc/helper.h
index 2bf9283..d512cb0 100644
--- a/target-ppc/helper.h
+++ b/target-ppc/helper.h
@@ -340,7 +340,6 @@ DEF_HELPER_1(74xx_tlbi, void, tl)
 DEF_HELPER_FLAGS_0(tlbia, TCG_CALL_CONST, void)
 DEF_HELPER_FLAGS_1(tlbie, TCG_CALL_CONST, void, tl)
 #if defined(TARGET_PPC64)
-DEF_HELPER_FLAGS_1(load_slb, TCG_CALL_CONST, tl, tl)
 DEF_HELPER_FLAGS_2(store_slb, TCG_CALL_CONST, void, tl, tl)
 DEF_HELPER_FLAGS_0(slbia, TCG_CALL_CONST, void)
 DEF_HELPER_FLAGS_1(slbie, TCG_CALL_CONST, void, tl)
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index 17e070a..bf41627 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -3746,14 +3746,11 @@ void helper_store_sr (target_ulong sr_num, target_ulong val)
 
 /* SLB management */
 #if defined(TARGET_PPC64)
-target_ulong helper_load_slb (target_ulong slb_nr)
-{
-    return ppc_load_slb(env, slb_nr);
-}
-
 void helper_store_slb (target_ulong rb, target_ulong rs)
 {
-    ppc_store_slb(env, rb, rs);
+    if (ppc_store_slb(env, rb, rs) < 0) {
+        helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL);
+    }
 }
 
 void helper_slbia (void)
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 03/28] Allow qemu_devtree_setprop() to take arbitrary values
  2011-02-15  4:56 [Qemu-devel] RFC: Implement emulation of pSeries logical partitions (v2) qemu
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 01/28] Add TAGS and *~ to .gitignore qemu
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 02/28] Clean up PowerPC SLB handling code qemu
@ 2011-02-15  4:56 ` qemu
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 04/28] Add a hook to allow hypercalls to be emulated on PowerPC qemu
                   ` (24 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: qemu @ 2011-02-15  4:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: paulus, agraf, anton

From: David Gibson <dwg@au1.ibm.com>

Currently qemu_devtree_setprop() expects the new property value to be
given as a uint32_t *.  While property values consisting of u32s are
common, in general they can have any bytestring value.

Therefore, this patch alters the function to take a void * instead,
allowing callers to easily give anything as the property value.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 device_tree.c |    2 +-
 device_tree.h |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/device_tree.c b/device_tree.c
index 426a631..21be070 100644
--- a/device_tree.c
+++ b/device_tree.c
@@ -74,7 +74,7 @@ fail:
 }
 
 int qemu_devtree_setprop(void *fdt, const char *node_path,
-                         const char *property, uint32_t *val_array, int size)
+                         const char *property, void *val_array, int size)
 {
     int offset;
 
diff --git a/device_tree.h b/device_tree.h
index f05c4e7..cecd98f 100644
--- a/device_tree.h
+++ b/device_tree.h
@@ -17,7 +17,7 @@
 void *load_device_tree(const char *filename_path, int *sizep);
 
 int qemu_devtree_setprop(void *fdt, const char *node_path,
-                         const char *property, uint32_t *val_array, int size);
+                         const char *property, void *val_array, int size);
 int qemu_devtree_setprop_cell(void *fdt, const char *node_path,
                               const char *property, uint32_t val);
 int qemu_devtree_setprop_string(void *fdt, const char *node_path,
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 04/28] Add a hook to allow hypercalls to be emulated on PowerPC
  2011-02-15  4:56 [Qemu-devel] RFC: Implement emulation of pSeries logical partitions (v2) qemu
                   ` (2 preceding siblings ...)
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 03/28] Allow qemu_devtree_setprop() to take arbitrary values qemu
@ 2011-02-15  4:56 ` qemu
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 05/28] Implement PowerPC slbmfee and slbmfev instructions qemu
                   ` (23 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: qemu @ 2011-02-15  4:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: paulus, agraf, anton

From: David Gibson <dwg@au1.ibm.com>

PowerPC and POWER chips since the POWER4 and 970 have a special
hypervisor mode, and a corresponding form of the system call
instruction which traps to the hypervisor.

qemu currently has stub implementations of hypervisor mode.  That
is, the outline is there to allow qemu to run a PowerPC hypervisor
under emulation.  There are a number of details missing so this
won't actually work at present, but the idea is there.

What there is no provision at all, is for qemu to instead emulate
the hypervisor itself.  That is to have hypercalls trap into qemu
and their result be emulated from qemu, rather than running
hypervisor code within the emulated system.

Hypervisor hardware aware KVM implementations are in the works and
it would  be useful for debugging and development to also allow
full emulation of the same para-virtualized guests as such a KVM.

Therefore, this patch adds a hook which will allow a machine to
set up emulation of hypervisor calls.

Signed-off-by: David Gibson <dwg@au1.ibm.com>
---
 target-ppc/cpu.h    |    2 ++
 target-ppc/helper.c |    4 ++++
 2 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index a20c132..eaddc27 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -692,6 +692,8 @@ struct CPUPPCState {
     int bfd_mach;
     uint32_t flags;
     uint64_t insns_flags;
+    void (*emulate_hypercall)(CPUState *, void *);
+    void *hcall_opaque;
 
     int error_code;
     uint32_t pending_interrupts;
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 2094ca3..19aa067 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -2152,6 +2152,10 @@ static inline void powerpc_excp(CPUState *env, int excp_model, int excp)
     case POWERPC_EXCP_SYSCALL:   /* System call exception                    */
         dump_syscall(env);
         lev = env->error_code;
+	if ((lev == 1) && env->emulate_hypercall) {
+	    env->emulate_hypercall(env, env->hcall_opaque);
+	    return;
+	}	    
         if (lev == 1 || (lpes0 == 0 && lpes1 == 0))
             new_msr |= (target_ulong)MSR_HVB;
         goto store_next;
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 05/28] Implement PowerPC slbmfee and slbmfev instructions
  2011-02-15  4:56 [Qemu-devel] RFC: Implement emulation of pSeries logical partitions (v2) qemu
                   ` (3 preceding siblings ...)
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 04/28] Add a hook to allow hypercalls to be emulated on PowerPC qemu
@ 2011-02-15  4:56 ` qemu
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 06/28] Implement missing parts of the logic for the POWER PURR qemu
                   ` (22 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: qemu @ 2011-02-15  4:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: paulus, agraf, anton

From: David Gibson <dwg@au1.ibm.com>

For a 64-bit PowerPC target, qemu correctly implements translation
through the segment lookaside buffer.  Likewise it supports the
slbmte instruction which is used to load entries into the SLB.

However, it does not emulate the slbmfee and slbmfev instructions
which read SLB entries back into registers.  Because these are
only occasionally used in guests (mostly for debugging) we get
away with it.

However, given the recent SLB cleanups, it becomes quite easy to
implement these, and thereby allow, amongst other things, a guest
Linux to use xmon's command to dump the SLB.

Signed-off-by: David Gibson <dwg@au1.ibm.com>
---
 target-ppc/cpu.h       |    2 ++
 target-ppc/helper.c    |   26 ++++++++++++++++++++++++++
 target-ppc/helper.h    |    2 ++
 target-ppc/op_helper.c |   20 ++++++++++++++++++++
 target-ppc/translate.c |   29 ++++++++++++++++++++++++++++-
 5 files changed, 78 insertions(+), 1 deletions(-)

diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index eaddc27..9a7495a 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -781,6 +781,8 @@ void ppc_store_asr (CPUPPCState *env, target_ulong value);
 target_ulong ppc_load_slb (CPUPPCState *env, int slb_nr);
 target_ulong ppc_load_sr (CPUPPCState *env, int sr_nr);
 int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs);
+int ppc_load_slb_esid (CPUPPCState *env, target_ulong rb, target_ulong *rt);
+int ppc_load_slb_vsid (CPUPPCState *env, target_ulong rb, target_ulong *rt);
 #endif /* defined(TARGET_PPC64) */
 void ppc_store_sr (CPUPPCState *env, int srnum, target_ulong value);
 #endif /* !defined(CONFIG_USER_ONLY) */
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 19aa067..4830981 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -770,6 +770,32 @@ int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs)
 
     return 0;
 }
+
+int ppc_load_slb_esid (CPUPPCState *env, target_ulong rb, target_ulong *rt)
+{
+    int slot = rb & 0xfff;
+    ppc_slb_t *slb = &env->slb[slot];
+
+    if (slot >= env->slb_nr) {
+        return -1;
+    }
+
+    *rt = slb->esid;
+    return 0;
+}
+
+int ppc_load_slb_vsid (CPUPPCState *env, target_ulong rb, target_ulong *rt)
+{
+    int slot = rb & 0xfff;
+    ppc_slb_t *slb = &env->slb[slot];
+
+    if (slot >= env->slb_nr) {
+        return -1;
+    }
+
+    *rt = slb->vsid;
+    return 0;
+}
 #endif /* defined(TARGET_PPC64) */
 
 /* Perform segment based translation */
diff --git a/target-ppc/helper.h b/target-ppc/helper.h
index d512cb0..1a69cf8 100644
--- a/target-ppc/helper.h
+++ b/target-ppc/helper.h
@@ -341,6 +341,8 @@ DEF_HELPER_FLAGS_0(tlbia, TCG_CALL_CONST, void)
 DEF_HELPER_FLAGS_1(tlbie, TCG_CALL_CONST, void, tl)
 #if defined(TARGET_PPC64)
 DEF_HELPER_FLAGS_2(store_slb, TCG_CALL_CONST, void, tl, tl)
+DEF_HELPER_1(load_slb_esid, tl, tl)
+DEF_HELPER_1(load_slb_vsid, tl, tl)
 DEF_HELPER_FLAGS_0(slbia, TCG_CALL_CONST, void)
 DEF_HELPER_FLAGS_1(slbie, TCG_CALL_CONST, void, tl)
 #endif
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index bf41627..bdb1f17 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -3753,6 +3753,26 @@ void helper_store_slb (target_ulong rb, target_ulong rs)
     }
 }
 
+target_ulong helper_load_slb_esid (target_ulong rb)
+{
+    target_ulong rt;
+
+    if (ppc_load_slb_esid(env, rb, &rt) < 0) {
+        helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL);
+    }
+    return rt;
+}
+
+target_ulong helper_load_slb_vsid (target_ulong rb)
+{
+    target_ulong rt;
+
+    if (ppc_load_slb_vsid(env, rb, &rt) < 0) {
+        helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL);
+    }
+    return rt;
+}
+
 void helper_slbia (void)
 {
     ppc_slb_invalidate_all(env);
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 89413c5..2b1a851 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -4227,6 +4227,31 @@ static void gen_slbmte(DisasContext *ctx)
 #endif
 }
 
+static void gen_slbmfee(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+        return;
+    }
+    gen_helper_load_slb_esid(cpu_gpr[rS(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
+#endif
+}
+
+static void gen_slbmfev(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+    gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+#else
+    if (unlikely(!ctx->mem_idx)) {
+        gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+        return;
+    }
+    gen_helper_load_slb_vsid(cpu_gpr[rS(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
+#endif
+}
 #endif /* defined(TARGET_PPC64) */
 
 /***                      Lookaside buffer management                      ***/
@@ -8110,7 +8135,9 @@ GEN_HANDLER2(mfsrin_64b, "mfsrin", 0x1F, 0x13, 0x14, 0x001F0001,
 GEN_HANDLER2(mtsr_64b, "mtsr", 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT_64B),
 GEN_HANDLER2(mtsrin_64b, "mtsrin", 0x1F, 0x12, 0x07, 0x001F0001,
              PPC_SEGMENT_64B),
-GEN_HANDLER2(slbmte, "slbmte", 0x1F, 0x12, 0x0C, 0x00000000, PPC_SEGMENT_64B),
+GEN_HANDLER2(slbmte, "slbmte", 0x1F, 0x12, 0x0C, 0x001F0001, PPC_SEGMENT_64B),
+GEN_HANDLER2(slbmfee, "slbmfee", 0x1F, 0x13, 0x1C, 0x001F0001, PPC_SEGMENT_64B),
+GEN_HANDLER2(slbmfev, "slbmfev", 0x1F, 0x13, 0x1A, 0x001F0001, PPC_SEGMENT_64B),
 #endif
 GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA),
 GEN_HANDLER(tlbiel, 0x1F, 0x12, 0x08, 0x03FF0001, PPC_MEM_TLBIE),
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 06/28] Implement missing parts of the logic for the POWER PURR
  2011-02-15  4:56 [Qemu-devel] RFC: Implement emulation of pSeries logical partitions (v2) qemu
                   ` (4 preceding siblings ...)
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 05/28] Implement PowerPC slbmfee and slbmfev instructions qemu
@ 2011-02-15  4:56 ` qemu
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 07/28] Correct ppc popcntb logic, implement popcntw and popcntd qemu
                   ` (21 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: qemu @ 2011-02-15  4:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: paulus, agraf, anton

From: David Gibson <dwg@au1.ibm.com>

The PURR (Processor Utilization Resource Register) is a register found
on recent POWER CPUs.  The guts of implementing it at least enough to
get by are already present in qemu, however some of the helper
functions needed to actually wire it up are missing.

This patch adds the necessary glue, so that the PURR can be wired up
when we implement newer POWER CPU targets which include it.

Signed-off-by: David Gibson <dwg@au1.ibm.com>
---
 target-ppc/helper.h         |    1 +
 target-ppc/op_helper.c      |    5 +++++
 target-ppc/translate_init.c |    6 ++++++
 3 files changed, 12 insertions(+), 0 deletions(-)

diff --git a/target-ppc/helper.h b/target-ppc/helper.h
index 1a69cf8..4227897 100644
--- a/target-ppc/helper.h
+++ b/target-ppc/helper.h
@@ -371,6 +371,7 @@ DEF_HELPER_0(load_tbl, tl)
 DEF_HELPER_0(load_tbu, tl)
 DEF_HELPER_0(load_atbl, tl)
 DEF_HELPER_0(load_atbu, tl)
+DEF_HELPER_0(load_purr, tl)
 DEF_HELPER_0(load_601_rtcl, tl)
 DEF_HELPER_0(load_601_rtcu, tl)
 #if !defined(CONFIG_USER_ONLY)
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index bdb1f17..b9b5ae2 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -86,6 +86,11 @@ target_ulong helper_load_atbu (void)
     return cpu_ppc_load_atbu(env);
 }
 
+target_ulong helper_load_purr (void)
+{
+    return (target_ulong)cpu_ppc_load_purr(env);
+}
+
 target_ulong helper_load_601_rtcl (void)
 {
     return cpu_ppc601_load_rtcl(env);
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index dfcd949..c842330 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -209,6 +209,12 @@ static void spr_write_atbu (void *opaque, int sprn, int gprn)
 {
     gen_helper_store_atbu(cpu_gpr[gprn]);
 }
+
+__attribute__ (( unused ))
+static void spr_read_purr(void *opaque, int gprn, int sprn)
+{
+    gen_helper_load_purr(cpu_gpr[gprn]);
+}
 #endif
 
 #if !defined(CONFIG_USER_ONLY)
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 07/28] Correct ppc popcntb logic, implement popcntw and popcntd
  2011-02-15  4:56 [Qemu-devel] RFC: Implement emulation of pSeries logical partitions (v2) qemu
                   ` (5 preceding siblings ...)
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 06/28] Implement missing parts of the logic for the POWER PURR qemu
@ 2011-02-15  4:56 ` qemu
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 08/28] Clean up slb_lookup() function qemu
                   ` (20 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: qemu @ 2011-02-15  4:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: paulus, agraf, anton

From: David Gibson <dwg@au1.ibm.com>

qemu already includes support for the popcntb instruction introduced
in POWER5 (although it doesn't actually allow you to choose POWER5).

However, the logic is slightly incorrect: it will generate results
truncated to 32-bits when the CPU is in 32-bit mode.  This is not
normal for powerpc - generally arithmetic instructions on a 64-bit
powerpc cpu will generate full 64 bit results, it's just that only the
low 32 bits will be significant for condition codes.

This patch corrects this nit, which actually simplifies the code slightly.

In addition, this patch implements the popcntw and popcntd
instructions added in POWER7, in preparation for allowing POWER7 as an
emulated CPU.

Signed-off-by: David Gibson <dwg@au1.ibm.com>
---
 target-ppc/cpu.h       |    2 +
 target-ppc/helper.h    |    3 +-
 target-ppc/op_helper.c |   55 +++++++++++++++++++++++++++++++++++++++++++----
 target-ppc/translate.c |   20 +++++++++++++----
 4 files changed, 69 insertions(+), 11 deletions(-)

diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 9a7495a..f9ad3b8 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1507,6 +1507,8 @@ enum {
     PPC_DCRX           = 0x2000000000000000ULL,
     /* user-mode DCR access, implemented in PowerPC 460                      */
     PPC_DCRUX          = 0x4000000000000000ULL,
+    /* popcntw and popcntd instructions                                      */
+    PPC_POPCNTWD       = 0x8000000000000000ULL,
 };
 
 /*****************************************************************************/
diff --git a/target-ppc/helper.h b/target-ppc/helper.h
index 4227897..19c5ebe 100644
--- a/target-ppc/helper.h
+++ b/target-ppc/helper.h
@@ -38,10 +38,11 @@ DEF_HELPER_2(mulldo, i64, i64, i64)
 
 DEF_HELPER_FLAGS_1(cntlzw, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl)
 DEF_HELPER_FLAGS_1(popcntb, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl)
+DEF_HELPER_FLAGS_1(popcntw, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl)
 DEF_HELPER_2(sraw, tl, tl, tl)
 #if defined(TARGET_PPC64)
 DEF_HELPER_FLAGS_1(cntlzd, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl)
-DEF_HELPER_FLAGS_1(popcntb_64, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl)
+DEF_HELPER_FLAGS_1(popcntd, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl)
 DEF_HELPER_2(srad, tl, tl, tl)
 #endif
 
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index b9b5ae2..9dd3217 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -497,6 +497,50 @@ target_ulong helper_srad (target_ulong value, target_ulong shift)
 }
 #endif
 
+#if defined(TARGET_PPC64)
+target_ulong helper_popcntb (target_ulong val)
+{
+    val = (val & 0x5555555555555555ULL) + ((val >>  1) &
+                                           0x5555555555555555ULL);
+    val = (val & 0x3333333333333333ULL) + ((val >>  2) &
+                                           0x3333333333333333ULL);
+    val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >>  4) &
+                                           0x0f0f0f0f0f0f0f0fULL);
+    return val;
+}
+
+target_ulong helper_popcntw (target_ulong val)
+{
+    val = (val & 0x5555555555555555ULL) + ((val >>  1) &
+                                           0x5555555555555555ULL);
+    val = (val & 0x3333333333333333ULL) + ((val >>  2) &
+                                           0x3333333333333333ULL);
+    val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >>  4) &
+                                           0x0f0f0f0f0f0f0f0fULL);
+    val = (val & 0x00ff00ff00ff00ffULL) + ((val >>  8) &
+                                           0x00ff00ff00ff00ffULL);
+    val = (val & 0x0000ffff0000ffffULL) + ((val >> 16) &
+                                           0x0000ffff0000ffffULL);
+    return val;
+}
+
+target_ulong helper_popcntd (target_ulong val)
+{
+    val = (val & 0x5555555555555555ULL) + ((val >>  1) &
+                                           0x5555555555555555ULL);
+    val = (val & 0x3333333333333333ULL) + ((val >>  2) &
+                                           0x3333333333333333ULL);
+    val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >>  4) &
+                                           0x0f0f0f0f0f0f0f0fULL);
+    val = (val & 0x00ff00ff00ff00ffULL) + ((val >>  8) &
+                                           0x00ff00ff00ff00ffULL);
+    val = (val & 0x0000ffff0000ffffULL) + ((val >> 16) &
+                                           0x0000ffff0000ffffULL);
+    val = (val & 0x00000000ffffffffULL) + ((val >> 32) &
+                                           0x00000000ffffffffULL);
+    return val;
+}
+#else
 target_ulong helper_popcntb (target_ulong val)
 {
     val = (val & 0x55555555) + ((val >>  1) & 0x55555555);
@@ -505,12 +549,13 @@ target_ulong helper_popcntb (target_ulong val)
     return val;
 }
 
-#if defined(TARGET_PPC64)
-target_ulong helper_popcntb_64 (target_ulong val)
+target_ulong helper_popcntw (target_ulong val)
 {
-    val = (val & 0x5555555555555555ULL) + ((val >>  1) & 0x5555555555555555ULL);
-    val = (val & 0x3333333333333333ULL) + ((val >>  2) & 0x3333333333333333ULL);
-    val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >>  4) & 0x0f0f0f0f0f0f0f0fULL);
+    val = (val & 0x55555555) + ((val >>  1) & 0x55555555);
+    val = (val & 0x33333333) + ((val >>  2) & 0x33333333);
+    val = (val & 0x0f0f0f0f) + ((val >>  4) & 0x0f0f0f0f);
+    val = (val & 0x00ff00ff) + ((val >>  8) & 0x00ff00ff);
+    val = (val & 0x0000ffff) + ((val >> 16) & 0x0000ffff);
     return val;
 }
 #endif
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 2b1a851..5c28ac3 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -1483,13 +1483,21 @@ static void gen_xoris(DisasContext *ctx)
 /* popcntb : PowerPC 2.03 specification */
 static void gen_popcntb(DisasContext *ctx)
 {
+    gen_helper_popcntb(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
+}
+
+static void gen_popcntw(DisasContext *ctx)
+{
+    gen_helper_popcntw(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
+}
+
 #if defined(TARGET_PPC64)
-    if (ctx->sf_mode)
-        gen_helper_popcntb_64(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
-    else
-#endif
-        gen_helper_popcntb(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
+/* popcntd: PowerPC 2.06 specification */
+static void gen_popcntd(DisasContext *ctx)
+{
+    gen_helper_popcntd(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)]);
 }
+#endif
 
 #if defined(TARGET_PPC64)
 /* extsw & extsw. */
@@ -8034,7 +8042,9 @@ GEN_HANDLER(oris, 0x19, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
 GEN_HANDLER(xori, 0x1A, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
 GEN_HANDLER(xoris, 0x1B, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
 GEN_HANDLER(popcntb, 0x1F, 0x03, 0x03, 0x0000F801, PPC_POPCNTB),
+GEN_HANDLER(popcntw, 0x1F, 0x1A, 0x0b, 0x0000F801, PPC_POPCNTWD),
 #if defined(TARGET_PPC64)
+GEN_HANDLER(popcntd, 0x1F, 0x1A, 0x0F, 0x0000F801, PPC_POPCNTWD),
 GEN_HANDLER(cntlzd, 0x1F, 0x1A, 0x01, 0x00000000, PPC_64B),
 #endif
 GEN_HANDLER(rlwimi, 0x14, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 08/28] Clean up slb_lookup() function
  2011-02-15  4:56 [Qemu-devel] RFC: Implement emulation of pSeries logical partitions (v2) qemu
                   ` (6 preceding siblings ...)
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 07/28] Correct ppc popcntb logic, implement popcntw and popcntd qemu
@ 2011-02-15  4:56 ` qemu
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 09/28] Parse SDR1 on mtspr instead of at translate time qemu
                   ` (19 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: qemu @ 2011-02-15  4:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: paulus, agraf, anton

From: David Gibson <david@gibson.dropbear.id.au>

The slb_lookup() function, used in the ppc translation path returns a
number of slb entry fields in reference parameters.  However, only one
of the two callers of slb_lookup() actually wants this information.

This patch, therefore, makes slb_lookup() return a simple pointer to the
located SLB entry (or NULL), and the caller which needs the fields can
extract them itself.

Signed-off-by: David Gibson <dwg@au1.ibm.com>
---
 target-ppc/helper.c |   45 ++++++++++++++++++---------------------------
 1 files changed, 18 insertions(+), 27 deletions(-)

diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 4830981..73d93ca 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -672,9 +672,7 @@ static inline int find_pte(CPUState *env, mmu_ctx_t *ctx, int h, int rw,
 }
 
 #if defined(TARGET_PPC64)
-static inline int slb_lookup(CPUPPCState *env, target_ulong eaddr,
-                             target_ulong *vsid, target_ulong *page_mask,
-                             int *attr, int *target_page_bits)
+static inline ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr)
 {
     uint64_t esid;
     int n;
@@ -689,19 +687,11 @@ static inline int slb_lookup(CPUPPCState *env, target_ulong eaddr,
         LOG_SLB("%s: slot %d %016" PRIx64 " %016"
                     PRIx64 "\n", __func__, n, slb->esid, slb->vsid);
         if (slb->esid == esid) {
-            *vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT;
-            *page_mask = ~SEGMENT_MASK_256M;
-            *attr = slb->vsid & SLB_VSID_ATTR;
-            if (target_page_bits) {
-                *target_page_bits = (slb->vsid & SLB_VSID_L)
-                    ? TARGET_PAGE_BITS_16M
-                    : TARGET_PAGE_BITS;
-            }
-            return n;
+            return slb;
         }
     }
 
-    return -5;
+    return NULL;
 }
 
 void ppc_slb_invalidate_all (CPUPPCState *env)
@@ -728,18 +718,13 @@ void ppc_slb_invalidate_all (CPUPPCState *env)
 
 void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0)
 {
-    target_ulong vsid, page_mask;
-    int attr;
-    int n;
     ppc_slb_t *slb;
 
-    n = slb_lookup(env, T0, &vsid, &page_mask, &attr, NULL);
-    if (n < 0) {
+    slb = slb_lookup(env, T0);
+    if (!slb) {
         return;
     }
 
-    slb = &env->slb[n];
-
     if (slb->esid & SLB_ESID_V) {
         slb->esid &= ~SLB_ESID_V;
 
@@ -818,16 +803,22 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx,
     pr = msr_pr;
 #if defined(TARGET_PPC64)
     if (env->mmu_model & POWERPC_MMU_64) {
-        int attr;
+        ppc_slb_t *slb;
 
         LOG_MMU("Check SLBs\n");
-        ret = slb_lookup(env, eaddr, &vsid, &page_mask, &attr,
-                         &target_page_bits);
-        if (ret < 0)
-            return ret;
-        ctx->key = !!(pr ? (attr & SLB_VSID_KP) : (attr & SLB_VSID_KS));
+        slb = slb_lookup(env, eaddr);
+        if (!slb) {
+            return -5;
+        }
+
+        vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT;
+        page_mask = ~SEGMENT_MASK_256M;
+        target_page_bits = (slb->vsid & SLB_VSID_L)
+            ? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS;
+        ctx->key = !!(pr ? (slb->vsid & SLB_VSID_KP)
+                      : (slb->vsid & SLB_VSID_KS));
         ds = 0;
-        ctx->nx = !!(attr & SLB_VSID_N);
+        ctx->nx = !!(slb->vsid & SLB_VSID_N);
         ctx->eaddr = eaddr;
         vsid_mask = 0x00003FFFFFFFFF80ULL;
         vsid_sh = 7;
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 09/28] Parse SDR1 on mtspr instead of at translate time
  2011-02-15  4:56 [Qemu-devel] RFC: Implement emulation of pSeries logical partitions (v2) qemu
                   ` (7 preceding siblings ...)
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 08/28] Clean up slb_lookup() function qemu
@ 2011-02-15  4:56 ` qemu
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 10/28] Use "hash" more consistently in ppc mmu code qemu
                   ` (18 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: qemu @ 2011-02-15  4:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: paulus, agraf, anton

From: David Gibson <david@gibson.dropbear.id.au>

On ppc machines with hash table MMUs, the special purpose register SDR1
contains both the base address of the encoded size (hashed) page tables.

At present, we interpret the SDR1 value within the address translation
path.  But because the encodings of the size for 32-bit and 64-bit are
different this makes for a confusing branch on the MMU type with a bunch
of curly shifts and masks in the middle of the translate path.

This patch cleans things up by moving the interpretation on SDR1 into the
helper function handling the write to the register.  This leaves a simple
pre-sanitized base address and mask for the hash table in the CPUState
structure which is easier to work with in the translation path.

This makes the translation path more readable.  It addresses the FIXME
comment currently in the mtsdr1 helper, by validating the SDR1 value during
interpretation.  Finally it opens the way for emulating a pSeries-style
partition where the hash table used for translation is not mapped into
the guests's RAM.

Signed-off-by: David Gibson <dwg@au1.ibm.com>
---
 monitor.c                   |    2 +-
 target-ppc/cpu.h            |   11 +++++-
 target-ppc/helper.c         |   79 ++++++++++++++++++++++++-------------------
 target-ppc/machine.c        |    6 ++-
 target-ppc/translate.c      |    2 +-
 target-ppc/translate_init.c |    7 +---
 6 files changed, 61 insertions(+), 46 deletions(-)

diff --git a/monitor.c b/monitor.c
index 7fc311d..3f77ffc 100644
--- a/monitor.c
+++ b/monitor.c
@@ -3457,7 +3457,7 @@ static const MonitorDef monitor_defs[] = {
     { "asr", offsetof(CPUState, asr) },
 #endif
     /* Segment registers */
-    { "sdr1", offsetof(CPUState, sdr1) },
+    { "sdr1", offsetof(CPUState, spr[SPR_SDR1]) },
     { "sr0", offsetof(CPUState, sr[0]) },
     { "sr1", offsetof(CPUState, sr[1]) },
     { "sr2", offsetof(CPUState, sr[2]) },
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index f9ad3b8..42d0973 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -359,6 +359,14 @@ union ppc_tlb_t {
 };
 #endif
 
+#define SDR_32_HTABORG         0xFFFF0000UL
+#define SDR_32_HTABMASK        0x000001FFUL
+
+#if defined(TARGET_PPC64)
+#define SDR_64_HTABORG         0xFFFFFFFFFFFC0000ULL
+#define SDR_64_HTABSIZE        0x000000000000001FULL
+#endif /* defined(TARGET_PPC64 */
+
 typedef struct ppc_slb_t ppc_slb_t;
 struct ppc_slb_t {
     uint64_t esid;
@@ -642,7 +650,8 @@ struct CPUPPCState {
     int slb_nr;
 #endif
     /* segment registers */
-    target_ulong sdr1;
+    target_phys_addr_t htab_base;
+    target_phys_addr_t htab_mask;
     target_ulong sr[32];
     /* BATs */
     int nb_BATs;
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 73d93ca..df90722 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -784,20 +784,19 @@ int ppc_load_slb_vsid (CPUPPCState *env, target_ulong rb, target_ulong *rt)
 #endif /* defined(TARGET_PPC64) */
 
 /* Perform segment based translation */
-static inline target_phys_addr_t get_pgaddr(target_phys_addr_t sdr1,
-                                            int sdr_sh,
-                                            target_phys_addr_t hash,
-                                            target_phys_addr_t mask)
+static inline target_phys_addr_t get_pgaddr(target_phys_addr_t htab_base,
+                                            target_phys_addr_t htab_mask,
+                                            target_phys_addr_t hash)
 {
-    return (sdr1 & ((target_phys_addr_t)(-1ULL) << sdr_sh)) | (hash & mask);
+    return htab_base | (hash & htab_mask);
 }
 
 static inline int get_segment(CPUState *env, mmu_ctx_t *ctx,
                               target_ulong eaddr, int rw, int type)
 {
-    target_phys_addr_t sdr, hash, mask, sdr_mask, htab_mask;
+    target_phys_addr_t hash;
     target_ulong sr, vsid, vsid_mask, pgidx, page_mask;
-    int ds, vsid_sh, sdr_sh, pr, target_page_bits;
+    int ds, vsid_sh, pr, target_page_bits;
     int ret, ret2;
 
     pr = msr_pr;
@@ -822,8 +821,6 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx,
         ctx->eaddr = eaddr;
         vsid_mask = 0x00003FFFFFFFFF80ULL;
         vsid_sh = 7;
-        sdr_sh = 18;
-        sdr_mask = 0x3FF80;
     } else
 #endif /* defined(TARGET_PPC64) */
     {
@@ -836,8 +833,6 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx,
         vsid = sr & 0x00FFFFFF;
         vsid_mask = 0x01FFFFC0;
         vsid_sh = 6;
-        sdr_sh = 16;
-        sdr_mask = 0xFFC0;
         target_page_bits = TARGET_PAGE_BITS;
         LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip="
                 TARGET_FMT_lx " lr=" TARGET_FMT_lx
@@ -853,29 +848,26 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx,
         if (type != ACCESS_CODE || ctx->nx == 0) {
             /* Page address translation */
             /* Primary table address */
-            sdr = env->sdr1;
             pgidx = (eaddr & page_mask) >> target_page_bits;
 #if defined(TARGET_PPC64)
             if (env->mmu_model & POWERPC_MMU_64) {
-                htab_mask = 0x0FFFFFFF >> (28 - (sdr & 0x1F));
                 /* XXX: this is false for 1 TB segments */
                 hash = ((vsid ^ pgidx) << vsid_sh) & vsid_mask;
             } else
 #endif
             {
-                htab_mask = sdr & 0x000001FF;
                 hash = ((vsid ^ pgidx) << vsid_sh) & vsid_mask;
             }
-            mask = (htab_mask << sdr_sh) | sdr_mask;
-            LOG_MMU("sdr " TARGET_FMT_plx " sh %d hash " TARGET_FMT_plx
-                    " mask " TARGET_FMT_plx " " TARGET_FMT_lx "\n",
-                    sdr, sdr_sh, hash, mask, page_mask);
-            ctx->pg_addr[0] = get_pgaddr(sdr, sdr_sh, hash, mask);
+            LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
+                    " hash " TARGET_FMT_plx "\n",
+                    env->htab_base, env->htab_mask, hash);
+            ctx->pg_addr[0] = get_pgaddr(env->htab_base, env->htab_mask, hash);
             /* Secondary table address */
             hash = (~hash) & vsid_mask;
-            LOG_MMU("sdr " TARGET_FMT_plx " sh %d hash " TARGET_FMT_plx
-                    " mask " TARGET_FMT_plx "\n", sdr, sdr_sh, hash, mask);
-            ctx->pg_addr[1] = get_pgaddr(sdr, sdr_sh, hash, mask);
+            LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
+                    " hash " TARGET_FMT_plx "\n",
+                    env->htab_base, env->htab_mask, hash);
+            ctx->pg_addr[1] = get_pgaddr(env->htab_base, env->htab_mask, hash);
 #if defined(TARGET_PPC64)
             if (env->mmu_model & POWERPC_MMU_64) {
                 /* Only 5 bits of the page index are used in the AVPN */
@@ -897,19 +889,21 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx,
                 /* Software TLB search */
                 ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
             } else {
-                LOG_MMU("0 sdr1=" TARGET_FMT_plx " vsid=" TARGET_FMT_lx " "
-                        "api=" TARGET_FMT_lx " hash=" TARGET_FMT_plx
-                        " pg_addr=" TARGET_FMT_plx "\n",
-                        sdr, vsid, pgidx, hash, ctx->pg_addr[0]);
+                LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
+                        " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
+                        " hash=" TARGET_FMT_plx " pg_addr=" TARGET_FMT_plx "\n",
+                        env->htab_base, env->htab_mask, vsid, pgidx, hash,
+                        ctx->pg_addr[0]);
                 /* Primary table lookup */
                 ret = find_pte(env, ctx, 0, rw, type, target_page_bits);
                 if (ret < 0) {
                     /* Secondary table lookup */
                     if (eaddr != 0xEFFFFFFF)
-                        LOG_MMU("1 sdr1=" TARGET_FMT_plx " vsid=" TARGET_FMT_lx " "
-                                "api=" TARGET_FMT_lx " hash=" TARGET_FMT_plx
-                                " pg_addr=" TARGET_FMT_plx "\n", sdr, vsid,
-                                pgidx, hash, ctx->pg_addr[1]);
+                        LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
+                                " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
+                                " hash=" TARGET_FMT_plx " pg_addr=" TARGET_FMT_plx "\n",
+                                env->htab_base, env->htab_mask, vsid, pgidx, hash,
+                                ctx->pg_addr[1]);
                     ret2 = find_pte(env, ctx, 1, rw, type,
                                     target_page_bits);
                     if (ret2 != -1)
@@ -1915,11 +1909,26 @@ void ppc_store_asr (CPUPPCState *env, target_ulong value)
 void ppc_store_sdr1 (CPUPPCState *env, target_ulong value)
 {
     LOG_MMU("%s: " TARGET_FMT_lx "\n", __func__, value);
-    if (env->sdr1 != value) {
-        /* XXX: for PowerPC 64, should check that the HTABSIZE value
-         *      is <= 28
-         */
-        env->sdr1 = value;
+    if (env->spr[SPR_SDR1] != value) {
+        env->spr[SPR_SDR1] = value;
+#if defined(TARGET_PPC64)
+        if (env->mmu_model & POWERPC_MMU_64) {
+            target_ulong htabsize = value & SDR_64_HTABSIZE;
+
+            if (htabsize > 28) {
+                fprintf(stderr, "Invalid HTABSIZE 0x" TARGET_FMT_lx
+                        " stored in SDR1\n", htabsize);
+                htabsize = 28;
+            }
+            env->htab_mask = (1ULL << (htabsize + 18)) - 1;
+            env->htab_base = value & SDR_64_HTABORG;
+        } else
+#endif /* defined(TARGET_PPC64) */
+        {
+            /* FIXME: Should check for valid HTABMASK values */
+            env->htab_mask = ((value & SDR_32_HTABMASK) << 16) | 0xFFFF;
+            env->htab_base = value & SDR_32_HTABORG;
+        }
         tlb_flush(env, 1);
     }
 }
diff --git a/target-ppc/machine.c b/target-ppc/machine.c
index 67de951..0c1986e 100644
--- a/target-ppc/machine.c
+++ b/target-ppc/machine.c
@@ -37,7 +37,7 @@ void cpu_save(QEMUFile *f, void *opaque)
     qemu_put_betls(f, &env->asr);
     qemu_put_sbe32s(f, &env->slb_nr);
 #endif
-    qemu_put_betls(f, &env->sdr1);
+    qemu_put_betls(f, &env->spr[SPR_SDR1]);
     for (i = 0; i < 32; i++)
         qemu_put_betls(f, &env->sr[i]);
     for (i = 0; i < 2; i++)
@@ -93,6 +93,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
 {
     CPUState *env = (CPUState *)opaque;
     unsigned int i, j;
+    target_ulong sdr1;
 
     for (i = 0; i < 32; i++)
         qemu_get_betls(f, &env->gpr[i]);
@@ -124,7 +125,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
     qemu_get_betls(f, &env->asr);
     qemu_get_sbe32s(f, &env->slb_nr);
 #endif
-    qemu_get_betls(f, &env->sdr1);
+    qemu_get_betls(f, &sdr1);
     for (i = 0; i < 32; i++)
         qemu_get_betls(f, &env->sr[i]);
     for (i = 0; i < 2; i++)
@@ -152,6 +153,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
 #endif
     for (i = 0; i < 1024; i++)
         qemu_get_betls(f, &env->spr[i]);
+    ppc_store_sdr1(env, sdr1);
     qemu_get_be32s(f, &env->vscr);
     qemu_get_be64s(f, &env->spe_acc);
     qemu_get_be32s(f, &env->spe_fscr);
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 5c28ac3..561b756 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -8930,7 +8930,7 @@ void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf,
 #if !defined(CONFIG_USER_ONLY)
     cpu_fprintf(f, "SRR0 " TARGET_FMT_lx " SRR1 " TARGET_FMT_lx " SDR1 "
                 TARGET_FMT_lx "\n", env->spr[SPR_SRR0], env->spr[SPR_SRR1],
-                env->sdr1);
+                env->spr[SPR_SDR1]);
 #endif
 
 #undef RGPL
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index c842330..c84581e 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -299,11 +299,6 @@ static void spr_write_dbatl_h (void *opaque, int sprn, int gprn)
 }
 
 /* SDR1 */
-static void spr_read_sdr1 (void *opaque, int gprn, int sprn)
-{
-    tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env, offsetof(CPUState, sdr1));
-}
-
 static void spr_write_sdr1 (void *opaque, int sprn, int gprn)
 {
     gen_helper_store_sdr1(cpu_gpr[gprn]);
@@ -627,7 +622,7 @@ static void gen_spr_ne_601 (CPUPPCState *env)
     /* Memory management */
     spr_register(env, SPR_SDR1, "SDR1",
                  SPR_NOACCESS, SPR_NOACCESS,
-                 &spr_read_sdr1, &spr_write_sdr1,
+                 &spr_read_generic, &spr_write_sdr1,
                  0x00000000);
 }
 
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 10/28] Use "hash" more consistently in ppc mmu code
  2011-02-15  4:56 [Qemu-devel] RFC: Implement emulation of pSeries logical partitions (v2) qemu
                   ` (8 preceding siblings ...)
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 09/28] Parse SDR1 on mtspr instead of at translate time qemu
@ 2011-02-15  4:56 ` qemu
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 11/28] Better factor the ppc hash translation path qemu
                   ` (17 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: qemu @ 2011-02-15  4:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: paulus, agraf, anton

From: David Gibson <david@gibson.dropbear.id.au>

Currently, get_segment() has a variable called hash.  However it doesn't
(quite) get the hash value for the ppc hashed page table.  Instead it
gets the hash shifted - effectively the offset of the hash bucket within
the hash page table.

As well, as being different to the normal use of plain "hash" in the
architecture documentation, this usage necessitates some awkward 32/64
dependent masks and shifts which clutter up the path in get_segment().

This patch alters the code to use raw hash values through get_segment()
including storing raw hashes instead of pte group offsets in the ctx
structure.  This cleans up the path noticeably.

This does necessitate 32/64 dependent shifts when the hash values are
taken out of the ctx structure and used, but those paths already have
32/64 bit variants so this is less awkward than it was in get_segment().

Signed-off-by: David Gibson <dwg@au1.ibm.com>
---
 target-ppc/cpu.h    |    5 ++-
 target-ppc/helper.c |   99 ++++++++++++++++++++++++--------------------------
 2 files changed, 52 insertions(+), 52 deletions(-)

diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 42d0973..592907a 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -367,6 +367,9 @@ union ppc_tlb_t {
 #define SDR_64_HTABSIZE        0x000000000000001FULL
 #endif /* defined(TARGET_PPC64 */
 
+#define HASH_PTE_SIZE_32       8
+#define HASH_PTE_SIZE_64       16
+
 typedef struct ppc_slb_t ppc_slb_t;
 struct ppc_slb_t {
     uint64_t esid;
@@ -746,7 +749,7 @@ struct mmu_ctx_t {
     target_phys_addr_t raddr;      /* Real address              */
     target_phys_addr_t eaddr;      /* Effective address         */
     int prot;                      /* Protection bits           */
-    target_phys_addr_t pg_addr[2]; /* PTE tables base addresses */
+    target_phys_addr_t hash[2];    /* Pagetable hash values     */
     target_ulong ptem;             /* Virtual segment ID | API  */
     int key;                       /* Access key                */
     int nx;                        /* Non-execute area          */
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index df90722..b9438b2 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -563,21 +563,30 @@ static inline int get_bat(CPUState *env, mmu_ctx_t *ctx, target_ulong virtual,
     return ret;
 }
 
+static inline target_phys_addr_t get_pteg_offset(CPUState *env,
+                                                 target_phys_addr_t hash,
+                                                 int pte_size)
+{
+    return (hash * pte_size * 8) & env->htab_mask;
+}
+
 /* PTE table lookup */
-static inline int _find_pte(mmu_ctx_t *ctx, int is_64b, int h, int rw,
-                            int type, int target_page_bits)
+static inline int _find_pte(CPUState *env, mmu_ctx_t *ctx, int is_64b, int h,
+                            int rw, int type, int target_page_bits)
 {
-    target_ulong base, pte0, pte1;
+    target_phys_addr_t pteg_off;
+    target_ulong pte0, pte1;
     int i, good = -1;
     int ret, r;
 
     ret = -1; /* No entry found */
-    base = ctx->pg_addr[h];
+    pteg_off = get_pteg_offset(env, ctx->hash[h],
+                               is_64b ? HASH_PTE_SIZE_64 : HASH_PTE_SIZE_32);
     for (i = 0; i < 8; i++) {
 #if defined(TARGET_PPC64)
         if (is_64b) {
-            pte0 = ldq_phys(base + (i * 16));
-            pte1 = ldq_phys(base + (i * 16) + 8);
+            pte0 = ldq_phys(env->htab_base + pteg_off + (i * 16));
+            pte1 = ldq_phys(env->htab_base + pteg_off + (i * 16) + 8);
 
             /* We have a TLB that saves 4K pages, so let's
              * split a huge page to 4k chunks */
@@ -588,17 +597,17 @@ static inline int _find_pte(mmu_ctx_t *ctx, int is_64b, int h, int rw,
             r = pte64_check(ctx, pte0, pte1, h, rw, type);
             LOG_MMU("Load pte from " TARGET_FMT_lx " => " TARGET_FMT_lx " "
                     TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n",
-                    base + (i * 16), pte0, pte1, (int)(pte0 & 1), h,
+                    pteg_base + (i * 16), pte0, pte1, (int)(pte0 & 1), h,
                     (int)((pte0 >> 1) & 1), ctx->ptem);
         } else
 #endif
         {
-            pte0 = ldl_phys(base + (i * 8));
-            pte1 =  ldl_phys(base + (i * 8) + 4);
+            pte0 = ldl_phys(env->htab_base + pteg_off + (i * 8));
+            pte1 =  ldl_phys(env->htab_base + pteg_off + (i * 8) + 4);
             r = pte32_check(ctx, pte0, pte1, h, rw, type);
             LOG_MMU("Load pte from " TARGET_FMT_lx " => " TARGET_FMT_lx " "
                     TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n",
-                    base + (i * 8), pte0, pte1, (int)(pte0 >> 31), h,
+                    pteg_base + (i * 8), pte0, pte1, (int)(pte0 >> 31), h,
                     (int)((pte0 >> 6) & 1), ctx->ptem);
         }
         switch (r) {
@@ -634,11 +643,13 @@ static inline int _find_pte(mmu_ctx_t *ctx, int is_64b, int h, int rw,
         if (pte_update_flags(ctx, &pte1, ret, rw) == 1) {
 #if defined(TARGET_PPC64)
             if (is_64b) {
-                stq_phys_notdirty(base + (good * 16) + 8, pte1);
+                stq_phys_notdirty(env->htab_base + pteg_off + (good * 16) + 8,
+                                  pte1);
             } else
 #endif
             {
-                stl_phys_notdirty(base + (good * 8) + 4, pte1);
+                stl_phys_notdirty(env->htab_base + pteg_off + (good * 8) + 4,
+                                  pte1);
             }
         }
     }
@@ -646,17 +657,17 @@ static inline int _find_pte(mmu_ctx_t *ctx, int is_64b, int h, int rw,
     return ret;
 }
 
-static inline int find_pte32(mmu_ctx_t *ctx, int h, int rw, int type,
-                             int target_page_bits)
+static inline int find_pte32(CPUState *env, mmu_ctx_t *ctx, int h, int rw,
+                             int type, int target_page_bits)
 {
-    return _find_pte(ctx, 0, h, rw, type, target_page_bits);
+    return _find_pte(env, ctx, 0, h, rw, type, target_page_bits);
 }
 
 #if defined(TARGET_PPC64)
-static inline int find_pte64(mmu_ctx_t *ctx, int h, int rw, int type,
-                             int target_page_bits)
+static inline int find_pte64(CPUState *env, mmu_ctx_t *ctx, int h, int rw,
+                             int type, int target_page_bits)
 {
-    return _find_pte(ctx, 1, h, rw, type, target_page_bits);
+    return _find_pte(env, ctx, 1, h, rw, type, target_page_bits);
 }
 #endif
 
@@ -665,10 +676,10 @@ static inline int find_pte(CPUState *env, mmu_ctx_t *ctx, int h, int rw,
 {
 #if defined(TARGET_PPC64)
     if (env->mmu_model & POWERPC_MMU_64)
-        return find_pte64(ctx, h, rw, type, target_page_bits);
+        return find_pte64(env, ctx, h, rw, type, target_page_bits);
 #endif
 
-    return find_pte32(ctx, h, rw, type, target_page_bits);
+    return find_pte32(env, ctx, h, rw, type, target_page_bits);
 }
 
 #if defined(TARGET_PPC64)
@@ -784,19 +795,12 @@ int ppc_load_slb_vsid (CPUPPCState *env, target_ulong rb, target_ulong *rt)
 #endif /* defined(TARGET_PPC64) */
 
 /* Perform segment based translation */
-static inline target_phys_addr_t get_pgaddr(target_phys_addr_t htab_base,
-                                            target_phys_addr_t htab_mask,
-                                            target_phys_addr_t hash)
-{
-    return htab_base | (hash & htab_mask);
-}
-
 static inline int get_segment(CPUState *env, mmu_ctx_t *ctx,
                               target_ulong eaddr, int rw, int type)
 {
     target_phys_addr_t hash;
-    target_ulong sr, vsid, vsid_mask, pgidx, page_mask;
-    int ds, vsid_sh, pr, target_page_bits;
+    target_ulong sr, vsid, pgidx, page_mask;
+    int ds, pr, target_page_bits;
     int ret, ret2;
 
     pr = msr_pr;
@@ -819,8 +823,6 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx,
         ds = 0;
         ctx->nx = !!(slb->vsid & SLB_VSID_N);
         ctx->eaddr = eaddr;
-        vsid_mask = 0x00003FFFFFFFFF80ULL;
-        vsid_sh = 7;
     } else
 #endif /* defined(TARGET_PPC64) */
     {
@@ -831,8 +833,6 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx,
         ds = sr & 0x80000000 ? 1 : 0;
         ctx->nx = sr & 0x10000000 ? 1 : 0;
         vsid = sr & 0x00FFFFFF;
-        vsid_mask = 0x01FFFFC0;
-        vsid_sh = 6;
         target_page_bits = TARGET_PAGE_BITS;
         LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip="
                 TARGET_FMT_lx " lr=" TARGET_FMT_lx
@@ -847,27 +847,22 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx,
         /* Check if instruction fetch is allowed, if needed */
         if (type != ACCESS_CODE || ctx->nx == 0) {
             /* Page address translation */
-            /* Primary table address */
             pgidx = (eaddr & page_mask) >> target_page_bits;
 #if defined(TARGET_PPC64)
             if (env->mmu_model & POWERPC_MMU_64) {
                 /* XXX: this is false for 1 TB segments */
-                hash = ((vsid ^ pgidx) << vsid_sh) & vsid_mask;
+                hash = vsid ^ pgidx;
             } else
 #endif
             {
-                hash = ((vsid ^ pgidx) << vsid_sh) & vsid_mask;
+                hash = vsid ^ pgidx;
             }
             LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
                     " hash " TARGET_FMT_plx "\n",
                     env->htab_base, env->htab_mask, hash);
-            ctx->pg_addr[0] = get_pgaddr(env->htab_base, env->htab_mask, hash);
-            /* Secondary table address */
-            hash = (~hash) & vsid_mask;
-            LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
-                    " hash " TARGET_FMT_plx "\n",
-                    env->htab_base, env->htab_mask, hash);
-            ctx->pg_addr[1] = get_pgaddr(env->htab_base, env->htab_mask, hash);
+            ctx->hash[0] = hash;
+            ctx->hash[1] = ~hash;
+
 #if defined(TARGET_PPC64)
             if (env->mmu_model & POWERPC_MMU_64) {
                 /* Only 5 bits of the page index are used in the AVPN */
@@ -891,9 +886,9 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx,
             } else {
                 LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
                         " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
-                        " hash=" TARGET_FMT_plx " pg_addr=" TARGET_FMT_plx "\n",
-                        env->htab_base, env->htab_mask, vsid, pgidx, hash,
-                        ctx->pg_addr[0]);
+                        " hash=" TARGET_FMT_plx "\n",
+                        env->htab_base, env->htab_mask, vsid, pgidx,
+                        ctx->hash[0]);
                 /* Primary table lookup */
                 ret = find_pte(env, ctx, 0, rw, type, target_page_bits);
                 if (ret < 0) {
@@ -901,9 +896,9 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx,
                     if (eaddr != 0xEFFFFFFF)
                         LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
                                 " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
-                                " hash=" TARGET_FMT_plx " pg_addr=" TARGET_FMT_plx "\n",
-                                env->htab_base, env->htab_mask, vsid, pgidx, hash,
-                                ctx->pg_addr[1]);
+                                " hash=" TARGET_FMT_plx "\n",
+                                env->htab_base, env->htab_mask, vsid, pgidx,
+                                ctx->hash[1]);
                     ret2 = find_pte(env, ctx, 1, rw, type,
                                     target_page_bits);
                     if (ret2 != -1)
@@ -1455,8 +1450,10 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
                     env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
                 tlb_miss:
                     env->error_code |= ctx.key << 19;
-                    env->spr[SPR_HASH1] = ctx.pg_addr[0];
-                    env->spr[SPR_HASH2] = ctx.pg_addr[1];
+                    env->spr[SPR_HASH1] = env->htab_base +
+                        get_pteg_offset(env, ctx.hash[0], HASH_PTE_SIZE_32);
+                    env->spr[SPR_HASH2] = env->htab_base +
+                        get_pteg_offset(env, ctx.hash[1], HASH_PTE_SIZE_32);
                     break;
                 case POWERPC_MMU_SOFT_74xx:
                     if (rw == 1) {
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 11/28] Better factor the ppc hash translation path
  2011-02-15  4:56 [Qemu-devel] RFC: Implement emulation of pSeries logical partitions (v2) qemu
                   ` (9 preceding siblings ...)
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 10/28] Use "hash" more consistently in ppc mmu code qemu
@ 2011-02-15  4:56 ` qemu
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 12/28] Support 1T segments on ppc qemu
                   ` (16 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: qemu @ 2011-02-15  4:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: paulus, agraf, anton

From: David Gibson <david@gibson.dropbear.id.au>

Currently the path handling hash page table translation in get_segment()
has a mix of common and 32 or 64 bit specific code.  However the
division is not done terribly well which results in a lot of messy code
flipping between common and divided paths.

This patch improves the organization, consolidating several divided paths
into one.  This in turn allows simplification of some code in
get_segment(), removing a number of ugly interim variables.

This new factorization will also make it easier to add support for the 1T
segments added in newer CPUs.

Signed-off-by: David Gibson <dwg@au1.ibm.com>
---
 target-ppc/cpu.h    |    1 +
 target-ppc/helper.c |   68 +++++++++++++++------------------------------------
 2 files changed, 21 insertions(+), 48 deletions(-)

diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 592907a..71f8d72 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -386,6 +386,7 @@ struct ppc_slb_t {
 #define SLB_VSID_B              0xc000000000000000ULL
 #define SLB_VSID_B_256M         0x0000000000000000ULL
 #define SLB_VSID_VSID           0x3FFFFFFFFFFFF000ULL
+#define SLB_VSID_PTEM           (SLB_VSID_B | SLB_VSID_VSID)
 #define SLB_VSID_KS             0x0000000000000800ULL
 #define SLB_VSID_KP             0x0000000000000400ULL
 #define SLB_VSID_N              0x0000000000000200ULL /* no-execute */
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index b9438b2..111675d 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -657,29 +657,15 @@ static inline int _find_pte(CPUState *env, mmu_ctx_t *ctx, int is_64b, int h,
     return ret;
 }
 
-static inline int find_pte32(CPUState *env, mmu_ctx_t *ctx, int h, int rw,
-                             int type, int target_page_bits)
-{
-    return _find_pte(env, ctx, 0, h, rw, type, target_page_bits);
-}
-
-#if defined(TARGET_PPC64)
-static inline int find_pte64(CPUState *env, mmu_ctx_t *ctx, int h, int rw,
-                             int type, int target_page_bits)
-{
-    return _find_pte(env, ctx, 1, h, rw, type, target_page_bits);
-}
-#endif
-
 static inline int find_pte(CPUState *env, mmu_ctx_t *ctx, int h, int rw,
                            int type, int target_page_bits)
 {
 #if defined(TARGET_PPC64)
     if (env->mmu_model & POWERPC_MMU_64)
-        return find_pte64(env, ctx, h, rw, type, target_page_bits);
+        return _find_pte(env, ctx, 1, h, rw, type, target_page_bits);
 #endif
 
-    return find_pte32(env, ctx, h, rw, type, target_page_bits);
+    return _find_pte(env, ctx, 0, h, rw, type, target_page_bits);
 }
 
 #if defined(TARGET_PPC64)
@@ -799,14 +785,16 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx,
                               target_ulong eaddr, int rw, int type)
 {
     target_phys_addr_t hash;
-    target_ulong sr, vsid, pgidx, page_mask;
+    target_ulong vsid;
     int ds, pr, target_page_bits;
     int ret, ret2;
 
     pr = msr_pr;
+    ctx->eaddr = eaddr;
 #if defined(TARGET_PPC64)
     if (env->mmu_model & POWERPC_MMU_64) {
         ppc_slb_t *slb;
+        target_ulong pageaddr;
 
         LOG_MMU("Check SLBs\n");
         slb = slb_lookup(env, eaddr);
@@ -815,19 +803,24 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx,
         }
 
         vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT;
-        page_mask = ~SEGMENT_MASK_256M;
         target_page_bits = (slb->vsid & SLB_VSID_L)
             ? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS;
         ctx->key = !!(pr ? (slb->vsid & SLB_VSID_KP)
                       : (slb->vsid & SLB_VSID_KS));
         ds = 0;
         ctx->nx = !!(slb->vsid & SLB_VSID_N);
-        ctx->eaddr = eaddr;
+
+        pageaddr = eaddr & ((1ULL << 28) - (1ULL << target_page_bits));
+        /* XXX: this is false for 1 TB segments */
+        hash = vsid ^ (pageaddr >> target_page_bits);
+        /* Only 5 bits of the page index are used in the AVPN */
+        ctx->ptem = (slb->vsid & SLB_VSID_PTEM) | ((pageaddr >> 16) & 0x0F80);
     } else
 #endif /* defined(TARGET_PPC64) */
     {
+        target_ulong sr, pgidx;
+
         sr = env->sr[eaddr >> 28];
-        page_mask = 0x0FFFFFFF;
         ctx->key = (((sr & 0x20000000) && (pr != 0)) ||
                     ((sr & 0x40000000) && (pr == 0))) ? 1 : 0;
         ds = sr & 0x80000000 ? 1 : 0;
@@ -839,6 +832,9 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx,
                 " ir=%d dr=%d pr=%d %d t=%d\n",
                 eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir,
                 (int)msr_dr, pr != 0 ? 1 : 0, rw, type);
+        pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
+        hash = vsid ^ pgidx;
+        ctx->ptem = (vsid << 7) | (pgidx >> 10);
     }
     LOG_MMU("pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n",
             ctx->key, ds, ctx->nx, vsid);
@@ -847,36 +843,12 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx,
         /* Check if instruction fetch is allowed, if needed */
         if (type != ACCESS_CODE || ctx->nx == 0) {
             /* Page address translation */
-            pgidx = (eaddr & page_mask) >> target_page_bits;
-#if defined(TARGET_PPC64)
-            if (env->mmu_model & POWERPC_MMU_64) {
-                /* XXX: this is false for 1 TB segments */
-                hash = vsid ^ pgidx;
-            } else
-#endif
-            {
-                hash = vsid ^ pgidx;
-            }
             LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
                     " hash " TARGET_FMT_plx "\n",
                     env->htab_base, env->htab_mask, hash);
             ctx->hash[0] = hash;
             ctx->hash[1] = ~hash;
 
-#if defined(TARGET_PPC64)
-            if (env->mmu_model & POWERPC_MMU_64) {
-                /* Only 5 bits of the page index are used in the AVPN */
-                if (target_page_bits > 23) {
-                    ctx->ptem = (vsid << 12) |
-                                ((pgidx << (target_page_bits - 16)) & 0xF80);
-                } else {
-                    ctx->ptem = (vsid << 12) | ((pgidx >> 4) & 0x0F80);
-                }
-            } else
-#endif
-            {
-                ctx->ptem = (vsid << 7) | (pgidx >> 10);
-            }
             /* Initialize real address with an invalid value */
             ctx->raddr = (target_phys_addr_t)-1ULL;
             if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx ||
@@ -885,9 +857,9 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx,
                 ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
             } else {
                 LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
-                        " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
+                        " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
                         " hash=" TARGET_FMT_plx "\n",
-                        env->htab_base, env->htab_mask, vsid, pgidx,
+                        env->htab_base, env->htab_mask, vsid, ctx->ptem,
                         ctx->hash[0]);
                 /* Primary table lookup */
                 ret = find_pte(env, ctx, 0, rw, type, target_page_bits);
@@ -895,9 +867,9 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx,
                     /* Secondary table lookup */
                     if (eaddr != 0xEFFFFFFF)
                         LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
-                                " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
+                                " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
                                 " hash=" TARGET_FMT_plx "\n",
-                                env->htab_base, env->htab_mask, vsid, pgidx,
+                                env->htab_base, env->htab_mask, vsid, ctx->ptem,
                                 ctx->hash[1]);
                     ret2 = find_pte(env, ctx, 1, rw, type,
                                     target_page_bits);
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 12/28] Support 1T segments on ppc
  2011-02-15  4:56 [Qemu-devel] RFC: Implement emulation of pSeries logical partitions (v2) qemu
                   ` (10 preceding siblings ...)
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 11/28] Better factor the ppc hash translation path qemu
@ 2011-02-15  4:56 ` qemu
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 13/28] Add POWER7 support for ppc qemu
                   ` (15 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: qemu @ 2011-02-15  4:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: paulus, agraf, anton

From: David Gibson <david@gibson.dropbear.id.au>

Traditionally, the "segments" used for the two-stage translation used on
powerpc MMUs were 256MB in size.  This was the only option on all hash
page table based 32-bit powerpc cpus, and on the earlier 64-bit hash page
table based cpus.  However, newer 64-bit cpus also permit 1TB segments

This patch adds support for 1TB segment translation to the qemu code.

Signed-off-by: David Gibson <dwg@au1.ibm.com>
---
 target-ppc/cpu.h    |    7 ++++++
 target-ppc/helper.c |   54 +++++++++++++++++++++++++++++++++++---------------
 2 files changed, 45 insertions(+), 16 deletions(-)

diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 71f8d72..9abf4a9 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -114,6 +114,7 @@ enum powerpc_mmu_t {
     POWERPC_MMU_601        = 0x0000000A,
 #if defined(TARGET_PPC64)
 #define POWERPC_MMU_64       0x00010000
+#define POWERPC_MMU_1TSEG    0x00020000
     /* 64 bits PowerPC MMU                                     */
     POWERPC_MMU_64B        = POWERPC_MMU_64 | 0x00000001,
     /* 620 variant (no segment exceptions)                     */
@@ -382,9 +383,11 @@ struct ppc_slb_t {
 
 /* Bits in the SLB VSID word */
 #define SLB_VSID_SHIFT          12
+#define SLB_VSID_SHIFT_1T       24
 #define SLB_VSID_SSIZE_SHIFT    62
 #define SLB_VSID_B              0xc000000000000000ULL
 #define SLB_VSID_B_256M         0x0000000000000000ULL
+#define SLB_VSID_B_1T           0x4000000000000000ULL
 #define SLB_VSID_VSID           0x3FFFFFFFFFFFF000ULL
 #define SLB_VSID_PTEM           (SLB_VSID_B | SLB_VSID_VSID)
 #define SLB_VSID_KS             0x0000000000000800ULL
@@ -398,6 +401,10 @@ struct ppc_slb_t {
 #define SEGMENT_SHIFT_256M      28
 #define SEGMENT_MASK_256M       ~((1ULL << SEGMENT_SHIFT_256M) - 1)
 
+#define SEGMENT_SHIFT_1T        40
+#define SEGMENT_MASK_1T         ~((1ULL << SEGMENT_SHIFT_1T) - 1)
+
+
 /*****************************************************************************/
 /* Machine state register bits definition                                    */
 #define MSR_SF   63 /* Sixty-four-bit mode                            hflags */
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 111675d..3e3b5da 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -671,19 +671,26 @@ static inline int find_pte(CPUState *env, mmu_ctx_t *ctx, int h, int rw,
 #if defined(TARGET_PPC64)
 static inline ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr)
 {
-    uint64_t esid;
+    uint64_t esid_256M, esid_1T;
     int n;
 
     LOG_SLB("%s: eaddr " TARGET_FMT_lx "\n", __func__, eaddr);
 
-    esid = (eaddr & SEGMENT_MASK_256M) | SLB_ESID_V;
+    esid_256M = (eaddr & SEGMENT_MASK_256M) | SLB_ESID_V;
+    esid_1T = (eaddr & SEGMENT_MASK_1T) | SLB_ESID_V;
 
     for (n = 0; n < env->slb_nr; n++) {
         ppc_slb_t *slb = &env->slb[n];
 
         LOG_SLB("%s: slot %d %016" PRIx64 " %016"
                     PRIx64 "\n", __func__, n, slb->esid, slb->vsid);
-        if (slb->esid == esid) {
+        /* We check for 1T matches on all MMUs here - if the MMU
+         * doesn't have 1T segment support, we will have prevented 1T
+         * entries from being inserted in the slbmte code. */
+        if ( ((slb->esid == esid_256M) &&
+              ((slb->vsid & SLB_VSID_B) == SLB_VSID_B_256M))
+             || ((slb->esid == esid_1T) &&
+                 ((slb->vsid & SLB_VSID_B) == SLB_VSID_B_1T)) ) {
             return slb;
         }
     }
@@ -736,16 +743,19 @@ void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0)
 int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs)
 {
     int slot = rb & 0xfff;
-    uint64_t esid = rb & ~0xfff;
     ppc_slb_t *slb = &env->slb[slot];
-
-    if (slot >= env->slb_nr) {
-        return -1;
-    }
-
-    slb->esid = esid;
+ 
+    if (rb & (0x1000 - env->slb_nr))
+	return -1; /* Reserved bits set or slot too high */
+    if (rs & (SLB_VSID_B & ~SLB_VSID_B_1T))
+	return -1; /* Bad segment size */
+    if ((rs & SLB_VSID_B) && !(env->mmu_model & POWERPC_MMU_1TSEG))
+ 	return -1; /* 1T segment on MMU that doesn't support it */
+
+    /* Mask out the slot number as we store the entry */
+    slb->esid = rb & (SLB_ESID_ESID | SLB_ESID_V);
     slb->vsid = rs;
-
+ 
     LOG_SLB("%s: %d " TARGET_FMT_lx " - " TARGET_FMT_lx " => %016" PRIx64
             " %016" PRIx64 "\n", __func__, slot, rb, rs,
             slb->esid, slb->vsid);
@@ -795,6 +805,7 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx,
     if (env->mmu_model & POWERPC_MMU_64) {
         ppc_slb_t *slb;
         target_ulong pageaddr;
+        int segment_bits;
 
         LOG_MMU("Check SLBs\n");
         slb = slb_lookup(env, eaddr);
@@ -802,7 +813,14 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx,
             return -5;
         }
 
-        vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT;
+	if (slb->vsid & SLB_VSID_B) {
+	    vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT_1T;
+	    segment_bits = 40;
+	} else {
+	    vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT;
+	    segment_bits = 28;
+	}
+
         target_page_bits = (slb->vsid & SLB_VSID_L)
             ? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS;
         ctx->key = !!(pr ? (slb->vsid & SLB_VSID_KP)
@@ -810,11 +828,15 @@ static inline int get_segment(CPUState *env, mmu_ctx_t *ctx,
         ds = 0;
         ctx->nx = !!(slb->vsid & SLB_VSID_N);
 
-        pageaddr = eaddr & ((1ULL << 28) - (1ULL << target_page_bits));
-        /* XXX: this is false for 1 TB segments */
-        hash = vsid ^ (pageaddr >> target_page_bits);
+        pageaddr = eaddr & ((1ULL << segment_bits) 
+                            - (1ULL << target_page_bits));
+	if (slb->vsid & SLB_VSID_B)
+	    hash = vsid ^ (vsid << 25) ^ (pageaddr >> target_page_bits);
+	else
+	    hash = vsid ^ (pageaddr >> target_page_bits);
         /* Only 5 bits of the page index are used in the AVPN */
-        ctx->ptem = (slb->vsid & SLB_VSID_PTEM) | ((pageaddr >> 16) & 0x0F80);
+        ctx->ptem = (slb->vsid & SLB_VSID_PTEM) | 
+            ((pageaddr >> 16) & ((1ULL << segment_bits) - 0x80));
     } else
 #endif /* defined(TARGET_PPC64) */
     {
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 13/28] Add POWER7 support for ppc
  2011-02-15  4:56 [Qemu-devel] RFC: Implement emulation of pSeries logical partitions (v2) qemu
                   ` (11 preceding siblings ...)
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 12/28] Support 1T segments on ppc qemu
@ 2011-02-15  4:56 ` qemu
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 14/28] Start implementing pSeries logical partition machine qemu
                   ` (14 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: qemu @ 2011-02-15  4:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: paulus, agraf, anton

From: David Gibson <david@gibson.dropbear.id.au>

This adds emulation support for the recent POWER7 cpu to qemu.  It's far
from perfect - it's missing a number of POWER7 features so far, including
any support for VSX or decimal floating point instructions.  However, it's
close enough to boot a kernel with the POWER7 PVR.

Signed-off-by: David Gibson <dwg@au1.ibm.com>
---
 hw/ppc.c                    |   35 +++++++++++++++
 hw/ppc.h                    |    1 +
 target-ppc/cpu.h            |   16 +++++++
 target-ppc/helper.c         |    6 +++
 target-ppc/translate_init.c |  103 +++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 161 insertions(+), 0 deletions(-)

diff --git a/hw/ppc.c b/hw/ppc.c
index 968aec1..2c4eade 100644
--- a/hw/ppc.c
+++ b/hw/ppc.c
@@ -246,6 +246,41 @@ void ppc970_irq_init (CPUState *env)
     env->irq_inputs = (void **)qemu_allocate_irqs(&ppc970_set_irq, env,
                                                   PPC970_INPUT_NB);
 }
+
+/* POWER7 internal IRQ controller */
+static void power7_set_irq (void *opaque, int pin, int level)
+{
+    CPUState *env = opaque;
+    int cur_level;
+
+    LOG_IRQ("%s: env %p pin %d level %d\n", __func__,
+                env, pin, level);
+    cur_level = (env->irq_input_state >> pin) & 1;
+
+    switch (pin) {
+    case POWER7_INPUT_INT:
+        /* Level sensitive - active high */
+        LOG_IRQ("%s: set the external IRQ state to %d\n",
+                __func__, level);
+        ppc_set_irq(env, PPC_INTERRUPT_EXT, level);
+        break;
+    default:
+        /* Unknown pin - do nothing */
+        LOG_IRQ("%s: unknown IRQ pin %d\n", __func__, pin);
+        return;
+    }
+    if (level) {
+        env->irq_input_state |= 1 << pin;
+    } else {
+        env->irq_input_state &= ~(1 << pin);
+    }
+}
+
+void ppcPOWER7_irq_init (CPUState *env)
+{
+    env->irq_inputs = (void **)qemu_allocate_irqs(&power7_set_irq, env,
+                                                  POWER7_INPUT_NB);
+}
 #endif /* defined(TARGET_PPC64) */
 
 /* PowerPC 40x internal IRQ controller */
diff --git a/hw/ppc.h b/hw/ppc.h
index 34f54cf..3ccf134 100644
--- a/hw/ppc.h
+++ b/hw/ppc.h
@@ -36,6 +36,7 @@ void ppc40x_irq_init (CPUState *env);
 void ppce500_irq_init (CPUState *env);
 void ppc6xx_irq_init (CPUState *env);
 void ppc970_irq_init (CPUState *env);
+void ppcPOWER7_irq_init (CPUState *env);
 
 /* PPC machines for OpenBIOS */
 enum {
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 9abf4a9..3a47d11 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -119,6 +119,8 @@ enum powerpc_mmu_t {
     POWERPC_MMU_64B        = POWERPC_MMU_64 | 0x00000001,
     /* 620 variant (no segment exceptions)                     */
     POWERPC_MMU_620        = POWERPC_MMU_64 | 0x00000002,
+    /* Architecture 2.06 variant                               */
+    POWERPC_MMU_2_06       = POWERPC_MMU_64 | POWERPC_MMU_1TSEG | 0x00000003,
 #endif /* defined(TARGET_PPC64) */
 };
 
@@ -154,6 +156,8 @@ enum powerpc_excp_t {
 #if defined(TARGET_PPC64)
     /* PowerPC 970 exception model      */
     POWERPC_EXCP_970,
+    /* POWER7 exception model           */
+    POWERPC_EXCP_POWER7,
 #endif /* defined(TARGET_PPC64) */
 };
 
@@ -289,6 +293,8 @@ enum powerpc_input_t {
     PPC_FLAGS_INPUT_405,
     /* PowerPC 970 bus                  */
     PPC_FLAGS_INPUT_970,
+    /* PowerPC POWER7 bus               */
+    PPC_FLAGS_INPUT_POWER7,
     /* PowerPC 401 bus                  */
     PPC_FLAGS_INPUT_401,
     /* Freescale RCPU bus               */
@@ -1003,6 +1009,7 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
 #define SPR_HSPRG1            (0x131)
 #define SPR_HDSISR            (0x132)
 #define SPR_HDAR              (0x133)
+#define SPR_SPURR             (0x134)
 #define SPR_BOOKE_DBCR0       (0x134)
 #define SPR_IBCR              (0x135)
 #define SPR_PURR              (0x135)
@@ -1627,6 +1634,15 @@ enum {
     PPC970_INPUT_THINT      = 6,
     PPC970_INPUT_NB,
 };
+
+enum {
+    /* POWER7 input pins */
+    POWER7_INPUT_INT        = 0,
+    /* POWER7 probably has other inputs, but we don't care about them
+     * for any existing machine.  We can wire these up when we need
+     * them */
+    POWER7_INPUT_NB,
+};
 #endif
 
 /* Hardware exceptions definitions */
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 3e3b5da..13a5ab1 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -1192,6 +1192,7 @@ static inline int check_physical(CPUState *env, mmu_ctx_t *ctx,
 #if defined(TARGET_PPC64)
     case POWERPC_MMU_620:
     case POWERPC_MMU_64B:
+    case POWERPC_MMU_2_06:
         /* Real address are 60 bits long */
         ctx->raddr &= 0x0FFFFFFFFFFFFFFFULL;
         ctx->prot |= PAGE_WRITE;
@@ -1269,6 +1270,7 @@ int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr,
 #if defined(TARGET_PPC64)
         case POWERPC_MMU_620:
         case POWERPC_MMU_64B:
+        case POWERPC_MMU_2_06:
 #endif
             if (ret < 0) {
                 /* We didn't match any BAT entry or don't have BATs */
@@ -1368,6 +1370,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
 #if defined(TARGET_PPC64)
                 case POWERPC_MMU_620:
                 case POWERPC_MMU_64B:
+                case POWERPC_MMU_2_06:
 #endif
                     env->exception_index = POWERPC_EXCP_ISI;
                     env->error_code = 0x40000000;
@@ -1477,6 +1480,7 @@ int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
 #if defined(TARGET_PPC64)
                 case POWERPC_MMU_620:
                 case POWERPC_MMU_64B:
+                case POWERPC_MMU_2_06:
 #endif
                     env->exception_index = POWERPC_EXCP_DSI;
                     env->error_code = 0;
@@ -1800,6 +1804,7 @@ void ppc_tlb_invalidate_all (CPUPPCState *env)
 #if defined(TARGET_PPC64)
     case POWERPC_MMU_620:
     case POWERPC_MMU_64B:
+    case POWERPC_MMU_2_06:
 #endif /* defined(TARGET_PPC64) */
         tlb_flush(env, 1);
         break;
@@ -1867,6 +1872,7 @@ void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr)
 #if defined(TARGET_PPC64)
     case POWERPC_MMU_620:
     case POWERPC_MMU_64B:
+    case POWERPC_MMU_2_06:
         /* tlbie invalidate TLBs for all segments */
         /* XXX: given the fact that there are too many segments to invalidate,
          *      and we still don't have a tlb_flush_mask(env, n, mask) in Qemu,
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index c84581e..e41e683 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -61,6 +61,7 @@ void glue(glue(ppc, name),_irq_init) (CPUPPCState *env);
 PPC_IRQ_INIT_FN(40x);
 PPC_IRQ_INIT_FN(6xx);
 PPC_IRQ_INIT_FN(970);
+PPC_IRQ_INIT_FN(POWER7);
 PPC_IRQ_INIT_FN(e500);
 
 /* Generic callbacks:
@@ -3087,6 +3088,35 @@ static void init_excp_970 (CPUPPCState *env)
     env->hreset_vector = 0x0000000000000100ULL;
 #endif
 }
+
+static void init_excp_POWER7 (CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
+    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
+    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
+    env->excp_vectors[POWERPC_EXCP_DSEG]     = 0x00000380;
+    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
+    env->excp_vectors[POWERPC_EXCP_ISEG]     = 0x00000480;
+    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
+    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
+    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
+    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
+    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
+    env->excp_vectors[POWERPC_EXCP_HDECR]    = 0x00000980;
+    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
+    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
+    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
+    env->excp_vectors[POWERPC_EXCP_VPU]      = 0x00000F20;
+    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
+    env->excp_vectors[POWERPC_EXCP_MAINT]    = 0x00001600;
+    env->excp_vectors[POWERPC_EXCP_VPUA]     = 0x00001700;
+    env->excp_vectors[POWERPC_EXCP_THERM]    = 0x00001800;
+    env->hreset_excp_prefix = 0;
+    /* Hardware reset vector */
+    env->hreset_vector = 0x0000000000000100ULL;
+#endif
+}
 #endif
 
 /*****************************************************************************/
@@ -6268,6 +6298,74 @@ static void init_proc_970MP (CPUPPCState *env)
     vscr_init(env, 0x00010000);
 }
 
+/* POWER7 */
+#define POWERPC_INSNS_POWER7  (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |        \
+                              PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |   \
+                              PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |           \
+                              PPC_FLOAT_STFIWX |                              \
+                              PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZT |  \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |               \
+                              PPC_64B | PPC_ALTIVEC |                         \
+                              PPC_SEGMENT_64B | PPC_SLBI |                    \
+                              PPC_POPCNTB | PPC_POPCNTWD)
+#define POWERPC_MSRM_POWER7   (0x800000000204FF36ULL)
+#define POWERPC_MMU_POWER7    (POWERPC_MMU_2_06)
+#define POWERPC_EXCP_POWER7   (POWERPC_EXCP_POWER7)
+#define POWERPC_INPUT_POWER7  (PPC_FLAGS_INPUT_POWER7)
+#define POWERPC_BFDM_POWER7   (bfd_mach_ppc64)
+#define POWERPC_FLAG_POWER7   (POWERPC_FLAG_VRE | POWERPC_FLAG_SE |            \
+                              POWERPC_FLAG_BE | POWERPC_FLAG_PMM |            \
+                              POWERPC_FLAG_BUS_CLK)
+#define check_pow_POWER7    check_pow_nocheck
+
+static void init_proc_POWER7 (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_7xx(env);
+    /* Time base */
+    gen_tbl(env);
+    /* PURR & SPURR: Hack - treat these as aliases for the TB for now */
+    spr_register(env, SPR_PURR,   "PURR",
+                 &spr_read_purr, SPR_NOACCESS,
+                 &spr_read_purr, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_SPURR,   "SPURR",
+                 &spr_read_purr, SPR_NOACCESS,
+                 &spr_read_purr, SPR_NOACCESS,
+                 0x00000000);
+    /* Memory management */
+    /* XXX : not implemented */
+    spr_register(env, SPR_MMUCFG, "MMUCFG",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000); /* TOFIX */
+    /* XXX : not implemented */
+    spr_register(env, SPR_CTRL, "SPR_CTRLT",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x80800000);
+    spr_register(env, SPR_UCTRL, "SPR_CTRLF",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x80800000);
+    spr_register(env, SPR_VRSAVE, "SPR_VRSAVE",
+                 &spr_read_generic, &spr_write_generic,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+#if !defined(CONFIG_USER_ONLY)
+    env->slb_nr = 32;
+#endif
+    init_excp_POWER7(env);
+    env->dcache_line_size = 128;
+    env->icache_line_size = 128;
+    /* Allocate hardware IRQ controller */
+    ppcPOWER7_irq_init(env);
+    /* Can't find information on what this should be on reset.  This
+     * value is the one used by 74xx processors. */
+    vscr_init(env, 0x00010000);
+}
+
 /* PowerPC 620                                                               */
 #define POWERPC_INSNS_620    (PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |        \
                               PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |   \
@@ -6990,6 +7088,8 @@ enum {
     CPU_POWERPC_POWER6             = 0x003E0000,
     CPU_POWERPC_POWER6_5           = 0x0F000001, /* POWER6 in POWER5 mode */
     CPU_POWERPC_POWER6A            = 0x0F000002,
+#define CPU_POWERPC_POWER7           CPU_POWERPC_POWER7_v20
+    CPU_POWERPC_POWER7_v20         = 0x003F0200,
     CPU_POWERPC_970                = 0x00390202,
 #define CPU_POWERPC_970FX            CPU_POWERPC_970FX_v31
     CPU_POWERPC_970FX_v10          = 0x00391100,
@@ -8792,6 +8892,9 @@ static const ppc_def_t ppc_defs[] = {
     /* POWER6A                                                               */
     POWERPC_DEF("POWER6A",       CPU_POWERPC_POWER6A,                POWER6),
 #endif
+    /* POWER7                                                                */
+    POWERPC_DEF("POWER7",	 CPU_POWERPC_POWER7,		     POWER7),
+    POWERPC_DEF("POWER7_v2.0",	 CPU_POWERPC_POWER7_v20,	     POWER7),
     /* PowerPC 970                                                           */
     POWERPC_DEF("970",           CPU_POWERPC_970,                    970),
     /* PowerPC 970FX (G5)                                                    */
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 14/28] Start implementing pSeries logical partition machine
  2011-02-15  4:56 [Qemu-devel] RFC: Implement emulation of pSeries logical partitions (v2) qemu
                   ` (12 preceding siblings ...)
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 13/28] Add POWER7 support for ppc qemu
@ 2011-02-15  4:56 ` qemu
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 15/28] Implement the bus structure for PAPR virtual IO qemu
                   ` (13 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: qemu @ 2011-02-15  4:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: paulus, agraf, anton

From: David Gibson <david@gibson.dropbear.id.au>

This patch adds a "pseries" machine to qemu.  This aims to emulate a
logical partition on an IBM pSeries machine, compliant to the
"PowerPC Architecture Platform Requirements" (PAPR) document.

This initial version is quite limited, it implements a basic machine
and PAPR hypercall emulation.  So far only one hypercall is present -
H_PUT_TERM_CHAR - so that a (write-only) console is available.

Multiple CPUs are permitted, with SMP entry handled kexec() style.

The machine so far more resembles an old POWER4 style "full system
partition" rather than a modern LPAR, in that the guest manages the
page tables directly, rather than via hypercalls.

The machine requires qemu to be configured with --enable-fdt.  The
machine can (so far) only be booted with -kernel - i.e. no partition
firmware is provided.

Signed-off-by: David Gibson <dwg@au1.ibm.com>
---
 Makefile.target  |    2 +
 hw/spapr.c       |  314 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/spapr.h       |  246 ++++++++++++++++++++++++++++++++++++++++++
 hw/spapr_hcall.c |   43 ++++++++
 4 files changed, 605 insertions(+), 0 deletions(-)
 create mode 100644 hw/spapr.c
 create mode 100644 hw/spapr.h
 create mode 100644 hw/spapr_hcall.c

diff --git a/Makefile.target b/Makefile.target
index a6c30dd..72fac45 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -231,6 +231,8 @@ obj-ppc-y += ppc_prep.o
 obj-ppc-y += ppc_oldworld.o
 # NewWorld PowerMac
 obj-ppc-y += ppc_newworld.o
+# IBM pSeries (sPAPR)
+obj-ppc-y += spapr.o spapr_hcall.o
 # PowerPC 4xx boards
 obj-ppc-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
 obj-ppc-y += ppc440.o ppc440_bamboo.o
diff --git a/hw/spapr.c b/hw/spapr.c
new file mode 100644
index 0000000..8b4e16e
--- /dev/null
+++ b/hw/spapr.c
@@ -0,0 +1,314 @@
+/*
+ * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
+ *
+ * Copyright (c) 2004-2007 Fabrice Bellard
+ * Copyright (c) 2007 Jocelyn Mayer
+ * Copyright (c) 2010 David Gibson, IBM Corporation.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+#include "sysemu.h"
+#include "qemu-char.h"
+#include "hw.h"
+#include "elf.h"
+
+#include "hw/boards.h"
+#include "hw/ppc.h"
+#include "hw/loader.h"
+
+#include "hw/spapr.h"
+
+#include <libfdt.h>
+
+#define KERNEL_LOAD_ADDR        0x00000000
+#define INITRD_LOAD_ADDR        0x02800000
+#define FDT_MAX_SIZE            0x10000
+
+#define TIMEBASE_FREQ           512000000ULL
+
+#define MAX_CPUS                32
+
+static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize,
+                              const char *cpu_model, CPUState *envs[],
+                              sPAPREnvironment *spapr,
+                              target_phys_addr_t initrd_base,
+                              target_phys_addr_t initrd_size,
+                              const char *kernel_cmdline)
+{
+    void *fdt;
+    uint64_t mem_reg_property[] = { 0, cpu_to_be64(ramsize) };
+    uint32_t start_prop = cpu_to_be32(initrd_base);
+    uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
+    int i;
+    char *modelname;
+
+#define _FDT(exp) \
+    do { \
+        int ret = (exp);                                           \
+        if (ret < 0) {                                             \
+            hw_error("qemu: error creating device tree: %s: %s\n", \
+                     #exp, fdt_strerror(ret));                     \
+            return NULL;                                           \
+        }                                                          \
+    } while (0)
+
+    fdt = qemu_mallocz(FDT_MAX_SIZE);
+    _FDT((fdt_create(fdt, FDT_MAX_SIZE)));
+    
+    _FDT((fdt_finish_reservemap(fdt)));
+
+    /* Root node */
+    _FDT((fdt_begin_node(fdt, "")));
+    _FDT((fdt_property_string(fdt, "device_type", "chrp")));
+    _FDT((fdt_property_string(fdt, "model", "qemu,emulated-pSeries-LPAR")));
+
+    _FDT((fdt_property_cell(fdt, "#address-cells", 0x2)));
+    _FDT((fdt_property_cell(fdt, "#size-cells", 0x2)));
+
+    /* /chosen */
+    _FDT((fdt_begin_node(fdt, "chosen")));
+
+    _FDT((fdt_property_string(fdt, "bootargs", kernel_cmdline)));
+    _FDT((fdt_property(fdt, "linux,initrd-start", &start_prop, sizeof(start_prop))));
+    _FDT((fdt_property(fdt, "linux,initrd-end", &end_prop, sizeof(end_prop))));
+    
+    _FDT((fdt_end_node(fdt)));
+
+    /* memory node */
+    _FDT((fdt_begin_node(fdt, "memory@0")));
+
+    _FDT((fdt_property_string(fdt, "device_type", "memory")));
+    _FDT((fdt_property(fdt, "reg", mem_reg_property, sizeof(mem_reg_property))));
+    
+    _FDT((fdt_end_node(fdt)));
+    
+    /* cpus */
+    _FDT((fdt_begin_node(fdt, "cpus")));
+
+    _FDT((fdt_property_cell(fdt, "#address-cells", 0x1)));
+    _FDT((fdt_property_cell(fdt, "#size-cells", 0x0)));
+
+    modelname = qemu_strdup(cpu_model);
+    
+    for (i = 0; i < strlen(modelname); i++) {
+        modelname[i] = toupper(modelname[i]);
+    }
+
+    for (i = 0; i < smp_cpus; i++) {
+        CPUState *env = envs[i];
+        char *nodename;
+        uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
+                           0xffffffff, 0xffffffff};
+
+        if (asprintf(&nodename, "%s@%x", modelname, i) < 0) {
+            fprintf(stderr, "Allocation failure\n");
+            exit(1);
+        }
+
+        _FDT((fdt_begin_node(fdt, nodename)));
+
+        free(nodename);
+
+        _FDT((fdt_property_cell(fdt, "reg", i)));
+        _FDT((fdt_property_string(fdt, "device_type", "cpu")));
+
+        _FDT((fdt_property_cell(fdt, "cpu-version", env->spr[SPR_PVR])));
+        _FDT((fdt_property_cell(fdt, "dcache-block-size", env->dcache_line_size)));
+        _FDT((fdt_property_cell(fdt, "icache-block-size", env->icache_line_size)));
+        _FDT((fdt_property_cell(fdt, "timebase-frequency", TIMEBASE_FREQ)));
+        /* Hardcode CPU frequency for now.  It's kind of arbitrary on
+         * full emu, for kvm we should copy it from the host */
+        _FDT((fdt_property_cell(fdt, "clock-frequency", 1000000000)));
+        _FDT((fdt_property_cell(fdt, "ibm,slb-size", env->slb_nr)));
+        _FDT((fdt_property_string(fdt, "status", "okay")));
+        _FDT((fdt_property(fdt, "64-bit", NULL, 0)));
+
+        if (envs[i]->mmu_model & POWERPC_MMU_1TSEG) {
+            _FDT((fdt_property(fdt, "ibm,processor-segment-sizes",
+                               segs, sizeof(segs))));
+        }
+
+        _FDT((fdt_end_node(fdt)));
+    }
+
+    qemu_free(modelname);
+
+    _FDT((fdt_end_node(fdt)));
+
+    _FDT((fdt_end_node(fdt))); /* close root node */
+    _FDT((fdt_finish(fdt)));
+
+    if (fdt_size) {
+        *fdt_size = fdt_totalsize(fdt);
+    }
+
+    return fdt;
+}
+
+static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
+{
+    return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR;
+}
+
+static void emulate_spapr_hypercall(CPUState *env, void *opaque)
+{
+    env->gpr[3] = spapr_hypercall(env, (sPAPREnvironment *)opaque,
+                                  env->gpr[3], &env->gpr[4]);
+}
+
+/* FIXME: hack until we implement the proper VIO console */
+static target_ulong h_put_term_char(CPUState *env, sPAPREnvironment *spapr,
+                                    target_ulong opcode, target_ulong *args)
+{
+    uint8_t buf[16];
+
+    stq_p(buf, args[2]);
+    stq_p(buf + 8, args[3]);
+
+    qemu_chr_write(serial_hds[0], buf, args[1]);
+
+    return 0;
+}
+
+
+/* pSeries LPAR / sPAPR hardware init */
+static void ppc_spapr_init(ram_addr_t ram_size,
+                           const char *boot_device,
+                           const char *kernel_filename,
+                           const char *kernel_cmdline,
+                           const char *initrd_filename,
+                           const char *cpu_model)
+{
+    CPUState *envs[MAX_CPUS];
+    void *fdt;
+    int i;
+    ram_addr_t ram_offset;
+    target_phys_addr_t fdt_addr;
+    uint32_t kernel_base, initrd_base;
+    long kernel_size, initrd_size;
+    int fdt_size;
+    sPAPREnvironment *spapr;
+
+    spapr = qemu_malloc(sizeof(*spapr));
+
+    /* We place the device tree just below either the top of RAM, or
+     * 2GB, so that it can be processed with 32-bit code if
+     * necessary */
+    fdt_addr = MIN(ram_size, 0x80000000) - FDT_MAX_SIZE;
+
+    /* init CPUs */
+    if (cpu_model == NULL) {
+        cpu_model = "POWER7";
+    }
+    for (i = 0; i < smp_cpus; i++) {
+        CPUState *env =  cpu_init(cpu_model);
+
+        if (!env) {
+            fprintf(stderr, "Unable to find PowerPC CPU definition\n");
+            exit(1);
+        }
+        /* Set time-base frequency to 512 MHz */
+        cpu_ppc_tb_init(env, TIMEBASE_FREQ);
+        qemu_register_reset((QEMUResetHandler*)&cpu_reset, env);
+
+        env->emulate_hypercall = emulate_spapr_hypercall;
+        env->hcall_opaque = spapr;
+
+        env->hreset_vector = 0x60;
+        env->hreset_excp_prefix = 0;
+        env->gpr[3] = i;
+
+        envs[i] = env;
+    }
+
+    /* allocate RAM */
+    ram_offset = qemu_ram_alloc(NULL, "ppc_spapr.ram", ram_size);
+    cpu_register_physical_memory(0, ram_size, ram_offset);
+
+    spapr_register_hypercall(H_PUT_TERM_CHAR, h_put_term_char);
+
+    if (kernel_filename) {
+        uint64_t lowaddr = 0;
+
+        kernel_base = KERNEL_LOAD_ADDR;
+
+        kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL,
+                               NULL, &lowaddr, NULL, 1, ELF_MACHINE, 0);
+        if (kernel_size < 0) {
+            kernel_size = load_image_targphys(kernel_filename, kernel_base,
+                                              ram_size - kernel_base);
+        }
+        if (kernel_size < 0) {
+            hw_error("qemu: could not load kernel '%s'\n", kernel_filename);
+            exit(1);
+        }
+
+        /* load initrd */
+        if (initrd_filename) {
+            initrd_base = INITRD_LOAD_ADDR;
+            initrd_size = load_image_targphys(initrd_filename, initrd_base,
+                                              ram_size - initrd_base);
+            if (initrd_size < 0) {
+                hw_error("qemu: could not load initial ram disk '%s'\n",
+                         initrd_filename);
+                exit(1);
+            }
+        } else {
+            initrd_base = 0;
+            initrd_size = 0;
+        }
+
+    } else {
+        fprintf(stderr, "pSeries machine needs -kernel for now");
+        exit(1);
+    }
+
+    /* Prepare the device tree */
+    fdt = spapr_create_fdt(&fdt_size, ram_size, cpu_model, envs, spapr,
+                           initrd_base, initrd_size, kernel_cmdline);
+    if (!fdt) {
+        hw_error("Couldn't create pSeries device tree\n");
+        exit(1);
+    }
+
+    cpu_physical_memory_write(fdt_addr, fdt, fdt_size);
+
+    qemu_free(fdt);
+
+    envs[0]->gpr[3] = fdt_addr;
+    envs[0]->gpr[5] = 0;
+    envs[0]->hreset_vector = kernel_base;
+}
+
+static QEMUMachine spapr_machine = {
+    .name = "pseries",
+    .desc = "pSeries Logical Partition (PAPR compliant)",
+    .init = ppc_spapr_init,
+    .max_cpus = MAX_CPUS,
+    .no_vga = 1,
+    .no_parallel = 1,
+};
+
+static void spapr_machine_init(void)
+{
+    qemu_register_machine(&spapr_machine);
+}
+
+machine_init(spapr_machine_init);
diff --git a/hw/spapr.h b/hw/spapr.h
new file mode 100644
index 0000000..9e63a19
--- /dev/null
+++ b/hw/spapr.h
@@ -0,0 +1,246 @@
+#if !defined (__HW_SPAPR_H__)
+#define __HW_SPAPR_H__
+
+typedef struct sPAPREnvironment {
+} sPAPREnvironment;
+
+#define H_SUCCESS         0
+#define H_BUSY            1        /* Hardware busy -- retry later */
+#define H_CLOSED          2        /* Resource closed */
+#define H_NOT_AVAILABLE   3
+#define H_CONSTRAINED     4        /* Resource request constrained to max allowed */
+#define H_PARTIAL         5
+#define H_IN_PROGRESS     14       /* Kind of like busy */
+#define H_PAGE_REGISTERED 15
+#define H_PARTIAL_STORE   16
+#define H_PENDING         17       /* returned from H_POLL_PENDING */
+#define H_CONTINUE        18       /* Returned from H_Join on success */
+#define H_LONG_BUSY_START_RANGE         9900  /* Start of long busy range */
+#define H_LONG_BUSY_ORDER_1_MSEC        9900  /* Long busy, hint that 1msec \
+                                                 is a good time to retry */
+#define H_LONG_BUSY_ORDER_10_MSEC       9901  /* Long busy, hint that 10msec \
+                                                 is a good time to retry */
+#define H_LONG_BUSY_ORDER_100_MSEC      9902  /* Long busy, hint that 100msec \
+                                                 is a good time to retry */
+#define H_LONG_BUSY_ORDER_1_SEC         9903  /* Long busy, hint that 1sec \
+                                                 is a good time to retry */
+#define H_LONG_BUSY_ORDER_10_SEC        9904  /* Long busy, hint that 10sec \
+                                                 is a good time to retry */
+#define H_LONG_BUSY_ORDER_100_SEC       9905  /* Long busy, hint that 100sec \
+                                                 is a good time to retry */
+#define H_LONG_BUSY_END_RANGE           9905  /* End of long busy range */
+#define H_HARDWARE        -1       /* Hardware error */
+#define H_FUNCTION        -2       /* Function not supported */
+#define H_PRIVILEGE       -3       /* Caller not privileged */
+#define H_PARAMETER       -4       /* Parameter invalid, out-of-range or conflicting */
+#define H_BAD_MODE        -5       /* Illegal msr value */
+#define H_PTEG_FULL       -6       /* PTEG is full */
+#define H_NOT_FOUND       -7       /* PTE was not found" */
+#define H_RESERVED_DABR   -8       /* DABR address is reserved by the hypervisor on this processor" */
+#define H_NO_MEM          -9
+#define H_AUTHORITY       -10
+#define H_PERMISSION      -11
+#define H_DROPPED         -12
+#define H_SOURCE_PARM     -13
+#define H_DEST_PARM       -14
+#define H_REMOTE_PARM     -15
+#define H_RESOURCE        -16
+#define H_ADAPTER_PARM    -17
+#define H_RH_PARM         -18
+#define H_RCQ_PARM        -19
+#define H_SCQ_PARM        -20
+#define H_EQ_PARM         -21
+#define H_RT_PARM         -22
+#define H_ST_PARM         -23
+#define H_SIGT_PARM       -24
+#define H_TOKEN_PARM      -25
+#define H_MLENGTH_PARM    -27
+#define H_MEM_PARM        -28
+#define H_MEM_ACCESS_PARM -29
+#define H_ATTR_PARM       -30
+#define H_PORT_PARM       -31
+#define H_MCG_PARM        -32
+#define H_VL_PARM         -33
+#define H_TSIZE_PARM      -34
+#define H_TRACE_PARM      -35
+
+#define H_MASK_PARM       -37
+#define H_MCG_FULL        -38
+#define H_ALIAS_EXIST     -39
+#define H_P_COUNTER       -40
+#define H_TABLE_FULL      -41
+#define H_ALT_TABLE       -42
+#define H_MR_CONDITION    -43
+#define H_NOT_ENOUGH_RESOURCES -44
+#define H_R_STATE         -45
+#define H_RESCINDEND      -46
+#define H_MULTI_THREADS_ACTIVE -9005
+
+
+/* Long Busy is a condition that can be returned by the firmware
+ * when a call cannot be completed now, but the identical call
+ * should be retried later.  This prevents calls blocking in the
+ * firmware for long periods of time.  Annoyingly the firmware can return
+ * a range of return codes, hinting at how long we should wait before
+ * retrying.  If you don't care for the hint, the macro below is a good
+ * way to check for the long_busy return codes
+ */
+#define H_IS_LONG_BUSY(x)  ((x >= H_LONG_BUSY_START_RANGE) \
+                            && (x <= H_LONG_BUSY_END_RANGE))
+
+/* Flags */
+#define H_LARGE_PAGE      (1ULL<<(63-16))
+#define H_EXACT           (1ULL<<(63-24))       /* Use exact PTE or return H_PTEG_FULL */
+#define H_R_XLATE         (1ULL<<(63-25))       /* include a valid logical page num in the pte if the valid bit is set */
+#define H_READ_4          (1ULL<<(63-26))       /* Return 4 PTEs */
+#define H_PAGE_STATE_CHANGE (1ULL<<(63-28))
+#define H_PAGE_UNUSED     ((1ULL<<(63-29)) | (1ULL<<(63-30)))
+#define H_PAGE_SET_UNUSED (H_PAGE_STATE_CHANGE | H_PAGE_UNUSED)
+#define H_PAGE_SET_LOANED (H_PAGE_SET_UNUSED | (1ULL<<(63-31)))
+#define H_PAGE_SET_ACTIVE H_PAGE_STATE_CHANGE
+#define H_AVPN            (1ULL<<(63-32))       /* An avpn is provided as a sanity test */
+#define H_ANDCOND         (1ULL<<(63-33))
+#define H_ICACHE_INVALIDATE (1ULL<<(63-40))     /* icbi, etc.  (ignored for IO pages) */
+#define H_ICACHE_SYNCHRONIZE (1ULL<<(63-41))    /* dcbst, icbi, etc (ignored for IO pages */
+#define H_ZERO_PAGE       (1ULL<<(63-48))       /* zero the page before mapping (ignored for IO pages) */
+#define H_COPY_PAGE       (1ULL<<(63-49))
+#define H_N               (1ULL<<(63-61))
+#define H_PP1             (1ULL<<(63-62))
+#define H_PP2             (1ULL<<(63-63))
+
+/* VASI States */
+#define H_VASI_INVALID    0
+#define H_VASI_ENABLED    1
+#define H_VASI_ABORTED    2
+#define H_VASI_SUSPENDING 3
+#define H_VASI_SUSPENDED  4
+#define H_VASI_RESUMED    5
+#define H_VASI_COMPLETED  6
+
+/* DABRX flags */
+#define H_DABRX_HYPERVISOR (1ULL<<(63-61))
+#define H_DABRX_KERNEL     (1ULL<<(63-62))
+#define H_DABRX_USER       (1ULL<<(63-63))
+
+/* Each control block has to be on a 4K bondary */
+#define H_CB_ALIGNMENT     4096
+
+/* pSeries hypervisor opcodes */
+#define H_REMOVE                0x04
+#define H_ENTER                 0x08
+#define H_READ                  0x0c
+#define H_CLEAR_MOD             0x10
+#define H_CLEAR_REF             0x14
+#define H_PROTECT               0x18
+#define H_GET_TCE               0x1c
+#define H_PUT_TCE               0x20
+#define H_SET_SPRG0             0x24
+#define H_SET_DABR              0x28
+#define H_PAGE_INIT             0x2c
+#define H_SET_ASR               0x30
+#define H_ASR_ON                0x34
+#define H_ASR_OFF               0x38
+#define H_LOGICAL_CI_LOAD       0x3c
+#define H_LOGICAL_CI_STORE      0x40
+#define H_LOGICAL_CACHE_LOAD    0x44
+#define H_LOGICAL_CACHE_STORE   0x48
+#define H_LOGICAL_ICBI          0x4c
+#define H_LOGICAL_DCBF          0x50
+#define H_GET_TERM_CHAR         0x54
+#define H_PUT_TERM_CHAR         0x58
+#define H_REAL_TO_LOGICAL       0x5c
+#define H_HYPERVISOR_DATA       0x60
+#define H_EOI                   0x64
+#define H_CPPR                  0x68
+#define H_IPI                   0x6c
+#define H_IPOLL                 0x70
+#define H_XIRR                  0x74
+#define H_PERFMON               0x7c
+#define H_MIGRATE_DMA           0x78
+#define H_REGISTER_VPA          0xDC
+#define H_CEDE                  0xE0
+#define H_CONFER                0xE4
+#define H_PROD                  0xE8
+#define H_GET_PPP               0xEC
+#define H_SET_PPP               0xF0
+#define H_PURR                  0xF4
+#define H_PIC                   0xF8
+#define H_REG_CRQ               0xFC
+#define H_FREE_CRQ              0x100
+#define H_VIO_SIGNAL            0x104
+#define H_SEND_CRQ              0x108
+#define H_COPY_RDMA             0x110
+#define H_REGISTER_LOGICAL_LAN  0x114
+#define H_FREE_LOGICAL_LAN      0x118
+#define H_ADD_LOGICAL_LAN_BUFFER 0x11C
+#define H_SEND_LOGICAL_LAN      0x120
+#define H_BULK_REMOVE           0x124
+#define H_MULTICAST_CTRL        0x130
+#define H_SET_XDABR             0x134
+#define H_STUFF_TCE             0x138
+#define H_PUT_TCE_INDIRECT      0x13C
+#define H_CHANGE_LOGICAL_LAN_MAC 0x14C
+#define H_VTERM_PARTNER_INFO    0x150
+#define H_REGISTER_VTERM        0x154
+#define H_FREE_VTERM            0x158
+#define H_RESET_EVENTS          0x15C
+#define H_ALLOC_RESOURCE        0x160
+#define H_FREE_RESOURCE         0x164
+#define H_MODIFY_QP             0x168
+#define H_QUERY_QP              0x16C
+#define H_REREGISTER_PMR        0x170
+#define H_REGISTER_SMR          0x174
+#define H_QUERY_MR              0x178
+#define H_QUERY_MW              0x17C
+#define H_QUERY_HCA             0x180
+#define H_QUERY_PORT            0x184
+#define H_MODIFY_PORT           0x188
+#define H_DEFINE_AQP1           0x18C
+#define H_GET_TRACE_BUFFER      0x190
+#define H_DEFINE_AQP0           0x194
+#define H_RESIZE_MR             0x198
+#define H_ATTACH_MCQP           0x19C
+#define H_DETACH_MCQP           0x1A0
+#define H_CREATE_RPT            0x1A4
+#define H_REMOVE_RPT            0x1A8
+#define H_REGISTER_RPAGES       0x1AC
+#define H_DISABLE_AND_GETC      0x1B0
+#define H_ERROR_DATA            0x1B4
+#define H_GET_HCA_INFO          0x1B8
+#define H_GET_PERF_COUNT        0x1BC
+#define H_MANAGE_TRACE          0x1C0
+#define H_FREE_LOGICAL_LAN_BUFFER 0x1D4
+#define H_QUERY_INT_STATE       0x1E4
+#define H_POLL_PENDING          0x1D8
+#define H_ILLAN_ATTRIBUTES      0x244
+#define H_MODIFY_HEA_QP         0x250
+#define H_QUERY_HEA_QP          0x254
+#define H_QUERY_HEA             0x258
+#define H_QUERY_HEA_PORT        0x25C
+#define H_MODIFY_HEA_PORT       0x260
+#define H_REG_BCMC              0x264
+#define H_DEREG_BCMC            0x268
+#define H_REGISTER_HEA_RPAGES   0x26C
+#define H_DISABLE_AND_GET_HEA   0x270
+#define H_GET_HEA_INFO          0x274
+#define H_ALLOC_HEA_RESOURCE    0x278
+#define H_ADD_CONN              0x284
+#define H_DEL_CONN              0x288
+#define H_JOIN                  0x298
+#define H_VASI_STATE            0x2A4
+#define H_ENABLE_CRQ            0x2B0
+#define H_GET_EM_PARMS          0x2B8
+#define H_SET_MPP               0x2D0
+#define H_GET_MPP               0x2D4
+#define MAX_HCALL_OPCODE        H_GET_MPP
+
+typedef target_ulong (*spapr_hcall_fn)(CPUState *env, sPAPREnvironment *spapr,
+                                       target_ulong opcode,
+                                       target_ulong *args);
+
+void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn);
+target_ulong spapr_hypercall(CPUState *env, sPAPREnvironment *spapr,
+                             target_ulong opcode, target_ulong *args);
+
+
+#endif /* !defined (__HW_SPAPR_H__) */
diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c
new file mode 100644
index 0000000..6ddac00
--- /dev/null
+++ b/hw/spapr_hcall.c
@@ -0,0 +1,43 @@
+#include "sysemu.h"
+#include "cpu.h"
+#include "qemu-char.h"
+#include "hw/spapr.h"
+
+struct hypercall {
+    spapr_hcall_fn fn;
+} hypercall_table[(MAX_HCALL_OPCODE / 4) + 1];
+
+void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn)
+{
+    struct hypercall *hc;
+
+    assert(opcode <= MAX_HCALL_OPCODE);
+    assert((opcode & 0x3) == 0);
+
+    hc = hypercall_table + (opcode / 4);
+
+    assert(!hc->fn || (fn == hc->fn));
+
+    hc->fn = fn;
+}
+
+target_ulong spapr_hypercall(CPUState *env, sPAPREnvironment *spapr,
+                             target_ulong opcode, target_ulong *args)
+{
+    if (msr_pr) {
+        fprintf(stderr, "Hypercall made with MSR=0x" TARGET_FMT_lx "\n",
+                env->msr);
+        return H_PRIVILEGE;
+    }
+
+    if ((opcode <= MAX_HCALL_OPCODE)
+        && ((opcode & 0x3) == 0)) {
+        struct hypercall *hc = hypercall_table + (opcode / 4);
+
+        if (hc->fn)
+            return hc->fn(env, spapr, opcode, args);
+    }
+
+    fprintf(stderr, "Unimplemented hcall 0x" TARGET_FMT_lx "\n", opcode);
+    return H_FUNCTION;
+}
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 15/28] Implement the bus structure for PAPR virtual IO
  2011-02-15  4:56 [Qemu-devel] RFC: Implement emulation of pSeries logical partitions (v2) qemu
                   ` (13 preceding siblings ...)
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 14/28] Start implementing pSeries logical partition machine qemu
@ 2011-02-15  4:56 ` qemu
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 16/28] Virtual hash page table handling on pSeries machine qemu
                   ` (12 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: qemu @ 2011-02-15  4:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: paulus, agraf, anton

From: David Gibson <david@gibson.dropbear.id.au>

This extends the "pseries" (PAPR) machine to include a virtual IO bus
supporting the PAPR defined hypercall based virtual IO mechanisms.

So far only one VIO device is provided, the vty / vterm, providing
a full console (polled only, for now).

Signed-off-by: David Gibson <dwg@au1.ibm.com>
---
 Makefile.target |    3 +-
 hw/spapr.c      |   47 ++++++++-----
 hw/spapr.h      |    3 +
 hw/spapr_vio.c  |  212 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/spapr_vio.h  |   50 +++++++++++++
 hw/spapr_vty.c  |  145 +++++++++++++++++++++++++++++++++++++
 6 files changed, 441 insertions(+), 19 deletions(-)
 create mode 100644 hw/spapr_vio.c
 create mode 100644 hw/spapr_vio.h
 create mode 100644 hw/spapr_vty.c

diff --git a/Makefile.target b/Makefile.target
index 72fac45..ba243bf 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -232,7 +232,8 @@ obj-ppc-y += ppc_oldworld.o
 # NewWorld PowerMac
 obj-ppc-y += ppc_newworld.o
 # IBM pSeries (sPAPR)
-obj-ppc-y += spapr.o spapr_hcall.o
+obj-ppc-y += spapr.o spapr_hcall.o spapr_vio.o
+obj-ppc-y += spapr_vty.o
 # PowerPC 4xx boards
 obj-ppc-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
 obj-ppc-y += ppc440.o ppc440_bamboo.o
diff --git a/hw/spapr.c b/hw/spapr.c
index 8b4e16e..25e4a9e 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -25,7 +25,6 @@
  *
  */
 #include "sysemu.h"
-#include "qemu-char.h"
 #include "hw.h"
 #include "elf.h"
 
@@ -34,6 +33,7 @@
 #include "hw/loader.h"
 
 #include "hw/spapr.h"
+#include "hw/spapr_vio.h"
 
 #include <libfdt.h>
 
@@ -58,6 +58,7 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize,
     uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
     int i;
     char *modelname;
+    int ret;
 
 #define _FDT(exp) \
     do { \
@@ -152,9 +153,29 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize,
 
     _FDT((fdt_end_node(fdt)));
 
+    /* vdevice */
+    _FDT((fdt_begin_node(fdt, "vdevice")));
+
+    _FDT((fdt_property_string(fdt, "device_type", "vdevice")));
+    _FDT((fdt_property_string(fdt, "compatible", "IBM,vdevice")));
+    _FDT((fdt_property_cell(fdt, "#address-cells", 0x1)));
+    _FDT((fdt_property_cell(fdt, "#size-cells", 0x0)));
+    
+    _FDT((fdt_end_node(fdt)));
+
     _FDT((fdt_end_node(fdt))); /* close root node */
     _FDT((fdt_finish(fdt)));
 
+    /* re-expand to allow for further tweaks */
+    _FDT((fdt_open_into(fdt, fdt, FDT_MAX_SIZE)));
+
+    ret = spapr_populate_vdevice(spapr->vio_bus, fdt);
+    if (ret < 0) {
+        fprintf(stderr, "couldn't setup vio devices in fdt\n");
+    }
+
+    _FDT((fdt_pack(fdt)));
+
     if (fdt_size) {
         *fdt_size = fdt_totalsize(fdt);
     }
@@ -173,21 +194,6 @@ static void emulate_spapr_hypercall(CPUState *env, void *opaque)
                                   env->gpr[3], &env->gpr[4]);
 }
 
-/* FIXME: hack until we implement the proper VIO console */
-static target_ulong h_put_term_char(CPUState *env, sPAPREnvironment *spapr,
-                                    target_ulong opcode, target_ulong *args)
-{
-    uint8_t buf[16];
-
-    stq_p(buf, args[2]);
-    stq_p(buf + 8, args[3]);
-
-    qemu_chr_write(serial_hds[0], buf, args[1]);
-
-    return 0;
-}
-
-
 /* pSeries LPAR / sPAPR hardware init */
 static void ppc_spapr_init(ram_addr_t ram_size,
                            const char *boot_device,
@@ -242,7 +248,13 @@ static void ppc_spapr_init(ram_addr_t ram_size,
     ram_offset = qemu_ram_alloc(NULL, "ppc_spapr.ram", ram_size);
     cpu_register_physical_memory(0, ram_size, ram_offset);
 
-    spapr_register_hypercall(H_PUT_TERM_CHAR, h_put_term_char);
+    spapr->vio_bus = spapr_vio_bus_init();
+
+    for (i = 0; i < MAX_SERIAL_PORTS; i++) {
+        if (serial_hds[i]) {
+            spapr_vty_create(spapr->vio_bus, i, serial_hds[i]);
+        }
+    }
 
     if (kernel_filename) {
         uint64_t lowaddr = 0;
@@ -274,7 +286,6 @@ static void ppc_spapr_init(ram_addr_t ram_size,
             initrd_base = 0;
             initrd_size = 0;
         }
-
     } else {
         fprintf(stderr, "pSeries machine needs -kernel for now");
         exit(1);
diff --git a/hw/spapr.h b/hw/spapr.h
index 9e63a19..47bf2ef 100644
--- a/hw/spapr.h
+++ b/hw/spapr.h
@@ -1,7 +1,10 @@
 #if !defined (__HW_SPAPR_H__)
 #define __HW_SPAPR_H__
 
+struct VIOsPAPRBus;
+
 typedef struct sPAPREnvironment {
+    struct VIOsPAPRBus *vio_bus;
 } sPAPREnvironment;
 
 #define H_SUCCESS         0
diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
new file mode 100644
index 0000000..67005bb
--- /dev/null
+++ b/hw/spapr_vio.c
@@ -0,0 +1,212 @@
+/*
+ * QEMU sPAPR VIO code
+ *
+ * Copyright (c) 2010 David Gibson, IBM Corporation <david@gibson.dropbear.id.au>
+ * Based on the s390 virtio bus code:
+ * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw.h"
+#include "sysemu.h"
+#include "boards.h"
+#include "monitor.h"
+#include "loader.h"
+#include "elf.h"
+#include "hw/sysbus.h"
+#include "kvm.h"
+#include "device_tree.h"
+
+#include "hw/spapr.h"
+#include "hw/spapr_vio.h"
+
+#ifdef CONFIG_FDT
+#include <libfdt.h>
+#endif /* CONFIG_FDT */
+
+/* #define DEBUG_SPAPR */
+
+#ifdef DEBUG_SPAPR
+#define dprintf(fmt, ...) \
+    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define dprintf(fmt, ...) \
+    do { } while (0)
+#endif
+
+struct BusInfo spapr_vio_bus_info = {
+    .name       = "spapr-vio",
+    .size       = sizeof(VIOsPAPRBus),
+};
+
+VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg)
+{
+    DeviceState *qdev;
+    VIOsPAPRDevice *dev = NULL;
+
+    QLIST_FOREACH(qdev, &bus->bus.children, sibling) {
+        dev = (VIOsPAPRDevice *)qdev;
+        if (dev->reg == reg) {
+            break;
+        }
+    }
+
+    return dev;
+}
+
+#ifdef CONFIG_FDT
+static int vio_make_devnode(VIOsPAPRDevice *dev,
+                            void *fdt)
+{
+    VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)dev->qdev.info;
+    int vdevice_off, node_off;
+    int ret;
+
+    vdevice_off = fdt_path_offset(fdt, "/vdevice");
+    if (vdevice_off < 0) {
+        return vdevice_off;
+    }
+
+    node_off = fdt_add_subnode(fdt, vdevice_off, dev->qdev.id);
+    if (node_off < 0) {
+        return node_off;
+    }
+
+    ret = fdt_setprop_cell(fdt, node_off, "reg", dev->reg);
+    if (ret < 0) {
+        return ret;
+    }
+
+    if (info->dt_type) {
+        ret = fdt_setprop_string(fdt, node_off, "device_type",
+                                 info->dt_type);
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
+    if (info->dt_compatible) {
+        ret = fdt_setprop_string(fdt, node_off, "compatible",
+                                 info->dt_compatible);
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
+    if (info->devnode) {
+        ret = (info->devnode)(dev, fdt, node_off);
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
+    return node_off;
+}
+#endif /* CONFIG_FDT */
+
+static int spapr_vio_busdev_init(DeviceState *dev, DeviceInfo *info)
+{
+    VIOsPAPRDeviceInfo *_info = (VIOsPAPRDeviceInfo *)info;
+    VIOsPAPRDevice *_dev = (VIOsPAPRDevice *)dev;
+    char *id;
+
+    if (asprintf(&id, "%s@%x", _info->dt_name, _dev->reg) < 0) {
+        return -1;
+    }
+
+    _dev->qdev.id = id;
+
+    return _info->init(_dev);
+}
+
+void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info)
+{
+    info->qdev.init = spapr_vio_busdev_init;
+    info->qdev.bus_info = &spapr_vio_bus_info;
+
+    assert(info->qdev.size >= sizeof(VIOsPAPRDevice));
+    qdev_register(&info->qdev);
+}
+
+VIOsPAPRBus *spapr_vio_bus_init(void)
+{
+    VIOsPAPRBus *bus;
+    BusState *_bus;
+    DeviceState *dev;
+    DeviceInfo *_info;
+
+    /* Create bridge device */
+    dev = qdev_create(NULL, "spapr-vio-bridge");
+    qdev_init_nofail(dev);
+
+    /* Create bus on bridge device */
+
+    _bus = qbus_create(&spapr_vio_bus_info, dev, "spapr-vio");
+    bus = DO_UPCAST(VIOsPAPRBus, bus, _bus);
+
+    for (_info = device_info_list; _info; _info = _info->next) {
+        VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)_info;
+
+        if (_info->bus_info != &spapr_vio_bus_info)
+            continue;
+
+        if (info->hcalls)
+            info->hcalls(bus);
+    }
+
+    return bus;
+}
+
+/* Represents sPAPR hcall VIO devices */
+
+static int spapr_vio_bridge_init(SysBusDevice *dev)
+{
+    /* nothing */
+    return 0;
+}
+
+static SysBusDeviceInfo spapr_vio_bridge_info = {
+    .init = spapr_vio_bridge_init,
+    .qdev.name  = "spapr-vio-bridge",
+    .qdev.size  = sizeof(SysBusDevice),
+    .qdev.no_user = 1,
+};
+
+static void spapr_vio_register_devices(void)
+{
+    sysbus_register_withprop(&spapr_vio_bridge_info);
+}
+
+device_init(spapr_vio_register_devices)
+
+#ifdef CONFIG_FDT
+int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt)
+{
+    DeviceState *qdev;
+    int ret = 0;
+
+    QLIST_FOREACH(qdev, &bus->bus.children, sibling) {
+        VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
+
+        ret = vio_make_devnode(dev, fdt);
+
+        if (ret < 0) {
+            return ret;
+        }
+    }
+    
+    return 0;
+}
+#endif /* CONFIG_FDT */
diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h
new file mode 100644
index 0000000..b164ad3
--- /dev/null
+++ b/hw/spapr_vio.h
@@ -0,0 +1,50 @@
+#ifndef _HW_SPAPR_VIO_H
+#define _HW_SPAPR_VIO_H
+/*
+ * QEMU sPAPR VIO bus definitions
+ *
+ * Copyright (c) 2010 David Gibson, IBM Corporation <david@gibson.dropbear.id.au>
+ * Based on the s390 virtio bus definitions:
+ * Copyright (c) 2009 Alexander Graf <agraf@suse.de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+typedef struct VIOsPAPRDevice {
+    DeviceState qdev;
+    uint32_t reg;
+} VIOsPAPRDevice;
+
+typedef struct VIOsPAPRBus {
+    BusState bus;
+} VIOsPAPRBus;
+
+typedef struct {
+    DeviceInfo qdev;
+    const char *dt_name, *dt_type, *dt_compatible;
+    int (*init)(VIOsPAPRDevice *dev);
+    void (*hcalls)(VIOsPAPRBus *bus);
+    int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off);
+} VIOsPAPRDeviceInfo;
+
+extern VIOsPAPRBus *spapr_vio_bus_init(void);
+extern VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg);
+extern void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info);
+extern int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt);
+
+void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len);
+void spapr_vty_create(VIOsPAPRBus *bus,
+                      uint32_t reg, CharDriverState *chardev);
+
+#endif /* _HW_SPAPR_VIO_H */
diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c
new file mode 100644
index 0000000..afc9ef9
--- /dev/null
+++ b/hw/spapr_vty.c
@@ -0,0 +1,145 @@
+#include "qdev.h"
+#include "qemu-char.h"
+#include "hw/spapr.h"
+#include "hw/spapr_vio.h"
+
+#define VTERM_BUFSIZE   16
+
+typedef struct VIOsPAPRVTYDevice {
+    VIOsPAPRDevice sdev;
+    CharDriverState *chardev;
+    uint32_t in, out;
+    uint8_t buf[VTERM_BUFSIZE];
+} VIOsPAPRVTYDevice;
+
+static int vty_can_receive(void *opaque)
+{
+    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)opaque;
+
+    return (dev->in - dev->out) < VTERM_BUFSIZE;
+}
+
+static void vty_receive(void *opaque, const uint8_t *buf, int size)
+{
+    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)opaque;
+    int i;
+
+    for (i = 0; i < size; i++) {
+        assert((dev->in - dev->out) < VTERM_BUFSIZE);
+        dev->buf[dev->in++ % VTERM_BUFSIZE] = buf[i];
+    }
+}
+
+static int vty_getchars(VIOsPAPRDevice *sdev, uint8_t *buf, int max)
+{
+    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev;
+    int n = 0;
+
+    while ((n < max) && (dev->out != dev->in))
+        buf[n++] = dev->buf[dev->out++ % VTERM_BUFSIZE];
+
+    return n;
+}
+
+void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len)
+{
+    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev;
+
+    /* FIXME: should check the qemu_chr_write() return value */
+    qemu_chr_write(dev->chardev, buf, len);
+}
+
+static int spapr_vty_init(VIOsPAPRDevice *sdev)
+{
+    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev;
+
+    qemu_chr_add_handlers(dev->chardev, vty_can_receive,
+                          vty_receive, NULL, dev);
+
+    return 0;
+}
+
+static target_ulong h_put_term_char(CPUState *env, sPAPREnvironment *spapr,
+                                    target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    target_ulong len = args[1];
+    target_ulong char0_7 = args[2];
+    target_ulong char8_15 = args[3];
+    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+    uint8_t buf[16];
+
+    if (!sdev)
+        return H_PARAMETER;
+
+    if (len > 16)
+        return H_PARAMETER;
+
+    *((uint64_t *)buf) = cpu_to_be64(char0_7);
+    *((uint64_t *)buf + 1) = cpu_to_be64(char8_15);
+
+    vty_putchars(sdev, buf, len);
+
+    return H_SUCCESS;
+}
+
+static target_ulong h_get_term_char(CPUState *env, sPAPREnvironment *spapr,
+                                    target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    target_ulong *len = args + 0;
+    target_ulong *char0_7 = args + 1;
+    target_ulong *char8_15 = args + 2;
+    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+    uint8_t buf[16];
+
+    if (!sdev)
+        return H_PARAMETER;
+
+    *len = vty_getchars(sdev, buf, sizeof(buf));
+    if (*len < 16)
+        memset(buf + *len, 0, 16 - *len);
+
+    *char0_7 = be64_to_cpu(*((uint64_t *)buf));
+    *char8_15 = be64_to_cpu(*((uint64_t *)buf + 1));
+
+    return H_SUCCESS;
+}
+
+void spapr_vty_create(VIOsPAPRBus *bus,
+                      uint32_t reg, CharDriverState *chardev)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(&bus->bus, "spapr-vty");
+    qdev_prop_set_uint32(dev, "reg", reg);
+    qdev_prop_set_chr(dev, "chardev", chardev);
+    qdev_init_nofail(dev);
+}
+
+static void vty_hcalls(VIOsPAPRBus *bus)
+{
+    spapr_register_hypercall(H_PUT_TERM_CHAR, h_put_term_char);
+    spapr_register_hypercall(H_GET_TERM_CHAR, h_get_term_char);
+}
+
+static VIOsPAPRDeviceInfo spapr_vty = {
+    .init = spapr_vty_init,
+    .dt_name = "vty",
+    .dt_type = "serial",
+    .dt_compatible = "hvterm1",
+    .hcalls = vty_hcalls,
+    .qdev.name = "spapr-vty",
+    .qdev.size = sizeof(VIOsPAPRVTYDevice),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("reg", VIOsPAPRDevice, reg, 0),
+        DEFINE_PROP_CHR("chardev", VIOsPAPRVTYDevice, chardev),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void spapr_vty_register(void)
+{
+    spapr_vio_bus_register_withprop(&spapr_vty);
+}
+device_init(spapr_vty_register);
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 16/28] Virtual hash page table handling on pSeries machine
  2011-02-15  4:56 [Qemu-devel] RFC: Implement emulation of pSeries logical partitions (v2) qemu
                   ` (14 preceding siblings ...)
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 15/28] Implement the bus structure for PAPR virtual IO qemu
@ 2011-02-15  4:56 ` qemu
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 17/28] Implement hcall based RTAS for pSeries machines qemu
                   ` (11 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: qemu @ 2011-02-15  4:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: paulus, agraf, anton

From: David Gibson <david@gibson.dropbear.id.au>

On pSeries logical partitions, excepting the old POWER4-style full system
partitions, the guest does not have direct access to the hardware page
table.  Instead, the pagetable exists in hypervisor memory, and the guest
must manipulate it with hypercalls.

However, our current pSeries emulation more closely resembles the old
style where the guest must set up and handle the pagetables itself.  This
patch converts it to act like a modern partition.

This involves two things: first, the hash translation path is modified to
permit the has table to be stored externally to the emulated machine's
RAM.  The pSeries machine init code configures the CPUs to use this mode.

Secondly, we emulate the PAPR hypercalls for manipulating the external
hashed page table.

Signed-off-by: David Gibson <dwg@au1.ibm.com>
---
 hw/spapr.c          |   32 ++++++-
 hw/spapr_hcall.c    |  247 +++++++++++++++++++++++++++++++++++++++++++++++++++
 target-ppc/cpu.h    |    2 +
 target-ppc/helper.c |   36 ++++++--
 4 files changed, 305 insertions(+), 12 deletions(-)

diff --git a/hw/spapr.c b/hw/spapr.c
index 25e4a9e..c3d9286 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -50,12 +50,15 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize,
                               sPAPREnvironment *spapr,
                               target_phys_addr_t initrd_base,
                               target_phys_addr_t initrd_size,
-                              const char *kernel_cmdline)
+                              const char *kernel_cmdline,
+                              long hash_shift)
 {
     void *fdt;
     uint64_t mem_reg_property[] = { 0, cpu_to_be64(ramsize) };
     uint32_t start_prop = cpu_to_be32(initrd_base);
     uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
+    uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)};
+    char hypertas_prop[] = "hcall-pft\0hcall-term";
     int i;
     char *modelname;
     int ret;
@@ -138,6 +141,7 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize,
          * full emu, for kvm we should copy it from the host */
         _FDT((fdt_property_cell(fdt, "clock-frequency", 1000000000)));
         _FDT((fdt_property_cell(fdt, "ibm,slb-size", env->slb_nr)));
+        _FDT((fdt_property(fdt, "ibm,pft-size", pft_size_prop, sizeof(pft_size_prop))));
         _FDT((fdt_property_string(fdt, "status", "okay")));
         _FDT((fdt_property(fdt, "64-bit", NULL, 0)));
 
@@ -153,6 +157,14 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize,
 
     _FDT((fdt_end_node(fdt)));
 
+    /* RTAS */
+    _FDT((fdt_begin_node(fdt, "rtas")));
+
+    _FDT((fdt_property(fdt, "ibm,hypertas-functions", hypertas_prop,
+                       sizeof(hypertas_prop))));
+    
+    _FDT((fdt_end_node(fdt)));
+
     /* vdevice */
     _FDT((fdt_begin_node(fdt, "vdevice")));
 
@@ -203,12 +215,13 @@ static void ppc_spapr_init(ram_addr_t ram_size,
                            const char *cpu_model)
 {
     CPUState *envs[MAX_CPUS];
-    void *fdt;
+    void *fdt, *htab;
     int i;
     ram_addr_t ram_offset;
     target_phys_addr_t fdt_addr;
     uint32_t kernel_base, initrd_base;
-    long kernel_size, initrd_size;
+    long kernel_size, initrd_size, htab_size;
+    long pteg_shift = 17;
     int fdt_size;
     sPAPREnvironment *spapr;
 
@@ -248,6 +261,16 @@ static void ppc_spapr_init(ram_addr_t ram_size,
     ram_offset = qemu_ram_alloc(NULL, "ppc_spapr.ram", ram_size);
     cpu_register_physical_memory(0, ram_size, ram_offset);
 
+    /* allocate hash page table */
+    htab_size = 1ULL << (pteg_shift + 7);
+    htab = qemu_mallocz(htab_size);
+
+    for (i = 0; i < smp_cpus; i++) {
+        envs[i]->external_htab = htab;
+        envs[i]->htab_base = -1;
+        envs[i]->htab_mask = htab_size - 1;
+    }
+
     spapr->vio_bus = spapr_vio_bus_init();
 
     for (i = 0; i < MAX_SERIAL_PORTS; i++) {
@@ -293,7 +316,8 @@ static void ppc_spapr_init(ram_addr_t ram_size,
 
     /* Prepare the device tree */
     fdt = spapr_create_fdt(&fdt_size, ram_size, cpu_model, envs, spapr,
-                           initrd_base, initrd_size, kernel_cmdline);
+                           initrd_base, initrd_size, kernel_cmdline,
+                           pteg_shift + 7);
     if (!fdt) {
         hw_error("Couldn't create pSeries device tree\n");
         exit(1);
diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c
index 6ddac00..2b14000 100644
--- a/hw/spapr_hcall.c
+++ b/hw/spapr_hcall.c
@@ -1,8 +1,246 @@
 #include "sysemu.h"
 #include "cpu.h"
 #include "qemu-char.h"
+#include "sysemu.h"
+#include "qemu-char.h"
+#include "exec-all.h"
 #include "hw/spapr.h"
 
+#define HPTES_PER_GROUP 8
+
+#define HPTE_V_SSIZE_SHIFT      62
+#define HPTE_V_AVPN_SHIFT       7
+#define HPTE_V_AVPN             0x3fffffffffffff80ULL
+#define HPTE_V_AVPN_VAL(x)      (((x) & HPTE_V_AVPN) >> HPTE_V_AVPN_SHIFT)
+#define HPTE_V_COMPARE(x,y)     (!(((x) ^ (y)) & 0xffffffffffffff80UL))
+#define HPTE_V_BOLTED           0x0000000000000010ULL
+#define HPTE_V_LOCK             0x0000000000000008ULL
+#define HPTE_V_LARGE            0x0000000000000004ULL
+#define HPTE_V_SECONDARY        0x0000000000000002ULL
+#define HPTE_V_VALID            0x0000000000000001ULL
+
+#define HPTE_R_PP0              0x8000000000000000ULL
+#define HPTE_R_TS               0x4000000000000000ULL
+#define HPTE_R_KEY_HI           0x3000000000000000ULL
+#define HPTE_R_RPN_SHIFT        12
+#define HPTE_R_RPN              0x3ffffffffffff000ULL
+#define HPTE_R_FLAGS            0x00000000000003ffULL
+#define HPTE_R_PP               0x0000000000000003ULL
+#define HPTE_R_N                0x0000000000000004ULL
+#define HPTE_R_G                0x0000000000000008ULL
+#define HPTE_R_M                0x0000000000000010ULL
+#define HPTE_R_I                0x0000000000000020ULL
+#define HPTE_R_W                0x0000000000000040ULL
+#define HPTE_R_WIMG             0x0000000000000078ULL
+#define HPTE_R_C                0x0000000000000080ULL
+#define HPTE_R_R                0x0000000000000100ULL
+#define HPTE_R_KEY_LO           0x0000000000000e00ULL
+
+#define HPTE_V_1TB_SEG          0x4000000000000000ULL
+#define HPTE_V_VRMA_MASK        0x4001ffffff000000ULL
+
+#define HPTE_V_HVLOCK           0x40ULL
+
+static inline int lock_hpte(void *hpte, target_ulong bits)
+{
+    uint64_t pteh;
+
+    pteh = ldq_p(hpte);
+
+    /* FIXME: probably need some sort of lockage for SMP */
+    if (pteh & bits) {
+        return 0;
+    }
+    stq_p(hpte, pteh | HPTE_V_HVLOCK);
+    return 1;
+}
+
+static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r,
+                                     target_ulong pte_index)
+{
+    target_ulong rb, va_low;
+
+    rb = (v & ~0x7fULL) << 16; /* AVA field */
+    va_low = pte_index >> 3;
+    if (v & HPTE_V_SECONDARY)
+        va_low = ~va_low;
+    /* xor vsid from AVA */
+    if (!(v & HPTE_V_1TB_SEG))
+        va_low ^= v >> 12;
+    else
+        va_low ^= v >> 24;
+    va_low &= 0x7ff;
+    if (v & HPTE_V_LARGE) {
+        rb |= 1;                         /* L field */
+#if 0 /* Disable that P7 specific bit for now */
+        if (r & 0xff000) {
+            /* non-16MB large page, must be 64k */
+            /* (masks depend on page size) */
+            rb |= 0x1000;                /* page encoding in LP field */
+            rb |= (va_low & 0x7f) << 16; /* 7b of VA in AVA/LP field */
+            rb |= (va_low & 0xfe);       /* AVAL field */
+        }
+#endif
+    } else {
+        /* 4kB page */
+        rb |= (va_low & 0x7ff) << 12;   /* remaining 11b of AVA */
+    }
+    rb |= (v >> 54) & 0x300;            /* B field */
+    return rb;
+}
+
+static target_ulong h_enter(CPUState *env, sPAPREnvironment *spapr,
+                            target_ulong opcode, target_ulong *args)
+{
+    target_ulong flags = args[0];
+    target_ulong pte_index = args[1];
+    target_ulong pteh = args[2];
+    target_ulong ptel = args[3];
+    target_ulong porder;
+    target_ulong i, pa;
+    uint8_t *hpte;
+
+    /* only handle 4k and 16M pages for now */
+    porder = 12;
+    if (pteh & HPTE_V_LARGE) {
+        if ((ptel & 0xf000) == 0x1000) {
+            /* 64k page */
+            porder = 16;
+        } else if ((ptel & 0xff000) == 0) {
+            /* 16M page */
+            porder = 24;
+            /* lowest AVA bit must be 0 for 16M pages */
+            if (pteh & 0x80)
+                return H_PARAMETER;
+        } else {
+            return H_PARAMETER;
+        }
+    }
+
+    pa = ptel & HPTE_R_RPN;
+    /* FIXME: bounds check the pa? */
+
+    /* Check WIMG */
+    if ((ptel & HPTE_R_WIMG) != HPTE_R_M)
+        return H_PARAMETER;
+    pteh &= ~0x60ULL;
+
+    if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask)
+        return H_PARAMETER;
+    if (likely((flags & H_EXACT) == 0)) {
+        pte_index &= ~7ULL;
+        hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64);
+        for (i = 0; ; ++i) {
+            if (i == 8)
+                return H_PTEG_FULL;
+            if (((ldq_p(hpte) & HPTE_V_VALID) == 0) &&
+                lock_hpte(hpte, HPTE_V_HVLOCK | HPTE_V_VALID)) {
+                break;
+            }
+            hpte += HASH_PTE_SIZE_64;
+        }
+    } else {
+        i = 0;
+        hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64);
+        if (!lock_hpte(hpte, HPTE_V_HVLOCK | HPTE_V_VALID)) {
+            return H_PTEG_FULL;
+        }
+    }
+    stq_p(hpte + (HASH_PTE_SIZE_64/2), ptel);
+    /* eieio();  FIXME: need some sort of barrier for smp? */
+    stq_p(hpte, pteh);
+
+    assert (!(ldq_p(hpte) & HPTE_V_HVLOCK));
+    args[0] = pte_index + i;
+    return H_SUCCESS;
+}
+
+static target_ulong h_remove(CPUState *env, sPAPREnvironment *spapr,
+                             target_ulong opcode, target_ulong *args)
+{
+    target_ulong flags = args[0];
+    target_ulong pte_index = args[1];
+    target_ulong avpn = args[2];
+    uint8_t *hpte;
+    target_ulong v, r, rb;
+
+    if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
+        return H_PARAMETER;
+    }
+
+    hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64);
+    while (!lock_hpte(hpte, HPTE_V_HVLOCK)) {
+        /* We have no real concurrency in qemu soft-emulation, so we
+         * will never actually have a contested lock */
+        assert(0);
+    }
+
+    v = ldq_p(hpte);
+    r = ldq_p(hpte + (HASH_PTE_SIZE_64/2));
+
+    if ((v & HPTE_V_VALID) == 0 ||
+        ((flags & H_AVPN) && (v & ~0x7fULL) != avpn) ||
+        ((flags & H_ANDCOND) && (v & avpn) != 0)) {
+        stq_p(hpte, v & ~HPTE_V_HVLOCK);
+        assert (!(ldq_p(hpte) & HPTE_V_HVLOCK));
+        return H_NOT_FOUND;
+    }
+    args[0] = v & ~HPTE_V_HVLOCK;
+    args[1] = r;
+    stq_p(hpte, 0);
+    rb = compute_tlbie_rb(v, r, pte_index);
+//    ppc_tlb_invalidate_one(env, rb);
+    tlb_flush(env, 1);
+    assert (!(ldq_p(hpte) & HPTE_V_HVLOCK));
+    return H_SUCCESS;
+}
+
+static target_ulong h_protect(CPUState *env, sPAPREnvironment *spapr,
+                              target_ulong opcode, target_ulong *args)
+{
+    target_ulong flags = args[0];
+    target_ulong pte_index = args[1];
+    target_ulong avpn = args[2];
+    uint8_t *hpte;
+    target_ulong v, r, rb;
+
+    if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
+        return H_PARAMETER;
+    }
+
+    hpte = env->external_htab + (pte_index * HASH_PTE_SIZE_64);
+    while (!lock_hpte(hpte, HPTE_V_HVLOCK)) {
+        /* We have no real concurrency in qemu soft-emulation, so we
+         * will never actually have a contested lock */
+        assert(0);
+    }
+
+    v = ldq_p(hpte);
+    r = ldq_p(hpte + (HASH_PTE_SIZE_64/2));
+
+    if ((v & HPTE_V_VALID) == 0 ||
+        ((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) {
+        stq_p(hpte, v & ~HPTE_V_HVLOCK);
+        assert (!(ldq_p(hpte) & HPTE_V_HVLOCK));
+        return H_NOT_FOUND;
+    }
+
+    r &= ~(HPTE_R_PP0 | HPTE_R_PP | HPTE_R_N |
+           HPTE_R_KEY_HI | HPTE_R_KEY_LO);
+    r |= (flags << 55) & HPTE_R_PP0;
+    r |= (flags << 48) & HPTE_R_KEY_HI;
+    r |= flags & (HPTE_R_PP | HPTE_R_N | HPTE_R_KEY_LO);
+    rb = compute_tlbie_rb(v, r, pte_index);
+    stq_p(hpte, v & ~HPTE_V_VALID);
+    //ppc_tlb_invalidate_one(env, rb);
+    tlb_flush(env, 1);
+    stq_p(hpte + (HASH_PTE_SIZE_64/2), r);
+    /* eieio(); FIXME: need some sort of barrier on smp? */
+    stq_p(hpte, v & ~HPTE_V_HVLOCK);
+    assert (!(ldq_p(hpte) & HPTE_V_HVLOCK));
+    return H_SUCCESS;
+}
+
 struct hypercall {
     spapr_hcall_fn fn;
 } hypercall_table[(MAX_HCALL_OPCODE / 4) + 1];
@@ -41,3 +279,12 @@ target_ulong spapr_hypercall(CPUState *env, sPAPREnvironment *spapr,
     fprintf(stderr, "Unimplemented hcall 0x" TARGET_FMT_lx "\n", opcode);
     return H_FUNCTION;
 }
+
+static void hypercall_init(void)
+{
+    /* hcall-pft */
+    spapr_register_hypercall(H_ENTER, h_enter);
+    spapr_register_hypercall(H_REMOVE, h_remove);
+    spapr_register_hypercall(H_PROTECT, h_protect);
+}
+device_init(hypercall_init);
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 3a47d11..29d6b49 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -670,6 +670,8 @@ struct CPUPPCState {
     target_phys_addr_t htab_base;
     target_phys_addr_t htab_mask;
     target_ulong sr[32];
+    /* externally stored hash table */
+    uint8_t *external_htab;
     /* BATs */
     int nb_BATs;
     target_ulong DBAT[2][8];
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 13a5ab1..5ead62f 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -585,8 +585,13 @@ static inline int _find_pte(CPUState *env, mmu_ctx_t *ctx, int is_64b, int h,
     for (i = 0; i < 8; i++) {
 #if defined(TARGET_PPC64)
         if (is_64b) {
-            pte0 = ldq_phys(env->htab_base + pteg_off + (i * 16));
-            pte1 = ldq_phys(env->htab_base + pteg_off + (i * 16) + 8);
+            if (env->external_htab) {
+                pte0 = ldq_p(env->external_htab + pteg_off + (i * 16));
+                pte1 = ldq_p(env->external_htab + pteg_off + (i * 16) + 8);
+            } else {
+                pte0 = ldq_phys(env->htab_base + pteg_off + (i * 16));
+                pte1 = ldq_phys(env->htab_base + pteg_off + (i * 16) + 8);
+            }
 
             /* We have a TLB that saves 4K pages, so let's
              * split a huge page to 4k chunks */
@@ -602,8 +607,13 @@ static inline int _find_pte(CPUState *env, mmu_ctx_t *ctx, int is_64b, int h,
         } else
 #endif
         {
-            pte0 = ldl_phys(env->htab_base + pteg_off + (i * 8));
-            pte1 =  ldl_phys(env->htab_base + pteg_off + (i * 8) + 4);
+            if (env->external_htab) {
+                pte0 = ldl_p(env->external_htab + pteg_off + (i * 8));
+                pte1 = ldl_p(env->external_htab + pteg_off + (i * 8) + 4);
+            } else {
+                pte0 = ldl_phys(env->htab_base + pteg_off + (i * 8));
+                pte1 = ldl_phys(env->htab_base + pteg_off + (i * 8) + 4);
+            }
             r = pte32_check(ctx, pte0, pte1, h, rw, type);
             LOG_MMU("Load pte from " TARGET_FMT_lx " => " TARGET_FMT_lx " "
                     TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n",
@@ -643,13 +653,23 @@ static inline int _find_pte(CPUState *env, mmu_ctx_t *ctx, int is_64b, int h,
         if (pte_update_flags(ctx, &pte1, ret, rw) == 1) {
 #if defined(TARGET_PPC64)
             if (is_64b) {
-                stq_phys_notdirty(env->htab_base + pteg_off + (good * 16) + 8,
-                                  pte1);
+                if (env->external_htab) {
+                    stq_p(env->external_htab + pteg_off + (good * 16) + 8,
+                          pte1);
+                } else {
+                    stq_phys_notdirty(env->htab_base + pteg_off +
+                                      (good * 16) + 8, pte1);
+                }
             } else
 #endif
             {
-                stl_phys_notdirty(env->htab_base + pteg_off + (good * 8) + 4,
-                                  pte1);
+                if (env->external_htab) {
+                    stl_p(env->external_htab + pteg_off + (good * 8) + 4,
+                          pte1);
+                } else {
+                    stl_phys_notdirty(env->htab_base + pteg_off +
+                                      (good * 8) + 4, pte1);
+                }
             }
         }
     }
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 17/28] Implement hcall based RTAS for pSeries machines
  2011-02-15  4:56 [Qemu-devel] RFC: Implement emulation of pSeries logical partitions (v2) qemu
                   ` (15 preceding siblings ...)
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 16/28] Virtual hash page table handling on pSeries machine qemu
@ 2011-02-15  4:56 ` qemu
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 18/28] Implement assorted pSeries hcalls and RTAS methods qemu
                   ` (10 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: qemu @ 2011-02-15  4:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: paulus, agraf, anton

From: David Gibson <david@gibson.dropbear.id.au>

On pSeries machines, operating systems can instantiate "RTAS" (Run-Time
Abstraction Services), a runtime component of the firmware which implements
a number of low-level, infrequently used operations.  On logical partitions
under a hypervisor, many of the RTAS functions require hypervisor
privilege.  For simplicity, therefore, hypervisor systems typically
implement the in-partition RTAS as just a tiny wrapper around a hypercall
which actually implements the various RTAS functions.

This patch implements such a hypercall based RTAS for our emulated pSeries
machine.  A tiny in-partition "firmware" calls a new hypercall, which
looks up available RTAS services in a table.


Signed-off-by: David Gibson <dwg@au1.ibm.com>
---
 Makefile               |    3 +-
 Makefile.target        |    2 +-
 hw/spapr.c             |   27 +++++++++++--
 hw/spapr.h             |   21 ++++++++++
 hw/spapr_hcall.c       |   15 +++++++
 hw/spapr_rtas.c        |  104 ++++++++++++++++++++++++++++++++++++++++++++++++
 pc-bios/spapr-rtas.bin |  Bin 0 -> 20 bytes
 7 files changed, 166 insertions(+), 6 deletions(-)
 create mode 100644 hw/spapr_rtas.c
 create mode 100644 pc-bios/spapr-rtas.bin

diff --git a/Makefile b/Makefile
index eca4c76..fc4bd24 100644
--- a/Makefile
+++ b/Makefile
@@ -213,7 +213,8 @@ pxe-ne2k_pci.bin pxe-pcnet.bin \
 pxe-rtl8139.bin pxe-virtio.bin \
 bamboo.dtb petalogix-s3adsp1800.dtb \
 multiboot.bin linuxboot.bin \
-s390-zipl.rom
+s390-zipl.rom \
+spapr-rtas.bin
 else
 BLOBS=
 endif
diff --git a/Makefile.target b/Makefile.target
index ba243bf..fa59109 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -232,7 +232,7 @@ obj-ppc-y += ppc_oldworld.o
 # NewWorld PowerMac
 obj-ppc-y += ppc_newworld.o
 # IBM pSeries (sPAPR)
-obj-ppc-y += spapr.o spapr_hcall.o spapr_vio.o
+obj-ppc-y += spapr.o spapr_hcall.o spapr_rtas.o spapr_vio.o
 obj-ppc-y += spapr_vty.o
 # PowerPC 4xx boards
 obj-ppc-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
diff --git a/hw/spapr.c b/hw/spapr.c
index c3d9286..f41451b 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -40,6 +40,7 @@
 #define KERNEL_LOAD_ADDR        0x00000000
 #define INITRD_LOAD_ADDR        0x02800000
 #define FDT_MAX_SIZE            0x10000
+#define RTAS_MAX_SIZE           0x10000
 
 #define TIMEBASE_FREQ           512000000ULL
 
@@ -51,6 +52,8 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize,
                               target_phys_addr_t initrd_base,
                               target_phys_addr_t initrd_size,
                               const char *kernel_cmdline,
+                              target_phys_addr_t rtas_addr,
+                              target_phys_addr_t rtas_size,
                               long hash_shift)
 {
     void *fdt;
@@ -162,7 +165,7 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize,
 
     _FDT((fdt_property(fdt, "ibm,hypertas-functions", hypertas_prop,
                        sizeof(hypertas_prop))));
-    
+
     _FDT((fdt_end_node(fdt)));
 
     /* vdevice */
@@ -186,6 +189,11 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize,
         fprintf(stderr, "couldn't setup vio devices in fdt\n");
     }
 
+    /* RTAS */
+    ret = spapr_rtas_device_tree_setup(fdt, rtas_addr, rtas_size);
+    if (ret < 0)
+        fprintf(stderr, "Couldn't set up RTAS device tree properties\n");
+
     _FDT((fdt_pack(fdt)));
 
     if (fdt_size) {
@@ -218,12 +226,13 @@ static void ppc_spapr_init(ram_addr_t ram_size,
     void *fdt, *htab;
     int i;
     ram_addr_t ram_offset;
-    target_phys_addr_t fdt_addr;
+    target_phys_addr_t fdt_addr, rtas_addr;
     uint32_t kernel_base, initrd_base;
-    long kernel_size, initrd_size, htab_size;
+    long kernel_size, initrd_size, htab_size, rtas_size;
     long pteg_shift = 17;
     int fdt_size;
     sPAPREnvironment *spapr;
+    char *filename;
 
     spapr = qemu_malloc(sizeof(*spapr));
 
@@ -231,6 +240,8 @@ static void ppc_spapr_init(ram_addr_t ram_size,
      * 2GB, so that it can be processed with 32-bit code if
      * necessary */
     fdt_addr = MIN(ram_size, 0x80000000) - FDT_MAX_SIZE;
+    /* RTAS goes just below that */
+    rtas_addr = fdt_addr - RTAS_MAX_SIZE;
 
     /* init CPUs */
     if (cpu_model == NULL) {
@@ -271,6 +282,14 @@ static void ppc_spapr_init(ram_addr_t ram_size,
         envs[i]->htab_mask = htab_size - 1;
     }
 
+    filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin");
+    rtas_size = load_image_targphys(filename, rtas_addr, ram_size - rtas_addr);
+    if (rtas_size < 0) {
+        hw_error("qemu: could not load LPAR rtas '%s'\n", filename);
+        exit(1);
+    }
+    qemu_free(filename);
+
     spapr->vio_bus = spapr_vio_bus_init();
 
     for (i = 0; i < MAX_SERIAL_PORTS; i++) {
@@ -317,7 +336,7 @@ static void ppc_spapr_init(ram_addr_t ram_size,
     /* Prepare the device tree */
     fdt = spapr_create_fdt(&fdt_size, ram_size, cpu_model, envs, spapr,
                            initrd_base, initrd_size, kernel_cmdline,
-                           pteg_shift + 7);
+                           rtas_addr, rtas_size, pteg_shift + 7);
     if (!fdt) {
         hw_error("Couldn't create pSeries device tree\n");
         exit(1);
diff --git a/hw/spapr.h b/hw/spapr.h
index 47bf2ef..7a7c319 100644
--- a/hw/spapr.h
+++ b/hw/spapr.h
@@ -237,6 +237,8 @@ typedef struct sPAPREnvironment {
 #define H_GET_MPP               0x2D4
 #define MAX_HCALL_OPCODE        H_GET_MPP
 
+#define H_RTAS                  0x72746173
+
 typedef target_ulong (*spapr_hcall_fn)(CPUState *env, sPAPREnvironment *spapr,
                                        target_ulong opcode,
                                        target_ulong *args);
@@ -245,5 +247,24 @@ void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn);
 target_ulong spapr_hypercall(CPUState *env, sPAPREnvironment *spapr,
                              target_ulong opcode, target_ulong *args);
 
+static inline uint32_t rtas_ld(target_ulong phys, int n)
+{
+    return ldl_phys(phys + 4*n);
+}
+
+static inline void rtas_st(target_ulong phys, int n, uint32_t val)
+{
+    stl_phys(phys + 4*n, val);
+}
+
+typedef void (*spapr_rtas_fn)(sPAPREnvironment *spapr, uint32_t token,
+                              uint32_t nargs, target_ulong args,
+                              uint32_t nret, target_ulong rets);
+void spapr_rtas_register(const char *name, spapr_rtas_fn fn);
+target_ulong spapr_rtas_call(sPAPREnvironment *spapr,
+                             uint32_t token, uint32_t nargs, target_ulong args,
+                             uint32_t nret, target_ulong rets);
+int spapr_rtas_device_tree_setup(void *fdt, target_phys_addr_t rtas_addr,
+                                 target_phys_addr_t rtas_size);
 
 #endif /* !defined (__HW_SPAPR_H__) */
diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c
index 2b14000..7b8e17c 100644
--- a/hw/spapr_hcall.c
+++ b/hw/spapr_hcall.c
@@ -241,6 +241,16 @@ static target_ulong h_protect(CPUState *env, sPAPREnvironment *spapr,
     return H_SUCCESS;
 }
 
+static target_ulong h_rtas(sPAPREnvironment *spapr, target_ulong rtas_r3)
+{
+    uint32_t token = ldl_phys(rtas_r3);
+    uint32_t nargs = ldl_phys(rtas_r3 + 4);
+    uint32_t nret = ldl_phys(rtas_r3 + 8);
+
+    return spapr_rtas_call(spapr, token, nargs, rtas_r3 + 12,
+                           nret, rtas_r3 + 12 + 4*nargs);
+}
+
 struct hypercall {
     spapr_hcall_fn fn;
 } hypercall_table[(MAX_HCALL_OPCODE / 4) + 1];
@@ -276,6 +286,11 @@ target_ulong spapr_hypercall(CPUState *env, sPAPREnvironment *spapr,
             return hc->fn(env, spapr, opcode, args);
     }
 
+    if (opcode == H_RTAS) {
+        /* H_RTAS is a special case outside the normal range */
+        return h_rtas(spapr, args[0]);
+    }
+
     fprintf(stderr, "Unimplemented hcall 0x" TARGET_FMT_lx "\n", opcode);
     return H_FUNCTION;
 }
diff --git a/hw/spapr_rtas.c b/hw/spapr_rtas.c
new file mode 100644
index 0000000..c606018
--- /dev/null
+++ b/hw/spapr_rtas.c
@@ -0,0 +1,104 @@
+#include "cpu.h"
+#include "sysemu.h"
+#include "qemu-char.h"
+#include "hw/qdev.h"
+#include "device_tree.h"
+
+#include "hw/spapr.h"
+#include "hw/spapr_vio.h"
+
+#include <libfdt.h>
+
+#define TOKEN_BASE      0x2000
+#define TOKEN_MAX       0x100
+
+static struct rtas_call {
+    const char *name;
+    spapr_rtas_fn fn;
+} rtas_table[TOKEN_MAX];
+
+struct rtas_call *rtas_next = rtas_table;
+
+target_ulong spapr_rtas_call(sPAPREnvironment *spapr,
+                             uint32_t token, uint32_t nargs, target_ulong args,
+                             uint32_t nret, target_ulong rets)
+{
+    if ((token >= TOKEN_BASE)
+        && ((token - TOKEN_BASE) < TOKEN_MAX)) {
+        struct rtas_call *call = rtas_table + (token - TOKEN_BASE);
+
+        if (call->fn) {
+            call->fn(spapr, token, nargs, args, nret, rets);
+            return H_SUCCESS;
+        }
+    }
+
+    fprintf(stderr, "Unknown RTAS token 0x%x\n", token);
+    rtas_st(rets, 0, -3);
+    return H_PARAMETER;
+}
+
+void spapr_rtas_register(const char *name, spapr_rtas_fn fn)
+{
+    assert(rtas_next < (rtas_table + TOKEN_MAX));
+
+    rtas_next->name = name;
+    rtas_next->fn = fn;
+
+    rtas_next++;
+}
+
+int spapr_rtas_device_tree_setup(void *fdt, target_phys_addr_t rtas_addr,
+                                 target_phys_addr_t rtas_size)
+{
+    int ret;
+    int i;
+
+    ret = fdt_add_mem_rsv(fdt, rtas_addr, rtas_size);
+    if (ret < 0) {
+        fprintf(stderr, "Couldn't add RTAS reserve entry: %s\n",
+                fdt_strerror(ret));
+        return ret;
+    }
+
+    ret = qemu_devtree_setprop_cell(fdt, "/rtas", "linux,rtas-base",
+                                    rtas_addr);
+    if (ret < 0) {
+        fprintf(stderr, "Couldn't add linux,rtas-base property: %s\n",
+                fdt_strerror(ret));
+        return ret;
+    }
+
+    ret = qemu_devtree_setprop_cell(fdt, "/rtas", "linux,rtas-entry",
+                                    rtas_addr);
+    if (ret < 0) {
+        fprintf(stderr, "Couldn't add linux,rtas-entry property: %s\n",
+                fdt_strerror(ret));
+        return ret;
+    }
+
+    ret = qemu_devtree_setprop_cell(fdt, "/rtas", "rtas-size",
+                                    rtas_size);
+    if (ret < 0) {
+        fprintf(stderr, "Couldn't add rtas-size property: %s\n",
+                fdt_strerror(ret));
+        return ret;
+    }
+
+    for (i = 0; i < TOKEN_MAX; i++) {
+        struct rtas_call *call = &rtas_table[i];
+
+        if (!call->fn) {
+            continue;
+        }
+
+        ret = qemu_devtree_setprop_cell(fdt, "/rtas", call->name, i + TOKEN_BASE);
+        if (ret < 0) {
+            fprintf(stderr, "Couldn't add rtas token for %s: %s\n",
+                    call->name, fdt_strerror(ret));
+            return ret;
+        }
+
+    }
+    return 0;
+}
diff --git a/pc-bios/spapr-rtas.bin b/pc-bios/spapr-rtas.bin
new file mode 100644
index 0000000000000000000000000000000000000000..eade9c0e8ff0fd3071e3a6638a11c1a2e9a47152
GIT binary patch
literal 20
bcmb<Pk*=^wC@M)vPAqm|U{LaFU{C-6M#cr<

literal 0
HcmV?d00001

-- 
1.7.1

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 18/28] Implement assorted pSeries hcalls and RTAS methods
  2011-02-15  4:56 [Qemu-devel] RFC: Implement emulation of pSeries logical partitions (v2) qemu
                   ` (16 preceding siblings ...)
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 17/28] Implement hcall based RTAS for pSeries machines qemu
@ 2011-02-15  4:56 ` qemu
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 19/28] Implement the PAPR (pSeries) virtualized interrupt controller (xics) qemu
                   ` (9 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: qemu @ 2011-02-15  4:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: paulus, agraf, anton

From: David Gibson <dgibson@yookeroo.(none)>

This patch adds several small utility hypercalls and RTAS methods to
the pSeries platform emulation.  Specifically:

* 'display-character' rtas call

This just prints a character to the console, it's occasionally used
for early debug of the OS.  The support includes a hack to make this
RTAS call respond on the normal token value present on real hardware,
since some early debugging tools just assume this value without
checking the device tree.

* 'get-time-of-day' rtas call

This one just takes the host real time, converts to the PAPR described
format and returns it to the guest.

* 'power-off' rtas call

This one shuts down the emulated system.

* H_DABR hypercall

On pSeries, the DABR debug register is usually a hypervisor resource
and virtualized through this hypercall.  If the hypercall is not
present, Linux will under some circumstances attempt to manipulate the
DABR directly which will fail on this emulated machine.

This stub implementation is enough to stop that behaviour, although it
doesn't actually implement the requested DABR operations as yet.

Signed-off-by: David Gibson <dwg@au1.ibm.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
---
 hw/spapr.c       |    2 +-
 hw/spapr_hcall.c |   10 ++++++++
 hw/spapr_rtas.c  |   69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 80 insertions(+), 1 deletions(-)

diff --git a/hw/spapr.c b/hw/spapr.c
index f41451b..23f493a 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -61,7 +61,7 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize,
     uint32_t start_prop = cpu_to_be32(initrd_base);
     uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
     uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)};
-    char hypertas_prop[] = "hcall-pft\0hcall-term";
+    char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr";
     int i;
     char *modelname;
     int ret;
diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c
index 7b8e17c..0ff83c9 100644
--- a/hw/spapr_hcall.c
+++ b/hw/spapr_hcall.c
@@ -241,6 +241,13 @@ static target_ulong h_protect(CPUState *env, sPAPREnvironment *spapr,
     return H_SUCCESS;
 }
 
+static target_ulong h_set_dabr(CPUState *env, sPAPREnvironment *spapr,
+                               target_ulong opcode, target_ulong *args)
+{
+    /* FIXME: actually implement this */
+    return H_HARDWARE;
+}
+
 static target_ulong h_rtas(sPAPREnvironment *spapr, target_ulong rtas_r3)
 {
     uint32_t token = ldl_phys(rtas_r3);
@@ -301,5 +308,8 @@ static void hypercall_init(void)
     spapr_register_hypercall(H_ENTER, h_enter);
     spapr_register_hypercall(H_REMOVE, h_remove);
     spapr_register_hypercall(H_PROTECT, h_protect);
+
+    /* hcall-dabr */
+    spapr_register_hypercall(H_SET_DABR, h_set_dabr);
 }
 device_init(hypercall_init);
diff --git a/hw/spapr_rtas.c b/hw/spapr_rtas.c
index c606018..354f4df 100644
--- a/hw/spapr_rtas.c
+++ b/hw/spapr_rtas.c
@@ -12,6 +12,58 @@
 #define TOKEN_BASE      0x2000
 #define TOKEN_MAX       0x100
 
+static void rtas_display_character(sPAPREnvironment *spapr,
+                                   uint32_t token, uint32_t nargs,
+                                   target_ulong args,
+                                   uint32_t nret, target_ulong rets)
+{
+    uint8_t c = rtas_ld(args, 0);
+    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, 0);
+
+    if (!sdev) {
+        rtas_st(rets, 0, -1);
+    } else {
+        vty_putchars(sdev, &c, sizeof(c));
+        rtas_st(rets, 0, 0);
+    }
+}
+
+static void rtas_get_time_of_day(sPAPREnvironment *spapr,
+                                 uint32_t token, uint32_t nargs,
+                                 target_ulong args,
+                                 uint32_t nret, target_ulong rets)
+{
+    struct tm tm;
+
+    if (nret != 8) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    qemu_get_timedate(&tm, 0);    
+
+    rtas_st(rets, 0, 0); /* Success */
+    rtas_st(rets, 1, tm.tm_year + 1900);
+    rtas_st(rets, 2, tm.tm_mon + 1);
+    rtas_st(rets, 3, tm.tm_mday);
+    rtas_st(rets, 4, tm.tm_hour);
+    rtas_st(rets, 5, tm.tm_min);
+    rtas_st(rets, 6, tm.tm_sec);
+    rtas_st(rets, 7, 0); /* we don't do nanoseconds */
+}
+
+static void rtas_power_off(sPAPREnvironment *spapr,
+                           uint32_t token, uint32_t nargs, target_ulong args,
+                           uint32_t nret, target_ulong rets)
+{
+    if (nargs != 2 || nret != 1) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+    qemu_system_shutdown_request();
+    rtas_st(rets, 0, 0);
+}
+
 static struct rtas_call {
     const char *name;
     spapr_rtas_fn fn;
@@ -33,6 +85,15 @@ target_ulong spapr_rtas_call(sPAPREnvironment *spapr,
         }
     }
 
+    /* HACK: Some Linux early debug code uses RTAS display-character,
+     * but assumes the token value is 0xa (which it is on some real
+     * machines) without looking it up in the device tree.  This
+     * special case makes this work */
+    if (token == 0xa) {
+        rtas_display_character(spapr, 0xa, nargs, args, nret, rets);
+        return H_SUCCESS;
+    }
+
     fprintf(stderr, "Unknown RTAS token 0x%x\n", token);
     rtas_st(rets, 0, -3);
     return H_PARAMETER;
@@ -102,3 +163,11 @@ int spapr_rtas_device_tree_setup(void *fdt, target_phys_addr_t rtas_addr,
     }
     return 0;
 }
+
+static void register_core_rtas(void)
+{
+    spapr_rtas_register("display-character", rtas_display_character);
+    spapr_rtas_register("get-time-of-day", rtas_get_time_of_day);
+    spapr_rtas_register("power-off", rtas_power_off);
+}
+device_init(register_core_rtas);
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 19/28] Implement the PAPR (pSeries) virtualized interrupt controller (xics)
  2011-02-15  4:56 [Qemu-devel] RFC: Implement emulation of pSeries logical partitions (v2) qemu
                   ` (17 preceding siblings ...)
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 18/28] Implement assorted pSeries hcalls and RTAS methods qemu
@ 2011-02-15  4:56 ` qemu
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 20/28] Add PAPR H_VIO_SIGNAL hypercall and infrastructure for VIO interrupts qemu
                   ` (8 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: qemu @ 2011-02-15  4:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: paulus, agraf, anton

From: David Gibson <david@gibson.dropbear.id.au>

PAPR defines an interrupt control architecture which is logically divided
into ICS (Interrupt Control Presentation, each unit is responsible for
presenting interrupts to a particular "interrupt server", i.e. CPU) and
ICS (Interrupt Control Source, each unit responsible for one or more
hardware interrupts as numbered globally across the system).  All PAPR
virtual IO devices expect to deliver interrupts via this mechanism.  In
Linux, this interrupt controller system is handled by the "xics" driver.

On pSeries systems, access to the interrupt controller is virtualized via
hypercalls and RTAS methods.  However, the virtualized interface is very
similar to the underlying interrupt controller hardware, and similar PICs
exist un-virtualized in some other systems.

This patch implements both the ICP and ICS sides of the PAPR interrupt
controller.  For now, only the hypercall virtualized interface is provided,
however it would be relatively straightforward to graft an emulated
register interface onto the underlying interrupt logic if we want to add
a machine with a hardware ICS/ICP system in the future.

There are some limitations in this implementation: it is assumed for now
that only one instance of the ICS exists, although a full xics system can
have several, each responsible for a different group of hardware irqs.
ICP/ICS can handle both level-sensitve (LSI) and message signalled (MSI)
interrupt inputs.  For now, this implementation supports only MSI
interrupts, since that is used by PAPR virtual IO devices.

Signed-off-by: David Gibson <dwg@au1.ibm.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
---
 Makefile.target |    2 +-
 hw/spapr.c      |   26 +++
 hw/spapr.h      |    2 +
 hw/xics.c       |  528 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/xics.h       |   13 ++
 5 files changed, 570 insertions(+), 1 deletions(-)
 create mode 100644 hw/xics.c
 create mode 100644 hw/xics.h

diff --git a/Makefile.target b/Makefile.target
index fa59109..00cb554 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -233,7 +233,7 @@ obj-ppc-y += ppc_oldworld.o
 obj-ppc-y += ppc_newworld.o
 # IBM pSeries (sPAPR)
 obj-ppc-y += spapr.o spapr_hcall.o spapr_rtas.o spapr_vio.o
-obj-ppc-y += spapr_vty.o
+obj-ppc-y += xics.o spapr_vty.o
 # PowerPC 4xx boards
 obj-ppc-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
 obj-ppc-y += ppc440.o ppc440_bamboo.o
diff --git a/hw/spapr.c b/hw/spapr.c
index 23f493a..be30def 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -34,6 +34,7 @@
 
 #include "hw/spapr.h"
 #include "hw/spapr_vio.h"
+#include "hw/xics.h"
 
 #include <libfdt.h>
 
@@ -62,6 +63,7 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize,
     uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
     uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)};
     char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr";
+    uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)};
     int i;
     char *modelname;
     int ret;
@@ -120,6 +122,7 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize,
 
     for (i = 0; i < smp_cpus; i++) {
         CPUState *env = envs[i];
+        uint32_t gserver_prop[] = {cpu_to_be32(i), 0}; /* HACK! */
         char *nodename;
         uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
                            0xffffffff, 0xffffffff};
@@ -147,6 +150,9 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize,
         _FDT((fdt_property(fdt, "ibm,pft-size", pft_size_prop, sizeof(pft_size_prop))));
         _FDT((fdt_property_string(fdt, "status", "okay")));
         _FDT((fdt_property(fdt, "64-bit", NULL, 0)));
+        _FDT((fdt_property_cell(fdt, "ibm,ppc-interrupt-server#s", i)));
+        _FDT((fdt_property(fdt, "ibm,ppc-interrupt-gserver#s", 
+                           gserver_prop, sizeof(gserver_prop))));
 
         if (envs[i]->mmu_model & POWERPC_MMU_1TSEG) {
             _FDT((fdt_property(fdt, "ibm,processor-segment-sizes",
@@ -168,6 +174,20 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize,
 
     _FDT((fdt_end_node(fdt)));
 
+    /* interrupt controller */ 
+    _FDT((fdt_begin_node(fdt, "interrupt-controller@0")));
+
+    _FDT((fdt_property_string(fdt, "device_type",
+                              "PowerPC-External-Interrupt-Presentation")));
+    _FDT((fdt_property_string(fdt, "compatible", "IBM,ppc-xicp")));
+    _FDT((fdt_property_cell(fdt, "reg", 0)));    
+    _FDT((fdt_property(fdt, "interrupt-controller", NULL, 0)));
+    _FDT((fdt_property(fdt, "ibm,interrupt-server-ranges",
+                       interrupt_server_ranges_prop,
+                       sizeof(interrupt_server_ranges_prop))));
+
+    _FDT((fdt_end_node(fdt)));
+   
     /* vdevice */
     _FDT((fdt_begin_node(fdt, "vdevice")));
 
@@ -175,6 +195,8 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize,
     _FDT((fdt_property_string(fdt, "compatible", "IBM,vdevice")));
     _FDT((fdt_property_cell(fdt, "#address-cells", 0x1)));
     _FDT((fdt_property_cell(fdt, "#size-cells", 0x0)));
+    _FDT((fdt_property_cell(fdt, "#interrupt-cells", 0x2)));
+    _FDT((fdt_property(fdt, "interrupt-controller", NULL, 0)));
     
     _FDT((fdt_end_node(fdt)));
 
@@ -290,6 +312,10 @@ static void ppc_spapr_init(ram_addr_t ram_size,
     }
     qemu_free(filename);
 
+    /* Set up Interrupt Controller */
+    spapr->icp = xics_system_init(smp_cpus, &env, MAX_SERIAL_PORTS);
+
+    /* Set up VIO bus */
     spapr->vio_bus = spapr_vio_bus_init();
 
     for (i = 0; i < MAX_SERIAL_PORTS; i++) {
diff --git a/hw/spapr.h b/hw/spapr.h
index 7a7c319..4b54c22 100644
--- a/hw/spapr.h
+++ b/hw/spapr.h
@@ -2,9 +2,11 @@
 #define __HW_SPAPR_H__
 
 struct VIOsPAPRBus;
+struct icp_state;
 
 typedef struct sPAPREnvironment {
     struct VIOsPAPRBus *vio_bus;
+    struct icp_state *icp;
 } sPAPREnvironment;
 
 #define H_SUCCESS         0
diff --git a/hw/xics.c b/hw/xics.c
new file mode 100644
index 0000000..46e778a
--- /dev/null
+++ b/hw/xics.c
@@ -0,0 +1,528 @@
+#include "hw.h"
+#include "hw/spapr.h"
+#include "hw/xics.h"
+
+#include <pthread.h>
+
+/*
+ * ICP: Presentation layer
+ */
+
+struct icp_server_state {
+    uint32_t cppr :8;
+    uint32_t xisr :24;
+    uint8_t pending_priority;
+    uint8_t mfrr;
+    qemu_irq output;
+    pthread_mutex_t lock;
+};
+
+struct ics_state;
+
+struct icp_state {
+    long nr_servers;
+    struct icp_server_state *ss;
+    struct ics_state *ics;
+};
+
+static void ics_reject(struct ics_state *ics, int nr);
+static void ics_resend(struct ics_state *ics);
+static void ics_eoi(struct ics_state *ics, int nr);
+
+static void icp_check_ipi(struct icp_state *icp, int server)
+{
+    struct icp_server_state *ss = icp->ss + server;
+    
+    if (ss->xisr && (ss->pending_priority <= ss->mfrr)) {
+        return;
+    }
+
+    if (ss->xisr) {
+        ics_reject(icp->ics, ss->xisr);
+    }
+
+    ss->xisr = XICS_IPI;
+    ss->pending_priority = ss->mfrr;
+    qemu_irq_raise(ss->output);
+}
+
+static void icp_resend(struct icp_state *icp, int server)
+{
+    struct icp_server_state *ss = icp->ss + server;
+
+    if (ss->mfrr < ss->cppr) {
+        icp_check_ipi(icp, server);
+    }
+    ics_resend(icp->ics);
+}
+
+static void icp_set_cppr(struct icp_state *icp, int server, uint8_t cppr)
+{
+    struct icp_server_state *ss = icp->ss + server;
+    uint8_t old_cppr;
+    uint32_t old_xisr;
+
+    pthread_mutex_lock(&ss->lock);
+    old_cppr = ss->cppr;
+    ss->cppr = cppr;
+
+    if (cppr < old_cppr) {
+        if (ss->xisr && (cppr <= ss->pending_priority)) {
+            old_xisr = ss->xisr;
+            ss->xisr = 0;
+            qemu_irq_lower(ss->output);
+            ics_reject(icp->ics, old_xisr);
+        }
+    } else {
+        if (!ss->xisr) {
+            icp_resend(icp, server);
+        }
+    }
+    pthread_mutex_unlock(&ss->lock);
+}
+
+static void icp_set_mfrr(struct icp_state *icp, int nr, uint8_t mfrr)
+{
+    struct icp_server_state *ss = icp->ss + nr;
+
+    pthread_mutex_lock(&ss->lock);
+
+    ss->mfrr = mfrr;
+    if (mfrr < ss->cppr) {
+        icp_check_ipi(icp, nr);
+    }
+
+    pthread_mutex_unlock(&ss->lock);
+}
+
+static uint32_t icp_accept(struct icp_server_state *ss)
+{
+    uint32_t xirr;
+
+    pthread_mutex_lock(&ss->lock);
+    qemu_irq_lower(ss->output);
+    xirr = ss->cppr << 24 | ss->xisr;
+    ss->xisr = 0;
+    ss->cppr = ss->pending_priority;
+    pthread_mutex_unlock(&ss->lock);
+    return xirr;
+}
+
+static void icp_eoi(struct icp_state *icp, int server, uint32_t xirr)
+{
+    struct icp_server_state *ss = icp->ss + server;
+
+    ics_eoi(icp->ics, xirr & 0xffffff);
+    /* Send EOI -> ICS */
+    ss->cppr = xirr >> 24;
+    if (!ss->xisr) {
+        icp_resend(icp, server);
+    }
+}
+
+static void icp_irq(struct icp_state *icp, int server, int nr, uint8_t priority)
+{
+    struct icp_server_state *ss = icp->ss + server;
+
+    pthread_mutex_lock(&ss->lock);
+
+    if ((priority >= ss->cppr)
+        || (ss->xisr && (ss->pending_priority <= priority))) {
+        ics_reject(icp->ics, nr);
+    } else {
+        if (ss->xisr) {
+            ics_reject(icp->ics, ss->xisr);
+        }
+        ss->xisr = nr;
+        ss->pending_priority = priority;
+        qemu_irq_raise(ss->output);
+    }
+
+    pthread_mutex_unlock(&ss->lock);
+}
+
+/*
+ * ICS: Source layer
+ */
+
+struct ics_irq_state {
+    int server;
+    uint8_t priority;
+    uint8_t saved_priority;
+    /* int pending :1; */
+    /* int presented :1; */
+    int rejected :1;
+    int masked_pending :1;
+};
+
+struct ics_state {
+    int nr_irqs;
+    int offset;
+    qemu_irq *qirqs;
+    struct ics_irq_state *irqs;
+    struct icp_state *icp;
+};
+
+static int ics_valid_irq(struct ics_state *ics, uint32_t nr)
+{
+    return (nr >= ics->offset)
+        && (nr < (ics->offset + ics->nr_irqs));
+}
+
+static void ics_set_irq_msi(void *opaque, int nr, int val)
+{
+    struct ics_state *ics = (struct ics_state *)opaque;
+    struct ics_irq_state *irq = ics->irqs + nr;
+
+    if (val) {
+        if (irq->priority == 0xff) {
+            irq->masked_pending = 1;
+            /* masked pending */ ;
+        } else  {
+            icp_irq(ics->icp, irq->server, nr + ics->offset, irq->priority);
+        }
+    }
+}
+
+static void ics_reject_msi(struct ics_state *ics, int nr)
+{
+    struct ics_irq_state *irq = ics->irqs + nr - ics->offset;
+
+    irq->rejected = 1;
+}
+
+static void ics_resend_msi(struct ics_state *ics)
+{
+    int i;
+
+    for (i = 0; i < ics->nr_irqs; i++) {
+        struct ics_irq_state *irq = ics->irqs + i;
+
+        /* FIXME: filter by server#? */
+        if (irq->rejected) {
+            irq->rejected = 0;
+            if (irq->priority != 0xff) {
+                icp_irq(ics->icp, irq->server, i + ics->offset, irq->priority);
+            }
+        }
+    }
+}
+
+static void ics_write_xive_msi(struct ics_state *ics, int nr, int server,
+                               uint8_t priority)
+{
+    struct ics_irq_state *irq = ics->irqs + nr;
+
+    irq->server = server;
+    irq->priority = priority;
+
+    if (!irq->masked_pending || (priority = 0xff)) {
+        return;
+    }
+
+    irq->masked_pending = 0;
+    icp_irq(ics->icp, server, nr + ics->offset, priority);
+}
+
+/* static void ics_recheck_irq(struct ics_state *ics, int nr) */
+/* { */
+/*     struct ics_irq_state *irq = xics->irqs + (nr - xics->offset); */
+
+/*     if (irq->pending && (irq->priority != 0xff)) { */
+/*      irq->presented = 1; */
+/*      icp_irq(xicp->ss + irq->server, nr + ics->offset, irq->priority); */
+/*     } */
+/* } */
+
+/* static void ics_set_irq(void *opaque, int nr, int val) */
+/* { */
+/*     struct ics_state *ics = (struct ics_state *)opaque; */
+/*     struct ics_irq_state *irq = ics->irqs + nr; */
+
+/*     irq->pending = val; */
+/*     ics_recheck_irq(ics, nr); */
+/* } */
+
+/* static void ics_reject(int nr) */
+/* { */
+/*     struct ics_irq_state *irq = xics->irqs + (nr - xics->offset); */
+
+/*     assert(irq->presented); */
+/*     irq->rejected = 1; */
+/*     irq->presented = 0; */
+/* } */
+
+/* static void ics_eoi(int nr) */
+/* { */
+/*     struct ics_irq_state *irq = xics->irqs + (nr - xics->offset); */
+
+/*     assert(irq->presented); */
+/*     irq->presented = 0; */
+/*     irq->rejected = 0; */
+/*     ics_recheck_irq(xics, nr); */
+/* } */
+
+/* static void ics_resend_irq(struct ics_state *ics, int nr, */
+/*                            struct icp_server_state *ss) */
+/* { */
+/*     struct ics_irq_state *irq = ics->irqs + (nr - ics->offset); */
+
+/*     if (!irq->rejected) */
+/*         return; /\* Not rejected, so no need to resend *\/ */
+
+/*     if (ss != (xicp->ss + irq->server)) */
+/*         return; /\* Not for this server, so don't resend *\/ */
+
+/*     ics_recheck_irq(ics, nr); */
+/* } */
+
+/* static void ics_resend(struct icp_server_state *ss) */
+/* { */
+/*     int i; */
+
+/*     for (i = 0; i < xics->nr_irqs; i++) */
+/*         ics_resend_irq(xics, nr, ss); */
+/* } */
+
+static void ics_reject(struct ics_state *ics, int nr)
+{
+    ics_reject_msi(ics, nr);
+}
+
+static void ics_resend(struct ics_state *ics)
+{
+    ics_resend_msi(ics);
+}
+
+static void ics_eoi(struct ics_state *ics, int nr)
+{
+}
+
+/*
+ * Exported functions
+ */
+
+qemu_irq xics_find_qirq(struct icp_state *icp, int irq)
+{
+    if ((irq < icp->ics->offset)
+        || (irq >= (icp->ics->offset + icp->ics->nr_irqs))) {
+        return NULL;
+    }
+
+    return icp->ics->qirqs[irq - icp->ics->offset];
+}
+
+static target_ulong h_cppr(CPUState *env, sPAPREnvironment *spapr,
+                           target_ulong opcode, target_ulong *args)
+{
+    target_ulong cppr = args[0];
+
+    icp_set_cppr(spapr->icp, env->cpu_index, cppr);
+    return H_SUCCESS;
+}
+
+static target_ulong h_ipi(CPUState *env, sPAPREnvironment *spapr,
+                          target_ulong opcode, target_ulong *args)
+{
+    target_ulong server = args[0];
+    target_ulong mfrr = args[1];
+
+    if (server >= spapr->icp->nr_servers) {
+        return H_PARAMETER;
+    }
+
+    icp_set_mfrr(spapr->icp, server, mfrr);
+    return H_SUCCESS;
+
+}
+
+static target_ulong h_xirr(CPUState *env, sPAPREnvironment *spapr,
+                           target_ulong opcode, target_ulong *args)
+{
+    uint32_t xirr = icp_accept(spapr->icp->ss + env->cpu_index);
+
+    args[0] = xirr;
+    return H_SUCCESS;
+}
+
+static target_ulong h_eoi(CPUState *env, sPAPREnvironment *spapr,
+                          target_ulong opcode, target_ulong *args)
+{
+    target_ulong xirr = args[0];
+
+    icp_eoi(spapr->icp, env->cpu_index, xirr);
+    return H_SUCCESS;
+}
+
+static void rtas_set_xive(sPAPREnvironment *spapr, uint32_t token,
+                          uint32_t nargs, target_ulong args,
+                          uint32_t nret, target_ulong rets)
+{
+    struct ics_state *ics = spapr->icp->ics;
+    uint32_t nr, server, priority;
+
+    if ((nargs != 3) || (nret != 1)) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    nr = rtas_ld(args, 0);
+    server = rtas_ld(args, 1);
+    priority = rtas_ld(args, 2);
+
+    if (!ics_valid_irq(ics, nr) || (server >= ics->icp->nr_servers)
+        || (priority > 0xff)) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    ics_write_xive_msi(ics, nr - ics->offset, server, priority);
+
+    rtas_st(rets, 0, 0); /* Success */
+}
+
+static void rtas_get_xive(sPAPREnvironment *spapr, uint32_t token,
+                          uint32_t nargs, target_ulong args,
+                          uint32_t nret, target_ulong rets)
+{
+    struct ics_state *ics = spapr->icp->ics;
+    uint32_t nr;
+
+    if ((nargs != 1) || (nret != 3)) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    nr = rtas_ld(args, 0);
+
+    if (!ics_valid_irq(ics, nr)) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    rtas_st(rets, 0, 0); /* Success */
+    rtas_st(rets, 1, ics->irqs[nr - ics->offset].server);
+    rtas_st(rets, 2, ics->irqs[nr - ics->offset].priority);
+}
+
+static void rtas_int_off(sPAPREnvironment *spapr, uint32_t token,
+                         uint32_t nargs, target_ulong args,
+                         uint32_t nret, target_ulong rets)
+{
+    struct ics_state *ics = spapr->icp->ics;
+    uint32_t nr;
+
+    if ((nargs != 1) || (nret != 1)) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    nr = rtas_ld(args, 0);
+
+    if (!ics_valid_irq(ics, nr)) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    /* This is a NOP for now, since the described PAPR semantics don't
+     * seem to gel with what Linux does */
+#if 0
+    struct ics_irq_state *irq = xics->irqs + (nr - xics->offset);
+
+    irq->saved_priority = irq->priority;
+    ics_write_xive_msi(xics, nr - xics->offset, irq->server, 0xff);
+#endif
+
+    rtas_st(rets, 0, 0); /* Success */
+}
+
+static void rtas_int_on(sPAPREnvironment *spapr, uint32_t token,
+                        uint32_t nargs, target_ulong args,
+                        uint32_t nret, target_ulong rets)
+{
+    struct ics_state *ics = spapr->icp->ics;
+    uint32_t nr;
+
+    if ((nargs != 1) || (nret != 1)) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    nr = rtas_ld(args, 0);
+
+    if (!ics_valid_irq(ics, nr)) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    /* This is a NOP for now, since the described PAPR semantics don't
+     * seem to gel with what Linux does */
+#if 0
+    struct ics_irq_state *irq = xics->irqs + (nr - xics->offset);
+
+    ics_write_xive_msi(xics, nr - xics->offset,
+                       irq->server, irq->saved_priority);
+#endif
+
+    rtas_st(rets, 0, 0); /* Success */
+}
+
+struct icp_state *xics_system_init(int nr_servers, CPUState *servers[],
+                                   int nr_irqs)
+{
+    int i;
+    struct icp_state *icp;
+    struct ics_state *ics;
+
+    icp = qemu_mallocz(sizeof(*icp));
+    icp->nr_servers = nr_servers;
+    icp->ss = qemu_mallocz(nr_servers * sizeof(struct icp_server_state));
+
+    for (i = 0; i < nr_servers; i++) {
+        servers[i]->cpu_index = i;
+
+        switch (PPC_INPUT(servers[i])) {
+        case PPC_FLAGS_INPUT_POWER7:
+            icp->ss[i].output = servers[i]->irq_inputs[POWER7_INPUT_INT];
+            break;
+
+        case PPC_FLAGS_INPUT_970:
+            icp->ss[i].output = servers[i]->irq_inputs[PPC970_INPUT_INT];
+            break;
+
+        default:
+            hw_error("XICS interrupt model does not support this CPU bus model\n");
+            exit(1);
+        }
+
+        icp->ss[i].mfrr = 0xff;
+        pthread_mutex_init(&icp->ss[i].lock, NULL);
+    }
+
+    ics = qemu_mallocz(sizeof(*ics));
+    ics->nr_irqs = nr_irqs;
+    ics->offset = 16;
+    ics->irqs = qemu_mallocz(nr_irqs * sizeof(struct ics_irq_state));
+
+    icp->ics = ics;
+    ics->icp = icp;
+
+    for (i = 0; i < nr_irqs; i++) {
+        ics->irqs[i].priority = 0xff;
+        ics->irqs[i].saved_priority = 0xff;
+    }
+
+    ics->qirqs = qemu_allocate_irqs(ics_set_irq_msi, ics, nr_irqs);
+
+    spapr_register_hypercall(H_CPPR, h_cppr);
+    spapr_register_hypercall(H_IPI, h_ipi);
+    spapr_register_hypercall(H_XIRR, h_xirr);
+    spapr_register_hypercall(H_EOI, h_eoi);
+
+    spapr_rtas_register("ibm,set-xive", rtas_set_xive);
+    spapr_rtas_register("ibm,get-xive", rtas_get_xive);
+    spapr_rtas_register("ibm,int-off", rtas_int_off);
+    spapr_rtas_register("ibm,int-on", rtas_int_on);
+
+    return icp;
+}
diff --git a/hw/xics.h b/hw/xics.h
new file mode 100644
index 0000000..e55f5f1
--- /dev/null
+++ b/hw/xics.h
@@ -0,0 +1,13 @@
+#if !defined(__XICS_H__)
+#define __XICS_H__
+
+#define XICS_IPI        0x2
+
+struct icp_state;
+
+qemu_irq xics_find_qirq(struct icp_state *icp, int irq);
+
+struct icp_state *xics_system_init(int nr_servers, CPUState *servers[],
+                                   int nr_irqs);
+
+#endif /* __XICS_H__ */
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 20/28] Add PAPR H_VIO_SIGNAL hypercall and infrastructure for VIO interrupts
  2011-02-15  4:56 [Qemu-devel] RFC: Implement emulation of pSeries logical partitions (v2) qemu
                   ` (18 preceding siblings ...)
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 19/28] Implement the PAPR (pSeries) virtualized interrupt controller (xics) qemu
@ 2011-02-15  4:56 ` qemu
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 21/28] Add (virtual)_interrupt to PAPR virtual tty device qemu
                   ` (7 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: qemu @ 2011-02-15  4:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: paulus, agraf, anton

From: David Gibson <david@gibson.dropbear.id.au>

This patch adds infrastructure to support interrupts from PAPR virtual IO
devices.  This includes correctly advertising those interrupts in the
device tree, and implementing the H_VIO_SIGNAL hypercall, used to
enable and disable individual device interrupts.

Signed-off-by: David Gibson <dwg@au1.ibm.com>
---
 hw/spapr.c     |    2 +-
 hw/spapr_vio.c |   34 ++++++++++++++++++++++++++++++++++
 hw/spapr_vio.h |    6 ++++++
 3 files changed, 41 insertions(+), 1 deletions(-)

diff --git a/hw/spapr.c b/hw/spapr.c
index be30def..5b19963 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -62,7 +62,7 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize,
     uint32_t start_prop = cpu_to_be32(initrd_base);
     uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
     uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)};
-    char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr";
+    char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt";
     uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)};
     int i;
     char *modelname;
diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
index 67005bb..b01331d 100644
--- a/hw/spapr_vio.c
+++ b/hw/spapr_vio.c
@@ -105,6 +105,15 @@ static int vio_make_devnode(VIOsPAPRDevice *dev,
         }
     }
 
+    if (dev->qirq) {
+        uint32_t ints_prop[] = {cpu_to_be32(dev->vio_irq_num), 0};
+
+        ret = fdt_setprop(fdt, node_off, "interrupts", ints_prop,
+                          sizeof(ints_prop));
+        if (ret < 0)
+            return ret;
+    }
+
     if (info->devnode) {
         ret = (info->devnode)(dev, fdt, node_off);
         if (ret < 0) {
@@ -140,6 +149,28 @@ void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info)
     qdev_register(&info->qdev);
 }
 
+static target_ulong h_vio_signal(CPUState *env, sPAPREnvironment *spapr,
+                                 target_ulong opcode,
+                                 target_ulong *args)
+{
+    target_ulong reg = args[0];
+    target_ulong mode = args[1];
+    VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+    VIOsPAPRDeviceInfo *info;
+
+    if (!dev)
+        return H_PARAMETER;
+
+    info = (VIOsPAPRDeviceInfo *)dev->qdev.info;
+
+    if (mode & ~info->signal_mask)
+        return H_PARAMETER;;
+
+    dev->signal_state = mode;
+
+    return H_SUCCESS;
+}
+
 VIOsPAPRBus *spapr_vio_bus_init(void)
 {
     VIOsPAPRBus *bus;
@@ -156,6 +187,9 @@ VIOsPAPRBus *spapr_vio_bus_init(void)
     _bus = qbus_create(&spapr_vio_bus_info, dev, "spapr-vio");
     bus = DO_UPCAST(VIOsPAPRBus, bus, _bus);
 
+    /* hcall-vio */
+    spapr_register_hypercall(H_VIO_SIGNAL, h_vio_signal);
+
     for (_info = device_info_list; _info; _info = _info->next) {
         VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)_info;
 
diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h
index b164ad3..8a000c6 100644
--- a/hw/spapr_vio.h
+++ b/hw/spapr_vio.h
@@ -24,6 +24,9 @@
 typedef struct VIOsPAPRDevice {
     DeviceState qdev;
     uint32_t reg;
+    qemu_irq qirq;
+    uint32_t vio_irq_num;
+    target_ulong signal_state;
 } VIOsPAPRDevice;
 
 typedef struct VIOsPAPRBus {
@@ -33,6 +36,7 @@ typedef struct VIOsPAPRBus {
 typedef struct {
     DeviceInfo qdev;
     const char *dt_name, *dt_type, *dt_compatible;
+    target_ulong signal_mask;
     int (*init)(VIOsPAPRDevice *dev);
     void (*hcalls)(VIOsPAPRBus *bus);
     int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off);
@@ -43,6 +47,8 @@ extern VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg);
 extern void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info);
 extern int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt);
 
+extern int spapr_vio_signal(VIOsPAPRDevice *dev, target_ulong mode);
+
 void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len);
 void spapr_vty_create(VIOsPAPRBus *bus,
                       uint32_t reg, CharDriverState *chardev);
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 21/28] Add (virtual)_interrupt to PAPR virtual tty device
  2011-02-15  4:56 [Qemu-devel] RFC: Implement emulation of pSeries logical partitions (v2) qemu
                   ` (19 preceding siblings ...)
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 20/28] Add PAPR H_VIO_SIGNAL hypercall and infrastructure for VIO interrupts qemu
@ 2011-02-15  4:56 ` qemu
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 22/28] Implement TCE translation for sPAPR VIO qemu
                   ` (6 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: qemu @ 2011-02-15  4:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: paulus, agraf, anton

From: David Gibson <david@gibson.dropbear.id.au>

Now that we have implemented the PAPR "xics" virtualized interrupt
controller, we can add interrupts in PAPR VIO devices.  This patch adds
interrupt support to the PAPR virtual tty/console device.

Signed-off-by: David Gibson <dwg@au1.ibm.com>
---
 hw/spapr.c     |    6 ++++--
 hw/spapr_vio.h |    3 ++-
 hw/spapr_vty.c |   11 ++++++++++-
 3 files changed, 16 insertions(+), 4 deletions(-)

diff --git a/hw/spapr.c b/hw/spapr.c
index 5b19963..e7f8864 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -255,6 +255,7 @@ static void ppc_spapr_init(ram_addr_t ram_size,
     int fdt_size;
     sPAPREnvironment *spapr;
     char *filename;
+    int irq = 16;
 
     spapr = qemu_malloc(sizeof(*spapr));
 
@@ -318,9 +319,10 @@ static void ppc_spapr_init(ram_addr_t ram_size,
     /* Set up VIO bus */
     spapr->vio_bus = spapr_vio_bus_init();
 
-    for (i = 0; i < MAX_SERIAL_PORTS; i++) {
+    for (i = 0; i < MAX_SERIAL_PORTS; i++, irq++) {
         if (serial_hds[i]) {
-            spapr_vty_create(spapr->vio_bus, i, serial_hds[i]);
+            spapr_vty_create(spapr->vio_bus, i, serial_hds[i],
+                             xics_find_qirq(spapr->icp, irq), irq);
         }
     }
 
diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h
index 8a000c6..2013927 100644
--- a/hw/spapr_vio.h
+++ b/hw/spapr_vio.h
@@ -51,6 +51,7 @@ extern int spapr_vio_signal(VIOsPAPRDevice *dev, target_ulong mode);
 
 void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len);
 void spapr_vty_create(VIOsPAPRBus *bus,
-                      uint32_t reg, CharDriverState *chardev);
+                      uint32_t reg, CharDriverState *chardev,
+                      qemu_irq qirq, uint32_t vio_irq_num);
 
 #endif /* _HW_SPAPR_VIO_H */
diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c
index afc9ef9..5c2412a 100644
--- a/hw/spapr_vty.c
+++ b/hw/spapr_vty.c
@@ -24,6 +24,10 @@ static void vty_receive(void *opaque, const uint8_t *buf, int size)
     VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)opaque;
     int i;
 
+    if ((dev->in == dev->out) && size) {
+        /* toggle line to simulate edge interrupt */
+        qemu_irq_pulse(dev->sdev.qirq);
+    }
     for (i = 0; i < size; i++) {
         assert((dev->in - dev->out) < VTERM_BUFSIZE);
         dev->buf[dev->in++ % VTERM_BUFSIZE] = buf[i];
@@ -107,14 +111,19 @@ static target_ulong h_get_term_char(CPUState *env, sPAPREnvironment *spapr,
 }
 
 void spapr_vty_create(VIOsPAPRBus *bus,
-                      uint32_t reg, CharDriverState *chardev)
+                      uint32_t reg, CharDriverState *chardev,
+                      qemu_irq qirq, uint32_t vio_irq_num)
 {
     DeviceState *dev;
+    VIOsPAPRDevice *sdev;
 
     dev = qdev_create(&bus->bus, "spapr-vty");
     qdev_prop_set_uint32(dev, "reg", reg);
     qdev_prop_set_chr(dev, "chardev", chardev);
     qdev_init_nofail(dev);
+    sdev = (VIOsPAPRDevice *)dev;
+    sdev->qirq = qirq;
+    sdev->vio_irq_num = vio_irq_num;
 }
 
 static void vty_hcalls(VIOsPAPRBus *bus)
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 22/28] Implement TCE translation for sPAPR VIO
  2011-02-15  4:56 [Qemu-devel] RFC: Implement emulation of pSeries logical partitions (v2) qemu
                   ` (20 preceding siblings ...)
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 21/28] Add (virtual)_interrupt to PAPR virtual tty device qemu
@ 2011-02-15  4:56 ` qemu
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 23/28] Implement sPAPR Virtual LAN (ibmveth) qemu
                   ` (5 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: qemu @ 2011-02-15  4:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: paulus, agraf, anton

From: David Gibson <david@gibson.dropbear.id.au>

This patch implements the necessary infrastructure and hypercalls for
sPAPR's TCE (Translation Control Entry) IOMMU mechanism.  This is necessary
for all virtual IO devices which do DMA (i.e. nearly all of them).

Signed-off-by: David Gibson <dwg@au1.ibm.com>
Signed-off-by: Ben Herrenschmidt <benh@kernel.crashing.org>
---
 hw/spapr.c     |    3 +-
 hw/spapr_vio.c |  232 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/spapr_vio.h |   32 ++++++++
 3 files changed, 266 insertions(+), 1 deletions(-)

diff --git a/hw/spapr.c b/hw/spapr.c
index e7f8864..a362889 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -62,7 +62,8 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize,
     uint32_t start_prop = cpu_to_be32(initrd_base);
     uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
     uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)};
-    char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt";
+    char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt"
+        "\0hcall-tce";
     uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)};
     int i;
     char *modelname;
diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
index b01331d..cb90d48 100644
--- a/hw/spapr_vio.c
+++ b/hw/spapr_vio.c
@@ -37,6 +37,7 @@
 #endif /* CONFIG_FDT */
 
 /* #define DEBUG_SPAPR */
+/* #define DEBUG_TCE */
 
 #ifdef DEBUG_SPAPR
 #define dprintf(fmt, ...) \
@@ -114,6 +115,28 @@ static int vio_make_devnode(VIOsPAPRDevice *dev,
             return ret;
     }
 
+    if (dev->rtce_window_size) {
+        uint32_t dma_prop[] = {cpu_to_be32(dev->reg),
+                               0, 0,
+                               0, cpu_to_be32(dev->rtce_window_size)};
+
+        ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-address-cells", 2);
+        if (ret < 0) {
+            return ret;
+        }
+
+        ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-size-cells", 2);
+        if (ret < 0) {
+            return ret;
+        }
+
+        ret = fdt_setprop(fdt, node_off, "ibm,my-dma-window", dma_prop,
+                          sizeof(dma_prop));
+        if (ret < 0) {
+            return ret;
+        }
+    }
+
     if (info->devnode) {
         ret = (info->devnode)(dev, fdt, node_off);
         if (ret < 0) {
@@ -125,6 +148,210 @@ static int vio_make_devnode(VIOsPAPRDevice *dev,
 }
 #endif /* CONFIG_FDT */
 
+/*
+ * RTCE handling
+ */
+
+static void rtce_init(VIOsPAPRDevice *dev)
+{
+    size_t size = (dev->rtce_window_size >> SPAPR_VIO_TCE_PAGE_SHIFT)
+        * sizeof(VIOsPAPR_RTCE);
+
+    if (size) {
+        dev->rtce_table = qemu_mallocz(size);
+    }
+}
+
+static target_ulong h_put_tce(CPUState *env, sPAPREnvironment *spapr,
+                              target_ulong opcode, target_ulong *args)
+{
+    target_ulong liobn = args[0];
+    target_ulong ioba = args[1];
+    target_ulong tce = args[2];
+    VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, liobn);
+    VIOsPAPR_RTCE *rtce;
+
+    if (!dev) {
+        fprintf(stderr, "spapr_vio_put_tce on non-existent LIOBN "
+                TARGET_FMT_lx "\n",
+                liobn);
+        return H_PARAMETER;
+    }
+
+    ioba &= ~(SPAPR_VIO_TCE_PAGE_SIZE - 1);
+
+#ifdef DEBUG_TCE
+    fprintf(stderr, "spapr_vio_put_tce on %s  ioba 0x" TARGET_FMT_lx 
+            "  TCE 0x" TARGET_FMT_lx "\n", dev->qdev.id, ioba, tce);
+#endif
+
+    if (ioba >= dev->rtce_window_size) {
+        fprintf(stderr, "spapr_vio_put_tce on out-of-boards IOBA 0x" TARGET_FMT_lx "\n",
+                ioba);
+        return H_PARAMETER;
+    }
+
+    rtce = dev->rtce_table + (ioba >> SPAPR_VIO_TCE_PAGE_SHIFT);
+    rtce->tce = tce;
+   
+    return H_SUCCESS;
+}
+
+int spapr_vio_check_tces(VIOsPAPRDevice *dev, target_ulong ioba,
+                         target_ulong len, enum VIOsPAPR_TCEAccess access)
+{
+    int start, end, i;
+
+    start = ioba >> SPAPR_VIO_TCE_PAGE_SHIFT;
+    end = (ioba + len - 1) >> SPAPR_VIO_TCE_PAGE_SHIFT;
+
+    for (i = start; i <= end; i++) {
+        if ((dev->rtce_table[i].tce & access) != access) {
+            fprintf(stderr, "FAIL on %d\n", i);
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+/* XX Might want to special case KVM for speed ? */
+int spapr_tce_dma_write(VIOsPAPRDevice *dev, uint64_t taddr, const void *buf,
+                        uint32_t size)
+{
+#ifdef DEBUG_TCE
+    fprintf(stderr, "spapr_tce_dma_write taddr=0x%llx size=0x%x\n",
+            (unsigned long long)taddr, size);
+#endif
+
+    while(size) {
+        uint64_t tce;
+        uint32_t lsize;
+        uint64_t txaddr;
+
+        /* Check if we are in bound */
+        if (taddr >= dev->rtce_window_size) {
+            fprintf(stderr, "spapr_tce_dma_write out of bounds\n");
+            return -H_DEST_PARM;
+        }
+        tce = dev->rtce_table[taddr >> SPAPR_VIO_TCE_PAGE_SHIFT].tce;
+
+        /* How much til end of page ? */
+        lsize = MIN(size, ((~taddr) & SPAPR_VIO_TCE_PAGE_MASK) + 1);
+
+        /* Check TCE */
+        if (!(tce & 2))
+            return -H_DEST_PARM;
+
+        /* Translate */
+        txaddr = (tce & ~SPAPR_VIO_TCE_PAGE_MASK) | (taddr & SPAPR_VIO_TCE_PAGE_MASK);
+
+#ifdef DEBUG_TCE
+        fprintf(stderr, " -> write to txaddr=0x%llx, size=0x%x\n",
+                (unsigned long long)txaddr, lsize);
+#endif
+
+        /* Do it */
+        cpu_physical_memory_write(txaddr, buf, lsize);
+        buf += lsize;
+        taddr += lsize;
+        size -= lsize;
+    }
+    return 0;
+}
+
+/* XX Might want to special case KVM for speed ? */
+int spapr_tce_dma_zero(VIOsPAPRDevice *dev, uint64_t taddr, uint32_t size)
+{
+    uint8_t *zeroes;
+
+#ifdef DEBUG_TCE
+    fprintf(stderr, "spapr_tce_dma_zero taddr=0x%llx size=0x%x\n",
+            (unsigned long long)taddr, size);
+#endif
+
+    /* FIXME: do this better... */
+    zeroes = alloca(size);
+    memset(zeroes, 0, size);
+    return spapr_tce_dma_write(dev, taddr, zeroes, size);
+}
+
+void stb_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint8_t val)
+{
+    spapr_tce_dma_write(dev, taddr, &val, sizeof(val));
+}
+
+void sth_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint16_t val)
+{
+    val = tswap16(val);
+    spapr_tce_dma_write(dev, taddr, &val, sizeof(val));
+}
+
+
+void stw_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint32_t val)
+{
+    val = tswap32(val);
+    spapr_tce_dma_write(dev, taddr, &val, sizeof(val));
+}
+
+void stq_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint64_t val)
+{
+    val = tswap64(val);
+    spapr_tce_dma_write(dev, taddr, &val, sizeof(val));
+}
+
+int spapr_tce_dma_read(VIOsPAPRDevice *dev, uint64_t taddr, void *buf,
+                       uint32_t size)
+{
+#ifdef DEBUG_TCE
+    fprintf(stderr, "spapr_tce_dma_write taddr=0x%llx size=0x%x\n",
+            (unsigned long long)taddr, size);
+#endif
+
+    while(size) {
+        uint64_t tce;
+        uint32_t lsize;
+        uint64_t txaddr;
+
+        /* Check if we are in bound */
+        if (taddr >= dev->rtce_window_size) {
+            fprintf(stderr, "spapr_tce_dma_read out of bounds\n");
+            return -H_DEST_PARM;
+        }
+        tce = dev->rtce_table[taddr >> SPAPR_VIO_TCE_PAGE_SHIFT].tce;
+
+        /* How much til end of page ? */
+        lsize = MIN(size, ((~taddr) & SPAPR_VIO_TCE_PAGE_MASK) + 1);
+
+        /* Check TCE */
+        if (!(tce & 1)) {
+            return H_DEST_PARM;
+        }
+
+        /* Translate */
+        txaddr = (tce & ~SPAPR_VIO_TCE_PAGE_MASK) | (taddr & SPAPR_VIO_TCE_PAGE_MASK);
+
+#ifdef DEBUG_TCE
+        fprintf(stderr, " -> write to txaddr=0x%llx, size=0x%x\n",
+                (unsigned long long)txaddr, lsize);
+#endif
+        /* Do it */
+        cpu_physical_memory_read(txaddr, buf, lsize);
+        buf += lsize;
+        taddr += lsize;
+        size -= lsize;
+    }
+    return H_SUCCESS;
+}
+
+uint64_t ldq_tce(VIOsPAPRDevice *dev, uint64_t taddr)
+{
+    uint64_t val;
+
+    spapr_tce_dma_read(dev, taddr, &val, sizeof(val));
+    return tswap64(val);
+}
+
 static int spapr_vio_busdev_init(DeviceState *dev, DeviceInfo *info)
 {
     VIOsPAPRDeviceInfo *_info = (VIOsPAPRDeviceInfo *)info;
@@ -137,6 +364,8 @@ static int spapr_vio_busdev_init(DeviceState *dev, DeviceInfo *info)
 
     _dev->qdev.id = id;
 
+    rtce_init(_dev);
+
     return _info->init(_dev);
 }
 
@@ -190,6 +419,9 @@ VIOsPAPRBus *spapr_vio_bus_init(void)
     /* hcall-vio */
     spapr_register_hypercall(H_VIO_SIGNAL, h_vio_signal);
 
+    /* hcall-tce */
+    spapr_register_hypercall(H_PUT_TCE, h_put_tce);
+
     for (_info = device_info_list; _info; _info = _info->next) {
         VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)_info;
 
diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h
index 2013927..1b15d3e 100644
--- a/hw/spapr_vio.h
+++ b/hw/spapr_vio.h
@@ -21,12 +21,29 @@
  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 
+#define SPAPR_VIO_TCE_PAGE_SHIFT	12
+#define SPAPR_VIO_TCE_PAGE_SIZE		(1ULL << SPAPR_VIO_TCE_PAGE_SHIFT)
+#define SPAPR_VIO_TCE_PAGE_MASK		(SPAPR_VIO_TCE_PAGE_SIZE - 1)
+
+enum VIOsPAPR_TCEAccess {
+    SPAPR_TCE_FAULT = 0,
+    SPAPR_TCE_RO = 1,
+    SPAPR_TCE_WO = 2,
+    SPAPR_TCE_RW = 3,
+};
+
+typedef struct VIOsPAPR_RTCE {
+    uint64_t tce;
+} VIOsPAPR_RTCE;
+
 typedef struct VIOsPAPRDevice {
     DeviceState qdev;
     uint32_t reg;
     qemu_irq qirq;
     uint32_t vio_irq_num;
     target_ulong signal_state;
+    uint32_t rtce_window_size;
+    VIOsPAPR_RTCE *rtce_table;
 } VIOsPAPRDevice;
 
 typedef struct VIOsPAPRBus {
@@ -49,6 +66,21 @@ extern int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt);
 
 extern int spapr_vio_signal(VIOsPAPRDevice *dev, target_ulong mode);
 
+int spapr_vio_check_tces(VIOsPAPRDevice *dev, target_ulong ioba,
+                         target_ulong len,
+                         enum VIOsPAPR_TCEAccess access);
+
+int spapr_tce_dma_read(VIOsPAPRDevice *dev, uint64_t taddr,
+                       void *buf, uint32_t size);
+int spapr_tce_dma_write(VIOsPAPRDevice *dev, uint64_t taddr,
+                        const void *buf, uint32_t size);
+int spapr_tce_dma_zero(VIOsPAPRDevice *dev, uint64_t taddr, uint32_t size);
+void stb_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint8_t val);
+void sth_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint16_t val);
+void stw_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint32_t val);
+void stq_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint64_t val);
+uint64_t ldq_tce(VIOsPAPRDevice *dev, uint64_t taddr);
+
 void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len);
 void spapr_vty_create(VIOsPAPRBus *bus,
                       uint32_t reg, CharDriverState *chardev,
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 23/28] Implement sPAPR Virtual LAN (ibmveth)
  2011-02-15  4:56 [Qemu-devel] RFC: Implement emulation of pSeries logical partitions (v2) qemu
                   ` (21 preceding siblings ...)
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 22/28] Implement TCE translation for sPAPR VIO qemu
@ 2011-02-15  4:56 ` qemu
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 24/28] Implement PAPR CRQ hypercalls qemu
                   ` (4 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: qemu @ 2011-02-15  4:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: paulus, agraf, anton

From: David Gibson <david@gibson.dropbear.id.au>

This patch implements the PAPR specified Inter Virtual Machine Logical
LAN; that is the virtual hardware used by the Linux ibmveth driver.

Signed-off-by: David Gibson <dwg@au1.ibm.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
---
 Makefile.target |    2 +-
 hw/spapr.c      |   21 +++-
 hw/spapr_llan.c |  476 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/spapr_vio.h  |    9 +-
 4 files changed, 503 insertions(+), 5 deletions(-)
 create mode 100644 hw/spapr_llan.c

diff --git a/Makefile.target b/Makefile.target
index 00cb554..0e155bc 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -233,7 +233,7 @@ obj-ppc-y += ppc_oldworld.o
 obj-ppc-y += ppc_newworld.o
 # IBM pSeries (sPAPR)
 obj-ppc-y += spapr.o spapr_hcall.o spapr_rtas.o spapr_vio.o
-obj-ppc-y += xics.o spapr_vty.o
+obj-ppc-y += xics.o spapr_vty.o spapr_llan.o
 # PowerPC 4xx boards
 obj-ppc-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
 obj-ppc-y += ppc440.o ppc440_bamboo.o
diff --git a/hw/spapr.c b/hw/spapr.c
index a362889..44cf3cc 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -27,6 +27,7 @@
 #include "sysemu.h"
 #include "hw.h"
 #include "elf.h"
+#include "net.h"
 
 #include "hw/boards.h"
 #include "hw/ppc.h"
@@ -315,7 +316,7 @@ static void ppc_spapr_init(ram_addr_t ram_size,
     qemu_free(filename);
 
     /* Set up Interrupt Controller */
-    spapr->icp = xics_system_init(smp_cpus, &env, MAX_SERIAL_PORTS);
+    spapr->icp = xics_system_init(smp_cpus, envs, MAX_SERIAL_PORTS + nb_nics);
 
     /* Set up VIO bus */
     spapr->vio_bus = spapr_vio_bus_init();
@@ -327,6 +328,24 @@ static void ppc_spapr_init(ram_addr_t ram_size,
         }
     }
 
+    for (i = 0; i < nb_nics; i++, irq++) {
+        NICInfo *nd = &nd_table[i];
+
+        if (!nd->model) {
+            nd->model = qemu_strdup("ibmveth");
+        }
+
+        if (strcmp(nd->model, "ibmveth") == 0) {
+            spapr_vlan_create(spapr->vio_bus, 0x1000 + i, nd,
+                              xics_find_qirq(spapr->icp, irq), irq);
+        } else {
+            fprintf(stderr, "pSeries (sPAPR) platform does not support "
+                    "NIC model '%s' (only ibmveth is supported)\n",
+                    nd->model);
+            exit(1);
+        }
+    }
+
     if (kernel_filename) {
         uint64_t lowaddr = 0;
 
diff --git a/hw/spapr_llan.c b/hw/spapr_llan.c
new file mode 100644
index 0000000..da0562d
--- /dev/null
+++ b/hw/spapr_llan.c
@@ -0,0 +1,476 @@
+#include "hw.h"
+#include "net.h"
+#include "hw/qdev.h"
+#include "hw/spapr.h"
+#include "hw/spapr_vio.h"
+
+#include <libfdt.h>
+
+#define ETH_ALEN        6
+
+//#define DEBUG
+
+#ifdef DEBUG
+#define dprintf(fmt...) do { fprintf(stderr, fmt); } while(0)
+#else
+#define dprintf(fmt...)
+#endif
+
+/*
+ * Virtual LAN device
+ */
+
+typedef uint64_t vlan_bd_t;
+
+#define VLAN_BD_VALID        0x8000000000000000ULL
+#define VLAN_BD_TOGGLE       0x4000000000000000ULL
+#define VLAN_BD_NO_CSUM      0x0200000000000000ULL
+#define VLAN_BD_CSUM_GOOD    0x0100000000000000ULL
+#define VLAN_BD_LEN_MASK     0x00ffffff00000000ULL
+#define VLAN_BD_LEN(bd)      (((bd) & VLAN_BD_LEN_MASK) >> 32)
+#define VLAN_BD_ADDR_MASK    0x00000000ffffffffULL
+#define VLAN_BD_ADDR(bd)     ((bd) & VLAN_BD_ADDR_MASK)
+
+#define VLAN_VALID_BD(addr, len) (VLAN_BD_VALID | \
+                                  (((len) << 32) & VLAN_BD_LEN_MASK) |  \
+                                  (addr & VLAN_BD_ADDR_MASK))
+
+#define VLAN_RXQC_TOGGLE     0x80
+#define VLAN_RXQC_VALID      0x40
+#define VLAN_RXQC_NO_CSUM    0x02
+#define VLAN_RXQC_CSUM_GOOD  0x01
+
+#define VLAN_RQ_ALIGNMENT    16
+#define VLAN_RXQ_BD_OFF      0
+#define VLAN_FILTER_BD_OFF   8
+#define VLAN_RX_BDS_OFF      16
+#define VLAN_MAX_BUFS        ((SPAPR_VIO_TCE_PAGE_SIZE - VLAN_RX_BDS_OFF) / 8)
+
+typedef struct VIOsPAPRVLANDevice {
+    VIOsPAPRDevice sdev;
+    NICConf nicconf;
+    NICState *nic;
+    int isopen;
+    target_ulong buf_list;
+    int add_buf_ptr, use_buf_ptr, rx_bufs;
+    target_ulong rxq_ptr;
+} VIOsPAPRVLANDevice;
+
+static int spapr_vlan_can_receive(VLANClientState *nc)
+{
+    VIOsPAPRVLANDevice *dev = DO_UPCAST(NICState, nc, nc)->opaque;
+
+    return (dev->isopen && dev->rx_bufs > 0);
+}
+
+static ssize_t spapr_vlan_receive(VLANClientState *nc, const uint8_t *buf,
+                                  size_t size)
+{
+    VIOsPAPRDevice *sdev = DO_UPCAST(NICState, nc, nc)->opaque;
+    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
+    vlan_bd_t rxq_bd = ldq_tce(sdev, dev->buf_list + VLAN_RXQ_BD_OFF);
+    vlan_bd_t bd;
+    int buf_ptr = dev->use_buf_ptr;
+    uint64_t handle;
+    uint8_t control;
+
+    dprintf("spapr_vlan_receive() [%s] rx_bufs=%d\n", sdev->qdev.id,
+            dev->rx_bufs);
+
+    if (!dev->isopen) {
+        return -1;
+    }
+
+    if (!dev->rx_bufs) {
+        return -1;
+    }
+
+    do {
+        buf_ptr += 8;
+        if (buf_ptr >= SPAPR_VIO_TCE_PAGE_SIZE) {
+            buf_ptr = VLAN_RX_BDS_OFF;
+        }
+
+        bd = ldq_tce(sdev, dev->buf_list + buf_ptr);
+        dprintf("use_buf_ptr=%d bd=0x%016llx\n",
+                buf_ptr, (unsigned long long)bd);
+    } while ((!(bd & VLAN_BD_VALID) || (VLAN_BD_LEN(bd) < (size + 8)))
+             && (buf_ptr != dev->use_buf_ptr));
+
+    if (!(bd & VLAN_BD_VALID) || (VLAN_BD_LEN(bd) < (size + 8))) {
+        /* Failed to find a suitable buffer */
+        return -1;
+    }
+
+    /* Remove the buffer from the pool */
+    dev->rx_bufs--;
+    dev->use_buf_ptr = buf_ptr;
+    stq_tce(sdev, dev->buf_list + dev->use_buf_ptr, 0);
+
+    dprintf("Found buffer: ptr=%d num=%d\n", dev->use_buf_ptr, dev->rx_bufs);
+
+    /* Transfer the packet data */
+    if (spapr_tce_dma_write(sdev, VLAN_BD_ADDR(bd) + 8, buf, size) < 0) {
+        return -1;
+    }
+
+    dprintf("spapr_vlan_receive: DMA write completed\n");
+
+    /* Update the receive queue */
+    control = VLAN_RXQC_TOGGLE | VLAN_RXQC_VALID;
+    if (rxq_bd & VLAN_BD_TOGGLE) {
+        control ^= VLAN_RXQC_TOGGLE;
+    }
+
+    handle = ldq_tce(sdev, VLAN_BD_ADDR(bd));
+    stq_tce(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr + 8, handle);
+    stw_tce(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr + 4, size);
+    sth_tce(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr + 2, 8);
+    stb_tce(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr, control);
+
+    dprintf("wrote rxq entry (ptr=0x%llx): 0x%016llx 0x%016llx\n",
+            (unsigned long long)dev->rxq_ptr,
+            (unsigned long long)ldq_tce(sdev, VLAN_BD_ADDR(rxq_bd) +
+                                        dev->rxq_ptr),
+            (unsigned long long)ldq_tce(sdev, VLAN_BD_ADDR(rxq_bd) +
+                                        dev->rxq_ptr + 8));
+
+    dev->rxq_ptr += 16;
+    if (dev->rxq_ptr >= VLAN_BD_LEN(rxq_bd)) {
+        dev->rxq_ptr = 0;
+        stq_tce(sdev, dev->buf_list + VLAN_RXQ_BD_OFF, rxq_bd ^ VLAN_BD_TOGGLE);
+    }
+
+    if (sdev->signal_state & 1) {
+        qemu_irq_pulse(sdev->qirq);
+    }
+
+    return size;
+}
+
+static NetClientInfo net_spapr_vlan_info = {
+    .type = NET_CLIENT_TYPE_NIC,
+    .size = sizeof(NICState),
+    .can_receive = spapr_vlan_can_receive,
+    .receive = spapr_vlan_receive,
+};
+
+static int spapr_vlan_init(VIOsPAPRDevice *sdev)
+{
+    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
+    VIOsPAPRBus *bus;
+
+    bus = DO_UPCAST(VIOsPAPRBus, bus, sdev->qdev.parent_bus);
+
+    qemu_macaddr_default_if_unset(&dev->nicconf.macaddr);
+
+    dev->nic = qemu_new_nic(&net_spapr_vlan_info, &dev->nicconf,
+                            sdev->qdev.info->name, sdev->qdev.id, dev);
+    qemu_format_nic_info_str(&dev->nic->nc, dev->nicconf.macaddr.a);
+
+    return 0;
+}
+
+void spapr_vlan_create(VIOsPAPRBus *bus, uint32_t reg, NICInfo *nd,
+                       qemu_irq qirq, uint32_t vio_irq_num)
+{
+    DeviceState *dev;
+    VIOsPAPRDevice *sdev;
+
+    dev = qdev_create(&bus->bus, "spapr-vlan");
+    qdev_prop_set_uint32(dev, "reg", reg);
+    
+    qdev_set_nic_properties(dev, nd);
+
+    qdev_init_nofail(dev);
+    sdev = (VIOsPAPRDevice *)dev;
+    sdev->qirq = qirq;
+    sdev->vio_irq_num = vio_irq_num;
+}
+
+static int spapr_vlan_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off)
+{
+    VIOsPAPRVLANDevice *vdev = (VIOsPAPRVLANDevice *)dev;
+    int ret;
+
+    ret = fdt_setprop(fdt, node_off, "local-mac-address",
+                      &vdev->nicconf.macaddr, ETH_ALEN);
+    if (ret < 0) {
+        return ret;
+    }
+
+    ret = fdt_setprop_cell(fdt, node_off, "ibm,mac-address-filters", 0);
+    if (ret < 0) {
+        return ret;
+    }
+
+    return 0;
+}
+
+static int check_bd(VIOsPAPRVLANDevice *dev, vlan_bd_t bd, target_ulong alignment)
+{
+    if ((VLAN_BD_ADDR(bd) % alignment)
+        || (VLAN_BD_LEN(bd) % alignment)) {
+        return -1;
+    }
+
+    if (spapr_vio_check_tces(&dev->sdev, VLAN_BD_ADDR(bd),
+                             VLAN_BD_LEN(bd), SPAPR_TCE_RW) != 0) {
+        return -1;
+    }
+
+    return 0;
+}
+
+static target_ulong h_register_logical_lan(CPUState *env, sPAPREnvironment *spapr,
+                                           target_ulong opcode,
+                                           target_ulong *args)
+{
+    target_ulong reg = args[0];
+    target_ulong buf_list = args[1];
+    target_ulong rec_queue = args[2];
+    target_ulong filter_list = args[3];
+//    target_ulong mac_address = args[4];
+    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
+    vlan_bd_t filter_list_bd;
+#ifdef DEBUG
+    target_ulong mac_address = args[4];
+#endif
+
+    if (!dev) {
+        return H_PARAMETER;
+    }
+
+    if (dev->isopen) {
+        fprintf(stderr, "H_REGISTER_LOGICAL_LAN called twice without "
+                "H_FREE_LOGICAL_LAN\n");
+        return H_RESOURCE;
+    }
+
+    if (check_bd(dev, VLAN_VALID_BD(buf_list, SPAPR_VIO_TCE_PAGE_SIZE),
+                 SPAPR_VIO_TCE_PAGE_SIZE) < 0) {
+        fprintf(stderr, "Bad buf_list 0x" TARGET_FMT_lx 
+                " for H_REGISTER_LOGICAL_LAN\n", buf_list);
+        return H_PARAMETER;
+    }
+
+    filter_list_bd = VLAN_VALID_BD(filter_list, SPAPR_VIO_TCE_PAGE_SIZE);
+    if (check_bd(dev, filter_list_bd, SPAPR_VIO_TCE_PAGE_SIZE) < 0) {
+        fprintf(stderr, "Bad filter_list 0x" TARGET_FMT_lx 
+                " for H_REGISTER_LOGICAL_LAN\n", filter_list);
+        return H_PARAMETER;
+    }
+
+    if (!(rec_queue & VLAN_BD_VALID)
+        || (check_bd(dev, rec_queue, VLAN_RQ_ALIGNMENT) < 0)) {
+        fprintf(stderr, "Bad receive queue for H_REGISTER_LOGICAL_LAN\n");
+        return H_PARAMETER;
+    }
+
+    dev->buf_list = buf_list;
+    sdev->signal_state = 0;
+
+    rec_queue &= ~VLAN_BD_TOGGLE;
+
+    /* Initialize the buffer list */
+    stq_tce(sdev, buf_list, rec_queue);
+    stq_tce(sdev, buf_list + 8, filter_list_bd);
+    spapr_tce_dma_zero(sdev, buf_list + VLAN_RX_BDS_OFF,
+                       SPAPR_VIO_TCE_PAGE_SIZE - VLAN_RX_BDS_OFF);
+    dev->add_buf_ptr = VLAN_RX_BDS_OFF - 8;
+    dev->use_buf_ptr = VLAN_RX_BDS_OFF - 8;
+    dev->rx_bufs = 0;
+    dev->rxq_ptr = 0;
+
+    /* Initialize the receive queue */
+    spapr_tce_dma_zero(sdev, VLAN_BD_ADDR(rec_queue), VLAN_BD_LEN(rec_queue));
+
+    dev->isopen = 1;
+    return H_SUCCESS;
+}
+
+
+static target_ulong h_free_logical_lan(CPUState *env, sPAPREnvironment *spapr,
+                                       target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
+
+    if (!dev) {
+        return H_PARAMETER;
+    }
+
+    if (!dev->isopen) {
+        fprintf(stderr, "H_FREE_LOGICAL_LAN called without "
+                "H_REGISTER_LOGICAL_LAN\n");
+        return H_RESOURCE;
+    }
+
+    dev->buf_list = 0;
+    dev->rx_bufs = 0;
+    dev->isopen = 0;
+    return H_SUCCESS;
+}
+
+static target_ulong h_add_logical_lan_buffer(CPUState *env, sPAPREnvironment *spapr,
+                                             target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    target_ulong buf = args[1];
+    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
+    vlan_bd_t bd;
+
+    dprintf("H_ADD_LOGICAL_LAN_BUFFER(0x" TARGET_FMT_lx
+            ", 0x" TARGET_FMT_lx ")\n", reg, buf);
+
+    if (!sdev) {
+        fprintf(stderr, "Wrong device in h_add_logical_lan_buffer\n");
+        return H_PARAMETER;
+    }
+
+    if ((check_bd(dev, buf, 4) < 0)
+        || (VLAN_BD_LEN(buf) < 16)) {
+        fprintf(stderr, "Bad buffer enqueued in h_add_logical_lan_buffer\n");
+        return H_PARAMETER;
+    }
+
+    if (!dev->isopen || dev->rx_bufs >= VLAN_MAX_BUFS) {
+        return H_RESOURCE;
+    }
+
+    do {
+        dev->add_buf_ptr += 8;
+        if (dev->add_buf_ptr >= SPAPR_VIO_TCE_PAGE_SIZE) {
+            dev->add_buf_ptr = VLAN_RX_BDS_OFF;
+        }
+
+        bd = ldq_tce(sdev, dev->buf_list + dev->add_buf_ptr);
+    } while (bd & VLAN_BD_VALID);
+
+    stq_tce(sdev, dev->buf_list + dev->add_buf_ptr, buf);
+
+    dev->rx_bufs++;
+
+    dprintf("h_add_logical_lan_buffer():  Added buf  ptr=%d  rx_bufs=%d"
+            " bd=0x%016llx\n", dev->add_buf_ptr, dev->rx_bufs,
+            (unsigned long long)buf);
+    
+    return H_SUCCESS;
+}
+
+static target_ulong h_send_logical_lan(CPUState *env, sPAPREnvironment *spapr,
+                                       target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    target_ulong *bufs = args + 1;
+    target_ulong continue_token = args[7];
+    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
+    unsigned total_len;
+    uint8_t *lbuf, *p;
+    int i, nbufs;
+    int ret = H_SUCCESS;
+
+    dprintf("H_SEND_LOGICAL_LAN(0x" TARGET_FMT_lx ", <bufs>, 0x" 
+            TARGET_FMT_lx ")\n", reg, continue_token); 
+
+    if (!sdev) {
+        return H_PARAMETER;
+    }
+
+    dprintf("rxbufs = %d\n", dev->rx_bufs);
+
+    if (!dev->isopen) {
+        return H_DROPPED;
+    }
+
+    if (continue_token) {
+        return H_HARDWARE; /* FIXME actually handle this */
+    }
+
+    total_len = 0;
+    for (i = 0; i < 6; i++) {
+        dprintf("   buf desc: 0x" TARGET_FMT_lx "\n", bufs[i]);
+        if (!(bufs[i] & VLAN_BD_VALID)) {
+            break;
+        }
+        total_len += VLAN_BD_LEN(bufs[i]);
+    }
+    
+    nbufs = i;
+    dprintf("h_send_logical_lan() %d buffers, total length 0x%x\n",
+            nbufs, total_len);
+
+    if (total_len == 0) {
+        return ret;
+    }
+
+    lbuf = qemu_mallocz(total_len);
+    p = lbuf;
+    for (i = 0; i < nbufs; i++) {
+        ret = spapr_tce_dma_read(sdev, VLAN_BD_ADDR(bufs[i]),
+                                 p, VLAN_BD_LEN(bufs[i]));
+        if (ret < 0) {
+            goto out;
+        }
+
+        p += VLAN_BD_LEN(bufs[i]);
+    }
+
+    qemu_send_packet(&dev->nic->nc, lbuf, total_len);
+
+out:
+    qemu_free(lbuf);
+
+    return ret;
+}
+
+static target_ulong h_multicast_ctrl(CPUState *env, sPAPREnvironment *spapr,
+                                     target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+
+    if (!dev) {
+        return H_PARAMETER;
+    }
+
+    return H_SUCCESS;
+}
+
+static void vlan_hcalls(VIOsPAPRBus *bus)
+{
+    spapr_register_hypercall(H_REGISTER_LOGICAL_LAN, h_register_logical_lan);
+    spapr_register_hypercall(H_FREE_LOGICAL_LAN, h_free_logical_lan);
+    spapr_register_hypercall(H_SEND_LOGICAL_LAN, h_send_logical_lan);
+    spapr_register_hypercall(H_ADD_LOGICAL_LAN_BUFFER, h_add_logical_lan_buffer);
+    spapr_register_hypercall(H_MULTICAST_CTRL, h_multicast_ctrl);
+}
+
+static VIOsPAPRDeviceInfo spapr_vlan = {
+    .init = spapr_vlan_init,
+    .devnode = spapr_vlan_devnode,
+    .dt_name = "l-lan",
+    .dt_type = "network",
+    .dt_compatible = "IBM,l-lan",
+    .signal_mask = 0x1,
+    .hcalls = vlan_hcalls,
+    .qdev.name = "spapr-vlan",
+    .qdev.size = sizeof(VIOsPAPRVLANDevice),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("reg", VIOsPAPRDevice, reg, 0x1000),
+        DEFINE_PROP_UINT32("dma-window", VIOsPAPRDevice, rtce_window_size,
+                           0x10000000),
+        DEFINE_NIC_PROPERTIES(VIOsPAPRVLANDevice, nicconf),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void spapr_vlan_register(void)
+{
+    spapr_vio_bus_register_withprop(&spapr_vlan);
+}
+device_init(spapr_vlan_register);
diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h
index 1b15d3e..4cfaf55 100644
--- a/hw/spapr_vio.h
+++ b/hw/spapr_vio.h
@@ -21,9 +21,9 @@
  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 
-#define SPAPR_VIO_TCE_PAGE_SHIFT	12
-#define SPAPR_VIO_TCE_PAGE_SIZE		(1ULL << SPAPR_VIO_TCE_PAGE_SHIFT)
-#define SPAPR_VIO_TCE_PAGE_MASK		(SPAPR_VIO_TCE_PAGE_SIZE - 1)
+#define SPAPR_VIO_TCE_PAGE_SHIFT   12
+#define SPAPR_VIO_TCE_PAGE_SIZE    (1ULL << SPAPR_VIO_TCE_PAGE_SHIFT)
+#define SPAPR_VIO_TCE_PAGE_MASK    (SPAPR_VIO_TCE_PAGE_SIZE - 1)
 
 enum VIOsPAPR_TCEAccess {
     SPAPR_TCE_FAULT = 0,
@@ -86,4 +86,7 @@ void spapr_vty_create(VIOsPAPRBus *bus,
                       uint32_t reg, CharDriverState *chardev,
                       qemu_irq qirq, uint32_t vio_irq_num);
 
+void spapr_vlan_create(VIOsPAPRBus *bus, uint32_t reg, NICInfo *nd,
+                       qemu_irq qirq, uint32_t vio_irq_num);
+
 #endif /* _HW_SPAPR_VIO_H */
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 24/28] Implement PAPR CRQ hypercalls
  2011-02-15  4:56 [Qemu-devel] RFC: Implement emulation of pSeries logical partitions (v2) qemu
                   ` (22 preceding siblings ...)
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 23/28] Implement sPAPR Virtual LAN (ibmveth) qemu
@ 2011-02-15  4:56 ` qemu
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 25/28] Implement PAPR virtual SCSI interface (ibmvscsi) qemu
                   ` (3 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: qemu @ 2011-02-15  4:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: paulus, agraf, anton

From: David Gibson <david@gibson.dropbear.id.au>

This patch implements the infrastructure and hypercalls necessary for the
PAPR specified CRQ (Command Request Queue) mechanism.  This general
request queueing system is used by many of the PAPR virtual IO devices,
including the virtual scsi adapter.

Signed-off-by: Ben Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: David Gibson <dwg@au1.ibm.com>
---
 hw/spapr.c     |    2 +-
 hw/spapr_vio.c |  159 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/spapr_vio.h |   12 ++++
 3 files changed, 172 insertions(+), 1 deletions(-)

diff --git a/hw/spapr.c b/hw/spapr.c
index 44cf3cc..cb97a16 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -64,7 +64,7 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize,
     uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
     uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)};
     char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt"
-        "\0hcall-tce";
+        "\0hcall-tce\0hcall-vio";
     uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)};
     int i;
     char *modelname;
diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
index cb90d48..5ea2aa2 100644
--- a/hw/spapr_vio.c
+++ b/hw/spapr_vio.c
@@ -352,6 +352,159 @@ uint64_t ldq_tce(VIOsPAPRDevice *dev, uint64_t taddr)
     return tswap64(val);
 }
 
+/*
+ * CRQ handling
+ */
+static target_ulong h_reg_crq(CPUState *env, sPAPREnvironment *spapr,
+                              target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    target_ulong queue_addr = args[1];
+    target_ulong queue_len = args[2];
+    VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+
+    if (!dev) {
+        fprintf(stderr, "h_reg_crq on non-existent unit 0x"
+                TARGET_FMT_lx "\n", reg);
+        return H_PARAMETER;
+    }
+
+    /* We can't grok a queue size bigger than 256M for now */
+    if (queue_len < 0x1000 || queue_len > 0x10000000) {
+        fprintf(stderr, "h_reg_crq, queue size too small or too big (0x%llx)\n",
+                (unsigned long long)queue_len);
+        return H_PARAMETER;
+    }
+
+    /* Check queue alignment */
+    if (queue_addr & 0xfff) {
+        fprintf(stderr, "h_reg_crq, queue not aligned (0x%llx)\n",
+                (unsigned long long)queue_addr);
+        return H_PARAMETER;
+    }
+
+    /* Check if device supports CRQs */
+    if (!dev->crq.SendFunc) {
+        return H_NOT_FOUND;
+    }
+
+
+    /* Already a queue ? */
+    if (dev->crq.qsize) {
+        return H_RESOURCE;
+    }
+    dev->crq.qladdr = queue_addr;
+    dev->crq.qsize = queue_len;
+    dev->crq.qnext = 0;
+
+    dprintf("CRQ for dev 0x" TARGET_FMT_lx " registered at 0x"
+            TARGET_FMT_lx "/0x" TARGET_FMT_lx "\n",
+            reg, queue_addr, queue_len);
+    return H_SUCCESS;
+}
+
+static target_ulong h_free_crq(CPUState *env, sPAPREnvironment *spapr,
+                               target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+
+    if (!dev) {
+        fprintf(stderr, "h_free_crq on non-existent unit 0x"
+                TARGET_FMT_lx "\n", reg);
+        return H_PARAMETER;
+    }
+
+    dev->crq.qladdr = 0;
+    dev->crq.qsize = 0;
+    dev->crq.qnext = 0;
+
+    dprintf("CRQ for dev 0x" TARGET_FMT_lx " freed\n", reg);
+
+    return H_SUCCESS;
+}
+
+static target_ulong h_send_crq(CPUState *env, sPAPREnvironment *spapr,
+                               target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    target_ulong msg_hi = args[1];
+    target_ulong msg_lo = args[2];
+    VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+    uint64_t crq_mangle[2];
+
+    if (!dev) {
+        fprintf(stderr, "h_send_crq on non-existent unit 0x"
+                TARGET_FMT_lx "\n", reg);
+        return H_PARAMETER;
+    }
+    crq_mangle[0] = cpu_to_be64(msg_hi);
+    crq_mangle[1] = cpu_to_be64(msg_lo);
+
+    if (dev->crq.SendFunc) {
+        return dev->crq.SendFunc(dev, (uint8_t *)crq_mangle);
+    }
+
+    return H_HARDWARE;
+}
+
+static target_ulong h_enable_crq(CPUState *env, sPAPREnvironment *spapr,
+                                 target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+
+    if (!dev) {
+        fprintf(stderr, "h_enable_crq on non-existent unit 0x"
+                TARGET_FMT_lx "\n", reg);
+        return H_PARAMETER;
+    }
+
+    return 0;
+}
+
+/* Returns negative error, 0 success, or positive: queue full */
+int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq)
+{
+    int rc;
+    uint8_t byte;
+
+    if (!dev->crq.qsize) {
+        fprintf(stderr, "spapr_vio_send_creq on uninitialized queue\n");
+        return -1;
+    }
+
+    /* Maybe do a fast path for KVM just writing to the pages */
+    rc = spapr_tce_dma_read(dev, dev->crq.qladdr + dev->crq.qnext, &byte, 1);
+    if (rc) {
+        return rc;
+    }
+    if (byte != 0) {
+        return 1;
+    }
+
+    rc = spapr_tce_dma_write(dev, dev->crq.qladdr + dev->crq.qnext + 8, &crq[8], 8);
+    if (rc) {
+        return rc;
+    }
+#ifdef __powerpc__
+    /* Really only needed for kvm... */
+    asm volatile("eieio" : : : "memory");
+#endif
+    rc = spapr_tce_dma_write(dev, dev->crq.qladdr + dev->crq.qnext, crq, 8);
+    if (rc) {
+        return rc;
+    }
+
+    dev->crq.qnext = (dev->crq.qnext + 16) % dev->crq.qsize;
+
+    if (dev->signal_state & 1) {
+        qemu_irq_pulse(dev->qirq);
+    }
+
+    return 0;
+}
+
 static int spapr_vio_busdev_init(DeviceState *dev, DeviceInfo *info)
 {
     VIOsPAPRDeviceInfo *_info = (VIOsPAPRDeviceInfo *)info;
@@ -422,6 +575,12 @@ VIOsPAPRBus *spapr_vio_bus_init(void)
     /* hcall-tce */
     spapr_register_hypercall(H_PUT_TCE, h_put_tce);
 
+    /* hcall-crq */
+    spapr_register_hypercall(H_REG_CRQ, h_reg_crq);
+    spapr_register_hypercall(H_FREE_CRQ, h_free_crq);
+    spapr_register_hypercall(H_SEND_CRQ, h_send_crq);
+    spapr_register_hypercall(H_ENABLE_CRQ, h_enable_crq);
+
     for (_info = device_info_list; _info; _info = _info->next) {
         VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)_info;
 
diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h
index 4cfaf55..ba16795 100644
--- a/hw/spapr_vio.h
+++ b/hw/spapr_vio.h
@@ -32,10 +32,19 @@ enum VIOsPAPR_TCEAccess {
     SPAPR_TCE_RW = 3,
 };
 
+struct VIOsPAPRDevice;
+
 typedef struct VIOsPAPR_RTCE {
     uint64_t tce;
 } VIOsPAPR_RTCE;
 
+typedef struct VIOsPAPR_CRQ {
+    uint64_t qladdr;
+    uint32_t qsize;
+    uint32_t qnext;
+    int(*SendFunc)(struct VIOsPAPRDevice *vdev, uint8_t *crq);
+} VIOsPAPR_CRQ;
+
 typedef struct VIOsPAPRDevice {
     DeviceState qdev;
     uint32_t reg;
@@ -44,6 +53,7 @@ typedef struct VIOsPAPRDevice {
     target_ulong signal_state;
     uint32_t rtce_window_size;
     VIOsPAPR_RTCE *rtce_table;
+    VIOsPAPR_CRQ crq;
 } VIOsPAPRDevice;
 
 typedef struct VIOsPAPRBus {
@@ -81,6 +91,8 @@ void stw_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint32_t val);
 void stq_tce(VIOsPAPRDevice *dev, uint64_t taddr, uint64_t val);
 uint64_t ldq_tce(VIOsPAPRDevice *dev, uint64_t taddr);
 
+int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq);
+
 void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len);
 void spapr_vty_create(VIOsPAPRBus *bus,
                       uint32_t reg, CharDriverState *chardev,
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 25/28] Implement PAPR virtual SCSI interface (ibmvscsi)
  2011-02-15  4:56 [Qemu-devel] RFC: Implement emulation of pSeries logical partitions (v2) qemu
                   ` (23 preceding siblings ...)
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 24/28] Implement PAPR CRQ hypercalls qemu
@ 2011-02-15  4:56 ` qemu
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 26/28] Add a PAPR TCE-bypass mechanism for the pSeries machine qemu
                   ` (2 subsequent siblings)
  27 siblings, 0 replies; 29+ messages in thread
From: qemu @ 2011-02-15  4:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: paulus, agraf, anton

From: David Gibson <david@gibson.dropbear.id.au>

This patch implements the infrastructure and hypercalls necessary for
the PAPR specified Virtual SCSI interface.  This is the normal method
for providing (virtual) disks to PAPR partitions.

Signed-off-by: Ben Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: David Gibson <dwg@au1.ibm.com>
---
 Makefile.target  |    2 +-
 hw/ppc-viosrp.h  |  216 ++++++++++++
 hw/spapr.c       |   10 +-
 hw/spapr_vio.h   |    3 +
 hw/spapr_vscsi.c |  960 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/srp.h         |  241 ++++++++++++++
 6 files changed, 1430 insertions(+), 2 deletions(-)
 create mode 100644 hw/ppc-viosrp.h
 create mode 100644 hw/spapr_vscsi.c
 create mode 100644 hw/srp.h

diff --git a/Makefile.target b/Makefile.target
index 0e155bc..99d1317 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -233,7 +233,7 @@ obj-ppc-y += ppc_oldworld.o
 obj-ppc-y += ppc_newworld.o
 # IBM pSeries (sPAPR)
 obj-ppc-y += spapr.o spapr_hcall.o spapr_rtas.o spapr_vio.o
-obj-ppc-y += xics.o spapr_vty.o spapr_llan.o
+obj-ppc-y += xics.o spapr_vty.o spapr_llan.o spapr_vscsi.o
 # PowerPC 4xx boards
 obj-ppc-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
 obj-ppc-y += ppc440.o ppc440_bamboo.o
diff --git a/hw/ppc-viosrp.h b/hw/ppc-viosrp.h
new file mode 100644
index 0000000..9afcf7a
--- /dev/null
+++ b/hw/ppc-viosrp.h
@@ -0,0 +1,216 @@
+/*****************************************************************************/
+/* srp.h -- SCSI RDMA Protocol definitions                                   */
+/*                                                                           */
+/* Written By: Colin Devilbis, IBM Corporation                               */
+/*                                                                           */
+/* Copyright (C) 2003 IBM Corporation                                        */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify      */
+/* it under the terms of the GNU General Public License as published by      */
+/* the Free Software Foundation; either version 2 of the License, or         */
+/* (at your option) any later version.                                       */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful,           */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of            */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             */
+/* GNU General Public License for more details.                              */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License         */
+/* along with this program; if not, write to the Free Software               */
+/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+/*                                                                           */
+/*                                                                           */
+/* This file contains structures and definitions for IBM RPA (RS/6000        */
+/* platform architecture) implementation of the SRP (SCSI RDMA Protocol)     */
+/* standard.  SRP is used on IBM iSeries and pSeries platforms to send SCSI  */
+/* commands between logical partitions.                                      */
+/*                                                                           */
+/* SRP Information Units (IUs) are sent on a "Command/Response Queue" (CRQ)  */
+/* between partitions.  The definitions in this file are architected,        */
+/* and cannot be changed without breaking compatibility with other versions  */
+/* of Linux and other operating systems (AIX, OS/400) that talk this protocol*/
+/* between logical partitions                                                */
+/*****************************************************************************/
+#ifndef PPC_VIOSRP_H
+#define PPC_VIOSRP_H
+
+#define SRP_VERSION "16.a"
+#define SRP_MAX_IU_LEN    256
+#define SRP_MAX_LOC_LEN 32
+
+union srp_iu {
+    struct srp_login_req login_req;
+    struct srp_login_rsp login_rsp;
+    struct srp_login_rej login_rej;
+    struct srp_i_logout i_logout;
+    struct srp_t_logout t_logout;
+    struct srp_tsk_mgmt tsk_mgmt;
+    struct srp_cmd cmd;
+    struct srp_rsp rsp;
+    uint8_t reserved[SRP_MAX_IU_LEN];
+};
+
+enum viosrp_crq_formats {
+    VIOSRP_SRP_FORMAT = 0x01,
+    VIOSRP_MAD_FORMAT = 0x02,
+    VIOSRP_OS400_FORMAT = 0x03,
+    VIOSRP_AIX_FORMAT = 0x04,
+    VIOSRP_LINUX_FORMAT = 0x06,
+    VIOSRP_INLINE_FORMAT = 0x07
+};
+
+enum viosrp_crq_status {
+    VIOSRP_OK = 0x0,
+    VIOSRP_NONRECOVERABLE_ERR = 0x1,
+    VIOSRP_VIOLATES_MAX_XFER = 0x2,
+    VIOSRP_PARTNER_PANIC = 0x3,
+    VIOSRP_DEVICE_BUSY = 0x8,
+    VIOSRP_ADAPTER_FAIL = 0x10,
+    VIOSRP_OK2 = 0x99,
+};
+
+struct viosrp_crq {
+    uint8_t valid;        /* used by RPA */
+    uint8_t format;        /* SCSI vs out-of-band */
+    uint8_t reserved;
+    uint8_t status;        /* non-scsi failure? (e.g. DMA failure) */
+    uint16_t timeout;        /* in seconds */
+    uint16_t IU_length;        /* in bytes */
+    uint64_t IU_data_ptr;    /* the TCE for transferring data */
+};
+
+/* MADs are Management requests above and beyond the IUs defined in the SRP
+ * standard.  
+ */
+enum viosrp_mad_types {
+    VIOSRP_EMPTY_IU_TYPE = 0x01,
+    VIOSRP_ERROR_LOG_TYPE = 0x02,
+    VIOSRP_ADAPTER_INFO_TYPE = 0x03,
+    VIOSRP_HOST_CONFIG_TYPE = 0x04,
+    VIOSRP_CAPABILITIES_TYPE = 0x05,
+    VIOSRP_ENABLE_FAST_FAIL = 0x08,
+};
+
+enum viosrp_mad_status {
+    VIOSRP_MAD_SUCCESS = 0x00,
+    VIOSRP_MAD_NOT_SUPPORTED = 0xF1,
+    VIOSRP_MAD_FAILED = 0xF7,
+};
+
+enum viosrp_capability_type {
+    MIGRATION_CAPABILITIES = 0x01,
+    RESERVATION_CAPABILITIES = 0x02,
+};
+
+enum viosrp_capability_support {
+    SERVER_DOES_NOT_SUPPORTS_CAP = 0x0,
+    SERVER_SUPPORTS_CAP = 0x01,
+    SERVER_CAP_DATA = 0x02,
+};
+
+enum viosrp_reserve_type {
+    CLIENT_RESERVE_SCSI_2 = 0x01,
+};
+
+enum viosrp_capability_flag {
+    CLIENT_MIGRATED = 0x01,
+    CLIENT_RECONNECT = 0x02,
+    CAP_LIST_SUPPORTED = 0x04,
+    CAP_LIST_DATA = 0x08,
+};
+
+/* 
+ * Common MAD header
+ */
+struct mad_common {
+    uint32_t type;
+    uint16_t status;
+    uint16_t length;
+    uint64_t tag;
+};
+
+/*
+ * All SRP (and MAD) requests normally flow from the
+ * client to the server.  There is no way for the server to send
+ * an asynchronous message back to the client.  The Empty IU is used
+ * to hang out a meaningless request to the server so that it can respond
+ * asynchrouously with something like a SCSI AER 
+ */
+struct viosrp_empty_iu {
+    struct mad_common common;
+    uint64_t buffer;
+    uint32_t port;
+};
+
+struct viosrp_error_log {
+    struct mad_common common;
+    uint64_t buffer;
+};
+
+struct viosrp_adapter_info {
+    struct mad_common common;
+    uint64_t buffer;
+};
+
+struct viosrp_host_config {
+    struct mad_common common;
+    uint64_t buffer;
+};
+
+struct viosrp_fast_fail {
+    struct mad_common common;
+};
+
+struct viosrp_capabilities {
+    struct mad_common common;
+    uint64_t buffer;
+};
+
+struct mad_capability_common {
+    uint32_t cap_type;
+    uint16_t length;
+    uint16_t server_support;
+};
+
+struct mad_reserve_cap {
+    struct mad_capability_common common;
+    uint32_t type;
+};
+
+struct mad_migration_cap {
+    struct mad_capability_common common;
+    uint32_t ecl;
+};
+
+struct capabilities{
+    uint32_t flags;
+    char name[SRP_MAX_LOC_LEN];
+    char loc[SRP_MAX_LOC_LEN];
+    struct mad_migration_cap migration;
+    struct mad_reserve_cap reserve;
+};
+
+union mad_iu {
+    struct viosrp_empty_iu empty_iu;
+    struct viosrp_error_log error_log;
+    struct viosrp_adapter_info adapter_info;
+    struct viosrp_host_config host_config;
+    struct viosrp_fast_fail fast_fail;
+    struct viosrp_capabilities capabilities;
+};
+
+union viosrp_iu {
+    union srp_iu srp;
+    union mad_iu mad;
+};
+
+struct mad_adapter_info_data {
+    char srp_version[8];
+    char partition_name[96];
+    uint32_t partition_number;
+    uint32_t mad_version;
+    uint32_t os_type;
+    uint32_t port_max_txu[8];    /* per-port maximum transfer */
+};
+
+#endif
diff --git a/hw/spapr.c b/hw/spapr.c
index cb97a16..28ec928 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -28,6 +28,7 @@
 #include "hw.h"
 #include "elf.h"
 #include "net.h"
+#include "blockdev.h"
 
 #include "hw/boards.h"
 #include "hw/ppc.h"
@@ -316,7 +317,7 @@ static void ppc_spapr_init(ram_addr_t ram_size,
     qemu_free(filename);
 
     /* Set up Interrupt Controller */
-    spapr->icp = xics_system_init(smp_cpus, envs, MAX_SERIAL_PORTS + nb_nics);
+    spapr->icp = xics_system_init(smp_cpus, envs, MAX_SERIAL_PORTS + nb_nics + drive_get_max_bus(IF_SCSI));
 
     /* Set up VIO bus */
     spapr->vio_bus = spapr_vio_bus_init();
@@ -346,6 +347,12 @@ static void ppc_spapr_init(ram_addr_t ram_size,
         }
     }
 
+    for (i = 0; i <= drive_get_max_bus(IF_SCSI); i++) {
+        spapr_vscsi_create(spapr->vio_bus, 0x2000 + i,
+                           xics_find_qirq(spapr->icp, irq), irq);
+        irq++;
+    }
+
     if (kernel_filename) {
         uint64_t lowaddr = 0;
 
@@ -406,6 +413,7 @@ static QEMUMachine spapr_machine = {
     .max_cpus = MAX_CPUS,
     .no_vga = 1,
     .no_parallel = 1,
+    .use_scsi = 1,
 };
 
 static void spapr_machine_init(void)
diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h
index ba16795..b7d0daa 100644
--- a/hw/spapr_vio.h
+++ b/hw/spapr_vio.h
@@ -101,4 +101,7 @@ void spapr_vty_create(VIOsPAPRBus *bus,
 void spapr_vlan_create(VIOsPAPRBus *bus, uint32_t reg, NICInfo *nd,
                        qemu_irq qirq, uint32_t vio_irq_num);
 
+void spapr_vscsi_create(VIOsPAPRBus *bus, uint32_t reg,
+                        qemu_irq qirq, uint32_t vio_irq_num);
+
 #endif /* _HW_SPAPR_VIO_H */
diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c
new file mode 100644
index 0000000..0a67095
--- /dev/null
+++ b/hw/spapr_vscsi.c
@@ -0,0 +1,960 @@
+/* TODO:
+ *
+ *  - Cleanups :-)
+ *  - Sort out better how to assign devices to VSCSI instances
+ *  - Fix residual counts
+ *  - Add indirect descriptors support
+ *  - Maybe do autosense (PAPR seems to mandate it, linux doesn't care)
+ */
+#include "hw.h"
+#include "scsi.h"
+#include "scsi-defs.h"
+#include "net.h" /* Remove that when we can */
+#include "srp.h"
+#include "hw/qdev.h"
+#include "hw/spapr.h"
+#include "hw/spapr_vio.h"
+#include "hw/ppc-viosrp.h"
+
+#include <libfdt.h>
+
+//#define DEBUG_VSCSI
+
+#ifdef DEBUG_VSCSI
+#define dprintf(fmt, ...) \
+    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define dprintf(fmt, ...) \
+    do { } while (0)
+#endif
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
+/*
+ * Virtual SCSI device
+ */
+
+/* Random numbers */
+#define VSCSI_MAX_SECTORS       4096/*1024*//*256*/
+#define VSCSI_REQ_LIMIT         24
+
+#define SCSI_SENSE_BUF_SIZE     96
+#define SRP_RSP_SENSE_DATA_LEN  18
+
+typedef union vscsi_crq {
+    struct viosrp_crq s;
+    uint8_t raw[16];
+} vscsi_crq;
+
+typedef struct vscsi_req
+{
+    vscsi_crq               crq;
+    union viosrp_iu         iu;
+
+    /* SCSI request tracking */
+    SCSIDevice              *sdev;
+    uint32_t                qtag; /* qemu tag != srp tag */
+    int                     lun;
+    int                     active;
+    long                    data_len;
+    int                     writing;
+    int                     sensing;
+    int                     senselen;
+    uint8_t                 sense[SCSI_SENSE_BUF_SIZE];
+
+    /* RDMA related bits */
+    uint8_t                 dma_fmt;
+    struct srp_direct_buf   ext_desc;
+    struct srp_direct_buf   *cur_desc;
+    struct srp_indirect_buf *ind_desc;
+    int                     local_desc;
+    int                     total_desc;
+    
+} vscsi_req;
+
+
+typedef struct {
+    VIOsPAPRDevice vdev;
+    SCSIBus bus;
+    vscsi_req reqs[VSCSI_REQ_LIMIT];
+} VSCSIState;
+
+/* XXX Debug only */
+static VSCSIState *dbg_vscsi_state;
+
+
+static struct vscsi_req *vscsi_get_req(VSCSIState *s)
+{
+    vscsi_req *req;
+    int i;
+
+    for (i = 0; i < VSCSI_REQ_LIMIT; i++) {
+        req = &s->reqs[i];
+        if (!req->active) {
+            memset(req, 0, sizeof(*req));
+            req->qtag = i;
+            req->active = 1;
+            return req;
+        }
+    }
+    return NULL;
+}
+
+static void vscsi_put_req(VSCSIState *s, vscsi_req *req)
+{
+    req->active = 0;
+}
+
+static vscsi_req *vscsi_find_req(VSCSIState *s, uint32_t tag)
+{
+    if (tag >= VSCSI_REQ_LIMIT || !s->reqs[tag].active) {
+        return NULL;
+    }
+    return &s->reqs[tag];
+}
+
+static void vscsi_decode_id_lun(uint64_t srp_lun, int *id, int *lun)
+{
+    /* XXX Figure that one out properly ! This is crackpot */
+    *id = (srp_lun >> 56) & 0x7f;
+    *lun = (srp_lun >> 48) & 0xff;
+}
+
+static int vscsi_send_iu(VSCSIState *s, vscsi_req *req,
+                         uint64_t length, uint8_t format)
+{
+    long rc, rc1;
+
+    /* First copy the SRP */
+    rc = spapr_tce_dma_write(&s->vdev, req->crq.s.IU_data_ptr,
+                             &req->iu, length);
+    if (rc) {
+        fprintf(stderr, "vscsi_send_iu: DMA write failure !\n");
+    }
+
+    req->crq.s.valid = 0x80;
+    req->crq.s.format = format;
+    req->crq.s.reserved = 0x00;
+    req->crq.s.timeout = cpu_to_be16(0x0000);
+    req->crq.s.IU_length = cpu_to_be16(length);
+    req->crq.s.IU_data_ptr = req->iu.srp.rsp.tag; /* right byte order */
+
+    if (rc == 0) {
+        req->crq.s.status = 0x99; /* Just needs to be non-zero */
+    } else {
+        req->crq.s.status = 0x00;
+    }
+
+    rc1 = spapr_vio_send_crq(&s->vdev, req->crq.raw);
+    if (rc1) {
+        fprintf(stderr, "vscsi_send_iu: Error sending response\n");
+        return rc1;
+    }
+
+    return rc;
+}
+
+static void vscsi_makeup_sense(VSCSIState *s, vscsi_req *req,
+                               uint8_t key, uint8_t asc, uint8_t ascq)
+{
+    req->senselen = SRP_RSP_SENSE_DATA_LEN;
+
+    /* Valid bit and 'current errors' */
+    req->sense[0] = (0x1 << 7 | 0x70);
+    /* Sense key */
+    req->sense[2] = key;
+    /* Additional sense length */
+    req->sense[7] = 0xa; /* 10 bytes */
+    /* Additional sense code */
+    req->sense[12] = asc;
+    req->sense[13] = ascq;
+}
+
+static int vscsi_send_rsp(VSCSIState *s, vscsi_req *req,
+                          uint8_t status, int32_t res_in, int32_t res_out)
+{
+   union viosrp_iu *iu = &req->iu;
+   uint64_t tag = iu->srp.rsp.tag;
+   int total_len = sizeof(iu->srp.rsp);
+
+   dprintf("VSCSI: Sending resp status: 0x%x, "
+           "res_in: %d, res_out: %d \n", status, res_in, res_out);
+
+   memset(iu, 0, sizeof(struct srp_rsp));
+   iu->srp.rsp.opcode = SRP_RSP;
+   iu->srp.rsp.req_lim_delta = cpu_to_be32(1);
+   iu->srp.rsp.tag = tag;
+
+   /* Handle residuals */
+   if (res_in < 0) {
+       iu->srp.rsp.flags |= SRP_RSP_FLAG_DIUNDER;
+       res_in = -res_in;
+   } else if (res_in) {
+       iu->srp.rsp.flags |= SRP_RSP_FLAG_DIOVER;
+   }
+   if (res_out < 0) {
+       iu->srp.rsp.flags |= SRP_RSP_FLAG_DOUNDER;
+       res_out = -res_out;
+   } else if (res_out) {
+       iu->srp.rsp.flags |= SRP_RSP_FLAG_DOOVER;
+   }
+   iu->srp.rsp.data_in_res_cnt = cpu_to_be32(res_in);
+   iu->srp.rsp.data_out_res_cnt = cpu_to_be32(res_out);
+
+   /* We don't do response data */
+   /* iu->srp.rsp.flags &= ~SRP_RSP_FLAG_RSPVALID; */
+   iu->srp.rsp.resp_data_len = cpu_to_be32(0);
+
+   /* Handle success vs. failure */
+   iu->srp.rsp.status = status;
+   if (status) {
+       iu->srp.rsp.sol_not = (iu->srp.cmd.sol_not & 0x04) >> 2;
+       if (req->senselen) {
+           req->iu.srp.rsp.flags |= SRP_RSP_FLAG_SNSVALID;
+           req->iu.srp.rsp.sense_data_len = cpu_to_be32(req->senselen);
+           memcpy(req->iu.srp.rsp.data, req->sense, req->senselen);
+           total_len += req->senselen;
+       }
+   } else {
+       iu->srp.rsp.sol_not = (iu->srp.cmd.sol_not & 0x02) >> 1;
+   }
+
+   vscsi_send_iu(s, req, total_len, VIOSRP_SRP_FORMAT);
+   return 0;
+}
+
+static inline void vscsi_swap_desc(struct srp_direct_buf *desc)
+{
+    desc->va = be64_to_cpu(desc->va);
+    desc->len = be32_to_cpu(desc->len);
+}
+
+static int vscsi_srp_direct_data(VSCSIState *s, vscsi_req *req,
+                                 uint8_t *buf, uint32_t len)
+{
+    struct srp_direct_buf *md = req->cur_desc;
+    uint32_t llen;
+    int rc;
+
+    dprintf("VSCSI: direct segment 0x%x bytes, va=0x%llx desc len=0x%x\n",
+            len, (unsigned long long)md->va, md->len);
+
+    llen = min(len, md->len);
+    if (llen) {
+        if (req->writing) { /* writing = to device = reading from memory */
+            rc = spapr_tce_dma_read(&s->vdev, md->va, buf, llen);
+        } else {
+            rc = spapr_tce_dma_write(&s->vdev, md->va, buf, llen);
+        }
+    }
+    md->len -= llen;
+    md->va += llen;
+
+    if (rc) {
+        return -1;
+    }
+    return llen;
+}
+
+static int vscsi_srp_indirect_data(VSCSIState *s, vscsi_req *req,
+                                   uint8_t *buf, uint32_t len)
+{
+    struct srp_direct_buf *td = &req->ind_desc->table_desc;
+    struct srp_direct_buf *md = req->cur_desc;
+    int rc = 0;
+    uint32_t llen, total = 0;
+
+    dprintf("VSCSI: indirect segment 0x%x bytes, td va=0x%llx len=0x%x\n",
+            len, (unsigned long long)td->va, td->len);
+
+    /* While we have data ... */
+    while(len) {
+        /* If we have a descriptor but it's empty, go fetch a new one */
+        if (md && md->len == 0) {
+            /* More local available, use one */
+            if (req->local_desc) {
+                md = ++req->cur_desc;
+                --req->local_desc;
+                --req->total_desc;
+                td->va += sizeof(struct srp_direct_buf);
+            } else {
+                md = req->cur_desc = NULL;
+            }
+        }
+        /* No descriptor at hand, fetch one */
+        if (!md) {
+            if (!req->total_desc) {
+                dprintf("VSCSI:   Out of descriptors !\n");
+                break;
+            }
+            md = req->cur_desc = &req->ext_desc;
+            dprintf("VSCSI:   Reading desc from 0x%llx\n", (unsigned long long)td->va);
+            rc = spapr_tce_dma_read(&s->vdev, td->va, md, sizeof(struct srp_direct_buf));
+            if (rc) {
+                dprintf("VSCSI: tce_dma_read -> %d reading ext_desc\n", rc);
+                break;
+            }
+            vscsi_swap_desc(md);
+            td->va += sizeof(struct srp_direct_buf);
+            --req->total_desc;
+        }
+        dprintf("VSCSI:   [desc va=0x%llx,len=0x%x] remaining=0x%x\n",
+                (unsigned long long)md->va, md->len, len);
+
+        /* Perform transfer */
+        llen = min(len, md->len);
+        if (req->writing) { /* writing = to device = reading from memory */ 
+            rc = spapr_tce_dma_read(&s->vdev, md->va, buf, llen);
+            
+        } else {
+            rc = spapr_tce_dma_write(&s->vdev, md->va, buf, llen);
+        }
+        if (rc) {
+            dprintf("VSCSI: tce_dma_r/w(%d) -> %d\n", req->writing, rc);
+            break;
+        }
+        dprintf("VSCSI:     data: %02x %02x %02x %02x...\n",
+                buf[0], buf[1], buf[2], buf[3]);
+
+        len -= llen;
+        buf += llen;
+        total += llen;
+        md->va += llen;
+        md->len -= llen;
+    }
+    return rc ? -1 : total;
+}
+
+static int vscsi_srp_transfer_data(VSCSIState *s, vscsi_req *req,
+                                   int writing, uint8_t *buf, uint32_t len)
+{
+    int err = 0;
+  
+    switch (req->dma_fmt) {
+    case SRP_NO_DATA_DESC:
+        dprintf("VSCSI: no data desc transfer, skipping 0x%x bytes\n", len);
+        break;
+    case SRP_DATA_DESC_DIRECT:
+        err = vscsi_srp_direct_data(s, req, buf, len);
+        break;
+    case SRP_DATA_DESC_INDIRECT:
+        err = vscsi_srp_indirect_data(s, req, buf, len);
+        break;
+    }
+    return err;
+}
+
+/* Bits from linux srp */
+static int data_out_desc_size(struct srp_cmd *cmd)
+{
+    int size = 0;
+    uint8_t fmt = cmd->buf_fmt >> 4;
+
+    switch (fmt) {
+    case SRP_NO_DATA_DESC:
+        break;
+    case SRP_DATA_DESC_DIRECT:
+        size = sizeof(struct srp_direct_buf);
+        break;
+    case SRP_DATA_DESC_INDIRECT:
+        size = sizeof(struct srp_indirect_buf) +
+            sizeof(struct srp_direct_buf) * cmd->data_out_desc_cnt;
+        break;
+    default:
+        break;
+    }
+    return size;
+}
+
+static int vscsi_preprocess_desc(vscsi_req *req)
+{
+    struct srp_cmd *cmd = &req->iu.srp.cmd;
+    int offset, i;
+
+    offset = cmd->add_cdb_len & ~3;
+
+    if (req->writing) {
+        req->dma_fmt = cmd->buf_fmt >> 4;
+    } else {
+        offset += data_out_desc_size(cmd);
+        req->dma_fmt = cmd->buf_fmt & ((1U << 4) - 1);
+    }
+
+    switch (req->dma_fmt) {
+    case SRP_NO_DATA_DESC:
+        break;
+    case SRP_DATA_DESC_DIRECT:
+        req->cur_desc = (struct srp_direct_buf *)(cmd->add_data + offset);
+        req->total_desc = req->local_desc = 1;
+        vscsi_swap_desc(req->cur_desc);
+        dprintf("VSCSI: using direct RDMA %s, 0x%x bytes MD: 0x%llx\n",
+                req->writing ? "write" : "read",
+                req->cur_desc->len, (unsigned long long)req->cur_desc->va);
+        break;
+    case SRP_DATA_DESC_INDIRECT:
+        req->ind_desc = (struct srp_indirect_buf *)(cmd->add_data + offset);
+        vscsi_swap_desc(&req->ind_desc->table_desc);
+        req->total_desc = req->ind_desc->table_desc.len / sizeof(struct srp_direct_buf);
+        req->local_desc = req->writing ? cmd->data_out_desc_cnt :
+            cmd->data_in_desc_cnt;
+        for (i = 0; i < req->local_desc; i++)
+            vscsi_swap_desc(&req->ind_desc->desc_list[i]);
+        req->cur_desc = req->local_desc ? &req->ind_desc->desc_list[0] : NULL;
+        dprintf("VSCSI: using indirect RDMA %s, 0x%x bytes %d descs (%d local) VA: 0x%llx\n",
+                req->writing ? "read" : "write", be32_to_cpu(req->ind_desc->len),
+                req->total_desc, req->local_desc,
+                (unsigned long long)req->ind_desc->table_desc.va);
+        break;
+    default:
+        fprintf(stderr,
+                "vscsi_preprocess_desc: Unknown format %x\n", req->dma_fmt);
+        return -1;
+    }
+
+    return 0;
+}
+
+static void vscsi_send_request_sense(VSCSIState *s, vscsi_req *req)
+{
+    SCSIDevice *sdev = req->sdev;
+    uint8_t *cdb = req->iu.srp.cmd.cdb;
+    int n;
+
+    cdb[0] = 3;
+    cdb[1] = 0;
+    cdb[2] = 0;
+    cdb[3] = 0;
+    cdb[4] = 96;
+    cdb[5] = 0;
+    req->sensing = 1;
+    n = sdev->info->send_command(sdev, req->qtag, cdb, req->lun);
+    dprintf("VSCSI: Queued request sense tag 0x%x \n", req->qtag);
+    if (n < 0) {
+        fprintf(stderr, "VSCSI: REQUEST_SENSE wants write data !?!?!?\n");
+        sdev->info->cancel_io(sdev, req->qtag);
+        vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0);
+        vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
+        vscsi_put_req(s, req);
+        return;
+    } else if (n == 0) {
+        return;
+    }
+    sdev->info->read_data(sdev, req->qtag);
+}
+
+/* Callback to indicate that the SCSI layer has completed a transfer.  */
+static void vscsi_command_complete(SCSIBus *bus, int reason, uint32_t tag,
+                                   uint32_t arg)
+{
+    VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, bus->qbus.parent);
+    vscsi_req *req = vscsi_find_req(s, tag);
+    SCSIDevice *sdev;
+    uint8_t *buf;
+    int32_t res_in = 0, res_out = 0;
+    int len, rc = 0;
+
+    dprintf("VSCSI: SCSI cmd complete, r=0x%x tag=0x%x arg=0x%x, req=%p\n",
+            reason, tag, arg, req);
+    if (req == NULL) {
+        fprintf(stderr, "VSCSI: Can't find request for tag 0x%x\n", tag);
+        return;
+    }
+    sdev = req->sdev;
+
+    if (req->sensing) {
+        if (reason == SCSI_REASON_DONE) {
+            dprintf("VSCSI: Sense done !\n");
+            vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
+            vscsi_put_req(s, req);
+        } else {
+            uint8_t *buf = sdev->info->get_buf(sdev, tag);
+
+            len = min(arg, SCSI_SENSE_BUF_SIZE);
+            dprintf("VSCSI: Sense data, %d bytes:\n", len);
+            dprintf("       %02x  %02x  %02x  %02x  %02x  %02x  %02x  %02x\n",
+                    buf[0], buf[1], buf[2], buf[3],
+                    buf[4], buf[5], buf[6], buf[7]);
+            dprintf("       %02x  %02x  %02x  %02x  %02x  %02x  %02x  %02x\n",
+                    buf[8], buf[9], buf[10], buf[11],
+                    buf[12], buf[13], buf[14], buf[15]);
+            memcpy(req->sense, buf, len);
+            req->senselen = len;
+            sdev->info->read_data(sdev, req->qtag);
+        }
+        return;
+    }
+
+    if (reason == SCSI_REASON_DONE) {
+        dprintf("VSCSI: Command complete err=%d\n", arg);
+        if (arg == 0) {
+            /* We handle overflows, not underflows for normal commands,
+             * but hopefully nobody cares
+             */
+            if (req->writing)
+                res_out = req->data_len;
+            else
+                res_in = req->data_len;
+            vscsi_send_rsp(s, req, 0, res_in, res_out);
+        } else if (arg == CHECK_CONDITION) {
+            dprintf("VSCSI: Got CHECK_CONDITION, requesting sense...\n");
+            vscsi_send_request_sense(s, req);
+            return;
+        } else {
+            vscsi_send_rsp(s, req, arg, 0, 0);
+        }
+        vscsi_put_req(s, req);
+        return;
+    }
+
+    /* "arg" is how much we have read for reads and how much we want
+     * to write for writes (ie, how much is to be DMA'd)
+     */
+    if (arg) {
+        buf = sdev->info->get_buf(sdev, tag);
+        rc = vscsi_srp_transfer_data(s, req, req->writing, buf, arg);
+    }
+    if (rc < 0) {
+        fprintf(stderr, "VSCSI: RDMA error rc=%d!\n", rc);
+        sdev->info->cancel_io(sdev, req->qtag);
+        vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0);
+        vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
+        vscsi_put_req(s, req);
+        return;
+    }
+
+    /* Start next chunk */
+    req->data_len -= rc;
+    if (req->writing) {
+        sdev->info->write_data(sdev, req->qtag);
+    } else {
+        sdev->info->read_data(sdev, req->qtag);
+    }
+}
+
+static void vscsi_process_login(VSCSIState *s, vscsi_req *req)
+{
+    union viosrp_iu *iu = &req->iu;
+    struct srp_login_rsp *rsp = &iu->srp.login_rsp;
+    uint64_t tag = iu->srp.rsp.tag;
+
+    dprintf("VSCSI: Got login, sendin response !\n");
+
+    /* TODO handle case that requested size is wrong and
+     * buffer format is wrong
+     */
+    memset(iu, 0, sizeof(struct srp_login_rsp));
+    rsp->opcode = SRP_LOGIN_RSP;
+    /* Don't advertise quite as many request as we support to
+     * keep room for management stuff etc...
+     */
+    rsp->req_lim_delta = cpu_to_be32(VSCSI_REQ_LIMIT-2);
+    rsp->tag = tag;
+    rsp->max_it_iu_len = cpu_to_be32(sizeof(union srp_iu));
+    rsp->max_ti_iu_len = cpu_to_be32(sizeof(union srp_iu));
+    /* direct and indirect */
+    rsp->buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT | SRP_BUF_FORMAT_INDIRECT);
+
+    vscsi_send_iu(s, req, sizeof(*rsp), VIOSRP_SRP_FORMAT);
+}
+
+static void vscsi_inquiry_no_target(VSCSIState *s, vscsi_req *req)
+{
+    uint8_t *cdb = req->iu.srp.cmd.cdb;
+    uint8_t resp_data[36];
+    int rc, len, alen;
+
+    /* We dont do EVPD. Also check that page_code is 0 */
+    if ((cdb[1] & 0x01) || (cdb[1] & 0x01) || cdb[2] != 0) {
+        /* Send INVALID FIELD IN CDB */
+        vscsi_makeup_sense(s, req, ILLEGAL_REQUEST, 0x24, 0);
+        vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
+        return;
+    }
+    alen = cdb[3];
+    alen = (alen << 8) | cdb[4];
+    len = min(alen, 36);
+
+    /* Fake up inquiry using PQ=3 */
+    memset(resp_data, 0, 36);
+    resp_data[0] = 0x7f;   /* Not capable of supporting a device here */
+    resp_data[2] = 0x06;   /* SPS-4 */
+    resp_data[3] = 0x02;   /* Resp data format */
+    resp_data[4] = 36 - 5; /* Additional length */ 
+    resp_data[7] = 0x10;   /* Sync transfers */
+    memcpy(&resp_data[16], "QEMU EMPTY      ", 16);
+    memcpy(&resp_data[8], "QEMU    ", 8);
+
+    req->writing = 0;
+    vscsi_preprocess_desc(req);
+    rc = vscsi_srp_transfer_data(s, req, 0, resp_data, len);
+    if (rc < 0) {
+        vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0);
+        vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
+    } else {
+        vscsi_send_rsp(s, req, 0, 36 - rc, 0);
+    }
+}
+
+static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req)
+{
+    union srp_iu *srp = &req->iu.srp;
+    SCSIDevice *sdev;
+    int n, id, lun;
+
+    vscsi_decode_id_lun(be64_to_cpu(srp->cmd.lun), &id, &lun);
+
+    /* Qemu vs. linux issue with LUNs to be sorted out ... */
+    sdev = (id < 8 && lun < 16) ? s->bus.devs[id] : NULL;
+    if (!sdev) {
+        dprintf("VSCSI: Command for id %d with no drive\n", id);
+        if (srp->cmd.cdb[0] == INQUIRY) {
+            vscsi_inquiry_no_target(s, req);
+        } else {
+            vscsi_makeup_sense(s, req, ILLEGAL_REQUEST, 0x24, 0x00);
+            vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
+        } return 1;
+    }
+
+    req->sdev = sdev;
+    req->lun = lun;
+    n = sdev->info->send_command(sdev, req->qtag, srp->cmd.cdb, lun);
+    
+    dprintf("VSCSI: Queued command tag 0x%x CMD 0x%x ID %d LUN %d ret: %d\n",
+            req->qtag, srp->cmd.cdb[0], id, lun, n);
+
+    if (n) {
+        /* Transfer direction must be set before preprocessing the
+         * descriptors
+         */
+        req->writing = (n < 1);
+
+        /* Preprocess RDMA descriptors */
+        vscsi_preprocess_desc(req);
+    }
+
+    /* Get transfer direction and initiate transfer */
+    if (n > 0) {
+        req->data_len = n;
+        sdev->info->read_data(sdev, req->qtag);
+    } else if (n < 0) {
+        req->data_len = -n;
+        sdev->info->write_data(sdev, req->qtag);
+    }
+    /* Don't touch req here, it may have been recycled already */
+
+    return 0;
+}
+
+static int vscsi_process_tsk_mgmt(VSCSIState *s, vscsi_req *req)
+{
+    union viosrp_iu *iu = &req->iu;
+    int fn;
+
+    fprintf(stderr, "vscsi_process_tsk_mgmt %02x\n",
+            iu->srp.tsk_mgmt.tsk_mgmt_func);
+
+    switch (iu->srp.tsk_mgmt.tsk_mgmt_func) {
+#if 0 /* We really don't deal with these for now */
+    case SRP_TSK_ABORT_TASK:
+        fn = ABORT_TASK;
+        break;
+    case SRP_TSK_ABORT_TASK_SET:
+        fn = ABORT_TASK_SET;
+        break;
+    case SRP_TSK_CLEAR_TASK_SET:
+        fn = CLEAR_TASK_SET;
+        break;
+    case SRP_TSK_LUN_RESET:
+        fn = LOGICAL_UNIT_RESET;
+        break;
+    case SRP_TSK_CLEAR_ACA:
+        fn = CLEAR_ACA;
+        break;
+#endif
+    default:
+        fn = 0;
+    }
+    if (fn) {
+        /* XXX Send/Handle target task management */
+        ;
+    } else {
+        vscsi_makeup_sense(s, req, ILLEGAL_REQUEST, 0x20, 0);
+        vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
+    }
+    return !fn;
+}
+
+static int vscsi_handle_srp_req(VSCSIState *s, vscsi_req *req)
+{
+    union srp_iu *srp = &req->iu.srp;
+    int done = 1;
+    uint8_t opcode = srp->rsp.opcode;
+
+    switch (opcode) {
+    case SRP_LOGIN_REQ:
+        vscsi_process_login(s, req);
+        break;
+    case SRP_TSK_MGMT:
+        done = vscsi_process_tsk_mgmt(s, req);
+        break;
+    case SRP_CMD:
+        done = vscsi_queue_cmd(s, req);
+        break;
+    case SRP_LOGIN_RSP:
+    case SRP_I_LOGOUT:
+    case SRP_T_LOGOUT:
+    case SRP_RSP:
+    case SRP_CRED_REQ:
+    case SRP_CRED_RSP:
+    case SRP_AER_REQ:
+    case SRP_AER_RSP:
+        fprintf(stderr, "VSCSI: Unsupported opcode %02x\n", opcode);
+        break;
+    default:
+        fprintf(stderr, "VSCSI: Unknown type %02x\n", opcode);
+    }
+
+    return done;
+}
+
+static int vscsi_send_adapter_info(VSCSIState *s, vscsi_req *req)
+{
+    struct viosrp_adapter_info *sinfo;
+    struct mad_adapter_info_data info;
+    int rc;
+
+    sinfo = &req->iu.mad.adapter_info;
+
+#if 0 /* What for ? */
+    rc = spapr_tce_dma_read(&s->vdev, be64_to_cpu(sinfo->buffer),
+                            &info, be16_to_cpu(sinfo->common.length));
+    if (rc) {
+        fprintf(stderr, "vscsi_send_adapter_info: DMA read failure !\n");
+    }
+#endif
+    memset(&info, 0, sizeof(info));
+    strcpy(info.srp_version, SRP_VERSION);
+    strncpy(info.partition_name, "qemu", sizeof("qemu"));
+    info.partition_number = cpu_to_be32(0);
+    info.mad_version = cpu_to_be32(1);
+    info.os_type = cpu_to_be32(2);
+    info.port_max_txu[0] = cpu_to_be32(VSCSI_MAX_SECTORS << 9);
+
+    rc = spapr_tce_dma_write(&s->vdev, be64_to_cpu(sinfo->buffer),
+                             &info, be16_to_cpu(sinfo->common.length));
+    if (rc)  {
+        fprintf(stderr, "vscsi_send_adapter_info: DMA write failure !\n");
+    }
+
+    sinfo->common.status = rc ? cpu_to_be32(1) : 0;
+
+    return vscsi_send_iu(s, req, sizeof(*sinfo), VIOSRP_MAD_FORMAT);
+}
+
+static int vscsi_handle_mad_req(VSCSIState *s, vscsi_req *req)
+{
+    union mad_iu *mad = &req->iu.mad;
+
+    switch (be32_to_cpu(mad->empty_iu.common.type)) {
+    case VIOSRP_EMPTY_IU_TYPE:
+        fprintf(stderr, "Unsupported EMPTY MAD IU\n");
+        break;
+    case VIOSRP_ERROR_LOG_TYPE:
+        fprintf(stderr, "Unsupported ERROR LOG MAD IU\n");
+        mad->error_log.common.status = cpu_to_be16(1);
+        vscsi_send_iu(s, req, sizeof(mad->error_log), VIOSRP_MAD_FORMAT);
+        break;
+    case VIOSRP_ADAPTER_INFO_TYPE:
+        vscsi_send_adapter_info(s, req);
+        break;
+    case VIOSRP_HOST_CONFIG_TYPE:
+        mad->host_config.common.status = cpu_to_be16(1);
+        vscsi_send_iu(s, req, sizeof(mad->host_config), VIOSRP_MAD_FORMAT);
+        break;
+    default:
+        fprintf(stderr, "VSCSI: Unknown MAD type %02x\n",
+                be32_to_cpu(mad->empty_iu.common.type));
+    }
+
+    return 1;
+}
+
+static void vscsi_got_payload(VSCSIState *s, vscsi_crq *crq)
+{
+    vscsi_req *req;
+    int done;
+
+    req = vscsi_get_req(s);
+    if (req == NULL) {
+        fprintf(stderr, "VSCSI: Failed to get a request !\n");
+        return;
+    }
+
+    /* We only support a limited number of descriptors, we know
+     * the ibmvscsi driver uses up to 10 max, so it should fit
+     * in our 256 bytes IUs. If not we'll have to increase the size
+     * of the structure.
+     */
+    if (crq->s.IU_length > sizeof(union viosrp_iu)) {
+        fprintf(stderr, "VSCSI: SRP IU too long (%d bytes) !\n",
+                crq->s.IU_length);
+        return;
+    }
+
+    /* XXX Handle failure differently ? */
+    if (spapr_tce_dma_read(&s->vdev, crq->s.IU_data_ptr, &req->iu,
+                           crq->s.IU_length)) {
+        fprintf(stderr, "vscsi_got_payload: DMA read failure !\n");
+        qemu_free(req);
+    }
+    memcpy(&req->crq, crq, sizeof(vscsi_crq));
+
+    if (crq->s.format == VIOSRP_MAD_FORMAT) {
+        done = vscsi_handle_mad_req(s, req);
+    } else {
+        done = vscsi_handle_srp_req(s, req);
+    }
+
+    if (done) {
+        vscsi_put_req(s, req);
+    }
+}
+
+
+static int vscsi_do_crq(struct VIOsPAPRDevice *dev, uint8_t *crq_data)
+{
+    VSCSIState *s = DO_UPCAST(VSCSIState, vdev, dev);
+    vscsi_crq crq;
+    
+    memcpy(crq.raw, crq_data, 16);
+    crq.s.timeout = be16_to_cpu(crq.s.timeout);
+    crq.s.IU_length = be16_to_cpu(crq.s.IU_length);
+    crq.s.IU_data_ptr = be64_to_cpu(crq.s.IU_data_ptr);
+
+    dprintf("VSCSI: do_crq %02x %02x ...\n", crq.raw[0], crq.raw[1]);
+
+    switch(crq.s.valid) {
+    case 0xc0: /* Init command/response */
+
+        /* Respond to initialization request */
+        if (crq.s.format == 0x01) {
+            memset(crq.raw, 0, 16);
+            crq.s.valid = 0xc0;
+            crq.s.format = 0x02;
+            spapr_vio_send_crq(dev, crq.raw);
+        }
+
+        /* Note that in hotplug cases, we might get a 0x02
+         * as a result of us emitting the init request
+         */
+
+        break;
+    case 0xff: /* Link event */
+
+        /* Not handled for now */
+
+        break;
+    case 0x80: /* Payloads */
+        switch (crq.s.format) {
+        case VIOSRP_SRP_FORMAT: /* AKA VSCSI request */
+        case VIOSRP_MAD_FORMAT: /* AKA VSCSI response */
+            vscsi_got_payload(s, &crq);
+            break;
+        case VIOSRP_OS400_FORMAT:
+        case VIOSRP_AIX_FORMAT:
+        case VIOSRP_LINUX_FORMAT:
+        case VIOSRP_INLINE_FORMAT:
+            fprintf(stderr, "vscsi_do_srq: Unsupported payload format %02x\n",
+                    crq.s.format);
+            break;
+        default:
+            fprintf(stderr, "vscsi_do_srq: Unknown payload format %02x\n",
+                    crq.s.format);
+        }
+        break;
+    default:
+        fprintf(stderr, "vscsi_do_crq: unknown CRQ %02x %02x ...\n",
+                crq.raw[0], crq.raw[1]);
+    };
+
+    return 0;
+}
+
+static int spapr_vscsi_init(VIOsPAPRDevice *dev)
+{
+    VSCSIState *s = DO_UPCAST(VSCSIState, vdev, dev);
+    int i;
+
+    dbg_vscsi_state = s;
+
+    /* Initialize qemu request tags */
+    memset(s->reqs, 0, sizeof(s->reqs));
+    for (i = 0; i < VSCSI_REQ_LIMIT; i++)
+        s->reqs[i].qtag = i;
+
+    dev->crq.SendFunc = vscsi_do_crq;
+
+    scsi_bus_new(&s->bus, &dev->qdev, 1, VSCSI_REQ_LIMIT,
+                 vscsi_command_complete);
+    if (!dev->qdev.hotplugged) {
+        scsi_bus_legacy_handle_cmdline(&s->bus);
+    }
+
+    return 0;
+}
+
+void spapr_vscsi_create(VIOsPAPRBus *bus, uint32_t reg,
+                        qemu_irq qirq, uint32_t vio_irq_num)
+{
+    DeviceState *dev;
+    VIOsPAPRDevice *sdev;
+
+    dev = qdev_create(&bus->bus, "spapr-vscsi");
+    qdev_prop_set_uint32(dev, "reg", reg);
+
+    qdev_init_nofail(dev);
+
+    sdev = (VIOsPAPRDevice *)dev;
+    sdev->qirq = qirq;
+    sdev->vio_irq_num = vio_irq_num;
+}
+
+static int spapr_vscsi_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off)
+{
+    int ret;
+
+    ret = fdt_setprop_cell(fdt, node_off, "#address-cells", 2);
+    if (ret < 0) {
+        return ret;
+    }
+
+    ret = fdt_setprop_cell(fdt, node_off, "#size-cells", 0);
+    if (ret < 0) {
+        return ret;
+    }
+
+    return 0;
+}
+
+static VIOsPAPRDeviceInfo spapr_vscsi = {
+    .init = spapr_vscsi_init,
+    .devnode = spapr_vscsi_devnode,
+    .dt_name = "v-scsi",
+    .dt_type = "vscsi",
+    .dt_compatible = "IBM,v-scsi",
+    .signal_mask = 0x00000001,
+    .qdev.name = "spapr-vscsi",
+    .qdev.size = sizeof(VSCSIState),
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("reg", VIOsPAPRDevice, reg, 0x2000),
+        DEFINE_PROP_UINT32("dma-window", VIOsPAPRDevice,
+                           rtce_window_size, 0x10000000),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void spapr_vscsi_register(void)
+{
+    spapr_vio_bus_register_withprop(&spapr_vscsi);
+}
+device_init(spapr_vscsi_register);
diff --git a/hw/srp.h b/hw/srp.h
new file mode 100644
index 0000000..9d55fc4
--- /dev/null
+++ b/hw/srp.h
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2005 Cisco Systems.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * $Id$
+ */
+
+#ifndef SCSI_SRP_H
+#define SCSI_SRP_H
+
+/*
+ * Structures and constants for the SCSI RDMA Protocol (SRP) as
+ * defined by the INCITS T10 committee.  This file was written using
+ * draft Revision 16a of the SRP standard.
+ */
+
+enum {
+
+    SRP_LOGIN_REQ = 0x00,
+    SRP_TSK_MGMT  = 0x01,
+    SRP_CMD       = 0x02,
+    SRP_I_LOGOUT  = 0x03,
+    SRP_LOGIN_RSP = 0xc0,
+    SRP_RSP       = 0xc1,
+    SRP_LOGIN_REJ = 0xc2,
+    SRP_T_LOGOUT  = 0x80,
+    SRP_CRED_REQ  = 0x81,
+    SRP_AER_REQ   = 0x82,
+    SRP_CRED_RSP  = 0x41,
+    SRP_AER_RSP   = 0x42
+};
+
+enum {
+    SRP_BUF_FORMAT_DIRECT   = 1 << 1,
+    SRP_BUF_FORMAT_INDIRECT = 1 << 2
+};
+
+enum {
+    SRP_NO_DATA_DESC       = 0,
+    SRP_DATA_DESC_DIRECT   = 1,
+    SRP_DATA_DESC_INDIRECT = 2
+};
+
+enum {
+    SRP_TSK_ABORT_TASK     = 0x01,
+    SRP_TSK_ABORT_TASK_SET = 0x02,
+    SRP_TSK_CLEAR_TASK_SET = 0x04,
+    SRP_TSK_LUN_RESET      = 0x08,
+    SRP_TSK_CLEAR_ACA      = 0x40
+};
+
+enum srp_login_rej_reason {
+    SRP_LOGIN_REJ_UNABLE_ESTABLISH_CHANNEL   = 0x00010000,
+    SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES     = 0x00010001,
+    SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE = 0x00010002,
+    SRP_LOGIN_REJ_UNABLE_ASSOCIATE_CHANNEL   = 0x00010003,
+    SRP_LOGIN_REJ_UNSUPPORTED_DESCRIPTOR_FMT = 0x00010004,
+    SRP_LOGIN_REJ_MULTI_CHANNEL_UNSUPPORTED  = 0x00010005,
+    SRP_LOGIN_REJ_CHANNEL_LIMIT_REACHED      = 0x00010006
+};
+
+enum {
+    SRP_REV10_IB_IO_CLASS  = 0xff00,
+    SRP_REV16A_IB_IO_CLASS = 0x0100
+};
+
+struct srp_direct_buf {
+    uint64_t    va;
+    uint32_t    key;
+    uint32_t    len;
+};
+
+/*
+ * We need the packed attribute because the SRP spec puts the list of
+ * descriptors at an offset of 20, which is not aligned to the size of
+ * struct srp_direct_buf.  The whole structure must be packed to avoid
+ * having the 20-byte structure padded to 24 bytes on 64-bit architectures.
+ */
+struct srp_indirect_buf {
+    struct srp_direct_buf    table_desc;
+    uint32_t                 len;
+    struct srp_direct_buf    desc_list[0];
+} __attribute__((packed));
+
+enum {
+    SRP_MULTICHAN_SINGLE = 0,
+    SRP_MULTICHAN_MULTI  = 1
+};
+
+struct srp_login_req {
+    uint8_t    opcode;
+    uint8_t    reserved1[7];
+    uint64_t   tag;
+    uint32_t   req_it_iu_len;
+    uint8_t    reserved2[4];
+    uint16_t   req_buf_fmt;
+    uint8_t    req_flags;
+    uint8_t    reserved3[5];
+    uint8_t    initiator_port_id[16];
+    uint8_t    target_port_id[16];
+};
+
+/*
+ * The SRP spec defines the size of the LOGIN_RSP structure to be 52
+ * bytes, so it needs to be packed to avoid having it padded to 56
+ * bytes on 64-bit architectures.
+ */
+struct srp_login_rsp {
+    uint8_t    opcode;
+    uint8_t    reserved1[3];
+    uint32_t   req_lim_delta;
+    uint64_t   tag;
+    uint32_t   max_it_iu_len;
+    uint32_t   max_ti_iu_len;
+    uint16_t   buf_fmt;
+    uint8_t    rsp_flags;
+    uint8_t    reserved2[25];
+} __attribute__((packed));
+
+struct srp_login_rej {
+    uint8_t    opcode;
+    uint8_t    reserved1[3];
+    uint32_t   reason;
+    uint64_t   tag;
+    uint8_t    reserved2[8];
+    uint16_t   buf_fmt;
+    uint8_t    reserved3[6];
+};
+
+struct srp_i_logout {
+    uint8_t    opcode;
+    uint8_t    reserved[7];
+    uint64_t   tag;
+};
+
+struct srp_t_logout {
+    uint8_t    opcode;
+    uint8_t    sol_not;
+    uint8_t    reserved[2];
+    uint32_t   reason;
+    uint64_t   tag;
+};
+
+/*
+ * We need the packed attribute because the SRP spec only aligns the
+ * 8-byte LUN field to 4 bytes.
+ */
+struct srp_tsk_mgmt {
+    uint8_t    opcode;
+    uint8_t    sol_not;
+    uint8_t    reserved1[6];
+    uint64_t   tag;
+    uint8_t    reserved2[4];
+    uint64_t   lun __attribute__((packed));
+    uint8_t    reserved3[2];
+    uint8_t    tsk_mgmt_func;
+    uint8_t    reserved4;
+    uint64_t   task_tag;
+    uint8_t    reserved5[8];
+};
+
+/*
+ * We need the packed attribute because the SRP spec only aligns the
+ * 8-byte LUN field to 4 bytes.
+ */
+struct srp_cmd {
+    uint8_t    opcode;
+    uint8_t    sol_not;
+    uint8_t    reserved1[3];
+    uint8_t    buf_fmt;
+    uint8_t    data_out_desc_cnt;
+    uint8_t    data_in_desc_cnt;
+    uint64_t   tag;
+    uint8_t    reserved2[4];
+    uint64_t   lun __attribute__((packed));
+    uint8_t    reserved3;
+    uint8_t    task_attr;
+    uint8_t    reserved4;
+    uint8_t    add_cdb_len;
+    uint8_t    cdb[16];
+    uint8_t    add_data[0];
+};
+
+enum {
+    SRP_RSP_FLAG_RSPVALID = 1 << 0,
+    SRP_RSP_FLAG_SNSVALID = 1 << 1,
+    SRP_RSP_FLAG_DOOVER   = 1 << 2,
+    SRP_RSP_FLAG_DOUNDER  = 1 << 3,
+    SRP_RSP_FLAG_DIOVER   = 1 << 4,
+    SRP_RSP_FLAG_DIUNDER  = 1 << 5
+};
+
+/*
+ * The SRP spec defines the size of the RSP structure to be 36 bytes,
+ * so it needs to be packed to avoid having it padded to 40 bytes on
+ * 64-bit architectures.
+ */
+struct srp_rsp {
+    uint8_t    opcode;
+    uint8_t    sol_not;
+    uint8_t    reserved1[2];
+    uint32_t   req_lim_delta;
+    uint64_t   tag;
+    uint8_t    reserved2[2];
+    uint8_t    flags;
+    uint8_t    status;
+    uint32_t   data_out_res_cnt;
+    uint32_t   data_in_res_cnt;
+    uint32_t   sense_data_len;
+    uint32_t   resp_data_len;
+    uint8_t    data[0];
+} __attribute__((packed));
+
+#endif /* SCSI_SRP_H */
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 26/28] Add a PAPR TCE-bypass mechanism for the pSeries machine
  2011-02-15  4:56 [Qemu-devel] RFC: Implement emulation of pSeries logical partitions (v2) qemu
                   ` (24 preceding siblings ...)
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 25/28] Implement PAPR virtual SCSI interface (ibmvscsi) qemu
@ 2011-02-15  4:56 ` qemu
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 27/28] Add SLOF-based partition firmware for pSeries machine, allowing more boot options qemu
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 28/28] Implement PAPR VPA functions for pSeries shared processor partitions qemu
  27 siblings, 0 replies; 29+ messages in thread
From: qemu @ 2011-02-15  4:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: paulus, agraf, anton

From: David Gibson <david@gibson.dropbear.id.au>

Usually, PAPR virtual IO devices use a virtual IOMMU mechanism, TCEs,
to mediate all DMA transfers.  While this is necessary for some sorts of
operation, it can be complex to program and slow for others.

This patch implements a mechanism for bypassing TCE translation, treating
"IO" addresses as plain (guest) physical memory addresses.  This has two
main uses:
 * Simple, but 64-bit aware programs like firmwares can use the VIO devices
without the complexity of TCE setup.
 * The guest OS can optionally use the TCE bypass to improve performance in
suitable situations.

The mechanism used is a per-device flag which disables TCE translation.
The flag is toggled with some (hypervisor-implemented) RTAS methods.

Signed-off-by: Ben Herrenschmidt <benh@kernel.crashing.org>
---
 hw/spapr_vio.c |   82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/spapr_vio.h |    5 +++
 2 files changed, 87 insertions(+), 0 deletions(-)

diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
index 5ea2aa2..df30f85 100644
--- a/hw/spapr_vio.c
+++ b/hw/spapr_vio.c
@@ -224,6 +224,12 @@ int spapr_tce_dma_write(VIOsPAPRDevice *dev, uint64_t taddr, const void *buf,
             (unsigned long long)taddr, size);
 #endif
 
+    /* Check for bypass */
+    if (dev->flags & VIO_PAPR_FLAG_DMA_BYPASS) {
+        cpu_physical_memory_write(taddr, buf, size);
+        return 0;
+    }
+
     while(size) {
         uint64_t tce;
         uint32_t lsize;
@@ -308,6 +314,12 @@ int spapr_tce_dma_read(VIOsPAPRDevice *dev, uint64_t taddr, void *buf,
             (unsigned long long)taddr, size);
 #endif
 
+    /* Check for bypass */
+    if (dev->flags & VIO_PAPR_FLAG_DMA_BYPASS) {
+        cpu_physical_memory_read(taddr, buf, size);
+        return 0;
+    }
+
     while(size) {
         uint64_t tce;
         uint32_t lsize;
@@ -505,6 +517,72 @@ int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq)
     return 0;
 }
 
+/* "quiesce" handling */
+
+static void spapr_vio_quiesce_one(VIOsPAPRDevice *dev)
+{
+    dev->flags &= ~VIO_PAPR_FLAG_DMA_BYPASS;
+    
+    if (dev->rtce_table) {
+        size_t size = (dev->rtce_window_size >> SPAPR_VIO_TCE_PAGE_SHIFT)
+            * sizeof(VIOsPAPR_RTCE);
+        memset(dev->rtce_table, 0, size);
+    }
+
+    dev->crq.qladdr = 0;
+    dev->crq.qsize = 0;
+    dev->crq.qnext = 0;
+}
+
+static void rtas_set_tce_bypass(sPAPREnvironment *spapr, uint32_t token,
+                                uint32_t nargs, target_ulong args,
+                                uint32_t nret, target_ulong rets)
+{
+    VIOsPAPRBus *bus = spapr->vio_bus;
+    VIOsPAPRDevice *dev;
+    uint32_t unit, enable;
+
+    if (nargs != 2) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+    unit = rtas_ld(args, 0);
+    enable = rtas_ld(args, 1);
+    dev = spapr_vio_find_by_reg(bus, unit);
+    if (!dev) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+    if (enable) {
+        dev->flags |= VIO_PAPR_FLAG_DMA_BYPASS;
+    } else {
+        dev->flags &= ~VIO_PAPR_FLAG_DMA_BYPASS;
+    }
+
+    rtas_st(rets, 0, 0);
+}
+
+static void rtas_quiesce(sPAPREnvironment *spapr, uint32_t token,
+                         uint32_t nargs, target_ulong args,
+                         uint32_t nret, target_ulong rets)
+{
+    VIOsPAPRBus *bus = spapr->vio_bus;
+    DeviceState *qdev;
+    VIOsPAPRDevice *dev = NULL;
+
+    if (nargs != 0) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+ 
+    QLIST_FOREACH(qdev, &bus->bus.children, sibling) {
+        dev = (VIOsPAPRDevice *)qdev;
+        spapr_vio_quiesce_one(dev);
+    }
+
+    rtas_st(rets, 0, 0);
+}
+
 static int spapr_vio_busdev_init(DeviceState *dev, DeviceInfo *info)
 {
     VIOsPAPRDeviceInfo *_info = (VIOsPAPRDeviceInfo *)info;
@@ -581,6 +659,10 @@ VIOsPAPRBus *spapr_vio_bus_init(void)
     spapr_register_hypercall(H_SEND_CRQ, h_send_crq);
     spapr_register_hypercall(H_ENABLE_CRQ, h_enable_crq);
 
+    /* RTAS calls */
+    spapr_rtas_register("ibm,set-tce-bypass", rtas_set_tce_bypass);
+    spapr_rtas_register("quiesce", rtas_quiesce);
+
     for (_info = device_info_list; _info; _info = _info->next) {
         VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)_info;
 
diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h
index b7d0daa..841b043 100644
--- a/hw/spapr_vio.h
+++ b/hw/spapr_vio.h
@@ -48,6 +48,8 @@ typedef struct VIOsPAPR_CRQ {
 typedef struct VIOsPAPRDevice {
     DeviceState qdev;
     uint32_t reg;
+    uint32_t flags;
+#define VIO_PAPR_FLAG_DMA_BYPASS        0x1
     qemu_irq qirq;
     uint32_t vio_irq_num;
     target_ulong signal_state;
@@ -104,4 +106,7 @@ void spapr_vlan_create(VIOsPAPRBus *bus, uint32_t reg, NICInfo *nd,
 void spapr_vscsi_create(VIOsPAPRBus *bus, uint32_t reg,
                         qemu_irq qirq, uint32_t vio_irq_num);
 
+int spapr_tce_set_bypass(uint32_t unit, uint32_t enable);
+void spapr_vio_quiesce(void);
+
 #endif /* _HW_SPAPR_VIO_H */
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 27/28] Add SLOF-based partition firmware for pSeries machine, allowing more boot options
  2011-02-15  4:56 [Qemu-devel] RFC: Implement emulation of pSeries logical partitions (v2) qemu
                   ` (25 preceding siblings ...)
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 26/28] Add a PAPR TCE-bypass mechanism for the pSeries machine qemu
@ 2011-02-15  4:56 ` qemu
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 28/28] Implement PAPR VPA functions for pSeries shared processor partitions qemu
  27 siblings, 0 replies; 29+ messages in thread
From: qemu @ 2011-02-15  4:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: paulus, agraf, anton

From: David Gibson <david@gibson.dropbear.id.au>

Currently, the emulated pSeries machine requires the use of the
-kernel parameter in order to explicitly load a guest kernel.  This
means booting from the virtual disk, cdrom or network is not possible.

This patch addresses this limitation by inserting a within-partition
firmware image (derived from the "SLOF" free Open Firmware project).
If -kernel is not specified, qemu will now load the SLOF image, which
has access to the qemu boot device list through the device tree, and
can boot from any of the usual virtual devices.

In order to support the new firmware, an extension to the emulated
machine/hypervisor is necessary.  Unlike Linux, which expects
multi-CPU entry to be handled kexec() style, the SLOF firmware expects
only one CPU to be active at entry, and to use a hypervisor RTAS
method to enable the other CPUs one by one.

This patch also implements this 'start-cpu' method, so that SLOF can
start the secondary CPUs and marshal them into the kexec() holding
pattern ready for entry into the guest OS.  Linux should, and in the
future might directly use the start-cpu method to enable initially
disabled CPUs, but for now it does require kexec() entry.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Signed-off-by: David Gibson <dwg@au1.ibm.com>
---
 Makefile         |    2 +-
 hw/spapr.c       |   28 +++++++++++++++++---
 hw/spapr_rtas.c  |   77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 pc-bios/slof.bin |  Bin 0 -> 575184 bytes
 4 files changed, 102 insertions(+), 5 deletions(-)
 create mode 100644 pc-bios/slof.bin

diff --git a/Makefile b/Makefile
index fc4bd24..06230a6 100644
--- a/Makefile
+++ b/Makefile
@@ -214,7 +214,7 @@ pxe-rtl8139.bin pxe-virtio.bin \
 bamboo.dtb petalogix-s3adsp1800.dtb \
 multiboot.bin linuxboot.bin \
 s390-zipl.rom \
-spapr-rtas.bin
+spapr-rtas.bin slof.bin
 else
 BLOBS=
 endif
diff --git a/hw/spapr.c b/hw/spapr.c
index 28ec928..80ea512 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -44,6 +44,8 @@
 #define INITRD_LOAD_ADDR        0x02800000
 #define FDT_MAX_SIZE            0x10000
 #define RTAS_MAX_SIZE           0x10000
+#define FW_MAX_SIZE             0x400000
+#define FW_FILE_NAME            "slof.bin"
 
 #define TIMEBASE_FREQ           512000000ULL
 
@@ -54,6 +56,7 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize,
                               sPAPREnvironment *spapr,
                               target_phys_addr_t initrd_base,
                               target_phys_addr_t initrd_size,
+                              const char *boot_device,
                               const char *kernel_cmdline,
                               target_phys_addr_t rtas_addr,
                               target_phys_addr_t rtas_size,
@@ -101,6 +104,7 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize,
     _FDT((fdt_property(fdt, "linux,initrd-start", &start_prop, sizeof(start_prop))));
     _FDT((fdt_property(fdt, "linux,initrd-end", &end_prop, sizeof(end_prop))));
     
+    _FDT((fdt_property_string(fdt, "qemu,boot-device", boot_device)));
     _FDT((fdt_end_node(fdt)));
 
     /* memory node */
@@ -253,7 +257,7 @@ static void ppc_spapr_init(ram_addr_t ram_size,
     ram_addr_t ram_offset;
     target_phys_addr_t fdt_addr, rtas_addr;
     uint32_t kernel_base, initrd_base;
-    long kernel_size, initrd_size, htab_size, rtas_size;
+    long kernel_size, initrd_size, htab_size, rtas_size, fw_size;
     long pteg_shift = 17;
     int fdt_size;
     sPAPREnvironment *spapr;
@@ -384,13 +388,28 @@ static void ppc_spapr_init(ram_addr_t ram_size,
             initrd_size = 0;
         }
     } else {
-        fprintf(stderr, "pSeries machine needs -kernel for now");
-        exit(1);
+        filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "slof.bin");
+        fw_size = load_image_targphys(filename, 0, FW_MAX_SIZE);
+        if (fw_size < 0) {
+            hw_error("qemu: could not load LPAR rtas '%s'\n", filename);
+            exit(1);
+        }
+        qemu_free(filename);
+        kernel_base = 0x100;
+        initrd_base = 0;
+        initrd_size = 0;
+
+        /* SLOF will startup the secondary CPUs using RTAS,
+           rather than expecting a kexec() style entry */
+        for (i = 0; i < smp_cpus; i++) {
+            envs[i]->halted = 1;
+        }
     }
 
     /* Prepare the device tree */
     fdt = spapr_create_fdt(&fdt_size, ram_size, cpu_model, envs, spapr,
-                           initrd_base, initrd_size, kernel_cmdline,
+                           initrd_base, initrd_size,
+                           boot_device, kernel_cmdline,
                            rtas_addr, rtas_size, pteg_shift + 7);
     if (!fdt) {
         hw_error("Couldn't create pSeries device tree\n");
@@ -404,6 +423,7 @@ static void ppc_spapr_init(ram_addr_t ram_size,
     envs[0]->gpr[3] = fdt_addr;
     envs[0]->gpr[5] = 0;
     envs[0]->hreset_vector = kernel_base;
+    envs[0]->halted = 0;
 }
 
 static QEMUMachine spapr_machine = {
diff --git a/hw/spapr_rtas.c b/hw/spapr_rtas.c
index 354f4df..393aa1e 100644
--- a/hw/spapr_rtas.c
+++ b/hw/spapr_rtas.c
@@ -64,6 +64,81 @@ static void rtas_power_off(sPAPREnvironment *spapr,
     rtas_st(rets, 0, 0);
 }
 
+static void rtas_query_cpu_stopped_state(sPAPREnvironment *spapr,
+                                         uint32_t token, uint32_t nargs,
+                                         target_ulong args,
+                                         uint32_t nret, target_ulong rets)
+{
+    target_ulong id;
+    CPUState *env;
+
+    if (nargs != 1 || nret != 2) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    id = rtas_ld(args, 0);
+    for (env = first_cpu; env; env = env->next_cpu) {
+        if (env->cpu_index != id) {
+            continue;
+        }
+
+        if (env->halted) {
+            rtas_st(rets, 1, 0);
+        } else {
+            rtas_st(rets, 1, 2);
+        }
+
+        rtas_st(rets, 0, 0);
+        return;
+    }
+
+    /* Didn't find a matching cpu */
+    rtas_st(rets, 0, -3);
+}
+
+static void rtas_start_cpu(sPAPREnvironment *spapr,
+                           uint32_t token, uint32_t nargs,
+                           target_ulong args,
+                           uint32_t nret, target_ulong rets)
+{
+    target_ulong id, start, r3;
+    CPUState *env;
+
+    if (nargs != 3 || nret != 1) {
+        rtas_st(rets, 0, -3);
+        return;
+    }
+
+    id = rtas_ld(args, 0);
+    start = rtas_ld(args, 1);
+    r3 = rtas_ld(args, 2);
+
+    for (env = first_cpu; env; env = env->next_cpu) {
+        if (env->cpu_index != id) {
+            continue;
+        }
+
+        if (!env->halted) {
+            rtas_st(rets, 0, -1);
+            return;
+        }
+
+        env->msr = (1ULL << MSR_SF) | (1ULL << MSR_ME);
+        env->nip = start;
+        env->gpr[3] = r3;
+        env->halted = 0;
+
+        qemu_cpu_kick(env);
+
+        rtas_st(rets, 0, 0);
+        return;
+    }
+
+    /* Didn't find a matching cpu */
+    rtas_st(rets, 0, -3);
+}
+
 static struct rtas_call {
     const char *name;
     spapr_rtas_fn fn;
@@ -169,5 +244,7 @@ static void register_core_rtas(void)
     spapr_rtas_register("display-character", rtas_display_character);
     spapr_rtas_register("get-time-of-day", rtas_get_time_of_day);
     spapr_rtas_register("power-off", rtas_power_off);
+    spapr_rtas_register("query-cpu-stopped-state", rtas_query_cpu_stopped_state);
+    spapr_rtas_register("start-cpu", rtas_start_cpu);
 }
 device_init(register_core_rtas);
diff --git a/pc-bios/slof.bin b/pc-bios/slof.bin
new file mode 100644
index 0000000000000000000000000000000000000000..1fe3fc54fe8adfebee62493c3393426c0bab7e09
GIT binary patch
literal 575184
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
H`t$z)kHTqT

literal 0
HcmV?d00001

-- 
1.7.1

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [Qemu-devel] [PATCH 28/28] Implement PAPR VPA functions for pSeries shared processor partitions
  2011-02-15  4:56 [Qemu-devel] RFC: Implement emulation of pSeries logical partitions (v2) qemu
                   ` (26 preceding siblings ...)
  2011-02-15  4:56 ` [Qemu-devel] [PATCH 27/28] Add SLOF-based partition firmware for pSeries machine, allowing more boot options qemu
@ 2011-02-15  4:56 ` qemu
  27 siblings, 0 replies; 29+ messages in thread
From: qemu @ 2011-02-15  4:56 UTC (permalink / raw)
  To: qemu-devel; +Cc: paulus, agraf, anton

From: David Gibson <david@gibson.dropbear.id.au>

Shared-processor partitions are those where a CPU is time-sliced between
partitions, rather than being permanently dedicated to a single
partition.  qemu emulated partitions, since they are just scheduled with
the qemu user process, behave mostly like shared processor partitions.

In order to better support shared processor partitions (splpar), PAPR
defines the "VPA" (Virtual Processor Area), a shared memory communication
channel between the hypervisor and partitions.  There are also two
additional shared memory communication areas for specialized purposes
associated with the VPA.

A VPA is not essential for operating an splpar, though it can be necessary
for obtaining accurate performance measurements in the presence of
runtime partition switching.

Most importantly, however, the VPA is a prerequisite for PAPR's H_CEDE,
hypercall, which allows a partition OS to give up it's shared processor
timeslices to other partitions when idle.

This patch implements the VPA and H_CEDE hypercalls in qemu.  We don't
implement any of the more advanced statistics which can be communicated
through the VPA.  However, this is enough to make normal pSeries kernels
do an effective power-save idle on an emulated pSeries, significantly
reducing the host load of a qemu emulated pSeries running an idle guest OS.

Signed-off-by: David Gibson <dwg@au1.ibm.com>
---
 hw/spapr.c       |    2 +-
 hw/spapr_hcall.c |  192 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 target-ppc/cpu.h |    4 +
 3 files changed, 197 insertions(+), 1 deletions(-)

diff --git a/hw/spapr.c b/hw/spapr.c
index 80ea512..2e04554 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -68,7 +68,7 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize,
     uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
     uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)};
     char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt"
-        "\0hcall-tce\0hcall-vio";
+        "\0hcall-tce\0hcall-vio\0hcall-splpar";
     uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)};
     int i;
     char *modelname;
diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c
index 0ff83c9..6f65655 100644
--- a/hw/spapr_hcall.c
+++ b/hw/spapr_hcall.c
@@ -4,6 +4,8 @@
 #include "sysemu.h"
 #include "qemu-char.h"
 #include "exec-all.h"
+#include "exec.h"
+#include "helper_regs.h"
 #include "hw/spapr.h"
 
 #define HPTES_PER_GROUP 8
@@ -248,6 +250,192 @@ static target_ulong h_set_dabr(CPUState *env, sPAPREnvironment *spapr,
     return H_HARDWARE;
 }
 
+#define FLAGS_REGISTER_VPA         0x0000200000000000ULL
+#define FLAGS_REGISTER_DTL         0x0000400000000000ULL
+#define FLAGS_REGISTER_SLBSHADOW   0x0000600000000000ULL
+#define FLAGS_DEREGISTER_VPA       0x0000a00000000000ULL
+#define FLAGS_DEREGISTER_DTL       0x0000c00000000000ULL
+#define FLAGS_DEREGISTER_SLBSHADOW 0x0000e00000000000ULL
+
+#define VPA_MIN_SIZE           640
+#define VPA_SIZE_OFFSET        0x4
+#define VPA_SHARED_PROC_OFFSET 0x9
+#define VPA_SHARED_PROC_VAL    0x2
+
+static target_ulong register_vpa(CPUState *env, target_ulong vpa)
+{
+    uint16_t size;
+    uint8_t tmp;
+
+    if (vpa == 0) {
+        fprintf(stderr, "Can't cope with registering a VPA at logical 0\n");
+        return H_HARDWARE;
+    }
+
+    if (vpa % env->dcache_line_size) {
+        return H_PARAMETER;
+    }
+    /* FIXME: bounds check the address */
+
+    size = lduw_phys(vpa + 0x4);
+
+    if (size < VPA_MIN_SIZE) {
+        return H_PARAMETER;
+    }
+
+    /* VPA is not allowed to cross a page boundary */
+    if ((vpa / 4096) != ((vpa + size - 1) / 4096)) {
+        return H_PARAMETER;
+    }
+
+    env->vpa = vpa;
+
+    tmp = ldub_phys(env->vpa + VPA_SHARED_PROC_OFFSET);
+    tmp |= VPA_SHARED_PROC_VAL;
+    stb_phys(env->vpa + VPA_SHARED_PROC_OFFSET, tmp);
+
+    return H_SUCCESS;
+}
+
+static target_ulong deregister_vpa(CPUState *env, target_ulong vpa)
+{
+    if (env->slb_shadow) {
+        return H_RESOURCE;
+    }
+
+    if (env->dispatch_trace_log) {
+        return H_RESOURCE;
+    }
+
+    env->vpa = 0;
+    return H_SUCCESS;
+}
+
+static target_ulong register_slb_shadow(CPUState *env, target_ulong addr)
+{
+    uint32_t size;
+
+    if (addr == 0) {
+        fprintf(stderr, "Can't cope with SLB shadow at logical 0\n");
+        return H_HARDWARE;
+    }
+
+    size = ldl_phys(addr + 0x4);
+    if (size < 0x8) {
+        return H_PARAMETER;
+    }
+
+    if ((addr / 4096) != ((addr + size - 1) / 4096)) {
+        return H_PARAMETER;
+    }
+
+    if (!env->vpa) {
+        return H_RESOURCE;
+    }
+
+    env->slb_shadow = addr;
+
+    return H_SUCCESS;
+}
+
+static target_ulong deregister_slb_shadow(CPUState *env, target_ulong addr)
+{
+    env->slb_shadow = 0;
+    return H_SUCCESS;
+}
+
+static target_ulong register_dtl(CPUState *env, target_ulong addr)
+{
+    uint32_t size;
+
+    if (addr == 0) {
+        fprintf(stderr, "Can't cope with DTL at logical 0\n");
+        return H_HARDWARE;
+    }
+
+    size = ldl_phys(addr + 0x4);
+
+    if (size < 48) {
+        return H_PARAMETER;
+    }
+
+    if (!env->vpa) {
+        return H_RESOURCE;
+    }
+
+    env->dispatch_trace_log = addr;
+    env->dtl_size = size;
+
+    return H_SUCCESS;
+}
+
+static target_ulong deregister_dtl(CPUState *emv, target_ulong addr)
+{
+    env->dispatch_trace_log = 0;
+    env->dtl_size = 0;
+
+    return H_SUCCESS;
+}
+
+static target_ulong h_register_vpa(CPUState *env, sPAPREnvironment *spapr,
+                                   target_ulong opcode, target_ulong *args)
+{
+    target_ulong flags = args[0];
+    target_ulong procno = args[1];
+    target_ulong vpa = args[2];
+    target_ulong ret = H_PARAMETER;
+    CPUState *tenv;
+
+    for (tenv = first_cpu; tenv; tenv = tenv->next_cpu) {
+        if (tenv->cpu_index == procno) {
+            break;
+        }
+    }
+
+    if (!tenv) {
+        return H_PARAMETER;
+    }
+
+    switch (flags) {
+    case FLAGS_REGISTER_VPA:
+        ret = register_vpa(tenv, vpa);
+        break;
+
+    case FLAGS_DEREGISTER_VPA:
+        ret = deregister_vpa(tenv, vpa);
+        break;
+
+    case FLAGS_REGISTER_SLBSHADOW:
+        ret = register_slb_shadow(tenv, vpa);
+        break;
+
+    case FLAGS_DEREGISTER_SLBSHADOW:
+        ret = deregister_slb_shadow(tenv, vpa);
+        break;
+
+    case FLAGS_REGISTER_DTL:
+        ret = register_dtl(tenv, vpa);
+        break;
+
+    case FLAGS_DEREGISTER_DTL:
+        ret = deregister_dtl(tenv, vpa);
+        break;
+    }
+
+    return ret;
+}
+
+static target_ulong h_cede(CPUState *env, sPAPREnvironment *spapr,
+                           target_ulong opcode, target_ulong *args)
+{
+    env->msr |= (1ULL << MSR_EE);
+    hreg_compute_hflags(env);
+    if (!cpu_has_work(env)) {
+        env->halted = 1;
+    }
+    return H_SUCCESS;
+}
+
 static target_ulong h_rtas(sPAPREnvironment *spapr, target_ulong rtas_r3)
 {
     uint32_t token = ldl_phys(rtas_r3);
@@ -311,5 +499,9 @@ static void hypercall_init(void)
 
     /* hcall-dabr */
     spapr_register_hypercall(H_SET_DABR, h_set_dabr);
+
+    /* hcall-splpar */
+    spapr_register_hypercall(H_REGISTER_VPA, h_register_vpa);
+    spapr_register_hypercall(H_CEDE, h_cede);
 }
 device_init(hypercall_init);
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 29d6b49..867a2d8 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -722,6 +722,10 @@ struct CPUPPCState {
     uint64_t insns_flags;
     void (*emulate_hypercall)(CPUState *, void *);
     void *hcall_opaque;
+    target_phys_addr_t vpa;
+    target_phys_addr_t slb_shadow;
+    target_phys_addr_t dispatch_trace_log;
+    uint32_t dtl_size;
 
     int error_code;
     uint32_t pending_interrupts;
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 29+ messages in thread

end of thread, other threads:[~2011-02-15  4:57 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-02-15  4:56 [Qemu-devel] RFC: Implement emulation of pSeries logical partitions (v2) qemu
2011-02-15  4:56 ` [Qemu-devel] [PATCH 01/28] Add TAGS and *~ to .gitignore qemu
2011-02-15  4:56 ` [Qemu-devel] [PATCH 02/28] Clean up PowerPC SLB handling code qemu
2011-02-15  4:56 ` [Qemu-devel] [PATCH 03/28] Allow qemu_devtree_setprop() to take arbitrary values qemu
2011-02-15  4:56 ` [Qemu-devel] [PATCH 04/28] Add a hook to allow hypercalls to be emulated on PowerPC qemu
2011-02-15  4:56 ` [Qemu-devel] [PATCH 05/28] Implement PowerPC slbmfee and slbmfev instructions qemu
2011-02-15  4:56 ` [Qemu-devel] [PATCH 06/28] Implement missing parts of the logic for the POWER PURR qemu
2011-02-15  4:56 ` [Qemu-devel] [PATCH 07/28] Correct ppc popcntb logic, implement popcntw and popcntd qemu
2011-02-15  4:56 ` [Qemu-devel] [PATCH 08/28] Clean up slb_lookup() function qemu
2011-02-15  4:56 ` [Qemu-devel] [PATCH 09/28] Parse SDR1 on mtspr instead of at translate time qemu
2011-02-15  4:56 ` [Qemu-devel] [PATCH 10/28] Use "hash" more consistently in ppc mmu code qemu
2011-02-15  4:56 ` [Qemu-devel] [PATCH 11/28] Better factor the ppc hash translation path qemu
2011-02-15  4:56 ` [Qemu-devel] [PATCH 12/28] Support 1T segments on ppc qemu
2011-02-15  4:56 ` [Qemu-devel] [PATCH 13/28] Add POWER7 support for ppc qemu
2011-02-15  4:56 ` [Qemu-devel] [PATCH 14/28] Start implementing pSeries logical partition machine qemu
2011-02-15  4:56 ` [Qemu-devel] [PATCH 15/28] Implement the bus structure for PAPR virtual IO qemu
2011-02-15  4:56 ` [Qemu-devel] [PATCH 16/28] Virtual hash page table handling on pSeries machine qemu
2011-02-15  4:56 ` [Qemu-devel] [PATCH 17/28] Implement hcall based RTAS for pSeries machines qemu
2011-02-15  4:56 ` [Qemu-devel] [PATCH 18/28] Implement assorted pSeries hcalls and RTAS methods qemu
2011-02-15  4:56 ` [Qemu-devel] [PATCH 19/28] Implement the PAPR (pSeries) virtualized interrupt controller (xics) qemu
2011-02-15  4:56 ` [Qemu-devel] [PATCH 20/28] Add PAPR H_VIO_SIGNAL hypercall and infrastructure for VIO interrupts qemu
2011-02-15  4:56 ` [Qemu-devel] [PATCH 21/28] Add (virtual)_interrupt to PAPR virtual tty device qemu
2011-02-15  4:56 ` [Qemu-devel] [PATCH 22/28] Implement TCE translation for sPAPR VIO qemu
2011-02-15  4:56 ` [Qemu-devel] [PATCH 23/28] Implement sPAPR Virtual LAN (ibmveth) qemu
2011-02-15  4:56 ` [Qemu-devel] [PATCH 24/28] Implement PAPR CRQ hypercalls qemu
2011-02-15  4:56 ` [Qemu-devel] [PATCH 25/28] Implement PAPR virtual SCSI interface (ibmvscsi) qemu
2011-02-15  4:56 ` [Qemu-devel] [PATCH 26/28] Add a PAPR TCE-bypass mechanism for the pSeries machine qemu
2011-02-15  4:56 ` [Qemu-devel] [PATCH 27/28] Add SLOF-based partition firmware for pSeries machine, allowing more boot options qemu
2011-02-15  4:56 ` [Qemu-devel] [PATCH 28/28] Implement PAPR VPA functions for pSeries shared processor partitions qemu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).