All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH V9 0/6] mips: Add Loongson-3 machine support
@ 2020-09-16  2:12 Huacai Chen
  2020-09-16  2:12 ` [PATCH V9 1/6] linux-headers: Update MIPS KVM type defintition Huacai Chen
                   ` (7 more replies)
  0 siblings, 8 replies; 26+ messages in thread
From: Huacai Chen @ 2020-09-16  2:12 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).

Huacai Chen and Jiaxun Yang (6):
 linux-headers: Update MIPS KVM type defintition
 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: Add Loongson-3 machine support

Signed-off-by: Huacai Chen <chenhc@lemote.com>
---
 default-configs/mips64el-softmmu.mak |   1 +
 hw/mips/Kconfig                      |  11 +
 hw/mips/fw_cfg.c                     |  35 ++
 hw/mips/fw_cfg.h                     |  19 +
 hw/mips/loongson3_virt.c             | 956 +++++++++++++++++++++++++++++++++++
 hw/mips/meson.build                  |   3 +-
 linux-headers/linux/kvm.h            |   5 +-
 target/mips/cp0_helper.c             |  36 +-
 target/mips/cpu.h                    |   1 +
 target/mips/translate.c              | 437 ++++++++++++++++
 10 files changed, 1494 insertions(+), 10 deletions(-)
 create mode 100644 hw/mips/fw_cfg.c
 create mode 100644 hw/mips/fw_cfg.h
 create mode 100644 hw/mips/loongson3_virt.c
--
2.7.0


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

* [PATCH V9 1/6] linux-headers: Update MIPS KVM type defintition
  2020-09-16  2:12 [PATCH V9 0/6] mips: Add Loongson-3 machine support Huacai Chen
@ 2020-09-16  2:12 ` Huacai Chen
  2020-09-16  2:12 ` [PATCH V9 2/6] target/mips: Fix PageMask with variable page size Huacai Chen
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 26+ messages in thread
From: Huacai Chen @ 2020-09-16  2:12 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 a28c366..36a480f 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -789,9 +789,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] 26+ messages in thread

* [PATCH V9 2/6] target/mips: Fix PageMask with variable page size
  2020-09-16  2:12 [PATCH V9 0/6] mips: Add Loongson-3 machine support Huacai Chen
  2020-09-16  2:12 ` [PATCH V9 1/6] linux-headers: Update MIPS KVM type defintition Huacai Chen
@ 2020-09-16  2:12 ` Huacai Chen
  2020-09-16  2:12 ` [PATCH V9 3/6] target/mips: Add loongson-ext lswc2 group of instructions (Part 1) Huacai Chen
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 26+ messages in thread
From: Huacai Chen @ 2020-09-16  2:12 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 nolonger true.

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..62bcb97 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 tan or equel to
+     * the minimal but smaller than or equel 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] 26+ messages in thread

* [PATCH V9 3/6] target/mips: Add loongson-ext lswc2 group of instructions (Part 1)
  2020-09-16  2:12 [PATCH V9 0/6] mips: Add Loongson-3 machine support Huacai Chen
  2020-09-16  2:12 ` [PATCH V9 1/6] linux-headers: Update MIPS KVM type defintition Huacai Chen
  2020-09-16  2:12 ` [PATCH V9 2/6] target/mips: Fix PageMask with variable page size Huacai Chen
@ 2020-09-16  2:12 ` Huacai Chen
  2020-09-16  7:46   ` Philippe Mathieu-Daudé
  2020-09-16 15:15   ` Richard Henderson
  2020-09-16  2:12 ` [PATCH V9 4/6] target/mips: Add loongson-ext lswc2 group of instructions (Part 2) Huacai Chen
                   ` (4 subsequent siblings)
  7 siblings, 2 replies; 26+ messages in thread
From: Huacai Chen @ 2020-09-16  2:12 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 | 81 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 81 insertions(+)

diff --git a/target/mips/translate.c b/target/mips/translate.c
index 398edf7..08d51e1 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,74 @@ 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;
+    int lsq_offset = ((int)((ctx->opcode >> 6) & 0x1ff) << 23) >> 19;
+    int lsq_rt1 = ctx->opcode & 0x1f;
+    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:
+        gen_base_offset_addr(ctx, t0, rs, lsq_offset);
+        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ |
+                            ctx->default_tcg_memop_mask);
+        gen_store_gpr(t0, rt);
+        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(t0, lsq_rt1);
+        break;
+    case OPC_GSLQC1:
+        check_cp1_enabled(ctx);
+        gen_base_offset_addr(ctx, t0, rs, lsq_offset);
+        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ |
+                            ctx->default_tcg_memop_mask);
+        gen_store_fpr64(ctx, t0, rt);
+        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, t0, lsq_rt1);
+        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 +30853,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] 26+ messages in thread

* [PATCH V9 4/6] target/mips: Add loongson-ext lswc2 group of instructions (Part 2)
  2020-09-16  2:12 [PATCH V9 0/6] mips: Add Loongson-3 machine support Huacai Chen
                   ` (2 preceding siblings ...)
  2020-09-16  2:12 ` [PATCH V9 3/6] target/mips: Add loongson-ext lswc2 group of instructions (Part 1) Huacai Chen
@ 2020-09-16  2:12 ` Huacai Chen
  2020-09-16  2:12 ` [PATCH V9 5/6] target/mips: Add loongson-ext lsdc2 group of instructions Huacai Chen
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 26+ messages in thread
From: Huacai Chen @ 2020-09-16  2:12 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 08d51e1..2bcf1ce 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)))
 
@@ -5981,6 +5994,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] 26+ messages in thread

* [PATCH V9 5/6] target/mips: Add loongson-ext lsdc2 group of instructions
  2020-09-16  2:12 [PATCH V9 0/6] mips: Add Loongson-3 machine support Huacai Chen
                   ` (3 preceding siblings ...)
  2020-09-16  2:12 ` [PATCH V9 4/6] target/mips: Add loongson-ext lswc2 group of instructions (Part 2) Huacai Chen
@ 2020-09-16  2:12 ` Huacai Chen
  2020-09-16  2:12 ` [PATCH V9 6/6] hw/mips: Add Loongson-3 machine support Huacai Chen
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 26+ messages in thread
From: Huacai Chen @ 2020-09-16  2:12 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 2bcf1ce..c7ec8cf 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)))
 
@@ -6166,6 +6184,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)
@@ -31049,6 +31226,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] 26+ messages in thread

* [PATCH V9 6/6] hw/mips: Add Loongson-3 machine support
  2020-09-16  2:12 [PATCH V9 0/6] mips: Add Loongson-3 machine support Huacai Chen
                   ` (4 preceding siblings ...)
  2020-09-16  2:12 ` [PATCH V9 5/6] target/mips: Add loongson-ext lsdc2 group of instructions Huacai Chen
@ 2020-09-16  2:12 ` Huacai Chen
  2020-09-16  7:56   ` Philippe Mathieu-Daudé
  2020-09-17  7:56 ` [PATCH V9 0/6] mips: " Philippe Mathieu-Daudé
  2020-09-17  8:22 ` Aleksandar Markovic
  7 siblings, 1 reply; 26+ messages in thread
From: Huacai Chen @ 2020-09-16  2:12 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/mips64el-softmmu.mak |   1 +
 hw/mips/Kconfig                      |  11 +
 hw/mips/fw_cfg.c                     |  35 ++
 hw/mips/fw_cfg.h                     |  19 +
 hw/mips/loongson3_virt.c             | 956 +++++++++++++++++++++++++++++++++++
 hw/mips/meson.build                  |   3 +-
 6 files changed, 1024 insertions(+), 1 deletion(-)
 create mode 100644 hw/mips/fw_cfg.c
 create mode 100644 hw/mips/fw_cfg.h
 create mode 100644 hw/mips/loongson3_virt.c

diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak
index 9f8a3ef..26c660a 100644
--- a/default-configs/mips64el-softmmu.mak
+++ b/default-configs/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..cc5609b 100644
--- a/hw/mips/Kconfig
+++ b/hw/mips/Kconfig
@@ -45,6 +45,17 @@ config FULOONG
     bool
     select PCI_BONITO
 
+config LOONGSON3V
+    bool
+    select PCKBD
+    select SERIAL
+    select GOLDFISH_RTC
+    select LOONGSON_LIOINTC
+    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/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/loongson3_virt.c b/hw/mips/loongson3_virt.c
new file mode 100644
index 0000000..14d3024
--- /dev/null
+++ b/hw/mips/loongson3_virt.c
@@ -0,0 +1,956 @@
+/*
+ * 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 "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/misc/empty_slot.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
+
+/* 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;
+};
+
+/*
+ * 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
+ */
+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];
+} __attribute__((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];
+} __attribute__((packed));
+
+#define MAX_UARTS 64
+struct uart_device {
+    uint32_t iotype;
+    uint32_t uartclk;
+    uint32_t int_offset;
+    uint64_t uart_base;
+} __attribute__((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 */
+} __attribute__((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 */
+} __attribute__((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;
+} __attribute__((packed));
+
+struct interface_info {
+    uint16_t vers;               /* version of the specificition */
+    uint16_t size;
+    uint8_t  flag;
+    char description[64];
+} __attribute__((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;
+};
+
+#define LOONGSON_MAX_VCPUS      16
+
+#define LOONGSON3_BIOSNAME "bios_loongson3.bin"
+
+#define UART_IRQ            0
+#define RTC_IRQ             1
+#define PCIE_IRQ_BASE       2
+
+#define align(x) (((x) + 63) & ~63)
+
+static 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,
+};
+
+static struct efi_memory_map_loongson *init_memory_map(void *g_map)
+{
+    struct efi_memory_map_loongson *emap = g_map;
+
+    emap->nr_map = 2;
+    emap->mem_freq = 300000000;
+
+    emap->map[0].node_id = 0;
+    emap->map[0].mem_type = 1;
+    emap->map[0].mem_start = 0x0;
+    emap->map[0].mem_size = 240;
+
+    emap->map[1].node_id = 0;
+    emap->map[1].mem_type = 2;
+    emap->map[1].mem_start = 0x90000000;
+    emap->map[1].mem_size = (loaderparams.ram_size / MiB) - 256;
+
+    return emap;
+}
+
+static uint64_t get_cpu_freq(void)
+{
+    int ret;
+    uint64_t freq;
+    struct kvm_one_reg freq_reg = {
+        .id = KVM_REG_MIPS_COUNT_HZ,
+        .addr = (uintptr_t)(&freq)
+    };
+
+    if (!kvm_enabled()) {
+        return 200 * 1000 * 1000;
+    } else {
+        ret = kvm_vcpu_ioctl(first_cpu, KVM_GET_ONE_REG, &freq_reg);
+        if (ret < 0) {
+            return 1600 * 1000 * 1000;
+        }
+        return (freq * 2);
+    }
+}
+
+static struct efi_cpuinfo_loongson *init_cpu_info(void *g_cpuinfo_loongson)
+{
+    struct efi_cpuinfo_loongson *c = g_cpuinfo_loongson;
+
+    c->cputype = Loongson_3A;
+    c->processor_id = MIPS_CPU(first_cpu)->env.CP0_PRid;
+    if (loaderparams.cpu_freq > UINT_MAX) {
+        c->cpu_clock_freq = UINT_MAX;
+    } else {
+        c->cpu_clock_freq = loaderparams.cpu_freq;
+    }
+
+    c->cpu_startup_core_id = 0;
+    c->nr_cpus = current_machine->smp.cpus;
+    c->total_node = (current_machine->smp.cpus + 3) / 4;
+
+    return c;
+}
+
+static struct system_loongson *init_system_loongson(void *g_system)
+{
+    struct system_loongson *s = g_system;
+
+    s->ccnuma_smp = 0;
+    s->sing_double_channel = 1;
+    s->nr_uarts = 1;
+    s->uarts[0].iotype = 2;
+    s->uarts[0].int_offset = 2;
+    s->uarts[0].uartclk = 25000000; /* Random value */
+    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;
+
+    irq_info->node_id = 0;
+    irq_info->PIC_type = 0;
+    irq_info->dma_mask_bits = 64;
+    irq_info->pci_mem_start_addr = virt_memmap[VIRT_PCIE_MMIO].base;
+    irq_info->pci_mem_end_addr   = virt_memmap[VIRT_PCIE_MMIO].base +
+                                   virt_memmap[VIRT_PCIE_MMIO].size - 1;
+    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;
+
+    interface->vers = 0x01;
+    strcpy(interface->description, "UEFI_Version_v1.0");
+
+    return interface;
+}
+
+static struct board_devices *board_devices_info(void *g_board)
+{
+    struct board_devices *bd = g_board;
+
+    strcpy(bd->name, "Loongson-3A-VIRT-1w-V1.00-demo");
+
+    return bd;
+}
+
+static struct loongson_special_attribute *init_special_info(void *g_special)
+{
+    struct loongson_special_attribute *special = g_special;
+
+    strcpy(special->special_name, "2017-05-01");
+
+    return special;
+}
+
+static void init_loongson_params(struct loongson_params *lp, void *p)
+{
+    lp->memory_offset = (unsigned long long)init_memory_map(p)
+                        - (unsigned long long)lp;
+    p += align(sizeof(struct efi_memory_map_loongson));
+
+    lp->cpu_offset = (unsigned long long)init_cpu_info(p)
+                     - (unsigned long long)lp;
+    p += align(sizeof(struct efi_cpuinfo_loongson));
+
+    lp->system_offset = (unsigned long long)init_system_loongson(p)
+                        - (unsigned long long)lp;
+    p += align(sizeof(struct system_loongson));
+
+    lp->irq_offset = (unsigned long long)init_irq_source(p)
+                     - (unsigned long long)lp;
+    p += align(sizeof(struct irq_source_routing_table));
+
+    lp->interface_offset = (unsigned long long)init_interface_info(p)
+                           - (unsigned long long)lp;
+    p += align(sizeof(struct interface_info));
+
+    lp->boarddev_table_offset = (unsigned long long)board_devices_info(p)
+                                - (unsigned long long)lp;
+    p += align(sizeof(struct board_devices));
+
+    lp->special_offset = (unsigned long long)init_special_info(p)
+                         - (unsigned long long)lp;
+    p += align(sizeof(struct loongson_special_attribute));
+}
+
+static void init_reset_system(struct efi_reset_system_t *reset)
+{
+    reset->Shutdown = 0xffffffffbfc000a8;
+    reset->ResetCold = 0xffffffffbfc00080;
+    reset->ResetWarm = 0xffffffffbfc00080;
+}
+
+static void init_boot_param(void)
+{
+    void *p;
+    struct boot_params *bp;
+
+    p = g_malloc0(loader_rommap[LOADER_PARAM].size);
+    bp = p;
+
+    bp->efi.smbios.vers = 1;
+    init_reset_system(&(bp->reset_system));
+    p += align(sizeof(struct boot_params));
+    init_loongson_params(&(bp->efi.smbios.lp), p);
+
+    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, "%ld", loaderparams.ram_size > 0x10000000
+            ? 256 : (loaderparams.ram_size >> 20));
+    sprintf(highmemenv, "%ld", loaderparams.ram_size > 0x10000000
+            ? (loaderparams.ram_size >> 20) - 256 : 0);
+
+    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 need 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 need cpu type Loongson-3A4000");
+            exit(1);
+        }
+    }
+
+    if (ram_size < 512 * MiB) {
+        error_report("Loongson-3 need at least 512MB memory");
+        exit(1);
+    }
+
+    /*
+     * The whole MMIO range among configure registers doesn't generate
+     * exception when accessing invalid memory. Create an empty slot to
+     * emulate this feature.
+     */
+    empty_slot_init("fallback", 0, 0x80000000);
+
+    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 46294b7..32c8b95 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'))
+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_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] 26+ messages in thread

* Re: [PATCH V9 3/6] target/mips: Add loongson-ext lswc2 group of instructions (Part 1)
  2020-09-16  2:12 ` [PATCH V9 3/6] target/mips: Add loongson-ext lswc2 group of instructions (Part 1) Huacai Chen
@ 2020-09-16  7:46   ` Philippe Mathieu-Daudé
  2020-09-16  7:58     ` Huacai Chen
  2020-09-16 15:15   ` Richard Henderson
  1 sibling, 1 reply; 26+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-09-16  7:46 UTC (permalink / raw)
  To: Huacai Chen, Aleksandar Markovic
  Cc: Aleksandar Rikalo, Huacai Chen, qemu-devel, Jiaxun Yang,
	Huacai Chen, Aurelien Jarno

On 9/16/20 4:12 AM, Huacai Chen wrote:
> 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 | 81 +++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 81 insertions(+)
> 
> diff --git a/target/mips/translate.c b/target/mips/translate.c
> index 398edf7..08d51e1 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,74 @@ 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;
> +    int lsq_offset = ((int)((ctx->opcode >> 6) & 0x1ff) << 23) >> 19;
> +    int lsq_rt1 = ctx->opcode & 0x1f;
> +    int shf_offset = (int8_t)(ctx->opcode >> 6);
> +
> +    t0 = tcg_temp_new();
> +
> +    switch (MASK_LOONGSON_GSLSQ(ctx->opcode)) {
> +#if defined(TARGET_MIPS64)

Build failure (is this code tested?):

target/mips/translate.c: In function ‘gen_loongson_lswc2’:
target/mips/translate.c:5961:9: error: unused variable ‘lsq_rt1’
[-Werror=unused-variable]
     int lsq_rt1 = ctx->opcode & 0x1f;
         ^
target/mips/translate.c:5960:9: error: unused variable ‘lsq_offset’
[-Werror=unused-variable]
     int lsq_offset = ((int)((ctx->opcode >> 6) & 0x1ff) << 23) >> 19;
         ^
cc1: all warnings being treated as errors

> +    case OPC_GSLQ:
> +        gen_base_offset_addr(ctx, t0, rs, lsq_offset);
> +        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ |
> +                            ctx->default_tcg_memop_mask);
> +        gen_store_gpr(t0, rt);
> +        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(t0, lsq_rt1);
> +        break;
> +    case OPC_GSLQC1:
> +        check_cp1_enabled(ctx);
> +        gen_base_offset_addr(ctx, t0, rs, lsq_offset);
> +        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ |
> +                            ctx->default_tcg_memop_mask);
> +        gen_store_fpr64(ctx, t0, rt);
> +        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, t0, lsq_rt1);
> +        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 +30853,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. */
> 


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

* Re: [PATCH V9 6/6] hw/mips: Add Loongson-3 machine support
  2020-09-16  2:12 ` [PATCH V9 6/6] hw/mips: Add Loongson-3 machine support Huacai Chen
@ 2020-09-16  7:56   ` Philippe Mathieu-Daudé
  2020-09-16  8:08     ` Philippe Mathieu-Daudé
  2020-09-16  9:49     ` Huacai Chen
  0 siblings, 2 replies; 26+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-09-16  7:56 UTC (permalink / raw)
  To: Huacai Chen, Aleksandar Markovic
  Cc: Aleksandar Rikalo, Huacai Chen, qemu-devel, Jiaxun Yang,
	Huacai Chen, Aurelien Jarno

Hi Huacai,

On 9/16/20 4:12 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.

Alternatively you can name it loongson3-virt-5.2 from start.

> 
> 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;

Which produces all the following errors:

hw/mips/loongson3_virt.c: In function 'get_cpu_freq':
hw/mips/loongson3_virt.c:372:12: error: variable 'freq_reg' has
initializer but incomplete type
     struct kvm_one_reg freq_reg = {
            ^
hw/mips/loongson3_virt.c:373:9: error: unknown field 'id' specified in
initializer
         .id = KVM_REG_MIPS_COUNT_HZ,
         ^
hw/mips/loongson3_virt.c:373:15: error: 'KVM_REG_MIPS_COUNT_HZ'
undeclared (first use in this function)
         .id = KVM_REG_MIPS_COUNT_HZ,
               ^
hw/mips/loongson3_virt.c:373:15: note: each undeclared identifier is
reported only once for each function it appears in
hw/mips/loongson3_virt.c:373:15: error: excess elements in struct
initializer [-Werror]
hw/mips/loongson3_virt.c:373:15: note: (near initialization for 'freq_reg')
hw/mips/loongson3_virt.c:374:9: error: unknown field 'addr' specified in
initializer
         .addr = (uintptr_t)(&freq)
         ^
hw/mips/loongson3_virt.c:374:17: error: excess elements in struct
initializer [-Werror]
         .addr = (uintptr_t)(&freq)
                 ^
hw/mips/loongson3_virt.c:374:17: note: (near initialization for 'freq_reg')
hw/mips/loongson3_virt.c:372:24: error: storage size of 'freq_reg' isn't
known
     struct kvm_one_reg freq_reg = {
                        ^
hw/mips/loongson3_virt.c:380:41: error: 'KVM_GET_ONE_REG' undeclared
(first use in this function)
         ret = kvm_vcpu_ioctl(first_cpu, KVM_GET_ONE_REG, &freq_reg);
                                         ^
hw/mips/loongson3_virt.c:372:24: error: unused variable 'freq_reg'
[-Werror=unused-variable]
     struct kvm_one_reg freq_reg = {
                        ^
hw/mips/loongson3_virt.c: In function 'init_loongson_params':
hw/mips/loongson3_virt.c:467:25: error: cast from pointer to integer of
different size [-Werror=pointer-to-int-cast]
     lp->memory_offset = (unsigned long long)init_memory_map(p)
                         ^
hw/mips/loongson3_virt.c:468:27: error: cast from pointer to integer of
different size [-Werror=pointer-to-int-cast]
                         - (unsigned long long)lp;
                           ^
hw/mips/loongson3_virt.c:471:22: error: cast from pointer to integer of
different size [-Werror=pointer-to-int-cast]
     lp->cpu_offset = (unsigned long long)init_cpu_info(p)
                      ^
hw/mips/loongson3_virt.c:472:24: error: cast from pointer to integer of
different size [-Werror=pointer-to-int-cast]
                      - (unsigned long long)lp;
                        ^
hw/mips/loongson3_virt.c:475:25: error: cast from pointer to integer of
different size [-Werror=pointer-to-int-cast]
     lp->system_offset = (unsigned long long)init_system_loongson(p)
                         ^
hw/mips/loongson3_virt.c:476:27: error: cast from pointer to integer of
different size [-Werror=pointer-to-int-cast]
                         - (unsigned long long)lp;
                           ^
hw/mips/loongson3_virt.c:479:22: error: cast from pointer to integer of
different size [-Werror=pointer-to-int-cast]
     lp->irq_offset = (unsigned long long)init_irq_source(p)
                      ^
hw/mips/loongson3_virt.c:480:24: error: cast from pointer to integer of
different size [-Werror=pointer-to-int-cast]
                      - (unsigned long long)lp;
                        ^
hw/mips/loongson3_virt.c:483:28: error: cast from pointer to integer of
different size [-Werror=pointer-to-int-cast]
     lp->interface_offset = (unsigned long long)init_interface_info(p)
                            ^
hw/mips/loongson3_virt.c:484:30: error: cast from pointer to integer of
different size [-Werror=pointer-to-int-cast]
                            - (unsigned long long)lp;
                              ^
hw/mips/loongson3_virt.c:487:33: error: cast from pointer to integer of
different size [-Werror=pointer-to-int-cast]
     lp->boarddev_table_offset = (unsigned long long)board_devices_info(p)
                                 ^
hw/mips/loongson3_virt.c:488:35: error: cast from pointer to integer of
different size [-Werror=pointer-to-int-cast]
                                 - (unsigned long long)lp;
                                   ^
hw/mips/loongson3_virt.c:491:26: error: cast from pointer to integer of
different size [-Werror=pointer-to-int-cast]
     lp->special_offset = (unsigned long long)init_special_info(p)
                          ^
hw/mips/loongson3_virt.c:492:28: error: cast from pointer to integer of
different size [-Werror=pointer-to-int-cast]
                          - (unsigned long long)lp;
                            ^
hw/mips/loongson3_virt.c: In function 'set_prom_cmdline':
hw/mips/loongson3_virt.c:652:21: error: format '%ld' expects argument of
type 'long int', but argument 3 has type 'uint64_t {aka long long
unsigned int}' [-Werror=format=]
     sprintf(memenv, "%ld", loaderparams.ram_size > 0x10000000
                     ^
hw/mips/loongson3_virt.c:654:25: error: format '%ld' expects argument of
type 'long int', but argument 3 has type 'uint64_t {aka long long
unsigned int}' [-Werror=format=]
     sprintf(highmemenv, "%ld", loaderparams.ram_size > 0x10000000
                         ^
cc1: all warnings being treated as errors
Makefile.ninja:2459: recipe for target
'libqemu-mips64el-softmmu.fa.p/hw_mips_loongson3_virt.c.obj' failed
make: *** [libqemu-mips64el-softmmu.fa.p/hw_mips_loongson3_virt.c.obj]
Error 1

Anyway I'll keep reviewing this patch.

> 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/mips64el-softmmu.mak |   1 +
>  hw/mips/Kconfig                      |  11 +
>  hw/mips/fw_cfg.c                     |  35 ++
>  hw/mips/fw_cfg.h                     |  19 +
>  hw/mips/loongson3_virt.c             | 956 +++++++++++++++++++++++++++++++++++
>  hw/mips/meson.build                  |   3 +-
>  6 files changed, 1024 insertions(+), 1 deletion(-)
>  create mode 100644 hw/mips/fw_cfg.c
>  create mode 100644 hw/mips/fw_cfg.h
>  create mode 100644 hw/mips/loongson3_virt.c
> 
> diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak
> index 9f8a3ef..26c660a 100644
> --- a/default-configs/mips64el-softmmu.mak
> +++ b/default-configs/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..cc5609b 100644
> --- a/hw/mips/Kconfig
> +++ b/hw/mips/Kconfig
> @@ -45,6 +45,17 @@ config FULOONG
>      bool
>      select PCI_BONITO
>  
> +config LOONGSON3V
> +    bool
> +    select PCKBD
> +    select SERIAL
> +    select GOLDFISH_RTC
> +    select LOONGSON_LIOINTC
> +    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/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

Please keep the fw_cfg changes in a separate patch.

> diff --git a/hw/mips/loongson3_virt.c b/hw/mips/loongson3_virt.c
> new file mode 100644
> index 0000000..14d3024
> --- /dev/null
> +++ b/hw/mips/loongson3_virt.c
> @@ -0,0 +1,956 @@
> +/*
> + * 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 "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/misc/empty_slot.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
> +
> +/* 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;
> +};
> +
> +/*
> + * 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
> + */
> +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];
> +} __attribute__((packed));

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];
> +} __attribute__((packed));
> +
> +#define MAX_UARTS 64
> +struct uart_device {
> +    uint32_t iotype;
> +    uint32_t uartclk;
> +    uint32_t int_offset;
> +    uint64_t uart_base;
> +} __attribute__((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 */
> +} __attribute__((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 */
> +} __attribute__((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;
> +} __attribute__((packed));
> +
> +struct interface_info {
> +    uint16_t vers;               /* version of the specificition */
> +    uint16_t size;
> +    uint8_t  flag;
> +    char description[64];
> +} __attribute__((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 */
> +};

What about moving most of this declarations in a "loongson_efi.h"
local header?

> +
> +struct boot_params {
> +    struct efi_loongson efi;
> +    struct efi_reset_system_t reset_system;
> +};
> +
> +#define LOONGSON_MAX_VCPUS      16
> +
> +#define LOONGSON3_BIOSNAME "bios_loongson3.bin"
> +
> +#define UART_IRQ            0
> +#define RTC_IRQ             1
> +#define PCIE_IRQ_BASE       2
> +
> +#define align(x) (((x) + 63) & ~63)
> +
> +static 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,
> +};
> +
> +static struct efi_memory_map_loongson *init_memory_map(void *g_map)
> +{
> +    struct efi_memory_map_loongson *emap = g_map;
> +
> +    emap->nr_map = 2;
> +    emap->mem_freq = 300000000;
> +
> +    emap->map[0].node_id = 0;
> +    emap->map[0].mem_type = 1;
> +    emap->map[0].mem_start = 0x0;
> +    emap->map[0].mem_size = 240;
> +
> +    emap->map[1].node_id = 0;
> +    emap->map[1].mem_type = 2;
> +    emap->map[1].mem_start = 0x90000000;
> +    emap->map[1].mem_size = (loaderparams.ram_size / MiB) - 256;
> +
> +    return emap;
> +}
> +
> +static uint64_t get_cpu_freq(void)
> +{
> +    int ret;
> +    uint64_t freq;
> +    struct kvm_one_reg freq_reg = {
> +        .id = KVM_REG_MIPS_COUNT_HZ,
> +        .addr = (uintptr_t)(&freq)
> +    };
> +
> +    if (!kvm_enabled()) {
> +        return 200 * 1000 * 1000;

You earlier commented:
"Loongson-3 CPU (MIPS64R2 with extensions, 800~2000MHz"

Why not use 800 here?

> +    } else {
> +        ret = kvm_vcpu_ioctl(first_cpu, KVM_GET_ONE_REG, &freq_reg);
> +        if (ret < 0) {
> +            return 1600 * 1000 * 1000;
> +        }
> +        return (freq * 2);
> +    }
> +}
> +
> +static struct efi_cpuinfo_loongson *init_cpu_info(void *g_cpuinfo_loongson)
> +{
> +    struct efi_cpuinfo_loongson *c = g_cpuinfo_loongson;
> +
> +    c->cputype = Loongson_3A;
> +    c->processor_id = MIPS_CPU(first_cpu)->env.CP0_PRid;
> +    if (loaderparams.cpu_freq > UINT_MAX) {
> +        c->cpu_clock_freq = UINT_MAX;
> +    } else {
> +        c->cpu_clock_freq = loaderparams.cpu_freq;
> +    }
> +
> +    c->cpu_startup_core_id = 0;
> +    c->nr_cpus = current_machine->smp.cpus;
> +    c->total_node = (current_machine->smp.cpus + 3) / 4;
> +
> +    return c;
> +}
> +
> +static struct system_loongson *init_system_loongson(void *g_system)
> +{
> +    struct system_loongson *s = g_system;
> +
> +    s->ccnuma_smp = 0;
> +    s->sing_double_channel = 1;
> +    s->nr_uarts = 1;
> +    s->uarts[0].iotype = 2;
> +    s->uarts[0].int_offset = 2;
> +    s->uarts[0].uartclk = 25000000; /* Random value */
> +    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;
> +
> +    irq_info->node_id = 0;
> +    irq_info->PIC_type = 0;
> +    irq_info->dma_mask_bits = 64;
> +    irq_info->pci_mem_start_addr = virt_memmap[VIRT_PCIE_MMIO].base;
> +    irq_info->pci_mem_end_addr   = virt_memmap[VIRT_PCIE_MMIO].base +
> +                                   virt_memmap[VIRT_PCIE_MMIO].size - 1;
> +    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;
> +
> +    interface->vers = 0x01;
> +    strcpy(interface->description, "UEFI_Version_v1.0");
> +
> +    return interface;
> +}
> +
> +static struct board_devices *board_devices_info(void *g_board)
> +{
> +    struct board_devices *bd = g_board;
> +
> +    strcpy(bd->name, "Loongson-3A-VIRT-1w-V1.00-demo");
> +
> +    return bd;
> +}
> +
> +static struct loongson_special_attribute *init_special_info(void *g_special)
> +{
> +    struct loongson_special_attribute *special = g_special;
> +
> +    strcpy(special->special_name, "2017-05-01");

strpadcpy?

> +
> +    return special;
> +}
> +
> +static void init_loongson_params(struct loongson_params *lp, void *p)
> +{
> +    lp->memory_offset = (unsigned long long)init_memory_map(p)
> +                        - (unsigned long long)lp;
> +    p += align(sizeof(struct efi_memory_map_loongson));

       p += ROUND_UP(sizeof(struct efi_memory_map_loongson), 64);

or use QEMU_ALIGN_PTR_UP()?

> +
> +    lp->cpu_offset = (unsigned long long)init_cpu_info(p)
> +                     - (unsigned long long)lp;
> +    p += align(sizeof(struct efi_cpuinfo_loongson));
> +
> +    lp->system_offset = (unsigned long long)init_system_loongson(p)
> +                        - (unsigned long long)lp;
> +    p += align(sizeof(struct system_loongson));
> +
> +    lp->irq_offset = (unsigned long long)init_irq_source(p)
> +                     - (unsigned long long)lp;
> +    p += align(sizeof(struct irq_source_routing_table));
> +
> +    lp->interface_offset = (unsigned long long)init_interface_info(p)
> +                           - (unsigned long long)lp;
> +    p += align(sizeof(struct interface_info));
> +
> +    lp->boarddev_table_offset = (unsigned long long)board_devices_info(p)
> +                                - (unsigned long long)lp;
> +    p += align(sizeof(struct board_devices));
> +
> +    lp->special_offset = (unsigned long long)init_special_info(p)
> +                         - (unsigned long long)lp;
> +    p += align(sizeof(struct loongson_special_attribute));
> +}
> +
> +static void init_reset_system(struct efi_reset_system_t *reset)
> +{
> +    reset->Shutdown = 0xffffffffbfc000a8;
> +    reset->ResetCold = 0xffffffffbfc00080;
> +    reset->ResetWarm = 0xffffffffbfc00080;
> +}
> +
> +static void init_boot_param(void)
> +{
> +    void *p;
> +    struct boot_params *bp;
> +
> +    p = g_malloc0(loader_rommap[LOADER_PARAM].size);
> +    bp = p;
> +
> +    bp->efi.smbios.vers = 1;
> +    init_reset_system(&(bp->reset_system));
> +    p += align(sizeof(struct boot_params));
> +    init_loongson_params(&(bp->efi.smbios.lp), p);
> +
> +    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, "%ld", loaderparams.ram_size > 0x10000000
> +            ? 256 : (loaderparams.ram_size >> 20));

Please use 256 * MiB and MiB.

(I'm not sure why you check this, since you enforce 512M min).

> +    sprintf(highmemenv, "%ld", loaderparams.ram_size > 0x10000000
> +            ? (loaderparams.ram_size >> 20) - 256 : 0);
> +
> +    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 need 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 need cpu type Loongson-3A4000");
> +            exit(1);
> +        }
> +    }
> +
> +    if (ram_size < 512 * MiB) {
> +        error_report("Loongson-3 need at least 512MB memory");

Typo "needs", but why?

> +        exit(1);
> +    }
> +
> +    /*
> +     * The whole MMIO range among configure registers doesn't generate
> +     * exception when accessing invalid memory. Create an empty slot to
> +     * emulate this feature.
> +     */
> +    empty_slot_init("fallback", 0, 0x80000000);

Again, this doesn't look correct (no comment in my previous review).

> +
> +    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 46294b7..32c8b95 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'))
> +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_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] 26+ messages in thread

* Re: [PATCH V9 3/6] target/mips: Add loongson-ext lswc2 group of instructions (Part 1)
  2020-09-16  7:46   ` Philippe Mathieu-Daudé
@ 2020-09-16  7:58     ` Huacai Chen
  0 siblings, 0 replies; 26+ messages in thread
From: Huacai Chen @ 2020-09-16  7:58 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Huacai Chen, Aleksandar Rikalo, QEMU Developers, Jiaxun Yang,
	Aleksandar Markovic, Aurelien Jarno

Hi, Philippe,

On Wed, Sep 16, 2020 at 3:46 AM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
>
> On 9/16/20 4:12 AM, Huacai Chen wrote:
> > 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 | 81 +++++++++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 81 insertions(+)
> >
> > diff --git a/target/mips/translate.c b/target/mips/translate.c
> > index 398edf7..08d51e1 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,74 @@ 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;
> > +    int lsq_offset = ((int)((ctx->opcode >> 6) & 0x1ff) << 23) >> 19;
> > +    int lsq_rt1 = ctx->opcode & 0x1f;
> > +    int shf_offset = (int8_t)(ctx->opcode >> 6);
> > +
> > +    t0 = tcg_temp_new();
> > +
> > +    switch (MASK_LOONGSON_GSLSQ(ctx->opcode)) {
> > +#if defined(TARGET_MIPS64)
>
> Build failure (is this code tested?):
>
> target/mips/translate.c: In function ‘gen_loongson_lswc2’:
> target/mips/translate.c:5961:9: error: unused variable ‘lsq_rt1’
> [-Werror=unused-variable]
>      int lsq_rt1 = ctx->opcode & 0x1f;
>          ^
> target/mips/translate.c:5960:9: error: unused variable ‘lsq_offset’
> [-Werror=unused-variable]
>      int lsq_offset = ((int)((ctx->opcode >> 6) & 0x1ff) << 23) >> 19;
>          ^
> cc1: all warnings being treated as errors
Thank you very much, lsq_rt1 and lsq_offset should be guarded by TARGET_MIPS64.

Huacai
>
> > +    case OPC_GSLQ:
> > +        gen_base_offset_addr(ctx, t0, rs, lsq_offset);
> > +        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ |
> > +                            ctx->default_tcg_memop_mask);
> > +        gen_store_gpr(t0, rt);
> > +        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(t0, lsq_rt1);
> > +        break;
> > +    case OPC_GSLQC1:
> > +        check_cp1_enabled(ctx);
> > +        gen_base_offset_addr(ctx, t0, rs, lsq_offset);
> > +        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ |
> > +                            ctx->default_tcg_memop_mask);
> > +        gen_store_fpr64(ctx, t0, rt);
> > +        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, t0, lsq_rt1);
> > +        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 +30853,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. */
> >


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

* Re: [PATCH V9 6/6] hw/mips: Add Loongson-3 machine support
  2020-09-16  7:56   ` Philippe Mathieu-Daudé
@ 2020-09-16  8:08     ` Philippe Mathieu-Daudé
  2020-09-16  9:49     ` Huacai Chen
  1 sibling, 0 replies; 26+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-09-16  8:08 UTC (permalink / raw)
  To: Huacai Chen, Aleksandar Markovic
  Cc: Aleksandar Rikalo, Huacai Chen, qemu-devel, Jiaxun Yang,
	Huacai Chen, Aurelien Jarno

On 9/16/20 9:56 AM, Philippe Mathieu-Daudé wrote:
> On 9/16/20 4:12 AM, Huacai Chen wrote:
[...]
>> diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak
>> index 9f8a3ef..26c660a 100644
>> --- a/default-configs/mips64el-softmmu.mak
>> +++ b/default-configs/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..cc5609b 100644
>> --- a/hw/mips/Kconfig
>> +++ b/hw/mips/Kconfig
>> @@ -45,6 +45,17 @@ config FULOONG
>>      bool
>>      select PCI_BONITO
>>  
>> +config LOONGSON3V
>> +    bool
>> +    select PCKBD
>> +    select SERIAL
>> +    select GOLDFISH_RTC
>> +    select LOONGSON_LIOINTC
>> +    select PCI_EXPRESS_GENERIC_BRIDGE
>> +    select VIRTIO_VGA
>> +    select QXL if SPICE
>> +    select MSI_NONBROKEN

Another error:

../meson.build:577:4: ERROR: Running configure command failed.
The following clauses were found for VIRTIO_VGA
    config VIRTIO_VGA depends on VIRTIO_PCI
    select VIRTIO_VGA if LOONGSON3V
Traceback (most recent call last):
  File "scripts/minikconf.py", line 703, in <module>
    config = data.compute_config()
  File "scripts/minikconf.py", line 253, in compute_config
    clause.process()
  File "scripts/minikconf.py", line 200, in process
    self.dest.set_value(True, self)
  File "scripts/minikconf.py", line 118, in set_value
    raise KconfigDataError('contradiction between clauses when setting
%s' % self)
__main__.KconfigDataError: contradiction between clauses when setting
VIRTIO_VGA

>> +
>>  config MIPS_CPS
>>      bool
>>      select PTIMER


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

* Re: [PATCH V9 6/6] hw/mips: Add Loongson-3 machine support
  2020-09-16  7:56   ` Philippe Mathieu-Daudé
  2020-09-16  8:08     ` Philippe Mathieu-Daudé
@ 2020-09-16  9:49     ` Huacai Chen
  2020-09-16 10:47       ` Philippe Mathieu-Daudé
                         ` (2 more replies)
  1 sibling, 3 replies; 26+ messages in thread
From: Huacai Chen @ 2020-09-16  9:49 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Huacai Chen, Aleksandar Rikalo, QEMU Developers, Jiaxun Yang,
	Aleksandar Markovic, Aurelien Jarno

Hi, Philippe,

On Wed, Sep 16, 2020 at 3:56 PM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
>
> Hi Huacai,
>
> On 9/16/20 4:12 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.
>
> Alternatively you can name it loongson3-virt-5.2 from start.
Aleksandar doesn't like a version number, so let's keep the name as is.

>
> >
> > 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;
>
> Which produces all the following errors:
>
> hw/mips/loongson3_virt.c: In function 'get_cpu_freq':
> hw/mips/loongson3_virt.c:372:12: error: variable 'freq_reg' has
> initializer but incomplete type
>      struct kvm_one_reg freq_reg = {
>             ^
> hw/mips/loongson3_virt.c:373:9: error: unknown field 'id' specified in
> initializer
>          .id = KVM_REG_MIPS_COUNT_HZ,
>          ^
> hw/mips/loongson3_virt.c:373:15: error: 'KVM_REG_MIPS_COUNT_HZ'
> undeclared (first use in this function)
>          .id = KVM_REG_MIPS_COUNT_HZ,
>                ^
I don't know how to reproduce these errors, struct kvm_one_reg and
KVM_REG_MIPS_COUNT_HZ are both defined..., could you please tell me?
My build steps are like this:
mkdir build
cd build
../configure
make

> hw/mips/loongson3_virt.c:373:15: note: each undeclared identifier is
> reported only once for each function it appears in
> hw/mips/loongson3_virt.c:373:15: error: excess elements in struct
> initializer [-Werror]
> hw/mips/loongson3_virt.c:373:15: note: (near initialization for 'freq_reg')
> hw/mips/loongson3_virt.c:374:9: error: unknown field 'addr' specified in
> initializer
>          .addr = (uintptr_t)(&freq)
>          ^
> hw/mips/loongson3_virt.c:374:17: error: excess elements in struct
> initializer [-Werror]
>          .addr = (uintptr_t)(&freq)
>                  ^
> hw/mips/loongson3_virt.c:374:17: note: (near initialization for 'freq_reg')
> hw/mips/loongson3_virt.c:372:24: error: storage size of 'freq_reg' isn't
> known
>      struct kvm_one_reg freq_reg = {
>                         ^
> hw/mips/loongson3_virt.c:380:41: error: 'KVM_GET_ONE_REG' undeclared
> (first use in this function)
>          ret = kvm_vcpu_ioctl(first_cpu, KVM_GET_ONE_REG, &freq_reg);
>                                          ^
> hw/mips/loongson3_virt.c:372:24: error: unused variable 'freq_reg'
> [-Werror=unused-variable]
>      struct kvm_one_reg freq_reg = {
>                         ^
> hw/mips/loongson3_virt.c: In function 'init_loongson_params':
> hw/mips/loongson3_virt.c:467:25: error: cast from pointer to integer of
> different size [-Werror=pointer-to-int-cast]
>      lp->memory_offset = (unsigned long long)init_memory_map(p)
>                          ^
I guess this happens on a 32bit platform where pointer is 32bit, and
could you please suggest a best solution for this? Maybe use uintptr_t
instead of unsigned long long?

> hw/mips/loongson3_virt.c:468:27: error: cast from pointer to integer of
> different size [-Werror=pointer-to-int-cast]
>                          - (unsigned long long)lp;
>                            ^
> hw/mips/loongson3_virt.c:471:22: error: cast from pointer to integer of
> different size [-Werror=pointer-to-int-cast]
>      lp->cpu_offset = (unsigned long long)init_cpu_info(p)
>                       ^
> hw/mips/loongson3_virt.c:472:24: error: cast from pointer to integer of
> different size [-Werror=pointer-to-int-cast]
>                       - (unsigned long long)lp;
>                         ^
> hw/mips/loongson3_virt.c:475:25: error: cast from pointer to integer of
> different size [-Werror=pointer-to-int-cast]
>      lp->system_offset = (unsigned long long)init_system_loongson(p)
>                          ^
> hw/mips/loongson3_virt.c:476:27: error: cast from pointer to integer of
> different size [-Werror=pointer-to-int-cast]
>                          - (unsigned long long)lp;
>                            ^
> hw/mips/loongson3_virt.c:479:22: error: cast from pointer to integer of
> different size [-Werror=pointer-to-int-cast]
>      lp->irq_offset = (unsigned long long)init_irq_source(p)
>                       ^
> hw/mips/loongson3_virt.c:480:24: error: cast from pointer to integer of
> different size [-Werror=pointer-to-int-cast]
>                       - (unsigned long long)lp;
>                         ^
> hw/mips/loongson3_virt.c:483:28: error: cast from pointer to integer of
> different size [-Werror=pointer-to-int-cast]
>      lp->interface_offset = (unsigned long long)init_interface_info(p)
>                             ^
> hw/mips/loongson3_virt.c:484:30: error: cast from pointer to integer of
> different size [-Werror=pointer-to-int-cast]
>                             - (unsigned long long)lp;
>                               ^
> hw/mips/loongson3_virt.c:487:33: error: cast from pointer to integer of
> different size [-Werror=pointer-to-int-cast]
>      lp->boarddev_table_offset = (unsigned long long)board_devices_info(p)
>                                  ^
> hw/mips/loongson3_virt.c:488:35: error: cast from pointer to integer of
> different size [-Werror=pointer-to-int-cast]
>                                  - (unsigned long long)lp;
>                                    ^
> hw/mips/loongson3_virt.c:491:26: error: cast from pointer to integer of
> different size [-Werror=pointer-to-int-cast]
>      lp->special_offset = (unsigned long long)init_special_info(p)
>                           ^
> hw/mips/loongson3_virt.c:492:28: error: cast from pointer to integer of
> different size [-Werror=pointer-to-int-cast]
>                           - (unsigned long long)lp;
>                             ^
> hw/mips/loongson3_virt.c: In function 'set_prom_cmdline':
> hw/mips/loongson3_virt.c:652:21: error: format '%ld' expects argument of
> type 'long int', but argument 3 has type 'uint64_t {aka long long
> unsigned int}' [-Werror=format=]
>      sprintf(memenv, "%ld", loaderparams.ram_size > 0x10000000
>                      ^
> hw/mips/loongson3_virt.c:654:25: error: format '%ld' expects argument of
> type 'long int', but argument 3 has type 'uint64_t {aka long long
> unsigned int}' [-Werror=format=]
>      sprintf(highmemenv, "%ld", loaderparams.ram_size > 0x10000000
>                          ^
> cc1: all warnings being treated as errors
> Makefile.ninja:2459: recipe for target
> 'libqemu-mips64el-softmmu.fa.p/hw_mips_loongson3_virt.c.obj' failed
> make: *** [libqemu-mips64el-softmmu.fa.p/hw_mips_loongson3_virt.c.obj]
> Error 1
>
> Anyway I'll keep reviewing this patch.
>
> > 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/mips64el-softmmu.mak |   1 +
> >  hw/mips/Kconfig                      |  11 +
> >  hw/mips/fw_cfg.c                     |  35 ++
> >  hw/mips/fw_cfg.h                     |  19 +
> >  hw/mips/loongson3_virt.c             | 956 +++++++++++++++++++++++++++++++++++
> >  hw/mips/meson.build                  |   3 +-
> >  6 files changed, 1024 insertions(+), 1 deletion(-)
> >  create mode 100644 hw/mips/fw_cfg.c
> >  create mode 100644 hw/mips/fw_cfg.h
> >  create mode 100644 hw/mips/loongson3_virt.c
> >
> > diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak
> > index 9f8a3ef..26c660a 100644
> > --- a/default-configs/mips64el-softmmu.mak
> > +++ b/default-configs/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..cc5609b 100644
> > --- a/hw/mips/Kconfig
> > +++ b/hw/mips/Kconfig
> > @@ -45,6 +45,17 @@ config FULOONG
> >      bool
> >      select PCI_BONITO
> >
> > +config LOONGSON3V
> > +    bool
> > +    select PCKBD
> > +    select SERIAL
> > +    select GOLDFISH_RTC
> > +    select LOONGSON_LIOINTC
> > +    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/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
>
> Please keep the fw_cfg changes in a separate patch.
OK.

>
> > diff --git a/hw/mips/loongson3_virt.c b/hw/mips/loongson3_virt.c
> > new file mode 100644
> > index 0000000..14d3024
> > --- /dev/null
> > +++ b/hw/mips/loongson3_virt.c
> > @@ -0,0 +1,956 @@
> > +/*
> > + * 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 "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/misc/empty_slot.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
> > +
> > +/* 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;
> > +};
> > +
> > +/*
> > + * 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
> > + */
> > +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];
> > +} __attribute__((packed));
>
> QEMU_PACKED
OK.

>
> > +
> > +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];
> > +} __attribute__((packed));
> > +
> > +#define MAX_UARTS 64
> > +struct uart_device {
> > +    uint32_t iotype;
> > +    uint32_t uartclk;
> > +    uint32_t int_offset;
> > +    uint64_t uart_base;
> > +} __attribute__((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 */
> > +} __attribute__((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 */
> > +} __attribute__((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;
> > +} __attribute__((packed));
> > +
> > +struct interface_info {
> > +    uint16_t vers;               /* version of the specificition */
> > +    uint16_t size;
> > +    uint8_t  flag;
> > +    char description[64];
> > +} __attribute__((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 */
> > +};
>
> What about moving most of this declarations in a "loongson_efi.h"
> local header?
OK.

>
> > +
> > +struct boot_params {
> > +    struct efi_loongson efi;
> > +    struct efi_reset_system_t reset_system;
> > +};
> > +
> > +#define LOONGSON_MAX_VCPUS      16
> > +
> > +#define LOONGSON3_BIOSNAME "bios_loongson3.bin"
> > +
> > +#define UART_IRQ            0
> > +#define RTC_IRQ             1
> > +#define PCIE_IRQ_BASE       2
> > +
> > +#define align(x) (((x) + 63) & ~63)
> > +
> > +static 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,
> > +};
> > +
> > +static struct efi_memory_map_loongson *init_memory_map(void *g_map)
> > +{
> > +    struct efi_memory_map_loongson *emap = g_map;
> > +
> > +    emap->nr_map = 2;
> > +    emap->mem_freq = 300000000;
> > +
> > +    emap->map[0].node_id = 0;
> > +    emap->map[0].mem_type = 1;
> > +    emap->map[0].mem_start = 0x0;
> > +    emap->map[0].mem_size = 240;
> > +
> > +    emap->map[1].node_id = 0;
> > +    emap->map[1].mem_type = 2;
> > +    emap->map[1].mem_start = 0x90000000;
> > +    emap->map[1].mem_size = (loaderparams.ram_size / MiB) - 256;
> > +
> > +    return emap;
> > +}
> > +
> > +static uint64_t get_cpu_freq(void)
> > +{
> > +    int ret;
> > +    uint64_t freq;
> > +    struct kvm_one_reg freq_reg = {
> > +        .id = KVM_REG_MIPS_COUNT_HZ,
> > +        .addr = (uintptr_t)(&freq)
> > +    };
> > +
> > +    if (!kvm_enabled()) {
> > +        return 200 * 1000 * 1000;
>
> You earlier commented:
> "Loongson-3 CPU (MIPS64R2 with extensions, 800~2000MHz"
>
> Why not use 800 here?
In target/mips/cp0_timer.cit is said that CP0 timer has "10 ns period
for 100 Mhz frequency", so the CPU frequency should be 200MHz for TCG,
I'll add a comment here.

>
> > +    } else {
> > +        ret = kvm_vcpu_ioctl(first_cpu, KVM_GET_ONE_REG, &freq_reg);
> > +        if (ret < 0) {
> > +            return 1600 * 1000 * 1000;
> > +        }
> > +        return (freq * 2);
> > +    }
> > +}
> > +
> > +static struct efi_cpuinfo_loongson *init_cpu_info(void *g_cpuinfo_loongson)
> > +{
> > +    struct efi_cpuinfo_loongson *c = g_cpuinfo_loongson;
> > +
> > +    c->cputype = Loongson_3A;
> > +    c->processor_id = MIPS_CPU(first_cpu)->env.CP0_PRid;
> > +    if (loaderparams.cpu_freq > UINT_MAX) {
> > +        c->cpu_clock_freq = UINT_MAX;
> > +    } else {
> > +        c->cpu_clock_freq = loaderparams.cpu_freq;
> > +    }
> > +
> > +    c->cpu_startup_core_id = 0;
> > +    c->nr_cpus = current_machine->smp.cpus;
> > +    c->total_node = (current_machine->smp.cpus + 3) / 4;
> > +
> > +    return c;
> > +}
> > +
> > +static struct system_loongson *init_system_loongson(void *g_system)
> > +{
> > +    struct system_loongson *s = g_system;
> > +
> > +    s->ccnuma_smp = 0;
> > +    s->sing_double_channel = 1;
> > +    s->nr_uarts = 1;
> > +    s->uarts[0].iotype = 2;
> > +    s->uarts[0].int_offset = 2;
> > +    s->uarts[0].uartclk = 25000000; /* Random value */
> > +    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;
> > +
> > +    irq_info->node_id = 0;
> > +    irq_info->PIC_type = 0;
> > +    irq_info->dma_mask_bits = 64;
> > +    irq_info->pci_mem_start_addr = virt_memmap[VIRT_PCIE_MMIO].base;
> > +    irq_info->pci_mem_end_addr   = virt_memmap[VIRT_PCIE_MMIO].base +
> > +                                   virt_memmap[VIRT_PCIE_MMIO].size - 1;
> > +    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;
> > +
> > +    interface->vers = 0x01;
> > +    strcpy(interface->description, "UEFI_Version_v1.0");
> > +
> > +    return interface;
> > +}
> > +
> > +static struct board_devices *board_devices_info(void *g_board)
> > +{
> > +    struct board_devices *bd = g_board;
> > +
> > +    strcpy(bd->name, "Loongson-3A-VIRT-1w-V1.00-demo");
> > +
> > +    return bd;
> > +}
> > +
> > +static struct loongson_special_attribute *init_special_info(void *g_special)
> > +{
> > +    struct loongson_special_attribute *special = g_special;
> > +
> > +    strcpy(special->special_name, "2017-05-01");
>
> strpadcpy?
OK.

>
> > +
> > +    return special;
> > +}
> > +
> > +static void init_loongson_params(struct loongson_params *lp, void *p)
> > +{
> > +    lp->memory_offset = (unsigned long long)init_memory_map(p)
> > +                        - (unsigned long long)lp;
> > +    p += align(sizeof(struct efi_memory_map_loongson));
>
>        p += ROUND_UP(sizeof(struct efi_memory_map_loongson), 64);
>
> or use QEMU_ALIGN_PTR_UP()?
OK, I'll use ROUND_UP().

>
> > +
> > +    lp->cpu_offset = (unsigned long long)init_cpu_info(p)
> > +                     - (unsigned long long)lp;
> > +    p += align(sizeof(struct efi_cpuinfo_loongson));
> > +
> > +    lp->system_offset = (unsigned long long)init_system_loongson(p)
> > +                        - (unsigned long long)lp;
> > +    p += align(sizeof(struct system_loongson));
> > +
> > +    lp->irq_offset = (unsigned long long)init_irq_source(p)
> > +                     - (unsigned long long)lp;
> > +    p += align(sizeof(struct irq_source_routing_table));
> > +
> > +    lp->interface_offset = (unsigned long long)init_interface_info(p)
> > +                           - (unsigned long long)lp;
> > +    p += align(sizeof(struct interface_info));
> > +
> > +    lp->boarddev_table_offset = (unsigned long long)board_devices_info(p)
> > +                                - (unsigned long long)lp;
> > +    p += align(sizeof(struct board_devices));
> > +
> > +    lp->special_offset = (unsigned long long)init_special_info(p)
> > +                         - (unsigned long long)lp;
> > +    p += align(sizeof(struct loongson_special_attribute));
> > +}
> > +
> > +static void init_reset_system(struct efi_reset_system_t *reset)
> > +{
> > +    reset->Shutdown = 0xffffffffbfc000a8;
> > +    reset->ResetCold = 0xffffffffbfc00080;
> > +    reset->ResetWarm = 0xffffffffbfc00080;
> > +}
> > +
> > +static void init_boot_param(void)
> > +{
> > +    void *p;
> > +    struct boot_params *bp;
> > +
> > +    p = g_malloc0(loader_rommap[LOADER_PARAM].size);
> > +    bp = p;
> > +
> > +    bp->efi.smbios.vers = 1;
> > +    init_reset_system(&(bp->reset_system));
> > +    p += align(sizeof(struct boot_params));
> > +    init_loongson_params(&(bp->efi.smbios.lp), p);
> > +
> > +    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, "%ld", loaderparams.ram_size > 0x10000000
> > +            ? 256 : (loaderparams.ram_size >> 20));
>
> Please use 256 * MiB and MiB.
OK.

>
> (I'm not sure why you check this, since you enforce 512M min).
>
> > +    sprintf(highmemenv, "%ld", loaderparams.ram_size > 0x10000000
> > +            ? (loaderparams.ram_size >> 20) - 256 : 0);
> > +
> > +    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 need 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 need cpu type Loongson-3A4000");
> > +            exit(1);
> > +        }
> > +    }
> > +
> > +    if (ram_size < 512 * MiB) {
> > +        error_report("Loongson-3 need at least 512MB memory");
>
> Typo "needs", but why?
Though you told me "QEMU shouldn't assume anything about the guest",
but Loongson-3 machine really need at least 512M memory. And as you
said, this can simplify the memsize/highmemsize process (always larger
than 256).

>
> > +        exit(1);
> > +    }
> > +
> > +    /*
> > +     * The whole MMIO range among configure registers doesn't generate
> > +     * exception when accessing invalid memory. Create an empty slot to
> > +     * emulate this feature.
> > +     */
> > +    empty_slot_init("fallback", 0, 0x80000000);
>
> Again, this doesn't look correct (no comment in my previous review).
This is written by Jiaxun because this is only needed by TCG, and he
said that malta also uses empty_slot_init() here.

>
> > +
> > +    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 46294b7..32c8b95 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'))
> > +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_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] 26+ messages in thread

* Re: [PATCH V9 6/6] hw/mips: Add Loongson-3 machine support
  2020-09-16  9:49     ` Huacai Chen
@ 2020-09-16 10:47       ` Philippe Mathieu-Daudé
  2020-09-17  7:53         ` Philippe Mathieu-Daudé
  2020-09-17  8:09       ` Philippe Mathieu-Daudé
  2020-09-24 15:40       ` Philippe Mathieu-Daudé
  2 siblings, 1 reply; 26+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-09-16 10:47 UTC (permalink / raw)
  To: Huacai Chen
  Cc: Huacai Chen, Aleksandar Rikalo, QEMU Developers, Jiaxun Yang,
	Aleksandar Markovic, Aurelien Jarno

On 9/16/20 11:49 AM, Huacai Chen wrote:
> On Wed, Sep 16, 2020 at 3:56 PM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
>> On 9/16/20 4:12 AM, Huacai Chen wrote:
[...]
>>> +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 need 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 need cpu type Loongson-3A4000");
>>> +            exit(1);
>>> +        }
>>> +    }
>>> +
>>> +    if (ram_size < 512 * MiB) {
>>> +        error_report("Loongson-3 need at least 512MB memory");
>>
>> Typo "needs", but why?
> Though you told me "QEMU shouldn't assume anything about the guest",
> but Loongson-3 machine really need at least 512M memory. And as you
> said, this can simplify the memsize/highmemsize process (always larger
> than 256).

OK, that's fine.

> 
>>
>>> +        exit(1);
>>> +    }
>>> +
>>> +    /*
>>> +     * The whole MMIO range among configure registers doesn't generate
>>> +     * exception when accessing invalid memory. Create an empty slot to
>>> +     * emulate this feature.
>>> +     */
>>> +    empty_slot_init("fallback", 0, 0x80000000);
>>
>> Again, this doesn't look correct (no comment in my previous review).
> This is written by Jiaxun because this is only needed by TCG, and he
> said that malta also uses empty_slot_init() here.

IIRC for Malta this is a GT64120 specific hole.

In this case I'd like to know the justification first.
Maybe you want to add this hole in the LOONGSON_LIOINTC device...

> 
>>
>>> +
>>> +    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);
>>> +
[...]


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

* Re: [PATCH V9 3/6] target/mips: Add loongson-ext lswc2 group of instructions (Part 1)
  2020-09-16  2:12 ` [PATCH V9 3/6] target/mips: Add loongson-ext lswc2 group of instructions (Part 1) Huacai Chen
  2020-09-16  7:46   ` Philippe Mathieu-Daudé
@ 2020-09-16 15:15   ` Richard Henderson
  2020-09-19  0:44     ` Huacai Chen
  1 sibling, 1 reply; 26+ messages in thread
From: Richard Henderson @ 2020-09-16 15:15 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 9/15/20 7:12 PM, Huacai Chen wrote:
> +    case OPC_GSLQ:
> +        gen_base_offset_addr(ctx, t0, rs, lsq_offset);
> +        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ |
> +                            ctx->default_tcg_memop_mask);
> +        gen_store_gpr(t0, rt);
> +        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(t0, lsq_rt1);

If rs == rt, this will compute the wrong address for the second load.

Either avoid storing t0 back to rt until both loads are complete, or retain the
address temporary and simply add 8 between the two loads.


r~


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

* Re: [PATCH V9 6/6] hw/mips: Add Loongson-3 machine support
  2020-09-16 10:47       ` Philippe Mathieu-Daudé
@ 2020-09-17  7:53         ` Philippe Mathieu-Daudé
  2020-09-19  1:00           ` Huacai Chen
  0 siblings, 1 reply; 26+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-09-17  7:53 UTC (permalink / raw)
  To: Huacai Chen
  Cc: Huacai Chen, Aleksandar Rikalo, QEMU Developers, Jiaxun Yang,
	Aleksandar Markovic, Aurelien Jarno

On 9/16/20 12:47 PM, Philippe Mathieu-Daudé wrote:
> On 9/16/20 11:49 AM, Huacai Chen wrote:
>> On Wed, Sep 16, 2020 at 3:56 PM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
>>> On 9/16/20 4:12 AM, Huacai Chen wrote:
> [...]
>>>> +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 need 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 need cpu type Loongson-3A4000");
>>>> +            exit(1);
>>>> +        }
>>>> +    }
>>>> +
>>>> +    if (ram_size < 512 * MiB) {
>>>> +        error_report("Loongson-3 need at least 512MB memory");
>>>
>>> Typo "needs", but why?
>> Though you told me "QEMU shouldn't assume anything about the guest",
>> but Loongson-3 machine really need at least 512M memory. And as you
>> said, this can simplify the memsize/highmemsize process (always larger
>> than 256).
> 
> OK, that's fine.
> 
>>
>>>
>>>> +        exit(1);
>>>> +    }
>>>> +
>>>> +    /*
>>>> +     * The whole MMIO range among configure registers doesn't generate
>>>> +     * exception when accessing invalid memory. Create an empty slot to
>>>> +     * emulate this feature.
>>>> +     */
>>>> +    empty_slot_init("fallback", 0, 0x80000000);
>>>
>>> Again, this doesn't look correct (no comment in my previous review).
>> This is written by Jiaxun because this is only needed by TCG, and he
>> said that malta also uses empty_slot_init() here.
> 
> IIRC for Malta this is a GT64120 specific hole.
> 
> In this case I'd like to know the justification first.
> Maybe you want to add this hole in the LOONGSON_LIOINTC device...

Which makes me also wonder why are you splitting out 256MB of the RAM?

This was a physical restriction of the GT64120 on 32-bit targets.
Your hardware is virtual and 64-bit...


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

* Re: [PATCH V9 0/6] mips: Add Loongson-3 machine support
  2020-09-16  2:12 [PATCH V9 0/6] mips: Add Loongson-3 machine support Huacai Chen
                   ` (5 preceding siblings ...)
  2020-09-16  2:12 ` [PATCH V9 6/6] hw/mips: Add Loongson-3 machine support Huacai Chen
@ 2020-09-17  7:56 ` Philippe Mathieu-Daudé
  2020-09-21  2:25   ` chen huacai
  2020-09-17  8:22 ` Aleksandar Markovic
  7 siblings, 1 reply; 26+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-09-17  7:56 UTC (permalink / raw)
  To: Huacai Chen, Aleksandar Markovic
  Cc: Aleksandar Rikalo, Huacai Chen, qemu-devel, Jiaxun Yang,
	Huacai Chen, Aurelien Jarno

Hi Huacai,

On 9/16/20 4:12 AM, Huacai Chen wrote:
> 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.
> 
[...]

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

Can you add a KVM-only build CI job?
Simply building, not running test, as there is no MIPS CI.

See for example commit 41e1f0e2256 (".travis.yml: Add a KVM-only
s390x job"), but add it to GitLab instead.

Thanks!

Phil.


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

* Re: [PATCH V9 6/6] hw/mips: Add Loongson-3 machine support
  2020-09-16  9:49     ` Huacai Chen
  2020-09-16 10:47       ` Philippe Mathieu-Daudé
@ 2020-09-17  8:09       ` Philippe Mathieu-Daudé
  2020-09-24 15:40       ` Philippe Mathieu-Daudé
  2 siblings, 0 replies; 26+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-09-17  8:09 UTC (permalink / raw)
  To: Huacai Chen
  Cc: Huacai Chen, Aleksandar Rikalo, QEMU Developers, Jiaxun Yang,
	Aleksandar Markovic, Aurelien Jarno

On 9/16/20 11:49 AM, Huacai Chen wrote:
>>> 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;
>>
>> Which produces all the following errors:
>>
>> hw/mips/loongson3_virt.c: In function 'get_cpu_freq':
>> hw/mips/loongson3_virt.c:372:12: error: variable 'freq_reg' has
>> initializer but incomplete type
>>      struct kvm_one_reg freq_reg = {
>>             ^
>> hw/mips/loongson3_virt.c:373:9: error: unknown field 'id' specified in
>> initializer
>>          .id = KVM_REG_MIPS_COUNT_HZ,
>>          ^
>> hw/mips/loongson3_virt.c:373:15: error: 'KVM_REG_MIPS_COUNT_HZ'
>> undeclared (first use in this function)
>>          .id = KVM_REG_MIPS_COUNT_HZ,
>>                ^
> I don't know how to reproduce these errors, struct kvm_one_reg and
> KVM_REG_MIPS_COUNT_HZ are both defined..., could you please tell me?
> My build steps are like this:
> mkdir build
> cd build
> ../configure
> make

Building on Ubuntu 20.04.

C compiler for the host machine: cc (gcc 9.3.0 "cc (Ubuntu
9.3.0-10ubuntu2) 9.3.0")
C linker for the host machine: cc ld.bfd 2.34


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

* Re: [PATCH V9 0/6] mips: Add Loongson-3 machine support
  2020-09-16  2:12 [PATCH V9 0/6] mips: Add Loongson-3 machine support Huacai Chen
                   ` (6 preceding siblings ...)
  2020-09-17  7:56 ` [PATCH V9 0/6] mips: " Philippe Mathieu-Daudé
@ 2020-09-17  8:22 ` Aleksandar Markovic
  2020-09-21  2:19   ` chen huacai
  7 siblings, 1 reply; 26+ messages in thread
From: Aleksandar Markovic @ 2020-09-17  8:22 UTC (permalink / raw)
  To: Huacai Chen
  Cc: Aleksandar Rikalo, Huacai Chen, Philippe Mathieu-Daudé,
	Jiaxun Yang, qemu-devel, Huacai Chen, Aurelien Jarno

[-- Attachment #1: Type: text/plain, Size: 5907 bytes --]

On Wednesday, September 16, 2020, Huacai Chen <zltjiangshi@gmail.com> wrote:

> 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).
>
> Huacai Chen and Jiaxun Yang (6):
>  linux-headers: Update MIPS KVM type defintition
>  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: Add Loongson-3 machine support
>
> Signed-off-by: Huacai Chen <chenhc@lemote.com>
> ---
>  default-configs/mips64el-softmmu.mak |   1 +
>  hw/mips/Kconfig                      |  11 +
>  hw/mips/fw_cfg.c                     |  35 ++
>  hw/mips/fw_cfg.h                     |  19 +
>  hw/mips/loongson3_virt.c             | 956 ++++++++++++++++++++++++++++++
> +++++
>  hw/mips/meson.build                  |   3 +-
>  linux-headers/linux/kvm.h            |   5 +-
>  target/mips/cp0_helper.c             |  36 +-
>  target/mips/cpu.h                    |   1 +
>  target/mips/translate.c              | 437 ++++++++++++++++
>  10 files changed, 1494 insertions(+), 10 deletions(-)
>  create mode 100644 hw/mips/fw_cfg.c
>  create mode 100644 hw/mips/fw_cfg.h
>  create mode 100644 hw/mips/loongson3_virt.c
> --


There should be a suitable note in QEMU documentation describing new
functionality.

Thanks,
Aleksandar



> 2.7.0
>

[-- Attachment #2: Type: text/html, Size: 8808 bytes --]

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

* Re: [PATCH V9 3/6] target/mips: Add loongson-ext lswc2 group of instructions (Part 1)
  2020-09-16 15:15   ` Richard Henderson
@ 2020-09-19  0:44     ` Huacai Chen
  0 siblings, 0 replies; 26+ messages in thread
From: Huacai Chen @ 2020-09-19  0:44 UTC (permalink / raw)
  To: Richard Henderson
  Cc: Huacai Chen, Aleksandar Rikalo, Philippe Mathieu-Daudé,
	QEMU Developers, Aleksandar Markovic, Aurelien Jarno

Hi, Richard,

On Wed, Sep 16, 2020 at 11:15 PM Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> On 9/15/20 7:12 PM, Huacai Chen wrote:
> > +    case OPC_GSLQ:
> > +        gen_base_offset_addr(ctx, t0, rs, lsq_offset);
> > +        tcg_gen_qemu_ld_tl(t0, t0, ctx->mem_idx, MO_TEQ |
> > +                            ctx->default_tcg_memop_mask);
> > +        gen_store_gpr(t0, rt);
> > +        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(t0, lsq_rt1);
>
> If rs == rt, this will compute the wrong address for the second load.
>
> Either avoid storing t0 back to rt until both loads are complete, or retain the
> address temporary and simply add 8 between the two loads.
OK, this will be improved in V10.

>
>
> r~


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

* Re: [PATCH V9 6/6] hw/mips: Add Loongson-3 machine support
  2020-09-17  7:53         ` Philippe Mathieu-Daudé
@ 2020-09-19  1:00           ` Huacai Chen
  2020-09-19 13:59             ` Philippe Mathieu-Daudé
  0 siblings, 1 reply; 26+ messages in thread
From: Huacai Chen @ 2020-09-19  1:00 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Huacai Chen, Aleksandar Rikalo, QEMU Developers,
	Aleksandar Markovic, Aurelien Jarno

Hi, Philippe,

On Thu, Sep 17, 2020 at 3:53 PM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
>
> On 9/16/20 12:47 PM, Philippe Mathieu-Daudé wrote:
> > On 9/16/20 11:49 AM, Huacai Chen wrote:
> >> On Wed, Sep 16, 2020 at 3:56 PM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
> >>> On 9/16/20 4:12 AM, Huacai Chen wrote:
> > [...]
> >>>> +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 need 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 need cpu type Loongson-3A4000");
> >>>> +            exit(1);
> >>>> +        }
> >>>> +    }
> >>>> +
> >>>> +    if (ram_size < 512 * MiB) {
> >>>> +        error_report("Loongson-3 need at least 512MB memory");
> >>>
> >>> Typo "needs", but why?
> >> Though you told me "QEMU shouldn't assume anything about the guest",
> >> but Loongson-3 machine really need at least 512M memory. And as you
> >> said, this can simplify the memsize/highmemsize process (always larger
> >> than 256).
> >
> > OK, that's fine.
> >
> >>
> >>>
> >>>> +        exit(1);
> >>>> +    }
> >>>> +
> >>>> +    /*
> >>>> +     * The whole MMIO range among configure registers doesn't generate
> >>>> +     * exception when accessing invalid memory. Create an empty slot to
> >>>> +     * emulate this feature.
> >>>> +     */
> >>>> +    empty_slot_init("fallback", 0, 0x80000000);
> >>>
> >>> Again, this doesn't look correct (no comment in my previous review).
> >> This is written by Jiaxun because this is only needed by TCG, and he
> >> said that malta also uses empty_slot_init() here.
> >
> > IIRC for Malta this is a GT64120 specific hole.
> >
> > In this case I'd like to know the justification first.
> > Maybe you want to add this hole in the LOONGSON_LIOINTC device...
>
> Which makes me also wonder why are you splitting out 256MB of the RAM?
>
> This was a physical restriction of the GT64120 on 32-bit targets.
> Your hardware is virtual and 64-bit...
The physical memory address layout of Loongson-3:
0-0x40000000  Low RAM (256MB)
0x40000000-0x80000000 Hole for several MMIO registers (256MB)
0x80000000-TopOfMemory High RAM

Thogh this is a virtual platform, but the kernel link address is in
CKSEG0, so "Low RAM" should exist. Though MMIO is different from real
hardware, but put it in the same hole can make life easy.

Then it seems there is really a mistake of empty_slot_init() but has
nothing to do with liointc, and the right one should be
empty_slot_init("fallback", 0x40000000, 0x40000000);

Huacai


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

* Re: [PATCH V9 6/6] hw/mips: Add Loongson-3 machine support
  2020-09-19  1:00           ` Huacai Chen
@ 2020-09-19 13:59             ` Philippe Mathieu-Daudé
  2020-09-21  2:12               ` chen huacai
  0 siblings, 1 reply; 26+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-09-19 13:59 UTC (permalink / raw)
  To: Huacai Chen
  Cc: Huacai Chen, Aleksandar Rikalo, QEMU Developers, Aurelien Jarno,
	Aleksandar Markovic

On 9/19/20 3:00 AM, Huacai Chen wrote:
> Hi, Philippe,
> 
> On Thu, Sep 17, 2020 at 3:53 PM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
>>
>> On 9/16/20 12:47 PM, Philippe Mathieu-Daudé wrote:
>>> On 9/16/20 11:49 AM, Huacai Chen wrote:
>>>> On Wed, Sep 16, 2020 at 3:56 PM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
>>>>> On 9/16/20 4:12 AM, Huacai Chen wrote:
>>> [...]
>>>>>> +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 need 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 need cpu type Loongson-3A4000");
>>>>>> +            exit(1);
>>>>>> +        }
>>>>>> +    }
>>>>>> +
>>>>>> +    if (ram_size < 512 * MiB) {
>>>>>> +        error_report("Loongson-3 need at least 512MB memory");
>>>>>
>>>>> Typo "needs", but why?
>>>> Though you told me "QEMU shouldn't assume anything about the guest",
>>>> but Loongson-3 machine really need at least 512M memory. And as you
>>>> said, this can simplify the memsize/highmemsize process (always larger
>>>> than 256).
>>>
>>> OK, that's fine.
>>>
>>>>
>>>>>
>>>>>> +        exit(1);
>>>>>> +    }
>>>>>> +
>>>>>> +    /*
>>>>>> +     * The whole MMIO range among configure registers doesn't generate
>>>>>> +     * exception when accessing invalid memory. Create an empty slot to
>>>>>> +     * emulate this feature.
>>>>>> +     */
>>>>>> +    empty_slot_init("fallback", 0, 0x80000000);
>>>>>
>>>>> Again, this doesn't look correct (no comment in my previous review).
>>>> This is written by Jiaxun because this is only needed by TCG, and he
>>>> said that malta also uses empty_slot_init() here.
>>>
>>> IIRC for Malta this is a GT64120 specific hole.
>>>
>>> In this case I'd like to know the justification first.
>>> Maybe you want to add this hole in the LOONGSON_LIOINTC device...
>>
>> Which makes me also wonder why are you splitting out 256MB of the RAM?
>>
>> This was a physical restriction of the GT64120 on 32-bit targets.
>> Your hardware is virtual and 64-bit...
> The physical memory address layout of Loongson-3:
> 0-0x40000000  Low RAM (256MB)
> 0x40000000-0x80000000 Hole for several MMIO registers (256MB)
> 0x80000000-TopOfMemory High RAM
> 
> Thogh this is a virtual platform, but the kernel link address is in
> CKSEG0, so "Low RAM" should exist. Though MMIO is different from real
> hardware, but put it in the same hole can make life easy.

OK...

> 
> Then it seems there is really a mistake of empty_slot_init() but has
> nothing to do with liointc, and the right one should be
> empty_slot_init("fallback", 0x40000000, 0x40000000);

The EMPTY_SLOT models physical slot for busses that don't
generate bus error when the slot is accessed and there is
nothing there.

If the 256MiB region starting at 0x40000000 is reserved for
MMIO registers, you certainly want to get a bus error if the
CPU tries to address an unmapped/illegal address.

If you know some area belong to a device that might be accessed
by firmware/kernel but it isn't important to model it, then you
can create an UNIMP_DEVICE with create_unimplemented_device(),
which behaves as RAZ/WI accesses on the bus.

Regards,

Phil.

> 
> Huacai
> 


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

* Re: [PATCH V9 6/6] hw/mips: Add Loongson-3 machine support
  2020-09-19 13:59             ` Philippe Mathieu-Daudé
@ 2020-09-21  2:12               ` chen huacai
  0 siblings, 0 replies; 26+ messages in thread
From: chen huacai @ 2020-09-21  2:12 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Huacai Chen, Aleksandar Rikalo, QEMU Developers, Aurelien Jarno,
	Aleksandar Markovic

Hi, Philippe,

On Sat, Sep 19, 2020 at 9:59 PM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
>
> On 9/19/20 3:00 AM, Huacai Chen wrote:
> > Hi, Philippe,
> >
> > On Thu, Sep 17, 2020 at 3:53 PM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
> >>
> >> On 9/16/20 12:47 PM, Philippe Mathieu-Daudé wrote:
> >>> On 9/16/20 11:49 AM, Huacai Chen wrote:
> >>>> On Wed, Sep 16, 2020 at 3:56 PM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
> >>>>> On 9/16/20 4:12 AM, Huacai Chen wrote:
> >>> [...]
> >>>>>> +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 need 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 need cpu type Loongson-3A4000");
> >>>>>> +            exit(1);
> >>>>>> +        }
> >>>>>> +    }
> >>>>>> +
> >>>>>> +    if (ram_size < 512 * MiB) {
> >>>>>> +        error_report("Loongson-3 need at least 512MB memory");
> >>>>>
> >>>>> Typo "needs", but why?
> >>>> Though you told me "QEMU shouldn't assume anything about the guest",
> >>>> but Loongson-3 machine really need at least 512M memory. And as you
> >>>> said, this can simplify the memsize/highmemsize process (always larger
> >>>> than 256).
> >>>
> >>> OK, that's fine.
> >>>
> >>>>
> >>>>>
> >>>>>> +        exit(1);
> >>>>>> +    }
> >>>>>> +
> >>>>>> +    /*
> >>>>>> +     * The whole MMIO range among configure registers doesn't generate
> >>>>>> +     * exception when accessing invalid memory. Create an empty slot to
> >>>>>> +     * emulate this feature.
> >>>>>> +     */
> >>>>>> +    empty_slot_init("fallback", 0, 0x80000000);
> >>>>>
> >>>>> Again, this doesn't look correct (no comment in my previous review).
> >>>> This is written by Jiaxun because this is only needed by TCG, and he
> >>>> said that malta also uses empty_slot_init() here.
> >>>
> >>> IIRC for Malta this is a GT64120 specific hole.
> >>>
> >>> In this case I'd like to know the justification first.
> >>> Maybe you want to add this hole in the LOONGSON_LIOINTC device...
> >>
> >> Which makes me also wonder why are you splitting out 256MB of the RAM?
> >>
> >> This was a physical restriction of the GT64120 on 32-bit targets.
> >> Your hardware is virtual and 64-bit...
> > The physical memory address layout of Loongson-3:
> > 0-0x40000000  Low RAM (256MB)
> > 0x40000000-0x80000000 Hole for several MMIO registers (256MB)
> > 0x80000000-TopOfMemory High RAM
> >
> > Thogh this is a virtual platform, but the kernel link address is in
> > CKSEG0, so "Low RAM" should exist. Though MMIO is different from real
> > hardware, but put it in the same hole can make life easy.
>
> OK...
>
> >
> > Then it seems there is really a mistake of empty_slot_init() but has
> > nothing to do with liointc, and the right one should be
> > empty_slot_init("fallback", 0x40000000, 0x40000000);
>
> The EMPTY_SLOT models physical slot for busses that don't
> generate bus error when the slot is accessed and there is
> nothing there.
>
> If the 256MiB region starting at 0x40000000 is reserved for
> MMIO registers, you certainly want to get a bus error if the
> CPU tries to address an unmapped/illegal address.
>
> If you know some area belong to a device that might be accessed
> by firmware/kernel but it isn't important to model it, then you
> can create an UNIMP_DEVICE with create_unimplemented_device(),
> which behaves as RAZ/WI accesses on the bus.
Yes, there are some MMIO access from firmware/kernel that doesn't
belong to any emulated devices, then I found that "empty slot" and
"unimplemented device" is nearly the same thing, what are their
differences?

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



-- 
Huacai Chen


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

* Re: [PATCH V9 0/6] mips: Add Loongson-3 machine support
  2020-09-17  8:22 ` Aleksandar Markovic
@ 2020-09-21  2:19   ` chen huacai
  0 siblings, 0 replies; 26+ messages in thread
From: chen huacai @ 2020-09-21  2:19 UTC (permalink / raw)
  To: Aleksandar Markovic
  Cc: Aleksandar Rikalo, Huacai Chen, Philippe Mathieu-Daudé,
	qemu-devel, Huacai Chen, Aurelien Jarno

Hi, Aleksandar,

On Thu, Sep 17, 2020 at 4:22 PM Aleksandar Markovic
<aleksandar.qemu.devel@gmail.com> wrote:
>
>
>
> On Wednesday, September 16, 2020, Huacai Chen <zltjiangshi@gmail.com> wrote:
>>
>> 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).
>>
>> Huacai Chen and Jiaxun Yang (6):
>>  linux-headers: Update MIPS KVM type defintition
>>  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: Add Loongson-3 machine support
>>
>> Signed-off-by: Huacai Chen <chenhc@lemote.com>
>> ---
>>  default-configs/mips64el-softmmu.mak |   1 +
>>  hw/mips/Kconfig                      |  11 +
>>  hw/mips/fw_cfg.c                     |  35 ++
>>  hw/mips/fw_cfg.h                     |  19 +
>>  hw/mips/loongson3_virt.c             | 956 +++++++++++++++++++++++++++++++++++
>>  hw/mips/meson.build                  |   3 +-
>>  linux-headers/linux/kvm.h            |   5 +-
>>  target/mips/cp0_helper.c             |  36 +-
>>  target/mips/cpu.h                    |   1 +
>>  target/mips/translate.c              | 437 ++++++++++++++++
>>  10 files changed, 1494 insertions(+), 10 deletions(-)
>>  create mode 100644 hw/mips/fw_cfg.c
>>  create mode 100644 hw/mips/fw_cfg.h
>>  create mode 100644 hw/mips/loongson3_virt.c
>> --
>
>
> There should be a suitable note in QEMU documentation describing new functionality.
OK, I will update documentations in V10.

Huacai
>
> Thanks,
> Aleksandar
>
>
>>
>> 2.7.0



-- 
Huacai Chen


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

* Re: [PATCH V9 0/6] mips: Add Loongson-3 machine support
  2020-09-17  7:56 ` [PATCH V9 0/6] mips: " Philippe Mathieu-Daudé
@ 2020-09-21  2:25   ` chen huacai
  0 siblings, 0 replies; 26+ messages in thread
From: chen huacai @ 2020-09-21  2:25 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Aleksandar Rikalo, Huacai Chen, qemu-level, Aleksandar Markovic,
	Huacai Chen, Aurelien Jarno

Hi, Philippe,

On Thu, Sep 17, 2020 at 3:56 PM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
>
> Hi Huacai,
>
> On 9/16/20 4:12 AM, Huacai Chen wrote:
> > 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.
> >
> [...]
>
> > 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 ...
>
> Can you add a KVM-only build CI job?
> Simply building, not running test, as there is no MIPS CI.
>
> See for example commit 41e1f0e2256 (".travis.yml: Add a KVM-only
> s390x job"), but add it to GitLab instead.
I have some difficulties in CI testing (I think I should setup a CI
environment first), can this work be done by others, or in future
after this series?

Huacai
>
> Thanks!
>
> Phil.



-- 
Huacai Chen


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

* Re: [PATCH V9 6/6] hw/mips: Add Loongson-3 machine support
  2020-09-16  9:49     ` Huacai Chen
  2020-09-16 10:47       ` Philippe Mathieu-Daudé
  2020-09-17  8:09       ` Philippe Mathieu-Daudé
@ 2020-09-24 15:40       ` Philippe Mathieu-Daudé
  2020-09-25  4:28         ` Huacai Chen
  2 siblings, 1 reply; 26+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-09-24 15:40 UTC (permalink / raw)
  To: Huacai Chen
  Cc: Huacai Chen, Aleksandar Rikalo, QEMU Developers,
	Aleksandar Markovic, Aurelien Jarno

On 9/16/20 11:49 AM, Huacai Chen wrote:
> Hi, Philippe,
> 
> On Wed, Sep 16, 2020 at 3:56 PM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
>>
>> Hi Huacai,
>>
>> On 9/16/20 4:12 AM, Huacai Chen wrote:
...
>> hw/mips/loongson3_virt.c:373:15: note: each undeclared identifier is
>> reported only once for each function it appears in
>> hw/mips/loongson3_virt.c:373:15: error: excess elements in struct
>> initializer [-Werror]
>> hw/mips/loongson3_virt.c:373:15: note: (near initialization for 'freq_reg')
>> hw/mips/loongson3_virt.c:374:9: error: unknown field 'addr' specified in
>> initializer
>>          .addr = (uintptr_t)(&freq)
>>          ^
>> hw/mips/loongson3_virt.c:374:17: error: excess elements in struct
>> initializer [-Werror]
>>          .addr = (uintptr_t)(&freq)
>>                  ^
>> hw/mips/loongson3_virt.c:374:17: note: (near initialization for 'freq_reg')
>> hw/mips/loongson3_virt.c:372:24: error: storage size of 'freq_reg' isn't
>> known
>>      struct kvm_one_reg freq_reg = {
>>                         ^
>> hw/mips/loongson3_virt.c:380:41: error: 'KVM_GET_ONE_REG' undeclared
>> (first use in this function)
>>          ret = kvm_vcpu_ioctl(first_cpu, KVM_GET_ONE_REG, &freq_reg);
>>                                          ^
>> hw/mips/loongson3_virt.c:372:24: error: unused variable 'freq_reg'
>> [-Werror=unused-variable]
>>      struct kvm_one_reg freq_reg = {
>>                         ^
>> hw/mips/loongson3_virt.c: In function 'init_loongson_params':
>> hw/mips/loongson3_virt.c:467:25: error: cast from pointer to integer of
>> different size [-Werror=pointer-to-int-cast]
>>      lp->memory_offset = (unsigned long long)init_memory_map(p)
>>                          ^
> I guess this happens on a 32bit platform where pointer is 32bit, and
> could you please suggest a best solution for this? Maybe use uintptr_t
> instead of unsigned long long?

Since the machine doesn't have to know the EFI structures
layout, I'd change your method to fill EFI structures as i.e.:

/*
 * @ptr: Pointer to fill
 * @size: Buffer size available at @ptr
 * Returns: Structure size filled on success, -1 on error.
 */
size_t fill_efi_memory_map_loongson(char *ptr, size_t size);

And move that to hw/mips/loongson_efi.{c,h}.

Then you don't need to worry about host pointer size, you just
exchange buffer/size, then caller can round up and increment an
offset.

BTW the EFI helpers are not endian safe.

You should use the helpers described in docs/devel/loads-stores.rst:

stw_le_p, stl_le_p(), ... (as I don't expect big-endian guests).

Regards,

Phil.


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

* Re: [PATCH V9 6/6] hw/mips: Add Loongson-3 machine support
  2020-09-24 15:40       ` Philippe Mathieu-Daudé
@ 2020-09-25  4:28         ` Huacai Chen
  0 siblings, 0 replies; 26+ messages in thread
From: Huacai Chen @ 2020-09-25  4:28 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Huacai Chen, Aleksandar Rikalo, QEMU Developers,
	Aleksandar Markovic, Aurelien Jarno

Hi, Philippe,

On Thu, Sep 24, 2020 at 11:40 PM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
>
> On 9/16/20 11:49 AM, Huacai Chen wrote:
> > Hi, Philippe,
> >
> > On Wed, Sep 16, 2020 at 3:56 PM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
> >>
> >> Hi Huacai,
> >>
> >> On 9/16/20 4:12 AM, Huacai Chen wrote:
> ...
> >> hw/mips/loongson3_virt.c:373:15: note: each undeclared identifier is
> >> reported only once for each function it appears in
> >> hw/mips/loongson3_virt.c:373:15: error: excess elements in struct
> >> initializer [-Werror]
> >> hw/mips/loongson3_virt.c:373:15: note: (near initialization for 'freq_reg')
> >> hw/mips/loongson3_virt.c:374:9: error: unknown field 'addr' specified in
> >> initializer
> >>          .addr = (uintptr_t)(&freq)
> >>          ^
> >> hw/mips/loongson3_virt.c:374:17: error: excess elements in struct
> >> initializer [-Werror]
> >>          .addr = (uintptr_t)(&freq)
> >>                  ^
> >> hw/mips/loongson3_virt.c:374:17: note: (near initialization for 'freq_reg')
> >> hw/mips/loongson3_virt.c:372:24: error: storage size of 'freq_reg' isn't
> >> known
> >>      struct kvm_one_reg freq_reg = {
> >>                         ^
> >> hw/mips/loongson3_virt.c:380:41: error: 'KVM_GET_ONE_REG' undeclared
> >> (first use in this function)
> >>          ret = kvm_vcpu_ioctl(first_cpu, KVM_GET_ONE_REG, &freq_reg);
> >>                                          ^
> >> hw/mips/loongson3_virt.c:372:24: error: unused variable 'freq_reg'
> >> [-Werror=unused-variable]
> >>      struct kvm_one_reg freq_reg = {
> >>                         ^
> >> hw/mips/loongson3_virt.c: In function 'init_loongson_params':
> >> hw/mips/loongson3_virt.c:467:25: error: cast from pointer to integer of
> >> different size [-Werror=pointer-to-int-cast]
> >>      lp->memory_offset = (unsigned long long)init_memory_map(p)
> >>                          ^
> > I guess this happens on a 32bit platform where pointer is 32bit, and
> > could you please suggest a best solution for this? Maybe use uintptr_t
> > instead of unsigned long long?
>
> Since the machine doesn't have to know the EFI structures
> layout, I'd change your method to fill EFI structures as i.e.:
>
> /*
>  * @ptr: Pointer to fill
>  * @size: Buffer size available at @ptr
>  * Returns: Structure size filled on success, -1 on error.
>  */
> size_t fill_efi_memory_map_loongson(char *ptr, size_t size);
>
> And move that to hw/mips/loongson_efi.{c,h}.
>
> Then you don't need to worry about host pointer size, you just
> exchange buffer/size, then caller can round up and increment an
> offset.
All boot parameters are located in a small region, so a uint32_t seems
enough for xxx_offset, so uintptr_t is just OK, I think.

>
> BTW the EFI helpers are not endian safe.
>
> You should use the helpers described in docs/devel/loads-stores.rst:
>
> stw_le_p, stl_le_p(), ... (as I don't expect big-endian guests).
This seems like a very big project, but I will do it in the next version.

Huacai
>
> Regards,
>
> Phil.


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

end of thread, other threads:[~2020-09-25  4:29 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-09-16  2:12 [PATCH V9 0/6] mips: Add Loongson-3 machine support Huacai Chen
2020-09-16  2:12 ` [PATCH V9 1/6] linux-headers: Update MIPS KVM type defintition Huacai Chen
2020-09-16  2:12 ` [PATCH V9 2/6] target/mips: Fix PageMask with variable page size Huacai Chen
2020-09-16  2:12 ` [PATCH V9 3/6] target/mips: Add loongson-ext lswc2 group of instructions (Part 1) Huacai Chen
2020-09-16  7:46   ` Philippe Mathieu-Daudé
2020-09-16  7:58     ` Huacai Chen
2020-09-16 15:15   ` Richard Henderson
2020-09-19  0:44     ` Huacai Chen
2020-09-16  2:12 ` [PATCH V9 4/6] target/mips: Add loongson-ext lswc2 group of instructions (Part 2) Huacai Chen
2020-09-16  2:12 ` [PATCH V9 5/6] target/mips: Add loongson-ext lsdc2 group of instructions Huacai Chen
2020-09-16  2:12 ` [PATCH V9 6/6] hw/mips: Add Loongson-3 machine support Huacai Chen
2020-09-16  7:56   ` Philippe Mathieu-Daudé
2020-09-16  8:08     ` Philippe Mathieu-Daudé
2020-09-16  9:49     ` Huacai Chen
2020-09-16 10:47       ` Philippe Mathieu-Daudé
2020-09-17  7:53         ` Philippe Mathieu-Daudé
2020-09-19  1:00           ` Huacai Chen
2020-09-19 13:59             ` Philippe Mathieu-Daudé
2020-09-21  2:12               ` chen huacai
2020-09-17  8:09       ` Philippe Mathieu-Daudé
2020-09-24 15:40       ` Philippe Mathieu-Daudé
2020-09-25  4:28         ` Huacai Chen
2020-09-17  7:56 ` [PATCH V9 0/6] mips: " Philippe Mathieu-Daudé
2020-09-21  2:25   ` chen huacai
2020-09-17  8:22 ` Aleksandar Markovic
2020-09-21  2:19   ` chen huacai

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