qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH V13 0/9] mips: Add Loongson-3 machine support
@ 2020-10-07  8:39 Huacai Chen
  2020-10-07  8:39 ` [PATCH V13 1/9] linux-headers: Update MIPS KVM type defintition Huacai Chen
                   ` (8 more replies)
  0 siblings, 9 replies; 34+ messages in thread
From: Huacai Chen @ 2020-10-07  8:39 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, Aleksandar Markovic
  Cc: Aleksandar Rikalo, Huacai Chen, qemu-devel, Jiaxun Yang,
	Huacai Chen, Aurelien Jarno

Loongson-3 CPU family include Loongson-3A R1/R2/R3/R4 and Loongson-3B
R1/R2. Loongson-3A R1 is the oldest and its ISA is the smallest, while
Loongson-3A R4 is the newest and its ISA is almost the superset of all
others. To reduce complexity, in QEMU we just define two CPU types:

1, "Loongson-3A1000" CPU which is corresponding to Loongson-3A R1. It is
   suitable for TCG because Loongson-3A R1 has fewest ASE.
2, "Loongson-3A4000" CPU which is corresponding to Loongson-3A R4. It is
   suitable for KVM because Loongson-3A R4 has the VZ ASE.

Loongson-3 lacks English documents. I've tried to translated them with
translate.google.com, and the machine translated documents (together
with their original Chinese versions) are available here.

Loongson-3A R1 (Loongson-3A1000)
User Manual Part 1:
http://ftp.godson.ac.cn/lemote/3A1000_p1.pdf
http://ftp.godson.ac.cn/lemote/Loongson3A1000_processor_user_manual_P1.pdf (Chinese Version)
User Manual Part 2:
http://ftp.godson.ac.cn/lemote/3A1000_p2.pdf
http://ftp.godson.ac.cn/lemote/Loongson3A1000_processor_user_manual_P2.pdf (Chinese Version)

Loongson-3A R2 (Loongson-3A2000)
User Manual Part 1:
http://ftp.godson.ac.cn/lemote/3A2000_p1.pdf
http://ftp.godson.ac.cn/lemote/Loongson3A2000_user1.pdf (Chinese Version)
User Manual Part 2:
http://ftp.godson.ac.cn/lemote/3A2000_p2.pdf
http://ftp.godson.ac.cn/lemote/Loongson3A2000_user2.pdf (Chinese Version)

Loongson-3A R3 (Loongson-3A3000)
User Manual Part 1:
http://ftp.godson.ac.cn/lemote/3A3000_p1.pdf
http://ftp.godson.ac.cn/lemote/Loongson3A3000_3B3000usermanual1.pdf (Chinese Version)
User Manual Part 2:
http://ftp.godson.ac.cn/lemote/3A3000_p2.pdf
http://ftp.godson.ac.cn/lemote/Loongson3A3000_3B3000usermanual2.pdf (Chinese Version)

Loongson-3A R4 (Loongson-3A4000)
User Manual Part 1:
http://ftp.godson.ac.cn/lemote/3A4000_p1.pdf
http://ftp.godson.ac.cn/lemote/3A4000user.pdf (Chinese Version)
User Manual Part 2:
I'm sorry that it is unavailable now.

And human-translated documents (W.I.P) are available here now:
https://github.com/loongson-community/docs/tree/master/English-translation-of-Loongson-manual

Both KVM and TCG are available now!

We now already have a full functional Linux kernel (based on Linux-5.4.x
LTS, the kvm host side and guest side have both been upstream for Linux-
5.9, but Linux-5.9 has not been released yet) here:

https://github.com/chenhuacai/linux

Of course the upstream kernel is also usable (though it is "unstable"
now):

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git

How to use QEMU/Loongson-3?
1, Download kernel source from the above URL;
2, Build a kernel with arch/mips/configs/loongson3_{def,hpc}config;
3, Boot a Loongson-3A4000 host with this kernel (for KVM mode);
4, Build QEMU-master with this patchset;
5, modprobe kvm (only necessary for KVM mode);
6, Use QEMU with TCG:
       qemu-system-mips64el -M loongson3-virt,accel=tcg -cpu Loongson-3A1000 -kernel <path_to_kernel> -append ...
   Use QEMU with KVM:
       qemu-system-mips64el -M loongson3-virt,accel=kvm -cpu Loongson-3A4000 -kernel <path_to_kernel> -append ...

   The "-cpu" parameter is optional here and QEMU will use the correct type for TCG/KVM automatically.

V1 -> V2:
1, Add a cover letter;
2, Improve CPU definitions;
3, Remove LS7A-related things (Use GPEX instead);
4, Add a description of how to run QEMU/Loongson-3.

V2 -> V3:
1, Fix all possible checkpatch.pl errors and warnings.

V3 -> V4:
1, Sync code with upstream;
2, Remove merged patches;
3, Fix build failure without CONFIG_KVM;
4, Add Reviewed-by: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>.

V4 -> V5:
1, Improve coding style;
2, Remove merged patches;
3, Rename machine name from "loongson3" to "loongson3-virt";
4, Rework the "loongson3-virt" machine to drop any ISA things;
5, Rework "hw/mips: Implement the kvm_type() hook in MachineClass";
6, Add Jiaxun Yang as a reviewer of Loongson-3.

V5 -> V6:
1, Fix license preamble;
2, Improve commit messages;
3, Add hw/intc/loongson_liointc.c to MAINTAINERS;
4, Fix all possible checkpatch.pl errors and warnings.

V7 and V8 have only one patch (machine definition) with some minor improvements.

V8 -> V9:
1, Update KVM type definition from kernel;
2, Fix PageMask with variable page size for TCG;
3, Add TCG support (add Loongson-EXT instructions).

V9 -> V10:
1, Split fw_cfg to a separate patch;
2, Split boot parameters definition to a local header;
3, Update MIPS machine documentation;
4, Many other improvements suggested by Philippe Mathieu-Daudé.

V10 -> V11:
1, Fix some typos;
2, Add Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>.

V11 -> V12:
1, Split boot parameter helpers to loongson3_bootp.c;
2, Support both BE and LE host (Loongson guests are always LE).

V12 -> V13:
1, Sync code with upstream;
2, Re-enable KVM support for MIPS in meson;

Huacai Chen and Jiaxun Yang (9):
 linux-headers: Update MIPS KVM type defintition
 meson.build: Re-enable KVM support for MIPS
 target/mips: Fix PageMask with variable page size
 target/mips: Add loongson-ext lswc2 group of instructions (Part 1)
 target/mips: Add loongson-ext lswc2 group of instructions (Part 2)
 target/mips: Add loongson-ext lsdc2 group of instructions
 hw/mips: Implement fw_cfg_arch_key_name()
 hw/mips: Add Loongson-3 machine support
 docs/system: Update MIPS machine documentation

Signed-off-by: Huacai Chen <chenhc@lemote.com>
---
 default-configs/devices/mips64el-softmmu.mak |   1 +
 docs/system/cpu-models-mips.rst.inc          |  10 +-
 docs/system/target-mips.rst                  |  10 +
 hw/mips/Kconfig                              |  12 +
 hw/mips/fw_cfg.c                             |  35 ++
 hw/mips/fw_cfg.h                             |  19 +
 hw/mips/loongson3_bootp.c                    | 162 +++++++
 hw/mips/loongson3_bootp.h                    | 225 ++++++++++
 hw/mips/loongson3_virt.c                     | 615 +++++++++++++++++++++++++++
 hw/mips/meson.build                          |   3 +-
 linux-headers/linux/kvm.h                    |   5 +-
 meson.build                                  |   2 +
 target/mips/cp0_helper.c                     |  36 +-
 target/mips/cpu.h                            |   1 +
 target/mips/translate.c                      | 443 +++++++++++++++++++
 15 files changed, 1567 insertions(+), 12 deletions(-)
 create mode 100644 hw/mips/fw_cfg.c
 create mode 100644 hw/mips/fw_cfg.h
 create mode 100644 hw/mips/loongson3_bootp.c
 create mode 100644 hw/mips/loongson3_bootp.h
 create mode 100644 hw/mips/loongson3_virt.c
--
2.7.0


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

* [PATCH V13 1/9] linux-headers: Update MIPS KVM type defintition
  2020-10-07  8:39 [PATCH V13 0/9] mips: Add Loongson-3 machine support Huacai Chen
@ 2020-10-07  8:39 ` Huacai Chen
  2020-10-10  8:25   ` Philippe Mathieu-Daudé
  2020-10-10 12:59   ` Peter Maydell
  2020-10-07  8:39 ` [PATCH V13 2/9] meson.build: Re-enable KVM support for MIPS Huacai Chen
                   ` (7 subsequent siblings)
  8 siblings, 2 replies; 34+ messages in thread
From: Huacai Chen @ 2020-10-07  8:39 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, Aleksandar Markovic
  Cc: Aleksandar Rikalo, Huacai Chen, qemu-devel, Jiaxun Yang,
	Huacai Chen, Aurelien Jarno

Update MIPS KVM type defintition from Linux 5.9-rc6.

Signed-off-by: Huacai Chen <chenhc@lemote.com>
---
 linux-headers/linux/kvm.h | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index 6683e2e..c138b2f 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -790,9 +790,10 @@ struct kvm_ppc_resize_hpt {
 #define KVM_VM_PPC_HV 1
 #define KVM_VM_PPC_PR 2
 
-/* on MIPS, 0 forces trap & emulate, 1 forces VZ ASE */
-#define KVM_VM_MIPS_TE		0
+/* on MIPS, 0 indicates auto, 1 forces VZ ASE, 2 forces trap & emulate */
+#define KVM_VM_MIPS_AUTO	0
 #define KVM_VM_MIPS_VZ		1
+#define KVM_VM_MIPS_TE		2
 
 #define KVM_S390_SIE_PAGE_OFFSET 1
 
-- 
2.7.0



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

* [PATCH V13 2/9] meson.build: Re-enable KVM support for MIPS
  2020-10-07  8:39 [PATCH V13 0/9] mips: Add Loongson-3 machine support Huacai Chen
  2020-10-07  8:39 ` [PATCH V13 1/9] linux-headers: Update MIPS KVM type defintition Huacai Chen
@ 2020-10-07  8:39 ` Huacai Chen
  2020-10-07  8:51   ` Paolo Bonzini
  2020-11-17 17:17   ` Philippe Mathieu-Daudé
  2020-10-07  8:39 ` [PATCH V13 3/9] target/mips: Fix PageMask with variable page size Huacai Chen
                   ` (6 subsequent siblings)
  8 siblings, 2 replies; 34+ messages in thread
From: Huacai Chen @ 2020-10-07  8:39 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, Aleksandar Markovic
  Cc: Aleksandar Rikalo, Huacai Chen, qemu-devel, Jiaxun Yang,
	aolo Bonzini, Huacai Chen, Aurelien Jarno

After converting from configure to meson, KVM support is lost for MIPS,
so re-enable it in meson.build.

Fixes: fdb75aeff7c212e1afaaa3a43 ("configure: remove target configuration")
Fixes: 8a19980e3fc42239aae054bc9 ("configure: move accelerator logic to meson")
Cc: aolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Huacai Chen <chenhc@lemote.com>
---
 meson.build | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/meson.build b/meson.build
index 17c89c8..b407ff4 100644
--- a/meson.build
+++ b/meson.build
@@ -59,6 +59,8 @@ elif cpu == 's390x'
   kvm_targets = ['s390x-softmmu']
 elif cpu in ['ppc', 'ppc64']
   kvm_targets = ['ppc-softmmu', 'ppc64-softmmu']
+elif cpu in ['mips', 'mips64']
+  kvm_targets = ['mips-softmmu', 'mipsel-softmmu', 'mips64-softmmu', 'mips64el-softmmu']
 else
   kvm_targets = []
 endif
-- 
2.7.0



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

* [PATCH V13 3/9] target/mips: Fix PageMask with variable page size
  2020-10-07  8:39 [PATCH V13 0/9] mips: Add Loongson-3 machine support Huacai Chen
  2020-10-07  8:39 ` [PATCH V13 1/9] linux-headers: Update MIPS KVM type defintition Huacai Chen
  2020-10-07  8:39 ` [PATCH V13 2/9] meson.build: Re-enable KVM support for MIPS Huacai Chen
@ 2020-10-07  8:39 ` Huacai Chen
  2020-10-07  8:39 ` [PATCH V13 4/9] target/mips: Add loongson-ext lswc2 group of instructions (Part 1) Huacai Chen
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 34+ messages in thread
From: Huacai Chen @ 2020-10-07  8:39 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, Aleksandar Markovic
  Cc: Aleksandar Rikalo, Huacai Chen, qemu-devel, Jiaxun Yang,
	Huacai Chen, Aurelien Jarno

From: Jiaxun Yang <jiaxun.yang@flygoat.com>

Our current code assumed the target page size is always 4k
when handling PageMask and VPN2, however, variable page size
was just added to mips target and that's no longer true.

Fixes: ee3863b9d414 ("target/mips: Support variable page size")
Signed-off-by: Huacai Chen <chenhc@lemote.com>
Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
---
 target/mips/cp0_helper.c | 36 +++++++++++++++++++++++++++++-------
 target/mips/cpu.h        |  1 +
 2 files changed, 30 insertions(+), 7 deletions(-)

diff --git a/target/mips/cp0_helper.c b/target/mips/cp0_helper.c
index de64add..f3478d8 100644
--- a/target/mips/cp0_helper.c
+++ b/target/mips/cp0_helper.c
@@ -867,13 +867,35 @@ void helper_mtc0_memorymapid(CPUMIPSState *env, target_ulong arg1)
 
 void update_pagemask(CPUMIPSState *env, target_ulong arg1, int32_t *pagemask)
 {
-    uint64_t mask = arg1 >> (TARGET_PAGE_BITS + 1);
-    if (!(env->insn_flags & ISA_MIPS32R6) || (arg1 == ~0) ||
-        (mask == 0x0000 || mask == 0x0003 || mask == 0x000F ||
-         mask == 0x003F || mask == 0x00FF || mask == 0x03FF ||
-         mask == 0x0FFF || mask == 0x3FFF || mask == 0xFFFF)) {
-        env->CP0_PageMask = arg1 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1));
+    unsigned long mask;
+    int maskbits;
+
+    if (env->insn_flags & ISA_MIPS32R6) {
+        return;
+    }
+    /* Don't care MASKX as we don't support 1KB page */
+    mask = extract32((uint32_t)arg1, CP0PM_MASK, 16);
+    maskbits = find_first_zero_bit(&mask, 32);
+
+    /* Ensure no more set bit after first zero */
+    if (mask >> maskbits) {
+        goto invalid;
+    }
+    /* We don't support VTLB entry smaller than target page */
+    if ((maskbits + 12) < TARGET_PAGE_BITS) {
+        goto invalid;
     }
+    env->CP0_PageMask = mask << CP0PM_MASK;
+
+    return;
+
+invalid:
+    /*
+     * When invalid, ensure the value is bigger than or equal to
+     * the minimal but smaller than or equal to the maxium.
+     */
+    maskbits = MIN(16, MAX(maskbits, TARGET_PAGE_BITS - 12));
+    env->CP0_PageMask = ((1 << (16 + 1)) - 1) << CP0PM_MASK;
 }
 
 void helper_mtc0_pagemask(CPUMIPSState *env, target_ulong arg1)
@@ -1104,7 +1126,7 @@ void helper_mthc0_saar(CPUMIPSState *env, target_ulong arg1)
 void helper_mtc0_entryhi(CPUMIPSState *env, target_ulong arg1)
 {
     target_ulong old, val, mask;
-    mask = (TARGET_PAGE_MASK << 1) | env->CP0_EntryHi_ASID_mask;
+    mask = ~((1 << 14) - 1) | env->CP0_EntryHi_ASID_mask;
     if (((env->CP0_Config4 >> CP0C4_IE) & 0x3) >= 2) {
         mask |= 1 << CP0EnHi_EHINV;
     }
diff --git a/target/mips/cpu.h b/target/mips/cpu.h
index 7cf7f52..9c8bb23 100644
--- a/target/mips/cpu.h
+++ b/target/mips/cpu.h
@@ -618,6 +618,7 @@ struct CPUMIPSState {
  * CP0 Register 5
  */
     int32_t CP0_PageMask;
+#define CP0PM_MASK 13
     int32_t CP0_PageGrain_rw_bitmask;
     int32_t CP0_PageGrain;
 #define CP0PG_RIE 31
-- 
2.7.0



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

* [PATCH V13 4/9] target/mips: Add loongson-ext lswc2 group of instructions (Part 1)
  2020-10-07  8:39 [PATCH V13 0/9] mips: Add Loongson-3 machine support Huacai Chen
                   ` (2 preceding siblings ...)
  2020-10-07  8:39 ` [PATCH V13 3/9] target/mips: Fix PageMask with variable page size Huacai Chen
@ 2020-10-07  8:39 ` Huacai Chen
  2020-10-07  8:39 ` [PATCH V13 5/9] target/mips: Add loongson-ext lswc2 group of instructions (Part 2) Huacai Chen
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 34+ messages in thread
From: Huacai Chen @ 2020-10-07  8:39 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, Aleksandar Markovic
  Cc: Aleksandar Rikalo, Huacai Chen, qemu-devel, Jiaxun Yang,
	Huacai Chen, Aurelien Jarno

From: Jiaxun Yang <jiaxun.yang@flygoat.com>

LWC2 & SWC2 have been rewritten by Loongson EXT vendor ASE
as "load/store quad word" and "shifted load/store" groups of
instructions.

This patch add implementation of these instructions:
gslq: load 16 bytes to GPR
gssq: store 16 bytes from GPR
gslqc1: load 16 bytes to FPR
gssqc1: store 16 bytes from FPR

Details of Loongson-EXT is here:
https://github.com/FlyGoat/loongson-insn/blob/master/loongson-ext.md

Signed-off-by: Huacai Chen <chenhc@lemote.com>
Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
---
 target/mips/translate.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 87 insertions(+)

diff --git a/target/mips/translate.c b/target/mips/translate.c
index 398edf7..cb0adde 100644
--- a/target/mips/translate.c
+++ b/target/mips/translate.c
@@ -460,6 +460,17 @@ enum {
     R6_OPC_SCD         = 0x27 | OPC_SPECIAL3,
 };
 
+/* Loongson EXT load/store quad word opcodes */
+#define MASK_LOONGSON_GSLSQ(op)           (MASK_OP_MAJOR(op) | (op & 0x8020))
+enum {
+    OPC_GSLQ        = 0x0020 | OPC_LWC2,
+    OPC_GSLQC1      = 0x8020 | OPC_LWC2,
+    OPC_GSSHFL      = OPC_LWC2,
+    OPC_GSSQ        = 0x0020 | OPC_SWC2,
+    OPC_GSSQC1      = 0x8020 | OPC_SWC2,
+    OPC_GSSHFS      = OPC_SWC2,
+};
+
 /* BSHFL opcodes */
 #define MASK_BSHFL(op)              (MASK_SPECIAL3(op) | (op & (0x1F << 6)))
 
@@ -5910,6 +5921,80 @@ no_rd:
     tcg_temp_free_i64(t1);
 }
 
+static void gen_loongson_lswc2(DisasContext *ctx, int rt,
+                                int rs, int rd)
+{
+    TCGv t0, t1, t2;
+    TCGv_i32 fp0;
+#if defined(TARGET_MIPS64)
+    int lsq_rt1 = ctx->opcode & 0x1f;
+    int lsq_offset = ((int)((ctx->opcode >> 6) & 0x1ff) << 23) >> 19;
+#endif
+    int shf_offset = (int8_t)(ctx->opcode >> 6);
+
+    t0 = tcg_temp_new();
+
+    switch (MASK_LOONGSON_GSLSQ(ctx->opcode)) {
+#if defined(TARGET_MIPS64)
+    case OPC_GSLQ:
+        t1 = tcg_temp_new();
+        gen_base_offset_addr(ctx, t0, rs, lsq_offset);
+        tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TEQ |
+                            ctx->default_tcg_memop_mask);
+        gen_base_offset_addr(ctx, t0, rs, lsq_offset + 8);
+        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ |
+                            ctx->default_tcg_memop_mask);
+        gen_store_gpr(t1, rt);
+        gen_store_gpr(t0, lsq_rt1);
+        tcg_temp_free(t1);
+        break;
+    case OPC_GSLQC1:
+        check_cp1_enabled(ctx);
+        t1 = tcg_temp_new();
+        gen_base_offset_addr(ctx, t0, rs, lsq_offset);
+        tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_TEQ |
+                            ctx->default_tcg_memop_mask);
+        gen_base_offset_addr(ctx, t0, rs, lsq_offset + 8);
+        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ |
+                            ctx->default_tcg_memop_mask);
+        gen_store_fpr64(ctx, t1, rt);
+        gen_store_fpr64(ctx, t0, lsq_rt1);
+        tcg_temp_free(t1);
+        break;
+    case OPC_GSSQ:
+        t1 = tcg_temp_new();
+        gen_base_offset_addr(ctx, t0, rs, lsq_offset);
+        gen_load_gpr(t1, rt);
+        tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEQ |
+                            ctx->default_tcg_memop_mask);
+        gen_base_offset_addr(ctx, t0, rs, lsq_offset + 8);
+        gen_load_gpr(t1, lsq_rt1);
+        tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEQ |
+                            ctx->default_tcg_memop_mask);
+        tcg_temp_free(t1);
+        break;
+    case OPC_GSSQC1:
+        check_cp1_enabled(ctx);
+        t1 = tcg_temp_new();
+        gen_base_offset_addr(ctx, t0, rs, lsq_offset);
+        gen_load_fpr64(ctx, t1, rt);
+        tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEQ |
+                            ctx->default_tcg_memop_mask);
+        gen_base_offset_addr(ctx, t0, rs, lsq_offset + 8);
+        gen_load_fpr64(ctx, t1, lsq_rt1);
+        tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEQ |
+                            ctx->default_tcg_memop_mask);
+        tcg_temp_free(t1);
+        break;
+#endif
+    default:
+        MIPS_INVAL("loongson_gslsq");
+        generate_exception_end(ctx, EXCP_RI);
+        break;
+    }
+    tcg_temp_free(t0);
+}
+
 /* Traps */
 static void gen_trap(DisasContext *ctx, uint32_t opc,
                      int rs, int rt, int16_t imm)
@@ -30774,6 +30859,8 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx)
             /* OPC_BC, OPC_BALC */
             gen_compute_compact_branch(ctx, op, 0, 0,
                                        sextract32(ctx->opcode << 2, 0, 28));
+        } else if (ctx->insn_flags & ASE_LEXT) {
+            gen_loongson_lswc2(ctx, rt, rs, rd);
         } else {
             /* OPC_LWC2, OPC_SWC2 */
             /* COP2: Not implemented. */
-- 
2.7.0



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

* [PATCH V13 5/9] target/mips: Add loongson-ext lswc2 group of instructions (Part 2)
  2020-10-07  8:39 [PATCH V13 0/9] mips: Add Loongson-3 machine support Huacai Chen
                   ` (3 preceding siblings ...)
  2020-10-07  8:39 ` [PATCH V13 4/9] target/mips: Add loongson-ext lswc2 group of instructions (Part 1) Huacai Chen
@ 2020-10-07  8:39 ` Huacai Chen
  2020-10-07  8:39 ` [PATCH V13 6/9] target/mips: Add loongson-ext lsdc2 group of instructions Huacai Chen
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 34+ messages in thread
From: Huacai Chen @ 2020-10-07  8:39 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, Aleksandar Markovic
  Cc: Aleksandar Rikalo, Huacai Chen, qemu-devel, Jiaxun Yang,
	Huacai Chen, Aurelien Jarno

From: Jiaxun Yang <jiaxun.yang@flygoat.com>

LWC2 & SWC2 have been rewritten by Loongson EXT vendor ASE
as "load/store quad word" and "shifted load/store" groups of
instructions.

This patch add implementation of these instructions:
gslwlc1: similar to lwl but RT is FPR instead of GPR
gslwrc1: similar to lwr but RT is FPR instead of GPR
gsldlc1: similar to ldl but RT is FPR instead of GPR
gsldrc1: similar to ldr but RT is FPR instead of GPR
gsswlc1: similar to swl but RT is FPR instead of GPR
gsswrc1: similar to swr but RT is FPR instead of GPR
gssdlc1: similar to sdl but RT is FPR instead of GPR
gssdrc1: similar to sdr but RT is FPR instead of GPR

Details of Loongson-EXT is here:
https://github.com/FlyGoat/loongson-insn/blob/master/loongson-ext.md

Signed-off-by: Huacai Chen <chenhc@lemote.com>
Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
---
 target/mips/translate.c | 177 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 177 insertions(+)

diff --git a/target/mips/translate.c b/target/mips/translate.c
index cb0adde..916b57f 100644
--- a/target/mips/translate.c
+++ b/target/mips/translate.c
@@ -471,6 +471,19 @@ enum {
     OPC_GSSHFS      = OPC_SWC2,
 };
 
+/* Loongson EXT shifted load/store opcodes */
+#define MASK_LOONGSON_GSSHFLS(op)         (MASK_OP_MAJOR(op) | (op & 0xc03f))
+enum {
+    OPC_GSLWLC1     = 0x4 | OPC_GSSHFL,
+    OPC_GSLWRC1     = 0x5 | OPC_GSSHFL,
+    OPC_GSLDLC1     = 0x6 | OPC_GSSHFL,
+    OPC_GSLDRC1     = 0x7 | OPC_GSSHFL,
+    OPC_GSSWLC1     = 0x4 | OPC_GSSHFS,
+    OPC_GSSWRC1     = 0x5 | OPC_GSSHFS,
+    OPC_GSSDLC1     = 0x6 | OPC_GSSHFS,
+    OPC_GSSDRC1     = 0x7 | OPC_GSSHFS,
+};
+
 /* BSHFL opcodes */
 #define MASK_BSHFL(op)              (MASK_SPECIAL3(op) | (op & (0x1F << 6)))
 
@@ -5987,6 +6000,170 @@ static void gen_loongson_lswc2(DisasContext *ctx, int rt,
         tcg_temp_free(t1);
         break;
 #endif
+    case OPC_GSSHFL:
+        switch (MASK_LOONGSON_GSSHFLS(ctx->opcode)) {
+        case OPC_GSLWLC1:
+            check_cp1_enabled(ctx);
+            gen_base_offset_addr(ctx, t0, rs, shf_offset);
+            t1 = tcg_temp_new();
+            tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_UB);
+            tcg_gen_andi_tl(t1, t0, 3);
+#ifndef TARGET_WORDS_BIGENDIAN
+            tcg_gen_xori_tl(t1, t1, 3);
+#endif
+            tcg_gen_shli_tl(t1, t1, 3);
+            tcg_gen_andi_tl(t0, t0, ~3);
+            tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUL);
+            tcg_gen_shl_tl(t0, t0, t1);
+            t2 = tcg_const_tl(-1);
+            tcg_gen_shl_tl(t2, t2, t1);
+            fp0 = tcg_temp_new_i32();
+            gen_load_fpr32(ctx, fp0, rt);
+            tcg_gen_ext_i32_tl(t1, fp0);
+            tcg_gen_andc_tl(t1, t1, t2);
+            tcg_temp_free(t2);
+            tcg_gen_or_tl(t0, t0, t1);
+            tcg_temp_free(t1);
+#if defined(TARGET_MIPS64)
+            tcg_gen_extrl_i64_i32(fp0, t0);
+#else
+            tcg_gen_ext32s_tl(fp0, t0);
+#endif
+            gen_store_fpr32(ctx, fp0, rt);
+            tcg_temp_free_i32(fp0);
+            break;
+        case OPC_GSLWRC1:
+            check_cp1_enabled(ctx);
+            gen_base_offset_addr(ctx, t0, rs, shf_offset);
+            t1 = tcg_temp_new();
+            tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_UB);
+            tcg_gen_andi_tl(t1, t0, 3);
+#ifdef TARGET_WORDS_BIGENDIAN
+            tcg_gen_xori_tl(t1, t1, 3);
+#endif
+            tcg_gen_shli_tl(t1, t1, 3);
+            tcg_gen_andi_tl(t0, t0, ~3);
+            tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEUL);
+            tcg_gen_shr_tl(t0, t0, t1);
+            tcg_gen_xori_tl(t1, t1, 31);
+            t2 = tcg_const_tl(0xfffffffeull);
+            tcg_gen_shl_tl(t2, t2, t1);
+            fp0 = tcg_temp_new_i32();
+            gen_load_fpr32(ctx, fp0, rt);
+            tcg_gen_ext_i32_tl(t1, fp0);
+            tcg_gen_and_tl(t1, t1, t2);
+            tcg_temp_free(t2);
+            tcg_gen_or_tl(t0, t0, t1);
+            tcg_temp_free(t1);
+#if defined(TARGET_MIPS64)
+            tcg_gen_extrl_i64_i32(fp0, t0);
+#else
+            tcg_gen_ext32s_tl(fp0, t0);
+#endif
+            gen_store_fpr32(ctx, fp0, rt);
+            tcg_temp_free_i32(fp0);
+            break;
+#if defined(TARGET_MIPS64)
+        case OPC_GSLDLC1:
+            check_cp1_enabled(ctx);
+            gen_base_offset_addr(ctx, t0, rs, shf_offset);
+            t1 = tcg_temp_new();
+            tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_UB);
+            tcg_gen_andi_tl(t1, t0, 7);
+#ifndef TARGET_WORDS_BIGENDIAN
+            tcg_gen_xori_tl(t1, t1, 7);
+#endif
+            tcg_gen_shli_tl(t1, t1, 3);
+            tcg_gen_andi_tl(t0, t0, ~7);
+            tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ);
+            tcg_gen_shl_tl(t0, t0, t1);
+            t2 = tcg_const_tl(-1);
+            tcg_gen_shl_tl(t2, t2, t1);
+            gen_load_fpr64(ctx, t1, rt);
+            tcg_gen_andc_tl(t1, t1, t2);
+            tcg_temp_free(t2);
+            tcg_gen_or_tl(t0, t0, t1);
+            tcg_temp_free(t1);
+            gen_store_fpr64(ctx, t0, rt);
+            break;
+        case OPC_GSLDRC1:
+            check_cp1_enabled(ctx);
+            gen_base_offset_addr(ctx, t0, rs, shf_offset);
+            t1 = tcg_temp_new();
+            tcg_gen_qemu_ld_tl(t1, t0, ctx->mem_idx, MO_UB);
+            tcg_gen_andi_tl(t1, t0, 7);
+#ifdef TARGET_WORDS_BIGENDIAN
+            tcg_gen_xori_tl(t1, t1, 7);
+#endif
+            tcg_gen_shli_tl(t1, t1, 3);
+            tcg_gen_andi_tl(t0, t0, ~7);
+            tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ);
+            tcg_gen_shr_tl(t0, t0, t1);
+            tcg_gen_xori_tl(t1, t1, 63);
+            t2 = tcg_const_tl(0xfffffffffffffffeull);
+            tcg_gen_shl_tl(t2, t2, t1);
+            gen_load_fpr64(ctx, t1, rt);
+            tcg_gen_and_tl(t1, t1, t2);
+            tcg_temp_free(t2);
+            tcg_gen_or_tl(t0, t0, t1);
+            tcg_temp_free(t1);
+            gen_store_fpr64(ctx, t0, rt);
+            break;
+#endif
+        default:
+            MIPS_INVAL("loongson_gsshfl");
+            generate_exception_end(ctx, EXCP_RI);
+            break;
+        }
+        break;
+    case OPC_GSSHFS:
+        switch (MASK_LOONGSON_GSSHFLS(ctx->opcode)) {
+        case OPC_GSSWLC1:
+            check_cp1_enabled(ctx);
+            t1 = tcg_temp_new();
+            gen_base_offset_addr(ctx, t0, rs, shf_offset);
+            fp0 = tcg_temp_new_i32();
+            gen_load_fpr32(ctx, fp0, rt);
+            tcg_gen_ext_i32_tl(t1, fp0);
+            gen_helper_0e2i(swl, t1, t0, ctx->mem_idx);
+            tcg_temp_free_i32(fp0);
+            tcg_temp_free(t1);
+            break;
+        case OPC_GSSWRC1:
+            check_cp1_enabled(ctx);
+            t1 = tcg_temp_new();
+            gen_base_offset_addr(ctx, t0, rs, shf_offset);
+            fp0 = tcg_temp_new_i32();
+            gen_load_fpr32(ctx, fp0, rt);
+            tcg_gen_ext_i32_tl(t1, fp0);
+            gen_helper_0e2i(swr, t1, t0, ctx->mem_idx);
+            tcg_temp_free_i32(fp0);
+            tcg_temp_free(t1);
+            break;
+#if defined(TARGET_MIPS64)
+        case OPC_GSSDLC1:
+            check_cp1_enabled(ctx);
+            t1 = tcg_temp_new();
+            gen_base_offset_addr(ctx, t0, rs, shf_offset);
+            gen_load_fpr64(ctx, t1, rt);
+            gen_helper_0e2i(sdl, t1, t0, ctx->mem_idx);
+            tcg_temp_free(t1);
+            break;
+        case OPC_GSSDRC1:
+            check_cp1_enabled(ctx);
+            t1 = tcg_temp_new();
+            gen_base_offset_addr(ctx, t0, rs, shf_offset);
+            gen_load_fpr64(ctx, t1, rt);
+            gen_helper_0e2i(sdr, t1, t0, ctx->mem_idx);
+            tcg_temp_free(t1);
+            break;
+#endif
+        default:
+            MIPS_INVAL("loongson_gsshfs");
+            generate_exception_end(ctx, EXCP_RI);
+            break;
+        }
+        break;
     default:
         MIPS_INVAL("loongson_gslsq");
         generate_exception_end(ctx, EXCP_RI);
-- 
2.7.0



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

* [PATCH V13 6/9] target/mips: Add loongson-ext lsdc2 group of instructions
  2020-10-07  8:39 [PATCH V13 0/9] mips: Add Loongson-3 machine support Huacai Chen
                   ` (4 preceding siblings ...)
  2020-10-07  8:39 ` [PATCH V13 5/9] target/mips: Add loongson-ext lswc2 group of instructions (Part 2) Huacai Chen
@ 2020-10-07  8:39 ` Huacai Chen
  2020-10-10 13:07   ` Philippe Mathieu-Daudé
  2020-10-07  8:39 ` [PATCH V13 7/9] hw/mips: Implement fw_cfg_arch_key_name() Huacai Chen
                   ` (2 subsequent siblings)
  8 siblings, 1 reply; 34+ messages in thread
From: Huacai Chen @ 2020-10-07  8:39 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, Aleksandar Markovic
  Cc: Aleksandar Rikalo, Huacai Chen, qemu-devel, Jiaxun Yang,
	Huacai Chen, Aurelien Jarno

From: Jiaxun Yang <jiaxun.yang@flygoat.com>

LDC2/SDC2 opcodes have been rewritten as "load & store with offset"
group of instructions by loongson-ext ASE.

This patch add implementation of these instructions:
gslbx: load 1 bytes to GPR
gslhx: load 2 bytes to GPR
gslwx: load 4 bytes to GPR
gsldx: load 8 bytes to GPR
gslwxc1: load 4 bytes to FPR
gsldxc1: load 8 bytes to FPR
gssbx: store 1 bytes from GPR
gsshx: store 2 bytes from GPR
gsswx: store 4 bytes from GPR
gssdx: store 8 bytes from GPR
gsswxc1: store 4 bytes from FPR
gssdxc1: store 8 bytes from FPR

Details of Loongson-EXT is here:
https://github.com/FlyGoat/loongson-insn/blob/master/loongson-ext.md

Signed-off-by: Huacai Chen <chenhc@lemote.com>
Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
---
 target/mips/translate.c | 179 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 179 insertions(+)

diff --git a/target/mips/translate.c b/target/mips/translate.c
index 916b57f..4d42cfc 100644
--- a/target/mips/translate.c
+++ b/target/mips/translate.c
@@ -484,6 +484,24 @@ enum {
     OPC_GSSDRC1     = 0x7 | OPC_GSSHFS,
 };
 
+/* Loongson EXT LDC2/SDC2 opcodes */
+#define MASK_LOONGSON_LSDC2(op)           (MASK_OP_MAJOR(op) | (op & 0x7))
+
+enum {
+    OPC_GSLBX      = 0x0 | OPC_LDC2,
+    OPC_GSLHX      = 0x1 | OPC_LDC2,
+    OPC_GSLWX      = 0x2 | OPC_LDC2,
+    OPC_GSLDX      = 0x3 | OPC_LDC2,
+    OPC_GSLWXC1    = 0x6 | OPC_LDC2,
+    OPC_GSLDXC1    = 0x7 | OPC_LDC2,
+    OPC_GSSBX      = 0x0 | OPC_SDC2,
+    OPC_GSSHX      = 0x1 | OPC_SDC2,
+    OPC_GSSWX      = 0x2 | OPC_SDC2,
+    OPC_GSSDX      = 0x3 | OPC_SDC2,
+    OPC_GSSWXC1    = 0x6 | OPC_SDC2,
+    OPC_GSSDXC1    = 0x7 | OPC_SDC2,
+};
+
 /* BSHFL opcodes */
 #define MASK_BSHFL(op)              (MASK_SPECIAL3(op) | (op & (0x1F << 6)))
 
@@ -6172,6 +6190,165 @@ static void gen_loongson_lswc2(DisasContext *ctx, int rt,
     tcg_temp_free(t0);
 }
 
+/* Loongson EXT LDC2/SDC2 */
+static void gen_loongson_lsdc2(DisasContext *ctx, int rt,
+                                int rs, int rd)
+{
+    int offset = (int8_t)(ctx->opcode >> 3);
+    uint32_t opc = MASK_LOONGSON_LSDC2(ctx->opcode);
+    TCGv t0, t1;
+    TCGv_i32 fp0;
+
+    /* Pre-conditions */
+    switch (opc) {
+    case OPC_GSLBX:
+    case OPC_GSLHX:
+    case OPC_GSLWX:
+    case OPC_GSLDX:
+        /* prefetch, implement as NOP */
+        if (rt == 0) {
+            return;
+        }
+        break;
+    case OPC_GSSBX:
+    case OPC_GSSHX:
+    case OPC_GSSWX:
+    case OPC_GSSDX:
+        break;
+    case OPC_GSLWXC1:
+#if defined(TARGET_MIPS64)
+    case OPC_GSLDXC1:
+#endif
+        check_cp1_enabled(ctx);
+        /* prefetch, implement as NOP */
+        if (rt == 0) {
+            return;
+        }
+        break;
+    case OPC_GSSWXC1:
+#if defined(TARGET_MIPS64)
+    case OPC_GSSDXC1:
+#endif
+        check_cp1_enabled(ctx);
+        break;
+    default:
+        MIPS_INVAL("loongson_lsdc2");
+        generate_exception_end(ctx, EXCP_RI);
+        return;
+        break;
+    }
+
+    t0 = tcg_temp_new();
+
+    gen_base_offset_addr(ctx, t0, rs, offset);
+    gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0);
+
+    switch (opc) {
+    case OPC_GSLBX:
+        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_SB);
+        gen_store_gpr(t0, rt);
+        break;
+    case OPC_GSLHX:
+        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESW |
+                            ctx->default_tcg_memop_mask);
+        gen_store_gpr(t0, rt);
+        break;
+    case OPC_GSLWX:
+        gen_base_offset_addr(ctx, t0, rs, offset);
+        if (rd) {
+            gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0);
+        }
+        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESL |
+                            ctx->default_tcg_memop_mask);
+        gen_store_gpr(t0, rt);
+        break;
+#if defined(TARGET_MIPS64)
+    case OPC_GSLDX:
+        gen_base_offset_addr(ctx, t0, rs, offset);
+        if (rd) {
+            gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0);
+        }
+        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ |
+                            ctx->default_tcg_memop_mask);
+        gen_store_gpr(t0, rt);
+        break;
+#endif
+    case OPC_GSLWXC1:
+        check_cp1_enabled(ctx);
+        gen_base_offset_addr(ctx, t0, rs, offset);
+        if (rd) {
+            gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0);
+        }
+        fp0 = tcg_temp_new_i32();
+        tcg_gen_qemu_ld_i32(fp0, t0, ctx->mem_idx, MO_TESL |
+                            ctx->default_tcg_memop_mask);
+        gen_store_fpr32(ctx, fp0, rt);
+        tcg_temp_free_i32(fp0);
+        break;
+#if defined(TARGET_MIPS64)
+    case OPC_GSLDXC1:
+        check_cp1_enabled(ctx);
+        gen_base_offset_addr(ctx, t0, rs, offset);
+        if (rd) {
+            gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0);
+        }
+        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ |
+                            ctx->default_tcg_memop_mask);
+        gen_store_fpr64(ctx, t0, rt);
+        break;
+#endif
+    case OPC_GSSBX:
+        t1 = tcg_temp_new();
+        gen_load_gpr(t1, rt);
+        tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_SB);
+        tcg_temp_free(t1);
+        break;
+    case OPC_GSSHX:
+        t1 = tcg_temp_new();
+        gen_load_gpr(t1, rt);
+        tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUW |
+                            ctx->default_tcg_memop_mask);
+        tcg_temp_free(t1);
+        break;
+    case OPC_GSSWX:
+        t1 = tcg_temp_new();
+        gen_load_gpr(t1, rt);
+        tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL |
+                            ctx->default_tcg_memop_mask);
+        tcg_temp_free(t1);
+        break;
+#if defined(TARGET_MIPS64)
+    case OPC_GSSDX:
+        t1 = tcg_temp_new();
+        gen_load_gpr(t1, rt);
+        tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEQ |
+                            ctx->default_tcg_memop_mask);
+        tcg_temp_free(t1);
+        break;
+#endif
+    case OPC_GSSWXC1:
+        fp0 = tcg_temp_new_i32();
+        gen_load_fpr32(ctx, fp0, rt);
+        tcg_gen_qemu_st_i32(fp0, t0, ctx->mem_idx, MO_TEUL |
+                            ctx->default_tcg_memop_mask);
+        tcg_temp_free_i32(fp0);
+        break;
+#if defined(TARGET_MIPS64)
+    case OPC_GSSDXC1:
+        t1 = tcg_temp_new();
+        gen_load_fpr64(ctx, t1, rt);
+        tcg_gen_qemu_st_i64(t1, t0, ctx->mem_idx, MO_TEQ |
+                            ctx->default_tcg_memop_mask);
+        tcg_temp_free(t1);
+        break;
+#endif
+    default:
+        break;
+    }
+
+    tcg_temp_free(t0);
+}
+
 /* Traps */
 static void gen_trap(DisasContext *ctx, uint32_t opc,
                      int rs, int rt, int16_t imm)
@@ -31055,6 +31232,8 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx)
                 /* OPC_JIC, OPC_JIALC */
                 gen_compute_compact_branch(ctx, op, 0, rt, imm);
             }
+        } else if (ctx->insn_flags & ASE_LEXT) {
+            gen_loongson_lsdc2(ctx, rt, rs, rd);
         } else {
             /* OPC_LWC2, OPC_SWC2 */
             /* COP2: Not implemented. */
-- 
2.7.0



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

* [PATCH V13 7/9] hw/mips: Implement fw_cfg_arch_key_name()
  2020-10-07  8:39 [PATCH V13 0/9] mips: Add Loongson-3 machine support Huacai Chen
                   ` (5 preceding siblings ...)
  2020-10-07  8:39 ` [PATCH V13 6/9] target/mips: Add loongson-ext lsdc2 group of instructions Huacai Chen
@ 2020-10-07  8:39 ` Huacai Chen
  2020-10-07  8:39 ` [PATCH V13 8/9] hw/mips: Add Loongson-3 machine support Huacai Chen
  2020-10-07  8:39 ` [PATCH V13 9/9] docs/system: Update MIPS machine documentation Huacai Chen
  8 siblings, 0 replies; 34+ messages in thread
From: Huacai Chen @ 2020-10-07  8:39 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, Aleksandar Markovic
  Cc: Aleksandar Rikalo, Huacai Chen, qemu-devel, Jiaxun Yang,
	Huacai Chen, Aurelien Jarno

Implement fw_cfg_arch_key_name(), which returns the name of a
mips-specific key.

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Signed-off-by: Huacai Chen <chenhc@lemote.com>
Co-developed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
---
 hw/mips/fw_cfg.c    | 35 +++++++++++++++++++++++++++++++++++
 hw/mips/fw_cfg.h    | 19 +++++++++++++++++++
 hw/mips/meson.build |  2 +-
 3 files changed, 55 insertions(+), 1 deletion(-)
 create mode 100644 hw/mips/fw_cfg.c
 create mode 100644 hw/mips/fw_cfg.h

diff --git a/hw/mips/fw_cfg.c b/hw/mips/fw_cfg.c
new file mode 100644
index 0000000..67c4a74
--- /dev/null
+++ b/hw/mips/fw_cfg.c
@@ -0,0 +1,35 @@
+/*
+ * QEMU fw_cfg helpers (MIPS specific)
+ *
+ * Copyright (c) 2020 Lemote, Inc.
+ *
+ * Author:
+ *   Huacai Chen (chenhc@lemote.com)
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/mips/fw_cfg.h"
+#include "hw/nvram/fw_cfg.h"
+
+const char *fw_cfg_arch_key_name(uint16_t key)
+{
+    static const struct {
+        uint16_t key;
+        const char *name;
+    } fw_cfg_arch_wellknown_keys[] = {
+        {FW_CFG_MACHINE_VERSION, "machine_version"},
+        {FW_CFG_CPU_FREQ, "cpu_frequency"},
+    };
+
+    for (size_t i = 0; i < ARRAY_SIZE(fw_cfg_arch_wellknown_keys); i++) {
+        if (fw_cfg_arch_wellknown_keys[i].key == key) {
+            return fw_cfg_arch_wellknown_keys[i].name;
+        }
+    }
+    return NULL;
+}
diff --git a/hw/mips/fw_cfg.h b/hw/mips/fw_cfg.h
new file mode 100644
index 0000000..e317d5b
--- /dev/null
+++ b/hw/mips/fw_cfg.h
@@ -0,0 +1,19 @@
+/*
+ * QEMU fw_cfg helpers (MIPS specific)
+ *
+ * Copyright (c) 2020 Huacai Chen
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#ifndef HW_MIPS_FW_CFG_H
+#define HW_MIPS_FW_CFG_H
+
+#include "hw/boards.h"
+#include "hw/nvram/fw_cfg.h"
+
+/* Data for BIOS to identify machine */
+#define FW_CFG_MACHINE_VERSION  (FW_CFG_ARCH_LOCAL + 0)
+#define FW_CFG_CPU_FREQ         (FW_CFG_ARCH_LOCAL + 1)
+
+#endif
diff --git a/hw/mips/meson.build b/hw/mips/meson.build
index 46294b7..c98391c 100644
--- a/hw/mips/meson.build
+++ b/hw/mips/meson.build
@@ -1,5 +1,5 @@
 mips_ss = ss.source_set()
-mips_ss.add(files('addr.c', 'mips_int.c'))
+mips_ss.add(files('addr.c', 'mips_int.c', 'fw_cfg.c'))
 mips_ss.add(when: 'CONFIG_FULOONG', if_true: files('fuloong2e.c'))
 mips_ss.add(when: 'CONFIG_JAZZ', if_true: files('jazz.c'))
 mips_ss.add(when: 'CONFIG_MALTA', if_true: files('gt64xxx_pci.c', 'malta.c'))
-- 
2.7.0



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

* [PATCH V13 8/9] hw/mips: Add Loongson-3 machine support
  2020-10-07  8:39 [PATCH V13 0/9] mips: Add Loongson-3 machine support Huacai Chen
                   ` (6 preceding siblings ...)
  2020-10-07  8:39 ` [PATCH V13 7/9] hw/mips: Implement fw_cfg_arch_key_name() Huacai Chen
@ 2020-10-07  8:39 ` Huacai Chen
  2020-10-10  9:09   ` Philippe Mathieu-Daudé
  2020-10-07  8:39 ` [PATCH V13 9/9] docs/system: Update MIPS machine documentation Huacai Chen
  8 siblings, 1 reply; 34+ messages in thread
From: Huacai Chen @ 2020-10-07  8:39 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, Aleksandar Markovic
  Cc: Aleksandar Rikalo, Huacai Chen, qemu-devel, Jiaxun Yang,
	Huacai Chen, Aurelien Jarno

Add Loongson-3 based machine support, it use liointc as the interrupt
controler and use GPEX as the pci controller. Currently it can work with
both TCG and KVM.

As the machine model is not based on any exiting physical hardware, the
name of the machine is "loongson3-virt". It may be superseded in future
by a real machine model. If this happens, then a regular deprecation
procedure shall occur for "loongson3-virt" machine.

We now already have a full functional Linux kernel (based on Linux-5.4.x
LTS, the kvm host side and guest side have both been upstream for Linux-
5.9, but Linux-5.9 has not been released yet) here:

https://github.com/chenhuacai/linux

Of course the upstream kernel is also usable (though it is "unstable"
now):

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git

How to use QEMU/Loongson-3?
1, Download kernel source from the above URL;
2, Build a kernel with arch/mips/configs/loongson3_defconfig;
3, Boot a Loongson-3A4000 host with this kernel (for KVM mode);
4, Build QEMU-master with this patchset;
5, modprobe kvm (only necessary for KVM mode);
6, Use QEMU with TCG:
       qemu-system-mips64el -M loongson3-virt,accel=tcg -cpu Loongson-3A1000 -kernel <path_to_kernel> -append ...
   Use QEMU with KVM:
       qemu-system-mips64el -M loongson3-virt,accel=kvm -cpu Loongson-3A4000 -kernel <path_to_kernel> -append ...

   The "-cpu" parameter is optional here and QEMU will use the correct type for TCG/KVM automatically.

Signed-off-by: Huacai Chen <chenhc@lemote.com>
Co-developed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
---
 default-configs/devices/mips64el-softmmu.mak |   1 +
 hw/mips/Kconfig                              |  12 +
 hw/mips/loongson3_bootp.c                    | 162 +++++++
 hw/mips/loongson3_bootp.h                    | 225 ++++++++++
 hw/mips/loongson3_virt.c                     | 615 +++++++++++++++++++++++++++
 hw/mips/meson.build                          |   1 +
 6 files changed, 1016 insertions(+)
 create mode 100644 hw/mips/loongson3_bootp.c
 create mode 100644 hw/mips/loongson3_bootp.h
 create mode 100644 hw/mips/loongson3_virt.c

diff --git a/default-configs/devices/mips64el-softmmu.mak b/default-configs/devices/mips64el-softmmu.mak
index 9f8a3ef..26c660a 100644
--- a/default-configs/devices/mips64el-softmmu.mak
+++ b/default-configs/devices/mips64el-softmmu.mak
@@ -3,6 +3,7 @@
 include mips-softmmu-common.mak
 CONFIG_IDE_VIA=y
 CONFIG_FULOONG=y
+CONFIG_LOONGSON3V=y
 CONFIG_ATI_VGA=y
 CONFIG_RTL8139_PCI=y
 CONFIG_JAZZ=y
diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig
index 67d39c5..6562b34 100644
--- a/hw/mips/Kconfig
+++ b/hw/mips/Kconfig
@@ -45,6 +45,18 @@ config FULOONG
     bool
     select PCI_BONITO
 
+config LOONGSON3V
+    bool
+    select PCKBD
+    select SERIAL
+    select GOLDFISH_RTC
+    select LOONGSON_LIOINTC
+    select PCI_DEVICES
+    select PCI_EXPRESS_GENERIC_BRIDGE
+    select VIRTIO_VGA
+    select QXL if SPICE
+    select MSI_NONBROKEN
+
 config MIPS_CPS
     bool
     select PTIMER
diff --git a/hw/mips/loongson3_bootp.c b/hw/mips/loongson3_bootp.c
new file mode 100644
index 0000000..1f11acf
--- /dev/null
+++ b/hw/mips/loongson3_bootp.c
@@ -0,0 +1,162 @@
+/*
+ * LEFI (a UEFI-like interface for BIOS-Kernel boot parameters) helpers
+ *
+ * Copyright (c) 2017-2020 Huacai Chen (chenhc@lemote.com)
+ * Copyright (c) 2017-2020 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ *
+ * 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, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "qemu/cutils.h"
+#include "cpu.h"
+#include "hw/boards.h"
+#include "hw/mips/loongson3_bootp.h"
+
+static struct efi_cpuinfo_loongson *init_cpu_info(void *g_cpuinfo, uint64_t cpu_freq)
+{
+    struct efi_cpuinfo_loongson *c = g_cpuinfo;
+
+    stl_le_p(&c->cputype, Loongson_3A);
+    stl_le_p(&c->processor_id, MIPS_CPU(first_cpu)->env.CP0_PRid);
+    if (cpu_freq > UINT_MAX) {
+        stl_le_p(&c->cpu_clock_freq, UINT_MAX);
+    } else {
+        stl_le_p(&c->cpu_clock_freq, cpu_freq);
+    }
+
+    stw_le_p(&c->cpu_startup_core_id, 0);
+    stl_le_p(&c->nr_cpus, current_machine->smp.cpus);
+    stl_le_p(&c->total_node, (current_machine->smp.cpus + 3) / 4);
+
+    return c;
+}
+
+static struct efi_memory_map_loongson *init_memory_map(void *g_map, uint64_t ram_size)
+{
+    struct efi_memory_map_loongson *emap = g_map;
+
+    stl_le_p(&emap->nr_map, 2);
+    stl_le_p(&emap->mem_freq, 300000000);
+
+    stl_le_p(&emap->map[0].node_id, 0);
+    stl_le_p(&emap->map[0].mem_type, 1);
+    stq_le_p(&emap->map[0].mem_start, 0x0);
+    stl_le_p(&emap->map[0].mem_size, 240);
+
+    stl_le_p(&emap->map[1].node_id, 0);
+    stl_le_p(&emap->map[1].mem_type, 2);
+    stq_le_p(&emap->map[1].mem_start, 0x90000000);
+    stl_le_p(&emap->map[1].mem_size, (ram_size / MiB) - 256);
+
+    return emap;
+}
+
+static struct system_loongson *init_system_loongson(void *g_system)
+{
+    struct system_loongson *s = g_system;
+
+    stl_le_p(&s->ccnuma_smp, 0);
+    stl_le_p(&s->sing_double_channel, 1);
+    stl_le_p(&s->nr_uarts, 1);
+    stl_le_p(&s->uarts[0].iotype, 2);
+    stl_le_p(&s->uarts[0].int_offset, 2);
+    stl_le_p(&s->uarts[0].uartclk, 25000000); /* Random value */
+    stq_le_p(&s->uarts[0].uart_base, virt_memmap[VIRT_UART].base);
+
+    return s;
+}
+
+static struct irq_source_routing_table *init_irq_source(void *g_irq_source)
+{
+    struct irq_source_routing_table *irq_info = g_irq_source;
+
+    stl_le_p(&irq_info->node_id, 0);
+    stl_le_p(&irq_info->PIC_type, 0);
+    stw_le_p(&irq_info->dma_mask_bits, 64);
+    stq_le_p(&irq_info->pci_mem_start_addr, virt_memmap[VIRT_PCIE_MMIO].base);
+    stq_le_p(&irq_info->pci_mem_end_addr, virt_memmap[VIRT_PCIE_MMIO].base +
+                                          virt_memmap[VIRT_PCIE_MMIO].size - 1);
+    stq_le_p(&irq_info->pci_io_start_addr, virt_memmap[VIRT_PCIE_PIO].base);
+
+    return irq_info;
+}
+
+static struct interface_info *init_interface_info(void *g_interface)
+{
+    struct interface_info *interface = g_interface;
+
+    stw_le_p(&interface->vers, 0x01);
+    strpadcpy(interface->description, 64, "UEFI_Version_v1.0", '\0');
+
+    return interface;
+}
+
+static struct board_devices *board_devices_info(void *g_board)
+{
+    struct board_devices *bd = g_board;
+
+    strpadcpy(bd->name, 64, "Loongson-3A-VIRT-1w-V1.00-demo", '\0');
+
+    return bd;
+}
+
+static struct loongson_special_attribute *init_special_info(void *g_special)
+{
+    struct loongson_special_attribute *special = g_special;
+
+    strpadcpy(special->special_name, 64, "2017-09-06", '\0');
+
+    return special;
+}
+
+void init_loongson_params(struct loongson_params *lp, void *p,
+                          uint64_t cpu_freq, uint64_t ram_size)
+{
+    stq_le_p(&lp->cpu_offset,
+              (uintptr_t)init_cpu_info(p, cpu_freq) - (uintptr_t)lp);
+    p += ROUND_UP(sizeof(struct efi_cpuinfo_loongson), 64);
+
+    stq_le_p(&lp->memory_offset,
+              (uintptr_t)init_memory_map(p, ram_size) - (uintptr_t)lp);
+    p += ROUND_UP(sizeof(struct efi_memory_map_loongson), 64);
+
+    stq_le_p(&lp->system_offset,
+              (uintptr_t)init_system_loongson(p) - (uintptr_t)lp);
+    p += ROUND_UP(sizeof(struct system_loongson), 64);
+
+    stq_le_p(&lp->irq_offset,
+              (uintptr_t)init_irq_source(p) - (uintptr_t)lp);
+    p += ROUND_UP(sizeof(struct irq_source_routing_table), 64);
+
+    stq_le_p(&lp->interface_offset,
+              (uintptr_t)init_interface_info(p) - (uintptr_t)lp);
+    p += ROUND_UP(sizeof(struct interface_info), 64);
+
+    stq_le_p(&lp->boarddev_table_offset,
+              (uintptr_t)board_devices_info(p) - (uintptr_t)lp);
+    p += ROUND_UP(sizeof(struct board_devices), 64);
+
+    stq_le_p(&lp->special_offset,
+              (uintptr_t)init_special_info(p) - (uintptr_t)lp);
+    p += ROUND_UP(sizeof(struct loongson_special_attribute), 64);
+}
+
+void init_reset_system(struct efi_reset_system_t *reset)
+{
+    stq_le_p(&reset->Shutdown, 0xffffffffbfc000a8);
+    stq_le_p(&reset->ResetCold, 0xffffffffbfc00080);
+    stq_le_p(&reset->ResetWarm, 0xffffffffbfc00080);
+}
diff --git a/hw/mips/loongson3_bootp.h b/hw/mips/loongson3_bootp.h
new file mode 100644
index 0000000..1edd736
--- /dev/null
+++ b/hw/mips/loongson3_bootp.h
@@ -0,0 +1,225 @@
+/*
+ * LEFI (a UEFI-like interface for BIOS-Kernel boot parameters) data structrues
+ * defined at arch/mips/include/asm/mach-loongson64/boot_param.h in Linux kernel
+ */
+
+#ifndef HW_MIPS_LOONGSON3_BOOTP_H
+#define HW_MIPS_LOONGSON3_BOOTP_H
+
+struct efi_memory_map_loongson {
+    uint16_t vers;               /* version of efi_memory_map */
+    uint32_t nr_map;             /* number of memory_maps */
+    uint32_t mem_freq;           /* memory frequence */
+    struct mem_map {
+        uint32_t node_id;        /* node_id which memory attached to */
+        uint32_t mem_type;       /* system memory, pci memory, pci io, etc. */
+        uint64_t mem_start;      /* memory map start address */
+        uint32_t mem_size;       /* each memory_map size, not the total size */
+    } map[128];
+} QEMU_PACKED;
+
+enum loongson_cpu_type {
+    Legacy_2E = 0x0,
+    Legacy_2F = 0x1,
+    Legacy_3A = 0x2,
+    Legacy_3B = 0x3,
+    Legacy_1A = 0x4,
+    Legacy_1B = 0x5,
+    Legacy_2G = 0x6,
+    Legacy_2H = 0x7,
+    Loongson_1A = 0x100,
+    Loongson_1B = 0x101,
+    Loongson_2E = 0x200,
+    Loongson_2F = 0x201,
+    Loongson_2G = 0x202,
+    Loongson_2H = 0x203,
+    Loongson_3A = 0x300,
+    Loongson_3B = 0x301
+};
+
+/*
+ * Capability and feature descriptor structure for MIPS CPU
+ */
+struct efi_cpuinfo_loongson {
+    uint16_t vers;               /* version of efi_cpuinfo_loongson */
+    uint32_t processor_id;       /* PRID, e.g. 6305, 6306 */
+    uint32_t cputype;            /* Loongson_3A/3B, etc. */
+    uint32_t total_node;         /* num of total numa nodes */
+    uint16_t cpu_startup_core_id;   /* Boot core id */
+    uint16_t reserved_cores_mask;
+    uint32_t cpu_clock_freq;     /* cpu_clock */
+    uint32_t nr_cpus;
+    char cpuname[64];
+} QEMU_PACKED;
+
+#define MAX_UARTS 64
+struct uart_device {
+    uint32_t iotype;
+    uint32_t uartclk;
+    uint32_t int_offset;
+    uint64_t uart_base;
+} QEMU_PACKED;
+
+#define MAX_SENSORS 64
+#define SENSOR_TEMPER  0x00000001
+#define SENSOR_VOLTAGE 0x00000002
+#define SENSOR_FAN     0x00000004
+struct sensor_device {
+    char name[32];  /* a formal name */
+    char label[64]; /* a flexible description */
+    uint32_t type;       /* SENSOR_* */
+    uint32_t id;         /* instance id of a sensor-class */
+    uint32_t fan_policy; /* step speed or constant speed */
+    uint32_t fan_percent;/* only for constant speed policy */
+    uint64_t base_addr;  /* base address of device registers */
+} QEMU_PACKED;
+
+struct system_loongson {
+    uint16_t vers;               /* version of system_loongson */
+    uint32_t ccnuma_smp;         /* 0: no numa; 1: has numa */
+    uint32_t sing_double_channel;/* 1: single; 2: double */
+    uint32_t nr_uarts;
+    struct uart_device uarts[MAX_UARTS];
+    uint32_t nr_sensors;
+    struct sensor_device sensors[MAX_SENSORS];
+    char has_ec;
+    char ec_name[32];
+    uint64_t ec_base_addr;
+    char has_tcm;
+    char tcm_name[32];
+    uint64_t tcm_base_addr;
+    uint64_t workarounds;
+    uint64_t of_dtb_addr; /* NULL if not support */
+} QEMU_PACKED;
+
+struct irq_source_routing_table {
+    uint16_t vers;
+    uint16_t size;
+    uint16_t rtr_bus;
+    uint16_t rtr_devfn;
+    uint32_t vendor;
+    uint32_t device;
+    uint32_t PIC_type;           /* conform use HT or PCI to route to CPU-PIC */
+    uint64_t ht_int_bit;         /* 3A: 1<<24; 3B: 1<<16 */
+    uint64_t ht_enable;          /* irqs used in this PIC */
+    uint32_t node_id;            /* node id: 0x0-0; 0x1-1; 0x10-2; 0x11-3 */
+    uint64_t pci_mem_start_addr;
+    uint64_t pci_mem_end_addr;
+    uint64_t pci_io_start_addr;
+    uint64_t pci_io_end_addr;
+    uint64_t pci_config_addr;
+    uint16_t dma_mask_bits;
+    uint16_t dma_noncoherent;
+} QEMU_PACKED;
+
+struct interface_info {
+    uint16_t vers;               /* version of the specificition */
+    uint16_t size;
+    uint8_t  flag;
+    char description[64];
+} QEMU_PACKED;
+
+#define MAX_RESOURCE_NUMBER 128
+struct resource_loongson {
+    uint64_t start;              /* resource start address */
+    uint64_t end;                /* resource end address */
+    char name[64];
+    uint32_t flags;
+};
+
+struct archdev_data {};          /* arch specific additions */
+
+struct board_devices {
+    char name[64];               /* hold the device name */
+    uint32_t num_resources;      /* number of device_resource */
+    /* for each device's resource */
+    struct resource_loongson resource[MAX_RESOURCE_NUMBER];
+    /* arch specific additions */
+    struct archdev_data archdata;
+};
+
+struct loongson_special_attribute {
+    uint16_t vers;               /* version of this special */
+    char special_name[64];       /* special_atribute_name */
+    uint32_t loongson_special_type; /* type of special device */
+    /* for each device's resource */
+    struct resource_loongson resource[MAX_RESOURCE_NUMBER];
+};
+
+struct loongson_params {
+    uint64_t memory_offset;      /* efi_memory_map_loongson struct offset */
+    uint64_t cpu_offset;         /* efi_cpuinfo_loongson struct offset */
+    uint64_t system_offset;      /* system_loongson struct offset */
+    uint64_t irq_offset;         /* irq_source_routing_table struct offset */
+    uint64_t interface_offset;   /* interface_info struct offset */
+    uint64_t special_offset;     /* loongson_special_attribute struct offset */
+    uint64_t boarddev_table_offset;  /* board_devices offset */
+};
+
+struct smbios_tables {
+    uint16_t vers;               /* version of smbios */
+    uint64_t vga_bios;           /* vga_bios address */
+    struct loongson_params lp;
+};
+
+struct efi_reset_system_t {
+    uint64_t ResetCold;
+    uint64_t ResetWarm;
+    uint64_t ResetType;
+    uint64_t Shutdown;
+    uint64_t DoSuspend; /* NULL if not support */
+};
+
+struct efi_loongson {
+    uint64_t mps;                /* MPS table */
+    uint64_t acpi;               /* ACPI table (IA64 ext 0.71) */
+    uint64_t acpi20;             /* ACPI table (ACPI 2.0) */
+    struct smbios_tables smbios; /* SM BIOS table */
+    uint64_t sal_systab;         /* SAL system table */
+    uint64_t boot_info;          /* boot info table */
+};
+
+struct boot_params {
+    struct efi_loongson efi;
+    struct efi_reset_system_t reset_system;
+};
+
+/* Overall MMIO & Memory layout */
+enum {
+    VIRT_LOWMEM,
+    VIRT_PM,
+    VIRT_FW_CFG,
+    VIRT_RTC,
+    VIRT_PCIE_PIO,
+    VIRT_PCIE_ECAM,
+    VIRT_BIOS_ROM,
+    VIRT_UART,
+    VIRT_LIOINTC,
+    VIRT_PCIE_MMIO,
+    VIRT_HIGHMEM
+};
+
+/* Low MEM layout for QEMU kernel loader */
+enum {
+    LOADER_KERNEL,
+    LOADER_INITRD,
+    LOADER_CMDLINE
+};
+
+/* BIOS ROM layout for QEMU kernel loader */
+enum {
+    LOADER_BOOTROM,
+    LOADER_PARAM,
+};
+
+struct MemmapEntry {
+    hwaddr base;
+    hwaddr size;
+};
+
+extern const struct MemmapEntry virt_memmap[];
+void init_loongson_params(struct loongson_params *lp, void *p,
+                          uint64_t cpu_freq, uint64_t ram_size);
+void init_reset_system(struct efi_reset_system_t *reset);
+
+#endif
diff --git a/hw/mips/loongson3_virt.c b/hw/mips/loongson3_virt.c
new file mode 100644
index 0000000..4e573d6
--- /dev/null
+++ b/hw/mips/loongson3_virt.c
@@ -0,0 +1,615 @@
+/*
+ * Generic Loongson-3 Platform support
+ *
+ * Copyright (c) 2017-2020 Huacai Chen (chenhc@lemote.com)
+ * Copyright (c) 2017-2020 Jiaxun Yang <jiaxun.yang@flygoat.com>
+ *
+ * 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, see <https://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Generic virtualized PC Platform based on Loongson-3 CPU (MIPS64R2 with
+ * extensions, 800~2000MHz)
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "qemu/units.h"
+#include "qemu/cutils.h"
+#include "qapi/error.h"
+#include "cpu.h"
+#include "elf.h"
+#include "kvm_mips.h"
+#include "hw/boards.h"
+#include "hw/char/serial.h"
+#include "hw/mips/mips.h"
+#include "hw/mips/cpudevs.h"
+#include "hw/mips/fw_cfg.h"
+#include "hw/mips/loongson3_bootp.h"
+#include "hw/misc/unimp.h"
+#include "hw/intc/i8259.h"
+#include "hw/loader.h"
+#include "hw/isa/superio.h"
+#include "hw/pci/msi.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/pci_host.h"
+#include "hw/pci-host/gpex.h"
+#include "hw/rtc/mc146818rtc.h"
+#include "hw/usb.h"
+#include "net/net.h"
+#include "exec/address-spaces.h"
+#include "sysemu/kvm.h"
+#include "sysemu/qtest.h"
+#include "sysemu/reset.h"
+#include "sysemu/runstate.h"
+#include "qemu/log.h"
+#include "qemu/error-report.h"
+
+#define PM_CNTL_MODE          0x10
+
+#define LOONGSON_MAX_VCPUS      16
+
+#define LOONGSON3_BIOSNAME "bios_loongson3.bin"
+
+#define UART_IRQ            0
+#define RTC_IRQ             1
+#define PCIE_IRQ_BASE       2
+
+const struct MemmapEntry virt_memmap[] = {
+    [VIRT_LOWMEM] =      { 0x00000000,    0x10000000 },
+    [VIRT_PM] =          { 0x10080000,         0x100 },
+    [VIRT_FW_CFG] =      { 0x10080100,         0x100 },
+    [VIRT_RTC] =         { 0x10081000,        0x1000 },
+    [VIRT_PCIE_PIO] =    { 0x18000000,       0x80000 },
+    [VIRT_PCIE_ECAM] =   { 0x1a000000,     0x2000000 },
+    [VIRT_BIOS_ROM] =    { 0x1fc00000,      0x200000 },
+    [VIRT_UART] =        { 0x1fe001e0,           0x8 },
+    [VIRT_LIOINTC] =     { 0x3ff01400,          0x64 },
+    [VIRT_PCIE_MMIO] =   { 0x40000000,    0x40000000 },
+    [VIRT_HIGHMEM] =     { 0x80000000,           0x0 }, /* Variable */
+};
+
+static const struct MemmapEntry loader_memmap[] = {
+    [LOADER_KERNEL] =    { 0x00000000,     0x4000000 },
+    [LOADER_INITRD] =    { 0x04000000,           0x0 }, /* Variable */
+    [LOADER_CMDLINE] =   { 0x0ff00000,      0x100000 },
+};
+
+static const struct MemmapEntry loader_rommap[] = {
+    [LOADER_BOOTROM] =   { 0x1fc00000,        0x1000 },
+    [LOADER_PARAM] =     { 0x1fc01000,       0x10000 },
+};
+
+static struct _loaderparams {
+    uint64_t cpu_freq;
+    uint64_t ram_size;
+    const char *kernel_cmdline;
+    const char *kernel_filename;
+    const char *initrd_filename;
+    uint64_t kernel_entry;
+    uint64_t a0, a1, a2;
+} loaderparams;
+
+static uint64_t loongson3_pm_read(void *opaque, hwaddr addr, unsigned size)
+{
+    return 0;
+}
+
+static void loongson3_pm_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
+{
+    if (addr != PM_CNTL_MODE) {
+        return;
+    }
+
+    switch (val) {
+    case 0x00:
+        qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
+        return;
+    case 0xff:
+        qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
+        return;
+    default:
+        return;
+    }
+}
+
+static const MemoryRegionOps loongson3_pm_ops = {
+    .read  = loongson3_pm_read,
+    .write = loongson3_pm_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+#define DEF_TCG_FREQ (200 * 1000 * 1000)
+#define DEF_KVM_FREQ (1600 * 1000 * 1000)
+
+static uint64_t get_cpu_freq(void)
+{
+#ifdef CONFIG_KVM
+    int ret;
+    uint64_t freq;
+    struct kvm_one_reg freq_reg = {
+        .id = KVM_REG_MIPS_COUNT_HZ,
+        .addr = (uintptr_t)(&freq)
+    };
+
+    if (kvm_enabled()) {
+        ret = kvm_vcpu_ioctl(first_cpu, KVM_GET_ONE_REG, &freq_reg);
+        if (ret < 0) {
+            return DEF_KVM_FREQ;
+        }
+        return freq * 2;
+    } else {
+        /*
+         * TCG has a default CP0 Timer period 10 ns, which is 100MHz,
+         * CPU frequency is defined as double of CP0 timer frequency.
+         */
+        return DEF_TCG_FREQ;
+    }
+#else
+    return DEF_TCG_FREQ;
+#endif
+}
+
+static void init_boot_param(void)
+{
+    void *p;
+    struct boot_params *bp;
+
+    p = g_malloc0(loader_rommap[LOADER_PARAM].size);
+    bp = p;
+
+    stw_le_p(&bp->efi.smbios.vers, 1);
+    init_reset_system(&(bp->reset_system));
+    p += ROUND_UP(sizeof(struct boot_params), 64);
+    init_loongson_params(&(bp->efi.smbios.lp), p,
+                         loaderparams.cpu_freq, loaderparams.ram_size);
+
+    rom_add_blob_fixed("params_rom", bp,
+                       loader_rommap[LOADER_PARAM].size,
+                       loader_rommap[LOADER_PARAM].base);
+
+    g_free(bp);
+
+    loaderparams.a2 = cpu_mips_phys_to_kseg0(NULL, loader_rommap[LOADER_PARAM].base);
+}
+
+static void init_boot_rom(void)
+{
+    const unsigned int boot_code[] = {
+        0x40086000,   /* mfc0    t0, CP0_STATUS                               */
+        0x240900E4,   /* li      t1, 0xe4         #set kx, sx, ux, erl        */
+        0x01094025,   /* or      t0, t0, t1                                   */
+        0x3C090040,   /* lui     t1, 0x40         #set bev                    */
+        0x01094025,   /* or      t0, t0, t1                                   */
+        0x40886000,   /* mtc0    t0, CP0_STATUS                               */
+        0x00000000,
+        0x40806800,   /* mtc0    zero, CP0_CAUSE                              */
+        0x00000000,
+        0x400A7801,   /* mfc0    t2, $15, 1                                   */
+        0x314A00FF,   /* andi    t2, 0x0ff                                    */
+        0x3C089000,   /* dli     t0, 0x900000003ff01000                       */
+        0x00084438,
+        0x35083FF0,
+        0x00084438,
+        0x35081000,
+        0x314B0003,   /* andi    t3, t2, 0x3      #local cpuid                */
+        0x000B5A00,   /* sll     t3, 8                                        */
+        0x010B4025,   /* or      t0, t0, t3                                   */
+        0x314C000C,   /* andi    t4, t2, 0xc      #node id                    */
+        0x000C62BC,   /* dsll    t4, 42                                       */
+        0x010C4025,   /* or      t0, t0, t4                                   */
+                      /* WaitForInit:                                         */
+        0xDD020020,   /* ld      v0, FN_OFF(t0)   #FN_OFF 0x020               */
+        0x1040FFFE,   /* beqz    v0, WaitForInit                              */
+        0x00000000,   /* nop                                                  */
+        0xDD1D0028,   /* ld      sp, SP_OFF(t0)   #FN_OFF 0x028               */
+        0xDD1C0030,   /* ld      gp, GP_OFF(t0)   #FN_OFF 0x030               */
+        0xDD050038,   /* ld      a1, A1_OFF(t0)   #FN_OFF 0x038               */
+        0x00400008,   /* jr      v0               #byebye                     */
+        0x00000000,   /* nop                                                  */
+        0x1000FFFF,   /* 1:  b   1b                                           */
+        0x00000000,   /* nop                                                  */
+
+                      /* Reset                                                */
+        0x3C0C9000,   /* dli     t0, 0x9000000010080010                       */
+        0x358C0000,
+        0x000C6438,
+        0x358C1008,
+        0x000C6438,
+        0x358C0010,
+        0x240D0000,   /* li      t1, 0x00                                     */
+        0xA18D0000,   /* sb      t1, (t0)                                     */
+        0x1000FFFF,   /* 1:  b   1b                                           */
+        0x00000000,   /* nop                                                  */
+
+                      /* Shutdown                                             */
+        0x3C0C9000,   /* dli     t0, 0x9000000010080010                       */
+        0x358C0000,
+        0x000C6438,
+        0x358C1008,
+        0x000C6438,
+        0x358C0010,
+        0x240D00FF,   /* li      t1, 0xff                                     */
+        0xA18D0000,   /* sb      t1, (t0)                                     */
+        0x1000FFFF,   /* 1:  b   1b                                           */
+        0x00000000    /* nop                                                  */
+    };
+
+    rom_add_blob_fixed("boot_rom", boot_code, sizeof(boot_code),
+                        loader_rommap[LOADER_BOOTROM].base);
+}
+
+static void fw_cfg_boot_set(void *opaque, const char *boot_device,
+                            Error **errp)
+{
+    fw_cfg_modify_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
+}
+
+static void fw_conf_init(unsigned long ram_size)
+{
+    FWCfgState *fw_cfg;
+    hwaddr cfg_addr = virt_memmap[VIRT_FW_CFG].base;
+
+    fw_cfg = fw_cfg_init_mem_wide(cfg_addr, cfg_addr + 8, 8, 0, NULL);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)current_machine->smp.cpus);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)current_machine->smp.max_cpus);
+    fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_MACHINE_VERSION, 1);
+    fw_cfg_add_i64(fw_cfg, FW_CFG_CPU_FREQ, get_cpu_freq());
+    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
+}
+
+static int set_prom_cmdline(ram_addr_t initrd_offset, long initrd_size)
+{
+    hwaddr cmdline_vaddr;
+    char memenv[32];
+    char highmemenv[32];
+    void *cmdline_buf;
+    unsigned int *parg_env;
+    int ret = 0;
+
+    /* Allocate cmdline_buf for command line. */
+    cmdline_buf = g_malloc0(loader_memmap[LOADER_CMDLINE].size);
+    cmdline_vaddr = cpu_mips_phys_to_kseg0(NULL,
+                                           loader_memmap[LOADER_CMDLINE].base);
+
+    /*
+     * Layout of cmdline_buf looks like this:
+     * argv[0], argv[1], 0, env[0], env[1], ... env[i], 0,
+     * argv[0]'s data, argv[1]'s data, env[0]'data, ..., env[i]'s data, 0
+     */
+    parg_env = (void *)cmdline_buf;
+
+    ret = (3 + 1) * 4;
+    *parg_env++ = cmdline_vaddr + ret;
+    ret += (1 + snprintf(cmdline_buf + ret, 256 - ret, "g"));
+
+    /* argv1 */
+    *parg_env++ = cmdline_vaddr + ret;
+    if (initrd_size > 0)
+        ret += (1 + snprintf(cmdline_buf + ret, 256 - ret,
+                "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s",
+                cpu_mips_phys_to_kseg0(NULL, initrd_offset),
+                initrd_size, loaderparams.kernel_cmdline));
+    else
+        ret += (1 + snprintf(cmdline_buf + ret, 256 - ret, "%s",
+                loaderparams.kernel_cmdline));
+
+    /* argv2 */
+    *parg_env++ = cmdline_vaddr + 4 * ret;
+
+    /* env */
+    sprintf(memenv, "%d", 256);
+    sprintf(highmemenv, "%ld", (unsigned long)(loaderparams.ram_size / MiB) - 256);
+
+    rom_add_blob_fixed("cmdline", cmdline_buf,
+                       loader_memmap[LOADER_CMDLINE].size,
+                       loader_memmap[LOADER_CMDLINE].base);
+
+    g_free(cmdline_buf);
+
+    loaderparams.a0 = 2;
+    loaderparams.a1 = cmdline_vaddr;
+
+    return 0;
+}
+
+static uint64_t load_kernel(CPUMIPSState *env)
+{
+    long kernel_size;
+    ram_addr_t initrd_offset;
+    uint64_t kernel_entry, kernel_low, kernel_high, initrd_size;
+
+    kernel_size = load_elf(loaderparams.kernel_filename, NULL,
+                           cpu_mips_kseg0_to_phys, NULL,
+                           (uint64_t *)&kernel_entry,
+                           (uint64_t *)&kernel_low, (uint64_t *)&kernel_high,
+                           NULL, 0, EM_MIPS, 1, 0);
+    if (kernel_size < 0) {
+        error_report("could not load kernel '%s': %s",
+                     loaderparams.kernel_filename,
+                     load_elf_strerror(kernel_size));
+        exit(1);
+    }
+
+    /* load initrd */
+    initrd_size = 0;
+    initrd_offset = 0;
+    if (loaderparams.initrd_filename) {
+        initrd_size = get_image_size(loaderparams.initrd_filename);
+        if (initrd_size > 0) {
+            initrd_offset = (kernel_high + ~INITRD_PAGE_MASK) &
+                            INITRD_PAGE_MASK;
+            initrd_offset = MAX(initrd_offset,
+                                loader_memmap[LOADER_INITRD].base);
+
+            if (initrd_offset + initrd_size > ram_size) {
+                error_report("memory too small for initial ram disk '%s'",
+                             loaderparams.initrd_filename);
+                exit(1);
+            }
+
+            initrd_size = load_image_targphys(loaderparams.initrd_filename,
+                                              initrd_offset,
+                                              ram_size - initrd_offset);
+        }
+
+        if (initrd_size == (target_ulong) -1) {
+            error_report("could not load initial ram disk '%s'",
+                         loaderparams.initrd_filename);
+            exit(1);
+        }
+    }
+
+    /* Setup prom cmdline. */
+    set_prom_cmdline(initrd_offset, initrd_size);
+
+    return kernel_entry;
+}
+
+static void main_cpu_reset(void *opaque)
+{
+    MIPSCPU *cpu = opaque;
+    CPUMIPSState *env = &cpu->env;
+
+    cpu_reset(CPU(cpu));
+
+    /* Loongson-3 reset stuff */
+    if (loaderparams.kernel_filename) {
+        if (cpu == MIPS_CPU(first_cpu)) {
+            env->active_tc.gpr[4] = loaderparams.a0;
+            env->active_tc.gpr[5] = loaderparams.a1;
+            env->active_tc.gpr[6] = loaderparams.a2;
+            env->active_tc.PC = loaderparams.kernel_entry;
+        }
+        env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL));
+    }
+}
+
+static inline void loongson3_virt_devices_init(MachineState *machine, DeviceState *pic)
+{
+    int i;
+    qemu_irq irq;
+    PCIBus *pci_bus;
+    DeviceState *dev;
+    MemoryRegion *pio_alias;
+    MemoryRegion *mmio_alias, *mmio_reg;
+    MemoryRegion *ecam_alias, *ecam_reg;
+
+    dev = qdev_new(TYPE_GPEX_HOST);
+    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+    pci_bus = PCI_HOST_BRIDGE(dev)->bus;
+
+    ecam_alias = g_new0(MemoryRegion, 1);
+    ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
+    memory_region_init_alias(ecam_alias, OBJECT(dev), "pcie-ecam",
+                             ecam_reg, 0, virt_memmap[VIRT_PCIE_ECAM].size);
+    memory_region_add_subregion(get_system_memory(),
+                                virt_memmap[VIRT_PCIE_ECAM].base, ecam_alias);
+
+    mmio_alias = g_new0(MemoryRegion, 1);
+    mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
+    memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio",
+                             mmio_reg, virt_memmap[VIRT_PCIE_MMIO].base,
+                             virt_memmap[VIRT_PCIE_MMIO].size);
+    memory_region_add_subregion(get_system_memory(),
+                                virt_memmap[VIRT_PCIE_MMIO].base, mmio_alias);
+
+    pio_alias = g_new0(MemoryRegion, 1);
+    memory_region_init_alias(pio_alias, OBJECT(dev), "pcie-pio",
+                             get_system_io(), 0, virt_memmap[VIRT_PCIE_PIO].size);
+    memory_region_add_subregion(get_system_memory(),
+                                virt_memmap[VIRT_PCIE_PIO].base, pio_alias);
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, virt_memmap[VIRT_PCIE_PIO].base);
+
+    for (i = 0; i < GPEX_NUM_IRQS; i++) {
+        irq = qdev_get_gpio_in(pic, PCIE_IRQ_BASE + i);
+        sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
+        gpex_set_irq_num(GPEX_HOST(dev), i, PCIE_IRQ_BASE + i);
+    }
+
+    pci_vga_init(pci_bus);
+
+    if (defaults_enabled()) {
+        pci_create_simple(pci_bus, -1, "pci-ohci");
+        usb_create_simple(usb_bus_find(-1), "usb-kbd");
+        usb_create_simple(usb_bus_find(-1), "usb-tablet");
+    }
+
+    for (i = 0; i < nb_nics; i++) {
+        NICInfo *nd = &nd_table[i];
+
+        if (!nd->model) {
+            nd->model = g_strdup("virtio");
+        }
+
+        pci_nic_init_nofail(nd, pci_bus, nd->model, NULL);
+    }
+}
+
+static void mips_loongson3_virt_init(MachineState *machine)
+{
+    int i;
+    long bios_size;
+    MIPSCPU *cpu;
+    CPUMIPSState *env;
+    DeviceState *liointc;
+    char *filename;
+    const char *kernel_cmdline = machine->kernel_cmdline;
+    const char *kernel_filename = machine->kernel_filename;
+    const char *initrd_filename = machine->initrd_filename;
+    ram_addr_t ram_size = machine->ram_size;
+    MemoryRegion *address_space_mem = get_system_memory();
+    MemoryRegion *ram = g_new(MemoryRegion, 1);
+    MemoryRegion *bios = g_new(MemoryRegion, 1);
+    MemoryRegion *iomem = g_new(MemoryRegion, 1);
+
+    /* TODO: TCG will support all CPU types */
+    if (!kvm_enabled()) {
+        if (!machine->cpu_type) {
+            machine->cpu_type = MIPS_CPU_TYPE_NAME("Loongson-3A1000");
+        }
+        if (!strstr(machine->cpu_type, "Loongson-3A1000")) {
+            error_report("Loongson-3/TCG needs cpu type Loongson-3A1000");
+            exit(1);
+        }
+    } else {
+        if (!machine->cpu_type) {
+            machine->cpu_type = MIPS_CPU_TYPE_NAME("Loongson-3A4000");
+        }
+        if (!strstr(machine->cpu_type, "Loongson-3A4000")) {
+            error_report("Loongson-3/KVM needs cpu type Loongson-3A4000");
+            exit(1);
+        }
+    }
+
+    if (ram_size < 512 * MiB) {
+        error_report("Loongson-3 machine needs at least 512MB memory");
+        exit(1);
+    }
+
+    /*
+     * The whole MMIO range among configure registers doesn't generate
+     * exception when accessing invalid memory. Create an unimplememted
+     * device to emulate this feature.
+     */
+    create_unimplemented_device("fallback", 0x10000000, 0x30000000);
+
+    liointc = qdev_new("loongson.liointc");
+    sysbus_realize_and_unref(SYS_BUS_DEVICE(liointc), &error_fatal);
+
+    sysbus_mmio_map(SYS_BUS_DEVICE(liointc), 0, virt_memmap[VIRT_LIOINTC].base);
+
+    for (i = 0; i < machine->smp.cpus; i++) {
+        int ip;
+
+        /* init CPUs */
+        cpu = MIPS_CPU(cpu_create(machine->cpu_type));
+
+        /* Init internal devices */
+        cpu_mips_irq_init_cpu(cpu);
+        cpu_mips_clock_init(cpu);
+        qemu_register_reset(main_cpu_reset, cpu);
+
+        if (i >= 4) {
+            continue; /* Only node-0 can be connected to LIOINTC */
+        }
+
+        for (ip = 0; ip < 4 ; ip++) {
+            int pin = i * 4 + ip;
+            sysbus_connect_irq(SYS_BUS_DEVICE(liointc),
+                               pin, cpu->env.irq[ip + 2]);
+        }
+    }
+    env = &MIPS_CPU(first_cpu)->env;
+
+    /* Allocate RAM/BIOS, 0x00000000~0x10000000 is alias of 0x80000000~0x90000000 */
+    memory_region_init_rom(bios, NULL, "loongson3.bios",
+                           virt_memmap[VIRT_BIOS_ROM].size, &error_fatal);
+    memory_region_init_alias(ram, NULL, "loongson3.lowmem",
+                           machine->ram, 0, virt_memmap[VIRT_LOWMEM].size);
+    memory_region_init_io(iomem, NULL, &loongson3_pm_ops,
+                           NULL, "loongson3_pm", virt_memmap[VIRT_PM].size);
+
+    memory_region_add_subregion(address_space_mem,
+                      virt_memmap[VIRT_LOWMEM].base, ram);
+    memory_region_add_subregion(address_space_mem,
+                      virt_memmap[VIRT_BIOS_ROM].base, bios);
+    memory_region_add_subregion(address_space_mem,
+                      virt_memmap[VIRT_HIGHMEM].base, machine->ram);
+    memory_region_add_subregion(address_space_mem,
+                      virt_memmap[VIRT_PM].base, iomem);
+
+    /*
+     * We do not support flash operation, just loading bios.bin as raw BIOS.
+     * Please use -L to set the BIOS path and -bios to set bios name.
+     */
+
+    if (kernel_filename) {
+        loaderparams.cpu_freq = get_cpu_freq();
+        loaderparams.ram_size = ram_size;
+        loaderparams.kernel_filename = kernel_filename;
+        loaderparams.kernel_cmdline = kernel_cmdline;
+        loaderparams.initrd_filename = initrd_filename;
+        loaderparams.kernel_entry = load_kernel(env);
+
+        init_boot_rom();
+        init_boot_param();
+    } else {
+        if (bios_name == NULL) {
+                bios_name = LOONGSON3_BIOSNAME;
+        }
+        filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+        if (filename) {
+            bios_size = load_image_targphys(filename,
+                                            virt_memmap[VIRT_BIOS_ROM].base,
+                                            virt_memmap[VIRT_BIOS_ROM].size);
+            g_free(filename);
+        } else {
+            bios_size = -1;
+        }
+
+        if ((bios_size < 0 || bios_size > virt_memmap[VIRT_BIOS_ROM].size) &&
+            !kernel_filename && !qtest_enabled()) {
+            error_report("Could not load MIPS bios '%s'", bios_name);
+            exit(1);
+        }
+
+        fw_conf_init(ram_size);
+    }
+
+    msi_nonbroken = true;
+    loongson3_virt_devices_init(machine, liointc);
+
+    sysbus_create_simple("goldfish_rtc", virt_memmap[VIRT_RTC].base,
+                         qdev_get_gpio_in(liointc, RTC_IRQ));
+
+    serial_mm_init(address_space_mem, virt_memmap[VIRT_UART].base, 0,
+                   qdev_get_gpio_in(liointc, UART_IRQ), 115200, serial_hd(0),
+                   DEVICE_NATIVE_ENDIAN);
+}
+
+static void mips_loongson3_virt_machine_init(MachineClass *mc)
+{
+    mc->desc = "Loongson-3 Virtualization Platform";
+    mc->init = mips_loongson3_virt_init;
+    mc->block_default_type = IF_IDE;
+    mc->max_cpus = LOONGSON_MAX_VCPUS;
+    mc->default_ram_id = "loongson3.highram";
+    mc->default_ram_size = 1600 * MiB;
+    mc->kvm_type = mips_kvm_type;
+    mc->minimum_page_bits = 14;
+}
+
+DEFINE_MACHINE("loongson3-virt", mips_loongson3_virt_machine_init)
diff --git a/hw/mips/meson.build b/hw/mips/meson.build
index c98391c..72db43c 100644
--- a/hw/mips/meson.build
+++ b/hw/mips/meson.build
@@ -1,6 +1,7 @@
 mips_ss = ss.source_set()
 mips_ss.add(files('addr.c', 'mips_int.c', 'fw_cfg.c'))
 mips_ss.add(when: 'CONFIG_FULOONG', if_true: files('fuloong2e.c'))
+mips_ss.add(when: 'CONFIG_LOONGSON3V', if_true: files('loongson3_bootp.c', 'loongson3_virt.c'))
 mips_ss.add(when: 'CONFIG_JAZZ', if_true: files('jazz.c'))
 mips_ss.add(when: 'CONFIG_MALTA', if_true: files('gt64xxx_pci.c', 'malta.c'))
 mips_ss.add(when: 'CONFIG_MIPSSIM', if_true: files('mipssim.c'))
-- 
2.7.0



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

* [PATCH V13 9/9] docs/system: Update MIPS machine documentation
  2020-10-07  8:39 [PATCH V13 0/9] mips: Add Loongson-3 machine support Huacai Chen
                   ` (7 preceding siblings ...)
  2020-10-07  8:39 ` [PATCH V13 8/9] hw/mips: Add Loongson-3 machine support Huacai Chen
@ 2020-10-07  8:39 ` Huacai Chen
  2020-10-09 15:29   ` Philippe Mathieu-Daudé
  8 siblings, 1 reply; 34+ messages in thread
From: Huacai Chen @ 2020-10-07  8:39 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, Aleksandar Markovic
  Cc: Aleksandar Rikalo, Huacai Chen, qemu-devel, Jiaxun Yang,
	Huacai Chen, Aurelien Jarno

Add Loongson-3A CPU models and Loongson-3 based machine description.

Signed-off-by: Huacai Chen <chenhc@lemote.com>
---
 docs/system/cpu-models-mips.rst.inc | 10 ++++++++--
 docs/system/target-mips.rst         | 10 ++++++++++
 2 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/docs/system/cpu-models-mips.rst.inc b/docs/system/cpu-models-mips.rst.inc
index 499b5b6..02cc4bb 100644
--- a/docs/system/cpu-models-mips.rst.inc
+++ b/docs/system/cpu-models-mips.rst.inc
@@ -48,11 +48,17 @@ across all desired hosts.
 ``I6400``
     MIPS64 Processor (Release 6, 2014)
 
+``Loongson-2E``
+    MIPS64 Processor (Loongson 2, 2006)
+
 ``Loongson-2F``
     MIPS64 Processor (Loongson 2, 2008)
 
-``Loongson-2E``
-    MIPS64 Processor (Loongson 2, 2006)
+``Loongson-3A1000``
+    MIPS64 Processor (Loongson 3, 2010)
+
+``Loongson-3A4000``
+    MIPS64 Processor (Loongson 3, 2018)
 
 ``mips64dspr2``
     MIPS64 Processor (Release 2, 2006)
diff --git a/docs/system/target-mips.rst b/docs/system/target-mips.rst
index cd2a931..1f86ccb 100644
--- a/docs/system/target-mips.rst
+++ b/docs/system/target-mips.rst
@@ -84,6 +84,16 @@ The Fuloong 2E emulation supports:
 
 -  RTL8139D as a network card chipset
 
+The Loongson-3 virtual platform emulation supports:
+
+-  Loongson 3A CPU
+
+-  LIOINTC as interrupt controller
+
+-  GPEX and virtio as variable devices
+
+-  Both KVM and TCG supported
+
 The mipssim pseudo board emulation provides an environment similar to
 what the proprietary MIPS emulator uses for running Linux. It supports:
 
-- 
2.7.0



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

* Re: [PATCH V13 2/9] meson.build: Re-enable KVM support for MIPS
  2020-10-07  8:39 ` [PATCH V13 2/9] meson.build: Re-enable KVM support for MIPS Huacai Chen
@ 2020-10-07  8:51   ` Paolo Bonzini
  2020-11-17 17:17   ` Philippe Mathieu-Daudé
  1 sibling, 0 replies; 34+ messages in thread
From: Paolo Bonzini @ 2020-10-07  8:51 UTC (permalink / raw)
  To: Huacai Chen, Philippe Mathieu-Daudé, Aleksandar Markovic
  Cc: Aleksandar Rikalo, Huacai Chen, qemu-devel, Jiaxun Yang,
	Huacai Chen, Aurelien Jarno

On 07/10/20 10:39, Huacai Chen wrote:
> After converting from configure to meson, KVM support is lost for MIPS,
> so re-enable it in meson.build.
> 
> Fixes: fdb75aeff7c212e1afaaa3a43 ("configure: remove target configuration")
> Fixes: 8a19980e3fc42239aae054bc9 ("configure: move accelerator logic to meson")
> Cc: aolo Bonzini <pbonzini@redhat.com>
> Signed-off-by: Huacai Chen <chenhc@lemote.com>
> ---
>  meson.build | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/meson.build b/meson.build
> index 17c89c8..b407ff4 100644
> --- a/meson.build
> +++ b/meson.build
> @@ -59,6 +59,8 @@ elif cpu == 's390x'
>    kvm_targets = ['s390x-softmmu']
>  elif cpu in ['ppc', 'ppc64']
>    kvm_targets = ['ppc-softmmu', 'ppc64-softmmu']
> +elif cpu in ['mips', 'mips64']
> +  kvm_targets = ['mips-softmmu', 'mipsel-softmmu', 'mips64-softmmu', 'mips64el-softmmu']
>  else
>    kvm_targets = []
>  endif
> 

I'm queuing this one, sorry for the breakage. :(

Paolo



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

* Re: [PATCH V13 9/9] docs/system: Update MIPS machine documentation
  2020-10-07  8:39 ` [PATCH V13 9/9] docs/system: Update MIPS machine documentation Huacai Chen
@ 2020-10-09 15:29   ` Philippe Mathieu-Daudé
  2020-10-10  1:47     ` Huacai Chen
  0 siblings, 1 reply; 34+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-10-09 15:29 UTC (permalink / raw)
  To: Huacai Chen, Aleksandar Markovic
  Cc: Aleksandar Rikalo, Huacai Chen, qemu-devel, Huacai Chen, Aurelien Jarno

Hi Huacai,

On 10/7/20 10:39 AM, Huacai Chen wrote:
> Add Loongson-3A CPU models and Loongson-3 based machine description.
> 
> Signed-off-by: Huacai Chen <chenhc@lemote.com>
> ---
>   docs/system/cpu-models-mips.rst.inc | 10 ++++++++--
>   docs/system/target-mips.rst         | 10 ++++++++++
>   2 files changed, 18 insertions(+), 2 deletions(-)
> 
> diff --git a/docs/system/cpu-models-mips.rst.inc b/docs/system/cpu-models-mips.rst.inc
> index 499b5b6..02cc4bb 100644
> --- a/docs/system/cpu-models-mips.rst.inc
> +++ b/docs/system/cpu-models-mips.rst.inc
> @@ -48,11 +48,17 @@ across all desired hosts.
>   ``I6400``
>       MIPS64 Processor (Release 6, 2014)
>   
> +``Loongson-2E``
> +    MIPS64 Processor (Loongson 2, 2006)
> +
>   ``Loongson-2F``
>       MIPS64 Processor (Loongson 2, 2008)
>   
> -``Loongson-2E``
> -    MIPS64 Processor (Loongson 2, 2006)
> +``Loongson-3A1000``
> +    MIPS64 Processor (Loongson 3, 2010)
> +
> +``Loongson-3A4000``
> +    MIPS64 Processor (Loongson 3, 2018)
>   
>   ``mips64dspr2``
>       MIPS64 Processor (Release 2, 2006)
> diff --git a/docs/system/target-mips.rst b/docs/system/target-mips.rst
> index cd2a931..1f86ccb 100644
> --- a/docs/system/target-mips.rst
> +++ b/docs/system/target-mips.rst
> @@ -84,6 +84,16 @@ The Fuloong 2E emulation supports:
>   
>   -  RTL8139D as a network card chipset
>   
> +The Loongson-3 virtual platform emulation supports:
> +
> +-  Loongson 3A CPU
> +
> +-  LIOINTC as interrupt controller
> +
> +-  GPEX and virtio as variable devices

What do you mean by "as variable devices"?

> +
> +-  Both KVM and TCG supported
> +
>   The mipssim pseudo board emulation provides an environment similar to
>   what the proprietary MIPS emulator uses for running Linux. It supports:
>   
> 


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

* Re: [PATCH V13 9/9] docs/system: Update MIPS machine documentation
  2020-10-09 15:29   ` Philippe Mathieu-Daudé
@ 2020-10-10  1:47     ` Huacai Chen
  0 siblings, 0 replies; 34+ messages in thread
From: Huacai Chen @ 2020-10-10  1:47 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Huacai Chen, Aleksandar Rikalo, QEMU Developers,
	Aleksandar Markovic, Aurelien Jarno

Hi, Philippe,

On Fri, Oct 9, 2020 at 11:29 PM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
>
> Hi Huacai,
>
> On 10/7/20 10:39 AM, Huacai Chen wrote:
> > Add Loongson-3A CPU models and Loongson-3 based machine description.
> >
> > Signed-off-by: Huacai Chen <chenhc@lemote.com>
> > ---
> >   docs/system/cpu-models-mips.rst.inc | 10 ++++++++--
> >   docs/system/target-mips.rst         | 10 ++++++++++
> >   2 files changed, 18 insertions(+), 2 deletions(-)
> >
> > diff --git a/docs/system/cpu-models-mips.rst.inc b/docs/system/cpu-models-mips.rst.inc
> > index 499b5b6..02cc4bb 100644
> > --- a/docs/system/cpu-models-mips.rst.inc
> > +++ b/docs/system/cpu-models-mips.rst.inc
> > @@ -48,11 +48,17 @@ across all desired hosts.
> >   ``I6400``
> >       MIPS64 Processor (Release 6, 2014)
> >
> > +``Loongson-2E``
> > +    MIPS64 Processor (Loongson 2, 2006)
> > +
> >   ``Loongson-2F``
> >       MIPS64 Processor (Loongson 2, 2008)
> >
> > -``Loongson-2E``
> > -    MIPS64 Processor (Loongson 2, 2006)
> > +``Loongson-3A1000``
> > +    MIPS64 Processor (Loongson 3, 2010)
> > +
> > +``Loongson-3A4000``
> > +    MIPS64 Processor (Loongson 3, 2018)
> >
> >   ``mips64dspr2``
> >       MIPS64 Processor (Release 2, 2006)
> > diff --git a/docs/system/target-mips.rst b/docs/system/target-mips.rst
> > index cd2a931..1f86ccb 100644
> > --- a/docs/system/target-mips.rst
> > +++ b/docs/system/target-mips.rst
> > @@ -84,6 +84,16 @@ The Fuloong 2E emulation supports:
> >
> >   -  RTL8139D as a network card chipset
> >
> > +The Loongson-3 virtual platform emulation supports:
> > +
> > +-  Loongson 3A CPU
> > +
> > +-  LIOINTC as interrupt controller
> > +
> > +-  GPEX and virtio as variable devices
>
> What do you mean by "as variable devices"?
I want to describe "Loongson-3 virtual machine use GPEX as its pci
host controller, and use virtio as its device model to connect many
kinds of devices" here.

Huacai
>
> > +
> > +-  Both KVM and TCG supported
> > +
> >   The mipssim pseudo board emulation provides an environment similar to
> >   what the proprietary MIPS emulator uses for running Linux. It supports:
> >
> >


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

* Re: [PATCH V13 1/9] linux-headers: Update MIPS KVM type defintition
  2020-10-07  8:39 ` [PATCH V13 1/9] linux-headers: Update MIPS KVM type defintition Huacai Chen
@ 2020-10-10  8:25   ` Philippe Mathieu-Daudé
  2020-10-10 12:59   ` Peter Maydell
  1 sibling, 0 replies; 34+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-10-10  8:25 UTC (permalink / raw)
  To: Huacai Chen, Aleksandar Markovic
  Cc: Aleksandar Rikalo, Huacai Chen, qemu-devel, Huacai Chen, Aurelien Jarno

On 10/7/20 10:39 AM, Huacai Chen wrote:
> Update MIPS KVM type defintition from Linux 5.9-rc6.

Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>

> 
> Signed-off-by: Huacai Chen <chenhc@lemote.com>
> ---
>   linux-headers/linux/kvm.h | 5 +++--
>   1 file changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
> index 6683e2e..c138b2f 100644
> --- a/linux-headers/linux/kvm.h
> +++ b/linux-headers/linux/kvm.h
> @@ -790,9 +790,10 @@ struct kvm_ppc_resize_hpt {
>   #define KVM_VM_PPC_HV 1
>   #define KVM_VM_PPC_PR 2
>   
> -/* on MIPS, 0 forces trap & emulate, 1 forces VZ ASE */
> -#define KVM_VM_MIPS_TE		0
> +/* on MIPS, 0 indicates auto, 1 forces VZ ASE, 2 forces trap & emulate */
> +#define KVM_VM_MIPS_AUTO	0
>   #define KVM_VM_MIPS_VZ		1
> +#define KVM_VM_MIPS_TE		2
>   
>   #define KVM_S390_SIE_PAGE_OFFSET 1
>   
> 


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

* Re: [PATCH V13 8/9] hw/mips: Add Loongson-3 machine support
  2020-10-07  8:39 ` [PATCH V13 8/9] hw/mips: Add Loongson-3 machine support Huacai Chen
@ 2020-10-10  9:09   ` Philippe Mathieu-Daudé
  2020-10-11  2:53     ` Huacai Chen
  0 siblings, 1 reply; 34+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-10-10  9:09 UTC (permalink / raw)
  To: Huacai Chen, Aleksandar Markovic
  Cc: Aleksandar Rikalo, Huacai Chen, qemu-devel, Huacai Chen, Aurelien Jarno

Hi Huacai,

On 10/7/20 10:39 AM, Huacai Chen wrote:
> Add Loongson-3 based machine support, it use liointc as the interrupt
> controler and use GPEX as the pci controller. Currently it can work with
> both TCG and KVM.
> 
> As the machine model is not based on any exiting physical hardware, the
> name of the machine is "loongson3-virt". It may be superseded in future
> by a real machine model. If this happens, then a regular deprecation
> procedure shall occur for "loongson3-virt" machine.
> 
> We now already have a full functional Linux kernel (based on Linux-5.4.x
> LTS, the kvm host side and guest side have both been upstream for Linux-
> 5.9, but Linux-5.9 has not been released yet) here:
> 
> https://github.com/chenhuacai/linux
> 
> Of course the upstream kernel is also usable (though it is "unstable"
> now):
> 
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
> 
> How to use QEMU/Loongson-3?
> 1, Download kernel source from the above URL;
> 2, Build a kernel with arch/mips/configs/loongson3_defconfig;
> 3, Boot a Loongson-3A4000 host with this kernel (for KVM mode);
> 4, Build QEMU-master with this patchset;
> 5, modprobe kvm (only necessary for KVM mode);
> 6, Use QEMU with TCG:
>         qemu-system-mips64el -M loongson3-virt,accel=tcg -cpu Loongson-3A1000 -kernel <path_to_kernel> -append ...
>     Use QEMU with KVM:
>         qemu-system-mips64el -M loongson3-virt,accel=kvm -cpu Loongson-3A4000 -kernel <path_to_kernel> -append ...
> 
>     The "-cpu" parameter is optional here and QEMU will use the correct type for TCG/KVM automatically.
> 
> Signed-off-by: Huacai Chen <chenhc@lemote.com>
> Co-developed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> ---
>   default-configs/devices/mips64el-softmmu.mak |   1 +
>   hw/mips/Kconfig                              |  12 +
>   hw/mips/loongson3_bootp.c                    | 162 +++++++
>   hw/mips/loongson3_bootp.h                    | 225 ++++++++++

In a previous version I asked if you could split the bootp* files
(firmware related) in a previous separate patch to ease the review
of the machine part.

>   hw/mips/loongson3_virt.c                     | 615 +++++++++++++++++++++++++++
>   hw/mips/meson.build                          |   1 +
>   6 files changed, 1016 insertions(+)
[...]

> diff --git a/hw/mips/loongson3_virt.c b/hw/mips/loongson3_virt.c
> new file mode 100644
> index 0000000..4e573d6
> --- /dev/null
> +++ b/hw/mips/loongson3_virt.c
> @@ -0,0 +1,615 @@
> +/*
> + * Generic Loongson-3 Platform support
> + *
> + * Copyright (c) 2017-2020 Huacai Chen (chenhc@lemote.com)
> + * Copyright (c) 2017-2020 Jiaxun Yang <jiaxun.yang@flygoat.com>
> + *
> + * 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, see <https://www.gnu.org/licenses/>.
> + */
> +
> +/*
> + * Generic virtualized PC Platform based on Loongson-3 CPU (MIPS64R2 with
> + * extensions, 800~2000MHz)
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu-common.h"
> +#include "qemu/units.h"
> +#include "qemu/cutils.h"
> +#include "qapi/error.h"
> +#include "cpu.h"
> +#include "elf.h"
> +#include "kvm_mips.h"
> +#include "hw/boards.h"
> +#include "hw/char/serial.h"
> +#include "hw/mips/mips.h"
> +#include "hw/mips/cpudevs.h"
> +#include "hw/mips/fw_cfg.h"
> +#include "hw/mips/loongson3_bootp.h"
> +#include "hw/misc/unimp.h"
> +#include "hw/intc/i8259.h"
> +#include "hw/loader.h"
> +#include "hw/isa/superio.h"
> +#include "hw/pci/msi.h"
> +#include "hw/pci/pci.h"
> +#include "hw/pci/pci_host.h"
> +#include "hw/pci-host/gpex.h"
> +#include "hw/rtc/mc146818rtc.h"
> +#include "hw/usb.h"
> +#include "net/net.h"
> +#include "exec/address-spaces.h"
> +#include "sysemu/kvm.h"
> +#include "sysemu/qtest.h"
> +#include "sysemu/reset.h"
> +#include "sysemu/runstate.h"
> +#include "qemu/log.h"
> +#include "qemu/error-report.h"
> +
> +#define PM_CNTL_MODE          0x10
> +
> +#define LOONGSON_MAX_VCPUS      16
> +
> +#define LOONGSON3_BIOSNAME "bios_loongson3.bin"

Where is that file?

> +
> +#define UART_IRQ            0
> +#define RTC_IRQ             1
> +#define PCIE_IRQ_BASE       2
> +
> +const struct MemmapEntry virt_memmap[] = {
> +    [VIRT_LOWMEM] =      { 0x00000000,    0x10000000 },
> +    [VIRT_PM] =          { 0x10080000,         0x100 },
> +    [VIRT_FW_CFG] =      { 0x10080100,         0x100 },
> +    [VIRT_RTC] =         { 0x10081000,        0x1000 },
> +    [VIRT_PCIE_PIO] =    { 0x18000000,       0x80000 },
> +    [VIRT_PCIE_ECAM] =   { 0x1a000000,     0x2000000 },
> +    [VIRT_BIOS_ROM] =    { 0x1fc00000,      0x200000 },
> +    [VIRT_UART] =        { 0x1fe001e0,           0x8 },

See below about this mapping.

> +    [VIRT_LIOINTC] =     { 0x3ff01400,          0x64 },
> +    [VIRT_PCIE_MMIO] =   { 0x40000000,    0x40000000 },
> +    [VIRT_HIGHMEM] =     { 0x80000000,           0x0 }, /* Variable */
> +};
> +
> +static const struct MemmapEntry loader_memmap[] = {
> +    [LOADER_KERNEL] =    { 0x00000000,     0x4000000 },
> +    [LOADER_INITRD] =    { 0x04000000,           0x0 }, /* Variable */
> +    [LOADER_CMDLINE] =   { 0x0ff00000,      0x100000 },
> +};
> +
> +static const struct MemmapEntry loader_rommap[] = {
> +    [LOADER_BOOTROM] =   { 0x1fc00000,        0x1000 },
> +    [LOADER_PARAM] =     { 0x1fc01000,       0x10000 },
> +};
> +
> +static struct _loaderparams {
> +    uint64_t cpu_freq;
> +    uint64_t ram_size;
> +    const char *kernel_cmdline;
> +    const char *kernel_filename;
> +    const char *initrd_filename;
> +    uint64_t kernel_entry;
> +    uint64_t a0, a1, a2;
> +} loaderparams;
> +
> +static uint64_t loongson3_pm_read(void *opaque, hwaddr addr, unsigned size)
> +{
> +    return 0;
> +}
> +
> +static void loongson3_pm_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
> +{
> +    if (addr != PM_CNTL_MODE) {
> +        return;
> +    }
> +
> +    switch (val) {
> +    case 0x00:
> +        qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
> +        return;
> +    case 0xff:
> +        qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
> +        return;
> +    default:
> +        return;
> +    }
> +}
> +
> +static const MemoryRegionOps loongson3_pm_ops = {
> +    .read  = loongson3_pm_read,
> +    .write = loongson3_pm_write,
> +    .endianness = DEVICE_NATIVE_ENDIAN,
> +};
> +
> +#define DEF_TCG_FREQ (200 * 1000 * 1000)
> +#define DEF_KVM_FREQ (1600 * 1000 * 1000)
> +
> +static uint64_t get_cpu_freq(void)
> +{
> +#ifdef CONFIG_KVM
> +    int ret;
> +    uint64_t freq;
> +    struct kvm_one_reg freq_reg = {
> +        .id = KVM_REG_MIPS_COUNT_HZ,
> +        .addr = (uintptr_t)(&freq)
> +    };
> +
> +    if (kvm_enabled()) {
> +        ret = kvm_vcpu_ioctl(first_cpu, KVM_GET_ONE_REG, &freq_reg);
> +        if (ret < 0) {
> +            return DEF_KVM_FREQ;
> +        }
> +        return freq * 2;
> +    } else {
> +        /*
> +         * TCG has a default CP0 Timer period 10 ns, which is 100MHz,
> +         * CPU frequency is defined as double of CP0 timer frequency.
> +         */
> +        return DEF_TCG_FREQ;
> +    }
> +#else
> +    return DEF_TCG_FREQ;
> +#endif
> +}
> +
> +static void init_boot_param(void)
> +{
> +    void *p;
> +    struct boot_params *bp;
> +
> +    p = g_malloc0(loader_rommap[LOADER_PARAM].size);
> +    bp = p;
> +
> +    stw_le_p(&bp->efi.smbios.vers, 1);
> +    init_reset_system(&(bp->reset_system));
> +    p += ROUND_UP(sizeof(struct boot_params), 64);
> +    init_loongson_params(&(bp->efi.smbios.lp), p,
> +                         loaderparams.cpu_freq, loaderparams.ram_size);
> +
> +    rom_add_blob_fixed("params_rom", bp,
> +                       loader_rommap[LOADER_PARAM].size,
> +                       loader_rommap[LOADER_PARAM].base);
> +
> +    g_free(bp);
> +
> +    loaderparams.a2 = cpu_mips_phys_to_kseg0(NULL, loader_rommap[LOADER_PARAM].base);
> +}
> +
> +static void init_boot_rom(void)
> +{
> +    const unsigned int boot_code[] = {
> +        0x40086000,   /* mfc0    t0, CP0_STATUS                               */
> +        0x240900E4,   /* li      t1, 0xe4         #set kx, sx, ux, erl        */
> +        0x01094025,   /* or      t0, t0, t1                                   */
> +        0x3C090040,   /* lui     t1, 0x40         #set bev                    */
> +        0x01094025,   /* or      t0, t0, t1                                   */
> +        0x40886000,   /* mtc0    t0, CP0_STATUS                               */
> +        0x00000000,
> +        0x40806800,   /* mtc0    zero, CP0_CAUSE                              */
> +        0x00000000,
> +        0x400A7801,   /* mfc0    t2, $15, 1                                   */
> +        0x314A00FF,   /* andi    t2, 0x0ff                                    */
> +        0x3C089000,   /* dli     t0, 0x900000003ff01000                       */
> +        0x00084438,
> +        0x35083FF0,
> +        0x00084438,
> +        0x35081000,
> +        0x314B0003,   /* andi    t3, t2, 0x3      #local cpuid                */
> +        0x000B5A00,   /* sll     t3, 8                                        */
> +        0x010B4025,   /* or      t0, t0, t3                                   */
> +        0x314C000C,   /* andi    t4, t2, 0xc      #node id                    */
> +        0x000C62BC,   /* dsll    t4, 42                                       */
> +        0x010C4025,   /* or      t0, t0, t4                                   */
> +                      /* WaitForInit:                                         */
> +        0xDD020020,   /* ld      v0, FN_OFF(t0)   #FN_OFF 0x020               */
> +        0x1040FFFE,   /* beqz    v0, WaitForInit                              */
> +        0x00000000,   /* nop                                                  */
> +        0xDD1D0028,   /* ld      sp, SP_OFF(t0)   #FN_OFF 0x028               */
> +        0xDD1C0030,   /* ld      gp, GP_OFF(t0)   #FN_OFF 0x030               */
> +        0xDD050038,   /* ld      a1, A1_OFF(t0)   #FN_OFF 0x038               */
> +        0x00400008,   /* jr      v0               #byebye                     */
> +        0x00000000,   /* nop                                                  */
> +        0x1000FFFF,   /* 1:  b   1b                                           */
> +        0x00000000,   /* nop                                                  */
> +
> +                      /* Reset                                                */
> +        0x3C0C9000,   /* dli     t0, 0x9000000010080010                       */
> +        0x358C0000,
> +        0x000C6438,
> +        0x358C1008,
> +        0x000C6438,
> +        0x358C0010,
> +        0x240D0000,   /* li      t1, 0x00                                     */
> +        0xA18D0000,   /* sb      t1, (t0)                                     */
> +        0x1000FFFF,   /* 1:  b   1b                                           */
> +        0x00000000,   /* nop                                                  */
> +
> +                      /* Shutdown                                             */
> +        0x3C0C9000,   /* dli     t0, 0x9000000010080010                       */
> +        0x358C0000,
> +        0x000C6438,
> +        0x358C1008,
> +        0x000C6438,
> +        0x358C0010,
> +        0x240D00FF,   /* li      t1, 0xff                                     */
> +        0xA18D0000,   /* sb      t1, (t0)                                     */
> +        0x1000FFFF,   /* 1:  b   1b                                           */
> +        0x00000000    /* nop                                                  */
> +    };
> +
> +    rom_add_blob_fixed("boot_rom", boot_code, sizeof(boot_code),
> +                        loader_rommap[LOADER_BOOTROM].base);
> +}
> +
> +static void fw_cfg_boot_set(void *opaque, const char *boot_device,
> +                            Error **errp)
> +{
> +    fw_cfg_modify_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
> +}
> +
> +static void fw_conf_init(unsigned long ram_size)
> +{
> +    FWCfgState *fw_cfg;
> +    hwaddr cfg_addr = virt_memmap[VIRT_FW_CFG].base;
> +
> +    fw_cfg = fw_cfg_init_mem_wide(cfg_addr, cfg_addr + 8, 8, 0, NULL);
> +    fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)current_machine->smp.cpus);
> +    fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)current_machine->smp.max_cpus);
> +    fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
> +    fw_cfg_add_i32(fw_cfg, FW_CFG_MACHINE_VERSION, 1);
> +    fw_cfg_add_i64(fw_cfg, FW_CFG_CPU_FREQ, get_cpu_freq());
> +    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
> +}
> +
> +static int set_prom_cmdline(ram_addr_t initrd_offset, long initrd_size)
> +{
> +    hwaddr cmdline_vaddr;
> +    char memenv[32];
> +    char highmemenv[32];
> +    void *cmdline_buf;
> +    unsigned int *parg_env;
> +    int ret = 0;
> +
> +    /* Allocate cmdline_buf for command line. */
> +    cmdline_buf = g_malloc0(loader_memmap[LOADER_CMDLINE].size);
> +    cmdline_vaddr = cpu_mips_phys_to_kseg0(NULL,
> +                                           loader_memmap[LOADER_CMDLINE].base);
> +
> +    /*
> +     * Layout of cmdline_buf looks like this:
> +     * argv[0], argv[1], 0, env[0], env[1], ... env[i], 0,
> +     * argv[0]'s data, argv[1]'s data, env[0]'data, ..., env[i]'s data, 0
> +     */
> +    parg_env = (void *)cmdline_buf;
> +
> +    ret = (3 + 1) * 4;
> +    *parg_env++ = cmdline_vaddr + ret;
> +    ret += (1 + snprintf(cmdline_buf + ret, 256 - ret, "g"));
> +
> +    /* argv1 */
> +    *parg_env++ = cmdline_vaddr + ret;
> +    if (initrd_size > 0)
> +        ret += (1 + snprintf(cmdline_buf + ret, 256 - ret,
> +                "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s",
> +                cpu_mips_phys_to_kseg0(NULL, initrd_offset),
> +                initrd_size, loaderparams.kernel_cmdline));
> +    else
> +        ret += (1 + snprintf(cmdline_buf + ret, 256 - ret, "%s",
> +                loaderparams.kernel_cmdline));
> +
> +    /* argv2 */
> +    *parg_env++ = cmdline_vaddr + 4 * ret;
> +
> +    /* env */
> +    sprintf(memenv, "%d", 256);
> +    sprintf(highmemenv, "%ld", (unsigned long)(loaderparams.ram_size / MiB) - 256);
> +
> +    rom_add_blob_fixed("cmdline", cmdline_buf,
> +                       loader_memmap[LOADER_CMDLINE].size,
> +                       loader_memmap[LOADER_CMDLINE].base);
> +
> +    g_free(cmdline_buf);
> +
> +    loaderparams.a0 = 2;
> +    loaderparams.a1 = cmdline_vaddr;
> +
> +    return 0;
> +}
> +
> +static uint64_t load_kernel(CPUMIPSState *env)
> +{
> +    long kernel_size;
> +    ram_addr_t initrd_offset;
> +    uint64_t kernel_entry, kernel_low, kernel_high, initrd_size;
> +
> +    kernel_size = load_elf(loaderparams.kernel_filename, NULL,
> +                           cpu_mips_kseg0_to_phys, NULL,
> +                           (uint64_t *)&kernel_entry,
> +                           (uint64_t *)&kernel_low, (uint64_t *)&kernel_high,
> +                           NULL, 0, EM_MIPS, 1, 0);
> +    if (kernel_size < 0) {
> +        error_report("could not load kernel '%s': %s",
> +                     loaderparams.kernel_filename,
> +                     load_elf_strerror(kernel_size));
> +        exit(1);
> +    }
> +
> +    /* load initrd */
> +    initrd_size = 0;
> +    initrd_offset = 0;
> +    if (loaderparams.initrd_filename) {
> +        initrd_size = get_image_size(loaderparams.initrd_filename);
> +        if (initrd_size > 0) {
> +            initrd_offset = (kernel_high + ~INITRD_PAGE_MASK) &
> +                            INITRD_PAGE_MASK;
> +            initrd_offset = MAX(initrd_offset,
> +                                loader_memmap[LOADER_INITRD].base);
> +
> +            if (initrd_offset + initrd_size > ram_size) {
> +                error_report("memory too small for initial ram disk '%s'",
> +                             loaderparams.initrd_filename);
> +                exit(1);
> +            }
> +
> +            initrd_size = load_image_targphys(loaderparams.initrd_filename,
> +                                              initrd_offset,
> +                                              ram_size - initrd_offset);
> +        }
> +
> +        if (initrd_size == (target_ulong) -1) {
> +            error_report("could not load initial ram disk '%s'",
> +                         loaderparams.initrd_filename);
> +            exit(1);
> +        }
> +    }
> +
> +    /* Setup prom cmdline. */
> +    set_prom_cmdline(initrd_offset, initrd_size);
> +
> +    return kernel_entry;
> +}
> +
> +static void main_cpu_reset(void *opaque)
> +{
> +    MIPSCPU *cpu = opaque;
> +    CPUMIPSState *env = &cpu->env;
> +
> +    cpu_reset(CPU(cpu));
> +
> +    /* Loongson-3 reset stuff */
> +    if (loaderparams.kernel_filename) {
> +        if (cpu == MIPS_CPU(first_cpu)) {
> +            env->active_tc.gpr[4] = loaderparams.a0;
> +            env->active_tc.gpr[5] = loaderparams.a1;
> +            env->active_tc.gpr[6] = loaderparams.a2;
> +            env->active_tc.PC = loaderparams.kernel_entry;
> +        }
> +        env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL));
> +    }
> +}
> +
> +static inline void loongson3_virt_devices_init(MachineState *machine, DeviceState *pic)
> +{
> +    int i;
> +    qemu_irq irq;
> +    PCIBus *pci_bus;
> +    DeviceState *dev;
> +    MemoryRegion *pio_alias;
> +    MemoryRegion *mmio_alias, *mmio_reg;
> +    MemoryRegion *ecam_alias, *ecam_reg;
> +
> +    dev = qdev_new(TYPE_GPEX_HOST);
> +    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> +    pci_bus = PCI_HOST_BRIDGE(dev)->bus;
> +
> +    ecam_alias = g_new0(MemoryRegion, 1);
> +    ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
> +    memory_region_init_alias(ecam_alias, OBJECT(dev), "pcie-ecam",
> +                             ecam_reg, 0, virt_memmap[VIRT_PCIE_ECAM].size);
> +    memory_region_add_subregion(get_system_memory(),
> +                                virt_memmap[VIRT_PCIE_ECAM].base, ecam_alias);
> +
> +    mmio_alias = g_new0(MemoryRegion, 1);
> +    mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
> +    memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio",
> +                             mmio_reg, virt_memmap[VIRT_PCIE_MMIO].base,
> +                             virt_memmap[VIRT_PCIE_MMIO].size);
> +    memory_region_add_subregion(get_system_memory(),
> +                                virt_memmap[VIRT_PCIE_MMIO].base, mmio_alias);
> +
> +    pio_alias = g_new0(MemoryRegion, 1);
> +    memory_region_init_alias(pio_alias, OBJECT(dev), "pcie-pio",
> +                             get_system_io(), 0, virt_memmap[VIRT_PCIE_PIO].size);
> +    memory_region_add_subregion(get_system_memory(),
> +                                virt_memmap[VIRT_PCIE_PIO].base, pio_alias);
> +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, virt_memmap[VIRT_PCIE_PIO].base);
> +
> +    for (i = 0; i < GPEX_NUM_IRQS; i++) {
> +        irq = qdev_get_gpio_in(pic, PCIE_IRQ_BASE + i);
> +        sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
> +        gpex_set_irq_num(GPEX_HOST(dev), i, PCIE_IRQ_BASE + i);
> +    }
> +
> +    pci_vga_init(pci_bus);
> +
> +    if (defaults_enabled()) {
> +        pci_create_simple(pci_bus, -1, "pci-ohci");
> +        usb_create_simple(usb_bus_find(-1), "usb-kbd");
> +        usb_create_simple(usb_bus_find(-1), "usb-tablet");
> +    }
> +
> +    for (i = 0; i < nb_nics; i++) {
> +        NICInfo *nd = &nd_table[i];
> +
> +        if (!nd->model) {
> +            nd->model = g_strdup("virtio");
> +        }
> +
> +        pci_nic_init_nofail(nd, pci_bus, nd->model, NULL);
> +    }
> +}
> +
> +static void mips_loongson3_virt_init(MachineState *machine)
> +{
> +    int i;
> +    long bios_size;
> +    MIPSCPU *cpu;
> +    CPUMIPSState *env;
> +    DeviceState *liointc;
> +    char *filename;
> +    const char *kernel_cmdline = machine->kernel_cmdline;
> +    const char *kernel_filename = machine->kernel_filename;
> +    const char *initrd_filename = machine->initrd_filename;
> +    ram_addr_t ram_size = machine->ram_size;
> +    MemoryRegion *address_space_mem = get_system_memory();
> +    MemoryRegion *ram = g_new(MemoryRegion, 1);
> +    MemoryRegion *bios = g_new(MemoryRegion, 1);
> +    MemoryRegion *iomem = g_new(MemoryRegion, 1);
> +
> +    /* TODO: TCG will support all CPU types */
> +    if (!kvm_enabled()) {
> +        if (!machine->cpu_type) {
> +            machine->cpu_type = MIPS_CPU_TYPE_NAME("Loongson-3A1000");
> +        }
> +        if (!strstr(machine->cpu_type, "Loongson-3A1000")) {
> +            error_report("Loongson-3/TCG needs cpu type Loongson-3A1000");
> +            exit(1);
> +        }

IIUC here you need to check machine->smp.cpus is 4 or 8 for the 3A1000.
It would be easier if you model this as a qdev SoC, and this model
cares to create the 4/8 cores (QEMU MIPSCPU).

You defined max_cpu = LOONGSON_MAX_VCPUS = 16, this seems an impossible
configuration for the 3A1000.

> +    } else {
> +        if (!machine->cpu_type) {
> +            machine->cpu_type = MIPS_CPU_TYPE_NAME("Loongson-3A4000");
> +        }
> +        if (!strstr(machine->cpu_type, "Loongson-3A4000")) {
> +            error_report("Loongson-3/KVM needs cpu type Loongson-3A4000");
> +            exit(1);
> +        }

Similar comment, as the 3A4000 is also a quad-core.

> +    }
> +
> +    if (ram_size < 512 * MiB) {
> +        error_report("Loongson-3 machine needs at least 512MB memory");
> +        exit(1);
> +    }
> +
> +    /*
> +     * The whole MMIO range among configure registers doesn't generate
> +     * exception when accessing invalid memory. Create an unimplememted
> +     * device to emulate this feature.
> +     */
> +    create_unimplemented_device("fallback", 0x10000000, 0x30000000);

The secondary crosswise switch description is hard to follow:

* 2.4 Address routing distribution and configuration

According  to  the  default  register  configuration,  CPU [...] 
0x10000000-0x1fffffff  of  CPU  (256M)  is  mapped  to 
0x10000000-0x1fffffff  of  PCI,  and  0x80000000  of  PCIDMA.
In addition, when read access to illegal addresses occurs due to CPU 
guess execution, all 8 address Windows fail to hit, ?

Table 2-9 XBAR level 2 default address configuration
                   base                    high                     owner
0 x0000_0000_1000_0000  0 x0000_0000_2000_0000  Low speed I/O (PCI, etc)

* 14.4 Secondary cross-switch address window

After the address window is configured, the system address 
0x0000_2000_0000 is added-- 0x0000_2FFFF_FFFF  maps  to 
0x0000_0000_0000  -- 0x0000_0FFF_FFFF  of  memory  controller 0.An 
access to 0x0000_2000_0000 at this time will result in the original 
enabledThe value stored at address 0x0000_0000_0000.

But see:

* 14.6.3 Low speed device address window

Here are defined the peripherals in the 0x1c00_0000-0x1ff0_ffff range.

* 15.1 System memory space

IO device, 0x1000_0000 --  0x1FFF_FFFF

* 16 Memory allocation for system X

... divide  the  256M  PCI  space  (0x10000000~0x20000000)  into  two 
parts:  0x10000000~0x17ffffff for mem space and 0x18000000~0x20000000 
for IO space.

I still don't understand what is in the 0x20000000-0x30000000 range.

> +
> +    liointc = qdev_new("loongson.liointc");
> +    sysbus_realize_and_unref(SYS_BUS_DEVICE(liointc), &error_fatal);
> +
> +    sysbus_mmio_map(SYS_BUS_DEVICE(liointc), 0, virt_memmap[VIRT_LIOINTC].base);
> +
> +    for (i = 0; i < machine->smp.cpus; i++) {
> +        int ip;
> +
> +        /* init CPUs */
> +        cpu = MIPS_CPU(cpu_create(machine->cpu_type));
> +
> +        /* Init internal devices */
> +        cpu_mips_irq_init_cpu(cpu);
> +        cpu_mips_clock_init(cpu);
> +        qemu_register_reset(main_cpu_reset, cpu);
> +
> +        if (i >= 4) {
> +            continue; /* Only node-0 can be connected to LIOINTC */
> +        }
> +
> +        for (ip = 0; ip < 4 ; ip++) {
> +            int pin = i * 4 + ip;
> +            sysbus_connect_irq(SYS_BUS_DEVICE(liointc),
> +                               pin, cpu->env.irq[ip + 2]);
> +        }
> +    }
> +    env = &MIPS_CPU(first_cpu)->env;
> +
> +    /* Allocate RAM/BIOS, 0x00000000~0x10000000 is alias of 0x80000000~0x90000000 */
> +    memory_region_init_rom(bios, NULL, "loongson3.bios",
> +                           virt_memmap[VIRT_BIOS_ROM].size, &error_fatal);
> +    memory_region_init_alias(ram, NULL, "loongson3.lowmem",
> +                           machine->ram, 0, virt_memmap[VIRT_LOWMEM].size);
> +    memory_region_init_io(iomem, NULL, &loongson3_pm_ops,
> +                           NULL, "loongson3_pm", virt_memmap[VIRT_PM].size);
> +
> +    memory_region_add_subregion(address_space_mem,
> +                      virt_memmap[VIRT_LOWMEM].base, ram);
> +    memory_region_add_subregion(address_space_mem,
> +                      virt_memmap[VIRT_BIOS_ROM].base, bios);
> +    memory_region_add_subregion(address_space_mem,
> +                      virt_memmap[VIRT_HIGHMEM].base, machine->ram);
> +    memory_region_add_subregion(address_space_mem,
> +                      virt_memmap[VIRT_PM].base, iomem);
> +
> +    /*
> +     * We do not support flash operation, just loading bios.bin as raw BIOS.
> +     * Please use -L to set the BIOS path and -bios to set bios name.
> +     */
> +
> +    if (kernel_filename) {
> +        loaderparams.cpu_freq = get_cpu_freq();
> +        loaderparams.ram_size = ram_size;
> +        loaderparams.kernel_filename = kernel_filename;
> +        loaderparams.kernel_cmdline = kernel_cmdline;
> +        loaderparams.initrd_filename = initrd_filename;
> +        loaderparams.kernel_entry = load_kernel(env);
> +
> +        init_boot_rom();
> +        init_boot_param();
> +    } else {
> +        if (bios_name == NULL) {
> +                bios_name = LOONGSON3_BIOSNAME;
> +        }
> +        filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
> +        if (filename) {
> +            bios_size = load_image_targphys(filename,
> +                                            virt_memmap[VIRT_BIOS_ROM].base,
> +                                            virt_memmap[VIRT_BIOS_ROM].size);
> +            g_free(filename);
> +        } else {
> +            bios_size = -1;
> +        }
> +
> +        if ((bios_size < 0 || bios_size > virt_memmap[VIRT_BIOS_ROM].size) &&
> +            !kernel_filename && !qtest_enabled()) {
> +            error_report("Could not load MIPS bios '%s'", bios_name);
> +            exit(1);
> +        }
> +
> +        fw_conf_init(ram_size);
> +    }
> +
> +    msi_nonbroken = true;
> +    loongson3_virt_devices_init(machine, liointc);
> +
> +    sysbus_create_simple("goldfish_rtc", virt_memmap[VIRT_RTC].base,
> +                         qdev_get_gpio_in(liointc, RTC_IRQ));
> +
> +    serial_mm_init(address_space_mem, virt_memmap[VIRT_UART].base, 0,
> +                   qdev_get_gpio_in(liointc, UART_IRQ), 115200, serial_hd(0),
> +                   DEVICE_NATIVE_ENDIAN);

You need to split the SoC part from the machine part.

> +}
> +
> +static void mips_loongson3_virt_machine_init(MachineClass *mc)
> +{
> +    mc->desc = "Loongson-3 Virtualization Platform";
> +    mc->init = mips_loongson3_virt_init;
> +    mc->block_default_type = IF_IDE;

Don't you need min_cpus = 4?

> +    mc->max_cpus = LOONGSON_MAX_VCPUS;
> +    mc->default_ram_id = "loongson3.highram";
> +    mc->default_ram_size = 1600 * MiB;
> +    mc->kvm_type = mips_kvm_type;
> +    mc->minimum_page_bits = 14;
> +}
> +
> +DEFINE_MACHINE("loongson3-virt", mips_loongson3_virt_machine_init)
> diff --git a/hw/mips/meson.build b/hw/mips/meson.build
> index c98391c..72db43c 100644
> --- a/hw/mips/meson.build
> +++ b/hw/mips/meson.build
> @@ -1,6 +1,7 @@
>   mips_ss = ss.source_set()
>   mips_ss.add(files('addr.c', 'mips_int.c', 'fw_cfg.c'))
>   mips_ss.add(when: 'CONFIG_FULOONG', if_true: files('fuloong2e.c'))
> +mips_ss.add(when: 'CONFIG_LOONGSON3V', if_true: files('loongson3_bootp.c', 'loongson3_virt.c'))
>   mips_ss.add(when: 'CONFIG_JAZZ', if_true: files('jazz.c'))
>   mips_ss.add(when: 'CONFIG_MALTA', if_true: files('gt64xxx_pci.c', 'malta.c'))
>   mips_ss.add(when: 'CONFIG_MIPSSIM', if_true: files('mipssim.c'))
> 


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

* Re: [PATCH V13 1/9] linux-headers: Update MIPS KVM type defintition
  2020-10-07  8:39 ` [PATCH V13 1/9] linux-headers: Update MIPS KVM type defintition Huacai Chen
  2020-10-10  8:25   ` Philippe Mathieu-Daudé
@ 2020-10-10 12:59   ` Peter Maydell
  2020-10-10 13:11     ` Philippe Mathieu-Daudé
  1 sibling, 1 reply; 34+ messages in thread
From: Peter Maydell @ 2020-10-10 12:59 UTC (permalink / raw)
  To: Huacai Chen
  Cc: Aleksandar Rikalo, Huacai Chen, Philippe Mathieu-Daudé,
	QEMU Developers, Aleksandar Markovic, Huacai Chen,
	Aurelien Jarno

On Wed, 7 Oct 2020 at 09:44, Huacai Chen <zltjiangshi@gmail.com> wrote:
>
> Update MIPS KVM type defintition from Linux 5.9-rc6.
>
> Signed-off-by: Huacai Chen <chenhc@lemote.com>
> ---

Is this a sync using scripts/update-linux-headers.sh ?

(I vaguely had the idea of adding a --make-commit option to
that script so it would automatically create a git commit
with a header message saying it was a sync against the
kernel git commit, but I never got round to it.)

thanks
-- PMM


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

* Re: [PATCH V13 6/9] target/mips: Add loongson-ext lsdc2 group of instructions
  2020-10-07  8:39 ` [PATCH V13 6/9] target/mips: Add loongson-ext lsdc2 group of instructions Huacai Chen
@ 2020-10-10 13:07   ` Philippe Mathieu-Daudé
  2020-10-11  3:02     ` Huacai Chen
  0 siblings, 1 reply; 34+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-10-10 13:07 UTC (permalink / raw)
  To: Huacai Chen, Aleksandar Markovic
  Cc: Aleksandar Rikalo, Huacai Chen, qemu-devel, Huacai Chen, Aurelien Jarno

On 10/7/20 10:39 AM, Huacai Chen wrote:
> From: Jiaxun Yang <jiaxun.yang@flygoat.com>
> 
> LDC2/SDC2 opcodes have been rewritten as "load & store with offset"
> group of instructions by loongson-ext ASE.
> 
> This patch add implementation of these instructions:
> gslbx: load 1 bytes to GPR
> gslhx: load 2 bytes to GPR
> gslwx: load 4 bytes to GPR
> gsldx: load 8 bytes to GPR
> gslwxc1: load 4 bytes to FPR
> gsldxc1: load 8 bytes to FPR
> gssbx: store 1 bytes from GPR
> gsshx: store 2 bytes from GPR
> gsswx: store 4 bytes from GPR
> gssdx: store 8 bytes from GPR
> gsswxc1: store 4 bytes from FPR
> gssdxc1: store 8 bytes from FPR
> 
> Details of Loongson-EXT is here:
> https://github.com/FlyGoat/loongson-insn/blob/master/loongson-ext.md
> 
> Signed-off-by: Huacai Chen <chenhc@lemote.com>
> Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>

If this patch is from Jiaxun, Huacai's S-o-b should come *after*.

> ---
>   target/mips/translate.c | 179 ++++++++++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 179 insertions(+)
> 
> diff --git a/target/mips/translate.c b/target/mips/translate.c
> index 916b57f..4d42cfc 100644
> --- a/target/mips/translate.c
> +++ b/target/mips/translate.c
> @@ -484,6 +484,24 @@ enum {
>       OPC_GSSDRC1     = 0x7 | OPC_GSSHFS,
>   };
>   
> +/* Loongson EXT LDC2/SDC2 opcodes */
> +#define MASK_LOONGSON_LSDC2(op)           (MASK_OP_MAJOR(op) | (op & 0x7))
> +
> +enum {
> +    OPC_GSLBX      = 0x0 | OPC_LDC2,
> +    OPC_GSLHX      = 0x1 | OPC_LDC2,
> +    OPC_GSLWX      = 0x2 | OPC_LDC2,
> +    OPC_GSLDX      = 0x3 | OPC_LDC2,
> +    OPC_GSLWXC1    = 0x6 | OPC_LDC2,
> +    OPC_GSLDXC1    = 0x7 | OPC_LDC2,
> +    OPC_GSSBX      = 0x0 | OPC_SDC2,
> +    OPC_GSSHX      = 0x1 | OPC_SDC2,
> +    OPC_GSSWX      = 0x2 | OPC_SDC2,
> +    OPC_GSSDX      = 0x3 | OPC_SDC2,
> +    OPC_GSSWXC1    = 0x6 | OPC_SDC2,
> +    OPC_GSSDXC1    = 0x7 | OPC_SDC2,
> +};
> +
>   /* BSHFL opcodes */
>   #define MASK_BSHFL(op)              (MASK_SPECIAL3(op) | (op & (0x1F << 6)))
>   
> @@ -6172,6 +6190,165 @@ static void gen_loongson_lswc2(DisasContext *ctx, int rt,
>       tcg_temp_free(t0);
>   }
>   
> +/* Loongson EXT LDC2/SDC2 */
> +static void gen_loongson_lsdc2(DisasContext *ctx, int rt,
> +                                int rs, int rd)

Alignment off (various occurences in this series).

> +{
> +    int offset = (int8_t)(ctx->opcode >> 3);

Please use sextract32() which is easier to read:

        int32_t offset = sextract32(ctx->opcode, 3, 8);

> +    uint32_t opc = MASK_LOONGSON_LSDC2(ctx->opcode);
> +    TCGv t0, t1;
> +    TCGv_i32 fp0;
> +
> +    /* Pre-conditions */
> +    switch (opc) {
> +    case OPC_GSLBX:
> +    case OPC_GSLHX:
> +    case OPC_GSLWX:
> +    case OPC_GSLDX:
> +        /* prefetch, implement as NOP */
> +        if (rt == 0) {
> +            return;
> +        }
> +        break;
> +    case OPC_GSSBX:
> +    case OPC_GSSHX:
> +    case OPC_GSSWX:
> +    case OPC_GSSDX:
> +        break;
> +    case OPC_GSLWXC1:
> +#if defined(TARGET_MIPS64)
> +    case OPC_GSLDXC1:
> +#endif
> +        check_cp1_enabled(ctx);
> +        /* prefetch, implement as NOP */
> +        if (rt == 0) {
> +            return;
> +        }
> +        break;
> +    case OPC_GSSWXC1:
> +#if defined(TARGET_MIPS64)
> +    case OPC_GSSDXC1:
> +#endif
> +        check_cp1_enabled(ctx);
> +        break;
> +    default:
> +        MIPS_INVAL("loongson_lsdc2");
> +        generate_exception_end(ctx, EXCP_RI);
> +        return;
> +        break;
> +    }
> +
> +    t0 = tcg_temp_new();
> +
> +    gen_base_offset_addr(ctx, t0, rs, offset);
> +    gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0);
> +
> +    switch (opc) {
> +    case OPC_GSLBX:
> +        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_SB);
> +        gen_store_gpr(t0, rt);
> +        break;
> +    case OPC_GSLHX:
> +        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESW |
> +                            ctx->default_tcg_memop_mask);

Do Loongson EXT plan to support unaligned accesses?

> +        gen_store_gpr(t0, rt);
> +        break;
> +    case OPC_GSLWX:
> +        gen_base_offset_addr(ctx, t0, rs, offset);
> +        if (rd) {
> +            gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0);
> +        }
> +        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESL |
> +                            ctx->default_tcg_memop_mask);
> +        gen_store_gpr(t0, rt);
> +        break;
> +#if defined(TARGET_MIPS64)
> +    case OPC_GSLDX:
> +        gen_base_offset_addr(ctx, t0, rs, offset);
> +        if (rd) {
> +            gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0);
> +        }
> +        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ |
> +                            ctx->default_tcg_memop_mask);
> +        gen_store_gpr(t0, rt);
> +        break;
> +#endif
> +    case OPC_GSLWXC1:
> +        check_cp1_enabled(ctx);
> +        gen_base_offset_addr(ctx, t0, rs, offset);
> +        if (rd) {
> +            gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0);
> +        }
> +        fp0 = tcg_temp_new_i32();
> +        tcg_gen_qemu_ld_i32(fp0, t0, ctx->mem_idx, MO_TESL |
> +                            ctx->default_tcg_memop_mask);
> +        gen_store_fpr32(ctx, fp0, rt);
> +        tcg_temp_free_i32(fp0);
> +        break;
> +#if defined(TARGET_MIPS64)
> +    case OPC_GSLDXC1:
> +        check_cp1_enabled(ctx);
> +        gen_base_offset_addr(ctx, t0, rs, offset);
> +        if (rd) {
> +            gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0);
> +        }
> +        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ |
> +                            ctx->default_tcg_memop_mask);
> +        gen_store_fpr64(ctx, t0, rt);
> +        break;
> +#endif
> +    case OPC_GSSBX:
> +        t1 = tcg_temp_new();
> +        gen_load_gpr(t1, rt);
> +        tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_SB);
> +        tcg_temp_free(t1);
> +        break;
> +    case OPC_GSSHX:
> +        t1 = tcg_temp_new();
> +        gen_load_gpr(t1, rt);
> +        tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUW |
> +                            ctx->default_tcg_memop_mask);
> +        tcg_temp_free(t1);
> +        break;
> +    case OPC_GSSWX:
> +        t1 = tcg_temp_new();
> +        gen_load_gpr(t1, rt);
> +        tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL |
> +                            ctx->default_tcg_memop_mask);
> +        tcg_temp_free(t1);
> +        break;
> +#if defined(TARGET_MIPS64)
> +    case OPC_GSSDX:
> +        t1 = tcg_temp_new();
> +        gen_load_gpr(t1, rt);
> +        tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEQ |
> +                            ctx->default_tcg_memop_mask);
> +        tcg_temp_free(t1);
> +        break;
> +#endif
> +    case OPC_GSSWXC1:
> +        fp0 = tcg_temp_new_i32();
> +        gen_load_fpr32(ctx, fp0, rt);
> +        tcg_gen_qemu_st_i32(fp0, t0, ctx->mem_idx, MO_TEUL |
> +                            ctx->default_tcg_memop_mask);
> +        tcg_temp_free_i32(fp0);
> +        break;
> +#if defined(TARGET_MIPS64)
> +    case OPC_GSSDXC1:
> +        t1 = tcg_temp_new();
> +        gen_load_fpr64(ctx, t1, rt);
> +        tcg_gen_qemu_st_i64(t1, t0, ctx->mem_idx, MO_TEQ |
> +                            ctx->default_tcg_memop_mask);
> +        tcg_temp_free(t1);
> +        break;
> +#endif
> +    default:
> +        break;
> +    }
> +
> +    tcg_temp_free(t0);
> +}
> +
>   /* Traps */
>   static void gen_trap(DisasContext *ctx, uint32_t opc,
>                        int rs, int rt, int16_t imm)
> @@ -31055,6 +31232,8 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx)
>                   /* OPC_JIC, OPC_JIALC */
>                   gen_compute_compact_branch(ctx, op, 0, rt, imm);
>               }
> +        } else if (ctx->insn_flags & ASE_LEXT) {
> +            gen_loongson_lsdc2(ctx, rt, rs, rd);
>           } else {
>               /* OPC_LWC2, OPC_SWC2 */
>               /* COP2: Not implemented. */
> 


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

* Re: [PATCH V13 1/9] linux-headers: Update MIPS KVM type defintition
  2020-10-10 12:59   ` Peter Maydell
@ 2020-10-10 13:11     ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 34+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-10-10 13:11 UTC (permalink / raw)
  To: Peter Maydell, Huacai Chen
  Cc: Aleksandar Rikalo, Huacai Chen, QEMU Developers,
	Aleksandar Markovic, Huacai Chen, Aurelien Jarno

On 10/10/20 2:59 PM, Peter Maydell wrote:
> On Wed, 7 Oct 2020 at 09:44, Huacai Chen <zltjiangshi@gmail.com> wrote:
>>
>> Update MIPS KVM type defintition from Linux 5.9-rc6.
>>
>> Signed-off-by: Huacai Chen <chenhc@lemote.com>
>> ---
> 
> Is this a sync using scripts/update-linux-headers.sh ?
> 
> (I vaguely had the idea of adding a --make-commit option to
> that script so it would automatically create a git commit
> with a header message saying it was a sync against the
> kernel git commit, but I never got round to it.)

I just realized you merged this change as commit 94c7fefcb45
("linux headers: sync to 5.9-rc7") =)

> 
> thanks
> -- PMM
> 


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

* Re: [PATCH V13 8/9] hw/mips: Add Loongson-3 machine support
  2020-10-10  9:09   ` Philippe Mathieu-Daudé
@ 2020-10-11  2:53     ` Huacai Chen
  2020-10-12  8:12       ` Philippe Mathieu-Daudé
  0 siblings, 1 reply; 34+ messages in thread
From: Huacai Chen @ 2020-10-11  2:53 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Huacai Chen, Aleksandar Rikalo, QEMU Developers,
	Aleksandar Markovic, Aurelien Jarno

Hi, Philippe,

On Sat, Oct 10, 2020 at 5:09 PM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
>
> Hi Huacai,
>
> On 10/7/20 10:39 AM, Huacai Chen wrote:
> > Add Loongson-3 based machine support, it use liointc as the interrupt
> > controler and use GPEX as the pci controller. Currently it can work with
> > both TCG and KVM.
> >
> > As the machine model is not based on any exiting physical hardware, the
> > name of the machine is "loongson3-virt". It may be superseded in future
> > by a real machine model. If this happens, then a regular deprecation
> > procedure shall occur for "loongson3-virt" machine.
> >
> > We now already have a full functional Linux kernel (based on Linux-5.4.x
> > LTS, the kvm host side and guest side have both been upstream for Linux-
> > 5.9, but Linux-5.9 has not been released yet) here:
> >
> > https://github.com/chenhuacai/linux
> >
> > Of course the upstream kernel is also usable (though it is "unstable"
> > now):
> >
> > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
> >
> > How to use QEMU/Loongson-3?
> > 1, Download kernel source from the above URL;
> > 2, Build a kernel with arch/mips/configs/loongson3_defconfig;
> > 3, Boot a Loongson-3A4000 host with this kernel (for KVM mode);
> > 4, Build QEMU-master with this patchset;
> > 5, modprobe kvm (only necessary for KVM mode);
> > 6, Use QEMU with TCG:
> >         qemu-system-mips64el -M loongson3-virt,accel=tcg -cpu Loongson-3A1000 -kernel <path_to_kernel> -append ...
> >     Use QEMU with KVM:
> >         qemu-system-mips64el -M loongson3-virt,accel=kvm -cpu Loongson-3A4000 -kernel <path_to_kernel> -append ...
> >
> >     The "-cpu" parameter is optional here and QEMU will use the correct type for TCG/KVM automatically.
> >
> > Signed-off-by: Huacai Chen <chenhc@lemote.com>
> > Co-developed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> > ---
> >   default-configs/devices/mips64el-softmmu.mak |   1 +
> >   hw/mips/Kconfig                              |  12 +
> >   hw/mips/loongson3_bootp.c                    | 162 +++++++
> >   hw/mips/loongson3_bootp.h                    | 225 ++++++++++
>
> In a previous version I asked if you could split the bootp* files
> (firmware related) in a previous separate patch to ease the review
> of the machine part.
In previous version you told me to split the fw_cfg to a separate
patch, but split the efi-related helpers to seprate files (not to a
patch). But anyway, I will split them to a patch in the next version.

>
> >   hw/mips/loongson3_virt.c                     | 615 +++++++++++++++++++++++++++
> >   hw/mips/meson.build                          |   1 +
> >   6 files changed, 1016 insertions(+)
> [...]
>
> > diff --git a/hw/mips/loongson3_virt.c b/hw/mips/loongson3_virt.c
> > new file mode 100644
> > index 0000000..4e573d6
> > --- /dev/null
> > +++ b/hw/mips/loongson3_virt.c
> > @@ -0,0 +1,615 @@
> > +/*
> > + * Generic Loongson-3 Platform support
> > + *
> > + * Copyright (c) 2017-2020 Huacai Chen (chenhc@lemote.com)
> > + * Copyright (c) 2017-2020 Jiaxun Yang <jiaxun.yang@flygoat.com>
> > + *
> > + * 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, see <https://www.gnu.org/licenses/>.
> > + */
> > +
> > +/*
> > + * Generic virtualized PC Platform based on Loongson-3 CPU (MIPS64R2 with
> > + * extensions, 800~2000MHz)
> > + */
> > +
> > +#include "qemu/osdep.h"
> > +#include "qemu-common.h"
> > +#include "qemu/units.h"
> > +#include "qemu/cutils.h"
> > +#include "qapi/error.h"
> > +#include "cpu.h"
> > +#include "elf.h"
> > +#include "kvm_mips.h"
> > +#include "hw/boards.h"
> > +#include "hw/char/serial.h"
> > +#include "hw/mips/mips.h"
> > +#include "hw/mips/cpudevs.h"
> > +#include "hw/mips/fw_cfg.h"
> > +#include "hw/mips/loongson3_bootp.h"
> > +#include "hw/misc/unimp.h"
> > +#include "hw/intc/i8259.h"
> > +#include "hw/loader.h"
> > +#include "hw/isa/superio.h"
> > +#include "hw/pci/msi.h"
> > +#include "hw/pci/pci.h"
> > +#include "hw/pci/pci_host.h"
> > +#include "hw/pci-host/gpex.h"
> > +#include "hw/rtc/mc146818rtc.h"
> > +#include "hw/usb.h"
> > +#include "net/net.h"
> > +#include "exec/address-spaces.h"
> > +#include "sysemu/kvm.h"
> > +#include "sysemu/qtest.h"
> > +#include "sysemu/reset.h"
> > +#include "sysemu/runstate.h"
> > +#include "qemu/log.h"
> > +#include "qemu/error-report.h"
> > +
> > +#define PM_CNTL_MODE          0x10
> > +
> > +#define LOONGSON_MAX_VCPUS      16
> > +
> > +#define LOONGSON3_BIOSNAME "bios_loongson3.bin"
>
> Where is that file?
I don't know the policy of QEMU's binary file, just put that in the
roms directory?

>
> > +
> > +#define UART_IRQ            0
> > +#define RTC_IRQ             1
> > +#define PCIE_IRQ_BASE       2
> > +
> > +const struct MemmapEntry virt_memmap[] = {
> > +    [VIRT_LOWMEM] =      { 0x00000000,    0x10000000 },
> > +    [VIRT_PM] =          { 0x10080000,         0x100 },
> > +    [VIRT_FW_CFG] =      { 0x10080100,         0x100 },
> > +    [VIRT_RTC] =         { 0x10081000,        0x1000 },
> > +    [VIRT_PCIE_PIO] =    { 0x18000000,       0x80000 },
> > +    [VIRT_PCIE_ECAM] =   { 0x1a000000,     0x2000000 },
> > +    [VIRT_BIOS_ROM] =    { 0x1fc00000,      0x200000 },
> > +    [VIRT_UART] =        { 0x1fe001e0,           0x8 },
>
> See below about this mapping.
>
> > +    [VIRT_LIOINTC] =     { 0x3ff01400,          0x64 },
> > +    [VIRT_PCIE_MMIO] =   { 0x40000000,    0x40000000 },
> > +    [VIRT_HIGHMEM] =     { 0x80000000,           0x0 }, /* Variable */
> > +};
> > +
> > +static const struct MemmapEntry loader_memmap[] = {
> > +    [LOADER_KERNEL] =    { 0x00000000,     0x4000000 },
> > +    [LOADER_INITRD] =    { 0x04000000,           0x0 }, /* Variable */
> > +    [LOADER_CMDLINE] =   { 0x0ff00000,      0x100000 },
> > +};
> > +
> > +static const struct MemmapEntry loader_rommap[] = {
> > +    [LOADER_BOOTROM] =   { 0x1fc00000,        0x1000 },
> > +    [LOADER_PARAM] =     { 0x1fc01000,       0x10000 },
> > +};
> > +
> > +static struct _loaderparams {
> > +    uint64_t cpu_freq;
> > +    uint64_t ram_size;
> > +    const char *kernel_cmdline;
> > +    const char *kernel_filename;
> > +    const char *initrd_filename;
> > +    uint64_t kernel_entry;
> > +    uint64_t a0, a1, a2;
> > +} loaderparams;
> > +
> > +static uint64_t loongson3_pm_read(void *opaque, hwaddr addr, unsigned size)
> > +{
> > +    return 0;
> > +}
> > +
> > +static void loongson3_pm_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
> > +{
> > +    if (addr != PM_CNTL_MODE) {
> > +        return;
> > +    }
> > +
> > +    switch (val) {
> > +    case 0x00:
> > +        qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
> > +        return;
> > +    case 0xff:
> > +        qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
> > +        return;
> > +    default:
> > +        return;
> > +    }
> > +}
> > +
> > +static const MemoryRegionOps loongson3_pm_ops = {
> > +    .read  = loongson3_pm_read,
> > +    .write = loongson3_pm_write,
> > +    .endianness = DEVICE_NATIVE_ENDIAN,
> > +};
> > +
> > +#define DEF_TCG_FREQ (200 * 1000 * 1000)
> > +#define DEF_KVM_FREQ (1600 * 1000 * 1000)
> > +
> > +static uint64_t get_cpu_freq(void)
> > +{
> > +#ifdef CONFIG_KVM
> > +    int ret;
> > +    uint64_t freq;
> > +    struct kvm_one_reg freq_reg = {
> > +        .id = KVM_REG_MIPS_COUNT_HZ,
> > +        .addr = (uintptr_t)(&freq)
> > +    };
> > +
> > +    if (kvm_enabled()) {
> > +        ret = kvm_vcpu_ioctl(first_cpu, KVM_GET_ONE_REG, &freq_reg);
> > +        if (ret < 0) {
> > +            return DEF_KVM_FREQ;
> > +        }
> > +        return freq * 2;
> > +    } else {
> > +        /*
> > +         * TCG has a default CP0 Timer period 10 ns, which is 100MHz,
> > +         * CPU frequency is defined as double of CP0 timer frequency.
> > +         */
> > +        return DEF_TCG_FREQ;
> > +    }
> > +#else
> > +    return DEF_TCG_FREQ;
> > +#endif
> > +}
> > +
> > +static void init_boot_param(void)
> > +{
> > +    void *p;
> > +    struct boot_params *bp;
> > +
> > +    p = g_malloc0(loader_rommap[LOADER_PARAM].size);
> > +    bp = p;
> > +
> > +    stw_le_p(&bp->efi.smbios.vers, 1);
> > +    init_reset_system(&(bp->reset_system));
> > +    p += ROUND_UP(sizeof(struct boot_params), 64);
> > +    init_loongson_params(&(bp->efi.smbios.lp), p,
> > +                         loaderparams.cpu_freq, loaderparams.ram_size);
> > +
> > +    rom_add_blob_fixed("params_rom", bp,
> > +                       loader_rommap[LOADER_PARAM].size,
> > +                       loader_rommap[LOADER_PARAM].base);
> > +
> > +    g_free(bp);
> > +
> > +    loaderparams.a2 = cpu_mips_phys_to_kseg0(NULL, loader_rommap[LOADER_PARAM].base);
> > +}
> > +
> > +static void init_boot_rom(void)
> > +{
> > +    const unsigned int boot_code[] = {
> > +        0x40086000,   /* mfc0    t0, CP0_STATUS                               */
> > +        0x240900E4,   /* li      t1, 0xe4         #set kx, sx, ux, erl        */
> > +        0x01094025,   /* or      t0, t0, t1                                   */
> > +        0x3C090040,   /* lui     t1, 0x40         #set bev                    */
> > +        0x01094025,   /* or      t0, t0, t1                                   */
> > +        0x40886000,   /* mtc0    t0, CP0_STATUS                               */
> > +        0x00000000,
> > +        0x40806800,   /* mtc0    zero, CP0_CAUSE                              */
> > +        0x00000000,
> > +        0x400A7801,   /* mfc0    t2, $15, 1                                   */
> > +        0x314A00FF,   /* andi    t2, 0x0ff                                    */
> > +        0x3C089000,   /* dli     t0, 0x900000003ff01000                       */
> > +        0x00084438,
> > +        0x35083FF0,
> > +        0x00084438,
> > +        0x35081000,
> > +        0x314B0003,   /* andi    t3, t2, 0x3      #local cpuid                */
> > +        0x000B5A00,   /* sll     t3, 8                                        */
> > +        0x010B4025,   /* or      t0, t0, t3                                   */
> > +        0x314C000C,   /* andi    t4, t2, 0xc      #node id                    */
> > +        0x000C62BC,   /* dsll    t4, 42                                       */
> > +        0x010C4025,   /* or      t0, t0, t4                                   */
> > +                      /* WaitForInit:                                         */
> > +        0xDD020020,   /* ld      v0, FN_OFF(t0)   #FN_OFF 0x020               */
> > +        0x1040FFFE,   /* beqz    v0, WaitForInit                              */
> > +        0x00000000,   /* nop                                                  */
> > +        0xDD1D0028,   /* ld      sp, SP_OFF(t0)   #FN_OFF 0x028               */
> > +        0xDD1C0030,   /* ld      gp, GP_OFF(t0)   #FN_OFF 0x030               */
> > +        0xDD050038,   /* ld      a1, A1_OFF(t0)   #FN_OFF 0x038               */
> > +        0x00400008,   /* jr      v0               #byebye                     */
> > +        0x00000000,   /* nop                                                  */
> > +        0x1000FFFF,   /* 1:  b   1b                                           */
> > +        0x00000000,   /* nop                                                  */
> > +
> > +                      /* Reset                                                */
> > +        0x3C0C9000,   /* dli     t0, 0x9000000010080010                       */
> > +        0x358C0000,
> > +        0x000C6438,
> > +        0x358C1008,
> > +        0x000C6438,
> > +        0x358C0010,
> > +        0x240D0000,   /* li      t1, 0x00                                     */
> > +        0xA18D0000,   /* sb      t1, (t0)                                     */
> > +        0x1000FFFF,   /* 1:  b   1b                                           */
> > +        0x00000000,   /* nop                                                  */
> > +
> > +                      /* Shutdown                                             */
> > +        0x3C0C9000,   /* dli     t0, 0x9000000010080010                       */
> > +        0x358C0000,
> > +        0x000C6438,
> > +        0x358C1008,
> > +        0x000C6438,
> > +        0x358C0010,
> > +        0x240D00FF,   /* li      t1, 0xff                                     */
> > +        0xA18D0000,   /* sb      t1, (t0)                                     */
> > +        0x1000FFFF,   /* 1:  b   1b                                           */
> > +        0x00000000    /* nop                                                  */
> > +    };
> > +
> > +    rom_add_blob_fixed("boot_rom", boot_code, sizeof(boot_code),
> > +                        loader_rommap[LOADER_BOOTROM].base);
> > +}
> > +
> > +static void fw_cfg_boot_set(void *opaque, const char *boot_device,
> > +                            Error **errp)
> > +{
> > +    fw_cfg_modify_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
> > +}
> > +
> > +static void fw_conf_init(unsigned long ram_size)
> > +{
> > +    FWCfgState *fw_cfg;
> > +    hwaddr cfg_addr = virt_memmap[VIRT_FW_CFG].base;
> > +
> > +    fw_cfg = fw_cfg_init_mem_wide(cfg_addr, cfg_addr + 8, 8, 0, NULL);
> > +    fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)current_machine->smp.cpus);
> > +    fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)current_machine->smp.max_cpus);
> > +    fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
> > +    fw_cfg_add_i32(fw_cfg, FW_CFG_MACHINE_VERSION, 1);
> > +    fw_cfg_add_i64(fw_cfg, FW_CFG_CPU_FREQ, get_cpu_freq());
> > +    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
> > +}
> > +
> > +static int set_prom_cmdline(ram_addr_t initrd_offset, long initrd_size)
> > +{
> > +    hwaddr cmdline_vaddr;
> > +    char memenv[32];
> > +    char highmemenv[32];
> > +    void *cmdline_buf;
> > +    unsigned int *parg_env;
> > +    int ret = 0;
> > +
> > +    /* Allocate cmdline_buf for command line. */
> > +    cmdline_buf = g_malloc0(loader_memmap[LOADER_CMDLINE].size);
> > +    cmdline_vaddr = cpu_mips_phys_to_kseg0(NULL,
> > +                                           loader_memmap[LOADER_CMDLINE].base);
> > +
> > +    /*
> > +     * Layout of cmdline_buf looks like this:
> > +     * argv[0], argv[1], 0, env[0], env[1], ... env[i], 0,
> > +     * argv[0]'s data, argv[1]'s data, env[0]'data, ..., env[i]'s data, 0
> > +     */
> > +    parg_env = (void *)cmdline_buf;
> > +
> > +    ret = (3 + 1) * 4;
> > +    *parg_env++ = cmdline_vaddr + ret;
> > +    ret += (1 + snprintf(cmdline_buf + ret, 256 - ret, "g"));
> > +
> > +    /* argv1 */
> > +    *parg_env++ = cmdline_vaddr + ret;
> > +    if (initrd_size > 0)
> > +        ret += (1 + snprintf(cmdline_buf + ret, 256 - ret,
> > +                "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s",
> > +                cpu_mips_phys_to_kseg0(NULL, initrd_offset),
> > +                initrd_size, loaderparams.kernel_cmdline));
> > +    else
> > +        ret += (1 + snprintf(cmdline_buf + ret, 256 - ret, "%s",
> > +                loaderparams.kernel_cmdline));
> > +
> > +    /* argv2 */
> > +    *parg_env++ = cmdline_vaddr + 4 * ret;
> > +
> > +    /* env */
> > +    sprintf(memenv, "%d", 256);
> > +    sprintf(highmemenv, "%ld", (unsigned long)(loaderparams.ram_size / MiB) - 256);
> > +
> > +    rom_add_blob_fixed("cmdline", cmdline_buf,
> > +                       loader_memmap[LOADER_CMDLINE].size,
> > +                       loader_memmap[LOADER_CMDLINE].base);
> > +
> > +    g_free(cmdline_buf);
> > +
> > +    loaderparams.a0 = 2;
> > +    loaderparams.a1 = cmdline_vaddr;
> > +
> > +    return 0;
> > +}
> > +
> > +static uint64_t load_kernel(CPUMIPSState *env)
> > +{
> > +    long kernel_size;
> > +    ram_addr_t initrd_offset;
> > +    uint64_t kernel_entry, kernel_low, kernel_high, initrd_size;
> > +
> > +    kernel_size = load_elf(loaderparams.kernel_filename, NULL,
> > +                           cpu_mips_kseg0_to_phys, NULL,
> > +                           (uint64_t *)&kernel_entry,
> > +                           (uint64_t *)&kernel_low, (uint64_t *)&kernel_high,
> > +                           NULL, 0, EM_MIPS, 1, 0);
> > +    if (kernel_size < 0) {
> > +        error_report("could not load kernel '%s': %s",
> > +                     loaderparams.kernel_filename,
> > +                     load_elf_strerror(kernel_size));
> > +        exit(1);
> > +    }
> > +
> > +    /* load initrd */
> > +    initrd_size = 0;
> > +    initrd_offset = 0;
> > +    if (loaderparams.initrd_filename) {
> > +        initrd_size = get_image_size(loaderparams.initrd_filename);
> > +        if (initrd_size > 0) {
> > +            initrd_offset = (kernel_high + ~INITRD_PAGE_MASK) &
> > +                            INITRD_PAGE_MASK;
> > +            initrd_offset = MAX(initrd_offset,
> > +                                loader_memmap[LOADER_INITRD].base);
> > +
> > +            if (initrd_offset + initrd_size > ram_size) {
> > +                error_report("memory too small for initial ram disk '%s'",
> > +                             loaderparams.initrd_filename);
> > +                exit(1);
> > +            }
> > +
> > +            initrd_size = load_image_targphys(loaderparams.initrd_filename,
> > +                                              initrd_offset,
> > +                                              ram_size - initrd_offset);
> > +        }
> > +
> > +        if (initrd_size == (target_ulong) -1) {
> > +            error_report("could not load initial ram disk '%s'",
> > +                         loaderparams.initrd_filename);
> > +            exit(1);
> > +        }
> > +    }
> > +
> > +    /* Setup prom cmdline. */
> > +    set_prom_cmdline(initrd_offset, initrd_size);
> > +
> > +    return kernel_entry;
> > +}
> > +
> > +static void main_cpu_reset(void *opaque)
> > +{
> > +    MIPSCPU *cpu = opaque;
> > +    CPUMIPSState *env = &cpu->env;
> > +
> > +    cpu_reset(CPU(cpu));
> > +
> > +    /* Loongson-3 reset stuff */
> > +    if (loaderparams.kernel_filename) {
> > +        if (cpu == MIPS_CPU(first_cpu)) {
> > +            env->active_tc.gpr[4] = loaderparams.a0;
> > +            env->active_tc.gpr[5] = loaderparams.a1;
> > +            env->active_tc.gpr[6] = loaderparams.a2;
> > +            env->active_tc.PC = loaderparams.kernel_entry;
> > +        }
> > +        env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL));
> > +    }
> > +}
> > +
> > +static inline void loongson3_virt_devices_init(MachineState *machine, DeviceState *pic)
> > +{
> > +    int i;
> > +    qemu_irq irq;
> > +    PCIBus *pci_bus;
> > +    DeviceState *dev;
> > +    MemoryRegion *pio_alias;
> > +    MemoryRegion *mmio_alias, *mmio_reg;
> > +    MemoryRegion *ecam_alias, *ecam_reg;
> > +
> > +    dev = qdev_new(TYPE_GPEX_HOST);
> > +    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> > +    pci_bus = PCI_HOST_BRIDGE(dev)->bus;
> > +
> > +    ecam_alias = g_new0(MemoryRegion, 1);
> > +    ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
> > +    memory_region_init_alias(ecam_alias, OBJECT(dev), "pcie-ecam",
> > +                             ecam_reg, 0, virt_memmap[VIRT_PCIE_ECAM].size);
> > +    memory_region_add_subregion(get_system_memory(),
> > +                                virt_memmap[VIRT_PCIE_ECAM].base, ecam_alias);
> > +
> > +    mmio_alias = g_new0(MemoryRegion, 1);
> > +    mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
> > +    memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio",
> > +                             mmio_reg, virt_memmap[VIRT_PCIE_MMIO].base,
> > +                             virt_memmap[VIRT_PCIE_MMIO].size);
> > +    memory_region_add_subregion(get_system_memory(),
> > +                                virt_memmap[VIRT_PCIE_MMIO].base, mmio_alias);
> > +
> > +    pio_alias = g_new0(MemoryRegion, 1);
> > +    memory_region_init_alias(pio_alias, OBJECT(dev), "pcie-pio",
> > +                             get_system_io(), 0, virt_memmap[VIRT_PCIE_PIO].size);
> > +    memory_region_add_subregion(get_system_memory(),
> > +                                virt_memmap[VIRT_PCIE_PIO].base, pio_alias);
> > +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, virt_memmap[VIRT_PCIE_PIO].base);
> > +
> > +    for (i = 0; i < GPEX_NUM_IRQS; i++) {
> > +        irq = qdev_get_gpio_in(pic, PCIE_IRQ_BASE + i);
> > +        sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
> > +        gpex_set_irq_num(GPEX_HOST(dev), i, PCIE_IRQ_BASE + i);
> > +    }
> > +
> > +    pci_vga_init(pci_bus);
> > +
> > +    if (defaults_enabled()) {
> > +        pci_create_simple(pci_bus, -1, "pci-ohci");
> > +        usb_create_simple(usb_bus_find(-1), "usb-kbd");
> > +        usb_create_simple(usb_bus_find(-1), "usb-tablet");
> > +    }
> > +
> > +    for (i = 0; i < nb_nics; i++) {
> > +        NICInfo *nd = &nd_table[i];
> > +
> > +        if (!nd->model) {
> > +            nd->model = g_strdup("virtio");
> > +        }
> > +
> > +        pci_nic_init_nofail(nd, pci_bus, nd->model, NULL);
> > +    }
> > +}
> > +
> > +static void mips_loongson3_virt_init(MachineState *machine)
> > +{
> > +    int i;
> > +    long bios_size;
> > +    MIPSCPU *cpu;
> > +    CPUMIPSState *env;
> > +    DeviceState *liointc;
> > +    char *filename;
> > +    const char *kernel_cmdline = machine->kernel_cmdline;
> > +    const char *kernel_filename = machine->kernel_filename;
> > +    const char *initrd_filename = machine->initrd_filename;
> > +    ram_addr_t ram_size = machine->ram_size;
> > +    MemoryRegion *address_space_mem = get_system_memory();
> > +    MemoryRegion *ram = g_new(MemoryRegion, 1);
> > +    MemoryRegion *bios = g_new(MemoryRegion, 1);
> > +    MemoryRegion *iomem = g_new(MemoryRegion, 1);
> > +
> > +    /* TODO: TCG will support all CPU types */
> > +    if (!kvm_enabled()) {
> > +        if (!machine->cpu_type) {
> > +            machine->cpu_type = MIPS_CPU_TYPE_NAME("Loongson-3A1000");
> > +        }
> > +        if (!strstr(machine->cpu_type, "Loongson-3A1000")) {
> > +            error_report("Loongson-3/TCG needs cpu type Loongson-3A1000");
> > +            exit(1);
> > +        }
>
> IIUC here you need to check machine->smp.cpus is 4 or 8 for the 3A1000.
> It would be easier if you model this as a qdev SoC, and this model
> cares to create the 4/8 cores (QEMU MIPSCPU).
>
> You defined max_cpu = LOONGSON_MAX_VCPUS = 16, this seems an impossible
> configuration for the 3A1000.
There are 4 cores in a SoC, but Loongson-3 support multi-sockets, more
than 4 vcpus will be treated as multi-sockets automatically in guests.
And current linux kernel also handle the case that only boot part of 4
cores in a socket.

>
> > +    } else {
> > +        if (!machine->cpu_type) {
> > +            machine->cpu_type = MIPS_CPU_TYPE_NAME("Loongson-3A4000");
> > +        }
> > +        if (!strstr(machine->cpu_type, "Loongson-3A4000")) {
> > +            error_report("Loongson-3/KVM needs cpu type Loongson-3A4000");
> > +            exit(1);
> > +        }
>
> Similar comment, as the 3A4000 is also a quad-core.
>
> > +    }
> > +
> > +    if (ram_size < 512 * MiB) {
> > +        error_report("Loongson-3 machine needs at least 512MB memory");
> > +        exit(1);
> > +    }
> > +
> > +    /*
> > +     * The whole MMIO range among configure registers doesn't generate
> > +     * exception when accessing invalid memory. Create an unimplememted
> > +     * device to emulate this feature.
> > +     */
> > +    create_unimplemented_device("fallback", 0x10000000, 0x30000000);
>
> The secondary crosswise switch description is hard to follow:
>
> * 2.4 Address routing distribution and configuration
>
> According  to  the  default  register  configuration,  CPU [...]
> 0x10000000-0x1fffffff  of  CPU  (256M)  is  mapped  to
> 0x10000000-0x1fffffff  of  PCI,  and  0x80000000  of  PCIDMA.
> In addition, when read access to illegal addresses occurs due to CPU
> guess execution, all 8 address Windows fail to hit, ?
>
> Table 2-9 XBAR level 2 default address configuration
>                    base                    high                     owner
> 0 x0000_0000_1000_0000  0 x0000_0000_2000_0000  Low speed I/O (PCI, etc)
>
> * 14.4 Secondary cross-switch address window
>
> After the address window is configured, the system address
> 0x0000_2000_0000 is added-- 0x0000_2FFFF_FFFF  maps  to
> 0x0000_0000_0000  -- 0x0000_0FFF_FFFF  of  memory  controller 0.An
> access to 0x0000_2000_0000 at this time will result in the original
> enabledThe value stored at address 0x0000_0000_0000.
>
> But see:
>
> * 14.6.3 Low speed device address window
>
> Here are defined the peripherals in the 0x1c00_0000-0x1ff0_ffff range.
>
> * 15.1 System memory space
>
> IO device, 0x1000_0000 --  0x1FFF_FFFF
>
> * 16 Memory allocation for system X
>
> ... divide  the  256M  PCI  space  (0x10000000~0x20000000)  into  two
> parts:  0x10000000~0x17ffffff for mem space and 0x18000000~0x20000000
> for IO space.
>
> I still don't understand what is in the 0x20000000-0x30000000 range.
Loongson's user manual is a little confusing, as a native Chinese I
also feel uncomfortable sometimes. :)
Generally speaking, Loongson-3's address space is configurable via
address windows, and the recommended configurations is like this:
0x00000000-0x10000000   Low RAM
0x10000000-0x40000000   ROM and MMIO Registers (such as BIOS_ROM at
0x1fc00000, UART at 0x1fe001e0, LIOINTC at 0x3ff00140)
0x40000000-0x80000000  PCI MEM
0x80000000-TOM             High RAM

PCI DMA of 0x10000000-0x1fffffff is a legacy region from
Loongson-2E/2F, and be cancelled in Loongson-3's configuration.
In real hardware, there should be a default "big enough" address
window to catch illegal address, return 0 for read access.
Yes, there is "nothing" in 0x20000000-0x30000000, because it is
undocumented which means "reserved for internal usage".
>
> > +
> > +    liointc = qdev_new("loongson.liointc");
> > +    sysbus_realize_and_unref(SYS_BUS_DEVICE(liointc), &error_fatal);
> > +
> > +    sysbus_mmio_map(SYS_BUS_DEVICE(liointc), 0, virt_memmap[VIRT_LIOINTC].base);
> > +
> > +    for (i = 0; i < machine->smp.cpus; i++) {
> > +        int ip;
> > +
> > +        /* init CPUs */
> > +        cpu = MIPS_CPU(cpu_create(machine->cpu_type));
> > +
> > +        /* Init internal devices */
> > +        cpu_mips_irq_init_cpu(cpu);
> > +        cpu_mips_clock_init(cpu);
> > +        qemu_register_reset(main_cpu_reset, cpu);
> > +
> > +        if (i >= 4) {
> > +            continue; /* Only node-0 can be connected to LIOINTC */
> > +        }
> > +
> > +        for (ip = 0; ip < 4 ; ip++) {
> > +            int pin = i * 4 + ip;
> > +            sysbus_connect_irq(SYS_BUS_DEVICE(liointc),
> > +                               pin, cpu->env.irq[ip + 2]);
> > +        }
> > +    }
> > +    env = &MIPS_CPU(first_cpu)->env;
> > +
> > +    /* Allocate RAM/BIOS, 0x00000000~0x10000000 is alias of 0x80000000~0x90000000 */
> > +    memory_region_init_rom(bios, NULL, "loongson3.bios",
> > +                           virt_memmap[VIRT_BIOS_ROM].size, &error_fatal);
> > +    memory_region_init_alias(ram, NULL, "loongson3.lowmem",
> > +                           machine->ram, 0, virt_memmap[VIRT_LOWMEM].size);
> > +    memory_region_init_io(iomem, NULL, &loongson3_pm_ops,
> > +                           NULL, "loongson3_pm", virt_memmap[VIRT_PM].size);
> > +
> > +    memory_region_add_subregion(address_space_mem,
> > +                      virt_memmap[VIRT_LOWMEM].base, ram);
> > +    memory_region_add_subregion(address_space_mem,
> > +                      virt_memmap[VIRT_BIOS_ROM].base, bios);
> > +    memory_region_add_subregion(address_space_mem,
> > +                      virt_memmap[VIRT_HIGHMEM].base, machine->ram);
> > +    memory_region_add_subregion(address_space_mem,
> > +                      virt_memmap[VIRT_PM].base, iomem);
> > +
> > +    /*
> > +     * We do not support flash operation, just loading bios.bin as raw BIOS.
> > +     * Please use -L to set the BIOS path and -bios to set bios name.
> > +     */
> > +
> > +    if (kernel_filename) {
> > +        loaderparams.cpu_freq = get_cpu_freq();
> > +        loaderparams.ram_size = ram_size;
> > +        loaderparams.kernel_filename = kernel_filename;
> > +        loaderparams.kernel_cmdline = kernel_cmdline;
> > +        loaderparams.initrd_filename = initrd_filename;
> > +        loaderparams.kernel_entry = load_kernel(env);
> > +
> > +        init_boot_rom();
> > +        init_boot_param();
> > +    } else {
> > +        if (bios_name == NULL) {
> > +                bios_name = LOONGSON3_BIOSNAME;
> > +        }
> > +        filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
> > +        if (filename) {
> > +            bios_size = load_image_targphys(filename,
> > +                                            virt_memmap[VIRT_BIOS_ROM].base,
> > +                                            virt_memmap[VIRT_BIOS_ROM].size);
> > +            g_free(filename);
> > +        } else {
> > +            bios_size = -1;
> > +        }
> > +
> > +        if ((bios_size < 0 || bios_size > virt_memmap[VIRT_BIOS_ROM].size) &&
> > +            !kernel_filename && !qtest_enabled()) {
> > +            error_report("Could not load MIPS bios '%s'", bios_name);
> > +            exit(1);
> > +        }
> > +
> > +        fw_conf_init(ram_size);
> > +    }
> > +
> > +    msi_nonbroken = true;
> > +    loongson3_virt_devices_init(machine, liointc);
> > +
> > +    sysbus_create_simple("goldfish_rtc", virt_memmap[VIRT_RTC].base,
> > +                         qdev_get_gpio_in(liointc, RTC_IRQ));
> > +
> > +    serial_mm_init(address_space_mem, virt_memmap[VIRT_UART].base, 0,
> > +                   qdev_get_gpio_in(liointc, UART_IRQ), 115200, serial_hd(0),
> > +                   DEVICE_NATIVE_ENDIAN);
>
> You need to split the SoC part from the machine part.
What do you mean? UART is SoC part and put it near LIOINTC?

>
> > +}
> > +
> > +static void mips_loongson3_virt_machine_init(MachineClass *mc)
> > +{
> > +    mc->desc = "Loongson-3 Virtualization Platform";
> > +    mc->init = mips_loongson3_virt_init;
> > +    mc->block_default_type = IF_IDE;
>
> Don't you need min_cpus = 4?
I think this is needn't.

>
> > +    mc->max_cpus = LOONGSON_MAX_VCPUS;
> > +    mc->default_ram_id = "loongson3.highram";
> > +    mc->default_ram_size = 1600 * MiB;
> > +    mc->kvm_type = mips_kvm_type;
> > +    mc->minimum_page_bits = 14;
> > +}
> > +
> > +DEFINE_MACHINE("loongson3-virt", mips_loongson3_virt_machine_init)
> > diff --git a/hw/mips/meson.build b/hw/mips/meson.build
> > index c98391c..72db43c 100644
> > --- a/hw/mips/meson.build
> > +++ b/hw/mips/meson.build
> > @@ -1,6 +1,7 @@
> >   mips_ss = ss.source_set()
> >   mips_ss.add(files('addr.c', 'mips_int.c', 'fw_cfg.c'))
> >   mips_ss.add(when: 'CONFIG_FULOONG', if_true: files('fuloong2e.c'))
> > +mips_ss.add(when: 'CONFIG_LOONGSON3V', if_true: files('loongson3_bootp.c', 'loongson3_virt.c'))
> >   mips_ss.add(when: 'CONFIG_JAZZ', if_true: files('jazz.c'))
> >   mips_ss.add(when: 'CONFIG_MALTA', if_true: files('gt64xxx_pci.c', 'malta.c'))
> >   mips_ss.add(when: 'CONFIG_MIPSSIM', if_true: files('mipssim.c'))
> >
Huacai


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

* Re: [PATCH V13 6/9] target/mips: Add loongson-ext lsdc2 group of instructions
  2020-10-10 13:07   ` Philippe Mathieu-Daudé
@ 2020-10-11  3:02     ` Huacai Chen
  2020-10-11 11:13       ` Philippe Mathieu-Daudé
  0 siblings, 1 reply; 34+ messages in thread
From: Huacai Chen @ 2020-10-11  3:02 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Huacai Chen, Aleksandar Rikalo, QEMU Developers,
	Aleksandar Markovic, Aurelien Jarno

Hi, Philippe,

On Sat, Oct 10, 2020 at 9:07 PM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
>
> On 10/7/20 10:39 AM, Huacai Chen wrote:
> > From: Jiaxun Yang <jiaxun.yang@flygoat.com>
> >
> > LDC2/SDC2 opcodes have been rewritten as "load & store with offset"
> > group of instructions by loongson-ext ASE.
> >
> > This patch add implementation of these instructions:
> > gslbx: load 1 bytes to GPR
> > gslhx: load 2 bytes to GPR
> > gslwx: load 4 bytes to GPR
> > gsldx: load 8 bytes to GPR
> > gslwxc1: load 4 bytes to FPR
> > gsldxc1: load 8 bytes to FPR
> > gssbx: store 1 bytes from GPR
> > gsshx: store 2 bytes from GPR
> > gsswx: store 4 bytes from GPR
> > gssdx: store 8 bytes from GPR
> > gsswxc1: store 4 bytes from FPR
> > gssdxc1: store 8 bytes from FPR
> >
> > Details of Loongson-EXT is here:
> > https://github.com/FlyGoat/loongson-insn/blob/master/loongson-ext.md
> >
> > Signed-off-by: Huacai Chen <chenhc@lemote.com>
> > Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
>
> If this patch is from Jiaxun, Huacai's S-o-b should come *after*.
OK, I will do that.

>
> > ---
> >   target/mips/translate.c | 179 ++++++++++++++++++++++++++++++++++++++++++++++++
> >   1 file changed, 179 insertions(+)
> >
> > diff --git a/target/mips/translate.c b/target/mips/translate.c
> > index 916b57f..4d42cfc 100644
> > --- a/target/mips/translate.c
> > +++ b/target/mips/translate.c
> > @@ -484,6 +484,24 @@ enum {
> >       OPC_GSSDRC1     = 0x7 | OPC_GSSHFS,
> >   };
> >
> > +/* Loongson EXT LDC2/SDC2 opcodes */
> > +#define MASK_LOONGSON_LSDC2(op)           (MASK_OP_MAJOR(op) | (op & 0x7))
> > +
> > +enum {
> > +    OPC_GSLBX      = 0x0 | OPC_LDC2,
> > +    OPC_GSLHX      = 0x1 | OPC_LDC2,
> > +    OPC_GSLWX      = 0x2 | OPC_LDC2,
> > +    OPC_GSLDX      = 0x3 | OPC_LDC2,
> > +    OPC_GSLWXC1    = 0x6 | OPC_LDC2,
> > +    OPC_GSLDXC1    = 0x7 | OPC_LDC2,
> > +    OPC_GSSBX      = 0x0 | OPC_SDC2,
> > +    OPC_GSSHX      = 0x1 | OPC_SDC2,
> > +    OPC_GSSWX      = 0x2 | OPC_SDC2,
> > +    OPC_GSSDX      = 0x3 | OPC_SDC2,
> > +    OPC_GSSWXC1    = 0x6 | OPC_SDC2,
> > +    OPC_GSSDXC1    = 0x7 | OPC_SDC2,
> > +};
> > +
> >   /* BSHFL opcodes */
> >   #define MASK_BSHFL(op)              (MASK_SPECIAL3(op) | (op & (0x1F << 6)))
> >
> > @@ -6172,6 +6190,165 @@ static void gen_loongson_lswc2(DisasContext *ctx, int rt,
> >       tcg_temp_free(t0);
> >   }
> >
> > +/* Loongson EXT LDC2/SDC2 */
> > +static void gen_loongson_lsdc2(DisasContext *ctx, int rt,
> > +                                int rs, int rd)
>
> Alignment off (various occurences in this series).
OK, thanks.

>
> > +{
> > +    int offset = (int8_t)(ctx->opcode >> 3);
>
> Please use sextract32() which is easier to read:
>
>         int32_t offset = sextract32(ctx->opcode, 3, 8);
OK, thanks.

>
> > +    uint32_t opc = MASK_LOONGSON_LSDC2(ctx->opcode);
> > +    TCGv t0, t1;
> > +    TCGv_i32 fp0;
> > +
> > +    /* Pre-conditions */
> > +    switch (opc) {
> > +    case OPC_GSLBX:
> > +    case OPC_GSLHX:
> > +    case OPC_GSLWX:
> > +    case OPC_GSLDX:
> > +        /* prefetch, implement as NOP */
> > +        if (rt == 0) {
> > +            return;
> > +        }
> > +        break;
> > +    case OPC_GSSBX:
> > +    case OPC_GSSHX:
> > +    case OPC_GSSWX:
> > +    case OPC_GSSDX:
> > +        break;
> > +    case OPC_GSLWXC1:
> > +#if defined(TARGET_MIPS64)
> > +    case OPC_GSLDXC1:
> > +#endif
> > +        check_cp1_enabled(ctx);
> > +        /* prefetch, implement as NOP */
> > +        if (rt == 0) {
> > +            return;
> > +        }
> > +        break;
> > +    case OPC_GSSWXC1:
> > +#if defined(TARGET_MIPS64)
> > +    case OPC_GSSDXC1:
> > +#endif
> > +        check_cp1_enabled(ctx);
> > +        break;
> > +    default:
> > +        MIPS_INVAL("loongson_lsdc2");
> > +        generate_exception_end(ctx, EXCP_RI);
> > +        return;
> > +        break;
> > +    }
> > +
> > +    t0 = tcg_temp_new();
> > +
> > +    gen_base_offset_addr(ctx, t0, rs, offset);
> > +    gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0);
> > +
> > +    switch (opc) {
> > +    case OPC_GSLBX:
> > +        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_SB);
> > +        gen_store_gpr(t0, rt);
> > +        break;
> > +    case OPC_GSLHX:
> > +        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESW |
> > +                            ctx->default_tcg_memop_mask);
>
> Do Loongson EXT plan to support unaligned accesses?
Not support in hardware, and Linux kernel emulate the unaligned cases.

>
> > +        gen_store_gpr(t0, rt);
> > +        break;
> > +    case OPC_GSLWX:
> > +        gen_base_offset_addr(ctx, t0, rs, offset);
> > +        if (rd) {
> > +            gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0);
> > +        }
> > +        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESL |
> > +                            ctx->default_tcg_memop_mask);
> > +        gen_store_gpr(t0, rt);
> > +        break;
> > +#if defined(TARGET_MIPS64)
> > +    case OPC_GSLDX:
> > +        gen_base_offset_addr(ctx, t0, rs, offset);
> > +        if (rd) {
> > +            gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0);
> > +        }
> > +        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ |
> > +                            ctx->default_tcg_memop_mask);
> > +        gen_store_gpr(t0, rt);
> > +        break;
> > +#endif
> > +    case OPC_GSLWXC1:
> > +        check_cp1_enabled(ctx);
> > +        gen_base_offset_addr(ctx, t0, rs, offset);
> > +        if (rd) {
> > +            gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0);
> > +        }
> > +        fp0 = tcg_temp_new_i32();
> > +        tcg_gen_qemu_ld_i32(fp0, t0, ctx->mem_idx, MO_TESL |
> > +                            ctx->default_tcg_memop_mask);
> > +        gen_store_fpr32(ctx, fp0, rt);
> > +        tcg_temp_free_i32(fp0);
> > +        break;
> > +#if defined(TARGET_MIPS64)
> > +    case OPC_GSLDXC1:
> > +        check_cp1_enabled(ctx);
> > +        gen_base_offset_addr(ctx, t0, rs, offset);
> > +        if (rd) {
> > +            gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0);
> > +        }
> > +        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ |
> > +                            ctx->default_tcg_memop_mask);
> > +        gen_store_fpr64(ctx, t0, rt);
> > +        break;
> > +#endif
> > +    case OPC_GSSBX:
> > +        t1 = tcg_temp_new();
> > +        gen_load_gpr(t1, rt);
> > +        tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_SB);
> > +        tcg_temp_free(t1);
> > +        break;
> > +    case OPC_GSSHX:
> > +        t1 = tcg_temp_new();
> > +        gen_load_gpr(t1, rt);
> > +        tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUW |
> > +                            ctx->default_tcg_memop_mask);
> > +        tcg_temp_free(t1);
> > +        break;
> > +    case OPC_GSSWX:
> > +        t1 = tcg_temp_new();
> > +        gen_load_gpr(t1, rt);
> > +        tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEUL |
> > +                            ctx->default_tcg_memop_mask);
> > +        tcg_temp_free(t1);
> > +        break;
> > +#if defined(TARGET_MIPS64)
> > +    case OPC_GSSDX:
> > +        t1 = tcg_temp_new();
> > +        gen_load_gpr(t1, rt);
> > +        tcg_gen_qemu_st_tl(t1, t0, ctx->mem_idx, MO_TEQ |
> > +                            ctx->default_tcg_memop_mask);
> > +        tcg_temp_free(t1);
> > +        break;
> > +#endif
> > +    case OPC_GSSWXC1:
> > +        fp0 = tcg_temp_new_i32();
> > +        gen_load_fpr32(ctx, fp0, rt);
> > +        tcg_gen_qemu_st_i32(fp0, t0, ctx->mem_idx, MO_TEUL |
> > +                            ctx->default_tcg_memop_mask);
> > +        tcg_temp_free_i32(fp0);
> > +        break;
> > +#if defined(TARGET_MIPS64)
> > +    case OPC_GSSDXC1:
> > +        t1 = tcg_temp_new();
> > +        gen_load_fpr64(ctx, t1, rt);
> > +        tcg_gen_qemu_st_i64(t1, t0, ctx->mem_idx, MO_TEQ |
> > +                            ctx->default_tcg_memop_mask);
> > +        tcg_temp_free(t1);
> > +        break;
> > +#endif
> > +    default:
> > +        break;
> > +    }
> > +
> > +    tcg_temp_free(t0);
> > +}
> > +
> >   /* Traps */
> >   static void gen_trap(DisasContext *ctx, uint32_t opc,
> >                        int rs, int rt, int16_t imm)
> > @@ -31055,6 +31232,8 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx)
> >                   /* OPC_JIC, OPC_JIALC */
> >                   gen_compute_compact_branch(ctx, op, 0, rt, imm);
> >               }
> > +        } else if (ctx->insn_flags & ASE_LEXT) {
> > +            gen_loongson_lsdc2(ctx, rt, rs, rd);
> >           } else {
> >               /* OPC_LWC2, OPC_SWC2 */
> >               /* COP2: Not implemented. */
> >
Huacai


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

* Re: [PATCH V13 6/9] target/mips: Add loongson-ext lsdc2 group of instructions
  2020-10-11  3:02     ` Huacai Chen
@ 2020-10-11 11:13       ` Philippe Mathieu-Daudé
  2020-10-12 10:33         ` Huacai Chen
  0 siblings, 1 reply; 34+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-10-11 11:13 UTC (permalink / raw)
  To: Huacai Chen
  Cc: Huacai Chen, Aleksandar Rikalo, QEMU Developers, Aurelien Jarno,
	Aleksandar Markovic

On 10/11/20 5:02 AM, Huacai Chen wrote:
> Hi, Philippe,
> 
> On Sat, Oct 10, 2020 at 9:07 PM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
>>
>> On 10/7/20 10:39 AM, Huacai Chen wrote:
>>> From: Jiaxun Yang <jiaxun.yang@flygoat.com>
>>>
>>> LDC2/SDC2 opcodes have been rewritten as "load & store with offset"
>>> group of instructions by loongson-ext ASE.
>>>
>>> This patch add implementation of these instructions:
>>> gslbx: load 1 bytes to GPR
>>> gslhx: load 2 bytes to GPR
>>> gslwx: load 4 bytes to GPR
>>> gsldx: load 8 bytes to GPR
>>> gslwxc1: load 4 bytes to FPR
>>> gsldxc1: load 8 bytes to FPR
>>> gssbx: store 1 bytes from GPR
>>> gsshx: store 2 bytes from GPR
>>> gsswx: store 4 bytes from GPR
>>> gssdx: store 8 bytes from GPR
>>> gsswxc1: store 4 bytes from FPR
>>> gssdxc1: store 8 bytes from FPR
>>>
>>> Details of Loongson-EXT is here:
>>> https://github.com/FlyGoat/loongson-insn/blob/master/loongson-ext.md
>>>
>>> Signed-off-by: Huacai Chen <chenhc@lemote.com>
>>> Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
>>
>> If this patch is from Jiaxun, Huacai's S-o-b should come *after*.
> OK, I will do that.
> 
>>
>>> ---
>>>    target/mips/translate.c | 179 ++++++++++++++++++++++++++++++++++++++++++++++++
>>>    1 file changed, 179 insertions(+)
>>>
>>> diff --git a/target/mips/translate.c b/target/mips/translate.c
>>> index 916b57f..4d42cfc 100644
>>> --- a/target/mips/translate.c
>>> +++ b/target/mips/translate.c
>>> @@ -484,6 +484,24 @@ enum {
>>>        OPC_GSSDRC1     = 0x7 | OPC_GSSHFS,
>>>    };
>>>
>>> +/* Loongson EXT LDC2/SDC2 opcodes */
>>> +#define MASK_LOONGSON_LSDC2(op)           (MASK_OP_MAJOR(op) | (op & 0x7))
>>> +
>>> +enum {
>>> +    OPC_GSLBX      = 0x0 | OPC_LDC2,
>>> +    OPC_GSLHX      = 0x1 | OPC_LDC2,
>>> +    OPC_GSLWX      = 0x2 | OPC_LDC2,
>>> +    OPC_GSLDX      = 0x3 | OPC_LDC2,
>>> +    OPC_GSLWXC1    = 0x6 | OPC_LDC2,
>>> +    OPC_GSLDXC1    = 0x7 | OPC_LDC2,
>>> +    OPC_GSSBX      = 0x0 | OPC_SDC2,
>>> +    OPC_GSSHX      = 0x1 | OPC_SDC2,
>>> +    OPC_GSSWX      = 0x2 | OPC_SDC2,
>>> +    OPC_GSSDX      = 0x3 | OPC_SDC2,
>>> +    OPC_GSSWXC1    = 0x6 | OPC_SDC2,
>>> +    OPC_GSSDXC1    = 0x7 | OPC_SDC2,
>>> +};
>>> +
>>>    /* BSHFL opcodes */
>>>    #define MASK_BSHFL(op)              (MASK_SPECIAL3(op) | (op & (0x1F << 6)))
>>>
>>> @@ -6172,6 +6190,165 @@ static void gen_loongson_lswc2(DisasContext *ctx, int rt,
>>>        tcg_temp_free(t0);
>>>    }
>>>
>>> +/* Loongson EXT LDC2/SDC2 */
>>> +static void gen_loongson_lsdc2(DisasContext *ctx, int rt,
>>> +                                int rs, int rd)
>>
>> Alignment off (various occurences in this series).
> OK, thanks.
> 
>>
>>> +{
>>> +    int offset = (int8_t)(ctx->opcode >> 3);
>>
>> Please use sextract32() which is easier to read:
>>
>>          int32_t offset = sextract32(ctx->opcode, 3, 8);
> OK, thanks.
> 
>>
>>> +    uint32_t opc = MASK_LOONGSON_LSDC2(ctx->opcode);
>>> +    TCGv t0, t1;
>>> +    TCGv_i32 fp0;
>>> +
>>> +    /* Pre-conditions */
>>> +    switch (opc) {
>>> +    case OPC_GSLBX:
>>> +    case OPC_GSLHX:
>>> +    case OPC_GSLWX:
>>> +    case OPC_GSLDX:
>>> +        /* prefetch, implement as NOP */
>>> +        if (rt == 0) {
>>> +            return;
>>> +        }
>>> +        break;
>>> +    case OPC_GSSBX:
>>> +    case OPC_GSSHX:
>>> +    case OPC_GSSWX:
>>> +    case OPC_GSSDX:
>>> +        break;
>>> +    case OPC_GSLWXC1:
>>> +#if defined(TARGET_MIPS64)
>>> +    case OPC_GSLDXC1:
>>> +#endif
>>> +        check_cp1_enabled(ctx);
>>> +        /* prefetch, implement as NOP */
>>> +        if (rt == 0) {
>>> +            return;
>>> +        }
>>> +        break;
>>> +    case OPC_GSSWXC1:
>>> +#if defined(TARGET_MIPS64)
>>> +    case OPC_GSSDXC1:
>>> +#endif
>>> +        check_cp1_enabled(ctx);
>>> +        break;
>>> +    default:
>>> +        MIPS_INVAL("loongson_lsdc2");
>>> +        generate_exception_end(ctx, EXCP_RI);
>>> +        return;
>>> +        break;
>>> +    }
>>> +
>>> +    t0 = tcg_temp_new();
>>> +
>>> +    gen_base_offset_addr(ctx, t0, rs, offset);
>>> +    gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0);
>>> +
>>> +    switch (opc) {
>>> +    case OPC_GSLBX:
>>> +        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_SB);
>>> +        gen_store_gpr(t0, rt);
>>> +        break;
>>> +    case OPC_GSLHX:
>>> +        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESW |
>>> +                            ctx->default_tcg_memop_mask);
>>
>> Do Loongson EXT plan to support unaligned accesses?
> Not support in hardware, and Linux kernel emulate the unaligned cases.

OK, that was my understanding. So we don't need to use
default_tcg_memop_mask, we can directly use MO_ALIGN in
place instead.

Regards,

Phil.


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

* Re: [PATCH V13 8/9] hw/mips: Add Loongson-3 machine support
  2020-10-11  2:53     ` Huacai Chen
@ 2020-10-12  8:12       ` Philippe Mathieu-Daudé
  2020-10-13 11:12         ` Huacai Chen
  0 siblings, 1 reply; 34+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-10-12  8:12 UTC (permalink / raw)
  To: Huacai Chen
  Cc: Huacai Chen, Aleksandar Rikalo, QEMU Developers, Aurelien Jarno,
	Aleksandar Markovic

On 10/11/20 4:53 AM, Huacai Chen wrote:
> Hi, Philippe,
> 
> On Sat, Oct 10, 2020 at 5:09 PM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
>>
>> Hi Huacai,
>>
>> On 10/7/20 10:39 AM, Huacai Chen wrote:
>>> Add Loongson-3 based machine support, it use liointc as the interrupt
>>> controler and use GPEX as the pci controller. Currently it can work with
>>> both TCG and KVM.
>>>
>>> As the machine model is not based on any exiting physical hardware, the
>>> name of the machine is "loongson3-virt". It may be superseded in future
>>> by a real machine model. If this happens, then a regular deprecation
>>> procedure shall occur for "loongson3-virt" machine.
>>>
>>> We now already have a full functional Linux kernel (based on Linux-5.4.x
>>> LTS, the kvm host side and guest side have both been upstream for Linux-
>>> 5.9, but Linux-5.9 has not been released yet) here:
>>>
>>> https://github.com/chenhuacai/linux
>>>
>>> Of course the upstream kernel is also usable (though it is "unstable"
>>> now):
>>>
>>> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
>>>
>>> How to use QEMU/Loongson-3?
>>> 1, Download kernel source from the above URL;
>>> 2, Build a kernel with arch/mips/configs/loongson3_defconfig;
>>> 3, Boot a Loongson-3A4000 host with this kernel (for KVM mode);
>>> 4, Build QEMU-master with this patchset;
>>> 5, modprobe kvm (only necessary for KVM mode);
>>> 6, Use QEMU with TCG:
>>>          qemu-system-mips64el -M loongson3-virt,accel=tcg -cpu Loongson-3A1000 -kernel <path_to_kernel> -append ...
>>>      Use QEMU with KVM:
>>>          qemu-system-mips64el -M loongson3-virt,accel=kvm -cpu Loongson-3A4000 -kernel <path_to_kernel> -append ...
>>>
>>>      The "-cpu" parameter is optional here and QEMU will use the correct type for TCG/KVM automatically.
>>>
>>> Signed-off-by: Huacai Chen <chenhc@lemote.com>
>>> Co-developed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
>>> ---
>>>    default-configs/devices/mips64el-softmmu.mak |   1 +
>>>    hw/mips/Kconfig                              |  12 +
>>>    hw/mips/loongson3_bootp.c                    | 162 +++++++
>>>    hw/mips/loongson3_bootp.h                    | 225 ++++++++++
>>
>> In a previous version I asked if you could split the bootp* files
>> (firmware related) in a previous separate patch to ease the review
>> of the machine part.
 >
> In previous version you told me to split the fw_cfg to a separate
> patch, but split the efi-related helpers to seprate files (not to a
> patch). But anyway, I will split them to a patch in the next version.

Sorry if I wasn't clear enough. It is very hard to review a patch
of more than 1000 lines of C code without loosing focus or missing
problems. It explains why big patches might stay unreviewed on the
list. If you can split in smaller logical units, it will be very
helpful.

Peter Maydell rule of thumb is to keep patch below 200 lines.
This is a good limit.

> 
>>
>>>    hw/mips/loongson3_virt.c                     | 615 +++++++++++++++++++++++++++
>>>    hw/mips/meson.build                          |   1 +
>>>    6 files changed, 1016 insertions(+)
>> [...]
>>
>>> diff --git a/hw/mips/loongson3_virt.c b/hw/mips/loongson3_virt.c
>>> new file mode 100644
>>> index 0000000..4e573d6
>>> --- /dev/null
>>> +++ b/hw/mips/loongson3_virt.c
>>> @@ -0,0 +1,615 @@
>>> +/*
>>> + * Generic Loongson-3 Platform support
>>> + *
>>> + * Copyright (c) 2017-2020 Huacai Chen (chenhc@lemote.com)
>>> + * Copyright (c) 2017-2020 Jiaxun Yang <jiaxun.yang@flygoat.com>
>>> + *
>>> + * 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, see <https://www.gnu.org/licenses/>.
>>> + */
>>> +
>>> +/*
>>> + * Generic virtualized PC Platform based on Loongson-3 CPU (MIPS64R2 with
>>> + * extensions, 800~2000MHz)
>>> + */
>>> +
>>> +#include "qemu/osdep.h"
>>> +#include "qemu-common.h"
>>> +#include "qemu/units.h"
>>> +#include "qemu/cutils.h"
>>> +#include "qapi/error.h"
>>> +#include "cpu.h"
>>> +#include "elf.h"
>>> +#include "kvm_mips.h"
>>> +#include "hw/boards.h"
>>> +#include "hw/char/serial.h"
>>> +#include "hw/mips/mips.h"
>>> +#include "hw/mips/cpudevs.h"
>>> +#include "hw/mips/fw_cfg.h"
>>> +#include "hw/mips/loongson3_bootp.h"
>>> +#include "hw/misc/unimp.h"
>>> +#include "hw/intc/i8259.h"
>>> +#include "hw/loader.h"
>>> +#include "hw/isa/superio.h"
>>> +#include "hw/pci/msi.h"
>>> +#include "hw/pci/pci.h"
>>> +#include "hw/pci/pci_host.h"
>>> +#include "hw/pci-host/gpex.h"
>>> +#include "hw/rtc/mc146818rtc.h"
>>> +#include "hw/usb.h"
>>> +#include "net/net.h"
>>> +#include "exec/address-spaces.h"
>>> +#include "sysemu/kvm.h"
>>> +#include "sysemu/qtest.h"
>>> +#include "sysemu/reset.h"
>>> +#include "sysemu/runstate.h"
>>> +#include "qemu/log.h"
>>> +#include "qemu/error-report.h"
>>> +
>>> +#define PM_CNTL_MODE          0x10
>>> +
>>> +#define LOONGSON_MAX_VCPUS      16
>>> +
>>> +#define LOONGSON3_BIOSNAME "bios_loongson3.bin"
>>
>> Where is that file?
 >
> I don't know the policy of QEMU's binary file, just put that in the
> roms directory?

If this is a closed source binary, we reference the URL where it can
be downloaded accepting eventual EULA.
If it is open source, the project is added as submodule. QEMU then
provides a link to how to build the firmware, or if there is no such
documentation, buildsys machinery is added to QEMU to build to it
(see roms/Makefile).

> 
>>
>>> +
>>> +#define UART_IRQ            0
>>> +#define RTC_IRQ             1
>>> +#define PCIE_IRQ_BASE       2
>>> +
>>> +const struct MemmapEntry virt_memmap[] = {
>>> +    [VIRT_LOWMEM] =      { 0x00000000,    0x10000000 },
>>> +    [VIRT_PM] =          { 0x10080000,         0x100 },
>>> +    [VIRT_FW_CFG] =      { 0x10080100,         0x100 },
>>> +    [VIRT_RTC] =         { 0x10081000,        0x1000 },
>>> +    [VIRT_PCIE_PIO] =    { 0x18000000,       0x80000 },
>>> +    [VIRT_PCIE_ECAM] =   { 0x1a000000,     0x2000000 },
>>> +    [VIRT_BIOS_ROM] =    { 0x1fc00000,      0x200000 },
>>> +    [VIRT_UART] =        { 0x1fe001e0,           0x8 },
>>
>> See below about this mapping.
>>
>>> +    [VIRT_LIOINTC] =     { 0x3ff01400,          0x64 },
>>> +    [VIRT_PCIE_MMIO] =   { 0x40000000,    0x40000000 },
>>> +    [VIRT_HIGHMEM] =     { 0x80000000,           0x0 }, /* Variable */
>>> +};
>>> +
>>> +static const struct MemmapEntry loader_memmap[] = {
>>> +    [LOADER_KERNEL] =    { 0x00000000,     0x4000000 },
>>> +    [LOADER_INITRD] =    { 0x04000000,           0x0 }, /* Variable */
>>> +    [LOADER_CMDLINE] =   { 0x0ff00000,      0x100000 },
>>> +};
>>> +
>>> +static const struct MemmapEntry loader_rommap[] = {
>>> +    [LOADER_BOOTROM] =   { 0x1fc00000,        0x1000 },
>>> +    [LOADER_PARAM] =     { 0x1fc01000,       0x10000 },
>>> +};
>>> +
>>> +static struct _loaderparams {
>>> +    uint64_t cpu_freq;
>>> +    uint64_t ram_size;
>>> +    const char *kernel_cmdline;
>>> +    const char *kernel_filename;
>>> +    const char *initrd_filename;
>>> +    uint64_t kernel_entry;
>>> +    uint64_t a0, a1, a2;
>>> +} loaderparams;
>>> +
>>> +static uint64_t loongson3_pm_read(void *opaque, hwaddr addr, unsigned size)
>>> +{
>>> +    return 0;
>>> +}
>>> +
>>> +static void loongson3_pm_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
>>> +{
>>> +    if (addr != PM_CNTL_MODE) {
>>> +        return;
>>> +    }
>>> +
>>> +    switch (val) {
>>> +    case 0x00:
>>> +        qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
>>> +        return;
>>> +    case 0xff:
>>> +        qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
>>> +        return;
>>> +    default:
>>> +        return;
>>> +    }
>>> +}
>>> +
>>> +static const MemoryRegionOps loongson3_pm_ops = {
>>> +    .read  = loongson3_pm_read,
>>> +    .write = loongson3_pm_write,
>>> +    .endianness = DEVICE_NATIVE_ENDIAN,
>>> +};
>>> +
>>> +#define DEF_TCG_FREQ (200 * 1000 * 1000)
>>> +#define DEF_KVM_FREQ (1600 * 1000 * 1000)
>>> +
>>> +static uint64_t get_cpu_freq(void)
>>> +{
>>> +#ifdef CONFIG_KVM
>>> +    int ret;
>>> +    uint64_t freq;
>>> +    struct kvm_one_reg freq_reg = {
>>> +        .id = KVM_REG_MIPS_COUNT_HZ,
>>> +        .addr = (uintptr_t)(&freq)
>>> +    };
>>> +
>>> +    if (kvm_enabled()) {
>>> +        ret = kvm_vcpu_ioctl(first_cpu, KVM_GET_ONE_REG, &freq_reg);
>>> +        if (ret < 0) {
>>> +            return DEF_KVM_FREQ;
>>> +        }
>>> +        return freq * 2;
>>> +    } else {
>>> +        /*
>>> +         * TCG has a default CP0 Timer period 10 ns, which is 100MHz,
>>> +         * CPU frequency is defined as double of CP0 timer frequency.
>>> +         */
>>> +        return DEF_TCG_FREQ;
>>> +    }
>>> +#else
>>> +    return DEF_TCG_FREQ;
>>> +#endif
>>> +}
>>> +
>>> +static void init_boot_param(void)
>>> +{
>>> +    void *p;
>>> +    struct boot_params *bp;
>>> +
>>> +    p = g_malloc0(loader_rommap[LOADER_PARAM].size);
>>> +    bp = p;
>>> +
>>> +    stw_le_p(&bp->efi.smbios.vers, 1);
>>> +    init_reset_system(&(bp->reset_system));
>>> +    p += ROUND_UP(sizeof(struct boot_params), 64);
>>> +    init_loongson_params(&(bp->efi.smbios.lp), p,
>>> +                         loaderparams.cpu_freq, loaderparams.ram_size);
>>> +
>>> +    rom_add_blob_fixed("params_rom", bp,
>>> +                       loader_rommap[LOADER_PARAM].size,
>>> +                       loader_rommap[LOADER_PARAM].base);
>>> +
>>> +    g_free(bp);
>>> +
>>> +    loaderparams.a2 = cpu_mips_phys_to_kseg0(NULL, loader_rommap[LOADER_PARAM].base);
>>> +}
>>> +
>>> +static void init_boot_rom(void)
>>> +{
>>> +    const unsigned int boot_code[] = {
>>> +        0x40086000,   /* mfc0    t0, CP0_STATUS                               */
>>> +        0x240900E4,   /* li      t1, 0xe4         #set kx, sx, ux, erl        */
>>> +        0x01094025,   /* or      t0, t0, t1                                   */
>>> +        0x3C090040,   /* lui     t1, 0x40         #set bev                    */
>>> +        0x01094025,   /* or      t0, t0, t1                                   */
>>> +        0x40886000,   /* mtc0    t0, CP0_STATUS                               */
>>> +        0x00000000,
>>> +        0x40806800,   /* mtc0    zero, CP0_CAUSE                              */
>>> +        0x00000000,
>>> +        0x400A7801,   /* mfc0    t2, $15, 1                                   */
>>> +        0x314A00FF,   /* andi    t2, 0x0ff                                    */
>>> +        0x3C089000,   /* dli     t0, 0x900000003ff01000                       */
>>> +        0x00084438,
>>> +        0x35083FF0,
>>> +        0x00084438,
>>> +        0x35081000,
>>> +        0x314B0003,   /* andi    t3, t2, 0x3      #local cpuid                */
>>> +        0x000B5A00,   /* sll     t3, 8                                        */
>>> +        0x010B4025,   /* or      t0, t0, t3                                   */
>>> +        0x314C000C,   /* andi    t4, t2, 0xc      #node id                    */
>>> +        0x000C62BC,   /* dsll    t4, 42                                       */
>>> +        0x010C4025,   /* or      t0, t0, t4                                   */
>>> +                      /* WaitForInit:                                         */
>>> +        0xDD020020,   /* ld      v0, FN_OFF(t0)   #FN_OFF 0x020               */
>>> +        0x1040FFFE,   /* beqz    v0, WaitForInit                              */
>>> +        0x00000000,   /* nop                                                  */
>>> +        0xDD1D0028,   /* ld      sp, SP_OFF(t0)   #FN_OFF 0x028               */
>>> +        0xDD1C0030,   /* ld      gp, GP_OFF(t0)   #FN_OFF 0x030               */
>>> +        0xDD050038,   /* ld      a1, A1_OFF(t0)   #FN_OFF 0x038               */
>>> +        0x00400008,   /* jr      v0               #byebye                     */
>>> +        0x00000000,   /* nop                                                  */
>>> +        0x1000FFFF,   /* 1:  b   1b                                           */
>>> +        0x00000000,   /* nop                                                  */
>>> +
>>> +                      /* Reset                                                */
>>> +        0x3C0C9000,   /* dli     t0, 0x9000000010080010                       */
>>> +        0x358C0000,
>>> +        0x000C6438,
>>> +        0x358C1008,
>>> +        0x000C6438,
>>> +        0x358C0010,
>>> +        0x240D0000,   /* li      t1, 0x00                                     */
>>> +        0xA18D0000,   /* sb      t1, (t0)                                     */
>>> +        0x1000FFFF,   /* 1:  b   1b                                           */
>>> +        0x00000000,   /* nop                                                  */
>>> +
>>> +                      /* Shutdown                                             */
>>> +        0x3C0C9000,   /* dli     t0, 0x9000000010080010                       */
>>> +        0x358C0000,
>>> +        0x000C6438,
>>> +        0x358C1008,
>>> +        0x000C6438,
>>> +        0x358C0010,
>>> +        0x240D00FF,   /* li      t1, 0xff                                     */
>>> +        0xA18D0000,   /* sb      t1, (t0)                                     */
>>> +        0x1000FFFF,   /* 1:  b   1b                                           */
>>> +        0x00000000    /* nop                                                  */
>>> +    };
>>> +
>>> +    rom_add_blob_fixed("boot_rom", boot_code, sizeof(boot_code),
>>> +                        loader_rommap[LOADER_BOOTROM].base);
>>> +}
>>> +
>>> +static void fw_cfg_boot_set(void *opaque, const char *boot_device,
>>> +                            Error **errp)
>>> +{
>>> +    fw_cfg_modify_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
>>> +}
>>> +
>>> +static void fw_conf_init(unsigned long ram_size)
>>> +{
>>> +    FWCfgState *fw_cfg;
>>> +    hwaddr cfg_addr = virt_memmap[VIRT_FW_CFG].base;
>>> +
>>> +    fw_cfg = fw_cfg_init_mem_wide(cfg_addr, cfg_addr + 8, 8, 0, NULL);
>>> +    fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)current_machine->smp.cpus);
>>> +    fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)current_machine->smp.max_cpus);
>>> +    fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
>>> +    fw_cfg_add_i32(fw_cfg, FW_CFG_MACHINE_VERSION, 1);
>>> +    fw_cfg_add_i64(fw_cfg, FW_CFG_CPU_FREQ, get_cpu_freq());
>>> +    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
>>> +}
>>> +
>>> +static int set_prom_cmdline(ram_addr_t initrd_offset, long initrd_size)
>>> +{
>>> +    hwaddr cmdline_vaddr;
>>> +    char memenv[32];
>>> +    char highmemenv[32];
>>> +    void *cmdline_buf;
>>> +    unsigned int *parg_env;
>>> +    int ret = 0;
>>> +
>>> +    /* Allocate cmdline_buf for command line. */
>>> +    cmdline_buf = g_malloc0(loader_memmap[LOADER_CMDLINE].size);
>>> +    cmdline_vaddr = cpu_mips_phys_to_kseg0(NULL,
>>> +                                           loader_memmap[LOADER_CMDLINE].base);
>>> +
>>> +    /*
>>> +     * Layout of cmdline_buf looks like this:
>>> +     * argv[0], argv[1], 0, env[0], env[1], ... env[i], 0,
>>> +     * argv[0]'s data, argv[1]'s data, env[0]'data, ..., env[i]'s data, 0
>>> +     */
>>> +    parg_env = (void *)cmdline_buf;
>>> +
>>> +    ret = (3 + 1) * 4;
>>> +    *parg_env++ = cmdline_vaddr + ret;
>>> +    ret += (1 + snprintf(cmdline_buf + ret, 256 - ret, "g"));
>>> +
>>> +    /* argv1 */
>>> +    *parg_env++ = cmdline_vaddr + ret;
>>> +    if (initrd_size > 0)
>>> +        ret += (1 + snprintf(cmdline_buf + ret, 256 - ret,
>>> +                "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s",
>>> +                cpu_mips_phys_to_kseg0(NULL, initrd_offset),
>>> +                initrd_size, loaderparams.kernel_cmdline));
>>> +    else
>>> +        ret += (1 + snprintf(cmdline_buf + ret, 256 - ret, "%s",
>>> +                loaderparams.kernel_cmdline));
>>> +
>>> +    /* argv2 */
>>> +    *parg_env++ = cmdline_vaddr + 4 * ret;
>>> +
>>> +    /* env */
>>> +    sprintf(memenv, "%d", 256);
>>> +    sprintf(highmemenv, "%ld", (unsigned long)(loaderparams.ram_size / MiB) - 256);
>>> +
>>> +    rom_add_blob_fixed("cmdline", cmdline_buf,
>>> +                       loader_memmap[LOADER_CMDLINE].size,
>>> +                       loader_memmap[LOADER_CMDLINE].base);
>>> +
>>> +    g_free(cmdline_buf);
>>> +
>>> +    loaderparams.a0 = 2;
>>> +    loaderparams.a1 = cmdline_vaddr;
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +static uint64_t load_kernel(CPUMIPSState *env)
>>> +{
>>> +    long kernel_size;
>>> +    ram_addr_t initrd_offset;
>>> +    uint64_t kernel_entry, kernel_low, kernel_high, initrd_size;
>>> +
>>> +    kernel_size = load_elf(loaderparams.kernel_filename, NULL,
>>> +                           cpu_mips_kseg0_to_phys, NULL,
>>> +                           (uint64_t *)&kernel_entry,
>>> +                           (uint64_t *)&kernel_low, (uint64_t *)&kernel_high,
>>> +                           NULL, 0, EM_MIPS, 1, 0);
>>> +    if (kernel_size < 0) {
>>> +        error_report("could not load kernel '%s': %s",
>>> +                     loaderparams.kernel_filename,
>>> +                     load_elf_strerror(kernel_size));
>>> +        exit(1);
>>> +    }
>>> +
>>> +    /* load initrd */
>>> +    initrd_size = 0;
>>> +    initrd_offset = 0;
>>> +    if (loaderparams.initrd_filename) {
>>> +        initrd_size = get_image_size(loaderparams.initrd_filename);
>>> +        if (initrd_size > 0) {
>>> +            initrd_offset = (kernel_high + ~INITRD_PAGE_MASK) &
>>> +                            INITRD_PAGE_MASK;
>>> +            initrd_offset = MAX(initrd_offset,
>>> +                                loader_memmap[LOADER_INITRD].base);
>>> +
>>> +            if (initrd_offset + initrd_size > ram_size) {
>>> +                error_report("memory too small for initial ram disk '%s'",
>>> +                             loaderparams.initrd_filename);
>>> +                exit(1);
>>> +            }
>>> +
>>> +            initrd_size = load_image_targphys(loaderparams.initrd_filename,
>>> +                                              initrd_offset,
>>> +                                              ram_size - initrd_offset);
>>> +        }
>>> +
>>> +        if (initrd_size == (target_ulong) -1) {
>>> +            error_report("could not load initial ram disk '%s'",
>>> +                         loaderparams.initrd_filename);
>>> +            exit(1);
>>> +        }
>>> +    }
>>> +
>>> +    /* Setup prom cmdline. */
>>> +    set_prom_cmdline(initrd_offset, initrd_size);
>>> +
>>> +    return kernel_entry;
>>> +}
>>> +
>>> +static void main_cpu_reset(void *opaque)
>>> +{
>>> +    MIPSCPU *cpu = opaque;
>>> +    CPUMIPSState *env = &cpu->env;
>>> +
>>> +    cpu_reset(CPU(cpu));
>>> +
>>> +    /* Loongson-3 reset stuff */
>>> +    if (loaderparams.kernel_filename) {
>>> +        if (cpu == MIPS_CPU(first_cpu)) {
>>> +            env->active_tc.gpr[4] = loaderparams.a0;
>>> +            env->active_tc.gpr[5] = loaderparams.a1;
>>> +            env->active_tc.gpr[6] = loaderparams.a2;
>>> +            env->active_tc.PC = loaderparams.kernel_entry;
>>> +        }
>>> +        env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL));
>>> +    }
>>> +}
>>> +
>>> +static inline void loongson3_virt_devices_init(MachineState *machine, DeviceState *pic)
>>> +{
>>> +    int i;
>>> +    qemu_irq irq;
>>> +    PCIBus *pci_bus;
>>> +    DeviceState *dev;
>>> +    MemoryRegion *pio_alias;
>>> +    MemoryRegion *mmio_alias, *mmio_reg;
>>> +    MemoryRegion *ecam_alias, *ecam_reg;
>>> +
>>> +    dev = qdev_new(TYPE_GPEX_HOST);
>>> +    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
>>> +    pci_bus = PCI_HOST_BRIDGE(dev)->bus;
>>> +
>>> +    ecam_alias = g_new0(MemoryRegion, 1);
>>> +    ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
>>> +    memory_region_init_alias(ecam_alias, OBJECT(dev), "pcie-ecam",
>>> +                             ecam_reg, 0, virt_memmap[VIRT_PCIE_ECAM].size);
>>> +    memory_region_add_subregion(get_system_memory(),
>>> +                                virt_memmap[VIRT_PCIE_ECAM].base, ecam_alias);
>>> +
>>> +    mmio_alias = g_new0(MemoryRegion, 1);
>>> +    mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
>>> +    memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio",
>>> +                             mmio_reg, virt_memmap[VIRT_PCIE_MMIO].base,
>>> +                             virt_memmap[VIRT_PCIE_MMIO].size);
>>> +    memory_region_add_subregion(get_system_memory(),
>>> +                                virt_memmap[VIRT_PCIE_MMIO].base, mmio_alias);
>>> +
>>> +    pio_alias = g_new0(MemoryRegion, 1);
>>> +    memory_region_init_alias(pio_alias, OBJECT(dev), "pcie-pio",
>>> +                             get_system_io(), 0, virt_memmap[VIRT_PCIE_PIO].size);
>>> +    memory_region_add_subregion(get_system_memory(),
>>> +                                virt_memmap[VIRT_PCIE_PIO].base, pio_alias);
>>> +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, virt_memmap[VIRT_PCIE_PIO].base);
>>> +
>>> +    for (i = 0; i < GPEX_NUM_IRQS; i++) {
>>> +        irq = qdev_get_gpio_in(pic, PCIE_IRQ_BASE + i);
>>> +        sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
>>> +        gpex_set_irq_num(GPEX_HOST(dev), i, PCIE_IRQ_BASE + i);
>>> +    }
>>> +
>>> +    pci_vga_init(pci_bus);
>>> +
>>> +    if (defaults_enabled()) {
>>> +        pci_create_simple(pci_bus, -1, "pci-ohci");
>>> +        usb_create_simple(usb_bus_find(-1), "usb-kbd");
>>> +        usb_create_simple(usb_bus_find(-1), "usb-tablet");
>>> +    }
>>> +
>>> +    for (i = 0; i < nb_nics; i++) {
>>> +        NICInfo *nd = &nd_table[i];
>>> +
>>> +        if (!nd->model) {
>>> +            nd->model = g_strdup("virtio");
>>> +        }
>>> +
>>> +        pci_nic_init_nofail(nd, pci_bus, nd->model, NULL);
>>> +    }
>>> +}
>>> +
>>> +static void mips_loongson3_virt_init(MachineState *machine)
>>> +{
>>> +    int i;
>>> +    long bios_size;
>>> +    MIPSCPU *cpu;
>>> +    CPUMIPSState *env;
>>> +    DeviceState *liointc;
>>> +    char *filename;
>>> +    const char *kernel_cmdline = machine->kernel_cmdline;
>>> +    const char *kernel_filename = machine->kernel_filename;
>>> +    const char *initrd_filename = machine->initrd_filename;
>>> +    ram_addr_t ram_size = machine->ram_size;
>>> +    MemoryRegion *address_space_mem = get_system_memory();
>>> +    MemoryRegion *ram = g_new(MemoryRegion, 1);
>>> +    MemoryRegion *bios = g_new(MemoryRegion, 1);
>>> +    MemoryRegion *iomem = g_new(MemoryRegion, 1);
>>> +
>>> +    /* TODO: TCG will support all CPU types */
>>> +    if (!kvm_enabled()) {
>>> +        if (!machine->cpu_type) {
>>> +            machine->cpu_type = MIPS_CPU_TYPE_NAME("Loongson-3A1000");
>>> +        }
>>> +        if (!strstr(machine->cpu_type, "Loongson-3A1000")) {
>>> +            error_report("Loongson-3/TCG needs cpu type Loongson-3A1000");
>>> +            exit(1);
>>> +        }
>>
>> IIUC here you need to check machine->smp.cpus is 4 or 8 for the 3A1000.
>> It would be easier if you model this as a qdev SoC, and this model
>> cares to create the 4/8 cores (QEMU MIPSCPU).
>>
>> You defined max_cpu = LOONGSON_MAX_VCPUS = 16, this seems an impossible
>> configuration for the 3A1000.
 >
> There are 4 cores in a SoC, but Loongson-3 support multi-sockets, more
> than 4 vcpus will be treated as multi-sockets automatically in guests.
> And current linux kernel also handle the case that only boot part of 4
> cores in a socket.

What I want to avoid is user booting the machine with 3 or 5 vCPUs,
then complain booting Linux isn't working. It is simpler to check
the number of vCPUs matches the hardware possibilities.

> 
>>
>>> +    } else {
>>> +        if (!machine->cpu_type) {
>>> +            machine->cpu_type = MIPS_CPU_TYPE_NAME("Loongson-3A4000");
>>> +        }
>>> +        if (!strstr(machine->cpu_type, "Loongson-3A4000")) {
>>> +            error_report("Loongson-3/KVM needs cpu type Loongson-3A4000");
>>> +            exit(1);
>>> +        }
>>
>> Similar comment, as the 3A4000 is also a quad-core.
>>
>>> +    }
>>> +
>>> +    if (ram_size < 512 * MiB) {
>>> +        error_report("Loongson-3 machine needs at least 512MB memory");
>>> +        exit(1);
>>> +    }
>>> +
>>> +    /*
>>> +     * The whole MMIO range among configure registers doesn't generate
>>> +     * exception when accessing invalid memory. Create an unimplememted
>>> +     * device to emulate this feature.
>>> +     */
>>> +    create_unimplemented_device("fallback", 0x10000000, 0x30000000);
>>
>> The secondary crosswise switch description is hard to follow:
>>
>> * 2.4 Address routing distribution and configuration
>>
>> According  to  the  default  register  configuration,  CPU [...]
>> 0x10000000-0x1fffffff  of  CPU  (256M)  is  mapped  to
>> 0x10000000-0x1fffffff  of  PCI,  and  0x80000000  of  PCIDMA.
>> In addition, when read access to illegal addresses occurs due to CPU
>> guess execution, all 8 address Windows fail to hit, ?
>>
>> Table 2-9 XBAR level 2 default address configuration
>>                     base                    high                     owner
>> 0 x0000_0000_1000_0000  0 x0000_0000_2000_0000  Low speed I/O (PCI, etc)
>>
>> * 14.4 Secondary cross-switch address window
>>
>> After the address window is configured, the system address
>> 0x0000_2000_0000 is added-- 0x0000_2FFFF_FFFF  maps  to
>> 0x0000_0000_0000  -- 0x0000_0FFF_FFFF  of  memory  controller 0.An
>> access to 0x0000_2000_0000 at this time will result in the original
>> enabledThe value stored at address 0x0000_0000_0000.
>>
>> But see:
>>
>> * 14.6.3 Low speed device address window
>>
>> Here are defined the peripherals in the 0x1c00_0000-0x1ff0_ffff range.
>>
>> * 15.1 System memory space
>>
>> IO device, 0x1000_0000 --  0x1FFF_FFFF
>>
>> * 16 Memory allocation for system X
>>
>> ... divide  the  256M  PCI  space  (0x10000000~0x20000000)  into  two
>> parts:  0x10000000~0x17ffffff for mem space and 0x18000000~0x20000000
>> for IO space.
>>
>> I still don't understand what is in the 0x20000000-0x30000000 range.
> Loongson's user manual is a little confusing, as a native Chinese I
> also feel uncomfortable sometimes. :)
> Generally speaking, Loongson-3's address space is configurable via
> address windows, and the recommended configurations is like this:
> 0x00000000-0x10000000   Low RAM
> 0x10000000-0x40000000   ROM and MMIO Registers (such as BIOS_ROM at
> 0x1fc00000, UART at 0x1fe001e0, LIOINTC at 0x3ff00140)
> 0x40000000-0x80000000  PCI MEM
> 0x80000000-TOM             High RAM

Having a "fallback" region catching everything is not very helpful
when debugging. Listing each unimplemented peripheral is more useful:

   create_unimplemented_device("LPC MEM", 0x1c000000, 32 * MiB);
   ...
   create_unimplemented_device("UART1",   0x1fe001e8, 8);
   create_unimplemented_device("SPI",     0x1fe001f0, 16);
   create_unimplemented_device("LPC IO",  0x1ff00000, 64 * KiB);
   ...

> 
> PCI DMA of 0x10000000-0x1fffffff is a legacy region from
> Loongson-2E/2F, and be cancelled in Loongson-3's configuration.
> In real hardware, there should be a default "big enough" address
> window to catch illegal address, return 0 for read access.
> Yes, there is "nothing" in 0x20000000-0x30000000, because it is
> undocumented which means "reserved for internal usage".

If it is reserved, then the guest shouldn't be trying to use it...

>>
>>> +
>>> +    liointc = qdev_new("loongson.liointc");
>>> +    sysbus_realize_and_unref(SYS_BUS_DEVICE(liointc), &error_fatal);
>>> +
>>> +    sysbus_mmio_map(SYS_BUS_DEVICE(liointc), 0, virt_memmap[VIRT_LIOINTC].base);
>>> +
>>> +    for (i = 0; i < machine->smp.cpus; i++) {
>>> +        int ip;
>>> +
>>> +        /* init CPUs */
>>> +        cpu = MIPS_CPU(cpu_create(machine->cpu_type));
>>> +
>>> +        /* Init internal devices */
>>> +        cpu_mips_irq_init_cpu(cpu);
>>> +        cpu_mips_clock_init(cpu);
>>> +        qemu_register_reset(main_cpu_reset, cpu);
>>> +
>>> +        if (i >= 4) {
>>> +            continue; /* Only node-0 can be connected to LIOINTC */
>>> +        }
>>> +
>>> +        for (ip = 0; ip < 4 ; ip++) {
>>> +            int pin = i * 4 + ip;
>>> +            sysbus_connect_irq(SYS_BUS_DEVICE(liointc),
>>> +                               pin, cpu->env.irq[ip + 2]);
>>> +        }
>>> +    }
>>> +    env = &MIPS_CPU(first_cpu)->env;
>>> +
>>> +    /* Allocate RAM/BIOS, 0x00000000~0x10000000 is alias of 0x80000000~0x90000000 */
>>> +    memory_region_init_rom(bios, NULL, "loongson3.bios",
>>> +                           virt_memmap[VIRT_BIOS_ROM].size, &error_fatal);
>>> +    memory_region_init_alias(ram, NULL, "loongson3.lowmem",
>>> +                           machine->ram, 0, virt_memmap[VIRT_LOWMEM].size);
>>> +    memory_region_init_io(iomem, NULL, &loongson3_pm_ops,
>>> +                           NULL, "loongson3_pm", virt_memmap[VIRT_PM].size);
>>> +
>>> +    memory_region_add_subregion(address_space_mem,
>>> +                      virt_memmap[VIRT_LOWMEM].base, ram);
>>> +    memory_region_add_subregion(address_space_mem,
>>> +                      virt_memmap[VIRT_BIOS_ROM].base, bios);
>>> +    memory_region_add_subregion(address_space_mem,
>>> +                      virt_memmap[VIRT_HIGHMEM].base, machine->ram);
>>> +    memory_region_add_subregion(address_space_mem,
>>> +                      virt_memmap[VIRT_PM].base, iomem);
>>> +
>>> +    /*
>>> +     * We do not support flash operation, just loading bios.bin as raw BIOS.
>>> +     * Please use -L to set the BIOS path and -bios to set bios name.
>>> +     */
>>> +
>>> +    if (kernel_filename) {
>>> +        loaderparams.cpu_freq = get_cpu_freq();
>>> +        loaderparams.ram_size = ram_size;
>>> +        loaderparams.kernel_filename = kernel_filename;
>>> +        loaderparams.kernel_cmdline = kernel_cmdline;
>>> +        loaderparams.initrd_filename = initrd_filename;
>>> +        loaderparams.kernel_entry = load_kernel(env);
>>> +
>>> +        init_boot_rom();
>>> +        init_boot_param();
>>> +    } else {
>>> +        if (bios_name == NULL) {
>>> +                bios_name = LOONGSON3_BIOSNAME;
>>> +        }
>>> +        filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
>>> +        if (filename) {
>>> +            bios_size = load_image_targphys(filename,
>>> +                                            virt_memmap[VIRT_BIOS_ROM].base,
>>> +                                            virt_memmap[VIRT_BIOS_ROM].size);
>>> +            g_free(filename);
>>> +        } else {
>>> +            bios_size = -1;
>>> +        }
>>> +
>>> +        if ((bios_size < 0 || bios_size > virt_memmap[VIRT_BIOS_ROM].size) &&
>>> +            !kernel_filename && !qtest_enabled()) {
>>> +            error_report("Could not load MIPS bios '%s'", bios_name);
>>> +            exit(1);
>>> +        }
>>> +
>>> +        fw_conf_init(ram_size);
>>> +    }
>>> +
>>> +    msi_nonbroken = true;
>>> +    loongson3_virt_devices_init(machine, liointc);
>>> +
>>> +    sysbus_create_simple("goldfish_rtc", virt_memmap[VIRT_RTC].base,
>>> +                         qdev_get_gpio_in(liointc, RTC_IRQ));
>>> +
>>> +    serial_mm_init(address_space_mem, virt_memmap[VIRT_UART].base, 0,
>>> +                   qdev_get_gpio_in(liointc, UART_IRQ), 115200, serial_hd(0),
>>> +                   DEVICE_NATIVE_ENDIAN);
>>
>> You need to split the SoC part from the machine part.
> What do you mean? UART is SoC part and put it near LIOINTC?

I understand the 3A4000 is a system-on-chip (SoC) with various
peripherals (INTC, HT Bus, UART/SPI/I2C Ctrl, GPIO, Temp Sensors,
DDR/ECC Ctrl, ...). Then the Godson-3 is the CPU unit,
embedding the various GS464V cores.

Maybe as:

  +-------------------Machine-----------------+
  |                                           |
  | +--------------Loongson-3------------+    |
  | |                                    |    |
  | |  +------+Godson+3+----+  +----+    |    |
  | |  |                    |  |TEMP|    |    |
  | |  | +------+  +------+ |  +----+    |    |
  | |  | |GS464V|  |GS464V| |            |    |
  | |  | |=1vCPU|  |=1vCPU| |    +-------+    |
  | |  | +------+  +------+ |    |       |    |
  | |  |                    |    | GPIO  |    |
  | |  | +------+  +------+ |    |       |    |
  | |  | |GS464V|  |GS464V| |    +-------+    |
  | |  | |=1vCPU|  |=1vCPU| |            |    |
  | |  | +------+  +------+ |    +-------+    |
  | |  |                    |    |       |    |
  | |  +--------------------+    | LINTC |    |
  | |                            |       |    |
  | |                            +-------+    |
  | |                                    |    |
  | | +------+  +-----+  +-----+ +-----+ |    |
  | | | UART |  | SPI |  | I2C | | ... | |    |
  | +------------------------------------+    |
  |                                           |
  | +-------------+               +-------+   |
  | |    DRAM     |               | FLASH |   |
  | +-------------+               +-------+   |
  +-------------------------------------------+

QEMU tries to model each block as QOM.

Anyway if you are happy with the current state,
this can be improved later.

> 
>>
>>> +}
>>> +
>>> +static void mips_loongson3_virt_machine_init(MachineClass *mc)
>>> +{
>>> +    mc->desc = "Loongson-3 Virtualization Platform";
>>> +    mc->init = mips_loongson3_virt_init;
>>> +    mc->block_default_type = IF_IDE;
>>
>> Don't you need min_cpus = 4?
> I think this is needn't.

Well, you can not have a GS464V with 1 vCPU.

> 
>>
>>> +    mc->max_cpus = LOONGSON_MAX_VCPUS;
>>> +    mc->default_ram_id = "loongson3.highram";
>>> +    mc->default_ram_size = 1600 * MiB;
>>> +    mc->kvm_type = mips_kvm_type;
>>> +    mc->minimum_page_bits = 14;
>>> +}
>>> +
>>> +DEFINE_MACHINE("loongson3-virt", mips_loongson3_virt_machine_init)
>>> diff --git a/hw/mips/meson.build b/hw/mips/meson.build
>>> index c98391c..72db43c 100644
>>> --- a/hw/mips/meson.build
>>> +++ b/hw/mips/meson.build
>>> @@ -1,6 +1,7 @@
>>>    mips_ss = ss.source_set()
>>>    mips_ss.add(files('addr.c', 'mips_int.c', 'fw_cfg.c'))
>>>    mips_ss.add(when: 'CONFIG_FULOONG', if_true: files('fuloong2e.c'))
>>> +mips_ss.add(when: 'CONFIG_LOONGSON3V', if_true: files('loongson3_bootp.c', 'loongson3_virt.c'))
>>>    mips_ss.add(when: 'CONFIG_JAZZ', if_true: files('jazz.c'))
>>>    mips_ss.add(when: 'CONFIG_MALTA', if_true: files('gt64xxx_pci.c', 'malta.c'))
>>>    mips_ss.add(when: 'CONFIG_MIPSSIM', if_true: files('mipssim.c'))
>>>
> Huacai
> 


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

* Re: [PATCH V13 6/9] target/mips: Add loongson-ext lsdc2 group of instructions
  2020-10-11 11:13       ` Philippe Mathieu-Daudé
@ 2020-10-12 10:33         ` Huacai Chen
  2020-10-12 11:04           ` Philippe Mathieu-Daudé
  0 siblings, 1 reply; 34+ messages in thread
From: Huacai Chen @ 2020-10-12 10:33 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Huacai Chen, Aleksandar Rikalo, QEMU Developers, Aurelien Jarno,
	Aleksandar Markovic

Hi, Philippe,

On Sun, Oct 11, 2020 at 7:13 PM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
>
> On 10/11/20 5:02 AM, Huacai Chen wrote:
> > Hi, Philippe,
> >
> > On Sat, Oct 10, 2020 at 9:07 PM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
> >>
> >> On 10/7/20 10:39 AM, Huacai Chen wrote:
> >>> From: Jiaxun Yang <jiaxun.yang@flygoat.com>
> >>>
> >>> LDC2/SDC2 opcodes have been rewritten as "load & store with offset"
> >>> group of instructions by loongson-ext ASE.
> >>>
> >>> This patch add implementation of these instructions:
> >>> gslbx: load 1 bytes to GPR
> >>> gslhx: load 2 bytes to GPR
> >>> gslwx: load 4 bytes to GPR
> >>> gsldx: load 8 bytes to GPR
> >>> gslwxc1: load 4 bytes to FPR
> >>> gsldxc1: load 8 bytes to FPR
> >>> gssbx: store 1 bytes from GPR
> >>> gsshx: store 2 bytes from GPR
> >>> gsswx: store 4 bytes from GPR
> >>> gssdx: store 8 bytes from GPR
> >>> gsswxc1: store 4 bytes from FPR
> >>> gssdxc1: store 8 bytes from FPR
> >>>
> >>> Details of Loongson-EXT is here:
> >>> https://github.com/FlyGoat/loongson-insn/blob/master/loongson-ext.md
> >>>
> >>> Signed-off-by: Huacai Chen <chenhc@lemote.com>
> >>> Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> >>
> >> If this patch is from Jiaxun, Huacai's S-o-b should come *after*.
> > OK, I will do that.
> >
> >>
> >>> ---
> >>>    target/mips/translate.c | 179 ++++++++++++++++++++++++++++++++++++++++++++++++
> >>>    1 file changed, 179 insertions(+)
> >>>
> >>> diff --git a/target/mips/translate.c b/target/mips/translate.c
> >>> index 916b57f..4d42cfc 100644
> >>> --- a/target/mips/translate.c
> >>> +++ b/target/mips/translate.c
> >>> @@ -484,6 +484,24 @@ enum {
> >>>        OPC_GSSDRC1     = 0x7 | OPC_GSSHFS,
> >>>    };
> >>>
> >>> +/* Loongson EXT LDC2/SDC2 opcodes */
> >>> +#define MASK_LOONGSON_LSDC2(op)           (MASK_OP_MAJOR(op) | (op & 0x7))
> >>> +
> >>> +enum {
> >>> +    OPC_GSLBX      = 0x0 | OPC_LDC2,
> >>> +    OPC_GSLHX      = 0x1 | OPC_LDC2,
> >>> +    OPC_GSLWX      = 0x2 | OPC_LDC2,
> >>> +    OPC_GSLDX      = 0x3 | OPC_LDC2,
> >>> +    OPC_GSLWXC1    = 0x6 | OPC_LDC2,
> >>> +    OPC_GSLDXC1    = 0x7 | OPC_LDC2,
> >>> +    OPC_GSSBX      = 0x0 | OPC_SDC2,
> >>> +    OPC_GSSHX      = 0x1 | OPC_SDC2,
> >>> +    OPC_GSSWX      = 0x2 | OPC_SDC2,
> >>> +    OPC_GSSDX      = 0x3 | OPC_SDC2,
> >>> +    OPC_GSSWXC1    = 0x6 | OPC_SDC2,
> >>> +    OPC_GSSDXC1    = 0x7 | OPC_SDC2,
> >>> +};
> >>> +
> >>>    /* BSHFL opcodes */
> >>>    #define MASK_BSHFL(op)              (MASK_SPECIAL3(op) | (op & (0x1F << 6)))
> >>>
> >>> @@ -6172,6 +6190,165 @@ static void gen_loongson_lswc2(DisasContext *ctx, int rt,
> >>>        tcg_temp_free(t0);
> >>>    }
> >>>
> >>> +/* Loongson EXT LDC2/SDC2 */
> >>> +static void gen_loongson_lsdc2(DisasContext *ctx, int rt,
> >>> +                                int rs, int rd)
> >>
> >> Alignment off (various occurences in this series).
> > OK, thanks.
> >
> >>
> >>> +{
> >>> +    int offset = (int8_t)(ctx->opcode >> 3);
> >>
> >> Please use sextract32() which is easier to read:
> >>
> >>          int32_t offset = sextract32(ctx->opcode, 3, 8);
> > OK, thanks.
> >
> >>
> >>> +    uint32_t opc = MASK_LOONGSON_LSDC2(ctx->opcode);
> >>> +    TCGv t0, t1;
> >>> +    TCGv_i32 fp0;
> >>> +
> >>> +    /* Pre-conditions */
> >>> +    switch (opc) {
> >>> +    case OPC_GSLBX:
> >>> +    case OPC_GSLHX:
> >>> +    case OPC_GSLWX:
> >>> +    case OPC_GSLDX:
> >>> +        /* prefetch, implement as NOP */
> >>> +        if (rt == 0) {
> >>> +            return;
> >>> +        }
> >>> +        break;
> >>> +    case OPC_GSSBX:
> >>> +    case OPC_GSSHX:
> >>> +    case OPC_GSSWX:
> >>> +    case OPC_GSSDX:
> >>> +        break;
> >>> +    case OPC_GSLWXC1:
> >>> +#if defined(TARGET_MIPS64)
> >>> +    case OPC_GSLDXC1:
> >>> +#endif
> >>> +        check_cp1_enabled(ctx);
> >>> +        /* prefetch, implement as NOP */
> >>> +        if (rt == 0) {
> >>> +            return;
> >>> +        }
> >>> +        break;
> >>> +    case OPC_GSSWXC1:
> >>> +#if defined(TARGET_MIPS64)
> >>> +    case OPC_GSSDXC1:
> >>> +#endif
> >>> +        check_cp1_enabled(ctx);
> >>> +        break;
> >>> +    default:
> >>> +        MIPS_INVAL("loongson_lsdc2");
> >>> +        generate_exception_end(ctx, EXCP_RI);
> >>> +        return;
> >>> +        break;
> >>> +    }
> >>> +
> >>> +    t0 = tcg_temp_new();
> >>> +
> >>> +    gen_base_offset_addr(ctx, t0, rs, offset);
> >>> +    gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0);
> >>> +
> >>> +    switch (opc) {
> >>> +    case OPC_GSLBX:
> >>> +        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_SB);
> >>> +        gen_store_gpr(t0, rt);
> >>> +        break;
> >>> +    case OPC_GSLHX:
> >>> +        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESW |
> >>> +                            ctx->default_tcg_memop_mask);
> >>
> >> Do Loongson EXT plan to support unaligned accesses?
> > Not support in hardware, and Linux kernel emulate the unaligned cases.
>
> OK, that was my understanding. So we don't need to use
> default_tcg_memop_mask, we can directly use MO_ALIGN in
> place instead.
I read the code again, and found that MIPSR6 uses MO_UNALN while
others use MO_ALIGN. And I also realized that Loongson-3A4000 supports
unaligned access in hardware (the same as R6). So, I think I should
keep default_tcg_memop_mask here. And if possible, I want to set
MO_UNALN for all Loongson-3 processors.

Huacai
>
> Regards,
>
> Phil.


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

* Re: [PATCH V13 6/9] target/mips: Add loongson-ext lsdc2 group of instructions
  2020-10-12 10:33         ` Huacai Chen
@ 2020-10-12 11:04           ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 34+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-10-12 11:04 UTC (permalink / raw)
  To: Huacai Chen
  Cc: Huacai Chen, Aleksandar Rikalo, QEMU Developers, Aurelien Jarno,
	Aleksandar Markovic

On 10/12/20 12:33 PM, Huacai Chen wrote:
> Hi, Philippe,
> 
> On Sun, Oct 11, 2020 at 7:13 PM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
>>
>> On 10/11/20 5:02 AM, Huacai Chen wrote:
>>> Hi, Philippe,
>>>
>>> On Sat, Oct 10, 2020 at 9:07 PM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
>>>>
>>>> On 10/7/20 10:39 AM, Huacai Chen wrote:
>>>>> From: Jiaxun Yang <jiaxun.yang@flygoat.com>
>>>>>
>>>>> LDC2/SDC2 opcodes have been rewritten as "load & store with offset"
>>>>> group of instructions by loongson-ext ASE.
>>>>>
>>>>> This patch add implementation of these instructions:
>>>>> gslbx: load 1 bytes to GPR
>>>>> gslhx: load 2 bytes to GPR
>>>>> gslwx: load 4 bytes to GPR
>>>>> gsldx: load 8 bytes to GPR
>>>>> gslwxc1: load 4 bytes to FPR
>>>>> gsldxc1: load 8 bytes to FPR
>>>>> gssbx: store 1 bytes from GPR
>>>>> gsshx: store 2 bytes from GPR
>>>>> gsswx: store 4 bytes from GPR
>>>>> gssdx: store 8 bytes from GPR
>>>>> gsswxc1: store 4 bytes from FPR
>>>>> gssdxc1: store 8 bytes from FPR
>>>>>
>>>>> Details of Loongson-EXT is here:
>>>>> https://github.com/FlyGoat/loongson-insn/blob/master/loongson-ext.md
>>>>>
>>>>> Signed-off-by: Huacai Chen <chenhc@lemote.com>
>>>>> Signed-off-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
>>>>
>>>> If this patch is from Jiaxun, Huacai's S-o-b should come *after*.
>>> OK, I will do that.
>>>
>>>>
>>>>> ---
>>>>>     target/mips/translate.c | 179 ++++++++++++++++++++++++++++++++++++++++++++++++
>>>>>     1 file changed, 179 insertions(+)
>>>>>
>>>>> diff --git a/target/mips/translate.c b/target/mips/translate.c
>>>>> index 916b57f..4d42cfc 100644
>>>>> --- a/target/mips/translate.c
>>>>> +++ b/target/mips/translate.c
>>>>> @@ -484,6 +484,24 @@ enum {
>>>>>         OPC_GSSDRC1     = 0x7 | OPC_GSSHFS,
>>>>>     };
>>>>>
>>>>> +/* Loongson EXT LDC2/SDC2 opcodes */
>>>>> +#define MASK_LOONGSON_LSDC2(op)           (MASK_OP_MAJOR(op) | (op & 0x7))
>>>>> +
>>>>> +enum {
>>>>> +    OPC_GSLBX      = 0x0 | OPC_LDC2,
>>>>> +    OPC_GSLHX      = 0x1 | OPC_LDC2,
>>>>> +    OPC_GSLWX      = 0x2 | OPC_LDC2,
>>>>> +    OPC_GSLDX      = 0x3 | OPC_LDC2,
>>>>> +    OPC_GSLWXC1    = 0x6 | OPC_LDC2,
>>>>> +    OPC_GSLDXC1    = 0x7 | OPC_LDC2,
>>>>> +    OPC_GSSBX      = 0x0 | OPC_SDC2,
>>>>> +    OPC_GSSHX      = 0x1 | OPC_SDC2,
>>>>> +    OPC_GSSWX      = 0x2 | OPC_SDC2,
>>>>> +    OPC_GSSDX      = 0x3 | OPC_SDC2,
>>>>> +    OPC_GSSWXC1    = 0x6 | OPC_SDC2,
>>>>> +    OPC_GSSDXC1    = 0x7 | OPC_SDC2,
>>>>> +};
>>>>> +
>>>>>     /* BSHFL opcodes */
>>>>>     #define MASK_BSHFL(op)              (MASK_SPECIAL3(op) | (op & (0x1F << 6)))
>>>>>
>>>>> @@ -6172,6 +6190,165 @@ static void gen_loongson_lswc2(DisasContext *ctx, int rt,
>>>>>         tcg_temp_free(t0);
>>>>>     }
>>>>>
>>>>> +/* Loongson EXT LDC2/SDC2 */
>>>>> +static void gen_loongson_lsdc2(DisasContext *ctx, int rt,
>>>>> +                                int rs, int rd)
>>>>
>>>> Alignment off (various occurences in this series).
>>> OK, thanks.
>>>
>>>>
>>>>> +{
>>>>> +    int offset = (int8_t)(ctx->opcode >> 3);
>>>>
>>>> Please use sextract32() which is easier to read:
>>>>
>>>>           int32_t offset = sextract32(ctx->opcode, 3, 8);
>>> OK, thanks.
>>>
>>>>
>>>>> +    uint32_t opc = MASK_LOONGSON_LSDC2(ctx->opcode);
>>>>> +    TCGv t0, t1;
>>>>> +    TCGv_i32 fp0;
>>>>> +
>>>>> +    /* Pre-conditions */
>>>>> +    switch (opc) {
>>>>> +    case OPC_GSLBX:
>>>>> +    case OPC_GSLHX:
>>>>> +    case OPC_GSLWX:
>>>>> +    case OPC_GSLDX:
>>>>> +        /* prefetch, implement as NOP */
>>>>> +        if (rt == 0) {
>>>>> +            return;
>>>>> +        }
>>>>> +        break;
>>>>> +    case OPC_GSSBX:
>>>>> +    case OPC_GSSHX:
>>>>> +    case OPC_GSSWX:
>>>>> +    case OPC_GSSDX:
>>>>> +        break;
>>>>> +    case OPC_GSLWXC1:
>>>>> +#if defined(TARGET_MIPS64)
>>>>> +    case OPC_GSLDXC1:
>>>>> +#endif
>>>>> +        check_cp1_enabled(ctx);
>>>>> +        /* prefetch, implement as NOP */
>>>>> +        if (rt == 0) {
>>>>> +            return;
>>>>> +        }
>>>>> +        break;
>>>>> +    case OPC_GSSWXC1:
>>>>> +#if defined(TARGET_MIPS64)
>>>>> +    case OPC_GSSDXC1:
>>>>> +#endif
>>>>> +        check_cp1_enabled(ctx);
>>>>> +        break;
>>>>> +    default:
>>>>> +        MIPS_INVAL("loongson_lsdc2");
>>>>> +        generate_exception_end(ctx, EXCP_RI);
>>>>> +        return;
>>>>> +        break;
>>>>> +    }
>>>>> +
>>>>> +    t0 = tcg_temp_new();
>>>>> +
>>>>> +    gen_base_offset_addr(ctx, t0, rs, offset);
>>>>> +    gen_op_addr_add(ctx, t0, cpu_gpr[rd], t0);
>>>>> +
>>>>> +    switch (opc) {
>>>>> +    case OPC_GSLBX:
>>>>> +        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_SB);
>>>>> +        gen_store_gpr(t0, rt);
>>>>> +        break;
>>>>> +    case OPC_GSLHX:
>>>>> +        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TESW |
>>>>> +                            ctx->default_tcg_memop_mask);
>>>>
>>>> Do Loongson EXT plan to support unaligned accesses?
>>> Not support in hardware, and Linux kernel emulate the unaligned cases.
>>
>> OK, that was my understanding. So we don't need to use
>> default_tcg_memop_mask, we can directly use MO_ALIGN in
>> place instead.
> I read the code again, and found that MIPSR6 uses MO_UNALN while
> others use MO_ALIGN. And I also realized that Loongson-3A4000 supports
> unaligned access in hardware (the same as R6). So, I think I should
> keep default_tcg_memop_mask here. And if possible, I want to set
> MO_UNALN for all Loongson-3 processors.

OK.

> 
> Huacai
>>
>> Regards,
>>
>> Phil.
> 


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

* Re: [PATCH V13 8/9] hw/mips: Add Loongson-3 machine support
  2020-10-12  8:12       ` Philippe Mathieu-Daudé
@ 2020-10-13 11:12         ` Huacai Chen
  2020-10-13 13:45           ` Philippe Mathieu-Daudé
  0 siblings, 1 reply; 34+ messages in thread
From: Huacai Chen @ 2020-10-13 11:12 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Huacai Chen, Aleksandar Rikalo, QEMU Developers, Aurelien Jarno,
	Aleksandar Markovic

Hi, Philippe,

On Mon, Oct 12, 2020 at 4:12 PM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
>
> On 10/11/20 4:53 AM, Huacai Chen wrote:
> > Hi, Philippe,
> >
> > On Sat, Oct 10, 2020 at 5:09 PM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
> >>
> >> Hi Huacai,
> >>
> >> On 10/7/20 10:39 AM, Huacai Chen wrote:
> >>> Add Loongson-3 based machine support, it use liointc as the interrupt
> >>> controler and use GPEX as the pci controller. Currently it can work with
> >>> both TCG and KVM.
> >>>
> >>> As the machine model is not based on any exiting physical hardware, the
> >>> name of the machine is "loongson3-virt". It may be superseded in future
> >>> by a real machine model. If this happens, then a regular deprecation
> >>> procedure shall occur for "loongson3-virt" machine.
> >>>
> >>> We now already have a full functional Linux kernel (based on Linux-5.4.x
> >>> LTS, the kvm host side and guest side have both been upstream for Linux-
> >>> 5.9, but Linux-5.9 has not been released yet) here:
> >>>
> >>> https://github.com/chenhuacai/linux
> >>>
> >>> Of course the upstream kernel is also usable (though it is "unstable"
> >>> now):
> >>>
> >>> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
> >>>
> >>> How to use QEMU/Loongson-3?
> >>> 1, Download kernel source from the above URL;
> >>> 2, Build a kernel with arch/mips/configs/loongson3_defconfig;
> >>> 3, Boot a Loongson-3A4000 host with this kernel (for KVM mode);
> >>> 4, Build QEMU-master with this patchset;
> >>> 5, modprobe kvm (only necessary for KVM mode);
> >>> 6, Use QEMU with TCG:
> >>>          qemu-system-mips64el -M loongson3-virt,accel=tcg -cpu Loongson-3A1000 -kernel <path_to_kernel> -append ...
> >>>      Use QEMU with KVM:
> >>>          qemu-system-mips64el -M loongson3-virt,accel=kvm -cpu Loongson-3A4000 -kernel <path_to_kernel> -append ...
> >>>
> >>>      The "-cpu" parameter is optional here and QEMU will use the correct type for TCG/KVM automatically.
> >>>
> >>> Signed-off-by: Huacai Chen <chenhc@lemote.com>
> >>> Co-developed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> >>> ---
> >>>    default-configs/devices/mips64el-softmmu.mak |   1 +
> >>>    hw/mips/Kconfig                              |  12 +
> >>>    hw/mips/loongson3_bootp.c                    | 162 +++++++
> >>>    hw/mips/loongson3_bootp.h                    | 225 ++++++++++
> >>
> >> In a previous version I asked if you could split the bootp* files
> >> (firmware related) in a previous separate patch to ease the review
> >> of the machine part.
>  >
> > In previous version you told me to split the fw_cfg to a separate
> > patch, but split the efi-related helpers to seprate files (not to a
> > patch). But anyway, I will split them to a patch in the next version.
>
> Sorry if I wasn't clear enough. It is very hard to review a patch
> of more than 1000 lines of C code without loosing focus or missing
> problems. It explains why big patches might stay unreviewed on the
> list. If you can split in smaller logical units, it will be very
> helpful.
>
> Peter Maydell rule of thumb is to keep patch below 200 lines.
> This is a good limit.
>
> >
> >>
> >>>    hw/mips/loongson3_virt.c                     | 615 +++++++++++++++++++++++++++
> >>>    hw/mips/meson.build                          |   1 +
> >>>    6 files changed, 1016 insertions(+)
> >> [...]
> >>
> >>> diff --git a/hw/mips/loongson3_virt.c b/hw/mips/loongson3_virt.c
> >>> new file mode 100644
> >>> index 0000000..4e573d6
> >>> --- /dev/null
> >>> +++ b/hw/mips/loongson3_virt.c
> >>> @@ -0,0 +1,615 @@
> >>> +/*
> >>> + * Generic Loongson-3 Platform support
> >>> + *
> >>> + * Copyright (c) 2017-2020 Huacai Chen (chenhc@lemote.com)
> >>> + * Copyright (c) 2017-2020 Jiaxun Yang <jiaxun.yang@flygoat.com>
> >>> + *
> >>> + * 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, see <https://www.gnu.org/licenses/>.
> >>> + */
> >>> +
> >>> +/*
> >>> + * Generic virtualized PC Platform based on Loongson-3 CPU (MIPS64R2 with
> >>> + * extensions, 800~2000MHz)
> >>> + */
> >>> +
> >>> +#include "qemu/osdep.h"
> >>> +#include "qemu-common.h"
> >>> +#include "qemu/units.h"
> >>> +#include "qemu/cutils.h"
> >>> +#include "qapi/error.h"
> >>> +#include "cpu.h"
> >>> +#include "elf.h"
> >>> +#include "kvm_mips.h"
> >>> +#include "hw/boards.h"
> >>> +#include "hw/char/serial.h"
> >>> +#include "hw/mips/mips.h"
> >>> +#include "hw/mips/cpudevs.h"
> >>> +#include "hw/mips/fw_cfg.h"
> >>> +#include "hw/mips/loongson3_bootp.h"
> >>> +#include "hw/misc/unimp.h"
> >>> +#include "hw/intc/i8259.h"
> >>> +#include "hw/loader.h"
> >>> +#include "hw/isa/superio.h"
> >>> +#include "hw/pci/msi.h"
> >>> +#include "hw/pci/pci.h"
> >>> +#include "hw/pci/pci_host.h"
> >>> +#include "hw/pci-host/gpex.h"
> >>> +#include "hw/rtc/mc146818rtc.h"
> >>> +#include "hw/usb.h"
> >>> +#include "net/net.h"
> >>> +#include "exec/address-spaces.h"
> >>> +#include "sysemu/kvm.h"
> >>> +#include "sysemu/qtest.h"
> >>> +#include "sysemu/reset.h"
> >>> +#include "sysemu/runstate.h"
> >>> +#include "qemu/log.h"
> >>> +#include "qemu/error-report.h"
> >>> +
> >>> +#define PM_CNTL_MODE          0x10
> >>> +
> >>> +#define LOONGSON_MAX_VCPUS      16
> >>> +
> >>> +#define LOONGSON3_BIOSNAME "bios_loongson3.bin"
> >>
> >> Where is that file?
>  >
> > I don't know the policy of QEMU's binary file, just put that in the
> > roms directory?
>
> If this is a closed source binary, we reference the URL where it can
> be downloaded accepting eventual EULA.
> If it is open source, the project is added as submodule. QEMU then
> provides a link to how to build the firmware, or if there is no such
> documentation, buildsys machinery is added to QEMU to build to it
> (see roms/Makefile).
OK, now the firmware is close-source (maybe open source in future), so
I will put an URL here.

>
> >
> >>
> >>> +
> >>> +#define UART_IRQ            0
> >>> +#define RTC_IRQ             1
> >>> +#define PCIE_IRQ_BASE       2
> >>> +
> >>> +const struct MemmapEntry virt_memmap[] = {
> >>> +    [VIRT_LOWMEM] =      { 0x00000000,    0x10000000 },
> >>> +    [VIRT_PM] =          { 0x10080000,         0x100 },
> >>> +    [VIRT_FW_CFG] =      { 0x10080100,         0x100 },
> >>> +    [VIRT_RTC] =         { 0x10081000,        0x1000 },
> >>> +    [VIRT_PCIE_PIO] =    { 0x18000000,       0x80000 },
> >>> +    [VIRT_PCIE_ECAM] =   { 0x1a000000,     0x2000000 },
> >>> +    [VIRT_BIOS_ROM] =    { 0x1fc00000,      0x200000 },
> >>> +    [VIRT_UART] =        { 0x1fe001e0,           0x8 },
> >>
> >> See below about this mapping.
> >>
> >>> +    [VIRT_LIOINTC] =     { 0x3ff01400,          0x64 },
> >>> +    [VIRT_PCIE_MMIO] =   { 0x40000000,    0x40000000 },
> >>> +    [VIRT_HIGHMEM] =     { 0x80000000,           0x0 }, /* Variable */
> >>> +};
> >>> +
> >>> +static const struct MemmapEntry loader_memmap[] = {
> >>> +    [LOADER_KERNEL] =    { 0x00000000,     0x4000000 },
> >>> +    [LOADER_INITRD] =    { 0x04000000,           0x0 }, /* Variable */
> >>> +    [LOADER_CMDLINE] =   { 0x0ff00000,      0x100000 },
> >>> +};
> >>> +
> >>> +static const struct MemmapEntry loader_rommap[] = {
> >>> +    [LOADER_BOOTROM] =   { 0x1fc00000,        0x1000 },
> >>> +    [LOADER_PARAM] =     { 0x1fc01000,       0x10000 },
> >>> +};
> >>> +
> >>> +static struct _loaderparams {
> >>> +    uint64_t cpu_freq;
> >>> +    uint64_t ram_size;
> >>> +    const char *kernel_cmdline;
> >>> +    const char *kernel_filename;
> >>> +    const char *initrd_filename;
> >>> +    uint64_t kernel_entry;
> >>> +    uint64_t a0, a1, a2;
> >>> +} loaderparams;
> >>> +
> >>> +static uint64_t loongson3_pm_read(void *opaque, hwaddr addr, unsigned size)
> >>> +{
> >>> +    return 0;
> >>> +}
> >>> +
> >>> +static void loongson3_pm_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
> >>> +{
> >>> +    if (addr != PM_CNTL_MODE) {
> >>> +        return;
> >>> +    }
> >>> +
> >>> +    switch (val) {
> >>> +    case 0x00:
> >>> +        qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
> >>> +        return;
> >>> +    case 0xff:
> >>> +        qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
> >>> +        return;
> >>> +    default:
> >>> +        return;
> >>> +    }
> >>> +}
> >>> +
> >>> +static const MemoryRegionOps loongson3_pm_ops = {
> >>> +    .read  = loongson3_pm_read,
> >>> +    .write = loongson3_pm_write,
> >>> +    .endianness = DEVICE_NATIVE_ENDIAN,
> >>> +};
> >>> +
> >>> +#define DEF_TCG_FREQ (200 * 1000 * 1000)
> >>> +#define DEF_KVM_FREQ (1600 * 1000 * 1000)
> >>> +
> >>> +static uint64_t get_cpu_freq(void)
> >>> +{
> >>> +#ifdef CONFIG_KVM
> >>> +    int ret;
> >>> +    uint64_t freq;
> >>> +    struct kvm_one_reg freq_reg = {
> >>> +        .id = KVM_REG_MIPS_COUNT_HZ,
> >>> +        .addr = (uintptr_t)(&freq)
> >>> +    };
> >>> +
> >>> +    if (kvm_enabled()) {
> >>> +        ret = kvm_vcpu_ioctl(first_cpu, KVM_GET_ONE_REG, &freq_reg);
> >>> +        if (ret < 0) {
> >>> +            return DEF_KVM_FREQ;
> >>> +        }
> >>> +        return freq * 2;
> >>> +    } else {
> >>> +        /*
> >>> +         * TCG has a default CP0 Timer period 10 ns, which is 100MHz,
> >>> +         * CPU frequency is defined as double of CP0 timer frequency.
> >>> +         */
> >>> +        return DEF_TCG_FREQ;
> >>> +    }
> >>> +#else
> >>> +    return DEF_TCG_FREQ;
> >>> +#endif
> >>> +}
> >>> +
> >>> +static void init_boot_param(void)
> >>> +{
> >>> +    void *p;
> >>> +    struct boot_params *bp;
> >>> +
> >>> +    p = g_malloc0(loader_rommap[LOADER_PARAM].size);
> >>> +    bp = p;
> >>> +
> >>> +    stw_le_p(&bp->efi.smbios.vers, 1);
> >>> +    init_reset_system(&(bp->reset_system));
> >>> +    p += ROUND_UP(sizeof(struct boot_params), 64);
> >>> +    init_loongson_params(&(bp->efi.smbios.lp), p,
> >>> +                         loaderparams.cpu_freq, loaderparams.ram_size);
> >>> +
> >>> +    rom_add_blob_fixed("params_rom", bp,
> >>> +                       loader_rommap[LOADER_PARAM].size,
> >>> +                       loader_rommap[LOADER_PARAM].base);
> >>> +
> >>> +    g_free(bp);
> >>> +
> >>> +    loaderparams.a2 = cpu_mips_phys_to_kseg0(NULL, loader_rommap[LOADER_PARAM].base);
> >>> +}
> >>> +
> >>> +static void init_boot_rom(void)
> >>> +{
> >>> +    const unsigned int boot_code[] = {
> >>> +        0x40086000,   /* mfc0    t0, CP0_STATUS                               */
> >>> +        0x240900E4,   /* li      t1, 0xe4         #set kx, sx, ux, erl        */
> >>> +        0x01094025,   /* or      t0, t0, t1                                   */
> >>> +        0x3C090040,   /* lui     t1, 0x40         #set bev                    */
> >>> +        0x01094025,   /* or      t0, t0, t1                                   */
> >>> +        0x40886000,   /* mtc0    t0, CP0_STATUS                               */
> >>> +        0x00000000,
> >>> +        0x40806800,   /* mtc0    zero, CP0_CAUSE                              */
> >>> +        0x00000000,
> >>> +        0x400A7801,   /* mfc0    t2, $15, 1                                   */
> >>> +        0x314A00FF,   /* andi    t2, 0x0ff                                    */
> >>> +        0x3C089000,   /* dli     t0, 0x900000003ff01000                       */
> >>> +        0x00084438,
> >>> +        0x35083FF0,
> >>> +        0x00084438,
> >>> +        0x35081000,
> >>> +        0x314B0003,   /* andi    t3, t2, 0x3      #local cpuid                */
> >>> +        0x000B5A00,   /* sll     t3, 8                                        */
> >>> +        0x010B4025,   /* or      t0, t0, t3                                   */
> >>> +        0x314C000C,   /* andi    t4, t2, 0xc      #node id                    */
> >>> +        0x000C62BC,   /* dsll    t4, 42                                       */
> >>> +        0x010C4025,   /* or      t0, t0, t4                                   */
> >>> +                      /* WaitForInit:                                         */
> >>> +        0xDD020020,   /* ld      v0, FN_OFF(t0)   #FN_OFF 0x020               */
> >>> +        0x1040FFFE,   /* beqz    v0, WaitForInit                              */
> >>> +        0x00000000,   /* nop                                                  */
> >>> +        0xDD1D0028,   /* ld      sp, SP_OFF(t0)   #FN_OFF 0x028               */
> >>> +        0xDD1C0030,   /* ld      gp, GP_OFF(t0)   #FN_OFF 0x030               */
> >>> +        0xDD050038,   /* ld      a1, A1_OFF(t0)   #FN_OFF 0x038               */
> >>> +        0x00400008,   /* jr      v0               #byebye                     */
> >>> +        0x00000000,   /* nop                                                  */
> >>> +        0x1000FFFF,   /* 1:  b   1b                                           */
> >>> +        0x00000000,   /* nop                                                  */
> >>> +
> >>> +                      /* Reset                                                */
> >>> +        0x3C0C9000,   /* dli     t0, 0x9000000010080010                       */
> >>> +        0x358C0000,
> >>> +        0x000C6438,
> >>> +        0x358C1008,
> >>> +        0x000C6438,
> >>> +        0x358C0010,
> >>> +        0x240D0000,   /* li      t1, 0x00                                     */
> >>> +        0xA18D0000,   /* sb      t1, (t0)                                     */
> >>> +        0x1000FFFF,   /* 1:  b   1b                                           */
> >>> +        0x00000000,   /* nop                                                  */
> >>> +
> >>> +                      /* Shutdown                                             */
> >>> +        0x3C0C9000,   /* dli     t0, 0x9000000010080010                       */
> >>> +        0x358C0000,
> >>> +        0x000C6438,
> >>> +        0x358C1008,
> >>> +        0x000C6438,
> >>> +        0x358C0010,
> >>> +        0x240D00FF,   /* li      t1, 0xff                                     */
> >>> +        0xA18D0000,   /* sb      t1, (t0)                                     */
> >>> +        0x1000FFFF,   /* 1:  b   1b                                           */
> >>> +        0x00000000    /* nop                                                  */
> >>> +    };
> >>> +
> >>> +    rom_add_blob_fixed("boot_rom", boot_code, sizeof(boot_code),
> >>> +                        loader_rommap[LOADER_BOOTROM].base);
> >>> +}
> >>> +
> >>> +static void fw_cfg_boot_set(void *opaque, const char *boot_device,
> >>> +                            Error **errp)
> >>> +{
> >>> +    fw_cfg_modify_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
> >>> +}
> >>> +
> >>> +static void fw_conf_init(unsigned long ram_size)
> >>> +{
> >>> +    FWCfgState *fw_cfg;
> >>> +    hwaddr cfg_addr = virt_memmap[VIRT_FW_CFG].base;
> >>> +
> >>> +    fw_cfg = fw_cfg_init_mem_wide(cfg_addr, cfg_addr + 8, 8, 0, NULL);
> >>> +    fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)current_machine->smp.cpus);
> >>> +    fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)current_machine->smp.max_cpus);
> >>> +    fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
> >>> +    fw_cfg_add_i32(fw_cfg, FW_CFG_MACHINE_VERSION, 1);
> >>> +    fw_cfg_add_i64(fw_cfg, FW_CFG_CPU_FREQ, get_cpu_freq());
> >>> +    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
> >>> +}
> >>> +
> >>> +static int set_prom_cmdline(ram_addr_t initrd_offset, long initrd_size)
> >>> +{
> >>> +    hwaddr cmdline_vaddr;
> >>> +    char memenv[32];
> >>> +    char highmemenv[32];
> >>> +    void *cmdline_buf;
> >>> +    unsigned int *parg_env;
> >>> +    int ret = 0;
> >>> +
> >>> +    /* Allocate cmdline_buf for command line. */
> >>> +    cmdline_buf = g_malloc0(loader_memmap[LOADER_CMDLINE].size);
> >>> +    cmdline_vaddr = cpu_mips_phys_to_kseg0(NULL,
> >>> +                                           loader_memmap[LOADER_CMDLINE].base);
> >>> +
> >>> +    /*
> >>> +     * Layout of cmdline_buf looks like this:
> >>> +     * argv[0], argv[1], 0, env[0], env[1], ... env[i], 0,
> >>> +     * argv[0]'s data, argv[1]'s data, env[0]'data, ..., env[i]'s data, 0
> >>> +     */
> >>> +    parg_env = (void *)cmdline_buf;
> >>> +
> >>> +    ret = (3 + 1) * 4;
> >>> +    *parg_env++ = cmdline_vaddr + ret;
> >>> +    ret += (1 + snprintf(cmdline_buf + ret, 256 - ret, "g"));
> >>> +
> >>> +    /* argv1 */
> >>> +    *parg_env++ = cmdline_vaddr + ret;
> >>> +    if (initrd_size > 0)
> >>> +        ret += (1 + snprintf(cmdline_buf + ret, 256 - ret,
> >>> +                "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s",
> >>> +                cpu_mips_phys_to_kseg0(NULL, initrd_offset),
> >>> +                initrd_size, loaderparams.kernel_cmdline));
> >>> +    else
> >>> +        ret += (1 + snprintf(cmdline_buf + ret, 256 - ret, "%s",
> >>> +                loaderparams.kernel_cmdline));
> >>> +
> >>> +    /* argv2 */
> >>> +    *parg_env++ = cmdline_vaddr + 4 * ret;
> >>> +
> >>> +    /* env */
> >>> +    sprintf(memenv, "%d", 256);
> >>> +    sprintf(highmemenv, "%ld", (unsigned long)(loaderparams.ram_size / MiB) - 256);
> >>> +
> >>> +    rom_add_blob_fixed("cmdline", cmdline_buf,
> >>> +                       loader_memmap[LOADER_CMDLINE].size,
> >>> +                       loader_memmap[LOADER_CMDLINE].base);
> >>> +
> >>> +    g_free(cmdline_buf);
> >>> +
> >>> +    loaderparams.a0 = 2;
> >>> +    loaderparams.a1 = cmdline_vaddr;
> >>> +
> >>> +    return 0;
> >>> +}
> >>> +
> >>> +static uint64_t load_kernel(CPUMIPSState *env)
> >>> +{
> >>> +    long kernel_size;
> >>> +    ram_addr_t initrd_offset;
> >>> +    uint64_t kernel_entry, kernel_low, kernel_high, initrd_size;
> >>> +
> >>> +    kernel_size = load_elf(loaderparams.kernel_filename, NULL,
> >>> +                           cpu_mips_kseg0_to_phys, NULL,
> >>> +                           (uint64_t *)&kernel_entry,
> >>> +                           (uint64_t *)&kernel_low, (uint64_t *)&kernel_high,
> >>> +                           NULL, 0, EM_MIPS, 1, 0);
> >>> +    if (kernel_size < 0) {
> >>> +        error_report("could not load kernel '%s': %s",
> >>> +                     loaderparams.kernel_filename,
> >>> +                     load_elf_strerror(kernel_size));
> >>> +        exit(1);
> >>> +    }
> >>> +
> >>> +    /* load initrd */
> >>> +    initrd_size = 0;
> >>> +    initrd_offset = 0;
> >>> +    if (loaderparams.initrd_filename) {
> >>> +        initrd_size = get_image_size(loaderparams.initrd_filename);
> >>> +        if (initrd_size > 0) {
> >>> +            initrd_offset = (kernel_high + ~INITRD_PAGE_MASK) &
> >>> +                            INITRD_PAGE_MASK;
> >>> +            initrd_offset = MAX(initrd_offset,
> >>> +                                loader_memmap[LOADER_INITRD].base);
> >>> +
> >>> +            if (initrd_offset + initrd_size > ram_size) {
> >>> +                error_report("memory too small for initial ram disk '%s'",
> >>> +                             loaderparams.initrd_filename);
> >>> +                exit(1);
> >>> +            }
> >>> +
> >>> +            initrd_size = load_image_targphys(loaderparams.initrd_filename,
> >>> +                                              initrd_offset,
> >>> +                                              ram_size - initrd_offset);
> >>> +        }
> >>> +
> >>> +        if (initrd_size == (target_ulong) -1) {
> >>> +            error_report("could not load initial ram disk '%s'",
> >>> +                         loaderparams.initrd_filename);
> >>> +            exit(1);
> >>> +        }
> >>> +    }
> >>> +
> >>> +    /* Setup prom cmdline. */
> >>> +    set_prom_cmdline(initrd_offset, initrd_size);
> >>> +
> >>> +    return kernel_entry;
> >>> +}
> >>> +
> >>> +static void main_cpu_reset(void *opaque)
> >>> +{
> >>> +    MIPSCPU *cpu = opaque;
> >>> +    CPUMIPSState *env = &cpu->env;
> >>> +
> >>> +    cpu_reset(CPU(cpu));
> >>> +
> >>> +    /* Loongson-3 reset stuff */
> >>> +    if (loaderparams.kernel_filename) {
> >>> +        if (cpu == MIPS_CPU(first_cpu)) {
> >>> +            env->active_tc.gpr[4] = loaderparams.a0;
> >>> +            env->active_tc.gpr[5] = loaderparams.a1;
> >>> +            env->active_tc.gpr[6] = loaderparams.a2;
> >>> +            env->active_tc.PC = loaderparams.kernel_entry;
> >>> +        }
> >>> +        env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL));
> >>> +    }
> >>> +}
> >>> +
> >>> +static inline void loongson3_virt_devices_init(MachineState *machine, DeviceState *pic)
> >>> +{
> >>> +    int i;
> >>> +    qemu_irq irq;
> >>> +    PCIBus *pci_bus;
> >>> +    DeviceState *dev;
> >>> +    MemoryRegion *pio_alias;
> >>> +    MemoryRegion *mmio_alias, *mmio_reg;
> >>> +    MemoryRegion *ecam_alias, *ecam_reg;
> >>> +
> >>> +    dev = qdev_new(TYPE_GPEX_HOST);
> >>> +    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> >>> +    pci_bus = PCI_HOST_BRIDGE(dev)->bus;
> >>> +
> >>> +    ecam_alias = g_new0(MemoryRegion, 1);
> >>> +    ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
> >>> +    memory_region_init_alias(ecam_alias, OBJECT(dev), "pcie-ecam",
> >>> +                             ecam_reg, 0, virt_memmap[VIRT_PCIE_ECAM].size);
> >>> +    memory_region_add_subregion(get_system_memory(),
> >>> +                                virt_memmap[VIRT_PCIE_ECAM].base, ecam_alias);
> >>> +
> >>> +    mmio_alias = g_new0(MemoryRegion, 1);
> >>> +    mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
> >>> +    memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio",
> >>> +                             mmio_reg, virt_memmap[VIRT_PCIE_MMIO].base,
> >>> +                             virt_memmap[VIRT_PCIE_MMIO].size);
> >>> +    memory_region_add_subregion(get_system_memory(),
> >>> +                                virt_memmap[VIRT_PCIE_MMIO].base, mmio_alias);
> >>> +
> >>> +    pio_alias = g_new0(MemoryRegion, 1);
> >>> +    memory_region_init_alias(pio_alias, OBJECT(dev), "pcie-pio",
> >>> +                             get_system_io(), 0, virt_memmap[VIRT_PCIE_PIO].size);
> >>> +    memory_region_add_subregion(get_system_memory(),
> >>> +                                virt_memmap[VIRT_PCIE_PIO].base, pio_alias);
> >>> +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, virt_memmap[VIRT_PCIE_PIO].base);
> >>> +
> >>> +    for (i = 0; i < GPEX_NUM_IRQS; i++) {
> >>> +        irq = qdev_get_gpio_in(pic, PCIE_IRQ_BASE + i);
> >>> +        sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
> >>> +        gpex_set_irq_num(GPEX_HOST(dev), i, PCIE_IRQ_BASE + i);
> >>> +    }
> >>> +
> >>> +    pci_vga_init(pci_bus);
> >>> +
> >>> +    if (defaults_enabled()) {
> >>> +        pci_create_simple(pci_bus, -1, "pci-ohci");
> >>> +        usb_create_simple(usb_bus_find(-1), "usb-kbd");
> >>> +        usb_create_simple(usb_bus_find(-1), "usb-tablet");
> >>> +    }
> >>> +
> >>> +    for (i = 0; i < nb_nics; i++) {
> >>> +        NICInfo *nd = &nd_table[i];
> >>> +
> >>> +        if (!nd->model) {
> >>> +            nd->model = g_strdup("virtio");
> >>> +        }
> >>> +
> >>> +        pci_nic_init_nofail(nd, pci_bus, nd->model, NULL);
> >>> +    }
> >>> +}
> >>> +
> >>> +static void mips_loongson3_virt_init(MachineState *machine)
> >>> +{
> >>> +    int i;
> >>> +    long bios_size;
> >>> +    MIPSCPU *cpu;
> >>> +    CPUMIPSState *env;
> >>> +    DeviceState *liointc;
> >>> +    char *filename;
> >>> +    const char *kernel_cmdline = machine->kernel_cmdline;
> >>> +    const char *kernel_filename = machine->kernel_filename;
> >>> +    const char *initrd_filename = machine->initrd_filename;
> >>> +    ram_addr_t ram_size = machine->ram_size;
> >>> +    MemoryRegion *address_space_mem = get_system_memory();
> >>> +    MemoryRegion *ram = g_new(MemoryRegion, 1);
> >>> +    MemoryRegion *bios = g_new(MemoryRegion, 1);
> >>> +    MemoryRegion *iomem = g_new(MemoryRegion, 1);
> >>> +
> >>> +    /* TODO: TCG will support all CPU types */
> >>> +    if (!kvm_enabled()) {
> >>> +        if (!machine->cpu_type) {
> >>> +            machine->cpu_type = MIPS_CPU_TYPE_NAME("Loongson-3A1000");
> >>> +        }
> >>> +        if (!strstr(machine->cpu_type, "Loongson-3A1000")) {
> >>> +            error_report("Loongson-3/TCG needs cpu type Loongson-3A1000");
> >>> +            exit(1);
> >>> +        }
> >>
> >> IIUC here you need to check machine->smp.cpus is 4 or 8 for the 3A1000.
> >> It would be easier if you model this as a qdev SoC, and this model
> >> cares to create the 4/8 cores (QEMU MIPSCPU).
> >>
> >> You defined max_cpu = LOONGSON_MAX_VCPUS = 16, this seems an impossible
> >> configuration for the 3A1000.
>  >
> > There are 4 cores in a SoC, but Loongson-3 support multi-sockets, more
> > than 4 vcpus will be treated as multi-sockets automatically in guests.
> > And current linux kernel also handle the case that only boot part of 4
> > cores in a socket.
>
> What I want to avoid is user booting the machine with 3 or 5 vCPUs,
> then complain booting Linux isn't working. It is simpler to check
> the number of vCPUs matches the hardware possibilities.
The upstream kernel can boot 3 or 5 cores on real hardware (reserve
several cores via boot parameters), so in virtual machine there is
also no problems to boot 3 or 5 vCPUs.

>
> >
> >>
> >>> +    } else {
> >>> +        if (!machine->cpu_type) {
> >>> +            machine->cpu_type = MIPS_CPU_TYPE_NAME("Loongson-3A4000");
> >>> +        }
> >>> +        if (!strstr(machine->cpu_type, "Loongson-3A4000")) {
> >>> +            error_report("Loongson-3/KVM needs cpu type Loongson-3A4000");
> >>> +            exit(1);
> >>> +        }
> >>
> >> Similar comment, as the 3A4000 is also a quad-core.
> >>
> >>> +    }
> >>> +
> >>> +    if (ram_size < 512 * MiB) {
> >>> +        error_report("Loongson-3 machine needs at least 512MB memory");
> >>> +        exit(1);
> >>> +    }
> >>> +
> >>> +    /*
> >>> +     * The whole MMIO range among configure registers doesn't generate
> >>> +     * exception when accessing invalid memory. Create an unimplememted
> >>> +     * device to emulate this feature.
> >>> +     */
> >>> +    create_unimplemented_device("fallback", 0x10000000, 0x30000000);
> >>
> >> The secondary crosswise switch description is hard to follow:
> >>
> >> * 2.4 Address routing distribution and configuration
> >>
> >> According  to  the  default  register  configuration,  CPU [...]
> >> 0x10000000-0x1fffffff  of  CPU  (256M)  is  mapped  to
> >> 0x10000000-0x1fffffff  of  PCI,  and  0x80000000  of  PCIDMA.
> >> In addition, when read access to illegal addresses occurs due to CPU
> >> guess execution, all 8 address Windows fail to hit, ?
> >>
> >> Table 2-9 XBAR level 2 default address configuration
> >>                     base                    high                     owner
> >> 0 x0000_0000_1000_0000  0 x0000_0000_2000_0000  Low speed I/O (PCI, etc)
> >>
> >> * 14.4 Secondary cross-switch address window
> >>
> >> After the address window is configured, the system address
> >> 0x0000_2000_0000 is added-- 0x0000_2FFFF_FFFF  maps  to
> >> 0x0000_0000_0000  -- 0x0000_0FFF_FFFF  of  memory  controller 0.An
> >> access to 0x0000_2000_0000 at this time will result in the original
> >> enabledThe value stored at address 0x0000_0000_0000.
> >>
> >> But see:
> >>
> >> * 14.6.3 Low speed device address window
> >>
> >> Here are defined the peripherals in the 0x1c00_0000-0x1ff0_ffff range.
> >>
> >> * 15.1 System memory space
> >>
> >> IO device, 0x1000_0000 --  0x1FFF_FFFF
> >>
> >> * 16 Memory allocation for system X
> >>
> >> ... divide  the  256M  PCI  space  (0x10000000~0x20000000)  into  two
> >> parts:  0x10000000~0x17ffffff for mem space and 0x18000000~0x20000000
> >> for IO space.
> >>
> >> I still don't understand what is in the 0x20000000-0x30000000 range.
> > Loongson's user manual is a little confusing, as a native Chinese I
> > also feel uncomfortable sometimes. :)
> > Generally speaking, Loongson-3's address space is configurable via
> > address windows, and the recommended configurations is like this:
> > 0x00000000-0x10000000   Low RAM
> > 0x10000000-0x40000000   ROM and MMIO Registers (such as BIOS_ROM at
> > 0x1fc00000, UART at 0x1fe001e0, LIOINTC at 0x3ff00140)
> > 0x40000000-0x80000000  PCI MEM
> > 0x80000000-TOM             High RAM
>
> Having a "fallback" region catching everything is not very helpful
> when debugging. Listing each unimplemented peripheral is more useful:
>
>    create_unimplemented_device("LPC MEM", 0x1c000000, 32 * MiB);
>    ...
>    create_unimplemented_device("UART1",   0x1fe001e8, 8);
>    create_unimplemented_device("SPI",     0x1fe001f0, 16);
>    create_unimplemented_device("LPC IO",  0x1ff00000, 64 * KiB);
>    ...
Catch everything here is because both host and guest use the same
kernel now, and there is some code try to access some address regions
which doesn't exist on virtual machine.

>
> >
> > PCI DMA of 0x10000000-0x1fffffff is a legacy region from
> > Loongson-2E/2F, and be cancelled in Loongson-3's configuration.
> > In real hardware, there should be a default "big enough" address
> > window to catch illegal address, return 0 for read access.
> > Yes, there is "nothing" in 0x20000000-0x30000000, because it is
> > undocumented which means "reserved for internal usage".
>
> If it is reserved, then the guest shouldn't be trying to use it...
OK, this will be improved, but create_uniplemented_device() for every
small region seems not good (see above).

>
> >>
> >>> +
> >>> +    liointc = qdev_new("loongson.liointc");
> >>> +    sysbus_realize_and_unref(SYS_BUS_DEVICE(liointc), &error_fatal);
> >>> +
> >>> +    sysbus_mmio_map(SYS_BUS_DEVICE(liointc), 0, virt_memmap[VIRT_LIOINTC].base);
> >>> +
> >>> +    for (i = 0; i < machine->smp.cpus; i++) {
> >>> +        int ip;
> >>> +
> >>> +        /* init CPUs */
> >>> +        cpu = MIPS_CPU(cpu_create(machine->cpu_type));
> >>> +
> >>> +        /* Init internal devices */
> >>> +        cpu_mips_irq_init_cpu(cpu);
> >>> +        cpu_mips_clock_init(cpu);
> >>> +        qemu_register_reset(main_cpu_reset, cpu);
> >>> +
> >>> +        if (i >= 4) {
> >>> +            continue; /* Only node-0 can be connected to LIOINTC */
> >>> +        }
> >>> +
> >>> +        for (ip = 0; ip < 4 ; ip++) {
> >>> +            int pin = i * 4 + ip;
> >>> +            sysbus_connect_irq(SYS_BUS_DEVICE(liointc),
> >>> +                               pin, cpu->env.irq[ip + 2]);
> >>> +        }
> >>> +    }
> >>> +    env = &MIPS_CPU(first_cpu)->env;
> >>> +
> >>> +    /* Allocate RAM/BIOS, 0x00000000~0x10000000 is alias of 0x80000000~0x90000000 */
> >>> +    memory_region_init_rom(bios, NULL, "loongson3.bios",
> >>> +                           virt_memmap[VIRT_BIOS_ROM].size, &error_fatal);
> >>> +    memory_region_init_alias(ram, NULL, "loongson3.lowmem",
> >>> +                           machine->ram, 0, virt_memmap[VIRT_LOWMEM].size);
> >>> +    memory_region_init_io(iomem, NULL, &loongson3_pm_ops,
> >>> +                           NULL, "loongson3_pm", virt_memmap[VIRT_PM].size);
> >>> +
> >>> +    memory_region_add_subregion(address_space_mem,
> >>> +                      virt_memmap[VIRT_LOWMEM].base, ram);
> >>> +    memory_region_add_subregion(address_space_mem,
> >>> +                      virt_memmap[VIRT_BIOS_ROM].base, bios);
> >>> +    memory_region_add_subregion(address_space_mem,
> >>> +                      virt_memmap[VIRT_HIGHMEM].base, machine->ram);
> >>> +    memory_region_add_subregion(address_space_mem,
> >>> +                      virt_memmap[VIRT_PM].base, iomem);
> >>> +
> >>> +    /*
> >>> +     * We do not support flash operation, just loading bios.bin as raw BIOS.
> >>> +     * Please use -L to set the BIOS path and -bios to set bios name.
> >>> +     */
> >>> +
> >>> +    if (kernel_filename) {
> >>> +        loaderparams.cpu_freq = get_cpu_freq();
> >>> +        loaderparams.ram_size = ram_size;
> >>> +        loaderparams.kernel_filename = kernel_filename;
> >>> +        loaderparams.kernel_cmdline = kernel_cmdline;
> >>> +        loaderparams.initrd_filename = initrd_filename;
> >>> +        loaderparams.kernel_entry = load_kernel(env);
> >>> +
> >>> +        init_boot_rom();
> >>> +        init_boot_param();
> >>> +    } else {
> >>> +        if (bios_name == NULL) {
> >>> +                bios_name = LOONGSON3_BIOSNAME;
> >>> +        }
> >>> +        filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
> >>> +        if (filename) {
> >>> +            bios_size = load_image_targphys(filename,
> >>> +                                            virt_memmap[VIRT_BIOS_ROM].base,
> >>> +                                            virt_memmap[VIRT_BIOS_ROM].size);
> >>> +            g_free(filename);
> >>> +        } else {
> >>> +            bios_size = -1;
> >>> +        }
> >>> +
> >>> +        if ((bios_size < 0 || bios_size > virt_memmap[VIRT_BIOS_ROM].size) &&
> >>> +            !kernel_filename && !qtest_enabled()) {
> >>> +            error_report("Could not load MIPS bios '%s'", bios_name);
> >>> +            exit(1);
> >>> +        }
> >>> +
> >>> +        fw_conf_init(ram_size);
> >>> +    }
> >>> +
> >>> +    msi_nonbroken = true;
> >>> +    loongson3_virt_devices_init(machine, liointc);
> >>> +
> >>> +    sysbus_create_simple("goldfish_rtc", virt_memmap[VIRT_RTC].base,
> >>> +                         qdev_get_gpio_in(liointc, RTC_IRQ));
> >>> +
> >>> +    serial_mm_init(address_space_mem, virt_memmap[VIRT_UART].base, 0,
> >>> +                   qdev_get_gpio_in(liointc, UART_IRQ), 115200, serial_hd(0),
> >>> +                   DEVICE_NATIVE_ENDIAN);
> >>
> >> You need to split the SoC part from the machine part.
> > What do you mean? UART is SoC part and put it near LIOINTC?
>
> I understand the 3A4000 is a system-on-chip (SoC) with various
> peripherals (INTC, HT Bus, UART/SPI/I2C Ctrl, GPIO, Temp Sensors,
> DDR/ECC Ctrl, ...). Then the Godson-3 is the CPU unit,
> embedding the various GS464V cores.
>
> Maybe as:
>
>   +-------------------Machine-----------------+
>   |                                           |
>   | +--------------Loongson-3------------+    |
>   | |                                    |    |
>   | |  +------+Godson+3+----+  +----+    |    |
>   | |  |                    |  |TEMP|    |    |
>   | |  | +------+  +------+ |  +----+    |    |
>   | |  | |GS464V|  |GS464V| |            |    |
>   | |  | |=1vCPU|  |=1vCPU| |    +-------+    |
>   | |  | +------+  +------+ |    |       |    |
>   | |  |                    |    | GPIO  |    |
>   | |  | +------+  +------+ |    |       |    |
>   | |  | |GS464V|  |GS464V| |    +-------+    |
>   | |  | |=1vCPU|  |=1vCPU| |            |    |
>   | |  | +------+  +------+ |    +-------+    |
>   | |  |                    |    |       |    |
>   | |  +--------------------+    | LINTC |    |
>   | |                            |       |    |
>   | |                            +-------+    |
>   | |                                    |    |
>   | | +------+  +-----+  +-----+ +-----+ |    |
>   | | | UART |  | SPI |  | I2C | | ... | |    |
>   | +------------------------------------+    |
>   |                                           |
>   | +-------------+               +-------+   |
>   | |    DRAM     |               | FLASH |   |
>   | +-------------+               +-------+   |
>   +-------------------------------------------+
>
> QEMU tries to model each block as QOM.
>
> Anyway if you are happy with the current state,
> this can be improved later.
>
> >
> >>
> >>> +}
> >>> +
> >>> +static void mips_loongson3_virt_machine_init(MachineClass *mc)
> >>> +{
> >>> +    mc->desc = "Loongson-3 Virtualization Platform";
> >>> +    mc->init = mips_loongson3_virt_init;
> >>> +    mc->block_default_type = IF_IDE;
> >>
> >> Don't you need min_cpus = 4?
> > I think this is needn't.
>
> Well, you can not have a GS464V with 1 vCPU.
It is possible to boot a guest with 1 vCPU. :)

>
> >
> >>
> >>> +    mc->max_cpus = LOONGSON_MAX_VCPUS;
> >>> +    mc->default_ram_id = "loongson3.highram";
> >>> +    mc->default_ram_size = 1600 * MiB;
> >>> +    mc->kvm_type = mips_kvm_type;
> >>> +    mc->minimum_page_bits = 14;
> >>> +}
> >>> +
> >>> +DEFINE_MACHINE("loongson3-virt", mips_loongson3_virt_machine_init)
> >>> diff --git a/hw/mips/meson.build b/hw/mips/meson.build
> >>> index c98391c..72db43c 100644
> >>> --- a/hw/mips/meson.build
> >>> +++ b/hw/mips/meson.build
> >>> @@ -1,6 +1,7 @@
> >>>    mips_ss = ss.source_set()
> >>>    mips_ss.add(files('addr.c', 'mips_int.c', 'fw_cfg.c'))
> >>>    mips_ss.add(when: 'CONFIG_FULOONG', if_true: files('fuloong2e.c'))
> >>> +mips_ss.add(when: 'CONFIG_LOONGSON3V', if_true: files('loongson3_bootp.c', 'loongson3_virt.c'))
> >>>    mips_ss.add(when: 'CONFIG_JAZZ', if_true: files('jazz.c'))
> >>>    mips_ss.add(when: 'CONFIG_MALTA', if_true: files('gt64xxx_pci.c', 'malta.c'))
> >>>    mips_ss.add(when: 'CONFIG_MIPSSIM', if_true: files('mipssim.c'))
> >>>
> > Huacai
> >
Huacai


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

* Re: [PATCH V13 8/9] hw/mips: Add Loongson-3 machine support
  2020-10-13 11:12         ` Huacai Chen
@ 2020-10-13 13:45           ` Philippe Mathieu-Daudé
  2020-10-14  1:28             ` Huacai Chen
  0 siblings, 1 reply; 34+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-10-13 13:45 UTC (permalink / raw)
  To: Huacai Chen
  Cc: Huacai Chen, Aleksandar Rikalo, QEMU Developers, Aurelien Jarno,
	Aleksandar Markovic

On 10/13/20 1:12 PM, Huacai Chen wrote:
> Hi, Philippe,
> 
> On Mon, Oct 12, 2020 at 4:12 PM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
>>
>> On 10/11/20 4:53 AM, Huacai Chen wrote:
>>> Hi, Philippe,
>>>
>>> On Sat, Oct 10, 2020 at 5:09 PM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
>>>>
>>>> Hi Huacai,
>>>>
>>>> On 10/7/20 10:39 AM, Huacai Chen wrote:
>>>>> Add Loongson-3 based machine support, it use liointc as the interrupt
>>>>> controler and use GPEX as the pci controller. Currently it can work with
>>>>> both TCG and KVM.
>>>>>
>>>>> As the machine model is not based on any exiting physical hardware, the
>>>>> name of the machine is "loongson3-virt". It may be superseded in future
>>>>> by a real machine model. If this happens, then a regular deprecation
>>>>> procedure shall occur for "loongson3-virt" machine.
>>>>>
>>>>> We now already have a full functional Linux kernel (based on Linux-5.4.x
>>>>> LTS, the kvm host side and guest side have both been upstream for Linux-
>>>>> 5.9, but Linux-5.9 has not been released yet) here:
>>>>>
>>>>> https://github.com/chenhuacai/linux
>>>>>
>>>>> Of course the upstream kernel is also usable (though it is "unstable"
>>>>> now):
>>>>>
>>>>> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
>>>>>
>>>>> How to use QEMU/Loongson-3?
>>>>> 1, Download kernel source from the above URL;
>>>>> 2, Build a kernel with arch/mips/configs/loongson3_defconfig;
>>>>> 3, Boot a Loongson-3A4000 host with this kernel (for KVM mode);
>>>>> 4, Build QEMU-master with this patchset;
>>>>> 5, modprobe kvm (only necessary for KVM mode);
>>>>> 6, Use QEMU with TCG:
>>>>>           qemu-system-mips64el -M loongson3-virt,accel=tcg -cpu Loongson-3A1000 -kernel <path_to_kernel> -append ...
>>>>>       Use QEMU with KVM:
>>>>>           qemu-system-mips64el -M loongson3-virt,accel=kvm -cpu Loongson-3A4000 -kernel <path_to_kernel> -append ...
>>>>>
>>>>>       The "-cpu" parameter is optional here and QEMU will use the correct type for TCG/KVM automatically.
>>>>>
>>>>> Signed-off-by: Huacai Chen <chenhc@lemote.com>
>>>>> Co-developed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
>>>>> ---
>>>>>     default-configs/devices/mips64el-softmmu.mak |   1 +
>>>>>     hw/mips/Kconfig                              |  12 +
>>>>>     hw/mips/loongson3_bootp.c                    | 162 +++++++
>>>>>     hw/mips/loongson3_bootp.h                    | 225 ++++++++++
>>>>
>>>> In a previous version I asked if you could split the bootp* files
>>>> (firmware related) in a previous separate patch to ease the review
>>>> of the machine part.
>>   >
>>> In previous version you told me to split the fw_cfg to a separate
>>> patch, but split the efi-related helpers to seprate files (not to a
>>> patch). But anyway, I will split them to a patch in the next version.
>>
>> Sorry if I wasn't clear enough. It is very hard to review a patch
>> of more than 1000 lines of C code without loosing focus or missing
>> problems. It explains why big patches might stay unreviewed on the
>> list. If you can split in smaller logical units, it will be very
>> helpful.
>>
>> Peter Maydell rule of thumb is to keep patch below 200 lines.
>> This is a good limit.
>>
>>>
>>>>
>>>>>     hw/mips/loongson3_virt.c                     | 615 +++++++++++++++++++++++++++
>>>>>     hw/mips/meson.build                          |   1 +
>>>>>     6 files changed, 1016 insertions(+)
>>>> [...]
>>>>
>>>>> diff --git a/hw/mips/loongson3_virt.c b/hw/mips/loongson3_virt.c
>>>>> new file mode 100644
>>>>> index 0000000..4e573d6
>>>>> --- /dev/null
>>>>> +++ b/hw/mips/loongson3_virt.c
>>>>> @@ -0,0 +1,615 @@
>>>>> +/*
>>>>> + * Generic Loongson-3 Platform support
>>>>> + *
>>>>> + * Copyright (c) 2017-2020 Huacai Chen (chenhc@lemote.com)
>>>>> + * Copyright (c) 2017-2020 Jiaxun Yang <jiaxun.yang@flygoat.com>
>>>>> + *
>>>>> + * 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, see <https://www.gnu.org/licenses/>.
>>>>> + */
>>>>> +
>>>>> +/*
>>>>> + * Generic virtualized PC Platform based on Loongson-3 CPU (MIPS64R2 with
>>>>> + * extensions, 800~2000MHz)
>>>>> + */
>>>>> +
>>>>> +#include "qemu/osdep.h"
>>>>> +#include "qemu-common.h"
>>>>> +#include "qemu/units.h"
>>>>> +#include "qemu/cutils.h"
>>>>> +#include "qapi/error.h"
>>>>> +#include "cpu.h"
>>>>> +#include "elf.h"
>>>>> +#include "kvm_mips.h"
>>>>> +#include "hw/boards.h"
>>>>> +#include "hw/char/serial.h"
>>>>> +#include "hw/mips/mips.h"
>>>>> +#include "hw/mips/cpudevs.h"
>>>>> +#include "hw/mips/fw_cfg.h"
>>>>> +#include "hw/mips/loongson3_bootp.h"
>>>>> +#include "hw/misc/unimp.h"
>>>>> +#include "hw/intc/i8259.h"
>>>>> +#include "hw/loader.h"
>>>>> +#include "hw/isa/superio.h"
>>>>> +#include "hw/pci/msi.h"
>>>>> +#include "hw/pci/pci.h"
>>>>> +#include "hw/pci/pci_host.h"
>>>>> +#include "hw/pci-host/gpex.h"
>>>>> +#include "hw/rtc/mc146818rtc.h"
>>>>> +#include "hw/usb.h"
>>>>> +#include "net/net.h"
>>>>> +#include "exec/address-spaces.h"
>>>>> +#include "sysemu/kvm.h"
>>>>> +#include "sysemu/qtest.h"
>>>>> +#include "sysemu/reset.h"
>>>>> +#include "sysemu/runstate.h"
>>>>> +#include "qemu/log.h"
>>>>> +#include "qemu/error-report.h"
>>>>> +
>>>>> +#define PM_CNTL_MODE          0x10
>>>>> +
>>>>> +#define LOONGSON_MAX_VCPUS      16
>>>>> +
>>>>> +#define LOONGSON3_BIOSNAME "bios_loongson3.bin"
>>>>
>>>> Where is that file?
>>   >
>>> I don't know the policy of QEMU's binary file, just put that in the
>>> roms directory?
>>
>> If this is a closed source binary, we reference the URL where it can
>> be downloaded accepting eventual EULA.
>> If it is open source, the project is added as submodule. QEMU then
>> provides a link to how to build the firmware, or if there is no such
>> documentation, buildsys machinery is added to QEMU to build to it
>> (see roms/Makefile).
> OK, now the firmware is close-source (maybe open source in future), so
> I will put an URL here.
> 
>>
>>>
>>>>
>>>>> +
>>>>> +#define UART_IRQ            0
>>>>> +#define RTC_IRQ             1
>>>>> +#define PCIE_IRQ_BASE       2
>>>>> +
>>>>> +const struct MemmapEntry virt_memmap[] = {
>>>>> +    [VIRT_LOWMEM] =      { 0x00000000,    0x10000000 },
>>>>> +    [VIRT_PM] =          { 0x10080000,         0x100 },
>>>>> +    [VIRT_FW_CFG] =      { 0x10080100,         0x100 },
>>>>> +    [VIRT_RTC] =         { 0x10081000,        0x1000 },
>>>>> +    [VIRT_PCIE_PIO] =    { 0x18000000,       0x80000 },
>>>>> +    [VIRT_PCIE_ECAM] =   { 0x1a000000,     0x2000000 },
>>>>> +    [VIRT_BIOS_ROM] =    { 0x1fc00000,      0x200000 },
>>>>> +    [VIRT_UART] =        { 0x1fe001e0,           0x8 },
>>>>
>>>> See below about this mapping.
>>>>
>>>>> +    [VIRT_LIOINTC] =     { 0x3ff01400,          0x64 },
>>>>> +    [VIRT_PCIE_MMIO] =   { 0x40000000,    0x40000000 },
>>>>> +    [VIRT_HIGHMEM] =     { 0x80000000,           0x0 }, /* Variable */
>>>>> +};
>>>>> +
>>>>> +static const struct MemmapEntry loader_memmap[] = {
>>>>> +    [LOADER_KERNEL] =    { 0x00000000,     0x4000000 },
>>>>> +    [LOADER_INITRD] =    { 0x04000000,           0x0 }, /* Variable */
>>>>> +    [LOADER_CMDLINE] =   { 0x0ff00000,      0x100000 },
>>>>> +};
>>>>> +
>>>>> +static const struct MemmapEntry loader_rommap[] = {
>>>>> +    [LOADER_BOOTROM] =   { 0x1fc00000,        0x1000 },
>>>>> +    [LOADER_PARAM] =     { 0x1fc01000,       0x10000 },
>>>>> +};
>>>>> +
>>>>> +static struct _loaderparams {
>>>>> +    uint64_t cpu_freq;
>>>>> +    uint64_t ram_size;
>>>>> +    const char *kernel_cmdline;
>>>>> +    const char *kernel_filename;
>>>>> +    const char *initrd_filename;
>>>>> +    uint64_t kernel_entry;
>>>>> +    uint64_t a0, a1, a2;
>>>>> +} loaderparams;
>>>>> +
>>>>> +static uint64_t loongson3_pm_read(void *opaque, hwaddr addr, unsigned size)
>>>>> +{
>>>>> +    return 0;
>>>>> +}
>>>>> +
>>>>> +static void loongson3_pm_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
>>>>> +{
>>>>> +    if (addr != PM_CNTL_MODE) {
>>>>> +        return;
>>>>> +    }
>>>>> +
>>>>> +    switch (val) {
>>>>> +    case 0x00:
>>>>> +        qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
>>>>> +        return;
>>>>> +    case 0xff:
>>>>> +        qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
>>>>> +        return;
>>>>> +    default:
>>>>> +        return;
>>>>> +    }
>>>>> +}
>>>>> +
>>>>> +static const MemoryRegionOps loongson3_pm_ops = {
>>>>> +    .read  = loongson3_pm_read,
>>>>> +    .write = loongson3_pm_write,
>>>>> +    .endianness = DEVICE_NATIVE_ENDIAN,
>>>>> +};
>>>>> +
>>>>> +#define DEF_TCG_FREQ (200 * 1000 * 1000)
>>>>> +#define DEF_KVM_FREQ (1600 * 1000 * 1000)
>>>>> +
>>>>> +static uint64_t get_cpu_freq(void)
>>>>> +{
>>>>> +#ifdef CONFIG_KVM
>>>>> +    int ret;
>>>>> +    uint64_t freq;
>>>>> +    struct kvm_one_reg freq_reg = {
>>>>> +        .id = KVM_REG_MIPS_COUNT_HZ,
>>>>> +        .addr = (uintptr_t)(&freq)
>>>>> +    };
>>>>> +
>>>>> +    if (kvm_enabled()) {
>>>>> +        ret = kvm_vcpu_ioctl(first_cpu, KVM_GET_ONE_REG, &freq_reg);
>>>>> +        if (ret < 0) {
>>>>> +            return DEF_KVM_FREQ;
>>>>> +        }
>>>>> +        return freq * 2;
>>>>> +    } else {
>>>>> +        /*
>>>>> +         * TCG has a default CP0 Timer period 10 ns, which is 100MHz,
>>>>> +         * CPU frequency is defined as double of CP0 timer frequency.
>>>>> +         */
>>>>> +        return DEF_TCG_FREQ;
>>>>> +    }
>>>>> +#else
>>>>> +    return DEF_TCG_FREQ;
>>>>> +#endif
>>>>> +}
>>>>> +
>>>>> +static void init_boot_param(void)
>>>>> +{
>>>>> +    void *p;
>>>>> +    struct boot_params *bp;
>>>>> +
>>>>> +    p = g_malloc0(loader_rommap[LOADER_PARAM].size);
>>>>> +    bp = p;
>>>>> +
>>>>> +    stw_le_p(&bp->efi.smbios.vers, 1);
>>>>> +    init_reset_system(&(bp->reset_system));
>>>>> +    p += ROUND_UP(sizeof(struct boot_params), 64);
>>>>> +    init_loongson_params(&(bp->efi.smbios.lp), p,
>>>>> +                         loaderparams.cpu_freq, loaderparams.ram_size);
>>>>> +
>>>>> +    rom_add_blob_fixed("params_rom", bp,
>>>>> +                       loader_rommap[LOADER_PARAM].size,
>>>>> +                       loader_rommap[LOADER_PARAM].base);
>>>>> +
>>>>> +    g_free(bp);
>>>>> +
>>>>> +    loaderparams.a2 = cpu_mips_phys_to_kseg0(NULL, loader_rommap[LOADER_PARAM].base);
>>>>> +}
>>>>> +
>>>>> +static void init_boot_rom(void)
>>>>> +{
>>>>> +    const unsigned int boot_code[] = {
>>>>> +        0x40086000,   /* mfc0    t0, CP0_STATUS                               */
>>>>> +        0x240900E4,   /* li      t1, 0xe4         #set kx, sx, ux, erl        */
>>>>> +        0x01094025,   /* or      t0, t0, t1                                   */
>>>>> +        0x3C090040,   /* lui     t1, 0x40         #set bev                    */
>>>>> +        0x01094025,   /* or      t0, t0, t1                                   */
>>>>> +        0x40886000,   /* mtc0    t0, CP0_STATUS                               */
>>>>> +        0x00000000,
>>>>> +        0x40806800,   /* mtc0    zero, CP0_CAUSE                              */
>>>>> +        0x00000000,
>>>>> +        0x400A7801,   /* mfc0    t2, $15, 1                                   */
>>>>> +        0x314A00FF,   /* andi    t2, 0x0ff                                    */
>>>>> +        0x3C089000,   /* dli     t0, 0x900000003ff01000                       */
>>>>> +        0x00084438,
>>>>> +        0x35083FF0,
>>>>> +        0x00084438,
>>>>> +        0x35081000,
>>>>> +        0x314B0003,   /* andi    t3, t2, 0x3      #local cpuid                */
>>>>> +        0x000B5A00,   /* sll     t3, 8                                        */
>>>>> +        0x010B4025,   /* or      t0, t0, t3                                   */
>>>>> +        0x314C000C,   /* andi    t4, t2, 0xc      #node id                    */
>>>>> +        0x000C62BC,   /* dsll    t4, 42                                       */
>>>>> +        0x010C4025,   /* or      t0, t0, t4                                   */
>>>>> +                      /* WaitForInit:                                         */
>>>>> +        0xDD020020,   /* ld      v0, FN_OFF(t0)   #FN_OFF 0x020               */
>>>>> +        0x1040FFFE,   /* beqz    v0, WaitForInit                              */
>>>>> +        0x00000000,   /* nop                                                  */
>>>>> +        0xDD1D0028,   /* ld      sp, SP_OFF(t0)   #FN_OFF 0x028               */
>>>>> +        0xDD1C0030,   /* ld      gp, GP_OFF(t0)   #FN_OFF 0x030               */
>>>>> +        0xDD050038,   /* ld      a1, A1_OFF(t0)   #FN_OFF 0x038               */
>>>>> +        0x00400008,   /* jr      v0               #byebye                     */
>>>>> +        0x00000000,   /* nop                                                  */
>>>>> +        0x1000FFFF,   /* 1:  b   1b                                           */
>>>>> +        0x00000000,   /* nop                                                  */
>>>>> +
>>>>> +                      /* Reset                                                */
>>>>> +        0x3C0C9000,   /* dli     t0, 0x9000000010080010                       */
>>>>> +        0x358C0000,
>>>>> +        0x000C6438,
>>>>> +        0x358C1008,
>>>>> +        0x000C6438,
>>>>> +        0x358C0010,
>>>>> +        0x240D0000,   /* li      t1, 0x00                                     */
>>>>> +        0xA18D0000,   /* sb      t1, (t0)                                     */
>>>>> +        0x1000FFFF,   /* 1:  b   1b                                           */
>>>>> +        0x00000000,   /* nop                                                  */
>>>>> +
>>>>> +                      /* Shutdown                                             */
>>>>> +        0x3C0C9000,   /* dli     t0, 0x9000000010080010                       */
>>>>> +        0x358C0000,
>>>>> +        0x000C6438,
>>>>> +        0x358C1008,
>>>>> +        0x000C6438,
>>>>> +        0x358C0010,
>>>>> +        0x240D00FF,   /* li      t1, 0xff                                     */
>>>>> +        0xA18D0000,   /* sb      t1, (t0)                                     */
>>>>> +        0x1000FFFF,   /* 1:  b   1b                                           */
>>>>> +        0x00000000    /* nop                                                  */
>>>>> +    };
>>>>> +
>>>>> +    rom_add_blob_fixed("boot_rom", boot_code, sizeof(boot_code),
>>>>> +                        loader_rommap[LOADER_BOOTROM].base);
>>>>> +}
>>>>> +
>>>>> +static void fw_cfg_boot_set(void *opaque, const char *boot_device,
>>>>> +                            Error **errp)
>>>>> +{
>>>>> +    fw_cfg_modify_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
>>>>> +}
>>>>> +
>>>>> +static void fw_conf_init(unsigned long ram_size)
>>>>> +{
>>>>> +    FWCfgState *fw_cfg;
>>>>> +    hwaddr cfg_addr = virt_memmap[VIRT_FW_CFG].base;
>>>>> +
>>>>> +    fw_cfg = fw_cfg_init_mem_wide(cfg_addr, cfg_addr + 8, 8, 0, NULL);
>>>>> +    fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)current_machine->smp.cpus);
>>>>> +    fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)current_machine->smp.max_cpus);
>>>>> +    fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
>>>>> +    fw_cfg_add_i32(fw_cfg, FW_CFG_MACHINE_VERSION, 1);
>>>>> +    fw_cfg_add_i64(fw_cfg, FW_CFG_CPU_FREQ, get_cpu_freq());
>>>>> +    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
>>>>> +}
>>>>> +
>>>>> +static int set_prom_cmdline(ram_addr_t initrd_offset, long initrd_size)
>>>>> +{
>>>>> +    hwaddr cmdline_vaddr;
>>>>> +    char memenv[32];
>>>>> +    char highmemenv[32];
>>>>> +    void *cmdline_buf;
>>>>> +    unsigned int *parg_env;
>>>>> +    int ret = 0;
>>>>> +
>>>>> +    /* Allocate cmdline_buf for command line. */
>>>>> +    cmdline_buf = g_malloc0(loader_memmap[LOADER_CMDLINE].size);
>>>>> +    cmdline_vaddr = cpu_mips_phys_to_kseg0(NULL,
>>>>> +                                           loader_memmap[LOADER_CMDLINE].base);
>>>>> +
>>>>> +    /*
>>>>> +     * Layout of cmdline_buf looks like this:
>>>>> +     * argv[0], argv[1], 0, env[0], env[1], ... env[i], 0,
>>>>> +     * argv[0]'s data, argv[1]'s data, env[0]'data, ..., env[i]'s data, 0
>>>>> +     */
>>>>> +    parg_env = (void *)cmdline_buf;
>>>>> +
>>>>> +    ret = (3 + 1) * 4;
>>>>> +    *parg_env++ = cmdline_vaddr + ret;
>>>>> +    ret += (1 + snprintf(cmdline_buf + ret, 256 - ret, "g"));
>>>>> +
>>>>> +    /* argv1 */
>>>>> +    *parg_env++ = cmdline_vaddr + ret;
>>>>> +    if (initrd_size > 0)
>>>>> +        ret += (1 + snprintf(cmdline_buf + ret, 256 - ret,
>>>>> +                "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s",
>>>>> +                cpu_mips_phys_to_kseg0(NULL, initrd_offset),
>>>>> +                initrd_size, loaderparams.kernel_cmdline));
>>>>> +    else
>>>>> +        ret += (1 + snprintf(cmdline_buf + ret, 256 - ret, "%s",
>>>>> +                loaderparams.kernel_cmdline));
>>>>> +
>>>>> +    /* argv2 */
>>>>> +    *parg_env++ = cmdline_vaddr + 4 * ret;
>>>>> +
>>>>> +    /* env */
>>>>> +    sprintf(memenv, "%d", 256);
>>>>> +    sprintf(highmemenv, "%ld", (unsigned long)(loaderparams.ram_size / MiB) - 256);
>>>>> +
>>>>> +    rom_add_blob_fixed("cmdline", cmdline_buf,
>>>>> +                       loader_memmap[LOADER_CMDLINE].size,
>>>>> +                       loader_memmap[LOADER_CMDLINE].base);
>>>>> +
>>>>> +    g_free(cmdline_buf);
>>>>> +
>>>>> +    loaderparams.a0 = 2;
>>>>> +    loaderparams.a1 = cmdline_vaddr;
>>>>> +
>>>>> +    return 0;
>>>>> +}
>>>>> +
>>>>> +static uint64_t load_kernel(CPUMIPSState *env)
>>>>> +{
>>>>> +    long kernel_size;
>>>>> +    ram_addr_t initrd_offset;
>>>>> +    uint64_t kernel_entry, kernel_low, kernel_high, initrd_size;
>>>>> +
>>>>> +    kernel_size = load_elf(loaderparams.kernel_filename, NULL,
>>>>> +                           cpu_mips_kseg0_to_phys, NULL,
>>>>> +                           (uint64_t *)&kernel_entry,
>>>>> +                           (uint64_t *)&kernel_low, (uint64_t *)&kernel_high,
>>>>> +                           NULL, 0, EM_MIPS, 1, 0);
>>>>> +    if (kernel_size < 0) {
>>>>> +        error_report("could not load kernel '%s': %s",
>>>>> +                     loaderparams.kernel_filename,
>>>>> +                     load_elf_strerror(kernel_size));
>>>>> +        exit(1);
>>>>> +    }
>>>>> +
>>>>> +    /* load initrd */
>>>>> +    initrd_size = 0;
>>>>> +    initrd_offset = 0;
>>>>> +    if (loaderparams.initrd_filename) {
>>>>> +        initrd_size = get_image_size(loaderparams.initrd_filename);
>>>>> +        if (initrd_size > 0) {
>>>>> +            initrd_offset = (kernel_high + ~INITRD_PAGE_MASK) &
>>>>> +                            INITRD_PAGE_MASK;
>>>>> +            initrd_offset = MAX(initrd_offset,
>>>>> +                                loader_memmap[LOADER_INITRD].base);
>>>>> +
>>>>> +            if (initrd_offset + initrd_size > ram_size) {
>>>>> +                error_report("memory too small for initial ram disk '%s'",
>>>>> +                             loaderparams.initrd_filename);
>>>>> +                exit(1);
>>>>> +            }
>>>>> +
>>>>> +            initrd_size = load_image_targphys(loaderparams.initrd_filename,
>>>>> +                                              initrd_offset,
>>>>> +                                              ram_size - initrd_offset);
>>>>> +        }
>>>>> +
>>>>> +        if (initrd_size == (target_ulong) -1) {
>>>>> +            error_report("could not load initial ram disk '%s'",
>>>>> +                         loaderparams.initrd_filename);
>>>>> +            exit(1);
>>>>> +        }
>>>>> +    }
>>>>> +
>>>>> +    /* Setup prom cmdline. */
>>>>> +    set_prom_cmdline(initrd_offset, initrd_size);
>>>>> +
>>>>> +    return kernel_entry;
>>>>> +}
>>>>> +
>>>>> +static void main_cpu_reset(void *opaque)
>>>>> +{
>>>>> +    MIPSCPU *cpu = opaque;
>>>>> +    CPUMIPSState *env = &cpu->env;
>>>>> +
>>>>> +    cpu_reset(CPU(cpu));
>>>>> +
>>>>> +    /* Loongson-3 reset stuff */
>>>>> +    if (loaderparams.kernel_filename) {
>>>>> +        if (cpu == MIPS_CPU(first_cpu)) {
>>>>> +            env->active_tc.gpr[4] = loaderparams.a0;
>>>>> +            env->active_tc.gpr[5] = loaderparams.a1;
>>>>> +            env->active_tc.gpr[6] = loaderparams.a2;
>>>>> +            env->active_tc.PC = loaderparams.kernel_entry;
>>>>> +        }
>>>>> +        env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL));
>>>>> +    }
>>>>> +}
>>>>> +
>>>>> +static inline void loongson3_virt_devices_init(MachineState *machine, DeviceState *pic)
>>>>> +{
>>>>> +    int i;
>>>>> +    qemu_irq irq;
>>>>> +    PCIBus *pci_bus;
>>>>> +    DeviceState *dev;
>>>>> +    MemoryRegion *pio_alias;
>>>>> +    MemoryRegion *mmio_alias, *mmio_reg;
>>>>> +    MemoryRegion *ecam_alias, *ecam_reg;
>>>>> +
>>>>> +    dev = qdev_new(TYPE_GPEX_HOST);
>>>>> +    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
>>>>> +    pci_bus = PCI_HOST_BRIDGE(dev)->bus;
>>>>> +
>>>>> +    ecam_alias = g_new0(MemoryRegion, 1);
>>>>> +    ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
>>>>> +    memory_region_init_alias(ecam_alias, OBJECT(dev), "pcie-ecam",
>>>>> +                             ecam_reg, 0, virt_memmap[VIRT_PCIE_ECAM].size);
>>>>> +    memory_region_add_subregion(get_system_memory(),
>>>>> +                                virt_memmap[VIRT_PCIE_ECAM].base, ecam_alias);
>>>>> +
>>>>> +    mmio_alias = g_new0(MemoryRegion, 1);
>>>>> +    mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
>>>>> +    memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio",
>>>>> +                             mmio_reg, virt_memmap[VIRT_PCIE_MMIO].base,
>>>>> +                             virt_memmap[VIRT_PCIE_MMIO].size);
>>>>> +    memory_region_add_subregion(get_system_memory(),
>>>>> +                                virt_memmap[VIRT_PCIE_MMIO].base, mmio_alias);
>>>>> +
>>>>> +    pio_alias = g_new0(MemoryRegion, 1);
>>>>> +    memory_region_init_alias(pio_alias, OBJECT(dev), "pcie-pio",
>>>>> +                             get_system_io(), 0, virt_memmap[VIRT_PCIE_PIO].size);
>>>>> +    memory_region_add_subregion(get_system_memory(),
>>>>> +                                virt_memmap[VIRT_PCIE_PIO].base, pio_alias);
>>>>> +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, virt_memmap[VIRT_PCIE_PIO].base);
>>>>> +
>>>>> +    for (i = 0; i < GPEX_NUM_IRQS; i++) {
>>>>> +        irq = qdev_get_gpio_in(pic, PCIE_IRQ_BASE + i);
>>>>> +        sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
>>>>> +        gpex_set_irq_num(GPEX_HOST(dev), i, PCIE_IRQ_BASE + i);
>>>>> +    }
>>>>> +
>>>>> +    pci_vga_init(pci_bus);
>>>>> +
>>>>> +    if (defaults_enabled()) {
>>>>> +        pci_create_simple(pci_bus, -1, "pci-ohci");
>>>>> +        usb_create_simple(usb_bus_find(-1), "usb-kbd");
>>>>> +        usb_create_simple(usb_bus_find(-1), "usb-tablet");
>>>>> +    }
>>>>> +
>>>>> +    for (i = 0; i < nb_nics; i++) {
>>>>> +        NICInfo *nd = &nd_table[i];
>>>>> +
>>>>> +        if (!nd->model) {
>>>>> +            nd->model = g_strdup("virtio");
>>>>> +        }
>>>>> +
>>>>> +        pci_nic_init_nofail(nd, pci_bus, nd->model, NULL);
>>>>> +    }
>>>>> +}
>>>>> +
>>>>> +static void mips_loongson3_virt_init(MachineState *machine)
>>>>> +{
>>>>> +    int i;
>>>>> +    long bios_size;
>>>>> +    MIPSCPU *cpu;
>>>>> +    CPUMIPSState *env;
>>>>> +    DeviceState *liointc;
>>>>> +    char *filename;
>>>>> +    const char *kernel_cmdline = machine->kernel_cmdline;
>>>>> +    const char *kernel_filename = machine->kernel_filename;
>>>>> +    const char *initrd_filename = machine->initrd_filename;
>>>>> +    ram_addr_t ram_size = machine->ram_size;
>>>>> +    MemoryRegion *address_space_mem = get_system_memory();
>>>>> +    MemoryRegion *ram = g_new(MemoryRegion, 1);
>>>>> +    MemoryRegion *bios = g_new(MemoryRegion, 1);
>>>>> +    MemoryRegion *iomem = g_new(MemoryRegion, 1);
>>>>> +
>>>>> +    /* TODO: TCG will support all CPU types */
>>>>> +    if (!kvm_enabled()) {
>>>>> +        if (!machine->cpu_type) {
>>>>> +            machine->cpu_type = MIPS_CPU_TYPE_NAME("Loongson-3A1000");
>>>>> +        }
>>>>> +        if (!strstr(machine->cpu_type, "Loongson-3A1000")) {
>>>>> +            error_report("Loongson-3/TCG needs cpu type Loongson-3A1000");
>>>>> +            exit(1);
>>>>> +        }
>>>>
>>>> IIUC here you need to check machine->smp.cpus is 4 or 8 for the 3A1000.
>>>> It would be easier if you model this as a qdev SoC, and this model
>>>> cares to create the 4/8 cores (QEMU MIPSCPU).
>>>>
>>>> You defined max_cpu = LOONGSON_MAX_VCPUS = 16, this seems an impossible
>>>> configuration for the 3A1000.
>>   >
>>> There are 4 cores in a SoC, but Loongson-3 support multi-sockets, more
>>> than 4 vcpus will be treated as multi-sockets automatically in guests.
>>> And current linux kernel also handle the case that only boot part of 4
>>> cores in a socket.
>>
>> What I want to avoid is user booting the machine with 3 or 5 vCPUs,
>> then complain booting Linux isn't working. It is simpler to check
>> the number of vCPUs matches the hardware possibilities.
 >
> The upstream kernel can boot 3 or 5 cores on real hardware (reserve
> several cores via boot parameters), so in virtual machine there is
> also no problems to boot 3 or 5 vCPUs.

So we have:

- emulate hw with TCG, boot with fw
   -> follow real hw, 1 socket must have 4 cores

- virtualize with KVM, boot kernel
   -> any number of vCPU

Other use cases?

> 
>>
>>>
>>>>
>>>>> +    } else {
>>>>> +        if (!machine->cpu_type) {
>>>>> +            machine->cpu_type = MIPS_CPU_TYPE_NAME("Loongson-3A4000");
>>>>> +        }
>>>>> +        if (!strstr(machine->cpu_type, "Loongson-3A4000")) {
>>>>> +            error_report("Loongson-3/KVM needs cpu type Loongson-3A4000");
>>>>> +            exit(1);
>>>>> +        }
>>>>
>>>> Similar comment, as the 3A4000 is also a quad-core.
>>>>
>>>>> +    }
>>>>> +
>>>>> +    if (ram_size < 512 * MiB) {
>>>>> +        error_report("Loongson-3 machine needs at least 512MB memory");
>>>>> +        exit(1);
>>>>> +    }
>>>>> +
>>>>> +    /*
>>>>> +     * The whole MMIO range among configure registers doesn't generate
>>>>> +     * exception when accessing invalid memory. Create an unimplememted
>>>>> +     * device to emulate this feature.
>>>>> +     */
>>>>> +    create_unimplemented_device("fallback", 0x10000000, 0x30000000);
>>>>
>>>> The secondary crosswise switch description is hard to follow:
>>>>
>>>> * 2.4 Address routing distribution and configuration
>>>>
>>>> According  to  the  default  register  configuration,  CPU [...]
>>>> 0x10000000-0x1fffffff  of  CPU  (256M)  is  mapped  to
>>>> 0x10000000-0x1fffffff  of  PCI,  and  0x80000000  of  PCIDMA.
>>>> In addition, when read access to illegal addresses occurs due to CPU
>>>> guess execution, all 8 address Windows fail to hit, ?
>>>>
>>>> Table 2-9 XBAR level 2 default address configuration
>>>>                      base                    high                     owner
>>>> 0 x0000_0000_1000_0000  0 x0000_0000_2000_0000  Low speed I/O (PCI, etc)
>>>>
>>>> * 14.4 Secondary cross-switch address window
>>>>
>>>> After the address window is configured, the system address
>>>> 0x0000_2000_0000 is added-- 0x0000_2FFFF_FFFF  maps  to
>>>> 0x0000_0000_0000  -- 0x0000_0FFF_FFFF  of  memory  controller 0.An
>>>> access to 0x0000_2000_0000 at this time will result in the original
>>>> enabledThe value stored at address 0x0000_0000_0000.
>>>>
>>>> But see:
>>>>
>>>> * 14.6.3 Low speed device address window
>>>>
>>>> Here are defined the peripherals in the 0x1c00_0000-0x1ff0_ffff range.
>>>>
>>>> * 15.1 System memory space
>>>>
>>>> IO device, 0x1000_0000 --  0x1FFF_FFFF
>>>>
>>>> * 16 Memory allocation for system X
>>>>
>>>> ... divide  the  256M  PCI  space  (0x10000000~0x20000000)  into  two
>>>> parts:  0x10000000~0x17ffffff for mem space and 0x18000000~0x20000000
>>>> for IO space.
>>>>
>>>> I still don't understand what is in the 0x20000000-0x30000000 range.
>>> Loongson's user manual is a little confusing, as a native Chinese I
>>> also feel uncomfortable sometimes. :)
>>> Generally speaking, Loongson-3's address space is configurable via
>>> address windows, and the recommended configurations is like this:
>>> 0x00000000-0x10000000   Low RAM
>>> 0x10000000-0x40000000   ROM and MMIO Registers (such as BIOS_ROM at
>>> 0x1fc00000, UART at 0x1fe001e0, LIOINTC at 0x3ff00140)
>>> 0x40000000-0x80000000  PCI MEM
>>> 0x80000000-TOM             High RAM
>>
>> Having a "fallback" region catching everything is not very helpful
>> when debugging. Listing each unimplemented peripheral is more useful:
>>
>>     create_unimplemented_device("LPC MEM", 0x1c000000, 32 * MiB);
>>     ...
>>     create_unimplemented_device("UART1",   0x1fe001e8, 8);
>>     create_unimplemented_device("SPI",     0x1fe001f0, 16);
>>     create_unimplemented_device("LPC IO",  0x1ff00000, 64 * KiB);
>>     ...
> Catch everything here is because both host and guest use the same
> kernel now, and there is some code try to access some address regions
> which doesn't exist on virtual machine.

Why don't you want to start clean and create each unimp region?

> 
>>
>>>
>>> PCI DMA of 0x10000000-0x1fffffff is a legacy region from
>>> Loongson-2E/2F, and be cancelled in Loongson-3's configuration.
>>> In real hardware, there should be a default "big enough" address
>>> window to catch illegal address, return 0 for read access.
>>> Yes, there is "nothing" in 0x20000000-0x30000000, because it is
>>> undocumented which means "reserved for internal usage".
>>
>> If it is reserved, then the guest shouldn't be trying to use it...
> OK, this will be improved, but create_uniplemented_device() for every
> small region seems not good (see above).

"not good" -> why?


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

* Re: [PATCH V13 8/9] hw/mips: Add Loongson-3 machine support
  2020-10-13 13:45           ` Philippe Mathieu-Daudé
@ 2020-10-14  1:28             ` Huacai Chen
  0 siblings, 0 replies; 34+ messages in thread
From: Huacai Chen @ 2020-10-14  1:28 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Huacai Chen, Aleksandar Rikalo, QEMU Developers, Aurelien Jarno,
	Aleksandar Markovic

Hi, Philippe,

On Tue, Oct 13, 2020 at 9:45 PM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
>
> On 10/13/20 1:12 PM, Huacai Chen wrote:
> > Hi, Philippe,
> >
> > On Mon, Oct 12, 2020 at 4:12 PM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
> >>
> >> On 10/11/20 4:53 AM, Huacai Chen wrote:
> >>> Hi, Philippe,
> >>>
> >>> On Sat, Oct 10, 2020 at 5:09 PM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
> >>>>
> >>>> Hi Huacai,
> >>>>
> >>>> On 10/7/20 10:39 AM, Huacai Chen wrote:
> >>>>> Add Loongson-3 based machine support, it use liointc as the interrupt
> >>>>> controler and use GPEX as the pci controller. Currently it can work with
> >>>>> both TCG and KVM.
> >>>>>
> >>>>> As the machine model is not based on any exiting physical hardware, the
> >>>>> name of the machine is "loongson3-virt". It may be superseded in future
> >>>>> by a real machine model. If this happens, then a regular deprecation
> >>>>> procedure shall occur for "loongson3-virt" machine.
> >>>>>
> >>>>> We now already have a full functional Linux kernel (based on Linux-5.4.x
> >>>>> LTS, the kvm host side and guest side have both been upstream for Linux-
> >>>>> 5.9, but Linux-5.9 has not been released yet) here:
> >>>>>
> >>>>> https://github.com/chenhuacai/linux
> >>>>>
> >>>>> Of course the upstream kernel is also usable (though it is "unstable"
> >>>>> now):
> >>>>>
> >>>>> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
> >>>>>
> >>>>> How to use QEMU/Loongson-3?
> >>>>> 1, Download kernel source from the above URL;
> >>>>> 2, Build a kernel with arch/mips/configs/loongson3_defconfig;
> >>>>> 3, Boot a Loongson-3A4000 host with this kernel (for KVM mode);
> >>>>> 4, Build QEMU-master with this patchset;
> >>>>> 5, modprobe kvm (only necessary for KVM mode);
> >>>>> 6, Use QEMU with TCG:
> >>>>>           qemu-system-mips64el -M loongson3-virt,accel=tcg -cpu Loongson-3A1000 -kernel <path_to_kernel> -append ...
> >>>>>       Use QEMU with KVM:
> >>>>>           qemu-system-mips64el -M loongson3-virt,accel=kvm -cpu Loongson-3A4000 -kernel <path_to_kernel> -append ...
> >>>>>
> >>>>>       The "-cpu" parameter is optional here and QEMU will use the correct type for TCG/KVM automatically.
> >>>>>
> >>>>> Signed-off-by: Huacai Chen <chenhc@lemote.com>
> >>>>> Co-developed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> >>>>> ---
> >>>>>     default-configs/devices/mips64el-softmmu.mak |   1 +
> >>>>>     hw/mips/Kconfig                              |  12 +
> >>>>>     hw/mips/loongson3_bootp.c                    | 162 +++++++
> >>>>>     hw/mips/loongson3_bootp.h                    | 225 ++++++++++
> >>>>
> >>>> In a previous version I asked if you could split the bootp* files
> >>>> (firmware related) in a previous separate patch to ease the review
> >>>> of the machine part.
> >>   >
> >>> In previous version you told me to split the fw_cfg to a separate
> >>> patch, but split the efi-related helpers to seprate files (not to a
> >>> patch). But anyway, I will split them to a patch in the next version.
> >>
> >> Sorry if I wasn't clear enough. It is very hard to review a patch
> >> of more than 1000 lines of C code without loosing focus or missing
> >> problems. It explains why big patches might stay unreviewed on the
> >> list. If you can split in smaller logical units, it will be very
> >> helpful.
> >>
> >> Peter Maydell rule of thumb is to keep patch below 200 lines.
> >> This is a good limit.
> >>
> >>>
> >>>>
> >>>>>     hw/mips/loongson3_virt.c                     | 615 +++++++++++++++++++++++++++
> >>>>>     hw/mips/meson.build                          |   1 +
> >>>>>     6 files changed, 1016 insertions(+)
> >>>> [...]
> >>>>
> >>>>> diff --git a/hw/mips/loongson3_virt.c b/hw/mips/loongson3_virt.c
> >>>>> new file mode 100644
> >>>>> index 0000000..4e573d6
> >>>>> --- /dev/null
> >>>>> +++ b/hw/mips/loongson3_virt.c
> >>>>> @@ -0,0 +1,615 @@
> >>>>> +/*
> >>>>> + * Generic Loongson-3 Platform support
> >>>>> + *
> >>>>> + * Copyright (c) 2017-2020 Huacai Chen (chenhc@lemote.com)
> >>>>> + * Copyright (c) 2017-2020 Jiaxun Yang <jiaxun.yang@flygoat.com>
> >>>>> + *
> >>>>> + * 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, see <https://www.gnu.org/licenses/>.
> >>>>> + */
> >>>>> +
> >>>>> +/*
> >>>>> + * Generic virtualized PC Platform based on Loongson-3 CPU (MIPS64R2 with
> >>>>> + * extensions, 800~2000MHz)
> >>>>> + */
> >>>>> +
> >>>>> +#include "qemu/osdep.h"
> >>>>> +#include "qemu-common.h"
> >>>>> +#include "qemu/units.h"
> >>>>> +#include "qemu/cutils.h"
> >>>>> +#include "qapi/error.h"
> >>>>> +#include "cpu.h"
> >>>>> +#include "elf.h"
> >>>>> +#include "kvm_mips.h"
> >>>>> +#include "hw/boards.h"
> >>>>> +#include "hw/char/serial.h"
> >>>>> +#include "hw/mips/mips.h"
> >>>>> +#include "hw/mips/cpudevs.h"
> >>>>> +#include "hw/mips/fw_cfg.h"
> >>>>> +#include "hw/mips/loongson3_bootp.h"
> >>>>> +#include "hw/misc/unimp.h"
> >>>>> +#include "hw/intc/i8259.h"
> >>>>> +#include "hw/loader.h"
> >>>>> +#include "hw/isa/superio.h"
> >>>>> +#include "hw/pci/msi.h"
> >>>>> +#include "hw/pci/pci.h"
> >>>>> +#include "hw/pci/pci_host.h"
> >>>>> +#include "hw/pci-host/gpex.h"
> >>>>> +#include "hw/rtc/mc146818rtc.h"
> >>>>> +#include "hw/usb.h"
> >>>>> +#include "net/net.h"
> >>>>> +#include "exec/address-spaces.h"
> >>>>> +#include "sysemu/kvm.h"
> >>>>> +#include "sysemu/qtest.h"
> >>>>> +#include "sysemu/reset.h"
> >>>>> +#include "sysemu/runstate.h"
> >>>>> +#include "qemu/log.h"
> >>>>> +#include "qemu/error-report.h"
> >>>>> +
> >>>>> +#define PM_CNTL_MODE          0x10
> >>>>> +
> >>>>> +#define LOONGSON_MAX_VCPUS      16
> >>>>> +
> >>>>> +#define LOONGSON3_BIOSNAME "bios_loongson3.bin"
> >>>>
> >>>> Where is that file?
> >>   >
> >>> I don't know the policy of QEMU's binary file, just put that in the
> >>> roms directory?
> >>
> >> If this is a closed source binary, we reference the URL where it can
> >> be downloaded accepting eventual EULA.
> >> If it is open source, the project is added as submodule. QEMU then
> >> provides a link to how to build the firmware, or if there is no such
> >> documentation, buildsys machinery is added to QEMU to build to it
> >> (see roms/Makefile).
> > OK, now the firmware is close-source (maybe open source in future), so
> > I will put an URL here.
> >
> >>
> >>>
> >>>>
> >>>>> +
> >>>>> +#define UART_IRQ            0
> >>>>> +#define RTC_IRQ             1
> >>>>> +#define PCIE_IRQ_BASE       2
> >>>>> +
> >>>>> +const struct MemmapEntry virt_memmap[] = {
> >>>>> +    [VIRT_LOWMEM] =      { 0x00000000,    0x10000000 },
> >>>>> +    [VIRT_PM] =          { 0x10080000,         0x100 },
> >>>>> +    [VIRT_FW_CFG] =      { 0x10080100,         0x100 },
> >>>>> +    [VIRT_RTC] =         { 0x10081000,        0x1000 },
> >>>>> +    [VIRT_PCIE_PIO] =    { 0x18000000,       0x80000 },
> >>>>> +    [VIRT_PCIE_ECAM] =   { 0x1a000000,     0x2000000 },
> >>>>> +    [VIRT_BIOS_ROM] =    { 0x1fc00000,      0x200000 },
> >>>>> +    [VIRT_UART] =        { 0x1fe001e0,           0x8 },
> >>>>
> >>>> See below about this mapping.
> >>>>
> >>>>> +    [VIRT_LIOINTC] =     { 0x3ff01400,          0x64 },
> >>>>> +    [VIRT_PCIE_MMIO] =   { 0x40000000,    0x40000000 },
> >>>>> +    [VIRT_HIGHMEM] =     { 0x80000000,           0x0 }, /* Variable */
> >>>>> +};
> >>>>> +
> >>>>> +static const struct MemmapEntry loader_memmap[] = {
> >>>>> +    [LOADER_KERNEL] =    { 0x00000000,     0x4000000 },
> >>>>> +    [LOADER_INITRD] =    { 0x04000000,           0x0 }, /* Variable */
> >>>>> +    [LOADER_CMDLINE] =   { 0x0ff00000,      0x100000 },
> >>>>> +};
> >>>>> +
> >>>>> +static const struct MemmapEntry loader_rommap[] = {
> >>>>> +    [LOADER_BOOTROM] =   { 0x1fc00000,        0x1000 },
> >>>>> +    [LOADER_PARAM] =     { 0x1fc01000,       0x10000 },
> >>>>> +};
> >>>>> +
> >>>>> +static struct _loaderparams {
> >>>>> +    uint64_t cpu_freq;
> >>>>> +    uint64_t ram_size;
> >>>>> +    const char *kernel_cmdline;
> >>>>> +    const char *kernel_filename;
> >>>>> +    const char *initrd_filename;
> >>>>> +    uint64_t kernel_entry;
> >>>>> +    uint64_t a0, a1, a2;
> >>>>> +} loaderparams;
> >>>>> +
> >>>>> +static uint64_t loongson3_pm_read(void *opaque, hwaddr addr, unsigned size)
> >>>>> +{
> >>>>> +    return 0;
> >>>>> +}
> >>>>> +
> >>>>> +static void loongson3_pm_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
> >>>>> +{
> >>>>> +    if (addr != PM_CNTL_MODE) {
> >>>>> +        return;
> >>>>> +    }
> >>>>> +
> >>>>> +    switch (val) {
> >>>>> +    case 0x00:
> >>>>> +        qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
> >>>>> +        return;
> >>>>> +    case 0xff:
> >>>>> +        qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
> >>>>> +        return;
> >>>>> +    default:
> >>>>> +        return;
> >>>>> +    }
> >>>>> +}
> >>>>> +
> >>>>> +static const MemoryRegionOps loongson3_pm_ops = {
> >>>>> +    .read  = loongson3_pm_read,
> >>>>> +    .write = loongson3_pm_write,
> >>>>> +    .endianness = DEVICE_NATIVE_ENDIAN,
> >>>>> +};
> >>>>> +
> >>>>> +#define DEF_TCG_FREQ (200 * 1000 * 1000)
> >>>>> +#define DEF_KVM_FREQ (1600 * 1000 * 1000)
> >>>>> +
> >>>>> +static uint64_t get_cpu_freq(void)
> >>>>> +{
> >>>>> +#ifdef CONFIG_KVM
> >>>>> +    int ret;
> >>>>> +    uint64_t freq;
> >>>>> +    struct kvm_one_reg freq_reg = {
> >>>>> +        .id = KVM_REG_MIPS_COUNT_HZ,
> >>>>> +        .addr = (uintptr_t)(&freq)
> >>>>> +    };
> >>>>> +
> >>>>> +    if (kvm_enabled()) {
> >>>>> +        ret = kvm_vcpu_ioctl(first_cpu, KVM_GET_ONE_REG, &freq_reg);
> >>>>> +        if (ret < 0) {
> >>>>> +            return DEF_KVM_FREQ;
> >>>>> +        }
> >>>>> +        return freq * 2;
> >>>>> +    } else {
> >>>>> +        /*
> >>>>> +         * TCG has a default CP0 Timer period 10 ns, which is 100MHz,
> >>>>> +         * CPU frequency is defined as double of CP0 timer frequency.
> >>>>> +         */
> >>>>> +        return DEF_TCG_FREQ;
> >>>>> +    }
> >>>>> +#else
> >>>>> +    return DEF_TCG_FREQ;
> >>>>> +#endif
> >>>>> +}
> >>>>> +
> >>>>> +static void init_boot_param(void)
> >>>>> +{
> >>>>> +    void *p;
> >>>>> +    struct boot_params *bp;
> >>>>> +
> >>>>> +    p = g_malloc0(loader_rommap[LOADER_PARAM].size);
> >>>>> +    bp = p;
> >>>>> +
> >>>>> +    stw_le_p(&bp->efi.smbios.vers, 1);
> >>>>> +    init_reset_system(&(bp->reset_system));
> >>>>> +    p += ROUND_UP(sizeof(struct boot_params), 64);
> >>>>> +    init_loongson_params(&(bp->efi.smbios.lp), p,
> >>>>> +                         loaderparams.cpu_freq, loaderparams.ram_size);
> >>>>> +
> >>>>> +    rom_add_blob_fixed("params_rom", bp,
> >>>>> +                       loader_rommap[LOADER_PARAM].size,
> >>>>> +                       loader_rommap[LOADER_PARAM].base);
> >>>>> +
> >>>>> +    g_free(bp);
> >>>>> +
> >>>>> +    loaderparams.a2 = cpu_mips_phys_to_kseg0(NULL, loader_rommap[LOADER_PARAM].base);
> >>>>> +}
> >>>>> +
> >>>>> +static void init_boot_rom(void)
> >>>>> +{
> >>>>> +    const unsigned int boot_code[] = {
> >>>>> +        0x40086000,   /* mfc0    t0, CP0_STATUS                               */
> >>>>> +        0x240900E4,   /* li      t1, 0xe4         #set kx, sx, ux, erl        */
> >>>>> +        0x01094025,   /* or      t0, t0, t1                                   */
> >>>>> +        0x3C090040,   /* lui     t1, 0x40         #set bev                    */
> >>>>> +        0x01094025,   /* or      t0, t0, t1                                   */
> >>>>> +        0x40886000,   /* mtc0    t0, CP0_STATUS                               */
> >>>>> +        0x00000000,
> >>>>> +        0x40806800,   /* mtc0    zero, CP0_CAUSE                              */
> >>>>> +        0x00000000,
> >>>>> +        0x400A7801,   /* mfc0    t2, $15, 1                                   */
> >>>>> +        0x314A00FF,   /* andi    t2, 0x0ff                                    */
> >>>>> +        0x3C089000,   /* dli     t0, 0x900000003ff01000                       */
> >>>>> +        0x00084438,
> >>>>> +        0x35083FF0,
> >>>>> +        0x00084438,
> >>>>> +        0x35081000,
> >>>>> +        0x314B0003,   /* andi    t3, t2, 0x3      #local cpuid                */
> >>>>> +        0x000B5A00,   /* sll     t3, 8                                        */
> >>>>> +        0x010B4025,   /* or      t0, t0, t3                                   */
> >>>>> +        0x314C000C,   /* andi    t4, t2, 0xc      #node id                    */
> >>>>> +        0x000C62BC,   /* dsll    t4, 42                                       */
> >>>>> +        0x010C4025,   /* or      t0, t0, t4                                   */
> >>>>> +                      /* WaitForInit:                                         */
> >>>>> +        0xDD020020,   /* ld      v0, FN_OFF(t0)   #FN_OFF 0x020               */
> >>>>> +        0x1040FFFE,   /* beqz    v0, WaitForInit                              */
> >>>>> +        0x00000000,   /* nop                                                  */
> >>>>> +        0xDD1D0028,   /* ld      sp, SP_OFF(t0)   #FN_OFF 0x028               */
> >>>>> +        0xDD1C0030,   /* ld      gp, GP_OFF(t0)   #FN_OFF 0x030               */
> >>>>> +        0xDD050038,   /* ld      a1, A1_OFF(t0)   #FN_OFF 0x038               */
> >>>>> +        0x00400008,   /* jr      v0               #byebye                     */
> >>>>> +        0x00000000,   /* nop                                                  */
> >>>>> +        0x1000FFFF,   /* 1:  b   1b                                           */
> >>>>> +        0x00000000,   /* nop                                                  */
> >>>>> +
> >>>>> +                      /* Reset                                                */
> >>>>> +        0x3C0C9000,   /* dli     t0, 0x9000000010080010                       */
> >>>>> +        0x358C0000,
> >>>>> +        0x000C6438,
> >>>>> +        0x358C1008,
> >>>>> +        0x000C6438,
> >>>>> +        0x358C0010,
> >>>>> +        0x240D0000,   /* li      t1, 0x00                                     */
> >>>>> +        0xA18D0000,   /* sb      t1, (t0)                                     */
> >>>>> +        0x1000FFFF,   /* 1:  b   1b                                           */
> >>>>> +        0x00000000,   /* nop                                                  */
> >>>>> +
> >>>>> +                      /* Shutdown                                             */
> >>>>> +        0x3C0C9000,   /* dli     t0, 0x9000000010080010                       */
> >>>>> +        0x358C0000,
> >>>>> +        0x000C6438,
> >>>>> +        0x358C1008,
> >>>>> +        0x000C6438,
> >>>>> +        0x358C0010,
> >>>>> +        0x240D00FF,   /* li      t1, 0xff                                     */
> >>>>> +        0xA18D0000,   /* sb      t1, (t0)                                     */
> >>>>> +        0x1000FFFF,   /* 1:  b   1b                                           */
> >>>>> +        0x00000000    /* nop                                                  */
> >>>>> +    };
> >>>>> +
> >>>>> +    rom_add_blob_fixed("boot_rom", boot_code, sizeof(boot_code),
> >>>>> +                        loader_rommap[LOADER_BOOTROM].base);
> >>>>> +}
> >>>>> +
> >>>>> +static void fw_cfg_boot_set(void *opaque, const char *boot_device,
> >>>>> +                            Error **errp)
> >>>>> +{
> >>>>> +    fw_cfg_modify_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
> >>>>> +}
> >>>>> +
> >>>>> +static void fw_conf_init(unsigned long ram_size)
> >>>>> +{
> >>>>> +    FWCfgState *fw_cfg;
> >>>>> +    hwaddr cfg_addr = virt_memmap[VIRT_FW_CFG].base;
> >>>>> +
> >>>>> +    fw_cfg = fw_cfg_init_mem_wide(cfg_addr, cfg_addr + 8, 8, 0, NULL);
> >>>>> +    fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)current_machine->smp.cpus);
> >>>>> +    fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)current_machine->smp.max_cpus);
> >>>>> +    fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
> >>>>> +    fw_cfg_add_i32(fw_cfg, FW_CFG_MACHINE_VERSION, 1);
> >>>>> +    fw_cfg_add_i64(fw_cfg, FW_CFG_CPU_FREQ, get_cpu_freq());
> >>>>> +    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
> >>>>> +}
> >>>>> +
> >>>>> +static int set_prom_cmdline(ram_addr_t initrd_offset, long initrd_size)
> >>>>> +{
> >>>>> +    hwaddr cmdline_vaddr;
> >>>>> +    char memenv[32];
> >>>>> +    char highmemenv[32];
> >>>>> +    void *cmdline_buf;
> >>>>> +    unsigned int *parg_env;
> >>>>> +    int ret = 0;
> >>>>> +
> >>>>> +    /* Allocate cmdline_buf for command line. */
> >>>>> +    cmdline_buf = g_malloc0(loader_memmap[LOADER_CMDLINE].size);
> >>>>> +    cmdline_vaddr = cpu_mips_phys_to_kseg0(NULL,
> >>>>> +                                           loader_memmap[LOADER_CMDLINE].base);
> >>>>> +
> >>>>> +    /*
> >>>>> +     * Layout of cmdline_buf looks like this:
> >>>>> +     * argv[0], argv[1], 0, env[0], env[1], ... env[i], 0,
> >>>>> +     * argv[0]'s data, argv[1]'s data, env[0]'data, ..., env[i]'s data, 0
> >>>>> +     */
> >>>>> +    parg_env = (void *)cmdline_buf;
> >>>>> +
> >>>>> +    ret = (3 + 1) * 4;
> >>>>> +    *parg_env++ = cmdline_vaddr + ret;
> >>>>> +    ret += (1 + snprintf(cmdline_buf + ret, 256 - ret, "g"));
> >>>>> +
> >>>>> +    /* argv1 */
> >>>>> +    *parg_env++ = cmdline_vaddr + ret;
> >>>>> +    if (initrd_size > 0)
> >>>>> +        ret += (1 + snprintf(cmdline_buf + ret, 256 - ret,
> >>>>> +                "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s",
> >>>>> +                cpu_mips_phys_to_kseg0(NULL, initrd_offset),
> >>>>> +                initrd_size, loaderparams.kernel_cmdline));
> >>>>> +    else
> >>>>> +        ret += (1 + snprintf(cmdline_buf + ret, 256 - ret, "%s",
> >>>>> +                loaderparams.kernel_cmdline));
> >>>>> +
> >>>>> +    /* argv2 */
> >>>>> +    *parg_env++ = cmdline_vaddr + 4 * ret;
> >>>>> +
> >>>>> +    /* env */
> >>>>> +    sprintf(memenv, "%d", 256);
> >>>>> +    sprintf(highmemenv, "%ld", (unsigned long)(loaderparams.ram_size / MiB) - 256);
> >>>>> +
> >>>>> +    rom_add_blob_fixed("cmdline", cmdline_buf,
> >>>>> +                       loader_memmap[LOADER_CMDLINE].size,
> >>>>> +                       loader_memmap[LOADER_CMDLINE].base);
> >>>>> +
> >>>>> +    g_free(cmdline_buf);
> >>>>> +
> >>>>> +    loaderparams.a0 = 2;
> >>>>> +    loaderparams.a1 = cmdline_vaddr;
> >>>>> +
> >>>>> +    return 0;
> >>>>> +}
> >>>>> +
> >>>>> +static uint64_t load_kernel(CPUMIPSState *env)
> >>>>> +{
> >>>>> +    long kernel_size;
> >>>>> +    ram_addr_t initrd_offset;
> >>>>> +    uint64_t kernel_entry, kernel_low, kernel_high, initrd_size;
> >>>>> +
> >>>>> +    kernel_size = load_elf(loaderparams.kernel_filename, NULL,
> >>>>> +                           cpu_mips_kseg0_to_phys, NULL,
> >>>>> +                           (uint64_t *)&kernel_entry,
> >>>>> +                           (uint64_t *)&kernel_low, (uint64_t *)&kernel_high,
> >>>>> +                           NULL, 0, EM_MIPS, 1, 0);
> >>>>> +    if (kernel_size < 0) {
> >>>>> +        error_report("could not load kernel '%s': %s",
> >>>>> +                     loaderparams.kernel_filename,
> >>>>> +                     load_elf_strerror(kernel_size));
> >>>>> +        exit(1);
> >>>>> +    }
> >>>>> +
> >>>>> +    /* load initrd */
> >>>>> +    initrd_size = 0;
> >>>>> +    initrd_offset = 0;
> >>>>> +    if (loaderparams.initrd_filename) {
> >>>>> +        initrd_size = get_image_size(loaderparams.initrd_filename);
> >>>>> +        if (initrd_size > 0) {
> >>>>> +            initrd_offset = (kernel_high + ~INITRD_PAGE_MASK) &
> >>>>> +                            INITRD_PAGE_MASK;
> >>>>> +            initrd_offset = MAX(initrd_offset,
> >>>>> +                                loader_memmap[LOADER_INITRD].base);
> >>>>> +
> >>>>> +            if (initrd_offset + initrd_size > ram_size) {
> >>>>> +                error_report("memory too small for initial ram disk '%s'",
> >>>>> +                             loaderparams.initrd_filename);
> >>>>> +                exit(1);
> >>>>> +            }
> >>>>> +
> >>>>> +            initrd_size = load_image_targphys(loaderparams.initrd_filename,
> >>>>> +                                              initrd_offset,
> >>>>> +                                              ram_size - initrd_offset);
> >>>>> +        }
> >>>>> +
> >>>>> +        if (initrd_size == (target_ulong) -1) {
> >>>>> +            error_report("could not load initial ram disk '%s'",
> >>>>> +                         loaderparams.initrd_filename);
> >>>>> +            exit(1);
> >>>>> +        }
> >>>>> +    }
> >>>>> +
> >>>>> +    /* Setup prom cmdline. */
> >>>>> +    set_prom_cmdline(initrd_offset, initrd_size);
> >>>>> +
> >>>>> +    return kernel_entry;
> >>>>> +}
> >>>>> +
> >>>>> +static void main_cpu_reset(void *opaque)
> >>>>> +{
> >>>>> +    MIPSCPU *cpu = opaque;
> >>>>> +    CPUMIPSState *env = &cpu->env;
> >>>>> +
> >>>>> +    cpu_reset(CPU(cpu));
> >>>>> +
> >>>>> +    /* Loongson-3 reset stuff */
> >>>>> +    if (loaderparams.kernel_filename) {
> >>>>> +        if (cpu == MIPS_CPU(first_cpu)) {
> >>>>> +            env->active_tc.gpr[4] = loaderparams.a0;
> >>>>> +            env->active_tc.gpr[5] = loaderparams.a1;
> >>>>> +            env->active_tc.gpr[6] = loaderparams.a2;
> >>>>> +            env->active_tc.PC = loaderparams.kernel_entry;
> >>>>> +        }
> >>>>> +        env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL));
> >>>>> +    }
> >>>>> +}
> >>>>> +
> >>>>> +static inline void loongson3_virt_devices_init(MachineState *machine, DeviceState *pic)
> >>>>> +{
> >>>>> +    int i;
> >>>>> +    qemu_irq irq;
> >>>>> +    PCIBus *pci_bus;
> >>>>> +    DeviceState *dev;
> >>>>> +    MemoryRegion *pio_alias;
> >>>>> +    MemoryRegion *mmio_alias, *mmio_reg;
> >>>>> +    MemoryRegion *ecam_alias, *ecam_reg;
> >>>>> +
> >>>>> +    dev = qdev_new(TYPE_GPEX_HOST);
> >>>>> +    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> >>>>> +    pci_bus = PCI_HOST_BRIDGE(dev)->bus;
> >>>>> +
> >>>>> +    ecam_alias = g_new0(MemoryRegion, 1);
> >>>>> +    ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
> >>>>> +    memory_region_init_alias(ecam_alias, OBJECT(dev), "pcie-ecam",
> >>>>> +                             ecam_reg, 0, virt_memmap[VIRT_PCIE_ECAM].size);
> >>>>> +    memory_region_add_subregion(get_system_memory(),
> >>>>> +                                virt_memmap[VIRT_PCIE_ECAM].base, ecam_alias);
> >>>>> +
> >>>>> +    mmio_alias = g_new0(MemoryRegion, 1);
> >>>>> +    mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
> >>>>> +    memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio",
> >>>>> +                             mmio_reg, virt_memmap[VIRT_PCIE_MMIO].base,
> >>>>> +                             virt_memmap[VIRT_PCIE_MMIO].size);
> >>>>> +    memory_region_add_subregion(get_system_memory(),
> >>>>> +                                virt_memmap[VIRT_PCIE_MMIO].base, mmio_alias);
> >>>>> +
> >>>>> +    pio_alias = g_new0(MemoryRegion, 1);
> >>>>> +    memory_region_init_alias(pio_alias, OBJECT(dev), "pcie-pio",
> >>>>> +                             get_system_io(), 0, virt_memmap[VIRT_PCIE_PIO].size);
> >>>>> +    memory_region_add_subregion(get_system_memory(),
> >>>>> +                                virt_memmap[VIRT_PCIE_PIO].base, pio_alias);
> >>>>> +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, virt_memmap[VIRT_PCIE_PIO].base);
> >>>>> +
> >>>>> +    for (i = 0; i < GPEX_NUM_IRQS; i++) {
> >>>>> +        irq = qdev_get_gpio_in(pic, PCIE_IRQ_BASE + i);
> >>>>> +        sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
> >>>>> +        gpex_set_irq_num(GPEX_HOST(dev), i, PCIE_IRQ_BASE + i);
> >>>>> +    }
> >>>>> +
> >>>>> +    pci_vga_init(pci_bus);
> >>>>> +
> >>>>> +    if (defaults_enabled()) {
> >>>>> +        pci_create_simple(pci_bus, -1, "pci-ohci");
> >>>>> +        usb_create_simple(usb_bus_find(-1), "usb-kbd");
> >>>>> +        usb_create_simple(usb_bus_find(-1), "usb-tablet");
> >>>>> +    }
> >>>>> +
> >>>>> +    for (i = 0; i < nb_nics; i++) {
> >>>>> +        NICInfo *nd = &nd_table[i];
> >>>>> +
> >>>>> +        if (!nd->model) {
> >>>>> +            nd->model = g_strdup("virtio");
> >>>>> +        }
> >>>>> +
> >>>>> +        pci_nic_init_nofail(nd, pci_bus, nd->model, NULL);
> >>>>> +    }
> >>>>> +}
> >>>>> +
> >>>>> +static void mips_loongson3_virt_init(MachineState *machine)
> >>>>> +{
> >>>>> +    int i;
> >>>>> +    long bios_size;
> >>>>> +    MIPSCPU *cpu;
> >>>>> +    CPUMIPSState *env;
> >>>>> +    DeviceState *liointc;
> >>>>> +    char *filename;
> >>>>> +    const char *kernel_cmdline = machine->kernel_cmdline;
> >>>>> +    const char *kernel_filename = machine->kernel_filename;
> >>>>> +    const char *initrd_filename = machine->initrd_filename;
> >>>>> +    ram_addr_t ram_size = machine->ram_size;
> >>>>> +    MemoryRegion *address_space_mem = get_system_memory();
> >>>>> +    MemoryRegion *ram = g_new(MemoryRegion, 1);
> >>>>> +    MemoryRegion *bios = g_new(MemoryRegion, 1);
> >>>>> +    MemoryRegion *iomem = g_new(MemoryRegion, 1);
> >>>>> +
> >>>>> +    /* TODO: TCG will support all CPU types */
> >>>>> +    if (!kvm_enabled()) {
> >>>>> +        if (!machine->cpu_type) {
> >>>>> +            machine->cpu_type = MIPS_CPU_TYPE_NAME("Loongson-3A1000");
> >>>>> +        }
> >>>>> +        if (!strstr(machine->cpu_type, "Loongson-3A1000")) {
> >>>>> +            error_report("Loongson-3/TCG needs cpu type Loongson-3A1000");
> >>>>> +            exit(1);
> >>>>> +        }
> >>>>
> >>>> IIUC here you need to check machine->smp.cpus is 4 or 8 for the 3A1000.
> >>>> It would be easier if you model this as a qdev SoC, and this model
> >>>> cares to create the 4/8 cores (QEMU MIPSCPU).
> >>>>
> >>>> You defined max_cpu = LOONGSON_MAX_VCPUS = 16, this seems an impossible
> >>>> configuration for the 3A1000.
> >>   >
> >>> There are 4 cores in a SoC, but Loongson-3 support multi-sockets, more
> >>> than 4 vcpus will be treated as multi-sockets automatically in guests.
> >>> And current linux kernel also handle the case that only boot part of 4
> >>> cores in a socket.
> >>
> >> What I want to avoid is user booting the machine with 3 or 5 vCPUs,
> >> then complain booting Linux isn't working. It is simpler to check
> >> the number of vCPUs matches the hardware possibilities.
>  >
> > The upstream kernel can boot 3 or 5 cores on real hardware (reserve
> > several cores via boot parameters), so in virtual machine there is
> > also no problems to boot 3 or 5 vCPUs.
>
> So we have:
>
> - emulate hw with TCG, boot with fw
>    -> follow real hw, 1 socket must have 4 cores
>
> - virtualize with KVM, boot kernel
>    -> any number of vCPU
>
> Other use cases?
"How many cores a socket have" need not be the same as "how many cores
we boot", both for real hardware and virtual machines. Though the
"standard configuration" of Loongson-3A is 4 cores, there are some
real chips with hardware flaws. Our solution is to mask some cores in
hardware and modify the kernel to boot any number of cores (already
upstream since 3.17). So, our infrastructure already supports this, we
needn't limit anything.

>
> >
> >>
> >>>
> >>>>
> >>>>> +    } else {
> >>>>> +        if (!machine->cpu_type) {
> >>>>> +            machine->cpu_type = MIPS_CPU_TYPE_NAME("Loongson-3A4000");
> >>>>> +        }
> >>>>> +        if (!strstr(machine->cpu_type, "Loongson-3A4000")) {
> >>>>> +            error_report("Loongson-3/KVM needs cpu type Loongson-3A4000");
> >>>>> +            exit(1);
> >>>>> +        }
> >>>>
> >>>> Similar comment, as the 3A4000 is also a quad-core.
> >>>>
> >>>>> +    }
> >>>>> +
> >>>>> +    if (ram_size < 512 * MiB) {
> >>>>> +        error_report("Loongson-3 machine needs at least 512MB memory");
> >>>>> +        exit(1);
> >>>>> +    }
> >>>>> +
> >>>>> +    /*
> >>>>> +     * The whole MMIO range among configure registers doesn't generate
> >>>>> +     * exception when accessing invalid memory. Create an unimplememted
> >>>>> +     * device to emulate this feature.
> >>>>> +     */
> >>>>> +    create_unimplemented_device("fallback", 0x10000000, 0x30000000);
> >>>>
> >>>> The secondary crosswise switch description is hard to follow:
> >>>>
> >>>> * 2.4 Address routing distribution and configuration
> >>>>
> >>>> According  to  the  default  register  configuration,  CPU [...]
> >>>> 0x10000000-0x1fffffff  of  CPU  (256M)  is  mapped  to
> >>>> 0x10000000-0x1fffffff  of  PCI,  and  0x80000000  of  PCIDMA.
> >>>> In addition, when read access to illegal addresses occurs due to CPU
> >>>> guess execution, all 8 address Windows fail to hit, ?
> >>>>
> >>>> Table 2-9 XBAR level 2 default address configuration
> >>>>                      base                    high                     owner
> >>>> 0 x0000_0000_1000_0000  0 x0000_0000_2000_0000  Low speed I/O (PCI, etc)
> >>>>
> >>>> * 14.4 Secondary cross-switch address window
> >>>>
> >>>> After the address window is configured, the system address
> >>>> 0x0000_2000_0000 is added-- 0x0000_2FFFF_FFFF  maps  to
> >>>> 0x0000_0000_0000  -- 0x0000_0FFF_FFFF  of  memory  controller 0.An
> >>>> access to 0x0000_2000_0000 at this time will result in the original
> >>>> enabledThe value stored at address 0x0000_0000_0000.
> >>>>
> >>>> But see:
> >>>>
> >>>> * 14.6.3 Low speed device address window
> >>>>
> >>>> Here are defined the peripherals in the 0x1c00_0000-0x1ff0_ffff range.
> >>>>
> >>>> * 15.1 System memory space
> >>>>
> >>>> IO device, 0x1000_0000 --  0x1FFF_FFFF
> >>>>
> >>>> * 16 Memory allocation for system X
> >>>>
> >>>> ... divide  the  256M  PCI  space  (0x10000000~0x20000000)  into  two
> >>>> parts:  0x10000000~0x17ffffff for mem space and 0x18000000~0x20000000
> >>>> for IO space.
> >>>>
> >>>> I still don't understand what is in the 0x20000000-0x30000000 range.
> >>> Loongson's user manual is a little confusing, as a native Chinese I
> >>> also feel uncomfortable sometimes. :)
> >>> Generally speaking, Loongson-3's address space is configurable via
> >>> address windows, and the recommended configurations is like this:
> >>> 0x00000000-0x10000000   Low RAM
> >>> 0x10000000-0x40000000   ROM and MMIO Registers (such as BIOS_ROM at
> >>> 0x1fc00000, UART at 0x1fe001e0, LIOINTC at 0x3ff00140)
> >>> 0x40000000-0x80000000  PCI MEM
> >>> 0x80000000-TOM             High RAM
> >>
> >> Having a "fallback" region catching everything is not very helpful
> >> when debugging. Listing each unimplemented peripheral is more useful:
> >>
> >>     create_unimplemented_device("LPC MEM", 0x1c000000, 32 * MiB);
> >>     ...
> >>     create_unimplemented_device("UART1",   0x1fe001e8, 8);
> >>     create_unimplemented_device("SPI",     0x1fe001f0, 16);
> >>     create_unimplemented_device("LPC IO",  0x1ff00000, 64 * KiB);
> >>     ...
> > Catch everything here is because both host and guest use the same
> > kernel now, and there is some code try to access some address regions
> > which doesn't exist on virtual machine.
>
> Why don't you want to start clean and create each unimp region?
Let me explain the memory layout again:
0x00000000-0x10000000 256M low RAM
0x10000000-0x20000000 256M MMIO space 0
0x20000000-0x30000000 256M reserved
0x30000000-0x40000000 256M MMIO space 1
0x40000000-0x80000000 1G PCI MEM
0x80000000-TOM           high RAM

Now I realize that 0x20000000-0x30000000 should not be accessed by
software, so I want to change the code like this:
    create_unimplemented_device("mmio fallback 0", 0x10000000, 256 * MiB);
    create_unimplemented_device("mmio fallback 1", 0x30000000, 256 * MiB);

Then, why don't I want to create small regions? Because the MMIO space
contains something from SoC, and also something from peripheral
devices (mainly from the host bridge), this fact makes the detail
layout of MMIO space different from one real hardware to another real
hardware, and also different from real hardware to virtual machine.
So, a small region which holds a real device on a real machine may be
meaningless for the virtual machine, or meaningful but hold a
different virtual device (but we need to catch these addresses in
virtual machines, because real machines and virtual machines use the
same kernel, and some kernel code may unconditionally access these
addresses).

>
> >
> >>
> >>>
> >>> PCI DMA of 0x10000000-0x1fffffff is a legacy region from
> >>> Loongson-2E/2F, and be cancelled in Loongson-3's configuration.
> >>> In real hardware, there should be a default "big enough" address
> >>> window to catch illegal address, return 0 for read access.
> >>> Yes, there is "nothing" in 0x20000000-0x30000000, because it is
> >>> undocumented which means "reserved for internal usage".
> >>
> >> If it is reserved, then the guest shouldn't be trying to use it...
> > OK, this will be improved, but create_uniplemented_device() for every
> > small region seems not good (see above).
>
> "not good" -> why?
See above.

Huacai


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

* Re: [PATCH V13 2/9] meson.build: Re-enable KVM support for MIPS
  2020-10-07  8:39 ` [PATCH V13 2/9] meson.build: Re-enable KVM support for MIPS Huacai Chen
  2020-10-07  8:51   ` Paolo Bonzini
@ 2020-11-17 17:17   ` Philippe Mathieu-Daudé
  2020-11-20  4:28     ` Huacai Chen
  1 sibling, 1 reply; 34+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-11-17 17:17 UTC (permalink / raw)
  To: Huacai Chen, Paolo Bonzini, Thomas Huth, Peter Maydell
  Cc: Aleksandar Rikalo, Huacai Chen, qemu-devel, Huacai Chen, Aurelien Jarno

Hi Huacai,

On 10/7/20 10:39 AM, Huacai Chen wrote:
> After converting from configure to meson, KVM support is lost for MIPS,
> so re-enable it in meson.build.
> 
> Fixes: fdb75aeff7c212e1afaaa3a43 ("configure: remove target configuration")
> Fixes: 8a19980e3fc42239aae054bc9 ("configure: move accelerator logic to meson")
> Cc: aolo Bonzini <pbonzini@redhat.com>
> Signed-off-by: Huacai Chen <chenhc@lemote.com>
> ---
>  meson.build | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/meson.build b/meson.build
> index 17c89c8..b407ff4 100644
> --- a/meson.build
> +++ b/meson.build
> @@ -59,6 +59,8 @@ elif cpu == 's390x'
>    kvm_targets = ['s390x-softmmu']
>  elif cpu in ['ppc', 'ppc64']
>    kvm_targets = ['ppc-softmmu', 'ppc64-softmmu']
> +elif cpu in ['mips', 'mips64']
> +  kvm_targets = ['mips-softmmu', 'mipsel-softmmu', 'mips64-softmmu', 'mips64el-softmmu']

Are you sure both 32-bit hosts and targets are supported?

I don't have hardware to test. If you are not working with
32-bit hardware I'd remove them.

>  else
>    kvm_targets = []
>  endif
> 


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

* Re: [PATCH V13 2/9] meson.build: Re-enable KVM support for MIPS
  2020-11-17 17:17   ` Philippe Mathieu-Daudé
@ 2020-11-20  4:28     ` Huacai Chen
  2020-11-20 10:55       ` Philippe Mathieu-Daudé
  0 siblings, 1 reply; 34+ messages in thread
From: Huacai Chen @ 2020-11-20  4:28 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Peter Maydell, Thomas Huth, Huacai Chen, QEMU Developers,
	Paolo Bonzini, Aleksandar Rikalo, Aurelien Jarno

Hi, Philippe,

On Wed, Nov 18, 2020 at 1:17 AM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
>
> Hi Huacai,
>
> On 10/7/20 10:39 AM, Huacai Chen wrote:
> > After converting from configure to meson, KVM support is lost for MIPS,
> > so re-enable it in meson.build.
> >
> > Fixes: fdb75aeff7c212e1afaaa3a43 ("configure: remove target configuration")
> > Fixes: 8a19980e3fc42239aae054bc9 ("configure: move accelerator logic to meson")
> > Cc: aolo Bonzini <pbonzini@redhat.com>
> > Signed-off-by: Huacai Chen <chenhc@lemote.com>
> > ---
> >  meson.build | 2 ++
> >  1 file changed, 2 insertions(+)
> >
> > diff --git a/meson.build b/meson.build
> > index 17c89c8..b407ff4 100644
> > --- a/meson.build
> > +++ b/meson.build
> > @@ -59,6 +59,8 @@ elif cpu == 's390x'
> >    kvm_targets = ['s390x-softmmu']
> >  elif cpu in ['ppc', 'ppc64']
> >    kvm_targets = ['ppc-softmmu', 'ppc64-softmmu']
> > +elif cpu in ['mips', 'mips64']
> > +  kvm_targets = ['mips-softmmu', 'mipsel-softmmu', 'mips64-softmmu', 'mips64el-softmmu']
>
> Are you sure both 32-bit hosts and targets are supported?
>
> I don't have hardware to test. If you are not working with
> 32-bit hardware I'd remove them.
When I add MIPS64 KVM support (Loongson-3 is MIPS64), MIPS32 KVM is
already there. On the kernel side, MIPS32 KVM is supported, but I
don't know whether it can work well.

Huacai

>
> >  else
> >    kvm_targets = []
> >  endif
> >


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

* Re: [PATCH V13 2/9] meson.build: Re-enable KVM support for MIPS
  2020-11-20  4:28     ` Huacai Chen
@ 2020-11-20 10:55       ` Philippe Mathieu-Daudé
  2020-11-22  3:31         ` Huacai Chen
  0 siblings, 1 reply; 34+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-11-20 10:55 UTC (permalink / raw)
  To: Huacai Chen, Huacai Chen, Paolo Bonzini
  Cc: Peter Maydell, Thomas Huth, kvm, Huacai Chen, Aleksandar Rikalo,
	QEMU Developers, Aurelien Jarno

On 11/20/20 5:28 AM, Huacai Chen wrote:
> On Wed, Nov 18, 2020 at 1:17 AM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
>> On 10/7/20 10:39 AM, Huacai Chen wrote:
>>> After converting from configure to meson, KVM support is lost for MIPS,
>>> so re-enable it in meson.build.
>>>
>>> Fixes: fdb75aeff7c212e1afaaa3a43 ("configure: remove target configuration")
>>> Fixes: 8a19980e3fc42239aae054bc9 ("configure: move accelerator logic to meson")
>>> Cc: aolo Bonzini <pbonzini@redhat.com>
>>> Signed-off-by: Huacai Chen <chenhc@lemote.com>
>>> ---
>>>  meson.build | 2 ++
>>>  1 file changed, 2 insertions(+)
>>>
>>> diff --git a/meson.build b/meson.build
>>> index 17c89c8..b407ff4 100644
>>> --- a/meson.build
>>> +++ b/meson.build
>>> @@ -59,6 +59,8 @@ elif cpu == 's390x'
>>>    kvm_targets = ['s390x-softmmu']
>>>  elif cpu in ['ppc', 'ppc64']
>>>    kvm_targets = ['ppc-softmmu', 'ppc64-softmmu']
>>> +elif cpu in ['mips', 'mips64']
>>> +  kvm_targets = ['mips-softmmu', 'mipsel-softmmu', 'mips64-softmmu', 'mips64el-softmmu']
>>
>> Are you sure both 32-bit hosts and targets are supported?
>>
>> I don't have hardware to test. If you are not working with
>> 32-bit hardware I'd remove them.
> When I add MIPS64 KVM support (Loongson-3 is MIPS64), MIPS32 KVM is
> already there. On the kernel side, MIPS32 KVM is supported, but I
> don't know whether it can work well.

Well, from the history, you inherited from it:

commit 1fa639e5618029e944ac68d27e32a99dcb85a349
Author: James Hogan <jhogan@kernel.org>
Date:   Sat Dec 21 15:53:06 2019 +0000

    MAINTAINERS: Orphan MIPS KVM CPUs

    I haven't been active for 18 months, and don't have the hardware
    set up to test KVM for MIPS, so mark it as orphaned and remove
    myself as maintainer. Hopefully somebody from MIPS can pick this up.


commit 134f7f7da12aad99daafbeb2a7ba9dbc6bd40abc
Author: Aleksandar Markovic <aleksandar.m.mail@gmail.com>
Date:   Mon Feb 24 12:50:58 2020 +0100

    MAINTAINERS: Reactivate MIPS KVM CPUs

    Reactivate MIPS KVM maintainership with a modest goal of keeping
    the support alive, checking common KVM code changes against MIPS
    functionality, etc. (hence the status "Odd Fixes"), with hope that
    this component will be fully maintained at some further, but not
    distant point in future.


commit 15d983dee95edff1dc4c0bed71ce02fff877e766
Author: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
Date:   Wed Jul 1 20:25:58 2020 +0200

    MAINTAINERS: Adjust MIPS maintainership (Huacai Chen & Jiaxun Yang)

    Huacai Chen and Jiaxun Yang step in as new energy [1].


commit ca263c0fb9f33cc746e6e3d968b7db80072ecf86
Author: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
Date:   Wed Oct 7 22:37:21 2020 +0200

    MAINTAINERS: Remove myself

    I have been working on project other than QEMU for some time,
    and would like to devote myself to that project. It is impossible
    for me to find enough time to perform maintainer's duties with
    needed meticulousness and patience.


QEMU deprecation process is quite slow, if we release mips-softmmu
and mipsel-softmmu binaries with KVM support in 5.2, and you can not
test them, you will still have to maintain them during 2021...

If you don't have neither the hardware nor the time, I suggest you
to only release it on 64-bit hosts. Personally I'd even only
announce KVM supported on the little-endian binary only, because
AFAIK you don't test big-endian KVM neither.

Your call as a maintainer, but remember last RC tag is next
Tuesday (Nov 24) in *4* days, then we release 5.2:
https://wiki.qemu.org/Planning/5.2#Release_Schedule

Regards,

Phil.


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

* Re: [PATCH V13 2/9] meson.build: Re-enable KVM support for MIPS
  2020-11-20 10:55       ` Philippe Mathieu-Daudé
@ 2020-11-22  3:31         ` Huacai Chen
  2021-03-23 13:56           ` Philippe Mathieu-Daudé
  0 siblings, 1 reply; 34+ messages in thread
From: Huacai Chen @ 2020-11-22  3:31 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, Jiaxun Yang
  Cc: Huacai Chen, Thomas Huth, kvm, Peter Maydell, Aleksandar Rikalo,
	QEMU Developers, Paolo Bonzini, Aurelien Jarno

+CC Jiaxun

Hi, Jiaxun,

What do you think about?

Huacai

On Fri, Nov 20, 2020 at 6:55 PM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
>
> On 11/20/20 5:28 AM, Huacai Chen wrote:
> > On Wed, Nov 18, 2020 at 1:17 AM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
> >> On 10/7/20 10:39 AM, Huacai Chen wrote:
> >>> After converting from configure to meson, KVM support is lost for MIPS,
> >>> so re-enable it in meson.build.
> >>>
> >>> Fixes: fdb75aeff7c212e1afaaa3a43 ("configure: remove target configuration")
> >>> Fixes: 8a19980e3fc42239aae054bc9 ("configure: move accelerator logic to meson")
> >>> Cc: aolo Bonzini <pbonzini@redhat.com>
> >>> Signed-off-by: Huacai Chen <chenhc@lemote.com>
> >>> ---
> >>>  meson.build | 2 ++
> >>>  1 file changed, 2 insertions(+)
> >>>
> >>> diff --git a/meson.build b/meson.build
> >>> index 17c89c8..b407ff4 100644
> >>> --- a/meson.build
> >>> +++ b/meson.build
> >>> @@ -59,6 +59,8 @@ elif cpu == 's390x'
> >>>    kvm_targets = ['s390x-softmmu']
> >>>  elif cpu in ['ppc', 'ppc64']
> >>>    kvm_targets = ['ppc-softmmu', 'ppc64-softmmu']
> >>> +elif cpu in ['mips', 'mips64']
> >>> +  kvm_targets = ['mips-softmmu', 'mipsel-softmmu', 'mips64-softmmu', 'mips64el-softmmu']
> >>
> >> Are you sure both 32-bit hosts and targets are supported?
> >>
> >> I don't have hardware to test. If you are not working with
> >> 32-bit hardware I'd remove them.
> > When I add MIPS64 KVM support (Loongson-3 is MIPS64), MIPS32 KVM is
> > already there. On the kernel side, MIPS32 KVM is supported, but I
> > don't know whether it can work well.
>
> Well, from the history, you inherited from it:
>
> commit 1fa639e5618029e944ac68d27e32a99dcb85a349
> Author: James Hogan <jhogan@kernel.org>
> Date:   Sat Dec 21 15:53:06 2019 +0000
>
>     MAINTAINERS: Orphan MIPS KVM CPUs
>
>     I haven't been active for 18 months, and don't have the hardware
>     set up to test KVM for MIPS, so mark it as orphaned and remove
>     myself as maintainer. Hopefully somebody from MIPS can pick this up.
>
>
> commit 134f7f7da12aad99daafbeb2a7ba9dbc6bd40abc
> Author: Aleksandar Markovic <aleksandar.m.mail@gmail.com>
> Date:   Mon Feb 24 12:50:58 2020 +0100
>
>     MAINTAINERS: Reactivate MIPS KVM CPUs
>
>     Reactivate MIPS KVM maintainership with a modest goal of keeping
>     the support alive, checking common KVM code changes against MIPS
>     functionality, etc. (hence the status "Odd Fixes"), with hope that
>     this component will be fully maintained at some further, but not
>     distant point in future.
>
>
> commit 15d983dee95edff1dc4c0bed71ce02fff877e766
> Author: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
> Date:   Wed Jul 1 20:25:58 2020 +0200
>
>     MAINTAINERS: Adjust MIPS maintainership (Huacai Chen & Jiaxun Yang)
>
>     Huacai Chen and Jiaxun Yang step in as new energy [1].
>
>
> commit ca263c0fb9f33cc746e6e3d968b7db80072ecf86
> Author: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
> Date:   Wed Oct 7 22:37:21 2020 +0200
>
>     MAINTAINERS: Remove myself
>
>     I have been working on project other than QEMU for some time,
>     and would like to devote myself to that project. It is impossible
>     for me to find enough time to perform maintainer's duties with
>     needed meticulousness and patience.
>
>
> QEMU deprecation process is quite slow, if we release mips-softmmu
> and mipsel-softmmu binaries with KVM support in 5.2, and you can not
> test them, you will still have to maintain them during 2021...
>
> If you don't have neither the hardware nor the time, I suggest you
> to only release it on 64-bit hosts. Personally I'd even only
> announce KVM supported on the little-endian binary only, because
> AFAIK you don't test big-endian KVM neither.
>
> Your call as a maintainer, but remember last RC tag is next
> Tuesday (Nov 24) in *4* days, then we release 5.2:
> https://wiki.qemu.org/Planning/5.2#Release_Schedule
>
> Regards,
>
> Phil.


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

* Re: [PATCH V13 2/9] meson.build: Re-enable KVM support for MIPS
  2020-11-22  3:31         ` Huacai Chen
@ 2021-03-23 13:56           ` Philippe Mathieu-Daudé
  2021-03-24  1:22             ` Jiaxun Yang
  0 siblings, 1 reply; 34+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-03-23 13:56 UTC (permalink / raw)
  To: Huacai Chen, Jiaxun Yang
  Cc: Huacai Chen, Thomas Huth, kvm, Peter Maydell, QEMU Developers,
	Paolo Bonzini, Aleksandar Rikalo, Aurelien Jarno

Hi Huacai,

We are going to tag QEMU v6.0-rc0 today.

I only have access to a 64-bit MIPS in little-endian to
test KVM.

Can you test the other configurations please?
- 32-bit BE
- 32-bit LE
- 64-bit BE

Thanks!

Phil.

On 11/22/20 4:31 AM, Huacai Chen wrote:
> +CC Jiaxun
> 
> Hi, Jiaxun,
> 
> What do you think about?
> 
> Huacai
> 
> On Fri, Nov 20, 2020 at 6:55 PM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
>>
>> On 11/20/20 5:28 AM, Huacai Chen wrote:
>>> On Wed, Nov 18, 2020 at 1:17 AM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
>>>> On 10/7/20 10:39 AM, Huacai Chen wrote:
>>>>> After converting from configure to meson, KVM support is lost for MIPS,
>>>>> so re-enable it in meson.build.
>>>>>
>>>>> Fixes: fdb75aeff7c212e1afaaa3a43 ("configure: remove target configuration")
>>>>> Fixes: 8a19980e3fc42239aae054bc9 ("configure: move accelerator logic to meson")
>>>>> Cc: aolo Bonzini <pbonzini@redhat.com>
>>>>> Signed-off-by: Huacai Chen <chenhc@lemote.com>
>>>>> ---
>>>>>  meson.build | 2 ++
>>>>>  1 file changed, 2 insertions(+)
>>>>>
>>>>> diff --git a/meson.build b/meson.build
>>>>> index 17c89c8..b407ff4 100644
>>>>> --- a/meson.build
>>>>> +++ b/meson.build
>>>>> @@ -59,6 +59,8 @@ elif cpu == 's390x'
>>>>>    kvm_targets = ['s390x-softmmu']
>>>>>  elif cpu in ['ppc', 'ppc64']
>>>>>    kvm_targets = ['ppc-softmmu', 'ppc64-softmmu']
>>>>> +elif cpu in ['mips', 'mips64']
>>>>> +  kvm_targets = ['mips-softmmu', 'mipsel-softmmu', 'mips64-softmmu', 'mips64el-softmmu']
>>>>
>>>> Are you sure both 32-bit hosts and targets are supported?
>>>>
>>>> I don't have hardware to test. If you are not working with
>>>> 32-bit hardware I'd remove them.
>>> When I add MIPS64 KVM support (Loongson-3 is MIPS64), MIPS32 KVM is
>>> already there. On the kernel side, MIPS32 KVM is supported, but I
>>> don't know whether it can work well.
>>
>> Well, from the history, you inherited from it:
>>
>> commit 1fa639e5618029e944ac68d27e32a99dcb85a349
>> Author: James Hogan <jhogan@kernel.org>
>> Date:   Sat Dec 21 15:53:06 2019 +0000
>>
>>     MAINTAINERS: Orphan MIPS KVM CPUs
>>
>>     I haven't been active for 18 months, and don't have the hardware
>>     set up to test KVM for MIPS, so mark it as orphaned and remove
>>     myself as maintainer. Hopefully somebody from MIPS can pick this up.
>>
>>
>> commit 134f7f7da12aad99daafbeb2a7ba9dbc6bd40abc
>> Author: Aleksandar Markovic <aleksandar.m.mail@gmail.com>
>> Date:   Mon Feb 24 12:50:58 2020 +0100
>>
>>     MAINTAINERS: Reactivate MIPS KVM CPUs
>>
>>     Reactivate MIPS KVM maintainership with a modest goal of keeping
>>     the support alive, checking common KVM code changes against MIPS
>>     functionality, etc. (hence the status "Odd Fixes"), with hope that
>>     this component will be fully maintained at some further, but not
>>     distant point in future.
>>
>>
>> commit 15d983dee95edff1dc4c0bed71ce02fff877e766
>> Author: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
>> Date:   Wed Jul 1 20:25:58 2020 +0200
>>
>>     MAINTAINERS: Adjust MIPS maintainership (Huacai Chen & Jiaxun Yang)
>>
>>     Huacai Chen and Jiaxun Yang step in as new energy [1].
>>
>>
>> commit ca263c0fb9f33cc746e6e3d968b7db80072ecf86
>> Author: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
>> Date:   Wed Oct 7 22:37:21 2020 +0200
>>
>>     MAINTAINERS: Remove myself
>>
>>     I have been working on project other than QEMU for some time,
>>     and would like to devote myself to that project. It is impossible
>>     for me to find enough time to perform maintainer's duties with
>>     needed meticulousness and patience.
>>
>>
>> QEMU deprecation process is quite slow, if we release mips-softmmu
>> and mipsel-softmmu binaries with KVM support in 5.2, and you can not
>> test them, you will still have to maintain them during 2021...
>>
>> If you don't have neither the hardware nor the time, I suggest you
>> to only release it on 64-bit hosts. Personally I'd even only
>> announce KVM supported on the little-endian binary only, because
>> AFAIK you don't test big-endian KVM neither.
>>
>> Your call as a maintainer, but remember last RC tag is next
>> Tuesday (Nov 24) in *4* days, then we release 5.2:
>> https://wiki.qemu.org/Planning/5.2#Release_Schedule
>>
>> Regards,
>>
>> Phil.
> 


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

* Re: [PATCH V13 2/9] meson.build: Re-enable KVM support for MIPS
  2021-03-23 13:56           ` Philippe Mathieu-Daudé
@ 2021-03-24  1:22             ` Jiaxun Yang
  2021-03-24  2:12               ` YunQiang Su
  0 siblings, 1 reply; 34+ messages in thread
From: Jiaxun Yang @ 2021-03-24  1:22 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, Huacai Chen
  Cc: Huacai Chen, Thomas Huth, YunQiang Su, kvm, Peter Maydell,
	BALATON Zoltan via, Paolo Bonzini, Aleksandar Rikalo,
	Aurelien Jarno



On Tue, Mar 23, 2021, at 9:56 PM, Philippe Mathieu-Daudé wrote:
> Hi Huacai,
> 
> We are going to tag QEMU v6.0-rc0 today.
> 
> I only have access to a 64-bit MIPS in little-endian to
> test KVM.
> 
> Can you test the other configurations please?
> - 32-bit BE
> - 32-bit LE
> - 64-bit BE

+syq
As Loongson doesn't have Big-Endian processor and Loongson 3A won't run 32bit kernel.

Probably wecan test on boston or malta board? 

Thanks. 


> 
> Thanks!
> 
> Phil.
> 
> 
[...]

-- 
- Jiaxun


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

* Re: [PATCH V13 2/9] meson.build: Re-enable KVM support for MIPS
  2021-03-24  1:22             ` Jiaxun Yang
@ 2021-03-24  2:12               ` YunQiang Su
  0 siblings, 0 replies; 34+ messages in thread
From: YunQiang Su @ 2021-03-24  2:12 UTC (permalink / raw)
  To: Jiaxun Yang
  Cc: Huacai Chen, Thomas Huth, kvm, Peter Maydell, Huacai Chen,
	Philippe Mathieu-Daudé,
	BALATON Zoltan via, Paolo Bonzini, Aleksandar Rikalo,
	Aurelien Jarno

Jiaxun Yang <jiaxun.yang@flygoat.com> 于2021年3月24日周三 上午9:29写道:
>
>
>
> On Tue, Mar 23, 2021, at 9:56 PM, Philippe Mathieu-Daudé wrote:
> > Hi Huacai,
> >
> > We are going to tag QEMU v6.0-rc0 today.
> >
> > I only have access to a 64-bit MIPS in little-endian to
> > test KVM.
> >
> > Can you test the other configurations please?
> > - 32-bit BE
> > - 32-bit LE
> > - 64-bit BE
>

How to run the test? just run a VM with KVM support on these kernel?

> +syq
> As Loongson doesn't have Big-Endian processor and Loongson 3A won't run 32bit kernel.
>
> Probably wecan test on boston or malta board?
>
> Thanks.
>
>
> >
> > Thanks!
> >
> > Phil.
> >
> >
> [...]
>
> --
> - Jiaxun


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

end of thread, other threads:[~2021-03-24  2:14 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-10-07  8:39 [PATCH V13 0/9] mips: Add Loongson-3 machine support Huacai Chen
2020-10-07  8:39 ` [PATCH V13 1/9] linux-headers: Update MIPS KVM type defintition Huacai Chen
2020-10-10  8:25   ` Philippe Mathieu-Daudé
2020-10-10 12:59   ` Peter Maydell
2020-10-10 13:11     ` Philippe Mathieu-Daudé
2020-10-07  8:39 ` [PATCH V13 2/9] meson.build: Re-enable KVM support for MIPS Huacai Chen
2020-10-07  8:51   ` Paolo Bonzini
2020-11-17 17:17   ` Philippe Mathieu-Daudé
2020-11-20  4:28     ` Huacai Chen
2020-11-20 10:55       ` Philippe Mathieu-Daudé
2020-11-22  3:31         ` Huacai Chen
2021-03-23 13:56           ` Philippe Mathieu-Daudé
2021-03-24  1:22             ` Jiaxun Yang
2021-03-24  2:12               ` YunQiang Su
2020-10-07  8:39 ` [PATCH V13 3/9] target/mips: Fix PageMask with variable page size Huacai Chen
2020-10-07  8:39 ` [PATCH V13 4/9] target/mips: Add loongson-ext lswc2 group of instructions (Part 1) Huacai Chen
2020-10-07  8:39 ` [PATCH V13 5/9] target/mips: Add loongson-ext lswc2 group of instructions (Part 2) Huacai Chen
2020-10-07  8:39 ` [PATCH V13 6/9] target/mips: Add loongson-ext lsdc2 group of instructions Huacai Chen
2020-10-10 13:07   ` Philippe Mathieu-Daudé
2020-10-11  3:02     ` Huacai Chen
2020-10-11 11:13       ` Philippe Mathieu-Daudé
2020-10-12 10:33         ` Huacai Chen
2020-10-12 11:04           ` Philippe Mathieu-Daudé
2020-10-07  8:39 ` [PATCH V13 7/9] hw/mips: Implement fw_cfg_arch_key_name() Huacai Chen
2020-10-07  8:39 ` [PATCH V13 8/9] hw/mips: Add Loongson-3 machine support Huacai Chen
2020-10-10  9:09   ` Philippe Mathieu-Daudé
2020-10-11  2:53     ` Huacai Chen
2020-10-12  8:12       ` Philippe Mathieu-Daudé
2020-10-13 11:12         ` Huacai Chen
2020-10-13 13:45           ` Philippe Mathieu-Daudé
2020-10-14  1:28             ` Huacai Chen
2020-10-07  8:39 ` [PATCH V13 9/9] docs/system: Update MIPS machine documentation Huacai Chen
2020-10-09 15:29   ` Philippe Mathieu-Daudé
2020-10-10  1:47     ` Huacai Chen

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).