[PATCH v3] target/loongarch/kvm: Add software breakpoint support

2024-06-06 Thread Bibo Mao
With KVM virtualization, debug exception is injected to guest kernel
rather than host for normal break intruction. Here hypercall
instruction with special code is used for sw breakpoint usage,
and detailed instruction comes from kvm kernel with user API
KVM_REG_LOONGARCH_DEBUG_INST.

Now only software breakpoint is supported, and it is allowed to
insert/remove software breakpoint. We can debug guest kernel with gdb
method after kernel is loaded, hardware breakpoint will be added in later.

Signed-off-by: Bibo Mao 
---
v2 ... v3:
  1. Refresh patch based on the latest version, succeed in compile and
run since kvm uapi header files is updated.
v1 ... v2:
  1. Enable TARGET_KVM_HAVE_GUEST_DEBUG on loongarch64 platform
---
 configs/targets/loongarch64-softmmu.mak |  1 +
 target/loongarch/kvm/kvm.c  | 76 +
 2 files changed, 77 insertions(+)

diff --git a/configs/targets/loongarch64-softmmu.mak 
b/configs/targets/loongarch64-softmmu.mak
index 84beb19b90..65b65e0c34 100644
--- a/configs/targets/loongarch64-softmmu.mak
+++ b/configs/targets/loongarch64-softmmu.mak
@@ -1,5 +1,6 @@
 TARGET_ARCH=loongarch64
 TARGET_BASE_ARCH=loongarch
+TARGET_KVM_HAVE_GUEST_DEBUG=y
 TARGET_SUPPORTS_MTTCG=y
 TARGET_XML_FILES= gdb-xml/loongarch-base32.xml gdb-xml/loongarch-base64.xml 
gdb-xml/loongarch-fpu.xml
 # all boards require libfdt
diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
index 8e6e27c8bf..e1be6a6959 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -28,6 +28,7 @@
 #include "trace.h"
 
 static bool cap_has_mp_state;
+static unsigned int brk_insn;
 const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
 KVM_CAP_LAST_INFO
 };
@@ -664,7 +665,14 @@ static void kvm_loongarch_vm_stage_change(void *opaque, 
bool running,
 
 int kvm_arch_init_vcpu(CPUState *cs)
 {
+uint64_t val;
+
 qemu_add_vm_change_state_handler(kvm_loongarch_vm_stage_change, cs);
+
+if (!kvm_get_one_reg(cs, KVM_REG_LOONGARCH_DEBUG_INST, )) {
+brk_insn = val;
+}
+
 return 0;
 }
 
@@ -739,6 +747,67 @@ bool kvm_arch_stop_on_emulation_error(CPUState *cs)
 return true;
 }
 
+void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg)
+{
+if (kvm_sw_breakpoints_active(cpu)) {
+dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP;
+}
+}
+
+int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
+{
+if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)>saved_insn, 4, 0) ||
+cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)_insn, 4, 1)) {
+error_report("%s failed", __func__);
+return -EINVAL;
+}
+return 0;
+}
+
+int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
+{
+static uint32_t brk;
+
+if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *), 4, 0) ||
+brk != brk_insn ||
+cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)>saved_insn, 4, 1)) {
+error_report("%s failed", __func__);
+return -EINVAL;
+}
+return 0;
+}
+
+int kvm_arch_insert_hw_breakpoint(vaddr addr, vaddr len, int type)
+{
+return -ENOSYS;
+}
+
+int kvm_arch_remove_hw_breakpoint(vaddr addr, vaddr len, int type)
+{
+return -ENOSYS;
+}
+
+void kvm_arch_remove_all_hw_breakpoints(void)
+{
+}
+
+static bool kvm_loongarch_handle_debug(CPUState *cs, struct kvm_run *run)
+{
+LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+CPULoongArchState *env = >env;
+
+kvm_cpu_synchronize_state(cs);
+if (cs->singlestep_enabled) {
+return true;
+}
+
+if (kvm_find_sw_breakpoint(cs, env->pc)) {
+return true;
+}
+
+return false;
+}
+
 int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
 {
 int ret = 0;
@@ -757,6 +826,13 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
  run->iocsr_io.len,
  run->iocsr_io.is_write);
 break;
+
+case KVM_EXIT_DEBUG:
+if (kvm_loongarch_handle_debug(cs, run)) {
+ret = EXCP_DEBUG;
+}
+break;
+
 default:
 ret = -1;
 warn_report("KVM: unknown exit reason %d", run->exit_reason);

base-commit: dec9742cbc59415a8b83e382e7ae36395394e4bd
-- 
2.39.3




[PATCH 0/2] Add simd optimization with function buffer_is_zero

2024-06-05 Thread Bibo Mao
On some loongarch machines, simd FPU such lsx/lasx is supported. Here
function buffer_is_zero is optimized with simd FPU supported. 

Bibo Mao (2):
  util: Add lasx cpuinfo for loongarch64
  util/bufferiszero: Add simd acceleration for loongarch64

 host/include/loongarch64/host/cpuinfo.h |   1 +
 meson.build |  11 +++
 util/bufferiszero.c | 103 
 util/cpuinfo-loongarch.c|   1 +
 4 files changed, 116 insertions(+)


base-commit: 3ab42e46acf867c45bc929fcc37693e327a35a24
-- 
2.39.3




[PATCH 2/2] util/bufferiszero: Add simd acceleration for loongarch64

2024-06-05 Thread Bibo Mao
Different gcc versions have different features, macro CONFIG_LSX_OPT
and CONFIG_LASX_OPT is added here to detect whether gcc supports
built-in lsx/lasx macro.

Function buffer_zero_lsx() is added for 128bit simd fpu optimization,
and function buffer_zero_lasx() is for 256bit simd fpu optimization.

Loongarch gcc built-in lsx/lasx macro can be used only when compiler
option -mlsx/-mlasx is added, and there is no separate compiler option
for function only. So it is only in effect when qemu is compiled with
parameter --extra-cflags="-mlasx"

Signed-off-by: Bibo Mao 
---
 meson.build |  11 +
 util/bufferiszero.c | 103 
 2 files changed, 114 insertions(+)

diff --git a/meson.build b/meson.build
index 6386607144..29bc362d7a 100644
--- a/meson.build
+++ b/meson.build
@@ -2855,6 +2855,17 @@ config_host_data.set('CONFIG_ARM_AES_BUILTIN', 
cc.compiles('''
 void foo(uint8x16_t *p) { *p = vaesmcq_u8(*p); }
   '''))
 
+# For Loongarch64, detect if LSX/LASX are available.
+ config_host_data.set('CONFIG_LSX_OPT', cc.compiles('''
+#include "lsxintrin.h"
+int foo(__m128i v) { return __lsx_bz_v(v); }
+  '''))
+
+config_host_data.set('CONFIG_LASX_OPT', cc.compiles('''
+#include "lasxintrin.h"
+int foo(__m256i v) { return __lasx_xbz_v(v); }
+  '''))
+
 if get_option('membarrier').disabled()
   have_membarrier = false
 elif host_os == 'windows'
diff --git a/util/bufferiszero.c b/util/bufferiszero.c
index 74864f7b78..751e81dbb3 100644
--- a/util/bufferiszero.c
+++ b/util/bufferiszero.c
@@ -265,6 +265,109 @@ static biz_accel_fn const accel_table[] = {
 buffer_is_zero_int_ge256,
 buffer_is_zero_simd,
 };
+#elif defined(__loongarch__)
+#ifdef CONFIG_LSX_OPT
+#include "lsxintrin.h"
+static bool buffer_zero_lsx(const void *buf, size_t len)
+{
+/* Unaligned loads at head/tail.  */
+__m128i v = *(__m128i *)(buf);
+__m128i w = *(__m128i *)(buf + len - 16);
+/* Align head/tail to 16-byte boundaries.  */
+const __m128i *p = QEMU_ALIGN_PTR_DOWN(buf + 16, 16);
+const __m128i *e = QEMU_ALIGN_PTR_DOWN(buf + len - 1, 16);
+
+/* Collect a partial block at tail end.  */
+v |= e[-1]; w |= e[-2];
+v |= e[-3]; w |= e[-4];
+v |= e[-5]; w |= e[-6];
+v |= e[-7]; v |= w;
+
+/*
+ * Loop over complete 128-byte blocks.
+ * With the head and tail removed, e - p >= 14, so the loop
+ * must iterate at least once.
+ */
+do {
+if (!__lsx_bz_v(v)) {
+return false;
+}
+v = p[0];  w = p[1];
+v |= p[2]; w |= p[3];
+v |= p[4]; w |= p[5];
+v |= p[6]; w |= p[7];
+v |= w;
+p += 8;
+} while (p < e - 7);
+
+return __lsx_bz_v(v);
+}
+#endif
+
+#ifdef CONFIG_LASX_OPT
+#include "lasxintrin.h"
+static bool buffer_zero_lasx(const void *buf, size_t len)
+{
+/* Unaligned loads at head/tail.  */
+__m256i v = *(__m256i *)(buf);
+__m256i w = *(__m256i *)(buf + len - 32);
+/* Align head/tail to 32-byte boundaries.  */
+const __m256i *p = QEMU_ALIGN_PTR_DOWN(buf + 32, 32);
+const __m256i *e = QEMU_ALIGN_PTR_DOWN(buf + len - 1, 32);
+
+/* Collect a partial block at tail end.  */
+v |= e[-1]; w |= e[-2];
+v |= e[-3]; w |= e[-4];
+v |= e[-5]; w |= e[-6];
+v |= e[-7]; v |= w;
+
+/* Loop over complete 256-byte blocks.  */
+for (; p < e - 7; p += 8) {
+/* PTEST is not profitable here.  */
+if (!__lasx_xbz_v(v)) {
+return false;
+}
+
+v = p[0];  w = p[1];
+v |= p[2]; w |= p[3];
+v |= p[4]; w |= p[5];
+v |= p[6]; w |= p[7];
+v |= w;
+}
+
+return __lasx_xbz_v(v);
+}
+#endif
+
+static biz_accel_fn const accel_table[] = {
+buffer_is_zero_int_ge256,
+#ifdef CONFIG_LSX_OPT
+buffer_zero_lsx,
+#endif
+#ifdef CONFIG_LASX_OPT
+buffer_zero_lasx,
+#endif
+};
+
+static unsigned best_accel(void)
+{
+unsigned info = cpuinfo_init();
+
+/* CONFIG_LSX_OPT must be enabled if CONFIG_LASX_OPT is enabled */
+#ifdef CONFIG_LASX_OPT
+if (info & CPUINFO_LASX) {
+return 2;
+}
+#endif
+
+#ifdef CONFIG_LSX_OPT
+if (info & CPUINFO_LSX) {
+return 1;
+}
+#endif
+
+return 0;
+}
 #else
 #define best_accel() 0
 static biz_accel_fn const accel_table[1] = {
-- 
2.39.3




[PATCH 1/2] util: Add lasx cpuinfo for loongarch64

2024-06-05 Thread Bibo Mao
Lasx is 256bit vector FPU capability, lsx is 128bit vector VFP. lsx
is added already, lasx is added here.

Signed-off-by: Bibo Mao 
---
 host/include/loongarch64/host/cpuinfo.h | 1 +
 util/cpuinfo-loongarch.c| 1 +
 2 files changed, 2 insertions(+)

diff --git a/host/include/loongarch64/host/cpuinfo.h 
b/host/include/loongarch64/host/cpuinfo.h
index fab664a10b..d7bf27501d 100644
--- a/host/include/loongarch64/host/cpuinfo.h
+++ b/host/include/loongarch64/host/cpuinfo.h
@@ -8,6 +8,7 @@
 
 #define CPUINFO_ALWAYS  (1u << 0)  /* so cpuinfo is nonzero */
 #define CPUINFO_LSX (1u << 1)
+#define CPUINFO_LASX(1u << 2)
 
 /* Initialized with a constructor. */
 extern unsigned cpuinfo;
diff --git a/util/cpuinfo-loongarch.c b/util/cpuinfo-loongarch.c
index 08b6d7460c..bb1f7f698b 100644
--- a/util/cpuinfo-loongarch.c
+++ b/util/cpuinfo-loongarch.c
@@ -29,6 +29,7 @@ unsigned __attribute__((constructor)) cpuinfo_init(void)
 
 info = CPUINFO_ALWAYS;
 info |= (hwcap & HWCAP_LOONGARCH_LSX ? CPUINFO_LSX : 0);
+info |= (hwcap & HWCAP_LOONGARCH_LASX ? CPUINFO_LASX : 0);
 
 cpuinfo = info;
 return info;
-- 
2.39.3




[RFC v3 1/2] target/loongarch: Add loongson binary translation feature

2024-05-30 Thread Bibo Mao
Loongson Binary Translation (LBT) is used to accelerate binary
translation, which contains 4 scratch registers (scr0 to scr3), x86/ARM
eflags (eflags) and x87 fpu stack pointer (ftop).

Now LBT feature is added in kvm mode, not supported in TCG mode since
it is not emulated. Feature variable lbt is added with OnOffAuto type,
If lbt feature is not supported with KVM host, it reports error if there
is lbt=on command line.

If there is no any command line about lbt parameter, it checks whether
KVM host supports lbt feature and set the corresponding value in cpucfg.

Signed-off-by: Bibo Mao 
---
 target/loongarch/cpu.c| 53 +++
 target/loongarch/cpu.h|  6 +++
 target/loongarch/kvm/kvm.c| 26 +
 target/loongarch/kvm/kvm_loongarch.h  | 16 
 target/loongarch/loongarch-qmp-cmds.c |  2 +-
 5 files changed, 102 insertions(+), 1 deletion(-)

diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index b5c1ec94af..14265b6667 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -571,6 +571,30 @@ static void loongarch_cpu_disas_set_info(CPUState *s, 
disassemble_info *info)
 info->print_insn = print_insn_loongarch;
 }
 
+static void loongarch_cpu_check_lbt(CPUState *cs, Error **errp)
+{
+CPULoongArchState *env = cpu_env(cs);
+LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+bool kvm_supported;
+
+kvm_supported = kvm_feature_supported(cs, LOONGARCH_FEATURE_LBT);
+if (cpu->lbt == ON_OFF_AUTO_ON) {
+if (kvm_supported) {
+env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LBT_ALL, 7);
+} else {
+error_setg(errp, "'lbt' feature not supported by KVM on this 
host");
+return;
+}
+} else if ((cpu->lbt == ON_OFF_AUTO_AUTO) && kvm_supported) {
+env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LBT_ALL, 7);
+}
+}
+
+static void loongarch_cpu_feature_realize(CPUState *cs, Error **errp)
+{
+loongarch_cpu_check_lbt(cs, errp);
+}
+
 static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp)
 {
 CPUState *cs = CPU(dev);
@@ -584,6 +608,11 @@ static void loongarch_cpu_realizefn(DeviceState *dev, 
Error **errp)
 }
 
 loongarch_cpu_register_gdb_regs_for_features(cs);
+loongarch_cpu_feature_realize(cs, _err);
+if (local_err != NULL) {
+error_propagate(errp, local_err);
+return;
+}
 
 cpu_reset(cs);
 qemu_init_vcpu(cs);
@@ -643,12 +672,36 @@ static void loongarch_set_lasx(Object *obj, bool value, 
Error **errp)
 }
 }
 
+static bool loongarch_get_lbt(Object *obj, Error **errp)
+{
+return LOONGARCH_CPU(obj)->lbt != ON_OFF_AUTO_OFF;
+}
+
+static void loongarch_set_lbt(Object *obj, bool value, Error **errp)
+{
+LoongArchCPU *cpu = LOONGARCH_CPU(obj);
+
+cpu->lbt = value ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
+}
+
 void loongarch_cpu_post_init(Object *obj)
 {
+LoongArchCPU *cpu = LOONGARCH_CPU(obj);
+
 object_property_add_bool(obj, "lsx", loongarch_get_lsx,
  loongarch_set_lsx);
 object_property_add_bool(obj, "lasx", loongarch_get_lasx,
  loongarch_set_lasx);
+/* lbt is enabled only in kvm mode, not supported in tcg mode */
+if (kvm_enabled()) {
+cpu->lbt = ON_OFF_AUTO_AUTO;
+object_property_add_bool(obj, "lbt", loongarch_get_lbt,
+ loongarch_set_lbt);
+object_property_set_description(obj, "lbt",
+   "Set off to disable Binary Tranlation.");
+} else {
+cpu->lbt = ON_OFF_AUTO_OFF;
+}
 }
 
 static void loongarch_cpu_init(Object *obj)
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index 41b8e6d96d..623b96b184 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -152,6 +152,7 @@ FIELD(CPUCFG2, LLFTP_VER, 15, 3)
 FIELD(CPUCFG2, LBT_X86, 18, 1)
 FIELD(CPUCFG2, LBT_ARM, 19, 1)
 FIELD(CPUCFG2, LBT_MIPS, 20, 1)
+FIELD(CPUCFG2, LBT_ALL, 18, 3)
 FIELD(CPUCFG2, LSPW, 21, 1)
 FIELD(CPUCFG2, LAM, 22, 1)
 
@@ -280,6 +281,10 @@ struct LoongArchTLB {
 typedef struct LoongArchTLB LoongArchTLB;
 #endif
 
+enum loongarch_features {
+LOONGARCH_FEATURE_LBT, /* loongson binary translation extension */
+};
+
 typedef struct CPUArchState {
 uint64_t gpr[32];
 uint64_t pc;
@@ -380,6 +385,7 @@ struct ArchCPU {
 CPULoongArchState env;
 QEMUTimer timer;
 uint32_t  phy_id;
+OnOffAuto lbt;
 
 /* 'compatible' string for this CPU for Linux device trees */
 const char *dtb_compatible;
diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
index 8e6e27c8bf..55e85eff15 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -780,6 +780,32 @@ int kvm_loongarch_set_interrupt(LoongArchCPU *cpu, int 
irq, int level)
 return kvm_vc

[RFC v3 0/2] target/loongarch: Add loongson binary translation feature

2024-05-30 Thread Bibo Mao
Loongson Binary Translation (LBT) is used to accelerate binary
translation. LBT feature is added in kvm mode, not supported in TCG
mode since it is not emulated.

Here lbt=on/off property is added to parse command line to
enable/disable lbt feature. Also fix registers relative lbt are saved
and restored during migration.

It depends LBT support on kvm side, and it is listed at
https://lore.kernel.org/kvm/20240527074644.836699-1-maob...@loongson.cn/

---
v2 ... v3:
  1. Property lbt is added only if kvm is enabled
  2. Use feature variable lbt with OnOffAuto type, rather than feature
bitmap flags default_features and forced_features

v1 ... v2:
  1. Add LBT register saving and restoring in vmstate
  2. Add two pseudo feature flags: default_features and forced_features
---
Bibo Mao (2):
  target/loongarch: Add loongson binary translation feature
  target/loongarch: Implement lbt registers save/restore function

 target/loongarch/cpu.c| 53 ++
 target/loongarch/cpu.h| 18 +++
 target/loongarch/kvm/kvm.c| 78 +++
 target/loongarch/kvm/kvm_loongarch.h  | 16 ++
 target/loongarch/loongarch-qmp-cmds.c |  2 +-
 target/loongarch/machine.c| 24 +
 6 files changed, 190 insertions(+), 1 deletion(-)


base-commit: 3b2fe44bb7f605f179e5e7feb2c13c2eb3abbb80
-- 
2.39.3




[RFC v3 2/2] target/loongarch: Implement lbt registers save/restore function

2024-05-30 Thread Bibo Mao
Six registers scr0 - scr3, eflags and ftop are added in percpu vmstate.
And two functions kvm_loongarch_get_lbt/kvm_loongarch_put_lbt are added
to save/restore lbt registers.

Signed-off-by: Bibo Mao 
---
 target/loongarch/cpu.h | 12 +
 target/loongarch/kvm/kvm.c | 52 ++
 target/loongarch/machine.c | 24 ++
 3 files changed, 88 insertions(+)

diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index 623b96b184..93c97d5e23 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -285,6 +285,17 @@ enum loongarch_features {
 LOONGARCH_FEATURE_LBT, /* loongson binary translation extension */
 };
 
+typedef struct  LoongArchBT {
+/* scratch registers */
+uint64_t scr0;
+uint64_t scr1;
+uint64_t scr2;
+uint64_t scr3;
+/* loongarch eflags */
+uint64_t eflags;
+uint64_t ftop;
+} lbt_t;
+
 typedef struct CPUArchState {
 uint64_t gpr[32];
 uint64_t pc;
@@ -292,6 +303,7 @@ typedef struct CPUArchState {
 fpr_t fpr[32];
 bool cf[8];
 uint32_t fcsr0;
+lbt_t  lbt;
 
 uint32_t cpucfg[21];
 
diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
index 55e85eff15..c9c240a573 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -475,6 +475,48 @@ static int kvm_loongarch_put_regs_fp(CPUState *cs)
 return ret;
 }
 
+static int kvm_loongarch_put_lbt(CPUState *cs)
+{
+CPULoongArchState *env = cpu_env(cs);
+int ret;
+
+/* check whether vm support LBT firstly */
+if (FIELD_EX32(env->cpucfg[2], CPUCFG2, LBT_ALL) != 7) {
+return 0;
+}
+
+/* set six LBT registers including scr0-scr3, eflags, ftop */
+ret = kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR0, >lbt.scr0);
+ret |= kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR1, >lbt.scr1);
+ret |= kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR2, >lbt.scr2);
+ret |= kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR3, >lbt.scr3);
+ret |= kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_EFLAGS, >lbt.eflags);
+ret |= kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_FTOP, >lbt.ftop);
+
+return ret;
+}
+
+static int kvm_loongarch_get_lbt(CPUState *cs)
+{
+CPULoongArchState *env = cpu_env(cs);
+int ret;
+
+/* check whether vm support LBT firstly */
+if (FIELD_EX32(env->cpucfg[2], CPUCFG2, LBT_ALL) != 7) {
+return 0;
+}
+
+/* get six LBT registers including scr0-scr3, eflags, ftop */
+ret = kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR0, >lbt.scr0);
+ret |= kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR1, >lbt.scr1);
+ret |= kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR2, >lbt.scr2);
+ret |= kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR3, >lbt.scr3);
+ret |= kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_EFLAGS, >lbt.eflags);
+ret |= kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_FTOP, >lbt.ftop);
+
+return ret;
+}
+
 void kvm_arch_reset_vcpu(CPULoongArchState *env)
 {
 env->mp_state = KVM_MP_STATE_RUNNABLE;
@@ -608,6 +650,11 @@ int kvm_arch_get_registers(CPUState *cs)
 return ret;
 }
 
+ret = kvm_loongarch_get_lbt(cs);
+if (ret) {
+return ret;
+}
+
 ret = kvm_loongarch_get_mpstate(cs);
 return ret;
 }
@@ -636,6 +683,11 @@ int kvm_arch_put_registers(CPUState *cs, int level)
 return ret;
 }
 
+ret = kvm_loongarch_put_lbt(cs);
+if (ret) {
+return ret;
+}
+
 ret = kvm_loongarch_put_mpstate(cs);
 return ret;
 }
diff --git a/target/loongarch/machine.c b/target/loongarch/machine.c
index 08a7fa5370..a371d5a2ab 100644
--- a/target/loongarch/machine.c
+++ b/target/loongarch/machine.c
@@ -110,6 +110,29 @@ static const VMStateDescription vmstate_lasx = {
 },
 };
 
+static bool lbt_needed(void *opaque)
+{
+LoongArchCPU *cpu = opaque;
+
+return !!FIELD_EX64(cpu->env.cpucfg[2], CPUCFG2, LBT_ALL);
+}
+
+static const VMStateDescription vmstate_lbt = {
+.name = "cpu/lbt",
+.version_id = 0,
+.minimum_version_id = 0,
+.needed = lbt_needed,
+.fields = (const VMStateField[]) {
+VMSTATE_UINT64(env.lbt.scr0,   LoongArchCPU),
+VMSTATE_UINT64(env.lbt.scr1,   LoongArchCPU),
+VMSTATE_UINT64(env.lbt.scr2,   LoongArchCPU),
+VMSTATE_UINT64(env.lbt.scr3,   LoongArchCPU),
+VMSTATE_UINT64(env.lbt.eflags, LoongArchCPU),
+VMSTATE_UINT64(env.lbt.ftop,   LoongArchCPU),
+VMSTATE_END_OF_LIST()
+},
+};
+
 #if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY)
 static bool tlb_needed(void *opaque)
 {
@@ -219,6 +242,7 @@ const VMStateDescription vmstate_loongarch_cpu = {
 #if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY)
 _tlb,
 #endif
+_lbt,
 NULL
 }
 };
-- 
2.39.3




[PATCH v2] tests/libqos: Add loongarch virt machine node

2024-05-29 Thread Bibo Mao
Add loongarch virt machine to the graph. It is a modified copy of
the existing riscv virtmachine in riscv-virt-machine.c

It contains a generic-pcihost controller, and an extra function
loongarch_config_qpci_bus() to configure GPEX pci host controller
information, such as ecam and pio_base addresses.

Also hotplug handle checking about TYPE_VIRTIO_IOMMU_PCI device is
added on loongarch virt machine, since virtio_mmu_pci device requires
it.

Signed-off-by: Bibo Mao 
Acked-by: Thomas Huth 

---
v1 ... v2:
  1. Update copyright licence notation with file loongarch-virt-machine.c
---

 hw/loongarch/virt.c |   2 +
 tests/qtest/libqos/loongarch-virt-machine.c | 115 
 tests/qtest/libqos/meson.build  |   1 +
 3 files changed, 118 insertions(+)
 create mode 100644 tests/qtest/libqos/loongarch-virt-machine.c

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 3e6e93edf3..2d7f718570 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -45,6 +45,7 @@
 #include "sysemu/tpm.h"
 #include "sysemu/block-backend.h"
 #include "hw/block/flash.h"
+#include "hw/virtio/virtio-iommu.h"
 #include "qemu/error-report.h"
 
 static PFlashCFI01 *virt_flash_create1(LoongArchVirtMachineState *lvms,
@@ -1213,6 +1214,7 @@ static HotplugHandler 
*virt_get_hotplug_handler(MachineState *machine,
 MachineClass *mc = MACHINE_GET_CLASS(machine);
 
 if (device_is_dynamic_sysbus(mc, dev) ||
+object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_IOMMU_PCI) ||
 memhp_type_supported(dev)) {
 return HOTPLUG_HANDLER(machine);
 }
diff --git a/tests/qtest/libqos/loongarch-virt-machine.c 
b/tests/qtest/libqos/loongarch-virt-machine.c
new file mode 100644
index 00..1eece28eba
--- /dev/null
+++ b/tests/qtest/libqos/loongarch-virt-machine.c
@@ -0,0 +1,115 @@
+/*
+ * libqos driver framework
+ *
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito 
+ * Copyright (c) 2024 Loongson Technology Corporation Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "qemu/osdep.h"
+#include "../libqtest.h"
+#include "qemu/module.h"
+#include "libqos-malloc.h"
+#include "qgraph.h"
+#include "virtio-mmio.h"
+#include "generic-pcihost.h"
+#include "hw/pci/pci_regs.h"
+
+#define LOONGARCH_PAGE_SIZE   0x1000
+#define LOONGARCH_VIRT_RAM_ADDR   0x10
+#define LOONGARCH_VIRT_RAM_SIZE   0xFF0
+
+#define LOONGARCH_VIRT_PIO_BASE   0x1800
+#define LOONGARCH_VIRT_PCIE_PIO_OFFSET0x4000
+#define LOONGARCH_VIRT_PCIE_PIO_LIMIT 0x1
+#define LOONGARCH_VIRT_PCIE_ECAM_BASE 0x2000
+#define LOONGARCH_VIRT_PCIE_MMIO32_BASE   0x4000
+#define LOONGARCH_VIRT_PCIE_MMIO32_LIMIT  0x8000
+
+typedef struct QVirtMachine QVirtMachine;
+
+struct QVirtMachine {
+QOSGraphObject obj;
+QGuestAllocator alloc;
+QVirtioMMIODevice virtio_mmio;
+QGenericPCIHost bridge;
+};
+
+static void virt_destructor(QOSGraphObject *obj)
+{
+QVirtMachine *machine = (QVirtMachine *) obj;
+alloc_destroy(>alloc);
+}
+
+static void *virt_get_driver(void *object, const char *interface)
+{
+QVirtMachine *machine = object;
+if (!g_strcmp0(interface, "memory")) {
+return >alloc;
+}
+
+fprintf(stderr, "%s not present in loongarch/virtio\n", interface);
+g_assert_not_reached();
+}
+
+static QOSGraphObject *virt_get_device(void *obj, const char *device)
+{
+QVirtMachine *machine = obj;
+if (!g_strcmp0(device, "generic-pcihost")) {
+return >bridge.obj;
+} else if (!g_strcmp0(device, "virtio-mmio")) {
+return >virtio_mmio.obj;
+}
+
+fprintf(stderr, "%s not present in loongarch/virt\n", device);
+g_assert_not_reached();
+}
+
+static void loongarch_config_qpci_bus(QGenericPCIBus *qpci)
+{
+qpci->gpex_pio_base = LOONGARCH_VIRT_PIO_BASE;
+qpci->bus.pio_alloc_ptr = LOONGARCH_VIRT_PCIE_PIO_OFFSET;
+qpci->bus.pio_limit = LOONGARCH_VIRT_PCIE_PIO_LIMIT;
+qpci->bus.mmio_alloc_ptr = LOONGARCH_VIRT_PCIE_MMIO32_BASE;
+qpci->bus.mmio_limit = LOONGARCH_VIRT_PCIE_MMIO32_LIMIT;
+qpci->ecam_alloc_ptr = LOONGARCH_VIRT_PCIE_ECAM_BASE;
+}
+
+static void *q

[PATCH] tests/qtest: Add numa test for loongarch system

2024-05-28 Thread Bibo Mao
Add numa test case for loongarch system, it passes to run
with command "make check-qtest".

Signed-off-by: Bibo Mao 
---
 tests/qtest/meson.build |  2 +-
 tests/qtest/numa-test.c | 53 +
 2 files changed, 54 insertions(+), 1 deletion(-)

diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index b98fae6a6d..12792948ff 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -140,7 +140,7 @@ qtests_hppa = ['boot-serial-test'] + \
   (config_all_devices.has_key('CONFIG_VGA') ? ['display-vga-test'] : [])
 
 qtests_loongarch64 = qtests_filter + \
-  ['boot-serial-test']
+  ['boot-serial-test', 'numa-test']
 
 qtests_m68k = ['boot-serial-test'] + \
   qtests_filter
diff --git a/tests/qtest/numa-test.c b/tests/qtest/numa-test.c
index 7aa262dbb9..5518f6596b 100644
--- a/tests/qtest/numa-test.c
+++ b/tests/qtest/numa-test.c
@@ -265,6 +265,54 @@ static void aarch64_numa_cpu(const void *data)
 qtest_quit(qts);
 }
 
+static void loongarch64_numa_cpu(const void *data)
+{
+QDict *resp;
+QList *cpus;
+QObject *e;
+QTestState *qts;
+g_autofree char *cli = NULL;
+
+cli = make_cli(data, "-machine "
+"smp.cpus=2,smp.sockets=2,smp.cores=1,smp.threads=1 "
+"-numa node,nodeid=0,memdev=ram -numa node,nodeid=1 "
+"-numa cpu,node-id=0,socket-id=1,core-id=0,thread-id=0 "
+"-numa cpu,node-id=1,socket-id=0,core-id=0,thread-id=0");
+qts = qtest_init(cli);
+cpus = get_cpus(qts, );
+g_assert(cpus);
+
+while ((e = qlist_pop(cpus))) {
+QDict *cpu, *props;
+int64_t socket, core, thread, node;
+
+cpu = qobject_to(QDict, e);
+g_assert(qdict_haskey(cpu, "props"));
+props = qdict_get_qdict(cpu, "props");
+
+g_assert(qdict_haskey(props, "node-id"));
+node = qdict_get_int(props, "node-id");
+g_assert(qdict_haskey(props, "socket-id"));
+socket = qdict_get_int(props, "socket-id");
+g_assert(qdict_haskey(props, "core-id"));
+core = qdict_get_int(props, "core-id");
+g_assert(qdict_haskey(props, "thread-id"));
+thread = qdict_get_int(props, "thread-id");
+
+if (socket == 0 && core == 0 && thread == 0) {
+g_assert_cmpint(node, ==, 1);
+} else if (socket == 1 && core == 0 && thread == 0) {
+g_assert_cmpint(node, ==, 0);
+} else {
+g_assert(false);
+}
+qobject_unref(e);
+}
+
+qobject_unref(resp);
+qtest_quit(qts);
+}
+
 static void pc_dynamic_cpu_cfg(const void *data)
 {
 QObject *e;
@@ -593,6 +641,11 @@ int main(int argc, char **argv)
 aarch64_numa_cpu);
 }
 
+if (!strcmp(arch, "loongarch64")) {
+qtest_add_data_func("/numa/loongarch64/cpu/explicit", args,
+loongarch64_numa_cpu);
+}
+
 out:
 return g_test_run();
 }
-- 
2.39.3




[PATCH] tests/libqos: Add loongarch virt machine node

2024-05-28 Thread Bibo Mao
Add loongarch virt machine to the graph. It is a modified copy of
the existing riscv virtmachine in riscv-virt-machine.c

It contains a generic-pcihost controller, and an extra function
loongarch_config_qpci_bus() to configure GPEX pci host controller
information, such as ecam and pio_base addresses.

Also hotplug handle checking about TYPE_VIRTIO_IOMMU_PCI device is
added on loongarch virt machine, since virtio_mmu_pci device requires
it.

Signed-off-by: Bibo Mao 
---
 hw/loongarch/virt.c |   2 +
 tests/qtest/libqos/loongarch-virt-machine.c | 114 
 tests/qtest/libqos/meson.build  |   1 +
 3 files changed, 117 insertions(+)
 create mode 100644 tests/qtest/libqos/loongarch-virt-machine.c

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 3e6e93edf3..2d7f718570 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -45,6 +45,7 @@
 #include "sysemu/tpm.h"
 #include "sysemu/block-backend.h"
 #include "hw/block/flash.h"
+#include "hw/virtio/virtio-iommu.h"
 #include "qemu/error-report.h"
 
 static PFlashCFI01 *virt_flash_create1(LoongArchVirtMachineState *lvms,
@@ -1213,6 +1214,7 @@ static HotplugHandler 
*virt_get_hotplug_handler(MachineState *machine,
 MachineClass *mc = MACHINE_GET_CLASS(machine);
 
 if (device_is_dynamic_sysbus(mc, dev) ||
+object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_IOMMU_PCI) ||
 memhp_type_supported(dev)) {
 return HOTPLUG_HANDLER(machine);
 }
diff --git a/tests/qtest/libqos/loongarch-virt-machine.c 
b/tests/qtest/libqos/loongarch-virt-machine.c
new file mode 100644
index 00..c12089c015
--- /dev/null
+++ b/tests/qtest/libqos/loongarch-virt-machine.c
@@ -0,0 +1,114 @@
+/*
+ * libqos driver framework
+ *
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito 
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "qemu/osdep.h"
+#include "../libqtest.h"
+#include "qemu/module.h"
+#include "libqos-malloc.h"
+#include "qgraph.h"
+#include "virtio-mmio.h"
+#include "generic-pcihost.h"
+#include "hw/pci/pci_regs.h"
+
+#define LOONGARCH_PAGE_SIZE   0x1000
+#define LOONGARCH_VIRT_RAM_ADDR   0x10
+#define LOONGARCH_VIRT_RAM_SIZE   0xFF0
+
+#define LOONGARCH_VIRT_PIO_BASE   0x1800
+#define LOONGARCH_VIRT_PCIE_PIO_OFFSET0x4000
+#define LOONGARCH_VIRT_PCIE_PIO_LIMIT 0x1
+#define LOONGARCH_VIRT_PCIE_ECAM_BASE 0x2000
+#define LOONGARCH_VIRT_PCIE_MMIO32_BASE   0x4000
+#define LOONGARCH_VIRT_PCIE_MMIO32_LIMIT  0x8000
+
+typedef struct QVirtMachine QVirtMachine;
+
+struct QVirtMachine {
+QOSGraphObject obj;
+QGuestAllocator alloc;
+QVirtioMMIODevice virtio_mmio;
+QGenericPCIHost bridge;
+};
+
+static void virt_destructor(QOSGraphObject *obj)
+{
+QVirtMachine *machine = (QVirtMachine *) obj;
+alloc_destroy(>alloc);
+}
+
+static void *virt_get_driver(void *object, const char *interface)
+{
+QVirtMachine *machine = object;
+if (!g_strcmp0(interface, "memory")) {
+return >alloc;
+}
+
+fprintf(stderr, "%s not present in loongarch/virtio\n", interface);
+g_assert_not_reached();
+}
+
+static QOSGraphObject *virt_get_device(void *obj, const char *device)
+{
+QVirtMachine *machine = obj;
+if (!g_strcmp0(device, "generic-pcihost")) {
+return >bridge.obj;
+} else if (!g_strcmp0(device, "virtio-mmio")) {
+return >virtio_mmio.obj;
+}
+
+fprintf(stderr, "%s not present in loongarch/virt\n", device);
+g_assert_not_reached();
+}
+
+static void loongarch_config_qpci_bus(QGenericPCIBus *qpci)
+{
+qpci->gpex_pio_base = LOONGARCH_VIRT_PIO_BASE;
+qpci->bus.pio_alloc_ptr = LOONGARCH_VIRT_PCIE_PIO_OFFSET;
+qpci->bus.pio_limit = LOONGARCH_VIRT_PCIE_PIO_LIMIT;
+qpci->bus.mmio_alloc_ptr = LOONGARCH_VIRT_PCIE_MMIO32_BASE;
+qpci->bus.mmio_limit = LOONGARCH_VIRT_PCIE_MMIO32_LIMIT;
+qpci->ecam_alloc_ptr = LOONGARCH_VIRT_PCIE_ECAM_BASE;
+}
+
+static void *qos_create_machine_loongarch_virt(QTestState *qts)
+{
+QVirtMachine *machine = g_new0(QVirtMachine, 1);
+
+alloc_init(>alloc, 0,
+   LOONGARCH_VIRT_RAM_ADDR,
+   LO

[RFC ] target/loongarch: Add steal time physical address in vmstate

2024-05-27 Thread Bibo Mao
With pv steal time supported, VM machine needs get physical address
of each vcpu and notify to new host during migration. Here two
functions kvm_loongarch_get_stealtime/kvm_loongarch_put_stealtime
are provided and they are called in cpu_pre_save/cpu_post_load
separately.

Signed-off-by: Bibo Mao 
---
 target/loongarch/cpu.h   |  3 ++
 target/loongarch/kvm/kvm.c   | 49 
 target/loongarch/kvm/kvm_loongarch.h | 12 +++
 target/loongarch/machine.c   | 24 +-
 4 files changed, 87 insertions(+), 1 deletion(-)

diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index 8fc99b8ee8..66e9dd227e 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -390,6 +390,9 @@ typedef struct CPUArchState {
 
 struct loongarch_boot_info *boot_info;
 #endif
+struct {
+uint64_t guest_addr;
+} st;
 } CPULoongArchState;
 
 /**
diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
index c9c240a573..c7f1b262dd 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -626,6 +626,55 @@ static int kvm_loongarch_put_cpucfg(CPUState *cs)
 return ret;
 }
 
+int kvm_loongarch_get_stealtime(LoongArchCPU *cpu)
+{
+CPULoongArchState *env = >env;
+int err;
+struct kvm_device_attr attr = {
+.group = KVM_LOONGARCH_VCPU_PVTIME_CTRL,
+.attr = KVM_LOONGARCH_VCPU_PVTIME_GPA,
+.addr = (uint64_t)>st.guest_addr,
+};
+
+err = kvm_vcpu_ioctl(CPU(cpu), KVM_HAS_DEVICE_ATTR, attr);
+if (err) {
+return 0;
+}
+
+err = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_DEVICE_ATTR, attr);
+if (err) {
+error_report("PVTIME: KVM_GET_DEVICE_ATTR: %s", strerror(errno));
+return err;
+}
+
+return 0;
+}
+
+int kvm_loongarch_put_stealtime(LoongArchCPU *cpu)
+{
+CPULoongArchState *env = >env;
+int err;
+struct kvm_device_attr attr = {
+.group = KVM_LOONGARCH_VCPU_PVTIME_CTRL,
+.attr = KVM_LOONGARCH_VCPU_PVTIME_GPA,
+.addr = (uint64_t)>st.guest_addr,
+};
+
+err = kvm_vcpu_ioctl(CPU(cpu), KVM_HAS_DEVICE_ATTR, attr);
+if (err) {
+return 0;
+}
+
+err = kvm_vcpu_ioctl(CPU(cpu), KVM_SET_DEVICE_ATTR, attr);
+if (err) {
+error_report("PVTIME: KVM_SET_DEVICE_ATTR %s with gpa "TARGET_FMT_lx,
+  strerror(errno), env->st.guest_addr);
+return err;
+}
+
+return 0;
+}
+
 int kvm_arch_get_registers(CPUState *cs)
 {
 int ret;
diff --git a/target/loongarch/kvm/kvm_loongarch.h 
b/target/loongarch/kvm/kvm_loongarch.h
index bdb4f180eb..d34a16515f 100644
--- a/target/loongarch/kvm/kvm_loongarch.h
+++ b/target/loongarch/kvm/kvm_loongarch.h
@@ -12,6 +12,8 @@
 
 int  kvm_loongarch_set_interrupt(LoongArchCPU *cpu, int irq, int level);
 void kvm_arch_reset_vcpu(CPULoongArchState *env);
+int  kvm_loongarch_get_stealtime(LoongArchCPU *cpu);
+int  kvm_loongarch_put_stealtime(LoongArchCPU *cpu);
 
 #ifdef CONFIG_KVM
 /*
@@ -27,6 +29,16 @@ static inline bool kvm_feature_supported(CPUState *cs,
 {
 return false;
 }
+
+static inline int kvm_loongarch_get_stealtime(LoongArchCPU *cpu)
+{
+return 0;
+}
+
+static inline int kvm_loongarch_put_stealtime(LoongArchCPU *cpu)
+{
+return 0;
+}
 #endif
 
 #endif
diff --git a/target/loongarch/machine.c b/target/loongarch/machine.c
index a371d5a2ab..344913703b 100644
--- a/target/loongarch/machine.c
+++ b/target/loongarch/machine.c
@@ -7,7 +7,9 @@
 
 #include "qemu/osdep.h"
 #include "cpu.h"
+#include "kvm/kvm_loongarch.h"
 #include "migration/cpu.h"
+#include "sysemu/kvm.h"
 #include "sysemu/tcg.h"
 #include "vec.h"
 
@@ -165,11 +167,29 @@ static const VMStateDescription vmstate_tlb = {
 };
 #endif
 
+static int cpu_post_load(void *opaque, int version_id)
+{
+LoongArchCPU *cpu = opaque;
+
+kvm_loongarch_put_stealtime(cpu);
+return 0;
+}
+
+static int cpu_pre_save(void *opaque)
+{
+LoongArchCPU *cpu = opaque;
+
+kvm_loongarch_get_stealtime(cpu);
+return 0;
+}
+
 /* LoongArch CPU state */
 const VMStateDescription vmstate_loongarch_cpu = {
 .name = "cpu",
-.version_id = 2,
+.version_id = 3,
 .minimum_version_id = 2,
+.post_load = cpu_post_load,
+.pre_save = cpu_pre_save,
 .fields = (const VMStateField[]) {
 VMSTATE_UINTTL_ARRAY(env.gpr, LoongArchCPU, 32),
 VMSTATE_UINTTL(env.pc, LoongArchCPU),
@@ -232,6 +252,8 @@ const VMStateDescription vmstate_loongarch_cpu = {
 VMSTATE_UINT64(env.CSR_DSAVE, LoongArchCPU),
 
 VMSTATE_UINT64(kvm_state_counter, LoongArchCPU),
+/* PV steal time */
+VMSTATE_UINT64(env.st.guest_addr, LoongArchCPU),
 
 VMSTATE_END_OF_LIST()
 },

base-commit: ffdd099a782556b9ead26551a6f1d070a595306d
-- 
2.39.3




[RFC v2 1/2] target/loongarch: Add loongson binary translation feature

2024-05-27 Thread Bibo Mao
Loongson Binary Translation (LBT) is used to accelerate binary
translation, which contains 4 scratch registers (scr0 to scr3), x86/ARM
eflags (eflags) and x87 fpu stack pointer (ftop).

Now LBT feature is added in kvm mode, not supported in TCG mode since
it is not emulated. There are two feature flags such as forced_features
and default_features for each vcpu, the real feature is still in cpucfg.
Flag forced_features is parsed from command line, default_features is
parsed from cpu type.

Flag forced_features has higher priority than flag default_features,
default_features will be used if there is no command line option for LBT
feature. If the feature is not supported with KVM host, it reports error
and exits if forced_features is set, else it disables feature and continues
if default_features is set.

Signed-off-by: Bibo Mao 
---
 target/loongarch/cpu.c| 69 +++
 target/loongarch/cpu.h| 12 +
 target/loongarch/kvm/kvm.c| 26 ++
 target/loongarch/kvm/kvm_loongarch.h  | 16 +++
 target/loongarch/loongarch-qmp-cmds.c |  2 +-
 5 files changed, 124 insertions(+), 1 deletion(-)

diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index b5c1ec94af..d9d601da07 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -380,6 +380,8 @@ static void loongarch_la464_initfn(Object *obj)
 CPULoongArchState *env = >env;
 int i;
 
+env->default_features = 0;
+env->forced_features  = 0;
 for (i = 0; i < 21; i++) {
 env->cpucfg[i] = 0x0;
 }
@@ -413,6 +415,7 @@ static void loongarch_la464_initfn(Object *obj)
 data = FIELD_DP32(data, CPUCFG2, LSPW, 1);
 data = FIELD_DP32(data, CPUCFG2, LAM, 1);
 env->cpucfg[2] = data;
+env->default_features |= BIT_ULL(LOONGARCH_FEATURE_LBT);
 
 env->cpucfg[4] = 100 * 1000 * 1000; /* Crystal frequency */
 
@@ -571,6 +574,35 @@ static void loongarch_cpu_disas_set_info(CPUState *s, 
disassemble_info *info)
 info->print_insn = print_insn_loongarch;
 }
 
+static void loongarch_cpu_check_lbt(CPUState *cs, Error **errp)
+{
+CPULoongArchState *env = cpu_env(cs);
+enum loongarch_features feature;
+bool kvm_supported;
+
+feature = LOONGARCH_FEATURE_LBT;
+kvm_supported = kvm_feature_supported(cs, feature);
+if (env->forced_features & BIT_ULL(feature)) {
+if (kvm_supported) {
+env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LBT_ALL, 7);
+} else {
+error_setg(errp, "'lbt' feature not supported by KVM on this 
host");
+return;
+}
+} else if (env->default_features & BIT_ULL(feature)) {
+if (kvm_supported) {
+env->cpucfg[2] = FIELD_DP32(env->cpucfg[2], CPUCFG2, LBT_ALL, 7);
+}
+}
+}
+
+static void loongarch_cpu_feature_realize(CPUState *cs, Error **errp)
+{
+if (kvm_enabled()) {
+loongarch_cpu_check_lbt(cs, errp);
+}
+}
+
 static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp)
 {
 CPUState *cs = CPU(dev);
@@ -584,6 +616,11 @@ static void loongarch_cpu_realizefn(DeviceState *dev, 
Error **errp)
 }
 
 loongarch_cpu_register_gdb_regs_for_features(cs);
+loongarch_cpu_feature_realize(cs, _err);
+if (local_err != NULL) {
+error_propagate(errp, local_err);
+return;
+}
 
 cpu_reset(cs);
 qemu_init_vcpu(cs);
@@ -643,12 +680,44 @@ static void loongarch_set_lasx(Object *obj, bool value, 
Error **errp)
 }
 }
 
+static bool loongarch_get_lbt(Object *obj, Error **errp)
+ {
+LoongArchCPU *cpu = LOONGARCH_CPU(obj);
+bool ret;
+
+ret = false;
+/* lbt is enabled only in kvm mode, not supported in tcg mode */
+if (cpu->env.forced_features & BIT_ULL(LOONGARCH_FEATURE_LBT)) {
+ret = true;
+ }
+return ret;
+}
+
+static void loongarch_set_lbt(Object *obj, bool value, Error **errp)
+{
+LoongArchCPU *cpu = LOONGARCH_CPU(obj);
+
+if (!kvm_enabled()) {
+return;
+}
+
+if (value) {
+/* Enable binary translation for all architectures */
+cpu->env.forced_features |= BIT_ULL(LOONGARCH_FEATURE_LBT);
+} else {
+/* Disable default features also */
+cpu->env.default_features &= ~BIT_ULL(LOONGARCH_FEATURE_LBT);
+}
+}
+
 void loongarch_cpu_post_init(Object *obj)
 {
 object_property_add_bool(obj, "lsx", loongarch_get_lsx,
  loongarch_set_lsx);
 object_property_add_bool(obj, "lasx", loongarch_get_lasx,
  loongarch_set_lasx);
+object_property_add_bool(obj, "lbt", loongarch_get_lbt,
+ loongarch_set_lbt);
 }
 
 static void loongarch_cpu_init(Object *obj)
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index 41b8e6d96d..36fb160a8c 100644
--- a/target/loongarch/cpu.h
+++ b/targ

[RFC v2 0/2] target/loongarch: Add loongson binary translation feature

2024-05-27 Thread Bibo Mao
Loongson Binary Translation (LBT) is used to accelerate binary
translation. LBT feature is added in kvm mode, not supported in TCG
mode since it is not emulated. And only LBT feature is added here, LBT
registers saving and restoring is not supported since it depeeds on LBT
feautre implemented in KVM kernel

---
v1 ... v2:
  1. Add LBT register saving and restoring in vmstate
  2. Add two pseudo feature flags: default_features and forced_features.
---

Bibo Mao (2):
  target/loongarch: Add loongson binary translation feature
  target/loongarch: Implement lbt registers save/restore function

 target/loongarch/cpu.c| 69 
 target/loongarch/cpu.h| 24 +
 target/loongarch/kvm/kvm.c| 78 +++
 target/loongarch/kvm/kvm_loongarch.h  | 16 ++
 target/loongarch/loongarch-qmp-cmds.c |  2 +-
 target/loongarch/machine.c| 24 +
 6 files changed, 212 insertions(+), 1 deletion(-)


base-commit: ffdd099a782556b9ead26551a6f1d070a595306d
-- 
2.39.3




[RFC v2 2/2] target/loongarch: Implement lbt registers save/restore function

2024-05-27 Thread Bibo Mao
Six registers scr0 - scr3, eflags and ftop are added in percpu vmstate.
And two functions kvm_loongarch_get_lbt/kvm_loongarch_put_lbt are added
to save/restore lbt registers.

Signed-off-by: Bibo Mao 
---
 target/loongarch/cpu.h | 12 +
 target/loongarch/kvm/kvm.c | 52 ++
 target/loongarch/machine.c | 24 ++
 3 files changed, 88 insertions(+)

diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index 36fb160a8c..8fc99b8ee8 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -285,6 +285,17 @@ enum loongarch_features {
 LOONGARCH_FEATURE_LBT, /* loongson binary translation extension */
 };
 
+typedef struct  LoongArchBT {
+/* scratch registers */
+uint64_t scr0;
+uint64_t scr1;
+uint64_t scr2;
+uint64_t scr3;
+/* loongarch eflags */
+uint64_t eflags;
+uint64_t ftop;
+} lbt_t;
+
 typedef struct CPUArchState {
 uint64_t gpr[32];
 uint64_t pc;
@@ -292,6 +303,7 @@ typedef struct CPUArchState {
 fpr_t fpr[32];
 bool cf[8];
 uint32_t fcsr0;
+lbt_t  lbt;
 
 uint32_t cpucfg[21];
 /*
diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
index 55e85eff15..c9c240a573 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -475,6 +475,48 @@ static int kvm_loongarch_put_regs_fp(CPUState *cs)
 return ret;
 }
 
+static int kvm_loongarch_put_lbt(CPUState *cs)
+{
+CPULoongArchState *env = cpu_env(cs);
+int ret;
+
+/* check whether vm support LBT firstly */
+if (FIELD_EX32(env->cpucfg[2], CPUCFG2, LBT_ALL) != 7) {
+return 0;
+}
+
+/* set six LBT registers including scr0-scr3, eflags, ftop */
+ret = kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR0, >lbt.scr0);
+ret |= kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR1, >lbt.scr1);
+ret |= kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR2, >lbt.scr2);
+ret |= kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR3, >lbt.scr3);
+ret |= kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_EFLAGS, >lbt.eflags);
+ret |= kvm_set_one_reg(cs, KVM_REG_LOONGARCH_LBT_FTOP, >lbt.ftop);
+
+return ret;
+}
+
+static int kvm_loongarch_get_lbt(CPUState *cs)
+{
+CPULoongArchState *env = cpu_env(cs);
+int ret;
+
+/* check whether vm support LBT firstly */
+if (FIELD_EX32(env->cpucfg[2], CPUCFG2, LBT_ALL) != 7) {
+return 0;
+}
+
+/* get six LBT registers including scr0-scr3, eflags, ftop */
+ret = kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR0, >lbt.scr0);
+ret |= kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR1, >lbt.scr1);
+ret |= kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR2, >lbt.scr2);
+ret |= kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_SCR3, >lbt.scr3);
+ret |= kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_EFLAGS, >lbt.eflags);
+ret |= kvm_get_one_reg(cs, KVM_REG_LOONGARCH_LBT_FTOP, >lbt.ftop);
+
+return ret;
+}
+
 void kvm_arch_reset_vcpu(CPULoongArchState *env)
 {
 env->mp_state = KVM_MP_STATE_RUNNABLE;
@@ -608,6 +650,11 @@ int kvm_arch_get_registers(CPUState *cs)
 return ret;
 }
 
+ret = kvm_loongarch_get_lbt(cs);
+if (ret) {
+return ret;
+}
+
 ret = kvm_loongarch_get_mpstate(cs);
 return ret;
 }
@@ -636,6 +683,11 @@ int kvm_arch_put_registers(CPUState *cs, int level)
 return ret;
 }
 
+ret = kvm_loongarch_put_lbt(cs);
+if (ret) {
+return ret;
+}
+
 ret = kvm_loongarch_put_mpstate(cs);
 return ret;
 }
diff --git a/target/loongarch/machine.c b/target/loongarch/machine.c
index 08a7fa5370..aa2d3db601 100644
--- a/target/loongarch/machine.c
+++ b/target/loongarch/machine.c
@@ -110,6 +110,29 @@ static const VMStateDescription vmstate_lasx = {
 },
 };
 
+static bool lbt_needed(void *opaque)
+{
+LoongArchCPU *cpu = opaque;
+
+return !!FIELD_EX64(cpu->env.cpucfg[2], CPUCFG2, LBT_ALL);
+}
+
+static const VMStateDescription vmstate_lbt = {
+.name = "cpu/lbt",
+.version_id = 0,
+.minimum_version_id = 0,
+.needed = lbt_needed,
+.fields = (const VMStateField[]) {
+VMSTATE_UINT64(env.lbt.scr0,   LoongArchCPU),
+VMSTATE_UINT64(env.lbt.scr1,   LoongArchCPU),
+VMSTATE_UINT64(env.lbt.scr2,   LoongArchCPU),
+VMSTATE_UINT64(env.lbt.scr3,   LoongArchCPU),
+VMSTATE_UINT64(env.lbt.eflags, LoongArchCPU),
+VMSTATE_UINT64(env.lbt.ftop,   LoongArchCPU),
+VMSTATE_END_OF_LIST()
+},
+};
+
 #if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY)
 static bool tlb_needed(void *opaque)
 {
@@ -219,6 +242,7 @@ const VMStateDescription vmstate_loongarch_cpu = {
 #if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY)
 _tlb,
 #endif
+_lbt,
 NULL
 }
 };
-- 
2.39.3




[PATCH 2/2] target/loongarch: Add loongson binary translation feature

2024-05-21 Thread Bibo Mao
Loongson Binary Translation (LBT) is used to accelerate binary
translation, which contains 4 scratch registers (scr0 to scr3), x86/ARM
eflags (eflags) and x87 fpu stack pointer (ftop).

Now LBT feature is added in kvm mode, not supported in TCG mode since
it is not emulated. And only LBT feature is added here, LBT register
saving and restoring is not supported since it depeeds on LBT feautre
implemented in KVM kernel.

Signed-off-by: Bibo Mao 
---
 target/loongarch/cpu.c| 32 +++
 target/loongarch/cpu.h|  1 +
 target/loongarch/loongarch-qmp-cmds.c |  2 +-
 3 files changed, 34 insertions(+), 1 deletion(-)

diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index b5c1ec94af..84254c0f42 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -412,6 +412,9 @@ static void loongarch_la464_initfn(Object *obj)
 data = FIELD_DP32(data, CPUCFG2, LLFTP_VER, 1);
 data = FIELD_DP32(data, CPUCFG2, LSPW, 1);
 data = FIELD_DP32(data, CPUCFG2, LAM, 1);
+if (kvm_enabled()) {
+data = FIELD_DP32(data, CPUCFG2, LBT_ALL, 7);
+}
 env->cpucfg[2] = data;
 
 env->cpucfg[4] = 100 * 1000 * 1000; /* Crystal frequency */
@@ -643,12 +646,41 @@ static void loongarch_set_lasx(Object *obj, bool value, 
Error **errp)
 }
 }
 
+static bool loongarch_get_lbt(Object *obj, Error **errp)
+ {
+LoongArchCPU *cpu = LOONGARCH_CPU(obj);
+bool ret;
+
+ret = false;
+/* lbt is enabled only in kvm mode, not supported in tcg mode */
+if (kvm_enabled() &&
+(FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LBT_ALL) == 7)) {
+ret = true;
+ }
+return ret;
+}
+
+static void loongarch_set_lbt(Object *obj, bool value, Error **errp)
+{
+LoongArchCPU *cpu = LOONGARCH_CPU(obj);
+int lbt;
+
+lbt = 0;
+if (kvm_enabled() && value) {
+/* Enable binary translation for all architectures */
+lbt = 7;
+}
+cpu->env.cpucfg[2] = FIELD_DP32(cpu->env.cpucfg[2], CPUCFG2, LBT_ALL, lbt);
+}
+
 void loongarch_cpu_post_init(Object *obj)
 {
 object_property_add_bool(obj, "lsx", loongarch_get_lsx,
  loongarch_set_lsx);
 object_property_add_bool(obj, "lasx", loongarch_get_lasx,
  loongarch_set_lasx);
+object_property_add_bool(obj, "lbt", loongarch_get_lbt,
+ loongarch_set_lbt);
 }
 
 static void loongarch_cpu_init(Object *obj)
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index 41b8e6d96d..2021e85303 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -152,6 +152,7 @@ FIELD(CPUCFG2, LLFTP_VER, 15, 3)
 FIELD(CPUCFG2, LBT_X86, 18, 1)
 FIELD(CPUCFG2, LBT_ARM, 19, 1)
 FIELD(CPUCFG2, LBT_MIPS, 20, 1)
+FIELD(CPUCFG2, LBT_ALL, 18, 3)
 FIELD(CPUCFG2, LSPW, 21, 1)
 FIELD(CPUCFG2, LAM, 22, 1)
 
diff --git a/target/loongarch/loongarch-qmp-cmds.c 
b/target/loongarch/loongarch-qmp-cmds.c
index 8721a5eb13..c6f6e1ef85 100644
--- a/target/loongarch/loongarch-qmp-cmds.c
+++ b/target/loongarch/loongarch-qmp-cmds.c
@@ -40,7 +40,7 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
 }
 
 static const char *cpu_model_advertised_features[] = {
-"lsx", "lasx", NULL
+"lsx", "lasx", "lbt", NULL
 };
 
 CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType 
type,
-- 
2.39.3




[PATCH 0/2] target/loongarch: Add loongson binary translation feature

2024-05-21 Thread Bibo Mao
Loongson Binary Translation (LBT) is used to accelerate binary
translation. LBT feature is added in kvm mode, not supported in TCG
mode since it is not emulated. And only LBT feature is added here, LBT
registers saving and restoring is not supported since it depeeds on LBT
feautre implemented in KVM kernel

Bibo Mao (2):
  target/loongarch: Add loongarch vector property unconditionally
  target/loongarch: Add loongson binary translation feature

 target/loongarch/cpu.c| 42 ++-
 target/loongarch/cpu.h|  1 +
 target/loongarch/loongarch-qmp-cmds.c |  2 +-
 3 files changed, 36 insertions(+), 9 deletions(-)


base-commit: 922582ace2df59572a671f5c0c5c6c5c706995e5
-- 
2.39.3




[PATCH 1/2] target/loongarch: Add loongarch vector property unconditionally

2024-05-21 Thread Bibo Mao
Currently LSX/LASX vector property is decided by the default value.
Instead vector property should be added unconditionally, and it is
irrelative with its default value. If vector is disabled by default,
vector also can be enabled from command line.

Signed-off-by: Bibo Mao 
---
 target/loongarch/cpu.c | 14 --
 1 file changed, 4 insertions(+), 10 deletions(-)

diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index a0cad53676..b5c1ec94af 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -645,16 +645,10 @@ static void loongarch_set_lasx(Object *obj, bool value, 
Error **errp)
 
 void loongarch_cpu_post_init(Object *obj)
 {
-LoongArchCPU *cpu = LOONGARCH_CPU(obj);
-
-if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LSX)) {
-object_property_add_bool(obj, "lsx", loongarch_get_lsx,
- loongarch_set_lsx);
-}
-if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LASX)) {
-object_property_add_bool(obj, "lasx", loongarch_get_lasx,
- loongarch_set_lasx);
-}
+object_property_add_bool(obj, "lsx", loongarch_get_lsx,
+ loongarch_set_lsx);
+object_property_add_bool(obj, "lasx", loongarch_get_lasx,
+ loongarch_set_lasx);
 }
 
 static void loongarch_cpu_init(Object *obj)
-- 
2.39.3




[PATCH] ui/console: Fix compiling issue

2024-05-16 Thread Bibo Mao
Local variable fence_fd is defined but not used if CONFIG_GBM is
not enabled, and there is compiling problem.

Signed-off-by: Bibo Mao 
---
 ui/gtk-egl.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c
index 0473f689c9..9831c10e1b 100644
--- a/ui/gtk-egl.c
+++ b/ui/gtk-egl.c
@@ -68,9 +68,9 @@ void gd_egl_draw(VirtualConsole *vc)
 GdkWindow *window;
 #ifdef CONFIG_GBM
 QemuDmaBuf *dmabuf = vc->gfx.guest_fb.dmabuf;
+int fence_fd;
 #endif
 int ww, wh, ws;
-int fence_fd;
 
 if (!vc->gfx.gls) {
 return;

base-commit: 922582ace2df59572a671f5c0c5c6c5c706995e5
-- 
2.39.3




[RFC v2] target/loongarch/kvm: Add software breakpoint support

2024-05-16 Thread Bibo Mao
With KVM virtualization, debug exception is passthrough to guest kernel
rather than host mode. Here hypercall instruction with special code is used
for sw breakpoint usage.

Now only software breakpoint is supported, and it is allowed to
insert/remove software breakpoint. We can debug guest kernel with gdb
method after kernel is loaded, hardware breakpoint will be added in later.

Signed-off-by: Bibo Mao 
---
v1 ... v2:
  1. Enable TARGET_KVM_HAVE_GUEST_DEBUG on loongarch64 platform
---
 configs/targets/loongarch64-softmmu.mak |  1 +
 target/loongarch/kvm/kvm.c  | 76 +
 2 files changed, 77 insertions(+)

diff --git a/configs/targets/loongarch64-softmmu.mak 
b/configs/targets/loongarch64-softmmu.mak
index 84beb19b90..65b65e0c34 100644
--- a/configs/targets/loongarch64-softmmu.mak
+++ b/configs/targets/loongarch64-softmmu.mak
@@ -1,5 +1,6 @@
 TARGET_ARCH=loongarch64
 TARGET_BASE_ARCH=loongarch
+TARGET_KVM_HAVE_GUEST_DEBUG=y
 TARGET_SUPPORTS_MTTCG=y
 TARGET_XML_FILES= gdb-xml/loongarch-base32.xml gdb-xml/loongarch-base64.xml 
gdb-xml/loongarch-fpu.xml
 # all boards require libfdt
diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
index bc75552d0f..0a94784276 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -28,6 +28,7 @@
 #include "trace.h"
 
 static bool cap_has_mp_state;
+static unsigned int brk_insn;
 const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
 KVM_CAP_LAST_INFO
 };
@@ -658,7 +659,14 @@ static void kvm_loongarch_vm_stage_change(void *opaque, 
bool running,
 
 int kvm_arch_init_vcpu(CPUState *cs)
 {
+uint64_t val;
+
 qemu_add_vm_change_state_handler(kvm_loongarch_vm_stage_change, cs);
+
+if (!kvm_get_one_reg(cs, KVM_REG_LOONGARCH_DEBUG_INST, )) {
+brk_insn = val;
+}
+
 return 0;
 }
 
@@ -733,6 +741,67 @@ bool kvm_arch_stop_on_emulation_error(CPUState *cs)
 return true;
 }
 
+void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg)
+{
+if (kvm_sw_breakpoints_active(cpu)) {
+dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP;
+}
+}
+
+int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
+{
+if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)>saved_insn, 4, 0) ||
+cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)_insn, 4, 1)) {
+error_report("%s failed", __func__);
+return -EINVAL;
+}
+return 0;
+}
+
+int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
+{
+static uint32_t brk;
+
+if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *), 4, 0) ||
+brk != brk_insn ||
+cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)>saved_insn, 4, 1)) {
+error_report("%s failed", __func__);
+return -EINVAL;
+}
+return 0;
+}
+
+int kvm_arch_insert_hw_breakpoint(vaddr addr, vaddr len, int type)
+{
+return -ENOSYS;
+}
+
+int kvm_arch_remove_hw_breakpoint(vaddr addr, vaddr len, int type)
+{
+return -ENOSYS;
+}
+
+void kvm_arch_remove_all_hw_breakpoints(void)
+{
+}
+
+static bool kvm_loongarch_handle_debug(CPUState *cs, struct kvm_run *run)
+{
+LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+CPULoongArchState *env = >env;
+
+kvm_cpu_synchronize_state(cs);
+if (cs->singlestep_enabled) {
+return true;
+}
+
+if (kvm_find_sw_breakpoint(cs, env->pc)) {
+return true;
+}
+
+return false;
+}
+
 int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
 {
 int ret = 0;
@@ -751,6 +820,13 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
  run->iocsr_io.len,
  run->iocsr_io.is_write);
 break;
+
+case KVM_EXIT_DEBUG:
+if (kvm_loongarch_handle_debug(cs, run)) {
+ret = EXCP_DEBUG;
+}
+break;
+
 default:
 ret = -1;
 warn_report("KVM: unknown exit reason %d", run->exit_reason);

base-commit: 922582ace2df59572a671f5c0c5c6c5c706995e5
-- 
2.39.3




[PATCH v3 0/6] hw/loongarch: Refine numa memory map

2024-05-15 Thread Bibo Mao
One LoongArch virt machine platform, there is limitation for memory
map information. The minimum memory size is 256M and minimum memory
size for numa node0 is 256M also. With qemu numa qtest, it is possible
that memory size of numa node0 is 128M.

Limitations for minimum memory size for both total memory and numa
node0 is removed here, including acpi srat table, fadt memory map table
and fw_cfg memory map table.

Also remove numa node about memory region, there is only low memory
region and how memory region.

---
v2 ... v3:
  1. Modify numa test case for loongarch system.
  2. Rebase the patch based on the latest version.

v1 ... v2:
  1. Refresh the patch based on the latest qemu version, solve the
confliction issue.
  2. Add numa test case for loongarch system.
---
Bibo Mao (6):
  hw/loongarch: Refine acpi srat table for numa memory
  hw/loongarch: Refine fadt memory table for numa memory
  hw/loongarch: Refine fwcfg memory map
  hw/loongarch: Refine system dram memory region
  hw/loongarch: Remove minimum and default memory size
  tests/qtest: Add numa test for loongarch system

 hw/loongarch/acpi-build.c |  58 +++--
 hw/loongarch/virt.c   | 166 +++---
 tests/qtest/meson.build   |   2 +-
 tests/qtest/numa-test.c   |  53 
 4 files changed, 206 insertions(+), 73 deletions(-)


base-commit: dafec285bdbfe415ac6823abdc510e0b92c3f094
-- 
2.39.3




[PATCH v3 3/6] hw/loongarch: Refine fwcfg memory map

2024-05-15 Thread Bibo Mao
Memory map table for fwcfg is used for UEFI BIOS, UEFI BIOS uses the first
entry from fwcfg memory map as the first memory HOB, the second memory HOB
will be used if the first memory HOB is used up.

Memory map table for fwcfg does not care about numa node, however in
generic the first memory HOB is part of numa node0, so that runtime
memory of UEFI which is allocated from the first memory HOB is located
at numa node0.

Signed-off-by: Bibo Mao 
---
 hw/loongarch/virt.c | 60 ++---
 1 file changed, 57 insertions(+), 3 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index c996305d87..b67d691fa5 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -912,6 +912,62 @@ static const MemoryRegionOps virt_iocsr_misc_ops = {
 },
 };
 
+static void fw_cfg_add_memory(MachineState *ms)
+{
+hwaddr base, size, ram_size, gap;
+int nb_numa_nodes, nodes;
+NodeInfo *numa_info;
+
+ram_size = ms->ram_size;
+base = VIRT_LOWMEM_BASE;
+gap = VIRT_LOWMEM_SIZE;
+nodes = nb_numa_nodes = ms->numa_state->num_nodes;
+numa_info = ms->numa_state->nodes;
+if (!nodes) {
+nodes = 1;
+}
+
+/* add fw_cfg memory map of node0 */
+if (nb_numa_nodes) {
+size = numa_info[0].node_mem;
+} else {
+size = ram_size;
+}
+
+if (size >= gap) {
+memmap_add_entry(base, gap, 1);
+size -= gap;
+base = VIRT_HIGHMEM_BASE;
+gap = ram_size - VIRT_LOWMEM_SIZE;
+}
+
+if (size) {
+memmap_add_entry(base, size, 1);
+base += size;
+}
+
+if (nodes < 2) {
+return;
+}
+
+/* add fw_cfg memory map of other nodes */
+size = ram_size - numa_info[0].node_mem;
+gap  = VIRT_LOWMEM_BASE + VIRT_LOWMEM_SIZE;
+if (base < gap && (base + size) > gap) {
+/*
+ * memory map for the maining nodes splited into two part
+ *   lowram:  [base, +(gap - base))
+ *   highram: [VIRT_HIGHMEM_BASE, +(size - (gap - base)))
+ */
+memmap_add_entry(base, gap - base, 1);
+size -= gap - base;
+base = VIRT_HIGHMEM_BASE;
+}
+
+   if (size)
+memmap_add_entry(base, size, 1);
+}
+
 static void virt_init(MachineState *machine)
 {
 LoongArchCPU *lacpu;
@@ -958,9 +1014,9 @@ static void virt_init(MachineState *machine)
 }
 fdt_add_cpu_nodes(lvms);
 fdt_add_memory_nodes(machine);
+fw_cfg_add_memory(machine);
 
 /* Node0 memory */
-memmap_add_entry(VIRT_LOWMEM_BASE, VIRT_LOWMEM_SIZE, 1);
 memory_region_init_alias(>lowmem, NULL, "loongarch.node0.lowram",
  machine->ram, offset, VIRT_LOWMEM_SIZE);
 memory_region_add_subregion(address_space_mem, phyAddr, >lowmem);
@@ -973,7 +1029,6 @@ static void virt_init(MachineState *machine)
 highram_size = ram_size - VIRT_LOWMEM_SIZE;
 }
 phyAddr = VIRT_HIGHMEM_BASE;
-memmap_add_entry(phyAddr, highram_size, 1);
 memory_region_init_alias(>highmem, NULL, "loongarch.node0.highram",
   machine->ram, offset, highram_size);
 memory_region_add_subregion(address_space_mem, phyAddr, >highmem);
@@ -988,7 +1043,6 @@ static void virt_init(MachineState *machine)
 memory_region_init_alias(nodemem, NULL, ramName, machine->ram,
  offset,  numa_info[i].node_mem);
 memory_region_add_subregion(address_space_mem, phyAddr, nodemem);
-memmap_add_entry(phyAddr, numa_info[i].node_mem, 1);
 offset += numa_info[i].node_mem;
 phyAddr += numa_info[i].node_mem;
 }
-- 
2.39.3




[PATCH v3 1/6] hw/loongarch: Refine acpi srat table for numa memory

2024-05-15 Thread Bibo Mao
One LoongArch virt machine platform, there is limitation for memory
map information. The minimum memory size is 256M and minimum memory
size for numa node0 is 256M also. With qemu numa qtest, it is possible
that memory size of numa node0 is 128M.

Limitations for minimum memory size for both total memory and numa
node0 is removed for acpi srat table creation.

Signed-off-by: Bibo Mao 
---
 hw/loongarch/acpi-build.c | 58 +++
 1 file changed, 34 insertions(+), 24 deletions(-)

diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c
index 5ef010d4da..af45ce526d 100644
--- a/hw/loongarch/acpi-build.c
+++ b/hw/loongarch/acpi-build.c
@@ -166,8 +166,9 @@ static void
 build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
 {
 int i, arch_id, node_id;
-uint64_t mem_len, mem_base;
-int nb_numa_nodes = machine->numa_state->num_nodes;
+hwaddr len, base, gap;
+NodeInfo *numa_info;
+int nodes, nb_numa_nodes = machine->numa_state->num_nodes;
 LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine);
 MachineClass *mc = MACHINE_GET_CLASS(lvms);
 const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(machine);
@@ -196,35 +197,44 @@ build_srat(GArray *table_data, BIOSLinker *linker, 
MachineState *machine)
 build_append_int_noprefix(table_data, 0, 4); /* Reserved */
 }
 
-/* Node0 */
-build_srat_memory(table_data, VIRT_LOWMEM_BASE, VIRT_LOWMEM_SIZE,
-  0, MEM_AFFINITY_ENABLED);
-mem_base = VIRT_HIGHMEM_BASE;
-if (!nb_numa_nodes) {
-mem_len = machine->ram_size - VIRT_LOWMEM_SIZE;
-} else {
-mem_len = machine->numa_state->nodes[0].node_mem - VIRT_LOWMEM_SIZE;
+base = VIRT_LOWMEM_BASE;
+gap = VIRT_LOWMEM_SIZE;
+numa_info = machine->numa_state->nodes;
+nodes = nb_numa_nodes;
+if (!nodes) {
+nodes = 1;
 }
-if (mem_len)
-build_srat_memory(table_data, mem_base, mem_len, 0, 
MEM_AFFINITY_ENABLED);
-
-/* Node1 - Nodemax */
-if (nb_numa_nodes) {
-mem_base += mem_len;
-for (i = 1; i < nb_numa_nodes; ++i) {
-if (machine->numa_state->nodes[i].node_mem > 0) {
-build_srat_memory(table_data, mem_base,
-  machine->numa_state->nodes[i].node_mem, i,
-  MEM_AFFINITY_ENABLED);
-mem_base += machine->numa_state->nodes[i].node_mem;
-}
+
+for (i = 0; i < nodes; i++) {
+if (nb_numa_nodes) {
+len = numa_info[i].node_mem;
+} else {
+len = machine->ram_size;
+}
+
+/*
+ * memory for the node splited into two part
+ *   lowram:  [base, +gap)
+ *   highram: [VIRT_HIGHMEM_BASE, +(len - gap))
+ */
+if (len >= gap) {
+build_srat_memory(table_data, base, len, i, MEM_AFFINITY_ENABLED);
+len -= gap;
+base = VIRT_HIGHMEM_BASE;
+gap = machine->ram_size - VIRT_LOWMEM_SIZE;
+}
+
+if (len) {
+build_srat_memory(table_data, base, len, i, MEM_AFFINITY_ENABLED);
+base += len;
+gap  -= len;
 }
 }
 
 if (machine->device_memory) {
 build_srat_memory(table_data, machine->device_memory->base,
   memory_region_size(>device_memory->mr),
-  nb_numa_nodes - 1,
+  nodes - 1,
   MEM_AFFINITY_HOTPLUGGABLE | MEM_AFFINITY_ENABLED);
 }
 
-- 
2.39.3




[PATCH v3 4/6] hw/loongarch: Refine system dram memory region

2024-05-15 Thread Bibo Mao
For system dram memory region, it is not necessary to use numa node
information. There is only low memory region and high memory region.

Remove numa node information for ddr memory region here, it can reduce
memory region number on LoongArch virt machine.

Signed-off-by: Bibo Mao 
---
 hw/loongarch/virt.c | 55 +++--
 1 file changed, 18 insertions(+), 37 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index b67d691fa5..ac980aec8e 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -972,14 +972,10 @@ static void virt_init(MachineState *machine)
 {
 LoongArchCPU *lacpu;
 const char *cpu_model = machine->cpu_type;
-ram_addr_t offset = 0;
-ram_addr_t ram_size = machine->ram_size;
-uint64_t highram_size = 0, phyAddr = 0;
 MemoryRegion *address_space_mem = get_system_memory();
 LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine);
-int nb_numa_nodes = machine->numa_state->num_nodes;
-NodeInfo *numa_info = machine->numa_state->nodes;
 int i;
+hwaddr base, size, ram_size = machine->ram_size;
 const CPUArchIdList *possible_cpus;
 MachineClass *mc = MACHINE_GET_CLASS(machine);
 CPUState *cpu;
@@ -1017,40 +1013,27 @@ static void virt_init(MachineState *machine)
 fw_cfg_add_memory(machine);
 
 /* Node0 memory */
-memory_region_init_alias(>lowmem, NULL, "loongarch.node0.lowram",
- machine->ram, offset, VIRT_LOWMEM_SIZE);
-memory_region_add_subregion(address_space_mem, phyAddr, >lowmem);
-
-offset += VIRT_LOWMEM_SIZE;
-if (nb_numa_nodes > 0) {
-assert(numa_info[0].node_mem > VIRT_LOWMEM_SIZE);
-highram_size = numa_info[0].node_mem - VIRT_LOWMEM_SIZE;
-} else {
-highram_size = ram_size - VIRT_LOWMEM_SIZE;
-}
-phyAddr = VIRT_HIGHMEM_BASE;
-memory_region_init_alias(>highmem, NULL, "loongarch.node0.highram",
-  machine->ram, offset, highram_size);
-memory_region_add_subregion(address_space_mem, phyAddr, >highmem);
-
-/* Node1 - Nodemax memory */
-offset += highram_size;
-phyAddr += highram_size;
-
-for (i = 1; i < nb_numa_nodes; i++) {
-MemoryRegion *nodemem = g_new(MemoryRegion, 1);
-g_autofree char *ramName = g_strdup_printf("loongarch.node%d.ram", i);
-memory_region_init_alias(nodemem, NULL, ramName, machine->ram,
- offset,  numa_info[i].node_mem);
-memory_region_add_subregion(address_space_mem, phyAddr, nodemem);
-offset += numa_info[i].node_mem;
-phyAddr += numa_info[i].node_mem;
+size = ram_size;
+base = VIRT_LOWMEM_BASE;
+if (size > VIRT_LOWMEM_SIZE) {
+size = VIRT_LOWMEM_SIZE;
 }
 
+memory_region_init_alias(>lowmem, NULL, "loongarch.lowram",
+  machine->ram, base, size);
+memory_region_add_subregion(address_space_mem, base, >lowmem);
+base += size;
+if (ram_size - size) {
+base = VIRT_HIGHMEM_BASE;
+memory_region_init_alias(>highmem, NULL, "loongarch.highram",
+machine->ram, VIRT_LOWMEM_BASE + size, ram_size - size);
+memory_region_add_subregion(address_space_mem, base, >highmem);
+base += ram_size - size;
+ }
+
 /* initialize device memory address space */
 if (machine->ram_size < machine->maxram_size) {
 ram_addr_t device_mem_size = machine->maxram_size - machine->ram_size;
-hwaddr device_mem_base;
 
 if (machine->ram_slots > ACPI_MAX_RAM_SLOTS) {
 error_report("unsupported amount of memory slots: %"PRIu64,
@@ -1064,9 +1047,7 @@ static void virt_init(MachineState *machine)
  "%d bytes", TARGET_PAGE_SIZE);
 exit(EXIT_FAILURE);
 }
-/* device memory base is the top of high memory address. */
-device_mem_base = ROUND_UP(VIRT_HIGHMEM_BASE + highram_size, 1 * GiB);
-machine_memory_devices_init(machine, device_mem_base, device_mem_size);
+machine_memory_devices_init(machine, base, device_mem_size);
 }
 
 /* load the BIOS image. */
-- 
2.39.3




[PATCH v3 5/6] hw/loongarch: Remove minimum and default memory size

2024-05-15 Thread Bibo Mao
Some qtest test cases such as numa use default memory size of generic
machine class, which is 128M by fault.

Here generic default memory size is used, and also remove minimum memory
size which is 1G originally.

Signed-off-by: Bibo Mao 
---
 hw/loongarch/virt.c | 5 -
 1 file changed, 5 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index ac980aec8e..7d3d1d1689 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -984,10 +984,6 @@ static void virt_init(MachineState *machine)
 cpu_model = LOONGARCH_CPU_TYPE_NAME("la464");
 }
 
-if (ram_size < 1 * GiB) {
-error_report("ram_size must be greater than 1G.");
-exit(1);
-}
 create_fdt(lvms);
 
 /* Create IOCSR space */
@@ -1273,7 +1269,6 @@ static void virt_class_init(ObjectClass *oc, void *data)
 HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
 
 mc->init = virt_init;
-mc->default_ram_size = 1 * GiB;
 mc->default_cpu_type = LOONGARCH_CPU_TYPE_NAME("la464");
 mc->default_ram_id = "loongarch.ram";
 mc->max_cpus = LOONGARCH_MAX_CPUS;
-- 
2.39.3




[PATCH v3 6/6] tests/qtest: Add numa test for loongarch system

2024-05-15 Thread Bibo Mao
Add numa test case for loongarch system, it passes to run
with command "make check-qtest".

Signed-off-by: Bibo Mao 
---
 tests/qtest/meson.build |  2 +-
 tests/qtest/numa-test.c | 53 +
 2 files changed, 54 insertions(+), 1 deletion(-)

diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 86293051dc..8df7b85d72 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -140,7 +140,7 @@ qtests_hppa = ['boot-serial-test'] + \
   (config_all_devices.has_key('CONFIG_VGA') ? ['display-vga-test'] : [])
 
 qtests_loongarch64 = qtests_filter + \
-  ['boot-serial-test']
+  ['boot-serial-test', 'numa-test']
 
 qtests_m68k = ['boot-serial-test'] + \
   qtests_filter
diff --git a/tests/qtest/numa-test.c b/tests/qtest/numa-test.c
index 4f4404a4b1..2f71d57a8d 100644
--- a/tests/qtest/numa-test.c
+++ b/tests/qtest/numa-test.c
@@ -265,6 +265,54 @@ static void aarch64_numa_cpu(const void *data)
 qtest_quit(qts);
 }
 
+static void loongarch64_numa_cpu(const void *data)
+{
+QDict *resp;
+QList *cpus;
+QObject *e;
+QTestState *qts;
+g_autofree char *cli = NULL;
+
+cli = make_cli(data, "-machine "
+"smp.cpus=2,smp.sockets=2,smp.cores=1,smp.threads=1 "
+"-numa node,nodeid=0,memdev=ram -numa node,nodeid=1 "
+"-numa cpu,node-id=0,socket-id=1,core-id=0,thread-id=0 "
+"-numa cpu,node-id=1,socket-id=0,core-id=0,thread-id=0");
+qts = qtest_init(cli);
+cpus = get_cpus(qts, );
+g_assert(cpus);
+
+while ((e = qlist_pop(cpus))) {
+QDict *cpu, *props;
+int64_t socket, core, thread, node;
+
+cpu = qobject_to(QDict, e);
+g_assert(qdict_haskey(cpu, "props"));
+props = qdict_get_qdict(cpu, "props");
+
+g_assert(qdict_haskey(props, "node-id"));
+node = qdict_get_int(props, "node-id");
+g_assert(qdict_haskey(props, "socket-id"));
+socket = qdict_get_int(props, "socket-id");
+g_assert(qdict_haskey(props, "core-id"));
+core = qdict_get_int(props, "core-id");
+g_assert(qdict_haskey(props, "thread-id"));
+thread = qdict_get_int(props, "thread-id");
+
+if (socket == 0 && core == 0 && thread == 0) {
+g_assert_cmpint(node, ==, 1);
+} else if (socket == 1 && core == 0 && thread == 0) {
+g_assert_cmpint(node, ==, 0);
+} else {
+g_assert(false);
+}
+qobject_unref(e);
+}
+
+qobject_unref(resp);
+qtest_quit(qts);
+}
+
 static void pc_dynamic_cpu_cfg(const void *data)
 {
 QObject *e;
@@ -590,5 +638,10 @@ int main(int argc, char **argv)
 aarch64_numa_cpu);
 }
 
+if (!strcmp(arch, "loongarch64")) {
+qtest_add_data_func("/numa/loongarch64/cpu/explicit", args,
+loongarch64_numa_cpu);
+}
+
 return g_test_run();
 }
-- 
2.39.3




[PATCH v3 2/6] hw/loongarch: Refine fadt memory table for numa memory

2024-05-15 Thread Bibo Mao
One LoongArch virt machine platform, there is limitation for memory
map information. The minimum memory size is 256M and minimum memory
size for numa node0 is 256M also. With qemu numa qtest, it is possible
that memory size of numa node0 is 128M.

Limitations for minimum memory size for both total memory and numa
node0 is removed for fadt numa memory table creation.

Signed-off-by: Bibo Mao 
---
 hw/loongarch/virt.c | 46 ++---
 1 file changed, 43 insertions(+), 3 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index f0640d2d80..c996305d87 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -473,6 +473,48 @@ static void fdt_add_memory_node(MachineState *ms,
 g_free(nodename);
 }
 
+static void fdt_add_memory_nodes(MachineState *ms)
+{
+hwaddr base, size, ram_size, gap;
+int i, nb_numa_nodes, nodes;
+NodeInfo *numa_info;
+
+ram_size = ms->ram_size;
+base = VIRT_LOWMEM_BASE;
+gap = VIRT_LOWMEM_SIZE;
+nodes = nb_numa_nodes = ms->numa_state->num_nodes;
+numa_info = ms->numa_state->nodes;
+if (!nodes) {
+nodes = 1;
+}
+
+for (i = 0; i < nodes; i++) {
+if (nb_numa_nodes) {
+size = numa_info[i].node_mem;
+} else {
+size = ram_size;
+}
+
+/*
+ * memory for the node splited into two part
+ *   lowram:  [base, +gap)
+ *   highram: [VIRT_HIGHMEM_BASE, +(len - gap))
+ */
+if (size >= gap) {
+fdt_add_memory_node(ms, base, gap, i);
+size -= gap;
+base = VIRT_HIGHMEM_BASE;
+gap = ram_size - VIRT_LOWMEM_SIZE;
+}
+
+if (size) {
+fdt_add_memory_node(ms, base, size, i);
+base += size;
+gap -= size;
+}
+}
+}
+
 static void virt_build_smbios(LoongArchVirtMachineState *lvms)
 {
 MachineState *ms = MACHINE(lvms);
@@ -915,10 +957,10 @@ static void virt_init(MachineState *machine)
 lacpu->phy_id = machine->possible_cpus->cpus[i].arch_id;
 }
 fdt_add_cpu_nodes(lvms);
+fdt_add_memory_nodes(machine);
 
 /* Node0 memory */
 memmap_add_entry(VIRT_LOWMEM_BASE, VIRT_LOWMEM_SIZE, 1);
-fdt_add_memory_node(machine, VIRT_LOWMEM_BASE, VIRT_LOWMEM_SIZE, 0);
 memory_region_init_alias(>lowmem, NULL, "loongarch.node0.lowram",
  machine->ram, offset, VIRT_LOWMEM_SIZE);
 memory_region_add_subregion(address_space_mem, phyAddr, >lowmem);
@@ -932,7 +974,6 @@ static void virt_init(MachineState *machine)
 }
 phyAddr = VIRT_HIGHMEM_BASE;
 memmap_add_entry(phyAddr, highram_size, 1);
-fdt_add_memory_node(machine, phyAddr, highram_size, 0);
 memory_region_init_alias(>highmem, NULL, "loongarch.node0.highram",
   machine->ram, offset, highram_size);
 memory_region_add_subregion(address_space_mem, phyAddr, >highmem);
@@ -948,7 +989,6 @@ static void virt_init(MachineState *machine)
  offset,  numa_info[i].node_mem);
 memory_region_add_subregion(address_space_mem, phyAddr, nodemem);
 memmap_add_entry(phyAddr, numa_info[i].node_mem, 1);
-fdt_add_memory_node(machine, phyAddr, numa_info[i].node_mem, i);
 offset += numa_info[i].node_mem;
 phyAddr += numa_info[i].node_mem;
 }
-- 
2.39.3




[PATCH] tests/libqos: Add loongarch virt machine node

2024-05-14 Thread Bibo Mao
Add loongarch virt machine to the graph. It is a modified copy of
the existing riscv virtmachine in riscv-virt-machine.c

It contains a generic-pcihost controller, and an extra function
loongarch_config_qpci_bus() to configure GPEX pci host controller
information, such as ecam and pio_base addresses.

Also hotplug handle checking about TYPE_VIRTIO_IOMMU_PCI device is
added on loongarch virt machine, since virtio_mmu_pci device requires
it.

Signed-off-by: Bibo Mao 
---
 hw/loongarch/virt.c |   2 +
 tests/qtest/libqos/loongarch-virt-machine.c | 114 
 tests/qtest/libqos/meson.build  |   1 +
 3 files changed, 117 insertions(+)
 create mode 100644 tests/qtest/libqos/loongarch-virt-machine.c

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index db43b2fe4b..7f5ef87be4 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -45,6 +45,7 @@
 #include "sysemu/tpm.h"
 #include "sysemu/block-backend.h"
 #include "hw/block/flash.h"
+#include "hw/virtio/virtio-iommu.h"
 #include "qemu/error-report.h"
 
 static PFlashCFI01 *virt_flash_create1(LoongArchVirtMachineState *lvms,
@@ -1212,6 +1213,7 @@ static HotplugHandler 
*virt_get_hotplug_handler(MachineState *machine,
 MachineClass *mc = MACHINE_GET_CLASS(machine);
 
 if (device_is_dynamic_sysbus(mc, dev) ||
+object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_IOMMU_PCI) ||
 memhp_type_supported(dev)) {
 return HOTPLUG_HANDLER(machine);
 }
diff --git a/tests/qtest/libqos/loongarch-virt-machine.c 
b/tests/qtest/libqos/loongarch-virt-machine.c
new file mode 100644
index 00..c12089c015
--- /dev/null
+++ b/tests/qtest/libqos/loongarch-virt-machine.c
@@ -0,0 +1,114 @@
+/*
+ * libqos driver framework
+ *
+ * Copyright (c) 2018 Emanuele Giuseppe Esposito 
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "qemu/osdep.h"
+#include "../libqtest.h"
+#include "qemu/module.h"
+#include "libqos-malloc.h"
+#include "qgraph.h"
+#include "virtio-mmio.h"
+#include "generic-pcihost.h"
+#include "hw/pci/pci_regs.h"
+
+#define LOONGARCH_PAGE_SIZE   0x1000
+#define LOONGARCH_VIRT_RAM_ADDR   0x10
+#define LOONGARCH_VIRT_RAM_SIZE   0xFF0
+
+#define LOONGARCH_VIRT_PIO_BASE   0x1800
+#define LOONGARCH_VIRT_PCIE_PIO_OFFSET0x4000
+#define LOONGARCH_VIRT_PCIE_PIO_LIMIT 0x1
+#define LOONGARCH_VIRT_PCIE_ECAM_BASE 0x2000
+#define LOONGARCH_VIRT_PCIE_MMIO32_BASE   0x4000
+#define LOONGARCH_VIRT_PCIE_MMIO32_LIMIT  0x8000
+
+typedef struct QVirtMachine QVirtMachine;
+
+struct QVirtMachine {
+QOSGraphObject obj;
+QGuestAllocator alloc;
+QVirtioMMIODevice virtio_mmio;
+QGenericPCIHost bridge;
+};
+
+static void virt_destructor(QOSGraphObject *obj)
+{
+QVirtMachine *machine = (QVirtMachine *) obj;
+alloc_destroy(>alloc);
+}
+
+static void *virt_get_driver(void *object, const char *interface)
+{
+QVirtMachine *machine = object;
+if (!g_strcmp0(interface, "memory")) {
+return >alloc;
+}
+
+fprintf(stderr, "%s not present in loongarch/virtio\n", interface);
+g_assert_not_reached();
+}
+
+static QOSGraphObject *virt_get_device(void *obj, const char *device)
+{
+QVirtMachine *machine = obj;
+if (!g_strcmp0(device, "generic-pcihost")) {
+return >bridge.obj;
+} else if (!g_strcmp0(device, "virtio-mmio")) {
+return >virtio_mmio.obj;
+}
+
+fprintf(stderr, "%s not present in loongarch/virt\n", device);
+g_assert_not_reached();
+}
+
+static void loongarch_config_qpci_bus(QGenericPCIBus *qpci)
+{
+qpci->gpex_pio_base = LOONGARCH_VIRT_PIO_BASE;
+qpci->bus.pio_alloc_ptr = LOONGARCH_VIRT_PCIE_PIO_OFFSET;
+qpci->bus.pio_limit = LOONGARCH_VIRT_PCIE_PIO_LIMIT;
+qpci->bus.mmio_alloc_ptr = LOONGARCH_VIRT_PCIE_MMIO32_BASE;
+qpci->bus.mmio_limit = LOONGARCH_VIRT_PCIE_MMIO32_LIMIT;
+qpci->ecam_alloc_ptr = LOONGARCH_VIRT_PCIE_ECAM_BASE;
+}
+
+static void *qos_create_machine_loongarch_virt(QTestState *qts)
+{
+QVirtMachine *machine = g_new0(QVirtMachine, 1);
+
+alloc_init(>alloc, 0,
+   LOONGARCH_VIRT_RAM_ADDR,
+   LO

[PATCH] hw/loongarch: Add VM mode in IOCSR feature register in kvm mode

2024-05-13 Thread Bibo Mao
If VM runs in kvm mode, VM mode is added in IOCSR feature register.
So guest can detect kvm hypervisor type and enable possible pv functions.

Signed-off-by: Bibo Mao 
---
 hw/loongarch/virt.c | 12 +---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index d87d9be576..44bcf25aee 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -10,6 +10,7 @@
 #include "qapi/error.h"
 #include "hw/boards.h"
 #include "hw/char/serial.h"
+#include "sysemu/kvm.h"
 #include "sysemu/sysemu.h"
 #include "sysemu/qtest.h"
 #include "sysemu/runstate.h"
@@ -840,18 +841,23 @@ static void virt_iocsr_misc_write(void *opaque, hwaddr 
addr,
 
 static uint64_t virt_iocsr_misc_read(void *opaque, hwaddr addr, unsigned size)
 {
+uint64_t ret;
+
 switch (addr) {
 case VERSION_REG:
 return 0x11ULL;
 case FEATURE_REG:
-return 1ULL << IOCSRF_MSI | 1ULL << IOCSRF_EXTIOI |
-   1ULL << IOCSRF_CSRIPI;
+ret = BIT(IOCSRF_MSI) | BIT(IOCSRF_EXTIOI) | BIT(IOCSRF_CSRIPI);
+if (kvm_enabled()) {
+ret |= BIT(IOCSRF_VM);
+}
+return ret;
 case VENDOR_REG:
 return 0x6e6f73676e6f6f4cULL; /* "Loongson" */
 case CPUNAME_REG:
 return 0x303030354133ULL; /* "3A5000" */
 case MISC_FUNC_REG:
-return 1ULL << IOCSRM_EXTIOI_EN;
+return BIT_ULL(IOCSRM_EXTIOI_EN);
 }
 return 0ULL;
 }
-- 
2.39.3




[PATCH v5 3/3] tests: Add migration test for loongarch64

2024-05-10 Thread Bibo Mao
This patch adds migration test support for loongarch64. The test code
comes from aarch64 mostly, only that it booted as bios in qemu since
kernel requires elf format and bios uses binary format.

In addition to providing the binary, this patch also includes the source
code and the build script in tests/migration/loongarch64. So users can
change the source and/or re-compile the binary as they wish.

Signed-off-by: Bibo Mao 
Acked-by: Thomas Huth 
Acked-by: Peter Xu 
Reviewed-by: Fabiano Rosas 
---
 tests/migration/Makefile |  2 +-
 tests/migration/loongarch64/Makefile | 18 +
 tests/migration/loongarch64/a-b-kernel.S | 49 
 tests/migration/loongarch64/a-b-kernel.h | 16 
 tests/migration/migration-test.h |  3 ++
 tests/qtest/meson.build  |  2 +-
 tests/qtest/migration-test.c | 10 +
 7 files changed, 98 insertions(+), 2 deletions(-)
 create mode 100644 tests/migration/loongarch64/Makefile
 create mode 100644 tests/migration/loongarch64/a-b-kernel.S
 create mode 100644 tests/migration/loongarch64/a-b-kernel.h

diff --git a/tests/migration/Makefile b/tests/migration/Makefile
index 13e99b1692..cfebfe23f8 100644
--- a/tests/migration/Makefile
+++ b/tests/migration/Makefile
@@ -5,7 +5,7 @@
 # See the COPYING file in the top-level directory.
 #
 
-TARGET_LIST = i386 aarch64 s390x
+TARGET_LIST = i386 aarch64 s390x loongarch64
 
 SRC_PATH = ../..
 
diff --git a/tests/migration/loongarch64/Makefile 
b/tests/migration/loongarch64/Makefile
new file mode 100644
index 00..5d8719205f
--- /dev/null
+++ b/tests/migration/loongarch64/Makefile
@@ -0,0 +1,18 @@
+# To specify cross compiler prefix, use CROSS_PREFIX=
+#   $ make CROSS_PREFIX=loongarch64-linux-gnu-
+
+.PHONY: all clean
+all: a-b-kernel.h
+
+a-b-kernel.h: loongarch64.kernel
+   echo "$$__note" > $@
+   xxd -i $< | sed -e 's/.*int.*//' >> $@
+
+loongarch64.kernel: loongarch64.elf
+   $(CROSS_PREFIX)objcopy -j .text -O binary $< $@
+
+loongarch64.elf: a-b-kernel.S
+   $(CROSS_PREFIX)gcc -o $@ -nostdlib -Wl,--build-id=none $<
+
+clean:
+   $(RM) *.kernel *.elf
diff --git a/tests/migration/loongarch64/a-b-kernel.S 
b/tests/migration/loongarch64/a-b-kernel.S
new file mode 100644
index 00..cd543345fe
--- /dev/null
+++ b/tests/migration/loongarch64/a-b-kernel.S
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2024 Loongson Technology Corporation Limited
+ */
+#include "../migration-test.h"
+
+#define LOONGARCH_CSR_CRMD  0
+#define LOONGARCH_VIRT_UART 0x1FE001E0
+.section .text
+
+.globl  _start
+_start:
+/* output char 'A' to UART16550 */
+li.d$t0, LOONGARCH_VIRT_UART
+li.w$t1, 'A'
+st.b$t1, $t0, 0
+
+/* traverse test memory region */
+li.d$t0, LOONGARCH_TEST_MEM_START
+li.d$t1, LOONGARCH_TEST_MEM_END
+li.d$t2, TEST_MEM_PAGE_SIZE
+li.d$t4, LOONGARCH_VIRT_UART
+li.w$t5, 'B'
+
+clean:
+st.b$zero, $t0, 0
+add.d   $t0,   $t0, $t2
+bne $t0,   $t1, clean
+/* keeps a counter so we can limit the output speed */
+addi.d  $t6,   $zero, 0
+
+mainloop:
+li.d$t0, LOONGARCH_TEST_MEM_START
+
+innerloop:
+ld.bu   $t3, $t0, 0
+addi.w  $t3, $t3, 1
+ext.w.b $t3, $t3
+st.b$t3, $t0, 0
+add.d   $t0, $t0, $t2
+bne $t0, $t1, innerloop
+
+addi.d  $t6, $t6, 1
+andi$t6, $t6, 31
+bnez$t6, mainloop
+
+st.b$t5, $t4, 0
+b   mainloop
+nop
diff --git a/tests/migration/loongarch64/a-b-kernel.h 
b/tests/migration/loongarch64/a-b-kernel.h
new file mode 100644
index 00..b3fe466754
--- /dev/null
+++ b/tests/migration/loongarch64/a-b-kernel.h
@@ -0,0 +1,16 @@
+/* This file is automatically generated from the assembly file in
+* tests/migration/loongarch64. Edit that file and then run "make all"
+* inside tests/migration to update, and then remember to send both
+* the header and the assembler differences in your patch submission.
+*/
+unsigned char loongarch64_kernel[] = {
+  0x0c, 0xc0, 0x3f, 0x14, 0x8c, 0x81, 0x87, 0x03, 0x0d, 0x04, 0x81, 0x03,
+  0x8d, 0x01, 0x00, 0x29, 0x0c, 0x00, 0x04, 0x14, 0x0d, 0x80, 0x0c, 0x14,
+  0x2e, 0x00, 0x00, 0x14, 0x10, 0xc0, 0x3f, 0x14, 0x10, 0x82, 0x87, 0x03,
+  0x11, 0x08, 0x81, 0x03, 0x80, 0x01, 0x00, 0x29, 0x8c, 0xb9, 0x10, 0x00,
+  0x8d, 0xf9, 0xff, 0x5f, 0x12, 0x00, 0xc0, 0x02, 0x0c, 0x00, 0x04, 0x14,
+  0x8f, 0x01, 0x00, 0x2a, 0xef, 0x05, 0x80, 0x02, 0xef, 0x5d, 0x00, 0x00,
+  0x8f, 0x01, 0x00, 0x29, 0x8c, 0xb9, 0x10, 0x00, 0x8d, 0xed, 0xff, 0x5f,
+  0x52, 0x06, 0xc0, 0x02, 0x52, 0x7e, 0x40, 0x03, 0x5f, 0xde, 0xff, 0x47,
+  0x11, 0x02, 0x00, 0x29, 0xff, 0xd7, 0xff, 0x53, 0x00, 0x00, 0x40, 0x03
+};
diff --git a/tests/migration/migration-test.h b/tests/migration/migration-test.h
index 68512c0b1b..f402e48349 100644
--- a/tests/migration/migrati

[PATCH v5 0/3] Add migration test for loongarch64

2024-05-10 Thread Bibo Mao
Migration test case is added for loongarch64 here. Since compat machine
type is required for migration test case, also compat machine qemu 9.1
is added for loongarch virt machine.

Migration test case passes to run in both tcg and kvm mode with the
patch, 54 migration subtests passes in 188 seconds.

---
v4 ... v5:
  1. Rename loongarch virt compat qemu 9.0 with 9.1
  2. Remove default memory size setting and minimum memory size checking

v3 ... v4:
  1. Rename VIRT_MACHINE with LOONGARCH_VIRT_MACHINE since other
architectures have the same machine type.

v2 ... v3:
  1. Refresh the patch based on the latest qemu version, solve the
confliction issue.

v1 ... v2:
  1. Keep the default memory size unchanged with 1GB, only modify minimum
memory size with 256MB
  2. Remove tab char in file tests/migration/loongarch64/a-b-kernel.S
---
Bibo Mao (3):
  hw/loongarch: Add compat machine for 9.1
  hw/loongarch: Remove minimum and default memory size
  tests: Add migration test for loongarch64

 hw/loongarch/virt.c  | 66 +---
 tests/migration/Makefile |  2 +-
 tests/migration/loongarch64/Makefile | 18 +++
 tests/migration/loongarch64/a-b-kernel.S | 49 ++
 tests/migration/loongarch64/a-b-kernel.h | 16 ++
 tests/migration/migration-test.h |  3 ++
 tests/qtest/meson.build  |  2 +-
 tests/qtest/migration-test.c | 10 
 8 files changed, 146 insertions(+), 20 deletions(-)
 create mode 100644 tests/migration/loongarch64/Makefile
 create mode 100644 tests/migration/loongarch64/a-b-kernel.S
 create mode 100644 tests/migration/loongarch64/a-b-kernel.h


base-commit: dafec285bdbfe415ac6823abdc510e0b92c3f094
-- 
2.39.3




[PATCH v5 2/3] hw/loongarch: Remove minimum and default memory size

2024-05-10 Thread Bibo Mao
Some qtest test cases such as numa use default memory size of generic
machine class, which is 128M by fault.

Here generic default memory size is used, and also remove minimum memory
size which is 1G originally.

Signed-off-by: Bibo Mao 
---
 hw/loongarch/virt.c | 5 -
 1 file changed, 5 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index f24ff5fcf4..d87d9be576 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -890,10 +890,6 @@ static void virt_init(MachineState *machine)
 cpu_model = LOONGARCH_CPU_TYPE_NAME("la464");
 }
 
-if (ram_size < 1 * GiB) {
-error_report("ram_size must be greater than 1G.");
-exit(1);
-}
 create_fdt(lvms);
 
 /* Create IOCSR space */
@@ -1198,7 +1194,6 @@ static void virt_class_init(ObjectClass *oc, void *data)
 HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
 
 mc->init = virt_init;
-mc->default_ram_size = 1 * GiB;
 mc->default_cpu_type = LOONGARCH_CPU_TYPE_NAME("la464");
 mc->default_ram_id = "loongarch.ram";
 mc->max_cpus = LOONGARCH_MAX_CPUS;
-- 
2.39.3




[PATCH v5 1/3] hw/loongarch: Add compat machine for 9.1

2024-05-10 Thread Bibo Mao
Since migration test case requires compat machine type support,
compat machine is added for qemu 9.1 here.

Signed-off-by: Bibo Mao 
---
 hw/loongarch/virt.c | 61 +++--
 1 file changed, 48 insertions(+), 13 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index f0640d2d80..f24ff5fcf4 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -1231,18 +1231,53 @@ static void virt_class_init(ObjectClass *oc, void *data)
 #endif
 }
 
-static const TypeInfo virt_machine_types[] = {
-{
-.name   = TYPE_LOONGARCH_VIRT_MACHINE,
-.parent = TYPE_MACHINE,
-.instance_size  = sizeof(LoongArchVirtMachineState),
-.class_init = virt_class_init,
-.instance_init  = virt_initfn,
-.interfaces = (InterfaceInfo[]) {
- { TYPE_HOTPLUG_HANDLER },
- { }
-},
-}
+#define DEFINE_VIRT_MACHINE_LATEST(major, minor, latest) \
+static void virt_##major##_##minor##_class_init(ObjectClass *oc, \
+void *data) \
+{ \
+MachineClass *mc = MACHINE_CLASS(oc); \
+virt_machine_##major##_##minor##_options(mc); \
+mc->desc = "QEMU " # major "." # minor " LoongArch Virtual Machine"; \
+if (latest) { \
+mc->alias = "virt"; \
+} \
+} \
+static const TypeInfo machvirt_##major##_##minor##_info = { \
+.name = MACHINE_TYPE_NAME("virt-" # major "." # minor), \
+.parent = TYPE_LOONGARCH_VIRT_MACHINE, \
+.class_init = virt_##major##_##minor##_class_init, \
+}; \
+static void machvirt_machine_##major##_##minor##_init(void) \
+{ \
+type_register_static(_##major##_##minor##_info); \
+} \
+type_init(machvirt_machine_##major##_##minor##_init);
+
+#define DEFINE_VIRT_MACHINE_AS_LATEST(major, minor) \
+DEFINE_VIRT_MACHINE_LATEST(major, minor, true)
+#define DEFINE_VIRT_MACHINE(major, minor) \
+DEFINE_VIRT_MACHINE_LATEST(major, minor, false)
+
+static const TypeInfo virt_machine_info = {
+.name   = TYPE_LOONGARCH_VIRT_MACHINE,
+.parent = TYPE_MACHINE,
+.abstract   = true,
+.instance_size  = sizeof(LoongArchVirtMachineState),
+.class_init = virt_class_init,
+.instance_init  = virt_initfn,
+.interfaces = (InterfaceInfo[]) {
+{ TYPE_HOTPLUG_HANDLER },
+{ }
+},
 };
 
-DEFINE_TYPES(virt_machine_types)
+static void machvirt_machine_init(void)
+{
+type_register_static(_machine_info);
+}
+type_init(machvirt_machine_init);
+
+static void virt_machine_9_1_options(MachineClass *mc)
+{
+}
+DEFINE_VIRT_MACHINE_AS_LATEST(9, 1)
-- 
2.39.3




[PATCH v2] tests/qtest: Add some test cases support on LoongArch

2024-05-09 Thread Bibo Mao
Add boot-serial-test and filter test cases support on LoongArch system.

Signed-off-by: Bibo Mao 
---
v1 ... v2:
 1. Refresh the changelog, adding filter test case support also.
 2. Adjust order of loongarch qtest in alphabetical order.
---
 tests/qtest/boot-serial-test.c | 10 ++
 tests/qtest/meson.build|  3 +++
 2 files changed, 13 insertions(+)

diff --git a/tests/qtest/boot-serial-test.c b/tests/qtest/boot-serial-test.c
index e3b7d65fe5..df389adeeb 100644
--- a/tests/qtest/boot-serial-test.c
+++ b/tests/qtest/boot-serial-test.c
@@ -26,6 +26,14 @@ static const uint8_t bios_avr[] = {
 0x80, 0x93, 0xc6, 0x00, /* sts 0x00C6, r24 ; Output 'T' */
 };
 
+static const uint8_t bios_loongarch64[] = {
+0x0c, 0xc0, 0x3f, 0x14, /* lu12i.w $t0, 0x1fe00*/
+0x8c, 0x81, 0x87, 0x03, /* ori $t0, $t0, 0x1e0 */
+0x0d, 0x50, 0x81, 0x03, /* li.w$t1, 'T'*/
+0x8d, 0x01, 0x00, 0x29, /* st.b$t1, $t0, 0 */
+0xff, 0xf3, 0xff, 0x53, /*  b  -16  # loop */
+};
+
 static const uint8_t kernel_mcf5208[] = {
 0x41, 0xf9, 0xfc, 0x06, 0x00, 0x00, /* lea 0xfc06,%a0 */
 0x10, 0x3c, 0x00, 0x54, /* move.b #'T',%d0 */
@@ -167,6 +175,8 @@ static const testdef_t tests[] = {
 { "sparc", "SS-600MP", "", "TMS390Z55" },
 { "sparc64", "sun4u", "", "UltraSPARC" },
 { "s390x", "s390-ccw-virtio", "", "device" },
+{ "loongarch64", "virt", "-cpu max", "TT", sizeof(bios_loongarch64),
+  NULL, bios_loongarch64 },
 { "m68k", "mcf5208evb", "", "TT", sizeof(kernel_mcf5208), kernel_mcf5208 },
 { "m68k", "next-cube", "", "TT", sizeof(bios_nextcube), 0, bios_nextcube },
 { "microblaze", "petalogix-s3adsp1800", "", "TT",
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 6f2f594ace..86293051dc 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -139,6 +139,9 @@ qtests_hppa = ['boot-serial-test'] + \
   qtests_filter + \
   (config_all_devices.has_key('CONFIG_VGA') ? ['display-vga-test'] : [])
 
+qtests_loongarch64 = qtests_filter + \
+  ['boot-serial-test']
+
 qtests_m68k = ['boot-serial-test'] + \
   qtests_filter
 

base-commit: 4e66a08546a2588a4667766a1edab9caccf24ce3
-- 
2.39.3




[PATCH] tests/qtest/boot-serial-test: Add support on LoongArch system

2024-05-08 Thread Bibo Mao
Add boot-serial-test test case support on LoongArch system.

Signed-off-by: Bibo Mao 
---
 tests/qtest/boot-serial-test.c | 10 ++
 tests/qtest/meson.build|  4 
 2 files changed, 14 insertions(+)

diff --git a/tests/qtest/boot-serial-test.c b/tests/qtest/boot-serial-test.c
index e3b7d65fe5..631015e8c8 100644
--- a/tests/qtest/boot-serial-test.c
+++ b/tests/qtest/boot-serial-test.c
@@ -129,6 +129,14 @@ static const uint8_t kernel_stm32vldiscovery[] = {
 0x04, 0x38, 0x01, 0x40  /* 0x40013804 = USART1 TXD */
 };
 
+static const uint8_t bios_loongarch64[] = {
+0x0c, 0xc0, 0x3f, 0x14, /* lu12i.w $t0, 0x1fe00*/
+0x8c, 0x81, 0x87, 0x03, /* ori $t0, $t0, 0x1e0 */
+0x0d, 0x50, 0x81, 0x03, /* li.w$t1, 'T'*/
+0x8d, 0x01, 0x00, 0x29, /* st.b$t1, $t0, 0 */
+0xff, 0xf3, 0xff, 0x53, /*  b  -16  # loop */
+};
+
 typedef struct testdef {
 const char *arch;   /* Target architecture */
 const char *machine;/* Name of the machine */
@@ -181,6 +189,8 @@ static const testdef_t tests[] = {
 { "arm", "microbit", "", "T", sizeof(kernel_nrf51), kernel_nrf51 },
 { "arm", "stm32vldiscovery", "", "T",
   sizeof(kernel_stm32vldiscovery), kernel_stm32vldiscovery },
+{ "loongarch64", "virt", "-cpu max", "TT", sizeof(bios_loongarch64),
+  NULL, bios_loongarch64 },
 
 { NULL }
 };
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 6f2f594ace..6619b630e6 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -256,6 +256,10 @@ qtests_s390x = \
 qtests_riscv32 = \
   (config_all_devices.has_key('CONFIG_SIFIVE_E_AON') ? 
['sifive-e-aon-watchdog-test'] : [])
 
+ qtests_loongarch64 = \
+  qtests_filter + \
+  ['boot-serial-test']
+
 qos_test_ss = ss.source_set()
 qos_test_ss.add(
   'ac97-test.c',

base-commit: 4e66a08546a2588a4667766a1edab9caccf24ce3
-- 
2.39.3




[PATCH v4 0/5] Add migration test for loongarch64

2024-05-07 Thread Bibo Mao
Migration test case is added for loongarch64 here. Since compat machine
type is required for migration test case, also compat machine qemu 9.0
is added for loongarch virt machine.

Migration test case passes to run in both tcg and kvm mode with the
patch, 54 migration subtests passes in 188 seconds.

---
v3 ... v4:
  1. Rename VIRT_MACHINE with LOONGARCH_VIRT_MACHINE since other
architectures have the same machine type.

v2 ... v3:
  1. Refresh the patch based on the latest qemu version, solve the
confliction issue.

v1 ... v2:
  1. Keep the default memory size unchanged with 1GB, only modify minimum
memory size with 256MB
  2. Remove tab char in file tests/migration/loongarch64/a-b-kernel.S
---
Bibo Mao (5):
  hw/loongarch: Rename LOONGARCH_MACHINE with LOONGARCH_VIRT_MACHINE
  hw/loongarch: Rename LoongArchMachineState with
LoongArchVirtMachineState
  hw/loongarch: Add compat machine for 9.0
  hw/loongarch: Set minimium memory size as 256M
  tests: Add migration test for loongarch64

 hw/loongarch/acpi-build.c|  88 ++---
 hw/loongarch/boot.c  |  10 +-
 hw/loongarch/fw_cfg.c|   2 +-
 hw/loongarch/fw_cfg.h|   2 +-
 hw/loongarch/virt.c  | 393 ---
 include/hw/loongarch/virt.h  |   9 +-
 tests/migration/Makefile |   2 +-
 tests/migration/loongarch64/Makefile |  18 ++
 tests/migration/loongarch64/a-b-kernel.S |  49 +++
 tests/migration/loongarch64/a-b-kernel.h |  16 +
 tests/migration/migration-test.h |   3 +
 tests/qtest/meson.build  |   4 +
 tests/qtest/migration-test.c |  10 +
 13 files changed, 370 insertions(+), 236 deletions(-)
 create mode 100644 tests/migration/loongarch64/Makefile
 create mode 100644 tests/migration/loongarch64/a-b-kernel.S
 create mode 100644 tests/migration/loongarch64/a-b-kernel.h


base-commit: 4e66a08546a2588a4667766a1edab9caccf24ce3
-- 
2.39.3




[PATCH v4 4/5] hw/loongarch: Set minimium memory size as 256M

2024-05-07 Thread Bibo Mao
The minimum memory size for LoongArch UEFI bios is 256M, also some
test cases such as migration and qos use 256M memory by default.

Here set minimum memory size for Loongarch VirtMachine with 256M rather
than 1G, so that test cases with 256M memory can pass to run.

Signed-off-by: Bibo Mao 
---
 hw/loongarch/virt.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index c3bb343574..5d590cf92f 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -894,8 +894,8 @@ static void virt_init(MachineState *machine)
 cpu_model = LOONGARCH_CPU_TYPE_NAME("la464");
 }
 
-if (ram_size < 1 * GiB) {
-error_report("ram_size must be greater than 1G.");
+if (ram_size < 256 * MiB) {
+error_report("ram_size must be greater than 256M.");
 exit(1);
 }
 create_fdt(lvms);
-- 
2.39.3




[PATCH v4 1/5] hw/loongarch: Rename LOONGARCH_MACHINE with LOONGARCH_VIRT_MACHINE

2024-05-07 Thread Bibo Mao
On LoongArch system, there is only virt machine type now, name
LOONGARCH_MACHINE is confused, rename it with LOONGARCH_VIRT_MACHINE.
Machine name about Other real hw boards can be added in future.

Signed-off-by: Bibo Mao 
---
 hw/loongarch/acpi-build.c   |  8 
 hw/loongarch/boot.c |  2 +-
 hw/loongarch/virt.c | 19 +--
 include/hw/loongarch/virt.h |  4 ++--
 4 files changed, 16 insertions(+), 17 deletions(-)

diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c
index e5ab1080af..c7150cc0c4 100644
--- a/hw/loongarch/acpi-build.c
+++ b/hw/loongarch/acpi-build.c
@@ -167,7 +167,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, 
MachineState *machine)
 int i, arch_id, node_id;
 uint64_t mem_len, mem_base;
 int nb_numa_nodes = machine->numa_state->num_nodes;
-LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
+LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(machine);
 MachineClass *mc = MACHINE_GET_CLASS(lams);
 const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(machine);
 AcpiTable table = { .sig = "SRAT", .rev = 1, .oem_id = lams->oem_id,
@@ -279,7 +279,7 @@ static void
 build_la_ged_aml(Aml *dsdt, MachineState *machine)
 {
 uint32_t event;
-LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
+LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(machine);
 
 build_ged_aml(dsdt, "\\_SB."GED_DEVICE,
   HOTPLUG_HANDLER(lams->acpi_ged),
@@ -391,7 +391,7 @@ static void
 build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine)
 {
 Aml *dsdt, *scope, *pkg;
-LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
+LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(machine);
 AcpiTable table = { .sig = "DSDT", .rev = 1, .oem_id = lams->oem_id,
 .oem_table_id = lams->oem_table_id };
 
@@ -421,7 +421,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, 
MachineState *machine)
 
 static void acpi_build(AcpiBuildTables *tables, MachineState *machine)
 {
-LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
+LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(machine);
 GArray *table_offsets;
 AcpiFadtData fadt_data;
 unsigned facs, rsdt, dsdt;
diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index 7d1630b2e7..9b4a2d19a9 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -316,7 +316,7 @@ static void loongarch_direct_kernel_boot(struct 
loongarch_boot_info *info)
 
 void loongarch_load_kernel(MachineState *ms, struct loongarch_boot_info *info)
 {
-LoongArchMachineState *lams = LOONGARCH_MACHINE(ms);
+LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(ms);
 int i;
 
 /* register reset function */
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index c0999878df..6619cb52a9 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -880,7 +880,7 @@ static void loongarch_init(MachineState *machine)
 ram_addr_t ram_size = machine->ram_size;
 uint64_t highram_size = 0, phyAddr = 0;
 MemoryRegion *address_space_mem = get_system_memory();
-LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
+LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(machine);
 int nb_numa_nodes = machine->numa_state->num_nodes;
 NodeInfo *numa_info = machine->numa_state->nodes;
 int i;
@@ -1032,7 +1032,7 @@ bool loongarch_is_acpi_enabled(LoongArchMachineState 
*lams)
 static void loongarch_get_acpi(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
 {
-LoongArchMachineState *lams = LOONGARCH_MACHINE(obj);
+LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(obj);
 OnOffAuto acpi = lams->acpi;
 
 visit_type_OnOffAuto(v, name, , errp);
@@ -1041,14 +1041,14 @@ static void loongarch_get_acpi(Object *obj, Visitor *v, 
const char *name,
 static void loongarch_set_acpi(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
 {
-LoongArchMachineState *lams = LOONGARCH_MACHINE(obj);
+LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(obj);
 
 visit_type_OnOffAuto(v, name, >acpi, errp);
 }
 
 static void loongarch_machine_initfn(Object *obj)
 {
-LoongArchMachineState *lams = LOONGARCH_MACHINE(obj);
+LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(obj);
 
 lams->acpi = ON_OFF_AUTO_AUTO;
 lams->oem_id = g_strndup(ACPI_BUILD_APPNAME6, 6);
@@ -1080,7 +1080,7 @@ static void virt_machine_device_pre_plug(HotplugHandler 
*hotplug_dev,
 static void virt_mem_unplug_request(HotplugHandler *hotplug_dev,
  DeviceState *dev, Error **errp)
 {
-LoongArchMachineState *lams = LOONGARCH_MACHINE(hotplug_dev);
+LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(hotplug_dev);
 
 /* the acpi g

[PATCH v4 2/5] hw/loongarch: Rename LoongArchMachineState with LoongArchVirtMachineState

2024-05-07 Thread Bibo Mao
Rename LoongArchMachineState with LoongArchVirtMachineState, and change
variable name LoongArchMachineState *lams with LoongArchVirtMachineState
*lvms.

Rename function specific for virtmachine loongarch_xxx()
with virt_xxx(). However some common functions keep unchanged such as
loongarch_acpi_setup()/loongarch_load_kernel(), since there functions
can be used for real hw boards.

Signed-off-by: Bibo Mao 
---
 hw/loongarch/acpi-build.c   |  89 +-
 hw/loongarch/boot.c |  10 +-
 hw/loongarch/fw_cfg.c   |   2 +-
 hw/loongarch/fw_cfg.h   |   2 +-
 hw/loongarch/virt.c | 340 ++--
 include/hw/loongarch/virt.h |   7 +-
 6 files changed, 226 insertions(+), 224 deletions(-)

diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c
index c7150cc0c4..5ef010d4da 100644
--- a/hw/loongarch/acpi-build.c
+++ b/hw/loongarch/acpi-build.c
@@ -105,14 +105,15 @@ build_facs(GArray *table_data)
 
 /* build MADT */
 static void
-build_madt(GArray *table_data, BIOSLinker *linker, LoongArchMachineState *lams)
+build_madt(GArray *table_data, BIOSLinker *linker,
+   LoongArchVirtMachineState *lvms)
 {
-MachineState *ms = MACHINE(lams);
+MachineState *ms = MACHINE(lvms);
 MachineClass *mc = MACHINE_GET_CLASS(ms);
 const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(ms);
 int i, arch_id;
-AcpiTable table = { .sig = "APIC", .rev = 1, .oem_id = lams->oem_id,
-.oem_table_id = lams->oem_table_id };
+AcpiTable table = { .sig = "APIC", .rev = 1, .oem_id = lvms->oem_id,
+.oem_table_id = lvms->oem_table_id };
 
 acpi_table_begin(, table_data);
 
@@ -167,11 +168,11 @@ build_srat(GArray *table_data, BIOSLinker *linker, 
MachineState *machine)
 int i, arch_id, node_id;
 uint64_t mem_len, mem_base;
 int nb_numa_nodes = machine->numa_state->num_nodes;
-LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(machine);
-MachineClass *mc = MACHINE_GET_CLASS(lams);
+LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine);
+MachineClass *mc = MACHINE_GET_CLASS(lvms);
 const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(machine);
-AcpiTable table = { .sig = "SRAT", .rev = 1, .oem_id = lams->oem_id,
-.oem_table_id = lams->oem_table_id };
+AcpiTable table = { .sig = "SRAT", .rev = 1, .oem_id = lvms->oem_id,
+.oem_table_id = lvms->oem_table_id };
 
 acpi_table_begin(, table_data);
 build_append_int_noprefix(table_data, 1, 4); /* Reserved */
@@ -279,13 +280,13 @@ static void
 build_la_ged_aml(Aml *dsdt, MachineState *machine)
 {
 uint32_t event;
-LoongArchMachineState *lams = LOONGARCH_VIRT_MACHINE(machine);
+LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine);
 
 build_ged_aml(dsdt, "\\_SB."GED_DEVICE,
-  HOTPLUG_HANDLER(lams->acpi_ged),
+  HOTPLUG_HANDLER(lvms->acpi_ged),
   VIRT_SCI_IRQ, AML_SYSTEM_MEMORY,
   VIRT_GED_EVT_ADDR);
-event = object_property_get_uint(OBJECT(lams->acpi_ged),
+event = object_property_get_uint(OBJECT(lvms->acpi_ged),
  "ged-event", _abort);
 if (event & ACPI_GED_MEM_HOTPLUG_EVT) {
 build_memory_hotplug_aml(dsdt, machine->ram_slots, "\\_SB", NULL,
@@ -295,7 +296,7 @@ build_la_ged_aml(Aml *dsdt, MachineState *machine)
 acpi_dsdt_add_power_button(dsdt);
 }
 
-static void build_pci_device_aml(Aml *scope, LoongArchMachineState *lams)
+static void build_pci_device_aml(Aml *scope, LoongArchVirtMachineState *lvms)
 {
 struct GPEXConfig cfg = {
 .mmio64.base = VIRT_PCI_MEM_BASE,
@@ -305,13 +306,13 @@ static void build_pci_device_aml(Aml *scope, 
LoongArchMachineState *lams)
 .ecam.base   = VIRT_PCI_CFG_BASE,
 .ecam.size   = VIRT_PCI_CFG_SIZE,
 .irq = VIRT_GSI_BASE + VIRT_DEVICE_IRQS,
-.bus = lams->pci_bus,
+.bus = lvms->pci_bus,
 };
 
 acpi_dsdt_add_gpex(scope, );
 }
 
-static void build_flash_aml(Aml *scope, LoongArchMachineState *lams)
+static void build_flash_aml(Aml *scope, LoongArchVirtMachineState *lvms)
 {
 Aml *dev, *crs;
 MemoryRegion *flash_mem;
@@ -322,11 +323,11 @@ static void build_flash_aml(Aml *scope, 
LoongArchMachineState *lams)
 hwaddr flash1_base;
 hwaddr flash1_size;
 
-flash_mem = pflash_cfi01_get_memory(lams->flash[0]);
+flash_mem = pflash_cfi01_get_memory(lvms->flash[0]);
 flash0_base = flash_mem->addr;
 flash0_size = memory_region_size(flash_mem);
 
-flash_mem = pflash_cfi01_get_memory(lams->flash[1]);
+flash_mem = pflash_cfi01_get_memory(lvms->flash[1]);
 flash1_base = flash_mem->addr;
 flash1_size = memory_reg

[PATCH v4 5/5] tests: Add migration test for loongarch64

2024-05-07 Thread Bibo Mao
This patch adds migration test support for loongarch64. The test code
comes from aarch64 mostly, only that it booted as bios in qemu since
kernel requires elf format and bios uses binary format.

In addition to providing the binary, this patch also includes the source
code and the build script in tests/migration/loongarch64. So users can
change the source and/or re-compile the binary as they wish.

Signed-off-by: Bibo Mao 
Acked-by: Thomas Huth 
Acked-by: Peter Xu 
Reviewed-by: Fabiano Rosas 
---
 tests/migration/Makefile |  2 +-
 tests/migration/loongarch64/Makefile | 18 +
 tests/migration/loongarch64/a-b-kernel.S | 49 
 tests/migration/loongarch64/a-b-kernel.h | 16 
 tests/migration/migration-test.h |  3 ++
 tests/qtest/meson.build  |  4 ++
 tests/qtest/migration-test.c | 10 +
 7 files changed, 101 insertions(+), 1 deletion(-)
 create mode 100644 tests/migration/loongarch64/Makefile
 create mode 100644 tests/migration/loongarch64/a-b-kernel.S
 create mode 100644 tests/migration/loongarch64/a-b-kernel.h

diff --git a/tests/migration/Makefile b/tests/migration/Makefile
index 13e99b1692..cfebfe23f8 100644
--- a/tests/migration/Makefile
+++ b/tests/migration/Makefile
@@ -5,7 +5,7 @@
 # See the COPYING file in the top-level directory.
 #
 
-TARGET_LIST = i386 aarch64 s390x
+TARGET_LIST = i386 aarch64 s390x loongarch64
 
 SRC_PATH = ../..
 
diff --git a/tests/migration/loongarch64/Makefile 
b/tests/migration/loongarch64/Makefile
new file mode 100644
index 00..5d8719205f
--- /dev/null
+++ b/tests/migration/loongarch64/Makefile
@@ -0,0 +1,18 @@
+# To specify cross compiler prefix, use CROSS_PREFIX=
+#   $ make CROSS_PREFIX=loongarch64-linux-gnu-
+
+.PHONY: all clean
+all: a-b-kernel.h
+
+a-b-kernel.h: loongarch64.kernel
+   echo "$$__note" > $@
+   xxd -i $< | sed -e 's/.*int.*//' >> $@
+
+loongarch64.kernel: loongarch64.elf
+   $(CROSS_PREFIX)objcopy -j .text -O binary $< $@
+
+loongarch64.elf: a-b-kernel.S
+   $(CROSS_PREFIX)gcc -o $@ -nostdlib -Wl,--build-id=none $<
+
+clean:
+   $(RM) *.kernel *.elf
diff --git a/tests/migration/loongarch64/a-b-kernel.S 
b/tests/migration/loongarch64/a-b-kernel.S
new file mode 100644
index 00..cd543345fe
--- /dev/null
+++ b/tests/migration/loongarch64/a-b-kernel.S
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2024 Loongson Technology Corporation Limited
+ */
+#include "../migration-test.h"
+
+#define LOONGARCH_CSR_CRMD  0
+#define LOONGARCH_VIRT_UART 0x1FE001E0
+.section .text
+
+.globl  _start
+_start:
+/* output char 'A' to UART16550 */
+li.d$t0, LOONGARCH_VIRT_UART
+li.w$t1, 'A'
+st.b$t1, $t0, 0
+
+/* traverse test memory region */
+li.d$t0, LOONGARCH_TEST_MEM_START
+li.d$t1, LOONGARCH_TEST_MEM_END
+li.d$t2, TEST_MEM_PAGE_SIZE
+li.d$t4, LOONGARCH_VIRT_UART
+li.w$t5, 'B'
+
+clean:
+st.b$zero, $t0, 0
+add.d   $t0,   $t0, $t2
+bne $t0,   $t1, clean
+/* keeps a counter so we can limit the output speed */
+addi.d  $t6,   $zero, 0
+
+mainloop:
+li.d$t0, LOONGARCH_TEST_MEM_START
+
+innerloop:
+ld.bu   $t3, $t0, 0
+addi.w  $t3, $t3, 1
+ext.w.b $t3, $t3
+st.b$t3, $t0, 0
+add.d   $t0, $t0, $t2
+bne $t0, $t1, innerloop
+
+addi.d  $t6, $t6, 1
+andi$t6, $t6, 31
+bnez$t6, mainloop
+
+st.b$t5, $t4, 0
+b   mainloop
+nop
diff --git a/tests/migration/loongarch64/a-b-kernel.h 
b/tests/migration/loongarch64/a-b-kernel.h
new file mode 100644
index 00..b3fe466754
--- /dev/null
+++ b/tests/migration/loongarch64/a-b-kernel.h
@@ -0,0 +1,16 @@
+/* This file is automatically generated from the assembly file in
+* tests/migration/loongarch64. Edit that file and then run "make all"
+* inside tests/migration to update, and then remember to send both
+* the header and the assembler differences in your patch submission.
+*/
+unsigned char loongarch64_kernel[] = {
+  0x0c, 0xc0, 0x3f, 0x14, 0x8c, 0x81, 0x87, 0x03, 0x0d, 0x04, 0x81, 0x03,
+  0x8d, 0x01, 0x00, 0x29, 0x0c, 0x00, 0x04, 0x14, 0x0d, 0x80, 0x0c, 0x14,
+  0x2e, 0x00, 0x00, 0x14, 0x10, 0xc0, 0x3f, 0x14, 0x10, 0x82, 0x87, 0x03,
+  0x11, 0x08, 0x81, 0x03, 0x80, 0x01, 0x00, 0x29, 0x8c, 0xb9, 0x10, 0x00,
+  0x8d, 0xf9, 0xff, 0x5f, 0x12, 0x00, 0xc0, 0x02, 0x0c, 0x00, 0x04, 0x14,
+  0x8f, 0x01, 0x00, 0x2a, 0xef, 0x05, 0x80, 0x02, 0xef, 0x5d, 0x00, 0x00,
+  0x8f, 0x01, 0x00, 0x29, 0x8c, 0xb9, 0x10, 0x00, 0x8d, 0xed, 0xff, 0x5f,
+  0x52, 0x06, 0xc0, 0x02, 0x52, 0x7e, 0x40, 0x03, 0x5f, 0xde, 0xff, 0x47,
+  0x11, 0x02, 0x00, 0x29, 0xff, 0xd7, 0xff, 0x53, 0x00, 0x00, 0x40, 0x03
+};
diff --git a/tests/migration/migration-test.h b/tests/migration/migration-test.h
index 68512c0b1b..f402e48349 100644
--- a/tests/migration/migrati

[PATCH v4 3/5] hw/loongarch: Add compat machine for 9.0

2024-05-07 Thread Bibo Mao
Since migration test case requires compat machine type support,
compat machine is added for qemu 9.0 here.

Signed-off-by: Bibo Mao 
---
 hw/loongarch/virt.c | 61 +++--
 1 file changed, 48 insertions(+), 13 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 93cdadfb8a..c3bb343574 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -1236,18 +1236,53 @@ static void virt_class_init(ObjectClass *oc, void *data)
 #endif
 }
 
-static const TypeInfo virt_machine_types[] = {
-{
-.name   = TYPE_LOONGARCH_VIRT_MACHINE,
-.parent = TYPE_MACHINE,
-.instance_size  = sizeof(LoongArchVirtMachineState),
-.class_init = virt_class_init,
-.instance_init  = virt_initfn,
-.interfaces = (InterfaceInfo[]) {
- { TYPE_HOTPLUG_HANDLER },
- { }
-},
-}
+#define DEFINE_VIRT_MACHINE_LATEST(major, minor, latest) \
+static void virt_##major##_##minor##_class_init(ObjectClass *oc, \
+void *data) \
+{ \
+MachineClass *mc = MACHINE_CLASS(oc); \
+virt_machine_##major##_##minor##_options(mc); \
+mc->desc = "QEMU " # major "." # minor " LoongArch Virtual Machine"; \
+if (latest) { \
+mc->alias = "virt"; \
+} \
+} \
+static const TypeInfo machvirt_##major##_##minor##_info = { \
+.name = MACHINE_TYPE_NAME("virt-" # major "." # minor), \
+.parent = TYPE_LOONGARCH_VIRT_MACHINE, \
+.class_init = virt_##major##_##minor##_class_init, \
+}; \
+static void machvirt_machine_##major##_##minor##_init(void) \
+{ \
+type_register_static(_##major##_##minor##_info); \
+} \
+type_init(machvirt_machine_##major##_##minor##_init);
+
+#define DEFINE_VIRT_MACHINE_AS_LATEST(major, minor) \
+DEFINE_VIRT_MACHINE_LATEST(major, minor, true)
+#define DEFINE_VIRT_MACHINE(major, minor) \
+DEFINE_VIRT_MACHINE_LATEST(major, minor, false)
+
+static const TypeInfo virt_machine_info = {
+.name   = TYPE_LOONGARCH_VIRT_MACHINE,
+.parent = TYPE_MACHINE,
+.abstract   = true,
+.instance_size  = sizeof(LoongArchVirtMachineState),
+.class_init = virt_class_init,
+.instance_init  = virt_initfn,
+.interfaces = (InterfaceInfo[]) {
+{ TYPE_HOTPLUG_HANDLER },
+{ }
+},
 };
 
-DEFINE_TYPES(virt_machine_types)
+static void machvirt_machine_init(void)
+{
+type_register_static(_machine_info);
+}
+type_init(machvirt_machine_init);
+
+static void virt_machine_9_0_options(MachineClass *mc)
+{
+}
+DEFINE_VIRT_MACHINE_AS_LATEST(9, 0)
-- 
2.39.3




[PATCH v2 1/6] hw/loongarch: Refine acpi srat table for numa memory

2024-05-06 Thread Bibo Mao
One LoongArch virt machine platform, there is limitation for memory
map information. The minimum memory size is 256M and minimum memory
size for numa node0 is 256M also. With qemu numa qtest, it is possible
that memory size of numa node0 is 128M.

Limitations for minimum memory size for both total memory and numa
node0 is removed for acpi srat table creation.

Signed-off-by: Bibo Mao 
---
 hw/loongarch/acpi-build.c | 58 +++
 1 file changed, 34 insertions(+), 24 deletions(-)

diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c
index e5ab1080af..d0247d93ee 100644
--- a/hw/loongarch/acpi-build.c
+++ b/hw/loongarch/acpi-build.c
@@ -165,8 +165,9 @@ static void
 build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
 {
 int i, arch_id, node_id;
-uint64_t mem_len, mem_base;
-int nb_numa_nodes = machine->numa_state->num_nodes;
+hwaddr len, base, gap;
+NodeInfo *numa_info;
+int nodes, nb_numa_nodes = machine->numa_state->num_nodes;
 LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
 MachineClass *mc = MACHINE_GET_CLASS(lams);
 const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(machine);
@@ -195,35 +196,44 @@ build_srat(GArray *table_data, BIOSLinker *linker, 
MachineState *machine)
 build_append_int_noprefix(table_data, 0, 4); /* Reserved */
 }
 
-/* Node0 */
-build_srat_memory(table_data, VIRT_LOWMEM_BASE, VIRT_LOWMEM_SIZE,
-  0, MEM_AFFINITY_ENABLED);
-mem_base = VIRT_HIGHMEM_BASE;
-if (!nb_numa_nodes) {
-mem_len = machine->ram_size - VIRT_LOWMEM_SIZE;
-} else {
-mem_len = machine->numa_state->nodes[0].node_mem - VIRT_LOWMEM_SIZE;
+base = VIRT_LOWMEM_BASE;
+gap = VIRT_LOWMEM_SIZE;
+numa_info = machine->numa_state->nodes;
+nodes = nb_numa_nodes;
+if (!nodes) {
+nodes = 1;
 }
-if (mem_len)
-build_srat_memory(table_data, mem_base, mem_len, 0, 
MEM_AFFINITY_ENABLED);
-
-/* Node1 - Nodemax */
-if (nb_numa_nodes) {
-mem_base += mem_len;
-for (i = 1; i < nb_numa_nodes; ++i) {
-if (machine->numa_state->nodes[i].node_mem > 0) {
-build_srat_memory(table_data, mem_base,
-  machine->numa_state->nodes[i].node_mem, i,
-  MEM_AFFINITY_ENABLED);
-mem_base += machine->numa_state->nodes[i].node_mem;
-}
+
+for (i = 0; i < nodes; i++) {
+if (nb_numa_nodes) {
+len = numa_info[i].node_mem;
+} else {
+len = machine->ram_size;
+}
+
+/*
+ * memory for the node splited into two part
+ *   lowram:  [base, +gap)
+ *   highram: [VIRT_HIGHMEM_BASE, +(len - gap))
+ */
+if (len >= gap) {
+build_srat_memory(table_data, base, len, i, MEM_AFFINITY_ENABLED);
+len -= gap;
+base = VIRT_HIGHMEM_BASE;
+gap = machine->ram_size - VIRT_LOWMEM_SIZE;
+}
+
+if (len) {
+build_srat_memory(table_data, base, len, i, MEM_AFFINITY_ENABLED);
+base += len;
+gap  -= len;
 }
 }
 
 if (machine->device_memory) {
 build_srat_memory(table_data, machine->device_memory->base,
   memory_region_size(>device_memory->mr),
-  nb_numa_nodes - 1,
+  nodes - 1,
   MEM_AFFINITY_HOTPLUGGABLE | MEM_AFFINITY_ENABLED);
 }
 
-- 
2.39.3




[PATCH v2 6/6] tests/qtest: Add numa test for loongarch system

2024-05-06 Thread Bibo Mao
Add numa test case for loongarch system, it passes to run
with command "make check-qtest", after the following patch
is applied.
https://lore.kernel.org/all/20240319022606.2994565-1-maob...@loongson.cn/

Signed-off-by: Bibo Mao 
---
 tests/qtest/meson.build | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 6f2f594ace..a72436df65 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -256,6 +256,8 @@ qtests_s390x = \
 qtests_riscv32 = \
   (config_all_devices.has_key('CONFIG_SIFIVE_E_AON') ? 
['sifive-e-aon-watchdog-test'] : [])
 
+qtests_loongarch64 = ['numa-test']
+
 qos_test_ss = ss.source_set()
 qos_test_ss.add(
   'ac97-test.c',
-- 
2.39.3




[PATCH v2 4/6] hw/loongarch: Refine system dram memory region

2024-05-06 Thread Bibo Mao
For system dram memory region, it is not necessary to use numa node
information. There is only low memory region and high memory region.

Remove numa node information for ddr memory region here, it can reduce
memory region number about LoongArch virt machine.

Signed-off-by: Bibo Mao 
---
 hw/loongarch/virt.c | 55 ++---
 1 file changed, 17 insertions(+), 38 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index aca8290795..5abfe0a9d7 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -974,18 +974,13 @@ static void loongarch_init(MachineState *machine)
 {
 LoongArchCPU *lacpu;
 const char *cpu_model = machine->cpu_type;
-ram_addr_t offset = 0;
-ram_addr_t ram_size = machine->ram_size;
-uint64_t highram_size = 0, phyAddr = 0;
 MemoryRegion *address_space_mem = get_system_memory();
 LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
-int nb_numa_nodes = machine->numa_state->num_nodes;
-NodeInfo *numa_info = machine->numa_state->nodes;
 int i;
+hwaddr base, size, ram_size = machine->ram_size;
 const CPUArchIdList *possible_cpus;
 MachineClass *mc = MACHINE_GET_CLASS(machine);
 CPUState *cpu;
-char *ramName = NULL;
 
 if (!cpu_model) {
 cpu_model = LOONGARCH_CPU_TYPE_NAME("la464");
@@ -1020,41 +1015,27 @@ static void loongarch_init(MachineState *machine)
 fdt_add_memory_nodes(machine);
 fw_cfg_add_memory(machine);
 
-/* Node0 memory */
-memory_region_init_alias(>lowmem, NULL, "loongarch.node0.lowram",
- machine->ram, offset, VIRT_LOWMEM_SIZE);
-memory_region_add_subregion(address_space_mem, phyAddr, >lowmem);
-
-offset += VIRT_LOWMEM_SIZE;
-if (nb_numa_nodes > 0) {
-assert(numa_info[0].node_mem > VIRT_LOWMEM_SIZE);
-highram_size = numa_info[0].node_mem - VIRT_LOWMEM_SIZE;
-} else {
-highram_size = ram_size - VIRT_LOWMEM_SIZE;
+size = ram_size;
+base = VIRT_LOWMEM_BASE;
+if (size > VIRT_LOWMEM_SIZE) {
+size = VIRT_LOWMEM_SIZE;
 }
-phyAddr = VIRT_HIGHMEM_BASE;
-memory_region_init_alias(>highmem, NULL, "loongarch.node0.highram",
-  machine->ram, offset, highram_size);
-memory_region_add_subregion(address_space_mem, phyAddr, >highmem);
-
-/* Node1 - Nodemax memory */
-offset += highram_size;
-phyAddr += highram_size;
-
-for (i = 1; i < nb_numa_nodes; i++) {
-MemoryRegion *nodemem = g_new(MemoryRegion, 1);
-ramName = g_strdup_printf("loongarch.node%d.ram", i);
-memory_region_init_alias(nodemem, NULL, ramName, machine->ram,
- offset,  numa_info[i].node_mem);
-memory_region_add_subregion(address_space_mem, phyAddr, nodemem);
-offset += numa_info[i].node_mem;
-phyAddr += numa_info[i].node_mem;
+
+memory_region_init_alias(>lowmem, NULL, "loongarch.lowram",
+  machine->ram, base, size);
+memory_region_add_subregion(address_space_mem, base, >lowmem);
+base += size;
+if (ram_size - size) {
+base = VIRT_HIGHMEM_BASE;
+memory_region_init_alias(>highmem, NULL, "loongarch.highram",
+machine->ram, VIRT_LOWMEM_BASE + size, ram_size - size);
+memory_region_add_subregion(address_space_mem, base, >highmem);
+base += ram_size - size;
 }
 
 /* initialize device memory address space */
 if (machine->ram_size < machine->maxram_size) {
 ram_addr_t device_mem_size = machine->maxram_size - machine->ram_size;
-hwaddr device_mem_base;
 
 if (machine->ram_slots > ACPI_MAX_RAM_SLOTS) {
 error_report("unsupported amount of memory slots: %"PRIu64,
@@ -1068,9 +1049,7 @@ static void loongarch_init(MachineState *machine)
  "%d bytes", TARGET_PAGE_SIZE);
 exit(EXIT_FAILURE);
 }
-/* device memory base is the top of high memory address. */
-device_mem_base = ROUND_UP(VIRT_HIGHMEM_BASE + highram_size, 1 * GiB);
-machine_memory_devices_init(machine, device_mem_base, device_mem_size);
+machine_memory_devices_init(machine, base, device_mem_size);
 }
 
 /* load the BIOS image. */
-- 
2.39.3




[PATCH v2 3/6] hw/loongarch: Refine fwcfg memory map

2024-05-06 Thread Bibo Mao
Memory map table for fwcfg is used for UEFI BIOS, UEFI BIOS uses the first
entry from fwcfg memory map as the first memory HOB, the second memory HOB
will be used if the first memory HOB is used up.

Memory map table for fwcfg does not care about numa node, however in
generic the first memory HOB is part of numa node0, so that runtime
memory of UEFI which is allocated from the first memory HOB is located
at numa node0.

Signed-off-by: Bibo Mao 
---
 hw/loongarch/virt.c | 60 ++---
 1 file changed, 57 insertions(+), 3 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index db76bc94f8..aca8290795 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -914,6 +914,62 @@ static const MemoryRegionOps loongarch_qemu_ops = {
 },
 };
 
+static void fw_cfg_add_memory(MachineState *ms)
+{
+hwaddr base, size, ram_size, gap;
+int nb_numa_nodes, nodes;
+NodeInfo *numa_info;
+
+ram_size = ms->ram_size;
+base = VIRT_LOWMEM_BASE;
+gap = VIRT_LOWMEM_SIZE;
+nodes = nb_numa_nodes = ms->numa_state->num_nodes;
+numa_info = ms->numa_state->nodes;
+if (!nodes) {
+nodes = 1;
+}
+
+/* add fw_cfg memory map of node0 */
+if (nb_numa_nodes) {
+size = numa_info[0].node_mem;
+} else {
+size = ram_size;
+}
+
+if (size >= gap) {
+memmap_add_entry(base, gap, 1);
+size -= gap;
+base = VIRT_HIGHMEM_BASE;
+gap = ram_size - VIRT_LOWMEM_SIZE;
+}
+
+if (size) {
+memmap_add_entry(base, size, 1);
+base += size;
+}
+
+if (nodes < 2) {
+return;
+}
+
+/* add fw_cfg memory map of other nodes */
+size = ram_size - numa_info[0].node_mem;
+gap  = VIRT_LOWMEM_BASE + VIRT_LOWMEM_SIZE;
+if (base < gap && (base + size) > gap) {
+/*
+ * memory map for the maining nodes splited into two part
+ *   lowram:  [base, +(gap - base))
+ *   highram: [VIRT_HIGHMEM_BASE, +(size - (gap - base)))
+ */
+memmap_add_entry(base, gap - base, 1);
+size -= gap - base;
+base = VIRT_HIGHMEM_BASE;
+}
+
+   if (size)
+memmap_add_entry(base, size, 1);
+}
+
 static void loongarch_init(MachineState *machine)
 {
 LoongArchCPU *lacpu;
@@ -962,9 +1018,9 @@ static void loongarch_init(MachineState *machine)
 fdt_add_cpu_nodes(lams);
 
 fdt_add_memory_nodes(machine);
+fw_cfg_add_memory(machine);
 
 /* Node0 memory */
-memmap_add_entry(VIRT_LOWMEM_BASE, VIRT_LOWMEM_SIZE, 1);
 memory_region_init_alias(>lowmem, NULL, "loongarch.node0.lowram",
  machine->ram, offset, VIRT_LOWMEM_SIZE);
 memory_region_add_subregion(address_space_mem, phyAddr, >lowmem);
@@ -977,7 +1033,6 @@ static void loongarch_init(MachineState *machine)
 highram_size = ram_size - VIRT_LOWMEM_SIZE;
 }
 phyAddr = VIRT_HIGHMEM_BASE;
-memmap_add_entry(phyAddr, highram_size, 1);
 memory_region_init_alias(>highmem, NULL, "loongarch.node0.highram",
   machine->ram, offset, highram_size);
 memory_region_add_subregion(address_space_mem, phyAddr, >highmem);
@@ -992,7 +1047,6 @@ static void loongarch_init(MachineState *machine)
 memory_region_init_alias(nodemem, NULL, ramName, machine->ram,
  offset,  numa_info[i].node_mem);
 memory_region_add_subregion(address_space_mem, phyAddr, nodemem);
-memmap_add_entry(phyAddr, numa_info[i].node_mem, 1);
 offset += numa_info[i].node_mem;
 phyAddr += numa_info[i].node_mem;
 }
-- 
2.39.3




[PATCH v2 5/6] hw/loongarch: Remove minimum and default memory size

2024-05-06 Thread Bibo Mao
Some qtest test cases such as numa use default memory size of generic
machine class, which is 128M by fault.

Here generic default memory size is used, and also remove minimum memory
size which is 1G originally.

Signed-off-by: Bibo Mao 
---
 hw/loongarch/virt.c | 5 -
 1 file changed, 5 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 5abfe0a9d7..36477172ea 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -986,10 +986,6 @@ static void loongarch_init(MachineState *machine)
 cpu_model = LOONGARCH_CPU_TYPE_NAME("la464");
 }
 
-if (ram_size < 1 * GiB) {
-error_report("ram_size must be greater than 1G.");
-exit(1);
-}
 create_fdt(lams);
 
 /* Create IOCSR space */
@@ -1284,7 +1280,6 @@ static void loongarch_class_init(ObjectClass *oc, void 
*data)
 
 mc->desc = "Loongson-3A5000 LS7A1000 machine";
 mc->init = loongarch_init;
-mc->default_ram_size = 1 * GiB;
 mc->default_cpu_type = LOONGARCH_CPU_TYPE_NAME("la464");
 mc->default_ram_id = "loongarch.ram";
 mc->max_cpus = LOONGARCH_MAX_CPUS;
-- 
2.39.3




[PATCH v2 0/6] hw/loongarch: Refine numa memory map

2024-05-06 Thread Bibo Mao
One LoongArch virt machine platform, there is limitation for memory
map information. The minimum memory size is 256M and minimum memory
size for numa node0 is 256M also. With qemu numa qtest, it is possible
that memory size of numa node0 is 128M.

Limitations for minimum memory size for both total memory and numa
node0 is removed here, including acpi srat table, fadt memory map table
and fw_cfg memory map table.

Also remove numa node about memory region, there is only low memory
region and how memory region.

---
v1 ... v2:
  1. Refresh the patch based on the latest qemu version, solve the
confliction issue.
  2. Add numa test case for loongarch system.
---
Bibo Mao (6):
  hw/loongarch: Refine acpi srat table for numa memory
  hw/loongarch: Refine fadt memory table for numa memory
  hw/loongarch: Refine fwcfg memory map
  hw/loongarch: Refine system dram memory region
  hw/loongarch: Remove minimum and default memory size
  tests/qtest: Add numa test for loongarch system

 hw/loongarch/acpi-build.c |  58 +++--
 hw/loongarch/virt.c   | 167 +++---
 tests/qtest/meson.build   |   2 +
 3 files changed, 154 insertions(+), 73 deletions(-)


base-commit: 248f6f62df073a3b4158fd0093863ab885feabb5
-- 
2.39.3




[PATCH v2 2/6] hw/loongarch: Refine fadt memory table for numa memory

2024-05-06 Thread Bibo Mao
One LoongArch virt machine platform, there is limitation for memory
map information. The minimum memory size is 256M and minimum memory
size for numa node0 is 256M also. With qemu numa qtest, it is possible
that memory size of numa node0 is 128M.

Limitations for minimum memory size for both total memory and numa
node0 is removed for fadt numa memory table creation.

Signed-off-by: Bibo Mao 
---
 hw/loongarch/virt.c | 47 ++---
 1 file changed, 44 insertions(+), 3 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index c0999878df..db76bc94f8 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -473,6 +473,48 @@ static void fdt_add_memory_node(MachineState *ms,
 g_free(nodename);
 }
 
+static void fdt_add_memory_nodes(MachineState *ms)
+{
+hwaddr base, size, ram_size, gap;
+int i, nb_numa_nodes, nodes;
+NodeInfo *numa_info;
+
+ram_size = ms->ram_size;
+base = VIRT_LOWMEM_BASE;
+gap = VIRT_LOWMEM_SIZE;
+nodes = nb_numa_nodes = ms->numa_state->num_nodes;
+numa_info = ms->numa_state->nodes;
+if (!nodes) {
+nodes = 1;
+}
+
+for (i = 0; i < nodes; i++) {
+if (nb_numa_nodes) {
+size = numa_info[i].node_mem;
+} else {
+size = ram_size;
+}
+
+/*
+ * memory for the node splited into two part
+ *   lowram:  [base, +gap)
+ *   highram: [VIRT_HIGHMEM_BASE, +(len - gap))
+ */
+if (size >= gap) {
+fdt_add_memory_node(ms, base, gap, i);
+size -= gap;
+base = VIRT_HIGHMEM_BASE;
+gap = ram_size - VIRT_LOWMEM_SIZE;
+}
+
+if (size) {
+fdt_add_memory_node(ms, base, size, i);
+base += size;
+gap -= size;
+}
+}
+}
+
 static void virt_build_smbios(LoongArchMachineState *lams)
 {
 MachineState *ms = MACHINE(lams);
@@ -919,9 +961,10 @@ static void loongarch_init(MachineState *machine)
 }
 fdt_add_cpu_nodes(lams);
 
+fdt_add_memory_nodes(machine);
+
 /* Node0 memory */
 memmap_add_entry(VIRT_LOWMEM_BASE, VIRT_LOWMEM_SIZE, 1);
-fdt_add_memory_node(machine, VIRT_LOWMEM_BASE, VIRT_LOWMEM_SIZE, 0);
 memory_region_init_alias(>lowmem, NULL, "loongarch.node0.lowram",
  machine->ram, offset, VIRT_LOWMEM_SIZE);
 memory_region_add_subregion(address_space_mem, phyAddr, >lowmem);
@@ -935,7 +978,6 @@ static void loongarch_init(MachineState *machine)
 }
 phyAddr = VIRT_HIGHMEM_BASE;
 memmap_add_entry(phyAddr, highram_size, 1);
-fdt_add_memory_node(machine, phyAddr, highram_size, 0);
 memory_region_init_alias(>highmem, NULL, "loongarch.node0.highram",
   machine->ram, offset, highram_size);
 memory_region_add_subregion(address_space_mem, phyAddr, >highmem);
@@ -951,7 +993,6 @@ static void loongarch_init(MachineState *machine)
  offset,  numa_info[i].node_mem);
 memory_region_add_subregion(address_space_mem, phyAddr, nodemem);
 memmap_add_entry(phyAddr, numa_info[i].node_mem, 1);
-fdt_add_memory_node(machine, phyAddr, numa_info[i].node_mem, i);
 offset += numa_info[i].node_mem;
 phyAddr += numa_info[i].node_mem;
 }
-- 
2.39.3




[PATCH v3 0/5] Add migration test for loongarch64

2024-05-05 Thread Bibo Mao
Migration test case is added for loongarch64 here. Since compat machine
type is required for migration test case, also compat machine qemu 9.0
is added for loongarch virt machine.

Migration test case passes to run in both tcg and kvm mode with the
patch, 54 migration subtests passes in 188 seconds.

---
v2 ... v3:
  1. Refresh the patch based on the latest qemu version, solve the
confliction issue.

v1 ... v2:
  1. Keep the default memory size unchanged with 1GB, only modify minimum
memory size with 256MB
  2. Remove tab char in file tests/migration/loongarch64/a-b-kernel.S
---
Bibo Mao (5):
  hw/loongarch: Rename LOONGARCH_MACHINE with VIRT_MACHINE
  hw/loongarch: Rename LoongArchMachineState with VirtMachineState
  hw/loongarch: Add compat machine for 9.0
  hw/loongarch: Set minimium memory size as 256M
  tests: Add migration test for loongarch64

 hw/loongarch/acpi-build.c|  80 ++---
 hw/loongarch/boot.c  |  10 +-
 hw/loongarch/fw_cfg.c|   2 +-
 hw/loongarch/fw_cfg.h|   2 +-
 hw/loongarch/virt.c  | 364 ---
 include/hw/loongarch/virt.h  |  10 +-
 tests/migration/Makefile |   2 +-
 tests/migration/loongarch64/Makefile |  18 ++
 tests/migration/loongarch64/a-b-kernel.S |  49 +++
 tests/migration/loongarch64/a-b-kernel.h |  16 +
 tests/migration/migration-test.h |   3 +
 tests/qtest/meson.build  |   4 +
 tests/qtest/migration-test.c |  10 +
 13 files changed, 351 insertions(+), 219 deletions(-)
 create mode 100644 tests/migration/loongarch64/Makefile
 create mode 100644 tests/migration/loongarch64/a-b-kernel.S
 create mode 100644 tests/migration/loongarch64/a-b-kernel.h


base-commit: 248f6f62df073a3b4158fd0093863ab885feabb5
-- 
2.39.3




[PATCH v3 1/5] hw/loongarch: Rename LOONGARCH_MACHINE with VIRT_MACHINE

2024-05-05 Thread Bibo Mao
On LoongArch system, there is only virt machine type now, name
LOONGARCH_MACHINE is confused, rename it with VIRT_MACHINE. Machine name
about Other real hw boards can be added in future.

Signed-off-by: Bibo Mao 
---
 hw/loongarch/acpi-build.c   |  8 
 hw/loongarch/boot.c |  2 +-
 hw/loongarch/virt.c | 19 +--
 include/hw/loongarch/virt.h |  4 ++--
 4 files changed, 16 insertions(+), 17 deletions(-)

diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c
index e5ab1080af..72322cdb1e 100644
--- a/hw/loongarch/acpi-build.c
+++ b/hw/loongarch/acpi-build.c
@@ -167,7 +167,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, 
MachineState *machine)
 int i, arch_id, node_id;
 uint64_t mem_len, mem_base;
 int nb_numa_nodes = machine->numa_state->num_nodes;
-LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
+LoongArchMachineState *lams = VIRT_MACHINE(machine);
 MachineClass *mc = MACHINE_GET_CLASS(lams);
 const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(machine);
 AcpiTable table = { .sig = "SRAT", .rev = 1, .oem_id = lams->oem_id,
@@ -279,7 +279,7 @@ static void
 build_la_ged_aml(Aml *dsdt, MachineState *machine)
 {
 uint32_t event;
-LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
+LoongArchMachineState *lams = VIRT_MACHINE(machine);
 
 build_ged_aml(dsdt, "\\_SB."GED_DEVICE,
   HOTPLUG_HANDLER(lams->acpi_ged),
@@ -391,7 +391,7 @@ static void
 build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine)
 {
 Aml *dsdt, *scope, *pkg;
-LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
+LoongArchMachineState *lams = VIRT_MACHINE(machine);
 AcpiTable table = { .sig = "DSDT", .rev = 1, .oem_id = lams->oem_id,
 .oem_table_id = lams->oem_table_id };
 
@@ -421,7 +421,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, 
MachineState *machine)
 
 static void acpi_build(AcpiBuildTables *tables, MachineState *machine)
 {
-LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
+LoongArchMachineState *lams = VIRT_MACHINE(machine);
 GArray *table_offsets;
 AcpiFadtData fadt_data;
 unsigned facs, rsdt, dsdt;
diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index 7d1630b2e7..e46c70b1b3 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -316,7 +316,7 @@ static void loongarch_direct_kernel_boot(struct 
loongarch_boot_info *info)
 
 void loongarch_load_kernel(MachineState *ms, struct loongarch_boot_info *info)
 {
-LoongArchMachineState *lams = LOONGARCH_MACHINE(ms);
+LoongArchMachineState *lams = VIRT_MACHINE(ms);
 int i;
 
 /* register reset function */
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index c0999878df..e343974b48 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -880,7 +880,7 @@ static void loongarch_init(MachineState *machine)
 ram_addr_t ram_size = machine->ram_size;
 uint64_t highram_size = 0, phyAddr = 0;
 MemoryRegion *address_space_mem = get_system_memory();
-LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
+LoongArchMachineState *lams = VIRT_MACHINE(machine);
 int nb_numa_nodes = machine->numa_state->num_nodes;
 NodeInfo *numa_info = machine->numa_state->nodes;
 int i;
@@ -1032,7 +1032,7 @@ bool loongarch_is_acpi_enabled(LoongArchMachineState 
*lams)
 static void loongarch_get_acpi(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
 {
-LoongArchMachineState *lams = LOONGARCH_MACHINE(obj);
+LoongArchMachineState *lams = VIRT_MACHINE(obj);
 OnOffAuto acpi = lams->acpi;
 
 visit_type_OnOffAuto(v, name, , errp);
@@ -1041,14 +1041,14 @@ static void loongarch_get_acpi(Object *obj, Visitor *v, 
const char *name,
 static void loongarch_set_acpi(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
 {
-LoongArchMachineState *lams = LOONGARCH_MACHINE(obj);
+LoongArchMachineState *lams = VIRT_MACHINE(obj);
 
 visit_type_OnOffAuto(v, name, >acpi, errp);
 }
 
 static void loongarch_machine_initfn(Object *obj)
 {
-LoongArchMachineState *lams = LOONGARCH_MACHINE(obj);
+LoongArchMachineState *lams = VIRT_MACHINE(obj);
 
 lams->acpi = ON_OFF_AUTO_AUTO;
 lams->oem_id = g_strndup(ACPI_BUILD_APPNAME6, 6);
@@ -1080,7 +1080,7 @@ static void virt_machine_device_pre_plug(HotplugHandler 
*hotplug_dev,
 static void virt_mem_unplug_request(HotplugHandler *hotplug_dev,
  DeviceState *dev, Error **errp)
 {
-LoongArchMachineState *lams = LOONGARCH_MACHINE(hotplug_dev);
+LoongArchMachineState *lams = VIRT_MACHINE(hotplug_dev);
 
 /* the acpi ged is always exist */
 hotplug_handler_unplug_request(HOTPLUG_HANDLER(lams->acpi_ged), dev,
@@ 

[PATCH v3 4/5] hw/loongarch: Set minimium memory size as 256M

2024-05-05 Thread Bibo Mao
The minimum memory size for LoongArch UEFI bios is 256M, also some
test cases such as migration and qos use 256M memory by default.

Here set minimum memory size for Loongarch VirtMachine with 256M rather
than 1G, so that test cases with 256M memory can pass to run.

Signed-off-by: Bibo Mao 
---
 hw/loongarch/virt.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 8a6e2d6677..7d699c036b 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -919,8 +919,8 @@ static void virt_init(MachineState *machine)
 cpu_model = LOONGARCH_CPU_TYPE_NAME("la464");
 }
 
-if (ram_size < 1 * GiB) {
-error_report("ram_size must be greater than 1G.");
+if (ram_size < 256 * MiB) {
+error_report("ram_size must be greater than 256M.");
 exit(1);
 }
 create_fdt(vms);
-- 
2.39.3




[PATCH v3 2/5] hw/loongarch: Rename LoongArchMachineState with VirtMachineState

2024-05-05 Thread Bibo Mao
Rename LoongArchMachineState with VirtMachineState, and change variable
name LoongArchMachineState *lams with VirtMachineState *vms, and rename
function loongarch_xxx() with virt_xxx() also.

Signed-off-by: Bibo Mao 
---
 hw/loongarch/acpi-build.c   |  80 +-
 hw/loongarch/boot.c |  10 +-
 hw/loongarch/fw_cfg.c   |   2 +-
 hw/loongarch/fw_cfg.h   |   2 +-
 hw/loongarch/virt.c | 309 ++--
 include/hw/loongarch/virt.h |   8 +-
 6 files changed, 205 insertions(+), 206 deletions(-)

diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c
index 72322cdb1e..b6741809ef 100644
--- a/hw/loongarch/acpi-build.c
+++ b/hw/loongarch/acpi-build.c
@@ -105,14 +105,14 @@ build_facs(GArray *table_data)
 
 /* build MADT */
 static void
-build_madt(GArray *table_data, BIOSLinker *linker, LoongArchMachineState *lams)
+build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
 {
-MachineState *ms = MACHINE(lams);
+MachineState *ms = MACHINE(vms);
 MachineClass *mc = MACHINE_GET_CLASS(ms);
 const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(ms);
 int i, arch_id;
-AcpiTable table = { .sig = "APIC", .rev = 1, .oem_id = lams->oem_id,
-.oem_table_id = lams->oem_table_id };
+AcpiTable table = { .sig = "APIC", .rev = 1, .oem_id = vms->oem_id,
+.oem_table_id = vms->oem_table_id };
 
 acpi_table_begin(, table_data);
 
@@ -167,11 +167,11 @@ build_srat(GArray *table_data, BIOSLinker *linker, 
MachineState *machine)
 int i, arch_id, node_id;
 uint64_t mem_len, mem_base;
 int nb_numa_nodes = machine->numa_state->num_nodes;
-LoongArchMachineState *lams = VIRT_MACHINE(machine);
-MachineClass *mc = MACHINE_GET_CLASS(lams);
+VirtMachineState *vms = VIRT_MACHINE(machine);
+MachineClass *mc = MACHINE_GET_CLASS(vms);
 const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(machine);
-AcpiTable table = { .sig = "SRAT", .rev = 1, .oem_id = lams->oem_id,
-.oem_table_id = lams->oem_table_id };
+AcpiTable table = { .sig = "SRAT", .rev = 1, .oem_id = vms->oem_id,
+.oem_table_id = vms->oem_table_id };
 
 acpi_table_begin(, table_data);
 build_append_int_noprefix(table_data, 1, 4); /* Reserved */
@@ -279,13 +279,13 @@ static void
 build_la_ged_aml(Aml *dsdt, MachineState *machine)
 {
 uint32_t event;
-LoongArchMachineState *lams = VIRT_MACHINE(machine);
+VirtMachineState *vms = VIRT_MACHINE(machine);
 
 build_ged_aml(dsdt, "\\_SB."GED_DEVICE,
-  HOTPLUG_HANDLER(lams->acpi_ged),
+  HOTPLUG_HANDLER(vms->acpi_ged),
   VIRT_SCI_IRQ, AML_SYSTEM_MEMORY,
   VIRT_GED_EVT_ADDR);
-event = object_property_get_uint(OBJECT(lams->acpi_ged),
+event = object_property_get_uint(OBJECT(vms->acpi_ged),
  "ged-event", _abort);
 if (event & ACPI_GED_MEM_HOTPLUG_EVT) {
 build_memory_hotplug_aml(dsdt, machine->ram_slots, "\\_SB", NULL,
@@ -295,7 +295,7 @@ build_la_ged_aml(Aml *dsdt, MachineState *machine)
 acpi_dsdt_add_power_button(dsdt);
 }
 
-static void build_pci_device_aml(Aml *scope, LoongArchMachineState *lams)
+static void build_pci_device_aml(Aml *scope, VirtMachineState *vms)
 {
 struct GPEXConfig cfg = {
 .mmio64.base = VIRT_PCI_MEM_BASE,
@@ -305,13 +305,13 @@ static void build_pci_device_aml(Aml *scope, 
LoongArchMachineState *lams)
 .ecam.base   = VIRT_PCI_CFG_BASE,
 .ecam.size   = VIRT_PCI_CFG_SIZE,
 .irq = VIRT_GSI_BASE + VIRT_DEVICE_IRQS,
-.bus = lams->pci_bus,
+.bus = vms->pci_bus,
 };
 
 acpi_dsdt_add_gpex(scope, );
 }
 
-static void build_flash_aml(Aml *scope, LoongArchMachineState *lams)
+static void build_flash_aml(Aml *scope, VirtMachineState *vms)
 {
 Aml *dev, *crs;
 MemoryRegion *flash_mem;
@@ -322,11 +322,11 @@ static void build_flash_aml(Aml *scope, 
LoongArchMachineState *lams)
 hwaddr flash1_base;
 hwaddr flash1_size;
 
-flash_mem = pflash_cfi01_get_memory(lams->flash[0]);
+flash_mem = pflash_cfi01_get_memory(vms->flash[0]);
 flash0_base = flash_mem->addr;
 flash0_size = memory_region_size(flash_mem);
 
-flash_mem = pflash_cfi01_get_memory(lams->flash[1]);
+flash_mem = pflash_cfi01_get_memory(vms->flash[1]);
 flash1_base = flash_mem->addr;
 flash1_size = memory_region_size(flash_mem);
 
@@ -352,7 +352,7 @@ static void build_flash_aml(Aml *scope, 
LoongArchMachineState *lams)
 }
 
 #ifdef CONFIG_TPM
-static void acpi_dsdt_add_tpm(Aml *scope, LoongArchMachineState *vms)
+static void acpi_dsdt_add_tpm(Aml *scope, VirtMachineState *vms)
 {
 PlatformBusDevice *pbus = PL

[PATCH v3 3/5] hw/loongarch: Add compat machine for 9.0

2024-05-05 Thread Bibo Mao
Since migration test case requires compat machine type support,
compat machine is added for qemu 9.0 here.

Signed-off-by: Bibo Mao 
---
 hw/loongarch/virt.c | 60 +++--
 1 file changed, 47 insertions(+), 13 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index c8d697f38f..8a6e2d6677 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -408,6 +408,32 @@ static void fdt_add_pcie_irq_map_node(const 
VirtMachineState *vms,
 }
 }
 
+#define DEFINE_VIRT_MACHINE_LATEST(major, minor, latest) \
+static void virt_##major##_##minor##_class_init(ObjectClass *oc, \
+void *data) \
+{ \
+MachineClass *mc = MACHINE_CLASS(oc); \
+virt_machine_##major##_##minor##_options(mc); \
+mc->desc = "QEMU " # major "." # minor " ARM Virtual Machine"; \
+if (latest) { \
+mc->alias = "virt"; \
+} \
+} \
+static const TypeInfo machvirt_##major##_##minor##_info = { \
+.name = MACHINE_TYPE_NAME("virt-" # major "." # minor), \
+.parent = TYPE_VIRT_MACHINE, \
+.class_init = virt_##major##_##minor##_class_init, \
+}; \
+static void machvirt_machine_##major##_##minor##_init(void) \
+{ \
+type_register_static(_##major##_##minor##_info); \
+} \
+type_init(machvirt_machine_##major##_##minor##_init);
+
+#define DEFINE_VIRT_MACHINE_AS_LATEST(major, minor) \
+DEFINE_VIRT_MACHINE_LATEST(major, minor, true)
+#define DEFINE_VIRT_MACHINE(major, minor) \
+DEFINE_VIRT_MACHINE_LATEST(major, minor, false)
 
 qemu_fdt_setprop(ms->fdt, nodename, "interrupt-map", full_irq_map,
  GPEX_NUM_IRQS * GPEX_NUM_IRQS *
@@ -1241,18 +1267,26 @@ static void virt_class_init(ObjectClass *oc, void *data)
 #endif
 }
 
-static const TypeInfo virt_machine_types[] = {
-{
-.name   = TYPE_VIRT_MACHINE,
-.parent = TYPE_MACHINE,
-.instance_size  = sizeof(VirtMachineState),
-.class_init = virt_class_init,
-.instance_init = virt_machine_initfn,
-.interfaces = (InterfaceInfo[]) {
- { TYPE_HOTPLUG_HANDLER },
- { }
-},
-}
+static const TypeInfo virt_machine_info = {
+.name   = TYPE_VIRT_MACHINE,
+.parent = TYPE_MACHINE,
+.abstract   = true,
+.instance_size  = sizeof(VirtMachineState),
+.class_init = virt_class_init,
+.instance_init = virt_machine_initfn,
+.interfaces = (InterfaceInfo[]) {
+{ TYPE_HOTPLUG_HANDLER },
+{ }
+},
 };
 
-DEFINE_TYPES(virt_machine_types)
+static void machvirt_machine_init(void)
+{
+type_register_static(_machine_info);
+}
+type_init(machvirt_machine_init);
+
+static void virt_machine_9_0_options(MachineClass *mc)
+{
+}
+DEFINE_VIRT_MACHINE_AS_LATEST(9, 0)
-- 
2.39.3




[PATCH v3 5/5] tests: Add migration test for loongarch64

2024-05-05 Thread Bibo Mao
This patch adds migration test support for loongarch64. The test code
comes from aarch64 mostly, only that it booted as bios in qemu since
kernel requires elf format and bios uses binary format.

In addition to providing the binary, this patch also includes the source
code and the build script in tests/migration/loongarch64. So users can
change the source and/or re-compile the binary as they wish.

Signed-off-by: Bibo Mao 
Acked-by: Thomas Huth 
Acked-by: Peter Xu 
Reviewed-by: Fabiano Rosas 
---
 tests/migration/Makefile |  2 +-
 tests/migration/loongarch64/Makefile | 18 +
 tests/migration/loongarch64/a-b-kernel.S | 49 
 tests/migration/loongarch64/a-b-kernel.h | 16 
 tests/migration/migration-test.h |  3 ++
 tests/qtest/meson.build  |  4 ++
 tests/qtest/migration-test.c | 10 +
 7 files changed, 101 insertions(+), 1 deletion(-)
 create mode 100644 tests/migration/loongarch64/Makefile
 create mode 100644 tests/migration/loongarch64/a-b-kernel.S
 create mode 100644 tests/migration/loongarch64/a-b-kernel.h

diff --git a/tests/migration/Makefile b/tests/migration/Makefile
index 13e99b1692..cfebfe23f8 100644
--- a/tests/migration/Makefile
+++ b/tests/migration/Makefile
@@ -5,7 +5,7 @@
 # See the COPYING file in the top-level directory.
 #
 
-TARGET_LIST = i386 aarch64 s390x
+TARGET_LIST = i386 aarch64 s390x loongarch64
 
 SRC_PATH = ../..
 
diff --git a/tests/migration/loongarch64/Makefile 
b/tests/migration/loongarch64/Makefile
new file mode 100644
index 00..5d8719205f
--- /dev/null
+++ b/tests/migration/loongarch64/Makefile
@@ -0,0 +1,18 @@
+# To specify cross compiler prefix, use CROSS_PREFIX=
+#   $ make CROSS_PREFIX=loongarch64-linux-gnu-
+
+.PHONY: all clean
+all: a-b-kernel.h
+
+a-b-kernel.h: loongarch64.kernel
+   echo "$$__note" > $@
+   xxd -i $< | sed -e 's/.*int.*//' >> $@
+
+loongarch64.kernel: loongarch64.elf
+   $(CROSS_PREFIX)objcopy -j .text -O binary $< $@
+
+loongarch64.elf: a-b-kernel.S
+   $(CROSS_PREFIX)gcc -o $@ -nostdlib -Wl,--build-id=none $<
+
+clean:
+   $(RM) *.kernel *.elf
diff --git a/tests/migration/loongarch64/a-b-kernel.S 
b/tests/migration/loongarch64/a-b-kernel.S
new file mode 100644
index 00..cd543345fe
--- /dev/null
+++ b/tests/migration/loongarch64/a-b-kernel.S
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2024 Loongson Technology Corporation Limited
+ */
+#include "../migration-test.h"
+
+#define LOONGARCH_CSR_CRMD  0
+#define LOONGARCH_VIRT_UART 0x1FE001E0
+.section .text
+
+.globl  _start
+_start:
+/* output char 'A' to UART16550 */
+li.d$t0, LOONGARCH_VIRT_UART
+li.w$t1, 'A'
+st.b$t1, $t0, 0
+
+/* traverse test memory region */
+li.d$t0, LOONGARCH_TEST_MEM_START
+li.d$t1, LOONGARCH_TEST_MEM_END
+li.d$t2, TEST_MEM_PAGE_SIZE
+li.d$t4, LOONGARCH_VIRT_UART
+li.w$t5, 'B'
+
+clean:
+st.b$zero, $t0, 0
+add.d   $t0,   $t0, $t2
+bne $t0,   $t1, clean
+/* keeps a counter so we can limit the output speed */
+addi.d  $t6,   $zero, 0
+
+mainloop:
+li.d$t0, LOONGARCH_TEST_MEM_START
+
+innerloop:
+ld.bu   $t3, $t0, 0
+addi.w  $t3, $t3, 1
+ext.w.b $t3, $t3
+st.b$t3, $t0, 0
+add.d   $t0, $t0, $t2
+bne $t0, $t1, innerloop
+
+addi.d  $t6, $t6, 1
+andi$t6, $t6, 31
+bnez$t6, mainloop
+
+st.b$t5, $t4, 0
+b   mainloop
+nop
diff --git a/tests/migration/loongarch64/a-b-kernel.h 
b/tests/migration/loongarch64/a-b-kernel.h
new file mode 100644
index 00..b3fe466754
--- /dev/null
+++ b/tests/migration/loongarch64/a-b-kernel.h
@@ -0,0 +1,16 @@
+/* This file is automatically generated from the assembly file in
+* tests/migration/loongarch64. Edit that file and then run "make all"
+* inside tests/migration to update, and then remember to send both
+* the header and the assembler differences in your patch submission.
+*/
+unsigned char loongarch64_kernel[] = {
+  0x0c, 0xc0, 0x3f, 0x14, 0x8c, 0x81, 0x87, 0x03, 0x0d, 0x04, 0x81, 0x03,
+  0x8d, 0x01, 0x00, 0x29, 0x0c, 0x00, 0x04, 0x14, 0x0d, 0x80, 0x0c, 0x14,
+  0x2e, 0x00, 0x00, 0x14, 0x10, 0xc0, 0x3f, 0x14, 0x10, 0x82, 0x87, 0x03,
+  0x11, 0x08, 0x81, 0x03, 0x80, 0x01, 0x00, 0x29, 0x8c, 0xb9, 0x10, 0x00,
+  0x8d, 0xf9, 0xff, 0x5f, 0x12, 0x00, 0xc0, 0x02, 0x0c, 0x00, 0x04, 0x14,
+  0x8f, 0x01, 0x00, 0x2a, 0xef, 0x05, 0x80, 0x02, 0xef, 0x5d, 0x00, 0x00,
+  0x8f, 0x01, 0x00, 0x29, 0x8c, 0xb9, 0x10, 0x00, 0x8d, 0xed, 0xff, 0x5f,
+  0x52, 0x06, 0xc0, 0x02, 0x52, 0x7e, 0x40, 0x03, 0x5f, 0xde, 0xff, 0x47,
+  0x11, 0x02, 0x00, 0x29, 0xff, 0xd7, 0xff, 0x53, 0x00, 0x00, 0x40, 0x03
+};
diff --git a/tests/migration/migration-test.h b/tests/migration/migration-test.h
index 68512c0b1b..f402e48349 100644
--- a/tests/migration/migrati

[PATCH v4] target/loongarch: Add TCG macro in structure CPUArchState

2024-05-05 Thread Bibo Mao
In structure CPUArchState some struct elements are only used in TCG
mode, and it is not used in KVM mode. Macro CONFIG_TCG is added to
make it simpiler in KVM mode, also there is the same modification
in c code when these structure elements are used.

When VM runs in KVM mode, TLB entries are not used and do not need
migrate. It is only useful when it runs in TCG mode.

Signed-off-by: Bibo Mao 
Reviewed-by: Richard Henderson 
---
v3 --> v4:
- Refresh the patch based on the latest mainline version.

v2 --> v3:
- Remove print info about fp_status in loongarch_cpu_dump_state() since
it is always zero.
- Return tcg_enabled() directly in tlb_needed()

v1 --> v2:
- Add field needed in structure vmstate_tlb, dynamically judge whether
tlb should be migrated, since mostly qemu-system-loongarch64 is compiled
with both kvm and tcg accl enabled.
---
 target/loongarch/cpu.c|  7 +--
 target/loongarch/cpu.h| 16 ++--
 target/loongarch/cpu_helper.c |  9 +
 target/loongarch/machine.c| 30 +-
 4 files changed, 49 insertions(+), 13 deletions(-)

diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index 1ebba043f4..ab813a8f67 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -505,7 +505,9 @@ static void loongarch_cpu_reset_hold(Object *obj, ResetType 
type)
 lacc->parent_phases.hold(obj, type);
 }
 
+#ifdef CONFIG_TCG
 env->fcsr0_mask = FCSR0_M1 | FCSR0_M2 | FCSR0_M3;
+#endif
 env->fcsr0 = 0x0;
 
 int n;
@@ -550,7 +552,9 @@ static void loongarch_cpu_reset_hold(Object *obj, ResetType 
type)
 
 #ifndef CONFIG_USER_ONLY
 env->pc = 0x1c00;
+#ifdef CONFIG_TCG
 memset(env->tlb, 0, sizeof(env->tlb));
+#endif
 if (kvm_enabled()) {
 kvm_arch_reset_vcpu(env);
 }
@@ -686,8 +690,7 @@ void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int 
flags)
 int i;
 
 qemu_fprintf(f, " PC=%016" PRIx64 " ", env->pc);
-qemu_fprintf(f, " FCSR0 0x%08x  fp_status 0x%02x\n", env->fcsr0,
- get_float_exception_flags(>fp_status));
+qemu_fprintf(f, " FCSR0 0x%08x\n", env->fcsr0);
 
 /* gpr */
 for (i = 0; i < 32; i++) {
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index c5722670f5..41b8e6d96d 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -270,6 +270,7 @@ union fpr_t {
 VReg  vreg;
 };
 
+#ifdef CONFIG_TCG
 struct LoongArchTLB {
 uint64_t tlb_misc;
 /* Fields corresponding to CSR_TLBELO0/1 */
@@ -277,23 +278,18 @@ struct LoongArchTLB {
 uint64_t tlb_entry1;
 };
 typedef struct LoongArchTLB LoongArchTLB;
+#endif
 
 typedef struct CPUArchState {
 uint64_t gpr[32];
 uint64_t pc;
 
 fpr_t fpr[32];
-float_status fp_status;
 bool cf[8];
-
 uint32_t fcsr0;
-uint32_t fcsr0_mask;
 
 uint32_t cpucfg[21];
 
-uint64_t lladdr; /* LL virtual address compared against SC */
-uint64_t llval;
-
 /* LoongArch CSRs */
 uint64_t CSR_CRMD;
 uint64_t CSR_PRMD;
@@ -350,8 +346,16 @@ typedef struct CPUArchState {
 uint64_t CSR_DERA;
 uint64_t CSR_DSAVE;
 
+#ifdef CONFIG_TCG
+float_status fp_status;
+uint32_t fcsr0_mask;
+uint64_t lladdr; /* LL virtual address compared against SC */
+uint64_t llval;
+#endif
 #ifndef CONFIG_USER_ONLY
+#ifdef CONFIG_TCG
 LoongArchTLB  tlb[LOONGARCH_TLB_MAX];
+#endif
 
 AddressSpace *address_space_iocsr;
 bool load_elf;
diff --git a/target/loongarch/cpu_helper.c b/target/loongarch/cpu_helper.c
index 960eec9567..580362ac3e 100644
--- a/target/loongarch/cpu_helper.c
+++ b/target/loongarch/cpu_helper.c
@@ -11,6 +11,7 @@
 #include "internals.h"
 #include "cpu-csr.h"
 
+#ifdef CONFIG_TCG
 static int loongarch_map_tlb_entry(CPULoongArchState *env, hwaddr *physical,
int *prot, target_ulong address,
int access_type, int index, int mmu_idx)
@@ -154,6 +155,14 @@ static int loongarch_map_address(CPULoongArchState *env, 
hwaddr *physical,
 
 return TLBRET_NOMATCH;
 }
+#else
+static int loongarch_map_address(CPULoongArchState *env, hwaddr *physical,
+ int *prot, target_ulong address,
+ MMUAccessType access_type, int mmu_idx)
+{
+return TLBRET_NOMATCH;
+}
+#endif
 
 static hwaddr dmw_va2pa(CPULoongArchState *env, target_ulong va,
 target_ulong dmw)
diff --git a/target/loongarch/machine.c b/target/loongarch/machine.c
index c7029fb9b4..9cd9e848d6 100644
--- a/target/loongarch/machine.c
+++ b/target/loongarch/machine.c
@@ -8,6 +8,7 @@
 #include "qemu/osdep.h"
 #include "cpu.h"
 #include "migration/cpu.h"
+#include "sysemu/tcg.h"
 #include "vec.h"
 
 static const VMStateDescription vmstate_fpu_reg = {
@@ -109,9 +110,15 @@ st

[PATCH] target/loongarch: Put cpucfg operation before CSR register

2024-04-27 Thread Bibo Mao
On Loongarch, cpucfg is register for cpu feature, some other registers
depend on cpucfg feature such as perf CSR registers. Here put cpucfg
read/write operations before CSR register, so that KVM knows how many
perf CSR registers are valid from pre-set cpucfg feature information.

Signed-off-by: Bibo Mao 
---
 target/loongarch/kvm/kvm.c | 16 
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
index 8224d94333..bc75552d0f 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -587,22 +587,22 @@ int kvm_arch_get_registers(CPUState *cs)
 return ret;
 }
 
-ret = kvm_loongarch_get_csr(cs);
+ret = kvm_loongarch_get_cpucfg(cs);
 if (ret) {
 return ret;
 }
 
-ret = kvm_loongarch_get_regs_fp(cs);
+ret = kvm_loongarch_get_csr(cs);
 if (ret) {
 return ret;
 }
 
-ret = kvm_loongarch_get_mpstate(cs);
+ret = kvm_loongarch_get_regs_fp(cs);
 if (ret) {
 return ret;
 }
 
-ret = kvm_loongarch_get_cpucfg(cs);
+ret = kvm_loongarch_get_mpstate(cs);
 return ret;
 }
 
@@ -615,22 +615,22 @@ int kvm_arch_put_registers(CPUState *cs, int level)
 return ret;
 }
 
-ret = kvm_loongarch_put_csr(cs, level);
+ret = kvm_loongarch_put_cpucfg(cs);
 if (ret) {
 return ret;
 }
 
-ret = kvm_loongarch_put_regs_fp(cs);
+ret = kvm_loongarch_put_csr(cs, level);
 if (ret) {
 return ret;
 }
 
-ret = kvm_loongarch_put_mpstate(cs);
+ret = kvm_loongarch_put_regs_fp(cs);
 if (ret) {
 return ret;
 }
 
-ret = kvm_loongarch_put_cpucfg(cs);
+ret = kvm_loongarch_put_mpstate(cs);
 return ret;
 }
 

base-commit: a118c4aff4087eafb68f7132b233ad548cf16376
-- 
2.39.3




[PATCH] hw/loongarch: Refine default numa id calculation

2024-03-18 Thread Bibo Mao
With numa_test test case, there is subcase named test_def_cpu_split(),
there are 8 sockets and 2 numa nodes. Here is command line:
"-machine smp.cpus=8,smp.sockets=8 -numa node,memdev=ram -numa node"

The required result is:
  node 0 cpus: 0 2 4 6
  node 1 cpus: 1 3 5 7
Test case numa_test fails on LoongArch, since the actual result is:
  node 0 cpus: 0 1 2 3
  node 1 cpus: 4 5 6 7

It will be better if all the cpus in one socket share the same numa
node. Here socket id is used to calculate numa id in function
virt_get_default_cpu_node_id().

Signed-off-by: Bibo Mao 
---
 hw/loongarch/virt.c | 11 +--
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index deb3750d81..29885f6777 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -1219,15 +1219,14 @@ virt_cpu_index_to_props(MachineState *ms, unsigned 
cpu_index)
 
 static int64_t virt_get_default_cpu_node_id(const MachineState *ms, int idx)
 {
-int64_t nidx = 0;
+int64_t socket_id;
 
 if (ms->numa_state->num_nodes) {
-nidx = idx / (ms->smp.cpus / ms->numa_state->num_nodes);
-if (ms->numa_state->num_nodes <= nidx) {
-nidx = ms->numa_state->num_nodes - 1;
-}
+socket_id = ms->possible_cpus->cpus[idx].props.socket_id;
+return socket_id % ms->numa_state->num_nodes;
+} else {
+return 0;
 }
-return nidx;
 }
 
 static void loongarch_class_init(ObjectClass *oc, void *data)
-- 
2.39.3




[PATCH 1/5] hw/loongarch: Refine acpi srat table for numa memory

2024-03-18 Thread Bibo Mao
One LoongArch virt machine platform, there is limitation for memory
map information. The minimum memory size is 256M and minimum memory
size for numa node0 is 256M also. With qemu numa qtest, it is possible
that memory size of numa node0 is 128M.

Limitations for minimum memory size for both total memory and numa
node0 is removed for acpi srat table creation.

Signed-off-by: Bibo Mao 
---
 hw/loongarch/acpi-build.c | 58 +++
 1 file changed, 34 insertions(+), 24 deletions(-)

diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c
index e5ab1080af..d0247d93ee 100644
--- a/hw/loongarch/acpi-build.c
+++ b/hw/loongarch/acpi-build.c
@@ -165,8 +165,9 @@ static void
 build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
 {
 int i, arch_id, node_id;
-uint64_t mem_len, mem_base;
-int nb_numa_nodes = machine->numa_state->num_nodes;
+hwaddr len, base, gap;
+NodeInfo *numa_info;
+int nodes, nb_numa_nodes = machine->numa_state->num_nodes;
 LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
 MachineClass *mc = MACHINE_GET_CLASS(lams);
 const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(machine);
@@ -195,35 +196,44 @@ build_srat(GArray *table_data, BIOSLinker *linker, 
MachineState *machine)
 build_append_int_noprefix(table_data, 0, 4); /* Reserved */
 }
 
-/* Node0 */
-build_srat_memory(table_data, VIRT_LOWMEM_BASE, VIRT_LOWMEM_SIZE,
-  0, MEM_AFFINITY_ENABLED);
-mem_base = VIRT_HIGHMEM_BASE;
-if (!nb_numa_nodes) {
-mem_len = machine->ram_size - VIRT_LOWMEM_SIZE;
-} else {
-mem_len = machine->numa_state->nodes[0].node_mem - VIRT_LOWMEM_SIZE;
+base = VIRT_LOWMEM_BASE;
+gap = VIRT_LOWMEM_SIZE;
+numa_info = machine->numa_state->nodes;
+nodes = nb_numa_nodes;
+if (!nodes) {
+nodes = 1;
 }
-if (mem_len)
-build_srat_memory(table_data, mem_base, mem_len, 0, 
MEM_AFFINITY_ENABLED);
-
-/* Node1 - Nodemax */
-if (nb_numa_nodes) {
-mem_base += mem_len;
-for (i = 1; i < nb_numa_nodes; ++i) {
-if (machine->numa_state->nodes[i].node_mem > 0) {
-build_srat_memory(table_data, mem_base,
-  machine->numa_state->nodes[i].node_mem, i,
-  MEM_AFFINITY_ENABLED);
-mem_base += machine->numa_state->nodes[i].node_mem;
-}
+
+for (i = 0; i < nodes; i++) {
+if (nb_numa_nodes) {
+len = numa_info[i].node_mem;
+} else {
+len = machine->ram_size;
+}
+
+/*
+ * memory for the node splited into two part
+ *   lowram:  [base, +gap)
+ *   highram: [VIRT_HIGHMEM_BASE, +(len - gap))
+ */
+if (len >= gap) {
+build_srat_memory(table_data, base, len, i, MEM_AFFINITY_ENABLED);
+len -= gap;
+base = VIRT_HIGHMEM_BASE;
+gap = machine->ram_size - VIRT_LOWMEM_SIZE;
+}
+
+if (len) {
+build_srat_memory(table_data, base, len, i, MEM_AFFINITY_ENABLED);
+base += len;
+gap  -= len;
 }
 }
 
 if (machine->device_memory) {
 build_srat_memory(table_data, machine->device_memory->base,
   memory_region_size(>device_memory->mr),
-  nb_numa_nodes - 1,
+  nodes - 1,
   MEM_AFFINITY_HOTPLUGGABLE | MEM_AFFINITY_ENABLED);
 }
 
-- 
2.39.3




[PATCH 4/5] hw/loongarch: Refine system dram memory region

2024-03-18 Thread Bibo Mao
For system dram memory region, it is not necessary to use numa node
information. There is only low memory region and high memory region.

Remove numa node information for ddr memory region here, it can reduce
memory region number about LoongArch virt machine.

Signed-off-by: Bibo Mao 
---
 hw/loongarch/virt.c | 56 ++---
 1 file changed, 17 insertions(+), 39 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index d7e0886c7c..a2975c3c5a 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -917,19 +917,13 @@ static void loongarch_init(MachineState *machine)
 {
 LoongArchCPU *lacpu;
 const char *cpu_model = machine->cpu_type;
-ram_addr_t offset = 0;
-ram_addr_t ram_size = machine->ram_size;
-uint64_t highram_size = 0, phyAddr = 0;
 MemoryRegion *address_space_mem = get_system_memory();
 LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
-int nb_numa_nodes = machine->numa_state->num_nodes;
-NodeInfo *numa_info = machine->numa_state->nodes;
 int i;
-hwaddr fdt_base;
+hwaddr fdt_base, base, size, ram_size = machine->ram_size;
 const CPUArchIdList *possible_cpus;
 MachineClass *mc = MACHINE_GET_CLASS(machine);
 CPUState *cpu;
-char *ramName = NULL;
 struct loaderparams loaderparams = { };
 
 if (!cpu_model) {
@@ -965,41 +959,27 @@ static void loongarch_init(MachineState *machine)
 fdt_add_memory_nodes(machine);
 fw_cfg_add_memory(machine);
 
-/* Node0 memory */
-memory_region_init_alias(>lowmem, NULL, "loongarch.node0.lowram",
- machine->ram, offset, VIRT_LOWMEM_SIZE);
-memory_region_add_subregion(address_space_mem, phyAddr, >lowmem);
-
-offset += VIRT_LOWMEM_SIZE;
-if (nb_numa_nodes > 0) {
-assert(numa_info[0].node_mem > VIRT_LOWMEM_SIZE);
-highram_size = numa_info[0].node_mem - VIRT_LOWMEM_SIZE;
-} else {
-highram_size = ram_size - VIRT_LOWMEM_SIZE;
+size = ram_size;
+base = VIRT_LOWMEM_BASE;
+if (size > VIRT_LOWMEM_SIZE) {
+size = VIRT_LOWMEM_SIZE;
 }
-phyAddr = VIRT_HIGHMEM_BASE;
-memory_region_init_alias(>highmem, NULL, "loongarch.node0.highram",
-  machine->ram, offset, highram_size);
-memory_region_add_subregion(address_space_mem, phyAddr, >highmem);
-
-/* Node1 - Nodemax memory */
-offset += highram_size;
-phyAddr += highram_size;
-
-for (i = 1; i < nb_numa_nodes; i++) {
-MemoryRegion *nodemem = g_new(MemoryRegion, 1);
-ramName = g_strdup_printf("loongarch.node%d.ram", i);
-memory_region_init_alias(nodemem, NULL, ramName, machine->ram,
- offset,  numa_info[i].node_mem);
-memory_region_add_subregion(address_space_mem, phyAddr, nodemem);
-offset += numa_info[i].node_mem;
-phyAddr += numa_info[i].node_mem;
+
+memory_region_init_alias(>lowmem, NULL, "loongarch.lowram",
+  machine->ram, base, size);
+memory_region_add_subregion(address_space_mem, base, >lowmem);
+base += size;
+if (ram_size - size) {
+base = VIRT_HIGHMEM_BASE;
+memory_region_init_alias(>highmem, NULL, "loongarch.highram",
+machine->ram, VIRT_LOWMEM_BASE + size, ram_size - size);
+memory_region_add_subregion(address_space_mem, base, >highmem);
+base += ram_size - size;
 }
 
 /* initialize device memory address space */
 if (machine->ram_size < machine->maxram_size) {
 ram_addr_t device_mem_size = machine->maxram_size - machine->ram_size;
-hwaddr device_mem_base;
 
 if (machine->ram_slots > ACPI_MAX_RAM_SLOTS) {
 error_report("unsupported amount of memory slots: %"PRIu64,
@@ -1013,9 +993,7 @@ static void loongarch_init(MachineState *machine)
  "%d bytes", TARGET_PAGE_SIZE);
 exit(EXIT_FAILURE);
 }
-/* device memory base is the top of high memory address. */
-device_mem_base = ROUND_UP(VIRT_HIGHMEM_BASE + highram_size, 1 * GiB);
-machine_memory_devices_init(machine, device_mem_base, device_mem_size);
+machine_memory_devices_init(machine, base, device_mem_size);
 }
 
 /* load the BIOS image. */
-- 
2.39.3




[PATCH 5/5] hw/loongarch: Remove minimum and default memory size

2024-03-18 Thread Bibo Mao
Some qtest test cases such as numa use default memory size of generic
machine class, which is 128M by fault.

Here generic default memory size is used, and also remove minimum memory
size which is 1G originally.

Signed-off-by: Bibo Mao 
---
 hw/loongarch/virt.c | 5 -
 1 file changed, 5 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index a2975c3c5a..deb3750d81 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -930,10 +930,6 @@ static void loongarch_init(MachineState *machine)
 cpu_model = LOONGARCH_CPU_TYPE_NAME("la464");
 }
 
-if (ram_size < 1 * GiB) {
-error_report("ram_size must be greater than 1G.");
-exit(1);
-}
 create_fdt(lams);
 
 /* Create IOCSR space */
@@ -1241,7 +1237,6 @@ static void loongarch_class_init(ObjectClass *oc, void 
*data)
 
 mc->desc = "Loongson-3A5000 LS7A1000 machine";
 mc->init = loongarch_init;
-mc->default_ram_size = 1 * GiB;
 mc->default_cpu_type = LOONGARCH_CPU_TYPE_NAME("la464");
 mc->default_ram_id = "loongarch.ram";
 mc->max_cpus = LOONGARCH_MAX_CPUS;
-- 
2.39.3




[PATCH 0/5] hw/loongarch: Refine numa memory map

2024-03-18 Thread Bibo Mao
One LoongArch virt machine platform, there is limitation for memory
map information. The minimum memory size is 256M and minimum memory
size for numa node0 is 256M also. With qemu numa qtest, it is possible
that memory size of numa node0 is 128M.

Limitations for minimum memory size for both total memory and numa
node0 is removed here, including acpi srat table, fadt memory map table
and fw_cfg memory map table.

Also remove numa node about memory region, there is only low memory
region and how memory region.

Bibo Mao (5):
  hw/loongarch: Refine acpi srat table for numa memory
  hw/loongarch: Refine fadt memory table for numa memory
  hw/loongarch: Refine fwcfg memory map
  hw/loongarch: Refine system dram memory region
  hw/loongarch: Remove minimum and default memory size

 hw/loongarch/acpi-build.c |  58 +++--
 hw/loongarch/virt.c   | 168 ++
 2 files changed, 152 insertions(+), 74 deletions(-)


base-commit: ba49d760eb04630e7b15f423ebecf6c871b8f77b
-- 
2.39.3




[PATCH 3/5] hw/loongarch: Refine fwcfg memory map

2024-03-18 Thread Bibo Mao
Memory map table for fwcfg is used for UEFI BIOS, UEFI BIOS uses the first
entry from fwcfg memory map as the first memory HOB, the second memory HOB
will be used if the first memory HOB is used up.

Memory map table for fwcfg does not care about numa node, however in
generic the first memory HOB is part of numa node0, so that runtime
memory of UEFI which is allocated from the first memory HOB is located
at numa node0.

Signed-off-by: Bibo Mao 
---
 hw/loongarch/virt.c | 60 ++---
 1 file changed, 57 insertions(+), 3 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index ae79b49774..d7e0886c7c 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -796,6 +796,62 @@ static void fw_cfg_add_kernel_info(const struct 
loaderparams *loaderparams,
 }
 }
 
+static void fw_cfg_add_memory(MachineState *ms)
+{
+hwaddr base, size, ram_size, gap;
+int nb_numa_nodes, nodes;
+NodeInfo *numa_info;
+
+ram_size = ms->ram_size;
+base = VIRT_LOWMEM_BASE;
+gap = VIRT_LOWMEM_SIZE;
+nodes = nb_numa_nodes = ms->numa_state->num_nodes;
+numa_info = ms->numa_state->nodes;
+if (!nodes) {
+nodes = 1;
+}
+
+/* add fw_cfg memory map of node0 */
+if (nb_numa_nodes) {
+size = numa_info[0].node_mem;
+} else {
+size = ram_size;
+}
+
+if (size >= gap) {
+memmap_add_entry(base, gap, 1);
+size -= gap;
+base = VIRT_HIGHMEM_BASE;
+gap = ram_size - VIRT_LOWMEM_SIZE;
+}
+
+if (size) {
+memmap_add_entry(base, size, 1);
+base += size;
+}
+
+if (nodes < 2) {
+return;
+}
+
+/* add fw_cfg memory map of other nodes */
+size = ram_size - numa_info[0].node_mem;
+gap  = VIRT_LOWMEM_BASE + VIRT_LOWMEM_SIZE;
+if (base < gap && (base + size) > gap) {
+/*
+ * memory map for the maining nodes splited into two part
+ *   lowram:  [base, +(gap - base))
+ *   highram: [VIRT_HIGHMEM_BASE, +(size - (gap - base)))
+ */
+memmap_add_entry(base, gap - base, 1);
+size -= gap - base;
+base = VIRT_HIGHMEM_BASE;
+}
+
+if (size)
+memmap_add_entry(base, size, 1);
+}
+
 static void loongarch_firmware_boot(LoongArchMachineState *lams,
 const struct loaderparams *loaderparams)
 {
@@ -907,9 +963,9 @@ static void loongarch_init(MachineState *machine)
 fdt_add_cpu_nodes(lams);
 
 fdt_add_memory_nodes(machine);
+fw_cfg_add_memory(machine);
 
 /* Node0 memory */
-memmap_add_entry(VIRT_LOWMEM_BASE, VIRT_LOWMEM_SIZE, 1);
 memory_region_init_alias(>lowmem, NULL, "loongarch.node0.lowram",
  machine->ram, offset, VIRT_LOWMEM_SIZE);
 memory_region_add_subregion(address_space_mem, phyAddr, >lowmem);
@@ -922,7 +978,6 @@ static void loongarch_init(MachineState *machine)
 highram_size = ram_size - VIRT_LOWMEM_SIZE;
 }
 phyAddr = VIRT_HIGHMEM_BASE;
-memmap_add_entry(phyAddr, highram_size, 1);
 memory_region_init_alias(>highmem, NULL, "loongarch.node0.highram",
   machine->ram, offset, highram_size);
 memory_region_add_subregion(address_space_mem, phyAddr, >highmem);
@@ -937,7 +992,6 @@ static void loongarch_init(MachineState *machine)
 memory_region_init_alias(nodemem, NULL, ramName, machine->ram,
  offset,  numa_info[i].node_mem);
 memory_region_add_subregion(address_space_mem, phyAddr, nodemem);
-memmap_add_entry(phyAddr, numa_info[i].node_mem, 1);
 offset += numa_info[i].node_mem;
 phyAddr += numa_info[i].node_mem;
 }
-- 
2.39.3




[PATCH 2/5] hw/loongarch: Refine fadt memory table for numa memory

2024-03-18 Thread Bibo Mao
One LoongArch virt machine platform, there is limitation for memory
map information. The minimum memory size is 256M and minimum memory
size for numa node0 is 256M also. With qemu numa qtest, it is possible
that memory size of numa node0 is 128M.

Limitations for minimum memory size for both total memory and numa
node0 is removed for fadt numa memory table creation.

Signed-off-by: Bibo Mao 
---
 hw/loongarch/virt.c | 47 ++---
 1 file changed, 44 insertions(+), 3 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index efce112310..ae79b49774 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -343,6 +343,48 @@ static void fdt_add_memory_node(MachineState *ms,
 g_free(nodename);
 }
 
+static void fdt_add_memory_nodes(MachineState *ms)
+{
+hwaddr base, size, ram_size, gap;
+int i, nb_numa_nodes, nodes;
+NodeInfo *numa_info;
+
+ram_size = ms->ram_size;
+base = VIRT_LOWMEM_BASE;
+gap = VIRT_LOWMEM_SIZE;
+nodes = nb_numa_nodes = ms->numa_state->num_nodes;
+numa_info = ms->numa_state->nodes;
+if (!nodes) {
+nodes = 1;
+}
+
+for (i = 0; i < nodes; i++) {
+if (nb_numa_nodes) {
+size = numa_info[i].node_mem;
+} else {
+size = ram_size;
+}
+
+/*
+ * memory for the node splited into two part
+ *   lowram:  [base, +gap)
+ *   highram: [VIRT_HIGHMEM_BASE, +(len - gap))
+ */
+if (size >= gap) {
+fdt_add_memory_node(ms, base, gap, i);
+size -= gap;
+base = VIRT_HIGHMEM_BASE;
+gap = ram_size - VIRT_LOWMEM_SIZE;
+}
+
+if (size) {
+fdt_add_memory_node(ms, base, size, i);
+base += size;
+gap -= size;
+}
+}
+}
+
 static void virt_build_smbios(LoongArchMachineState *lams)
 {
 MachineState *ms = MACHINE(lams);
@@ -864,9 +906,10 @@ static void loongarch_init(MachineState *machine)
 }
 fdt_add_cpu_nodes(lams);
 
+fdt_add_memory_nodes(machine);
+
 /* Node0 memory */
 memmap_add_entry(VIRT_LOWMEM_BASE, VIRT_LOWMEM_SIZE, 1);
-fdt_add_memory_node(machine, VIRT_LOWMEM_BASE, VIRT_LOWMEM_SIZE, 0);
 memory_region_init_alias(>lowmem, NULL, "loongarch.node0.lowram",
  machine->ram, offset, VIRT_LOWMEM_SIZE);
 memory_region_add_subregion(address_space_mem, phyAddr, >lowmem);
@@ -880,7 +923,6 @@ static void loongarch_init(MachineState *machine)
 }
 phyAddr = VIRT_HIGHMEM_BASE;
 memmap_add_entry(phyAddr, highram_size, 1);
-fdt_add_memory_node(machine, phyAddr, highram_size, 0);
 memory_region_init_alias(>highmem, NULL, "loongarch.node0.highram",
   machine->ram, offset, highram_size);
 memory_region_add_subregion(address_space_mem, phyAddr, >highmem);
@@ -896,7 +938,6 @@ static void loongarch_init(MachineState *machine)
  offset,  numa_info[i].node_mem);
 memory_region_add_subregion(address_space_mem, phyAddr, nodemem);
 memmap_add_entry(phyAddr, numa_info[i].node_mem, 1);
-fdt_add_memory_node(machine, phyAddr, numa_info[i].node_mem, i);
 offset += numa_info[i].node_mem;
 phyAddr += numa_info[i].node_mem;
 }
-- 
2.39.3




[PATCH] hw/intc/loongarch_extioi: Fix interrupt routing update

2024-03-13 Thread Bibo Mao
Interrupt number in loop sentence should be base irq plus
loop index, it is missing on checking whether the irq
is pending.

Fixes: 428a6ef4396 ("Add vmstate post_load support")
Signed-off-by: Bibo Mao 
---
 hw/intc/loongarch_extioi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/intc/loongarch_extioi.c b/hw/intc/loongarch_extioi.c
index bdfa3b481e..0b358548eb 100644
--- a/hw/intc/loongarch_extioi.c
+++ b/hw/intc/loongarch_extioi.c
@@ -151,7 +151,7 @@ static inline void extioi_update_sw_coremap(LoongArchExtIOI 
*s, int irq,
 continue;
 }
 
-if (notify && test_bit(irq, (unsigned long *)s->isr)) {
+if (notify && test_bit(irq + i, (unsigned long *)s->isr)) {
 /*
  * lower irq at old cpu and raise irq at new cpu
  */
-- 
2.39.3




[PATCH v3] target/loongarch: Add TCG macro in structure CPUArchState

2024-03-04 Thread Bibo Mao
In structure CPUArchState some struct elements are only used in TCG
mode, and it is not used in KVM mode. Macro CONFIG_TCG is added to
make it simpiler in KVM mode, also there is the same modification
in c code when these struct elements are used.

When VM runs in KVM mode, TLB entries are not used and do not need
migrate. It is only useful when it runs in TCG mode.

Signed-off-by: Bibo Mao 
---
v2 --> v3:
- Remove print info about fp_status in loongarch_cpu_dump_state() since
it is always zero.
- Return tcg_enabled() directly in tlb_needed()

v1 --> v2:
- Add field needed in structure vmstate_tlb, dynamically judge whether
tlb should be migrated, since mostly qemu-system-loongarch64 is compiled
with both kvm and tcg accl enabled.

Signed-off-by: Bibo Mao 
---
 target/loongarch/cpu.c|  7 +--
 target/loongarch/cpu.h| 16 ++--
 target/loongarch/cpu_helper.c |  9 +
 target/loongarch/machine.c| 30 +-
 4 files changed, 49 insertions(+), 13 deletions(-)

diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index bc2684179f..6d0349ded2 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -517,7 +517,9 @@ static void loongarch_cpu_reset_hold(Object *obj)
 lacc->parent_phases.hold(obj);
 }
 
+#ifdef CONFIG_TCG
 env->fcsr0_mask = FCSR0_M1 | FCSR0_M2 | FCSR0_M3;
+#endif
 env->fcsr0 = 0x0;
 
 int n;
@@ -562,7 +564,9 @@ static void loongarch_cpu_reset_hold(Object *obj)
 
 #ifndef CONFIG_USER_ONLY
 env->pc = 0x1c00;
+#ifdef CONFIG_TCG
 memset(env->tlb, 0, sizeof(env->tlb));
+#endif
 if (kvm_enabled()) {
 kvm_arch_reset_vcpu(env);
 }
@@ -699,8 +703,7 @@ void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int 
flags)
 int i;
 
 qemu_fprintf(f, " PC=%016" PRIx64 " ", env->pc);
-qemu_fprintf(f, " FCSR0 0x%08x  fp_status 0x%02x\n", env->fcsr0,
- get_float_exception_flags(>fp_status));
+qemu_fprintf(f, " FCSR0 0x%08x\n", env->fcsr0);
 
 /* gpr */
 for (i = 0; i < 32; i++) {
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index ec37579fd6..c25ad112b1 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -272,6 +272,7 @@ union fpr_t {
 VReg  vreg;
 };
 
+#ifdef CONFIG_TCG
 struct LoongArchTLB {
 uint64_t tlb_misc;
 /* Fields corresponding to CSR_TLBELO0/1 */
@@ -279,23 +280,18 @@ struct LoongArchTLB {
 uint64_t tlb_entry1;
 };
 typedef struct LoongArchTLB LoongArchTLB;
+#endif
 
 typedef struct CPUArchState {
 uint64_t gpr[32];
 uint64_t pc;
 
 fpr_t fpr[32];
-float_status fp_status;
 bool cf[8];
-
 uint32_t fcsr0;
-uint32_t fcsr0_mask;
 
 uint32_t cpucfg[21];
 
-uint64_t lladdr; /* LL virtual address compared against SC */
-uint64_t llval;
-
 /* LoongArch CSRs */
 uint64_t CSR_CRMD;
 uint64_t CSR_PRMD;
@@ -352,8 +348,16 @@ typedef struct CPUArchState {
 uint64_t CSR_DERA;
 uint64_t CSR_DSAVE;
 
+#ifdef CONFIG_TCG
+float_status fp_status;
+uint32_t fcsr0_mask;
+uint64_t lladdr; /* LL virtual address compared against SC */
+uint64_t llval;
+#endif
 #ifndef CONFIG_USER_ONLY
+#ifdef CONFIG_TCG
 LoongArchTLB  tlb[LOONGARCH_TLB_MAX];
+#endif
 
 AddressSpace *address_space_iocsr;
 bool load_elf;
diff --git a/target/loongarch/cpu_helper.c b/target/loongarch/cpu_helper.c
index 45f821d086..d1cdbe30ba 100644
--- a/target/loongarch/cpu_helper.c
+++ b/target/loongarch/cpu_helper.c
@@ -11,6 +11,7 @@
 #include "internals.h"
 #include "cpu-csr.h"
 
+#ifdef CONFIG_TCG
 static int loongarch_map_tlb_entry(CPULoongArchState *env, hwaddr *physical,
int *prot, target_ulong address,
int access_type, int index, int mmu_idx)
@@ -154,6 +155,14 @@ static int loongarch_map_address(CPULoongArchState *env, 
hwaddr *physical,
 
 return TLBRET_NOMATCH;
 }
+#else
+static int loongarch_map_address(CPULoongArchState *env, hwaddr *physical,
+ int *prot, target_ulong address,
+ MMUAccessType access_type, int mmu_idx)
+{
+return TLBRET_NOMATCH;
+}
+#endif
 
 static hwaddr dmw_va2pa(CPULoongArchState *env, target_ulong va,
 target_ulong dmw)
diff --git a/target/loongarch/machine.c b/target/loongarch/machine.c
index c7029fb9b4..9cd9e848d6 100644
--- a/target/loongarch/machine.c
+++ b/target/loongarch/machine.c
@@ -8,6 +8,7 @@
 #include "qemu/osdep.h"
 #include "cpu.h"
 #include "migration/cpu.h"
+#include "sysemu/tcg.h"
 #include "vec.h"
 
 static const VMStateDescription vmstate_fpu_reg = {
@@ -109,9 +110,15 @@ static const VMStateDescription vmstate_lasx = {
 },
 };
 
+#if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY)
+stati

[PATCH v2] target/loongarch: Add TCG macro in structure CPUArchState

2024-03-03 Thread Bibo Mao
In structure CPUArchState some struct elements are only used in TCG
mode, and it is not used in KVM mode. Macro CONFIG_TCG is added to
make it simpiler in KVM mode, also there is the same modification
in c code when these struct elements are used.

When VM runs in KVM mode, TLB entries are not used and do not need
migrate. It is only useful when it runs in TCG mode.

Signed-off-by: Bibo Mao 
Change-Id: Id30d663f5d7bc3436520638f606f99d93926eb2e
---
v1 --> v2:
- Add field needed in structure vmstate_tlb, dynamically judge whether
tlb should be migrated, since mostly qemu-system-loongarch64 is compiled
with both kvm and tcg accl enabled.
---
 target/loongarch/cpu.c| 14 +++---
 target/loongarch/cpu.h| 16 ++--
 target/loongarch/cpu_helper.c |  9 +
 target/loongarch/machine.c| 34 +-
 4 files changed, 59 insertions(+), 14 deletions(-)

diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index bc2684179f..35db8e244d 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -517,7 +517,9 @@ static void loongarch_cpu_reset_hold(Object *obj)
 lacc->parent_phases.hold(obj);
 }
 
+#ifdef CONFIG_TCG
 env->fcsr0_mask = FCSR0_M1 | FCSR0_M2 | FCSR0_M3;
+#endif
 env->fcsr0 = 0x0;
 
 int n;
@@ -562,7 +564,9 @@ static void loongarch_cpu_reset_hold(Object *obj)
 
 #ifndef CONFIG_USER_ONLY
 env->pc = 0x1c00;
+#ifdef CONFIG_TCG
 memset(env->tlb, 0, sizeof(env->tlb));
+#endif
 if (kvm_enabled()) {
 kvm_arch_reset_vcpu(env);
 }
@@ -696,11 +700,15 @@ void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int 
flags)
 {
 LoongArchCPU *cpu = LOONGARCH_CPU(cs);
 CPULoongArchState *env = >env;
-int i;
+int i, fp_status;
 
+#ifdef CONFIG_TCG
+fp_status = get_float_exception_flags(>fp_status);
+#else
+fp_status = 0;
+#endif
 qemu_fprintf(f, " PC=%016" PRIx64 " ", env->pc);
-qemu_fprintf(f, " FCSR0 0x%08x  fp_status 0x%02x\n", env->fcsr0,
- get_float_exception_flags(>fp_status));
+qemu_fprintf(f, " FCSR0 0x%08x  fp_status 0x%02x\n", env->fcsr0, 
fp_status);
 
 /* gpr */
 for (i = 0; i < 32; i++) {
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index ec37579fd6..c25ad112b1 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -272,6 +272,7 @@ union fpr_t {
 VReg  vreg;
 };
 
+#ifdef CONFIG_TCG
 struct LoongArchTLB {
 uint64_t tlb_misc;
 /* Fields corresponding to CSR_TLBELO0/1 */
@@ -279,23 +280,18 @@ struct LoongArchTLB {
 uint64_t tlb_entry1;
 };
 typedef struct LoongArchTLB LoongArchTLB;
+#endif
 
 typedef struct CPUArchState {
 uint64_t gpr[32];
 uint64_t pc;
 
 fpr_t fpr[32];
-float_status fp_status;
 bool cf[8];
-
 uint32_t fcsr0;
-uint32_t fcsr0_mask;
 
 uint32_t cpucfg[21];
 
-uint64_t lladdr; /* LL virtual address compared against SC */
-uint64_t llval;
-
 /* LoongArch CSRs */
 uint64_t CSR_CRMD;
 uint64_t CSR_PRMD;
@@ -352,8 +348,16 @@ typedef struct CPUArchState {
 uint64_t CSR_DERA;
 uint64_t CSR_DSAVE;
 
+#ifdef CONFIG_TCG
+float_status fp_status;
+uint32_t fcsr0_mask;
+uint64_t lladdr; /* LL virtual address compared against SC */
+uint64_t llval;
+#endif
 #ifndef CONFIG_USER_ONLY
+#ifdef CONFIG_TCG
 LoongArchTLB  tlb[LOONGARCH_TLB_MAX];
+#endif
 
 AddressSpace *address_space_iocsr;
 bool load_elf;
diff --git a/target/loongarch/cpu_helper.c b/target/loongarch/cpu_helper.c
index 45f821d086..d1cdbe30ba 100644
--- a/target/loongarch/cpu_helper.c
+++ b/target/loongarch/cpu_helper.c
@@ -11,6 +11,7 @@
 #include "internals.h"
 #include "cpu-csr.h"
 
+#ifdef CONFIG_TCG
 static int loongarch_map_tlb_entry(CPULoongArchState *env, hwaddr *physical,
int *prot, target_ulong address,
int access_type, int index, int mmu_idx)
@@ -154,6 +155,14 @@ static int loongarch_map_address(CPULoongArchState *env, 
hwaddr *physical,
 
 return TLBRET_NOMATCH;
 }
+#else
+static int loongarch_map_address(CPULoongArchState *env, hwaddr *physical,
+ int *prot, target_ulong address,
+ MMUAccessType access_type, int mmu_idx)
+{
+return TLBRET_NOMATCH;
+}
+#endif
 
 static hwaddr dmw_va2pa(CPULoongArchState *env, target_ulong va,
 target_ulong dmw)
diff --git a/target/loongarch/machine.c b/target/loongarch/machine.c
index c7029fb9b4..77890f07cc 100644
--- a/target/loongarch/machine.c
+++ b/target/loongarch/machine.c
@@ -8,6 +8,7 @@
 #include "qemu/osdep.h"
 #include "cpu.h"
 #include "migration/cpu.h"
+#include "sysemu/kvm.h"
 #include "vec.h"
 
 static const VMStateDescription vmstate_fpu_reg = {
@@ -109,9 +110,

[PATCH] target/loongarch: Add TCG macro in structure CPUArchState

2024-02-28 Thread Bibo Mao
In structure CPUArchState some struct elements are only used in TCG
mode, and it is not used in KVM mode. Macro CONFIG_TCG is added to
make it simpiler in KVM mode, also there is the same modification
in c code when these struct elements are used.

When VM is migrated in KVM mode, TLB entries are not necessary to save
in VMState. It is only useful when it runs in TCG mode, macro CONFIG_TCG
is also added.

Signed-off-by: Bibo Mao 
---
 target/loongarch/cpu.c| 14 +++---
 target/loongarch/cpu.h| 16 ++--
 target/loongarch/cpu_helper.c |  9 +
 target/loongarch/machine.c|  4 
 4 files changed, 34 insertions(+), 9 deletions(-)

diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index bc2684179f..35db8e244d 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -517,7 +517,9 @@ static void loongarch_cpu_reset_hold(Object *obj)
 lacc->parent_phases.hold(obj);
 }
 
+#ifdef CONFIG_TCG
 env->fcsr0_mask = FCSR0_M1 | FCSR0_M2 | FCSR0_M3;
+#endif
 env->fcsr0 = 0x0;
 
 int n;
@@ -562,7 +564,9 @@ static void loongarch_cpu_reset_hold(Object *obj)
 
 #ifndef CONFIG_USER_ONLY
 env->pc = 0x1c00;
+#ifdef CONFIG_TCG
 memset(env->tlb, 0, sizeof(env->tlb));
+#endif
 if (kvm_enabled()) {
 kvm_arch_reset_vcpu(env);
 }
@@ -696,11 +700,15 @@ void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int 
flags)
 {
 LoongArchCPU *cpu = LOONGARCH_CPU(cs);
 CPULoongArchState *env = >env;
-int i;
+int i, fp_status;
 
+#ifdef CONFIG_TCG
+fp_status = get_float_exception_flags(>fp_status);
+#else
+fp_status = 0;
+#endif
 qemu_fprintf(f, " PC=%016" PRIx64 " ", env->pc);
-qemu_fprintf(f, " FCSR0 0x%08x  fp_status 0x%02x\n", env->fcsr0,
- get_float_exception_flags(>fp_status));
+qemu_fprintf(f, " FCSR0 0x%08x  fp_status 0x%02x\n", env->fcsr0, 
fp_status);
 
 /* gpr */
 for (i = 0; i < 32; i++) {
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index ec37579fd6..c25ad112b1 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -272,6 +272,7 @@ union fpr_t {
 VReg  vreg;
 };
 
+#ifdef CONFIG_TCG
 struct LoongArchTLB {
 uint64_t tlb_misc;
 /* Fields corresponding to CSR_TLBELO0/1 */
@@ -279,23 +280,18 @@ struct LoongArchTLB {
 uint64_t tlb_entry1;
 };
 typedef struct LoongArchTLB LoongArchTLB;
+#endif
 
 typedef struct CPUArchState {
 uint64_t gpr[32];
 uint64_t pc;
 
 fpr_t fpr[32];
-float_status fp_status;
 bool cf[8];
-
 uint32_t fcsr0;
-uint32_t fcsr0_mask;
 
 uint32_t cpucfg[21];
 
-uint64_t lladdr; /* LL virtual address compared against SC */
-uint64_t llval;
-
 /* LoongArch CSRs */
 uint64_t CSR_CRMD;
 uint64_t CSR_PRMD;
@@ -352,8 +348,16 @@ typedef struct CPUArchState {
 uint64_t CSR_DERA;
 uint64_t CSR_DSAVE;
 
+#ifdef CONFIG_TCG
+float_status fp_status;
+uint32_t fcsr0_mask;
+uint64_t lladdr; /* LL virtual address compared against SC */
+uint64_t llval;
+#endif
 #ifndef CONFIG_USER_ONLY
+#ifdef CONFIG_TCG
 LoongArchTLB  tlb[LOONGARCH_TLB_MAX];
+#endif
 
 AddressSpace *address_space_iocsr;
 bool load_elf;
diff --git a/target/loongarch/cpu_helper.c b/target/loongarch/cpu_helper.c
index 45f821d086..d1cdbe30ba 100644
--- a/target/loongarch/cpu_helper.c
+++ b/target/loongarch/cpu_helper.c
@@ -11,6 +11,7 @@
 #include "internals.h"
 #include "cpu-csr.h"
 
+#ifdef CONFIG_TCG
 static int loongarch_map_tlb_entry(CPULoongArchState *env, hwaddr *physical,
int *prot, target_ulong address,
int access_type, int index, int mmu_idx)
@@ -154,6 +155,14 @@ static int loongarch_map_address(CPULoongArchState *env, 
hwaddr *physical,
 
 return TLBRET_NOMATCH;
 }
+#else
+static int loongarch_map_address(CPULoongArchState *env, hwaddr *physical,
+ int *prot, target_ulong address,
+ MMUAccessType access_type, int mmu_idx)
+{
+return TLBRET_NOMATCH;
+}
+#endif
 
 static hwaddr dmw_va2pa(CPULoongArchState *env, target_ulong va,
 target_ulong dmw)
diff --git a/target/loongarch/machine.c b/target/loongarch/machine.c
index c7029fb9b4..eb6f878789 100644
--- a/target/loongarch/machine.c
+++ b/target/loongarch/machine.c
@@ -109,6 +109,7 @@ static const VMStateDescription vmstate_lasx = {
 },
 };
 
+#ifdef CONFIG_TCG
 /* TLB state */
 const VMStateDescription vmstate_tlb = {
 .name = "cpu/tlb",
@@ -121,6 +122,7 @@ const VMStateDescription vmstate_tlb = {
 VMSTATE_END_OF_LIST()
 }
 };
+#endif
 
 /* LoongArch CPU state */
 const VMStateDescription vmstate_loongarch_cpu = {
@@ -187,9 +189,11 @@ const VMStateDescription vmstate_loongarch_cpu = {
 VMSTATE_UINT64(env.CSR_D

[PATCH v2 5/5] tests: Add migration test for loongarch64

2024-02-26 Thread Bibo Mao
This patch adds migration test support for loongarch64. The test code
comes from aarch64 mostly, only that it booted as bios in qemu since
kernel requires elf format and bios uses binary format.

In addition to providing the binary, this patch also includes the source
code and the build script in tests/migration/loongarch64. So users can
change the source and/or re-compile the binary as they wish.

Signed-off-by: Bibo Mao 
Reviewed-by: Fabiano Rosas 
Acked-by: Thomas Huth 
Acked-by: Peter Xu 
---
 tests/migration/Makefile |  2 +-
 tests/migration/loongarch64/Makefile | 18 +
 tests/migration/loongarch64/a-b-kernel.S | 49 
 tests/migration/loongarch64/a-b-kernel.h | 16 
 tests/migration/migration-test.h |  3 ++
 tests/qtest/meson.build  |  4 ++
 tests/qtest/migration-test.c | 10 +
 7 files changed, 101 insertions(+), 1 deletion(-)
 create mode 100644 tests/migration/loongarch64/Makefile
 create mode 100644 tests/migration/loongarch64/a-b-kernel.S
 create mode 100644 tests/migration/loongarch64/a-b-kernel.h

diff --git a/tests/migration/Makefile b/tests/migration/Makefile
index 13e99b1692..cfebfe23f8 100644
--- a/tests/migration/Makefile
+++ b/tests/migration/Makefile
@@ -5,7 +5,7 @@
 # See the COPYING file in the top-level directory.
 #
 
-TARGET_LIST = i386 aarch64 s390x
+TARGET_LIST = i386 aarch64 s390x loongarch64
 
 SRC_PATH = ../..
 
diff --git a/tests/migration/loongarch64/Makefile 
b/tests/migration/loongarch64/Makefile
new file mode 100644
index 00..5d8719205f
--- /dev/null
+++ b/tests/migration/loongarch64/Makefile
@@ -0,0 +1,18 @@
+# To specify cross compiler prefix, use CROSS_PREFIX=
+#   $ make CROSS_PREFIX=loongarch64-linux-gnu-
+
+.PHONY: all clean
+all: a-b-kernel.h
+
+a-b-kernel.h: loongarch64.kernel
+   echo "$$__note" > $@
+   xxd -i $< | sed -e 's/.*int.*//' >> $@
+
+loongarch64.kernel: loongarch64.elf
+   $(CROSS_PREFIX)objcopy -j .text -O binary $< $@
+
+loongarch64.elf: a-b-kernel.S
+   $(CROSS_PREFIX)gcc -o $@ -nostdlib -Wl,--build-id=none $<
+
+clean:
+   $(RM) *.kernel *.elf
diff --git a/tests/migration/loongarch64/a-b-kernel.S 
b/tests/migration/loongarch64/a-b-kernel.S
new file mode 100644
index 00..cd543345fe
--- /dev/null
+++ b/tests/migration/loongarch64/a-b-kernel.S
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2024 Loongson Technology Corporation Limited
+ */
+#include "../migration-test.h"
+
+#define LOONGARCH_CSR_CRMD  0
+#define LOONGARCH_VIRT_UART 0x1FE001E0
+.section .text
+
+.globl  _start
+_start:
+/* output char 'A' to UART16550 */
+li.d$t0, LOONGARCH_VIRT_UART
+li.w$t1, 'A'
+st.b$t1, $t0, 0
+
+/* traverse test memory region */
+li.d$t0, LOONGARCH_TEST_MEM_START
+li.d$t1, LOONGARCH_TEST_MEM_END
+li.d$t2, TEST_MEM_PAGE_SIZE
+li.d$t4, LOONGARCH_VIRT_UART
+li.w$t5, 'B'
+
+clean:
+st.b$zero, $t0, 0
+add.d   $t0,   $t0, $t2
+bne $t0,   $t1, clean
+/* keeps a counter so we can limit the output speed */
+addi.d  $t6,   $zero, 0
+
+mainloop:
+li.d$t0, LOONGARCH_TEST_MEM_START
+
+innerloop:
+ld.bu   $t3, $t0, 0
+addi.w  $t3, $t3, 1
+ext.w.b $t3, $t3
+st.b$t3, $t0, 0
+add.d   $t0, $t0, $t2
+bne $t0, $t1, innerloop
+
+addi.d  $t6, $t6, 1
+andi$t6, $t6, 31
+bnez$t6, mainloop
+
+st.b$t5, $t4, 0
+b   mainloop
+nop
diff --git a/tests/migration/loongarch64/a-b-kernel.h 
b/tests/migration/loongarch64/a-b-kernel.h
new file mode 100644
index 00..b3fe466754
--- /dev/null
+++ b/tests/migration/loongarch64/a-b-kernel.h
@@ -0,0 +1,16 @@
+/* This file is automatically generated from the assembly file in
+* tests/migration/loongarch64. Edit that file and then run "make all"
+* inside tests/migration to update, and then remember to send both
+* the header and the assembler differences in your patch submission.
+*/
+unsigned char loongarch64_kernel[] = {
+  0x0c, 0xc0, 0x3f, 0x14, 0x8c, 0x81, 0x87, 0x03, 0x0d, 0x04, 0x81, 0x03,
+  0x8d, 0x01, 0x00, 0x29, 0x0c, 0x00, 0x04, 0x14, 0x0d, 0x80, 0x0c, 0x14,
+  0x2e, 0x00, 0x00, 0x14, 0x10, 0xc0, 0x3f, 0x14, 0x10, 0x82, 0x87, 0x03,
+  0x11, 0x08, 0x81, 0x03, 0x80, 0x01, 0x00, 0x29, 0x8c, 0xb9, 0x10, 0x00,
+  0x8d, 0xf9, 0xff, 0x5f, 0x12, 0x00, 0xc0, 0x02, 0x0c, 0x00, 0x04, 0x14,
+  0x8f, 0x01, 0x00, 0x2a, 0xef, 0x05, 0x80, 0x02, 0xef, 0x5d, 0x00, 0x00,
+  0x8f, 0x01, 0x00, 0x29, 0x8c, 0xb9, 0x10, 0x00, 0x8d, 0xed, 0xff, 0x5f,
+  0x52, 0x06, 0xc0, 0x02, 0x52, 0x7e, 0x40, 0x03, 0x5f, 0xde, 0xff, 0x47,
+  0x11, 0x02, 0x00, 0x29, 0xff, 0xd7, 0xff, 0x53, 0x00, 0x00, 0x40, 0x03
+};
diff --git a/tests/migration/migration-test.h b/tests/migration/migration-test.h
index 68512c0b1b..f402e48349 100644
--- a/tests/migration/migrati

[PATCH v2 0/5] Add migration test for loongarch64

2024-02-26 Thread Bibo Mao
Migration test case is added for loongarch64 here. Since compat machine
type is required for migration test case, also compat machine qemu 9.0
is added for loongarch virt machine.

Migration test case passes to run in both tcg and kvm mode with the
patch.

---
Change in v2:
  1. Keep the default memory size unchanged with 1GB, only modify minimum
memory size with 256MB
  2. Remove tab char in file tests/migration/loongarch64/a-b-kernel.S
  3. Rebase patch on 
https://patchwork.kernel.org/project/qemu-devel/patch/0bd892aa9b88e0f4cc904cb70efd0251fc1cde29.1708336919.git.lixiang...@loongson.cn
to avoid confliction
---
Bibo Mao (5):
  hw/loongarch: Rename LOONGARCH_MACHINE with VIRT_MACHINE.
  hw/loongarch: Rename LoongArchMachineState with VirtMachineState
  hw/loongarch: Add compat machine for 9.0
  hw/loongarch: Set minimium memory size as 256M
  tests: Add migration test for loongarch64

 hw/loongarch/acpi-build.c|  80 +++---
 hw/loongarch/fw_cfg.c|   2 +-
 hw/loongarch/fw_cfg.h|   2 +-
 hw/loongarch/virt.c  | 345 +--
 include/hw/loongarch/virt.h  |  10 +-
 tests/migration/Makefile |   2 +-
 tests/migration/loongarch64/Makefile |  18 ++
 tests/migration/loongarch64/a-b-kernel.S |  49 
 tests/migration/loongarch64/a-b-kernel.h |  16 ++
 tests/migration/migration-test.h |   3 +
 tests/qtest/meson.build  |   4 +
 tests/qtest/migration-test.c |  10 +
 12 files changed, 337 insertions(+), 204 deletions(-)
 create mode 100644 tests/migration/loongarch64/Makefile
 create mode 100644 tests/migration/loongarch64/a-b-kernel.S
 create mode 100644 tests/migration/loongarch64/a-b-kernel.h


base-commit: 03d496a992d98650315af41be7c0ca6de2a28da1
-- 
2.39.3




[PATCH v2 3/5] hw/loongarch: Add compat machine for 9.0

2024-02-26 Thread Bibo Mao
Since migration test case requires compat machine type support,
compat machine is added for qemu 9.0 here.

Signed-off-by: Bibo Mao 
---
 hw/loongarch/virt.c | 60 +++--
 1 file changed, 47 insertions(+), 13 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 3bc35c58c9..f37f642ede 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -46,6 +46,32 @@
 #include "hw/block/flash.h"
 #include "qemu/error-report.h"
 
+#define DEFINE_VIRT_MACHINE_LATEST(major, minor, latest) \
+static void virt_##major##_##minor##_class_init(ObjectClass *oc, \
+void *data) \
+{ \
+MachineClass *mc = MACHINE_CLASS(oc); \
+virt_machine_##major##_##minor##_options(mc); \
+mc->desc = "QEMU " # major "." # minor " ARM Virtual Machine"; \
+if (latest) { \
+mc->alias = "virt"; \
+} \
+} \
+static const TypeInfo machvirt_##major##_##minor##_info = { \
+.name = MACHINE_TYPE_NAME("virt-" # major "." # minor), \
+.parent = TYPE_VIRT_MACHINE, \
+.class_init = virt_##major##_##minor##_class_init, \
+}; \
+static void machvirt_machine_##major##_##minor##_init(void) \
+{ \
+type_register_static(_##major##_##minor##_info); \
+} \
+type_init(machvirt_machine_##major##_##minor##_init);
+
+#define DEFINE_VIRT_MACHINE_AS_LATEST(major, minor) \
+DEFINE_VIRT_MACHINE_LATEST(major, minor, true)
+#define DEFINE_VIRT_MACHINE(major, minor) \
+DEFINE_VIRT_MACHINE_LATEST(major, minor, false)
 
 struct loaderparams {
 uint64_t ram_size;
@@ -1200,18 +1226,26 @@ static void virt_class_init(ObjectClass *oc, void *data)
 #endif
 }
 
-static const TypeInfo virt_machine_types[] = {
-{
-.name   = TYPE_VIRT_MACHINE,
-.parent = TYPE_MACHINE,
-.instance_size  = sizeof(VirtMachineState),
-.class_init = virt_class_init,
-.instance_init = virt_machine_initfn,
-.interfaces = (InterfaceInfo[]) {
- { TYPE_HOTPLUG_HANDLER },
- { }
-},
-}
+static const TypeInfo virt_machine_info = {
+.name   = TYPE_VIRT_MACHINE,
+.parent = TYPE_MACHINE,
+.abstract   = true,
+.instance_size  = sizeof(VirtMachineState),
+.class_init = virt_class_init,
+.instance_init = virt_machine_initfn,
+.interfaces = (InterfaceInfo[]) {
+{ TYPE_HOTPLUG_HANDLER },
+{ }
+},
 };
 
-DEFINE_TYPES(virt_machine_types)
+static void machvirt_machine_init(void)
+{
+type_register_static(_machine_info);
+}
+type_init(machvirt_machine_init);
+
+static void virt_machine_9_0_options(MachineClass *mc)
+{
+}
+DEFINE_VIRT_MACHINE_AS_LATEST(9, 0)
-- 
2.39.3




[PATCH v2 1/5] hw/loongarch: Rename LOONGARCH_MACHINE with VIRT_MACHINE.

2024-02-26 Thread Bibo Mao
On LoongArch system, there is only virt machine type now, name
LOONGARCH_MACHINE is confused, rename it with VIRT_MACHINE. Machine name
about Other real hw boards can be added in future.

Signed-off-by: Bibo Mao 
---
 hw/loongarch/acpi-build.c   |  8 
 hw/loongarch/virt.c | 19 +--
 include/hw/loongarch/virt.h |  4 ++--
 3 files changed, 15 insertions(+), 16 deletions(-)

diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c
index e5ab1080af..72322cdb1e 100644
--- a/hw/loongarch/acpi-build.c
+++ b/hw/loongarch/acpi-build.c
@@ -167,7 +167,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, 
MachineState *machine)
 int i, arch_id, node_id;
 uint64_t mem_len, mem_base;
 int nb_numa_nodes = machine->numa_state->num_nodes;
-LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
+LoongArchMachineState *lams = VIRT_MACHINE(machine);
 MachineClass *mc = MACHINE_GET_CLASS(lams);
 const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(machine);
 AcpiTable table = { .sig = "SRAT", .rev = 1, .oem_id = lams->oem_id,
@@ -279,7 +279,7 @@ static void
 build_la_ged_aml(Aml *dsdt, MachineState *machine)
 {
 uint32_t event;
-LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
+LoongArchMachineState *lams = VIRT_MACHINE(machine);
 
 build_ged_aml(dsdt, "\\_SB."GED_DEVICE,
   HOTPLUG_HANDLER(lams->acpi_ged),
@@ -391,7 +391,7 @@ static void
 build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine)
 {
 Aml *dsdt, *scope, *pkg;
-LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
+LoongArchMachineState *lams = VIRT_MACHINE(machine);
 AcpiTable table = { .sig = "DSDT", .rev = 1, .oem_id = lams->oem_id,
 .oem_table_id = lams->oem_table_id };
 
@@ -421,7 +421,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, 
MachineState *machine)
 
 static void acpi_build(AcpiBuildTables *tables, MachineState *machine)
 {
-LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
+LoongArchMachineState *lams = VIRT_MACHINE(machine);
 GArray *table_offsets;
 AcpiFadtData fadt_data;
 unsigned facs, rsdt, dsdt;
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 1e98d8bda5..0d4ea57e5b 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -823,7 +823,7 @@ static void loongarch_init(MachineState *machine)
 ram_addr_t ram_size = machine->ram_size;
 uint64_t highram_size = 0, phyAddr = 0;
 MemoryRegion *address_space_mem = get_system_memory();
-LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
+LoongArchMachineState *lams = VIRT_MACHINE(machine);
 int nb_numa_nodes = machine->numa_state->num_nodes;
 NodeInfo *numa_info = machine->numa_state->nodes;
 int i;
@@ -990,7 +990,7 @@ bool loongarch_is_acpi_enabled(LoongArchMachineState *lams)
 static void loongarch_get_acpi(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
 {
-LoongArchMachineState *lams = LOONGARCH_MACHINE(obj);
+LoongArchMachineState *lams = VIRT_MACHINE(obj);
 OnOffAuto acpi = lams->acpi;
 
 visit_type_OnOffAuto(v, name, , errp);
@@ -999,14 +999,14 @@ static void loongarch_get_acpi(Object *obj, Visitor *v, 
const char *name,
 static void loongarch_set_acpi(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
 {
-LoongArchMachineState *lams = LOONGARCH_MACHINE(obj);
+LoongArchMachineState *lams = VIRT_MACHINE(obj);
 
 visit_type_OnOffAuto(v, name, >acpi, errp);
 }
 
 static void loongarch_machine_initfn(Object *obj)
 {
-LoongArchMachineState *lams = LOONGARCH_MACHINE(obj);
+LoongArchMachineState *lams = VIRT_MACHINE(obj);
 
 lams->acpi = ON_OFF_AUTO_AUTO;
 lams->oem_id = g_strndup(ACPI_BUILD_APPNAME6, 6);
@@ -1038,7 +1038,7 @@ static void virt_machine_device_pre_plug(HotplugHandler 
*hotplug_dev,
 static void virt_mem_unplug_request(HotplugHandler *hotplug_dev,
  DeviceState *dev, Error **errp)
 {
-LoongArchMachineState *lams = LOONGARCH_MACHINE(hotplug_dev);
+LoongArchMachineState *lams = VIRT_MACHINE(hotplug_dev);
 
 /* the acpi ged is always exist */
 hotplug_handler_unplug_request(HOTPLUG_HANDLER(lams->acpi_ged), dev,
@@ -1056,7 +1056,7 @@ static void 
virt_machine_device_unplug_request(HotplugHandler *hotplug_dev,
 static void virt_mem_unplug(HotplugHandler *hotplug_dev,
  DeviceState *dev, Error **errp)
 {
-LoongArchMachineState *lams = LOONGARCH_MACHINE(hotplug_dev);
+LoongArchMachineState *lams = VIRT_MACHINE(hotplug_dev);
 
 hotplug_handler_unplug(HOTPLUG_HANDLER(lams->acpi_ged), dev, errp);
 pc_dimm_unplug(PC_DIMM(dev), MACHINE(lams));
@@ -1074,7 +1074,7 @@ static void virt_machine_device_unplug(

[PATCH v2 4/5] hw/loongarch: Set minimium memory size as 256M

2024-02-26 Thread Bibo Mao
The minimum memory size for LoongArch UEFI bios is 256M, also some
test cases such as migration and qos use 256M memory by default.

Here set minimum memory size for Loongarch VirtMachine with 256M rather
than 1G, so that test cases with 256M memory can pass to run.

Signed-off-by: Bibo Mao 
---
 hw/loongarch/virt.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index f37f642ede..1dadb8e299 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -864,8 +864,8 @@ static void virt_init(MachineState *machine)
 cpu_model = LOONGARCH_CPU_TYPE_NAME("la464");
 }
 
-if (ram_size < 1 * GiB) {
-error_report("ram_size must be greater than 1G.");
+if (ram_size < 256 * MiB) {
+error_report("ram_size must be greater than 256M.");
 exit(1);
 }
 create_fdt(vms);
-- 
2.39.3




[PATCH v2 2/5] hw/loongarch: Rename LoongArchMachineState with VirtMachineState

2024-02-26 Thread Bibo Mao
Rename LoongArchMachineState with VirtMachineState, and change variable
name LoongArchMachineState *lams with VirtMachineState *vms, and rename
function loongarch_xxx() with virt_xxx() also.

Signed-off-by: Bibo Mao 
---
 hw/loongarch/acpi-build.c   |  80 +-
 hw/loongarch/fw_cfg.c   |   2 +-
 hw/loongarch/fw_cfg.h   |   2 +-
 hw/loongarch/virt.c | 290 ++--
 include/hw/loongarch/virt.h |   8 +-
 5 files changed, 191 insertions(+), 191 deletions(-)

diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c
index 72322cdb1e..b6741809ef 100644
--- a/hw/loongarch/acpi-build.c
+++ b/hw/loongarch/acpi-build.c
@@ -105,14 +105,14 @@ build_facs(GArray *table_data)
 
 /* build MADT */
 static void
-build_madt(GArray *table_data, BIOSLinker *linker, LoongArchMachineState *lams)
+build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
 {
-MachineState *ms = MACHINE(lams);
+MachineState *ms = MACHINE(vms);
 MachineClass *mc = MACHINE_GET_CLASS(ms);
 const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(ms);
 int i, arch_id;
-AcpiTable table = { .sig = "APIC", .rev = 1, .oem_id = lams->oem_id,
-.oem_table_id = lams->oem_table_id };
+AcpiTable table = { .sig = "APIC", .rev = 1, .oem_id = vms->oem_id,
+.oem_table_id = vms->oem_table_id };
 
 acpi_table_begin(, table_data);
 
@@ -167,11 +167,11 @@ build_srat(GArray *table_data, BIOSLinker *linker, 
MachineState *machine)
 int i, arch_id, node_id;
 uint64_t mem_len, mem_base;
 int nb_numa_nodes = machine->numa_state->num_nodes;
-LoongArchMachineState *lams = VIRT_MACHINE(machine);
-MachineClass *mc = MACHINE_GET_CLASS(lams);
+VirtMachineState *vms = VIRT_MACHINE(machine);
+MachineClass *mc = MACHINE_GET_CLASS(vms);
 const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(machine);
-AcpiTable table = { .sig = "SRAT", .rev = 1, .oem_id = lams->oem_id,
-.oem_table_id = lams->oem_table_id };
+AcpiTable table = { .sig = "SRAT", .rev = 1, .oem_id = vms->oem_id,
+.oem_table_id = vms->oem_table_id };
 
 acpi_table_begin(, table_data);
 build_append_int_noprefix(table_data, 1, 4); /* Reserved */
@@ -279,13 +279,13 @@ static void
 build_la_ged_aml(Aml *dsdt, MachineState *machine)
 {
 uint32_t event;
-LoongArchMachineState *lams = VIRT_MACHINE(machine);
+VirtMachineState *vms = VIRT_MACHINE(machine);
 
 build_ged_aml(dsdt, "\\_SB."GED_DEVICE,
-  HOTPLUG_HANDLER(lams->acpi_ged),
+  HOTPLUG_HANDLER(vms->acpi_ged),
   VIRT_SCI_IRQ, AML_SYSTEM_MEMORY,
   VIRT_GED_EVT_ADDR);
-event = object_property_get_uint(OBJECT(lams->acpi_ged),
+event = object_property_get_uint(OBJECT(vms->acpi_ged),
  "ged-event", _abort);
 if (event & ACPI_GED_MEM_HOTPLUG_EVT) {
 build_memory_hotplug_aml(dsdt, machine->ram_slots, "\\_SB", NULL,
@@ -295,7 +295,7 @@ build_la_ged_aml(Aml *dsdt, MachineState *machine)
 acpi_dsdt_add_power_button(dsdt);
 }
 
-static void build_pci_device_aml(Aml *scope, LoongArchMachineState *lams)
+static void build_pci_device_aml(Aml *scope, VirtMachineState *vms)
 {
 struct GPEXConfig cfg = {
 .mmio64.base = VIRT_PCI_MEM_BASE,
@@ -305,13 +305,13 @@ static void build_pci_device_aml(Aml *scope, 
LoongArchMachineState *lams)
 .ecam.base   = VIRT_PCI_CFG_BASE,
 .ecam.size   = VIRT_PCI_CFG_SIZE,
 .irq = VIRT_GSI_BASE + VIRT_DEVICE_IRQS,
-.bus = lams->pci_bus,
+.bus = vms->pci_bus,
 };
 
 acpi_dsdt_add_gpex(scope, );
 }
 
-static void build_flash_aml(Aml *scope, LoongArchMachineState *lams)
+static void build_flash_aml(Aml *scope, VirtMachineState *vms)
 {
 Aml *dev, *crs;
 MemoryRegion *flash_mem;
@@ -322,11 +322,11 @@ static void build_flash_aml(Aml *scope, 
LoongArchMachineState *lams)
 hwaddr flash1_base;
 hwaddr flash1_size;
 
-flash_mem = pflash_cfi01_get_memory(lams->flash[0]);
+flash_mem = pflash_cfi01_get_memory(vms->flash[0]);
 flash0_base = flash_mem->addr;
 flash0_size = memory_region_size(flash_mem);
 
-flash_mem = pflash_cfi01_get_memory(lams->flash[1]);
+flash_mem = pflash_cfi01_get_memory(vms->flash[1]);
 flash1_base = flash_mem->addr;
 flash1_size = memory_region_size(flash_mem);
 
@@ -352,7 +352,7 @@ static void build_flash_aml(Aml *scope, 
LoongArchMachineState *lams)
 }
 
 #ifdef CONFIG_TPM
-static void acpi_dsdt_add_tpm(Aml *scope, LoongArchMachineState *vms)
+static void acpi_dsdt_add_tpm(Aml *scope, VirtMachineState *vms)
 {
 PlatformBusDevice *pbus = PLATFORM_BUS_DEVICE(vms->platfo

[PATCH 3/5] hw/loongarch: Add compat machine for 9.0

2024-02-20 Thread Bibo Mao
Since migration test case requires compat machine type support,
compat machine is added for qemu 9.0 here.

Signed-off-by: Bibo Mao 
---
 hw/loongarch/virt.c | 60 +++--
 1 file changed, 47 insertions(+), 13 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index d0827aafab..a7d700497d 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -46,6 +46,32 @@
 #include "hw/block/flash.h"
 #include "qemu/error-report.h"
 
+#define DEFINE_VIRT_MACHINE_LATEST(major, minor, latest) \
+static void virt_##major##_##minor##_class_init(ObjectClass *oc, \
+void *data) \
+{ \
+MachineClass *mc = MACHINE_CLASS(oc); \
+virt_machine_##major##_##minor##_options(mc); \
+mc->desc = "QEMU " # major "." # minor " ARM Virtual Machine"; \
+if (latest) { \
+mc->alias = "virt"; \
+} \
+} \
+static const TypeInfo machvirt_##major##_##minor##_info = { \
+.name = MACHINE_TYPE_NAME("virt-" # major "." # minor), \
+.parent = TYPE_VIRT_MACHINE, \
+.class_init = virt_##major##_##minor##_class_init, \
+}; \
+static void machvirt_machine_##major##_##minor##_init(void) \
+{ \
+type_register_static(_##major##_##minor##_info); \
+} \
+type_init(machvirt_machine_##major##_##minor##_init);
+
+#define DEFINE_VIRT_MACHINE_AS_LATEST(major, minor) \
+DEFINE_VIRT_MACHINE_LATEST(major, minor, true)
+#define DEFINE_VIRT_MACHINE(major, minor) \
+DEFINE_VIRT_MACHINE_LATEST(major, minor, false)
 
 struct loaderparams {
 uint64_t ram_size;
@@ -1151,18 +1177,26 @@ static void virt_class_init(ObjectClass *oc, void *data)
 #endif
 }
 
-static const TypeInfo virt_machine_types[] = {
-{
-.name   = TYPE_VIRT_MACHINE,
-.parent = TYPE_MACHINE,
-.instance_size  = sizeof(VirtMachineState),
-.class_init = virt_class_init,
-.instance_init = virt_machine_initfn,
-.interfaces = (InterfaceInfo[]) {
- { TYPE_HOTPLUG_HANDLER },
- { }
-},
-}
+static const TypeInfo virt_machine_info = {
+.name   = TYPE_VIRT_MACHINE,
+.parent = TYPE_MACHINE,
+.abstract   = true,
+.instance_size  = sizeof(VirtMachineState),
+.class_init = virt_class_init,
+.instance_init = virt_machine_initfn,
+.interfaces = (InterfaceInfo[]) {
+{ TYPE_HOTPLUG_HANDLER },
+{ }
+},
 };
 
-DEFINE_TYPES(virt_machine_types)
+static void machvirt_machine_init(void)
+{
+type_register_static(_machine_info);
+}
+type_init(machvirt_machine_init);
+
+static void virt_machine_9_0_options(MachineClass *mc)
+{
+}
+DEFINE_VIRT_MACHINE_AS_LATEST(9, 0)
-- 
2.39.3




[PATCH 5/5] tests: Add migration test for loongarch64

2024-02-20 Thread Bibo Mao
This patch adds migration test support for loongarch64. The test code
comes from aarch64 mostly, only that it it booted as bios in qemu since
kernel requires elf format and bios uses binary format.

In addition to providing the binary, this patch also includes the source
code and the build script in tests/migration/loongarch64. So users can
change the source and/or re-compile the binary as they wish.

Signed-off-by: Bibo Mao 
---
 tests/migration/Makefile |  2 +-
 tests/migration/loongarch64/Makefile | 18 ++
 tests/migration/loongarch64/a-b-kernel.S | 46 
 tests/migration/loongarch64/a-b-kernel.h | 13 +++
 tests/migration/migration-test.h |  3 ++
 tests/qtest/meson.build  |  4 +++
 tests/qtest/migration-test.c | 10 ++
 7 files changed, 95 insertions(+), 1 deletion(-)
 create mode 100644 tests/migration/loongarch64/Makefile
 create mode 100644 tests/migration/loongarch64/a-b-kernel.S
 create mode 100644 tests/migration/loongarch64/a-b-kernel.h

diff --git a/tests/migration/Makefile b/tests/migration/Makefile
index 13e99b1692..cfebfe23f8 100644
--- a/tests/migration/Makefile
+++ b/tests/migration/Makefile
@@ -5,7 +5,7 @@
 # See the COPYING file in the top-level directory.
 #
 
-TARGET_LIST = i386 aarch64 s390x
+TARGET_LIST = i386 aarch64 s390x loongarch64
 
 SRC_PATH = ../..
 
diff --git a/tests/migration/loongarch64/Makefile 
b/tests/migration/loongarch64/Makefile
new file mode 100644
index 00..5d8719205f
--- /dev/null
+++ b/tests/migration/loongarch64/Makefile
@@ -0,0 +1,18 @@
+# To specify cross compiler prefix, use CROSS_PREFIX=
+#   $ make CROSS_PREFIX=loongarch64-linux-gnu-
+
+.PHONY: all clean
+all: a-b-kernel.h
+
+a-b-kernel.h: loongarch64.kernel
+   echo "$$__note" > $@
+   xxd -i $< | sed -e 's/.*int.*//' >> $@
+
+loongarch64.kernel: loongarch64.elf
+   $(CROSS_PREFIX)objcopy -j .text -O binary $< $@
+
+loongarch64.elf: a-b-kernel.S
+   $(CROSS_PREFIX)gcc -o $@ -nostdlib -Wl,--build-id=none $<
+
+clean:
+   $(RM) *.kernel *.elf
diff --git a/tests/migration/loongarch64/a-b-kernel.S 
b/tests/migration/loongarch64/a-b-kernel.S
new file mode 100644
index 00..078f91b306
--- /dev/null
+++ b/tests/migration/loongarch64/a-b-kernel.S
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2024 Loongson Technology Corporation Limited
+ */
+#include "../migration-test.h"
+
+#define LOONGARCH_CSR_CRMD  0
+#define LOONGARCH_VIRT_UART 0x1FE001E0
+.section .text
+
+.globl  _start
+_start:
+/* output char 'A' to UART16550 */
+li.d$t0, LOONGARCH_VIRT_UART
+li.w$t1, 'A'
+st.b$t1, $t0, 0
+
+/* traverse test memory region */
+   li.d$t0, LOONGARCH_TEST_MEM_START
+li.d$t1, LOONGARCH_TEST_MEM_END
+li.d$t2, TEST_MEM_PAGE_SIZE
+
+clean:
+st.b$zero, $t0, 0
+add.d   $t0,   $t0, $t2
+bne $t0,   $t1, clean
+
+mainloop:
+li.d$t0, LOONGARCH_TEST_MEM_START
+li.d$t1, LOONGARCH_TEST_MEM_END
+li.d$t2, TEST_MEM_PAGE_SIZE
+
+li.d$t4, LOONGARCH_VIRT_UART
+li.w$t5, 'B'
+
+innerloop:
+ld.bu   $t3, $t0, 0
+addi.w  $t3, $t3, 1
+ext.w.b $t3, $t3
+st.b$t3, $t0, 0
+add.d   $t0, $t0, $t2
+bne $t0, $t1, innerloop
+
+st.b$t5, $t4, 0
+b   mainloop
+nop
diff --git a/tests/migration/loongarch64/a-b-kernel.h 
b/tests/migration/loongarch64/a-b-kernel.h
new file mode 100644
index 00..6019450229
--- /dev/null
+++ b/tests/migration/loongarch64/a-b-kernel.h
@@ -0,0 +1,13 @@
+
+unsigned char loongarch64_kernel[] = {
+  0x0c, 0xc0, 0x3f, 0x14, 0x8c, 0x81, 0x87, 0x03, 0x0d, 0x04, 0x81, 0x03,
+  0x8d, 0x01, 0x00, 0x29, 0x0c, 0x00, 0x01, 0x14, 0x0d, 0x80, 0x0c, 0x14,
+  0x2e, 0x00, 0x00, 0x14, 0x80, 0x01, 0x00, 0x29, 0x8c, 0xb9, 0x10, 0x00,
+  0x8d, 0xf9, 0xff, 0x5f, 0x0c, 0x00, 0x01, 0x14, 0x0d, 0x80, 0x0c, 0x14,
+  0x2e, 0x00, 0x00, 0x14, 0x10, 0xc0, 0x3f, 0x14, 0x10, 0x82, 0x87, 0x03,
+  0x11, 0x08, 0x81, 0x03, 0x8f, 0x01, 0x00, 0x2a, 0xef, 0x05, 0x80, 0x02,
+  0xef, 0x5d, 0x00, 0x00, 0x8f, 0x01, 0x00, 0x29, 0x8c, 0xb9, 0x10, 0x00,
+  0x8d, 0xed, 0xff, 0x5f, 0x11, 0x02, 0x00, 0x29, 0xff, 0xcf, 0xff, 0x53,
+  0x00, 0x00, 0x40, 0x03
+};
+
diff --git a/tests/migration/migration-test.h b/tests/migration/migration-test.h
index 68512c0b1b..b6e9914f9c 100644
--- a/tests/migration/migration-test.h
+++ b/tests/migration/migration-test.h
@@ -32,4 +32,7 @@
  */
 #define ARM_TEST_MAX_KERNEL_SIZE (512 * 1024)
 
+/* LoongArch64 */
+#define LOONGARCH_TEST_MEM_START (8 * 1024 * 1024)
+#define LOONGARCH_TEST_MEM_END   (100 * 1024 * 1024)
 #endif /* MIGRATION_TEST_H */
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 2b89e8634b..b634587b0a 100644
--- a/tes

[PATCH 4/5] hw/loongarch: Set minimium memory size as 256M

2024-02-20 Thread Bibo Mao
The minium memory size for LoongArch UEFI bios is 256M, also some
test cases such as migration and qos uses parameter 256M.

Here set minium memory size for Loongarch VirtMachine with 256M,
also default memory size is changed with 256M.

Signed-off-by: Bibo Mao 
---
 hw/loongarch/virt.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index a7d700497d..5bc332f4e3 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -815,8 +815,8 @@ static void virt_init(MachineState *machine)
 cpu_model = LOONGARCH_CPU_TYPE_NAME("la464");
 }
 
-if (ram_size < 1 * GiB) {
-error_report("ram_size must be greater than 1G.");
+if (ram_size < 256 * MiB) {
+error_report("ram_size must be greater than 256M.");
 exit(1);
 }
 create_fdt(vms);
@@ -1144,7 +1144,7 @@ static void virt_class_init(ObjectClass *oc, void *data)
 HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
 
 mc->init = virt_init;
-mc->default_ram_size = 1 * GiB;
+mc->default_ram_size = 256 * MiB;
 mc->default_cpu_type = LOONGARCH_CPU_TYPE_NAME("la464");
 mc->default_ram_id = "loongarch.ram";
 mc->max_cpus = LOONGARCH_MAX_CPUS;
-- 
2.39.3




[PATCH 2/5] hw/loongarch: Rename LoongArchMachineState with VirtMachineState

2024-02-20 Thread Bibo Mao
Rename LoongArchMachineState with VirtMachineState, also change variable
name lams with vms.

Signed-off-by: Bibo Mao 
---
 hw/loongarch/acpi-build.c   |  76 +-
 hw/loongarch/fw_cfg.c   |   2 +-
 hw/loongarch/fw_cfg.h   |   2 +-
 hw/loongarch/virt.c | 276 ++--
 include/hw/loongarch/virt.h |   8 +-
 5 files changed, 182 insertions(+), 182 deletions(-)

diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c
index a2f1d6daf7..9c1599034f 100644
--- a/hw/loongarch/acpi-build.c
+++ b/hw/loongarch/acpi-build.c
@@ -105,14 +105,14 @@ build_facs(GArray *table_data)
 
 /* build MADT */
 static void
-build_madt(GArray *table_data, BIOSLinker *linker, LoongArchMachineState *lams)
+build_madt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
 {
-MachineState *ms = MACHINE(lams);
+MachineState *ms = MACHINE(vms);
 MachineClass *mc = MACHINE_GET_CLASS(ms);
 const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(ms);
 int i, arch_id;
-AcpiTable table = { .sig = "APIC", .rev = 1, .oem_id = lams->oem_id,
-.oem_table_id = lams->oem_table_id };
+AcpiTable table = { .sig = "APIC", .rev = 1, .oem_id = vms->oem_id,
+.oem_table_id = vms->oem_table_id };
 
 acpi_table_begin(, table_data);
 
@@ -167,11 +167,11 @@ build_srat(GArray *table_data, BIOSLinker *linker, 
MachineState *machine)
 int i, arch_id, node_id;
 uint64_t mem_len, mem_base;
 int nb_numa_nodes = machine->numa_state->num_nodes;
-LoongArchMachineState *lams = VIRT_MACHINE(machine);
-MachineClass *mc = MACHINE_GET_CLASS(lams);
+VirtMachineState *vms = VIRT_MACHINE(machine);
+MachineClass *mc = MACHINE_GET_CLASS(vms);
 const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(machine);
-AcpiTable table = { .sig = "SRAT", .rev = 1, .oem_id = lams->oem_id,
-.oem_table_id = lams->oem_table_id };
+AcpiTable table = { .sig = "SRAT", .rev = 1, .oem_id = vms->oem_id,
+.oem_table_id = vms->oem_table_id };
 
 acpi_table_begin(, table_data);
 build_append_int_noprefix(table_data, 1, 4); /* Reserved */
@@ -279,13 +279,13 @@ static void
 build_la_ged_aml(Aml *dsdt, MachineState *machine)
 {
 uint32_t event;
-LoongArchMachineState *lams = VIRT_MACHINE(machine);
+VirtMachineState *vms = VIRT_MACHINE(machine);
 
 build_ged_aml(dsdt, "\\_SB."GED_DEVICE,
-  HOTPLUG_HANDLER(lams->acpi_ged),
+  HOTPLUG_HANDLER(vms->acpi_ged),
   VIRT_SCI_IRQ, AML_SYSTEM_MEMORY,
   VIRT_GED_EVT_ADDR);
-event = object_property_get_uint(OBJECT(lams->acpi_ged),
+event = object_property_get_uint(OBJECT(vms->acpi_ged),
  "ged-event", _abort);
 if (event & ACPI_GED_MEM_HOTPLUG_EVT) {
 build_memory_hotplug_aml(dsdt, machine->ram_slots, "\\_SB", NULL,
@@ -295,7 +295,7 @@ build_la_ged_aml(Aml *dsdt, MachineState *machine)
 acpi_dsdt_add_power_button(dsdt);
 }
 
-static void build_pci_device_aml(Aml *scope, LoongArchMachineState *lams)
+static void build_pci_device_aml(Aml *scope, VirtMachineState *vms)
 {
 struct GPEXConfig cfg = {
 .mmio64.base = VIRT_PCI_MEM_BASE,
@@ -305,13 +305,13 @@ static void build_pci_device_aml(Aml *scope, 
LoongArchMachineState *lams)
 .ecam.base   = VIRT_PCI_CFG_BASE,
 .ecam.size   = VIRT_PCI_CFG_SIZE,
 .irq = VIRT_GSI_BASE + VIRT_DEVICE_IRQS,
-.bus = lams->pci_bus,
+.bus = vms->pci_bus,
 };
 
 acpi_dsdt_add_gpex(scope, );
 }
 
-static void build_flash_aml(Aml *scope, LoongArchMachineState *lams)
+static void build_flash_aml(Aml *scope, VirtMachineState *vms)
 {
 Aml *dev, *crs;
 
@@ -329,7 +329,7 @@ static void build_flash_aml(Aml *scope, 
LoongArchMachineState *lams)
 }
 
 #ifdef CONFIG_TPM
-static void acpi_dsdt_add_tpm(Aml *scope, LoongArchMachineState *vms)
+static void acpi_dsdt_add_tpm(Aml *scope, VirtMachineState *vms)
 {
 PlatformBusDevice *pbus = PLATFORM_BUS_DEVICE(vms->platform_bus_dev);
 hwaddr pbus_base = VIRT_PLATFORM_BUS_BASEADDRESS;
@@ -368,18 +368,18 @@ static void
 build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine)
 {
 Aml *dsdt, *scope, *pkg;
-LoongArchMachineState *lams = VIRT_MACHINE(machine);
-AcpiTable table = { .sig = "DSDT", .rev = 1, .oem_id = lams->oem_id,
-.oem_table_id = lams->oem_table_id };
+VirtMachineState *vms = VIRT_MACHINE(machine);
+AcpiTable table = { .sig = "DSDT", .rev = 1, .oem_id = vms->oem_id,
+.oem_table_id = vms->oem_table_id };
 
 acpi_table_begin(, table_data);
 dsdt = init_aml_allocator();
   

[PATCH 0/5] Add migration test for loongarch64

2024-02-20 Thread Bibo Mao
Migration test case is added for loongarch64 here. Since compat machine
type is required for migration test case, also compat machine qemu 9.0
is added for loongarch virt machine.

Bibo Mao (5):
  hw/loongarch: Rename LOONGARCH_MACHINE with VIRT_MACHINE.
  hw/loongarch: Rename LoongArchMachineState with VirtMachineState
  hw/loongarch: Add compat machine for 9.0
  hw/loongarch: Set minimium memory size as 256M
  tests: Add migration test for loongarch64

 hw/loongarch/acpi-build.c|  76 +++---
 hw/loongarch/fw_cfg.c|   2 +-
 hw/loongarch/fw_cfg.h|   2 +-
 hw/loongarch/virt.c  | 333 +--
 include/hw/loongarch/virt.h  |  10 +-
 tests/migration/Makefile |   2 +-
 tests/migration/loongarch64/Makefile |  18 ++
 tests/migration/loongarch64/a-b-kernel.S |  46 
 tests/migration/loongarch64/a-b-kernel.h |  13 +
 tests/migration/migration-test.h |   3 +
 tests/qtest/meson.build  |   4 +
 tests/qtest/migration-test.c |  10 +
 12 files changed, 323 insertions(+), 196 deletions(-)
 create mode 100644 tests/migration/loongarch64/Makefile
 create mode 100644 tests/migration/loongarch64/a-b-kernel.S
 create mode 100644 tests/migration/loongarch64/a-b-kernel.h


base-commit: da96ad4a6a2ef26c83b15fa95e7fceef5147269c
-- 
2.39.3




[PATCH 1/5] hw/loongarch: Rename LOONGARCH_MACHINE with VIRT_MACHINE.

2024-02-20 Thread Bibo Mao
On LoongArch system, there is only virt machine type now, name
LOONGARCH_MACHINE is confused, rename it with VIRT_MACHINE. Name
about Other real hw boards can be added in future.

Signed-off-by: Bibo Mao 
---
 hw/loongarch/acpi-build.c   |  8 
 hw/loongarch/virt.c | 19 +--
 include/hw/loongarch/virt.h |  4 ++--
 3 files changed, 15 insertions(+), 16 deletions(-)

diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c
index a1c4198741..a2f1d6daf7 100644
--- a/hw/loongarch/acpi-build.c
+++ b/hw/loongarch/acpi-build.c
@@ -167,7 +167,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, 
MachineState *machine)
 int i, arch_id, node_id;
 uint64_t mem_len, mem_base;
 int nb_numa_nodes = machine->numa_state->num_nodes;
-LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
+LoongArchMachineState *lams = VIRT_MACHINE(machine);
 MachineClass *mc = MACHINE_GET_CLASS(lams);
 const CPUArchIdList *arch_ids = mc->possible_cpu_arch_ids(machine);
 AcpiTable table = { .sig = "SRAT", .rev = 1, .oem_id = lams->oem_id,
@@ -279,7 +279,7 @@ static void
 build_la_ged_aml(Aml *dsdt, MachineState *machine)
 {
 uint32_t event;
-LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
+LoongArchMachineState *lams = VIRT_MACHINE(machine);
 
 build_ged_aml(dsdt, "\\_SB."GED_DEVICE,
   HOTPLUG_HANDLER(lams->acpi_ged),
@@ -368,7 +368,7 @@ static void
 build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine)
 {
 Aml *dsdt, *scope, *pkg;
-LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
+LoongArchMachineState *lams = VIRT_MACHINE(machine);
 AcpiTable table = { .sig = "DSDT", .rev = 1, .oem_id = lams->oem_id,
 .oem_table_id = lams->oem_table_id };
 
@@ -398,7 +398,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, 
MachineState *machine)
 
 static void acpi_build(AcpiBuildTables *tables, MachineState *machine)
 {
-LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
+LoongArchMachineState *lams = VIRT_MACHINE(machine);
 GArray *table_offsets;
 AcpiFadtData fadt_data;
 unsigned facs, rsdt, dsdt;
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 0ad7d8c887..02391baadd 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -774,7 +774,7 @@ static void loongarch_init(MachineState *machine)
 ram_addr_t ram_size = machine->ram_size;
 uint64_t highram_size = 0, phyAddr = 0;
 MemoryRegion *address_space_mem = get_system_memory();
-LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
+LoongArchMachineState *lams = VIRT_MACHINE(machine);
 int nb_numa_nodes = machine->numa_state->num_nodes;
 NodeInfo *numa_info = machine->numa_state->nodes;
 int i;
@@ -941,7 +941,7 @@ bool loongarch_is_acpi_enabled(LoongArchMachineState *lams)
 static void loongarch_get_acpi(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
 {
-LoongArchMachineState *lams = LOONGARCH_MACHINE(obj);
+LoongArchMachineState *lams = VIRT_MACHINE(obj);
 OnOffAuto acpi = lams->acpi;
 
 visit_type_OnOffAuto(v, name, , errp);
@@ -950,14 +950,14 @@ static void loongarch_get_acpi(Object *obj, Visitor *v, 
const char *name,
 static void loongarch_set_acpi(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
 {
-LoongArchMachineState *lams = LOONGARCH_MACHINE(obj);
+LoongArchMachineState *lams = VIRT_MACHINE(obj);
 
 visit_type_OnOffAuto(v, name, >acpi, errp);
 }
 
 static void loongarch_machine_initfn(Object *obj)
 {
-LoongArchMachineState *lams = LOONGARCH_MACHINE(obj);
+LoongArchMachineState *lams = VIRT_MACHINE(obj);
 
 lams->acpi = ON_OFF_AUTO_AUTO;
 lams->oem_id = g_strndup(ACPI_BUILD_APPNAME6, 6);
@@ -989,7 +989,7 @@ static void virt_machine_device_pre_plug(HotplugHandler 
*hotplug_dev,
 static void virt_mem_unplug_request(HotplugHandler *hotplug_dev,
  DeviceState *dev, Error **errp)
 {
-LoongArchMachineState *lams = LOONGARCH_MACHINE(hotplug_dev);
+LoongArchMachineState *lams = VIRT_MACHINE(hotplug_dev);
 
 /* the acpi ged is always exist */
 hotplug_handler_unplug_request(HOTPLUG_HANDLER(lams->acpi_ged), dev,
@@ -1007,7 +1007,7 @@ static void 
virt_machine_device_unplug_request(HotplugHandler *hotplug_dev,
 static void virt_mem_unplug(HotplugHandler *hotplug_dev,
  DeviceState *dev, Error **errp)
 {
-LoongArchMachineState *lams = LOONGARCH_MACHINE(hotplug_dev);
+LoongArchMachineState *lams = VIRT_MACHINE(hotplug_dev);
 
 hotplug_handler_unplug(HOTPLUG_HANDLER(lams->acpi_ged), dev, errp);
 pc_dimm_unplug(PC_DIMM(dev), MACHINE(lams));
@@ -1025,7 +1025,7 @@ static void virt_machine_device_unplug(

[RFC PATCH] target/loongarch/kvm: Add software breakpoint support

2024-02-17 Thread Bibo Mao
With KVM virtualization, debug exception is passthrough to
to guest kernel rather than host mode. Here hypercall
instruction with special hypercall code is used for sw
breakpoint usage.

Now only software breakpoint is supported, and itt is allowed
to insert/remove software breakpoint. Later hardware  breakpoint
will be added.

Signed-off-by: Bibo Mao 
---
 target/loongarch/kvm/kvm.c | 77 ++
 1 file changed, 77 insertions(+)

diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
index c19978a970..49d02076ad 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -29,6 +29,7 @@
 #include "trace.h"
 
 static bool cap_has_mp_state;
+static unsigned int brk_insn;
 const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
 KVM_CAP_LAST_INFO
 };
@@ -675,7 +676,14 @@ static void kvm_loongarch_vm_stage_change(void *opaque, 
bool running,
 
 int kvm_arch_init_vcpu(CPUState *cs)
 {
+uint64_t val;
+
 qemu_add_vm_change_state_handler(kvm_loongarch_vm_stage_change, cs);
+
+if (!kvm_get_one_reg(cs, KVM_REG_LOONGARCH_DEBUG_INST, )) {
+brk_insn = val;
+}
+
 return 0;
 }
 
@@ -755,6 +763,68 @@ bool kvm_arch_cpu_check_are_resettable(void)
 return true;
 }
 
+
+void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg)
+{
+if (kvm_sw_breakpoints_active(cpu)) {
+dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP;
+}
+}
+
+int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
+{
+if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)>saved_insn, 4, 0) ||
+cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)_insn, 4, 1)) {
+error_report("%s failed", __func__);
+return -EINVAL;
+}
+return 0;
+}
+
+int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
+{
+static uint32_t brk;
+
+if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *), 4, 0) ||
+brk != brk_insn ||
+cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)>saved_insn, 4, 1)) {
+error_report("%s failed", __func__);
+return -EINVAL;
+}
+return 0;
+}
+
+int kvm_arch_insert_hw_breakpoint(vaddr addr, vaddr len, int type)
+{
+return -ENOSYS;
+}
+
+int kvm_arch_remove_hw_breakpoint(vaddr addr, vaddr len, int type)
+{
+return -ENOSYS;
+}
+
+void kvm_arch_remove_all_hw_breakpoints(void)
+{
+}
+
+static bool kvm_loongarch_handle_debug(CPUState *cs, struct kvm_run *run)
+{
+LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+CPULoongArchState *env = >env;
+
+kvm_cpu_synchronize_state(cs);
+if (cs->singlestep_enabled) {
+return true;
+}
+
+if (kvm_find_sw_breakpoint(cs, env->pc)) {
+return true;
+}
+
+return false;
+}
+
 int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
 {
 int ret = 0;
@@ -774,6 +844,13 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
  run->iocsr_io.len,
  run->iocsr_io.is_write);
 break;
+
+case KVM_EXIT_DEBUG:
+if (kvm_loongarch_handle_debug(cs, run)) {
+ret = EXCP_DEBUG;
+}
+break;
+
 default:
 ret = -1;
 warn_report("KVM: unknown exit reason %d", run->exit_reason);

base-commit: 5767815218efd3cbfd409505ed824d5f356044ae
-- 
2.39.3




[PATCH v2] tests/cdrom-test: Add cdrom test for LoongArch virt machine

2024-02-17 Thread Bibo Mao
The cdrom test skips to execute on LoongArch system with command
"make check", this patch enables cdrom test for LoongArch virt
machine platform.

With this patch, cdrom test passes to run on LoongArch virt
machine type.

Signed-off-by: Bibo Mao 
---
Add virtio-blk-pci checking since LoongArch virt machine type does
not support ISA bus and IDE harddisk.

---
 tests/qtest/cdrom-test.c | 5 +
 1 file changed, 5 insertions(+)

diff --git a/tests/qtest/cdrom-test.c b/tests/qtest/cdrom-test.c
index 0945383789..5d89e62515 100644
--- a/tests/qtest/cdrom-test.c
+++ b/tests/qtest/cdrom-test.c
@@ -271,6 +271,11 @@ int main(int argc, char **argv)
 const char *virtmachine[] = { "virt", NULL };
 add_cdrom_param_tests(virtmachine);
 }
+} else if (g_str_equal(arch, "loongarch64")) {
+if (qtest_has_device("virtio-blk-pci")) {
+const char *virtmachine[] = { "virt", NULL };
+add_cdrom_param_tests(virtmachine);
+}
 } else {
 const char *nonemachine[] = { "none", NULL };
 add_cdrom_param_tests(nonemachine);

base-commit: 5767815218efd3cbfd409505ed824d5f356044ae
-- 
2.39.3




[PATCH] tests/cdrom-test: Add cdrom test for LoongArch virt machine

2024-02-04 Thread Bibo Mao
The cdrom test skips to execute on LoongArch system with command
"make check", this patch enables cdrom test for LoongArch virt
machine platform.

With this patch, cdrom test passes to run on LoongArch virt
machine type.

Signed-off-by: Bibo Mao 
---
 tests/qtest/cdrom-test.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/tests/qtest/cdrom-test.c b/tests/qtest/cdrom-test.c
index 0945383789..c8b97d8d9a 100644
--- a/tests/qtest/cdrom-test.c
+++ b/tests/qtest/cdrom-test.c
@@ -271,6 +271,9 @@ int main(int argc, char **argv)
 const char *virtmachine[] = { "virt", NULL };
 add_cdrom_param_tests(virtmachine);
 }
+} else if (g_str_equal(arch, "loongarch64")) {
+const char *virtmachine[] = { "virt", NULL };
+add_cdrom_param_tests(virtmachine);
 } else {
 const char *nonemachine[] = { "none", NULL };
 add_cdrom_param_tests(nonemachine);
-- 
2.39.3




[PATCH v2] configure: Add linux header compile support for LoongArch

2024-01-15 Thread Bibo Mao
When compiling qemu with system KVM mode for LoongArch, header files
in directory linux-headers/asm-loongarch should be used firstly.
Otherwise it fails to find kvm.h on system with old glibc, since
latest kernel header files are not installed.

This patch adds linux_arch definition for LoongArch system so that
header files in directory linux-headers/asm-loongarch can be included.

Fixes: 714b03c125 ("target/loongarch: Add loongarch kvm into meson build")
Signed-off-by: Bibo Mao 
Reviewed-by: Philippe Mathieu-Daudé 
---
Changes in v2:
 1. Add Fixes label for commit 714b03c125

---
 configure | 1 +
 1 file changed, 1 insertion(+)

diff --git a/configure b/configure
index 21ab9a64e9..3d8e24ae01 100755
--- a/configure
+++ b/configure
@@ -445,6 +445,7 @@ case "$cpu" in
   loongarch*)
 cpu=loongarch64
 host_arch=loongarch64
+linux_arch=loongarch
 ;;
 
   mips64*)

base-commit: 977542ded7e6b28d2bc077bcda24568c716e393c
-- 
2.39.3




[PATCH] target/loongarch: Set cpuid CSR register only once with kvm mode

2024-01-15 Thread Bibo Mao
CSR cpuid register is used for routing irq to different vcpus, its
value is kept unchanged since poweron. So it is not necessary to
set CSR cpuid register after system resets, and it is only set at
vm creation stage.

Signed-off-by: Bibo Mao 
---
 target/loongarch/kvm/kvm.c | 9 ++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
index 84bcdf5f86..2230f029d0 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -250,7 +250,7 @@ static int kvm_loongarch_get_csr(CPUState *cs)
 return ret;
 }
 
-static int kvm_loongarch_put_csr(CPUState *cs)
+static int kvm_loongarch_put_csr(CPUState *cs, int level)
 {
 int ret = 0;
 LoongArchCPU *cpu = LOONGARCH_CPU(cs);
@@ -322,8 +322,11 @@ static int kvm_loongarch_put_csr(CPUState *cs)
 ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_RVACFG),
>CSR_RVACFG);
 
-ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_CPUID),
+/* CPUID is constant after poweron, it should be set only once */
+if (level >= KVM_PUT_FULL_STATE) {
+ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_CPUID),
>CSR_CPUID);
+}
 
 ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRCFG1),
>CSR_PRCFG1);
@@ -598,7 +601,7 @@ int kvm_arch_put_registers(CPUState *cs, int level)
 return ret;
 }
 
-ret = kvm_loongarch_put_csr(cs);
+ret = kvm_loongarch_put_csr(cs, level);
 if (ret) {
 return ret;
 }

base-commit: 977542ded7e6b28d2bc077bcda24568c716e393c
-- 
2.39.3




[PATCH] qemu/osdep: Add huge page aligned support on LoongArch platform

2024-01-14 Thread Bibo Mao
On LoongArch kvm mode if transparent huge page wants to be enabled, base
address and size of memslot from both HVA and GPA view. And LoongArch
supports both 4K and 16K page size with Linux kernel, so transparent huge
page size is calculated from real page size rather than hardcoded size.

Signed-off-by: Bibo Mao 
---
 include/qemu/osdep.h | 8 
 1 file changed, 8 insertions(+)

diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h
index 9a405bed89..c9692cc314 100644
--- a/include/qemu/osdep.h
+++ b/include/qemu/osdep.h
@@ -547,6 +547,14 @@ int madvise(char *, size_t, int);
 #  define QEMU_VMALLOC_ALIGN (256 * 4096)
 #elif defined(__linux__) && defined(__sparc__)
 #  define QEMU_VMALLOC_ALIGN MAX(qemu_real_host_page_size(), SHMLBA)
+#elif defined(__linux__) && defined(__loongarch__)
+   /*
+* For transparent hugepage optimization, it has better be huge page
+* aligned. LoongArch host system supports two kinds of pagesize: 4K
+* and 16K, here calculate huge page size from host page size
+*/
+#  define QEMU_VMALLOC_ALIGN (qemu_real_host_page_size() * \
+ qemu_real_host_page_size() / sizeof(long))
 #else
 #  define QEMU_VMALLOC_ALIGN qemu_real_host_page_size()
 #endif
-- 
2.39.3




[PATCH] configure: Add linux header compile support for LoongArch

2024-01-14 Thread Bibo Mao
When compiling qemu with system KVM mode for LoongArch, header files in
directory linux-headers/asm-loongarch should be used firstly. Otherwise it
fails to find kvm.h on system with old glibc, since latest kernel header
files are not installed.

This patch adds linux_arch definition for LoongArch system so that header
files in directory linux-headers/asm-loongarch can be included.

Signed-off-by: Bibo Mao 
---
 configure | 1 +
 1 file changed, 1 insertion(+)

diff --git a/configure b/configure
index 21ab9a64e9..3d8e24ae01 100755
--- a/configure
+++ b/configure
@@ -445,6 +445,7 @@ case "$cpu" in
   loongarch*)
 cpu=loongarch64
 host_arch=loongarch64
+linux_arch=loongarch
 ;;
 
   mips64*)
-- 
2.39.3




[PATCH v2 0/4] hw/loongarch/virt: Set iocsr address space per-board rather percpu

2023-12-15 Thread Bibo Mao
On LoongArch system, there is iocsr address space simliar system io
address space on x86. And each cpu has its separate iocsr address space now,
with this patch, iocsr address space is changed with per-board, and
MemTxAttrs.requester_id is used to differentiate cpu cores.

---
Changes in v2:
  1. Add num-cpu property for extioi interrupt controller
  2. Add post_load support for extioi vmstate to calculate sw_ipmap/sw_coremap 
info
---
Bibo Mao (4):
  hw/intc/loongarch_ipi: Use MemTxAttrs interface for ipi ops
  hw/loongarch/virt: Set iocsr address space per-board rather than
percpu
  hw/intc/loongarch_extioi: Add dynamic cpu number support
  hw/intc/loongarch_extioi: Add vmstate post_load support

 hw/intc/loongarch_extioi.c | 230 ++---
 hw/intc/loongarch_ipi.c| 191 +++-
 hw/loongarch/virt.c|  94 
 include/hw/intc/loongarch_extioi.h |  12 +-
 include/hw/intc/loongarch_ipi.h|   3 +-
 include/hw/loongarch/virt.h|   3 +
 target/loongarch/cpu.c |  48 --
 target/loongarch/cpu.h |   4 +-
 target/loongarch/iocsr_helper.c|  16 +-
 9 files changed, 358 insertions(+), 243 deletions(-)


base-commit: 039afc5ef7367fbc8fb475580c291c2655e856cb
-- 
2.39.3




[PATCH v2 1/4] hw/intc/loongarch_ipi: Use MemTxAttrs interface for ipi ops

2023-12-15 Thread Bibo Mao
There are two interface pairs for MemoryRegionOps, read/write and
read_with_attrs/write_with_attrs. The later is better for ipi device
emulation since initial cpu can be parsed from attrs.requester_id.

And requester_id can be overrided for IOCSR_IPI_SEND and mail_send
function when it is to forward message to another vcpu.

Signed-off-by: Bibo Mao 
---
 hw/intc/loongarch_ipi.c | 136 +++-
 1 file changed, 77 insertions(+), 59 deletions(-)

diff --git a/hw/intc/loongarch_ipi.c b/hw/intc/loongarch_ipi.c
index 67858b521c..1d3449e77d 100644
--- a/hw/intc/loongarch_ipi.c
+++ b/hw/intc/loongarch_ipi.c
@@ -17,14 +17,16 @@
 #include "target/loongarch/internals.h"
 #include "trace.h"
 
-static void loongarch_ipi_writel(void *, hwaddr, uint64_t, unsigned);
-
-static uint64_t loongarch_ipi_readl(void *opaque, hwaddr addr, unsigned size)
+static MemTxResult loongarch_ipi_readl(void *opaque, hwaddr addr,
+   uint64_t *data,
+   unsigned size, MemTxAttrs attrs)
 {
-IPICore *s = opaque;
+IPICore *s;
+LoongArchIPI *ipi = opaque;
 uint64_t ret = 0;
 int index = 0;
 
+s = >ipi_core;
 addr &= 0xff;
 switch (addr) {
 case CORE_STATUS_OFF:
@@ -49,10 +51,12 @@ static uint64_t loongarch_ipi_readl(void *opaque, hwaddr 
addr, unsigned size)
 }
 
 trace_loongarch_ipi_read(size, (uint64_t)addr, ret);
-return ret;
+*data = ret;
+return MEMTX_OK;
 }
 
-static void send_ipi_data(CPULoongArchState *env, uint64_t val, hwaddr addr)
+static void send_ipi_data(CPULoongArchState *env, uint64_t val, hwaddr addr,
+  MemTxAttrs attrs)
 {
 int i, mask = 0, data = 0;
 
@@ -62,7 +66,7 @@ static void send_ipi_data(CPULoongArchState *env, uint64_t 
val, hwaddr addr)
  */
 if ((val >> 27) & 0xf) {
 data = address_space_ldl(>address_space_iocsr, addr,
- MEMTXATTRS_UNSPECIFIED, NULL);
+ attrs, NULL);
 for (i = 0; i < 4; i++) {
 /* get mask for byte writing */
 if (val & (0x1 << (27 + i))) {
@@ -74,7 +78,7 @@ static void send_ipi_data(CPULoongArchState *env, uint64_t 
val, hwaddr addr)
 data &= mask;
 data |= (val >> 32) & ~mask;
 address_space_stl(>address_space_iocsr, addr,
-  data, MEMTXATTRS_UNSPECIFIED, NULL);
+  data, attrs, NULL);
 }
 
 static int archid_cmp(const void *a, const void *b)
@@ -103,80 +107,72 @@ static CPUState *ipi_getcpu(int arch_id)
 CPUArchId *archid;
 
 archid = find_cpu_by_archid(machine, arch_id);
-return CPU(archid->cpu);
-}
-
-static void ipi_send(uint64_t val)
-{
-uint32_t cpuid;
-uint8_t vector;
-CPUState *cs;
-LoongArchCPU *cpu;
-LoongArchIPI *s;
-
-cpuid = extract32(val, 16, 10);
-if (cpuid >= LOONGARCH_MAX_CPUS) {
-trace_loongarch_ipi_unsupported_cpuid("IOCSR_IPI_SEND", cpuid);
-return;
+if (archid) {
+return CPU(archid->cpu);
 }
 
-/* IPI status vector */
-vector = extract8(val, 0, 5);
-
-cs = ipi_getcpu(cpuid);
-cpu = LOONGARCH_CPU(cs);
-s = LOONGARCH_IPI(cpu->env.ipistate);
-loongarch_ipi_writel(>ipi_core, CORE_SET_OFF, BIT(vector), 4);
+return NULL;
 }
 
-static void mail_send(uint64_t val)
+static MemTxResult mail_send(uint64_t val, MemTxAttrs attrs)
 {
 uint32_t cpuid;
 hwaddr addr;
-CPULoongArchState *env;
 CPUState *cs;
-LoongArchCPU *cpu;
 
 cpuid = extract32(val, 16, 10);
 if (cpuid >= LOONGARCH_MAX_CPUS) {
 trace_loongarch_ipi_unsupported_cpuid("IOCSR_MAIL_SEND", cpuid);
-return;
+return MEMTX_DECODE_ERROR;
 }
 
-addr = 0x1020 + (val & 0x1c);
 cs = ipi_getcpu(cpuid);
-cpu = LOONGARCH_CPU(cs);
-env = >env;
-send_ipi_data(env, val, addr);
+if (cs == NULL) {
+return MEMTX_DECODE_ERROR;
+}
+
+/* override requester_id */
+addr = SMP_IPI_MAILBOX + CORE_BUF_20 + (val & 0x1c);
+attrs.requester_id = cs->cpu_index;
+send_ipi_data(_CPU(cs)->env, val, addr, attrs);
+return MEMTX_OK;
 }
 
-static void any_send(uint64_t val)
+static MemTxResult any_send(uint64_t val, MemTxAttrs attrs)
 {
 uint32_t cpuid;
 hwaddr addr;
-CPULoongArchState *env;
 CPUState *cs;
-LoongArchCPU *cpu;
 
 cpuid = extract32(val, 16, 10);
 if (cpuid >= LOONGARCH_MAX_CPUS) {
 trace_loongarch_ipi_unsupported_cpuid("IOCSR_ANY_SEND", cpuid);
-return;
+return MEMTX_DECODE_ERROR;
 }
 
-addr = val & 0x;
 cs = ipi_getcpu(cpuid);
-cpu = LOONGARCH_CPU(cs);
-env = >env;
-send_ipi_data(env, val, addr);
+if (cs == NULL) {
+return MEMTX_DECODE_ERROR;
+}
+
+

[PATCH v2 3/4] hw/intc/loongarch_extioi: Add dynamic cpu number support

2023-12-15 Thread Bibo Mao
On LoongArch physical machine, one extioi interrupt controller only
supports 4 cpus. With processor more than 4 cpus, there are multiple
extioi interrupt controllers; if interrupts need to be routed to
other cpus, they are forwarded from extioi node0 to other extioi nodes.

On virt machine model, there is simple extioi interrupt device model.
All cpus can access register of extioi interrupt controller, however
interrupt can only be route to 4 vcpu for compatible with old kernel.

This patch adds dynamic cpu number support about extioi interrupt.
With old kernel legacy extioi model is used, however kernel can detect
and choose new route method in future, so that interrupt can be routed to
all vcpus.

Signed-off-by: Bibo Mao 
---
 hw/intc/loongarch_extioi.c | 107 +++--
 hw/loongarch/virt.c|   3 +-
 include/hw/intc/loongarch_extioi.h |  11 ++-
 3 files changed, 81 insertions(+), 40 deletions(-)

diff --git a/hw/intc/loongarch_extioi.c b/hw/intc/loongarch_extioi.c
index 77b4776958..d9d5066c3f 100644
--- a/hw/intc/loongarch_extioi.c
+++ b/hw/intc/loongarch_extioi.c
@@ -8,6 +8,7 @@
 #include "qemu/osdep.h"
 #include "qemu/module.h"
 #include "qemu/log.h"
+#include "qapi/error.h"
 #include "hw/irq.h"
 #include "hw/sysbus.h"
 #include "hw/loongarch/virt.h"
@@ -32,23 +33,23 @@ static void extioi_update_irq(LoongArchExtIOI *s, int irq, 
int level)
 if (((s->enable[irq_index]) & irq_mask) == 0) {
 return;
 }
-s->coreisr[cpu][irq_index] |= irq_mask;
-found = find_first_bit(s->sw_isr[cpu][ipnum], EXTIOI_IRQS);
-set_bit(irq, s->sw_isr[cpu][ipnum]);
+s->cpu[cpu].coreisr[irq_index] |= irq_mask;
+found = find_first_bit(s->cpu[cpu].sw_isr[ipnum], EXTIOI_IRQS);
+set_bit(irq, s->cpu[cpu].sw_isr[ipnum]);
 if (found < EXTIOI_IRQS) {
 /* other irq is handling, need not update parent irq level */
 return;
 }
 } else {
-s->coreisr[cpu][irq_index] &= ~irq_mask;
-clear_bit(irq, s->sw_isr[cpu][ipnum]);
-found = find_first_bit(s->sw_isr[cpu][ipnum], EXTIOI_IRQS);
+s->cpu[cpu].coreisr[irq_index] &= ~irq_mask;
+clear_bit(irq, s->cpu[cpu].sw_isr[ipnum]);
+found = find_first_bit(s->cpu[cpu].sw_isr[ipnum], EXTIOI_IRQS);
 if (found < EXTIOI_IRQS) {
 /* other irq is handling, need not update parent irq level */
 return;
 }
 }
-qemu_set_irq(s->parent_irq[cpu][ipnum], level);
+qemu_set_irq(s->cpu[cpu].parent_irq[ipnum], level);
 }
 
 static void extioi_setirq(void *opaque, int irq, int level)
@@ -96,7 +97,7 @@ static MemTxResult extioi_readw(void *opaque, hwaddr addr, 
uint64_t *data,
 index = (offset - EXTIOI_COREISR_START) >> 2;
 /* using attrs to get current cpu index */
 cpu = attrs.requester_id;
-*data = s->coreisr[cpu][index];
+*data = s->cpu[cpu].coreisr[index];
 break;
 case EXTIOI_COREMAP_START ... EXTIOI_COREMAP_END - 1:
 index = (offset - EXTIOI_COREMAP_START) >> 2;
@@ -189,8 +190,8 @@ static MemTxResult extioi_writew(void *opaque, hwaddr addr,
 index = (offset - EXTIOI_COREISR_START) >> 2;
 /* using attrs to get current cpu index */
 cpu = attrs.requester_id;
-old_data = s->coreisr[cpu][index];
-s->coreisr[cpu][index] = old_data & ~val;
+old_data = s->cpu[cpu].coreisr[index];
+s->cpu[cpu].coreisr[index] = old_data & ~val;
 /* write 1 to clear interrupt */
 old_data &= val;
 irq = ctz32(old_data);
@@ -248,14 +249,61 @@ static const MemoryRegionOps extioi_ops = {
 .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
-static const VMStateDescription vmstate_loongarch_extioi = {
-.name = TYPE_LOONGARCH_EXTIOI,
+static void loongarch_extioi_realize(DeviceState *dev, Error **errp)
+{
+LoongArchExtIOI *s = LOONGARCH_EXTIOI(dev);
+SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+int i, pin;
+
+if (s->num_cpu == 0) {
+error_setg(errp, "num-cpu must be at least 1");
+return;
+}
+
+for (i = 0; i < EXTIOI_IRQS; i++) {
+sysbus_init_irq(sbd, >irq[i]);
+}
+
+qdev_init_gpio_in(dev, extioi_setirq, EXTIOI_IRQS);
+memory_region_init_io(>extioi_system_mem, OBJECT(s), _ops,
+  s, "extioi_system_mem", 0x900);
+sysbus_init_mmio(sbd, >extioi_system_mem);
+s->cpu = g_new0(ExtIOICore, s->num_cpu);
+if (s->cpu == NULL) {
+error_setg(errp, "Memory allocation for ExtIOICore faile");
+return;
+}
+
+for (i = 0; i < s->num_cpu; i++) {
+for (pin = 0; pin < LS3A_INTC_IP; pin++) {
+qdev_init_gpio_o

[PATCH v2 4/4] hw/intc/loongarch_extioi: Add vmstate post_load support

2023-12-15 Thread Bibo Mao
There are elements sw_ipmap and sw_coremap, which is usd to speed
up irq injection flow. They are saved and restored in vmstate during
migration, indeed they can calculated from hw registers. Here
post_load is added for get sw_ipmap and sw_coremap from extioi hw
state.

Signed-off-by: Bibo Mao 
---
 hw/intc/loongarch_extioi.c | 120 +++--
 1 file changed, 76 insertions(+), 44 deletions(-)

diff --git a/hw/intc/loongarch_extioi.c b/hw/intc/loongarch_extioi.c
index d9d5066c3f..e0fd57f962 100644
--- a/hw/intc/loongarch_extioi.c
+++ b/hw/intc/loongarch_extioi.c
@@ -130,12 +130,66 @@ static inline void extioi_enable_irq(LoongArchExtIOI *s, 
int index,\
 }
 }
 
+static inline void extioi_update_sw_coremap(LoongArchExtIOI *s, int irq,
+uint64_t val, bool notify)
+{
+int i, cpu;
+
+/*
+ * loongarch only support little endian,
+ * so we paresd the value with little endian.
+ */
+val = cpu_to_le64(val);
+
+for (i = 0; i < 4; i++) {
+cpu = val & 0xff;
+cpu = ctz32(cpu);
+cpu = (cpu >= 4) ? 0 : cpu;
+val = val >> 8;
+
+if (s->sw_coremap[irq + i] == cpu) {
+continue;
+}
+
+if (notify && test_bit(irq, (unsigned long *)s->isr)) {
+/*
+ * lower irq at old cpu and raise irq at new cpu
+ */
+extioi_update_irq(s, irq + i, 0);
+s->sw_coremap[irq + i] = cpu;
+extioi_update_irq(s, irq + i, 1);
+} else {
+s->sw_coremap[irq + i] = cpu;
+}
+}
+}
+
+static inline void extioi_update_sw_ipmap(LoongArchExtIOI *s, int index,
+  uint64_t val)
+{
+int i;
+uint8_t ipnum;
+
+/*
+ * loongarch only support little endian,
+ * so we paresd the value with little endian.
+ */
+val = cpu_to_le64(val);
+for (i = 0; i < 4; i++) {
+ipnum = val & 0xff;
+ipnum = ctz32(ipnum);
+ipnum = (ipnum >= 4) ? 0 : ipnum;
+s->sw_ipmap[index * 4 + i] = ipnum;
+val = val >> 8;
+}
+}
+
 static MemTxResult extioi_writew(void *opaque, hwaddr addr,
   uint64_t val, unsigned size,
   MemTxAttrs attrs)
 {
 LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
-int i, cpu, index, old_data, irq;
+int cpu, index, old_data, irq;
 uint32_t offset;
 
 trace_loongarch_extioi_writew(addr, val);
@@ -153,20 +207,7 @@ static MemTxResult extioi_writew(void *opaque, hwaddr addr,
  */
 index = (offset - EXTIOI_IPMAP_START) >> 2;
 s->ipmap[index] = val;
-/*
- * loongarch only support little endian,
- * so we paresd the value with little endian.
- */
-val = cpu_to_le64(val);
-for (i = 0; i < 4; i++) {
-uint8_t ipnum;
-ipnum = val & 0xff;
-ipnum = ctz32(ipnum);
-ipnum = (ipnum >= 4) ? 0 : ipnum;
-s->sw_ipmap[index * 4 + i] = ipnum;
-val = val >> 8;
-}
-
+extioi_update_sw_ipmap(s, index, val);
 break;
 case EXTIOI_ENABLE_START ... EXTIOI_ENABLE_END - 1:
 index = (offset - EXTIOI_ENABLE_START) >> 2;
@@ -205,33 +246,8 @@ static MemTxResult extioi_writew(void *opaque, hwaddr addr,
 irq = offset - EXTIOI_COREMAP_START;
 index = irq / 4;
 s->coremap[index] = val;
-/*
- * loongarch only support little endian,
- * so we paresd the value with little endian.
- */
-val = cpu_to_le64(val);
-
-for (i = 0; i < 4; i++) {
-cpu = val & 0xff;
-cpu = ctz32(cpu);
-cpu = (cpu >= 4) ? 0 : cpu;
-val = val >> 8;
-
-if (s->sw_coremap[irq + i] == cpu) {
-continue;
-}
-
-if (test_bit(irq, (unsigned long *)s->isr)) {
-/*
- * lower irq at old cpu and raise irq at new cpu
- */
-extioi_update_irq(s, irq + i, 0);
-s->sw_coremap[irq + i] = cpu;
-extioi_update_irq(s, irq + i, 1);
-} else {
-s->sw_coremap[irq + i] = cpu;
-}
-}
+
+extioi_update_sw_coremap(s, irq, val, true);
 break;
 default:
 break;
@@ -288,6 +304,23 @@ static void loongarch_extioi_finalize(Object *obj)
 g_free(s->cpu);
 }
 
+static int vmstate_extioi_post_load(void *opaque, int version_id)
+{
+LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
+int i, start_irq;
+
+for (i = 0; i < (EXTIOI_IRQS / 4); i++) {
+start_irq = i * 4;
+extioi_update_sw_coremap(s, start_irq, s->coremap[i], false);
+}
+
+for (i = 0; i < (EXTIOI_IRQS_IPMAP

[PATCH v2 2/4] hw/loongarch/virt: Set iocsr address space per-board rather than percpu

2023-12-15 Thread Bibo Mao
LoongArch system has iocsr address space, most iocsr registers are
per-board, however some iocsr register spaces banked for percpu such
as ipi mailbox and extioi interrupt status. For banked iocsr space,
each cpu has the same iocsr space, but separate data.

This patch changes iocsr address space per-board rather percpu,
for iocsr registers specified for cpu, MemTxAttrs.requester_id
can be parsed for the cpu. With this patches, the total address space
on board will be simple, only iocsr address space and system memory,
rather than the number of cpu and system memory.

Signed-off-by: Bibo Mao 
---
 hw/intc/loongarch_extioi.c |  3 -
 hw/intc/loongarch_ipi.c| 61 +++-
 hw/loongarch/virt.c| 91 ++
 include/hw/intc/loongarch_extioi.h |  1 -
 include/hw/intc/loongarch_ipi.h|  3 +-
 include/hw/loongarch/virt.h|  3 +
 target/loongarch/cpu.c | 48 
 target/loongarch/cpu.h |  4 +-
 target/loongarch/iocsr_helper.c| 16 +++---
 9 files changed, 127 insertions(+), 103 deletions(-)

diff --git a/hw/intc/loongarch_extioi.c b/hw/intc/loongarch_extioi.c
index 24fb3af8cc..77b4776958 100644
--- a/hw/intc/loongarch_extioi.c
+++ b/hw/intc/loongarch_extioi.c
@@ -282,9 +282,6 @@ static void loongarch_extioi_instance_init(Object *obj)
 qdev_init_gpio_in(DEVICE(obj), extioi_setirq, EXTIOI_IRQS);
 
 for (cpu = 0; cpu < EXTIOI_CPUS; cpu++) {
-memory_region_init_io(>extioi_iocsr_mem[cpu], OBJECT(s), 
_ops,
-  s, "extioi_iocsr", 0x900);
-sysbus_init_mmio(dev, >extioi_iocsr_mem[cpu]);
 for (pin = 0; pin < LS3A_INTC_IP; pin++) {
 qdev_init_gpio_out(DEVICE(obj), >parent_irq[cpu][pin], 1);
 }
diff --git a/hw/intc/loongarch_ipi.c b/hw/intc/loongarch_ipi.c
index 1d3449e77d..bca01c88f6 100644
--- a/hw/intc/loongarch_ipi.c
+++ b/hw/intc/loongarch_ipi.c
@@ -9,6 +9,7 @@
 #include "hw/sysbus.h"
 #include "hw/intc/loongarch_ipi.h"
 #include "hw/irq.h"
+#include "hw/qdev-properties.h"
 #include "qapi/error.h"
 #include "qemu/log.h"
 #include "exec/address-spaces.h"
@@ -26,7 +27,7 @@ static MemTxResult loongarch_ipi_readl(void *opaque, hwaddr 
addr,
 uint64_t ret = 0;
 int index = 0;
 
-s = >ipi_core;
+s = >cpu[attrs.requester_id];
 addr &= 0xff;
 switch (addr) {
 case CORE_STATUS_OFF:
@@ -65,7 +66,7 @@ static void send_ipi_data(CPULoongArchState *env, uint64_t 
val, hwaddr addr,
  * if the mask is 0, we need not to do anything.
  */
 if ((val >> 27) & 0xf) {
-data = address_space_ldl(>address_space_iocsr, addr,
+data = address_space_ldl(env->address_space_iocsr, addr,
  attrs, NULL);
 for (i = 0; i < 4; i++) {
 /* get mask for byte writing */
@@ -77,7 +78,7 @@ static void send_ipi_data(CPULoongArchState *env, uint64_t 
val, hwaddr addr,
 
 data &= mask;
 data |= (val >> 32) & ~mask;
-address_space_stl(>address_space_iocsr, addr,
+address_space_stl(env->address_space_iocsr, addr,
   data, attrs, NULL);
 }
 
@@ -172,7 +173,7 @@ static MemTxResult loongarch_ipi_writel(void *opaque, 
hwaddr addr, uint64_t val,
 uint8_t vector;
 CPUState *cs;
 
-s = >ipi_core;
+s = >cpu[attrs.requester_id];
 addr &= 0xff;
 trace_loongarch_ipi_write(size, (uint64_t)addr, val);
 switch (addr) {
@@ -214,7 +215,6 @@ static MemTxResult loongarch_ipi_writel(void *opaque, 
hwaddr addr, uint64_t val,
 
 /* override requester_id */
 attrs.requester_id = cs->cpu_index;
-ipi = LOONGARCH_IPI(LOONGARCH_CPU(cs)->env.ipistate);
 loongarch_ipi_writel(ipi, CORE_SET_OFF, BIT(vector), 4, attrs);
 break;
 default:
@@ -265,12 +265,18 @@ static const MemoryRegionOps loongarch_ipi64_ops = {
 .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
-static void loongarch_ipi_init(Object *obj)
+static void loongarch_ipi_realize(DeviceState *dev, Error **errp)
 {
-LoongArchIPI *s = LOONGARCH_IPI(obj);
-SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+LoongArchIPI *s = LOONGARCH_IPI(dev);
+SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+int i;
+
+if (s->num_cpu == 0) {
+error_setg(errp, "num-cpu must be at least 1");
+return;
+}
 
-memory_region_init_io(>ipi_iocsr_mem, obj, _ipi_ops,
+memory_region_init_io(>ipi_iocsr_mem, OBJECT(dev), _ipi_ops,
   s, "loongarch_ipi_iocsr", 0x48);
 
 /* loongarch_ipi_iocsr performs re-entrant IO through ipi_send */
@@ -278,10 +284,20 @@ static void loongarch_ipi_init(Object *obj)
 
 sysbus_init_mmio(sbd, >ipi_iocsr_mem);
 
-memory_region_init_io(>ipi64_iocsr_mem, obj, _ipi64_ops,
+mem

[PATCH v1 1/2] hw/intc/loongarch_ipi: Use MemTxAttrs interface for ipi ops

2023-12-12 Thread Bibo Mao
There are two interface pairs for MemoryRegionOps, read/write and
read_with_attrs/write_with_attrs. The later is better for ipi device
emulation since initial cpu can be parsed from attrs.requester_id.

And requester_id can be overrided for IOCSR_IPI_SEND and mail_send
function when it is to forward message to another vcpu.

Signed-off-by: Bibo Mao 
---
 hw/intc/loongarch_ipi.c | 136 +++-
 1 file changed, 77 insertions(+), 59 deletions(-)

diff --git a/hw/intc/loongarch_ipi.c b/hw/intc/loongarch_ipi.c
index 67858b521c..1d3449e77d 100644
--- a/hw/intc/loongarch_ipi.c
+++ b/hw/intc/loongarch_ipi.c
@@ -17,14 +17,16 @@
 #include "target/loongarch/internals.h"
 #include "trace.h"
 
-static void loongarch_ipi_writel(void *, hwaddr, uint64_t, unsigned);
-
-static uint64_t loongarch_ipi_readl(void *opaque, hwaddr addr, unsigned size)
+static MemTxResult loongarch_ipi_readl(void *opaque, hwaddr addr,
+   uint64_t *data,
+   unsigned size, MemTxAttrs attrs)
 {
-IPICore *s = opaque;
+IPICore *s;
+LoongArchIPI *ipi = opaque;
 uint64_t ret = 0;
 int index = 0;
 
+s = >ipi_core;
 addr &= 0xff;
 switch (addr) {
 case CORE_STATUS_OFF:
@@ -49,10 +51,12 @@ static uint64_t loongarch_ipi_readl(void *opaque, hwaddr 
addr, unsigned size)
 }
 
 trace_loongarch_ipi_read(size, (uint64_t)addr, ret);
-return ret;
+*data = ret;
+return MEMTX_OK;
 }
 
-static void send_ipi_data(CPULoongArchState *env, uint64_t val, hwaddr addr)
+static void send_ipi_data(CPULoongArchState *env, uint64_t val, hwaddr addr,
+  MemTxAttrs attrs)
 {
 int i, mask = 0, data = 0;
 
@@ -62,7 +66,7 @@ static void send_ipi_data(CPULoongArchState *env, uint64_t 
val, hwaddr addr)
  */
 if ((val >> 27) & 0xf) {
 data = address_space_ldl(>address_space_iocsr, addr,
- MEMTXATTRS_UNSPECIFIED, NULL);
+ attrs, NULL);
 for (i = 0; i < 4; i++) {
 /* get mask for byte writing */
 if (val & (0x1 << (27 + i))) {
@@ -74,7 +78,7 @@ static void send_ipi_data(CPULoongArchState *env, uint64_t 
val, hwaddr addr)
 data &= mask;
 data |= (val >> 32) & ~mask;
 address_space_stl(>address_space_iocsr, addr,
-  data, MEMTXATTRS_UNSPECIFIED, NULL);
+  data, attrs, NULL);
 }
 
 static int archid_cmp(const void *a, const void *b)
@@ -103,80 +107,72 @@ static CPUState *ipi_getcpu(int arch_id)
 CPUArchId *archid;
 
 archid = find_cpu_by_archid(machine, arch_id);
-return CPU(archid->cpu);
-}
-
-static void ipi_send(uint64_t val)
-{
-uint32_t cpuid;
-uint8_t vector;
-CPUState *cs;
-LoongArchCPU *cpu;
-LoongArchIPI *s;
-
-cpuid = extract32(val, 16, 10);
-if (cpuid >= LOONGARCH_MAX_CPUS) {
-trace_loongarch_ipi_unsupported_cpuid("IOCSR_IPI_SEND", cpuid);
-return;
+if (archid) {
+return CPU(archid->cpu);
 }
 
-/* IPI status vector */
-vector = extract8(val, 0, 5);
-
-cs = ipi_getcpu(cpuid);
-cpu = LOONGARCH_CPU(cs);
-s = LOONGARCH_IPI(cpu->env.ipistate);
-loongarch_ipi_writel(>ipi_core, CORE_SET_OFF, BIT(vector), 4);
+return NULL;
 }
 
-static void mail_send(uint64_t val)
+static MemTxResult mail_send(uint64_t val, MemTxAttrs attrs)
 {
 uint32_t cpuid;
 hwaddr addr;
-CPULoongArchState *env;
 CPUState *cs;
-LoongArchCPU *cpu;
 
 cpuid = extract32(val, 16, 10);
 if (cpuid >= LOONGARCH_MAX_CPUS) {
 trace_loongarch_ipi_unsupported_cpuid("IOCSR_MAIL_SEND", cpuid);
-return;
+return MEMTX_DECODE_ERROR;
 }
 
-addr = 0x1020 + (val & 0x1c);
 cs = ipi_getcpu(cpuid);
-cpu = LOONGARCH_CPU(cs);
-env = >env;
-send_ipi_data(env, val, addr);
+if (cs == NULL) {
+return MEMTX_DECODE_ERROR;
+}
+
+/* override requester_id */
+addr = SMP_IPI_MAILBOX + CORE_BUF_20 + (val & 0x1c);
+attrs.requester_id = cs->cpu_index;
+send_ipi_data(_CPU(cs)->env, val, addr, attrs);
+return MEMTX_OK;
 }
 
-static void any_send(uint64_t val)
+static MemTxResult any_send(uint64_t val, MemTxAttrs attrs)
 {
 uint32_t cpuid;
 hwaddr addr;
-CPULoongArchState *env;
 CPUState *cs;
-LoongArchCPU *cpu;
 
 cpuid = extract32(val, 16, 10);
 if (cpuid >= LOONGARCH_MAX_CPUS) {
 trace_loongarch_ipi_unsupported_cpuid("IOCSR_ANY_SEND", cpuid);
-return;
+return MEMTX_DECODE_ERROR;
 }
 
-addr = val & 0x;
 cs = ipi_getcpu(cpuid);
-cpu = LOONGARCH_CPU(cs);
-env = >env;
-send_ipi_data(env, val, addr);
+if (cs == NULL) {
+return MEMTX_DECODE_ERROR;
+}
+
+

[PATCH v1 0/2] hw/loongarch/virt: Set iocsr address space per-board rather percpu

2023-12-12 Thread Bibo Mao
On LoongArch system, there is iocsr address space simliar system io
address space on x86. And each cpu has its separate iocsr address space now,
with this patch, iocsr address space is changed with per-board, and
MemTxAttrs.requester_id is used to differentiate cpu cores.

Bibo Mao (2):
  hw/intc/loongarch_ipi: Use MemTxAttrs interface for ipi ops
  hw/loongarch/virt: Set iocsr address space per-board rather percpu

 hw/intc/loongarch_extioi.c |   3 -
 hw/intc/loongarch_ipi.c| 184 ++---
 hw/loongarch/virt.c|  88 ++
 include/hw/intc/loongarch_extioi.h |   1 -
 include/hw/intc/loongarch_ipi.h|   3 +-
 include/hw/loongarch/virt.h|   3 +
 target/loongarch/cpu.c |  48 
 target/loongarch/cpu.h |   4 +-
 target/loongarch/iocsr_helper.c|  16 +--
 9 files changed, 195 insertions(+), 155 deletions(-)


base-commit: 9c74490bff6c8886a922008d0c9ce6cae70dd17e
-- 
2.39.3




[PATCH v1 2/2] hw/loongarch/virt: Set iocsr address space per-board rather percpu

2023-12-12 Thread Bibo Mao
LoongArch system has iocsr address space, most iocsr registers are
per-board, however some iocsr register spaces banked for percpu such
as ipi mailbox and extioi interrupt status. For banked iocsr space,
each cpu has the same iocsr space, but separate data.

This patch changes iocsr address space per-board rather percpu,
for iocsr registers specified for cpu, MemTxAttrs.requester_id
can be parsed for the cpu. With this patches, the total address space
on board will be simple, only iocsr address space and system memory,
rather than the number of cpu and system memory.

Signed-off-by: Bibo Mao 
---
 hw/intc/loongarch_extioi.c |  3 -
 hw/intc/loongarch_ipi.c| 54 +-
 hw/loongarch/virt.c| 88 +++---
 include/hw/intc/loongarch_extioi.h |  1 -
 include/hw/intc/loongarch_ipi.h|  3 +-
 include/hw/loongarch/virt.h|  3 +
 target/loongarch/cpu.c | 48 
 target/loongarch/cpu.h |  4 +-
 target/loongarch/iocsr_helper.c| 16 +++---
 9 files changed, 121 insertions(+), 99 deletions(-)

diff --git a/hw/intc/loongarch_extioi.c b/hw/intc/loongarch_extioi.c
index 24fb3af8cc..77b4776958 100644
--- a/hw/intc/loongarch_extioi.c
+++ b/hw/intc/loongarch_extioi.c
@@ -282,9 +282,6 @@ static void loongarch_extioi_instance_init(Object *obj)
 qdev_init_gpio_in(DEVICE(obj), extioi_setirq, EXTIOI_IRQS);
 
 for (cpu = 0; cpu < EXTIOI_CPUS; cpu++) {
-memory_region_init_io(>extioi_iocsr_mem[cpu], OBJECT(s), 
_ops,
-  s, "extioi_iocsr", 0x900);
-sysbus_init_mmio(dev, >extioi_iocsr_mem[cpu]);
 for (pin = 0; pin < LS3A_INTC_IP; pin++) {
 qdev_init_gpio_out(DEVICE(obj), >parent_irq[cpu][pin], 1);
 }
diff --git a/hw/intc/loongarch_ipi.c b/hw/intc/loongarch_ipi.c
index 1d3449e77d..550e899c69 100644
--- a/hw/intc/loongarch_ipi.c
+++ b/hw/intc/loongarch_ipi.c
@@ -9,6 +9,7 @@
 #include "hw/sysbus.h"
 #include "hw/intc/loongarch_ipi.h"
 #include "hw/irq.h"
+#include "hw/qdev-properties.h"
 #include "qapi/error.h"
 #include "qemu/log.h"
 #include "exec/address-spaces.h"
@@ -26,7 +27,7 @@ static MemTxResult loongarch_ipi_readl(void *opaque, hwaddr 
addr,
 uint64_t ret = 0;
 int index = 0;
 
-s = >ipi_core;
+s = >cpu[attrs.requester_id];
 addr &= 0xff;
 switch (addr) {
 case CORE_STATUS_OFF:
@@ -65,7 +66,7 @@ static void send_ipi_data(CPULoongArchState *env, uint64_t 
val, hwaddr addr,
  * if the mask is 0, we need not to do anything.
  */
 if ((val >> 27) & 0xf) {
-data = address_space_ldl(>address_space_iocsr, addr,
+data = address_space_ldl(env->address_space_iocsr, addr,
  attrs, NULL);
 for (i = 0; i < 4; i++) {
 /* get mask for byte writing */
@@ -77,7 +78,7 @@ static void send_ipi_data(CPULoongArchState *env, uint64_t 
val, hwaddr addr,
 
 data &= mask;
 data |= (val >> 32) & ~mask;
-address_space_stl(>address_space_iocsr, addr,
+address_space_stl(env->address_space_iocsr, addr,
   data, attrs, NULL);
 }
 
@@ -172,7 +173,7 @@ static MemTxResult loongarch_ipi_writel(void *opaque, 
hwaddr addr, uint64_t val,
 uint8_t vector;
 CPUState *cs;
 
-s = >ipi_core;
+s = >cpu[attrs.requester_id];
 addr &= 0xff;
 trace_loongarch_ipi_write(size, (uint64_t)addr, val);
 switch (addr) {
@@ -214,7 +215,6 @@ static MemTxResult loongarch_ipi_writel(void *opaque, 
hwaddr addr, uint64_t val,
 
 /* override requester_id */
 attrs.requester_id = cs->cpu_index;
-ipi = LOONGARCH_IPI(LOONGARCH_CPU(cs)->env.ipistate);
 loongarch_ipi_writel(ipi, CORE_SET_OFF, BIT(vector), 4, attrs);
 break;
 default:
@@ -265,12 +265,18 @@ static const MemoryRegionOps loongarch_ipi64_ops = {
 .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
-static void loongarch_ipi_init(Object *obj)
+static void loongarch_ipi_realize(DeviceState *dev, Error **errp)
 {
-LoongArchIPI *s = LOONGARCH_IPI(obj);
-SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+LoongArchIPI *s = LOONGARCH_IPI(dev);
+SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+int i;
+
+if (s->num_cpu == 0) {
+error_setg(errp, "num-cpu must be at least 1");
+return;
+}
 
-memory_region_init_io(>ipi_iocsr_mem, obj, _ipi_ops,
+memory_region_init_io(>ipi_iocsr_mem, OBJECT(dev), _ipi_ops,
   s, "loongarch_ipi_iocsr", 0x48);
 
 /* loongarch_ipi_iocsr performs re-entrant IO through ipi_send */
@@ -278,10 +284,15 @@ static void loongarch_ipi_init(Object *obj)
 
 sysbus_init_mmio(sbd, >ipi_iocsr_mem);
 
-memory_region_init_io(>ipi64_iocsr_mem, obj, _ipi64_ops,
+mem

[PATCH] target/loongarch: Add timer information dump support

2023-12-06 Thread Bibo Mao
Timer emulation sometimes is problematic especially when vm is running in
kvm mode. This patch adds registers dump support relative with timer
hardware, so that it is easier to find the problems.

Signed-off-by: Bibo Mao 
---
 target/loongarch/cpu.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index fc075952e6..db9a421cc4 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -762,6 +762,8 @@ void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int 
flags)
 qemu_fprintf(f, "TLBRENTRY=%016" PRIx64 "\n", env->CSR_TLBRENTRY);
 qemu_fprintf(f, "TLBRBADV=%016" PRIx64 "\n", env->CSR_TLBRBADV);
 qemu_fprintf(f, "TLBRERA=%016" PRIx64 "\n", env->CSR_TLBRERA);
+qemu_fprintf(f, "TCFG=%016" PRIx64 "\n", env->CSR_TCFG);
+qemu_fprintf(f, "TVAL=%016" PRIx64 "\n", env->CSR_TVAL);
 
 /* fpr */
 if (flags & CPU_DUMP_FPU) {
-- 
2.39.3




[PATCH] hw/loongarch/virt: Align high memory base address with super page size

2023-11-26 Thread Bibo Mao
With LoongArch virt machine, there is low memory space with region
0--0x1000, and high memory space with started from 0x9000.
High memory space is aligned with 256M, it will be better if it is
aligned with 1G, which is super page aligned for 4K page size.

Currently linux kernel and uefi bios has no limitation with high
memory base address, it is ok to set high memory base address
with 0x8000.

Signed-off-by: Bibo Mao 
Change-Id: Iac1af728bf6fd35c9c2f4e7dbdae6e3c0fbab623
---
 include/hw/loongarch/virt.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h
index 674f4655e0..db0831b471 100644
--- a/include/hw/loongarch/virt.h
+++ b/include/hw/loongarch/virt.h
@@ -25,7 +25,7 @@
 
 #define VIRT_LOWMEM_BASE0
 #define VIRT_LOWMEM_SIZE0x1000
-#define VIRT_HIGHMEM_BASE   0x9000
+#define VIRT_HIGHMEM_BASE   0x8000
 #define VIRT_GED_EVT_ADDR   0x100e
 #define VIRT_GED_MEM_ADDR   (VIRT_GED_EVT_ADDR + ACPI_GED_EVT_SEL_LEN)
 #define VIRT_GED_REG_ADDR   (VIRT_GED_MEM_ADDR + MEMORY_HOTPLUG_IO_LEN)
-- 
2.39.3




Re: [PATCH] hw/loongarch: Add virtio-mmio bus support

2023-09-05 Thread bibo mao



在 2023/9/6 10:50, Tianrui Zhao 写道:
> Add virtio-mmio bus support for LoongArch, so that devices
> could be added in the virtio-mmio bus.
> 
> Signed-off-by: Tianrui Zhao 
> ---
>  hw/loongarch/Kconfig | 1 +
>  hw/loongarch/virt.c  | 3 +++
>  2 files changed, 4 insertions(+)
> 
> diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
> index 1e7c5b43c5..01ab8ce8e7 100644
> --- a/hw/loongarch/Kconfig
> +++ b/hw/loongarch/Kconfig
> @@ -22,3 +22,4 @@ config LOONGARCH_VIRT
>  select DIMM
>  select PFLASH_CFI01
>  select ACPI_HMAT
> +select VIRTIO_MMIO
> diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
> index 2629128aed..06f4bc3a5e 100644
> --- a/hw/loongarch/virt.c
> +++ b/hw/loongarch/virt.c
> @@ -560,6 +560,9 @@ static void loongarch_devices_init(DeviceState *pch_pic, 
> LoongArchMachineState *
>   VIRT_RTC_IRQ - VIRT_GSI_BASE));
>  fdt_add_rtc_node(lams);
>  
> +/* virtio-mmio device */
> +sysbus_create_simple("virtio-mmio", 0x1e20, 
> qdev_get_gpio_in(pch_pic, 7));
It had better use macro rather than hardcoded value like 0x1e20/7.

Another way multiple virtio-mmio devices should be added like other arches.
And there should be fdt/acpi table added for the device so that users can use 
it.

Regards
Bibo Mao
> +
>  pm_mem = g_new(MemoryRegion, 1);
>  memory_region_init_io(pm_mem, NULL, _virt_pm_ops,
>NULL, "loongarch_virt_pm", PM_SIZE);




Re: [PATCH v3 16/16] tcg/loongarch64: Implement 128-bit load & store

2023-09-04 Thread bibo mao



在 2023/9/4 09:43, gaosong 写道:
> Hi, yijun
> 
> 在 2023/9/3 上午9:10, Jiajie Chen 写道:
>>
>> On 2023/9/3 09:06, Richard Henderson wrote:
>>> On 9/1/23 22:02, Jiajie Chen wrote:
>>>> If LSX is available, use LSX instructions to implement 128-bit load &
>>>> store.
>>>
>>> Is this really guaranteed to be an atomic 128-bit operation?
>>>
>>
>> Song Gao, please check this.
>>
>>
> Could you explain this issue?  Thanks.
If address is aligned with 16-bytes, the 128-bit load/store is atomic.
Else it is not atomic since maybe it crosses two cache lines or pages.

Regards
Bibo Mao
> 
>>> Or, as for many vector processors, is this really two separate 64-bit 
>>> memory operations under the hood?
>>>
>>>
>>>> +static void tcg_out_qemu_ldst_i128(TCGContext *s, TCGReg data_lo, TCGReg 
>>>> data_hi,
>>>> +   TCGReg addr_reg, MemOpIdx oi, bool 
>>>> is_ld)
>>>> +{
>>>> +    TCGLabelQemuLdst *ldst;
>>>> +    HostAddress h;
>>>> +
>>>> +    ldst = prepare_host_addr(s, , addr_reg, oi, true);
>>>> +    if (is_ld) {
>>>> +    tcg_out_opc_vldx(s, TCG_VEC_TMP0, h.base, h.index);
>>>> +    tcg_out_opc_vpickve2gr_d(s, data_lo, TCG_VEC_TMP0, 0);
>>>> +    tcg_out_opc_vpickve2gr_d(s, data_hi, TCG_VEC_TMP0, 1);
>>>> +    } else {
>>>> +    tcg_out_opc_vinsgr2vr_d(s, TCG_VEC_TMP0, data_lo, 0);
>>>> +    tcg_out_opc_vinsgr2vr_d(s, TCG_VEC_TMP0, data_hi, 1);
>>>> +    tcg_out_opc_vstx(s, TCG_VEC_TMP0, h.base, h.index);
>>>> +    }
>>>
>>> You should use h.aa.atom < MO_128 to determine if 128-bit atomicity, and 
>>> therefore the vector operation, is required.  I assume the gr<->vr moves 
>>> have a cost and two integer operations are preferred when allowable.
>>>
>>> Compare the other implementations of this function.
>>>
>>>
>>> r~
> 




[PATCH v2] target/loongarch: cpu: Implement get_arch_id callback

2023-08-23 Thread Bibo Mao
Implement the callback for getting the architecture-dependent CPU
ID, the cpu ID is physical id described in ACPI MADT table, this
will be used for cpu hotplug.

Signed-off-by: Bibo Mao 
Reviewed-by: Song Gao 
---

v1->v2:
 remove unuseful changeid.

---
 hw/loongarch/virt.c| 2 ++
 target/loongarch/cpu.c | 8 
 target/loongarch/cpu.h | 1 +
 3 files changed, 11 insertions(+)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index e19b042ce8..6f6b577749 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -815,6 +815,8 @@ static void loongarch_init(MachineState *machine)
 cpu = cpu_create(machine->cpu_type);
 cpu->cpu_index = i;
 machine->possible_cpus->cpus[i].cpu = OBJECT(cpu);
+lacpu = LOONGARCH_CPU(cpu);
+lacpu->phy_id = machine->possible_cpus->cpus[i].arch_id;
 }
 fdt_add_cpu_nodes(lams);
 
diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index ad93ecac92..7be3769672 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -690,6 +690,13 @@ static struct TCGCPUOps loongarch_tcg_ops = {
 static const struct SysemuCPUOps loongarch_sysemu_ops = {
 .get_phys_page_debug = loongarch_cpu_get_phys_page_debug,
 };
+
+static int64_t loongarch_cpu_get_arch_id(CPUState *cs)
+{
+LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+
+return cpu->phy_id;
+}
 #endif
 
 static gchar *loongarch_gdb_arch_name(CPUState *cs)
@@ -715,6 +722,7 @@ static void loongarch_cpu_class_init(ObjectClass *c, void 
*data)
 cc->set_pc = loongarch_cpu_set_pc;
 cc->get_pc = loongarch_cpu_get_pc;
 #ifndef CONFIG_USER_ONLY
+cc->get_arch_id = loongarch_cpu_get_arch_id;
 dc->vmsd = _loongarch_cpu;
 cc->sysemu_ops = _sysemu_ops;
 #endif
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index fa371ca8ba..033081593c 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -371,6 +371,7 @@ struct ArchCPU {
 CPUNegativeOffsetState neg;
 CPULoongArchState env;
 QEMUTimer timer;
+uint32_t  phy_id;
 
 /* 'compatible' string for this CPU for Linux device trees */
 const char *dtb_compatible;
-- 
2.27.0




Re: [PATCH] target/loongarch: cpu: Implement get_arch_id callback

2023-08-22 Thread bibo mao



在 2023/8/23 09:14, gaosong 写道:
> 在 2023/8/22 下午8:26, Bibo Mao 写道:
>> Implement the callback for getting the architecture-dependent CPU
>> ID, the cpu ID is physical id described in ACPI MADT table, this
>> will be used for cpu hotplug.
>>
>> Signed-off-by: Bibo Mao 
>> Change-Id: I53bcfb9f4279e491f33e8b99a9102534ad53409e
>> ---
> 
> Drop Chang-Id.
sure, will fix in next version.

Regards
Bibo Mao
> 
> Otherwise
> Reviewed-by: Song Gao 
> 
> Thanks.
> Song Gao
> 
>>   hw/loongarch/virt.c    | 2 ++
>>   target/loongarch/cpu.c | 8 
>>   target/loongarch/cpu.h | 1 +
>>   3 files changed, 11 insertions(+)
>>
>> diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
>> index e19b042ce8..6f6b577749 100644
>> --- a/hw/loongarch/virt.c
>> +++ b/hw/loongarch/virt.c
>> @@ -815,6 +815,8 @@ static void loongarch_init(MachineState *machine)
>>   cpu = cpu_create(machine->cpu_type);
>>   cpu->cpu_index = i;
>>   machine->possible_cpus->cpus[i].cpu = OBJECT(cpu);
>> +    lacpu = LOONGARCH_CPU(cpu);
>> +    lacpu->phy_id = machine->possible_cpus->cpus[i].arch_id;
>>   }
>>   fdt_add_cpu_nodes(lams);
>>   diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
>> index ad93ecac92..7be3769672 100644
>> --- a/target/loongarch/cpu.c
>> +++ b/target/loongarch/cpu.c
>> @@ -690,6 +690,13 @@ static struct TCGCPUOps loongarch_tcg_ops = {
>>   static const struct SysemuCPUOps loongarch_sysemu_ops = {
>>   .get_phys_page_debug = loongarch_cpu_get_phys_page_debug,
>>   };
>> +
>> +static int64_t loongarch_cpu_get_arch_id(CPUState *cs)
>> +{
>> +    LoongArchCPU *cpu = LOONGARCH_CPU(cs);
>> +
>> +    return cpu->phy_id;
>> +}
>>   #endif
>>     static gchar *loongarch_gdb_arch_name(CPUState *cs)
>> @@ -715,6 +722,7 @@ static void loongarch_cpu_class_init(ObjectClass *c, 
>> void *data)
>>   cc->set_pc = loongarch_cpu_set_pc;
>>   cc->get_pc = loongarch_cpu_get_pc;
>>   #ifndef CONFIG_USER_ONLY
>> +    cc->get_arch_id = loongarch_cpu_get_arch_id;
>>   dc->vmsd = _loongarch_cpu;
>>   cc->sysemu_ops = _sysemu_ops;
>>   #endif
>> diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
>> index fa371ca8ba..033081593c 100644
>> --- a/target/loongarch/cpu.h
>> +++ b/target/loongarch/cpu.h
>> @@ -371,6 +371,7 @@ struct ArchCPU {
>>   CPUNegativeOffsetState neg;
>>   CPULoongArchState env;
>>   QEMUTimer timer;
>> +    uint32_t  phy_id;
>>     /* 'compatible' string for this CPU for Linux device trees */
>>   const char *dtb_compatible;
>>
> 




[PATCH] target/loongarch: cpu: Implement get_arch_id callback

2023-08-22 Thread Bibo Mao
Implement the callback for getting the architecture-dependent CPU
ID, the cpu ID is physical id described in ACPI MADT table, this
will be used for cpu hotplug.

Signed-off-by: Bibo Mao 
Change-Id: I53bcfb9f4279e491f33e8b99a9102534ad53409e
---
 hw/loongarch/virt.c| 2 ++
 target/loongarch/cpu.c | 8 
 target/loongarch/cpu.h | 1 +
 3 files changed, 11 insertions(+)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index e19b042ce8..6f6b577749 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -815,6 +815,8 @@ static void loongarch_init(MachineState *machine)
 cpu = cpu_create(machine->cpu_type);
 cpu->cpu_index = i;
 machine->possible_cpus->cpus[i].cpu = OBJECT(cpu);
+lacpu = LOONGARCH_CPU(cpu);
+lacpu->phy_id = machine->possible_cpus->cpus[i].arch_id;
 }
 fdt_add_cpu_nodes(lams);
 
diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index ad93ecac92..7be3769672 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -690,6 +690,13 @@ static struct TCGCPUOps loongarch_tcg_ops = {
 static const struct SysemuCPUOps loongarch_sysemu_ops = {
 .get_phys_page_debug = loongarch_cpu_get_phys_page_debug,
 };
+
+static int64_t loongarch_cpu_get_arch_id(CPUState *cs)
+{
+LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+
+return cpu->phy_id;
+}
 #endif
 
 static gchar *loongarch_gdb_arch_name(CPUState *cs)
@@ -715,6 +722,7 @@ static void loongarch_cpu_class_init(ObjectClass *c, void 
*data)
 cc->set_pc = loongarch_cpu_set_pc;
 cc->get_pc = loongarch_cpu_get_pc;
 #ifndef CONFIG_USER_ONLY
+cc->get_arch_id = loongarch_cpu_get_arch_id;
 dc->vmsd = _loongarch_cpu;
 cc->sysemu_ops = _sysemu_ops;
 #endif
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index fa371ca8ba..033081593c 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -371,6 +371,7 @@ struct ArchCPU {
 CPUNegativeOffsetState neg;
 CPULoongArchState env;
 QEMUTimer timer;
+uint32_t  phy_id;
 
 /* 'compatible' string for this CPU for Linux device trees */
 const char *dtb_compatible;
-- 
2.27.0




  1   2   >