All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH v2 0/5] Port PPC64/PowerNV MMU tests to QEMU
@ 2022-03-31 14:58 Leandro Lupori
  2022-03-31 14:58 ` [RFC PATCH v2 1/5] target/ppc: Add support for the Processor Attention instruction Leandro Lupori
                   ` (5 more replies)
  0 siblings, 6 replies; 8+ messages in thread
From: Leandro Lupori @ 2022-03-31 14:58 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc
  Cc: Leandro Lupori, danielhb413, richard.henderson, groug, clg,
	pbonzini, alex.bennee, david

Changes from v1:
- added new files to MAINTAINERS, under PowerPC TCG CPUs, and added
  myself as a reviewer (not sure if this is the right procedure)
- removed the "virtual" ppc64le-softmmu target.
  ppc64/Makefile.softmmu-target now builds all tests in both BE and LE

Cédric Le Goater (2):
  target/ppc: Add support for the Processor Attention instruction
  ppc/pnv: Activate support for the Processor Attention instruction

Leandro Lupori (3):
  tests/tcg/ppc64: add basic softmmu test support
  tests/tcg/ppc64: add MMU test sources
  tests/tcg/ppc64: build PowerNV and LE tests

 MAINTAINERS                              |   2 +
 hw/ppc/pnv_core.c                        |   6 +
 include/hw/ppc/pnv_core.h                |   1 +
 target/ppc/cpu.h                         |   8 +
 target/ppc/excp_helper.c                 |  27 +
 target/ppc/helper.h                      |   1 +
 target/ppc/translate.c                   |  14 +
 tests/tcg/ppc64/Makefile.softmmu-rules   |  34 +
 tests/tcg/ppc64/Makefile.softmmu-target  | 124 ++++
 tests/tcg/ppc64/system/include/asm.h     |  62 ++
 tests/tcg/ppc64/system/include/console.h |  15 +
 tests/tcg/ppc64/system/include/io.h      |  61 ++
 tests/tcg/ppc64/system/include/pnv.h     |  21 +
 tests/tcg/ppc64/system/include/uart.h    |  54 ++
 tests/tcg/ppc64/system/lib/boot.S        |  68 ++
 tests/tcg/ppc64/system/lib/console.c     | 173 +++++
 tests/tcg/ppc64/system/lib/powerpc.lds   |  27 +
 tests/tcg/ppc64/system/mmu-head.S        | 142 +++++
 tests/tcg/ppc64/system/mmu.c             | 764 +++++++++++++++++++++++
 tests/tcg/ppc64/system/mmu.h             |   9 +
 20 files changed, 1613 insertions(+)
 create mode 100644 tests/tcg/ppc64/Makefile.softmmu-rules
 create mode 100644 tests/tcg/ppc64/Makefile.softmmu-target
 create mode 100644 tests/tcg/ppc64/system/include/asm.h
 create mode 100644 tests/tcg/ppc64/system/include/console.h
 create mode 100644 tests/tcg/ppc64/system/include/io.h
 create mode 100644 tests/tcg/ppc64/system/include/pnv.h
 create mode 100644 tests/tcg/ppc64/system/include/uart.h
 create mode 100644 tests/tcg/ppc64/system/lib/boot.S
 create mode 100644 tests/tcg/ppc64/system/lib/console.c
 create mode 100644 tests/tcg/ppc64/system/lib/powerpc.lds
 create mode 100644 tests/tcg/ppc64/system/mmu-head.S
 create mode 100644 tests/tcg/ppc64/system/mmu.c
 create mode 100644 tests/tcg/ppc64/system/mmu.h

-- 
2.25.1



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

* [RFC PATCH v2 1/5] target/ppc: Add support for the Processor Attention instruction
  2022-03-31 14:58 [RFC PATCH v2 0/5] Port PPC64/PowerNV MMU tests to QEMU Leandro Lupori
@ 2022-03-31 14:58 ` Leandro Lupori
  2022-03-31 14:58 ` [RFC PATCH v2 2/5] ppc/pnv: Activate " Leandro Lupori
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 8+ messages in thread
From: Leandro Lupori @ 2022-03-31 14:58 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc
  Cc: Leandro Lupori, danielhb413, richard.henderson, groug, clg,
	pbonzini, alex.bennee, david

From: Cédric Le Goater <clg@kaod.org>

Check the HID0 bit to send signal, currently modeled as a checkstop.
The QEMU implementation adds an exit using the GPR[3] value (that's a
hack for tests)

Signed-off-by: Cédric Le Goater <clg@kaod.org>
Signed-off-by: Leandro Lupori <leandro.lupori@eldorado.org.br>
---
 target/ppc/cpu.h         |  8 ++++++++
 target/ppc/excp_helper.c | 27 +++++++++++++++++++++++++++
 target/ppc/helper.h      |  1 +
 target/ppc/translate.c   | 14 ++++++++++++++
 4 files changed, 50 insertions(+)

diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 047b24ba50..12f9f3a880 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -173,6 +173,12 @@ enum {
     POWERPC_EXCP_PRIV_REG      = 0x02,  /* Privileged register exception     */
     /* Trap                                                                  */
     POWERPC_EXCP_TRAP          = 0x40,
+    /* Processor Attention                                                   */
+    POWERPC_EXCP_ATTN          = 0x100,
+    /*
+     * NOTE: POWERPC_EXCP_ATTN uses values from 0x100 to 0x1ff to return
+     *       error codes.
+     */
 };
 
 #define PPC_INPUT(env) ((env)->bus_model)
@@ -2089,6 +2095,8 @@ void ppc_compat_add_property(Object *obj, const char *name,
 #define HID0_DOZE           (1 << 23)           /* pre-2.06 */
 #define HID0_NAP            (1 << 22)           /* pre-2.06 */
 #define HID0_HILE           PPC_BIT(19) /* POWER8 */
+#define HID0_ATTN           PPC_BIT(31) /* Processor Attention */
+#define HID0_POWER9_ATTN    PPC_BIT(3)
 #define HID0_POWER9_HILE    PPC_BIT(4)
 
 /*****************************************************************************/
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index d3e2cfcd71..b0c629905c 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -1379,6 +1379,9 @@ static void powerpc_excp_books(PowerPCCPU *cpu, int excp)
             }
             cs->halted = 1;
             cpu_interrupt_exittb(cs);
+            if ((env->error_code & ~0xff) == POWERPC_EXCP_ATTN) {
+                exit(env->error_code & 0xff);
+            }
         }
         if (env->msr_mask & MSR_HVB) {
             /*
@@ -1971,6 +1974,30 @@ void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn)
     env->resume_as_sreset = (insn != PPC_PM_STOP) ||
         (env->spr[SPR_PSSCR] & PSSCR_EC);
 }
+
+/*
+ * Processor Attention instruction (Implementation dependent)
+ */
+void helper_attn(CPUPPCState *env, target_ulong r3)
+{
+    bool attn = false;
+
+    if (env->excp_model == POWERPC_EXCP_POWER8) {
+        attn = !!(env->spr[SPR_HID0] & HID0_ATTN);
+    } else if (env->excp_model == POWERPC_EXCP_POWER9 ||
+               env->excp_model == POWERPC_EXCP_POWER10) {
+        attn = !!(env->spr[SPR_HID0] & HID0_POWER9_ATTN);
+    }
+
+    if (attn) {
+        raise_exception_err(env, POWERPC_EXCP_MCHECK,
+                            POWERPC_EXCP_ATTN | (r3 & 0xff));
+    } else {
+        raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
+                               POWERPC_EXCP_INVAL |
+                               POWERPC_EXCP_INVAL_INVAL, GETPC());
+    }
+}
 #endif /* defined(TARGET_PPC64) */
 
 static void do_rfi(CPUPPCState *env, target_ulong nip, target_ulong msr)
diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index 57da11c77e..9a2497569b 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -14,6 +14,7 @@ DEF_HELPER_1(rfmci, void, env)
 #if defined(TARGET_PPC64)
 DEF_HELPER_2(scv, noreturn, env, i32)
 DEF_HELPER_2(pminsn, void, env, i32)
+DEF_HELPER_2(attn, void, env, tl)
 DEF_HELPER_1(rfid, void, env)
 DEF_HELPER_1(rfscv, void, env)
 DEF_HELPER_1(hrfid, void, env)
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 408ae26173..5ace6f3a29 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -4123,6 +4123,19 @@ static void gen_rvwinkle(DisasContext *ctx)
     gen_exception_nip(ctx, EXCP_HLT, ctx->base.pc_next);
 #endif /* defined(CONFIG_USER_ONLY) */
 }
+
+static void gen_attn(DisasContext *ctx)
+{
+ #if defined(CONFIG_USER_ONLY)
+    GEN_PRIV;
+#else
+    CHK_SV;
+
+    gen_helper_attn(cpu_env, cpu_gpr[3]);
+    ctx->base.is_jmp = DISAS_NORETURN;
+#endif
+}
+
 #endif /* #if defined(TARGET_PPC64) */
 
 static inline void gen_update_cfar(DisasContext *ctx, target_ulong nip)
@@ -6844,6 +6857,7 @@ GEN_HANDLER_E(nap, 0x13, 0x12, 0x0d, 0x03FFF801, PPC_NONE, PPC2_PM_ISA206),
 GEN_HANDLER_E(sleep, 0x13, 0x12, 0x0e, 0x03FFF801, PPC_NONE, PPC2_PM_ISA206),
 GEN_HANDLER_E(rvwinkle, 0x13, 0x12, 0x0f, 0x03FFF801, PPC_NONE, PPC2_PM_ISA206),
 GEN_HANDLER(hrfid, 0x13, 0x12, 0x08, 0x03FF8001, PPC_64H),
+GEN_HANDLER(attn, 0x0, 0x00, 0x8, 0xfffffdff, PPC_FLOW),
 #endif
 /* Top bit of opc2 corresponds with low bit of LEV, so use two handlers */
 GEN_HANDLER(sc, 0x11, 0x11, 0xFF, 0x03FFF01D, PPC_FLOW),
-- 
2.25.1



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

* [RFC PATCH v2 2/5] ppc/pnv: Activate support for the Processor Attention instruction
  2022-03-31 14:58 [RFC PATCH v2 0/5] Port PPC64/PowerNV MMU tests to QEMU Leandro Lupori
  2022-03-31 14:58 ` [RFC PATCH v2 1/5] target/ppc: Add support for the Processor Attention instruction Leandro Lupori
@ 2022-03-31 14:58 ` Leandro Lupori
  2022-03-31 14:58 ` [RFC PATCH v2 3/5] tests/tcg/ppc64: add basic softmmu test support Leandro Lupori
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 8+ messages in thread
From: Leandro Lupori @ 2022-03-31 14:58 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc
  Cc: Leandro Lupori, danielhb413, richard.henderson, groug, clg,
	pbonzini, alex.bennee, david

From: Cédric Le Goater <clg@kaod.org>

Signed-off-by: Cédric Le Goater <clg@kaod.org>
Signed-off-by: Leandro Lupori <leandro.lupori@eldorado.org.br>
---
 hw/ppc/pnv_core.c         | 6 ++++++
 include/hw/ppc/pnv_core.h | 1 +
 2 files changed, 7 insertions(+)

diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index 19e8eb885f..eb59b44a6c 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -46,6 +46,7 @@ static void pnv_core_cpu_reset(PnvCore *pc, PowerPCCPU *cpu)
     CPUState *cs = CPU(cpu);
     CPUPPCState *env = &cpu->env;
     PnvChipClass *pcc = PNV_CHIP_GET_CLASS(pc->chip);
+    PnvCoreClass *pcorec = PNV_CORE_GET_CLASS(pc);
 
     cpu_reset(cs);
 
@@ -57,6 +58,8 @@ static void pnv_core_cpu_reset(PnvCore *pc, PowerPCCPU *cpu)
     env->nip = 0x10;
     env->msr |= MSR_HVB; /* Hypervisor mode */
     env->spr[SPR_HRMOR] = pc->hrmor;
+    env->spr[SPR_HID0] |= pcorec->attn;
+
     hreg_compute_hflags(env);
 
     pcc->intc_reset(pc->chip, cpu);
@@ -300,6 +303,7 @@ static void pnv_core_power8_class_init(ObjectClass *oc, void *data)
     PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
 
     pcc->xscom_ops = &pnv_core_power8_xscom_ops;
+    pcc->attn = HID0_ATTN;
 }
 
 static void pnv_core_power9_class_init(ObjectClass *oc, void *data)
@@ -307,6 +311,7 @@ static void pnv_core_power9_class_init(ObjectClass *oc, void *data)
     PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
 
     pcc->xscom_ops = &pnv_core_power9_xscom_ops;
+    pcc->attn = HID0_POWER9_ATTN;
 }
 
 static void pnv_core_power10_class_init(ObjectClass *oc, void *data)
@@ -315,6 +320,7 @@ static void pnv_core_power10_class_init(ObjectClass *oc, void *data)
 
     /* TODO: Use the P9 XSCOMs for now on P10 */
     pcc->xscom_ops = &pnv_core_power9_xscom_ops;
+    pcc->attn = HID0_POWER9_ATTN;
 }
 
 static void pnv_core_class_init(ObjectClass *oc, void *data)
diff --git a/include/hw/ppc/pnv_core.h b/include/hw/ppc/pnv_core.h
index c22eab2e1f..04e1fec1f3 100644
--- a/include/hw/ppc/pnv_core.h
+++ b/include/hw/ppc/pnv_core.h
@@ -47,6 +47,7 @@ struct PnvCoreClass {
     DeviceClass parent_class;
 
     const MemoryRegionOps *xscom_ops;
+    uint64_t attn;
 };
 
 #define PNV_CORE_TYPE_SUFFIX "-" TYPE_PNV_CORE
-- 
2.25.1



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

* [RFC PATCH v2 3/5] tests/tcg/ppc64: add basic softmmu test support
  2022-03-31 14:58 [RFC PATCH v2 0/5] Port PPC64/PowerNV MMU tests to QEMU Leandro Lupori
  2022-03-31 14:58 ` [RFC PATCH v2 1/5] target/ppc: Add support for the Processor Attention instruction Leandro Lupori
  2022-03-31 14:58 ` [RFC PATCH v2 2/5] ppc/pnv: Activate " Leandro Lupori
@ 2022-03-31 14:58 ` Leandro Lupori
  2022-03-31 14:58 ` [RFC PATCH v2 4/5] tests/tcg/ppc64: add MMU test sources Leandro Lupori
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 8+ messages in thread
From: Leandro Lupori @ 2022-03-31 14:58 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc
  Cc: Leandro Lupori, danielhb413, richard.henderson, groug, clg,
	pbonzini, alex.bennee, david

Add support to build and run the multiarch hello test, that simply
prints a message and exits.

The linker script, console code and related header files were
imported from https://github.com/legoater/pnv-test, that are the
Microwatt tests adapted to use a PowerNV console.
Some other changes were made on top of these, mainly on boot.S,
that was based on pnv-test/mmu/head.S, to better integrate with
QEMU test infrastructure.

Signed-off-by: Leandro Lupori <leandro.lupori@eldorado.org.br>
---
 MAINTAINERS                              |   2 +
 tests/tcg/ppc64/Makefile.softmmu-target  |  59 ++++++++
 tests/tcg/ppc64/system/include/asm.h     |  62 ++++++++
 tests/tcg/ppc64/system/include/console.h |  15 ++
 tests/tcg/ppc64/system/include/io.h      |  61 ++++++++
 tests/tcg/ppc64/system/include/pnv.h     |  21 +++
 tests/tcg/ppc64/system/include/uart.h    |  54 +++++++
 tests/tcg/ppc64/system/lib/boot.S        |  68 +++++++++
 tests/tcg/ppc64/system/lib/console.c     | 173 +++++++++++++++++++++++
 tests/tcg/ppc64/system/lib/powerpc.lds   |  27 ++++
 10 files changed, 542 insertions(+)
 create mode 100644 tests/tcg/ppc64/Makefile.softmmu-target
 create mode 100644 tests/tcg/ppc64/system/include/asm.h
 create mode 100644 tests/tcg/ppc64/system/include/console.h
 create mode 100644 tests/tcg/ppc64/system/include/io.h
 create mode 100644 tests/tcg/ppc64/system/include/pnv.h
 create mode 100644 tests/tcg/ppc64/system/include/uart.h
 create mode 100644 tests/tcg/ppc64/system/lib/boot.S
 create mode 100644 tests/tcg/ppc64/system/lib/console.c
 create mode 100644 tests/tcg/ppc64/system/lib/powerpc.lds

diff --git a/MAINTAINERS b/MAINTAINERS
index cc364afef7..e8fde33562 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -266,6 +266,7 @@ M: Cédric Le Goater <clg@kaod.org>
 M: Daniel Henrique Barboza <danielhb413@gmail.com>
 R: David Gibson <david@gibson.dropbear.id.au>
 R: Greg Kurz <groug@kaod.org>
+R: Leandro Lupori <leandro.lupori@eldorado.org.br>
 L: qemu-ppc@nongnu.org
 S: Maintained
 F: target/ppc/
@@ -273,6 +274,7 @@ F: hw/ppc/ppc.c
 F: hw/ppc/ppc_booke.c
 F: include/hw/ppc/ppc.h
 F: disas/ppc.c
+F: tests/tcg/ppc64/
 
 RISC-V TCG CPUs
 M: Palmer Dabbelt <palmer@dabbelt.com>
diff --git a/tests/tcg/ppc64/Makefile.softmmu-target b/tests/tcg/ppc64/Makefile.softmmu-target
new file mode 100644
index 0000000000..8f9925ca5a
--- /dev/null
+++ b/tests/tcg/ppc64/Makefile.softmmu-target
@@ -0,0 +1,59 @@
+#
+# PowerPC64 system tests
+#
+
+# For now, disable tests that are failing
+DISABLED_TESTS := memory
+DISABLED_EXTRA_RUNS := run-gdbstub-memory
+
+PPC64_SYSTEM_SRC=$(SRC_PATH)/tests/tcg/ppc64/system
+VPATH+=$(PPC64_SYSTEM_SRC)
+
+# These objects provide the basic boot code and helper functions for all tests
+CRT_PATH=$(PPC64_SYSTEM_SRC)/lib
+CRT_OBJS=boot.o console.o
+
+PPC64_TEST_SRCS=$(wildcard $(PPC64_SYSTEM_SRC)/*.c)
+PPC64_TESTS=$(patsubst $(PPC64_SYSTEM_SRC)/%.c, %, $(PPC64_TEST_SRCS))
+
+LINK_SCRIPT=$(CRT_PATH)/powerpc.lds
+# NOTE: --build-id is stored before the first code section in the linked
+#       binary, which causes problems for most tests, that expect to
+#       begin at address 0.
+LDFLAGS=-Wl,-T$(LINK_SCRIPT) -Wl,--build-id=none -static -nostdlib \
+    $(CRT_OBJS) $(MINILIB_OBJS) -lgcc
+TESTS += $(filter-out $(DISABLED_TESTS),$(PPC64_TESTS) $(MULTIARCH_TESTS))
+EXTRA_RUNS += $(filter-out $(DISABLED_EXTRA_RUNS),$(MULTIARCH_RUNS))
+
+# NOTE: -Os doesn't work well with -Wl,--oformat=binary
+#       Some linker generated functions, such as savegpr*/restgpr*,
+#       end up being undefined.
+CFLAGS = -O -g -Wall -std=c99 -msoft-float -mno-vsx -mno-altivec \
+         -fno-stack-protector -ffreestanding \
+         -I $(PPC64_SYSTEM_SRC)/include $(MINILIB_INC) \
+         -mcpu=power8
+
+# Leave the .elf files, to make debugging easier
+.PRECIOUS: $(CRT_OBJS) $(addsuffix .elf,$(TESTS))
+
+# Build CRT objects
+%.o: $(CRT_PATH)/%.S
+	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -x assembler-with-cpp -c $< -o $@
+
+%.o: $(CRT_PATH)/%.c
+	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c $< -o $@
+
+# Build and link the tests
+
+# The .elf files are just for debugging
+%.elf: %.c $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS)
+	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS)
+
+%: %.c %.elf $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS)
+	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) -Wl,--oformat=binary
+
+memory: CFLAGS+=-DCHECK_UNALIGNED=1
+
+# Running
+QEMU_BASE_MACHINE=-cpu power9 -M powernv9 -m 1G -vga none -nographic
+QEMU_OPTS+=$(QEMU_BASE_MACHINE) -serial chardev:output -bios
diff --git a/tests/tcg/ppc64/system/include/asm.h b/tests/tcg/ppc64/system/include/asm.h
new file mode 100644
index 0000000000..60bc08cd5c
--- /dev/null
+++ b/tests/tcg/ppc64/system/include/asm.h
@@ -0,0 +1,62 @@
+#ifndef PPC64_ASM_H
+#define PPC64_ASM_H
+
+#define XCONCAT(a, b)       a ## b
+#define CONCAT(a, b)        XCONCAT(a, b)
+
+/* Load an immediate 64-bit value into a register */
+#define LOAD_IMM64(r, e)                        \
+    lis     r, (e)@highest;                     \
+    ori     r, r, (e)@higher;                   \
+    rldicr  r, r, 32, 31;                       \
+    oris    r, r, (e)@h;                        \
+    ori     r, r, (e)@l;
+
+/* Switch CPU to little-endian mode, if needed */
+#define FIXUP_ENDIAN \
+    tdi   0, 0, 0x48;   /* Reverse endian of b . + 8 */             \
+    b     $ + 44;       /* Skip trampoline if endian is good */     \
+    .long 0xa600607d;   /* mfmsr r11 */                             \
+    .long 0x01006b69;   /* xori r11,r11,1 */                        \
+    .long 0x00004039;   /* li r10,0 */                              \
+    .long 0x6401417d;   /* mtmsrd r10,1 */                          \
+    .long 0x05009f42;   /* bcl 20,31,$+4 */                         \
+    .long 0xa602487d;   /* mflr r10 */                              \
+    .long 0x14004a39;   /* addi r10,r10,20 */                       \
+    .long 0xa6035a7d;   /* mtsrr0 r10 */                            \
+    .long 0xa6037b7d;   /* mtsrr1 r11 */                            \
+    .long 0x2400004c    /* rfid */
+
+/* Handle differences between ELFv1 and ELFv2 ABIs */
+
+#define DOT_LABEL(name)     CONCAT(., name)
+
+#if !defined(_CALL_ELF) || _CALL_ELF == 1
+#define FUNCTION(name)                          \
+    .section ".opd", "aw";                      \
+    .p2align 3;                                 \
+    .globl   name;                              \
+name:                                           \
+    .quad   DOT_LABEL(name), .TOC.@tocbase, 0;  \
+    .previous;                                  \
+DOT_LABEL(name):
+
+#define CALL(fn)                                \
+    LOAD_IMM64(%r12, fn);                       \
+    ld      %r12, 0(%r12);                      \
+    mtctr   %r12;                               \
+    bctrl
+
+#else
+#define FUNCTION(name)                          \
+    .globl   name;                              \
+name:
+
+#define CALL(fn)                                \
+    LOAD_IMM64(%r12, fn);                       \
+    mtctr   %r12;                               \
+    bctrl
+
+#endif
+
+#endif
diff --git a/tests/tcg/ppc64/system/include/console.h b/tests/tcg/ppc64/system/include/console.h
new file mode 100644
index 0000000000..37ea45827b
--- /dev/null
+++ b/tests/tcg/ppc64/system/include/console.h
@@ -0,0 +1,15 @@
+#ifndef PPC64_CONSOLE_H
+#define PPC64_CONSOLE_H
+
+#include <stdbool.h>
+#include <stddef.h>
+
+void console_init(void);
+void console_set_irq_en(bool rx_irq, bool tx_irq);
+int getchar(void);
+int putchar(int c);
+int puts(const char *str);
+
+size_t strlen(const char *s);
+
+#endif
diff --git a/tests/tcg/ppc64/system/include/io.h b/tests/tcg/ppc64/system/include/io.h
new file mode 100644
index 0000000000..92932a5b75
--- /dev/null
+++ b/tests/tcg/ppc64/system/include/io.h
@@ -0,0 +1,61 @@
+#ifndef PPC64_IO_H
+#define PPC64_IO_H
+
+static inline uint8_t readb(unsigned long addr)
+{
+    uint8_t val;
+    __asm__ volatile("sync; lbzcix %0,0,%1"
+                     : "=r" (val) : "r" (addr) : "memory");
+    return val;
+}
+
+static inline uint16_t readw(unsigned long addr)
+{
+    uint16_t val;
+    __asm__ volatile("sync; lhzcix %0,0,%1"
+                     : "=r" (val) : "r" (addr) : "memory");
+    return val;
+}
+
+static inline uint32_t readl(unsigned long addr)
+{
+    uint32_t val;
+    __asm__ volatile("sync; lwzcix %0,0,%1"
+                     : "=r" (val) : "r" (addr) : "memory");
+    return val;
+}
+
+static inline uint64_t readq(unsigned long addr)
+{
+    uint64_t val;
+    __asm__ volatile("sync; ldcix %0,0,%1"
+                     : "=r" (val) : "r" (addr) : "memory");
+    return val;
+}
+
+static inline void writeb(uint8_t val, unsigned long addr)
+{
+    __asm__ volatile("sync; stbcix %0,0,%1"
+                     : : "r" (val), "r" (addr) : "memory");
+}
+
+static inline void writew(uint16_t val, unsigned long addr)
+{
+    __asm__ volatile("sync; sthcix %0,0,%1"
+                     : : "r" (val), "r" (addr) : "memory");
+}
+
+static inline void writel(uint32_t val, unsigned long addr)
+{
+    __asm__ volatile("sync; stwcix %0,0,%1"
+                     : : "r" (val), "r" (addr) : "memory");
+}
+
+static inline void writeq(uint64_t val, unsigned long addr)
+{
+    __asm__ volatile("sync; stdcix %0,0,%1"
+                     : : "r" (val), "r" (addr) : "memory");
+}
+
+#endif /* PPC64_IO_H */
+
diff --git a/tests/tcg/ppc64/system/include/pnv.h b/tests/tcg/ppc64/system/include/pnv.h
new file mode 100644
index 0000000000..0990a9fad9
--- /dev/null
+++ b/tests/tcg/ppc64/system/include/pnv.h
@@ -0,0 +1,21 @@
+#ifndef PPC64_PNV_H
+#define PPC64_PNV_H
+
+#define LPC_BASE_ADDR   0x0006030000000000
+#define LPC_IO_SPACE    0xd0010000
+#define LPC_FW_SPACE    0xf0000000
+
+#define UART_BASE       (LPC_BASE_ADDR + LPC_IO_SPACE + 0x3f8);
+
+#define MSR_HV (1ULL << (63 - 3))
+
+static inline bool is_pnv()
+{
+    unsigned long msr;
+
+    __asm__ volatile ("mfmsr %0"
+              : "=r" (msr)
+              : : "memory");
+    return !!(msr & MSR_HV);
+}
+#endif
diff --git a/tests/tcg/ppc64/system/include/uart.h b/tests/tcg/ppc64/system/include/uart.h
new file mode 100644
index 0000000000..77610e2ec2
--- /dev/null
+++ b/tests/tcg/ppc64/system/include/uart.h
@@ -0,0 +1,54 @@
+#ifndef PPC64_UART_H
+#define PPC64_UART_H
+
+/*
+ * Register definitions for our standard (16550 style) UART
+ */
+#define UART_REG_RX             0x00
+#define UART_REG_TX             0x00
+#define UART_REG_DLL            0x00
+#define UART_REG_IER            0x04
+#define   UART_REG_IER_RDI      0x01
+#define   UART_REG_IER_THRI     0x02
+#define   UART_REG_IER_RLSI     0x04
+#define   UART_REG_IER_MSI      0x08
+#define UART_REG_DLM            0x04
+#define UART_REG_IIR            0x08
+#define UART_REG_FCR            0x08
+#define   UART_REG_FCR_EN_FIFO  0x01
+#define   UART_REG_FCR_CLR_RCVR 0x02
+#define   UART_REG_FCR_CLR_XMIT 0x04
+#define   UART_REG_FCR_TRIG1    0x00
+#define   UART_REG_FCR_TRIG4    0x40
+#define   UART_REG_FCR_TRIG8    0x80
+#define   UART_REG_FCR_TRIG14   0xc0
+#define UART_REG_LCR            0x0c
+#define   UART_REG_LCR_5BIT     0x00
+#define   UART_REG_LCR_6BIT     0x01
+#define   UART_REG_LCR_7BIT     0x02
+#define   UART_REG_LCR_8BIT     0x03
+#define   UART_REG_LCR_STOP     0x04
+#define   UART_REG_LCR_PAR      0x08
+#define   UART_REG_LCR_EVEN_PAR 0x10
+#define   UART_REG_LCR_STIC_PAR 0x20
+#define   UART_REG_LCR_BREAK    0x40
+#define   UART_REG_LCR_DLAB     0x80
+#define UART_REG_MCR            0x10
+#define   UART_REG_MCR_DTR      0x01
+#define   UART_REG_MCR_RTS      0x02
+#define   UART_REG_MCR_OUT1     0x04
+#define   UART_REG_MCR_OUT2     0x08
+#define   UART_REG_MCR_LOOP     0x10
+#define UART_REG_LSR            0x14
+#define   UART_REG_LSR_DR       0x01
+#define   UART_REG_LSR_OE       0x02
+#define   UART_REG_LSR_PE       0x04
+#define   UART_REG_LSR_FE       0x08
+#define   UART_REG_LSR_BI       0x10
+#define   UART_REG_LSR_THRE     0x20
+#define   UART_REG_LSR_TEMT     0x40
+#define   UART_REG_LSR_FIFOE    0x80
+#define UART_REG_MSR            0x18
+#define UART_REG_SCR            0x1c
+
+#endif
diff --git a/tests/tcg/ppc64/system/lib/boot.S b/tests/tcg/ppc64/system/lib/boot.S
new file mode 100644
index 0000000000..607945fba4
--- /dev/null
+++ b/tests/tcg/ppc64/system/lib/boot.S
@@ -0,0 +1,68 @@
+/* Copyright 2013-2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "asm.h"
+
+#define SPR_HID0                0x3f0
+#define SPR_HID0_POWER9_HILE    0x0800000000000000
+
+    .section ".head","ax"
+
+    /* Microwatt currently enters in LE mode at 0x0 */
+    . = 0
+_start:
+    b start
+
+    /* QEMU enters in BE at 0x10 by default */
+    . = 0x10
+.global start
+start:
+    FIXUP_ENDIAN
+
+    /* Setup TOC */
+    LOAD_IMM64(%r2, .TOC.)
+
+    /* Configure interrupt endian */
+#ifdef __LITTLE_ENDIAN__
+    mfspr   %r10, SPR_HID0
+    LOAD_IMM64(%r11, SPR_HID0_POWER9_HILE)
+    or      %r10, %r10, %r11
+    mtspr   SPR_HID0, %r10
+#endif
+
+    /* Clear .bss */
+    LOAD_IMM64(%r10,__bss_start)
+    LOAD_IMM64(%r11,__bss_end)
+    subf    %r11,%r10,%r11
+    addi    %r11,%r11,63
+    srdi.   %r11,%r11,6
+    beq     2f
+    mtctr   %r11
+1:  dcbz    0,%r10
+    addi    %r10,%r10,64
+    bdnz    1b
+
+    /* Setup stack */
+2:  LOAD_IMM64(%r1,__stack_top)
+    li      %r0,0
+    stdu    %r0,-16(%r1)
+
+    CALL(console_init)
+    CALL(main)
+
+    /* Terminate on exit */
+    attn
+    b       .
diff --git a/tests/tcg/ppc64/system/lib/console.c b/tests/tcg/ppc64/system/lib/console.c
new file mode 100644
index 0000000000..a4d8b02e21
--- /dev/null
+++ b/tests/tcg/ppc64/system/lib/console.c
@@ -0,0 +1,173 @@
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "console.h"
+#include "pnv.h"
+#include "io.h"
+#include "uart.h"
+
+#define UART_BAUDS          115200
+#define H_PUT_TERM_CHAR     88
+
+/*
+ * Core UART functions to implement for a port
+ */
+
+static uint64_t uart_base;
+
+struct console_ops {
+    int (*putchar)(int c);
+} ops;
+
+
+static unsigned long uart_divisor(unsigned long uart_freq, unsigned long bauds)
+{
+    return uart_freq / (bauds * 16);
+}
+
+static bool std_uart_rx_empty(void)
+{
+    return !(readb(uart_base + UART_REG_LSR) & UART_REG_LSR_DR);
+}
+
+static uint8_t std_uart_read(void)
+{
+    return readb(uart_base + UART_REG_RX);
+}
+
+static bool std_uart_tx_full(void)
+{
+    /* TODO: check UART LSR */
+    return 0;
+}
+
+static void std_uart_write(uint8_t c)
+{
+    writeb(c, uart_base + UART_REG_TX);
+}
+
+static void std_uart_set_irq_en(bool rx_irq, bool tx_irq)
+{
+    uint8_t ier = 0;
+
+    if (tx_irq) {
+        ier |= UART_REG_IER_THRI;
+    }
+    if (rx_irq) {
+        ier |= UART_REG_IER_RDI;
+    }
+    writeb(ier, uart_base + UART_REG_IER);
+}
+
+static void std_uart_init(uint64_t uart_freq)
+{
+    unsigned long div = uart_divisor(uart_freq, UART_BAUDS);
+
+    writeb(UART_REG_LCR_DLAB,     uart_base + UART_REG_LCR);
+    writeb(div & 0xff,            uart_base + UART_REG_DLL);
+    writeb(div >> 8,              uart_base + UART_REG_DLM);
+    writeb(UART_REG_LCR_8BIT,     uart_base + UART_REG_LCR);
+    writeb(UART_REG_MCR_DTR |
+           UART_REG_MCR_RTS,      uart_base + UART_REG_MCR);
+    writeb(UART_REG_FCR_EN_FIFO |
+           UART_REG_FCR_CLR_RCVR |
+           UART_REG_FCR_CLR_XMIT, uart_base + UART_REG_FCR);
+}
+
+int getchar(void)
+{
+    while (std_uart_rx_empty()) {
+        ;   /* Do nothing */
+    }
+    return std_uart_read();
+}
+
+int putchar(int c)
+{
+    return ops.putchar(c);
+}
+
+void __sys_outc(char c)
+{
+    putchar(c);
+}
+
+static int putchar_uart(int c)
+{
+    while (std_uart_tx_full()) {
+        ;   /* Do Nothing */
+    }
+    std_uart_write(c);
+    return c;
+}
+
+static int putchar_hvc(int c)
+{
+    register unsigned long hcall __asm__("r3") = H_PUT_TERM_CHAR;
+    register unsigned long termno __asm__("r4") = 0;
+    register unsigned long length __asm__("r5") = 1;
+    register unsigned long str __asm__("r6") = __builtin_bswap64(c);
+
+    __asm__ volatile ("sc 1" : : "r" (hcall), "r" (termno), "r" (length),
+                      "r" (str) : );
+    return c;
+}
+
+int puts(const char *str)
+{
+    unsigned int i;
+
+    for (i = 0; *str; i++) {
+        char c = *(str++);
+        if (c == 10) {
+            putchar(13);
+        }
+        putchar(c);
+    }
+    return 0;
+}
+
+size_t strlen(const char *s)
+{
+    size_t len = 0;
+
+    while (*s++) {
+        len++;
+    }
+
+    return len;
+}
+
+struct console_ops pseries_console = {
+    .putchar = putchar_hvc,
+};
+
+struct console_ops pnv_console = {
+    .putchar = putchar_uart,
+};
+
+void uart_init(void)
+{
+    uint64_t proc_freq; /* TODO */
+
+    proc_freq = 0; /* TODO */
+
+    uart_base = UART_BASE
+
+    std_uart_init(proc_freq);
+}
+
+void console_init(void)
+{
+    if (is_pnv()) {
+        ops = pnv_console;
+        uart_init();
+    } else {
+        ops = pseries_console;
+    }
+}
+
+void console_set_irq_en(bool rx_irq, bool tx_irq)
+{
+    std_uart_set_irq_en(rx_irq, tx_irq);
+}
diff --git a/tests/tcg/ppc64/system/lib/powerpc.lds b/tests/tcg/ppc64/system/lib/powerpc.lds
new file mode 100644
index 0000000000..db451e1fb9
--- /dev/null
+++ b/tests/tcg/ppc64/system/lib/powerpc.lds
@@ -0,0 +1,27 @@
+SECTIONS
+{
+    . = 0;
+    _start = .;
+    .head : {
+        KEEP(*(.head))
+    }
+    . = ALIGN(0x1000);
+    .text : { *(.text) *(.text.*) *(.rodata) *(.rodata.*) }
+    . = ALIGN(0x1000);
+    .data : { *(.data) *(.data.*) *(.got) *(.toc) }
+    . = ALIGN(0x80);
+    __bss_start = .;
+    .bss : {
+        *(.dynsbss)
+        *(.sbss)
+        *(.scommon)
+        *(.dynbss)
+        *(.bss)
+        *(.common)
+        *(.bss.*)
+    }
+    . = ALIGN(0x80);
+    __bss_end = .;
+    . = . + 0x4000;
+    __stack_top = .;
+}
-- 
2.25.1



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

* [RFC PATCH v2 4/5] tests/tcg/ppc64: add MMU test sources
  2022-03-31 14:58 [RFC PATCH v2 0/5] Port PPC64/PowerNV MMU tests to QEMU Leandro Lupori
                   ` (2 preceding siblings ...)
  2022-03-31 14:58 ` [RFC PATCH v2 3/5] tests/tcg/ppc64: add basic softmmu test support Leandro Lupori
@ 2022-03-31 14:58 ` Leandro Lupori
  2022-03-31 14:58 ` [RFC PATCH v2 5/5] tests/tcg/ppc64: build PowerNV and LE tests Leandro Lupori
  2022-03-31 15:47 ` [RFC PATCH v2 0/5] Port PPC64/PowerNV MMU tests to QEMU Cédric Le Goater
  5 siblings, 0 replies; 8+ messages in thread
From: Leandro Lupori @ 2022-03-31 14:58 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc
  Cc: Leandro Lupori, danielhb413, richard.henderson, groug, clg,
	pbonzini, alex.bennee, david

Add MMU test sources, from https://github.com/legoater/pnv-test,
based on Microwatt tests but with some adaptations.

In particular, the tests that check updates to RC bits were
removed, because, apparently, Microwatt never updates RC bits, but
just raise an exception when they must be updated, leaving the
task to the OS
(https://github.com/antonblanchard/microwatt/blob/master/mmu.vhdl#L402).

Signed-off-by: Leandro Lupori <leandro.lupori@eldorado.org.br>
---
 tests/tcg/ppc64/system/mmu-head.S | 142 ++++++
 tests/tcg/ppc64/system/mmu.c      | 764 ++++++++++++++++++++++++++++++
 tests/tcg/ppc64/system/mmu.h      |   9 +
 3 files changed, 915 insertions(+)
 create mode 100644 tests/tcg/ppc64/system/mmu-head.S
 create mode 100644 tests/tcg/ppc64/system/mmu.c
 create mode 100644 tests/tcg/ppc64/system/mmu.h

diff --git a/tests/tcg/ppc64/system/mmu-head.S b/tests/tcg/ppc64/system/mmu-head.S
new file mode 100644
index 0000000000..a3f23fcb17
--- /dev/null
+++ b/tests/tcg/ppc64/system/mmu-head.S
@@ -0,0 +1,142 @@
+/* Copyright 2013-2014 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "asm.h"
+
+#include "lib/boot.S"
+
+    /* Read a location with translation on */
+FUNCTION(test_read)
+    mfmsr   %r9
+    ori     %r8,%r9,0x10    /* set MSR_DR */
+    mtmsrd  %r8,0
+    mr      %r6,%r3
+    li      %r3,0
+    ld      %r5,0(%r6)
+    li      %r3,1
+    /* land here if DSI occurred */
+    mtmsrd  %r9,0
+    std     %r5,0(%r4)
+    blr
+
+    /* Write a location with translation on */
+FUNCTION(test_write)
+    mfmsr   %r9
+    ori     %r8,%r9,0x10    /* set MSR_DR */
+    mtmsrd  %r8,0
+    mr      %r6,%r3
+    li      %r3,0
+    std     %r4,0(%r6)
+    li      %r3,1
+    /* land here if DSI occurred */
+    mtmsrd  %r9,0
+    blr
+
+    /* Do a dcbz with translation on */
+FUNCTION(test_dcbz)
+    mfmsr   %r9
+    ori     %r8,%r9,0x10    /* set MSR_DR */
+    mtmsrd  %r8,0
+    mr      %r6,%r3
+    li      %r3,0
+    dcbz    0,%r6
+    li      %r3,1
+    /* land here if DSI occurred */
+    mtmsrd  %r9,0
+    blr
+
+FUNCTION(test_exec)
+    mtsrr0  %r4
+    mtsrr1  %r5
+    rfid
+
+#define EXCEPTION(nr)        \
+    .= nr                   ;\
+    li      %r3, (nr >> 4)  ;\
+    attn
+
+    /* DSI vector - skip the failing instruction + the next one */
+    . = 0x300
+    mtsprg0 %r10
+    mfsrr0  %r10
+    addi    %r10,%r10,8
+    mtsrr0  %r10
+    rfid
+
+    EXCEPTION(0x380)
+
+    /*
+     * ISI vector - jump to LR to return from the test,
+     * with r3 cleared
+     */
+    . = 0x400
+    li      %r3,0
+    blr
+
+    /* More exception stubs */
+    EXCEPTION(0x480)
+    EXCEPTION(0x500)
+    EXCEPTION(0x600)
+    EXCEPTION(0x700)
+    EXCEPTION(0x800)
+    EXCEPTION(0x900)
+    EXCEPTION(0x980)
+    EXCEPTION(0xa00)
+    EXCEPTION(0xb00)
+
+    /*
+     * System call - used to exit from tests where MSR[PR]
+     * may have been set.
+     */
+    . = 0xc00
+    blr
+
+    EXCEPTION(0xd00)
+    EXCEPTION(0xe00)
+    EXCEPTION(0xe20)
+    EXCEPTION(0xe40)
+    EXCEPTION(0xe60)
+    EXCEPTION(0xe80)
+    EXCEPTION(0xf00)
+    EXCEPTION(0xf20)
+    EXCEPTION(0xf40)
+    EXCEPTION(0xf60)
+    EXCEPTION(0xf80)
+
+    . = 0x1000
+    /*
+     * This page gets mapped at various locations and
+     * the tests try to execute from it.
+     * r3 contains the test number.
+     */
+FUNCTION(test_start)
+    nop
+    nop
+    cmpdi   %r3,1
+    beq     test_1
+    cmpdi   %r3,2
+    beq     test_2
+test_return:
+    li      %r3,1
+    sc
+
+    . = 0x1ff8
+    /* test a branch near the end of a page */
+test_1:     b   test_return
+
+    /* test flowing from one page to the next */
+test_2:     nop
+    b       test_return
diff --git a/tests/tcg/ppc64/system/mmu.c b/tests/tcg/ppc64/system/mmu.c
new file mode 100644
index 0000000000..8e9fca2675
--- /dev/null
+++ b/tests/tcg/ppc64/system/mmu.c
@@ -0,0 +1,764 @@
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "minilib.h"
+#include "mmu.h"
+
+#define MSR_LE    0x01
+#define MSR_DR    0x10
+#define MSR_IR    0x20
+#define MSR_HV    0x1000000000000000ul
+#define MSR_SF    0x8000000000000000ul
+
+#ifdef __LITTLE_ENDIAN__
+#define MSR_DFLT    (MSR_SF | MSR_HV | MSR_LE)
+#else
+#define MSR_DFLT    (MSR_SF | MSR_HV)
+#endif
+
+#define XSTR(x)     #x
+#define STR(x)      XSTR(x)
+
+#define RIC_TLB     0
+#define RIC_PWC     1
+#define RIC_ALL     2
+
+#define PRS         1
+
+#define IS(x)       ((unsigned long)(x) << 10)
+#define IS_VA       IS(0)
+#define IS_PID      IS(1)
+#define IS_LPID     IS(2)
+#define IS_ALL      IS(3)
+
+#define TLBIE_5(rb, rs, ric, prs, r)                \
+    __asm__ volatile(".long 0x7c000264 | "          \
+        "%0 << 21 | "                               \
+        STR(ric) " << 18 | "                        \
+        STR(prs) " << 17 | "                        \
+        STR(r) "<< 16 | "                           \
+        "%1 << 11"                                  \
+        : : "r" (rs), "r" (rb) : "memory")
+
+static inline void tlbie_all(int prs)
+{
+    if (prs) {
+        TLBIE_5(IS_ALL, 0, RIC_ALL, 1, 1);
+    } else {
+        TLBIE_5(IS_ALL, 0, RIC_ALL, 0, 1);
+    }
+}
+
+static inline void tlbie_va(unsigned long va, int prs)
+{
+    va &= ~0xffful;
+
+    if (prs) {
+        TLBIE_5(IS_VA | va, 0, RIC_TLB, 1, 1);
+    } else {
+        TLBIE_5(IS_VA | va, 0, RIC_TLB, 0, 1);
+    }
+    __asm__ volatile("eieio; tlbsync; ptesync" : : : "memory");
+}
+
+#define DSISR       18
+#define DAR         19
+#define SRR0        26
+#define SRR1        27
+#define PID         48
+#define LPCR        318
+#define PTCR        464
+
+#define PPC_BIT(x)  (0x8000000000000000ul >> (x))
+
+#define LPCR_UPRT   PPC_BIT(41)
+#define LPCR_HR     PPC_BIT(43)
+
+#define PATE_HR     PPC_BIT(0)
+
+static inline unsigned long mfspr(int sprnum)
+{
+    long val;
+
+    __asm__ volatile("mfspr %0,%1" : "=r" (val) : "i" (sprnum));
+    return val;
+}
+
+static inline void mtspr(int sprnum, unsigned long val)
+{
+    __asm__ volatile("mtspr %0,%1" : : "i" (sprnum), "r" (val));
+}
+
+static inline void store_pte(unsigned long *p, unsigned long pte)
+{
+#ifdef __LITTLE_ENDIAN__
+    __asm__ volatile("stdbrx %1,0,%0" : : "r" (p), "r" (pte) : "memory");
+#else
+    __asm__ volatile("stdx   %1,0,%0" : : "r" (p), "r" (pte) : "memory");
+#endif
+    __asm__ volatile("ptesync" : : : "memory");
+}
+
+#define CACHE_LINE_SIZE    64
+
+void zero_memory(void *ptr, unsigned long nbytes)
+{
+    unsigned long nb, i, nl;
+    void *p;
+
+    for (; nbytes != 0; nbytes -= nb, ptr += nb) {
+        nb = -((unsigned long)ptr) & (CACHE_LINE_SIZE - 1);
+        if (nb == 0 && nbytes >= CACHE_LINE_SIZE) {
+            nl = nbytes / CACHE_LINE_SIZE;
+            p = ptr;
+            for (i = 0; i < nl; ++i) {
+                __asm__ volatile("dcbz 0,%0" : : "r" (p) : "memory");
+                p += CACHE_LINE_SIZE;
+            }
+            nb = nl * CACHE_LINE_SIZE;
+        } else {
+            if (nb > nbytes) {
+                nb = nbytes;
+            }
+            for (i = 0; i < nb; ++i) {
+                ((unsigned char *)ptr)[i] = 0;
+            }
+        }
+    }
+}
+
+#define PAGE_SHIFT      12
+#define PAGE_SIZE       (1ul << PAGE_SHIFT)
+
+/* Partition Page Dir params */
+#define PPD_L1_BITS     5
+#define PPD_L2_BITS     14    /* virtual level 2 PGD address bits */
+#define PPD_PA_INC      (1ul << (PAGE_SHIFT + PPD_L2_BITS))
+
+#define RPTE_V          PPC_BIT(0)
+#define RPTE_L          PPC_BIT(1)
+#define RPTE_RPN_MASK   0x01fffffffffff000ul
+#define RPTE_R          PPC_BIT(55)
+#define RPTE_C          PPC_BIT(56)
+#define RPTE_PRIV       PPC_BIT(60)
+#define RPTE_RD         PPC_BIT(61)
+#define RPTE_RW         PPC_BIT(62)
+#define RPTE_EX         PPC_BIT(63)
+#define RPTE_PERM_ALL   (RPTE_RD | RPTE_RW | RPTE_EX)
+
+#define PERM_EX         RPTE_EX
+#define PERM_WR         RPTE_RW
+#define PERM_RD         RPTE_RD
+#define PERM_PRIV       RPTE_PRIV
+#define ATTR_NC         0x020
+#define CHG             RPTE_C
+#define REF             RPTE_R
+
+#define DFLT_PERM       (PERM_WR | PERM_RD | REF | CHG)
+
+/*
+ * Set up an MMU translation tree using memory starting at the 64k point.
+ * We use 2 levels, mapping 2GB (the minimum size possible), with a
+ * 8kB PGD level pointing to 4kB PTE pages.
+ */
+unsigned long *pgdir = (unsigned long *) 0x10000;
+unsigned long *proc_tbl = (unsigned long *) 0x12000;
+unsigned long *part_tbl = (unsigned long *) 0x13000;
+unsigned long *part_pgdir = (unsigned long *) 0x14000;
+unsigned long free_ptr = 0x15000;
+void *eas_mapped[4];
+int neas_mapped;
+
+void init_mmu(void)
+{
+    int i, n;
+    unsigned long pa, pte;
+
+    /* Select Radix MMU (HR), with HW process table */
+    mtspr(LPCR, mfspr(LPCR) | LPCR_UPRT | LPCR_HR);
+
+    /*
+     * Set up partition page dir, needed to translate process table
+     * addresses.
+     * We use only 1 level, mapping 2GB 1-1, with 32 64M pages.
+     */
+    zero_memory(part_tbl, PAGE_SIZE);
+    store_pte(&part_tbl[0], PATE_HR | (unsigned long) part_pgdir |
+            PPD_L1_BITS);
+
+    for (i = 0, n = 1 << PPD_L1_BITS, pa = 0;
+            i < n; i++, pa += PPD_PA_INC) {
+        pte = RPTE_V | RPTE_L | (pa & RPTE_RPN_MASK) | RPTE_PERM_ALL;
+        store_pte(&part_pgdir[i], pte);
+    }
+
+    /* set up partition table */
+    store_pte(&part_tbl[1], (unsigned long)proc_tbl);
+    /* set up process table */
+    zero_memory(proc_tbl, 512 * sizeof(unsigned long));
+    mtspr(PTCR, (unsigned long)part_tbl);
+    mtspr(PID, 1);
+    zero_memory(pgdir, 1024 * sizeof(unsigned long));
+    /* RTS = 0 (2GB address space), RPDS = 10 (1024-entry top level) */
+    store_pte(&proc_tbl[2 * 1], (unsigned long) pgdir | 10);
+    tlbie_all(0);   /* invalidate all TLB entries */
+}
+
+static unsigned long *read_pgd(unsigned long i)
+{
+    unsigned long ret;
+
+#ifdef __LITTLE_ENDIAN__
+    __asm__ volatile("ldbrx %0,%1,%2" : "=r" (ret) : "b" (pgdir),
+                     "r" (i * sizeof(unsigned long)));
+#else
+    __asm__ volatile("ldx   %0,%1,%2" : "=r" (ret) : "b" (pgdir),
+                     "r" (i * sizeof(unsigned long)));
+#endif
+    return (unsigned long *) (ret & 0x00ffffffffffff00);
+}
+
+void map(void *ea, void *pa, unsigned long perm_attr)
+{
+    unsigned long epn = (unsigned long) ea >> 12;
+    unsigned long i, j;
+    unsigned long *ptep;
+
+    i = (epn >> 9) & 0x3ff;
+    j = epn & 0x1ff;
+    if (pgdir[i] == 0) {
+        zero_memory((void *)free_ptr, 512 * sizeof(unsigned long));
+        store_pte(&pgdir[i], 0x8000000000000000 | free_ptr | 9);
+        free_ptr += 512 * sizeof(unsigned long);
+    }
+    ptep = read_pgd(i);
+    store_pte(&ptep[j], 0xc000000000000000 | ((unsigned long)pa &
+                                              0x00fffffffffff000) | perm_attr);
+    eas_mapped[neas_mapped++] = ea;
+}
+
+void unmap(void *ea)
+{
+    unsigned long epn = (unsigned long) ea >> 12;
+    unsigned long i, j;
+    unsigned long *ptep;
+
+    i = (epn >> 9) & 0x3ff;
+    j = epn & 0x1ff;
+    if (pgdir[i] == 0) {
+        return;
+    }
+    ptep = read_pgd(i);
+    store_pte(&ptep[j], 0);
+    tlbie_va((unsigned long)ea, PRS);
+}
+
+void unmap_all(void)
+{
+    int i;
+
+    for (i = 0; i < neas_mapped; ++i) {
+        unmap(eas_mapped[i]);
+    }
+    neas_mapped = 0;
+}
+
+int mmu_test_1(void)
+{
+    long *ptr = (long *) 0x123000;
+    long val;
+
+    /* this should fail */
+    if (test_read(ptr, &val, 0xdeadbeefd00d)) {
+        return 1;
+    }
+    /* dest reg of load should be unchanged */
+    if (val != 0xdeadbeefd00d) {
+        return 2;
+    }
+    /* DAR and DSISR should be set correctly */
+    if (mfspr(DAR) != (long) ptr || mfspr(DSISR) != 0x40000000) {
+        return 3;
+    }
+    return 0;
+}
+
+int mmu_test_2(void)
+{
+    long *mem = (long *) 0x8000;
+    long *ptr = (long *) 0x124000;
+    long *ptr2 = (long *) 0x1124000;
+    long val;
+
+    /* create PTE */
+    map(ptr, mem, DFLT_PERM);
+    /* initialize the memory content */
+    mem[33] = 0xbadc0ffee;
+    /* this should succeed and be a cache miss */
+    if (!test_read(&ptr[33], &val, 0xdeadbeefd00d)) {
+        return 1;
+    }
+    /* dest reg of load should have the value written */
+    if (val != 0xbadc0ffee) {
+        return 2;
+    }
+    /* load a second TLB entry in the same set as the first */
+    map(ptr2, mem, DFLT_PERM);
+    /* this should succeed and be a cache hit */
+    if (!test_read(&ptr2[33], &val, 0xdeadbeefd00d)) {
+        return 3;
+    }
+    /* dest reg of load should have the value written */
+    if (val != 0xbadc0ffee) {
+        return 4;
+    }
+    /* check that the first entry still works */
+    if (!test_read(&ptr[33], &val, 0xdeadbeefd00d)) {
+        return 5;
+    }
+    if (val != 0xbadc0ffee) {
+        return 6;
+    }
+    return 0;
+}
+
+int mmu_test_3(void)
+{
+    long *mem = (long *) 0x9000;
+    long *ptr = (long *) 0x14a000;
+    long val;
+
+    /* create PTE */
+    map(ptr, mem, DFLT_PERM);
+    /* initialize the memory content */
+    mem[45] = 0xfee1800d4ea;
+    /* this should succeed and be a cache miss */
+    if (!test_read(&ptr[45], &val, 0xdeadbeefd0d0)) {
+        return 1;
+    }
+    /* dest reg of load should have the value written */
+    if (val != 0xfee1800d4ea) {
+        return 2;
+    }
+    /* remove the PTE */
+    unmap(ptr);
+    /* this should fail */
+    if (test_read(&ptr[45], &val, 0xdeadbeefd0d0)) {
+        return 3;
+    }
+    /* dest reg of load should be unchanged */
+    if (val != 0xdeadbeefd0d0) {
+        return 4;
+    }
+    /* DAR and DSISR should be set correctly */
+    if (mfspr(DAR) != (long) &ptr[45] || mfspr(DSISR) != 0x40000000) {
+        return 5;
+    }
+    return 0;
+}
+
+int mmu_test_4(void)
+{
+    long *mem = (long *) 0xa000;
+    long *ptr = (long *) 0x10b000;
+    long *ptr2 = (long *) 0x110b000;
+    long val;
+
+    /* create PTE */
+    map(ptr, mem, DFLT_PERM);
+    /* initialize the memory content */
+    mem[27] = 0xf00f00f00f00;
+    /* this should succeed and be a cache miss */
+    if (!test_write(&ptr[27], 0xe44badc0ffee)) {
+        return 1;
+    }
+    /* memory should now have the value written */
+    if (mem[27] != 0xe44badc0ffee) {
+        return 2;
+    }
+    /* load a second TLB entry in the same set as the first */
+    map(ptr2, mem, DFLT_PERM);
+    /* this should succeed and be a cache hit */
+    if (!test_write(&ptr2[27], 0x6e11ae)) {
+        return 3;
+    }
+    /* memory should have the value written */
+    if (mem[27] != 0x6e11ae) {
+        return 4;
+    }
+    /* check that the first entry still exists */
+    /* (assumes TLB is 2-way associative or more) */
+    if (!test_read(&ptr[27], &val, 0xdeadbeefd00d)) {
+        return 5;
+    }
+    if (val != 0x6e11ae) {
+        return 6;
+    }
+    return 0;
+}
+
+int mmu_test_5(void)
+{
+    long *mem = (long *) 0xbffd;
+    long *ptr = (long *) 0x39fffd;
+    long val;
+
+    /* create PTE */
+    map(ptr, mem, DFLT_PERM);
+    /* this should fail */
+    if (test_read(ptr, &val, 0xdeadbeef0dd0)) {
+        return 1;
+    }
+    /* dest reg of load should be unchanged */
+    if (val != 0xdeadbeef0dd0) {
+        return 2;
+    }
+    /* DAR and DSISR should be set correctly */
+    if (mfspr(DAR) != ((long)ptr & ~0xfff) + 0x1000 ||
+            mfspr(DSISR) != 0x40000000) {
+        return 3;
+    }
+    return 0;
+}
+
+int mmu_test_6(void)
+{
+    long *mem = (long *) 0xbffd;
+    long *ptr = (long *) 0x39fffd;
+
+    /* create PTE */
+    map(ptr, mem, DFLT_PERM);
+    /* initialize memory */
+    *mem = 0x123456789abcdef0;
+    /* this should fail */
+    if (test_write(ptr, 0xdeadbeef0dd0)) {
+        return 1;
+    }
+    /* DAR and DSISR should be set correctly */
+    if (mfspr(DAR) != ((long)ptr & ~0xfff) + 0x1000 ||
+            mfspr(DSISR) != 0x42000000) {
+        return 2;
+    }
+    return 0;
+}
+
+int mmu_test_7(void)
+{
+    long *mem = (long *) 0x8000;
+    long *ptr = (long *) 0x124000;
+    long val;
+
+    *mem = 0x123456789abcdef0;
+    /* create PTE without read or write permission */
+    map(ptr, mem, REF);
+    /* this should fail */
+    if (test_read(ptr, &val, 0xdeadd00dbeef)) {
+        return 1;
+    }
+    /* dest reg of load should be unchanged */
+    if (val != 0xdeadd00dbeef) {
+        return 2;
+    }
+    /* DAR and DSISR should be set correctly */
+    if (mfspr(DAR) != (long) ptr || mfspr(DSISR) != 0x08000000) {
+        return 3;
+    }
+    /* this should fail */
+    if (test_write(ptr, 0xdeadbeef0dd1)) {
+        return 4;
+    }
+    /* DAR and DSISR should be set correctly */
+    if (mfspr(DAR) != (long)ptr || mfspr(DSISR) != 0x0a000000) {
+        return 5;
+    }
+    /* memory should be unchanged */
+    if (*mem != 0x123456789abcdef0) {
+        return 6;
+    }
+    return 0;
+}
+
+int mmu_test_8(void)
+{
+    long *mem = (long *) 0x8000;
+    long *ptr = (long *) 0x124000;
+    long val;
+
+    *mem = 0x123456789abcdef0;
+    /* create PTE with read but not write permission */
+    map(ptr, mem, REF | PERM_RD);
+    /* this should succeed */
+    if (!test_read(ptr, &val, 0xdeadd00dbeef)) {
+        return 1;
+    }
+    /* this should fail */
+    if (test_write(ptr, 0xdeadbeef0dd1)) {
+        return 2;
+    }
+    /* DAR and DSISR should be set correctly */
+    if (mfspr(DAR) != (long)ptr || mfspr(DSISR) != 0x0a000000) {
+        return 3;
+    }
+    /* memory should be unchanged */
+    if (*mem != 0x123456789abcdef0) {
+        return 4;
+    }
+    return 0;
+}
+
+int mmu_test_9(void)
+{
+    unsigned long ptr = 0x523000;
+
+    /* this should fail */
+    if (test_exec(0, ptr, MSR_DFLT | MSR_IR)) {
+        return 1;
+    }
+    /* SRR0 and SRR1 should be set correctly */
+    if (mfspr(SRR0) != (long) ptr ||
+            mfspr(SRR1) != (MSR_DFLT | 0x40000000 | MSR_IR)) {
+        return 2;
+    }
+    return 0;
+}
+
+int mmu_test_10(void)
+{
+    unsigned long mem = 0x1000;
+    unsigned long ptr = 0x324000;
+    unsigned long ptr2 = 0x1324000;
+
+    /* create PTE */
+    map((void *)ptr, (void *)mem, PERM_EX | REF);
+    /* this should succeed and be a cache miss */
+    if (!test_exec(0, ptr, MSR_DFLT | MSR_IR)) {
+        return 1;
+    }
+    /* create a second PTE */
+    map((void *)ptr2, (void *)mem, PERM_EX | REF);
+    /* this should succeed and be a cache hit */
+    if (!test_exec(0, ptr2, MSR_DFLT | MSR_IR)) {
+        return 2;
+    }
+    return 0;
+}
+
+int mmu_test_11(void)
+{
+    unsigned long mem = 0x1000;
+    unsigned long ptr = 0x349000;
+    unsigned long ptr2 = 0x34a000;
+
+    /* create a PTE */
+    map((void *)ptr, (void *)mem, PERM_EX | REF);
+    /* this should succeed */
+    if (!test_exec(1, ptr, MSR_DFLT | MSR_IR)) {
+        return 1;
+    }
+    /* invalidate the PTE */
+    unmap((void *)ptr);
+    /* install a second PTE */
+    map((void *)ptr2, (void *)mem, PERM_EX | REF);
+    /* this should fail */
+    if (test_exec(1, ptr, MSR_DFLT | MSR_IR)) {
+        return 2;
+    }
+    /* SRR0 and SRR1 should be set correctly */
+    if (mfspr(SRR0) != (long) ptr ||
+            mfspr(SRR1) != (MSR_DFLT | 0x40000000 | MSR_IR)) {
+        return 3;
+    }
+    return 0;
+}
+
+int mmu_test_12(void)
+{
+    unsigned long mem = 0x1000;
+    unsigned long mem2 = 0x2000;
+    unsigned long ptr = 0x30a000;
+    unsigned long ptr2 = 0x30b000;
+
+    /* create a PTE */
+    map((void *)ptr, (void *)mem, PERM_EX | REF);
+    /* this should fail due to second page not being mapped */
+    if (test_exec(2, ptr, MSR_DFLT | MSR_IR)) {
+        return 1;
+    }
+    /* SRR0 and SRR1 should be set correctly */
+    if (mfspr(SRR0) != ptr2 ||
+            mfspr(SRR1) != (MSR_DFLT | 0x40000000 | MSR_IR)) {
+        return 2;
+    }
+    /* create a PTE for the second page */
+    map((void *)ptr2, (void *)mem2, PERM_EX | REF);
+    /* this should succeed */
+    if (!test_exec(2, ptr, MSR_DFLT | MSR_IR)) {
+        return 3;
+    }
+    return 0;
+}
+
+int mmu_test_13(void)
+{
+    unsigned long mem = 0x1000;
+    unsigned long ptr = 0x324000;
+
+    /* create a PTE without execute permission */
+    map((void *)ptr, (void *)mem, DFLT_PERM);
+    /* this should fail */
+    if (test_exec(0, ptr, MSR_DFLT | MSR_IR)) {
+        return 1;
+    }
+    /* SRR0 and SRR1 should be set correctly */
+    if (mfspr(SRR0) != ptr ||
+            mfspr(SRR1) != (MSR_DFLT | 0x10000000 | MSR_IR)) {
+        return 2;
+    }
+    return 0;
+}
+
+int mmu_test_14(void)
+{
+    unsigned long mem = 0x1000;
+    unsigned long mem2 = 0x2000;
+    unsigned long ptr = 0x30a000;
+    unsigned long ptr2 = 0x30b000;
+
+    /* create a PTE */
+    map((void *)ptr, (void *)mem, PERM_EX | REF);
+    /* create a PTE for the second page without execute permission */
+    map((void *)ptr2, (void *)mem2, PERM_RD | REF);
+    /* this should fail due to second page being no-execute */
+    if (test_exec(2, ptr, MSR_DFLT | MSR_IR)) {
+        return 1;
+    }
+    /* SRR0 and SRR1 should be set correctly */
+    if (mfspr(SRR0) != ptr2 ||
+            mfspr(SRR1) != (MSR_DFLT | 0x10000000 | MSR_IR)) {
+        return 2;
+    }
+    /* create a PTE for the second page with execute permission */
+    map((void *)ptr2, (void *)mem2, PERM_RD | PERM_EX | REF);
+    /* this should succeed */
+    if (!test_exec(2, ptr, MSR_DFLT | MSR_IR)) {
+        return 3;
+    }
+    return 0;
+}
+
+int mmu_test_15(void)
+{
+    unsigned long mem = 0x1000;
+    unsigned long ptr = 0x349000;
+
+    /* create a PTE without ref or execute permission */
+    map((void *)ptr, (void *)mem, 0);
+    /* this should fail */
+    if (test_exec(2, ptr, MSR_DFLT | MSR_IR)) {
+        return 1;
+    }
+    /* SRR0 and SRR1 should be set correctly */
+    /* RC update fail bit should not be set */
+    if (mfspr(SRR0) != (long) ptr ||
+            mfspr(SRR1) != (MSR_DFLT | 0x10000000 | MSR_IR)) {
+        return 2;
+    }
+    return 0;
+}
+
+int mmu_test_16(void)
+{
+    long *mem = (long *) 0x8000;
+    long *ptr = (long *) 0x124000;
+    long *ptr2 = (long *) 0x1124000;
+
+    /* create PTE */
+    map(ptr, mem, DFLT_PERM);
+    /* this should succeed and be a cache miss */
+    if (!test_dcbz(&ptr[129])) {
+        return 1;
+    }
+    /* create a second PTE */
+    map(ptr2, mem, DFLT_PERM);
+    /* this should succeed and be a cache hit */
+    if (!test_dcbz(&ptr2[130])) {
+        return 2;
+    }
+    return 0;
+}
+
+int mmu_test_17(void)
+{
+    long *mem = (long *) 0x8000;
+    long *ptr = (long *) 0x124000;
+
+    *mem = 0x123456789abcdef0;
+    /* create PTE with read but not write permission */
+    map(ptr, mem, REF | PERM_RD);
+    /* this should fail and create a TLB entry */
+    if (test_write(ptr, 0xdeadbeef0dd1)) {
+        return 1;
+    }
+    /* DAR and DSISR should be set correctly */
+    if (mfspr(DAR) != (long)ptr || mfspr(DSISR) != 0x0a000000) {
+        return 2;
+    }
+    /* Update the PTE to have write permission */
+    map(ptr, mem, REF | CHG | PERM_RD | PERM_WR);
+    /* this should succeed */
+    if (!test_write(ptr, 0xdeadbeef0dd1)) {
+        return 3;
+    }
+    return 0;
+}
+
+int fail;
+
+void do_test(int num, int (*test)(void))
+{
+    int ret;
+
+    mtspr(DSISR, 0);
+    mtspr(DAR, 0);
+    unmap_all();
+    ml_printf("test %d:", num);
+    ret = test();
+    if (ret == 0) {
+        ml_printf("PASS\r\n");
+    } else {
+        fail = 1;
+        ml_printf("FAIL %d", ret);
+        if (num <= 10 || num == 19) {
+            ml_printf(" DAR=%lx DSISR=%lx", mfspr(DAR), mfspr(DSISR));
+        } else {
+            ml_printf(" SRR0=%lx SRR1=%lx", mfspr(SRR0), mfspr(SRR1));
+        }
+        ml_printf("\r\n");
+    }
+}
+
+int main(void)
+{
+    init_mmu();
+
+    do_test(1, mmu_test_1);
+    do_test(2, mmu_test_2);
+    do_test(3, mmu_test_3);
+    do_test(4, mmu_test_4);
+    do_test(5, mmu_test_5);
+    do_test(6, mmu_test_6);
+    do_test(7, mmu_test_7);
+    do_test(8, mmu_test_8);
+    do_test(9, mmu_test_9);
+    do_test(10, mmu_test_10);
+    do_test(11, mmu_test_11);
+    do_test(12, mmu_test_12);
+    do_test(13, mmu_test_13);
+    do_test(14, mmu_test_14);
+    do_test(15, mmu_test_15);
+    do_test(16, mmu_test_16);
+    do_test(17, mmu_test_17);
+
+    return fail;
+}
diff --git a/tests/tcg/ppc64/system/mmu.h b/tests/tcg/ppc64/system/mmu.h
new file mode 100644
index 0000000000..eb191e4bd0
--- /dev/null
+++ b/tests/tcg/ppc64/system/mmu.h
@@ -0,0 +1,9 @@
+#ifndef PPC64_MMU_H
+#define PPC64_MMU_H
+
+int test_read(long *addr, long *ret, long init);
+int test_write(long *addr, long val);
+int test_dcbz(long *addr);
+int test_exec(int testno, unsigned long pc, unsigned long msr);
+
+#endif
-- 
2.25.1



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

* [RFC PATCH v2 5/5] tests/tcg/ppc64: build PowerNV and LE tests
  2022-03-31 14:58 [RFC PATCH v2 0/5] Port PPC64/PowerNV MMU tests to QEMU Leandro Lupori
                   ` (3 preceding siblings ...)
  2022-03-31 14:58 ` [RFC PATCH v2 4/5] tests/tcg/ppc64: add MMU test sources Leandro Lupori
@ 2022-03-31 14:58 ` Leandro Lupori
  2022-03-31 15:47 ` [RFC PATCH v2 0/5] Port PPC64/PowerNV MMU tests to QEMU Cédric Le Goater
  5 siblings, 0 replies; 8+ messages in thread
From: Leandro Lupori @ 2022-03-31 14:58 UTC (permalink / raw)
  To: qemu-devel, qemu-ppc
  Cc: Leandro Lupori, danielhb413, richard.henderson, groug, clg,
	pbonzini, alex.bennee, david

Each Microwatt/PowerNV test use its own head.S file and thus needs
different build rules.

Also add rules to build and run all tests in LE mode.

Signed-off-by: Leandro Lupori <leandro.lupori@eldorado.org.br>
---
 tests/tcg/ppc64/Makefile.softmmu-rules  |  34 +++++++
 tests/tcg/ppc64/Makefile.softmmu-target | 119 ++++++++++++++++++------
 2 files changed, 126 insertions(+), 27 deletions(-)
 create mode 100644 tests/tcg/ppc64/Makefile.softmmu-rules

diff --git a/tests/tcg/ppc64/Makefile.softmmu-rules b/tests/tcg/ppc64/Makefile.softmmu-rules
new file mode 100644
index 0000000000..abe0de0a7f
--- /dev/null
+++ b/tests/tcg/ppc64/Makefile.softmmu-rules
@@ -0,0 +1,34 @@
+#
+# Rules to build PowerPC64 softmmu tests, for both BE and LE
+#
+
+# Build CRT and test objects
+%$(LE_SUFFIX).o: $(CRT_PATH)/%.S
+	$(CC) $(PPC64_CFLAGS) -x assembler-with-cpp -c $< -o $@
+
+%$(LE_SUFFIX).o: %.S
+	$(CC) $(PPC64_CFLAGS) -x assembler-with-cpp -c $< -o $@
+
+%$(LE_SUFFIX).o: $(CRT_PATH)/%.c
+	$(CC) $(PPC64_CFLAGS) -c $< -o $@
+
+%$(LE_SUFFIX).o: %.c
+	$(CC) $(PPC64_CFLAGS) -c $< -o $@
+
+# Build .elf files for debugging
+%$(LE_SUFFIX).elf: %$(LE_SUFFIX).o $(LINK_SCRIPT) $(CRT_DEPS) $(MINILIB_DEPS)
+	$(CC) $(PPC64_CFLAGS) -o $@ $< $(LDFLAGS)
+
+$(PPC64_PNV_ELFS): %$(LE_SUFFIX).elf: %-head$(LE_SUFFIX).o %$(LE_SUFFIX).o \
+                    $(LINK_SCRIPT) $(CRT_DEPS) $(MINILIB_DEPS)
+	$(CC) $(PPC64_CFLAGS) -o $@ $< $*$(LE_SUFFIX).o $(LDFLAGS)
+
+# Build test binaries
+%$(LE_SUFFIX): %$(LE_SUFFIX).o $(LINK_SCRIPT) $(CRT_DEPS) $(MINILIB_DEPS) \
+               %$(LE_SUFFIX).elf
+	$(CC) $(PPC64_CFLAGS) -o $@ $< $(LDFLAGS) -Wl,--oformat=binary
+
+$(PPC64_PNV_TESTS): %$(LE_SUFFIX): %-head$(LE_SUFFIX).o %$(LE_SUFFIX).o \
+                    $(LINK_SCRIPT) $(CRT_DEPS) $(MINILIB_DEPS) %$(LE_SUFFIX).elf
+	$(CC) $(PPC64_CFLAGS) -o $@ $< $*$(LE_SUFFIX).o $(LDFLAGS) \
+				-Wl,--oformat=binary
diff --git a/tests/tcg/ppc64/Makefile.softmmu-target b/tests/tcg/ppc64/Makefile.softmmu-target
index 8f9925ca5a..03d5d3e426 100644
--- a/tests/tcg/ppc64/Makefile.softmmu-target
+++ b/tests/tcg/ppc64/Makefile.softmmu-target
@@ -5,25 +5,52 @@
 # For now, disable tests that are failing
 DISABLED_TESTS := memory
 DISABLED_EXTRA_RUNS := run-gdbstub-memory
+# Disable LE tests too
+DISABLED_TESTS += $(addsuffix -le, $(DISABLED_TESTS))
+DISABLED_EXTRA_RUNS += $(addsuffix -le, $(DISABLED_EXTRA_RUNS))
 
-PPC64_SYSTEM_SRC=$(SRC_PATH)/tests/tcg/ppc64/system
-VPATH+=$(PPC64_SYSTEM_SRC)
+PPC64_SRC := $(SRC_PATH)/tests/tcg/ppc64
+PPC64_SYSTEM_SRC := $(PPC64_SRC)/system
+VPATH += $(PPC64_SYSTEM_SRC)
 
 # These objects provide the basic boot code and helper functions for all tests
-CRT_PATH=$(PPC64_SYSTEM_SRC)/lib
-CRT_OBJS=boot.o console.o
+CRT_PATH := $(PPC64_SYSTEM_SRC)/lib
+CRT_OBJS_BE := boot.o console.o
+CRT_OBJS_LE := $(patsubst %.o, %-le.o, $(CRT_OBJS_BE))
+# NOTE: %-head.o replaces boot.o on PowerNV tests
+PNV_CRT_OBJS_BE := $(filter-out boot.o, $(CRT_OBJS_BE))
+PNV_CRT_OBJS_LE := $(filter-out boot-le.o, $(CRT_OBJS_LE))
 
-PPC64_TEST_SRCS=$(wildcard $(PPC64_SYSTEM_SRC)/*.c)
-PPC64_TESTS=$(patsubst $(PPC64_SYSTEM_SRC)/%.c, %, $(PPC64_TEST_SRCS))
+MINILIB_OBJS_BE := $(MINILIB_OBJS)
+MINILIB_OBJS_LE := $(patsubst %.o, %-le.o, $(MINILIB_OBJS))
 
-LINK_SCRIPT=$(CRT_PATH)/powerpc.lds
-# NOTE: --build-id is stored before the first code section in the linked
-#       binary, which causes problems for most tests, that expect to
-#       begin at address 0.
-LDFLAGS=-Wl,-T$(LINK_SCRIPT) -Wl,--build-id=none -static -nostdlib \
-    $(CRT_OBJS) $(MINILIB_OBJS) -lgcc
-TESTS += $(filter-out $(DISABLED_TESTS),$(PPC64_TESTS) $(MULTIARCH_TESTS))
-EXTRA_RUNS += $(filter-out $(DISABLED_EXTRA_RUNS),$(MULTIARCH_RUNS))
+# Add BE and LE tests
+
+# Each Microwatt/PowerNV test use its own head.S file and thus needs
+# different rules.
+PPC64BE_PNV_TESTS := mmu
+PPC64BE_PNV_ELFS := $(addsuffix .elf, $(PPC64BE_PNV_TESTS))
+PPC64LE_PNV_TESTS := $(addsuffix -le, $(PPC64BE_PNV_TESTS))
+PPC64LE_PNV_ELFS := $(addsuffix .elf, $(PPC64LE_PNV_TESTS))
+
+# Remaining test sources are assumed to be non-PowerNV tests
+PPC64_TEST_SRCS := $(wildcard $(PPC64_SYSTEM_SRC)/*.c)
+PPC64BE_TESTS := $(MULTIARCH_TESTS)
+PPC64BE_TESTS += $(filter-out $(PPC64BE_PNV_TESTS),\
+                 $(patsubst $(PPC64_SYSTEM_SRC)/%.c, %, $(PPC64_TEST_SRCS)))
+PPC64BE_ELFS := $(addsuffix .elf,$(PPC64BE_TESTS))
+PPC64LE_TESTS := $(addsuffix -le, $(PPC64BE_TESTS))
+PPC64LE_ELFS := $(addsuffix .elf,$(PPC64LE_TESTS))
+
+TESTS += $(filter-out $(DISABLED_TESTS), $(PPC64BE_TESTS) $(PPC64LE_TESTS))
+TESTS += $(PPC64BE_PNV_TESTS) $(PPC64LE_PNV_TESTS)
+
+MULTIARCH_RUNS_BE := $(MULTIARCH_RUNS)
+MULTIARCH_RUNS_LE := $(addsuffix -le, $(MULTIARCH_RUNS))
+EXTRA_RUNS += $(filter-out $(DISABLED_EXTRA_RUNS), \
+                           $(MULTIARCH_RUNS_BE) $(MULTIARCH_RUNS_LE))
+
+LINK_SCRIPT := $(CRT_PATH)/powerpc.lds
 
 # NOTE: -Os doesn't work well with -Wl,--oformat=binary
 #       Some linker generated functions, such as savegpr*/restgpr*,
@@ -33,26 +60,64 @@ CFLAGS = -O -g -Wall -std=c99 -msoft-float -mno-vsx -mno-altivec \
          -I $(PPC64_SYSTEM_SRC)/include $(MINILIB_INC) \
          -mcpu=power8
 
+# NOTE: --build-id is stored before the first code section in the linked
+#       binary, which causes problems for most tests, that expect to
+#       begin at address 0.
+LDFLAGS = -Wl,-T$(LINK_SCRIPT) -Wl,--build-id=none -static -nostdlib \
+    $(CRT_OBJS) $(MINILIB_OBJS) -lgcc
+
+memory memory-le: CFLAGS+=-DCHECK_UNALIGNED=1
+
+# PowerNV tests build outputs
+PPC64BE_PNV_OUTPUTS := $(PPC64BE_PNV_TESTS) $(PPC64BE_PNV_ELFS)
+PPC64LE_PNV_OUTPUTS := $(PPC64LE_PNV_TESTS) $(PPC64LE_PNV_ELFS)
+# Non-PowerNV tests build outputs
+PPC64BE_OUTPUTS := $(PPC64BE_TESTS) $(PPC64BE_ELFS)
+PPC64LE_OUTPUTS := $(PPC64LE_TESTS) $(PPC64LE_ELFS)
+# Outputs of all tests
+PPC64BE_ALL_OUTPUTS := $(PPC64BE_OUTPUTS) $(PPC64BE_PNV_OUTPUTS)
+PPC64LE_ALL_OUTPUTS := $(PPC64LE_OUTPUTS) $(PPC64LE_PNV_OUTPUTS)
+
+PPC64_CFLAGS = $(CFLAGS) $(EXTRA_CFLAGS) $(PPC64LE_CFLAGS)
+
 # Leave the .elf files, to make debugging easier
-.PRECIOUS: $(CRT_OBJS) $(addsuffix .elf,$(TESTS))
+.PRECIOUS: $(CRT_OBJS_BE) $(CRT_OBJS_LE) $(addsuffix .elf,$(TESTS))
+
+# BE rules
+
+LE_SUFFIX :=
+CRT_DEPS := $(CRT_OBJS_BE)
+MINILIB_DEPS := $(MINILIB_OBJS_BE)
+PPC64_PNV_ELFS := $(PPC64BE_PNV_ELFS)
+PPC64_PNV_TESTS := $(PPC64BE_PNV_TESTS)
+
+$(PPC64BE_ALL_OUTPUTS): LE_SUFFIX =
+$(PPC64BE_ALL_OUTPUTS): PPC64LE_CFLAGS =
+$(PPC64BE_OUTPUTS): CRT_OBJS = $(CRT_OBJS_BE)
+$(PPC64BE_PNV_OUTPUTS): CRT_OBJS = $(PNV_CRT_OBJS_BE)
+$(PPC64BE_ALL_OUTPUTS): MINILIB_OBJS = $(MINILIB_OBJS_BE)
 
-# Build CRT objects
-%.o: $(CRT_PATH)/%.S
-	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -x assembler-with-cpp -c $< -o $@
+include $(PPC64_SRC)/Makefile.softmmu-rules
 
-%.o: $(CRT_PATH)/%.c
-	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c $< -o $@
+# LE rules
 
-# Build and link the tests
+LE_SUFFIX := -le
+CRT_DEPS := $(CRT_OBJS_LE)
+MINILIB_DEPS := $(MINILIB_OBJS_LE)
+PPC64_PNV_ELFS := $(PPC64LE_PNV_ELFS)
+PPC64_PNV_TESTS := $(PPC64LE_PNV_TESTS)
 
-# The .elf files are just for debugging
-%.elf: %.c $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS)
-	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS)
+$(PPC64LE_ALL_OUTPUTS): LE_SUFFIX = -le
+$(PPC64LE_ALL_OUTPUTS): PPC64LE_CFLAGS = -mlittle-endian -mabi=elfv2
+$(PPC64LE_OUTPUTS): CRT_OBJS = $(CRT_OBJS_LE)
+$(PPC64LE_PNV_OUTPUTS): CRT_OBJS = $(PNV_CRT_OBJS_LE)
+$(PPC64LE_ALL_OUTPUTS): MINILIB_OBJS = $(MINILIB_OBJS_LE)
 
-%: %.c %.elf $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS)
-	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS) -Wl,--oformat=binary
+include $(PPC64_SRC)/Makefile.softmmu-rules
 
-memory: CFLAGS+=-DCHECK_UNALIGNED=1
+# Build LE Minilib objs
+%-le.o: $(SYSTEM_MINILIB_SRC)/%.c
+	$(CC) $(PPC64_CFLAGS) -c $< -o $@
 
 # Running
 QEMU_BASE_MACHINE=-cpu power9 -M powernv9 -m 1G -vga none -nographic
-- 
2.25.1



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

* Re: [RFC PATCH v2 0/5] Port PPC64/PowerNV MMU tests to QEMU
  2022-03-31 14:58 [RFC PATCH v2 0/5] Port PPC64/PowerNV MMU tests to QEMU Leandro Lupori
                   ` (4 preceding siblings ...)
  2022-03-31 14:58 ` [RFC PATCH v2 5/5] tests/tcg/ppc64: build PowerNV and LE tests Leandro Lupori
@ 2022-03-31 15:47 ` Cédric Le Goater
  2022-03-31 16:16   ` Leandro Lupori
  5 siblings, 1 reply; 8+ messages in thread
From: Cédric Le Goater @ 2022-03-31 15:47 UTC (permalink / raw)
  To: Leandro Lupori, qemu-devel, qemu-ppc, Fabiano Rosas
  Cc: danielhb413, richard.henderson, groug, pbonzini, alex.bennee, david

Hello Leandro,

I think we should start looking at semihosting like Richard proposed
and for it, rework the QEMU attn implementation or may be use a special
form of scv.

It should not change too much the tests, only exit and output which
would remove the dependency on the platform console. In the long run,
it looks like  a good investment for more low level tests.

Thanks,

C.

On 3/31/22 16:58, Leandro Lupori wrote:
> Changes from v1:
> - added new files to MAINTAINERS, under PowerPC TCG CPUs, and added
>    myself as a reviewer (not sure if this is the right procedure)
> - removed the "virtual" ppc64le-softmmu target.
>    ppc64/Makefile.softmmu-target now builds all tests in both BE and LE
> 
> Cédric Le Goater (2):
>    target/ppc: Add support for the Processor Attention instruction
>    ppc/pnv: Activate support for the Processor Attention instruction
> 
> Leandro Lupori (3):
>    tests/tcg/ppc64: add basic softmmu test support
>    tests/tcg/ppc64: add MMU test sources
>    tests/tcg/ppc64: build PowerNV and LE tests
> 
>   MAINTAINERS                              |   2 +
>   hw/ppc/pnv_core.c                        |   6 +
>   include/hw/ppc/pnv_core.h                |   1 +
>   target/ppc/cpu.h                         |   8 +
>   target/ppc/excp_helper.c                 |  27 +
>   target/ppc/helper.h                      |   1 +
>   target/ppc/translate.c                   |  14 +
>   tests/tcg/ppc64/Makefile.softmmu-rules   |  34 +
>   tests/tcg/ppc64/Makefile.softmmu-target  | 124 ++++
>   tests/tcg/ppc64/system/include/asm.h     |  62 ++
>   tests/tcg/ppc64/system/include/console.h |  15 +
>   tests/tcg/ppc64/system/include/io.h      |  61 ++
>   tests/tcg/ppc64/system/include/pnv.h     |  21 +
>   tests/tcg/ppc64/system/include/uart.h    |  54 ++
>   tests/tcg/ppc64/system/lib/boot.S        |  68 ++
>   tests/tcg/ppc64/system/lib/console.c     | 173 +++++
>   tests/tcg/ppc64/system/lib/powerpc.lds   |  27 +
>   tests/tcg/ppc64/system/mmu-head.S        | 142 +++++
>   tests/tcg/ppc64/system/mmu.c             | 764 +++++++++++++++++++++++
>   tests/tcg/ppc64/system/mmu.h             |   9 +
>   20 files changed, 1613 insertions(+)
>   create mode 100644 tests/tcg/ppc64/Makefile.softmmu-rules
>   create mode 100644 tests/tcg/ppc64/Makefile.softmmu-target
>   create mode 100644 tests/tcg/ppc64/system/include/asm.h
>   create mode 100644 tests/tcg/ppc64/system/include/console.h
>   create mode 100644 tests/tcg/ppc64/system/include/io.h
>   create mode 100644 tests/tcg/ppc64/system/include/pnv.h
>   create mode 100644 tests/tcg/ppc64/system/include/uart.h
>   create mode 100644 tests/tcg/ppc64/system/lib/boot.S
>   create mode 100644 tests/tcg/ppc64/system/lib/console.c
>   create mode 100644 tests/tcg/ppc64/system/lib/powerpc.lds
>   create mode 100644 tests/tcg/ppc64/system/mmu-head.S
>   create mode 100644 tests/tcg/ppc64/system/mmu.c
>   create mode 100644 tests/tcg/ppc64/system/mmu.h
> 



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

* Re: [RFC PATCH v2 0/5] Port PPC64/PowerNV MMU tests to QEMU
  2022-03-31 15:47 ` [RFC PATCH v2 0/5] Port PPC64/PowerNV MMU tests to QEMU Cédric Le Goater
@ 2022-03-31 16:16   ` Leandro Lupori
  0 siblings, 0 replies; 8+ messages in thread
From: Leandro Lupori @ 2022-03-31 16:16 UTC (permalink / raw)
  To: Cédric Le Goater, qemu-devel, qemu-ppc, Fabiano Rosas
  Cc: danielhb413, richard.henderson, groug, pbonzini, alex.bennee, david

On 3/31/22 12:47, Cédric Le Goater wrote:
> 
> Hello Leandro,
> 
> I think we should start looking at semihosting like Richard proposed
> and for it, rework the QEMU attn implementation or may be use a special
> form of scv.
> 
> It should not change too much the tests, only exit and output which
> would remove the dependency on the platform console. In the long run,
> it looks like  a good investment for more low level tests.
> 
> Thanks,
> 
> C.
> 

Hi Cédric,

I've assumed you would handle the comments related to the attn 
instruction implementation, so that's why I've sent a v2 with only the 
other changes.
But no problem, we can coordinate how we're going to add semihosting 
support to PPC.

Thanks,
Leandro


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

end of thread, other threads:[~2022-03-31 16:19 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-31 14:58 [RFC PATCH v2 0/5] Port PPC64/PowerNV MMU tests to QEMU Leandro Lupori
2022-03-31 14:58 ` [RFC PATCH v2 1/5] target/ppc: Add support for the Processor Attention instruction Leandro Lupori
2022-03-31 14:58 ` [RFC PATCH v2 2/5] ppc/pnv: Activate " Leandro Lupori
2022-03-31 14:58 ` [RFC PATCH v2 3/5] tests/tcg/ppc64: add basic softmmu test support Leandro Lupori
2022-03-31 14:58 ` [RFC PATCH v2 4/5] tests/tcg/ppc64: add MMU test sources Leandro Lupori
2022-03-31 14:58 ` [RFC PATCH v2 5/5] tests/tcg/ppc64: build PowerNV and LE tests Leandro Lupori
2022-03-31 15:47 ` [RFC PATCH v2 0/5] Port PPC64/PowerNV MMU tests to QEMU Cédric Le Goater
2022-03-31 16:16   ` Leandro Lupori

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.