All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH for-5.1 V4 0/7] mips: Add Loongson-3 machine support (with KVM)
@ 2020-06-02  2:39 Huacai Chen
  2020-06-02  2:39 ` [PATCH for-5.1 V4 1/4] hw/mips: Implement the kvm_type() hook in MachineClass Huacai Chen
                   ` (4 more replies)
  0 siblings, 5 replies; 41+ messages in thread
From: Huacai Chen @ 2020-06-02  2:39 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, Aleksandar Markovic
  Cc: Huacai Chen, Huacai Chen, Aleksandar Rikalo, qemu-devel, 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.

We are preparing to add QEMU's Loongson-3 support. MIPS VZ extension is
fully supported in Loongson-3A R4+, so we at first add QEMU/KVM support
in this series. And the next series will add QEMU/TCG support (it will
emulate Loongson-3A R1).

We already have a full functional Linux kernel (based on Linux-5.4.x LTS
but not upstream yet) here:

https://github.com/chenhuacai/linux

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;
4, Build QEMU-5.0.0 with this patchset;
5, modprobe kvm;
6, Use QEMU with TCG (available in future):
       qemu-system-mips64el -M loongson3,accel=tcg -cpu Loongson-3A1000 -kernel <path_to_kernel> -append ... 
   Use QEMU with KVM (available at present): 
       qemu-system-mips64el -M loongson3,accel=kvm -cpu Loongson-3A4000 -kernel <path_to_kernel> -append ... 

   The "-cpu" parameter can be omitted 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>.

Huacai Chen(4):
 hw/mips: Implement the kvm_type() hook in MachineClass
 target/mips: Add Loongson-3 CPU definition
 hw/mips: Add Loongson-3 machine support (with KVM)
 MAINTAINERS: Add myself as Loongson-3 maintainer

Signed-off-by: Huacai Chen <chenhc@lemote.com>
---
 MAINTAINERS                          |   5 +
 default-configs/mips64el-softmmu.mak |   1 +
 hw/core/Makefile.objs                |   2 +-
 hw/core/null-machine.c               |   4 +
 hw/mips/Kconfig                      |  10 +
 hw/mips/Makefile.objs                |   3 +-
 hw/mips/common.c                     |  42 ++
 hw/mips/loongson3.c                  | 901 +++++++++++++++++++++++++++++++++++
 include/hw/mips/mips.h               |   3 +
 target/mips/cpu.h                    |  28 ++
 target/mips/internal.h               |   2 +
 target/mips/mips-defs.h              |   7 +-
 target/mips/translate.c              |   2 +
 target/mips/translate_init.inc.c     |  86 ++++
 14 files changed, 1092 insertions(+), 4 deletions(-)
 create mode 100644 hw/mips/common.c
 create mode 100644 hw/mips/loongson3.c
--
2.7.0


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

* [PATCH for-5.1 V4 1/4] hw/mips: Implement the kvm_type() hook in MachineClass
  2020-06-02  2:39 [PATCH for-5.1 V4 0/7] mips: Add Loongson-3 machine support (with KVM) Huacai Chen
@ 2020-06-02  2:39 ` Huacai Chen
  2020-06-03 14:34   ` Aleksandar Markovic
  2020-06-14  8:07   ` Aleksandar Markovic
  2020-06-02  2:39 ` [PATCH for-5.1 V4 2/4] target/mips: Add Loongson-3 CPU definition Huacai Chen
                   ` (3 subsequent siblings)
  4 siblings, 2 replies; 41+ messages in thread
From: Huacai Chen @ 2020-06-02  2:39 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, Aleksandar Markovic
  Cc: Huacai Chen, Huacai Chen, Aleksandar Rikalo, qemu-devel, Aurelien Jarno

MIPS has two types of KVM: TE & VZ, and TE is the default type. Now we
can't create a VZ guest in QEMU because it lacks the kvm_type() hook in
MachineClass. Besides, libvirt uses a null-machine to detect the kvm
capability, so by default it will return "KVM not supported" on a VZ
platform. Thus, null-machine also need the kvm_type() hook.

Reviewed-by: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
Signed-off-by: Huacai Chen <chenhc@lemote.com>
Co-developed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
---
 hw/core/Makefile.objs  |  2 +-
 hw/core/null-machine.c |  4 ++++
 hw/mips/Makefile.objs  |  2 +-
 hw/mips/common.c       | 42 ++++++++++++++++++++++++++++++++++++++++++
 include/hw/mips/mips.h |  3 +++
 5 files changed, 51 insertions(+), 2 deletions(-)
 create mode 100644 hw/mips/common.c

diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs
index 1d540ed..b5672f4 100644
--- a/hw/core/Makefile.objs
+++ b/hw/core/Makefile.objs
@@ -17,11 +17,11 @@ common-obj-$(CONFIG_SOFTMMU) += vm-change-state-handler.o
 common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o
 common-obj-$(CONFIG_SOFTMMU) += sysbus.o
 common-obj-$(CONFIG_SOFTMMU) += machine.o
-common-obj-$(CONFIG_SOFTMMU) += null-machine.o
 common-obj-$(CONFIG_SOFTMMU) += loader.o
 common-obj-$(CONFIG_SOFTMMU) += machine-hmp-cmds.o
 common-obj-$(CONFIG_SOFTMMU) += numa.o
 common-obj-$(CONFIG_SOFTMMU) += clock-vmstate.o
+obj-$(CONFIG_SOFTMMU) += null-machine.o
 obj-$(CONFIG_SOFTMMU) += machine-qmp-cmds.o
 
 common-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o
diff --git a/hw/core/null-machine.c b/hw/core/null-machine.c
index cb47d9d..94a36f9 100644
--- a/hw/core/null-machine.c
+++ b/hw/core/null-machine.c
@@ -17,6 +17,7 @@
 #include "sysemu/sysemu.h"
 #include "exec/address-spaces.h"
 #include "hw/core/cpu.h"
+#include "hw/mips/mips.h"
 
 static void machine_none_init(MachineState *mch)
 {
@@ -50,6 +51,9 @@ static void machine_none_machine_init(MachineClass *mc)
     mc->max_cpus = 1;
     mc->default_ram_size = 0;
     mc->default_ram_id = "ram";
+#ifdef TARGET_MIPS
+    mc->kvm_type = mips_kvm_type;
+#endif
 }
 
 DEFINE_MACHINE("none", machine_none_machine_init)
diff --git a/hw/mips/Makefile.objs b/hw/mips/Makefile.objs
index 739e2b7..3b3e6ea 100644
--- a/hw/mips/Makefile.objs
+++ b/hw/mips/Makefile.objs
@@ -1,4 +1,4 @@
-obj-y += addr.o mips_int.o
+obj-y += addr.o common.o mips_int.o
 obj-$(CONFIG_R4K) += r4k.o
 obj-$(CONFIG_MALTA) += gt64xxx_pci.o malta.o
 obj-$(CONFIG_MIPSSIM) += mipssim.o
diff --git a/hw/mips/common.c b/hw/mips/common.c
new file mode 100644
index 0000000..4d8e141
--- /dev/null
+++ b/hw/mips/common.c
@@ -0,0 +1,42 @@
+/*
+ * Common MIPS routines
+ *
+ * Copyright (c) 2020 Huacai Chen (chenhc@lemote.com)
+ * This code is licensed under the GNU GPL v2.
+ */
+
+#include <linux/kvm.h>
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "hw/boards.h"
+#include "hw/mips/mips.h"
+#include "sysemu/kvm_int.h"
+
+#ifndef CONFIG_KVM
+
+int mips_kvm_type(MachineState *machine, const char *vm_type)
+{
+    return 0;
+}
+
+#else
+
+int mips_kvm_type(MachineState *machine, const char *vm_type)
+{
+    int r;
+    KVMState *s = KVM_STATE(machine->accelerator);
+
+    r = kvm_check_extension(s, KVM_CAP_MIPS_VZ);
+    if (r > 0) {
+        return KVM_VM_MIPS_VZ;
+    }
+
+    r = kvm_check_extension(s, KVM_CAP_MIPS_TE);
+    if (r > 0) {
+        return KVM_VM_MIPS_TE;
+    }
+
+    return -1;
+}
+
+#endif
diff --git a/include/hw/mips/mips.h b/include/hw/mips/mips.h
index 0af4c3d..2ac0580 100644
--- a/include/hw/mips/mips.h
+++ b/include/hw/mips/mips.h
@@ -20,4 +20,7 @@ void rc4030_dma_write(void *dma, uint8_t *buf, int len);
 
 DeviceState *rc4030_init(rc4030_dma **dmas, IOMMUMemoryRegion **dma_mr);
 
+/* common.c */
+int mips_kvm_type(MachineState *machine, const char *vm_type);
+
 #endif
-- 
2.7.0



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

* [PATCH for-5.1 V4 2/4] target/mips: Add Loongson-3 CPU definition
  2020-06-02  2:39 [PATCH for-5.1 V4 0/7] mips: Add Loongson-3 machine support (with KVM) Huacai Chen
  2020-06-02  2:39 ` [PATCH for-5.1 V4 1/4] hw/mips: Implement the kvm_type() hook in MachineClass Huacai Chen
@ 2020-06-02  2:39 ` Huacai Chen
  2020-06-06  7:30   ` Aleksandar Markovic
  2020-06-02  2:39 ` [PATCH for-5.1 V4 3/4] hw/mips: Add Loongson-3 machine support (with KVM) Huacai Chen
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 41+ messages in thread
From: Huacai Chen @ 2020-06-02  2:39 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, Aleksandar Markovic
  Cc: Huacai Chen, Huacai Chen, Aleksandar Rikalo, qemu-devel, 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, 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-3A has CONFIG6 and CONFIG7, so add their bit-fields as well.

Signed-off-by: Huacai Chen <chenhc@lemote.com>
Co-developed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
---
 target/mips/cpu.h                | 28 +++++++++++++
 target/mips/internal.h           |  2 +
 target/mips/mips-defs.h          |  7 +++-
 target/mips/translate.c          |  2 +
 target/mips/translate_init.inc.c | 86 ++++++++++++++++++++++++++++++++++++++++
 5 files changed, 123 insertions(+), 2 deletions(-)

diff --git a/target/mips/cpu.h b/target/mips/cpu.h
index 94d01ea..0b3c987 100644
--- a/target/mips/cpu.h
+++ b/target/mips/cpu.h
@@ -940,7 +940,35 @@ struct CPUMIPSState {
 #define CP0C5_UFR          2
 #define CP0C5_NFExists     0
     int32_t CP0_Config6;
+    int32_t CP0_Config6_rw_bitmask;
+#define CP0C6_BPPASS          31
+#define CP0C6_KPOS            24
+#define CP0C6_KE              23
+#define CP0C6_VTLBONLY        22
+#define CP0C6_LASX            21
+#define CP0C6_SSEN            20
+#define CP0C6_DISDRTIME       19
+#define CP0C6_PIXNUEN         18
+#define CP0C6_SCRAND          17
+#define CP0C6_LLEXCEN         16
+#define CP0C6_DISVC           15
+#define CP0C6_VCLRU           14
+#define CP0C6_DCLRU           13
+#define CP0C6_PIXUEN          12
+#define CP0C6_DISBLKLYEN      11
+#define CP0C6_UMEMUALEN       10
+#define CP0C6_SFBEN           8
+#define CP0C6_FLTINT          7
+#define CP0C6_VLTINT          6
+#define CP0C6_DISBTB          5
+#define CP0C6_STPREFCTL       2
+#define CP0C6_INSTPREF        1
+#define CP0C6_DATAPREF        0
     int32_t CP0_Config7;
+    int64_t CP0_Config7_rw_bitmask;
+#define CP0C7_NAPCGEN       2
+#define CP0C7_UNIMUEN       1
+#define CP0C7_VFPUCGEN      0
     uint64_t CP0_LLAddr;
     uint64_t CP0_MAAR[MIPS_MAAR_MAX];
     int32_t CP0_MAARI;
diff --git a/target/mips/internal.h b/target/mips/internal.h
index 1bf274b..7853cb1 100644
--- a/target/mips/internal.h
+++ b/target/mips/internal.h
@@ -36,7 +36,9 @@ struct mips_def_t {
     int32_t CP0_Config5;
     int32_t CP0_Config5_rw_bitmask;
     int32_t CP0_Config6;
+    int32_t CP0_Config6_rw_bitmask;
     int32_t CP0_Config7;
+    int32_t CP0_Config7_rw_bitmask;
     target_ulong CP0_LLAddr_rw_bitmask;
     int CP0_LLAddr_shift;
     int32_t SYNCI_Step;
diff --git a/target/mips/mips-defs.h b/target/mips/mips-defs.h
index a831bb4..c2c96db 100644
--- a/target/mips/mips-defs.h
+++ b/target/mips/mips-defs.h
@@ -51,8 +51,9 @@
  */
 #define INSN_LOONGSON2E   0x0001000000000000ULL
 #define INSN_LOONGSON2F   0x0002000000000000ULL
-#define INSN_VR54XX       0x0004000000000000ULL
-#define INSN_R5900        0x0008000000000000ULL
+#define INSN_LOONGSON3A   0x0004000000000000ULL
+#define INSN_VR54XX       0x0008000000000000ULL
+#define INSN_R5900        0x0010000000000000ULL
 /*
  *   bits 56-63: vendor-specific ASEs
  */
@@ -94,6 +95,8 @@
 /* Wave Computing: "nanoMIPS" */
 #define CPU_NANOMIPS32  (CPU_MIPS32R6 | ISA_NANOMIPS32)
 
+#define CPU_LOONGSON3A  (CPU_MIPS64R2 | INSN_LOONGSON3A)
+
 /*
  * Strictly follow the architecture standard:
  * - Disallow "special" instruction handling for PMON/SPIM.
diff --git a/target/mips/translate.c b/target/mips/translate.c
index 25b595a..2caf4cb 100644
--- a/target/mips/translate.c
+++ b/target/mips/translate.c
@@ -31206,7 +31206,9 @@ void cpu_state_reset(CPUMIPSState *env)
     env->CP0_Config5 = env->cpu_model->CP0_Config5;
     env->CP0_Config5_rw_bitmask = env->cpu_model->CP0_Config5_rw_bitmask;
     env->CP0_Config6 = env->cpu_model->CP0_Config6;
+    env->CP0_Config6_rw_bitmask = env->cpu_model->CP0_Config6_rw_bitmask;
     env->CP0_Config7 = env->cpu_model->CP0_Config7;
+    env->CP0_Config7_rw_bitmask = env->cpu_model->CP0_Config7_rw_bitmask;
     env->CP0_LLAddr_rw_bitmask = env->cpu_model->CP0_LLAddr_rw_bitmask
                                  << env->cpu_model->CP0_LLAddr_shift;
     env->CP0_LLAddr_shift = env->cpu_model->CP0_LLAddr_shift;
diff --git a/target/mips/translate_init.inc.c b/target/mips/translate_init.inc.c
index 6d145a9..a31f229 100644
--- a/target/mips/translate_init.inc.c
+++ b/target/mips/translate_init.inc.c
@@ -802,6 +802,92 @@ const mips_def_t mips_defs[] =
         .mmu_type = MMU_TYPE_R4000,
     },
     {
+        .name = "Loongson-3A1000",
+        .CP0_PRid = 0x6305,
+        /* 64KB I-cache and d-cache. 4 way with 32 bit cache line size.  */
+        .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) | (0x2 << CP0C0_AT) |
+                       (MMU_TYPE_R4000 << CP0C0_MT),
+        .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (63 << CP0C1_MMU) |
+                       (3 << CP0C1_IS) | (4 << CP0C1_IL) | (3 << CP0C1_IA) |
+                       (3 << CP0C1_DS) | (4 << CP0C1_DL) | (3 << CP0C1_DA) |
+                       (1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP),
+        .CP0_Config2 = MIPS_CONFIG2 | (7 << CP0C2_SS) | (4 << CP0C2_SL) |
+                       (3 << CP0C2_SA),
+        .CP0_Config3 = MIPS_CONFIG3 | (1 << CP0C3_LPA),
+        .CP0_LLAddr_rw_bitmask = 0,
+        .SYNCI_Step = 32,
+        .CCRes = 2,
+        .CP0_Status_rw_bitmask = 0x74D8FFFF,
+        .CP0_PageGrain = (1 << CP0PG_ELPA),
+        .CP0_PageGrain_rw_bitmask = (1 << CP0PG_ELPA),
+        .CP1_fcr0 = (0x5 << FCR0_PRID) | (0x1 << FCR0_REV) | (0x1 << FCR0_F64) |
+                    (0x1 << FCR0_PS) | (0x1 << FCR0_L) | (0x1 << FCR0_W) |
+                    (0x1 << FCR0_D) | (0x1 << FCR0_S),
+        .CP1_fcr31 = 0,
+        .CP1_fcr31_rw_bitmask = 0xFF83FFFF,
+        .SEGBITS = 42,
+        .PABITS = 48,
+        .insn_flags = CPU_LOONGSON3A,
+        .mmu_type = MMU_TYPE_R4000,
+    },
+    {
+        .name = "Loongson-3A4000",
+        .CP0_PRid = 0x14C000,
+        /* 64KB I-cache and d-cache. 4 way with 32 bit cache line size.  */
+        .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) | (0x2 << CP0C0_AT) |
+                       (MMU_TYPE_R4000 << CP0C0_MT),
+        .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (63 << CP0C1_MMU) |
+                       (2 << CP0C1_IS) | (5 << CP0C1_IL) | (3 << CP0C1_IA) |
+                       (2 << CP0C1_DS) | (5 << CP0C1_DL) | (3 << CP0C1_DA) |
+                       (1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP),
+        .CP0_Config2 = MIPS_CONFIG2 | (5 << CP0C2_SS) | (5 << CP0C2_SL) |
+                       (15 << CP0C2_SA),
+        .CP0_Config3 = MIPS_CONFIG3 | (1U << CP0C3_M) | (1 << CP0C3_MSAP) |
+                       (1 << CP0C3_BP) | (1 << CP0C3_BI) | (1 << CP0C3_ULRI) |
+                       (1 << CP0C3_RXI) | (1 << CP0C3_LPA) | (1 << CP0C3_VInt),
+        .CP0_Config4 = MIPS_CONFIG4 | (1U << CP0C4_M) | (2 << CP0C4_IE) |
+                       (1 << CP0C4_AE) | (0x1c << CP0C4_KScrExist),
+        .CP0_Config4_rw_bitmask = 0,
+        .CP0_Config5 = MIPS_CONFIG5 | (1 << CP0C5_CRCP) | (1 << CP0C5_NFExists),
+        .CP0_Config5_rw_bitmask = (1 << CP0C5_K) | (1 << CP0C5_CV) |
+                                  (1 << CP0C5_MSAEn) | (1 << CP0C5_UFE) |
+                                  (1 << CP0C5_FRE) | (1 << CP0C5_SBRI),
+        .CP0_Config6 = (1 << CP0C6_VCLRU) | (1 << CP0C6_DCLRU) |
+                       (1 << CP0C6_SFBEN) | (1 << CP0C6_VLTINT) |
+                       (1 << CP0C6_INSTPREF) | (1 << CP0C6_DATAPREF),
+        .CP0_Config6_rw_bitmask = (1 << CP0C6_BPPASS) | (0x3f << CP0C6_KPOS) |
+                                  (1 << CP0C6_KE) | (1 << CP0C6_VTLBONLY) |
+                                  (1 << CP0C6_LASX) | (1 << CP0C6_SSEN) |
+                                  (1 << CP0C6_DISDRTIME) | (1 << CP0C6_PIXNUEN) |
+                                  (1 << CP0C6_SCRAND) | (1 << CP0C6_LLEXCEN) |
+                                  (1 << CP0C6_DISVC) | (1 << CP0C6_VCLRU) |
+                                  (1 << CP0C6_DCLRU) | (1 << CP0C6_PIXUEN) |
+                                  (1 << CP0C6_DISBLKLYEN) | (1 << CP0C6_UMEMUALEN) |
+                                  (1 << CP0C6_SFBEN) | (1 << CP0C6_FLTINT) |
+                                  (1 << CP0C6_VLTINT) | (1 << CP0C6_DISBTB) |
+                                  (3 << CP0C6_STPREFCTL) | (1 << CP0C6_INSTPREF) |
+                                  (1 << CP0C6_DATAPREF),
+        .CP0_Config7 = 0,
+        .CP0_Config7_rw_bitmask = (1 << CP0C7_NAPCGEN) | (1 << CP0C7_UNIMUEN) |
+                                  (1 << CP0C7_VFPUCGEN),
+        .CP0_LLAddr_rw_bitmask = 1,
+        .SYNCI_Step = 16,
+        .CCRes = 2,
+        .CP0_Status_rw_bitmask = 0x7DDBFFFF,
+        .CP0_PageGrain = (1 << CP0PG_ELPA),
+        .CP0_PageGrain_rw_bitmask = (1U << CP0PG_RIE) | (1 << CP0PG_XIE) |
+                    (1 << CP0PG_ELPA) | (1 << CP0PG_IEC),
+        .CP1_fcr0 = (0x5 << FCR0_PRID) | (0x1 << FCR0_REV) | (0x1 << FCR0_F64) |
+                    (0x1 << FCR0_PS) | (0x1 << FCR0_L) | (0x1 << FCR0_W) |
+                    (0x1 << FCR0_D) | (0x1 << FCR0_S),
+        .CP1_fcr31 = 0,
+        .CP1_fcr31_rw_bitmask = 0xFF83FFFF,
+        .SEGBITS = 48,
+        .PABITS = 48,
+        .insn_flags = CPU_LOONGSON3A,
+        .mmu_type = MMU_TYPE_R4000,
+    },
+    {
         /* A generic CPU providing MIPS64 DSP R2 ASE features.
            FIXME: Eventually this should be replaced by a real CPU model. */
         .name = "mips64dspr2",
-- 
2.7.0



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

* [PATCH for-5.1 V4 3/4] hw/mips: Add Loongson-3 machine support (with KVM)
  2020-06-02  2:39 [PATCH for-5.1 V4 0/7] mips: Add Loongson-3 machine support (with KVM) Huacai Chen
  2020-06-02  2:39 ` [PATCH for-5.1 V4 1/4] hw/mips: Implement the kvm_type() hook in MachineClass Huacai Chen
  2020-06-02  2:39 ` [PATCH for-5.1 V4 2/4] target/mips: Add Loongson-3 CPU definition Huacai Chen
@ 2020-06-02  2:39 ` Huacai Chen
  2020-06-06  7:32   ` Aleksandar Markovic
                     ` (2 more replies)
  2020-06-02  2:39 ` [PATCH for-5.1 V4 4/4] MAINTAINERS: Add myself as Loongson-3 maintainer Huacai Chen
  2020-06-05  8:38 ` [PATCH for-5.1 V4 0/7] mips: Add Loongson-3 machine support (with KVM) Aleksandar Markovic
  4 siblings, 3 replies; 41+ messages in thread
From: Huacai Chen @ 2020-06-02  2:39 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, Aleksandar Markovic
  Cc: Huacai Chen, Huacai Chen, Aleksandar Rikalo, qemu-devel, Aurelien Jarno

Add Loongson-3 based machine support, it use i8259 as the interrupt
controler and use GPEX as the pci controller. Currently it can only
work with KVM, but we will add TCG support in future.

We already have a full functional Linux kernel (based on Linux-5.4.x LTS
but not upstream yet) here:

https://github.com/chenhuacai/linux

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 the a Loongson-3A4000 host with this kernel;
4, Build QEMU-5.0.0 with this patchset;
5, modprobe kvm;
6, Use QEMU with TCG (available in future):
       qemu-system-mips64el -M loongson3,accel=tcg -cpu Loongson-3A1000 -kernel <path_to_kernel> -append ...
   Use QEMU with KVM (available at present):
       qemu-system-mips64el -M loongson3,accel=kvm -cpu Loongson-3A4000 -kernel <path_to_kernel> -append ...

   The "-cpu" parameter can be omitted 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                      |  10 +
 hw/mips/Makefile.objs                |   1 +
 hw/mips/loongson3.c                  | 901 +++++++++++++++++++++++++++++++++++
 4 files changed, 913 insertions(+)
 create mode 100644 hw/mips/loongson3.c

diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak
index 9f8a3ef..2a2a3fb 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_LOONGSON3=y
 CONFIG_ATI_VGA=y
 CONFIG_RTL8139_PCI=y
 CONFIG_JAZZ=y
diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig
index 67d39c5..42931fd 100644
--- a/hw/mips/Kconfig
+++ b/hw/mips/Kconfig
@@ -45,6 +45,16 @@ config FULOONG
     bool
     select PCI_BONITO
 
+config LOONGSON3
+    bool
+    select PCKBD
+    select SERIAL
+    select ISA_BUS
+    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/Makefile.objs b/hw/mips/Makefile.objs
index 3b3e6ea..31dedcb 100644
--- a/hw/mips/Makefile.objs
+++ b/hw/mips/Makefile.objs
@@ -4,5 +4,6 @@ obj-$(CONFIG_MALTA) += gt64xxx_pci.o malta.o
 obj-$(CONFIG_MIPSSIM) += mipssim.o
 obj-$(CONFIG_JAZZ) += jazz.o
 obj-$(CONFIG_FULOONG) += fuloong2e.o
+obj-$(CONFIG_LOONGSON3) += loongson3.o
 obj-$(CONFIG_MIPS_CPS) += cps.o
 obj-$(CONFIG_MIPS_BOSTON) += boston.o
diff --git a/hw/mips/loongson3.c b/hw/mips/loongson3.c
new file mode 100644
index 0000000..e4b9538
--- /dev/null
+++ b/hw/mips/loongson3.c
@@ -0,0 +1,901 @@
+/*
+ * Generic Loongson-3 Platform support
+ *
+ * Copyright (c) 2016-2020 Huacai Chen (chenhc@lemote.com)
+ * This code is licensed under the GNU GPL v2.
+ *
+ * Contributions are licensed under the terms of the GNU GPL,
+ * version 2 or (at your option) any later version.
+ */
+
+/*
+ * Generic 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 "hw/boards.h"
+#include "hw/char/serial.h"
+#include "hw/mips/mips.h"
+#include "hw/mips/cpudevs.h"
+#include "hw/intc/i8259.h"
+#include "hw/loader.h"
+#include "hw/ide.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 "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 INITRD_OFFSET         0x04000000
+#define BOOTPARAM_ADDR        0x8ff00000
+#define BOOTPARAM_PHYADDR     0x0ff00000
+#define CFG_ADDR              0x0f100000
+#define FW_CONF_ADDR          0x0fff0000
+#define PM_MMIO_ADDR          0x10080000
+#define PM_MMIO_SIZE          0x100
+#define PM_CNTL_MODE          0x10
+
+#define PHYS_TO_VIRT(x) ((x) | ~(target_ulong)0x7fffffff)
+
+/* Loongson-3 has a 2MB flash rom */
+#define BIOS_SIZE               (2 * MiB)
+#define LOONGSON_MAX_VCPUS      16
+
+#define LOONGSON3_BIOSNAME "bios_loongson3.bin"
+
+#define PCIE_IRQ_BASE       3
+
+#define VIRT_PCI_IO_BASE    0x18000000ul
+#define VIRT_PCI_IO_SIZE    0x000c0000ul
+#define VIRT_PCI_MEM_BASE   0x40000000ul
+#define VIRT_PCI_MEM_SIZE   0x40000000ul
+#define VIRT_PCI_ECAM_BASE  0x1a000000ul
+#define VIRT_PCI_ECAM_SIZE  0x02000000ul
+
+#define align(x) (((x) + 63) & ~63)
+
+/* 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;
+};
+
+static struct _fw_config {
+    unsigned long ram_size;
+    unsigned int mem_freq;
+    unsigned int nr_cpus;
+    unsigned int cpu_clock_freq;
+} fw_config;
+
+static struct _loaderparams {
+    unsigned long ram_size;
+    const char *kernel_cmdline;
+    const char *kernel_filename;
+    const char *initrd_filename;
+    int64_t kernel_entry;
+    unsigned long a0, a1, a2;
+} loaderparams;
+
+static void *boot_params_p;
+static void *boot_params_buf;
+
+static unsigned int bios_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                                                      */
+};
+
+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 = (loaderparams.ram_size > 0x10000000
+                            ? 256 : (loaderparams.ram_size >> 20)) - 16;
+
+    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 > 0x10000000
+                            ? (loaderparams.ram_size >> 20) - 256 : 0);
+
+    return emap;
+}
+
+static int get_host_cpu_freq(void)
+{
+    int fd = 0, freq = 0;
+    char buf[1024], *buf_p;
+
+    fd = open("/proc/cpuinfo", O_RDONLY);
+    if (fd == -1) {
+        fprintf(stderr, "Failed to open /proc/cpuinfo!\n");
+        return 0;
+    }
+
+    if (read(fd, buf, 1024) < 0) {
+        close(fd);
+        fprintf(stderr, "Failed to read /proc/cpuinfo!\n");
+        return 0;
+    }
+    close(fd);
+
+    buf_p = strstr(buf, "model name");
+    while (*buf_p != '@') {
+        buf_p++;
+    }
+
+    buf_p += 2;
+    memcpy(buf, buf_p, 12);
+    buf_p = buf;
+    while ((*buf_p >= '0') && (*buf_p <= '9')) {
+        buf_p++;
+    }
+    *buf_p = '\0';
+
+    freq = atoi(buf);
+
+    return freq * 1000 * 1000;
+}
+
+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 = 0x14C000;
+    c->cpu_clock_freq = get_host_cpu_freq();
+    if (!c->cpu_clock_freq) {
+        c->cpu_clock_freq = 500000000;
+    }
+
+    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;
+    s->uarts[0].uart_base = 0x1fe001e0;
+
+    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_PCI_MEM_BASE;
+    irq_info->pci_mem_end_addr   = VIRT_PCI_MEM_BASE + VIRT_PCI_MEM_SIZE - 1;
+    irq_info->pci_io_start_addr  = VIRT_PCI_IO_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, "2016-05-16");
+
+    return special;
+}
+
+static void init_loongson_params(struct loongson_params *lp)
+{
+    void *p = boot_params_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));
+
+    boot_params_p = p;
+}
+
+static void init_smbios(struct smbios_tables *smbios)
+{
+    smbios->vers = 1;
+    init_loongson_params(&(smbios->lp));
+}
+
+static void init_efi(struct efi_loongson *efi)
+{
+    init_smbios(&(efi->smbios));
+}
+
+static void init_reset_system(struct efi_reset_system_t *reset)
+{
+    reset->Shutdown = 0xffffffffbfc000a8;
+    reset->ResetCold = 0xffffffffbfc00080;
+    reset->ResetWarm = 0xffffffffbfc00080;
+}
+
+static int init_boot_param(struct boot_params *bp)
+{
+    init_efi(&(bp->efi));
+    init_reset_system(&(bp->reset_system));
+
+    return 0;
+}
+
+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;
+
+    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);
+    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
+
+    fw_config.ram_size = ram_size;
+    fw_config.mem_freq = 300000000;
+    fw_config.nr_cpus = current_machine->smp.cpus;
+    fw_config.cpu_clock_freq = get_host_cpu_freq();
+}
+
+static int set_prom_bootparam(ram_addr_t initrd_offset, long initrd_size)
+{
+    long params_size;
+    char memenv[32];
+    char highmemenv[32];
+    void *params_buf;
+    unsigned int *parg_env;
+    int ret = 0;
+
+    /* Allocate params_buf for command line. */
+    params_size = 0x100000;
+    params_buf = g_malloc0(params_size);
+
+    /*
+     * Layout of params_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 *)params_buf;
+
+    ret = (3 + 1) * 4;
+    *parg_env++ = (BOOTPARAM_ADDR + ret);
+    ret += (1 + snprintf(params_buf + ret, 256 - ret, "g"));
+
+    /* argv1 */
+    *parg_env++ = BOOTPARAM_ADDR + ret;
+    if (initrd_size > 0)
+        ret += (1 + snprintf(params_buf + ret, 256 - ret,
+                "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s",
+                PHYS_TO_VIRT((uint32_t)initrd_offset),
+                initrd_size, loaderparams.kernel_cmdline));
+    else
+        ret += (1 + snprintf(params_buf + ret, 256 - ret, "%s",
+                loaderparams.kernel_cmdline));
+
+    /* argv2 */
+    *parg_env++ = BOOTPARAM_ADDR + 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);
+
+    setenv("memsize", memenv, 1);
+    setenv("highmemsize", highmemenv, 1);
+
+    ret = ((ret + 32) & ~31);
+
+    boot_params_buf = (void *)(params_buf + ret);
+    boot_params_p = boot_params_buf + align(sizeof(struct boot_params));
+
+    init_boot_param(boot_params_buf);
+
+    rom_add_blob_fixed("params", params_buf, params_size,
+                       BOOTPARAM_PHYADDR);
+    loaderparams.a0 = 2;
+    loaderparams.a1 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR;
+    loaderparams.a2 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR + ret;
+
+    return 0;
+}
+
+static int64_t load_kernel(CPUMIPSState *env)
+{
+    long kernel_size;
+    ram_addr_t initrd_offset;
+    int64_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, INITRD_OFFSET);
+
+            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 parameters. */
+    set_prom_bootparam(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 void loongson3_isa_init(qemu_irq intc)
+{
+    qemu_irq *i8259;
+    ISABus *isa_bus;
+
+    isa_bus = isa_bus_new(NULL, get_system_memory(), get_system_io(), &error_abort);
+
+    /* Interrupt controller */
+    /* The 8259 -> IP3  */
+    i8259 = i8259_init(isa_bus, intc);
+    isa_bus_irqs(isa_bus, i8259);
+    /* init other devices */
+    isa_create_simple(isa_bus, "i8042");
+    mc146818_rtc_init(isa_bus, 2000, NULL);
+}
+
+static inline void loongson3_pcie_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_create(NULL, TYPE_GPEX_HOST);
+
+    qdev_init_nofail(dev);
+    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_PCI_ECAM_SIZE);
+    memory_region_add_subregion(get_system_memory(), VIRT_PCI_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_PCI_MEM_BASE, VIRT_PCI_MEM_SIZE);
+    memory_region_add_subregion(get_system_memory(), VIRT_PCI_MEM_BASE, mmio_alias);
+
+    pio_alias = g_new0(MemoryRegion, 1);
+    memory_region_init_alias(pio_alias, OBJECT(dev), "pcie-pio",
+                             get_system_io(), 0, VIRT_PCI_IO_SIZE);
+    memory_region_add_subregion(get_system_memory(), VIRT_PCI_IO_BASE, pio_alias);
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, VIRT_PCI_IO_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);
+
+    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_init(MachineState *machine)
+{
+    int i;
+    long bios_size;
+    MIPSCPU *cpu;
+    CPUMIPSState *env;
+    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);
+
+    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 < 256 * 0x100000) {
+        error_report("Loongson-3 need at least 256MB memory");
+        exit(1);
+    }
+
+    for (i = 0; i < machine->smp.cpus; i++) {
+        /* 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);
+    }
+    env = &MIPS_CPU(first_cpu)->env;
+
+    /* Allocate RAM/BIOS, 0x00000000~0x10000000 is alias of 0x80000000~0x90000000 */
+    memory_region_init_rom(bios, NULL, "loongson3.bios",
+                           BIOS_SIZE, &error_fatal);
+    memory_region_init_alias(ram, NULL, "loongson3.lowram",
+                           machine->ram, 0, 256 * 0x100000);
+    memory_region_init_io(iomem, NULL, &loongson3_pm_ops,
+                           NULL, "loongson3_pm", PM_MMIO_SIZE);
+
+    memory_region_add_subregion(address_space_mem, 0x00000000LL, ram);
+    memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios);
+    memory_region_add_subregion(address_space_mem, 0x80000000LL, machine->ram);
+    memory_region_add_subregion(address_space_mem, PM_MMIO_ADDR, iomem);
+
+    /*
+     * We do not support flash operation, just loading pmon.bin as raw BIOS.
+     * Please use -L to set the BIOS path and -bios to set bios name.
+     */
+
+    if (kernel_filename) {
+        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);
+        rom_add_blob_fixed("bios",
+                         bios_boot_code, sizeof(bios_boot_code), 0x1fc00000LL);
+    } 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, 0x1fc00000LL,
+                                            BIOS_SIZE);
+            g_free(filename);
+        } else {
+            bios_size = -1;
+        }
+
+        if ((bios_size < 0 || bios_size > BIOS_SIZE) &&
+            !kernel_filename && !qtest_enabled()) {
+            error_report("Could not load MIPS bios '%s'", bios_name);
+            exit(1);
+        }
+
+        fw_conf_init(ram_size);
+        rom_add_blob_fixed("fw_conf",
+                         &fw_config, sizeof(fw_config), FW_CONF_ADDR);
+    }
+
+    msi_nonbroken = true;
+    loongson3_isa_init(env->irq[3]);
+    loongson3_pcie_init(machine, isa_pic);
+
+    if (serial_hd(0)) {
+        serial_mm_init(address_space_mem, 0x1fe001e0, 0, env->irq[2],
+                           115200, serial_hd(0), DEVICE_NATIVE_ENDIAN);
+    }
+}
+
+static void mips_loongson3_machine_init(MachineClass *mc)
+{
+    mc->desc = "Generic Loongson-3 Platform";
+    mc->init = mips_loongson3_init;
+    mc->block_default_type = IF_IDE;
+    mc->max_cpus = LOONGSON_MAX_VCPUS;
+    mc->default_ram_id = "loongson3.highram";
+    mc->default_ram_size = 1200 * MiB;
+    mc->kvm_type = mips_kvm_type;
+    mc->minimum_page_bits = 14;
+}
+
+DEFINE_MACHINE("loongson3", mips_loongson3_machine_init)
-- 
2.7.0



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

* [PATCH for-5.1 V4 4/4] MAINTAINERS: Add myself as Loongson-3 maintainer
  2020-06-02  2:39 [PATCH for-5.1 V4 0/7] mips: Add Loongson-3 machine support (with KVM) Huacai Chen
                   ` (2 preceding siblings ...)
  2020-06-02  2:39 ` [PATCH for-5.1 V4 3/4] hw/mips: Add Loongson-3 machine support (with KVM) Huacai Chen
@ 2020-06-02  2:39 ` Huacai Chen
  2020-06-02  8:12   ` Philippe Mathieu-Daudé
  2020-06-05  8:38 ` [PATCH for-5.1 V4 0/7] mips: Add Loongson-3 machine support (with KVM) Aleksandar Markovic
  4 siblings, 1 reply; 41+ messages in thread
From: Huacai Chen @ 2020-06-02  2:39 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, Aleksandar Markovic
  Cc: Huacai Chen, Huacai Chen, Aleksandar Rikalo, qemu-devel, Aurelien Jarno

Signed-off-by: Huacai Chen <chenhc@lemote.com>
Co-developed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
---
 MAINTAINERS | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 0944d9c..c42a218 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1092,6 +1092,11 @@ F: hw/isa/vt82c686.c
 F: hw/pci-host/bonito.c
 F: include/hw/isa/vt82c686.h
 
+Loongson-3
+M: Huacai Chen <chenhc@lemote.com>
+S: Maintained
+F: hw/mips/mips_loongson3.c
+
 Boston
 M: Paul Burton <pburton@wavecomp.com>
 R: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com>
-- 
2.7.0



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

* Re: [PATCH for-5.1 V4 4/4] MAINTAINERS: Add myself as Loongson-3 maintainer
  2020-06-02  2:39 ` [PATCH for-5.1 V4 4/4] MAINTAINERS: Add myself as Loongson-3 maintainer Huacai Chen
@ 2020-06-02  8:12   ` Philippe Mathieu-Daudé
  2020-06-02 12:03     ` chen huacai
  0 siblings, 1 reply; 41+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-06-02  8:12 UTC (permalink / raw)
  To: Huacai Chen, Aleksandar Markovic
  Cc: Huacai Chen, Huacai Chen, Aleksandar Rikalo, qemu-devel, Aurelien Jarno

On 6/2/20 4:39 AM, Huacai Chen wrote:
> Signed-off-by: Huacai Chen <chenhc@lemote.com>
> Co-developed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> ---
>  MAINTAINERS | 5 +++++
>  1 file changed, 5 insertions(+)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 0944d9c..c42a218 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1092,6 +1092,11 @@ F: hw/isa/vt82c686.c
>  F: hw/pci-host/bonito.c
>  F: include/hw/isa/vt82c686.h
>  
> +Loongson-3
> +M: Huacai Chen <chenhc@lemote.com>

Jiaxun Yang, do you mind being listed as reviewer here?

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

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

> +S: Maintained
> +F: hw/mips/mips_loongson3.c
> +
>  Boston
>  M: Paul Burton <pburton@wavecomp.com>
>  R: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com>
> 


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

* Re: [PATCH for-5.1 V4 4/4] MAINTAINERS: Add myself as Loongson-3 maintainer
  2020-06-02  8:12   ` Philippe Mathieu-Daudé
@ 2020-06-02 12:03     ` chen huacai
  0 siblings, 0 replies; 41+ messages in thread
From: chen huacai @ 2020-06-02 12:03 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Huacai Chen, qemu-level, Aleksandar Markovic, Huacai Chen,
	Aleksandar Rikalo, Aurelien Jarno

On Tue, Jun 2, 2020 at 4:12 AM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
>
> On 6/2/20 4:39 AM, Huacai Chen wrote:
> > Signed-off-by: Huacai Chen <chenhc@lemote.com>
> > Co-developed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> > ---
> >  MAINTAINERS | 5 +++++
> >  1 file changed, 5 insertions(+)
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 0944d9c..c42a218 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -1092,6 +1092,11 @@ F: hw/isa/vt82c686.c
> >  F: hw/pci-host/bonito.c
> >  F: include/hw/isa/vt82c686.h
> >
> > +Loongson-3
> > +M: Huacai Chen <chenhc@lemote.com>
>
> Jiaxun Yang, do you mind being listed as reviewer here?
>
> R: Jiaxun Yang <jiaxun.yang@flygoat.com>
>
> At any rate:
> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
>

Replying on behalf of Jiaxun as he had some difficulties on receiving this mail:

I'm very glad to become a reviewer of loongson3 machine.
I'll continue to work on Loongson-3 TCG support soon.

Thanks.

> > +S: Maintained
> > +F: hw/mips/mips_loongson3.c
> > +
> >  Boston
> >  M: Paul Burton <pburton@wavecomp.com>
> >  R: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com>
> >



-- 
Huacai Chen


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

* Re: [PATCH for-5.1 V4 1/4] hw/mips: Implement the kvm_type() hook in MachineClass
  2020-06-02  2:39 ` [PATCH for-5.1 V4 1/4] hw/mips: Implement the kvm_type() hook in MachineClass Huacai Chen
@ 2020-06-03 14:34   ` Aleksandar Markovic
  2020-06-04  0:57     ` Huacai Chen
  2020-06-14  8:07   ` Aleksandar Markovic
  1 sibling, 1 reply; 41+ messages in thread
From: Aleksandar Markovic @ 2020-06-03 14:34 UTC (permalink / raw)
  To: Huacai Chen
  Cc: Huacai Chen, Philippe Mathieu-Daudé,
	QEMU Developers, Huacai Chen, Aleksandar Rikalo, Aurelien Jarno

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

уто, 2. јун 2020. у 04:38 Huacai Chen <zltjiangshi@gmail.com> је написао/ла:

> MIPS has two types of KVM: TE & VZ, and TE is the default type. Now we
> can't create a VZ guest in QEMU because it lacks the kvm_type() hook in
> MachineClass. Besides, libvirt uses a null-machine to detect the kvm
> capability, so by default it will return "KVM not supported" on a VZ
> platform. Thus, null-machine also need the kvm_type() hook.
>
> Reviewed-by: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
> Signed-off-by: Huacai Chen <chenhc@lemote.com>
> Co-developed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> ---
>


Hi, Huacai,

For MIPS parts of QEMU, we prefer the following licence preamble:

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

Do you agree with such preamble in hw/mips/common.c?

(of course you name and email will stay intact)

Regards,
Aleksandar

 hw/core/Makefile.objs  |  2 +-
>  hw/core/null-machine.c |  4 ++++
>  hw/mips/Makefile.objs  |  2 +-
>  hw/mips/common.c       | 42 ++++++++++++++++++++++++++++++++++++++++++
>  include/hw/mips/mips.h |  3 +++
>  5 files changed, 51 insertions(+), 2 deletions(-)
>  create mode 100644 hw/mips/common.c
>
> diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs
> index 1d540ed..b5672f4 100644
> --- a/hw/core/Makefile.objs
> +++ b/hw/core/Makefile.objs
> @@ -17,11 +17,11 @@ common-obj-$(CONFIG_SOFTMMU) +=
> vm-change-state-handler.o
>  common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o
>  common-obj-$(CONFIG_SOFTMMU) += sysbus.o
>  common-obj-$(CONFIG_SOFTMMU) += machine.o
> -common-obj-$(CONFIG_SOFTMMU) += null-machine.o
>  common-obj-$(CONFIG_SOFTMMU) += loader.o
>  common-obj-$(CONFIG_SOFTMMU) += machine-hmp-cmds.o
>  common-obj-$(CONFIG_SOFTMMU) += numa.o
>  common-obj-$(CONFIG_SOFTMMU) += clock-vmstate.o
> +obj-$(CONFIG_SOFTMMU) += null-machine.o
>  obj-$(CONFIG_SOFTMMU) += machine-qmp-cmds.o
>
>  common-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o
> diff --git a/hw/core/null-machine.c b/hw/core/null-machine.c
> index cb47d9d..94a36f9 100644
> --- a/hw/core/null-machine.c
> +++ b/hw/core/null-machine.c
> @@ -17,6 +17,7 @@
>  #include "sysemu/sysemu.h"
>  #include "exec/address-spaces.h"
>  #include "hw/core/cpu.h"
> +#include "hw/mips/mips.h"
>
>  static void machine_none_init(MachineState *mch)
>  {
> @@ -50,6 +51,9 @@ static void machine_none_machine_init(MachineClass *mc)
>      mc->max_cpus = 1;
>      mc->default_ram_size = 0;
>      mc->default_ram_id = "ram";
> +#ifdef TARGET_MIPS
> +    mc->kvm_type = mips_kvm_type;
> +#endif
>  }
>
>  DEFINE_MACHINE("none", machine_none_machine_init)
> diff --git a/hw/mips/Makefile.objs b/hw/mips/Makefile.objs
> index 739e2b7..3b3e6ea 100644
> --- a/hw/mips/Makefile.objs
> +++ b/hw/mips/Makefile.objs
> @@ -1,4 +1,4 @@
> -obj-y += addr.o mips_int.o
> +obj-y += addr.o common.o mips_int.o
>  obj-$(CONFIG_R4K) += r4k.o
>  obj-$(CONFIG_MALTA) += gt64xxx_pci.o malta.o
>  obj-$(CONFIG_MIPSSIM) += mipssim.o
> diff --git a/hw/mips/common.c b/hw/mips/common.c
> new file mode 100644
> index 0000000..4d8e141
> --- /dev/null
> +++ b/hw/mips/common.c
> @@ -0,0 +1,42 @@
> +/*
> + * Common MIPS routines
> + *
> + * Copyright (c) 2020 Huacai Chen (chenhc@lemote.com)
> + * This code is licensed under the GNU GPL v2.
> + */
> +
> +#include <linux/kvm.h>
> +#include "qemu/osdep.h"
> +#include "qemu-common.h"
> +#include "hw/boards.h"
> +#include "hw/mips/mips.h"
> +#include "sysemu/kvm_int.h"
> +
> +#ifndef CONFIG_KVM
> +
> +int mips_kvm_type(MachineState *machine, const char *vm_type)
> +{
> +    return 0;
> +}
> +
> +#else
> +
> +int mips_kvm_type(MachineState *machine, const char *vm_type)
> +{
> +    int r;
> +    KVMState *s = KVM_STATE(machine->accelerator);
> +
> +    r = kvm_check_extension(s, KVM_CAP_MIPS_VZ);
> +    if (r > 0) {
> +        return KVM_VM_MIPS_VZ;
> +    }
> +
> +    r = kvm_check_extension(s, KVM_CAP_MIPS_TE);
> +    if (r > 0) {
> +        return KVM_VM_MIPS_TE;
> +    }
> +
> +    return -1;
> +}
> +
> +#endif
> diff --git a/include/hw/mips/mips.h b/include/hw/mips/mips.h
> index 0af4c3d..2ac0580 100644
> --- a/include/hw/mips/mips.h
> +++ b/include/hw/mips/mips.h
> @@ -20,4 +20,7 @@ void rc4030_dma_write(void *dma, uint8_t *buf, int len);
>
>  DeviceState *rc4030_init(rc4030_dma **dmas, IOMMUMemoryRegion **dma_mr);
>
> +/* common.c */
> +int mips_kvm_type(MachineState *machine, const char *vm_type);
> +
>  #endif
> --
> 2.7.0
>
>

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

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

* Re: [PATCH for-5.1 V4 1/4] hw/mips: Implement the kvm_type() hook in MachineClass
  2020-06-03 14:34   ` Aleksandar Markovic
@ 2020-06-04  0:57     ` Huacai Chen
  2020-06-04 10:04       ` Aleksandar Markovic
  0 siblings, 1 reply; 41+ messages in thread
From: Huacai Chen @ 2020-06-04  0:57 UTC (permalink / raw)
  To: Aleksandar Markovic
  Cc: Huacai Chen, Aleksandar Rikalo, Philippe Mathieu-Daudé,
	Aurelien Jarno, QEMU Developers

Hi, Alexandar,

On Wed, Jun 3, 2020 at 10:34 PM Aleksandar Markovic
<aleksandar.qemu.devel@gmail.com> wrote:
>
>
>
> уто, 2. јун 2020. у 04:38 Huacai Chen <zltjiangshi@gmail.com> је написао/ла:
>>
>> MIPS has two types of KVM: TE & VZ, and TE is the default type. Now we
>> can't create a VZ guest in QEMU because it lacks the kvm_type() hook in
>> MachineClass. Besides, libvirt uses a null-machine to detect the kvm
>> capability, so by default it will return "KVM not supported" on a VZ
>> platform. Thus, null-machine also need the kvm_type() hook.
>>
>> Reviewed-by: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
>> Signed-off-by: Huacai Chen <chenhc@lemote.com>
>> Co-developed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
>> ---
>
>
>
> Hi, Huacai,
>
> For MIPS parts of QEMU, we prefer the following licence preamble:
>
>  *  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/>.
>
> Do you agree with such preamble in hw/mips/common.c?
Yes, I agree.

>
> (of course you name and email will stay intact)
>
> Regards,
> Aleksandar
>
>>  hw/core/Makefile.objs  |  2 +-
>>  hw/core/null-machine.c |  4 ++++
>>  hw/mips/Makefile.objs  |  2 +-
>>  hw/mips/common.c       | 42 ++++++++++++++++++++++++++++++++++++++++++
>>  include/hw/mips/mips.h |  3 +++
>>  5 files changed, 51 insertions(+), 2 deletions(-)
>>  create mode 100644 hw/mips/common.c
>>
>> diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs
>> index 1d540ed..b5672f4 100644
>> --- a/hw/core/Makefile.objs
>> +++ b/hw/core/Makefile.objs
>> @@ -17,11 +17,11 @@ common-obj-$(CONFIG_SOFTMMU) += vm-change-state-handler.o
>>  common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o
>>  common-obj-$(CONFIG_SOFTMMU) += sysbus.o
>>  common-obj-$(CONFIG_SOFTMMU) += machine.o
>> -common-obj-$(CONFIG_SOFTMMU) += null-machine.o
>>  common-obj-$(CONFIG_SOFTMMU) += loader.o
>>  common-obj-$(CONFIG_SOFTMMU) += machine-hmp-cmds.o
>>  common-obj-$(CONFIG_SOFTMMU) += numa.o
>>  common-obj-$(CONFIG_SOFTMMU) += clock-vmstate.o
>> +obj-$(CONFIG_SOFTMMU) += null-machine.o
>>  obj-$(CONFIG_SOFTMMU) += machine-qmp-cmds.o
>>
>>  common-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o
>> diff --git a/hw/core/null-machine.c b/hw/core/null-machine.c
>> index cb47d9d..94a36f9 100644
>> --- a/hw/core/null-machine.c
>> +++ b/hw/core/null-machine.c
>> @@ -17,6 +17,7 @@
>>  #include "sysemu/sysemu.h"
>>  #include "exec/address-spaces.h"
>>  #include "hw/core/cpu.h"
>> +#include "hw/mips/mips.h"
>>
>>  static void machine_none_init(MachineState *mch)
>>  {
>> @@ -50,6 +51,9 @@ static void machine_none_machine_init(MachineClass *mc)
>>      mc->max_cpus = 1;
>>      mc->default_ram_size = 0;
>>      mc->default_ram_id = "ram";
>> +#ifdef TARGET_MIPS
>> +    mc->kvm_type = mips_kvm_type;
>> +#endif
>>  }
>>
>>  DEFINE_MACHINE("none", machine_none_machine_init)
>> diff --git a/hw/mips/Makefile.objs b/hw/mips/Makefile.objs
>> index 739e2b7..3b3e6ea 100644
>> --- a/hw/mips/Makefile.objs
>> +++ b/hw/mips/Makefile.objs
>> @@ -1,4 +1,4 @@
>> -obj-y += addr.o mips_int.o
>> +obj-y += addr.o common.o mips_int.o
>>  obj-$(CONFIG_R4K) += r4k.o
>>  obj-$(CONFIG_MALTA) += gt64xxx_pci.o malta.o
>>  obj-$(CONFIG_MIPSSIM) += mipssim.o
>> diff --git a/hw/mips/common.c b/hw/mips/common.c
>> new file mode 100644
>> index 0000000..4d8e141
>> --- /dev/null
>> +++ b/hw/mips/common.c
>> @@ -0,0 +1,42 @@
>> +/*
>> + * Common MIPS routines
>> + *
>> + * Copyright (c) 2020 Huacai Chen (chenhc@lemote.com)
>> + * This code is licensed under the GNU GPL v2.
>> + */
>> +
>> +#include <linux/kvm.h>
>> +#include "qemu/osdep.h"
>> +#include "qemu-common.h"
>> +#include "hw/boards.h"
>> +#include "hw/mips/mips.h"
>> +#include "sysemu/kvm_int.h"
>> +
>> +#ifndef CONFIG_KVM
>> +
>> +int mips_kvm_type(MachineState *machine, const char *vm_type)
>> +{
>> +    return 0;
>> +}
>> +
>> +#else
>> +
>> +int mips_kvm_type(MachineState *machine, const char *vm_type)
>> +{
>> +    int r;
>> +    KVMState *s = KVM_STATE(machine->accelerator);
>> +
>> +    r = kvm_check_extension(s, KVM_CAP_MIPS_VZ);
>> +    if (r > 0) {
>> +        return KVM_VM_MIPS_VZ;
>> +    }
>> +
>> +    r = kvm_check_extension(s, KVM_CAP_MIPS_TE);
>> +    if (r > 0) {
>> +        return KVM_VM_MIPS_TE;
>> +    }
>> +
>> +    return -1;
>> +}
>> +
>> +#endif
>> diff --git a/include/hw/mips/mips.h b/include/hw/mips/mips.h
>> index 0af4c3d..2ac0580 100644
>> --- a/include/hw/mips/mips.h
>> +++ b/include/hw/mips/mips.h
>> @@ -20,4 +20,7 @@ void rc4030_dma_write(void *dma, uint8_t *buf, int len);
>>
>>  DeviceState *rc4030_init(rc4030_dma **dmas, IOMMUMemoryRegion **dma_mr);
>>
>> +/* common.c */
>> +int mips_kvm_type(MachineState *machine, const char *vm_type);
>> +
>>  #endif
>> --
>> 2.7.0
>>


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

* Re: [PATCH for-5.1 V4 1/4] hw/mips: Implement the kvm_type() hook in MachineClass
  2020-06-04  0:57     ` Huacai Chen
@ 2020-06-04 10:04       ` Aleksandar Markovic
  0 siblings, 0 replies; 41+ messages in thread
From: Aleksandar Markovic @ 2020-06-04 10:04 UTC (permalink / raw)
  To: Huacai Chen
  Cc: Huacai Chen, Aleksandar Rikalo, Philippe Mathieu-Daudé,
	Aurelien Jarno, QEMU Developers

чет, 4. јун 2020. у 02:57 Huacai Chen <chenhuacai@gmail.com> је написао/ла:
>
> Hi, Alexandar,
>
> On Wed, Jun 3, 2020 at 10:34 PM Aleksandar Markovic
> <aleksandar.qemu.devel@gmail.com> wrote:
> >
> >
> >
> > уто, 2. јун 2020. у 04:38 Huacai Chen <zltjiangshi@gmail.com> је написао/ла:
> >>
> >> MIPS has two types of KVM: TE & VZ, and TE is the default type. Now we
> >> can't create a VZ guest in QEMU because it lacks the kvm_type() hook in
> >> MachineClass. Besides, libvirt uses a null-machine to detect the kvm
> >> capability, so by default it will return "KVM not supported" on a VZ
> >> platform. Thus, null-machine also need the kvm_type() hook.
> >>
> >> Reviewed-by: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
> >> Signed-off-by: Huacai Chen <chenhc@lemote.com>
> >> Co-developed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> >> ---
> >
> >
> >
> > Hi, Huacai,
> >
> > For MIPS parts of QEMU, we prefer the following licence preamble:
> >
> >  *  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/>.
> >
> > Do you agree with such preamble in hw/mips/common.c?
> Yes, I agree.
>

Thank you!

No further action is needed from your side, I can change the preamble
while applying to mips queue.

Aleksandar
> >
> > (of course you name and email will stay intact)
> >
> > Regards,
> > Aleksandar
> >
> >>  hw/core/Makefile.objs  |  2 +-
> >>  hw/core/null-machine.c |  4 ++++
> >>  hw/mips/Makefile.objs  |  2 +-
> >>  hw/mips/common.c       | 42 ++++++++++++++++++++++++++++++++++++++++++
> >>  include/hw/mips/mips.h |  3 +++
> >>  5 files changed, 51 insertions(+), 2 deletions(-)
> >>  create mode 100644 hw/mips/common.c
> >>
> >> diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs
> >> index 1d540ed..b5672f4 100644
> >> --- a/hw/core/Makefile.objs
> >> +++ b/hw/core/Makefile.objs
> >> @@ -17,11 +17,11 @@ common-obj-$(CONFIG_SOFTMMU) += vm-change-state-handler.o
> >>  common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o
> >>  common-obj-$(CONFIG_SOFTMMU) += sysbus.o
> >>  common-obj-$(CONFIG_SOFTMMU) += machine.o
> >> -common-obj-$(CONFIG_SOFTMMU) += null-machine.o
> >>  common-obj-$(CONFIG_SOFTMMU) += loader.o
> >>  common-obj-$(CONFIG_SOFTMMU) += machine-hmp-cmds.o
> >>  common-obj-$(CONFIG_SOFTMMU) += numa.o
> >>  common-obj-$(CONFIG_SOFTMMU) += clock-vmstate.o
> >> +obj-$(CONFIG_SOFTMMU) += null-machine.o
> >>  obj-$(CONFIG_SOFTMMU) += machine-qmp-cmds.o
> >>
> >>  common-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o
> >> diff --git a/hw/core/null-machine.c b/hw/core/null-machine.c
> >> index cb47d9d..94a36f9 100644
> >> --- a/hw/core/null-machine.c
> >> +++ b/hw/core/null-machine.c
> >> @@ -17,6 +17,7 @@
> >>  #include "sysemu/sysemu.h"
> >>  #include "exec/address-spaces.h"
> >>  #include "hw/core/cpu.h"
> >> +#include "hw/mips/mips.h"
> >>
> >>  static void machine_none_init(MachineState *mch)
> >>  {
> >> @@ -50,6 +51,9 @@ static void machine_none_machine_init(MachineClass *mc)
> >>      mc->max_cpus = 1;
> >>      mc->default_ram_size = 0;
> >>      mc->default_ram_id = "ram";
> >> +#ifdef TARGET_MIPS
> >> +    mc->kvm_type = mips_kvm_type;
> >> +#endif
> >>  }
> >>
> >>  DEFINE_MACHINE("none", machine_none_machine_init)
> >> diff --git a/hw/mips/Makefile.objs b/hw/mips/Makefile.objs
> >> index 739e2b7..3b3e6ea 100644
> >> --- a/hw/mips/Makefile.objs
> >> +++ b/hw/mips/Makefile.objs
> >> @@ -1,4 +1,4 @@
> >> -obj-y += addr.o mips_int.o
> >> +obj-y += addr.o common.o mips_int.o
> >>  obj-$(CONFIG_R4K) += r4k.o
> >>  obj-$(CONFIG_MALTA) += gt64xxx_pci.o malta.o
> >>  obj-$(CONFIG_MIPSSIM) += mipssim.o
> >> diff --git a/hw/mips/common.c b/hw/mips/common.c
> >> new file mode 100644
> >> index 0000000..4d8e141
> >> --- /dev/null
> >> +++ b/hw/mips/common.c
> >> @@ -0,0 +1,42 @@
> >> +/*
> >> + * Common MIPS routines
> >> + *
> >> + * Copyright (c) 2020 Huacai Chen (chenhc@lemote.com)
> >> + * This code is licensed under the GNU GPL v2.
> >> + */
> >> +
> >> +#include <linux/kvm.h>
> >> +#include "qemu/osdep.h"
> >> +#include "qemu-common.h"
> >> +#include "hw/boards.h"
> >> +#include "hw/mips/mips.h"
> >> +#include "sysemu/kvm_int.h"
> >> +
> >> +#ifndef CONFIG_KVM
> >> +
> >> +int mips_kvm_type(MachineState *machine, const char *vm_type)
> >> +{
> >> +    return 0;
> >> +}
> >> +
> >> +#else
> >> +
> >> +int mips_kvm_type(MachineState *machine, const char *vm_type)
> >> +{
> >> +    int r;
> >> +    KVMState *s = KVM_STATE(machine->accelerator);
> >> +
> >> +    r = kvm_check_extension(s, KVM_CAP_MIPS_VZ);
> >> +    if (r > 0) {
> >> +        return KVM_VM_MIPS_VZ;
> >> +    }
> >> +
> >> +    r = kvm_check_extension(s, KVM_CAP_MIPS_TE);
> >> +    if (r > 0) {
> >> +        return KVM_VM_MIPS_TE;
> >> +    }
> >> +
> >> +    return -1;
> >> +}
> >> +
> >> +#endif
> >> diff --git a/include/hw/mips/mips.h b/include/hw/mips/mips.h
> >> index 0af4c3d..2ac0580 100644
> >> --- a/include/hw/mips/mips.h
> >> +++ b/include/hw/mips/mips.h
> >> @@ -20,4 +20,7 @@ void rc4030_dma_write(void *dma, uint8_t *buf, int len);
> >>
> >>  DeviceState *rc4030_init(rc4030_dma **dmas, IOMMUMemoryRegion **dma_mr);
> >>
> >> +/* common.c */
> >> +int mips_kvm_type(MachineState *machine, const char *vm_type);
> >> +
> >>  #endif
> >> --
> >> 2.7.0
> >>


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

* Re: [PATCH for-5.1 V4 0/7] mips: Add Loongson-3 machine support (with KVM)
  2020-06-02  2:39 [PATCH for-5.1 V4 0/7] mips: Add Loongson-3 machine support (with KVM) Huacai Chen
                   ` (3 preceding siblings ...)
  2020-06-02  2:39 ` [PATCH for-5.1 V4 4/4] MAINTAINERS: Add myself as Loongson-3 maintainer Huacai Chen
@ 2020-06-05  8:38 ` Aleksandar Markovic
  2020-06-05  8:40   ` Aleksandar Markovic
  2020-06-05  9:05   ` Jiaxun Yang
  4 siblings, 2 replies; 41+ messages in thread
From: Aleksandar Markovic @ 2020-06-05  8:38 UTC (permalink / raw)
  To: Huacai Chen
  Cc: Huacai Chen, Philippe Mathieu-Daudé,
	QEMU Developers, Huacai Chen, Aleksandar Rikalo, Aurelien Jarno

уто, 2. јун 2020. у 04:38 Huacai Chen <zltjiangshi@gmail.com> је написао/ла:
>
> Loongson-3 CPU family include Loongson-3A R1/R2/R3/R4 and Loongson-3B
> R1/R2.

Hi, Huacai,

The documents you kindly provided contain some valuable info on
Loongson-3A R1/R2/R3/R4 and Loongson-3B R1/R2. However, I
couldn't find detailed instruction-by-instruction specifications.

In fact, I don't need all the details right now, but some form of
overview of instructions sets of Loongson-3A R1/R2/R3/R4 and
Loongson-3B R1/R2. Could you please provide textual description
(one of two paragraph) of supported instructions for each of these
models:

* Loongson-3A R1
* Loongson-3A R2
* Loongson-3A R3
* Loongson-3A R4
* Loongson-3B R1
* Loongson-3B R2

(what is the base instructuin set; the difference to the previous model;
what SIMD extension (LMI/MSA) is supported other specifics around
supported instructions)

Based on your answer I may bring forward some suggestions on the
improvement of v4 of this series.

Truly yours,
Aleksandar

> 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.
>
> We are preparing to add QEMU's Loongson-3 support. MIPS VZ extension is
> fully supported in Loongson-3A R4+, so we at first add QEMU/KVM support
> in this series. And the next series will add QEMU/TCG support (it will
> emulate Loongson-3A R1).
>
> We already have a full functional Linux kernel (based on Linux-5.4.x LTS
> but not upstream yet) here:
>
> https://github.com/chenhuacai/linux
>
> 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;
> 4, Build QEMU-5.0.0 with this patchset;
> 5, modprobe kvm;
> 6, Use QEMU with TCG (available in future):
>        qemu-system-mips64el -M loongson3,accel=tcg -cpu Loongson-3A1000 -kernel <path_to_kernel> -append ...
>    Use QEMU with KVM (available at present):
>        qemu-system-mips64el -M loongson3,accel=kvm -cpu Loongson-3A4000 -kernel <path_to_kernel> -append ...
>
>    The "-cpu" parameter can be omitted 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>.
>
> Huacai Chen(4):
>  hw/mips: Implement the kvm_type() hook in MachineClass
>  target/mips: Add Loongson-3 CPU definition
>  hw/mips: Add Loongson-3 machine support (with KVM)
>  MAINTAINERS: Add myself as Loongson-3 maintainer
>
> Signed-off-by: Huacai Chen <chenhc@lemote.com>
> ---
>  MAINTAINERS                          |   5 +
>  default-configs/mips64el-softmmu.mak |   1 +
>  hw/core/Makefile.objs                |   2 +-
>  hw/core/null-machine.c               |   4 +
>  hw/mips/Kconfig                      |  10 +
>  hw/mips/Makefile.objs                |   3 +-
>  hw/mips/common.c                     |  42 ++
>  hw/mips/loongson3.c                  | 901 +++++++++++++++++++++++++++++++++++
>  include/hw/mips/mips.h               |   3 +
>  target/mips/cpu.h                    |  28 ++
>  target/mips/internal.h               |   2 +
>  target/mips/mips-defs.h              |   7 +-
>  target/mips/translate.c              |   2 +
>  target/mips/translate_init.inc.c     |  86 ++++
>  14 files changed, 1092 insertions(+), 4 deletions(-)
>  create mode 100644 hw/mips/common.c
>  create mode 100644 hw/mips/loongson3.c
> --
> 2.7.0


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

* Re: [PATCH for-5.1 V4 0/7] mips: Add Loongson-3 machine support (with KVM)
  2020-06-05  8:38 ` [PATCH for-5.1 V4 0/7] mips: Add Loongson-3 machine support (with KVM) Aleksandar Markovic
@ 2020-06-05  8:40   ` Aleksandar Markovic
  2020-06-05  9:05   ` Jiaxun Yang
  1 sibling, 0 replies; 41+ messages in thread
From: Aleksandar Markovic @ 2020-06-05  8:40 UTC (permalink / raw)
  To: Huacai Chen, Jiaxun Yang
  Cc: Huacai Chen, Philippe Mathieu-Daudé,
	QEMU Developers, Huacai Chen, Aleksandar Rikalo, Aurelien Jarno

Just adding Jiaxun.

пет, 5. јун 2020. у 10:38 Aleksandar Markovic
<aleksandar.qemu.devel@gmail.com> је написао/ла:
>
> уто, 2. јун 2020. у 04:38 Huacai Chen <zltjiangshi@gmail.com> је написао/ла:
> >
> > Loongson-3 CPU family include Loongson-3A R1/R2/R3/R4 and Loongson-3B
> > R1/R2.
>
> Hi, Huacai,
>
> The documents you kindly provided contain some valuable info on
> Loongson-3A R1/R2/R3/R4 and Loongson-3B R1/R2. However, I
> couldn't find detailed instruction-by-instruction specifications.
>
> In fact, I don't need all the details right now, but some form of
> overview of instructions sets of Loongson-3A R1/R2/R3/R4 and
> Loongson-3B R1/R2. Could you please provide textual description
> (one of two paragraph) of supported instructions for each of these
> models:
>
> * Loongson-3A R1
> * Loongson-3A R2
> * Loongson-3A R3
> * Loongson-3A R4
> * Loongson-3B R1
> * Loongson-3B R2
>
> (what is the base instructuin set; the difference to the previous model;
> what SIMD extension (LMI/MSA) is supported other specifics around
> supported instructions)
>
> Based on your answer I may bring forward some suggestions on the
> improvement of v4 of this series.
>
> Truly yours,
> Aleksandar
>
> > 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.
> >
> > We are preparing to add QEMU's Loongson-3 support. MIPS VZ extension is
> > fully supported in Loongson-3A R4+, so we at first add QEMU/KVM support
> > in this series. And the next series will add QEMU/TCG support (it will
> > emulate Loongson-3A R1).
> >
> > We already have a full functional Linux kernel (based on Linux-5.4.x LTS
> > but not upstream yet) here:
> >
> > https://github.com/chenhuacai/linux
> >
> > 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;
> > 4, Build QEMU-5.0.0 with this patchset;
> > 5, modprobe kvm;
> > 6, Use QEMU with TCG (available in future):
> >        qemu-system-mips64el -M loongson3,accel=tcg -cpu Loongson-3A1000 -kernel <path_to_kernel> -append ...
> >    Use QEMU with KVM (available at present):
> >        qemu-system-mips64el -M loongson3,accel=kvm -cpu Loongson-3A4000 -kernel <path_to_kernel> -append ...
> >
> >    The "-cpu" parameter can be omitted 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>.
> >
> > Huacai Chen(4):
> >  hw/mips: Implement the kvm_type() hook in MachineClass
> >  target/mips: Add Loongson-3 CPU definition
> >  hw/mips: Add Loongson-3 machine support (with KVM)
> >  MAINTAINERS: Add myself as Loongson-3 maintainer
> >
> > Signed-off-by: Huacai Chen <chenhc@lemote.com>
> > ---
> >  MAINTAINERS                          |   5 +
> >  default-configs/mips64el-softmmu.mak |   1 +
> >  hw/core/Makefile.objs                |   2 +-
> >  hw/core/null-machine.c               |   4 +
> >  hw/mips/Kconfig                      |  10 +
> >  hw/mips/Makefile.objs                |   3 +-
> >  hw/mips/common.c                     |  42 ++
> >  hw/mips/loongson3.c                  | 901 +++++++++++++++++++++++++++++++++++
> >  include/hw/mips/mips.h               |   3 +
> >  target/mips/cpu.h                    |  28 ++
> >  target/mips/internal.h               |   2 +
> >  target/mips/mips-defs.h              |   7 +-
> >  target/mips/translate.c              |   2 +
> >  target/mips/translate_init.inc.c     |  86 ++++
> >  14 files changed, 1092 insertions(+), 4 deletions(-)
> >  create mode 100644 hw/mips/common.c
> >  create mode 100644 hw/mips/loongson3.c
> > --
> > 2.7.0


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

* Re: [PATCH for-5.1 V4 0/7] mips: Add Loongson-3 machine support (with KVM)
  2020-06-05  8:38 ` [PATCH for-5.1 V4 0/7] mips: Add Loongson-3 machine support (with KVM) Aleksandar Markovic
  2020-06-05  8:40   ` Aleksandar Markovic
@ 2020-06-05  9:05   ` Jiaxun Yang
  2020-06-05  9:21     ` Huacai Chen
  2020-06-05  9:27     ` Aleksandar Markovic
  1 sibling, 2 replies; 41+ messages in thread
From: Jiaxun Yang @ 2020-06-05  9:05 UTC (permalink / raw)
  To: Aleksandar Markovic
  Cc: Huacai Chen, Huacai Chen,
	Philippe =?GB18030?B?TWF0aGlldS1EYXVkqKY=?=,
	QEMU Developers, Huacai Chen, Aleksandar Rikalo, Aurelien Jarno

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=GB18030, Size: 2808 bytes --]

On Fri, 5 Jun 2020 10:38:36 +0200
Aleksandar Markovic <aleksandar.qemu.devel@gmail.com> wrote:

> §å§ä§à, 2. 0Ó6§å§ß 2020. §å 04:38 Huacai Chen <zltjiangshi@gmail.com> 0Ó6§Ö
> §ß§Ñ§á§Ú§ã§Ñ§à/§Ý§Ñ:
> >
> > Loongson-3 CPU family include Loongson-3A R1/R2/R3/R4 and
> > Loongson-3B R1/R2.  
> 
> Hi, Huacai,
> 
> The documents you kindly provided contain some valuable info on
> Loongson-3A R1/R2/R3/R4 and Loongson-3B R1/R2. However, I
> couldn't find detailed instruction-by-instruction specifications.
> 
> In fact, I don't need all the details right now, but some form of
> overview of instructions sets of Loongson-3A R1/R2/R3/R4 and
> Loongson-3B R1/R2. Could you please provide textual description
> (one of two paragraph) of supported instructions for each of these
> models:
> 

Hi Aleksandar,

I'm going to explain this according to the names of vendor specified
ASEs name in GCC & Binutils.

There are some instruction that not covered by public documents, that's
out of our scope so I'm not going to talk them.

Firstly, there are some ASEs not being upstreamed yet:
 - Loongson-AMO (Atomic Opreations, Looks like RISC-V)
 - Loongson-EXT3 (Loongson Extention 3)
 - Loongson-CSR (Core Status Registers, instructions to read some
   private core register, including something called "stable-counter"
   (TSC like timer) and CPUCFG(something like cpuid in x86))

 - MIPS-MSA-Ctypto (Including AES, SHA, MD5 stuff)
 - MIPS MSA2 (256-bit MSA instructions)

And there is a ASE that only being used in kernel so not even being
mentioned in toolchain.
 - Loongson-SPW (LWPTE, LDPTE used to help with pagetable walking)

ALl these processors have mips64r2 as baseline.

> * Loongson-3A R1
Loongson-MMI, Loongson-EXT

> * Loongson-3A R2
Loongson-MMI, Loongson-EXT, Looongson-EXT2, Loongson-SPW, DSP, DSPr2

> * Loongson-3A R3
Same as R2. This revision mainly focus on bugfix and improve clock
speed.

> * Loongson-3A R4
Loongson-MMI, Loongson-EXT, Looongson-EXT2, Loongson-SPW, Loongson-AMO,
Loongson-EXT3, Loongson-CSR, MSA Crypto, MSA2

This processor even support hardware unaligned accessing.

> * Loongson-3B R1
> * Loongson-3B R2
Loongson-3B R1 and R2 are mostly identical with Loongson-3A R1, the
difference is it have 8-cores in a package. It was designed for HPC so
there are some domain specific SIMD instructions, but they're not
available to public.

And a new family member of Loongson64:
Loongson-2K (R1):
Loongson-MMI, Loongson-EXT, Looongson-EXT2, MSA.

> 
> (what is the base instructuin set; the difference to the previous
> model; what SIMD extension (LMI/MSA) is supported other specifics
> around supported instructions)
> 
> Based on your answer I may bring forward some suggestions on the
> improvement of v4 of this series.
> 
> Truly yours,
> Aleksandar
> 

Thank a lot.

- Jiaxun


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

* Re: [PATCH for-5.1 V4 0/7] mips: Add Loongson-3 machine support (with KVM)
  2020-06-05  9:05   ` Jiaxun Yang
@ 2020-06-05  9:21     ` Huacai Chen
  2020-06-05  9:27     ` Aleksandar Markovic
  1 sibling, 0 replies; 41+ messages in thread
From: Huacai Chen @ 2020-06-05  9:21 UTC (permalink / raw)
  To: Jiaxun Yang
  Cc: Huacai Chen, Philippe Mathieu-Daudé,
	QEMU Developers, Aleksandar Markovic, Aleksandar Rikalo,
	Aurelien Jarno

Hi, Jiaxun,

On Fri, Jun 5, 2020 at 5:06 PM Jiaxun Yang <jiaxun.yang@flygoat.com> wrote:
>
> On Fri, 5 Jun 2020 10:38:36 +0200
> Aleksandar Markovic <aleksandar.qemu.devel@gmail.com> wrote:
>
> > уто, 2. јун 2020. у 04:38 Huacai Chen <zltjiangshi@gmail.com> је
> > написао/ла:
> > >
> > > Loongson-3 CPU family include Loongson-3A R1/R2/R3/R4 and
> > > Loongson-3B R1/R2.
> >
> > Hi, Huacai,
> >
> > The documents you kindly provided contain some valuable info on
> > Loongson-3A R1/R2/R3/R4 and Loongson-3B R1/R2. However, I
> > couldn't find detailed instruction-by-instruction specifications.
> >
> > In fact, I don't need all the details right now, but some form of
> > overview of instructions sets of Loongson-3A R1/R2/R3/R4 and
> > Loongson-3B R1/R2. Could you please provide textual description
> > (one of two paragraph) of supported instructions for each of these
> > models:
> >
>
> Hi Aleksandar,
>
> I'm going to explain this according to the names of vendor specified
> ASEs name in GCC & Binutils.
>
> There are some instruction that not covered by public documents, that's
> out of our scope so I'm not going to talk them.
>
> Firstly, there are some ASEs not being upstreamed yet:
>  - Loongson-AMO (Atomic Opreations, Looks like RISC-V)
>  - Loongson-EXT3 (Loongson Extention 3)
>  - Loongson-CSR (Core Status Registers, instructions to read some
>    private core register, including something called "stable-counter"
>    (TSC like timer) and CPUCFG(something like cpuid in x86))
Core Status Registers  shoud be  Configuration Status Register

>
>  - MIPS-MSA-Ctypto (Including AES, SHA, MD5 stuff)
>  - MIPS MSA2 (256-bit MSA instructions)
>
> And there is a ASE that only being used in kernel so not even being
> mentioned in toolchain.
>  - Loongson-SPW (LWPTE, LDPTE used to help with pagetable walking)
>
> ALl these processors have mips64r2 as baseline.
>
> > * Loongson-3A R1
> Loongson-MMI, Loongson-EXT
>
> > * Loongson-3A R2
> Loongson-MMI, Loongson-EXT, Looongson-EXT2, Loongson-SPW, DSP, DSPr2
>
> > * Loongson-3A R3
> Same as R2. This revision mainly focus on bugfix and improve clock
> speed.
>
> > * Loongson-3A R4
> Loongson-MMI, Loongson-EXT, Looongson-EXT2, Loongson-SPW, Loongson-AMO,
> Loongson-EXT3, Loongson-CSR, MSA Crypto, MSA2
>
> This processor even support hardware unaligned accessing.
>
> > * Loongson-3B R1
> > * Loongson-3B R2
> Loongson-3B R1 and R2 are mostly identical with Loongson-3A R1, the
> difference is it have 8-cores in a package. It was designed for HPC so
> there are some domain specific SIMD instructions, but they're not
> available to public.
>
> And a new family member of Loongson64:
> Loongson-2K (R1):
> Loongson-MMI, Loongson-EXT, Looongson-EXT2, MSA.
>
> >
> > (what is the base instructuin set; the difference to the previous
> > model; what SIMD extension (LMI/MSA) is supported other specifics
> > around supported instructions)
> >
> > Based on your answer I may bring forward some suggestions on the
> > improvement of v4 of this series.
> >
> > Truly yours,
> > Aleksandar
> >
>
> Thank a lot.
>
> - Jiaxun


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

* Re: [PATCH for-5.1 V4 0/7] mips: Add Loongson-3 machine support (with KVM)
  2020-06-05  9:05   ` Jiaxun Yang
  2020-06-05  9:21     ` Huacai Chen
@ 2020-06-05  9:27     ` Aleksandar Markovic
  1 sibling, 0 replies; 41+ messages in thread
From: Aleksandar Markovic @ 2020-06-05  9:27 UTC (permalink / raw)
  To: Jiaxun Yang
  Cc: chen huacai, Huacai Chen, Philippe Mathieu-Daudé,
	QEMU Developers, Huacai Chen, Aleksandar Rikalo, Aurelien Jarno

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

11:06 Pet, 05.06.2020. Jiaxun Yang <jiaxun.yang@flygoat.com> је написао/ла:
>
> On Fri, 5 Jun 2020 10:38:36 +0200
> Aleksandar Markovic <aleksandar.qemu.devel@gmail.com> wrote:
>
> > уто, 2. јун 2020. у 04:38 Huacai Chen <zltjiangshi@gmail.com> је
> > написао/ла:
> > >
> > > Loongson-3 CPU family include Loongson-3A R1/R2/R3/R4 and
> > > Loongson-3B R1/R2.
> >
> > Hi, Huacai,
> >
> > The documents you kindly provided contain some valuable info on
> > Loongson-3A R1/R2/R3/R4 and Loongson-3B R1/R2. However, I
> > couldn't find detailed instruction-by-instruction specifications.
> >
> > In fact, I don't need all the details right now, but some form of
> > overview of instructions sets of Loongson-3A R1/R2/R3/R4 and
> > Loongson-3B R1/R2. Could you please provide textual description
> > (one of two paragraph) of supported instructions for each of these
> > models:
> >
>
> Hi Aleksandar,
>
> I'm going to explain this according to the names of vendor specified
> ASEs name in GCC & Binutils.
>
> There are some instruction that not covered by public documents, that's
> out of our scope so I'm not going to talk them.
>
> Firstly, there are some ASEs not being upstreamed yet:
>  - Loongson-AMO (Atomic Opreations, Looks like RISC-V)
>  - Loongson-EXT3 (Loongson Extention 3)
>  - Loongson-CSR (Core Status Registers, instructions to read some
>    private core register, including something called "stable-counter"
>    (TSC like timer) and CPUCFG(something like cpuid in x86))
>
>  - MIPS-MSA-Ctypto (Including AES, SHA, MD5 stuff)
>  - MIPS MSA2 (256-bit MSA instructions)
>
> And there is a ASE that only being used in kernel so not even being
> mentioned in toolchain.
>  - Loongson-SPW (LWPTE, LDPTE used to help with pagetable walking)
>
> ALl these processors have mips64r2 as baseline.
>
> > * Loongson-3A R1
> Loongson-MMI, Loongson-EXT
>
> > * Loongson-3A R2
> Loongson-MMI, Loongson-EXT, Looongson-EXT2, Loongson-SPW, DSP, DSPr2
>
> > * Loongson-3A R3
> Same as R2. This revision mainly focus on bugfix and improve clock
> speed.
>
> > * Loongson-3A R4
> Loongson-MMI, Loongson-EXT, Looongson-EXT2, Loongson-SPW, Loongson-AMO,
> Loongson-EXT3, Loongson-CSR, MSA Crypto, MSA2
>
> This processor even support hardware unaligned accessing.
>
> > * Loongson-3B R1
> > * Loongson-3B R2
> Loongson-3B R1 and R2 are mostly identical with Loongson-3A R1, the
> difference is it have 8-cores in a package. It was designed for HPC so
> there are some domain specific SIMD instructions, but they're not
> available to public.
>
> And a new family member of Loongson64:
> Loongson-2K (R1):
> Loongson-MMI, Loongson-EXT, Looongson-EXT2, MSA.
>

Thanks for your detailed response, Juaxun.

I will think over the weekend about the new aspects you mentioned here. All
this is valuable info for long-term planning. But also in short-term - for
this very series. Expect my answer early next week.

Best Regards and Best Health!

Aleksandar


> >
> > (what is the base instructuin set; the difference to the previous
> > model; what SIMD extension (LMI/MSA) is supported other specifics
> > around supported instructions)
> >
> > Based on your answer I may bring forward some suggestions on the
> > improvement of v4 of this series.
> >
> > Truly yours,
> > Aleksandar
> >
>
> Thank a lot.
>
> - Jiaxun

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

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

* Re: [PATCH for-5.1 V4 2/4] target/mips: Add Loongson-3 CPU definition
  2020-06-02  2:39 ` [PATCH for-5.1 V4 2/4] target/mips: Add Loongson-3 CPU definition Huacai Chen
@ 2020-06-06  7:30   ` Aleksandar Markovic
  0 siblings, 0 replies; 41+ messages in thread
From: Aleksandar Markovic @ 2020-06-06  7:30 UTC (permalink / raw)
  To: Huacai Chen
  Cc: Huacai Chen, Philippe Mathieu-Daudé,
	Jiaxun Yang, QEMU Developers, Huacai Chen, Aleksandar Rikalo,
	Aurelien Jarno

уто, 2. јун 2020. у 04:39 Huacai Chen <zltjiangshi@gmail.com> је написао/ла:
>
> 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, 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-3A has CONFIG6 and CONFIG7, so add their bit-fields as well.
>
> Signed-off-by: Huacai Chen <chenhc@lemote.com>
> Co-developed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> ---

In yesterday's discussion we discussed Loongson-3A R1/R2/R3/R4 and
Loongson-3B R1/R2 base instruction set and extensions. They all should
have their place in insn_flags. However, this is not crucial for KVM
functionality covered in this series, and could be done later on,
independently.

In other words, this should not stop this series from integrating to upstream.

So:

Reviewed-by: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>

>  target/mips/cpu.h                | 28 +++++++++++++
>  target/mips/internal.h           |  2 +
>  target/mips/mips-defs.h          |  7 +++-
>  target/mips/translate.c          |  2 +
>  target/mips/translate_init.inc.c | 86 ++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 123 insertions(+), 2 deletions(-)
>
> diff --git a/target/mips/cpu.h b/target/mips/cpu.h
> index 94d01ea..0b3c987 100644
> --- a/target/mips/cpu.h
> +++ b/target/mips/cpu.h
> @@ -940,7 +940,35 @@ struct CPUMIPSState {
>  #define CP0C5_UFR          2
>  #define CP0C5_NFExists     0
>      int32_t CP0_Config6;
> +    int32_t CP0_Config6_rw_bitmask;
> +#define CP0C6_BPPASS          31
> +#define CP0C6_KPOS            24
> +#define CP0C6_KE              23
> +#define CP0C6_VTLBONLY        22
> +#define CP0C6_LASX            21
> +#define CP0C6_SSEN            20
> +#define CP0C6_DISDRTIME       19
> +#define CP0C6_PIXNUEN         18
> +#define CP0C6_SCRAND          17
> +#define CP0C6_LLEXCEN         16
> +#define CP0C6_DISVC           15
> +#define CP0C6_VCLRU           14
> +#define CP0C6_DCLRU           13
> +#define CP0C6_PIXUEN          12
> +#define CP0C6_DISBLKLYEN      11
> +#define CP0C6_UMEMUALEN       10
> +#define CP0C6_SFBEN           8
> +#define CP0C6_FLTINT          7
> +#define CP0C6_VLTINT          6
> +#define CP0C6_DISBTB          5
> +#define CP0C6_STPREFCTL       2
> +#define CP0C6_INSTPREF        1
> +#define CP0C6_DATAPREF        0
>      int32_t CP0_Config7;
> +    int64_t CP0_Config7_rw_bitmask;
> +#define CP0C7_NAPCGEN       2
> +#define CP0C7_UNIMUEN       1
> +#define CP0C7_VFPUCGEN      0
>      uint64_t CP0_LLAddr;
>      uint64_t CP0_MAAR[MIPS_MAAR_MAX];
>      int32_t CP0_MAARI;
> diff --git a/target/mips/internal.h b/target/mips/internal.h
> index 1bf274b..7853cb1 100644
> --- a/target/mips/internal.h
> +++ b/target/mips/internal.h
> @@ -36,7 +36,9 @@ struct mips_def_t {
>      int32_t CP0_Config5;
>      int32_t CP0_Config5_rw_bitmask;
>      int32_t CP0_Config6;
> +    int32_t CP0_Config6_rw_bitmask;
>      int32_t CP0_Config7;
> +    int32_t CP0_Config7_rw_bitmask;
>      target_ulong CP0_LLAddr_rw_bitmask;
>      int CP0_LLAddr_shift;
>      int32_t SYNCI_Step;
> diff --git a/target/mips/mips-defs.h b/target/mips/mips-defs.h
> index a831bb4..c2c96db 100644
> --- a/target/mips/mips-defs.h
> +++ b/target/mips/mips-defs.h
> @@ -51,8 +51,9 @@
>   */
>  #define INSN_LOONGSON2E   0x0001000000000000ULL
>  #define INSN_LOONGSON2F   0x0002000000000000ULL
> -#define INSN_VR54XX       0x0004000000000000ULL
> -#define INSN_R5900        0x0008000000000000ULL
> +#define INSN_LOONGSON3A   0x0004000000000000ULL
> +#define INSN_VR54XX       0x0008000000000000ULL
> +#define INSN_R5900        0x0010000000000000ULL
>  /*
>   *   bits 56-63: vendor-specific ASEs
>   */
> @@ -94,6 +95,8 @@
>  /* Wave Computing: "nanoMIPS" */
>  #define CPU_NANOMIPS32  (CPU_MIPS32R6 | ISA_NANOMIPS32)
>
> +#define CPU_LOONGSON3A  (CPU_MIPS64R2 | INSN_LOONGSON3A)
> +
>  /*
>   * Strictly follow the architecture standard:
>   * - Disallow "special" instruction handling for PMON/SPIM.
> diff --git a/target/mips/translate.c b/target/mips/translate.c
> index 25b595a..2caf4cb 100644
> --- a/target/mips/translate.c
> +++ b/target/mips/translate.c
> @@ -31206,7 +31206,9 @@ void cpu_state_reset(CPUMIPSState *env)
>      env->CP0_Config5 = env->cpu_model->CP0_Config5;
>      env->CP0_Config5_rw_bitmask = env->cpu_model->CP0_Config5_rw_bitmask;
>      env->CP0_Config6 = env->cpu_model->CP0_Config6;
> +    env->CP0_Config6_rw_bitmask = env->cpu_model->CP0_Config6_rw_bitmask;
>      env->CP0_Config7 = env->cpu_model->CP0_Config7;
> +    env->CP0_Config7_rw_bitmask = env->cpu_model->CP0_Config7_rw_bitmask;
>      env->CP0_LLAddr_rw_bitmask = env->cpu_model->CP0_LLAddr_rw_bitmask
>                                   << env->cpu_model->CP0_LLAddr_shift;
>      env->CP0_LLAddr_shift = env->cpu_model->CP0_LLAddr_shift;
> diff --git a/target/mips/translate_init.inc.c b/target/mips/translate_init.inc.c
> index 6d145a9..a31f229 100644
> --- a/target/mips/translate_init.inc.c
> +++ b/target/mips/translate_init.inc.c
> @@ -802,6 +802,92 @@ const mips_def_t mips_defs[] =
>          .mmu_type = MMU_TYPE_R4000,
>      },
>      {
> +        .name = "Loongson-3A1000",
> +        .CP0_PRid = 0x6305,
> +        /* 64KB I-cache and d-cache. 4 way with 32 bit cache line size.  */
> +        .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) | (0x2 << CP0C0_AT) |
> +                       (MMU_TYPE_R4000 << CP0C0_MT),
> +        .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (63 << CP0C1_MMU) |
> +                       (3 << CP0C1_IS) | (4 << CP0C1_IL) | (3 << CP0C1_IA) |
> +                       (3 << CP0C1_DS) | (4 << CP0C1_DL) | (3 << CP0C1_DA) |
> +                       (1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP),
> +        .CP0_Config2 = MIPS_CONFIG2 | (7 << CP0C2_SS) | (4 << CP0C2_SL) |
> +                       (3 << CP0C2_SA),
> +        .CP0_Config3 = MIPS_CONFIG3 | (1 << CP0C3_LPA),
> +        .CP0_LLAddr_rw_bitmask = 0,
> +        .SYNCI_Step = 32,
> +        .CCRes = 2,
> +        .CP0_Status_rw_bitmask = 0x74D8FFFF,
> +        .CP0_PageGrain = (1 << CP0PG_ELPA),
> +        .CP0_PageGrain_rw_bitmask = (1 << CP0PG_ELPA),
> +        .CP1_fcr0 = (0x5 << FCR0_PRID) | (0x1 << FCR0_REV) | (0x1 << FCR0_F64) |
> +                    (0x1 << FCR0_PS) | (0x1 << FCR0_L) | (0x1 << FCR0_W) |
> +                    (0x1 << FCR0_D) | (0x1 << FCR0_S),
> +        .CP1_fcr31 = 0,
> +        .CP1_fcr31_rw_bitmask = 0xFF83FFFF,
> +        .SEGBITS = 42,
> +        .PABITS = 48,
> +        .insn_flags = CPU_LOONGSON3A,
> +        .mmu_type = MMU_TYPE_R4000,
> +    },
> +    {
> +        .name = "Loongson-3A4000",
> +        .CP0_PRid = 0x14C000,
> +        /* 64KB I-cache and d-cache. 4 way with 32 bit cache line size.  */
> +        .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR) | (0x2 << CP0C0_AT) |
> +                       (MMU_TYPE_R4000 << CP0C0_MT),
> +        .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (63 << CP0C1_MMU) |
> +                       (2 << CP0C1_IS) | (5 << CP0C1_IL) | (3 << CP0C1_IA) |
> +                       (2 << CP0C1_DS) | (5 << CP0C1_DL) | (3 << CP0C1_DA) |
> +                       (1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP),
> +        .CP0_Config2 = MIPS_CONFIG2 | (5 << CP0C2_SS) | (5 << CP0C2_SL) |
> +                       (15 << CP0C2_SA),
> +        .CP0_Config3 = MIPS_CONFIG3 | (1U << CP0C3_M) | (1 << CP0C3_MSAP) |
> +                       (1 << CP0C3_BP) | (1 << CP0C3_BI) | (1 << CP0C3_ULRI) |
> +                       (1 << CP0C3_RXI) | (1 << CP0C3_LPA) | (1 << CP0C3_VInt),
> +        .CP0_Config4 = MIPS_CONFIG4 | (1U << CP0C4_M) | (2 << CP0C4_IE) |
> +                       (1 << CP0C4_AE) | (0x1c << CP0C4_KScrExist),
> +        .CP0_Config4_rw_bitmask = 0,
> +        .CP0_Config5 = MIPS_CONFIG5 | (1 << CP0C5_CRCP) | (1 << CP0C5_NFExists),
> +        .CP0_Config5_rw_bitmask = (1 << CP0C5_K) | (1 << CP0C5_CV) |
> +                                  (1 << CP0C5_MSAEn) | (1 << CP0C5_UFE) |
> +                                  (1 << CP0C5_FRE) | (1 << CP0C5_SBRI),
> +        .CP0_Config6 = (1 << CP0C6_VCLRU) | (1 << CP0C6_DCLRU) |
> +                       (1 << CP0C6_SFBEN) | (1 << CP0C6_VLTINT) |
> +                       (1 << CP0C6_INSTPREF) | (1 << CP0C6_DATAPREF),
> +        .CP0_Config6_rw_bitmask = (1 << CP0C6_BPPASS) | (0x3f << CP0C6_KPOS) |
> +                                  (1 << CP0C6_KE) | (1 << CP0C6_VTLBONLY) |
> +                                  (1 << CP0C6_LASX) | (1 << CP0C6_SSEN) |
> +                                  (1 << CP0C6_DISDRTIME) | (1 << CP0C6_PIXNUEN) |
> +                                  (1 << CP0C6_SCRAND) | (1 << CP0C6_LLEXCEN) |
> +                                  (1 << CP0C6_DISVC) | (1 << CP0C6_VCLRU) |
> +                                  (1 << CP0C6_DCLRU) | (1 << CP0C6_PIXUEN) |
> +                                  (1 << CP0C6_DISBLKLYEN) | (1 << CP0C6_UMEMUALEN) |
> +                                  (1 << CP0C6_SFBEN) | (1 << CP0C6_FLTINT) |
> +                                  (1 << CP0C6_VLTINT) | (1 << CP0C6_DISBTB) |
> +                                  (3 << CP0C6_STPREFCTL) | (1 << CP0C6_INSTPREF) |
> +                                  (1 << CP0C6_DATAPREF),
> +        .CP0_Config7 = 0,
> +        .CP0_Config7_rw_bitmask = (1 << CP0C7_NAPCGEN) | (1 << CP0C7_UNIMUEN) |
> +                                  (1 << CP0C7_VFPUCGEN),
> +        .CP0_LLAddr_rw_bitmask = 1,
> +        .SYNCI_Step = 16,
> +        .CCRes = 2,
> +        .CP0_Status_rw_bitmask = 0x7DDBFFFF,
> +        .CP0_PageGrain = (1 << CP0PG_ELPA),
> +        .CP0_PageGrain_rw_bitmask = (1U << CP0PG_RIE) | (1 << CP0PG_XIE) |
> +                    (1 << CP0PG_ELPA) | (1 << CP0PG_IEC),
> +        .CP1_fcr0 = (0x5 << FCR0_PRID) | (0x1 << FCR0_REV) | (0x1 << FCR0_F64) |
> +                    (0x1 << FCR0_PS) | (0x1 << FCR0_L) | (0x1 << FCR0_W) |
> +                    (0x1 << FCR0_D) | (0x1 << FCR0_S),
> +        .CP1_fcr31 = 0,
> +        .CP1_fcr31_rw_bitmask = 0xFF83FFFF,
> +        .SEGBITS = 48,
> +        .PABITS = 48,
> +        .insn_flags = CPU_LOONGSON3A,
> +        .mmu_type = MMU_TYPE_R4000,
> +    },
> +    {
>          /* A generic CPU providing MIPS64 DSP R2 ASE features.
>             FIXME: Eventually this should be replaced by a real CPU model. */
>          .name = "mips64dspr2",
> --
> 2.7.0
>


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

* Re: [PATCH for-5.1 V4 3/4] hw/mips: Add Loongson-3 machine support (with KVM)
  2020-06-02  2:39 ` [PATCH for-5.1 V4 3/4] hw/mips: Add Loongson-3 machine support (with KVM) Huacai Chen
@ 2020-06-06  7:32   ` Aleksandar Markovic
  2020-06-06  8:01     ` Aleksandar Markovic
  2020-06-11  5:58   ` Jiaxun Yang
  2020-06-14  7:51   ` Aleksandar Markovic
  2 siblings, 1 reply; 41+ messages in thread
From: Aleksandar Markovic @ 2020-06-06  7:32 UTC (permalink / raw)
  To: Huacai Chen, Jiaxun Yang
  Cc: Huacai Chen, Philippe Mathieu-Daudé,
	QEMU Developers, Huacai Chen, Aleksandar Rikalo, Aurelien Jarno

уто, 2. јун 2020. у 04:40 Huacai Chen <zltjiangshi@gmail.com> је написао/ла:
>
> Add Loongson-3 based machine support, it use i8259 as the interrupt
> controler and use GPEX as the pci controller. Currently it can only
> work with KVM, but we will add TCG support in future.
>
> We already have a full functional Linux kernel (based on Linux-5.4.x LTS
> but not upstream yet) here:
>
> https://github.com/chenhuacai/linux
>
> 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 the a Loongson-3A4000 host with this kernel;
> 4, Build QEMU-5.0.0 with this patchset;
> 5, modprobe kvm;
> 6, Use QEMU with TCG (available in future):
>        qemu-system-mips64el -M loongson3,accel=tcg -cpu Loongson-3A1000 -kernel <path_to_kernel> -append ...
>    Use QEMU with KVM (available at present):
>        qemu-system-mips64el -M loongson3,accel=kvm -cpu Loongson-3A4000 -kernel <path_to_kernel> -append ...
>
>    The "-cpu" parameter can be omitted 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>
> ---

Reviewed-by: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>

>  default-configs/mips64el-softmmu.mak |   1 +
>  hw/mips/Kconfig                      |  10 +
>  hw/mips/Makefile.objs                |   1 +
>  hw/mips/loongson3.c                  | 901 +++++++++++++++++++++++++++++++++++
>  4 files changed, 913 insertions(+)
>  create mode 100644 hw/mips/loongson3.c
>
> diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak
> index 9f8a3ef..2a2a3fb 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_LOONGSON3=y
>  CONFIG_ATI_VGA=y
>  CONFIG_RTL8139_PCI=y
>  CONFIG_JAZZ=y
> diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig
> index 67d39c5..42931fd 100644
> --- a/hw/mips/Kconfig
> +++ b/hw/mips/Kconfig
> @@ -45,6 +45,16 @@ config FULOONG
>      bool
>      select PCI_BONITO
>
> +config LOONGSON3
> +    bool
> +    select PCKBD
> +    select SERIAL
> +    select ISA_BUS
> +    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/Makefile.objs b/hw/mips/Makefile.objs
> index 3b3e6ea..31dedcb 100644
> --- a/hw/mips/Makefile.objs
> +++ b/hw/mips/Makefile.objs
> @@ -4,5 +4,6 @@ obj-$(CONFIG_MALTA) += gt64xxx_pci.o malta.o
>  obj-$(CONFIG_MIPSSIM) += mipssim.o
>  obj-$(CONFIG_JAZZ) += jazz.o
>  obj-$(CONFIG_FULOONG) += fuloong2e.o
> +obj-$(CONFIG_LOONGSON3) += loongson3.o
>  obj-$(CONFIG_MIPS_CPS) += cps.o
>  obj-$(CONFIG_MIPS_BOSTON) += boston.o
> diff --git a/hw/mips/loongson3.c b/hw/mips/loongson3.c
> new file mode 100644
> index 0000000..e4b9538
> --- /dev/null
> +++ b/hw/mips/loongson3.c
> @@ -0,0 +1,901 @@
> +/*
> + * Generic Loongson-3 Platform support
> + *
> + * Copyright (c) 2016-2020 Huacai Chen (chenhc@lemote.com)
> + * This code is licensed under the GNU GPL v2.
> + *
> + * Contributions are licensed under the terms of the GNU GPL,
> + * version 2 or (at your option) any later version.
> + */
> +
> +/*
> + * Generic 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 "hw/boards.h"
> +#include "hw/char/serial.h"
> +#include "hw/mips/mips.h"
> +#include "hw/mips/cpudevs.h"
> +#include "hw/intc/i8259.h"
> +#include "hw/loader.h"
> +#include "hw/ide.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 "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 INITRD_OFFSET         0x04000000
> +#define BOOTPARAM_ADDR        0x8ff00000
> +#define BOOTPARAM_PHYADDR     0x0ff00000
> +#define CFG_ADDR              0x0f100000
> +#define FW_CONF_ADDR          0x0fff0000
> +#define PM_MMIO_ADDR          0x10080000
> +#define PM_MMIO_SIZE          0x100
> +#define PM_CNTL_MODE          0x10
> +
> +#define PHYS_TO_VIRT(x) ((x) | ~(target_ulong)0x7fffffff)
> +
> +/* Loongson-3 has a 2MB flash rom */
> +#define BIOS_SIZE               (2 * MiB)
> +#define LOONGSON_MAX_VCPUS      16
> +
> +#define LOONGSON3_BIOSNAME "bios_loongson3.bin"
> +
> +#define PCIE_IRQ_BASE       3
> +
> +#define VIRT_PCI_IO_BASE    0x18000000ul
> +#define VIRT_PCI_IO_SIZE    0x000c0000ul
> +#define VIRT_PCI_MEM_BASE   0x40000000ul
> +#define VIRT_PCI_MEM_SIZE   0x40000000ul
> +#define VIRT_PCI_ECAM_BASE  0x1a000000ul
> +#define VIRT_PCI_ECAM_SIZE  0x02000000ul
> +
> +#define align(x) (((x) + 63) & ~63)
> +
> +/* 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;
> +};
> +
> +static struct _fw_config {
> +    unsigned long ram_size;
> +    unsigned int mem_freq;
> +    unsigned int nr_cpus;
> +    unsigned int cpu_clock_freq;
> +} fw_config;
> +
> +static struct _loaderparams {
> +    unsigned long ram_size;
> +    const char *kernel_cmdline;
> +    const char *kernel_filename;
> +    const char *initrd_filename;
> +    int64_t kernel_entry;
> +    unsigned long a0, a1, a2;
> +} loaderparams;
> +
> +static void *boot_params_p;
> +static void *boot_params_buf;
> +
> +static unsigned int bios_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                                                      */
> +};
> +
> +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 = (loaderparams.ram_size > 0x10000000
> +                            ? 256 : (loaderparams.ram_size >> 20)) - 16;
> +
> +    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 > 0x10000000
> +                            ? (loaderparams.ram_size >> 20) - 256 : 0);
> +
> +    return emap;
> +}
> +
> +static int get_host_cpu_freq(void)
> +{
> +    int fd = 0, freq = 0;
> +    char buf[1024], *buf_p;
> +
> +    fd = open("/proc/cpuinfo", O_RDONLY);
> +    if (fd == -1) {
> +        fprintf(stderr, "Failed to open /proc/cpuinfo!\n");
> +        return 0;
> +    }
> +
> +    if (read(fd, buf, 1024) < 0) {
> +        close(fd);
> +        fprintf(stderr, "Failed to read /proc/cpuinfo!\n");
> +        return 0;
> +    }
> +    close(fd);
> +
> +    buf_p = strstr(buf, "model name");
> +    while (*buf_p != '@') {
> +        buf_p++;
> +    }
> +
> +    buf_p += 2;
> +    memcpy(buf, buf_p, 12);
> +    buf_p = buf;
> +    while ((*buf_p >= '0') && (*buf_p <= '9')) {
> +        buf_p++;
> +    }
> +    *buf_p = '\0';
> +
> +    freq = atoi(buf);
> +
> +    return freq * 1000 * 1000;
> +}
> +
> +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 = 0x14C000;
> +    c->cpu_clock_freq = get_host_cpu_freq();
> +    if (!c->cpu_clock_freq) {
> +        c->cpu_clock_freq = 500000000;
> +    }
> +
> +    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;
> +    s->uarts[0].uart_base = 0x1fe001e0;
> +
> +    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_PCI_MEM_BASE;
> +    irq_info->pci_mem_end_addr   = VIRT_PCI_MEM_BASE + VIRT_PCI_MEM_SIZE - 1;
> +    irq_info->pci_io_start_addr  = VIRT_PCI_IO_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, "2016-05-16");
> +
> +    return special;
> +}
> +
> +static void init_loongson_params(struct loongson_params *lp)
> +{
> +    void *p = boot_params_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));
> +
> +    boot_params_p = p;
> +}
> +
> +static void init_smbios(struct smbios_tables *smbios)
> +{
> +    smbios->vers = 1;
> +    init_loongson_params(&(smbios->lp));
> +}
> +
> +static void init_efi(struct efi_loongson *efi)
> +{
> +    init_smbios(&(efi->smbios));
> +}
> +
> +static void init_reset_system(struct efi_reset_system_t *reset)
> +{
> +    reset->Shutdown = 0xffffffffbfc000a8;
> +    reset->ResetCold = 0xffffffffbfc00080;
> +    reset->ResetWarm = 0xffffffffbfc00080;
> +}
> +
> +static int init_boot_param(struct boot_params *bp)
> +{
> +    init_efi(&(bp->efi));
> +    init_reset_system(&(bp->reset_system));
> +
> +    return 0;
> +}
> +
> +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;
> +
> +    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);
> +    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
> +
> +    fw_config.ram_size = ram_size;
> +    fw_config.mem_freq = 300000000;
> +    fw_config.nr_cpus = current_machine->smp.cpus;
> +    fw_config.cpu_clock_freq = get_host_cpu_freq();
> +}
> +
> +static int set_prom_bootparam(ram_addr_t initrd_offset, long initrd_size)
> +{
> +    long params_size;
> +    char memenv[32];
> +    char highmemenv[32];
> +    void *params_buf;
> +    unsigned int *parg_env;
> +    int ret = 0;
> +
> +    /* Allocate params_buf for command line. */
> +    params_size = 0x100000;
> +    params_buf = g_malloc0(params_size);
> +
> +    /*
> +     * Layout of params_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 *)params_buf;
> +
> +    ret = (3 + 1) * 4;
> +    *parg_env++ = (BOOTPARAM_ADDR + ret);
> +    ret += (1 + snprintf(params_buf + ret, 256 - ret, "g"));
> +
> +    /* argv1 */
> +    *parg_env++ = BOOTPARAM_ADDR + ret;
> +    if (initrd_size > 0)
> +        ret += (1 + snprintf(params_buf + ret, 256 - ret,
> +                "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s",
> +                PHYS_TO_VIRT((uint32_t)initrd_offset),
> +                initrd_size, loaderparams.kernel_cmdline));
> +    else
> +        ret += (1 + snprintf(params_buf + ret, 256 - ret, "%s",
> +                loaderparams.kernel_cmdline));
> +
> +    /* argv2 */
> +    *parg_env++ = BOOTPARAM_ADDR + 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);
> +
> +    setenv("memsize", memenv, 1);
> +    setenv("highmemsize", highmemenv, 1);
> +
> +    ret = ((ret + 32) & ~31);
> +
> +    boot_params_buf = (void *)(params_buf + ret);
> +    boot_params_p = boot_params_buf + align(sizeof(struct boot_params));
> +
> +    init_boot_param(boot_params_buf);
> +
> +    rom_add_blob_fixed("params", params_buf, params_size,
> +                       BOOTPARAM_PHYADDR);
> +    loaderparams.a0 = 2;
> +    loaderparams.a1 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR;
> +    loaderparams.a2 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR + ret;
> +
> +    return 0;
> +}
> +
> +static int64_t load_kernel(CPUMIPSState *env)
> +{
> +    long kernel_size;
> +    ram_addr_t initrd_offset;
> +    int64_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, INITRD_OFFSET);
> +
> +            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 parameters. */
> +    set_prom_bootparam(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 void loongson3_isa_init(qemu_irq intc)
> +{
> +    qemu_irq *i8259;
> +    ISABus *isa_bus;
> +
> +    isa_bus = isa_bus_new(NULL, get_system_memory(), get_system_io(), &error_abort);
> +
> +    /* Interrupt controller */
> +    /* The 8259 -> IP3  */
> +    i8259 = i8259_init(isa_bus, intc);
> +    isa_bus_irqs(isa_bus, i8259);
> +    /* init other devices */
> +    isa_create_simple(isa_bus, "i8042");
> +    mc146818_rtc_init(isa_bus, 2000, NULL);
> +}
> +
> +static inline void loongson3_pcie_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_create(NULL, TYPE_GPEX_HOST);
> +
> +    qdev_init_nofail(dev);
> +    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_PCI_ECAM_SIZE);
> +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_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_PCI_MEM_BASE, VIRT_PCI_MEM_SIZE);
> +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_MEM_BASE, mmio_alias);
> +
> +    pio_alias = g_new0(MemoryRegion, 1);
> +    memory_region_init_alias(pio_alias, OBJECT(dev), "pcie-pio",
> +                             get_system_io(), 0, VIRT_PCI_IO_SIZE);
> +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_IO_BASE, pio_alias);
> +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, VIRT_PCI_IO_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);
> +
> +    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_init(MachineState *machine)
> +{
> +    int i;
> +    long bios_size;
> +    MIPSCPU *cpu;
> +    CPUMIPSState *env;
> +    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);
> +
> +    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 < 256 * 0x100000) {
> +        error_report("Loongson-3 need at least 256MB memory");
> +        exit(1);
> +    }
> +
> +    for (i = 0; i < machine->smp.cpus; i++) {
> +        /* 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);
> +    }
> +    env = &MIPS_CPU(first_cpu)->env;
> +
> +    /* Allocate RAM/BIOS, 0x00000000~0x10000000 is alias of 0x80000000~0x90000000 */
> +    memory_region_init_rom(bios, NULL, "loongson3.bios",
> +                           BIOS_SIZE, &error_fatal);
> +    memory_region_init_alias(ram, NULL, "loongson3.lowram",
> +                           machine->ram, 0, 256 * 0x100000);
> +    memory_region_init_io(iomem, NULL, &loongson3_pm_ops,
> +                           NULL, "loongson3_pm", PM_MMIO_SIZE);
> +
> +    memory_region_add_subregion(address_space_mem, 0x00000000LL, ram);
> +    memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios);
> +    memory_region_add_subregion(address_space_mem, 0x80000000LL, machine->ram);
> +    memory_region_add_subregion(address_space_mem, PM_MMIO_ADDR, iomem);
> +
> +    /*
> +     * We do not support flash operation, just loading pmon.bin as raw BIOS.
> +     * Please use -L to set the BIOS path and -bios to set bios name.
> +     */
> +
> +    if (kernel_filename) {
> +        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);
> +        rom_add_blob_fixed("bios",
> +                         bios_boot_code, sizeof(bios_boot_code), 0x1fc00000LL);
> +    } 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, 0x1fc00000LL,
> +                                            BIOS_SIZE);
> +            g_free(filename);
> +        } else {
> +            bios_size = -1;
> +        }
> +
> +        if ((bios_size < 0 || bios_size > BIOS_SIZE) &&
> +            !kernel_filename && !qtest_enabled()) {
> +            error_report("Could not load MIPS bios '%s'", bios_name);
> +            exit(1);
> +        }
> +
> +        fw_conf_init(ram_size);
> +        rom_add_blob_fixed("fw_conf",
> +                         &fw_config, sizeof(fw_config), FW_CONF_ADDR);
> +    }
> +
> +    msi_nonbroken = true;
> +    loongson3_isa_init(env->irq[3]);
> +    loongson3_pcie_init(machine, isa_pic);
> +
> +    if (serial_hd(0)) {
> +        serial_mm_init(address_space_mem, 0x1fe001e0, 0, env->irq[2],
> +                           115200, serial_hd(0), DEVICE_NATIVE_ENDIAN);
> +    }
> +}
> +
> +static void mips_loongson3_machine_init(MachineClass *mc)
> +{
> +    mc->desc = "Generic Loongson-3 Platform";
> +    mc->init = mips_loongson3_init;
> +    mc->block_default_type = IF_IDE;
> +    mc->max_cpus = LOONGSON_MAX_VCPUS;
> +    mc->default_ram_id = "loongson3.highram";
> +    mc->default_ram_size = 1200 * MiB;
> +    mc->kvm_type = mips_kvm_type;
> +    mc->minimum_page_bits = 14;
> +}
> +
> +DEFINE_MACHINE("loongson3", mips_loongson3_machine_init)
> --
> 2.7.0
>


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

* Re: [PATCH for-5.1 V4 3/4] hw/mips: Add Loongson-3 machine support (with KVM)
  2020-06-06  7:32   ` Aleksandar Markovic
@ 2020-06-06  8:01     ` Aleksandar Markovic
  2020-06-07  1:12       ` chen huacai
  0 siblings, 1 reply; 41+ messages in thread
From: Aleksandar Markovic @ 2020-06-06  8:01 UTC (permalink / raw)
  To: Huacai Chen, Jiaxun Yang
  Cc: Huacai Chen, Philippe Mathieu-Daudé,
	QEMU Developers, Huacai Chen, Aleksandar Rikalo, Aurelien Jarno

суб, 6. јун 2020. у 09:32 Aleksandar Markovic
<aleksandar.qemu.devel@gmail.com> је написао/ла:
>
> уто, 2. јун 2020. у 04:40 Huacai Chen <zltjiangshi@gmail.com> је написао/ла:
> >
> > Add Loongson-3 based machine support, it use i8259 as the interrupt
> > controler and use GPEX as the pci controller. Currently it can only
> > work with KVM, but we will add TCG support in future.
> >
> > We already have a full functional Linux kernel (based on Linux-5.4.x LTS
> > but not upstream yet) here:
> >
> > https://github.com/chenhuacai/linux
> >
> > 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 the a Loongson-3A4000 host with this kernel;
> > 4, Build QEMU-5.0.0 with this patchset;
> > 5, modprobe kvm;
> > 6, Use QEMU with TCG (available in future):
> >        qemu-system-mips64el -M loongson3,accel=tcg -cpu Loongson-3A1000 -kernel <path_to_kernel> -append ...
> >    Use QEMU with KVM (available at present):
> >        qemu-system-mips64el -M loongson3,accel=kvm -cpu Loongson-3A4000 -kernel <path_to_kernel> -append ...
> >
> >    The "-cpu" parameter can be omitted 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>
> > ---
>
> Reviewed-by: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
>

Just the license preamble should be harmonized with the template we use for
QEMU for MIPS. It is the same license you mention in this patch - GPL 2.0 or
(at option) later, just in extended wording form.

There is no need for respin, I will do it by myself while applying.

Best Regards,
Aleksandar
> >  default-configs/mips64el-softmmu.mak |   1 +
> >  hw/mips/Kconfig                      |  10 +
> >  hw/mips/Makefile.objs                |   1 +
> >  hw/mips/loongson3.c                  | 901 +++++++++++++++++++++++++++++++++++
> >  4 files changed, 913 insertions(+)
> >  create mode 100644 hw/mips/loongson3.c
> >
> > diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak
> > index 9f8a3ef..2a2a3fb 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_LOONGSON3=y
> >  CONFIG_ATI_VGA=y
> >  CONFIG_RTL8139_PCI=y
> >  CONFIG_JAZZ=y
> > diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig
> > index 67d39c5..42931fd 100644
> > --- a/hw/mips/Kconfig
> > +++ b/hw/mips/Kconfig
> > @@ -45,6 +45,16 @@ config FULOONG
> >      bool
> >      select PCI_BONITO
> >
> > +config LOONGSON3
> > +    bool
> > +    select PCKBD
> > +    select SERIAL
> > +    select ISA_BUS
> > +    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/Makefile.objs b/hw/mips/Makefile.objs
> > index 3b3e6ea..31dedcb 100644
> > --- a/hw/mips/Makefile.objs
> > +++ b/hw/mips/Makefile.objs
> > @@ -4,5 +4,6 @@ obj-$(CONFIG_MALTA) += gt64xxx_pci.o malta.o
> >  obj-$(CONFIG_MIPSSIM) += mipssim.o
> >  obj-$(CONFIG_JAZZ) += jazz.o
> >  obj-$(CONFIG_FULOONG) += fuloong2e.o
> > +obj-$(CONFIG_LOONGSON3) += loongson3.o
> >  obj-$(CONFIG_MIPS_CPS) += cps.o
> >  obj-$(CONFIG_MIPS_BOSTON) += boston.o
> > diff --git a/hw/mips/loongson3.c b/hw/mips/loongson3.c
> > new file mode 100644
> > index 0000000..e4b9538
> > --- /dev/null
> > +++ b/hw/mips/loongson3.c
> > @@ -0,0 +1,901 @@
> > +/*
> > + * Generic Loongson-3 Platform support
> > + *
> > + * Copyright (c) 2016-2020 Huacai Chen (chenhc@lemote.com)
> > + * This code is licensed under the GNU GPL v2.
> > + *
> > + * Contributions are licensed under the terms of the GNU GPL,
> > + * version 2 or (at your option) any later version.
> > + */
> > +
> > +/*
> > + * Generic 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 "hw/boards.h"
> > +#include "hw/char/serial.h"
> > +#include "hw/mips/mips.h"
> > +#include "hw/mips/cpudevs.h"
> > +#include "hw/intc/i8259.h"
> > +#include "hw/loader.h"
> > +#include "hw/ide.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 "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 INITRD_OFFSET         0x04000000
> > +#define BOOTPARAM_ADDR        0x8ff00000
> > +#define BOOTPARAM_PHYADDR     0x0ff00000
> > +#define CFG_ADDR              0x0f100000
> > +#define FW_CONF_ADDR          0x0fff0000
> > +#define PM_MMIO_ADDR          0x10080000
> > +#define PM_MMIO_SIZE          0x100
> > +#define PM_CNTL_MODE          0x10
> > +
> > +#define PHYS_TO_VIRT(x) ((x) | ~(target_ulong)0x7fffffff)
> > +
> > +/* Loongson-3 has a 2MB flash rom */
> > +#define BIOS_SIZE               (2 * MiB)
> > +#define LOONGSON_MAX_VCPUS      16
> > +
> > +#define LOONGSON3_BIOSNAME "bios_loongson3.bin"
> > +
> > +#define PCIE_IRQ_BASE       3
> > +
> > +#define VIRT_PCI_IO_BASE    0x18000000ul
> > +#define VIRT_PCI_IO_SIZE    0x000c0000ul
> > +#define VIRT_PCI_MEM_BASE   0x40000000ul
> > +#define VIRT_PCI_MEM_SIZE   0x40000000ul
> > +#define VIRT_PCI_ECAM_BASE  0x1a000000ul
> > +#define VIRT_PCI_ECAM_SIZE  0x02000000ul
> > +
> > +#define align(x) (((x) + 63) & ~63)
> > +
> > +/* 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;
> > +};
> > +
> > +static struct _fw_config {
> > +    unsigned long ram_size;
> > +    unsigned int mem_freq;
> > +    unsigned int nr_cpus;
> > +    unsigned int cpu_clock_freq;
> > +} fw_config;
> > +
> > +static struct _loaderparams {
> > +    unsigned long ram_size;
> > +    const char *kernel_cmdline;
> > +    const char *kernel_filename;
> > +    const char *initrd_filename;
> > +    int64_t kernel_entry;
> > +    unsigned long a0, a1, a2;
> > +} loaderparams;
> > +
> > +static void *boot_params_p;
> > +static void *boot_params_buf;
> > +
> > +static unsigned int bios_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                                                      */
> > +};
> > +
> > +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 = (loaderparams.ram_size > 0x10000000
> > +                            ? 256 : (loaderparams.ram_size >> 20)) - 16;
> > +
> > +    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 > 0x10000000
> > +                            ? (loaderparams.ram_size >> 20) - 256 : 0);
> > +
> > +    return emap;
> > +}
> > +
> > +static int get_host_cpu_freq(void)
> > +{
> > +    int fd = 0, freq = 0;
> > +    char buf[1024], *buf_p;
> > +
> > +    fd = open("/proc/cpuinfo", O_RDONLY);
> > +    if (fd == -1) {
> > +        fprintf(stderr, "Failed to open /proc/cpuinfo!\n");
> > +        return 0;
> > +    }
> > +
> > +    if (read(fd, buf, 1024) < 0) {
> > +        close(fd);
> > +        fprintf(stderr, "Failed to read /proc/cpuinfo!\n");
> > +        return 0;
> > +    }
> > +    close(fd);
> > +
> > +    buf_p = strstr(buf, "model name");
> > +    while (*buf_p != '@') {
> > +        buf_p++;
> > +    }
> > +
> > +    buf_p += 2;
> > +    memcpy(buf, buf_p, 12);
> > +    buf_p = buf;
> > +    while ((*buf_p >= '0') && (*buf_p <= '9')) {
> > +        buf_p++;
> > +    }
> > +    *buf_p = '\0';
> > +
> > +    freq = atoi(buf);
> > +
> > +    return freq * 1000 * 1000;
> > +}
> > +
> > +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 = 0x14C000;
> > +    c->cpu_clock_freq = get_host_cpu_freq();
> > +    if (!c->cpu_clock_freq) {
> > +        c->cpu_clock_freq = 500000000;
> > +    }
> > +
> > +    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;
> > +    s->uarts[0].uart_base = 0x1fe001e0;
> > +
> > +    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_PCI_MEM_BASE;
> > +    irq_info->pci_mem_end_addr   = VIRT_PCI_MEM_BASE + VIRT_PCI_MEM_SIZE - 1;
> > +    irq_info->pci_io_start_addr  = VIRT_PCI_IO_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, "2016-05-16");
> > +
> > +    return special;
> > +}
> > +
> > +static void init_loongson_params(struct loongson_params *lp)
> > +{
> > +    void *p = boot_params_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));
> > +
> > +    boot_params_p = p;
> > +}
> > +
> > +static void init_smbios(struct smbios_tables *smbios)
> > +{
> > +    smbios->vers = 1;
> > +    init_loongson_params(&(smbios->lp));
> > +}
> > +
> > +static void init_efi(struct efi_loongson *efi)
> > +{
> > +    init_smbios(&(efi->smbios));
> > +}
> > +
> > +static void init_reset_system(struct efi_reset_system_t *reset)
> > +{
> > +    reset->Shutdown = 0xffffffffbfc000a8;
> > +    reset->ResetCold = 0xffffffffbfc00080;
> > +    reset->ResetWarm = 0xffffffffbfc00080;
> > +}
> > +
> > +static int init_boot_param(struct boot_params *bp)
> > +{
> > +    init_efi(&(bp->efi));
> > +    init_reset_system(&(bp->reset_system));
> > +
> > +    return 0;
> > +}
> > +
> > +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;
> > +
> > +    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);
> > +    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
> > +
> > +    fw_config.ram_size = ram_size;
> > +    fw_config.mem_freq = 300000000;
> > +    fw_config.nr_cpus = current_machine->smp.cpus;
> > +    fw_config.cpu_clock_freq = get_host_cpu_freq();
> > +}
> > +
> > +static int set_prom_bootparam(ram_addr_t initrd_offset, long initrd_size)
> > +{
> > +    long params_size;
> > +    char memenv[32];
> > +    char highmemenv[32];
> > +    void *params_buf;
> > +    unsigned int *parg_env;
> > +    int ret = 0;
> > +
> > +    /* Allocate params_buf for command line. */
> > +    params_size = 0x100000;
> > +    params_buf = g_malloc0(params_size);
> > +
> > +    /*
> > +     * Layout of params_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 *)params_buf;
> > +
> > +    ret = (3 + 1) * 4;
> > +    *parg_env++ = (BOOTPARAM_ADDR + ret);
> > +    ret += (1 + snprintf(params_buf + ret, 256 - ret, "g"));
> > +
> > +    /* argv1 */
> > +    *parg_env++ = BOOTPARAM_ADDR + ret;
> > +    if (initrd_size > 0)
> > +        ret += (1 + snprintf(params_buf + ret, 256 - ret,
> > +                "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s",
> > +                PHYS_TO_VIRT((uint32_t)initrd_offset),
> > +                initrd_size, loaderparams.kernel_cmdline));
> > +    else
> > +        ret += (1 + snprintf(params_buf + ret, 256 - ret, "%s",
> > +                loaderparams.kernel_cmdline));
> > +
> > +    /* argv2 */
> > +    *parg_env++ = BOOTPARAM_ADDR + 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);
> > +
> > +    setenv("memsize", memenv, 1);
> > +    setenv("highmemsize", highmemenv, 1);
> > +
> > +    ret = ((ret + 32) & ~31);
> > +
> > +    boot_params_buf = (void *)(params_buf + ret);
> > +    boot_params_p = boot_params_buf + align(sizeof(struct boot_params));
> > +
> > +    init_boot_param(boot_params_buf);
> > +
> > +    rom_add_blob_fixed("params", params_buf, params_size,
> > +                       BOOTPARAM_PHYADDR);
> > +    loaderparams.a0 = 2;
> > +    loaderparams.a1 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR;
> > +    loaderparams.a2 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR + ret;
> > +
> > +    return 0;
> > +}
> > +
> > +static int64_t load_kernel(CPUMIPSState *env)
> > +{
> > +    long kernel_size;
> > +    ram_addr_t initrd_offset;
> > +    int64_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, INITRD_OFFSET);
> > +
> > +            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 parameters. */
> > +    set_prom_bootparam(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 void loongson3_isa_init(qemu_irq intc)
> > +{
> > +    qemu_irq *i8259;
> > +    ISABus *isa_bus;
> > +
> > +    isa_bus = isa_bus_new(NULL, get_system_memory(), get_system_io(), &error_abort);
> > +
> > +    /* Interrupt controller */
> > +    /* The 8259 -> IP3  */
> > +    i8259 = i8259_init(isa_bus, intc);
> > +    isa_bus_irqs(isa_bus, i8259);
> > +    /* init other devices */
> > +    isa_create_simple(isa_bus, "i8042");
> > +    mc146818_rtc_init(isa_bus, 2000, NULL);
> > +}
> > +
> > +static inline void loongson3_pcie_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_create(NULL, TYPE_GPEX_HOST);
> > +
> > +    qdev_init_nofail(dev);
> > +    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_PCI_ECAM_SIZE);
> > +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_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_PCI_MEM_BASE, VIRT_PCI_MEM_SIZE);
> > +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_MEM_BASE, mmio_alias);
> > +
> > +    pio_alias = g_new0(MemoryRegion, 1);
> > +    memory_region_init_alias(pio_alias, OBJECT(dev), "pcie-pio",
> > +                             get_system_io(), 0, VIRT_PCI_IO_SIZE);
> > +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_IO_BASE, pio_alias);
> > +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, VIRT_PCI_IO_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);
> > +
> > +    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_init(MachineState *machine)
> > +{
> > +    int i;
> > +    long bios_size;
> > +    MIPSCPU *cpu;
> > +    CPUMIPSState *env;
> > +    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);
> > +
> > +    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 < 256 * 0x100000) {
> > +        error_report("Loongson-3 need at least 256MB memory");
> > +        exit(1);
> > +    }
> > +
> > +    for (i = 0; i < machine->smp.cpus; i++) {
> > +        /* 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);
> > +    }
> > +    env = &MIPS_CPU(first_cpu)->env;
> > +
> > +    /* Allocate RAM/BIOS, 0x00000000~0x10000000 is alias of 0x80000000~0x90000000 */
> > +    memory_region_init_rom(bios, NULL, "loongson3.bios",
> > +                           BIOS_SIZE, &error_fatal);
> > +    memory_region_init_alias(ram, NULL, "loongson3.lowram",
> > +                           machine->ram, 0, 256 * 0x100000);
> > +    memory_region_init_io(iomem, NULL, &loongson3_pm_ops,
> > +                           NULL, "loongson3_pm", PM_MMIO_SIZE);
> > +
> > +    memory_region_add_subregion(address_space_mem, 0x00000000LL, ram);
> > +    memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios);
> > +    memory_region_add_subregion(address_space_mem, 0x80000000LL, machine->ram);
> > +    memory_region_add_subregion(address_space_mem, PM_MMIO_ADDR, iomem);
> > +
> > +    /*
> > +     * We do not support flash operation, just loading pmon.bin as raw BIOS.
> > +     * Please use -L to set the BIOS path and -bios to set bios name.
> > +     */
> > +
> > +    if (kernel_filename) {
> > +        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);
> > +        rom_add_blob_fixed("bios",
> > +                         bios_boot_code, sizeof(bios_boot_code), 0x1fc00000LL);
> > +    } 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, 0x1fc00000LL,
> > +                                            BIOS_SIZE);
> > +            g_free(filename);
> > +        } else {
> > +            bios_size = -1;
> > +        }
> > +
> > +        if ((bios_size < 0 || bios_size > BIOS_SIZE) &&
> > +            !kernel_filename && !qtest_enabled()) {
> > +            error_report("Could not load MIPS bios '%s'", bios_name);
> > +            exit(1);
> > +        }
> > +
> > +        fw_conf_init(ram_size);
> > +        rom_add_blob_fixed("fw_conf",
> > +                         &fw_config, sizeof(fw_config), FW_CONF_ADDR);
> > +    }
> > +
> > +    msi_nonbroken = true;
> > +    loongson3_isa_init(env->irq[3]);
> > +    loongson3_pcie_init(machine, isa_pic);
> > +
> > +    if (serial_hd(0)) {
> > +        serial_mm_init(address_space_mem, 0x1fe001e0, 0, env->irq[2],
> > +                           115200, serial_hd(0), DEVICE_NATIVE_ENDIAN);
> > +    }
> > +}
> > +
> > +static void mips_loongson3_machine_init(MachineClass *mc)
> > +{
> > +    mc->desc = "Generic Loongson-3 Platform";
> > +    mc->init = mips_loongson3_init;
> > +    mc->block_default_type = IF_IDE;
> > +    mc->max_cpus = LOONGSON_MAX_VCPUS;
> > +    mc->default_ram_id = "loongson3.highram";
> > +    mc->default_ram_size = 1200 * MiB;
> > +    mc->kvm_type = mips_kvm_type;
> > +    mc->minimum_page_bits = 14;
> > +}
> > +
> > +DEFINE_MACHINE("loongson3", mips_loongson3_machine_init)
> > --
> > 2.7.0
> >


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

* Re: [PATCH for-5.1 V4 3/4] hw/mips: Add Loongson-3 machine support (with KVM)
  2020-06-06  8:01     ` Aleksandar Markovic
@ 2020-06-07  1:12       ` chen huacai
  2020-06-07 20:00         ` Aleksandar Markovic
  0 siblings, 1 reply; 41+ messages in thread
From: chen huacai @ 2020-06-07  1:12 UTC (permalink / raw)
  To: Aleksandar Markovic
  Cc: Huacai Chen, Philippe Mathieu-Daudé,
	Jiaxun Yang, QEMU Developers, Huacai Chen, Aleksandar Rikalo,
	Aurelien Jarno

On Sat, Jun 6, 2020 at 4:01 AM Aleksandar Markovic
<aleksandar.qemu.devel@gmail.com> wrote:
>
> суб, 6. јун 2020. у 09:32 Aleksandar Markovic
> <aleksandar.qemu.devel@gmail.com> је написао/ла:
> >
> > уто, 2. јун 2020. у 04:40 Huacai Chen <zltjiangshi@gmail.com> је написао/ла:
> > >
> > > Add Loongson-3 based machine support, it use i8259 as the interrupt
> > > controler and use GPEX as the pci controller. Currently it can only
> > > work with KVM, but we will add TCG support in future.
> > >
> > > We already have a full functional Linux kernel (based on Linux-5.4.x LTS
> > > but not upstream yet) here:
> > >
> > > https://github.com/chenhuacai/linux
> > >
> > > 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 the a Loongson-3A4000 host with this kernel;
> > > 4, Build QEMU-5.0.0 with this patchset;
> > > 5, modprobe kvm;
> > > 6, Use QEMU with TCG (available in future):
> > >        qemu-system-mips64el -M loongson3,accel=tcg -cpu Loongson-3A1000 -kernel <path_to_kernel> -append ...
> > >    Use QEMU with KVM (available at present):
> > >        qemu-system-mips64el -M loongson3,accel=kvm -cpu Loongson-3A4000 -kernel <path_to_kernel> -append ...
> > >
> > >    The "-cpu" parameter can be omitted 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>
> > > ---
> >
> > Reviewed-by: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
> >
>
> Just the license preamble should be harmonized with the template we use for
> QEMU for MIPS. It is the same license you mention in this patch - GPL 2.0 or
> (at option) later, just in extended wording form.
>
> There is no need for respin, I will do it by myself while applying.
>
> Best Regards,
> Aleksandar

I agree to use GPL v2, thanks.

Huacai

> > >  default-configs/mips64el-softmmu.mak |   1 +
> > >  hw/mips/Kconfig                      |  10 +
> > >  hw/mips/Makefile.objs                |   1 +
> > >  hw/mips/loongson3.c                  | 901 +++++++++++++++++++++++++++++++++++
> > >  4 files changed, 913 insertions(+)
> > >  create mode 100644 hw/mips/loongson3.c
> > >
> > > diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak
> > > index 9f8a3ef..2a2a3fb 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_LOONGSON3=y
> > >  CONFIG_ATI_VGA=y
> > >  CONFIG_RTL8139_PCI=y
> > >  CONFIG_JAZZ=y
> > > diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig
> > > index 67d39c5..42931fd 100644
> > > --- a/hw/mips/Kconfig
> > > +++ b/hw/mips/Kconfig
> > > @@ -45,6 +45,16 @@ config FULOONG
> > >      bool
> > >      select PCI_BONITO
> > >
> > > +config LOONGSON3
> > > +    bool
> > > +    select PCKBD
> > > +    select SERIAL
> > > +    select ISA_BUS
> > > +    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/Makefile.objs b/hw/mips/Makefile.objs
> > > index 3b3e6ea..31dedcb 100644
> > > --- a/hw/mips/Makefile.objs
> > > +++ b/hw/mips/Makefile.objs
> > > @@ -4,5 +4,6 @@ obj-$(CONFIG_MALTA) += gt64xxx_pci.o malta.o
> > >  obj-$(CONFIG_MIPSSIM) += mipssim.o
> > >  obj-$(CONFIG_JAZZ) += jazz.o
> > >  obj-$(CONFIG_FULOONG) += fuloong2e.o
> > > +obj-$(CONFIG_LOONGSON3) += loongson3.o
> > >  obj-$(CONFIG_MIPS_CPS) += cps.o
> > >  obj-$(CONFIG_MIPS_BOSTON) += boston.o
> > > diff --git a/hw/mips/loongson3.c b/hw/mips/loongson3.c
> > > new file mode 100644
> > > index 0000000..e4b9538
> > > --- /dev/null
> > > +++ b/hw/mips/loongson3.c
> > > @@ -0,0 +1,901 @@
> > > +/*
> > > + * Generic Loongson-3 Platform support
> > > + *
> > > + * Copyright (c) 2016-2020 Huacai Chen (chenhc@lemote.com)
> > > + * This code is licensed under the GNU GPL v2.
> > > + *
> > > + * Contributions are licensed under the terms of the GNU GPL,
> > > + * version 2 or (at your option) any later version.
> > > + */
> > > +
> > > +/*
> > > + * Generic 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 "hw/boards.h"
> > > +#include "hw/char/serial.h"
> > > +#include "hw/mips/mips.h"
> > > +#include "hw/mips/cpudevs.h"
> > > +#include "hw/intc/i8259.h"
> > > +#include "hw/loader.h"
> > > +#include "hw/ide.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 "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 INITRD_OFFSET         0x04000000
> > > +#define BOOTPARAM_ADDR        0x8ff00000
> > > +#define BOOTPARAM_PHYADDR     0x0ff00000
> > > +#define CFG_ADDR              0x0f100000
> > > +#define FW_CONF_ADDR          0x0fff0000
> > > +#define PM_MMIO_ADDR          0x10080000
> > > +#define PM_MMIO_SIZE          0x100
> > > +#define PM_CNTL_MODE          0x10
> > > +
> > > +#define PHYS_TO_VIRT(x) ((x) | ~(target_ulong)0x7fffffff)
> > > +
> > > +/* Loongson-3 has a 2MB flash rom */
> > > +#define BIOS_SIZE               (2 * MiB)
> > > +#define LOONGSON_MAX_VCPUS      16
> > > +
> > > +#define LOONGSON3_BIOSNAME "bios_loongson3.bin"
> > > +
> > > +#define PCIE_IRQ_BASE       3
> > > +
> > > +#define VIRT_PCI_IO_BASE    0x18000000ul
> > > +#define VIRT_PCI_IO_SIZE    0x000c0000ul
> > > +#define VIRT_PCI_MEM_BASE   0x40000000ul
> > > +#define VIRT_PCI_MEM_SIZE   0x40000000ul
> > > +#define VIRT_PCI_ECAM_BASE  0x1a000000ul
> > > +#define VIRT_PCI_ECAM_SIZE  0x02000000ul
> > > +
> > > +#define align(x) (((x) + 63) & ~63)
> > > +
> > > +/* 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;
> > > +};
> > > +
> > > +static struct _fw_config {
> > > +    unsigned long ram_size;
> > > +    unsigned int mem_freq;
> > > +    unsigned int nr_cpus;
> > > +    unsigned int cpu_clock_freq;
> > > +} fw_config;
> > > +
> > > +static struct _loaderparams {
> > > +    unsigned long ram_size;
> > > +    const char *kernel_cmdline;
> > > +    const char *kernel_filename;
> > > +    const char *initrd_filename;
> > > +    int64_t kernel_entry;
> > > +    unsigned long a0, a1, a2;
> > > +} loaderparams;
> > > +
> > > +static void *boot_params_p;
> > > +static void *boot_params_buf;
> > > +
> > > +static unsigned int bios_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                                                      */
> > > +};
> > > +
> > > +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 = (loaderparams.ram_size > 0x10000000
> > > +                            ? 256 : (loaderparams.ram_size >> 20)) - 16;
> > > +
> > > +    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 > 0x10000000
> > > +                            ? (loaderparams.ram_size >> 20) - 256 : 0);
> > > +
> > > +    return emap;
> > > +}
> > > +
> > > +static int get_host_cpu_freq(void)
> > > +{
> > > +    int fd = 0, freq = 0;
> > > +    char buf[1024], *buf_p;
> > > +
> > > +    fd = open("/proc/cpuinfo", O_RDONLY);
> > > +    if (fd == -1) {
> > > +        fprintf(stderr, "Failed to open /proc/cpuinfo!\n");
> > > +        return 0;
> > > +    }
> > > +
> > > +    if (read(fd, buf, 1024) < 0) {
> > > +        close(fd);
> > > +        fprintf(stderr, "Failed to read /proc/cpuinfo!\n");
> > > +        return 0;
> > > +    }
> > > +    close(fd);
> > > +
> > > +    buf_p = strstr(buf, "model name");
> > > +    while (*buf_p != '@') {
> > > +        buf_p++;
> > > +    }
> > > +
> > > +    buf_p += 2;
> > > +    memcpy(buf, buf_p, 12);
> > > +    buf_p = buf;
> > > +    while ((*buf_p >= '0') && (*buf_p <= '9')) {
> > > +        buf_p++;
> > > +    }
> > > +    *buf_p = '\0';
> > > +
> > > +    freq = atoi(buf);
> > > +
> > > +    return freq * 1000 * 1000;
> > > +}
> > > +
> > > +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 = 0x14C000;
> > > +    c->cpu_clock_freq = get_host_cpu_freq();
> > > +    if (!c->cpu_clock_freq) {
> > > +        c->cpu_clock_freq = 500000000;
> > > +    }
> > > +
> > > +    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;
> > > +    s->uarts[0].uart_base = 0x1fe001e0;
> > > +
> > > +    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_PCI_MEM_BASE;
> > > +    irq_info->pci_mem_end_addr   = VIRT_PCI_MEM_BASE + VIRT_PCI_MEM_SIZE - 1;
> > > +    irq_info->pci_io_start_addr  = VIRT_PCI_IO_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, "2016-05-16");
> > > +
> > > +    return special;
> > > +}
> > > +
> > > +static void init_loongson_params(struct loongson_params *lp)
> > > +{
> > > +    void *p = boot_params_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));
> > > +
> > > +    boot_params_p = p;
> > > +}
> > > +
> > > +static void init_smbios(struct smbios_tables *smbios)
> > > +{
> > > +    smbios->vers = 1;
> > > +    init_loongson_params(&(smbios->lp));
> > > +}
> > > +
> > > +static void init_efi(struct efi_loongson *efi)
> > > +{
> > > +    init_smbios(&(efi->smbios));
> > > +}
> > > +
> > > +static void init_reset_system(struct efi_reset_system_t *reset)
> > > +{
> > > +    reset->Shutdown = 0xffffffffbfc000a8;
> > > +    reset->ResetCold = 0xffffffffbfc00080;
> > > +    reset->ResetWarm = 0xffffffffbfc00080;
> > > +}
> > > +
> > > +static int init_boot_param(struct boot_params *bp)
> > > +{
> > > +    init_efi(&(bp->efi));
> > > +    init_reset_system(&(bp->reset_system));
> > > +
> > > +    return 0;
> > > +}
> > > +
> > > +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;
> > > +
> > > +    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);
> > > +    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
> > > +
> > > +    fw_config.ram_size = ram_size;
> > > +    fw_config.mem_freq = 300000000;
> > > +    fw_config.nr_cpus = current_machine->smp.cpus;
> > > +    fw_config.cpu_clock_freq = get_host_cpu_freq();
> > > +}
> > > +
> > > +static int set_prom_bootparam(ram_addr_t initrd_offset, long initrd_size)
> > > +{
> > > +    long params_size;
> > > +    char memenv[32];
> > > +    char highmemenv[32];
> > > +    void *params_buf;
> > > +    unsigned int *parg_env;
> > > +    int ret = 0;
> > > +
> > > +    /* Allocate params_buf for command line. */
> > > +    params_size = 0x100000;
> > > +    params_buf = g_malloc0(params_size);
> > > +
> > > +    /*
> > > +     * Layout of params_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 *)params_buf;
> > > +
> > > +    ret = (3 + 1) * 4;
> > > +    *parg_env++ = (BOOTPARAM_ADDR + ret);
> > > +    ret += (1 + snprintf(params_buf + ret, 256 - ret, "g"));
> > > +
> > > +    /* argv1 */
> > > +    *parg_env++ = BOOTPARAM_ADDR + ret;
> > > +    if (initrd_size > 0)
> > > +        ret += (1 + snprintf(params_buf + ret, 256 - ret,
> > > +                "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s",
> > > +                PHYS_TO_VIRT((uint32_t)initrd_offset),
> > > +                initrd_size, loaderparams.kernel_cmdline));
> > > +    else
> > > +        ret += (1 + snprintf(params_buf + ret, 256 - ret, "%s",
> > > +                loaderparams.kernel_cmdline));
> > > +
> > > +    /* argv2 */
> > > +    *parg_env++ = BOOTPARAM_ADDR + 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);
> > > +
> > > +    setenv("memsize", memenv, 1);
> > > +    setenv("highmemsize", highmemenv, 1);
> > > +
> > > +    ret = ((ret + 32) & ~31);
> > > +
> > > +    boot_params_buf = (void *)(params_buf + ret);
> > > +    boot_params_p = boot_params_buf + align(sizeof(struct boot_params));
> > > +
> > > +    init_boot_param(boot_params_buf);
> > > +
> > > +    rom_add_blob_fixed("params", params_buf, params_size,
> > > +                       BOOTPARAM_PHYADDR);
> > > +    loaderparams.a0 = 2;
> > > +    loaderparams.a1 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR;
> > > +    loaderparams.a2 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR + ret;
> > > +
> > > +    return 0;
> > > +}
> > > +
> > > +static int64_t load_kernel(CPUMIPSState *env)
> > > +{
> > > +    long kernel_size;
> > > +    ram_addr_t initrd_offset;
> > > +    int64_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, INITRD_OFFSET);
> > > +
> > > +            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 parameters. */
> > > +    set_prom_bootparam(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 void loongson3_isa_init(qemu_irq intc)
> > > +{
> > > +    qemu_irq *i8259;
> > > +    ISABus *isa_bus;
> > > +
> > > +    isa_bus = isa_bus_new(NULL, get_system_memory(), get_system_io(), &error_abort);
> > > +
> > > +    /* Interrupt controller */
> > > +    /* The 8259 -> IP3  */
> > > +    i8259 = i8259_init(isa_bus, intc);
> > > +    isa_bus_irqs(isa_bus, i8259);
> > > +    /* init other devices */
> > > +    isa_create_simple(isa_bus, "i8042");
> > > +    mc146818_rtc_init(isa_bus, 2000, NULL);
> > > +}
> > > +
> > > +static inline void loongson3_pcie_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_create(NULL, TYPE_GPEX_HOST);
> > > +
> > > +    qdev_init_nofail(dev);
> > > +    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_PCI_ECAM_SIZE);
> > > +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_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_PCI_MEM_BASE, VIRT_PCI_MEM_SIZE);
> > > +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_MEM_BASE, mmio_alias);
> > > +
> > > +    pio_alias = g_new0(MemoryRegion, 1);
> > > +    memory_region_init_alias(pio_alias, OBJECT(dev), "pcie-pio",
> > > +                             get_system_io(), 0, VIRT_PCI_IO_SIZE);
> > > +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_IO_BASE, pio_alias);
> > > +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, VIRT_PCI_IO_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);
> > > +
> > > +    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_init(MachineState *machine)
> > > +{
> > > +    int i;
> > > +    long bios_size;
> > > +    MIPSCPU *cpu;
> > > +    CPUMIPSState *env;
> > > +    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);
> > > +
> > > +    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 < 256 * 0x100000) {
> > > +        error_report("Loongson-3 need at least 256MB memory");
> > > +        exit(1);
> > > +    }
> > > +
> > > +    for (i = 0; i < machine->smp.cpus; i++) {
> > > +        /* 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);
> > > +    }
> > > +    env = &MIPS_CPU(first_cpu)->env;
> > > +
> > > +    /* Allocate RAM/BIOS, 0x00000000~0x10000000 is alias of 0x80000000~0x90000000 */
> > > +    memory_region_init_rom(bios, NULL, "loongson3.bios",
> > > +                           BIOS_SIZE, &error_fatal);
> > > +    memory_region_init_alias(ram, NULL, "loongson3.lowram",
> > > +                           machine->ram, 0, 256 * 0x100000);
> > > +    memory_region_init_io(iomem, NULL, &loongson3_pm_ops,
> > > +                           NULL, "loongson3_pm", PM_MMIO_SIZE);
> > > +
> > > +    memory_region_add_subregion(address_space_mem, 0x00000000LL, ram);
> > > +    memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios);
> > > +    memory_region_add_subregion(address_space_mem, 0x80000000LL, machine->ram);
> > > +    memory_region_add_subregion(address_space_mem, PM_MMIO_ADDR, iomem);
> > > +
> > > +    /*
> > > +     * We do not support flash operation, just loading pmon.bin as raw BIOS.
> > > +     * Please use -L to set the BIOS path and -bios to set bios name.
> > > +     */
> > > +
> > > +    if (kernel_filename) {
> > > +        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);
> > > +        rom_add_blob_fixed("bios",
> > > +                         bios_boot_code, sizeof(bios_boot_code), 0x1fc00000LL);
> > > +    } 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, 0x1fc00000LL,
> > > +                                            BIOS_SIZE);
> > > +            g_free(filename);
> > > +        } else {
> > > +            bios_size = -1;
> > > +        }
> > > +
> > > +        if ((bios_size < 0 || bios_size > BIOS_SIZE) &&
> > > +            !kernel_filename && !qtest_enabled()) {
> > > +            error_report("Could not load MIPS bios '%s'", bios_name);
> > > +            exit(1);
> > > +        }
> > > +
> > > +        fw_conf_init(ram_size);
> > > +        rom_add_blob_fixed("fw_conf",
> > > +                         &fw_config, sizeof(fw_config), FW_CONF_ADDR);
> > > +    }
> > > +
> > > +    msi_nonbroken = true;
> > > +    loongson3_isa_init(env->irq[3]);
> > > +    loongson3_pcie_init(machine, isa_pic);
> > > +
> > > +    if (serial_hd(0)) {
> > > +        serial_mm_init(address_space_mem, 0x1fe001e0, 0, env->irq[2],
> > > +                           115200, serial_hd(0), DEVICE_NATIVE_ENDIAN);
> > > +    }
> > > +}
> > > +
> > > +static void mips_loongson3_machine_init(MachineClass *mc)
> > > +{
> > > +    mc->desc = "Generic Loongson-3 Platform";
> > > +    mc->init = mips_loongson3_init;
> > > +    mc->block_default_type = IF_IDE;
> > > +    mc->max_cpus = LOONGSON_MAX_VCPUS;
> > > +    mc->default_ram_id = "loongson3.highram";
> > > +    mc->default_ram_size = 1200 * MiB;
> > > +    mc->kvm_type = mips_kvm_type;
> > > +    mc->minimum_page_bits = 14;
> > > +}
> > > +
> > > +DEFINE_MACHINE("loongson3", mips_loongson3_machine_init)
> > > --
> > > 2.7.0
> > >



-- 
Huacai Chen


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

* Re: [PATCH for-5.1 V4 3/4] hw/mips: Add Loongson-3 machine support (with KVM)
  2020-06-07  1:12       ` chen huacai
@ 2020-06-07 20:00         ` Aleksandar Markovic
  2020-06-08  3:56           ` Huacai Chen
  0 siblings, 1 reply; 41+ messages in thread
From: Aleksandar Markovic @ 2020-06-07 20:00 UTC (permalink / raw)
  To: chen huacai
  Cc: Huacai Chen, Philippe Mathieu-Daudé,
	Jiaxun Yang, QEMU Developers, Aleksandar Markovic, Huacai Chen,
	Aleksandar Rikalo, Aurelien Jarno

On Sun, Jun 7, 2020 at 3:13 AM chen huacai <zltjiangshi@gmail.com> wrote:
>
> On Sat, Jun 6, 2020 at 4:01 AM Aleksandar Markovic
> <aleksandar.qemu.devel@gmail.com> wrote:
> >
> > суб, 6. јун 2020. у 09:32 Aleksandar Markovic
> > <aleksandar.qemu.devel@gmail.com> је написао/ла:
> > >
> > > уто, 2. јун 2020. у 04:40 Huacai Chen <zltjiangshi@gmail.com> је написао/ла:
> > > >
> > > > Add Loongson-3 based machine support, it use i8259 as the interrupt
> > > > controler and use GPEX as the pci controller. Currently it can only
> > > > work with KVM, but we will add TCG support in future.
> > > >
> > > > We already have a full functional Linux kernel (based on Linux-5.4.x LTS
> > > > but not upstream yet) here:
> > > >
> > > > https://github.com/chenhuacai/linux
> > > >
> > > > 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 the a Loongson-3A4000 host with this kernel;
> > > > 4, Build QEMU-5.0.0 with this patchset;
> > > > 5, modprobe kvm;
> > > > 6, Use QEMU with TCG (available in future):
> > > >        qemu-system-mips64el -M loongson3,accel=tcg -cpu Loongson-3A1000 -kernel <path_to_kernel> -append ...
> > > >    Use QEMU with KVM (available at present):
> > > >        qemu-system-mips64el -M loongson3,accel=kvm -cpu Loongson-3A4000 -kernel <path_to_kernel> -append ...
> > > >
> > > >    The "-cpu" parameter can be omitted 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>
> > > > ---
> > >
> > > Reviewed-by: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
> > >
> >
> > Just the license preamble should be harmonized with the template we use for
> > QEMU for MIPS. It is the same license you mention in this patch - GPL 2.0 or
> > (at option) later, just in extended wording form.
> >
> > There is no need for respin, I will do it by myself while applying.
> >
> > Best Regards,
> > Aleksandar
>
> I agree to use GPL v2, thanks.
>

Hi, Huacai.

Patches 1 and 2 are applied to MIPS queue, while patches 3 and 4 will await
corresponding kernel changes to be upstreamed.

It looks you do not distinguish GPL 2.0 and GPL 2.0+. The latter allows usage
of GPL later than 2.0 (at the option of the user), while the former doesn't.

I don't blame you for that. We are engineers, not lawyers.

I need to ask you again, do you agree with the following license preamble:

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

Regards,
Aleksandar


> Huacai
>
> > > >  default-configs/mips64el-softmmu.mak |   1 +
> > > >  hw/mips/Kconfig                      |  10 +
> > > >  hw/mips/Makefile.objs                |   1 +
> > > >  hw/mips/loongson3.c                  | 901 +++++++++++++++++++++++++++++++++++
> > > >  4 files changed, 913 insertions(+)
> > > >  create mode 100644 hw/mips/loongson3.c
> > > >
> > > > diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak
> > > > index 9f8a3ef..2a2a3fb 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_LOONGSON3=y
> > > >  CONFIG_ATI_VGA=y
> > > >  CONFIG_RTL8139_PCI=y
> > > >  CONFIG_JAZZ=y
> > > > diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig
> > > > index 67d39c5..42931fd 100644
> > > > --- a/hw/mips/Kconfig
> > > > +++ b/hw/mips/Kconfig
> > > > @@ -45,6 +45,16 @@ config FULOONG
> > > >      bool
> > > >      select PCI_BONITO
> > > >
> > > > +config LOONGSON3
> > > > +    bool
> > > > +    select PCKBD
> > > > +    select SERIAL
> > > > +    select ISA_BUS
> > > > +    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/Makefile.objs b/hw/mips/Makefile.objs
> > > > index 3b3e6ea..31dedcb 100644
> > > > --- a/hw/mips/Makefile.objs
> > > > +++ b/hw/mips/Makefile.objs
> > > > @@ -4,5 +4,6 @@ obj-$(CONFIG_MALTA) += gt64xxx_pci.o malta.o
> > > >  obj-$(CONFIG_MIPSSIM) += mipssim.o
> > > >  obj-$(CONFIG_JAZZ) += jazz.o
> > > >  obj-$(CONFIG_FULOONG) += fuloong2e.o
> > > > +obj-$(CONFIG_LOONGSON3) += loongson3.o
> > > >  obj-$(CONFIG_MIPS_CPS) += cps.o
> > > >  obj-$(CONFIG_MIPS_BOSTON) += boston.o
> > > > diff --git a/hw/mips/loongson3.c b/hw/mips/loongson3.c
> > > > new file mode 100644
> > > > index 0000000..e4b9538
> > > > --- /dev/null
> > > > +++ b/hw/mips/loongson3.c
> > > > @@ -0,0 +1,901 @@
> > > > +/*
> > > > + * Generic Loongson-3 Platform support
> > > > + *
> > > > + * Copyright (c) 2016-2020 Huacai Chen (chenhc@lemote.com)
> > > > + * This code is licensed under the GNU GPL v2.
> > > > + *
> > > > + * Contributions are licensed under the terms of the GNU GPL,
> > > > + * version 2 or (at your option) any later version.
> > > > + */
> > > > +
> > > > +/*
> > > > + * Generic 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 "hw/boards.h"
> > > > +#include "hw/char/serial.h"
> > > > +#include "hw/mips/mips.h"
> > > > +#include "hw/mips/cpudevs.h"
> > > > +#include "hw/intc/i8259.h"
> > > > +#include "hw/loader.h"
> > > > +#include "hw/ide.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 "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 INITRD_OFFSET         0x04000000
> > > > +#define BOOTPARAM_ADDR        0x8ff00000
> > > > +#define BOOTPARAM_PHYADDR     0x0ff00000
> > > > +#define CFG_ADDR              0x0f100000
> > > > +#define FW_CONF_ADDR          0x0fff0000
> > > > +#define PM_MMIO_ADDR          0x10080000
> > > > +#define PM_MMIO_SIZE          0x100
> > > > +#define PM_CNTL_MODE          0x10
> > > > +
> > > > +#define PHYS_TO_VIRT(x) ((x) | ~(target_ulong)0x7fffffff)
> > > > +
> > > > +/* Loongson-3 has a 2MB flash rom */
> > > > +#define BIOS_SIZE               (2 * MiB)
> > > > +#define LOONGSON_MAX_VCPUS      16
> > > > +
> > > > +#define LOONGSON3_BIOSNAME "bios_loongson3.bin"
> > > > +
> > > > +#define PCIE_IRQ_BASE       3
> > > > +
> > > > +#define VIRT_PCI_IO_BASE    0x18000000ul
> > > > +#define VIRT_PCI_IO_SIZE    0x000c0000ul
> > > > +#define VIRT_PCI_MEM_BASE   0x40000000ul
> > > > +#define VIRT_PCI_MEM_SIZE   0x40000000ul
> > > > +#define VIRT_PCI_ECAM_BASE  0x1a000000ul
> > > > +#define VIRT_PCI_ECAM_SIZE  0x02000000ul
> > > > +
> > > > +#define align(x) (((x) + 63) & ~63)
> > > > +
> > > > +/* 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;
> > > > +};
> > > > +
> > > > +static struct _fw_config {
> > > > +    unsigned long ram_size;
> > > > +    unsigned int mem_freq;
> > > > +    unsigned int nr_cpus;
> > > > +    unsigned int cpu_clock_freq;
> > > > +} fw_config;
> > > > +
> > > > +static struct _loaderparams {
> > > > +    unsigned long ram_size;
> > > > +    const char *kernel_cmdline;
> > > > +    const char *kernel_filename;
> > > > +    const char *initrd_filename;
> > > > +    int64_t kernel_entry;
> > > > +    unsigned long a0, a1, a2;
> > > > +} loaderparams;
> > > > +
> > > > +static void *boot_params_p;
> > > > +static void *boot_params_buf;
> > > > +
> > > > +static unsigned int bios_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                                                      */
> > > > +};
> > > > +
> > > > +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 = (loaderparams.ram_size > 0x10000000
> > > > +                            ? 256 : (loaderparams.ram_size >> 20)) - 16;
> > > > +
> > > > +    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 > 0x10000000
> > > > +                            ? (loaderparams.ram_size >> 20) - 256 : 0);
> > > > +
> > > > +    return emap;
> > > > +}
> > > > +
> > > > +static int get_host_cpu_freq(void)
> > > > +{
> > > > +    int fd = 0, freq = 0;
> > > > +    char buf[1024], *buf_p;
> > > > +
> > > > +    fd = open("/proc/cpuinfo", O_RDONLY);
> > > > +    if (fd == -1) {
> > > > +        fprintf(stderr, "Failed to open /proc/cpuinfo!\n");
> > > > +        return 0;
> > > > +    }
> > > > +
> > > > +    if (read(fd, buf, 1024) < 0) {
> > > > +        close(fd);
> > > > +        fprintf(stderr, "Failed to read /proc/cpuinfo!\n");
> > > > +        return 0;
> > > > +    }
> > > > +    close(fd);
> > > > +
> > > > +    buf_p = strstr(buf, "model name");
> > > > +    while (*buf_p != '@') {
> > > > +        buf_p++;
> > > > +    }
> > > > +
> > > > +    buf_p += 2;
> > > > +    memcpy(buf, buf_p, 12);
> > > > +    buf_p = buf;
> > > > +    while ((*buf_p >= '0') && (*buf_p <= '9')) {
> > > > +        buf_p++;
> > > > +    }
> > > > +    *buf_p = '\0';
> > > > +
> > > > +    freq = atoi(buf);
> > > > +
> > > > +    return freq * 1000 * 1000;
> > > > +}
> > > > +
> > > > +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 = 0x14C000;
> > > > +    c->cpu_clock_freq = get_host_cpu_freq();
> > > > +    if (!c->cpu_clock_freq) {
> > > > +        c->cpu_clock_freq = 500000000;
> > > > +    }
> > > > +
> > > > +    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;
> > > > +    s->uarts[0].uart_base = 0x1fe001e0;
> > > > +
> > > > +    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_PCI_MEM_BASE;
> > > > +    irq_info->pci_mem_end_addr   = VIRT_PCI_MEM_BASE + VIRT_PCI_MEM_SIZE - 1;
> > > > +    irq_info->pci_io_start_addr  = VIRT_PCI_IO_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, "2016-05-16");
> > > > +
> > > > +    return special;
> > > > +}
> > > > +
> > > > +static void init_loongson_params(struct loongson_params *lp)
> > > > +{
> > > > +    void *p = boot_params_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));
> > > > +
> > > > +    boot_params_p = p;
> > > > +}
> > > > +
> > > > +static void init_smbios(struct smbios_tables *smbios)
> > > > +{
> > > > +    smbios->vers = 1;
> > > > +    init_loongson_params(&(smbios->lp));
> > > > +}
> > > > +
> > > > +static void init_efi(struct efi_loongson *efi)
> > > > +{
> > > > +    init_smbios(&(efi->smbios));
> > > > +}
> > > > +
> > > > +static void init_reset_system(struct efi_reset_system_t *reset)
> > > > +{
> > > > +    reset->Shutdown = 0xffffffffbfc000a8;
> > > > +    reset->ResetCold = 0xffffffffbfc00080;
> > > > +    reset->ResetWarm = 0xffffffffbfc00080;
> > > > +}
> > > > +
> > > > +static int init_boot_param(struct boot_params *bp)
> > > > +{
> > > > +    init_efi(&(bp->efi));
> > > > +    init_reset_system(&(bp->reset_system));
> > > > +
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +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;
> > > > +
> > > > +    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);
> > > > +    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
> > > > +
> > > > +    fw_config.ram_size = ram_size;
> > > > +    fw_config.mem_freq = 300000000;
> > > > +    fw_config.nr_cpus = current_machine->smp.cpus;
> > > > +    fw_config.cpu_clock_freq = get_host_cpu_freq();
> > > > +}
> > > > +
> > > > +static int set_prom_bootparam(ram_addr_t initrd_offset, long initrd_size)
> > > > +{
> > > > +    long params_size;
> > > > +    char memenv[32];
> > > > +    char highmemenv[32];
> > > > +    void *params_buf;
> > > > +    unsigned int *parg_env;
> > > > +    int ret = 0;
> > > > +
> > > > +    /* Allocate params_buf for command line. */
> > > > +    params_size = 0x100000;
> > > > +    params_buf = g_malloc0(params_size);
> > > > +
> > > > +    /*
> > > > +     * Layout of params_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 *)params_buf;
> > > > +
> > > > +    ret = (3 + 1) * 4;
> > > > +    *parg_env++ = (BOOTPARAM_ADDR + ret);
> > > > +    ret += (1 + snprintf(params_buf + ret, 256 - ret, "g"));
> > > > +
> > > > +    /* argv1 */
> > > > +    *parg_env++ = BOOTPARAM_ADDR + ret;
> > > > +    if (initrd_size > 0)
> > > > +        ret += (1 + snprintf(params_buf + ret, 256 - ret,
> > > > +                "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s",
> > > > +                PHYS_TO_VIRT((uint32_t)initrd_offset),
> > > > +                initrd_size, loaderparams.kernel_cmdline));
> > > > +    else
> > > > +        ret += (1 + snprintf(params_buf + ret, 256 - ret, "%s",
> > > > +                loaderparams.kernel_cmdline));
> > > > +
> > > > +    /* argv2 */
> > > > +    *parg_env++ = BOOTPARAM_ADDR + 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);
> > > > +
> > > > +    setenv("memsize", memenv, 1);
> > > > +    setenv("highmemsize", highmemenv, 1);
> > > > +
> > > > +    ret = ((ret + 32) & ~31);
> > > > +
> > > > +    boot_params_buf = (void *)(params_buf + ret);
> > > > +    boot_params_p = boot_params_buf + align(sizeof(struct boot_params));
> > > > +
> > > > +    init_boot_param(boot_params_buf);
> > > > +
> > > > +    rom_add_blob_fixed("params", params_buf, params_size,
> > > > +                       BOOTPARAM_PHYADDR);
> > > > +    loaderparams.a0 = 2;
> > > > +    loaderparams.a1 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR;
> > > > +    loaderparams.a2 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR + ret;
> > > > +
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int64_t load_kernel(CPUMIPSState *env)
> > > > +{
> > > > +    long kernel_size;
> > > > +    ram_addr_t initrd_offset;
> > > > +    int64_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, INITRD_OFFSET);
> > > > +
> > > > +            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 parameters. */
> > > > +    set_prom_bootparam(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 void loongson3_isa_init(qemu_irq intc)
> > > > +{
> > > > +    qemu_irq *i8259;
> > > > +    ISABus *isa_bus;
> > > > +
> > > > +    isa_bus = isa_bus_new(NULL, get_system_memory(), get_system_io(), &error_abort);
> > > > +
> > > > +    /* Interrupt controller */
> > > > +    /* The 8259 -> IP3  */
> > > > +    i8259 = i8259_init(isa_bus, intc);
> > > > +    isa_bus_irqs(isa_bus, i8259);
> > > > +    /* init other devices */
> > > > +    isa_create_simple(isa_bus, "i8042");
> > > > +    mc146818_rtc_init(isa_bus, 2000, NULL);
> > > > +}
> > > > +
> > > > +static inline void loongson3_pcie_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_create(NULL, TYPE_GPEX_HOST);
> > > > +
> > > > +    qdev_init_nofail(dev);
> > > > +    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_PCI_ECAM_SIZE);
> > > > +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_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_PCI_MEM_BASE, VIRT_PCI_MEM_SIZE);
> > > > +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_MEM_BASE, mmio_alias);
> > > > +
> > > > +    pio_alias = g_new0(MemoryRegion, 1);
> > > > +    memory_region_init_alias(pio_alias, OBJECT(dev), "pcie-pio",
> > > > +                             get_system_io(), 0, VIRT_PCI_IO_SIZE);
> > > > +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_IO_BASE, pio_alias);
> > > > +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, VIRT_PCI_IO_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);
> > > > +
> > > > +    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_init(MachineState *machine)
> > > > +{
> > > > +    int i;
> > > > +    long bios_size;
> > > > +    MIPSCPU *cpu;
> > > > +    CPUMIPSState *env;
> > > > +    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);
> > > > +
> > > > +    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 < 256 * 0x100000) {
> > > > +        error_report("Loongson-3 need at least 256MB memory");
> > > > +        exit(1);
> > > > +    }
> > > > +
> > > > +    for (i = 0; i < machine->smp.cpus; i++) {
> > > > +        /* 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);
> > > > +    }
> > > > +    env = &MIPS_CPU(first_cpu)->env;
> > > > +
> > > > +    /* Allocate RAM/BIOS, 0x00000000~0x10000000 is alias of 0x80000000~0x90000000 */
> > > > +    memory_region_init_rom(bios, NULL, "loongson3.bios",
> > > > +                           BIOS_SIZE, &error_fatal);
> > > > +    memory_region_init_alias(ram, NULL, "loongson3.lowram",
> > > > +                           machine->ram, 0, 256 * 0x100000);
> > > > +    memory_region_init_io(iomem, NULL, &loongson3_pm_ops,
> > > > +                           NULL, "loongson3_pm", PM_MMIO_SIZE);
> > > > +
> > > > +    memory_region_add_subregion(address_space_mem, 0x00000000LL, ram);
> > > > +    memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios);
> > > > +    memory_region_add_subregion(address_space_mem, 0x80000000LL, machine->ram);
> > > > +    memory_region_add_subregion(address_space_mem, PM_MMIO_ADDR, iomem);
> > > > +
> > > > +    /*
> > > > +     * We do not support flash operation, just loading pmon.bin as raw BIOS.
> > > > +     * Please use -L to set the BIOS path and -bios to set bios name.
> > > > +     */
> > > > +
> > > > +    if (kernel_filename) {
> > > > +        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);
> > > > +        rom_add_blob_fixed("bios",
> > > > +                         bios_boot_code, sizeof(bios_boot_code), 0x1fc00000LL);
> > > > +    } 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, 0x1fc00000LL,
> > > > +                                            BIOS_SIZE);
> > > > +            g_free(filename);
> > > > +        } else {
> > > > +            bios_size = -1;
> > > > +        }
> > > > +
> > > > +        if ((bios_size < 0 || bios_size > BIOS_SIZE) &&
> > > > +            !kernel_filename && !qtest_enabled()) {
> > > > +            error_report("Could not load MIPS bios '%s'", bios_name);
> > > > +            exit(1);
> > > > +        }
> > > > +
> > > > +        fw_conf_init(ram_size);
> > > > +        rom_add_blob_fixed("fw_conf",
> > > > +                         &fw_config, sizeof(fw_config), FW_CONF_ADDR);
> > > > +    }
> > > > +
> > > > +    msi_nonbroken = true;
> > > > +    loongson3_isa_init(env->irq[3]);
> > > > +    loongson3_pcie_init(machine, isa_pic);
> > > > +
> > > > +    if (serial_hd(0)) {
> > > > +        serial_mm_init(address_space_mem, 0x1fe001e0, 0, env->irq[2],
> > > > +                           115200, serial_hd(0), DEVICE_NATIVE_ENDIAN);
> > > > +    }
> > > > +}
> > > > +
> > > > +static void mips_loongson3_machine_init(MachineClass *mc)
> > > > +{
> > > > +    mc->desc = "Generic Loongson-3 Platform";
> > > > +    mc->init = mips_loongson3_init;
> > > > +    mc->block_default_type = IF_IDE;
> > > > +    mc->max_cpus = LOONGSON_MAX_VCPUS;
> > > > +    mc->default_ram_id = "loongson3.highram";
> > > > +    mc->default_ram_size = 1200 * MiB;
> > > > +    mc->kvm_type = mips_kvm_type;
> > > > +    mc->minimum_page_bits = 14;
> > > > +}
> > > > +
> > > > +DEFINE_MACHINE("loongson3", mips_loongson3_machine_init)
> > > > --
> > > > 2.7.0
> > > >
>
>
>
> --
> Huacai Chen
>


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

* Re: [PATCH for-5.1 V4 3/4] hw/mips: Add Loongson-3 machine support (with KVM)
  2020-06-07 20:00         ` Aleksandar Markovic
@ 2020-06-08  3:56           ` Huacai Chen
  0 siblings, 0 replies; 41+ messages in thread
From: Huacai Chen @ 2020-06-08  3:56 UTC (permalink / raw)
  To: Aleksandar Markovic
  Cc: chen huacai, Philippe Mathieu-Daudé,
	Jiaxun Yang, QEMU Developers, Aleksandar Markovic,
	Aleksandar Rikalo, Aurelien Jarno

Hi, Alexandar,

On Mon, Jun 8, 2020 at 4:00 AM Aleksandar Markovic
<aleksandar.m.mail@gmail.com> wrote:
>
> On Sun, Jun 7, 2020 at 3:13 AM chen huacai <zltjiangshi@gmail.com> wrote:
> >
> > On Sat, Jun 6, 2020 at 4:01 AM Aleksandar Markovic
> > <aleksandar.qemu.devel@gmail.com> wrote:
> > >
> > > суб, 6. јун 2020. у 09:32 Aleksandar Markovic
> > > <aleksandar.qemu.devel@gmail.com> је написао/ла:
> > > >
> > > > уто, 2. јун 2020. у 04:40 Huacai Chen <zltjiangshi@gmail.com> је написао/ла:
> > > > >
> > > > > Add Loongson-3 based machine support, it use i8259 as the interrupt
> > > > > controler and use GPEX as the pci controller. Currently it can only
> > > > > work with KVM, but we will add TCG support in future.
> > > > >
> > > > > We already have a full functional Linux kernel (based on Linux-5.4.x LTS
> > > > > but not upstream yet) here:
> > > > >
> > > > > https://github.com/chenhuacai/linux
> > > > >
> > > > > 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 the a Loongson-3A4000 host with this kernel;
> > > > > 4, Build QEMU-5.0.0 with this patchset;
> > > > > 5, modprobe kvm;
> > > > > 6, Use QEMU with TCG (available in future):
> > > > >        qemu-system-mips64el -M loongson3,accel=tcg -cpu Loongson-3A1000 -kernel <path_to_kernel> -append ...
> > > > >    Use QEMU with KVM (available at present):
> > > > >        qemu-system-mips64el -M loongson3,accel=kvm -cpu Loongson-3A4000 -kernel <path_to_kernel> -append ...
> > > > >
> > > > >    The "-cpu" parameter can be omitted 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>
> > > > > ---
> > > >
> > > > Reviewed-by: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
> > > >
> > >
> > > Just the license preamble should be harmonized with the template we use for
> > > QEMU for MIPS. It is the same license you mention in this patch - GPL 2.0 or
> > > (at option) later, just in extended wording form.
> > >
> > > There is no need for respin, I will do it by myself while applying.
> > >
> > > Best Regards,
> > > Aleksandar
> >
> > I agree to use GPL v2, thanks.
> >
>
> Hi, Huacai.
>
> Patches 1 and 2 are applied to MIPS queue, while patches 3 and 4 will await
> corresponding kernel changes to be upstreamed.
>
> It looks you do not distinguish GPL 2.0 and GPL 2.0+. The latter allows usage
> of GPL later than 2.0 (at the option of the user), while the former doesn't.
>
> I don't blame you for that. We are engineers, not lawyers.
>
> I need to ask you again, do you agree with the following license preamble:
>
>  *  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/>.
>
> Regards,
> Aleksandar
>
Yes, I totally agree to this version of license text.

Huacai
>
> > Huacai
> >
> > > > >  default-configs/mips64el-softmmu.mak |   1 +
> > > > >  hw/mips/Kconfig                      |  10 +
> > > > >  hw/mips/Makefile.objs                |   1 +
> > > > >  hw/mips/loongson3.c                  | 901 +++++++++++++++++++++++++++++++++++
> > > > >  4 files changed, 913 insertions(+)
> > > > >  create mode 100644 hw/mips/loongson3.c
> > > > >
> > > > > diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak
> > > > > index 9f8a3ef..2a2a3fb 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_LOONGSON3=y
> > > > >  CONFIG_ATI_VGA=y
> > > > >  CONFIG_RTL8139_PCI=y
> > > > >  CONFIG_JAZZ=y
> > > > > diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig
> > > > > index 67d39c5..42931fd 100644
> > > > > --- a/hw/mips/Kconfig
> > > > > +++ b/hw/mips/Kconfig
> > > > > @@ -45,6 +45,16 @@ config FULOONG
> > > > >      bool
> > > > >      select PCI_BONITO
> > > > >
> > > > > +config LOONGSON3
> > > > > +    bool
> > > > > +    select PCKBD
> > > > > +    select SERIAL
> > > > > +    select ISA_BUS
> > > > > +    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/Makefile.objs b/hw/mips/Makefile.objs
> > > > > index 3b3e6ea..31dedcb 100644
> > > > > --- a/hw/mips/Makefile.objs
> > > > > +++ b/hw/mips/Makefile.objs
> > > > > @@ -4,5 +4,6 @@ obj-$(CONFIG_MALTA) += gt64xxx_pci.o malta.o
> > > > >  obj-$(CONFIG_MIPSSIM) += mipssim.o
> > > > >  obj-$(CONFIG_JAZZ) += jazz.o
> > > > >  obj-$(CONFIG_FULOONG) += fuloong2e.o
> > > > > +obj-$(CONFIG_LOONGSON3) += loongson3.o
> > > > >  obj-$(CONFIG_MIPS_CPS) += cps.o
> > > > >  obj-$(CONFIG_MIPS_BOSTON) += boston.o
> > > > > diff --git a/hw/mips/loongson3.c b/hw/mips/loongson3.c
> > > > > new file mode 100644
> > > > > index 0000000..e4b9538
> > > > > --- /dev/null
> > > > > +++ b/hw/mips/loongson3.c
> > > > > @@ -0,0 +1,901 @@
> > > > > +/*
> > > > > + * Generic Loongson-3 Platform support
> > > > > + *
> > > > > + * Copyright (c) 2016-2020 Huacai Chen (chenhc@lemote.com)
> > > > > + * This code is licensed under the GNU GPL v2.
> > > > > + *
> > > > > + * Contributions are licensed under the terms of the GNU GPL,
> > > > > + * version 2 or (at your option) any later version.
> > > > > + */
> > > > > +
> > > > > +/*
> > > > > + * Generic 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 "hw/boards.h"
> > > > > +#include "hw/char/serial.h"
> > > > > +#include "hw/mips/mips.h"
> > > > > +#include "hw/mips/cpudevs.h"
> > > > > +#include "hw/intc/i8259.h"
> > > > > +#include "hw/loader.h"
> > > > > +#include "hw/ide.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 "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 INITRD_OFFSET         0x04000000
> > > > > +#define BOOTPARAM_ADDR        0x8ff00000
> > > > > +#define BOOTPARAM_PHYADDR     0x0ff00000
> > > > > +#define CFG_ADDR              0x0f100000
> > > > > +#define FW_CONF_ADDR          0x0fff0000
> > > > > +#define PM_MMIO_ADDR          0x10080000
> > > > > +#define PM_MMIO_SIZE          0x100
> > > > > +#define PM_CNTL_MODE          0x10
> > > > > +
> > > > > +#define PHYS_TO_VIRT(x) ((x) | ~(target_ulong)0x7fffffff)
> > > > > +
> > > > > +/* Loongson-3 has a 2MB flash rom */
> > > > > +#define BIOS_SIZE               (2 * MiB)
> > > > > +#define LOONGSON_MAX_VCPUS      16
> > > > > +
> > > > > +#define LOONGSON3_BIOSNAME "bios_loongson3.bin"
> > > > > +
> > > > > +#define PCIE_IRQ_BASE       3
> > > > > +
> > > > > +#define VIRT_PCI_IO_BASE    0x18000000ul
> > > > > +#define VIRT_PCI_IO_SIZE    0x000c0000ul
> > > > > +#define VIRT_PCI_MEM_BASE   0x40000000ul
> > > > > +#define VIRT_PCI_MEM_SIZE   0x40000000ul
> > > > > +#define VIRT_PCI_ECAM_BASE  0x1a000000ul
> > > > > +#define VIRT_PCI_ECAM_SIZE  0x02000000ul
> > > > > +
> > > > > +#define align(x) (((x) + 63) & ~63)
> > > > > +
> > > > > +/* 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;
> > > > > +};
> > > > > +
> > > > > +static struct _fw_config {
> > > > > +    unsigned long ram_size;
> > > > > +    unsigned int mem_freq;
> > > > > +    unsigned int nr_cpus;
> > > > > +    unsigned int cpu_clock_freq;
> > > > > +} fw_config;
> > > > > +
> > > > > +static struct _loaderparams {
> > > > > +    unsigned long ram_size;
> > > > > +    const char *kernel_cmdline;
> > > > > +    const char *kernel_filename;
> > > > > +    const char *initrd_filename;
> > > > > +    int64_t kernel_entry;
> > > > > +    unsigned long a0, a1, a2;
> > > > > +} loaderparams;
> > > > > +
> > > > > +static void *boot_params_p;
> > > > > +static void *boot_params_buf;
> > > > > +
> > > > > +static unsigned int bios_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                                                      */
> > > > > +};
> > > > > +
> > > > > +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 = (loaderparams.ram_size > 0x10000000
> > > > > +                            ? 256 : (loaderparams.ram_size >> 20)) - 16;
> > > > > +
> > > > > +    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 > 0x10000000
> > > > > +                            ? (loaderparams.ram_size >> 20) - 256 : 0);
> > > > > +
> > > > > +    return emap;
> > > > > +}
> > > > > +
> > > > > +static int get_host_cpu_freq(void)
> > > > > +{
> > > > > +    int fd = 0, freq = 0;
> > > > > +    char buf[1024], *buf_p;
> > > > > +
> > > > > +    fd = open("/proc/cpuinfo", O_RDONLY);
> > > > > +    if (fd == -1) {
> > > > > +        fprintf(stderr, "Failed to open /proc/cpuinfo!\n");
> > > > > +        return 0;
> > > > > +    }
> > > > > +
> > > > > +    if (read(fd, buf, 1024) < 0) {
> > > > > +        close(fd);
> > > > > +        fprintf(stderr, "Failed to read /proc/cpuinfo!\n");
> > > > > +        return 0;
> > > > > +    }
> > > > > +    close(fd);
> > > > > +
> > > > > +    buf_p = strstr(buf, "model name");
> > > > > +    while (*buf_p != '@') {
> > > > > +        buf_p++;
> > > > > +    }
> > > > > +
> > > > > +    buf_p += 2;
> > > > > +    memcpy(buf, buf_p, 12);
> > > > > +    buf_p = buf;
> > > > > +    while ((*buf_p >= '0') && (*buf_p <= '9')) {
> > > > > +        buf_p++;
> > > > > +    }
> > > > > +    *buf_p = '\0';
> > > > > +
> > > > > +    freq = atoi(buf);
> > > > > +
> > > > > +    return freq * 1000 * 1000;
> > > > > +}
> > > > > +
> > > > > +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 = 0x14C000;
> > > > > +    c->cpu_clock_freq = get_host_cpu_freq();
> > > > > +    if (!c->cpu_clock_freq) {
> > > > > +        c->cpu_clock_freq = 500000000;
> > > > > +    }
> > > > > +
> > > > > +    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;
> > > > > +    s->uarts[0].uart_base = 0x1fe001e0;
> > > > > +
> > > > > +    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_PCI_MEM_BASE;
> > > > > +    irq_info->pci_mem_end_addr   = VIRT_PCI_MEM_BASE + VIRT_PCI_MEM_SIZE - 1;
> > > > > +    irq_info->pci_io_start_addr  = VIRT_PCI_IO_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, "2016-05-16");
> > > > > +
> > > > > +    return special;
> > > > > +}
> > > > > +
> > > > > +static void init_loongson_params(struct loongson_params *lp)
> > > > > +{
> > > > > +    void *p = boot_params_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));
> > > > > +
> > > > > +    boot_params_p = p;
> > > > > +}
> > > > > +
> > > > > +static void init_smbios(struct smbios_tables *smbios)
> > > > > +{
> > > > > +    smbios->vers = 1;
> > > > > +    init_loongson_params(&(smbios->lp));
> > > > > +}
> > > > > +
> > > > > +static void init_efi(struct efi_loongson *efi)
> > > > > +{
> > > > > +    init_smbios(&(efi->smbios));
> > > > > +}
> > > > > +
> > > > > +static void init_reset_system(struct efi_reset_system_t *reset)
> > > > > +{
> > > > > +    reset->Shutdown = 0xffffffffbfc000a8;
> > > > > +    reset->ResetCold = 0xffffffffbfc00080;
> > > > > +    reset->ResetWarm = 0xffffffffbfc00080;
> > > > > +}
> > > > > +
> > > > > +static int init_boot_param(struct boot_params *bp)
> > > > > +{
> > > > > +    init_efi(&(bp->efi));
> > > > > +    init_reset_system(&(bp->reset_system));
> > > > > +
> > > > > +    return 0;
> > > > > +}
> > > > > +
> > > > > +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;
> > > > > +
> > > > > +    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);
> > > > > +    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
> > > > > +
> > > > > +    fw_config.ram_size = ram_size;
> > > > > +    fw_config.mem_freq = 300000000;
> > > > > +    fw_config.nr_cpus = current_machine->smp.cpus;
> > > > > +    fw_config.cpu_clock_freq = get_host_cpu_freq();
> > > > > +}
> > > > > +
> > > > > +static int set_prom_bootparam(ram_addr_t initrd_offset, long initrd_size)
> > > > > +{
> > > > > +    long params_size;
> > > > > +    char memenv[32];
> > > > > +    char highmemenv[32];
> > > > > +    void *params_buf;
> > > > > +    unsigned int *parg_env;
> > > > > +    int ret = 0;
> > > > > +
> > > > > +    /* Allocate params_buf for command line. */
> > > > > +    params_size = 0x100000;
> > > > > +    params_buf = g_malloc0(params_size);
> > > > > +
> > > > > +    /*
> > > > > +     * Layout of params_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 *)params_buf;
> > > > > +
> > > > > +    ret = (3 + 1) * 4;
> > > > > +    *parg_env++ = (BOOTPARAM_ADDR + ret);
> > > > > +    ret += (1 + snprintf(params_buf + ret, 256 - ret, "g"));
> > > > > +
> > > > > +    /* argv1 */
> > > > > +    *parg_env++ = BOOTPARAM_ADDR + ret;
> > > > > +    if (initrd_size > 0)
> > > > > +        ret += (1 + snprintf(params_buf + ret, 256 - ret,
> > > > > +                "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s",
> > > > > +                PHYS_TO_VIRT((uint32_t)initrd_offset),
> > > > > +                initrd_size, loaderparams.kernel_cmdline));
> > > > > +    else
> > > > > +        ret += (1 + snprintf(params_buf + ret, 256 - ret, "%s",
> > > > > +                loaderparams.kernel_cmdline));
> > > > > +
> > > > > +    /* argv2 */
> > > > > +    *parg_env++ = BOOTPARAM_ADDR + 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);
> > > > > +
> > > > > +    setenv("memsize", memenv, 1);
> > > > > +    setenv("highmemsize", highmemenv, 1);
> > > > > +
> > > > > +    ret = ((ret + 32) & ~31);
> > > > > +
> > > > > +    boot_params_buf = (void *)(params_buf + ret);
> > > > > +    boot_params_p = boot_params_buf + align(sizeof(struct boot_params));
> > > > > +
> > > > > +    init_boot_param(boot_params_buf);
> > > > > +
> > > > > +    rom_add_blob_fixed("params", params_buf, params_size,
> > > > > +                       BOOTPARAM_PHYADDR);
> > > > > +    loaderparams.a0 = 2;
> > > > > +    loaderparams.a1 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR;
> > > > > +    loaderparams.a2 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR + ret;
> > > > > +
> > > > > +    return 0;
> > > > > +}
> > > > > +
> > > > > +static int64_t load_kernel(CPUMIPSState *env)
> > > > > +{
> > > > > +    long kernel_size;
> > > > > +    ram_addr_t initrd_offset;
> > > > > +    int64_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, INITRD_OFFSET);
> > > > > +
> > > > > +            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 parameters. */
> > > > > +    set_prom_bootparam(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 void loongson3_isa_init(qemu_irq intc)
> > > > > +{
> > > > > +    qemu_irq *i8259;
> > > > > +    ISABus *isa_bus;
> > > > > +
> > > > > +    isa_bus = isa_bus_new(NULL, get_system_memory(), get_system_io(), &error_abort);
> > > > > +
> > > > > +    /* Interrupt controller */
> > > > > +    /* The 8259 -> IP3  */
> > > > > +    i8259 = i8259_init(isa_bus, intc);
> > > > > +    isa_bus_irqs(isa_bus, i8259);
> > > > > +    /* init other devices */
> > > > > +    isa_create_simple(isa_bus, "i8042");
> > > > > +    mc146818_rtc_init(isa_bus, 2000, NULL);
> > > > > +}
> > > > > +
> > > > > +static inline void loongson3_pcie_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_create(NULL, TYPE_GPEX_HOST);
> > > > > +
> > > > > +    qdev_init_nofail(dev);
> > > > > +    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_PCI_ECAM_SIZE);
> > > > > +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_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_PCI_MEM_BASE, VIRT_PCI_MEM_SIZE);
> > > > > +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_MEM_BASE, mmio_alias);
> > > > > +
> > > > > +    pio_alias = g_new0(MemoryRegion, 1);
> > > > > +    memory_region_init_alias(pio_alias, OBJECT(dev), "pcie-pio",
> > > > > +                             get_system_io(), 0, VIRT_PCI_IO_SIZE);
> > > > > +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_IO_BASE, pio_alias);
> > > > > +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, VIRT_PCI_IO_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);
> > > > > +
> > > > > +    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_init(MachineState *machine)
> > > > > +{
> > > > > +    int i;
> > > > > +    long bios_size;
> > > > > +    MIPSCPU *cpu;
> > > > > +    CPUMIPSState *env;
> > > > > +    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);
> > > > > +
> > > > > +    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 < 256 * 0x100000) {
> > > > > +        error_report("Loongson-3 need at least 256MB memory");
> > > > > +        exit(1);
> > > > > +    }
> > > > > +
> > > > > +    for (i = 0; i < machine->smp.cpus; i++) {
> > > > > +        /* 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);
> > > > > +    }
> > > > > +    env = &MIPS_CPU(first_cpu)->env;
> > > > > +
> > > > > +    /* Allocate RAM/BIOS, 0x00000000~0x10000000 is alias of 0x80000000~0x90000000 */
> > > > > +    memory_region_init_rom(bios, NULL, "loongson3.bios",
> > > > > +                           BIOS_SIZE, &error_fatal);
> > > > > +    memory_region_init_alias(ram, NULL, "loongson3.lowram",
> > > > > +                           machine->ram, 0, 256 * 0x100000);
> > > > > +    memory_region_init_io(iomem, NULL, &loongson3_pm_ops,
> > > > > +                           NULL, "loongson3_pm", PM_MMIO_SIZE);
> > > > > +
> > > > > +    memory_region_add_subregion(address_space_mem, 0x00000000LL, ram);
> > > > > +    memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios);
> > > > > +    memory_region_add_subregion(address_space_mem, 0x80000000LL, machine->ram);
> > > > > +    memory_region_add_subregion(address_space_mem, PM_MMIO_ADDR, iomem);
> > > > > +
> > > > > +    /*
> > > > > +     * We do not support flash operation, just loading pmon.bin as raw BIOS.
> > > > > +     * Please use -L to set the BIOS path and -bios to set bios name.
> > > > > +     */
> > > > > +
> > > > > +    if (kernel_filename) {
> > > > > +        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);
> > > > > +        rom_add_blob_fixed("bios",
> > > > > +                         bios_boot_code, sizeof(bios_boot_code), 0x1fc00000LL);
> > > > > +    } 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, 0x1fc00000LL,
> > > > > +                                            BIOS_SIZE);
> > > > > +            g_free(filename);
> > > > > +        } else {
> > > > > +            bios_size = -1;
> > > > > +        }
> > > > > +
> > > > > +        if ((bios_size < 0 || bios_size > BIOS_SIZE) &&
> > > > > +            !kernel_filename && !qtest_enabled()) {
> > > > > +            error_report("Could not load MIPS bios '%s'", bios_name);
> > > > > +            exit(1);
> > > > > +        }
> > > > > +
> > > > > +        fw_conf_init(ram_size);
> > > > > +        rom_add_blob_fixed("fw_conf",
> > > > > +                         &fw_config, sizeof(fw_config), FW_CONF_ADDR);
> > > > > +    }
> > > > > +
> > > > > +    msi_nonbroken = true;
> > > > > +    loongson3_isa_init(env->irq[3]);
> > > > > +    loongson3_pcie_init(machine, isa_pic);
> > > > > +
> > > > > +    if (serial_hd(0)) {
> > > > > +        serial_mm_init(address_space_mem, 0x1fe001e0, 0, env->irq[2],
> > > > > +                           115200, serial_hd(0), DEVICE_NATIVE_ENDIAN);
> > > > > +    }
> > > > > +}
> > > > > +
> > > > > +static void mips_loongson3_machine_init(MachineClass *mc)
> > > > > +{
> > > > > +    mc->desc = "Generic Loongson-3 Platform";
> > > > > +    mc->init = mips_loongson3_init;
> > > > > +    mc->block_default_type = IF_IDE;
> > > > > +    mc->max_cpus = LOONGSON_MAX_VCPUS;
> > > > > +    mc->default_ram_id = "loongson3.highram";
> > > > > +    mc->default_ram_size = 1200 * MiB;
> > > > > +    mc->kvm_type = mips_kvm_type;
> > > > > +    mc->minimum_page_bits = 14;
> > > > > +}
> > > > > +
> > > > > +DEFINE_MACHINE("loongson3", mips_loongson3_machine_init)
> > > > > --
> > > > > 2.7.0
> > > > >
> >
> >
> >
> > --
> > Huacai Chen
> >


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

* Re: [PATCH for-5.1 V4 3/4] hw/mips: Add Loongson-3 machine support (with KVM)
  2020-06-02  2:39 ` [PATCH for-5.1 V4 3/4] hw/mips: Add Loongson-3 machine support (with KVM) Huacai Chen
  2020-06-06  7:32   ` Aleksandar Markovic
@ 2020-06-11  5:58   ` Jiaxun Yang
  2020-06-11  7:49     ` Huacai Chen
  2020-06-14  7:51   ` Aleksandar Markovic
  2 siblings, 1 reply; 41+ messages in thread
From: Jiaxun Yang @ 2020-06-11  5:58 UTC (permalink / raw)
  To: Huacai Chen, Philippe Mathieu-Daudé, Aleksandar Markovic
  Cc: Huacai Chen, Huacai Chen, Aleksandar Rikalo, qemu-devel, Aurelien Jarno



在 2020/6/2 10:39, Huacai Chen 写道:
> Add Loongson-3 based machine support, it use i8259 as the interrupt
> controler and use GPEX as the pci controller. Currently it can only
> work with KVM, but we will add TCG support in future.
> 
> We already have a full functional Linux kernel (based on Linux-5.4.x LTS
> but not upstream yet) here:
> 
> https://github.com/chenhuacai/linux
> 
> 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 the a Loongson-3A4000 host with this kernel;
> 4, Build QEMU-5.0.0 with this patchset;
> 5, modprobe kvm;
> 6, Use QEMU with TCG (available in future):
>         qemu-system-mips64el -M loongson3,accel=tcg -cpu Loongson-3A1000 -kernel <path_to_kernel> -append ...
>     Use QEMU with KVM (available at present):
>         qemu-system-mips64el -M loongson3,accel=kvm -cpu Loongson-3A4000 -kernel <path_to_kernel> -append ...
> 
>     The "-cpu" parameter can be omitted 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>
> Reviewed-by: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
> ---
>   default-configs/mips64el-softmmu.mak |   1 +
>   hw/mips/Kconfig                      |  10 +
>   hw/mips/Makefile.objs                |   1 +
>   hw/mips/loongson3.c                  | 901 +++++++++++++++++++++++++++++++++++
>   4 files changed, 913 insertions(+)
>   create mode 100644 hw/mips/loongson3.c

Hi there,

I was working on TCG support based on this machine, and noticed some 
minor issue here.

Huacai, would you mind me to include your machine support in my TCG 
series? As currently KVM support is blocked kernel.


> 
> diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak
> index 9f8a3ef..2a2a3fb 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_LOONGSON3=y
>   CONFIG_ATI_VGA=y
>   CONFIG_RTL8139_PCI=y
>   CONFIG_JAZZ=y
> diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig
> index 67d39c5..42931fd 100644
> --- a/hw/mips/Kconfig
> +++ b/hw/mips/Kconfig
> @@ -45,6 +45,16 @@ config FULOONG
>       bool
>       select PCI_BONITO
>   
> +config LOONGSON3
> +    bool
> +    select PCKBD
> +    select SERIAL
> +    select ISA_BUS
> +    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/Makefile.objs b/hw/mips/Makefile.objs
> index 3b3e6ea..31dedcb 100644
> --- a/hw/mips/Makefile.objs
> +++ b/hw/mips/Makefile.objs
> @@ -4,5 +4,6 @@ obj-$(CONFIG_MALTA) += gt64xxx_pci.o malta.o
>   obj-$(CONFIG_MIPSSIM) += mipssim.o
>   obj-$(CONFIG_JAZZ) += jazz.o
>   obj-$(CONFIG_FULOONG) += fuloong2e.o
> +obj-$(CONFIG_LOONGSON3) += loongson3.o
>   obj-$(CONFIG_MIPS_CPS) += cps.o
>   obj-$(CONFIG_MIPS_BOSTON) += boston.o
> diff --git a/hw/mips/loongson3.c b/hw/mips/loongson3.c
> new file mode 100644
> index 0000000..e4b9538
> --- /dev/null
> +++ b/hw/mips/loongson3.c
> @@ -0,0 +1,901 @@
> +/*
> + * Generic Loongson-3 Platform support
> + *
> + * Copyright (c) 2016-2020 Huacai Chen (chenhc@lemote.com)
> + * This code is licensed under the GNU GPL v2.
> + *
> + * Contributions are licensed under the terms of the GNU GPL,
> + * version 2 or (at your option) any later version.
> + */
> +
> +/*
> + * Generic 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 "hw/boards.h"
> +#include "hw/char/serial.h"
> +#include "hw/mips/mips.h"
> +#include "hw/mips/cpudevs.h"
> +#include "hw/intc/i8259.h"
> +#include "hw/loader.h"
> +#include "hw/ide.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 "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 INITRD_OFFSET         0x04000000
> +#define BOOTPARAM_ADDR        0x8ff00000
> +#define BOOTPARAM_PHYADDR     0x0ff00000
> +#define CFG_ADDR              0x0f100000
> +#define FW_CONF_ADDR          0x0fff0000
> +#define PM_MMIO_ADDR          0x10080000
> +#define PM_MMIO_SIZE          0x100
> +#define PM_CNTL_MODE          0x10

Looks like use an array to manage all these address can be more organized.

> +
> +#define PHYS_TO_VIRT(x) ((x) | ~(target_ulong)0x7fffffff)

We've already got cpu_mips_phys_to_kseg0.

> +
> +/* Loongson-3 has a 2MB flash rom */
> +#define BIOS_SIZE               (2 * MiB)
> +#define LOONGSON_MAX_VCPUS      16
> +
> +#define LOONGSON3_BIOSNAME "bios_loongson3.bin"
> +
> +#define PCIE_IRQ_BASE       3
> +
> +#define VIRT_PCI_IO_BASE    0x18000000ul
> +#define VIRT_PCI_IO_SIZE    0x000c0000ul
> +#define VIRT_PCI_MEM_BASE   0x40000000ul
> +#define VIRT_PCI_MEM_SIZE   0x40000000ul
> +#define VIRT_PCI_ECAM_BASE  0x1a000000ul
> +#define VIRT_PCI_ECAM_SIZE  0x02000000ul
> +
> +#define align(x) (((x) + 63) & ~63)
> +
> +/* 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;
> +};
> +
> +static struct _fw_config {
> +    unsigned long ram_size;
> +    unsigned int mem_freq;
> +    unsigned int nr_cpus;
> +    unsigned int cpu_clock_freq;
> +} fw_config;
> +
> +static struct _loaderparams {
> +    unsigned long ram_size;
> +    const char *kernel_cmdline;
> +    const char *kernel_filename;
> +    const char *initrd_filename;
> +    int64_t kernel_entry;
> +    unsigned long a0, a1, a2;
> +} loaderparams;
> +
> +static void *boot_params_p;
> +static void *boot_params_buf;
> +
> +static unsigned int bios_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                                                      */
> +};
> +
> +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,

You'd better set min_access_size and max_access_size here as it can't 
handle write with different size.

> +    .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 = (loaderparams.ram_size > 0x10000000
> +                            ? 256 : (loaderparams.ram_size >> 20)) - 16;
> +
> +    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 > 0x10000000
> +                            ? (loaderparams.ram_size >> 20) - 256 : 0);
> +
> +    return emap;
> +}
> +
> +static int get_host_cpu_freq(void)
> +{

"model name" have not been accppted by mainline kernel.
Probably asking kernel frequency via a part of QEMU IOCTL is a better 
option?

> +    int fd = 0, freq = 0;
> +    char buf[1024], *buf_p;
> +
> +    fd = open("/proc/cpuinfo", O_RDONLY);
> +    if (fd == -1) {
> +        fprintf(stderr, "Failed to open /proc/cpuinfo!\n");
> +        return 0;
> +    }
> +
> +    if (read(fd, buf, 1024) < 0) {
> +        close(fd);
> +        fprintf(stderr, "Failed to read /proc/cpuinfo!\n");
> +        return 0;
> +    }
> +    close(fd);
> +
> +    buf_p = strstr(buf, "model name");
> +    while (*buf_p != '@') {
> +        buf_p++;
> +    }
> +
> +    buf_p += 2;
> +    memcpy(buf, buf_p, 12);
> +    buf_p = buf;
> +    while ((*buf_p >= '0') && (*buf_p <= '9')) {
> +        buf_p++;
> +    }
> +    *buf_p = '\0';
> +
> +    freq = atoi(buf);
> +
> +    return freq * 1000 * 1000;
> +}
> +
> +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 = 0x14C000;
> +    c->cpu_clock_freq = get_host_cpu_freq();
> +    if (!c->cpu_clock_freq) {
> +        c->cpu_clock_freq = 500000000;
> +    }
> +
> +    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;
> +    s->uarts[0].uart_base = 0x1fe001e0;
> +
> +    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_PCI_MEM_BASE;
> +    irq_info->pci_mem_end_addr   = VIRT_PCI_MEM_BASE + VIRT_PCI_MEM_SIZE - 1;
> +    irq_info->pci_io_start_addr  = VIRT_PCI_IO_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, "2016-05-16");
> +
> +    return special;
> +}
> +
> +static void init_loongson_params(struct loongson_params *lp)
> +{
> +    void *p = boot_params_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));
> +
> +    boot_params_p = p;
> +}
> +
> +static void init_smbios(struct smbios_tables *smbios)
> +{
> +    smbios->vers = 1;
> +    init_loongson_params(&(smbios->lp));
> +}
> +
> +static void init_efi(struct efi_loongson *efi)
> +{
> +    init_smbios(&(efi->smbios));
> +}
> +
> +static void init_reset_system(struct efi_reset_system_t *reset)
> +{
> +    reset->Shutdown = 0xffffffffbfc000a8;
> +    reset->ResetCold = 0xffffffffbfc00080;
> +    reset->ResetWarm = 0xffffffffbfc00080;
> +}
> +
> +static int init_boot_param(struct boot_params *bp)
> +{
> +    init_efi(&(bp->efi));
> +    init_reset_system(&(bp->reset_system));
> +
> +    return 0;
> +}
> +
> +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;
> +
> +    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);
> +    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
> +
> +    fw_config.ram_size = ram_size;
> +    fw_config.mem_freq = 300000000;
> +    fw_config.nr_cpus = current_machine->smp.cpus;
> +    fw_config.cpu_clock_freq = get_host_cpu_freq();
> +}
> +
> +static int set_prom_bootparam(ram_addr_t initrd_offset, long initrd_size)
> +{
> +    long params_size;
> +    char memenv[32];
> +    char highmemenv[32];
> +    void *params_buf;
> +    unsigned int *parg_env;
> +    int ret = 0;
> +
> +    /* Allocate params_buf for command line. */
> +    params_size = 0x100000;
> +    params_buf = g_malloc0(params_size);
> +
> +    /*
> +     * Layout of params_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 *)params_buf;
> +
> +    ret = (3 + 1) * 4;
> +    *parg_env++ = (BOOTPARAM_ADDR + ret);
> +    ret += (1 + snprintf(params_buf + ret, 256 - ret, "g"));
> +
> +    /* argv1 */
> +    *parg_env++ = BOOTPARAM_ADDR + ret;
> +    if (initrd_size > 0)
> +        ret += (1 + snprintf(params_buf + ret, 256 - ret,
> +                "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s",
> +                PHYS_TO_VIRT((uint32_t)initrd_offset),
> +                initrd_size, loaderparams.kernel_cmdline));
> +    else
> +        ret += (1 + snprintf(params_buf + ret, 256 - ret, "%s",
> +                loaderparams.kernel_cmdline));
> +
> +    /* argv2 */
> +    *parg_env++ = BOOTPARAM_ADDR + 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);
> +
> +    setenv("memsize", memenv, 1);
> +    setenv("highmemsize", highmemenv, 1);

These setenv looks pointless.

> +
> +    ret = ((ret + 32) & ~31);
> +
> +    boot_params_buf = (void *)(params_buf + ret);
> +    boot_params_p = boot_params_buf + align(sizeof(struct boot_params));
> +
> +    init_boot_param(boot_params_buf);
> +
> +    rom_add_blob_fixed("params", params_buf, params_size,
> +                       BOOTPARAM_PHYADDR);
> +    loaderparams.a0 = 2;
> +    loaderparams.a1 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR;
> +    loaderparams.a2 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR + ret;
> +
> +    return 0;
> +}
> +
> +static int64_t load_kernel(CPUMIPSState *env)
> +{
> +    long kernel_size;
> +    ram_addr_t initrd_offset;
> +    int64_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, INITRD_OFFSET);
> +
> +            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 parameters. */
> +    set_prom_bootparam(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 void loongson3_isa_init(qemu_irq intc)
> +{
> +    qemu_irq *i8259;
> +    ISABus *isa_bus;
> +
> +    isa_bus = isa_bus_new(NULL, get_system_memory(), get_system_io(), &error_abort);
> +
> +    /* Interrupt controller */
> +    /* The 8259 -> IP3  */
> +    i8259 = i8259_init(isa_bus, intc);
> +    isa_bus_irqs(isa_bus, i8259);
> +    /* init other devices */
> +    isa_create_simple(isa_bus, "i8042");
> +    mc146818_rtc_init(isa_bus, 2000, NULL);
> +}
> +
> +static inline void loongson3_pcie_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_create(NULL, TYPE_GPEX_HOST);
> +
> +    qdev_init_nofail(dev);
> +    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_PCI_ECAM_SIZE);
> +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_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_PCI_MEM_BASE, VIRT_PCI_MEM_SIZE);
> +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_MEM_BASE, mmio_alias);
> +
> +    pio_alias = g_new0(MemoryRegion, 1);
> +    memory_region_init_alias(pio_alias, OBJECT(dev), "pcie-pio",
> +                             get_system_io(), 0, VIRT_PCI_IO_SIZE);
> +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_IO_BASE, pio_alias);
> +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, VIRT_PCI_IO_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);
> +
> +    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_init(MachineState *machine)
> +{
> +    int i;
> +    long bios_size;
> +    MIPSCPU *cpu;
> +    CPUMIPSState *env;
> +    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);
> +
> +    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 < 256 * 0x100000) {
> +        error_report("Loongson-3 need at least 256MB memory");
> +        exit(1);
> +    }
> +
> +    for (i = 0; i < machine->smp.cpus; i++) {
> +        /* 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);
> +    }
> +    env = &MIPS_CPU(first_cpu)->env;
> +
> +    /* Allocate RAM/BIOS, 0x00000000~0x10000000 is alias of 0x80000000~0x90000000 */
> +    memory_region_init_rom(bios, NULL, "loongson3.bios",
> +                           BIOS_SIZE, &error_fatal);
> +    memory_region_init_alias(ram, NULL, "loongson3.lowram",
> +                           machine->ram, 0, 256 * 0x100000);
> +    memory_region_init_io(iomem, NULL, &loongson3_pm_ops,
> +                           NULL, "loongson3_pm", PM_MMIO_SIZE);
> +
> +    memory_region_add_subregion(address_space_mem, 0x00000000LL, ram);
> +    memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios);
> +    memory_region_add_subregion(address_space_mem, 0x80000000LL, machine->ram);
> +    memory_region_add_subregion(address_space_mem, PM_MMIO_ADDR, iomem);
> +
> +    /*
> +     * We do not support flash operation, just loading pmon.bin as raw BIOS.
> +     * Please use -L to set the BIOS path and -bios to set bios name.
> +     */
> +
> +    if (kernel_filename) {
> +        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);
> +        rom_add_blob_fixed("bios",
> +                         bios_boot_code, sizeof(bios_boot_code), 0x1fc00000LL);
> +    } 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, 0x1fc00000LL,
> +                                            BIOS_SIZE);
> +            g_free(filename);
> +        } else {
> +            bios_size = -1;
> +        }
> +
> +        if ((bios_size < 0 || bios_size > BIOS_SIZE) &&
> +            !kernel_filename && !qtest_enabled()) {
> +            error_report("Could not load MIPS bios '%s'", bios_name);
> +            exit(1);
> +        }
> +
> +        fw_conf_init(ram_size);
> +        rom_add_blob_fixed("fw_conf",
> +                         &fw_config, sizeof(fw_config), FW_CONF_ADDR);
> +    }
> +
> +    msi_nonbroken = true;

As this machine is not reflecting any actual Loongson-3 system, I would 
say "loongson3-virt" can be a better name.

> +    loongson3_isa_init(env->irq[3]);
> +    loongson3_pcie_init(machine, isa_pic);
> +
> +    if (serial_hd(0)) {
> +        serial_mm_init(address_space_mem, 0x1fe001e0, 0, env->irq[2],
> +                           115200, serial_hd(0), DEVICE_NATIVE_ENDIAN);
> +    }
> +}
> +
> +static void mips_loongson3_machine_init(MachineClass *mc)
> +{
> +    mc->desc = "Generic Loongson-3 Platform";
> +    mc->init = mips_loongson3_init;
> +    mc->block_default_type = IF_IDE;
> +    mc->max_cpus = LOONGSON_MAX_VCPUS;
> +    mc->default_ram_id = "loongson3.highram";
> +    mc->default_ram_size = 1200 * MiB;

1200MiB looks wired... Why not 1024?

> +    mc->kvm_type = mips_kvm_type;
> +    mc->minimum_page_bits = 14;
> +}
> +
> +DEFINE_MACHINE("loongson3", mips_loongson3_machine_init)
> 

As this machine is not reflecting any actual Loongson-3 system, I would 
say "loongson3-virt" can be a better name.

Furthermore, the design of machine can be updated over time. So probably 
we can add a version suffix to it just like what arm-virt did.

Thanks!

-- 
- Jiaxun



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

* Re: [PATCH for-5.1 V4 3/4] hw/mips: Add Loongson-3 machine support (with KVM)
  2020-06-11  5:58   ` Jiaxun Yang
@ 2020-06-11  7:49     ` Huacai Chen
  2020-06-11  8:12       ` Jiaxun Yang
  0 siblings, 1 reply; 41+ messages in thread
From: Huacai Chen @ 2020-06-11  7:49 UTC (permalink / raw)
  To: Jiaxun Yang
  Cc: Huacai Chen, Philippe Mathieu-Daudé,
	QEMU Developers, Aleksandar Markovic, Aleksandar Rikalo,
	Aurelien Jarno

Hi, Jiaxun,

On Thu, Jun 11, 2020 at 1:59 PM Jiaxun Yang <jiaxun.yang@flygoat.com> wrote:
>
>
>
> 在 2020/6/2 10:39, Huacai Chen 写道:
> > Add Loongson-3 based machine support, it use i8259 as the interrupt
> > controler and use GPEX as the pci controller. Currently it can only
> > work with KVM, but we will add TCG support in future.
> >
> > We already have a full functional Linux kernel (based on Linux-5.4.x LTS
> > but not upstream yet) here:
> >
> > https://github.com/chenhuacai/linux
> >
> > 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 the a Loongson-3A4000 host with this kernel;
> > 4, Build QEMU-5.0.0 with this patchset;
> > 5, modprobe kvm;
> > 6, Use QEMU with TCG (available in future):
> >         qemu-system-mips64el -M loongson3,accel=tcg -cpu Loongson-3A1000 -kernel <path_to_kernel> -append ...
> >     Use QEMU with KVM (available at present):
> >         qemu-system-mips64el -M loongson3,accel=kvm -cpu Loongson-3A4000 -kernel <path_to_kernel> -append ...
> >
> >     The "-cpu" parameter can be omitted 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>
> > Reviewed-by: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
> > ---
> >   default-configs/mips64el-softmmu.mak |   1 +
> >   hw/mips/Kconfig                      |  10 +
> >   hw/mips/Makefile.objs                |   1 +
> >   hw/mips/loongson3.c                  | 901 +++++++++++++++++++++++++++++++++++
> >   4 files changed, 913 insertions(+)
> >   create mode 100644 hw/mips/loongson3.c
>
> Hi there,
>
> I was working on TCG support based on this machine, and noticed some
> minor issue here.
>
> Huacai, would you mind me to include your machine support in my TCG
> series? As currently KVM support is blocked kernel.
>
>
> >
> > diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak
> > index 9f8a3ef..2a2a3fb 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_LOONGSON3=y
> >   CONFIG_ATI_VGA=y
> >   CONFIG_RTL8139_PCI=y
> >   CONFIG_JAZZ=y
> > diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig
> > index 67d39c5..42931fd 100644
> > --- a/hw/mips/Kconfig
> > +++ b/hw/mips/Kconfig
> > @@ -45,6 +45,16 @@ config FULOONG
> >       bool
> >       select PCI_BONITO
> >
> > +config LOONGSON3
> > +    bool
> > +    select PCKBD
> > +    select SERIAL
> > +    select ISA_BUS
> > +    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/Makefile.objs b/hw/mips/Makefile.objs
> > index 3b3e6ea..31dedcb 100644
> > --- a/hw/mips/Makefile.objs
> > +++ b/hw/mips/Makefile.objs
> > @@ -4,5 +4,6 @@ obj-$(CONFIG_MALTA) += gt64xxx_pci.o malta.o
> >   obj-$(CONFIG_MIPSSIM) += mipssim.o
> >   obj-$(CONFIG_JAZZ) += jazz.o
> >   obj-$(CONFIG_FULOONG) += fuloong2e.o
> > +obj-$(CONFIG_LOONGSON3) += loongson3.o
> >   obj-$(CONFIG_MIPS_CPS) += cps.o
> >   obj-$(CONFIG_MIPS_BOSTON) += boston.o
> > diff --git a/hw/mips/loongson3.c b/hw/mips/loongson3.c
> > new file mode 100644
> > index 0000000..e4b9538
> > --- /dev/null
> > +++ b/hw/mips/loongson3.c
> > @@ -0,0 +1,901 @@
> > +/*
> > + * Generic Loongson-3 Platform support
> > + *
> > + * Copyright (c) 2016-2020 Huacai Chen (chenhc@lemote.com)
> > + * This code is licensed under the GNU GPL v2.
> > + *
> > + * Contributions are licensed under the terms of the GNU GPL,
> > + * version 2 or (at your option) any later version.
> > + */
> > +
> > +/*
> > + * Generic 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 "hw/boards.h"
> > +#include "hw/char/serial.h"
> > +#include "hw/mips/mips.h"
> > +#include "hw/mips/cpudevs.h"
> > +#include "hw/intc/i8259.h"
> > +#include "hw/loader.h"
> > +#include "hw/ide.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 "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 INITRD_OFFSET         0x04000000
> > +#define BOOTPARAM_ADDR        0x8ff00000
> > +#define BOOTPARAM_PHYADDR     0x0ff00000
> > +#define CFG_ADDR              0x0f100000
> > +#define FW_CONF_ADDR          0x0fff0000
> > +#define PM_MMIO_ADDR          0x10080000
> > +#define PM_MMIO_SIZE          0x100
> > +#define PM_CNTL_MODE          0x10
>
> Looks like use an array to manage all these address can be more organized.
>
> > +
> > +#define PHYS_TO_VIRT(x) ((x) | ~(target_ulong)0x7fffffff)
>
> We've already got cpu_mips_phys_to_kseg0.
>
> > +
> > +/* Loongson-3 has a 2MB flash rom */
> > +#define BIOS_SIZE               (2 * MiB)
> > +#define LOONGSON_MAX_VCPUS      16
> > +
> > +#define LOONGSON3_BIOSNAME "bios_loongson3.bin"
> > +
> > +#define PCIE_IRQ_BASE       3
> > +
> > +#define VIRT_PCI_IO_BASE    0x18000000ul
> > +#define VIRT_PCI_IO_SIZE    0x000c0000ul
> > +#define VIRT_PCI_MEM_BASE   0x40000000ul
> > +#define VIRT_PCI_MEM_SIZE   0x40000000ul
> > +#define VIRT_PCI_ECAM_BASE  0x1a000000ul
> > +#define VIRT_PCI_ECAM_SIZE  0x02000000ul
> > +
> > +#define align(x) (((x) + 63) & ~63)
> > +
> > +/* 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;
> > +};
> > +
> > +static struct _fw_config {
> > +    unsigned long ram_size;
> > +    unsigned int mem_freq;
> > +    unsigned int nr_cpus;
> > +    unsigned int cpu_clock_freq;
> > +} fw_config;
> > +
> > +static struct _loaderparams {
> > +    unsigned long ram_size;
> > +    const char *kernel_cmdline;
> > +    const char *kernel_filename;
> > +    const char *initrd_filename;
> > +    int64_t kernel_entry;
> > +    unsigned long a0, a1, a2;
> > +} loaderparams;
> > +
> > +static void *boot_params_p;
> > +static void *boot_params_buf;
> > +
> > +static unsigned int bios_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                                                      */
> > +};
> > +
> > +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,
>
> You'd better set min_access_size and max_access_size here as it can't
> handle write with different size.
>
> > +    .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 = (loaderparams.ram_size > 0x10000000
> > +                            ? 256 : (loaderparams.ram_size >> 20)) - 16;
> > +
> > +    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 > 0x10000000
> > +                            ? (loaderparams.ram_size >> 20) - 256 : 0);
> > +
> > +    return emap;
> > +}
> > +
> > +static int get_host_cpu_freq(void)
> > +{
>
> "model name" have not been accppted by mainline kernel.
> Probably asking kernel frequency via a part of QEMU IOCTL is a better
> option?
Is there exsiting better method? I will use if possible.

>
> > +    int fd = 0, freq = 0;
> > +    char buf[1024], *buf_p;
> > +
> > +    fd = open("/proc/cpuinfo", O_RDONLY);
> > +    if (fd == -1) {
> > +        fprintf(stderr, "Failed to open /proc/cpuinfo!\n");
> > +        return 0;
> > +    }
> > +
> > +    if (read(fd, buf, 1024) < 0) {
> > +        close(fd);
> > +        fprintf(stderr, "Failed to read /proc/cpuinfo!\n");
> > +        return 0;
> > +    }
> > +    close(fd);
> > +
> > +    buf_p = strstr(buf, "model name");
> > +    while (*buf_p != '@') {
> > +        buf_p++;
> > +    }
> > +
> > +    buf_p += 2;
> > +    memcpy(buf, buf_p, 12);
> > +    buf_p = buf;
> > +    while ((*buf_p >= '0') && (*buf_p <= '9')) {
> > +        buf_p++;
> > +    }
> > +    *buf_p = '\0';
> > +
> > +    freq = atoi(buf);
> > +
> > +    return freq * 1000 * 1000;
> > +}
> > +
> > +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 = 0x14C000;
> > +    c->cpu_clock_freq = get_host_cpu_freq();
> > +    if (!c->cpu_clock_freq) {
> > +        c->cpu_clock_freq = 500000000;
> > +    }
> > +
> > +    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;
> > +    s->uarts[0].uart_base = 0x1fe001e0;
> > +
> > +    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_PCI_MEM_BASE;
> > +    irq_info->pci_mem_end_addr   = VIRT_PCI_MEM_BASE + VIRT_PCI_MEM_SIZE - 1;
> > +    irq_info->pci_io_start_addr  = VIRT_PCI_IO_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, "2016-05-16");
> > +
> > +    return special;
> > +}
> > +
> > +static void init_loongson_params(struct loongson_params *lp)
> > +{
> > +    void *p = boot_params_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));
> > +
> > +    boot_params_p = p;
> > +}
> > +
> > +static void init_smbios(struct smbios_tables *smbios)
> > +{
> > +    smbios->vers = 1;
> > +    init_loongson_params(&(smbios->lp));
> > +}
> > +
> > +static void init_efi(struct efi_loongson *efi)
> > +{
> > +    init_smbios(&(efi->smbios));
> > +}
> > +
> > +static void init_reset_system(struct efi_reset_system_t *reset)
> > +{
> > +    reset->Shutdown = 0xffffffffbfc000a8;
> > +    reset->ResetCold = 0xffffffffbfc00080;
> > +    reset->ResetWarm = 0xffffffffbfc00080;
> > +}
> > +
> > +static int init_boot_param(struct boot_params *bp)
> > +{
> > +    init_efi(&(bp->efi));
> > +    init_reset_system(&(bp->reset_system));
> > +
> > +    return 0;
> > +}
> > +
> > +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;
> > +
> > +    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);
> > +    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
> > +
> > +    fw_config.ram_size = ram_size;
> > +    fw_config.mem_freq = 300000000;
> > +    fw_config.nr_cpus = current_machine->smp.cpus;
> > +    fw_config.cpu_clock_freq = get_host_cpu_freq();
> > +}
> > +
> > +static int set_prom_bootparam(ram_addr_t initrd_offset, long initrd_size)
> > +{
> > +    long params_size;
> > +    char memenv[32];
> > +    char highmemenv[32];
> > +    void *params_buf;
> > +    unsigned int *parg_env;
> > +    int ret = 0;
> > +
> > +    /* Allocate params_buf for command line. */
> > +    params_size = 0x100000;
> > +    params_buf = g_malloc0(params_size);
> > +
> > +    /*
> > +     * Layout of params_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 *)params_buf;
> > +
> > +    ret = (3 + 1) * 4;
> > +    *parg_env++ = (BOOTPARAM_ADDR + ret);
> > +    ret += (1 + snprintf(params_buf + ret, 256 - ret, "g"));
> > +
> > +    /* argv1 */
> > +    *parg_env++ = BOOTPARAM_ADDR + ret;
> > +    if (initrd_size > 0)
> > +        ret += (1 + snprintf(params_buf + ret, 256 - ret,
> > +                "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s",
> > +                PHYS_TO_VIRT((uint32_t)initrd_offset),
> > +                initrd_size, loaderparams.kernel_cmdline));
> > +    else
> > +        ret += (1 + snprintf(params_buf + ret, 256 - ret, "%s",
> > +                loaderparams.kernel_cmdline));
> > +
> > +    /* argv2 */
> > +    *parg_env++ = BOOTPARAM_ADDR + 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);
> > +
> > +    setenv("memsize", memenv, 1);
> > +    setenv("highmemsize", highmemenv, 1);
>
> These setenv looks pointless.
memsize and highmemsize is standard MIPS kernel parameters.

>
> > +
> > +    ret = ((ret + 32) & ~31);
> > +
> > +    boot_params_buf = (void *)(params_buf + ret);
> > +    boot_params_p = boot_params_buf + align(sizeof(struct boot_params));
> > +
> > +    init_boot_param(boot_params_buf);
> > +
> > +    rom_add_blob_fixed("params", params_buf, params_size,
> > +                       BOOTPARAM_PHYADDR);
> > +    loaderparams.a0 = 2;
> > +    loaderparams.a1 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR;
> > +    loaderparams.a2 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR + ret;
> > +
> > +    return 0;
> > +}
> > +
> > +static int64_t load_kernel(CPUMIPSState *env)
> > +{
> > +    long kernel_size;
> > +    ram_addr_t initrd_offset;
> > +    int64_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, INITRD_OFFSET);
> > +
> > +            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 parameters. */
> > +    set_prom_bootparam(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 void loongson3_isa_init(qemu_irq intc)
> > +{
> > +    qemu_irq *i8259;
> > +    ISABus *isa_bus;
> > +
> > +    isa_bus = isa_bus_new(NULL, get_system_memory(), get_system_io(), &error_abort);
> > +
> > +    /* Interrupt controller */
> > +    /* The 8259 -> IP3  */
> > +    i8259 = i8259_init(isa_bus, intc);
> > +    isa_bus_irqs(isa_bus, i8259);
> > +    /* init other devices */
> > +    isa_create_simple(isa_bus, "i8042");
> > +    mc146818_rtc_init(isa_bus, 2000, NULL);
> > +}
> > +
> > +static inline void loongson3_pcie_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_create(NULL, TYPE_GPEX_HOST);
> > +
> > +    qdev_init_nofail(dev);
> > +    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_PCI_ECAM_SIZE);
> > +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_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_PCI_MEM_BASE, VIRT_PCI_MEM_SIZE);
> > +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_MEM_BASE, mmio_alias);
> > +
> > +    pio_alias = g_new0(MemoryRegion, 1);
> > +    memory_region_init_alias(pio_alias, OBJECT(dev), "pcie-pio",
> > +                             get_system_io(), 0, VIRT_PCI_IO_SIZE);
> > +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_IO_BASE, pio_alias);
> > +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, VIRT_PCI_IO_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);
> > +
> > +    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_init(MachineState *machine)
> > +{
> > +    int i;
> > +    long bios_size;
> > +    MIPSCPU *cpu;
> > +    CPUMIPSState *env;
> > +    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);
> > +
> > +    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 < 256 * 0x100000) {
> > +        error_report("Loongson-3 need at least 256MB memory");
> > +        exit(1);
> > +    }
> > +
> > +    for (i = 0; i < machine->smp.cpus; i++) {
> > +        /* 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);
> > +    }
> > +    env = &MIPS_CPU(first_cpu)->env;
> > +
> > +    /* Allocate RAM/BIOS, 0x00000000~0x10000000 is alias of 0x80000000~0x90000000 */
> > +    memory_region_init_rom(bios, NULL, "loongson3.bios",
> > +                           BIOS_SIZE, &error_fatal);
> > +    memory_region_init_alias(ram, NULL, "loongson3.lowram",
> > +                           machine->ram, 0, 256 * 0x100000);
> > +    memory_region_init_io(iomem, NULL, &loongson3_pm_ops,
> > +                           NULL, "loongson3_pm", PM_MMIO_SIZE);
> > +
> > +    memory_region_add_subregion(address_space_mem, 0x00000000LL, ram);
> > +    memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios);
> > +    memory_region_add_subregion(address_space_mem, 0x80000000LL, machine->ram);
> > +    memory_region_add_subregion(address_space_mem, PM_MMIO_ADDR, iomem);
> > +
> > +    /*
> > +     * We do not support flash operation, just loading pmon.bin as raw BIOS.
> > +     * Please use -L to set the BIOS path and -bios to set bios name.
> > +     */
> > +
> > +    if (kernel_filename) {
> > +        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);
> > +        rom_add_blob_fixed("bios",
> > +                         bios_boot_code, sizeof(bios_boot_code), 0x1fc00000LL);
> > +    } 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, 0x1fc00000LL,
> > +                                            BIOS_SIZE);
> > +            g_free(filename);
> > +        } else {
> > +            bios_size = -1;
> > +        }
> > +
> > +        if ((bios_size < 0 || bios_size > BIOS_SIZE) &&
> > +            !kernel_filename && !qtest_enabled()) {
> > +            error_report("Could not load MIPS bios '%s'", bios_name);
> > +            exit(1);
> > +        }
> > +
> > +        fw_conf_init(ram_size);
> > +        rom_add_blob_fixed("fw_conf",
> > +                         &fw_config, sizeof(fw_config), FW_CONF_ADDR);
> > +    }
> > +
> > +    msi_nonbroken = true;
>
> As this machine is not reflecting any actual Loongson-3 system, I would
> say "loongson3-virt" can be a better name.
I think "loongson3" can be a generic name, we don't need to show
"virt" explicitly.

>
> > +    loongson3_isa_init(env->irq[3]);
> > +    loongson3_pcie_init(machine, isa_pic);
> > +
> > +    if (serial_hd(0)) {
> > +        serial_mm_init(address_space_mem, 0x1fe001e0, 0, env->irq[2],
> > +                           115200, serial_hd(0), DEVICE_NATIVE_ENDIAN);
> > +    }
> > +}
> > +
> > +static void mips_loongson3_machine_init(MachineClass *mc)
> > +{
> > +    mc->desc = "Generic Loongson-3 Platform";
> > +    mc->init = mips_loongson3_init;
> > +    mc->block_default_type = IF_IDE;
> > +    mc->max_cpus = LOONGSON_MAX_VCPUS;
> > +    mc->default_ram_id = "loongson3.highram";
> > +    mc->default_ram_size = 1200 * MiB;
>
> 1200MiB looks wired... Why not 1024?
Oh, it is just because our Fedora28 needs more than 1024MB to work
fine, maybe 1280 is better?

>
> > +    mc->kvm_type = mips_kvm_type;
> > +    mc->minimum_page_bits = 14;
> > +}
> > +
> > +DEFINE_MACHINE("loongson3", mips_loongson3_machine_init)
> >
>
> As this machine is not reflecting any actual Loongson-3 system, I would
> say "loongson3-virt" can be a better name.
>
> Furthermore, the design of machine can be updated over time. So probably
> we can add a version suffix to it just like what arm-virt did.
>
> Thanks!
>
> --
> - Jiaxun
>


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

* Re: [PATCH for-5.1 V4 3/4] hw/mips: Add Loongson-3 machine support (with KVM)
  2020-06-11  7:49     ` Huacai Chen
@ 2020-06-11  8:12       ` Jiaxun Yang
  2020-06-11  8:50         ` Aleksandar Markovic
  0 siblings, 1 reply; 41+ messages in thread
From: Jiaxun Yang @ 2020-06-11  8:12 UTC (permalink / raw)
  To: Huacai Chen
  Cc: Huacai Chen, Philippe Mathieu-Daudé,
	QEMU Developers, Aleksandar Markovic, Aleksandar Rikalo,
	Aurelien Jarno



在 2020/6/11 15:49, Huacai Chen 写道:
> Hi, Jiaxun,
> 
> On Thu, Jun 11, 2020 at 1:59 PM Jiaxun Yang <jiaxun.yang@flygoat.com> wrote:
>>
>>
>>
>> 在 2020/6/2 10:39, Huacai Chen 写道:
>>> Add Loongson-3 based machine support, it use i8259 as the interrupt
>>> controler and use GPEX as the pci controller. Currently it can only
>>> work with KVM, but we will add TCG support in future.
>>>
>>> We already have a full functional Linux kernel (based on Linux-5.4.x LTS
>>> but not upstream yet) here:
>>>
>>> https://github.com/chenhuacai/linux
>>>
>>> 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 the a Loongson-3A4000 host with this kernel;
>>> 4, Build QEMU-5.0.0 with this patchset;
>>> 5, modprobe kvm;
>>> 6, Use QEMU with TCG (available in future):
>>>          qemu-system-mips64el -M loongson3,accel=tcg -cpu Loongson-3A1000 -kernel <path_to_kernel> -append ...
>>>      Use QEMU with KVM (available at present):
>>>          qemu-system-mips64el -M loongson3,accel=kvm -cpu Loongson-3A4000 -kernel <path_to_kernel> -append ...
>>>
>>>      The "-cpu" parameter can be omitted 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>
>>> Reviewed-by: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
>>> ---
>>>    default-configs/mips64el-softmmu.mak |   1 +
>>>    hw/mips/Kconfig                      |  10 +
>>>    hw/mips/Makefile.objs                |   1 +
>>>    hw/mips/loongson3.c                  | 901 +++++++++++++++++++++++++++++++++++
>>>    4 files changed, 913 insertions(+)
>>>    create mode 100644 hw/mips/loongson3.c
>>
>> Hi there,
>>
>> I was working on TCG support based on this machine, and noticed some
>> minor issue here.
>>
>> Huacai, would you mind me to include your machine support in my TCG
>> series? As currently KVM support is blocked kernel.
>>
>>

[...]

>>> +
>>> +static int get_host_cpu_freq(void)
>>> +{
>>
>> "model name" have not been accppted by mainline kernel.
>> Probably asking kernel frequency via a part of QEMU IOCTL is a better
>> option?
> Is there exsiting better method? I will use if possible.

CPUCFG instruction introduced by 3A4000 have CCfreq domain to describe 
the frequency.
Or we can add it to kernel's data structure?

> 
>>
>>> +    int fd = 0, freq = 0;
>>> +    char buf[1024], *buf_p;
>>> +
>>> +    fd = open("/proc/cpuinfo", O_RDONLY);
>>> +    if (fd == -1) {
>>> +        fprintf(stderr, "Failed to open /proc/cpuinfo!\n");
>>> +        return 0;
>>> +    }
>>> +
>>> +    if (read(fd, buf, 1024) < 0) {
>>> +        close(fd);
>>> +        fprintf(stderr, "Failed to read /proc/cpuinfo!\n");
>>> +        return 0;
>>> +    }
>>> +    close(fd);
>>> +
>>> +    buf_p = strstr(buf, "model name");
>>> +    while (*buf_p != '@') {
>>> +        buf_p++;
>>> +    }
>>> +
>>> +    buf_p += 2;
>>> +    memcpy(buf, buf_p, 12);
>>> +    buf_p = buf;
>>> +    while ((*buf_p >= '0') && (*buf_p <= '9')) {
>>> +        buf_p++;
>>> +    }
>>> +    *buf_p = '\0';
>>> +
>>> +    freq = atoi(buf);
>>> +
>>> +    return freq * 1000 * 1000;
>>> +}

[...]

>>> +
>>> +    setenv("memsize", memenv, 1);
>>> +    setenv("highmemsize", highmemenv, 1);
>>
>> These setenv looks pointless.
> memsize and highmemsize is standard MIPS kernel parameters.

By setenv you're not adding it to kernel parameter but adding it to 
*host's* environment variable.

Also memory size have already been passed by loongson's boot_param 
structure so no need to supply it in env again.

> 
>>
>>> +
>>> +    ret = ((ret + 32) & ~31);
>>> +
>>> +    boot_params_buf = (void *)(params_buf + ret);
>>> +    boot_params_p = boot_params_buf + align(sizeof(struct boot_params));
>>> +
>>> +    init_boot_param(boot_params_buf);
>>> +
>>> +    rom_add_blob_fixed("params", params_buf, params_size,
>>> +                       BOOTPARAM_PHYADDR);
>>> +    loaderparams.a0 = 2;
>>> +    loaderparams.a1 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR;
>>> +    loaderparams.a2 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR + ret;
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +static int64_t load_kernel(CPUMIPSState *env)
>>> +{
>>> +    long kernel_size;
>>> +    ram_addr_t initrd_offset;
>>> +    int64_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, INITRD_OFFSET);
>>> +
>>> +            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 parameters. */
>>> +    set_prom_bootparam(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 void loongson3_isa_init(qemu_irq intc)
>>> +{
>>> +    qemu_irq *i8259;
>>> +    ISABus *isa_bus;
>>> +
>>> +    isa_bus = isa_bus_new(NULL, get_system_memory(), get_system_io(), &error_abort);
>>> +
>>> +    /* Interrupt controller */
>>> +    /* The 8259 -> IP3  */
>>> +    i8259 = i8259_init(isa_bus, intc);
>>> +    isa_bus_irqs(isa_bus, i8259);
>>> +    /* init other devices */
>>> +    isa_create_simple(isa_bus, "i8042");
>>> +    mc146818_rtc_init(isa_bus, 2000, NULL);
>>> +}
>>> +
>>> +static inline void loongson3_pcie_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_create(NULL, TYPE_GPEX_HOST);
>>> +
>>> +    qdev_init_nofail(dev);
>>> +    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_PCI_ECAM_SIZE);
>>> +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_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_PCI_MEM_BASE, VIRT_PCI_MEM_SIZE);
>>> +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_MEM_BASE, mmio_alias);
>>> +
>>> +    pio_alias = g_new0(MemoryRegion, 1);
>>> +    memory_region_init_alias(pio_alias, OBJECT(dev), "pcie-pio",
>>> +                             get_system_io(), 0, VIRT_PCI_IO_SIZE);
>>> +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_IO_BASE, pio_alias);
>>> +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, VIRT_PCI_IO_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);
>>> +
>>> +    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_init(MachineState *machine)
>>> +{
>>> +    int i;
>>> +    long bios_size;
>>> +    MIPSCPU *cpu;
>>> +    CPUMIPSState *env;
>>> +    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);
>>> +
>>> +    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 < 256 * 0x100000) {
>>> +        error_report("Loongson-3 need at least 256MB memory");
>>> +        exit(1);
>>> +    }
>>> +
>>> +    for (i = 0; i < machine->smp.cpus; i++) {
>>> +        /* 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);
>>> +    }
>>> +    env = &MIPS_CPU(first_cpu)->env;
>>> +
>>> +    /* Allocate RAM/BIOS, 0x00000000~0x10000000 is alias of 0x80000000~0x90000000 */
>>> +    memory_region_init_rom(bios, NULL, "loongson3.bios",
>>> +                           BIOS_SIZE, &error_fatal);
>>> +    memory_region_init_alias(ram, NULL, "loongson3.lowram",
>>> +                           machine->ram, 0, 256 * 0x100000);
>>> +    memory_region_init_io(iomem, NULL, &loongson3_pm_ops,
>>> +                           NULL, "loongson3_pm", PM_MMIO_SIZE);
>>> +
>>> +    memory_region_add_subregion(address_space_mem, 0x00000000LL, ram);
>>> +    memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios);
>>> +    memory_region_add_subregion(address_space_mem, 0x80000000LL, machine->ram);
>>> +    memory_region_add_subregion(address_space_mem, PM_MMIO_ADDR, iomem);
>>> +
>>> +    /*
>>> +     * We do not support flash operation, just loading pmon.bin as raw BIOS.
>>> +     * Please use -L to set the BIOS path and -bios to set bios name.
>>> +     */
>>> +
>>> +    if (kernel_filename) {
>>> +        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);
>>> +        rom_add_blob_fixed("bios",
>>> +                         bios_boot_code, sizeof(bios_boot_code), 0x1fc00000LL);
>>> +    } 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, 0x1fc00000LL,
>>> +                                            BIOS_SIZE);
>>> +            g_free(filename);
>>> +        } else {
>>> +            bios_size = -1;
>>> +        }
>>> +
>>> +        if ((bios_size < 0 || bios_size > BIOS_SIZE) &&
>>> +            !kernel_filename && !qtest_enabled()) {
>>> +            error_report("Could not load MIPS bios '%s'", bios_name);
>>> +            exit(1);
>>> +        }
>>> +
>>> +        fw_conf_init(ram_size);
>>> +        rom_add_blob_fixed("fw_conf",
>>> +                         &fw_config, sizeof(fw_config), FW_CONF_ADDR);
>>> +    }
>>> +
>>> +    msi_nonbroken = true;
>>
>> As this machine is not reflecting any actual Loongson-3 system, I would
>> say "loongson3-virt" can be a better name.
> I think "loongson3" can be a generic name, we don't need to show
> "virt" explicitly.
> 
>>
>>> +    loongson3_isa_init(env->irq[3]);
>>> +    loongson3_pcie_init(machine, isa_pic);
>>> +
>>> +    if (serial_hd(0)) {
>>> +        serial_mm_init(address_space_mem, 0x1fe001e0, 0, env->irq[2],
>>> +                           115200, serial_hd(0), DEVICE_NATIVE_ENDIAN);
>>> +    }
>>> +}
>>> +
>>> +static void mips_loongson3_machine_init(MachineClass *mc)
>>> +{
>>> +    mc->desc = "Generic Loongson-3 Platform";
>>> +    mc->init = mips_loongson3_init;
>>> +    mc->block_default_type = IF_IDE;
>>> +    mc->max_cpus = LOONGSON_MAX_VCPUS;
>>> +    mc->default_ram_id = "loongson3.highram";
>>> +    mc->default_ram_size = 1200 * MiB;
>>
>> 1200MiB looks wired... Why not 1024?
> Oh, it is just because our Fedora28 needs more than 1024MB to work
> fine, maybe 1280 is better?

Ahh if that's the reason then it looks fine for me.

> 
>>
>>> +    mc->kvm_type = mips_kvm_type;
>>> +    mc->minimum_page_bits = 14;
>>> +}
>>> +
>>> +DEFINE_MACHINE("loongson3", mips_loongson3_machine_init)
>>>
>>
>> As this machine is not reflecting any actual Loongson-3 system, I would
>> say "loongson3-virt" can be a better name
>>
>> Furthermore, the design of machine can be updated over time. So probably
>> we can add a version suffix to it just like what arm-virt did.
>>
>> Thanks!
>>
>> --
>> - Jiaxun
>>

-- 
- Jiaxun


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

* Re: [PATCH for-5.1 V4 3/4] hw/mips: Add Loongson-3 machine support (with KVM)
  2020-06-11  8:12       ` Jiaxun Yang
@ 2020-06-11  8:50         ` Aleksandar Markovic
  2020-06-12  6:07           ` Huacai Chen
  0 siblings, 1 reply; 41+ messages in thread
From: Aleksandar Markovic @ 2020-06-11  8:50 UTC (permalink / raw)
  To: Jiaxun Yang
  Cc: Huacai Chen, Huacai Chen, Philippe Mathieu-Daudé,
	QEMU Developers, Aleksandar Rikalo, Aurelien Jarno

> >>> +    int fd = 0, freq = 0;
> >>> +    char buf[1024], *buf_p;

1024 should have been defined via preprocessor constant

> >>> +
> >>> +    fd = open("/proc/cpuinfo", O_RDONLY);
> >>> +    if (fd == -1) {
> >>> +        fprintf(stderr, "Failed to open /proc/cpuinfo!\n");
> >>> +        return 0;
> >>> +    }
> >>> +
> >>> +    if (read(fd, buf, 1024) < 0) {

The same constant should be used here.

...

> >>> +    loaderparams.a1 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR;
> >>> +    loaderparams.a2 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR + ret;

What is 0xffffffff80000000ULL? Preprocessor constant possible?

...

> >>> +    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);
> >>> +        }
> >>> +    }

Some explanation needs to be written in comments about the code segment above.

I find the whole segment a little bit questionable. For non-KVM one
CPU, for KVM another? Why non-KVM can't use both, and allow to be
specified via command line?

> >>> +    memory_region_add_subregion(address_space_mem, 0x00000000LL, ram);
> >>> +    memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios);
> >>> +    memory_region_add_subregion(address_space_mem, 0x80000000LL, machine->ram);
> >>> +    memory_region_add_subregion(address_space_mem, PM_MMIO_ADDR, iomem);

I would avoid hard coded numbers.

> >>> +
> >>> +    /*
> >>> +     * We do not support flash operation, just loading pmon.bin as raw BIOS.
> >>> +     * Please use -L to set the BIOS path and -bios to set bios name.
> >>> +     */
> >>> +
> >>> +    if (kernel_filename) {
> >>> +        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);
> >>> +        rom_add_blob_fixed("bios",
> >>> +                         bios_boot_code, sizeof(bios_boot_code), 0x1fc00000LL);

Again, here, 0x1fc00000LL. This should be defined and properly named
via preprocessor.

> >>> +    } 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, 0x1fc00000LL,

Again.

> >>> +                                            BIOS_SIZE);
> >>> +            g_free(filename);
> >>> +        } else {
> >>> +            bios_size = -1;
> >>> +        }
> >>> +
> >>> +    if (serial_hd(0)) {
> >>> +        serial_mm_init(address_space_mem, 0x1fe001e0, 0, env->irq[2],
> >>> +                           115200, serial_hd(0), DEVICE_NATIVE_ENDIAN);

115200 should be something like XXX_DEFAULT_BAUDRATE

> >>> +    }
> >>> +}
> >>> +
> >>> +static void mips_loongson3_machine_init(MachineClass *mc)
> >>> +{
> >>> +    mc->desc = "Generic Loongson-3 Platform";
> >>> +    mc->init = mips_loongson3_init;
> >>> +    mc->block_default_type = IF_IDE;
> >>> +    mc->max_cpus = LOONGSON_MAX_VCPUS;
> >>> +    mc->default_ram_id = "loongson3.highram";
> >>> +    mc->default_ram_size = 1200 * MiB;
> >>
> >> 1200MiB looks wired... Why not 1024?
> > Oh, it is just because our Fedora28 needs more than 1024MB to work
> > fine, maybe 1280 is better?
>
> Ahh if that's the reason then it looks fine for me.
>

These choices should be documented in brief comments.

If left this way, we leave future developers solve puzzles and
desperately guessing.

Thanks,
Aleksandar


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

* Re: [PATCH for-5.1 V4 3/4] hw/mips: Add Loongson-3 machine support (with KVM)
  2020-06-11  8:50         ` Aleksandar Markovic
@ 2020-06-12  6:07           ` Huacai Chen
  0 siblings, 0 replies; 41+ messages in thread
From: Huacai Chen @ 2020-06-12  6:07 UTC (permalink / raw)
  To: Aleksandar Markovic
  Cc: Huacai Chen, Philippe Mathieu-Daudé,
	Jiaxun Yang, QEMU Developers, Aleksandar Rikalo, Aurelien Jarno

Hi, Alexandar,

On Thu, Jun 11, 2020 at 4:51 PM Aleksandar Markovic
<aleksandar.qemu.devel@gmail.com> wrote:
>
> > >>> +    int fd = 0, freq = 0;
> > >>> +    char buf[1024], *buf_p;
>
> 1024 should have been defined via preprocessor constant
>
> > >>> +
> > >>> +    fd = open("/proc/cpuinfo", O_RDONLY);
> > >>> +    if (fd == -1) {
> > >>> +        fprintf(stderr, "Failed to open /proc/cpuinfo!\n");
> > >>> +        return 0;
> > >>> +    }
> > >>> +
> > >>> +    if (read(fd, buf, 1024) < 0) {
>
> The same constant should be used here.
>
> ...
>
> > >>> +    loaderparams.a1 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR;
> > >>> +    loaderparams.a2 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR + ret;
>
> What is 0xffffffff80000000ULL? Preprocessor constant possible?
>
> ...
>
> > >>> +    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);
> > >>> +        }
> > >>> +    }
>
> Some explanation needs to be written in comments about the code segment above.
>
> I find the whole segment a little bit questionable. For non-KVM one
> CPU, for KVM another? Why non-KVM can't use both, and allow to be
> specified via command line?
>
> > >>> +    memory_region_add_subregion(address_space_mem, 0x00000000LL, ram);
> > >>> +    memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios);
> > >>> +    memory_region_add_subregion(address_space_mem, 0x80000000LL, machine->ram);
> > >>> +    memory_region_add_subregion(address_space_mem, PM_MMIO_ADDR, iomem);
>
> I would avoid hard coded numbers.
>
> > >>> +
> > >>> +    /*
> > >>> +     * We do not support flash operation, just loading pmon.bin as raw BIOS.
> > >>> +     * Please use -L to set the BIOS path and -bios to set bios name.
> > >>> +     */
> > >>> +
> > >>> +    if (kernel_filename) {
> > >>> +        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);
> > >>> +        rom_add_blob_fixed("bios",
> > >>> +                         bios_boot_code, sizeof(bios_boot_code), 0x1fc00000LL);
>
> Again, here, 0x1fc00000LL. This should be defined and properly named
> via preprocessor.
>
> > >>> +    } 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, 0x1fc00000LL,
>
> Again.
>
> > >>> +                                            BIOS_SIZE);
> > >>> +            g_free(filename);
> > >>> +        } else {
> > >>> +            bios_size = -1;
> > >>> +        }
> > >>> +
> > >>> +    if (serial_hd(0)) {
> > >>> +        serial_mm_init(address_space_mem, 0x1fe001e0, 0, env->irq[2],
> > >>> +                           115200, serial_hd(0), DEVICE_NATIVE_ENDIAN);
>
> 115200 should be something like XXX_DEFAULT_BAUDRATE
>
> > >>> +    }
> > >>> +}
> > >>> +
> > >>> +static void mips_loongson3_machine_init(MachineClass *mc)
> > >>> +{
> > >>> +    mc->desc = "Generic Loongson-3 Platform";
> > >>> +    mc->init = mips_loongson3_init;
> > >>> +    mc->block_default_type = IF_IDE;
> > >>> +    mc->max_cpus = LOONGSON_MAX_VCPUS;
> > >>> +    mc->default_ram_id = "loongson3.highram";
> > >>> +    mc->default_ram_size = 1200 * MiB;
> > >>
> > >> 1200MiB looks wired... Why not 1024?
> > > Oh, it is just because our Fedora28 needs more than 1024MB to work
> > > fine, maybe 1280 is better?
> >
> > Ahh if that's the reason then it looks fine for me.
> >
>
> These choices should be documented in brief comments.
>
> If left this way, we leave future developers solve puzzles and
> desperately guessing.
>
> Thanks,
> Aleksandar
Thank you for your advice, I will improve that.

Huacai


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

* Re: [PATCH for-5.1 V4 3/4] hw/mips: Add Loongson-3 machine support (with KVM)
  2020-06-02  2:39 ` [PATCH for-5.1 V4 3/4] hw/mips: Add Loongson-3 machine support (with KVM) Huacai Chen
  2020-06-06  7:32   ` Aleksandar Markovic
  2020-06-11  5:58   ` Jiaxun Yang
@ 2020-06-14  7:51   ` Aleksandar Markovic
  2020-06-15  0:55     ` Huacai Chen
  2 siblings, 1 reply; 41+ messages in thread
From: Aleksandar Markovic @ 2020-06-14  7:51 UTC (permalink / raw)
  To: Huacai Chen
  Cc: Huacai Chen, Philippe Mathieu-Daudé,
	QEMU Developers, Huacai Chen, Aleksandar Rikalo, Aurelien Jarno

Hi, Huacai, this is another round of comments, that should be addressed in v5.

уто, 2. јун 2020. у 04:40 Huacai Chen <zltjiangshi@gmail.com> је написао/ла:
>
> Add Loongson-3 based machine support, it use i8259 as the interrupt
> controler and use GPEX as the pci controller. Currently it can only
> work with KVM, but we will add TCG support in future.
>

Add this paragraph at this place in the commit message:

"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, a regular deprecation
procedure shall occur for "loongson3-virt" machine."

> We already have a full functional Linux kernel (based on Linux-5.4.x LTS
> but not upstream yet) here:
>
> https://github.com/chenhuacai/linux
>
> 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 the a Loongson-3A4000 host with this kernel;
> 4, Build QEMU-5.0.0 with this patchset;
> 5, modprobe kvm;
> 6, Use QEMU with TCG (available in future):
>        qemu-system-mips64el -M loongson3,accel=tcg -cpu Loongson-3A1000 -kernel <path_to_kernel> -append ...

Machine should be named loongson3-virt.

>    Use QEMU with KVM (available at present):
>        qemu-system-mips64el -M loongson3,accel=kvm -cpu Loongson-3A4000 -kernel <path_to_kernel> -append ...
>

Machine should be named loongson3-virt.

>    The "-cpu" parameter can be omitted here and QEMU will use the correct type for TCG/KVM automatically.
>

This is not a good approach, the cpu parameter should be required,
and, if it is not correct for particular circumstance, an error
message should be emitted to the user, and the emulation terminated.

> 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                      |  10 +
>  hw/mips/Makefile.objs                |   1 +
>  hw/mips/loongson3.c                  | 901 +++++++++++++++++++++++++++++++++++

The name of the file should be loongson3-virt.c

>  4 files changed, 913 insertions(+)
>  create mode 100644 hw/mips/loongson3.c
>
> diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak
> index 9f8a3ef..2a2a3fb 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_LOONGSON3=y

CONFIG_LOONGSON3-VIRT

>  CONFIG_ATI_VGA=y
>  CONFIG_RTL8139_PCI=y
>  CONFIG_JAZZ=y
> diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig
> index 67d39c5..42931fd 100644
> --- a/hw/mips/Kconfig
> +++ b/hw/mips/Kconfig
> @@ -45,6 +45,16 @@ config FULOONG
>      bool
>      select PCI_BONITO
>
> +config LOONGSON3

LOONGSON3-VIRT

> +    bool
> +    select PCKBD
> +    select SERIAL
> +    select ISA_BUS
> +    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/Makefile.objs b/hw/mips/Makefile.objs
> index 3b3e6ea..31dedcb 100644
> --- a/hw/mips/Makefile.objs
> +++ b/hw/mips/Makefile.objs
> @@ -4,5 +4,6 @@ obj-$(CONFIG_MALTA) += gt64xxx_pci.o malta.o
>  obj-$(CONFIG_MIPSSIM) += mipssim.o
>  obj-$(CONFIG_JAZZ) += jazz.o
>  obj-$(CONFIG_FULOONG) += fuloong2e.o
> +obj-$(CONFIG_LOONGSON3) += loongson3.o

CONFIG_LOONGSON3-VIRT

>  obj-$(CONFIG_MIPS_CPS) += cps.o
>  obj-$(CONFIG_MIPS_BOSTON) += boston.o
> diff --git a/hw/mips/loongson3.c b/hw/mips/loongson3.c
> new file mode 100644
> index 0000000..e4b9538
> --- /dev/null
> +++ b/hw/mips/loongson3.c

The file shoul be named loongson3-virt.c

> @@ -0,0 +1,901 @@
> +/*
> + * Generic Loongson-3 Platform support

"Support for loongson3-virt platform"

> + *
> + * Copyright (c) 2016-2020 Huacai Chen (chenhc@lemote.com)
> + * This code is licensed under the GNU GPL v2.
> + *
> + * Contributions are licensed under the terms of the GNU GPL,
> + * version 2 or (at your option) any later version.

License preamble should be harmonized, as we already agreed upon.

> + */
> +
> +/*
> + * Generic 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 "hw/boards.h"
> +#include "hw/char/serial.h"
> +#include "hw/mips/mips.h"
> +#include "hw/mips/cpudevs.h"
> +#include "hw/intc/i8259.h"
> +#include "hw/loader.h"
> +#include "hw/ide.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 "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 INITRD_OFFSET         0x04000000
> +#define BOOTPARAM_ADDR        0x8ff00000
> +#define BOOTPARAM_PHYADDR     0x0ff00000
> +#define CFG_ADDR              0x0f100000
> +#define FW_CONF_ADDR          0x0fff0000
> +#define PM_MMIO_ADDR          0x10080000
> +#define PM_MMIO_SIZE          0x100
> +#define PM_CNTL_MODE          0x10
> +
> +#define PHYS_TO_VIRT(x) ((x) | ~(target_ulong)0x7fffffff)
> +
> +/* Loongson-3 has a 2MB flash rom */
> +#define BIOS_SIZE               (2 * MiB)
> +#define LOONGSON_MAX_VCPUS      16
> +
> +#define LOONGSON3_BIOSNAME "bios_loongson3.bin"
> +
> +#define PCIE_IRQ_BASE       3
> +
> +#define VIRT_PCI_IO_BASE    0x18000000ul
> +#define VIRT_PCI_IO_SIZE    0x000c0000ul
> +#define VIRT_PCI_MEM_BASE   0x40000000ul
> +#define VIRT_PCI_MEM_SIZE   0x40000000ul
> +#define VIRT_PCI_ECAM_BASE  0x1a000000ul
> +#define VIRT_PCI_ECAM_SIZE  0x02000000ul
> +
> +#define align(x) (((x) + 63) & ~63)
> +
> +/* 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;
> +};
> +
> +static struct _fw_config {
> +    unsigned long ram_size;
> +    unsigned int mem_freq;
> +    unsigned int nr_cpus;
> +    unsigned int cpu_clock_freq;
> +} fw_config;
> +
> +static struct _loaderparams {
> +    unsigned long ram_size;
> +    const char *kernel_cmdline;
> +    const char *kernel_filename;
> +    const char *initrd_filename;
> +    int64_t kernel_entry;
> +    unsigned long a0, a1, a2;
> +} loaderparams;
> +
> +static void *boot_params_p;
> +static void *boot_params_buf;
> +
> +static unsigned int bios_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                                                      */
> +};
> +
> +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 = (loaderparams.ram_size > 0x10000000
> +                            ? 256 : (loaderparams.ram_size >> 20)) - 16;
> +
> +    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 > 0x10000000
> +                            ? (loaderparams.ram_size >> 20) - 256 : 0);
> +
> +    return emap;
> +}
> +
> +static int get_host_cpu_freq(void)
> +{
> +    int fd = 0, freq = 0;
> +    char buf[1024], *buf_p;
> +
> +    fd = open("/proc/cpuinfo", O_RDONLY);
> +    if (fd == -1) {
> +        fprintf(stderr, "Failed to open /proc/cpuinfo!\n");
> +        return 0;
> +    }
> +
> +    if (read(fd, buf, 1024) < 0) {
> +        close(fd);
> +        fprintf(stderr, "Failed to read /proc/cpuinfo!\n");
> +        return 0;
> +    }
> +    close(fd);
> +
> +    buf_p = strstr(buf, "model name");
> +    while (*buf_p != '@') {
> +        buf_p++;
> +    }
> +
> +    buf_p += 2;
> +    memcpy(buf, buf_p, 12);
> +    buf_p = buf;
> +    while ((*buf_p >= '0') && (*buf_p <= '9')) {
> +        buf_p++;
> +    }
> +    *buf_p = '\0';
> +
> +    freq = atoi(buf);
> +
> +    return freq * 1000 * 1000;
> +}
> +
> +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 = 0x14C000;
> +    c->cpu_clock_freq = get_host_cpu_freq();
> +    if (!c->cpu_clock_freq) {
> +        c->cpu_clock_freq = 500000000;
> +    }
> +
> +    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;
> +    s->uarts[0].uart_base = 0x1fe001e0;
> +
> +    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_PCI_MEM_BASE;
> +    irq_info->pci_mem_end_addr   = VIRT_PCI_MEM_BASE + VIRT_PCI_MEM_SIZE - 1;
> +    irq_info->pci_io_start_addr  = VIRT_PCI_IO_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, "2016-05-16");
> +
> +    return special;
> +}
> +
> +static void init_loongson_params(struct loongson_params *lp)
> +{
> +    void *p = boot_params_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));
> +
> +    boot_params_p = p;
> +}
> +
> +static void init_smbios(struct smbios_tables *smbios)
> +{
> +    smbios->vers = 1;
> +    init_loongson_params(&(smbios->lp));
> +}
> +
> +static void init_efi(struct efi_loongson *efi)
> +{
> +    init_smbios(&(efi->smbios));
> +}
> +
> +static void init_reset_system(struct efi_reset_system_t *reset)
> +{
> +    reset->Shutdown = 0xffffffffbfc000a8;
> +    reset->ResetCold = 0xffffffffbfc00080;
> +    reset->ResetWarm = 0xffffffffbfc00080;
> +}
> +
> +static int init_boot_param(struct boot_params *bp)
> +{
> +    init_efi(&(bp->efi));
> +    init_reset_system(&(bp->reset_system));
> +
> +    return 0;
> +}
> +
> +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;
> +
> +    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);
> +    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
> +
> +    fw_config.ram_size = ram_size;
> +    fw_config.mem_freq = 300000000;
> +    fw_config.nr_cpus = current_machine->smp.cpus;
> +    fw_config.cpu_clock_freq = get_host_cpu_freq();
> +}
> +
> +static int set_prom_bootparam(ram_addr_t initrd_offset, long initrd_size)
> +{
> +    long params_size;
> +    char memenv[32];
> +    char highmemenv[32];
> +    void *params_buf;
> +    unsigned int *parg_env;
> +    int ret = 0;
> +
> +    /* Allocate params_buf for command line. */
> +    params_size = 0x100000;
> +    params_buf = g_malloc0(params_size);
> +
> +    /*
> +     * Layout of params_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 *)params_buf;
> +
> +    ret = (3 + 1) * 4;
> +    *parg_env++ = (BOOTPARAM_ADDR + ret);
> +    ret += (1 + snprintf(params_buf + ret, 256 - ret, "g"));
> +
> +    /* argv1 */
> +    *parg_env++ = BOOTPARAM_ADDR + ret;
> +    if (initrd_size > 0)
> +        ret += (1 + snprintf(params_buf + ret, 256 - ret,
> +                "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s",
> +                PHYS_TO_VIRT((uint32_t)initrd_offset),
> +                initrd_size, loaderparams.kernel_cmdline));
> +    else
> +        ret += (1 + snprintf(params_buf + ret, 256 - ret, "%s",
> +                loaderparams.kernel_cmdline));
> +
> +    /* argv2 */
> +    *parg_env++ = BOOTPARAM_ADDR + 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);
> +
> +    setenv("memsize", memenv, 1);
> +    setenv("highmemsize", highmemenv, 1);
> +
> +    ret = ((ret + 32) & ~31);
> +
> +    boot_params_buf = (void *)(params_buf + ret);
> +    boot_params_p = boot_params_buf + align(sizeof(struct boot_params));
> +
> +    init_boot_param(boot_params_buf);
> +
> +    rom_add_blob_fixed("params", params_buf, params_size,
> +                       BOOTPARAM_PHYADDR);
> +    loaderparams.a0 = 2;
> +    loaderparams.a1 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR;
> +    loaderparams.a2 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR + ret;
> +
> +    return 0;
> +}
> +
> +static int64_t load_kernel(CPUMIPSState *env)
> +{
> +    long kernel_size;
> +    ram_addr_t initrd_offset;
> +    int64_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, INITRD_OFFSET);
> +
> +            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 parameters. */
> +    set_prom_bootparam(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 void loongson3_isa_init(qemu_irq intc)

Rename it to loongson3-virt_isa_init.

> +{
> +    qemu_irq *i8259;
> +    ISABus *isa_bus;
> +
> +    isa_bus = isa_bus_new(NULL, get_system_memory(), get_system_io(), &error_abort);
> +
> +    /* Interrupt controller */
> +    /* The 8259 -> IP3  */
> +    i8259 = i8259_init(isa_bus, intc);
> +    isa_bus_irqs(isa_bus, i8259);
> +    /* init other devices */
> +    isa_create_simple(isa_bus, "i8042");
> +    mc146818_rtc_init(isa_bus, 2000, NULL);
> +}
> +
> +static inline void loongson3_pcie_init(MachineState *machine, DeviceState *pic)

Rename it to loongson3-virt_pcie_init.

> +{
> +    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_create(NULL, TYPE_GPEX_HOST);
> +
> +    qdev_init_nofail(dev);
> +    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_PCI_ECAM_SIZE);
> +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_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_PCI_MEM_BASE, VIRT_PCI_MEM_SIZE);
> +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_MEM_BASE, mmio_alias);
> +
> +    pio_alias = g_new0(MemoryRegion, 1);
> +    memory_region_init_alias(pio_alias, OBJECT(dev), "pcie-pio",
> +                             get_system_io(), 0, VIRT_PCI_IO_SIZE);
> +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_IO_BASE, pio_alias);
> +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, VIRT_PCI_IO_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);
> +
> +    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_init(MachineState *machine)

Rename it to loongson3-virt_init.

> +{
> +    int i;
> +    long bios_size;
> +    MIPSCPU *cpu;
> +    CPUMIPSState *env;
> +    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);
> +
> +    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 < 256 * 0x100000) {
> +        error_report("Loongson-3 need at least 256MB memory");
> +        exit(1);
> +    }
> +
> +    for (i = 0; i < machine->smp.cpus; i++) {
> +        /* 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);
> +    }
> +    env = &MIPS_CPU(first_cpu)->env;
> +
> +    /* Allocate RAM/BIOS, 0x00000000~0x10000000 is alias of 0x80000000~0x90000000 */
> +    memory_region_init_rom(bios, NULL, "loongson3.bios",
> +                           BIOS_SIZE, &error_fatal);
> +    memory_region_init_alias(ram, NULL, "loongson3.lowram",
> +                           machine->ram, 0, 256 * 0x100000);
> +    memory_region_init_io(iomem, NULL, &loongson3_pm_ops,
> +                           NULL, "loongson3_pm", PM_MMIO_SIZE);
> +
> +    memory_region_add_subregion(address_space_mem, 0x00000000LL, ram);
> +    memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios);
> +    memory_region_add_subregion(address_space_mem, 0x80000000LL, machine->ram);
> +    memory_region_add_subregion(address_space_mem, PM_MMIO_ADDR, iomem);
> +
> +    /*
> +     * We do not support flash operation, just loading pmon.bin as raw BIOS.
> +     * Please use -L to set the BIOS path and -bios to set bios name.
> +     */
> +
> +    if (kernel_filename) {
> +        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);
> +        rom_add_blob_fixed("bios",
> +                         bios_boot_code, sizeof(bios_boot_code), 0x1fc00000LL);
> +    } 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, 0x1fc00000LL,
> +                                            BIOS_SIZE);
> +            g_free(filename);
> +        } else {
> +            bios_size = -1;
> +        }
> +
> +        if ((bios_size < 0 || bios_size > BIOS_SIZE) &&
> +            !kernel_filename && !qtest_enabled()) {
> +            error_report("Could not load MIPS bios '%s'", bios_name);
> +            exit(1);
> +        }
> +
> +        fw_conf_init(ram_size);
> +        rom_add_blob_fixed("fw_conf",
> +                         &fw_config, sizeof(fw_config), FW_CONF_ADDR);
> +    }
> +
> +    msi_nonbroken = true;
> +    loongson3_isa_init(env->irq[3]);
> +    loongson3_pcie_init(machine, isa_pic);

Names for two last functions should be already different.

> +
> +    if (serial_hd(0)) {
> +        serial_mm_init(address_space_mem, 0x1fe001e0, 0, env->irq[2],
> +                           115200, serial_hd(0), DEVICE_NATIVE_ENDIAN);
> +    }
> +}
> +
> +static void mips_loongson3_machine_init(MachineClass *mc)

Rename it to loongson3-virt_machine_init.

> +{
> +    mc->desc = "Generic Loongson-3 Platform";
> +    mc->init = mips_loongson3_init;
> +    mc->block_default_type = IF_IDE;
> +    mc->max_cpus = LOONGSON_MAX_VCPUS;
> +    mc->default_ram_id = "loongson3.highram";
> +    mc->default_ram_size = 1200 * MiB;
> +    mc->kvm_type = mips_kvm_type;
> +    mc->minimum_page_bits = 14;
> +}
> +
> +DEFINE_MACHINE("loongson3", mips_loongson3_machine_init)

DEFINE_MACHINE("loongson3-virt", loongson3-virt_machine_init)

> --
> 2.7.0
>


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

* Re: [PATCH for-5.1 V4 1/4] hw/mips: Implement the kvm_type() hook in MachineClass
  2020-06-02  2:39 ` [PATCH for-5.1 V4 1/4] hw/mips: Implement the kvm_type() hook in MachineClass Huacai Chen
  2020-06-03 14:34   ` Aleksandar Markovic
@ 2020-06-14  8:07   ` Aleksandar Markovic
  2020-06-15  0:52     ` Huacai Chen
  1 sibling, 1 reply; 41+ messages in thread
From: Aleksandar Markovic @ 2020-06-14  8:07 UTC (permalink / raw)
  To: Huacai Chen
  Cc: Huacai Chen, Philippe Mathieu-Daudé,
	QEMU Developers, Huacai Chen, Aleksandar Rikalo, Aurelien Jarno

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

уто, 2. јун 2020. у 04:38 Huacai Chen <zltjiangshi@gmail.com> је написао/ла:
>
> MIPS has two types of KVM: TE & VZ, and TE is the default type. Now we
> can't create a VZ guest in QEMU because it lacks the kvm_type() hook in
> MachineClass. Besides, libvirt uses a null-machine to detect the kvm
> capability, so by default it will return "KVM not supported" on a VZ
> platform. Thus, null-machine also need the kvm_type() hook.
>
> Reviewed-by: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
> Signed-off-by: Huacai Chen <chenhc@lemote.com>
> Co-developed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> ---

Huacai,

Please take a look at Peter's remarks at:

https://lists.gnu.org/archive/html/qemu-devel/2020-06/msg01878.html

...and refactor this patch for v5. My general advice: The simpler, the
batter.

Best wishes,
Aleksandar

>  hw/core/Makefile.objs  |  2 +-
>  hw/core/null-machine.c |  4 ++++
>  hw/mips/Makefile.objs  |  2 +-
>  hw/mips/common.c       | 42 ++++++++++++++++++++++++++++++++++++++++++
>  include/hw/mips/mips.h |  3 +++
>  5 files changed, 51 insertions(+), 2 deletions(-)
>  create mode 100644 hw/mips/common.c
>
> diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs
> index 1d540ed..b5672f4 100644
> --- a/hw/core/Makefile.objs
> +++ b/hw/core/Makefile.objs
> @@ -17,11 +17,11 @@ common-obj-$(CONFIG_SOFTMMU) +=
vm-change-state-handler.o
>  common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o
>  common-obj-$(CONFIG_SOFTMMU) += sysbus.o
>  common-obj-$(CONFIG_SOFTMMU) += machine.o
> -common-obj-$(CONFIG_SOFTMMU) += null-machine.o
>  common-obj-$(CONFIG_SOFTMMU) += loader.o
>  common-obj-$(CONFIG_SOFTMMU) += machine-hmp-cmds.o
>  common-obj-$(CONFIG_SOFTMMU) += numa.o
>  common-obj-$(CONFIG_SOFTMMU) += clock-vmstate.o
> +obj-$(CONFIG_SOFTMMU) += null-machine.o
>  obj-$(CONFIG_SOFTMMU) += machine-qmp-cmds.o
>
>  common-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o
> diff --git a/hw/core/null-machine.c b/hw/core/null-machine.c
> index cb47d9d..94a36f9 100644
> --- a/hw/core/null-machine.c
> +++ b/hw/core/null-machine.c
> @@ -17,6 +17,7 @@
>  #include "sysemu/sysemu.h"
>  #include "exec/address-spaces.h"
>  #include "hw/core/cpu.h"
> +#include "hw/mips/mips.h"
>
>  static void machine_none_init(MachineState *mch)
>  {
> @@ -50,6 +51,9 @@ static void machine_none_machine_init(MachineClass *mc)
>      mc->max_cpus = 1;
>      mc->default_ram_size = 0;
>      mc->default_ram_id = "ram";
> +#ifdef TARGET_MIPS
> +    mc->kvm_type = mips_kvm_type;
> +#endif
>  }
>
>  DEFINE_MACHINE("none", machine_none_machine_init)
> diff --git a/hw/mips/Makefile.objs b/hw/mips/Makefile.objs
> index 739e2b7..3b3e6ea 100644
> --- a/hw/mips/Makefile.objs
> +++ b/hw/mips/Makefile.objs
> @@ -1,4 +1,4 @@
> -obj-y += addr.o mips_int.o
> +obj-y += addr.o common.o mips_int.o
>  obj-$(CONFIG_R4K) += r4k.o
>  obj-$(CONFIG_MALTA) += gt64xxx_pci.o malta.o
>  obj-$(CONFIG_MIPSSIM) += mipssim.o
> diff --git a/hw/mips/common.c b/hw/mips/common.c
> new file mode 100644
> index 0000000..4d8e141
> --- /dev/null
> +++ b/hw/mips/common.c
> @@ -0,0 +1,42 @@
> +/*
> + * Common MIPS routines
> + *
> + * Copyright (c) 2020 Huacai Chen (chenhc@lemote.com)
> + * This code is licensed under the GNU GPL v2.
> + */
> +
> +#include <linux/kvm.h>
> +#include "qemu/osdep.h"
> +#include "qemu-common.h"
> +#include "hw/boards.h"
> +#include "hw/mips/mips.h"
> +#include "sysemu/kvm_int.h"
> +
> +#ifndef CONFIG_KVM
> +
> +int mips_kvm_type(MachineState *machine, const char *vm_type)
> +{
> +    return 0;
> +}
> +
> +#else
> +
> +int mips_kvm_type(MachineState *machine, const char *vm_type)
> +{
> +    int r;
> +    KVMState *s = KVM_STATE(machine->accelerator);
> +
> +    r = kvm_check_extension(s, KVM_CAP_MIPS_VZ);
> +    if (r > 0) {
> +        return KVM_VM_MIPS_VZ;
> +    }
> +
> +    r = kvm_check_extension(s, KVM_CAP_MIPS_TE);
> +    if (r > 0) {
> +        return KVM_VM_MIPS_TE;
> +    }
> +
> +    return -1;
> +}
> +
> +#endif
> diff --git a/include/hw/mips/mips.h b/include/hw/mips/mips.h
> index 0af4c3d..2ac0580 100644
> --- a/include/hw/mips/mips.h
> +++ b/include/hw/mips/mips.h
> @@ -20,4 +20,7 @@ void rc4030_dma_write(void *dma, uint8_t *buf, int len);
>
>  DeviceState *rc4030_init(rc4030_dma **dmas, IOMMUMemoryRegion **dma_mr);
>
> +/* common.c */
> +int mips_kvm_type(MachineState *machine, const char *vm_type);
> +
>  #endif
> --
> 2.7.0
>

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

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

* Re: [PATCH for-5.1 V4 1/4] hw/mips: Implement the kvm_type() hook in MachineClass
  2020-06-14  8:07   ` Aleksandar Markovic
@ 2020-06-15  0:52     ` Huacai Chen
  2020-06-15  8:55       ` Thomas Huth
  0 siblings, 1 reply; 41+ messages in thread
From: Huacai Chen @ 2020-06-15  0:52 UTC (permalink / raw)
  To: Aleksandar Markovic
  Cc: Huacai Chen, Aleksandar Rikalo, Philippe Mathieu-Daudé,
	Aurelien Jarno, QEMU Developers

Hi, Aleksandar,

On Sun, Jun 14, 2020 at 4:07 PM Aleksandar Markovic
<aleksandar.qemu.devel@gmail.com> wrote:
>
>
>
> уто, 2. јун 2020. у 04:38 Huacai Chen <zltjiangshi@gmail.com> је написао/ла:
> >
> > MIPS has two types of KVM: TE & VZ, and TE is the default type. Now we
> > can't create a VZ guest in QEMU because it lacks the kvm_type() hook in
> > MachineClass. Besides, libvirt uses a null-machine to detect the kvm
> > capability, so by default it will return "KVM not supported" on a VZ
> > platform. Thus, null-machine also need the kvm_type() hook.
> >
> > Reviewed-by: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
> > Signed-off-by: Huacai Chen <chenhc@lemote.com>
> > Co-developed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> > ---
>
> Huacai,
>
> Please take a look at Peter's remarks at:
>
> https://lists.gnu.org/archive/html/qemu-devel/2020-06/msg01878.html
>
> ...and refactor this patch for v5. My general advice: The simpler, the batter.
>
OK, I will rework this patch.

Huacai
> Best wishes,
> Aleksandar
>
> >  hw/core/Makefile.objs  |  2 +-
> >  hw/core/null-machine.c |  4 ++++
> >  hw/mips/Makefile.objs  |  2 +-
> >  hw/mips/common.c       | 42 ++++++++++++++++++++++++++++++++++++++++++
> >  include/hw/mips/mips.h |  3 +++
> >  5 files changed, 51 insertions(+), 2 deletions(-)
> >  create mode 100644 hw/mips/common.c
> >
> > diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs
> > index 1d540ed..b5672f4 100644
> > --- a/hw/core/Makefile.objs
> > +++ b/hw/core/Makefile.objs
> > @@ -17,11 +17,11 @@ common-obj-$(CONFIG_SOFTMMU) += vm-change-state-handler.o
> >  common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o
> >  common-obj-$(CONFIG_SOFTMMU) += sysbus.o
> >  common-obj-$(CONFIG_SOFTMMU) += machine.o
> > -common-obj-$(CONFIG_SOFTMMU) += null-machine.o
> >  common-obj-$(CONFIG_SOFTMMU) += loader.o
> >  common-obj-$(CONFIG_SOFTMMU) += machine-hmp-cmds.o
> >  common-obj-$(CONFIG_SOFTMMU) += numa.o
> >  common-obj-$(CONFIG_SOFTMMU) += clock-vmstate.o
> > +obj-$(CONFIG_SOFTMMU) += null-machine.o
> >  obj-$(CONFIG_SOFTMMU) += machine-qmp-cmds.o
> >
> >  common-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o
> > diff --git a/hw/core/null-machine.c b/hw/core/null-machine.c
> > index cb47d9d..94a36f9 100644
> > --- a/hw/core/null-machine.c
> > +++ b/hw/core/null-machine.c
> > @@ -17,6 +17,7 @@
> >  #include "sysemu/sysemu.h"
> >  #include "exec/address-spaces.h"
> >  #include "hw/core/cpu.h"
> > +#include "hw/mips/mips.h"
> >
> >  static void machine_none_init(MachineState *mch)
> >  {
> > @@ -50,6 +51,9 @@ static void machine_none_machine_init(MachineClass *mc)
> >      mc->max_cpus = 1;
> >      mc->default_ram_size = 0;
> >      mc->default_ram_id = "ram";
> > +#ifdef TARGET_MIPS
> > +    mc->kvm_type = mips_kvm_type;
> > +#endif
> >  }
> >
> >  DEFINE_MACHINE("none", machine_none_machine_init)
> > diff --git a/hw/mips/Makefile.objs b/hw/mips/Makefile.objs
> > index 739e2b7..3b3e6ea 100644
> > --- a/hw/mips/Makefile.objs
> > +++ b/hw/mips/Makefile.objs
> > @@ -1,4 +1,4 @@
> > -obj-y += addr.o mips_int.o
> > +obj-y += addr.o common.o mips_int.o
> >  obj-$(CONFIG_R4K) += r4k.o
> >  obj-$(CONFIG_MALTA) += gt64xxx_pci.o malta.o
> >  obj-$(CONFIG_MIPSSIM) += mipssim.o
> > diff --git a/hw/mips/common.c b/hw/mips/common.c
> > new file mode 100644
> > index 0000000..4d8e141
> > --- /dev/null
> > +++ b/hw/mips/common.c
> > @@ -0,0 +1,42 @@
> > +/*
> > + * Common MIPS routines
> > + *
> > + * Copyright (c) 2020 Huacai Chen (chenhc@lemote.com)
> > + * This code is licensed under the GNU GPL v2.
> > + */
> > +
> > +#include <linux/kvm.h>
> > +#include "qemu/osdep.h"
> > +#include "qemu-common.h"
> > +#include "hw/boards.h"
> > +#include "hw/mips/mips.h"
> > +#include "sysemu/kvm_int.h"
> > +
> > +#ifndef CONFIG_KVM
> > +
> > +int mips_kvm_type(MachineState *machine, const char *vm_type)
> > +{
> > +    return 0;
> > +}
> > +
> > +#else
> > +
> > +int mips_kvm_type(MachineState *machine, const char *vm_type)
> > +{
> > +    int r;
> > +    KVMState *s = KVM_STATE(machine->accelerator);
> > +
> > +    r = kvm_check_extension(s, KVM_CAP_MIPS_VZ);
> > +    if (r > 0) {
> > +        return KVM_VM_MIPS_VZ;
> > +    }
> > +
> > +    r = kvm_check_extension(s, KVM_CAP_MIPS_TE);
> > +    if (r > 0) {
> > +        return KVM_VM_MIPS_TE;
> > +    }
> > +
> > +    return -1;
> > +}
> > +
> > +#endif
> > diff --git a/include/hw/mips/mips.h b/include/hw/mips/mips.h
> > index 0af4c3d..2ac0580 100644
> > --- a/include/hw/mips/mips.h
> > +++ b/include/hw/mips/mips.h
> > @@ -20,4 +20,7 @@ void rc4030_dma_write(void *dma, uint8_t *buf, int len);
> >
> >  DeviceState *rc4030_init(rc4030_dma **dmas, IOMMUMemoryRegion **dma_mr);
> >
> > +/* common.c */
> > +int mips_kvm_type(MachineState *machine, const char *vm_type);
> > +
> >  #endif
> > --
> > 2.7.0
> >


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

* Re: [PATCH for-5.1 V4 3/4] hw/mips: Add Loongson-3 machine support (with KVM)
  2020-06-14  7:51   ` Aleksandar Markovic
@ 2020-06-15  0:55     ` Huacai Chen
  2020-06-15  4:42       ` Aleksandar Markovic
  2020-06-15  4:50       ` Aleksandar Markovic
  0 siblings, 2 replies; 41+ messages in thread
From: Huacai Chen @ 2020-06-15  0:55 UTC (permalink / raw)
  To: Aleksandar Markovic
  Cc: Huacai Chen, Aleksandar Rikalo, Philippe Mathieu-Daudé,
	Aurelien Jarno, QEMU Developers

Hi, Aleksandar,

On Sun, Jun 14, 2020 at 3:51 PM Aleksandar Markovic
<aleksandar.qemu.devel@gmail.com> wrote:
>
> Hi, Huacai, this is another round of comments, that should be addressed in v5.
>
> уто, 2. јун 2020. у 04:40 Huacai Chen <zltjiangshi@gmail.com> је написао/ла:
> >
> > Add Loongson-3 based machine support, it use i8259 as the interrupt
> > controler and use GPEX as the pci controller. Currently it can only
> > work with KVM, but we will add TCG support in future.
> >
>
> Add this paragraph at this place in the commit message:
>
> "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, a regular deprecation
> procedure shall occur for "loongson3-virt" machine."
>
OK, this will be added, and I will rename to "loongson3-virt-1.0",
which can be updated in future.
But I think rename the name string is enough, file names and function
names can keep their old names.

Huacai
> > We already have a full functional Linux kernel (based on Linux-5.4.x LTS
> > but not upstream yet) here:
> >
> > https://github.com/chenhuacai/linux
> >
> > 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 the a Loongson-3A4000 host with this kernel;
> > 4, Build QEMU-5.0.0 with this patchset;
> > 5, modprobe kvm;
> > 6, Use QEMU with TCG (available in future):
> >        qemu-system-mips64el -M loongson3,accel=tcg -cpu Loongson-3A1000 -kernel <path_to_kernel> -append ...
>
> Machine should be named loongson3-virt.
>
> >    Use QEMU with KVM (available at present):
> >        qemu-system-mips64el -M loongson3,accel=kvm -cpu Loongson-3A4000 -kernel <path_to_kernel> -append ...
> >
>
> Machine should be named loongson3-virt.
>
> >    The "-cpu" parameter can be omitted here and QEMU will use the correct type for TCG/KVM automatically.
> >
>
> This is not a good approach, the cpu parameter should be required,
> and, if it is not correct for particular circumstance, an error
> message should be emitted to the user, and the emulation terminated.
>
> > 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                      |  10 +
> >  hw/mips/Makefile.objs                |   1 +
> >  hw/mips/loongson3.c                  | 901 +++++++++++++++++++++++++++++++++++
>
> The name of the file should be loongson3-virt.c
>
> >  4 files changed, 913 insertions(+)
> >  create mode 100644 hw/mips/loongson3.c
> >
> > diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak
> > index 9f8a3ef..2a2a3fb 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_LOONGSON3=y
>
> CONFIG_LOONGSON3-VIRT
>
> >  CONFIG_ATI_VGA=y
> >  CONFIG_RTL8139_PCI=y
> >  CONFIG_JAZZ=y
> > diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig
> > index 67d39c5..42931fd 100644
> > --- a/hw/mips/Kconfig
> > +++ b/hw/mips/Kconfig
> > @@ -45,6 +45,16 @@ config FULOONG
> >      bool
> >      select PCI_BONITO
> >
> > +config LOONGSON3
>
> LOONGSON3-VIRT
>
> > +    bool
> > +    select PCKBD
> > +    select SERIAL
> > +    select ISA_BUS
> > +    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/Makefile.objs b/hw/mips/Makefile.objs
> > index 3b3e6ea..31dedcb 100644
> > --- a/hw/mips/Makefile.objs
> > +++ b/hw/mips/Makefile.objs
> > @@ -4,5 +4,6 @@ obj-$(CONFIG_MALTA) += gt64xxx_pci.o malta.o
> >  obj-$(CONFIG_MIPSSIM) += mipssim.o
> >  obj-$(CONFIG_JAZZ) += jazz.o
> >  obj-$(CONFIG_FULOONG) += fuloong2e.o
> > +obj-$(CONFIG_LOONGSON3) += loongson3.o
>
> CONFIG_LOONGSON3-VIRT
>
> >  obj-$(CONFIG_MIPS_CPS) += cps.o
> >  obj-$(CONFIG_MIPS_BOSTON) += boston.o
> > diff --git a/hw/mips/loongson3.c b/hw/mips/loongson3.c
> > new file mode 100644
> > index 0000000..e4b9538
> > --- /dev/null
> > +++ b/hw/mips/loongson3.c
>
> The file shoul be named loongson3-virt.c
>
> > @@ -0,0 +1,901 @@
> > +/*
> > + * Generic Loongson-3 Platform support
>
> "Support for loongson3-virt platform"
>
> > + *
> > + * Copyright (c) 2016-2020 Huacai Chen (chenhc@lemote.com)
> > + * This code is licensed under the GNU GPL v2.
> > + *
> > + * Contributions are licensed under the terms of the GNU GPL,
> > + * version 2 or (at your option) any later version.
>
> License preamble should be harmonized, as we already agreed upon.
>
> > + */
> > +
> > +/*
> > + * Generic 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 "hw/boards.h"
> > +#include "hw/char/serial.h"
> > +#include "hw/mips/mips.h"
> > +#include "hw/mips/cpudevs.h"
> > +#include "hw/intc/i8259.h"
> > +#include "hw/loader.h"
> > +#include "hw/ide.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 "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 INITRD_OFFSET         0x04000000
> > +#define BOOTPARAM_ADDR        0x8ff00000
> > +#define BOOTPARAM_PHYADDR     0x0ff00000
> > +#define CFG_ADDR              0x0f100000
> > +#define FW_CONF_ADDR          0x0fff0000
> > +#define PM_MMIO_ADDR          0x10080000
> > +#define PM_MMIO_SIZE          0x100
> > +#define PM_CNTL_MODE          0x10
> > +
> > +#define PHYS_TO_VIRT(x) ((x) | ~(target_ulong)0x7fffffff)
> > +
> > +/* Loongson-3 has a 2MB flash rom */
> > +#define BIOS_SIZE               (2 * MiB)
> > +#define LOONGSON_MAX_VCPUS      16
> > +
> > +#define LOONGSON3_BIOSNAME "bios_loongson3.bin"
> > +
> > +#define PCIE_IRQ_BASE       3
> > +
> > +#define VIRT_PCI_IO_BASE    0x18000000ul
> > +#define VIRT_PCI_IO_SIZE    0x000c0000ul
> > +#define VIRT_PCI_MEM_BASE   0x40000000ul
> > +#define VIRT_PCI_MEM_SIZE   0x40000000ul
> > +#define VIRT_PCI_ECAM_BASE  0x1a000000ul
> > +#define VIRT_PCI_ECAM_SIZE  0x02000000ul
> > +
> > +#define align(x) (((x) + 63) & ~63)
> > +
> > +/* 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;
> > +};
> > +
> > +static struct _fw_config {
> > +    unsigned long ram_size;
> > +    unsigned int mem_freq;
> > +    unsigned int nr_cpus;
> > +    unsigned int cpu_clock_freq;
> > +} fw_config;
> > +
> > +static struct _loaderparams {
> > +    unsigned long ram_size;
> > +    const char *kernel_cmdline;
> > +    const char *kernel_filename;
> > +    const char *initrd_filename;
> > +    int64_t kernel_entry;
> > +    unsigned long a0, a1, a2;
> > +} loaderparams;
> > +
> > +static void *boot_params_p;
> > +static void *boot_params_buf;
> > +
> > +static unsigned int bios_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                                                      */
> > +};
> > +
> > +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 = (loaderparams.ram_size > 0x10000000
> > +                            ? 256 : (loaderparams.ram_size >> 20)) - 16;
> > +
> > +    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 > 0x10000000
> > +                            ? (loaderparams.ram_size >> 20) - 256 : 0);
> > +
> > +    return emap;
> > +}
> > +
> > +static int get_host_cpu_freq(void)
> > +{
> > +    int fd = 0, freq = 0;
> > +    char buf[1024], *buf_p;
> > +
> > +    fd = open("/proc/cpuinfo", O_RDONLY);
> > +    if (fd == -1) {
> > +        fprintf(stderr, "Failed to open /proc/cpuinfo!\n");
> > +        return 0;
> > +    }
> > +
> > +    if (read(fd, buf, 1024) < 0) {
> > +        close(fd);
> > +        fprintf(stderr, "Failed to read /proc/cpuinfo!\n");
> > +        return 0;
> > +    }
> > +    close(fd);
> > +
> > +    buf_p = strstr(buf, "model name");
> > +    while (*buf_p != '@') {
> > +        buf_p++;
> > +    }
> > +
> > +    buf_p += 2;
> > +    memcpy(buf, buf_p, 12);
> > +    buf_p = buf;
> > +    while ((*buf_p >= '0') && (*buf_p <= '9')) {
> > +        buf_p++;
> > +    }
> > +    *buf_p = '\0';
> > +
> > +    freq = atoi(buf);
> > +
> > +    return freq * 1000 * 1000;
> > +}
> > +
> > +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 = 0x14C000;
> > +    c->cpu_clock_freq = get_host_cpu_freq();
> > +    if (!c->cpu_clock_freq) {
> > +        c->cpu_clock_freq = 500000000;
> > +    }
> > +
> > +    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;
> > +    s->uarts[0].uart_base = 0x1fe001e0;
> > +
> > +    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_PCI_MEM_BASE;
> > +    irq_info->pci_mem_end_addr   = VIRT_PCI_MEM_BASE + VIRT_PCI_MEM_SIZE - 1;
> > +    irq_info->pci_io_start_addr  = VIRT_PCI_IO_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, "2016-05-16");
> > +
> > +    return special;
> > +}
> > +
> > +static void init_loongson_params(struct loongson_params *lp)
> > +{
> > +    void *p = boot_params_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));
> > +
> > +    boot_params_p = p;
> > +}
> > +
> > +static void init_smbios(struct smbios_tables *smbios)
> > +{
> > +    smbios->vers = 1;
> > +    init_loongson_params(&(smbios->lp));
> > +}
> > +
> > +static void init_efi(struct efi_loongson *efi)
> > +{
> > +    init_smbios(&(efi->smbios));
> > +}
> > +
> > +static void init_reset_system(struct efi_reset_system_t *reset)
> > +{
> > +    reset->Shutdown = 0xffffffffbfc000a8;
> > +    reset->ResetCold = 0xffffffffbfc00080;
> > +    reset->ResetWarm = 0xffffffffbfc00080;
> > +}
> > +
> > +static int init_boot_param(struct boot_params *bp)
> > +{
> > +    init_efi(&(bp->efi));
> > +    init_reset_system(&(bp->reset_system));
> > +
> > +    return 0;
> > +}
> > +
> > +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;
> > +
> > +    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);
> > +    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
> > +
> > +    fw_config.ram_size = ram_size;
> > +    fw_config.mem_freq = 300000000;
> > +    fw_config.nr_cpus = current_machine->smp.cpus;
> > +    fw_config.cpu_clock_freq = get_host_cpu_freq();
> > +}
> > +
> > +static int set_prom_bootparam(ram_addr_t initrd_offset, long initrd_size)
> > +{
> > +    long params_size;
> > +    char memenv[32];
> > +    char highmemenv[32];
> > +    void *params_buf;
> > +    unsigned int *parg_env;
> > +    int ret = 0;
> > +
> > +    /* Allocate params_buf for command line. */
> > +    params_size = 0x100000;
> > +    params_buf = g_malloc0(params_size);
> > +
> > +    /*
> > +     * Layout of params_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 *)params_buf;
> > +
> > +    ret = (3 + 1) * 4;
> > +    *parg_env++ = (BOOTPARAM_ADDR + ret);
> > +    ret += (1 + snprintf(params_buf + ret, 256 - ret, "g"));
> > +
> > +    /* argv1 */
> > +    *parg_env++ = BOOTPARAM_ADDR + ret;
> > +    if (initrd_size > 0)
> > +        ret += (1 + snprintf(params_buf + ret, 256 - ret,
> > +                "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s",
> > +                PHYS_TO_VIRT((uint32_t)initrd_offset),
> > +                initrd_size, loaderparams.kernel_cmdline));
> > +    else
> > +        ret += (1 + snprintf(params_buf + ret, 256 - ret, "%s",
> > +                loaderparams.kernel_cmdline));
> > +
> > +    /* argv2 */
> > +    *parg_env++ = BOOTPARAM_ADDR + 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);
> > +
> > +    setenv("memsize", memenv, 1);
> > +    setenv("highmemsize", highmemenv, 1);
> > +
> > +    ret = ((ret + 32) & ~31);
> > +
> > +    boot_params_buf = (void *)(params_buf + ret);
> > +    boot_params_p = boot_params_buf + align(sizeof(struct boot_params));
> > +
> > +    init_boot_param(boot_params_buf);
> > +
> > +    rom_add_blob_fixed("params", params_buf, params_size,
> > +                       BOOTPARAM_PHYADDR);
> > +    loaderparams.a0 = 2;
> > +    loaderparams.a1 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR;
> > +    loaderparams.a2 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR + ret;
> > +
> > +    return 0;
> > +}
> > +
> > +static int64_t load_kernel(CPUMIPSState *env)
> > +{
> > +    long kernel_size;
> > +    ram_addr_t initrd_offset;
> > +    int64_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, INITRD_OFFSET);
> > +
> > +            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 parameters. */
> > +    set_prom_bootparam(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 void loongson3_isa_init(qemu_irq intc)
>
> Rename it to loongson3-virt_isa_init.
>
> > +{
> > +    qemu_irq *i8259;
> > +    ISABus *isa_bus;
> > +
> > +    isa_bus = isa_bus_new(NULL, get_system_memory(), get_system_io(), &error_abort);
> > +
> > +    /* Interrupt controller */
> > +    /* The 8259 -> IP3  */
> > +    i8259 = i8259_init(isa_bus, intc);
> > +    isa_bus_irqs(isa_bus, i8259);
> > +    /* init other devices */
> > +    isa_create_simple(isa_bus, "i8042");
> > +    mc146818_rtc_init(isa_bus, 2000, NULL);
> > +}
> > +
> > +static inline void loongson3_pcie_init(MachineState *machine, DeviceState *pic)
>
> Rename it to loongson3-virt_pcie_init.
>
> > +{
> > +    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_create(NULL, TYPE_GPEX_HOST);
> > +
> > +    qdev_init_nofail(dev);
> > +    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_PCI_ECAM_SIZE);
> > +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_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_PCI_MEM_BASE, VIRT_PCI_MEM_SIZE);
> > +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_MEM_BASE, mmio_alias);
> > +
> > +    pio_alias = g_new0(MemoryRegion, 1);
> > +    memory_region_init_alias(pio_alias, OBJECT(dev), "pcie-pio",
> > +                             get_system_io(), 0, VIRT_PCI_IO_SIZE);
> > +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_IO_BASE, pio_alias);
> > +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, VIRT_PCI_IO_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);
> > +
> > +    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_init(MachineState *machine)
>
> Rename it to loongson3-virt_init.
>
> > +{
> > +    int i;
> > +    long bios_size;
> > +    MIPSCPU *cpu;
> > +    CPUMIPSState *env;
> > +    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);
> > +
> > +    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 < 256 * 0x100000) {
> > +        error_report("Loongson-3 need at least 256MB memory");
> > +        exit(1);
> > +    }
> > +
> > +    for (i = 0; i < machine->smp.cpus; i++) {
> > +        /* 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);
> > +    }
> > +    env = &MIPS_CPU(first_cpu)->env;
> > +
> > +    /* Allocate RAM/BIOS, 0x00000000~0x10000000 is alias of 0x80000000~0x90000000 */
> > +    memory_region_init_rom(bios, NULL, "loongson3.bios",
> > +                           BIOS_SIZE, &error_fatal);
> > +    memory_region_init_alias(ram, NULL, "loongson3.lowram",
> > +                           machine->ram, 0, 256 * 0x100000);
> > +    memory_region_init_io(iomem, NULL, &loongson3_pm_ops,
> > +                           NULL, "loongson3_pm", PM_MMIO_SIZE);
> > +
> > +    memory_region_add_subregion(address_space_mem, 0x00000000LL, ram);
> > +    memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios);
> > +    memory_region_add_subregion(address_space_mem, 0x80000000LL, machine->ram);
> > +    memory_region_add_subregion(address_space_mem, PM_MMIO_ADDR, iomem);
> > +
> > +    /*
> > +     * We do not support flash operation, just loading pmon.bin as raw BIOS.
> > +     * Please use -L to set the BIOS path and -bios to set bios name.
> > +     */
> > +
> > +    if (kernel_filename) {
> > +        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);
> > +        rom_add_blob_fixed("bios",
> > +                         bios_boot_code, sizeof(bios_boot_code), 0x1fc00000LL);
> > +    } 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, 0x1fc00000LL,
> > +                                            BIOS_SIZE);
> > +            g_free(filename);
> > +        } else {
> > +            bios_size = -1;
> > +        }
> > +
> > +        if ((bios_size < 0 || bios_size > BIOS_SIZE) &&
> > +            !kernel_filename && !qtest_enabled()) {
> > +            error_report("Could not load MIPS bios '%s'", bios_name);
> > +            exit(1);
> > +        }
> > +
> > +        fw_conf_init(ram_size);
> > +        rom_add_blob_fixed("fw_conf",
> > +                         &fw_config, sizeof(fw_config), FW_CONF_ADDR);
> > +    }
> > +
> > +    msi_nonbroken = true;
> > +    loongson3_isa_init(env->irq[3]);
> > +    loongson3_pcie_init(machine, isa_pic);
>
> Names for two last functions should be already different.
>
> > +
> > +    if (serial_hd(0)) {
> > +        serial_mm_init(address_space_mem, 0x1fe001e0, 0, env->irq[2],
> > +                           115200, serial_hd(0), DEVICE_NATIVE_ENDIAN);
> > +    }
> > +}
> > +
> > +static void mips_loongson3_machine_init(MachineClass *mc)
>
> Rename it to loongson3-virt_machine_init.
>
> > +{
> > +    mc->desc = "Generic Loongson-3 Platform";
> > +    mc->init = mips_loongson3_init;
> > +    mc->block_default_type = IF_IDE;
> > +    mc->max_cpus = LOONGSON_MAX_VCPUS;
> > +    mc->default_ram_id = "loongson3.highram";
> > +    mc->default_ram_size = 1200 * MiB;
> > +    mc->kvm_type = mips_kvm_type;
> > +    mc->minimum_page_bits = 14;
> > +}
> > +
> > +DEFINE_MACHINE("loongson3", mips_loongson3_machine_init)
>
> DEFINE_MACHINE("loongson3-virt", loongson3-virt_machine_init)
>
> > --
> > 2.7.0
> >


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

* Re: [PATCH for-5.1 V4 3/4] hw/mips: Add Loongson-3 machine support (with KVM)
  2020-06-15  0:55     ` Huacai Chen
@ 2020-06-15  4:42       ` Aleksandar Markovic
  2020-06-15  4:50       ` Aleksandar Markovic
  1 sibling, 0 replies; 41+ messages in thread
From: Aleksandar Markovic @ 2020-06-15  4:42 UTC (permalink / raw)
  To: Huacai Chen
  Cc: Huacai Chen, Aleksandar Rikalo, Philippe Mathieu-Daudé,
	Aurelien Jarno, QEMU Developers

пон, 15. јун 2020. у 02:55 Huacai Chen <chenhuacai@gmail.com> је написао/ла:
>
> Hi, Aleksandar,
>
> On Sun, Jun 14, 2020 at 3:51 PM Aleksandar Markovic
> <aleksandar.qemu.devel@gmail.com> wrote:
> >
> > Hi, Huacai, this is another round of comments, that should be addressed in v5.
> >
> > уто, 2. јун 2020. у 04:40 Huacai Chen <zltjiangshi@gmail.com> је написао/ла:
> > >
> > > Add Loongson-3 based machine support, it use i8259 as the interrupt
> > > controler and use GPEX as the pci controller. Currently it can only
> > > work with KVM, but we will add TCG support in future.
> > >
> >
> > Add this paragraph at this place in the commit message:
> >
> > "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, a regular deprecation
> > procedure shall occur for "loongson3-virt" machine."
> >
> OK, this will be added, and I will rename to "loongson3-virt-1.0",
> which can be updated in future.
> But I think rename the name string is enough, file names and function
> names can keep their old names.
>

Sorry, Huacai, this is ruled out. We definitely do not want to pile
versions 1.0, 2.0, 3.0 etc. of such virtual machine. One can update
the machine without creating a new version if backward compatibility
for end user is satisfied. But, the better outcome would be if you
provide real machine model instead, rather than spend time and energy
on multi-version virtual machine.

Yours,
Aleksandar

> Huacai
> > > We already have a full functional Linux kernel (based on Linux-5.4.x LTS
> > > but not upstream yet) here:
> > >
> > > https://github.com/chenhuacai/linux
> > >
> > > 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 the a Loongson-3A4000 host with this kernel;
> > > 4, Build QEMU-5.0.0 with this patchset;
> > > 5, modprobe kvm;
> > > 6, Use QEMU with TCG (available in future):
> > >        qemu-system-mips64el -M loongson3,accel=tcg -cpu Loongson-3A1000 -kernel <path_to_kernel> -append ...
> >
> > Machine should be named loongson3-virt.
> >
> > >    Use QEMU with KVM (available at present):
> > >        qemu-system-mips64el -M loongson3,accel=kvm -cpu Loongson-3A4000 -kernel <path_to_kernel> -append ...
> > >
> >
> > Machine should be named loongson3-virt.
> >
> > >    The "-cpu" parameter can be omitted here and QEMU will use the correct type for TCG/KVM automatically.
> > >
> >
> > This is not a good approach, the cpu parameter should be required,
> > and, if it is not correct for particular circumstance, an error
> > message should be emitted to the user, and the emulation terminated.
> >
> > > 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                      |  10 +
> > >  hw/mips/Makefile.objs                |   1 +
> > >  hw/mips/loongson3.c                  | 901 +++++++++++++++++++++++++++++++++++
> >
> > The name of the file should be loongson3-virt.c
> >
> > >  4 files changed, 913 insertions(+)
> > >  create mode 100644 hw/mips/loongson3.c
> > >
> > > diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak
> > > index 9f8a3ef..2a2a3fb 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_LOONGSON3=y
> >
> > CONFIG_LOONGSON3-VIRT
> >
> > >  CONFIG_ATI_VGA=y
> > >  CONFIG_RTL8139_PCI=y
> > >  CONFIG_JAZZ=y
> > > diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig
> > > index 67d39c5..42931fd 100644
> > > --- a/hw/mips/Kconfig
> > > +++ b/hw/mips/Kconfig
> > > @@ -45,6 +45,16 @@ config FULOONG
> > >      bool
> > >      select PCI_BONITO
> > >
> > > +config LOONGSON3
> >
> > LOONGSON3-VIRT
> >
> > > +    bool
> > > +    select PCKBD
> > > +    select SERIAL
> > > +    select ISA_BUS
> > > +    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/Makefile.objs b/hw/mips/Makefile.objs
> > > index 3b3e6ea..31dedcb 100644
> > > --- a/hw/mips/Makefile.objs
> > > +++ b/hw/mips/Makefile.objs
> > > @@ -4,5 +4,6 @@ obj-$(CONFIG_MALTA) += gt64xxx_pci.o malta.o
> > >  obj-$(CONFIG_MIPSSIM) += mipssim.o
> > >  obj-$(CONFIG_JAZZ) += jazz.o
> > >  obj-$(CONFIG_FULOONG) += fuloong2e.o
> > > +obj-$(CONFIG_LOONGSON3) += loongson3.o
> >
> > CONFIG_LOONGSON3-VIRT
> >
> > >  obj-$(CONFIG_MIPS_CPS) += cps.o
> > >  obj-$(CONFIG_MIPS_BOSTON) += boston.o
> > > diff --git a/hw/mips/loongson3.c b/hw/mips/loongson3.c
> > > new file mode 100644
> > > index 0000000..e4b9538
> > > --- /dev/null
> > > +++ b/hw/mips/loongson3.c
> >
> > The file shoul be named loongson3-virt.c
> >
> > > @@ -0,0 +1,901 @@
> > > +/*
> > > + * Generic Loongson-3 Platform support
> >
> > "Support for loongson3-virt platform"
> >
> > > + *
> > > + * Copyright (c) 2016-2020 Huacai Chen (chenhc@lemote.com)
> > > + * This code is licensed under the GNU GPL v2.
> > > + *
> > > + * Contributions are licensed under the terms of the GNU GPL,
> > > + * version 2 or (at your option) any later version.
> >
> > License preamble should be harmonized, as we already agreed upon.
> >
> > > + */
> > > +
> > > +/*
> > > + * Generic 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 "hw/boards.h"
> > > +#include "hw/char/serial.h"
> > > +#include "hw/mips/mips.h"
> > > +#include "hw/mips/cpudevs.h"
> > > +#include "hw/intc/i8259.h"
> > > +#include "hw/loader.h"
> > > +#include "hw/ide.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 "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 INITRD_OFFSET         0x04000000
> > > +#define BOOTPARAM_ADDR        0x8ff00000
> > > +#define BOOTPARAM_PHYADDR     0x0ff00000
> > > +#define CFG_ADDR              0x0f100000
> > > +#define FW_CONF_ADDR          0x0fff0000
> > > +#define PM_MMIO_ADDR          0x10080000
> > > +#define PM_MMIO_SIZE          0x100
> > > +#define PM_CNTL_MODE          0x10
> > > +
> > > +#define PHYS_TO_VIRT(x) ((x) | ~(target_ulong)0x7fffffff)
> > > +
> > > +/* Loongson-3 has a 2MB flash rom */
> > > +#define BIOS_SIZE               (2 * MiB)
> > > +#define LOONGSON_MAX_VCPUS      16
> > > +
> > > +#define LOONGSON3_BIOSNAME "bios_loongson3.bin"
> > > +
> > > +#define PCIE_IRQ_BASE       3
> > > +
> > > +#define VIRT_PCI_IO_BASE    0x18000000ul
> > > +#define VIRT_PCI_IO_SIZE    0x000c0000ul
> > > +#define VIRT_PCI_MEM_BASE   0x40000000ul
> > > +#define VIRT_PCI_MEM_SIZE   0x40000000ul
> > > +#define VIRT_PCI_ECAM_BASE  0x1a000000ul
> > > +#define VIRT_PCI_ECAM_SIZE  0x02000000ul
> > > +
> > > +#define align(x) (((x) + 63) & ~63)
> > > +
> > > +/* 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;
> > > +};
> > > +
> > > +static struct _fw_config {
> > > +    unsigned long ram_size;
> > > +    unsigned int mem_freq;
> > > +    unsigned int nr_cpus;
> > > +    unsigned int cpu_clock_freq;
> > > +} fw_config;
> > > +
> > > +static struct _loaderparams {
> > > +    unsigned long ram_size;
> > > +    const char *kernel_cmdline;
> > > +    const char *kernel_filename;
> > > +    const char *initrd_filename;
> > > +    int64_t kernel_entry;
> > > +    unsigned long a0, a1, a2;
> > > +} loaderparams;
> > > +
> > > +static void *boot_params_p;
> > > +static void *boot_params_buf;
> > > +
> > > +static unsigned int bios_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                                                      */
> > > +};
> > > +
> > > +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 = (loaderparams.ram_size > 0x10000000
> > > +                            ? 256 : (loaderparams.ram_size >> 20)) - 16;
> > > +
> > > +    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 > 0x10000000
> > > +                            ? (loaderparams.ram_size >> 20) - 256 : 0);
> > > +
> > > +    return emap;
> > > +}
> > > +
> > > +static int get_host_cpu_freq(void)
> > > +{
> > > +    int fd = 0, freq = 0;
> > > +    char buf[1024], *buf_p;
> > > +
> > > +    fd = open("/proc/cpuinfo", O_RDONLY);
> > > +    if (fd == -1) {
> > > +        fprintf(stderr, "Failed to open /proc/cpuinfo!\n");
> > > +        return 0;
> > > +    }
> > > +
> > > +    if (read(fd, buf, 1024) < 0) {
> > > +        close(fd);
> > > +        fprintf(stderr, "Failed to read /proc/cpuinfo!\n");
> > > +        return 0;
> > > +    }
> > > +    close(fd);
> > > +
> > > +    buf_p = strstr(buf, "model name");
> > > +    while (*buf_p != '@') {
> > > +        buf_p++;
> > > +    }
> > > +
> > > +    buf_p += 2;
> > > +    memcpy(buf, buf_p, 12);
> > > +    buf_p = buf;
> > > +    while ((*buf_p >= '0') && (*buf_p <= '9')) {
> > > +        buf_p++;
> > > +    }
> > > +    *buf_p = '\0';
> > > +
> > > +    freq = atoi(buf);
> > > +
> > > +    return freq * 1000 * 1000;
> > > +}
> > > +
> > > +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 = 0x14C000;
> > > +    c->cpu_clock_freq = get_host_cpu_freq();
> > > +    if (!c->cpu_clock_freq) {
> > > +        c->cpu_clock_freq = 500000000;
> > > +    }
> > > +
> > > +    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;
> > > +    s->uarts[0].uart_base = 0x1fe001e0;
> > > +
> > > +    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_PCI_MEM_BASE;
> > > +    irq_info->pci_mem_end_addr   = VIRT_PCI_MEM_BASE + VIRT_PCI_MEM_SIZE - 1;
> > > +    irq_info->pci_io_start_addr  = VIRT_PCI_IO_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, "2016-05-16");
> > > +
> > > +    return special;
> > > +}
> > > +
> > > +static void init_loongson_params(struct loongson_params *lp)
> > > +{
> > > +    void *p = boot_params_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));
> > > +
> > > +    boot_params_p = p;
> > > +}
> > > +
> > > +static void init_smbios(struct smbios_tables *smbios)
> > > +{
> > > +    smbios->vers = 1;
> > > +    init_loongson_params(&(smbios->lp));
> > > +}
> > > +
> > > +static void init_efi(struct efi_loongson *efi)
> > > +{
> > > +    init_smbios(&(efi->smbios));
> > > +}
> > > +
> > > +static void init_reset_system(struct efi_reset_system_t *reset)
> > > +{
> > > +    reset->Shutdown = 0xffffffffbfc000a8;
> > > +    reset->ResetCold = 0xffffffffbfc00080;
> > > +    reset->ResetWarm = 0xffffffffbfc00080;
> > > +}
> > > +
> > > +static int init_boot_param(struct boot_params *bp)
> > > +{
> > > +    init_efi(&(bp->efi));
> > > +    init_reset_system(&(bp->reset_system));
> > > +
> > > +    return 0;
> > > +}
> > > +
> > > +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;
> > > +
> > > +    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);
> > > +    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
> > > +
> > > +    fw_config.ram_size = ram_size;
> > > +    fw_config.mem_freq = 300000000;
> > > +    fw_config.nr_cpus = current_machine->smp.cpus;
> > > +    fw_config.cpu_clock_freq = get_host_cpu_freq();
> > > +}
> > > +
> > > +static int set_prom_bootparam(ram_addr_t initrd_offset, long initrd_size)
> > > +{
> > > +    long params_size;
> > > +    char memenv[32];
> > > +    char highmemenv[32];
> > > +    void *params_buf;
> > > +    unsigned int *parg_env;
> > > +    int ret = 0;
> > > +
> > > +    /* Allocate params_buf for command line. */
> > > +    params_size = 0x100000;
> > > +    params_buf = g_malloc0(params_size);
> > > +
> > > +    /*
> > > +     * Layout of params_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 *)params_buf;
> > > +
> > > +    ret = (3 + 1) * 4;
> > > +    *parg_env++ = (BOOTPARAM_ADDR + ret);
> > > +    ret += (1 + snprintf(params_buf + ret, 256 - ret, "g"));
> > > +
> > > +    /* argv1 */
> > > +    *parg_env++ = BOOTPARAM_ADDR + ret;
> > > +    if (initrd_size > 0)
> > > +        ret += (1 + snprintf(params_buf + ret, 256 - ret,
> > > +                "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s",
> > > +                PHYS_TO_VIRT((uint32_t)initrd_offset),
> > > +                initrd_size, loaderparams.kernel_cmdline));
> > > +    else
> > > +        ret += (1 + snprintf(params_buf + ret, 256 - ret, "%s",
> > > +                loaderparams.kernel_cmdline));
> > > +
> > > +    /* argv2 */
> > > +    *parg_env++ = BOOTPARAM_ADDR + 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);
> > > +
> > > +    setenv("memsize", memenv, 1);
> > > +    setenv("highmemsize", highmemenv, 1);
> > > +
> > > +    ret = ((ret + 32) & ~31);
> > > +
> > > +    boot_params_buf = (void *)(params_buf + ret);
> > > +    boot_params_p = boot_params_buf + align(sizeof(struct boot_params));
> > > +
> > > +    init_boot_param(boot_params_buf);
> > > +
> > > +    rom_add_blob_fixed("params", params_buf, params_size,
> > > +                       BOOTPARAM_PHYADDR);
> > > +    loaderparams.a0 = 2;
> > > +    loaderparams.a1 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR;
> > > +    loaderparams.a2 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR + ret;
> > > +
> > > +    return 0;
> > > +}
> > > +
> > > +static int64_t load_kernel(CPUMIPSState *env)
> > > +{
> > > +    long kernel_size;
> > > +    ram_addr_t initrd_offset;
> > > +    int64_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, INITRD_OFFSET);
> > > +
> > > +            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 parameters. */
> > > +    set_prom_bootparam(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 void loongson3_isa_init(qemu_irq intc)
> >
> > Rename it to loongson3-virt_isa_init.
> >
> > > +{
> > > +    qemu_irq *i8259;
> > > +    ISABus *isa_bus;
> > > +
> > > +    isa_bus = isa_bus_new(NULL, get_system_memory(), get_system_io(), &error_abort);
> > > +
> > > +    /* Interrupt controller */
> > > +    /* The 8259 -> IP3  */
> > > +    i8259 = i8259_init(isa_bus, intc);
> > > +    isa_bus_irqs(isa_bus, i8259);
> > > +    /* init other devices */
> > > +    isa_create_simple(isa_bus, "i8042");
> > > +    mc146818_rtc_init(isa_bus, 2000, NULL);
> > > +}
> > > +
> > > +static inline void loongson3_pcie_init(MachineState *machine, DeviceState *pic)
> >
> > Rename it to loongson3-virt_pcie_init.
> >
> > > +{
> > > +    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_create(NULL, TYPE_GPEX_HOST);
> > > +
> > > +    qdev_init_nofail(dev);
> > > +    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_PCI_ECAM_SIZE);
> > > +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_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_PCI_MEM_BASE, VIRT_PCI_MEM_SIZE);
> > > +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_MEM_BASE, mmio_alias);
> > > +
> > > +    pio_alias = g_new0(MemoryRegion, 1);
> > > +    memory_region_init_alias(pio_alias, OBJECT(dev), "pcie-pio",
> > > +                             get_system_io(), 0, VIRT_PCI_IO_SIZE);
> > > +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_IO_BASE, pio_alias);
> > > +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, VIRT_PCI_IO_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);
> > > +
> > > +    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_init(MachineState *machine)
> >
> > Rename it to loongson3-virt_init.
> >
> > > +{
> > > +    int i;
> > > +    long bios_size;
> > > +    MIPSCPU *cpu;
> > > +    CPUMIPSState *env;
> > > +    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);
> > > +
> > > +    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 < 256 * 0x100000) {
> > > +        error_report("Loongson-3 need at least 256MB memory");
> > > +        exit(1);
> > > +    }
> > > +
> > > +    for (i = 0; i < machine->smp.cpus; i++) {
> > > +        /* 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);
> > > +    }
> > > +    env = &MIPS_CPU(first_cpu)->env;
> > > +
> > > +    /* Allocate RAM/BIOS, 0x00000000~0x10000000 is alias of 0x80000000~0x90000000 */
> > > +    memory_region_init_rom(bios, NULL, "loongson3.bios",
> > > +                           BIOS_SIZE, &error_fatal);
> > > +    memory_region_init_alias(ram, NULL, "loongson3.lowram",
> > > +                           machine->ram, 0, 256 * 0x100000);
> > > +    memory_region_init_io(iomem, NULL, &loongson3_pm_ops,
> > > +                           NULL, "loongson3_pm", PM_MMIO_SIZE);
> > > +
> > > +    memory_region_add_subregion(address_space_mem, 0x00000000LL, ram);
> > > +    memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios);
> > > +    memory_region_add_subregion(address_space_mem, 0x80000000LL, machine->ram);
> > > +    memory_region_add_subregion(address_space_mem, PM_MMIO_ADDR, iomem);
> > > +
> > > +    /*
> > > +     * We do not support flash operation, just loading pmon.bin as raw BIOS.
> > > +     * Please use -L to set the BIOS path and -bios to set bios name.
> > > +     */
> > > +
> > > +    if (kernel_filename) {
> > > +        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);
> > > +        rom_add_blob_fixed("bios",
> > > +                         bios_boot_code, sizeof(bios_boot_code), 0x1fc00000LL);
> > > +    } 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, 0x1fc00000LL,
> > > +                                            BIOS_SIZE);
> > > +            g_free(filename);
> > > +        } else {
> > > +            bios_size = -1;
> > > +        }
> > > +
> > > +        if ((bios_size < 0 || bios_size > BIOS_SIZE) &&
> > > +            !kernel_filename && !qtest_enabled()) {
> > > +            error_report("Could not load MIPS bios '%s'", bios_name);
> > > +            exit(1);
> > > +        }
> > > +
> > > +        fw_conf_init(ram_size);
> > > +        rom_add_blob_fixed("fw_conf",
> > > +                         &fw_config, sizeof(fw_config), FW_CONF_ADDR);
> > > +    }
> > > +
> > > +    msi_nonbroken = true;
> > > +    loongson3_isa_init(env->irq[3]);
> > > +    loongson3_pcie_init(machine, isa_pic);
> >
> > Names for two last functions should be already different.
> >
> > > +
> > > +    if (serial_hd(0)) {
> > > +        serial_mm_init(address_space_mem, 0x1fe001e0, 0, env->irq[2],
> > > +                           115200, serial_hd(0), DEVICE_NATIVE_ENDIAN);
> > > +    }
> > > +}
> > > +
> > > +static void mips_loongson3_machine_init(MachineClass *mc)
> >
> > Rename it to loongson3-virt_machine_init.
> >
> > > +{
> > > +    mc->desc = "Generic Loongson-3 Platform";
> > > +    mc->init = mips_loongson3_init;
> > > +    mc->block_default_type = IF_IDE;
> > > +    mc->max_cpus = LOONGSON_MAX_VCPUS;
> > > +    mc->default_ram_id = "loongson3.highram";
> > > +    mc->default_ram_size = 1200 * MiB;
> > > +    mc->kvm_type = mips_kvm_type;
> > > +    mc->minimum_page_bits = 14;
> > > +}
> > > +
> > > +DEFINE_MACHINE("loongson3", mips_loongson3_machine_init)
> >
> > DEFINE_MACHINE("loongson3-virt", loongson3-virt_machine_init)
> >
> > > --
> > > 2.7.0
> > >


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

* Re: [PATCH for-5.1 V4 3/4] hw/mips: Add Loongson-3 machine support (with KVM)
  2020-06-15  0:55     ` Huacai Chen
  2020-06-15  4:42       ` Aleksandar Markovic
@ 2020-06-15  4:50       ` Aleksandar Markovic
  2020-06-15  5:36         ` Huacai Chen
  1 sibling, 1 reply; 41+ messages in thread
From: Aleksandar Markovic @ 2020-06-15  4:50 UTC (permalink / raw)
  To: Huacai Chen
  Cc: Huacai Chen, Aleksandar Rikalo, Philippe Mathieu-Daudé,
	Aurelien Jarno, QEMU Developers

пон, 15. јун 2020. у 02:55 Huacai Chen <chenhuacai@gmail.com> је написао/ла:
>
> Hi, Aleksandar,
>
> On Sun, Jun 14, 2020 at 3:51 PM Aleksandar Markovic
> <aleksandar.qemu.devel@gmail.com> wrote:
> >
> > Hi, Huacai, this is another round of comments, that should be addressed in v5.
> >
> > уто, 2. јун 2020. у 04:40 Huacai Chen <zltjiangshi@gmail.com> је написао/ла:
> > >
> > > Add Loongson-3 based machine support, it use i8259 as the interrupt
> > > controler and use GPEX as the pci controller. Currently it can only
> > > work with KVM, but we will add TCG support in future.
> > >
> >
> > Add this paragraph at this place in the commit message:
> >
> > "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, a regular deprecation
> > procedure shall occur for "loongson3-virt" machine."
> >
> OK, this will be added, and I will rename to "loongson3-virt-1.0",
> which can be updated in future.
> But I think rename the name string is enough, file names and function
> names can keep their old names.
>

Loongson3 is instruction set name, not a machine name, and treating
such name as machine name is incorrect. Renaming as I outlined in my
comments must occur.

Yours,
Aleksandar

> Huacai
> > > We already have a full functional Linux kernel (based on Linux-5.4.x LTS
> > > but not upstream yet) here:
> > >
> > > https://github.com/chenhuacai/linux
> > >
> > > 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 the a Loongson-3A4000 host with this kernel;
> > > 4, Build QEMU-5.0.0 with this patchset;
> > > 5, modprobe kvm;
> > > 6, Use QEMU with TCG (available in future):
> > >        qemu-system-mips64el -M loongson3,accel=tcg -cpu Loongson-3A1000 -kernel <path_to_kernel> -append ...
> >
> > Machine should be named loongson3-virt.
> >
> > >    Use QEMU with KVM (available at present):
> > >        qemu-system-mips64el -M loongson3,accel=kvm -cpu Loongson-3A4000 -kernel <path_to_kernel> -append ...
> > >
> >
> > Machine should be named loongson3-virt.
> >
> > >    The "-cpu" parameter can be omitted here and QEMU will use the correct type for TCG/KVM automatically.
> > >
> >
> > This is not a good approach, the cpu parameter should be required,
> > and, if it is not correct for particular circumstance, an error
> > message should be emitted to the user, and the emulation terminated.
> >
> > > 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                      |  10 +
> > >  hw/mips/Makefile.objs                |   1 +
> > >  hw/mips/loongson3.c                  | 901 +++++++++++++++++++++++++++++++++++
> >
> > The name of the file should be loongson3-virt.c
> >
> > >  4 files changed, 913 insertions(+)
> > >  create mode 100644 hw/mips/loongson3.c
> > >
> > > diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak
> > > index 9f8a3ef..2a2a3fb 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_LOONGSON3=y
> >
> > CONFIG_LOONGSON3-VIRT
> >
> > >  CONFIG_ATI_VGA=y
> > >  CONFIG_RTL8139_PCI=y
> > >  CONFIG_JAZZ=y
> > > diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig
> > > index 67d39c5..42931fd 100644
> > > --- a/hw/mips/Kconfig
> > > +++ b/hw/mips/Kconfig
> > > @@ -45,6 +45,16 @@ config FULOONG
> > >      bool
> > >      select PCI_BONITO
> > >
> > > +config LOONGSON3
> >
> > LOONGSON3-VIRT
> >
> > > +    bool
> > > +    select PCKBD
> > > +    select SERIAL
> > > +    select ISA_BUS
> > > +    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/Makefile.objs b/hw/mips/Makefile.objs
> > > index 3b3e6ea..31dedcb 100644
> > > --- a/hw/mips/Makefile.objs
> > > +++ b/hw/mips/Makefile.objs
> > > @@ -4,5 +4,6 @@ obj-$(CONFIG_MALTA) += gt64xxx_pci.o malta.o
> > >  obj-$(CONFIG_MIPSSIM) += mipssim.o
> > >  obj-$(CONFIG_JAZZ) += jazz.o
> > >  obj-$(CONFIG_FULOONG) += fuloong2e.o
> > > +obj-$(CONFIG_LOONGSON3) += loongson3.o
> >
> > CONFIG_LOONGSON3-VIRT
> >
> > >  obj-$(CONFIG_MIPS_CPS) += cps.o
> > >  obj-$(CONFIG_MIPS_BOSTON) += boston.o
> > > diff --git a/hw/mips/loongson3.c b/hw/mips/loongson3.c
> > > new file mode 100644
> > > index 0000000..e4b9538
> > > --- /dev/null
> > > +++ b/hw/mips/loongson3.c
> >
> > The file shoul be named loongson3-virt.c
> >
> > > @@ -0,0 +1,901 @@
> > > +/*
> > > + * Generic Loongson-3 Platform support
> >
> > "Support for loongson3-virt platform"
> >
> > > + *
> > > + * Copyright (c) 2016-2020 Huacai Chen (chenhc@lemote.com)
> > > + * This code is licensed under the GNU GPL v2.
> > > + *
> > > + * Contributions are licensed under the terms of the GNU GPL,
> > > + * version 2 or (at your option) any later version.
> >
> > License preamble should be harmonized, as we already agreed upon.
> >
> > > + */
> > > +
> > > +/*
> > > + * Generic 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 "hw/boards.h"
> > > +#include "hw/char/serial.h"
> > > +#include "hw/mips/mips.h"
> > > +#include "hw/mips/cpudevs.h"
> > > +#include "hw/intc/i8259.h"
> > > +#include "hw/loader.h"
> > > +#include "hw/ide.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 "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 INITRD_OFFSET         0x04000000
> > > +#define BOOTPARAM_ADDR        0x8ff00000
> > > +#define BOOTPARAM_PHYADDR     0x0ff00000
> > > +#define CFG_ADDR              0x0f100000
> > > +#define FW_CONF_ADDR          0x0fff0000
> > > +#define PM_MMIO_ADDR          0x10080000
> > > +#define PM_MMIO_SIZE          0x100
> > > +#define PM_CNTL_MODE          0x10
> > > +
> > > +#define PHYS_TO_VIRT(x) ((x) | ~(target_ulong)0x7fffffff)
> > > +
> > > +/* Loongson-3 has a 2MB flash rom */
> > > +#define BIOS_SIZE               (2 * MiB)
> > > +#define LOONGSON_MAX_VCPUS      16
> > > +
> > > +#define LOONGSON3_BIOSNAME "bios_loongson3.bin"
> > > +
> > > +#define PCIE_IRQ_BASE       3
> > > +
> > > +#define VIRT_PCI_IO_BASE    0x18000000ul
> > > +#define VIRT_PCI_IO_SIZE    0x000c0000ul
> > > +#define VIRT_PCI_MEM_BASE   0x40000000ul
> > > +#define VIRT_PCI_MEM_SIZE   0x40000000ul
> > > +#define VIRT_PCI_ECAM_BASE  0x1a000000ul
> > > +#define VIRT_PCI_ECAM_SIZE  0x02000000ul
> > > +
> > > +#define align(x) (((x) + 63) & ~63)
> > > +
> > > +/* 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;
> > > +};
> > > +
> > > +static struct _fw_config {
> > > +    unsigned long ram_size;
> > > +    unsigned int mem_freq;
> > > +    unsigned int nr_cpus;
> > > +    unsigned int cpu_clock_freq;
> > > +} fw_config;
> > > +
> > > +static struct _loaderparams {
> > > +    unsigned long ram_size;
> > > +    const char *kernel_cmdline;
> > > +    const char *kernel_filename;
> > > +    const char *initrd_filename;
> > > +    int64_t kernel_entry;
> > > +    unsigned long a0, a1, a2;
> > > +} loaderparams;
> > > +
> > > +static void *boot_params_p;
> > > +static void *boot_params_buf;
> > > +
> > > +static unsigned int bios_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                                                      */
> > > +};
> > > +
> > > +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 = (loaderparams.ram_size > 0x10000000
> > > +                            ? 256 : (loaderparams.ram_size >> 20)) - 16;
> > > +
> > > +    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 > 0x10000000
> > > +                            ? (loaderparams.ram_size >> 20) - 256 : 0);
> > > +
> > > +    return emap;
> > > +}
> > > +
> > > +static int get_host_cpu_freq(void)
> > > +{
> > > +    int fd = 0, freq = 0;
> > > +    char buf[1024], *buf_p;
> > > +
> > > +    fd = open("/proc/cpuinfo", O_RDONLY);
> > > +    if (fd == -1) {
> > > +        fprintf(stderr, "Failed to open /proc/cpuinfo!\n");
> > > +        return 0;
> > > +    }
> > > +
> > > +    if (read(fd, buf, 1024) < 0) {
> > > +        close(fd);
> > > +        fprintf(stderr, "Failed to read /proc/cpuinfo!\n");
> > > +        return 0;
> > > +    }
> > > +    close(fd);
> > > +
> > > +    buf_p = strstr(buf, "model name");
> > > +    while (*buf_p != '@') {
> > > +        buf_p++;
> > > +    }
> > > +
> > > +    buf_p += 2;
> > > +    memcpy(buf, buf_p, 12);
> > > +    buf_p = buf;
> > > +    while ((*buf_p >= '0') && (*buf_p <= '9')) {
> > > +        buf_p++;
> > > +    }
> > > +    *buf_p = '\0';
> > > +
> > > +    freq = atoi(buf);
> > > +
> > > +    return freq * 1000 * 1000;
> > > +}
> > > +
> > > +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 = 0x14C000;
> > > +    c->cpu_clock_freq = get_host_cpu_freq();
> > > +    if (!c->cpu_clock_freq) {
> > > +        c->cpu_clock_freq = 500000000;
> > > +    }
> > > +
> > > +    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;
> > > +    s->uarts[0].uart_base = 0x1fe001e0;
> > > +
> > > +    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_PCI_MEM_BASE;
> > > +    irq_info->pci_mem_end_addr   = VIRT_PCI_MEM_BASE + VIRT_PCI_MEM_SIZE - 1;
> > > +    irq_info->pci_io_start_addr  = VIRT_PCI_IO_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, "2016-05-16");
> > > +
> > > +    return special;
> > > +}
> > > +
> > > +static void init_loongson_params(struct loongson_params *lp)
> > > +{
> > > +    void *p = boot_params_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));
> > > +
> > > +    boot_params_p = p;
> > > +}
> > > +
> > > +static void init_smbios(struct smbios_tables *smbios)
> > > +{
> > > +    smbios->vers = 1;
> > > +    init_loongson_params(&(smbios->lp));
> > > +}
> > > +
> > > +static void init_efi(struct efi_loongson *efi)
> > > +{
> > > +    init_smbios(&(efi->smbios));
> > > +}
> > > +
> > > +static void init_reset_system(struct efi_reset_system_t *reset)
> > > +{
> > > +    reset->Shutdown = 0xffffffffbfc000a8;
> > > +    reset->ResetCold = 0xffffffffbfc00080;
> > > +    reset->ResetWarm = 0xffffffffbfc00080;
> > > +}
> > > +
> > > +static int init_boot_param(struct boot_params *bp)
> > > +{
> > > +    init_efi(&(bp->efi));
> > > +    init_reset_system(&(bp->reset_system));
> > > +
> > > +    return 0;
> > > +}
> > > +
> > > +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;
> > > +
> > > +    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);
> > > +    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
> > > +
> > > +    fw_config.ram_size = ram_size;
> > > +    fw_config.mem_freq = 300000000;
> > > +    fw_config.nr_cpus = current_machine->smp.cpus;
> > > +    fw_config.cpu_clock_freq = get_host_cpu_freq();
> > > +}
> > > +
> > > +static int set_prom_bootparam(ram_addr_t initrd_offset, long initrd_size)
> > > +{
> > > +    long params_size;
> > > +    char memenv[32];
> > > +    char highmemenv[32];
> > > +    void *params_buf;
> > > +    unsigned int *parg_env;
> > > +    int ret = 0;
> > > +
> > > +    /* Allocate params_buf for command line. */
> > > +    params_size = 0x100000;
> > > +    params_buf = g_malloc0(params_size);
> > > +
> > > +    /*
> > > +     * Layout of params_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 *)params_buf;
> > > +
> > > +    ret = (3 + 1) * 4;
> > > +    *parg_env++ = (BOOTPARAM_ADDR + ret);
> > > +    ret += (1 + snprintf(params_buf + ret, 256 - ret, "g"));
> > > +
> > > +    /* argv1 */
> > > +    *parg_env++ = BOOTPARAM_ADDR + ret;
> > > +    if (initrd_size > 0)
> > > +        ret += (1 + snprintf(params_buf + ret, 256 - ret,
> > > +                "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s",
> > > +                PHYS_TO_VIRT((uint32_t)initrd_offset),
> > > +                initrd_size, loaderparams.kernel_cmdline));
> > > +    else
> > > +        ret += (1 + snprintf(params_buf + ret, 256 - ret, "%s",
> > > +                loaderparams.kernel_cmdline));
> > > +
> > > +    /* argv2 */
> > > +    *parg_env++ = BOOTPARAM_ADDR + 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);
> > > +
> > > +    setenv("memsize", memenv, 1);
> > > +    setenv("highmemsize", highmemenv, 1);
> > > +
> > > +    ret = ((ret + 32) & ~31);
> > > +
> > > +    boot_params_buf = (void *)(params_buf + ret);
> > > +    boot_params_p = boot_params_buf + align(sizeof(struct boot_params));
> > > +
> > > +    init_boot_param(boot_params_buf);
> > > +
> > > +    rom_add_blob_fixed("params", params_buf, params_size,
> > > +                       BOOTPARAM_PHYADDR);
> > > +    loaderparams.a0 = 2;
> > > +    loaderparams.a1 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR;
> > > +    loaderparams.a2 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR + ret;
> > > +
> > > +    return 0;
> > > +}
> > > +
> > > +static int64_t load_kernel(CPUMIPSState *env)
> > > +{
> > > +    long kernel_size;
> > > +    ram_addr_t initrd_offset;
> > > +    int64_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, INITRD_OFFSET);
> > > +
> > > +            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 parameters. */
> > > +    set_prom_bootparam(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 void loongson3_isa_init(qemu_irq intc)
> >
> > Rename it to loongson3-virt_isa_init.
> >
> > > +{
> > > +    qemu_irq *i8259;
> > > +    ISABus *isa_bus;
> > > +
> > > +    isa_bus = isa_bus_new(NULL, get_system_memory(), get_system_io(), &error_abort);
> > > +
> > > +    /* Interrupt controller */
> > > +    /* The 8259 -> IP3  */
> > > +    i8259 = i8259_init(isa_bus, intc);
> > > +    isa_bus_irqs(isa_bus, i8259);
> > > +    /* init other devices */
> > > +    isa_create_simple(isa_bus, "i8042");
> > > +    mc146818_rtc_init(isa_bus, 2000, NULL);
> > > +}
> > > +
> > > +static inline void loongson3_pcie_init(MachineState *machine, DeviceState *pic)
> >
> > Rename it to loongson3-virt_pcie_init.
> >
> > > +{
> > > +    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_create(NULL, TYPE_GPEX_HOST);
> > > +
> > > +    qdev_init_nofail(dev);
> > > +    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_PCI_ECAM_SIZE);
> > > +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_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_PCI_MEM_BASE, VIRT_PCI_MEM_SIZE);
> > > +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_MEM_BASE, mmio_alias);
> > > +
> > > +    pio_alias = g_new0(MemoryRegion, 1);
> > > +    memory_region_init_alias(pio_alias, OBJECT(dev), "pcie-pio",
> > > +                             get_system_io(), 0, VIRT_PCI_IO_SIZE);
> > > +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_IO_BASE, pio_alias);
> > > +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, VIRT_PCI_IO_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);
> > > +
> > > +    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_init(MachineState *machine)
> >
> > Rename it to loongson3-virt_init.
> >
> > > +{
> > > +    int i;
> > > +    long bios_size;
> > > +    MIPSCPU *cpu;
> > > +    CPUMIPSState *env;
> > > +    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);
> > > +
> > > +    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 < 256 * 0x100000) {
> > > +        error_report("Loongson-3 need at least 256MB memory");
> > > +        exit(1);
> > > +    }
> > > +
> > > +    for (i = 0; i < machine->smp.cpus; i++) {
> > > +        /* 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);
> > > +    }
> > > +    env = &MIPS_CPU(first_cpu)->env;
> > > +
> > > +    /* Allocate RAM/BIOS, 0x00000000~0x10000000 is alias of 0x80000000~0x90000000 */
> > > +    memory_region_init_rom(bios, NULL, "loongson3.bios",
> > > +                           BIOS_SIZE, &error_fatal);
> > > +    memory_region_init_alias(ram, NULL, "loongson3.lowram",
> > > +                           machine->ram, 0, 256 * 0x100000);
> > > +    memory_region_init_io(iomem, NULL, &loongson3_pm_ops,
> > > +                           NULL, "loongson3_pm", PM_MMIO_SIZE);
> > > +
> > > +    memory_region_add_subregion(address_space_mem, 0x00000000LL, ram);
> > > +    memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios);
> > > +    memory_region_add_subregion(address_space_mem, 0x80000000LL, machine->ram);
> > > +    memory_region_add_subregion(address_space_mem, PM_MMIO_ADDR, iomem);
> > > +
> > > +    /*
> > > +     * We do not support flash operation, just loading pmon.bin as raw BIOS.
> > > +     * Please use -L to set the BIOS path and -bios to set bios name.
> > > +     */
> > > +
> > > +    if (kernel_filename) {
> > > +        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);
> > > +        rom_add_blob_fixed("bios",
> > > +                         bios_boot_code, sizeof(bios_boot_code), 0x1fc00000LL);
> > > +    } 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, 0x1fc00000LL,
> > > +                                            BIOS_SIZE);
> > > +            g_free(filename);
> > > +        } else {
> > > +            bios_size = -1;
> > > +        }
> > > +
> > > +        if ((bios_size < 0 || bios_size > BIOS_SIZE) &&
> > > +            !kernel_filename && !qtest_enabled()) {
> > > +            error_report("Could not load MIPS bios '%s'", bios_name);
> > > +            exit(1);
> > > +        }
> > > +
> > > +        fw_conf_init(ram_size);
> > > +        rom_add_blob_fixed("fw_conf",
> > > +                         &fw_config, sizeof(fw_config), FW_CONF_ADDR);
> > > +    }
> > > +
> > > +    msi_nonbroken = true;
> > > +    loongson3_isa_init(env->irq[3]);
> > > +    loongson3_pcie_init(machine, isa_pic);
> >
> > Names for two last functions should be already different.
> >
> > > +
> > > +    if (serial_hd(0)) {
> > > +        serial_mm_init(address_space_mem, 0x1fe001e0, 0, env->irq[2],
> > > +                           115200, serial_hd(0), DEVICE_NATIVE_ENDIAN);
> > > +    }
> > > +}
> > > +
> > > +static void mips_loongson3_machine_init(MachineClass *mc)
> >
> > Rename it to loongson3-virt_machine_init.
> >
> > > +{
> > > +    mc->desc = "Generic Loongson-3 Platform";
> > > +    mc->init = mips_loongson3_init;
> > > +    mc->block_default_type = IF_IDE;
> > > +    mc->max_cpus = LOONGSON_MAX_VCPUS;
> > > +    mc->default_ram_id = "loongson3.highram";
> > > +    mc->default_ram_size = 1200 * MiB;
> > > +    mc->kvm_type = mips_kvm_type;
> > > +    mc->minimum_page_bits = 14;
> > > +}
> > > +
> > > +DEFINE_MACHINE("loongson3", mips_loongson3_machine_init)
> >
> > DEFINE_MACHINE("loongson3-virt", loongson3-virt_machine_init)
> >
> > > --
> > > 2.7.0
> > >


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

* Re: [PATCH for-5.1 V4 3/4] hw/mips: Add Loongson-3 machine support (with KVM)
  2020-06-15  4:50       ` Aleksandar Markovic
@ 2020-06-15  5:36         ` Huacai Chen
  2020-06-15  5:58           ` Aleksandar Markovic
  2020-06-15  6:04           ` Aleksandar Markovic
  0 siblings, 2 replies; 41+ messages in thread
From: Huacai Chen @ 2020-06-15  5:36 UTC (permalink / raw)
  To: Aleksandar Markovic
  Cc: Huacai Chen, Aleksandar Rikalo, Philippe Mathieu-Daudé,
	Aurelien Jarno, QEMU Developers

Hi, Aleksandar,

On Mon, Jun 15, 2020 at 12:50 PM Aleksandar Markovic
<aleksandar.qemu.devel@gmail.com> wrote:
>
> пон, 15. јун 2020. у 02:55 Huacai Chen <chenhuacai@gmail.com> је написао/ла:
> >
> > Hi, Aleksandar,
> >
> > On Sun, Jun 14, 2020 at 3:51 PM Aleksandar Markovic
> > <aleksandar.qemu.devel@gmail.com> wrote:
> > >
> > > Hi, Huacai, this is another round of comments, that should be addressed in v5.
> > >
> > > уто, 2. јун 2020. у 04:40 Huacai Chen <zltjiangshi@gmail.com> је написао/ла:
> > > >
> > > > Add Loongson-3 based machine support, it use i8259 as the interrupt
> > > > controler and use GPEX as the pci controller. Currently it can only
> > > > work with KVM, but we will add TCG support in future.
> > > >
> > >
> > > Add this paragraph at this place in the commit message:
> > >
> > > "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, a regular deprecation
> > > procedure shall occur for "loongson3-virt" machine."
> > >
> > OK, this will be added, and I will rename to "loongson3-virt-1.0",
> > which can be updated in future.
> > But I think rename the name string is enough, file names and function
> > names can keep their old names.
Why ARM can use version name?
virt-2.10 QEMU 2.10 ARM Virtual Machine
virt-2.11 QEMU 2.11 ARM Virtual Machine
virt-2.12 QEMU 2.12 ARM Virtual Machine
virt-2.6 QEMU 2.6 ARM Virtual Machine
virt-2.7 QEMU 2.7 ARM Virtual Machine
virt-2.8 QEMU 2.8 ARM Virtual Machine
virt-2.9 QEMU 2.9 ARM Virtual Machine
virt-3.0 QEMU 3.0 ARM Virtual Machine
virt-3.1 QEMU 3.1 ARM Virtual Machine
virt-4.0 QEMU 4.0 ARM Virtual Machine
virt-4.1 QEMU 4.1 ARM Virtual Machine
virt-4.2 QEMU 4.2 ARM Virtual Machine
virt QEMU 5.0 ARM Virtual Machine (alias of virt-5.0)

In future will will replace i8259 with an advanced PIC, that will be
loongson3-virt-2.0.

> >
>
> Loongson3 is instruction set name, not a machine name, and treating
> such name as machine name is incorrect. Renaming as I outlined in my
> comments must occur.
In future, both real machine and virtual machine models will be
implement in the same file, so I think loongson3.c is better than
loongson3-virt.c

>
> Yours,
> Aleksandar
>
> > Huacai
> > > > We already have a full functional Linux kernel (based on Linux-5.4.x LTS
> > > > but not upstream yet) here:
> > > >
> > > > https://github.com/chenhuacai/linux
> > > >
> > > > 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 the a Loongson-3A4000 host with this kernel;
> > > > 4, Build QEMU-5.0.0 with this patchset;
> > > > 5, modprobe kvm;
> > > > 6, Use QEMU with TCG (available in future):
> > > >        qemu-system-mips64el -M loongson3,accel=tcg -cpu Loongson-3A1000 -kernel <path_to_kernel> -append ...
> > >
> > > Machine should be named loongson3-virt.
> > >
> > > >    Use QEMU with KVM (available at present):
> > > >        qemu-system-mips64el -M loongson3,accel=kvm -cpu Loongson-3A4000 -kernel <path_to_kernel> -append ...
> > > >
> > >
> > > Machine should be named loongson3-virt.
> > >
> > > >    The "-cpu" parameter can be omitted here and QEMU will use the correct type for TCG/KVM automatically.
> > > >
> > >
> > > This is not a good approach, the cpu parameter should be required,
> > > and, if it is not correct for particular circumstance, an error
> > > message should be emitted to the user, and the emulation terminated.
> > >
> > > > 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                      |  10 +
> > > >  hw/mips/Makefile.objs                |   1 +
> > > >  hw/mips/loongson3.c                  | 901 +++++++++++++++++++++++++++++++++++
> > >
> > > The name of the file should be loongson3-virt.c
> > >
> > > >  4 files changed, 913 insertions(+)
> > > >  create mode 100644 hw/mips/loongson3.c
> > > >
> > > > diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak
> > > > index 9f8a3ef..2a2a3fb 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_LOONGSON3=y
> > >
> > > CONFIG_LOONGSON3-VIRT
> > >
> > > >  CONFIG_ATI_VGA=y
> > > >  CONFIG_RTL8139_PCI=y
> > > >  CONFIG_JAZZ=y
> > > > diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig
> > > > index 67d39c5..42931fd 100644
> > > > --- a/hw/mips/Kconfig
> > > > +++ b/hw/mips/Kconfig
> > > > @@ -45,6 +45,16 @@ config FULOONG
> > > >      bool
> > > >      select PCI_BONITO
> > > >
> > > > +config LOONGSON3
> > >
> > > LOONGSON3-VIRT
> > >
> > > > +    bool
> > > > +    select PCKBD
> > > > +    select SERIAL
> > > > +    select ISA_BUS
> > > > +    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/Makefile.objs b/hw/mips/Makefile.objs
> > > > index 3b3e6ea..31dedcb 100644
> > > > --- a/hw/mips/Makefile.objs
> > > > +++ b/hw/mips/Makefile.objs
> > > > @@ -4,5 +4,6 @@ obj-$(CONFIG_MALTA) += gt64xxx_pci.o malta.o
> > > >  obj-$(CONFIG_MIPSSIM) += mipssim.o
> > > >  obj-$(CONFIG_JAZZ) += jazz.o
> > > >  obj-$(CONFIG_FULOONG) += fuloong2e.o
> > > > +obj-$(CONFIG_LOONGSON3) += loongson3.o
> > >
> > > CONFIG_LOONGSON3-VIRT
> > >
> > > >  obj-$(CONFIG_MIPS_CPS) += cps.o
> > > >  obj-$(CONFIG_MIPS_BOSTON) += boston.o
> > > > diff --git a/hw/mips/loongson3.c b/hw/mips/loongson3.c
> > > > new file mode 100644
> > > > index 0000000..e4b9538
> > > > --- /dev/null
> > > > +++ b/hw/mips/loongson3.c
> > >
> > > The file shoul be named loongson3-virt.c
> > >
> > > > @@ -0,0 +1,901 @@
> > > > +/*
> > > > + * Generic Loongson-3 Platform support
> > >
> > > "Support for loongson3-virt platform"
> > >
> > > > + *
> > > > + * Copyright (c) 2016-2020 Huacai Chen (chenhc@lemote.com)
> > > > + * This code is licensed under the GNU GPL v2.
> > > > + *
> > > > + * Contributions are licensed under the terms of the GNU GPL,
> > > > + * version 2 or (at your option) any later version.
> > >
> > > License preamble should be harmonized, as we already agreed upon.
> > >
> > > > + */
> > > > +
> > > > +/*
> > > > + * Generic 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 "hw/boards.h"
> > > > +#include "hw/char/serial.h"
> > > > +#include "hw/mips/mips.h"
> > > > +#include "hw/mips/cpudevs.h"
> > > > +#include "hw/intc/i8259.h"
> > > > +#include "hw/loader.h"
> > > > +#include "hw/ide.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 "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 INITRD_OFFSET         0x04000000
> > > > +#define BOOTPARAM_ADDR        0x8ff00000
> > > > +#define BOOTPARAM_PHYADDR     0x0ff00000
> > > > +#define CFG_ADDR              0x0f100000
> > > > +#define FW_CONF_ADDR          0x0fff0000
> > > > +#define PM_MMIO_ADDR          0x10080000
> > > > +#define PM_MMIO_SIZE          0x100
> > > > +#define PM_CNTL_MODE          0x10
> > > > +
> > > > +#define PHYS_TO_VIRT(x) ((x) | ~(target_ulong)0x7fffffff)
> > > > +
> > > > +/* Loongson-3 has a 2MB flash rom */
> > > > +#define BIOS_SIZE               (2 * MiB)
> > > > +#define LOONGSON_MAX_VCPUS      16
> > > > +
> > > > +#define LOONGSON3_BIOSNAME "bios_loongson3.bin"
> > > > +
> > > > +#define PCIE_IRQ_BASE       3
> > > > +
> > > > +#define VIRT_PCI_IO_BASE    0x18000000ul
> > > > +#define VIRT_PCI_IO_SIZE    0x000c0000ul
> > > > +#define VIRT_PCI_MEM_BASE   0x40000000ul
> > > > +#define VIRT_PCI_MEM_SIZE   0x40000000ul
> > > > +#define VIRT_PCI_ECAM_BASE  0x1a000000ul
> > > > +#define VIRT_PCI_ECAM_SIZE  0x02000000ul
> > > > +
> > > > +#define align(x) (((x) + 63) & ~63)
> > > > +
> > > > +/* 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;
> > > > +};
> > > > +
> > > > +static struct _fw_config {
> > > > +    unsigned long ram_size;
> > > > +    unsigned int mem_freq;
> > > > +    unsigned int nr_cpus;
> > > > +    unsigned int cpu_clock_freq;
> > > > +} fw_config;
> > > > +
> > > > +static struct _loaderparams {
> > > > +    unsigned long ram_size;
> > > > +    const char *kernel_cmdline;
> > > > +    const char *kernel_filename;
> > > > +    const char *initrd_filename;
> > > > +    int64_t kernel_entry;
> > > > +    unsigned long a0, a1, a2;
> > > > +} loaderparams;
> > > > +
> > > > +static void *boot_params_p;
> > > > +static void *boot_params_buf;
> > > > +
> > > > +static unsigned int bios_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                                                      */
> > > > +};
> > > > +
> > > > +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 = (loaderparams.ram_size > 0x10000000
> > > > +                            ? 256 : (loaderparams.ram_size >> 20)) - 16;
> > > > +
> > > > +    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 > 0x10000000
> > > > +                            ? (loaderparams.ram_size >> 20) - 256 : 0);
> > > > +
> > > > +    return emap;
> > > > +}
> > > > +
> > > > +static int get_host_cpu_freq(void)
> > > > +{
> > > > +    int fd = 0, freq = 0;
> > > > +    char buf[1024], *buf_p;
> > > > +
> > > > +    fd = open("/proc/cpuinfo", O_RDONLY);
> > > > +    if (fd == -1) {
> > > > +        fprintf(stderr, "Failed to open /proc/cpuinfo!\n");
> > > > +        return 0;
> > > > +    }
> > > > +
> > > > +    if (read(fd, buf, 1024) < 0) {
> > > > +        close(fd);
> > > > +        fprintf(stderr, "Failed to read /proc/cpuinfo!\n");
> > > > +        return 0;
> > > > +    }
> > > > +    close(fd);
> > > > +
> > > > +    buf_p = strstr(buf, "model name");
> > > > +    while (*buf_p != '@') {
> > > > +        buf_p++;
> > > > +    }
> > > > +
> > > > +    buf_p += 2;
> > > > +    memcpy(buf, buf_p, 12);
> > > > +    buf_p = buf;
> > > > +    while ((*buf_p >= '0') && (*buf_p <= '9')) {
> > > > +        buf_p++;
> > > > +    }
> > > > +    *buf_p = '\0';
> > > > +
> > > > +    freq = atoi(buf);
> > > > +
> > > > +    return freq * 1000 * 1000;
> > > > +}
> > > > +
> > > > +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 = 0x14C000;
> > > > +    c->cpu_clock_freq = get_host_cpu_freq();
> > > > +    if (!c->cpu_clock_freq) {
> > > > +        c->cpu_clock_freq = 500000000;
> > > > +    }
> > > > +
> > > > +    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;
> > > > +    s->uarts[0].uart_base = 0x1fe001e0;
> > > > +
> > > > +    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_PCI_MEM_BASE;
> > > > +    irq_info->pci_mem_end_addr   = VIRT_PCI_MEM_BASE + VIRT_PCI_MEM_SIZE - 1;
> > > > +    irq_info->pci_io_start_addr  = VIRT_PCI_IO_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, "2016-05-16");
> > > > +
> > > > +    return special;
> > > > +}
> > > > +
> > > > +static void init_loongson_params(struct loongson_params *lp)
> > > > +{
> > > > +    void *p = boot_params_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));
> > > > +
> > > > +    boot_params_p = p;
> > > > +}
> > > > +
> > > > +static void init_smbios(struct smbios_tables *smbios)
> > > > +{
> > > > +    smbios->vers = 1;
> > > > +    init_loongson_params(&(smbios->lp));
> > > > +}
> > > > +
> > > > +static void init_efi(struct efi_loongson *efi)
> > > > +{
> > > > +    init_smbios(&(efi->smbios));
> > > > +}
> > > > +
> > > > +static void init_reset_system(struct efi_reset_system_t *reset)
> > > > +{
> > > > +    reset->Shutdown = 0xffffffffbfc000a8;
> > > > +    reset->ResetCold = 0xffffffffbfc00080;
> > > > +    reset->ResetWarm = 0xffffffffbfc00080;
> > > > +}
> > > > +
> > > > +static int init_boot_param(struct boot_params *bp)
> > > > +{
> > > > +    init_efi(&(bp->efi));
> > > > +    init_reset_system(&(bp->reset_system));
> > > > +
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +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;
> > > > +
> > > > +    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);
> > > > +    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
> > > > +
> > > > +    fw_config.ram_size = ram_size;
> > > > +    fw_config.mem_freq = 300000000;
> > > > +    fw_config.nr_cpus = current_machine->smp.cpus;
> > > > +    fw_config.cpu_clock_freq = get_host_cpu_freq();
> > > > +}
> > > > +
> > > > +static int set_prom_bootparam(ram_addr_t initrd_offset, long initrd_size)
> > > > +{
> > > > +    long params_size;
> > > > +    char memenv[32];
> > > > +    char highmemenv[32];
> > > > +    void *params_buf;
> > > > +    unsigned int *parg_env;
> > > > +    int ret = 0;
> > > > +
> > > > +    /* Allocate params_buf for command line. */
> > > > +    params_size = 0x100000;
> > > > +    params_buf = g_malloc0(params_size);
> > > > +
> > > > +    /*
> > > > +     * Layout of params_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 *)params_buf;
> > > > +
> > > > +    ret = (3 + 1) * 4;
> > > > +    *parg_env++ = (BOOTPARAM_ADDR + ret);
> > > > +    ret += (1 + snprintf(params_buf + ret, 256 - ret, "g"));
> > > > +
> > > > +    /* argv1 */
> > > > +    *parg_env++ = BOOTPARAM_ADDR + ret;
> > > > +    if (initrd_size > 0)
> > > > +        ret += (1 + snprintf(params_buf + ret, 256 - ret,
> > > > +                "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s",
> > > > +                PHYS_TO_VIRT((uint32_t)initrd_offset),
> > > > +                initrd_size, loaderparams.kernel_cmdline));
> > > > +    else
> > > > +        ret += (1 + snprintf(params_buf + ret, 256 - ret, "%s",
> > > > +                loaderparams.kernel_cmdline));
> > > > +
> > > > +    /* argv2 */
> > > > +    *parg_env++ = BOOTPARAM_ADDR + 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);
> > > > +
> > > > +    setenv("memsize", memenv, 1);
> > > > +    setenv("highmemsize", highmemenv, 1);
> > > > +
> > > > +    ret = ((ret + 32) & ~31);
> > > > +
> > > > +    boot_params_buf = (void *)(params_buf + ret);
> > > > +    boot_params_p = boot_params_buf + align(sizeof(struct boot_params));
> > > > +
> > > > +    init_boot_param(boot_params_buf);
> > > > +
> > > > +    rom_add_blob_fixed("params", params_buf, params_size,
> > > > +                       BOOTPARAM_PHYADDR);
> > > > +    loaderparams.a0 = 2;
> > > > +    loaderparams.a1 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR;
> > > > +    loaderparams.a2 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR + ret;
> > > > +
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int64_t load_kernel(CPUMIPSState *env)
> > > > +{
> > > > +    long kernel_size;
> > > > +    ram_addr_t initrd_offset;
> > > > +    int64_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, INITRD_OFFSET);
> > > > +
> > > > +            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 parameters. */
> > > > +    set_prom_bootparam(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 void loongson3_isa_init(qemu_irq intc)
> > >
> > > Rename it to loongson3-virt_isa_init.
> > >
> > > > +{
> > > > +    qemu_irq *i8259;
> > > > +    ISABus *isa_bus;
> > > > +
> > > > +    isa_bus = isa_bus_new(NULL, get_system_memory(), get_system_io(), &error_abort);
> > > > +
> > > > +    /* Interrupt controller */
> > > > +    /* The 8259 -> IP3  */
> > > > +    i8259 = i8259_init(isa_bus, intc);
> > > > +    isa_bus_irqs(isa_bus, i8259);
> > > > +    /* init other devices */
> > > > +    isa_create_simple(isa_bus, "i8042");
> > > > +    mc146818_rtc_init(isa_bus, 2000, NULL);
> > > > +}
> > > > +
> > > > +static inline void loongson3_pcie_init(MachineState *machine, DeviceState *pic)
> > >
> > > Rename it to loongson3-virt_pcie_init.
> > >
> > > > +{
> > > > +    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_create(NULL, TYPE_GPEX_HOST);
> > > > +
> > > > +    qdev_init_nofail(dev);
> > > > +    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_PCI_ECAM_SIZE);
> > > > +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_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_PCI_MEM_BASE, VIRT_PCI_MEM_SIZE);
> > > > +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_MEM_BASE, mmio_alias);
> > > > +
> > > > +    pio_alias = g_new0(MemoryRegion, 1);
> > > > +    memory_region_init_alias(pio_alias, OBJECT(dev), "pcie-pio",
> > > > +                             get_system_io(), 0, VIRT_PCI_IO_SIZE);
> > > > +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_IO_BASE, pio_alias);
> > > > +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, VIRT_PCI_IO_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);
> > > > +
> > > > +    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_init(MachineState *machine)
> > >
> > > Rename it to loongson3-virt_init.
> > >
> > > > +{
> > > > +    int i;
> > > > +    long bios_size;
> > > > +    MIPSCPU *cpu;
> > > > +    CPUMIPSState *env;
> > > > +    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);
> > > > +
> > > > +    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 < 256 * 0x100000) {
> > > > +        error_report("Loongson-3 need at least 256MB memory");
> > > > +        exit(1);
> > > > +    }
> > > > +
> > > > +    for (i = 0; i < machine->smp.cpus; i++) {
> > > > +        /* 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);
> > > > +    }
> > > > +    env = &MIPS_CPU(first_cpu)->env;
> > > > +
> > > > +    /* Allocate RAM/BIOS, 0x00000000~0x10000000 is alias of 0x80000000~0x90000000 */
> > > > +    memory_region_init_rom(bios, NULL, "loongson3.bios",
> > > > +                           BIOS_SIZE, &error_fatal);
> > > > +    memory_region_init_alias(ram, NULL, "loongson3.lowram",
> > > > +                           machine->ram, 0, 256 * 0x100000);
> > > > +    memory_region_init_io(iomem, NULL, &loongson3_pm_ops,
> > > > +                           NULL, "loongson3_pm", PM_MMIO_SIZE);
> > > > +
> > > > +    memory_region_add_subregion(address_space_mem, 0x00000000LL, ram);
> > > > +    memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios);
> > > > +    memory_region_add_subregion(address_space_mem, 0x80000000LL, machine->ram);
> > > > +    memory_region_add_subregion(address_space_mem, PM_MMIO_ADDR, iomem);
> > > > +
> > > > +    /*
> > > > +     * We do not support flash operation, just loading pmon.bin as raw BIOS.
> > > > +     * Please use -L to set the BIOS path and -bios to set bios name.
> > > > +     */
> > > > +
> > > > +    if (kernel_filename) {
> > > > +        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);
> > > > +        rom_add_blob_fixed("bios",
> > > > +                         bios_boot_code, sizeof(bios_boot_code), 0x1fc00000LL);
> > > > +    } 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, 0x1fc00000LL,
> > > > +                                            BIOS_SIZE);
> > > > +            g_free(filename);
> > > > +        } else {
> > > > +            bios_size = -1;
> > > > +        }
> > > > +
> > > > +        if ((bios_size < 0 || bios_size > BIOS_SIZE) &&
> > > > +            !kernel_filename && !qtest_enabled()) {
> > > > +            error_report("Could not load MIPS bios '%s'", bios_name);
> > > > +            exit(1);
> > > > +        }
> > > > +
> > > > +        fw_conf_init(ram_size);
> > > > +        rom_add_blob_fixed("fw_conf",
> > > > +                         &fw_config, sizeof(fw_config), FW_CONF_ADDR);
> > > > +    }
> > > > +
> > > > +    msi_nonbroken = true;
> > > > +    loongson3_isa_init(env->irq[3]);
> > > > +    loongson3_pcie_init(machine, isa_pic);
> > >
> > > Names for two last functions should be already different.
> > >
> > > > +
> > > > +    if (serial_hd(0)) {
> > > > +        serial_mm_init(address_space_mem, 0x1fe001e0, 0, env->irq[2],
> > > > +                           115200, serial_hd(0), DEVICE_NATIVE_ENDIAN);
> > > > +    }
> > > > +}
> > > > +
> > > > +static void mips_loongson3_machine_init(MachineClass *mc)
> > >
> > > Rename it to loongson3-virt_machine_init.
> > >
> > > > +{
> > > > +    mc->desc = "Generic Loongson-3 Platform";
> > > > +    mc->init = mips_loongson3_init;
> > > > +    mc->block_default_type = IF_IDE;
> > > > +    mc->max_cpus = LOONGSON_MAX_VCPUS;
> > > > +    mc->default_ram_id = "loongson3.highram";
> > > > +    mc->default_ram_size = 1200 * MiB;
> > > > +    mc->kvm_type = mips_kvm_type;
> > > > +    mc->minimum_page_bits = 14;
> > > > +}
> > > > +
> > > > +DEFINE_MACHINE("loongson3", mips_loongson3_machine_init)
> > >
> > > DEFINE_MACHINE("loongson3-virt", loongson3-virt_machine_init)
> > >
> > > > --
> > > > 2.7.0
> > > >


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

* Re: [PATCH for-5.1 V4 3/4] hw/mips: Add Loongson-3 machine support (with KVM)
  2020-06-15  5:36         ` Huacai Chen
@ 2020-06-15  5:58           ` Aleksandar Markovic
  2020-06-15  6:04           ` Aleksandar Markovic
  1 sibling, 0 replies; 41+ messages in thread
From: Aleksandar Markovic @ 2020-06-15  5:58 UTC (permalink / raw)
  To: Huacai Chen
  Cc: Huacai Chen, Aleksandar Rikalo, Philippe Mathieu-Daudé,
	Aurelien Jarno, QEMU Developers

пон, 15. јун 2020. у 07:36 Huacai Chen <chenhuacai@gmail.com> је написао/ла:
>
> Hi, Aleksandar,
>
> On Mon, Jun 15, 2020 at 12:50 PM Aleksandar Markovic
> <aleksandar.qemu.devel@gmail.com> wrote:
> >
> > пон, 15. јун 2020. у 02:55 Huacai Chen <chenhuacai@gmail.com> је написао/ла:
> > >
> > > Hi, Aleksandar,
> > >
> > > On Sun, Jun 14, 2020 at 3:51 PM Aleksandar Markovic
> > > <aleksandar.qemu.devel@gmail.com> wrote:
> > > >
> > > > Hi, Huacai, this is another round of comments, that should be addressed in v5.
> > > >
> > > > уто, 2. јун 2020. у 04:40 Huacai Chen <zltjiangshi@gmail.com> је написао/ла:
> > > > >
> > > > > Add Loongson-3 based machine support, it use i8259 as the interrupt
> > > > > controler and use GPEX as the pci controller. Currently it can only
> > > > > work with KVM, but we will add TCG support in future.
> > > > >
> > > >
> > > > Add this paragraph at this place in the commit message:
> > > >
> > > > "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, a regular deprecation
> > > > procedure shall occur for "loongson3-virt" machine."
> > > >
> > > OK, this will be added, and I will rename to "loongson3-virt-1.0",
> > > which can be updated in future.
> > > But I think rename the name string is enough, file names and function
> > > names can keep their old names.
> Why ARM can use version name?
> virt-2.10 QEMU 2.10 ARM Virtual Machine
> virt-2.11 QEMU 2.11 ARM Virtual Machine
> virt-2.12 QEMU 2.12 ARM Virtual Machine
> virt-2.6 QEMU 2.6 ARM Virtual Machine
> virt-2.7 QEMU 2.7 ARM Virtual Machine
> virt-2.8 QEMU 2.8 ARM Virtual Machine
> virt-2.9 QEMU 2.9 ARM Virtual Machine
> virt-3.0 QEMU 3.0 ARM Virtual Machine
> virt-3.1 QEMU 3.1 ARM Virtual Machine
> virt-4.0 QEMU 4.0 ARM Virtual Machine
> virt-4.1 QEMU 4.1 ARM Virtual Machine
> virt-4.2 QEMU 4.2 ARM Virtual Machine
> virt QEMU 5.0 ARM Virtual Machine (alias of virt-5.0)
>
> In future will will replace i8259 with an advanced PIC, that will be
> loongson3-virt-2.0.

Huacai, you are making a mistake that I see over and over and over
again, most often with new contributors, but in some cases with
experienced contributors too.

QEMU is a complex system, made in various periods of time, its
internal interfaces and implementation approaches and principles also
changing in time. As a consequence, if you see an example in QEMU
code, it does not authomatically mean that you can or should make
something similar to that example.

As I said before, I would advice you to make future Loongson3 machines
reflect the real systems, but if you insist on making two or more
Loongson3 virtual machines, submit that proposal at some point in
future, and we will discuss it. Although I strongly discourage you
from doing that.

Yours,
Aleksandar

> > >
> >
> > Loongson3 is instruction set name, not a machine name, and treating
> > such name as machine name is incorrect. Renaming as I outlined in my
> > comments must occur.
> In future, both real machine and virtual machine models will be
> implement in the same file, so I think loongson3.c is better than
> loongson3-virt.c
>
> >
> > Yours,
> > Aleksandar
> >
> > > Huacai
> > > > > We already have a full functional Linux kernel (based on Linux-5.4.x LTS
> > > > > but not upstream yet) here:
> > > > >
> > > > > https://github.com/chenhuacai/linux
> > > > >
> > > > > 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 the a Loongson-3A4000 host with this kernel;
> > > > > 4, Build QEMU-5.0.0 with this patchset;
> > > > > 5, modprobe kvm;
> > > > > 6, Use QEMU with TCG (available in future):
> > > > >        qemu-system-mips64el -M loongson3,accel=tcg -cpu Loongson-3A1000 -kernel <path_to_kernel> -append ...
> > > >
> > > > Machine should be named loongson3-virt.
> > > >
> > > > >    Use QEMU with KVM (available at present):
> > > > >        qemu-system-mips64el -M loongson3,accel=kvm -cpu Loongson-3A4000 -kernel <path_to_kernel> -append ...
> > > > >
> > > >
> > > > Machine should be named loongson3-virt.
> > > >
> > > > >    The "-cpu" parameter can be omitted here and QEMU will use the correct type for TCG/KVM automatically.
> > > > >
> > > >
> > > > This is not a good approach, the cpu parameter should be required,
> > > > and, if it is not correct for particular circumstance, an error
> > > > message should be emitted to the user, and the emulation terminated.
> > > >
> > > > > 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                      |  10 +
> > > > >  hw/mips/Makefile.objs                |   1 +
> > > > >  hw/mips/loongson3.c                  | 901 +++++++++++++++++++++++++++++++++++
> > > >
> > > > The name of the file should be loongson3-virt.c
> > > >
> > > > >  4 files changed, 913 insertions(+)
> > > > >  create mode 100644 hw/mips/loongson3.c
> > > > >
> > > > > diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak
> > > > > index 9f8a3ef..2a2a3fb 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_LOONGSON3=y
> > > >
> > > > CONFIG_LOONGSON3-VIRT
> > > >
> > > > >  CONFIG_ATI_VGA=y
> > > > >  CONFIG_RTL8139_PCI=y
> > > > >  CONFIG_JAZZ=y
> > > > > diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig
> > > > > index 67d39c5..42931fd 100644
> > > > > --- a/hw/mips/Kconfig
> > > > > +++ b/hw/mips/Kconfig
> > > > > @@ -45,6 +45,16 @@ config FULOONG
> > > > >      bool
> > > > >      select PCI_BONITO
> > > > >
> > > > > +config LOONGSON3
> > > >
> > > > LOONGSON3-VIRT
> > > >
> > > > > +    bool
> > > > > +    select PCKBD
> > > > > +    select SERIAL
> > > > > +    select ISA_BUS
> > > > > +    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/Makefile.objs b/hw/mips/Makefile.objs
> > > > > index 3b3e6ea..31dedcb 100644
> > > > > --- a/hw/mips/Makefile.objs
> > > > > +++ b/hw/mips/Makefile.objs
> > > > > @@ -4,5 +4,6 @@ obj-$(CONFIG_MALTA) += gt64xxx_pci.o malta.o
> > > > >  obj-$(CONFIG_MIPSSIM) += mipssim.o
> > > > >  obj-$(CONFIG_JAZZ) += jazz.o
> > > > >  obj-$(CONFIG_FULOONG) += fuloong2e.o
> > > > > +obj-$(CONFIG_LOONGSON3) += loongson3.o
> > > >
> > > > CONFIG_LOONGSON3-VIRT
> > > >
> > > > >  obj-$(CONFIG_MIPS_CPS) += cps.o
> > > > >  obj-$(CONFIG_MIPS_BOSTON) += boston.o
> > > > > diff --git a/hw/mips/loongson3.c b/hw/mips/loongson3.c
> > > > > new file mode 100644
> > > > > index 0000000..e4b9538
> > > > > --- /dev/null
> > > > > +++ b/hw/mips/loongson3.c
> > > >
> > > > The file shoul be named loongson3-virt.c
> > > >
> > > > > @@ -0,0 +1,901 @@
> > > > > +/*
> > > > > + * Generic Loongson-3 Platform support
> > > >
> > > > "Support for loongson3-virt platform"
> > > >
> > > > > + *
> > > > > + * Copyright (c) 2016-2020 Huacai Chen (chenhc@lemote.com)
> > > > > + * This code is licensed under the GNU GPL v2.
> > > > > + *
> > > > > + * Contributions are licensed under the terms of the GNU GPL,
> > > > > + * version 2 or (at your option) any later version.
> > > >
> > > > License preamble should be harmonized, as we already agreed upon.
> > > >
> > > > > + */
> > > > > +
> > > > > +/*
> > > > > + * Generic 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 "hw/boards.h"
> > > > > +#include "hw/char/serial.h"
> > > > > +#include "hw/mips/mips.h"
> > > > > +#include "hw/mips/cpudevs.h"
> > > > > +#include "hw/intc/i8259.h"
> > > > > +#include "hw/loader.h"
> > > > > +#include "hw/ide.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 "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 INITRD_OFFSET         0x04000000
> > > > > +#define BOOTPARAM_ADDR        0x8ff00000
> > > > > +#define BOOTPARAM_PHYADDR     0x0ff00000
> > > > > +#define CFG_ADDR              0x0f100000
> > > > > +#define FW_CONF_ADDR          0x0fff0000
> > > > > +#define PM_MMIO_ADDR          0x10080000
> > > > > +#define PM_MMIO_SIZE          0x100
> > > > > +#define PM_CNTL_MODE          0x10
> > > > > +
> > > > > +#define PHYS_TO_VIRT(x) ((x) | ~(target_ulong)0x7fffffff)
> > > > > +
> > > > > +/* Loongson-3 has a 2MB flash rom */
> > > > > +#define BIOS_SIZE               (2 * MiB)
> > > > > +#define LOONGSON_MAX_VCPUS      16
> > > > > +
> > > > > +#define LOONGSON3_BIOSNAME "bios_loongson3.bin"
> > > > > +
> > > > > +#define PCIE_IRQ_BASE       3
> > > > > +
> > > > > +#define VIRT_PCI_IO_BASE    0x18000000ul
> > > > > +#define VIRT_PCI_IO_SIZE    0x000c0000ul
> > > > > +#define VIRT_PCI_MEM_BASE   0x40000000ul
> > > > > +#define VIRT_PCI_MEM_SIZE   0x40000000ul
> > > > > +#define VIRT_PCI_ECAM_BASE  0x1a000000ul
> > > > > +#define VIRT_PCI_ECAM_SIZE  0x02000000ul
> > > > > +
> > > > > +#define align(x) (((x) + 63) & ~63)
> > > > > +
> > > > > +/* 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;
> > > > > +};
> > > > > +
> > > > > +static struct _fw_config {
> > > > > +    unsigned long ram_size;
> > > > > +    unsigned int mem_freq;
> > > > > +    unsigned int nr_cpus;
> > > > > +    unsigned int cpu_clock_freq;
> > > > > +} fw_config;
> > > > > +
> > > > > +static struct _loaderparams {
> > > > > +    unsigned long ram_size;
> > > > > +    const char *kernel_cmdline;
> > > > > +    const char *kernel_filename;
> > > > > +    const char *initrd_filename;
> > > > > +    int64_t kernel_entry;
> > > > > +    unsigned long a0, a1, a2;
> > > > > +} loaderparams;
> > > > > +
> > > > > +static void *boot_params_p;
> > > > > +static void *boot_params_buf;
> > > > > +
> > > > > +static unsigned int bios_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                                                      */
> > > > > +};
> > > > > +
> > > > > +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 = (loaderparams.ram_size > 0x10000000
> > > > > +                            ? 256 : (loaderparams.ram_size >> 20)) - 16;
> > > > > +
> > > > > +    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 > 0x10000000
> > > > > +                            ? (loaderparams.ram_size >> 20) - 256 : 0);
> > > > > +
> > > > > +    return emap;
> > > > > +}
> > > > > +
> > > > > +static int get_host_cpu_freq(void)
> > > > > +{
> > > > > +    int fd = 0, freq = 0;
> > > > > +    char buf[1024], *buf_p;
> > > > > +
> > > > > +    fd = open("/proc/cpuinfo", O_RDONLY);
> > > > > +    if (fd == -1) {
> > > > > +        fprintf(stderr, "Failed to open /proc/cpuinfo!\n");
> > > > > +        return 0;
> > > > > +    }
> > > > > +
> > > > > +    if (read(fd, buf, 1024) < 0) {
> > > > > +        close(fd);
> > > > > +        fprintf(stderr, "Failed to read /proc/cpuinfo!\n");
> > > > > +        return 0;
> > > > > +    }
> > > > > +    close(fd);
> > > > > +
> > > > > +    buf_p = strstr(buf, "model name");
> > > > > +    while (*buf_p != '@') {
> > > > > +        buf_p++;
> > > > > +    }
> > > > > +
> > > > > +    buf_p += 2;
> > > > > +    memcpy(buf, buf_p, 12);
> > > > > +    buf_p = buf;
> > > > > +    while ((*buf_p >= '0') && (*buf_p <= '9')) {
> > > > > +        buf_p++;
> > > > > +    }
> > > > > +    *buf_p = '\0';
> > > > > +
> > > > > +    freq = atoi(buf);
> > > > > +
> > > > > +    return freq * 1000 * 1000;
> > > > > +}
> > > > > +
> > > > > +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 = 0x14C000;
> > > > > +    c->cpu_clock_freq = get_host_cpu_freq();
> > > > > +    if (!c->cpu_clock_freq) {
> > > > > +        c->cpu_clock_freq = 500000000;
> > > > > +    }
> > > > > +
> > > > > +    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;
> > > > > +    s->uarts[0].uart_base = 0x1fe001e0;
> > > > > +
> > > > > +    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_PCI_MEM_BASE;
> > > > > +    irq_info->pci_mem_end_addr   = VIRT_PCI_MEM_BASE + VIRT_PCI_MEM_SIZE - 1;
> > > > > +    irq_info->pci_io_start_addr  = VIRT_PCI_IO_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, "2016-05-16");
> > > > > +
> > > > > +    return special;
> > > > > +}
> > > > > +
> > > > > +static void init_loongson_params(struct loongson_params *lp)
> > > > > +{
> > > > > +    void *p = boot_params_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));
> > > > > +
> > > > > +    boot_params_p = p;
> > > > > +}
> > > > > +
> > > > > +static void init_smbios(struct smbios_tables *smbios)
> > > > > +{
> > > > > +    smbios->vers = 1;
> > > > > +    init_loongson_params(&(smbios->lp));
> > > > > +}
> > > > > +
> > > > > +static void init_efi(struct efi_loongson *efi)
> > > > > +{
> > > > > +    init_smbios(&(efi->smbios));
> > > > > +}
> > > > > +
> > > > > +static void init_reset_system(struct efi_reset_system_t *reset)
> > > > > +{
> > > > > +    reset->Shutdown = 0xffffffffbfc000a8;
> > > > > +    reset->ResetCold = 0xffffffffbfc00080;
> > > > > +    reset->ResetWarm = 0xffffffffbfc00080;
> > > > > +}
> > > > > +
> > > > > +static int init_boot_param(struct boot_params *bp)
> > > > > +{
> > > > > +    init_efi(&(bp->efi));
> > > > > +    init_reset_system(&(bp->reset_system));
> > > > > +
> > > > > +    return 0;
> > > > > +}
> > > > > +
> > > > > +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;
> > > > > +
> > > > > +    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);
> > > > > +    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
> > > > > +
> > > > > +    fw_config.ram_size = ram_size;
> > > > > +    fw_config.mem_freq = 300000000;
> > > > > +    fw_config.nr_cpus = current_machine->smp.cpus;
> > > > > +    fw_config.cpu_clock_freq = get_host_cpu_freq();
> > > > > +}
> > > > > +
> > > > > +static int set_prom_bootparam(ram_addr_t initrd_offset, long initrd_size)
> > > > > +{
> > > > > +    long params_size;
> > > > > +    char memenv[32];
> > > > > +    char highmemenv[32];
> > > > > +    void *params_buf;
> > > > > +    unsigned int *parg_env;
> > > > > +    int ret = 0;
> > > > > +
> > > > > +    /* Allocate params_buf for command line. */
> > > > > +    params_size = 0x100000;
> > > > > +    params_buf = g_malloc0(params_size);
> > > > > +
> > > > > +    /*
> > > > > +     * Layout of params_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 *)params_buf;
> > > > > +
> > > > > +    ret = (3 + 1) * 4;
> > > > > +    *parg_env++ = (BOOTPARAM_ADDR + ret);
> > > > > +    ret += (1 + snprintf(params_buf + ret, 256 - ret, "g"));
> > > > > +
> > > > > +    /* argv1 */
> > > > > +    *parg_env++ = BOOTPARAM_ADDR + ret;
> > > > > +    if (initrd_size > 0)
> > > > > +        ret += (1 + snprintf(params_buf + ret, 256 - ret,
> > > > > +                "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s",
> > > > > +                PHYS_TO_VIRT((uint32_t)initrd_offset),
> > > > > +                initrd_size, loaderparams.kernel_cmdline));
> > > > > +    else
> > > > > +        ret += (1 + snprintf(params_buf + ret, 256 - ret, "%s",
> > > > > +                loaderparams.kernel_cmdline));
> > > > > +
> > > > > +    /* argv2 */
> > > > > +    *parg_env++ = BOOTPARAM_ADDR + 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);
> > > > > +
> > > > > +    setenv("memsize", memenv, 1);
> > > > > +    setenv("highmemsize", highmemenv, 1);
> > > > > +
> > > > > +    ret = ((ret + 32) & ~31);
> > > > > +
> > > > > +    boot_params_buf = (void *)(params_buf + ret);
> > > > > +    boot_params_p = boot_params_buf + align(sizeof(struct boot_params));
> > > > > +
> > > > > +    init_boot_param(boot_params_buf);
> > > > > +
> > > > > +    rom_add_blob_fixed("params", params_buf, params_size,
> > > > > +                       BOOTPARAM_PHYADDR);
> > > > > +    loaderparams.a0 = 2;
> > > > > +    loaderparams.a1 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR;
> > > > > +    loaderparams.a2 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR + ret;
> > > > > +
> > > > > +    return 0;
> > > > > +}
> > > > > +
> > > > > +static int64_t load_kernel(CPUMIPSState *env)
> > > > > +{
> > > > > +    long kernel_size;
> > > > > +    ram_addr_t initrd_offset;
> > > > > +    int64_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, INITRD_OFFSET);
> > > > > +
> > > > > +            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 parameters. */
> > > > > +    set_prom_bootparam(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 void loongson3_isa_init(qemu_irq intc)
> > > >
> > > > Rename it to loongson3-virt_isa_init.
> > > >
> > > > > +{
> > > > > +    qemu_irq *i8259;
> > > > > +    ISABus *isa_bus;
> > > > > +
> > > > > +    isa_bus = isa_bus_new(NULL, get_system_memory(), get_system_io(), &error_abort);
> > > > > +
> > > > > +    /* Interrupt controller */
> > > > > +    /* The 8259 -> IP3  */
> > > > > +    i8259 = i8259_init(isa_bus, intc);
> > > > > +    isa_bus_irqs(isa_bus, i8259);
> > > > > +    /* init other devices */
> > > > > +    isa_create_simple(isa_bus, "i8042");
> > > > > +    mc146818_rtc_init(isa_bus, 2000, NULL);
> > > > > +}
> > > > > +
> > > > > +static inline void loongson3_pcie_init(MachineState *machine, DeviceState *pic)
> > > >
> > > > Rename it to loongson3-virt_pcie_init.
> > > >
> > > > > +{
> > > > > +    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_create(NULL, TYPE_GPEX_HOST);
> > > > > +
> > > > > +    qdev_init_nofail(dev);
> > > > > +    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_PCI_ECAM_SIZE);
> > > > > +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_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_PCI_MEM_BASE, VIRT_PCI_MEM_SIZE);
> > > > > +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_MEM_BASE, mmio_alias);
> > > > > +
> > > > > +    pio_alias = g_new0(MemoryRegion, 1);
> > > > > +    memory_region_init_alias(pio_alias, OBJECT(dev), "pcie-pio",
> > > > > +                             get_system_io(), 0, VIRT_PCI_IO_SIZE);
> > > > > +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_IO_BASE, pio_alias);
> > > > > +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, VIRT_PCI_IO_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);
> > > > > +
> > > > > +    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_init(MachineState *machine)
> > > >
> > > > Rename it to loongson3-virt_init.
> > > >
> > > > > +{
> > > > > +    int i;
> > > > > +    long bios_size;
> > > > > +    MIPSCPU *cpu;
> > > > > +    CPUMIPSState *env;
> > > > > +    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);
> > > > > +
> > > > > +    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 < 256 * 0x100000) {
> > > > > +        error_report("Loongson-3 need at least 256MB memory");
> > > > > +        exit(1);
> > > > > +    }
> > > > > +
> > > > > +    for (i = 0; i < machine->smp.cpus; i++) {
> > > > > +        /* 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);
> > > > > +    }
> > > > > +    env = &MIPS_CPU(first_cpu)->env;
> > > > > +
> > > > > +    /* Allocate RAM/BIOS, 0x00000000~0x10000000 is alias of 0x80000000~0x90000000 */
> > > > > +    memory_region_init_rom(bios, NULL, "loongson3.bios",
> > > > > +                           BIOS_SIZE, &error_fatal);
> > > > > +    memory_region_init_alias(ram, NULL, "loongson3.lowram",
> > > > > +                           machine->ram, 0, 256 * 0x100000);
> > > > > +    memory_region_init_io(iomem, NULL, &loongson3_pm_ops,
> > > > > +                           NULL, "loongson3_pm", PM_MMIO_SIZE);
> > > > > +
> > > > > +    memory_region_add_subregion(address_space_mem, 0x00000000LL, ram);
> > > > > +    memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios);
> > > > > +    memory_region_add_subregion(address_space_mem, 0x80000000LL, machine->ram);
> > > > > +    memory_region_add_subregion(address_space_mem, PM_MMIO_ADDR, iomem);
> > > > > +
> > > > > +    /*
> > > > > +     * We do not support flash operation, just loading pmon.bin as raw BIOS.
> > > > > +     * Please use -L to set the BIOS path and -bios to set bios name.
> > > > > +     */
> > > > > +
> > > > > +    if (kernel_filename) {
> > > > > +        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);
> > > > > +        rom_add_blob_fixed("bios",
> > > > > +                         bios_boot_code, sizeof(bios_boot_code), 0x1fc00000LL);
> > > > > +    } 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, 0x1fc00000LL,
> > > > > +                                            BIOS_SIZE);
> > > > > +            g_free(filename);
> > > > > +        } else {
> > > > > +            bios_size = -1;
> > > > > +        }
> > > > > +
> > > > > +        if ((bios_size < 0 || bios_size > BIOS_SIZE) &&
> > > > > +            !kernel_filename && !qtest_enabled()) {
> > > > > +            error_report("Could not load MIPS bios '%s'", bios_name);
> > > > > +            exit(1);
> > > > > +        }
> > > > > +
> > > > > +        fw_conf_init(ram_size);
> > > > > +        rom_add_blob_fixed("fw_conf",
> > > > > +                         &fw_config, sizeof(fw_config), FW_CONF_ADDR);
> > > > > +    }
> > > > > +
> > > > > +    msi_nonbroken = true;
> > > > > +    loongson3_isa_init(env->irq[3]);
> > > > > +    loongson3_pcie_init(machine, isa_pic);
> > > >
> > > > Names for two last functions should be already different.
> > > >
> > > > > +
> > > > > +    if (serial_hd(0)) {
> > > > > +        serial_mm_init(address_space_mem, 0x1fe001e0, 0, env->irq[2],
> > > > > +                           115200, serial_hd(0), DEVICE_NATIVE_ENDIAN);
> > > > > +    }
> > > > > +}
> > > > > +
> > > > > +static void mips_loongson3_machine_init(MachineClass *mc)
> > > >
> > > > Rename it to loongson3-virt_machine_init.
> > > >
> > > > > +{
> > > > > +    mc->desc = "Generic Loongson-3 Platform";
> > > > > +    mc->init = mips_loongson3_init;
> > > > > +    mc->block_default_type = IF_IDE;
> > > > > +    mc->max_cpus = LOONGSON_MAX_VCPUS;
> > > > > +    mc->default_ram_id = "loongson3.highram";
> > > > > +    mc->default_ram_size = 1200 * MiB;
> > > > > +    mc->kvm_type = mips_kvm_type;
> > > > > +    mc->minimum_page_bits = 14;
> > > > > +}
> > > > > +
> > > > > +DEFINE_MACHINE("loongson3", mips_loongson3_machine_init)
> > > >
> > > > DEFINE_MACHINE("loongson3-virt", loongson3-virt_machine_init)
> > > >
> > > > > --
> > > > > 2.7.0
> > > > >


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

* Re: [PATCH for-5.1 V4 3/4] hw/mips: Add Loongson-3 machine support (with KVM)
  2020-06-15  5:36         ` Huacai Chen
  2020-06-15  5:58           ` Aleksandar Markovic
@ 2020-06-15  6:04           ` Aleksandar Markovic
  2020-06-15  6:29             ` Huacai Chen
  1 sibling, 1 reply; 41+ messages in thread
From: Aleksandar Markovic @ 2020-06-15  6:04 UTC (permalink / raw)
  To: Huacai Chen
  Cc: Huacai Chen, Aleksandar Rikalo, Philippe Mathieu-Daudé,
	Aurelien Jarno, QEMU Developers

пон, 15. јун 2020. у 07:36 Huacai Chen <chenhuacai@gmail.com> је написао/ла:
>
> Hi, Aleksandar,
>
> On Mon, Jun 15, 2020 at 12:50 PM Aleksandar Markovic
> <aleksandar.qemu.devel@gmail.com> wrote:
> >
> > пон, 15. јун 2020. у 02:55 Huacai Chen <chenhuacai@gmail.com> је написао/ла:
> > >
> > > Hi, Aleksandar,
> > >
> > > On Sun, Jun 14, 2020 at 3:51 PM Aleksandar Markovic
> > > <aleksandar.qemu.devel@gmail.com> wrote:
> > > >
> > > > Hi, Huacai, this is another round of comments, that should be addressed in v5.
> > > >
> > > > уто, 2. јун 2020. у 04:40 Huacai Chen <zltjiangshi@gmail.com> је написао/ла:
> > > > >
> > > > > Add Loongson-3 based machine support, it use i8259 as the interrupt
> > > > > controler and use GPEX as the pci controller. Currently it can only
> > > > > work with KVM, but we will add TCG support in future.
> > > > >
> > > >
> > > > Add this paragraph at this place in the commit message:
> > > >
> > > > "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, a regular deprecation
> > > > procedure shall occur for "loongson3-virt" machine."
> > > >
> > > OK, this will be added, and I will rename to "loongson3-virt-1.0",
> > > which can be updated in future.
> > > But I think rename the name string is enough, file names and function
> > > names can keep their old names.
> Why ARM can use version name?
> virt-2.10 QEMU 2.10 ARM Virtual Machine
> virt-2.11 QEMU 2.11 ARM Virtual Machine
> virt-2.12 QEMU 2.12 ARM Virtual Machine
> virt-2.6 QEMU 2.6 ARM Virtual Machine
> virt-2.7 QEMU 2.7 ARM Virtual Machine
> virt-2.8 QEMU 2.8 ARM Virtual Machine
> virt-2.9 QEMU 2.9 ARM Virtual Machine
> virt-3.0 QEMU 3.0 ARM Virtual Machine
> virt-3.1 QEMU 3.1 ARM Virtual Machine
> virt-4.0 QEMU 4.0 ARM Virtual Machine
> virt-4.1 QEMU 4.1 ARM Virtual Machine
> virt-4.2 QEMU 4.2 ARM Virtual Machine
> virt QEMU 5.0 ARM Virtual Machine (alias of virt-5.0)
>
> In future will will replace i8259 with an advanced PIC, that will be
> loongson3-virt-2.0.
>
> > >
> >
> > Loongson3 is instruction set name, not a machine name, and treating
> > such name as machine name is incorrect. Renaming as I outlined in my
> > comments must occur.
> In future, both real machine and virtual machine models will be
> implement in the same file, so I think loongson3.c is better than
> loongson3-virt.c
>

I don't see any significant advantage of departing of existing
one-main-source-file-per-machine principle.

Regards,
Aleksandar

> >
> > Yours,
> > Aleksandar
> >
> > > Huacai
> > > > > We already have a full functional Linux kernel (based on Linux-5.4.x LTS
> > > > > but not upstream yet) here:
> > > > >
> > > > > https://github.com/chenhuacai/linux
> > > > >
> > > > > 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 the a Loongson-3A4000 host with this kernel;
> > > > > 4, Build QEMU-5.0.0 with this patchset;
> > > > > 5, modprobe kvm;
> > > > > 6, Use QEMU with TCG (available in future):
> > > > >        qemu-system-mips64el -M loongson3,accel=tcg -cpu Loongson-3A1000 -kernel <path_to_kernel> -append ...
> > > >
> > > > Machine should be named loongson3-virt.
> > > >
> > > > >    Use QEMU with KVM (available at present):
> > > > >        qemu-system-mips64el -M loongson3,accel=kvm -cpu Loongson-3A4000 -kernel <path_to_kernel> -append ...
> > > > >
> > > >
> > > > Machine should be named loongson3-virt.
> > > >
> > > > >    The "-cpu" parameter can be omitted here and QEMU will use the correct type for TCG/KVM automatically.
> > > > >
> > > >
> > > > This is not a good approach, the cpu parameter should be required,
> > > > and, if it is not correct for particular circumstance, an error
> > > > message should be emitted to the user, and the emulation terminated.
> > > >
> > > > > 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                      |  10 +
> > > > >  hw/mips/Makefile.objs                |   1 +
> > > > >  hw/mips/loongson3.c                  | 901 +++++++++++++++++++++++++++++++++++
> > > >
> > > > The name of the file should be loongson3-virt.c
> > > >
> > > > >  4 files changed, 913 insertions(+)
> > > > >  create mode 100644 hw/mips/loongson3.c
> > > > >
> > > > > diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak
> > > > > index 9f8a3ef..2a2a3fb 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_LOONGSON3=y
> > > >
> > > > CONFIG_LOONGSON3-VIRT
> > > >
> > > > >  CONFIG_ATI_VGA=y
> > > > >  CONFIG_RTL8139_PCI=y
> > > > >  CONFIG_JAZZ=y
> > > > > diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig
> > > > > index 67d39c5..42931fd 100644
> > > > > --- a/hw/mips/Kconfig
> > > > > +++ b/hw/mips/Kconfig
> > > > > @@ -45,6 +45,16 @@ config FULOONG
> > > > >      bool
> > > > >      select PCI_BONITO
> > > > >
> > > > > +config LOONGSON3
> > > >
> > > > LOONGSON3-VIRT
> > > >
> > > > > +    bool
> > > > > +    select PCKBD
> > > > > +    select SERIAL
> > > > > +    select ISA_BUS
> > > > > +    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/Makefile.objs b/hw/mips/Makefile.objs
> > > > > index 3b3e6ea..31dedcb 100644
> > > > > --- a/hw/mips/Makefile.objs
> > > > > +++ b/hw/mips/Makefile.objs
> > > > > @@ -4,5 +4,6 @@ obj-$(CONFIG_MALTA) += gt64xxx_pci.o malta.o
> > > > >  obj-$(CONFIG_MIPSSIM) += mipssim.o
> > > > >  obj-$(CONFIG_JAZZ) += jazz.o
> > > > >  obj-$(CONFIG_FULOONG) += fuloong2e.o
> > > > > +obj-$(CONFIG_LOONGSON3) += loongson3.o
> > > >
> > > > CONFIG_LOONGSON3-VIRT
> > > >
> > > > >  obj-$(CONFIG_MIPS_CPS) += cps.o
> > > > >  obj-$(CONFIG_MIPS_BOSTON) += boston.o
> > > > > diff --git a/hw/mips/loongson3.c b/hw/mips/loongson3.c
> > > > > new file mode 100644
> > > > > index 0000000..e4b9538
> > > > > --- /dev/null
> > > > > +++ b/hw/mips/loongson3.c
> > > >
> > > > The file shoul be named loongson3-virt.c
> > > >
> > > > > @@ -0,0 +1,901 @@
> > > > > +/*
> > > > > + * Generic Loongson-3 Platform support
> > > >
> > > > "Support for loongson3-virt platform"
> > > >
> > > > > + *
> > > > > + * Copyright (c) 2016-2020 Huacai Chen (chenhc@lemote.com)
> > > > > + * This code is licensed under the GNU GPL v2.
> > > > > + *
> > > > > + * Contributions are licensed under the terms of the GNU GPL,
> > > > > + * version 2 or (at your option) any later version.
> > > >
> > > > License preamble should be harmonized, as we already agreed upon.
> > > >
> > > > > + */
> > > > > +
> > > > > +/*
> > > > > + * Generic 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 "hw/boards.h"
> > > > > +#include "hw/char/serial.h"
> > > > > +#include "hw/mips/mips.h"
> > > > > +#include "hw/mips/cpudevs.h"
> > > > > +#include "hw/intc/i8259.h"
> > > > > +#include "hw/loader.h"
> > > > > +#include "hw/ide.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 "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 INITRD_OFFSET         0x04000000
> > > > > +#define BOOTPARAM_ADDR        0x8ff00000
> > > > > +#define BOOTPARAM_PHYADDR     0x0ff00000
> > > > > +#define CFG_ADDR              0x0f100000
> > > > > +#define FW_CONF_ADDR          0x0fff0000
> > > > > +#define PM_MMIO_ADDR          0x10080000
> > > > > +#define PM_MMIO_SIZE          0x100
> > > > > +#define PM_CNTL_MODE          0x10
> > > > > +
> > > > > +#define PHYS_TO_VIRT(x) ((x) | ~(target_ulong)0x7fffffff)
> > > > > +
> > > > > +/* Loongson-3 has a 2MB flash rom */
> > > > > +#define BIOS_SIZE               (2 * MiB)
> > > > > +#define LOONGSON_MAX_VCPUS      16
> > > > > +
> > > > > +#define LOONGSON3_BIOSNAME "bios_loongson3.bin"
> > > > > +
> > > > > +#define PCIE_IRQ_BASE       3
> > > > > +
> > > > > +#define VIRT_PCI_IO_BASE    0x18000000ul
> > > > > +#define VIRT_PCI_IO_SIZE    0x000c0000ul
> > > > > +#define VIRT_PCI_MEM_BASE   0x40000000ul
> > > > > +#define VIRT_PCI_MEM_SIZE   0x40000000ul
> > > > > +#define VIRT_PCI_ECAM_BASE  0x1a000000ul
> > > > > +#define VIRT_PCI_ECAM_SIZE  0x02000000ul
> > > > > +
> > > > > +#define align(x) (((x) + 63) & ~63)
> > > > > +
> > > > > +/* 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;
> > > > > +};
> > > > > +
> > > > > +static struct _fw_config {
> > > > > +    unsigned long ram_size;
> > > > > +    unsigned int mem_freq;
> > > > > +    unsigned int nr_cpus;
> > > > > +    unsigned int cpu_clock_freq;
> > > > > +} fw_config;
> > > > > +
> > > > > +static struct _loaderparams {
> > > > > +    unsigned long ram_size;
> > > > > +    const char *kernel_cmdline;
> > > > > +    const char *kernel_filename;
> > > > > +    const char *initrd_filename;
> > > > > +    int64_t kernel_entry;
> > > > > +    unsigned long a0, a1, a2;
> > > > > +} loaderparams;
> > > > > +
> > > > > +static void *boot_params_p;
> > > > > +static void *boot_params_buf;
> > > > > +
> > > > > +static unsigned int bios_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                                                      */
> > > > > +};
> > > > > +
> > > > > +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 = (loaderparams.ram_size > 0x10000000
> > > > > +                            ? 256 : (loaderparams.ram_size >> 20)) - 16;
> > > > > +
> > > > > +    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 > 0x10000000
> > > > > +                            ? (loaderparams.ram_size >> 20) - 256 : 0);
> > > > > +
> > > > > +    return emap;
> > > > > +}
> > > > > +
> > > > > +static int get_host_cpu_freq(void)
> > > > > +{
> > > > > +    int fd = 0, freq = 0;
> > > > > +    char buf[1024], *buf_p;
> > > > > +
> > > > > +    fd = open("/proc/cpuinfo", O_RDONLY);
> > > > > +    if (fd == -1) {
> > > > > +        fprintf(stderr, "Failed to open /proc/cpuinfo!\n");
> > > > > +        return 0;
> > > > > +    }
> > > > > +
> > > > > +    if (read(fd, buf, 1024) < 0) {
> > > > > +        close(fd);
> > > > > +        fprintf(stderr, "Failed to read /proc/cpuinfo!\n");
> > > > > +        return 0;
> > > > > +    }
> > > > > +    close(fd);
> > > > > +
> > > > > +    buf_p = strstr(buf, "model name");
> > > > > +    while (*buf_p != '@') {
> > > > > +        buf_p++;
> > > > > +    }
> > > > > +
> > > > > +    buf_p += 2;
> > > > > +    memcpy(buf, buf_p, 12);
> > > > > +    buf_p = buf;
> > > > > +    while ((*buf_p >= '0') && (*buf_p <= '9')) {
> > > > > +        buf_p++;
> > > > > +    }
> > > > > +    *buf_p = '\0';
> > > > > +
> > > > > +    freq = atoi(buf);
> > > > > +
> > > > > +    return freq * 1000 * 1000;
> > > > > +}
> > > > > +
> > > > > +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 = 0x14C000;
> > > > > +    c->cpu_clock_freq = get_host_cpu_freq();
> > > > > +    if (!c->cpu_clock_freq) {
> > > > > +        c->cpu_clock_freq = 500000000;
> > > > > +    }
> > > > > +
> > > > > +    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;
> > > > > +    s->uarts[0].uart_base = 0x1fe001e0;
> > > > > +
> > > > > +    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_PCI_MEM_BASE;
> > > > > +    irq_info->pci_mem_end_addr   = VIRT_PCI_MEM_BASE + VIRT_PCI_MEM_SIZE - 1;
> > > > > +    irq_info->pci_io_start_addr  = VIRT_PCI_IO_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, "2016-05-16");
> > > > > +
> > > > > +    return special;
> > > > > +}
> > > > > +
> > > > > +static void init_loongson_params(struct loongson_params *lp)
> > > > > +{
> > > > > +    void *p = boot_params_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));
> > > > > +
> > > > > +    boot_params_p = p;
> > > > > +}
> > > > > +
> > > > > +static void init_smbios(struct smbios_tables *smbios)
> > > > > +{
> > > > > +    smbios->vers = 1;
> > > > > +    init_loongson_params(&(smbios->lp));
> > > > > +}
> > > > > +
> > > > > +static void init_efi(struct efi_loongson *efi)
> > > > > +{
> > > > > +    init_smbios(&(efi->smbios));
> > > > > +}
> > > > > +
> > > > > +static void init_reset_system(struct efi_reset_system_t *reset)
> > > > > +{
> > > > > +    reset->Shutdown = 0xffffffffbfc000a8;
> > > > > +    reset->ResetCold = 0xffffffffbfc00080;
> > > > > +    reset->ResetWarm = 0xffffffffbfc00080;
> > > > > +}
> > > > > +
> > > > > +static int init_boot_param(struct boot_params *bp)
> > > > > +{
> > > > > +    init_efi(&(bp->efi));
> > > > > +    init_reset_system(&(bp->reset_system));
> > > > > +
> > > > > +    return 0;
> > > > > +}
> > > > > +
> > > > > +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;
> > > > > +
> > > > > +    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);
> > > > > +    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
> > > > > +
> > > > > +    fw_config.ram_size = ram_size;
> > > > > +    fw_config.mem_freq = 300000000;
> > > > > +    fw_config.nr_cpus = current_machine->smp.cpus;
> > > > > +    fw_config.cpu_clock_freq = get_host_cpu_freq();
> > > > > +}
> > > > > +
> > > > > +static int set_prom_bootparam(ram_addr_t initrd_offset, long initrd_size)
> > > > > +{
> > > > > +    long params_size;
> > > > > +    char memenv[32];
> > > > > +    char highmemenv[32];
> > > > > +    void *params_buf;
> > > > > +    unsigned int *parg_env;
> > > > > +    int ret = 0;
> > > > > +
> > > > > +    /* Allocate params_buf for command line. */
> > > > > +    params_size = 0x100000;
> > > > > +    params_buf = g_malloc0(params_size);
> > > > > +
> > > > > +    /*
> > > > > +     * Layout of params_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 *)params_buf;
> > > > > +
> > > > > +    ret = (3 + 1) * 4;
> > > > > +    *parg_env++ = (BOOTPARAM_ADDR + ret);
> > > > > +    ret += (1 + snprintf(params_buf + ret, 256 - ret, "g"));
> > > > > +
> > > > > +    /* argv1 */
> > > > > +    *parg_env++ = BOOTPARAM_ADDR + ret;
> > > > > +    if (initrd_size > 0)
> > > > > +        ret += (1 + snprintf(params_buf + ret, 256 - ret,
> > > > > +                "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s",
> > > > > +                PHYS_TO_VIRT((uint32_t)initrd_offset),
> > > > > +                initrd_size, loaderparams.kernel_cmdline));
> > > > > +    else
> > > > > +        ret += (1 + snprintf(params_buf + ret, 256 - ret, "%s",
> > > > > +                loaderparams.kernel_cmdline));
> > > > > +
> > > > > +    /* argv2 */
> > > > > +    *parg_env++ = BOOTPARAM_ADDR + 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);
> > > > > +
> > > > > +    setenv("memsize", memenv, 1);
> > > > > +    setenv("highmemsize", highmemenv, 1);
> > > > > +
> > > > > +    ret = ((ret + 32) & ~31);
> > > > > +
> > > > > +    boot_params_buf = (void *)(params_buf + ret);
> > > > > +    boot_params_p = boot_params_buf + align(sizeof(struct boot_params));
> > > > > +
> > > > > +    init_boot_param(boot_params_buf);
> > > > > +
> > > > > +    rom_add_blob_fixed("params", params_buf, params_size,
> > > > > +                       BOOTPARAM_PHYADDR);
> > > > > +    loaderparams.a0 = 2;
> > > > > +    loaderparams.a1 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR;
> > > > > +    loaderparams.a2 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR + ret;
> > > > > +
> > > > > +    return 0;
> > > > > +}
> > > > > +
> > > > > +static int64_t load_kernel(CPUMIPSState *env)
> > > > > +{
> > > > > +    long kernel_size;
> > > > > +    ram_addr_t initrd_offset;
> > > > > +    int64_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, INITRD_OFFSET);
> > > > > +
> > > > > +            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 parameters. */
> > > > > +    set_prom_bootparam(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 void loongson3_isa_init(qemu_irq intc)
> > > >
> > > > Rename it to loongson3-virt_isa_init.
> > > >
> > > > > +{
> > > > > +    qemu_irq *i8259;
> > > > > +    ISABus *isa_bus;
> > > > > +
> > > > > +    isa_bus = isa_bus_new(NULL, get_system_memory(), get_system_io(), &error_abort);
> > > > > +
> > > > > +    /* Interrupt controller */
> > > > > +    /* The 8259 -> IP3  */
> > > > > +    i8259 = i8259_init(isa_bus, intc);
> > > > > +    isa_bus_irqs(isa_bus, i8259);
> > > > > +    /* init other devices */
> > > > > +    isa_create_simple(isa_bus, "i8042");
> > > > > +    mc146818_rtc_init(isa_bus, 2000, NULL);
> > > > > +}
> > > > > +
> > > > > +static inline void loongson3_pcie_init(MachineState *machine, DeviceState *pic)
> > > >
> > > > Rename it to loongson3-virt_pcie_init.
> > > >
> > > > > +{
> > > > > +    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_create(NULL, TYPE_GPEX_HOST);
> > > > > +
> > > > > +    qdev_init_nofail(dev);
> > > > > +    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_PCI_ECAM_SIZE);
> > > > > +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_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_PCI_MEM_BASE, VIRT_PCI_MEM_SIZE);
> > > > > +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_MEM_BASE, mmio_alias);
> > > > > +
> > > > > +    pio_alias = g_new0(MemoryRegion, 1);
> > > > > +    memory_region_init_alias(pio_alias, OBJECT(dev), "pcie-pio",
> > > > > +                             get_system_io(), 0, VIRT_PCI_IO_SIZE);
> > > > > +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_IO_BASE, pio_alias);
> > > > > +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, VIRT_PCI_IO_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);
> > > > > +
> > > > > +    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_init(MachineState *machine)
> > > >
> > > > Rename it to loongson3-virt_init.
> > > >
> > > > > +{
> > > > > +    int i;
> > > > > +    long bios_size;
> > > > > +    MIPSCPU *cpu;
> > > > > +    CPUMIPSState *env;
> > > > > +    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);
> > > > > +
> > > > > +    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 < 256 * 0x100000) {
> > > > > +        error_report("Loongson-3 need at least 256MB memory");
> > > > > +        exit(1);
> > > > > +    }
> > > > > +
> > > > > +    for (i = 0; i < machine->smp.cpus; i++) {
> > > > > +        /* 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);
> > > > > +    }
> > > > > +    env = &MIPS_CPU(first_cpu)->env;
> > > > > +
> > > > > +    /* Allocate RAM/BIOS, 0x00000000~0x10000000 is alias of 0x80000000~0x90000000 */
> > > > > +    memory_region_init_rom(bios, NULL, "loongson3.bios",
> > > > > +                           BIOS_SIZE, &error_fatal);
> > > > > +    memory_region_init_alias(ram, NULL, "loongson3.lowram",
> > > > > +                           machine->ram, 0, 256 * 0x100000);
> > > > > +    memory_region_init_io(iomem, NULL, &loongson3_pm_ops,
> > > > > +                           NULL, "loongson3_pm", PM_MMIO_SIZE);
> > > > > +
> > > > > +    memory_region_add_subregion(address_space_mem, 0x00000000LL, ram);
> > > > > +    memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios);
> > > > > +    memory_region_add_subregion(address_space_mem, 0x80000000LL, machine->ram);
> > > > > +    memory_region_add_subregion(address_space_mem, PM_MMIO_ADDR, iomem);
> > > > > +
> > > > > +    /*
> > > > > +     * We do not support flash operation, just loading pmon.bin as raw BIOS.
> > > > > +     * Please use -L to set the BIOS path and -bios to set bios name.
> > > > > +     */
> > > > > +
> > > > > +    if (kernel_filename) {
> > > > > +        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);
> > > > > +        rom_add_blob_fixed("bios",
> > > > > +                         bios_boot_code, sizeof(bios_boot_code), 0x1fc00000LL);
> > > > > +    } 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, 0x1fc00000LL,
> > > > > +                                            BIOS_SIZE);
> > > > > +            g_free(filename);
> > > > > +        } else {
> > > > > +            bios_size = -1;
> > > > > +        }
> > > > > +
> > > > > +        if ((bios_size < 0 || bios_size > BIOS_SIZE) &&
> > > > > +            !kernel_filename && !qtest_enabled()) {
> > > > > +            error_report("Could not load MIPS bios '%s'", bios_name);
> > > > > +            exit(1);
> > > > > +        }
> > > > > +
> > > > > +        fw_conf_init(ram_size);
> > > > > +        rom_add_blob_fixed("fw_conf",
> > > > > +                         &fw_config, sizeof(fw_config), FW_CONF_ADDR);
> > > > > +    }
> > > > > +
> > > > > +    msi_nonbroken = true;
> > > > > +    loongson3_isa_init(env->irq[3]);
> > > > > +    loongson3_pcie_init(machine, isa_pic);
> > > >
> > > > Names for two last functions should be already different.
> > > >
> > > > > +
> > > > > +    if (serial_hd(0)) {
> > > > > +        serial_mm_init(address_space_mem, 0x1fe001e0, 0, env->irq[2],
> > > > > +                           115200, serial_hd(0), DEVICE_NATIVE_ENDIAN);
> > > > > +    }
> > > > > +}
> > > > > +
> > > > > +static void mips_loongson3_machine_init(MachineClass *mc)
> > > >
> > > > Rename it to loongson3-virt_machine_init.
> > > >
> > > > > +{
> > > > > +    mc->desc = "Generic Loongson-3 Platform";
> > > > > +    mc->init = mips_loongson3_init;
> > > > > +    mc->block_default_type = IF_IDE;
> > > > > +    mc->max_cpus = LOONGSON_MAX_VCPUS;
> > > > > +    mc->default_ram_id = "loongson3.highram";
> > > > > +    mc->default_ram_size = 1200 * MiB;
> > > > > +    mc->kvm_type = mips_kvm_type;
> > > > > +    mc->minimum_page_bits = 14;
> > > > > +}
> > > > > +
> > > > > +DEFINE_MACHINE("loongson3", mips_loongson3_machine_init)
> > > >
> > > > DEFINE_MACHINE("loongson3-virt", loongson3-virt_machine_init)
> > > >
> > > > > --
> > > > > 2.7.0
> > > > >


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

* Re: [PATCH for-5.1 V4 3/4] hw/mips: Add Loongson-3 machine support (with KVM)
  2020-06-15  6:04           ` Aleksandar Markovic
@ 2020-06-15  6:29             ` Huacai Chen
  2020-06-15  6:44               ` Aleksandar Markovic
  0 siblings, 1 reply; 41+ messages in thread
From: Huacai Chen @ 2020-06-15  6:29 UTC (permalink / raw)
  To: Aleksandar Markovic
  Cc: Huacai Chen, Aleksandar Rikalo, Philippe Mathieu-Daudé,
	Aurelien Jarno, QEMU Developers

Hi, Aleksandar,

On Mon, Jun 15, 2020 at 2:04 PM Aleksandar Markovic
<aleksandar.qemu.devel@gmail.com> wrote:
>
> пон, 15. јун 2020. у 07:36 Huacai Chen <chenhuacai@gmail.com> је написао/ла:
> >
> > Hi, Aleksandar,
> >
> > On Mon, Jun 15, 2020 at 12:50 PM Aleksandar Markovic
> > <aleksandar.qemu.devel@gmail.com> wrote:
> > >
> > > пон, 15. јун 2020. у 02:55 Huacai Chen <chenhuacai@gmail.com> је написао/ла:
> > > >
> > > > Hi, Aleksandar,
> > > >
> > > > On Sun, Jun 14, 2020 at 3:51 PM Aleksandar Markovic
> > > > <aleksandar.qemu.devel@gmail.com> wrote:
> > > > >
> > > > > Hi, Huacai, this is another round of comments, that should be addressed in v5.
> > > > >
> > > > > уто, 2. јун 2020. у 04:40 Huacai Chen <zltjiangshi@gmail.com> је написао/ла:
> > > > > >
> > > > > > Add Loongson-3 based machine support, it use i8259 as the interrupt
> > > > > > controler and use GPEX as the pci controller. Currently it can only
> > > > > > work with KVM, but we will add TCG support in future.
> > > > > >
> > > > >
> > > > > Add this paragraph at this place in the commit message:
> > > > >
> > > > > "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, a regular deprecation
> > > > > procedure shall occur for "loongson3-virt" machine."
> > > > >
> > > > OK, this will be added, and I will rename to "loongson3-virt-1.0",
> > > > which can be updated in future.
> > > > But I think rename the name string is enough, file names and function
> > > > names can keep their old names.
> > Why ARM can use version name?
> > virt-2.10 QEMU 2.10 ARM Virtual Machine
> > virt-2.11 QEMU 2.11 ARM Virtual Machine
> > virt-2.12 QEMU 2.12 ARM Virtual Machine
> > virt-2.6 QEMU 2.6 ARM Virtual Machine
> > virt-2.7 QEMU 2.7 ARM Virtual Machine
> > virt-2.8 QEMU 2.8 ARM Virtual Machine
> > virt-2.9 QEMU 2.9 ARM Virtual Machine
> > virt-3.0 QEMU 3.0 ARM Virtual Machine
> > virt-3.1 QEMU 3.1 ARM Virtual Machine
> > virt-4.0 QEMU 4.0 ARM Virtual Machine
> > virt-4.1 QEMU 4.1 ARM Virtual Machine
> > virt-4.2 QEMU 4.2 ARM Virtual Machine
> > virt QEMU 5.0 ARM Virtual Machine (alias of virt-5.0)
> >
> > In future will will replace i8259 with an advanced PIC, that will be
> > loongson3-virt-2.0.
> >
i8259 is not the best choice, but it is simple. Replacing i8259 with
an advanced PIC is our future plan (loongson3-virt-2.0 will not
replace loongson3-virt-1.0, but co-exist with it), but it need lots of
effort. If we can't use a version number for a machine type, what is
the best method?

> > > >
> > >
> > > Loongson3 is instruction set name, not a machine name, and treating
> > > such name as machine name is incorrect. Renaming as I outlined in my
> > > comments must occur.
> > In future, both real machine and virtual machine models will be
> > implement in the same file, so I think loongson3.c is better than
> > loongson3-virt.c
> >
>
> I don't see any significant advantage of departing of existing
> one-main-source-file-per-machine principle.
In my opinion, if two machine models share more than 90% of the code,
they can be implemented in the same file. In hw/i386/pc.c there are
many machine models (GlobalProperty). Maybe it is another bad example?

I'm not insisting on my bad practice, but I need some "correct style"
to achieve my goal.

Huacai
>
> Regards,
> Aleksandar
>
> > >
> > > Yours,
> > > Aleksandar
> > >
> > > > Huacai
> > > > > > We already have a full functional Linux kernel (based on Linux-5.4.x LTS
> > > > > > but not upstream yet) here:
> > > > > >
> > > > > > https://github.com/chenhuacai/linux
> > > > > >
> > > > > > 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 the a Loongson-3A4000 host with this kernel;
> > > > > > 4, Build QEMU-5.0.0 with this patchset;
> > > > > > 5, modprobe kvm;
> > > > > > 6, Use QEMU with TCG (available in future):
> > > > > >        qemu-system-mips64el -M loongson3,accel=tcg -cpu Loongson-3A1000 -kernel <path_to_kernel> -append ...
> > > > >
> > > > > Machine should be named loongson3-virt.
> > > > >
> > > > > >    Use QEMU with KVM (available at present):
> > > > > >        qemu-system-mips64el -M loongson3,accel=kvm -cpu Loongson-3A4000 -kernel <path_to_kernel> -append ...
> > > > > >
> > > > >
> > > > > Machine should be named loongson3-virt.
> > > > >
> > > > > >    The "-cpu" parameter can be omitted here and QEMU will use the correct type for TCG/KVM automatically.
> > > > > >
> > > > >
> > > > > This is not a good approach, the cpu parameter should be required,
> > > > > and, if it is not correct for particular circumstance, an error
> > > > > message should be emitted to the user, and the emulation terminated.
> > > > >
> > > > > > 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                      |  10 +
> > > > > >  hw/mips/Makefile.objs                |   1 +
> > > > > >  hw/mips/loongson3.c                  | 901 +++++++++++++++++++++++++++++++++++
> > > > >
> > > > > The name of the file should be loongson3-virt.c
> > > > >
> > > > > >  4 files changed, 913 insertions(+)
> > > > > >  create mode 100644 hw/mips/loongson3.c
> > > > > >
> > > > > > diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak
> > > > > > index 9f8a3ef..2a2a3fb 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_LOONGSON3=y
> > > > >
> > > > > CONFIG_LOONGSON3-VIRT
> > > > >
> > > > > >  CONFIG_ATI_VGA=y
> > > > > >  CONFIG_RTL8139_PCI=y
> > > > > >  CONFIG_JAZZ=y
> > > > > > diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig
> > > > > > index 67d39c5..42931fd 100644
> > > > > > --- a/hw/mips/Kconfig
> > > > > > +++ b/hw/mips/Kconfig
> > > > > > @@ -45,6 +45,16 @@ config FULOONG
> > > > > >      bool
> > > > > >      select PCI_BONITO
> > > > > >
> > > > > > +config LOONGSON3
> > > > >
> > > > > LOONGSON3-VIRT
> > > > >
> > > > > > +    bool
> > > > > > +    select PCKBD
> > > > > > +    select SERIAL
> > > > > > +    select ISA_BUS
> > > > > > +    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/Makefile.objs b/hw/mips/Makefile.objs
> > > > > > index 3b3e6ea..31dedcb 100644
> > > > > > --- a/hw/mips/Makefile.objs
> > > > > > +++ b/hw/mips/Makefile.objs
> > > > > > @@ -4,5 +4,6 @@ obj-$(CONFIG_MALTA) += gt64xxx_pci.o malta.o
> > > > > >  obj-$(CONFIG_MIPSSIM) += mipssim.o
> > > > > >  obj-$(CONFIG_JAZZ) += jazz.o
> > > > > >  obj-$(CONFIG_FULOONG) += fuloong2e.o
> > > > > > +obj-$(CONFIG_LOONGSON3) += loongson3.o
> > > > >
> > > > > CONFIG_LOONGSON3-VIRT
> > > > >
> > > > > >  obj-$(CONFIG_MIPS_CPS) += cps.o
> > > > > >  obj-$(CONFIG_MIPS_BOSTON) += boston.o
> > > > > > diff --git a/hw/mips/loongson3.c b/hw/mips/loongson3.c
> > > > > > new file mode 100644
> > > > > > index 0000000..e4b9538
> > > > > > --- /dev/null
> > > > > > +++ b/hw/mips/loongson3.c
> > > > >
> > > > > The file shoul be named loongson3-virt.c
> > > > >
> > > > > > @@ -0,0 +1,901 @@
> > > > > > +/*
> > > > > > + * Generic Loongson-3 Platform support
> > > > >
> > > > > "Support for loongson3-virt platform"
> > > > >
> > > > > > + *
> > > > > > + * Copyright (c) 2016-2020 Huacai Chen (chenhc@lemote.com)
> > > > > > + * This code is licensed under the GNU GPL v2.
> > > > > > + *
> > > > > > + * Contributions are licensed under the terms of the GNU GPL,
> > > > > > + * version 2 or (at your option) any later version.
> > > > >
> > > > > License preamble should be harmonized, as we already agreed upon.
> > > > >
> > > > > > + */
> > > > > > +
> > > > > > +/*
> > > > > > + * Generic 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 "hw/boards.h"
> > > > > > +#include "hw/char/serial.h"
> > > > > > +#include "hw/mips/mips.h"
> > > > > > +#include "hw/mips/cpudevs.h"
> > > > > > +#include "hw/intc/i8259.h"
> > > > > > +#include "hw/loader.h"
> > > > > > +#include "hw/ide.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 "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 INITRD_OFFSET         0x04000000
> > > > > > +#define BOOTPARAM_ADDR        0x8ff00000
> > > > > > +#define BOOTPARAM_PHYADDR     0x0ff00000
> > > > > > +#define CFG_ADDR              0x0f100000
> > > > > > +#define FW_CONF_ADDR          0x0fff0000
> > > > > > +#define PM_MMIO_ADDR          0x10080000
> > > > > > +#define PM_MMIO_SIZE          0x100
> > > > > > +#define PM_CNTL_MODE          0x10
> > > > > > +
> > > > > > +#define PHYS_TO_VIRT(x) ((x) | ~(target_ulong)0x7fffffff)
> > > > > > +
> > > > > > +/* Loongson-3 has a 2MB flash rom */
> > > > > > +#define BIOS_SIZE               (2 * MiB)
> > > > > > +#define LOONGSON_MAX_VCPUS      16
> > > > > > +
> > > > > > +#define LOONGSON3_BIOSNAME "bios_loongson3.bin"
> > > > > > +
> > > > > > +#define PCIE_IRQ_BASE       3
> > > > > > +
> > > > > > +#define VIRT_PCI_IO_BASE    0x18000000ul
> > > > > > +#define VIRT_PCI_IO_SIZE    0x000c0000ul
> > > > > > +#define VIRT_PCI_MEM_BASE   0x40000000ul
> > > > > > +#define VIRT_PCI_MEM_SIZE   0x40000000ul
> > > > > > +#define VIRT_PCI_ECAM_BASE  0x1a000000ul
> > > > > > +#define VIRT_PCI_ECAM_SIZE  0x02000000ul
> > > > > > +
> > > > > > +#define align(x) (((x) + 63) & ~63)
> > > > > > +
> > > > > > +/* 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;
> > > > > > +};
> > > > > > +
> > > > > > +static struct _fw_config {
> > > > > > +    unsigned long ram_size;
> > > > > > +    unsigned int mem_freq;
> > > > > > +    unsigned int nr_cpus;
> > > > > > +    unsigned int cpu_clock_freq;
> > > > > > +} fw_config;
> > > > > > +
> > > > > > +static struct _loaderparams {
> > > > > > +    unsigned long ram_size;
> > > > > > +    const char *kernel_cmdline;
> > > > > > +    const char *kernel_filename;
> > > > > > +    const char *initrd_filename;
> > > > > > +    int64_t kernel_entry;
> > > > > > +    unsigned long a0, a1, a2;
> > > > > > +} loaderparams;
> > > > > > +
> > > > > > +static void *boot_params_p;
> > > > > > +static void *boot_params_buf;
> > > > > > +
> > > > > > +static unsigned int bios_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                                                      */
> > > > > > +};
> > > > > > +
> > > > > > +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 = (loaderparams.ram_size > 0x10000000
> > > > > > +                            ? 256 : (loaderparams.ram_size >> 20)) - 16;
> > > > > > +
> > > > > > +    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 > 0x10000000
> > > > > > +                            ? (loaderparams.ram_size >> 20) - 256 : 0);
> > > > > > +
> > > > > > +    return emap;
> > > > > > +}
> > > > > > +
> > > > > > +static int get_host_cpu_freq(void)
> > > > > > +{
> > > > > > +    int fd = 0, freq = 0;
> > > > > > +    char buf[1024], *buf_p;
> > > > > > +
> > > > > > +    fd = open("/proc/cpuinfo", O_RDONLY);
> > > > > > +    if (fd == -1) {
> > > > > > +        fprintf(stderr, "Failed to open /proc/cpuinfo!\n");
> > > > > > +        return 0;
> > > > > > +    }
> > > > > > +
> > > > > > +    if (read(fd, buf, 1024) < 0) {
> > > > > > +        close(fd);
> > > > > > +        fprintf(stderr, "Failed to read /proc/cpuinfo!\n");
> > > > > > +        return 0;
> > > > > > +    }
> > > > > > +    close(fd);
> > > > > > +
> > > > > > +    buf_p = strstr(buf, "model name");
> > > > > > +    while (*buf_p != '@') {
> > > > > > +        buf_p++;
> > > > > > +    }
> > > > > > +
> > > > > > +    buf_p += 2;
> > > > > > +    memcpy(buf, buf_p, 12);
> > > > > > +    buf_p = buf;
> > > > > > +    while ((*buf_p >= '0') && (*buf_p <= '9')) {
> > > > > > +        buf_p++;
> > > > > > +    }
> > > > > > +    *buf_p = '\0';
> > > > > > +
> > > > > > +    freq = atoi(buf);
> > > > > > +
> > > > > > +    return freq * 1000 * 1000;
> > > > > > +}
> > > > > > +
> > > > > > +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 = 0x14C000;
> > > > > > +    c->cpu_clock_freq = get_host_cpu_freq();
> > > > > > +    if (!c->cpu_clock_freq) {
> > > > > > +        c->cpu_clock_freq = 500000000;
> > > > > > +    }
> > > > > > +
> > > > > > +    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;
> > > > > > +    s->uarts[0].uart_base = 0x1fe001e0;
> > > > > > +
> > > > > > +    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_PCI_MEM_BASE;
> > > > > > +    irq_info->pci_mem_end_addr   = VIRT_PCI_MEM_BASE + VIRT_PCI_MEM_SIZE - 1;
> > > > > > +    irq_info->pci_io_start_addr  = VIRT_PCI_IO_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, "2016-05-16");
> > > > > > +
> > > > > > +    return special;
> > > > > > +}
> > > > > > +
> > > > > > +static void init_loongson_params(struct loongson_params *lp)
> > > > > > +{
> > > > > > +    void *p = boot_params_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));
> > > > > > +
> > > > > > +    boot_params_p = p;
> > > > > > +}
> > > > > > +
> > > > > > +static void init_smbios(struct smbios_tables *smbios)
> > > > > > +{
> > > > > > +    smbios->vers = 1;
> > > > > > +    init_loongson_params(&(smbios->lp));
> > > > > > +}
> > > > > > +
> > > > > > +static void init_efi(struct efi_loongson *efi)
> > > > > > +{
> > > > > > +    init_smbios(&(efi->smbios));
> > > > > > +}
> > > > > > +
> > > > > > +static void init_reset_system(struct efi_reset_system_t *reset)
> > > > > > +{
> > > > > > +    reset->Shutdown = 0xffffffffbfc000a8;
> > > > > > +    reset->ResetCold = 0xffffffffbfc00080;
> > > > > > +    reset->ResetWarm = 0xffffffffbfc00080;
> > > > > > +}
> > > > > > +
> > > > > > +static int init_boot_param(struct boot_params *bp)
> > > > > > +{
> > > > > > +    init_efi(&(bp->efi));
> > > > > > +    init_reset_system(&(bp->reset_system));
> > > > > > +
> > > > > > +    return 0;
> > > > > > +}
> > > > > > +
> > > > > > +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;
> > > > > > +
> > > > > > +    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);
> > > > > > +    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
> > > > > > +
> > > > > > +    fw_config.ram_size = ram_size;
> > > > > > +    fw_config.mem_freq = 300000000;
> > > > > > +    fw_config.nr_cpus = current_machine->smp.cpus;
> > > > > > +    fw_config.cpu_clock_freq = get_host_cpu_freq();
> > > > > > +}
> > > > > > +
> > > > > > +static int set_prom_bootparam(ram_addr_t initrd_offset, long initrd_size)
> > > > > > +{
> > > > > > +    long params_size;
> > > > > > +    char memenv[32];
> > > > > > +    char highmemenv[32];
> > > > > > +    void *params_buf;
> > > > > > +    unsigned int *parg_env;
> > > > > > +    int ret = 0;
> > > > > > +
> > > > > > +    /* Allocate params_buf for command line. */
> > > > > > +    params_size = 0x100000;
> > > > > > +    params_buf = g_malloc0(params_size);
> > > > > > +
> > > > > > +    /*
> > > > > > +     * Layout of params_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 *)params_buf;
> > > > > > +
> > > > > > +    ret = (3 + 1) * 4;
> > > > > > +    *parg_env++ = (BOOTPARAM_ADDR + ret);
> > > > > > +    ret += (1 + snprintf(params_buf + ret, 256 - ret, "g"));
> > > > > > +
> > > > > > +    /* argv1 */
> > > > > > +    *parg_env++ = BOOTPARAM_ADDR + ret;
> > > > > > +    if (initrd_size > 0)
> > > > > > +        ret += (1 + snprintf(params_buf + ret, 256 - ret,
> > > > > > +                "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s",
> > > > > > +                PHYS_TO_VIRT((uint32_t)initrd_offset),
> > > > > > +                initrd_size, loaderparams.kernel_cmdline));
> > > > > > +    else
> > > > > > +        ret += (1 + snprintf(params_buf + ret, 256 - ret, "%s",
> > > > > > +                loaderparams.kernel_cmdline));
> > > > > > +
> > > > > > +    /* argv2 */
> > > > > > +    *parg_env++ = BOOTPARAM_ADDR + 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);
> > > > > > +
> > > > > > +    setenv("memsize", memenv, 1);
> > > > > > +    setenv("highmemsize", highmemenv, 1);
> > > > > > +
> > > > > > +    ret = ((ret + 32) & ~31);
> > > > > > +
> > > > > > +    boot_params_buf = (void *)(params_buf + ret);
> > > > > > +    boot_params_p = boot_params_buf + align(sizeof(struct boot_params));
> > > > > > +
> > > > > > +    init_boot_param(boot_params_buf);
> > > > > > +
> > > > > > +    rom_add_blob_fixed("params", params_buf, params_size,
> > > > > > +                       BOOTPARAM_PHYADDR);
> > > > > > +    loaderparams.a0 = 2;
> > > > > > +    loaderparams.a1 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR;
> > > > > > +    loaderparams.a2 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR + ret;
> > > > > > +
> > > > > > +    return 0;
> > > > > > +}
> > > > > > +
> > > > > > +static int64_t load_kernel(CPUMIPSState *env)
> > > > > > +{
> > > > > > +    long kernel_size;
> > > > > > +    ram_addr_t initrd_offset;
> > > > > > +    int64_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, INITRD_OFFSET);
> > > > > > +
> > > > > > +            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 parameters. */
> > > > > > +    set_prom_bootparam(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 void loongson3_isa_init(qemu_irq intc)
> > > > >
> > > > > Rename it to loongson3-virt_isa_init.
> > > > >
> > > > > > +{
> > > > > > +    qemu_irq *i8259;
> > > > > > +    ISABus *isa_bus;
> > > > > > +
> > > > > > +    isa_bus = isa_bus_new(NULL, get_system_memory(), get_system_io(), &error_abort);
> > > > > > +
> > > > > > +    /* Interrupt controller */
> > > > > > +    /* The 8259 -> IP3  */
> > > > > > +    i8259 = i8259_init(isa_bus, intc);
> > > > > > +    isa_bus_irqs(isa_bus, i8259);
> > > > > > +    /* init other devices */
> > > > > > +    isa_create_simple(isa_bus, "i8042");
> > > > > > +    mc146818_rtc_init(isa_bus, 2000, NULL);
> > > > > > +}
> > > > > > +
> > > > > > +static inline void loongson3_pcie_init(MachineState *machine, DeviceState *pic)
> > > > >
> > > > > Rename it to loongson3-virt_pcie_init.
> > > > >
> > > > > > +{
> > > > > > +    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_create(NULL, TYPE_GPEX_HOST);
> > > > > > +
> > > > > > +    qdev_init_nofail(dev);
> > > > > > +    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_PCI_ECAM_SIZE);
> > > > > > +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_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_PCI_MEM_BASE, VIRT_PCI_MEM_SIZE);
> > > > > > +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_MEM_BASE, mmio_alias);
> > > > > > +
> > > > > > +    pio_alias = g_new0(MemoryRegion, 1);
> > > > > > +    memory_region_init_alias(pio_alias, OBJECT(dev), "pcie-pio",
> > > > > > +                             get_system_io(), 0, VIRT_PCI_IO_SIZE);
> > > > > > +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_IO_BASE, pio_alias);
> > > > > > +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, VIRT_PCI_IO_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);
> > > > > > +
> > > > > > +    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_init(MachineState *machine)
> > > > >
> > > > > Rename it to loongson3-virt_init.
> > > > >
> > > > > > +{
> > > > > > +    int i;
> > > > > > +    long bios_size;
> > > > > > +    MIPSCPU *cpu;
> > > > > > +    CPUMIPSState *env;
> > > > > > +    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);
> > > > > > +
> > > > > > +    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 < 256 * 0x100000) {
> > > > > > +        error_report("Loongson-3 need at least 256MB memory");
> > > > > > +        exit(1);
> > > > > > +    }
> > > > > > +
> > > > > > +    for (i = 0; i < machine->smp.cpus; i++) {
> > > > > > +        /* 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);
> > > > > > +    }
> > > > > > +    env = &MIPS_CPU(first_cpu)->env;
> > > > > > +
> > > > > > +    /* Allocate RAM/BIOS, 0x00000000~0x10000000 is alias of 0x80000000~0x90000000 */
> > > > > > +    memory_region_init_rom(bios, NULL, "loongson3.bios",
> > > > > > +                           BIOS_SIZE, &error_fatal);
> > > > > > +    memory_region_init_alias(ram, NULL, "loongson3.lowram",
> > > > > > +                           machine->ram, 0, 256 * 0x100000);
> > > > > > +    memory_region_init_io(iomem, NULL, &loongson3_pm_ops,
> > > > > > +                           NULL, "loongson3_pm", PM_MMIO_SIZE);
> > > > > > +
> > > > > > +    memory_region_add_subregion(address_space_mem, 0x00000000LL, ram);
> > > > > > +    memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios);
> > > > > > +    memory_region_add_subregion(address_space_mem, 0x80000000LL, machine->ram);
> > > > > > +    memory_region_add_subregion(address_space_mem, PM_MMIO_ADDR, iomem);
> > > > > > +
> > > > > > +    /*
> > > > > > +     * We do not support flash operation, just loading pmon.bin as raw BIOS.
> > > > > > +     * Please use -L to set the BIOS path and -bios to set bios name.
> > > > > > +     */
> > > > > > +
> > > > > > +    if (kernel_filename) {
> > > > > > +        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);
> > > > > > +        rom_add_blob_fixed("bios",
> > > > > > +                         bios_boot_code, sizeof(bios_boot_code), 0x1fc00000LL);
> > > > > > +    } 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, 0x1fc00000LL,
> > > > > > +                                            BIOS_SIZE);
> > > > > > +            g_free(filename);
> > > > > > +        } else {
> > > > > > +            bios_size = -1;
> > > > > > +        }
> > > > > > +
> > > > > > +        if ((bios_size < 0 || bios_size > BIOS_SIZE) &&
> > > > > > +            !kernel_filename && !qtest_enabled()) {
> > > > > > +            error_report("Could not load MIPS bios '%s'", bios_name);
> > > > > > +            exit(1);
> > > > > > +        }
> > > > > > +
> > > > > > +        fw_conf_init(ram_size);
> > > > > > +        rom_add_blob_fixed("fw_conf",
> > > > > > +                         &fw_config, sizeof(fw_config), FW_CONF_ADDR);
> > > > > > +    }
> > > > > > +
> > > > > > +    msi_nonbroken = true;
> > > > > > +    loongson3_isa_init(env->irq[3]);
> > > > > > +    loongson3_pcie_init(machine, isa_pic);
> > > > >
> > > > > Names for two last functions should be already different.
> > > > >
> > > > > > +
> > > > > > +    if (serial_hd(0)) {
> > > > > > +        serial_mm_init(address_space_mem, 0x1fe001e0, 0, env->irq[2],
> > > > > > +                           115200, serial_hd(0), DEVICE_NATIVE_ENDIAN);
> > > > > > +    }
> > > > > > +}
> > > > > > +
> > > > > > +static void mips_loongson3_machine_init(MachineClass *mc)
> > > > >
> > > > > Rename it to loongson3-virt_machine_init.
> > > > >
> > > > > > +{
> > > > > > +    mc->desc = "Generic Loongson-3 Platform";
> > > > > > +    mc->init = mips_loongson3_init;
> > > > > > +    mc->block_default_type = IF_IDE;
> > > > > > +    mc->max_cpus = LOONGSON_MAX_VCPUS;
> > > > > > +    mc->default_ram_id = "loongson3.highram";
> > > > > > +    mc->default_ram_size = 1200 * MiB;
> > > > > > +    mc->kvm_type = mips_kvm_type;
> > > > > > +    mc->minimum_page_bits = 14;
> > > > > > +}
> > > > > > +
> > > > > > +DEFINE_MACHINE("loongson3", mips_loongson3_machine_init)
> > > > >
> > > > > DEFINE_MACHINE("loongson3-virt", loongson3-virt_machine_init)
> > > > >
> > > > > > --
> > > > > > 2.7.0
> > > > > >


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

* Re: [PATCH for-5.1 V4 3/4] hw/mips: Add Loongson-3 machine support (with KVM)
  2020-06-15  6:29             ` Huacai Chen
@ 2020-06-15  6:44               ` Aleksandar Markovic
  0 siblings, 0 replies; 41+ messages in thread
From: Aleksandar Markovic @ 2020-06-15  6:44 UTC (permalink / raw)
  To: Huacai Chen
  Cc: Huacai Chen, Aleksandar Rikalo, Philippe Mathieu-Daudé,
	Aurelien Jarno, QEMU Developers

пон, 15. јун 2020. у 08:29 Huacai Chen <chenhuacai@gmail.com> је написао/ла:
>
> Hi, Aleksandar,
>
> On Mon, Jun 15, 2020 at 2:04 PM Aleksandar Markovic
> <aleksandar.qemu.devel@gmail.com> wrote:
> >
> > пон, 15. јун 2020. у 07:36 Huacai Chen <chenhuacai@gmail.com> је написао/ла:
> > >
> > > Hi, Aleksandar,
> > >
> > > On Mon, Jun 15, 2020 at 12:50 PM Aleksandar Markovic
> > > <aleksandar.qemu.devel@gmail.com> wrote:
> > > >
> > > > пон, 15. јун 2020. у 02:55 Huacai Chen <chenhuacai@gmail.com> је написао/ла:
> > > > >
> > > > > Hi, Aleksandar,
> > > > >
> > > > > On Sun, Jun 14, 2020 at 3:51 PM Aleksandar Markovic
> > > > > <aleksandar.qemu.devel@gmail.com> wrote:
> > > > > >
> > > > > > Hi, Huacai, this is another round of comments, that should be addressed in v5.
> > > > > >
> > > > > > уто, 2. јун 2020. у 04:40 Huacai Chen <zltjiangshi@gmail.com> је написао/ла:
> > > > > > >
> > > > > > > Add Loongson-3 based machine support, it use i8259 as the interrupt
> > > > > > > controler and use GPEX as the pci controller. Currently it can only
> > > > > > > work with KVM, but we will add TCG support in future.
> > > > > > >
> > > > > >
> > > > > > Add this paragraph at this place in the commit message:
> > > > > >
> > > > > > "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, a regular deprecation
> > > > > > procedure shall occur for "loongson3-virt" machine."
> > > > > >
> > > > > OK, this will be added, and I will rename to "loongson3-virt-1.0",
> > > > > which can be updated in future.
> > > > > But I think rename the name string is enough, file names and function
> > > > > names can keep their old names.
> > > Why ARM can use version name?
> > > virt-2.10 QEMU 2.10 ARM Virtual Machine
> > > virt-2.11 QEMU 2.11 ARM Virtual Machine
> > > virt-2.12 QEMU 2.12 ARM Virtual Machine
> > > virt-2.6 QEMU 2.6 ARM Virtual Machine
> > > virt-2.7 QEMU 2.7 ARM Virtual Machine
> > > virt-2.8 QEMU 2.8 ARM Virtual Machine
> > > virt-2.9 QEMU 2.9 ARM Virtual Machine
> > > virt-3.0 QEMU 3.0 ARM Virtual Machine
> > > virt-3.1 QEMU 3.1 ARM Virtual Machine
> > > virt-4.0 QEMU 4.0 ARM Virtual Machine
> > > virt-4.1 QEMU 4.1 ARM Virtual Machine
> > > virt-4.2 QEMU 4.2 ARM Virtual Machine
> > > virt QEMU 5.0 ARM Virtual Machine (alias of virt-5.0)
> > >
> > > In future will will replace i8259 with an advanced PIC, that will be
> > > loongson3-virt-2.0.
> > >
> i8259 is not the best choice, but it is simple. Replacing i8259 with
> an advanced PIC is our future plan (loongson3-virt-2.0 will not
> replace loongson3-virt-1.0, but co-exist with it), but it need lots of
> effort. If we can't use a version number for a machine type, what is
> the best method?
>

Huacai,

The best method is that you focus on your current proposal, without
planing multiple Longson3 virtual machines, that I already discouraged
you from implementing altogether. And, for future, focus on
implementing emulation of a real Loongson3 machine, and at that moment
we should be able to deprecate Loongson3 virtual machine, altogether
with loongson3-virt.c file.

Yours,
Aleksandar

> > > > >
> > > >
> > > > Loongson3 is instruction set name, not a machine name, and treating
> > > > such name as machine name is incorrect. Renaming as I outlined in my
> > > > comments must occur.
> > > In future, both real machine and virtual machine models will be
> > > implement in the same file, so I think loongson3.c is better than
> > > loongson3-virt.c
> > >
> >
> > I don't see any significant advantage of departing of existing
> > one-main-source-file-per-machine principle.
> In my opinion, if two machine models share more than 90% of the code,
> they can be implemented in the same file. In hw/i386/pc.c there are
> many machine models (GlobalProperty). Maybe it is another bad example?
>
> I'm not insisting on my bad practice, but I need some "correct style"
> to achieve my goal.
>
> Huacai
> >
> > Regards,
> > Aleksandar
> >
> > > >
> > > > Yours,
> > > > Aleksandar
> > > >
> > > > > Huacai
> > > > > > > We already have a full functional Linux kernel (based on Linux-5.4.x LTS
> > > > > > > but not upstream yet) here:
> > > > > > >
> > > > > > > https://github.com/chenhuacai/linux
> > > > > > >
> > > > > > > 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 the a Loongson-3A4000 host with this kernel;
> > > > > > > 4, Build QEMU-5.0.0 with this patchset;
> > > > > > > 5, modprobe kvm;
> > > > > > > 6, Use QEMU with TCG (available in future):
> > > > > > >        qemu-system-mips64el -M loongson3,accel=tcg -cpu Loongson-3A1000 -kernel <path_to_kernel> -append ...
> > > > > >
> > > > > > Machine should be named loongson3-virt.
> > > > > >
> > > > > > >    Use QEMU with KVM (available at present):
> > > > > > >        qemu-system-mips64el -M loongson3,accel=kvm -cpu Loongson-3A4000 -kernel <path_to_kernel> -append ...
> > > > > > >
> > > > > >
> > > > > > Machine should be named loongson3-virt.
> > > > > >
> > > > > > >    The "-cpu" parameter can be omitted here and QEMU will use the correct type for TCG/KVM automatically.
> > > > > > >
> > > > > >
> > > > > > This is not a good approach, the cpu parameter should be required,
> > > > > > and, if it is not correct for particular circumstance, an error
> > > > > > message should be emitted to the user, and the emulation terminated.
> > > > > >
> > > > > > > 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                      |  10 +
> > > > > > >  hw/mips/Makefile.objs                |   1 +
> > > > > > >  hw/mips/loongson3.c                  | 901 +++++++++++++++++++++++++++++++++++
> > > > > >
> > > > > > The name of the file should be loongson3-virt.c
> > > > > >
> > > > > > >  4 files changed, 913 insertions(+)
> > > > > > >  create mode 100644 hw/mips/loongson3.c
> > > > > > >
> > > > > > > diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak
> > > > > > > index 9f8a3ef..2a2a3fb 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_LOONGSON3=y
> > > > > >
> > > > > > CONFIG_LOONGSON3-VIRT
> > > > > >
> > > > > > >  CONFIG_ATI_VGA=y
> > > > > > >  CONFIG_RTL8139_PCI=y
> > > > > > >  CONFIG_JAZZ=y
> > > > > > > diff --git a/hw/mips/Kconfig b/hw/mips/Kconfig
> > > > > > > index 67d39c5..42931fd 100644
> > > > > > > --- a/hw/mips/Kconfig
> > > > > > > +++ b/hw/mips/Kconfig
> > > > > > > @@ -45,6 +45,16 @@ config FULOONG
> > > > > > >      bool
> > > > > > >      select PCI_BONITO
> > > > > > >
> > > > > > > +config LOONGSON3
> > > > > >
> > > > > > LOONGSON3-VIRT
> > > > > >
> > > > > > > +    bool
> > > > > > > +    select PCKBD
> > > > > > > +    select SERIAL
> > > > > > > +    select ISA_BUS
> > > > > > > +    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/Makefile.objs b/hw/mips/Makefile.objs
> > > > > > > index 3b3e6ea..31dedcb 100644
> > > > > > > --- a/hw/mips/Makefile.objs
> > > > > > > +++ b/hw/mips/Makefile.objs
> > > > > > > @@ -4,5 +4,6 @@ obj-$(CONFIG_MALTA) += gt64xxx_pci.o malta.o
> > > > > > >  obj-$(CONFIG_MIPSSIM) += mipssim.o
> > > > > > >  obj-$(CONFIG_JAZZ) += jazz.o
> > > > > > >  obj-$(CONFIG_FULOONG) += fuloong2e.o
> > > > > > > +obj-$(CONFIG_LOONGSON3) += loongson3.o
> > > > > >
> > > > > > CONFIG_LOONGSON3-VIRT
> > > > > >
> > > > > > >  obj-$(CONFIG_MIPS_CPS) += cps.o
> > > > > > >  obj-$(CONFIG_MIPS_BOSTON) += boston.o
> > > > > > > diff --git a/hw/mips/loongson3.c b/hw/mips/loongson3.c
> > > > > > > new file mode 100644
> > > > > > > index 0000000..e4b9538
> > > > > > > --- /dev/null
> > > > > > > +++ b/hw/mips/loongson3.c
> > > > > >
> > > > > > The file shoul be named loongson3-virt.c
> > > > > >
> > > > > > > @@ -0,0 +1,901 @@
> > > > > > > +/*
> > > > > > > + * Generic Loongson-3 Platform support
> > > > > >
> > > > > > "Support for loongson3-virt platform"
> > > > > >
> > > > > > > + *
> > > > > > > + * Copyright (c) 2016-2020 Huacai Chen (chenhc@lemote.com)
> > > > > > > + * This code is licensed under the GNU GPL v2.
> > > > > > > + *
> > > > > > > + * Contributions are licensed under the terms of the GNU GPL,
> > > > > > > + * version 2 or (at your option) any later version.
> > > > > >
> > > > > > License preamble should be harmonized, as we already agreed upon.
> > > > > >
> > > > > > > + */
> > > > > > > +
> > > > > > > +/*
> > > > > > > + * Generic 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 "hw/boards.h"
> > > > > > > +#include "hw/char/serial.h"
> > > > > > > +#include "hw/mips/mips.h"
> > > > > > > +#include "hw/mips/cpudevs.h"
> > > > > > > +#include "hw/intc/i8259.h"
> > > > > > > +#include "hw/loader.h"
> > > > > > > +#include "hw/ide.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 "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 INITRD_OFFSET         0x04000000
> > > > > > > +#define BOOTPARAM_ADDR        0x8ff00000
> > > > > > > +#define BOOTPARAM_PHYADDR     0x0ff00000
> > > > > > > +#define CFG_ADDR              0x0f100000
> > > > > > > +#define FW_CONF_ADDR          0x0fff0000
> > > > > > > +#define PM_MMIO_ADDR          0x10080000
> > > > > > > +#define PM_MMIO_SIZE          0x100
> > > > > > > +#define PM_CNTL_MODE          0x10
> > > > > > > +
> > > > > > > +#define PHYS_TO_VIRT(x) ((x) | ~(target_ulong)0x7fffffff)
> > > > > > > +
> > > > > > > +/* Loongson-3 has a 2MB flash rom */
> > > > > > > +#define BIOS_SIZE               (2 * MiB)
> > > > > > > +#define LOONGSON_MAX_VCPUS      16
> > > > > > > +
> > > > > > > +#define LOONGSON3_BIOSNAME "bios_loongson3.bin"
> > > > > > > +
> > > > > > > +#define PCIE_IRQ_BASE       3
> > > > > > > +
> > > > > > > +#define VIRT_PCI_IO_BASE    0x18000000ul
> > > > > > > +#define VIRT_PCI_IO_SIZE    0x000c0000ul
> > > > > > > +#define VIRT_PCI_MEM_BASE   0x40000000ul
> > > > > > > +#define VIRT_PCI_MEM_SIZE   0x40000000ul
> > > > > > > +#define VIRT_PCI_ECAM_BASE  0x1a000000ul
> > > > > > > +#define VIRT_PCI_ECAM_SIZE  0x02000000ul
> > > > > > > +
> > > > > > > +#define align(x) (((x) + 63) & ~63)
> > > > > > > +
> > > > > > > +/* 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;
> > > > > > > +};
> > > > > > > +
> > > > > > > +static struct _fw_config {
> > > > > > > +    unsigned long ram_size;
> > > > > > > +    unsigned int mem_freq;
> > > > > > > +    unsigned int nr_cpus;
> > > > > > > +    unsigned int cpu_clock_freq;
> > > > > > > +} fw_config;
> > > > > > > +
> > > > > > > +static struct _loaderparams {
> > > > > > > +    unsigned long ram_size;
> > > > > > > +    const char *kernel_cmdline;
> > > > > > > +    const char *kernel_filename;
> > > > > > > +    const char *initrd_filename;
> > > > > > > +    int64_t kernel_entry;
> > > > > > > +    unsigned long a0, a1, a2;
> > > > > > > +} loaderparams;
> > > > > > > +
> > > > > > > +static void *boot_params_p;
> > > > > > > +static void *boot_params_buf;
> > > > > > > +
> > > > > > > +static unsigned int bios_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                                                      */
> > > > > > > +};
> > > > > > > +
> > > > > > > +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 = (loaderparams.ram_size > 0x10000000
> > > > > > > +                            ? 256 : (loaderparams.ram_size >> 20)) - 16;
> > > > > > > +
> > > > > > > +    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 > 0x10000000
> > > > > > > +                            ? (loaderparams.ram_size >> 20) - 256 : 0);
> > > > > > > +
> > > > > > > +    return emap;
> > > > > > > +}
> > > > > > > +
> > > > > > > +static int get_host_cpu_freq(void)
> > > > > > > +{
> > > > > > > +    int fd = 0, freq = 0;
> > > > > > > +    char buf[1024], *buf_p;
> > > > > > > +
> > > > > > > +    fd = open("/proc/cpuinfo", O_RDONLY);
> > > > > > > +    if (fd == -1) {
> > > > > > > +        fprintf(stderr, "Failed to open /proc/cpuinfo!\n");
> > > > > > > +        return 0;
> > > > > > > +    }
> > > > > > > +
> > > > > > > +    if (read(fd, buf, 1024) < 0) {
> > > > > > > +        close(fd);
> > > > > > > +        fprintf(stderr, "Failed to read /proc/cpuinfo!\n");
> > > > > > > +        return 0;
> > > > > > > +    }
> > > > > > > +    close(fd);
> > > > > > > +
> > > > > > > +    buf_p = strstr(buf, "model name");
> > > > > > > +    while (*buf_p != '@') {
> > > > > > > +        buf_p++;
> > > > > > > +    }
> > > > > > > +
> > > > > > > +    buf_p += 2;
> > > > > > > +    memcpy(buf, buf_p, 12);
> > > > > > > +    buf_p = buf;
> > > > > > > +    while ((*buf_p >= '0') && (*buf_p <= '9')) {
> > > > > > > +        buf_p++;
> > > > > > > +    }
> > > > > > > +    *buf_p = '\0';
> > > > > > > +
> > > > > > > +    freq = atoi(buf);
> > > > > > > +
> > > > > > > +    return freq * 1000 * 1000;
> > > > > > > +}
> > > > > > > +
> > > > > > > +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 = 0x14C000;
> > > > > > > +    c->cpu_clock_freq = get_host_cpu_freq();
> > > > > > > +    if (!c->cpu_clock_freq) {
> > > > > > > +        c->cpu_clock_freq = 500000000;
> > > > > > > +    }
> > > > > > > +
> > > > > > > +    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;
> > > > > > > +    s->uarts[0].uart_base = 0x1fe001e0;
> > > > > > > +
> > > > > > > +    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_PCI_MEM_BASE;
> > > > > > > +    irq_info->pci_mem_end_addr   = VIRT_PCI_MEM_BASE + VIRT_PCI_MEM_SIZE - 1;
> > > > > > > +    irq_info->pci_io_start_addr  = VIRT_PCI_IO_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, "2016-05-16");
> > > > > > > +
> > > > > > > +    return special;
> > > > > > > +}
> > > > > > > +
> > > > > > > +static void init_loongson_params(struct loongson_params *lp)
> > > > > > > +{
> > > > > > > +    void *p = boot_params_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));
> > > > > > > +
> > > > > > > +    boot_params_p = p;
> > > > > > > +}
> > > > > > > +
> > > > > > > +static void init_smbios(struct smbios_tables *smbios)
> > > > > > > +{
> > > > > > > +    smbios->vers = 1;
> > > > > > > +    init_loongson_params(&(smbios->lp));
> > > > > > > +}
> > > > > > > +
> > > > > > > +static void init_efi(struct efi_loongson *efi)
> > > > > > > +{
> > > > > > > +    init_smbios(&(efi->smbios));
> > > > > > > +}
> > > > > > > +
> > > > > > > +static void init_reset_system(struct efi_reset_system_t *reset)
> > > > > > > +{
> > > > > > > +    reset->Shutdown = 0xffffffffbfc000a8;
> > > > > > > +    reset->ResetCold = 0xffffffffbfc00080;
> > > > > > > +    reset->ResetWarm = 0xffffffffbfc00080;
> > > > > > > +}
> > > > > > > +
> > > > > > > +static int init_boot_param(struct boot_params *bp)
> > > > > > > +{
> > > > > > > +    init_efi(&(bp->efi));
> > > > > > > +    init_reset_system(&(bp->reset_system));
> > > > > > > +
> > > > > > > +    return 0;
> > > > > > > +}
> > > > > > > +
> > > > > > > +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;
> > > > > > > +
> > > > > > > +    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);
> > > > > > > +    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
> > > > > > > +
> > > > > > > +    fw_config.ram_size = ram_size;
> > > > > > > +    fw_config.mem_freq = 300000000;
> > > > > > > +    fw_config.nr_cpus = current_machine->smp.cpus;
> > > > > > > +    fw_config.cpu_clock_freq = get_host_cpu_freq();
> > > > > > > +}
> > > > > > > +
> > > > > > > +static int set_prom_bootparam(ram_addr_t initrd_offset, long initrd_size)
> > > > > > > +{
> > > > > > > +    long params_size;
> > > > > > > +    char memenv[32];
> > > > > > > +    char highmemenv[32];
> > > > > > > +    void *params_buf;
> > > > > > > +    unsigned int *parg_env;
> > > > > > > +    int ret = 0;
> > > > > > > +
> > > > > > > +    /* Allocate params_buf for command line. */
> > > > > > > +    params_size = 0x100000;
> > > > > > > +    params_buf = g_malloc0(params_size);
> > > > > > > +
> > > > > > > +    /*
> > > > > > > +     * Layout of params_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 *)params_buf;
> > > > > > > +
> > > > > > > +    ret = (3 + 1) * 4;
> > > > > > > +    *parg_env++ = (BOOTPARAM_ADDR + ret);
> > > > > > > +    ret += (1 + snprintf(params_buf + ret, 256 - ret, "g"));
> > > > > > > +
> > > > > > > +    /* argv1 */
> > > > > > > +    *parg_env++ = BOOTPARAM_ADDR + ret;
> > > > > > > +    if (initrd_size > 0)
> > > > > > > +        ret += (1 + snprintf(params_buf + ret, 256 - ret,
> > > > > > > +                "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s",
> > > > > > > +                PHYS_TO_VIRT((uint32_t)initrd_offset),
> > > > > > > +                initrd_size, loaderparams.kernel_cmdline));
> > > > > > > +    else
> > > > > > > +        ret += (1 + snprintf(params_buf + ret, 256 - ret, "%s",
> > > > > > > +                loaderparams.kernel_cmdline));
> > > > > > > +
> > > > > > > +    /* argv2 */
> > > > > > > +    *parg_env++ = BOOTPARAM_ADDR + 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);
> > > > > > > +
> > > > > > > +    setenv("memsize", memenv, 1);
> > > > > > > +    setenv("highmemsize", highmemenv, 1);
> > > > > > > +
> > > > > > > +    ret = ((ret + 32) & ~31);
> > > > > > > +
> > > > > > > +    boot_params_buf = (void *)(params_buf + ret);
> > > > > > > +    boot_params_p = boot_params_buf + align(sizeof(struct boot_params));
> > > > > > > +
> > > > > > > +    init_boot_param(boot_params_buf);
> > > > > > > +
> > > > > > > +    rom_add_blob_fixed("params", params_buf, params_size,
> > > > > > > +                       BOOTPARAM_PHYADDR);
> > > > > > > +    loaderparams.a0 = 2;
> > > > > > > +    loaderparams.a1 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR;
> > > > > > > +    loaderparams.a2 = 0xffffffff80000000ULL + BOOTPARAM_PHYADDR + ret;
> > > > > > > +
> > > > > > > +    return 0;
> > > > > > > +}
> > > > > > > +
> > > > > > > +static int64_t load_kernel(CPUMIPSState *env)
> > > > > > > +{
> > > > > > > +    long kernel_size;
> > > > > > > +    ram_addr_t initrd_offset;
> > > > > > > +    int64_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, INITRD_OFFSET);
> > > > > > > +
> > > > > > > +            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 parameters. */
> > > > > > > +    set_prom_bootparam(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 void loongson3_isa_init(qemu_irq intc)
> > > > > >
> > > > > > Rename it to loongson3-virt_isa_init.
> > > > > >
> > > > > > > +{
> > > > > > > +    qemu_irq *i8259;
> > > > > > > +    ISABus *isa_bus;
> > > > > > > +
> > > > > > > +    isa_bus = isa_bus_new(NULL, get_system_memory(), get_system_io(), &error_abort);
> > > > > > > +
> > > > > > > +    /* Interrupt controller */
> > > > > > > +    /* The 8259 -> IP3  */
> > > > > > > +    i8259 = i8259_init(isa_bus, intc);
> > > > > > > +    isa_bus_irqs(isa_bus, i8259);
> > > > > > > +    /* init other devices */
> > > > > > > +    isa_create_simple(isa_bus, "i8042");
> > > > > > > +    mc146818_rtc_init(isa_bus, 2000, NULL);
> > > > > > > +}
> > > > > > > +
> > > > > > > +static inline void loongson3_pcie_init(MachineState *machine, DeviceState *pic)
> > > > > >
> > > > > > Rename it to loongson3-virt_pcie_init.
> > > > > >
> > > > > > > +{
> > > > > > > +    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_create(NULL, TYPE_GPEX_HOST);
> > > > > > > +
> > > > > > > +    qdev_init_nofail(dev);
> > > > > > > +    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_PCI_ECAM_SIZE);
> > > > > > > +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_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_PCI_MEM_BASE, VIRT_PCI_MEM_SIZE);
> > > > > > > +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_MEM_BASE, mmio_alias);
> > > > > > > +
> > > > > > > +    pio_alias = g_new0(MemoryRegion, 1);
> > > > > > > +    memory_region_init_alias(pio_alias, OBJECT(dev), "pcie-pio",
> > > > > > > +                             get_system_io(), 0, VIRT_PCI_IO_SIZE);
> > > > > > > +    memory_region_add_subregion(get_system_memory(), VIRT_PCI_IO_BASE, pio_alias);
> > > > > > > +    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, VIRT_PCI_IO_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);
> > > > > > > +
> > > > > > > +    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_init(MachineState *machine)
> > > > > >
> > > > > > Rename it to loongson3-virt_init.
> > > > > >
> > > > > > > +{
> > > > > > > +    int i;
> > > > > > > +    long bios_size;
> > > > > > > +    MIPSCPU *cpu;
> > > > > > > +    CPUMIPSState *env;
> > > > > > > +    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);
> > > > > > > +
> > > > > > > +    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 < 256 * 0x100000) {
> > > > > > > +        error_report("Loongson-3 need at least 256MB memory");
> > > > > > > +        exit(1);
> > > > > > > +    }
> > > > > > > +
> > > > > > > +    for (i = 0; i < machine->smp.cpus; i++) {
> > > > > > > +        /* 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);
> > > > > > > +    }
> > > > > > > +    env = &MIPS_CPU(first_cpu)->env;
> > > > > > > +
> > > > > > > +    /* Allocate RAM/BIOS, 0x00000000~0x10000000 is alias of 0x80000000~0x90000000 */
> > > > > > > +    memory_region_init_rom(bios, NULL, "loongson3.bios",
> > > > > > > +                           BIOS_SIZE, &error_fatal);
> > > > > > > +    memory_region_init_alias(ram, NULL, "loongson3.lowram",
> > > > > > > +                           machine->ram, 0, 256 * 0x100000);
> > > > > > > +    memory_region_init_io(iomem, NULL, &loongson3_pm_ops,
> > > > > > > +                           NULL, "loongson3_pm", PM_MMIO_SIZE);
> > > > > > > +
> > > > > > > +    memory_region_add_subregion(address_space_mem, 0x00000000LL, ram);
> > > > > > > +    memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios);
> > > > > > > +    memory_region_add_subregion(address_space_mem, 0x80000000LL, machine->ram);
> > > > > > > +    memory_region_add_subregion(address_space_mem, PM_MMIO_ADDR, iomem);
> > > > > > > +
> > > > > > > +    /*
> > > > > > > +     * We do not support flash operation, just loading pmon.bin as raw BIOS.
> > > > > > > +     * Please use -L to set the BIOS path and -bios to set bios name.
> > > > > > > +     */
> > > > > > > +
> > > > > > > +    if (kernel_filename) {
> > > > > > > +        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);
> > > > > > > +        rom_add_blob_fixed("bios",
> > > > > > > +                         bios_boot_code, sizeof(bios_boot_code), 0x1fc00000LL);
> > > > > > > +    } 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, 0x1fc00000LL,
> > > > > > > +                                            BIOS_SIZE);
> > > > > > > +            g_free(filename);
> > > > > > > +        } else {
> > > > > > > +            bios_size = -1;
> > > > > > > +        }
> > > > > > > +
> > > > > > > +        if ((bios_size < 0 || bios_size > BIOS_SIZE) &&
> > > > > > > +            !kernel_filename && !qtest_enabled()) {
> > > > > > > +            error_report("Could not load MIPS bios '%s'", bios_name);
> > > > > > > +            exit(1);
> > > > > > > +        }
> > > > > > > +
> > > > > > > +        fw_conf_init(ram_size);
> > > > > > > +        rom_add_blob_fixed("fw_conf",
> > > > > > > +                         &fw_config, sizeof(fw_config), FW_CONF_ADDR);
> > > > > > > +    }
> > > > > > > +
> > > > > > > +    msi_nonbroken = true;
> > > > > > > +    loongson3_isa_init(env->irq[3]);
> > > > > > > +    loongson3_pcie_init(machine, isa_pic);
> > > > > >
> > > > > > Names for two last functions should be already different.
> > > > > >
> > > > > > > +
> > > > > > > +    if (serial_hd(0)) {
> > > > > > > +        serial_mm_init(address_space_mem, 0x1fe001e0, 0, env->irq[2],
> > > > > > > +                           115200, serial_hd(0), DEVICE_NATIVE_ENDIAN);
> > > > > > > +    }
> > > > > > > +}
> > > > > > > +
> > > > > > > +static void mips_loongson3_machine_init(MachineClass *mc)
> > > > > >
> > > > > > Rename it to loongson3-virt_machine_init.
> > > > > >
> > > > > > > +{
> > > > > > > +    mc->desc = "Generic Loongson-3 Platform";
> > > > > > > +    mc->init = mips_loongson3_init;
> > > > > > > +    mc->block_default_type = IF_IDE;
> > > > > > > +    mc->max_cpus = LOONGSON_MAX_VCPUS;
> > > > > > > +    mc->default_ram_id = "loongson3.highram";
> > > > > > > +    mc->default_ram_size = 1200 * MiB;
> > > > > > > +    mc->kvm_type = mips_kvm_type;
> > > > > > > +    mc->minimum_page_bits = 14;
> > > > > > > +}
> > > > > > > +
> > > > > > > +DEFINE_MACHINE("loongson3", mips_loongson3_machine_init)
> > > > > >
> > > > > > DEFINE_MACHINE("loongson3-virt", loongson3-virt_machine_init)
> > > > > >
> > > > > > > --
> > > > > > > 2.7.0
> > > > > > >


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

* Re: [PATCH for-5.1 V4 1/4] hw/mips: Implement the kvm_type() hook in MachineClass
  2020-06-15  0:52     ` Huacai Chen
@ 2020-06-15  8:55       ` Thomas Huth
  2020-06-15 19:44         ` Aleksandar Markovic
  0 siblings, 1 reply; 41+ messages in thread
From: Thomas Huth @ 2020-06-15  8:55 UTC (permalink / raw)
  To: Huacai Chen, Aleksandar Markovic
  Cc: Huacai Chen, Aleksandar Rikalo, Philippe Mathieu-Daudé,
	Aurelien Jarno, QEMU Developers

On 15/06/2020 02.52, Huacai Chen wrote:
> Hi, Aleksandar,
> 
> On Sun, Jun 14, 2020 at 4:07 PM Aleksandar Markovic
> <aleksandar.qemu.devel@gmail.com> wrote:
>>
>>
>>
>> уто, 2. јун 2020. у 04:38 Huacai Chen <zltjiangshi@gmail.com> је написао/ла:
>>>
>>> MIPS has two types of KVM: TE & VZ, and TE is the default type. Now we
>>> can't create a VZ guest in QEMU because it lacks the kvm_type() hook in
>>> MachineClass. Besides, libvirt uses a null-machine to detect the kvm
>>> capability, so by default it will return "KVM not supported" on a VZ
>>> platform. Thus, null-machine also need the kvm_type() hook.
>>>
>>> Reviewed-by: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
>>> Signed-off-by: Huacai Chen <chenhc@lemote.com>
>>> Co-developed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
>>> ---
>>
>> Huacai,
>>
>> Please take a look at Peter's remarks at:
>>
>> https://lists.gnu.org/archive/html/qemu-devel/2020-06/msg01878.html
>>
>> ...and refactor this patch for v5. My general advice: The simpler, the batter.
>>
> OK, I will rework this patch.

 Hi,

is there maybe also a way to do this without moving null-machine.o from
common-obj-y to obj-y, and to avoid the target-specific hacks in this
file ? We just moved the null-machine from obj-y to common-obj-y two
years ago (see commit 3858ff763985fb9e), since it's more desirable to
have as much code in common-obj to save compilation time and maybe to be
able to link a qemu with more than one target CPU in one binary one day...

ppc64 has also more than one kvm_type (kvm-hv and kvm-pr), and
apparently it also works without hacks to the null-machine code there
... so maybe you can peek into the ppc64 code to see how it is solved there?

 Thomas


>>>  hw/core/Makefile.objs  |  2 +-
>>>  hw/core/null-machine.c |  4 ++++
>>>  hw/mips/Makefile.objs  |  2 +-
>>>  hw/mips/common.c       | 42 ++++++++++++++++++++++++++++++++++++++++++
>>>  include/hw/mips/mips.h |  3 +++
>>>  5 files changed, 51 insertions(+), 2 deletions(-)
>>>  create mode 100644 hw/mips/common.c
>>>
>>> diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs
>>> index 1d540ed..b5672f4 100644
>>> --- a/hw/core/Makefile.objs
>>> +++ b/hw/core/Makefile.objs
>>> @@ -17,11 +17,11 @@ common-obj-$(CONFIG_SOFTMMU) += vm-change-state-handler.o
>>>  common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o
>>>  common-obj-$(CONFIG_SOFTMMU) += sysbus.o
>>>  common-obj-$(CONFIG_SOFTMMU) += machine.o
>>> -common-obj-$(CONFIG_SOFTMMU) += null-machine.o
>>>  common-obj-$(CONFIG_SOFTMMU) += loader.o
>>>  common-obj-$(CONFIG_SOFTMMU) += machine-hmp-cmds.o
>>>  common-obj-$(CONFIG_SOFTMMU) += numa.o
>>>  common-obj-$(CONFIG_SOFTMMU) += clock-vmstate.o
>>> +obj-$(CONFIG_SOFTMMU) += null-machine.o
>>>  obj-$(CONFIG_SOFTMMU) += machine-qmp-cmds.o
>>>
>>>  common-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o
>>> diff --git a/hw/core/null-machine.c b/hw/core/null-machine.c
>>> index cb47d9d..94a36f9 100644
>>> --- a/hw/core/null-machine.c
>>> +++ b/hw/core/null-machine.c
>>> @@ -17,6 +17,7 @@
>>>  #include "sysemu/sysemu.h"
>>>  #include "exec/address-spaces.h"
>>>  #include "hw/core/cpu.h"
>>> +#include "hw/mips/mips.h"
>>>
>>>  static void machine_none_init(MachineState *mch)
>>>  {
>>> @@ -50,6 +51,9 @@ static void machine_none_machine_init(MachineClass *mc)
>>>      mc->max_cpus = 1;
>>>      mc->default_ram_size = 0;
>>>      mc->default_ram_id = "ram";
>>> +#ifdef TARGET_MIPS
>>> +    mc->kvm_type = mips_kvm_type;
>>> +#endif
>>>  }
>>>
>>>  DEFINE_MACHINE("none", machine_none_machine_init)
>>> diff --git a/hw/mips/Makefile.objs b/hw/mips/Makefile.objs
>>> index 739e2b7..3b3e6ea 100644
>>> --- a/hw/mips/Makefile.objs
>>> +++ b/hw/mips/Makefile.objs
>>> @@ -1,4 +1,4 @@
>>> -obj-y += addr.o mips_int.o
>>> +obj-y += addr.o common.o mips_int.o
>>>  obj-$(CONFIG_R4K) += r4k.o
>>>  obj-$(CONFIG_MALTA) += gt64xxx_pci.o malta.o
>>>  obj-$(CONFIG_MIPSSIM) += mipssim.o
>>> diff --git a/hw/mips/common.c b/hw/mips/common.c
>>> new file mode 100644
>>> index 0000000..4d8e141
>>> --- /dev/null
>>> +++ b/hw/mips/common.c
>>> @@ -0,0 +1,42 @@
>>> +/*
>>> + * Common MIPS routines
>>> + *
>>> + * Copyright (c) 2020 Huacai Chen (chenhc@lemote.com)
>>> + * This code is licensed under the GNU GPL v2.
>>> + */
>>> +
>>> +#include <linux/kvm.h>
>>> +#include "qemu/osdep.h"
>>> +#include "qemu-common.h"
>>> +#include "hw/boards.h"
>>> +#include "hw/mips/mips.h"
>>> +#include "sysemu/kvm_int.h"
>>> +
>>> +#ifndef CONFIG_KVM
>>> +
>>> +int mips_kvm_type(MachineState *machine, const char *vm_type)
>>> +{
>>> +    return 0;
>>> +}
>>> +
>>> +#else
>>> +
>>> +int mips_kvm_type(MachineState *machine, const char *vm_type)
>>> +{
>>> +    int r;
>>> +    KVMState *s = KVM_STATE(machine->accelerator);
>>> +
>>> +    r = kvm_check_extension(s, KVM_CAP_MIPS_VZ);
>>> +    if (r > 0) {
>>> +        return KVM_VM_MIPS_VZ;
>>> +    }
>>> +
>>> +    r = kvm_check_extension(s, KVM_CAP_MIPS_TE);
>>> +    if (r > 0) {
>>> +        return KVM_VM_MIPS_TE;
>>> +    }
>>> +
>>> +    return -1;
>>> +}
>>> +
>>> +#endif
>>> diff --git a/include/hw/mips/mips.h b/include/hw/mips/mips.h
>>> index 0af4c3d..2ac0580 100644
>>> --- a/include/hw/mips/mips.h
>>> +++ b/include/hw/mips/mips.h
>>> @@ -20,4 +20,7 @@ void rc4030_dma_write(void *dma, uint8_t *buf, int len);
>>>
>>>  DeviceState *rc4030_init(rc4030_dma **dmas, IOMMUMemoryRegion **dma_mr);
>>>
>>> +/* common.c */
>>> +int mips_kvm_type(MachineState *machine, const char *vm_type);
>>> +
>>>  #endif
>>> --
>>> 2.7.0
>>>
> 



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

* Re: [PATCH for-5.1 V4 1/4] hw/mips: Implement the kvm_type() hook in MachineClass
  2020-06-15  8:55       ` Thomas Huth
@ 2020-06-15 19:44         ` Aleksandar Markovic
  2020-06-16  6:11           ` Huacai Chen
  0 siblings, 1 reply; 41+ messages in thread
From: Aleksandar Markovic @ 2020-06-15 19:44 UTC (permalink / raw)
  To: Thomas Huth
  Cc: Huacai Chen, Huacai Chen, Philippe Mathieu-Daudé,
	QEMU Developers, Aleksandar Markovic, Aleksandar Rikalo,
	Aurelien Jarno

On Mon, Jun 15, 2020 at 10:55 AM Thomas Huth <thuth@redhat.com> wrote:
>
> On 15/06/2020 02.52, Huacai Chen wrote:
> > Hi, Aleksandar,
> >
> > On Sun, Jun 14, 2020 at 4:07 PM Aleksandar Markovic
> > <aleksandar.qemu.devel@gmail.com> wrote:
> >>
> >>
> >>
> >> уто, 2. јун 2020. у 04:38 Huacai Chen <zltjiangshi@gmail.com> је написао/ла:
> >>>
> >>> MIPS has two types of KVM: TE & VZ, and TE is the default type. Now we
> >>> can't create a VZ guest in QEMU because it lacks the kvm_type() hook in
> >>> MachineClass. Besides, libvirt uses a null-machine to detect the kvm
> >>> capability, so by default it will return "KVM not supported" on a VZ
> >>> platform. Thus, null-machine also need the kvm_type() hook.
> >>>
> >>> Reviewed-by: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
> >>> Signed-off-by: Huacai Chen <chenhc@lemote.com>
> >>> Co-developed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> >>> ---
> >>
> >> Huacai,
> >>
> >> Please take a look at Peter's remarks at:
> >>
> >> https://lists.gnu.org/archive/html/qemu-devel/2020-06/msg01878.html
> >>
> >> ...and refactor this patch for v5. My general advice: The simpler, the batter.
> >>
> > OK, I will rework this patch.
>
>  Hi,
>
> is there maybe also a way to do this without moving null-machine.o from
> common-obj-y to obj-y, and to avoid the target-specific hacks in this
> file ? We just moved the null-machine from obj-y to common-obj-y two
> years ago (see commit 3858ff763985fb9e), since it's more desirable to
> have as much code in common-obj to save compilation time and maybe to be
> able to link a qemu with more than one target CPU in one binary one day...
>
> ppc64 has also more than one kvm_type (kvm-hv and kvm-pr), and
> apparently it also works without hacks to the null-machine code there
> ... so maybe you can peek into the ppc64 code to see how it is solved there?
>

Hi, Huacai,

I think the optimal outcome for this release of QEMU would be if you
drop support for VZ. I think your scenario could work without VZ,
couldn't it?

This is a fairly complex thing, and, as you see, it is a little
intrusive, it could negatively impact other targets. With enough
development time, you can easily provide that support in 5.2. - but
now we are close to 5.1 softfreeze.

Even without VZ support, I would consider your contribution the most
significant for MIPS target in last two years, at least - a giant step
ahead!

Best Regards,
Aleksandar

>  Thomas
>
>
> >>>  hw/core/Makefile.objs  |  2 +-
> >>>  hw/core/null-machine.c |  4 ++++
> >>>  hw/mips/Makefile.objs  |  2 +-
> >>>  hw/mips/common.c       | 42 ++++++++++++++++++++++++++++++++++++++++++
> >>>  include/hw/mips/mips.h |  3 +++
> >>>  5 files changed, 51 insertions(+), 2 deletions(-)
> >>>  create mode 100644 hw/mips/common.c
> >>>
> >>> diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs
> >>> index 1d540ed..b5672f4 100644
> >>> --- a/hw/core/Makefile.objs
> >>> +++ b/hw/core/Makefile.objs
> >>> @@ -17,11 +17,11 @@ common-obj-$(CONFIG_SOFTMMU) += vm-change-state-handler.o
> >>>  common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o
> >>>  common-obj-$(CONFIG_SOFTMMU) += sysbus.o
> >>>  common-obj-$(CONFIG_SOFTMMU) += machine.o
> >>> -common-obj-$(CONFIG_SOFTMMU) += null-machine.o
> >>>  common-obj-$(CONFIG_SOFTMMU) += loader.o
> >>>  common-obj-$(CONFIG_SOFTMMU) += machine-hmp-cmds.o
> >>>  common-obj-$(CONFIG_SOFTMMU) += numa.o
> >>>  common-obj-$(CONFIG_SOFTMMU) += clock-vmstate.o
> >>> +obj-$(CONFIG_SOFTMMU) += null-machine.o
> >>>  obj-$(CONFIG_SOFTMMU) += machine-qmp-cmds.o
> >>>
> >>>  common-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o
> >>> diff --git a/hw/core/null-machine.c b/hw/core/null-machine.c
> >>> index cb47d9d..94a36f9 100644
> >>> --- a/hw/core/null-machine.c
> >>> +++ b/hw/core/null-machine.c
> >>> @@ -17,6 +17,7 @@
> >>>  #include "sysemu/sysemu.h"
> >>>  #include "exec/address-spaces.h"
> >>>  #include "hw/core/cpu.h"
> >>> +#include "hw/mips/mips.h"
> >>>
> >>>  static void machine_none_init(MachineState *mch)
> >>>  {
> >>> @@ -50,6 +51,9 @@ static void machine_none_machine_init(MachineClass *mc)
> >>>      mc->max_cpus = 1;
> >>>      mc->default_ram_size = 0;
> >>>      mc->default_ram_id = "ram";
> >>> +#ifdef TARGET_MIPS
> >>> +    mc->kvm_type = mips_kvm_type;
> >>> +#endif
> >>>  }
> >>>
> >>>  DEFINE_MACHINE("none", machine_none_machine_init)
> >>> diff --git a/hw/mips/Makefile.objs b/hw/mips/Makefile.objs
> >>> index 739e2b7..3b3e6ea 100644
> >>> --- a/hw/mips/Makefile.objs
> >>> +++ b/hw/mips/Makefile.objs
> >>> @@ -1,4 +1,4 @@
> >>> -obj-y += addr.o mips_int.o
> >>> +obj-y += addr.o common.o mips_int.o
> >>>  obj-$(CONFIG_R4K) += r4k.o
> >>>  obj-$(CONFIG_MALTA) += gt64xxx_pci.o malta.o
> >>>  obj-$(CONFIG_MIPSSIM) += mipssim.o
> >>> diff --git a/hw/mips/common.c b/hw/mips/common.c
> >>> new file mode 100644
> >>> index 0000000..4d8e141
> >>> --- /dev/null
> >>> +++ b/hw/mips/common.c
> >>> @@ -0,0 +1,42 @@
> >>> +/*
> >>> + * Common MIPS routines
> >>> + *
> >>> + * Copyright (c) 2020 Huacai Chen (chenhc@lemote.com)
> >>> + * This code is licensed under the GNU GPL v2.
> >>> + */
> >>> +
> >>> +#include <linux/kvm.h>
> >>> +#include "qemu/osdep.h"
> >>> +#include "qemu-common.h"
> >>> +#include "hw/boards.h"
> >>> +#include "hw/mips/mips.h"
> >>> +#include "sysemu/kvm_int.h"
> >>> +
> >>> +#ifndef CONFIG_KVM
> >>> +
> >>> +int mips_kvm_type(MachineState *machine, const char *vm_type)
> >>> +{
> >>> +    return 0;
> >>> +}
> >>> +
> >>> +#else
> >>> +
> >>> +int mips_kvm_type(MachineState *machine, const char *vm_type)
> >>> +{
> >>> +    int r;
> >>> +    KVMState *s = KVM_STATE(machine->accelerator);
> >>> +
> >>> +    r = kvm_check_extension(s, KVM_CAP_MIPS_VZ);
> >>> +    if (r > 0) {
> >>> +        return KVM_VM_MIPS_VZ;
> >>> +    }
> >>> +
> >>> +    r = kvm_check_extension(s, KVM_CAP_MIPS_TE);
> >>> +    if (r > 0) {
> >>> +        return KVM_VM_MIPS_TE;
> >>> +    }
> >>> +
> >>> +    return -1;
> >>> +}
> >>> +
> >>> +#endif
> >>> diff --git a/include/hw/mips/mips.h b/include/hw/mips/mips.h
> >>> index 0af4c3d..2ac0580 100644
> >>> --- a/include/hw/mips/mips.h
> >>> +++ b/include/hw/mips/mips.h
> >>> @@ -20,4 +20,7 @@ void rc4030_dma_write(void *dma, uint8_t *buf, int len);
> >>>
> >>>  DeviceState *rc4030_init(rc4030_dma **dmas, IOMMUMemoryRegion **dma_mr);
> >>>
> >>> +/* common.c */
> >>> +int mips_kvm_type(MachineState *machine, const char *vm_type);
> >>> +
> >>>  #endif
> >>> --
> >>> 2.7.0
> >>>
> >
>
>


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

* Re: [PATCH for-5.1 V4 1/4] hw/mips: Implement the kvm_type() hook in MachineClass
  2020-06-15 19:44         ` Aleksandar Markovic
@ 2020-06-16  6:11           ` Huacai Chen
  2020-06-16 21:17             ` Aleksandar Markovic
  0 siblings, 1 reply; 41+ messages in thread
From: Huacai Chen @ 2020-06-16  6:11 UTC (permalink / raw)
  To: Aleksandar Markovic
  Cc: Huacai Chen, Thomas Huth, Philippe Mathieu-Daudé,
	QEMU Developers, Aleksandar Markovic, Aleksandar Rikalo,
	Aurelien Jarno

Hi, Thomas and Aleksandar,

On Tue, Jun 16, 2020 at 3:45 AM Aleksandar Markovic
<aleksandar.m.mail@gmail.com> wrote:
>
> On Mon, Jun 15, 2020 at 10:55 AM Thomas Huth <thuth@redhat.com> wrote:
> >
> > On 15/06/2020 02.52, Huacai Chen wrote:
> > > Hi, Aleksandar,
> > >
> > > On Sun, Jun 14, 2020 at 4:07 PM Aleksandar Markovic
> > > <aleksandar.qemu.devel@gmail.com> wrote:
> > >>
> > >>
> > >>
> > >> уто, 2. јун 2020. у 04:38 Huacai Chen <zltjiangshi@gmail.com> је написао/ла:
> > >>>
> > >>> MIPS has two types of KVM: TE & VZ, and TE is the default type. Now we
> > >>> can't create a VZ guest in QEMU because it lacks the kvm_type() hook in
> > >>> MachineClass. Besides, libvirt uses a null-machine to detect the kvm
> > >>> capability, so by default it will return "KVM not supported" on a VZ
> > >>> platform. Thus, null-machine also need the kvm_type() hook.
> > >>>
> > >>> Reviewed-by: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
> > >>> Signed-off-by: Huacai Chen <chenhc@lemote.com>
> > >>> Co-developed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> > >>> ---
> > >>
> > >> Huacai,
> > >>
> > >> Please take a look at Peter's remarks at:
> > >>
> > >> https://lists.gnu.org/archive/html/qemu-devel/2020-06/msg01878.html
> > >>
> > >> ...and refactor this patch for v5. My general advice: The simpler, the batter.
> > >>
> > > OK, I will rework this patch.
> >
> >  Hi,
> >
> > is there maybe also a way to do this without moving null-machine.o from
> > common-obj-y to obj-y, and to avoid the target-specific hacks in this
> > file ? We just moved the null-machine from obj-y to common-obj-y two
> > years ago (see commit 3858ff763985fb9e), since it's more desirable to
> > have as much code in common-obj to save compilation time and maybe to be
> > able to link a qemu with more than one target CPU in one binary one day...
> >
> > ppc64 has also more than one kvm_type (kvm-hv and kvm-pr), and
> > apparently it also works without hacks to the null-machine code there
> > ... so maybe you can peek into the ppc64 code to see how it is solved there?
> >
>
> Hi, Huacai,
>
> I think the optimal outcome for this release of QEMU would be if you
> drop support for VZ. I think your scenario could work without VZ,
> couldn't it?
>
> This is a fairly complex thing, and, as you see, it is a little
> intrusive, it could negatively impact other targets. With enough
> development time, you can easily provide that support in 5.2. - but
> now we are close to 5.1 softfreeze.
>
> Even without VZ support, I would consider your contribution the most
> significant for MIPS target in last two years, at least - a giant step
> ahead!
There are two problems: 1, qemu need kvm_type() to create a normal KVM
guest. 2, libvirt use the null-machine to detect the KVM capability.
For the first problem, just provide a kvm_type() hook for MIPS is
enough, which is similar to ppc64. For the second problem, I think
libvirt is also unable to detect the KVM capabilty on ppc64, unless
ppc64 do the same hack on null-machine.

V5 of this patch will only provide kvm_type() for MIPS (not hack
null-machine.c), but all of us should think how to solve the second
problem.

Huacai
>
> Best Regards,
> Aleksandar
>
> >  Thomas
> >
> >
> > >>>  hw/core/Makefile.objs  |  2 +-
> > >>>  hw/core/null-machine.c |  4 ++++
> > >>>  hw/mips/Makefile.objs  |  2 +-
> > >>>  hw/mips/common.c       | 42 ++++++++++++++++++++++++++++++++++++++++++
> > >>>  include/hw/mips/mips.h |  3 +++
> > >>>  5 files changed, 51 insertions(+), 2 deletions(-)
> > >>>  create mode 100644 hw/mips/common.c
> > >>>
> > >>> diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs
> > >>> index 1d540ed..b5672f4 100644
> > >>> --- a/hw/core/Makefile.objs
> > >>> +++ b/hw/core/Makefile.objs
> > >>> @@ -17,11 +17,11 @@ common-obj-$(CONFIG_SOFTMMU) += vm-change-state-handler.o
> > >>>  common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o
> > >>>  common-obj-$(CONFIG_SOFTMMU) += sysbus.o
> > >>>  common-obj-$(CONFIG_SOFTMMU) += machine.o
> > >>> -common-obj-$(CONFIG_SOFTMMU) += null-machine.o
> > >>>  common-obj-$(CONFIG_SOFTMMU) += loader.o
> > >>>  common-obj-$(CONFIG_SOFTMMU) += machine-hmp-cmds.o
> > >>>  common-obj-$(CONFIG_SOFTMMU) += numa.o
> > >>>  common-obj-$(CONFIG_SOFTMMU) += clock-vmstate.o
> > >>> +obj-$(CONFIG_SOFTMMU) += null-machine.o
> > >>>  obj-$(CONFIG_SOFTMMU) += machine-qmp-cmds.o
> > >>>
> > >>>  common-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o
> > >>> diff --git a/hw/core/null-machine.c b/hw/core/null-machine.c
> > >>> index cb47d9d..94a36f9 100644
> > >>> --- a/hw/core/null-machine.c
> > >>> +++ b/hw/core/null-machine.c
> > >>> @@ -17,6 +17,7 @@
> > >>>  #include "sysemu/sysemu.h"
> > >>>  #include "exec/address-spaces.h"
> > >>>  #include "hw/core/cpu.h"
> > >>> +#include "hw/mips/mips.h"
> > >>>
> > >>>  static void machine_none_init(MachineState *mch)
> > >>>  {
> > >>> @@ -50,6 +51,9 @@ static void machine_none_machine_init(MachineClass *mc)
> > >>>      mc->max_cpus = 1;
> > >>>      mc->default_ram_size = 0;
> > >>>      mc->default_ram_id = "ram";
> > >>> +#ifdef TARGET_MIPS
> > >>> +    mc->kvm_type = mips_kvm_type;
> > >>> +#endif
> > >>>  }
> > >>>
> > >>>  DEFINE_MACHINE("none", machine_none_machine_init)
> > >>> diff --git a/hw/mips/Makefile.objs b/hw/mips/Makefile.objs
> > >>> index 739e2b7..3b3e6ea 100644
> > >>> --- a/hw/mips/Makefile.objs
> > >>> +++ b/hw/mips/Makefile.objs
> > >>> @@ -1,4 +1,4 @@
> > >>> -obj-y += addr.o mips_int.o
> > >>> +obj-y += addr.o common.o mips_int.o
> > >>>  obj-$(CONFIG_R4K) += r4k.o
> > >>>  obj-$(CONFIG_MALTA) += gt64xxx_pci.o malta.o
> > >>>  obj-$(CONFIG_MIPSSIM) += mipssim.o
> > >>> diff --git a/hw/mips/common.c b/hw/mips/common.c
> > >>> new file mode 100644
> > >>> index 0000000..4d8e141
> > >>> --- /dev/null
> > >>> +++ b/hw/mips/common.c
> > >>> @@ -0,0 +1,42 @@
> > >>> +/*
> > >>> + * Common MIPS routines
> > >>> + *
> > >>> + * Copyright (c) 2020 Huacai Chen (chenhc@lemote.com)
> > >>> + * This code is licensed under the GNU GPL v2.
> > >>> + */
> > >>> +
> > >>> +#include <linux/kvm.h>
> > >>> +#include "qemu/osdep.h"
> > >>> +#include "qemu-common.h"
> > >>> +#include "hw/boards.h"
> > >>> +#include "hw/mips/mips.h"
> > >>> +#include "sysemu/kvm_int.h"
> > >>> +
> > >>> +#ifndef CONFIG_KVM
> > >>> +
> > >>> +int mips_kvm_type(MachineState *machine, const char *vm_type)
> > >>> +{
> > >>> +    return 0;
> > >>> +}
> > >>> +
> > >>> +#else
> > >>> +
> > >>> +int mips_kvm_type(MachineState *machine, const char *vm_type)
> > >>> +{
> > >>> +    int r;
> > >>> +    KVMState *s = KVM_STATE(machine->accelerator);
> > >>> +
> > >>> +    r = kvm_check_extension(s, KVM_CAP_MIPS_VZ);
> > >>> +    if (r > 0) {
> > >>> +        return KVM_VM_MIPS_VZ;
> > >>> +    }
> > >>> +
> > >>> +    r = kvm_check_extension(s, KVM_CAP_MIPS_TE);
> > >>> +    if (r > 0) {
> > >>> +        return KVM_VM_MIPS_TE;
> > >>> +    }
> > >>> +
> > >>> +    return -1;
> > >>> +}
> > >>> +
> > >>> +#endif
> > >>> diff --git a/include/hw/mips/mips.h b/include/hw/mips/mips.h
> > >>> index 0af4c3d..2ac0580 100644
> > >>> --- a/include/hw/mips/mips.h
> > >>> +++ b/include/hw/mips/mips.h
> > >>> @@ -20,4 +20,7 @@ void rc4030_dma_write(void *dma, uint8_t *buf, int len);
> > >>>
> > >>>  DeviceState *rc4030_init(rc4030_dma **dmas, IOMMUMemoryRegion **dma_mr);
> > >>>
> > >>> +/* common.c */
> > >>> +int mips_kvm_type(MachineState *machine, const char *vm_type);
> > >>> +
> > >>>  #endif
> > >>> --
> > >>> 2.7.0
> > >>>
> > >
> >
> >


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

* Re: [PATCH for-5.1 V4 1/4] hw/mips: Implement the kvm_type() hook in MachineClass
  2020-06-16  6:11           ` Huacai Chen
@ 2020-06-16 21:17             ` Aleksandar Markovic
  0 siblings, 0 replies; 41+ messages in thread
From: Aleksandar Markovic @ 2020-06-16 21:17 UTC (permalink / raw)
  To: Huacai Chen
  Cc: Huacai Chen, Thomas Huth, Philippe Mathieu-Daudé,
	QEMU Developers, Aleksandar Markovic, Aleksandar Rikalo,
	Aurelien Jarno

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

уторак, 16. јун 2020., Huacai Chen <chenhuacai@gmail.com> је написао/ла:

> Hi, Thomas and Aleksandar,
>
> On Tue, Jun 16, 2020 at 3:45 AM Aleksandar Markovic
> <aleksandar.m.mail@gmail.com> wrote:
> >
> > On Mon, Jun 15, 2020 at 10:55 AM Thomas Huth <thuth@redhat.com> wrote:
> > >
> > > On 15/06/2020 02.52, Huacai Chen wrote:
> > > > Hi, Aleksandar,
> > > >
> > > > On Sun, Jun 14, 2020 at 4:07 PM Aleksandar Markovic
> > > > <aleksandar.qemu.devel@gmail.com> wrote:
> > > >>
> > > >>
> > > >>
> > > >> уто, 2. јун 2020. у 04:38 Huacai Chen <zltjiangshi@gmail.com> је
> написао/ла:
> > > >>>
> > > >>> MIPS has two types of KVM: TE & VZ, and TE is the default type.
> Now we
> > > >>> can't create a VZ guest in QEMU because it lacks the kvm_type()
> hook in
> > > >>> MachineClass. Besides, libvirt uses a null-machine to detect the
> kvm
> > > >>> capability, so by default it will return "KVM not supported" on a
> VZ
> > > >>> platform. Thus, null-machine also need the kvm_type() hook.
> > > >>>
> > > >>> Reviewed-by: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
> > > >>> Signed-off-by: Huacai Chen <chenhc@lemote.com>
> > > >>> Co-developed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> > > >>> ---
> > > >>
> > > >> Huacai,
> > > >>
> > > >> Please take a look at Peter's remarks at:
> > > >>
> > > >> https://lists.gnu.org/archive/html/qemu-devel/2020-06/msg01878.html
> > > >>
> > > >> ...and refactor this patch for v5. My general advice: The simpler,
> the batter.
> > > >>
> > > > OK, I will rework this patch.
> > >
> > >  Hi,
> > >
> > > is there maybe also a way to do this without moving null-machine.o from
> > > common-obj-y to obj-y, and to avoid the target-specific hacks in this
> > > file ? We just moved the null-machine from obj-y to common-obj-y two
> > > years ago (see commit 3858ff763985fb9e), since it's more desirable to
> > > have as much code in common-obj to save compilation time and maybe to
> be
> > > able to link a qemu with more than one target CPU in one binary one
> day...
> > >
> > > ppc64 has also more than one kvm_type (kvm-hv and kvm-pr), and
> > > apparently it also works without hacks to the null-machine code there
> > > ... so maybe you can peek into the ppc64 code to see how it is solved
> there?
> > >
> >
> > Hi, Huacai,
> >
> > I think the optimal outcome for this release of QEMU would be if you
> > drop support for VZ. I think your scenario could work without VZ,
> > couldn't it?
> >
> > This is a fairly complex thing, and, as you see, it is a little
> > intrusive, it could negatively impact other targets. With enough
> > development time, you can easily provide that support in 5.2. - but
> > now we are close to 5.1 softfreeze.
> >
> > Even without VZ support, I would consider your contribution the most
> > significant for MIPS target in last two years, at least - a giant step
> > ahead!
> There are two problems: 1, qemu need kvm_type() to create a normal KVM
> guest. 2, libvirt use the null-machine to detect the KVM capability.
> For the first problem, just provide a kvm_type() hook for MIPS is
> enough, which is similar to ppc64. For the second problem, I think
> libvirt is also unable to detect the KVM capabilty on ppc64, unless
> ppc64 do the same hack on null-machine.
>
> V5 of this patch will only provide kvm_type() for MIPS (not hack
> null-machine.c), but all of us should think how to solve the second
> problem.
>
>
I think this is a good approach, Huacai. Looking forward to v5.

May health be with you,

Aleksandar




> Huacai
> >
> > Best Regards,
> > Aleksandar
> >
> > >  Thomas
> > >
> > >
> > > >>>  hw/core/Makefile.objs  |  2 +-
> > > >>>  hw/core/null-machine.c |  4 ++++
> > > >>>  hw/mips/Makefile.objs  |  2 +-
> > > >>>  hw/mips/common.c       | 42 ++++++++++++++++++++++++++++++
> ++++++++++++
> > > >>>  include/hw/mips/mips.h |  3 +++
> > > >>>  5 files changed, 51 insertions(+), 2 deletions(-)
> > > >>>  create mode 100644 hw/mips/common.c
> > > >>>
> > > >>> diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs
> > > >>> index 1d540ed..b5672f4 100644
> > > >>> --- a/hw/core/Makefile.objs
> > > >>> +++ b/hw/core/Makefile.objs
> > > >>> @@ -17,11 +17,11 @@ common-obj-$(CONFIG_SOFTMMU) +=
> vm-change-state-handler.o
> > > >>>  common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o
> > > >>>  common-obj-$(CONFIG_SOFTMMU) += sysbus.o
> > > >>>  common-obj-$(CONFIG_SOFTMMU) += machine.o
> > > >>> -common-obj-$(CONFIG_SOFTMMU) += null-machine.o
> > > >>>  common-obj-$(CONFIG_SOFTMMU) += loader.o
> > > >>>  common-obj-$(CONFIG_SOFTMMU) += machine-hmp-cmds.o
> > > >>>  common-obj-$(CONFIG_SOFTMMU) += numa.o
> > > >>>  common-obj-$(CONFIG_SOFTMMU) += clock-vmstate.o
> > > >>> +obj-$(CONFIG_SOFTMMU) += null-machine.o
> > > >>>  obj-$(CONFIG_SOFTMMU) += machine-qmp-cmds.o
> > > >>>
> > > >>>  common-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o
> > > >>> diff --git a/hw/core/null-machine.c b/hw/core/null-machine.c
> > > >>> index cb47d9d..94a36f9 100644
> > > >>> --- a/hw/core/null-machine.c
> > > >>> +++ b/hw/core/null-machine.c
> > > >>> @@ -17,6 +17,7 @@
> > > >>>  #include "sysemu/sysemu.h"
> > > >>>  #include "exec/address-spaces.h"
> > > >>>  #include "hw/core/cpu.h"
> > > >>> +#include "hw/mips/mips.h"
> > > >>>
> > > >>>  static void machine_none_init(MachineState *mch)
> > > >>>  {
> > > >>> @@ -50,6 +51,9 @@ static void machine_none_machine_init(MachineClass
> *mc)
> > > >>>      mc->max_cpus = 1;
> > > >>>      mc->default_ram_size = 0;
> > > >>>      mc->default_ram_id = "ram";
> > > >>> +#ifdef TARGET_MIPS
> > > >>> +    mc->kvm_type = mips_kvm_type;
> > > >>> +#endif
> > > >>>  }
> > > >>>
> > > >>>  DEFINE_MACHINE("none", machine_none_machine_init)
> > > >>> diff --git a/hw/mips/Makefile.objs b/hw/mips/Makefile.objs
> > > >>> index 739e2b7..3b3e6ea 100644
> > > >>> --- a/hw/mips/Makefile.objs
> > > >>> +++ b/hw/mips/Makefile.objs
> > > >>> @@ -1,4 +1,4 @@
> > > >>> -obj-y += addr.o mips_int.o
> > > >>> +obj-y += addr.o common.o mips_int.o
> > > >>>  obj-$(CONFIG_R4K) += r4k.o
> > > >>>  obj-$(CONFIG_MALTA) += gt64xxx_pci.o malta.o
> > > >>>  obj-$(CONFIG_MIPSSIM) += mipssim.o
> > > >>> diff --git a/hw/mips/common.c b/hw/mips/common.c
> > > >>> new file mode 100644
> > > >>> index 0000000..4d8e141
> > > >>> --- /dev/null
> > > >>> +++ b/hw/mips/common.c
> > > >>> @@ -0,0 +1,42 @@
> > > >>> +/*
> > > >>> + * Common MIPS routines
> > > >>> + *
> > > >>> + * Copyright (c) 2020 Huacai Chen (chenhc@lemote.com)
> > > >>> + * This code is licensed under the GNU GPL v2.
> > > >>> + */
> > > >>> +
> > > >>> +#include <linux/kvm.h>
> > > >>> +#include "qemu/osdep.h"
> > > >>> +#include "qemu-common.h"
> > > >>> +#include "hw/boards.h"
> > > >>> +#include "hw/mips/mips.h"
> > > >>> +#include "sysemu/kvm_int.h"
> > > >>> +
> > > >>> +#ifndef CONFIG_KVM
> > > >>> +
> > > >>> +int mips_kvm_type(MachineState *machine, const char *vm_type)
> > > >>> +{
> > > >>> +    return 0;
> > > >>> +}
> > > >>> +
> > > >>> +#else
> > > >>> +
> > > >>> +int mips_kvm_type(MachineState *machine, const char *vm_type)
> > > >>> +{
> > > >>> +    int r;
> > > >>> +    KVMState *s = KVM_STATE(machine->accelerator);
> > > >>> +
> > > >>> +    r = kvm_check_extension(s, KVM_CAP_MIPS_VZ);
> > > >>> +    if (r > 0) {
> > > >>> +        return KVM_VM_MIPS_VZ;
> > > >>> +    }
> > > >>> +
> > > >>> +    r = kvm_check_extension(s, KVM_CAP_MIPS_TE);
> > > >>> +    if (r > 0) {
> > > >>> +        return KVM_VM_MIPS_TE;
> > > >>> +    }
> > > >>> +
> > > >>> +    return -1;
> > > >>> +}
> > > >>> +
> > > >>> +#endif
> > > >>> diff --git a/include/hw/mips/mips.h b/include/hw/mips/mips.h
> > > >>> index 0af4c3d..2ac0580 100644
> > > >>> --- a/include/hw/mips/mips.h
> > > >>> +++ b/include/hw/mips/mips.h
> > > >>> @@ -20,4 +20,7 @@ void rc4030_dma_write(void *dma, uint8_t *buf,
> int len);
> > > >>>
> > > >>>  DeviceState *rc4030_init(rc4030_dma **dmas, IOMMUMemoryRegion
> **dma_mr);
> > > >>>
> > > >>> +/* common.c */
> > > >>> +int mips_kvm_type(MachineState *machine, const char *vm_type);
> > > >>> +
> > > >>>  #endif
> > > >>> --
> > > >>> 2.7.0
> > > >>>
> > > >
> > >
> > >
>

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

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

end of thread, other threads:[~2020-06-16 21:18 UTC | newest]

Thread overview: 41+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-06-02  2:39 [PATCH for-5.1 V4 0/7] mips: Add Loongson-3 machine support (with KVM) Huacai Chen
2020-06-02  2:39 ` [PATCH for-5.1 V4 1/4] hw/mips: Implement the kvm_type() hook in MachineClass Huacai Chen
2020-06-03 14:34   ` Aleksandar Markovic
2020-06-04  0:57     ` Huacai Chen
2020-06-04 10:04       ` Aleksandar Markovic
2020-06-14  8:07   ` Aleksandar Markovic
2020-06-15  0:52     ` Huacai Chen
2020-06-15  8:55       ` Thomas Huth
2020-06-15 19:44         ` Aleksandar Markovic
2020-06-16  6:11           ` Huacai Chen
2020-06-16 21:17             ` Aleksandar Markovic
2020-06-02  2:39 ` [PATCH for-5.1 V4 2/4] target/mips: Add Loongson-3 CPU definition Huacai Chen
2020-06-06  7:30   ` Aleksandar Markovic
2020-06-02  2:39 ` [PATCH for-5.1 V4 3/4] hw/mips: Add Loongson-3 machine support (with KVM) Huacai Chen
2020-06-06  7:32   ` Aleksandar Markovic
2020-06-06  8:01     ` Aleksandar Markovic
2020-06-07  1:12       ` chen huacai
2020-06-07 20:00         ` Aleksandar Markovic
2020-06-08  3:56           ` Huacai Chen
2020-06-11  5:58   ` Jiaxun Yang
2020-06-11  7:49     ` Huacai Chen
2020-06-11  8:12       ` Jiaxun Yang
2020-06-11  8:50         ` Aleksandar Markovic
2020-06-12  6:07           ` Huacai Chen
2020-06-14  7:51   ` Aleksandar Markovic
2020-06-15  0:55     ` Huacai Chen
2020-06-15  4:42       ` Aleksandar Markovic
2020-06-15  4:50       ` Aleksandar Markovic
2020-06-15  5:36         ` Huacai Chen
2020-06-15  5:58           ` Aleksandar Markovic
2020-06-15  6:04           ` Aleksandar Markovic
2020-06-15  6:29             ` Huacai Chen
2020-06-15  6:44               ` Aleksandar Markovic
2020-06-02  2:39 ` [PATCH for-5.1 V4 4/4] MAINTAINERS: Add myself as Loongson-3 maintainer Huacai Chen
2020-06-02  8:12   ` Philippe Mathieu-Daudé
2020-06-02 12:03     ` chen huacai
2020-06-05  8:38 ` [PATCH for-5.1 V4 0/7] mips: Add Loongson-3 machine support (with KVM) Aleksandar Markovic
2020-06-05  8:40   ` Aleksandar Markovic
2020-06-05  9:05   ` Jiaxun Yang
2020-06-05  9:21     ` Huacai Chen
2020-06-05  9:27     ` Aleksandar Markovic

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.