[PATCH] tests/avocado: Update LoongArch bios file

2024-05-30 Thread Song Gao
The VM uses old bios to boot up only 1 cpu, causing the test case to fail.
Update the bios to solve this problem.

Reported-by: Thomas Huth 
Signed-off-by: Song Gao 
---
 tests/avocado/machine_loongarch.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/avocado/machine_loongarch.py 
b/tests/avocado/machine_loongarch.py
index 7d8a3c1fa5..12cc5ed814 100644
--- a/tests/avocado/machine_loongarch.py
+++ b/tests/avocado/machine_loongarch.py
@@ -38,7 +38,7 @@ def test_loongarch64_devices(self):
 
 bios_url = ('https://github.com/yangxiaojuan-loongson/qemu-binary/'
 'releases/download/binary-files/QEMU_EFI.fd')
-bios_hash = ('dfc1bfba4853cd763b9d392d0031827e8addbca8')
+bios_hash = ('f4d0966b5117d4cd82327c050dd668741046be69')
 bios_path = self.fetch_asset(bios_url, asset_hash=bios_hash)
 
 self.vm.set_console()
-- 
2.34.1




[PATCH v4 0/3] Add extioi virt extension support

2024-05-28 Thread Song Gao
On LoongArch, IRQs can be routed to four vcpus with hardware extioi.
This patch adds the extioi virt extension support so that the IRQ can
route to 256 vcpus.

v4:
- Put patch3 ahead of patch2;
- patch1 Introduce two IRQ model(Extended IRQ model and Virt extended IRQ 
model);
- Link to v3: 
https://patchew.org/QEMU/20240521123225.231072-1-gaos...@loongson.cn/

v3:
- Split patch2 to two small patch.
- remove unused code.
- loongarch_extioi_reset() clear status without checking virt extioi
  features.
- Link to v2: 
https://patchew.org/QEMU/20240514090756.988096-1-gaos...@loongson.cn/

v2:
- Split the patch to two small patch.
- Drop 'RFC' title. extioi virt extension suport only enable on kvm
  mode and  the extioi driver need patch[1].
  but this series do not affect the old codes in any way.
- Link to v1: 
https://lore.kernel.org/all/20240116022526.498613-1-gaos...@loongson.cn/#r

[1]: 
https://gitee.com/openeuler/kernel/commit/5d97cff72f91f4f20a536efd60eca75bfcb78a64

Thanks.
Song Gao

Song Gao (3):
  hw/intc/loongarch_extioi: Add extioi virt extension definition
  hw/loongarch/virt: Use MemTxAttrs interface for misc ops
  hw/loongarch/virt: Enable extioi virt extension

 include/hw/intc/loongarch_extioi.h |  21 
 include/hw/loongarch/virt.h|   1 +
 target/loongarch/cpu.h |   1 +
 hw/intc/loongarch_extioi.c |  88 +-
 hw/loongarch/virt.c| 182 +++--
 5 files changed, 256 insertions(+), 37 deletions(-)

-- 
2.34.1




[PATCH v4 2/3] hw/loongarch/virt: Use MemTxAttrs interface for misc ops

2024-05-28 Thread Song Gao
Use MemTxAttrs interface read_with_attrs/write_with_attrs
for virt_iocsr_misc_ops.

Signed-off-by: Song Gao 
---
 hw/loongarch/virt.c | 36 
 1 file changed, 24 insertions(+), 12 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 4db0d82dbd..a70eeda2fd 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -899,37 +899,49 @@ static void virt_firmware_init(LoongArchVirtMachineState 
*lvms)
 }
 
 
-static void virt_iocsr_misc_write(void *opaque, hwaddr addr,
-  uint64_t val, unsigned size)
+static MemTxResult virt_iocsr_misc_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size,
+ MemTxAttrs attrs)
 {
+return MEMTX_OK;
 }
 
-static uint64_t virt_iocsr_misc_read(void *opaque, hwaddr addr, unsigned size)
+static MemTxResult virt_iocsr_misc_read(void *opaque, hwaddr addr,
+uint64_t *data,
+unsigned size, MemTxAttrs attrs)
 {
-uint64_t ret;
+uint64_t ret = 0;
 
 switch (addr) {
 case VERSION_REG:
-return 0x11ULL;
+ret = 0x11ULL;
+break;
 case FEATURE_REG:
 ret = BIT(IOCSRF_MSI) | BIT(IOCSRF_EXTIOI) | BIT(IOCSRF_CSRIPI);
 if (kvm_enabled()) {
 ret |= BIT(IOCSRF_VM);
 }
-return ret;
+break;
 case VENDOR_REG:
-return 0x6e6f73676e6f6f4cULL; /* "Loongson" */
+ret = 0x6e6f73676e6f6f4cULL; /* "Loongson" */
+break;
 case CPUNAME_REG:
-return 0x303030354133ULL; /* "3A5000" */
+ret = 0x303030354133ULL; /* "3A5000" */
+break;
 case MISC_FUNC_REG:
-return BIT_ULL(IOCSRM_EXTIOI_EN);
+ret = BIT_ULL(IOCSRM_EXTIOI_EN);
+break;
+default:
+g_assert_not_reached();
 }
-return 0ULL;
+
+*data = ret;
+return MEMTX_OK;
 }
 
 static const MemoryRegionOps virt_iocsr_misc_ops = {
-.read  = virt_iocsr_misc_read,
-.write = virt_iocsr_misc_write,
+.read_with_attrs  = virt_iocsr_misc_read,
+.write_with_attrs = virt_iocsr_misc_write,
 .endianness = DEVICE_LITTLE_ENDIAN,
 .valid = {
 .min_access_size = 4,
-- 
2.34.1




[PATCH v4 1/3] hw/intc/loongarch_extioi: Add extioi virt extension definition

2024-05-28 Thread Song Gao
On LoongArch, IRQs can be routed to four vcpus with hardware extended
IRQ model. This patch adds the virt extension definition so that
the IRQ can route to 256 vcpus.

1.Extended IRQ model:
|
+---+ +-|+ +---+
| IPI/Timer | --> | CPUINTC(0-3)|(4-255) | <-- | IPI/Timer |
+---+ +-|+ +---+
^   |
|
   +-+
   | EIOINTC |
   +-+
^   ^
|   |
 +-+ +-+
 | PCH-PIC | | PCH-MSI |
 +-+ +-+
   ^  ^  ^
   |  |  |
++ +-+ +-+
| UARTs  | | Devices | | Devices |
++ +-+ +-+

2.Virt extended IRQ model:

  +-++---+ +---+
  | IPI |--> | CPUINTC(0-255)| <-- | Timer |
  +-++---+ +---+
^
|
  +---+
  | V-EIOINTC |
  +---+
   ^ ^
   | |
+-+ +-+
| PCH-PIC | | PCH-MSI |
+-+ +-+
  ^  ^  ^
  |  |  |
   ++ +-+ +-+
   | UARTs  | | Devices | | Devices |
   ++ +-+ +-+

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
---
 include/hw/intc/loongarch_extioi.h | 21 +++
 hw/intc/loongarch_extioi.c | 88 --
 hw/loongarch/virt.c| 60 +---
 3 files changed, 146 insertions(+), 23 deletions(-)

diff --git a/include/hw/intc/loongarch_extioi.h 
b/include/hw/intc/loongarch_extioi.h
index 410c6e1121..eccc2e0d18 100644
--- a/include/hw/intc/loongarch_extioi.h
+++ b/include/hw/intc/loongarch_extioi.h
@@ -41,6 +41,24 @@
 #define EXTIOI_COREMAP_END   (0xD00 - APIC_OFFSET)
 #define EXTIOI_SIZE  0x800
 
+#define EXTIOI_VIRT_BASE (0x4000)
+#define EXTIOI_VIRT_SIZE (0x1000)
+#define EXTIOI_VIRT_FEATURES (0x0)
+#define  EXTIOI_HAS_VIRT_EXTENSION   (0)
+#define  EXTIOI_HAS_ENABLE_OPTION(1)
+#define  EXTIOI_HAS_INT_ENCODE   (2)
+#define  EXTIOI_HAS_CPU_ENCODE   (3)
+#define  EXTIOI_VIRT_HAS_FEATURES(BIT(EXTIOI_HAS_VIRT_EXTENSION)  \
+  | BIT(EXTIOI_HAS_ENABLE_OPTION) \
+  | BIT(EXTIOI_HAS_INT_ENCODE)\
+  | BIT(EXTIOI_HAS_CPU_ENCODE))
+#define EXTIOI_VIRT_CONFIG   (0x4)
+#define  EXTIOI_ENABLE   (1)
+#define  EXTIOI_ENABLE_INT_ENCODE(2)
+#define  EXTIOI_ENABLE_CPU_ENCODE(3)
+#define EXTIOI_VIRT_COREMAP_START(0x40)
+#define EXTIOI_VIRT_COREMAP_END  (0x240)
+
 typedef struct ExtIOICore {
 uint32_t coreisr[EXTIOI_IRQS_GROUP_COUNT];
 DECLARE_BITMAP(sw_isr[LS3A_INTC_IP], EXTIOI_IRQS);
@@ -52,6 +70,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(LoongArchExtIOI, LOONGARCH_EXTIOI)
 struct LoongArchExtIOI {
 SysBusDevice parent_obj;
 uint32_t num_cpu;
+uint32_t features;
+uint32_t status;
 /* hardware state */
 uint32_t nodetype[EXTIOI_IRQS_NODETYPE_COUNT / 2];
 uint32_t bounce[EXTIOI_IRQS_GROUP_COUNT];
@@ -65,5 +85,6 @@ struct LoongArchExtIOI {
 qemu_irq irq[EXTIOI_IRQS];
 ExtIOICore *cpu;
 MemoryRegion extioi_system_mem;
+MemoryRegion virt_extend;
 };
 #endif /* LOONGARCH_EXTIOI_H */
diff --git a/hw/intc/loongarch_extioi.c b/hw/intc/loongarch_extioi.c
index 0b358548eb..1e8e0114dc 100644
--- a/hw/intc/loongarch_extioi.c
+++ b/hw/intc/loongarch_extioi.c
@@ -143,10 +143,13 @@ static inline void 
extioi_update_sw_coremap(LoongArchExtIOI *s, int irq,
 
 for (i = 0; i < 4; i++) {
 cpu = val & 0xff;
-cpu = ctz32(cpu);
-cpu = (cpu >= 4) ? 0 : cpu;
 val = val >> 8;
 
+if (!(s->status & BIT(EXTIOI_ENABLE_CPU_ENCODE))) {
+cpu = ctz32(cpu);
+cpu = (cpu >= 4) ? 0 : cpu;
+}
+
 if (s->sw_coremap[irq + i] == cpu) {
 continue;
 }
@@ -265,6 +268,61 @@ static const MemoryRegionOps extioi_ops = {
 .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
+static MemTxResult extioi_virt_readw(void *opaque, hwaddr addr, uint64_t *data,
+ unsigned size, MemTxAttrs attrs)
+{
+LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
+
+switch (addr) {
+case EXTIOI_VIRT_FEATURES:
+*data = s->features;
+break;
+case EXTIOI_VIRT_CONFIG

[PATCH v4 3/3] hw/loongarch/virt: Enable extioi virt extension

2024-05-28 Thread Song Gao
This patch adds a new board attribute 'v-eiointc'.
A value of true enables the virt extended I/O interrupt controller.
VMs working in kvm mode have 'v-eiointc' enabled by default.

Signed-off-by: Song Gao 
---
 include/hw/loongarch/virt.h |  1 +
 target/loongarch/cpu.h  |  1 +
 hw/loongarch/virt.c | 88 +++--
 3 files changed, 87 insertions(+), 3 deletions(-)

diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h
index 2c4f5cf9c8..8fdfacf268 100644
--- a/include/hw/loongarch/virt.h
+++ b/include/hw/loongarch/virt.h
@@ -50,6 +50,7 @@ struct LoongArchVirtMachineState {
 Notifier machine_done;
 Notifier powerdown_notifier;
 OnOffAutoacpi;
+OnOffAutoveiointc;
 char *oem_id;
 char *oem_table_id;
 DeviceState  *acpi_ged;
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index 41b8e6d96d..6c41fafb70 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -36,6 +36,7 @@
 #define CPUNAME_REG 0x20
 #define MISC_FUNC_REG   0x420
 #define IOCSRM_EXTIOI_EN48
+#define IOCSRM_EXTIOI_INT_ENCODE 49
 
 #define IOCSR_MEM_SIZE  0x428
 
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index a70eeda2fd..b33b1ad9d3 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -11,6 +11,7 @@
 #include "hw/boards.h"
 #include "hw/char/serial.h"
 #include "sysemu/kvm.h"
+#include "sysemu/tcg.h"
 #include "sysemu/sysemu.h"
 #include "sysemu/qtest.h"
 #include "sysemu/runstate.h"
@@ -47,6 +48,31 @@
 #include "hw/block/flash.h"
 #include "qemu/error-report.h"
 
+static bool virt_is_veiointc_enabled(LoongArchVirtMachineState *lvms)
+{
+if (lvms->veiointc == ON_OFF_AUTO_OFF) {
+return false;
+}
+return true;
+}
+
+static void virt_get_veiointc(Object *obj, Visitor *v, const char *name,
+  void *opaque, Error **errp)
+{
+LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(obj);
+OnOffAuto veiointc = lvms->veiointc;
+
+visit_type_OnOffAuto(v, name, , errp);
+}
+
+static void virt_set_veiointc(Object *obj, Visitor *v, const char *name,
+  void *opaque, Error **errp)
+{
+LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(obj);
+
+visit_type_OnOffAuto(v, name, >veiointc, errp);
+}
+
 static PFlashCFI01 *virt_flash_create1(LoongArchVirtMachineState *lvms,
const char *name,
const char *alias_prop_name)
@@ -789,9 +815,16 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms)
 /* Create EXTIOI device */
 extioi = qdev_new(TYPE_LOONGARCH_EXTIOI);
 qdev_prop_set_uint32(extioi, "num-cpu", ms->smp.cpus);
+if (virt_is_veiointc_enabled(lvms)) {
+qdev_prop_set_bit(extioi, "has-virtualization-extension", true);
+}
 sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi), _fatal);
 memory_region_add_subregion(>system_iocsr, APIC_BASE,
-   sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 0));
+sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 0));
+if (virt_is_veiointc_enabled(lvms)) {
+memory_region_add_subregion(>system_iocsr, EXTIOI_VIRT_BASE,
+sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 1));
+}
 
 /*
  * connect ext irq to the cpu irq
@@ -898,11 +931,37 @@ static void virt_firmware_init(LoongArchVirtMachineState 
*lvms)
 }
 }
 
-
 static MemTxResult virt_iocsr_misc_write(void *opaque, hwaddr addr,
  uint64_t val, unsigned size,
  MemTxAttrs attrs)
 {
+LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(opaque);
+uint64_t features;
+
+switch (addr) {
+case MISC_FUNC_REG:
+if (!virt_is_veiointc_enabled(lvms)) {
+return MEMTX_OK;
+}
+
+features = address_space_ldl(>as_iocsr,
+ EXTIOI_VIRT_BASE + EXTIOI_VIRT_CONFIG,
+ attrs, NULL);
+if (val & BIT_ULL(IOCSRM_EXTIOI_EN)) {
+features |= BIT(EXTIOI_ENABLE);
+}
+if (val & BIT_ULL(IOCSRM_EXTIOI_INT_ENCODE)) {
+features |= BIT(EXTIOI_ENABLE_INT_ENCODE);
+}
+
+address_space_stl(>as_iocsr,
+  EXTIOI_VIRT_BASE + EXTIOI_VIRT_CONFIG,
+  features, attrs, NULL);
+break;
+default:
+g_assert_not_reached();
+}
+
 return MEMTX_OK;
 }
 
@@ -910,7 +969,9 @@ static MemTxResult virt_iocsr_misc_read(void *opaque, 
hwaddr addr,
 uint64_t *data,
 unsigned size, MemTxAttrs attrs)
 {
+  

[PULL 10/10] hw/loongarch/virt: Fix FDT memory node address width

2024-05-22 Thread Song Gao
From: Jiaxun Yang 

Higher bits for memory nodes were omitted at qemu_fdt_setprop_cells.

Cc: qemu-sta...@nongnu.org
Signed-off-by: Jiaxun Yang 
Reviewed-by: Song Gao 
Message-Id: <20240520-loongarch-fdt-memnode-v1-1-5ea9be939...@flygoat.com>
Signed-off-by: Song Gao 
---
 hw/loongarch/virt.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index e3bdf085b5..3e6e93edf3 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -464,7 +464,8 @@ static void fdt_add_memory_node(MachineState *ms,
 char *nodename = g_strdup_printf("/memory@%" PRIx64, base);
 
 qemu_fdt_add_subnode(ms->fdt, nodename);
-qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0, base, 0, size);
+qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", base >> 32, base,
+   size >> 32, size);
 qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "memory");
 
 if (ms->numa_state && ms->numa_state->num_nodes) {
-- 
2.34.1




[PULL 04/10] hw/loongarch: Refine acpi srat table for numa memory

2024-05-22 Thread Song Gao
From: 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 
Reviewed-by: Song Gao 
Message-Id: <20240515093927.3453674-2-maob...@loongson.cn>
Signed-off-by: Song Gao 
---
 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.34.1




[PULL 02/10] target/loongarch/kvm: fpu save the vreg registers high 192bit

2024-05-22 Thread Song Gao
On kvm side, get_fpu/set_fpu save the vreg registers high 192bits,
but QEMU missing.

Cc: qemu-sta...@nongnu.org
Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240514110752.989572-1-gaos...@loongson.cn>
---
 target/loongarch/kvm/kvm.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
index bc75552d0f..8e6e27c8bf 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -436,6 +436,9 @@ static int kvm_loongarch_get_regs_fp(CPUState *cs)
 env->fcsr0 = fpu.fcsr;
 for (i = 0; i < 32; i++) {
 env->fpr[i].vreg.UD[0] = fpu.fpr[i].val64[0];
+env->fpr[i].vreg.UD[1] = fpu.fpr[i].val64[1];
+env->fpr[i].vreg.UD[2] = fpu.fpr[i].val64[2];
+env->fpr[i].vreg.UD[3] = fpu.fpr[i].val64[3];
 }
 for (i = 0; i < 8; i++) {
 env->cf[i] = fpu.fcc & 0xFF;
@@ -455,6 +458,9 @@ static int kvm_loongarch_put_regs_fp(CPUState *cs)
 fpu.fcc = 0;
 for (i = 0; i < 32; i++) {
 fpu.fpr[i].val64[0] = env->fpr[i].vreg.UD[0];
+fpu.fpr[i].val64[1] = env->fpr[i].vreg.UD[1];
+fpu.fpr[i].val64[2] = env->fpr[i].vreg.UD[2];
+fpu.fpr[i].val64[3] = env->fpr[i].vreg.UD[3];
 }
 
 for (i = 0; i < 8; i++) {
-- 
2.34.1




[PULL 09/10] target/loongarch: Add loongarch vector property unconditionally

2024-05-22 Thread Song Gao
From: 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 
Reviewed-by: Song Gao 
Message-Id: <20240521080549.434197-2-maob...@loongson.cn>
Signed-off-by: Song Gao 
---
 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.34.1




[PULL 07/10] hw/loongarch: Refine system dram memory region

2024-05-22 Thread Song Gao
From: 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 
Reviewed-by: Song Gao 
Message-Id: <20240515093927.3453674-5-maob...@loongson.cn>
Signed-off-by: Song Gao 
---
 hw/loongarch/virt.c | 53 +++--
 1 file changed, 17 insertions(+), 36 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 449050cba5..4ec2b9a061 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -978,14 +978,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;
@@ -1023,40 +1019,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;
+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);
-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;
+
+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,
@@ -1070,9 +1053,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.34.1




[PULL 05/10] hw/loongarch: Refine fadt memory table for numa memory

2024-05-22 Thread Song Gao
From: 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 
Reviewed-by: Song Gao 
Message-Id: <20240515093927.3453674-3-maob...@loongson.cn>
Signed-off-by: Song Gao 
---
 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 95f9ed5cae..850729202f 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -474,6 +474,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);
@@ -921,10 +963,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);
@@ -938,7 +980,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);
@@ -954,7 +995,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.34.1




[PULL 01/10] target/loongarch/kvm: Fix VM recovery from disk failures

2024-05-22 Thread Song Gao
vmstate does not save kvm_state_conter,
which can cause VM recovery from disk to fail.

Cc: qemu-sta...@nongnu.org
Signed-off-by: Song Gao 
Acked-by: Peter Xu 
Message-Id: <20240508024732.3127792-1-gaos...@loongson.cn>
---
 target/loongarch/machine.c | 6 --
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/target/loongarch/machine.c b/target/loongarch/machine.c
index 9cd9e848d6..08a7fa5370 100644
--- a/target/loongarch/machine.c
+++ b/target/loongarch/machine.c
@@ -145,8 +145,8 @@ static const VMStateDescription vmstate_tlb = {
 /* LoongArch CPU state */
 const VMStateDescription vmstate_loongarch_cpu = {
 .name = "cpu",
-.version_id = 1,
-.minimum_version_id = 1,
+.version_id = 2,
+.minimum_version_id = 2,
 .fields = (const VMStateField[]) {
 VMSTATE_UINTTL_ARRAY(env.gpr, LoongArchCPU, 32),
 VMSTATE_UINTTL(env.pc, LoongArchCPU),
@@ -208,6 +208,8 @@ const VMStateDescription vmstate_loongarch_cpu = {
 VMSTATE_UINT64(env.CSR_DERA, LoongArchCPU),
 VMSTATE_UINT64(env.CSR_DSAVE, LoongArchCPU),
 
+VMSTATE_UINT64(kvm_state_counter, LoongArchCPU),
+
 VMSTATE_END_OF_LIST()
 },
 .subsections = (const VMStateDescription * const []) {
-- 
2.34.1




[PULL 08/10] hw/loongarch: Remove minimum and default memory size

2024-05-22 Thread Song Gao
From: 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 
Reviewed-by: Song Gao 
Message-Id: <20240515093927.3453674-6-maob...@loongson.cn>
Signed-off-by: Song Gao 
---
 hw/loongarch/virt.c | 5 -
 1 file changed, 5 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 4ec2b9a061..e3bdf085b5 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -990,10 +990,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 */
@@ -1279,7 +1275,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.34.1




[PULL 03/10] hw/loongarch: Add VM mode in IOCSR feature register in kvm mode

2024-05-22 Thread Song Gao
From: 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 
Reviewed-by: Song Gao 
Message-Id: <20240514025109.3238398-1-maob...@loongson.cn>
Signed-off-by: Song Gao 
---
 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 f0640d2d80..95f9ed5cae 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.34.1




[PULL 06/10] hw/loongarch: Refine fwcfg memory map

2024-05-22 Thread Song Gao
From: 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 
Reviewed-by: Song Gao 
Message-Id: <20240515093927.3453674-4-maob...@loongson.cn>
Signed-off-by: Song Gao 
---
 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 850729202f..449050cba5 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -918,6 +918,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;
@@ -964,9 +1020,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);
@@ -979,7 +1035,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);
@@ -994,7 +1049,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.34.1




[PULL 00/10] loongarch-to-apply queue

2024-05-22 Thread Song Gao
The following changes since commit 6af8037c42fdc3d20d5aa2686799ab356a9ee1a9:

  Merge tag 'pull-vfio-20240522' of https://github.com/legoater/qemu into 
staging (2024-05-22 06:02:06 -0700)

are available in the Git repository at:

  https://gitlab.com/gaosong/qemu.git tags/pull-loongarch-20240523

for you to fetch changes up to 6204af704a071ea68d3af55c0502b112a7af9546:

  hw/loongarch/virt: Fix FDT memory node address width (2024-05-23 09:30:41 
+0800)


pull-loongarch-20240523


Bibo Mao (7):
  hw/loongarch: Add VM mode in IOCSR feature register in kvm mode
  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
  target/loongarch: Add loongarch vector property unconditionally

Jiaxun Yang (1):
  hw/loongarch/virt: Fix FDT memory node address width

Song Gao (2):
  target/loongarch/kvm: Fix VM recovery from disk failures
  target/loongarch/kvm: fpu save the vreg registers high 192bit

 hw/loongarch/acpi-build.c  |  58 +--
 hw/loongarch/virt.c| 179 -
 target/loongarch/cpu.c |  14 +---
 target/loongarch/kvm/kvm.c |   6 ++
 target/loongarch/machine.c |   6 +-
 5 files changed, 176 insertions(+), 87 deletions(-)




[PATCH v3 3/3] hw/loongarch/virt: Use MemTxAttrs interface for misc ops

2024-05-21 Thread Song Gao
Use MemTxAttrs interface read_with_attrs/write_with_attrs
for virt_iocsr_misc_ops.

Signed-off-by: Song Gao 
---
 hw/loongarch/virt.c | 26 --
 1 file changed, 16 insertions(+), 10 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index e7edc6c9f9..0ab2b6860a 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -866,8 +866,9 @@ static void virt_firmware_init(LoongArchVirtMachineState 
*lvms)
 }
 }
 
-static void virt_iocsr_misc_write(void *opaque, hwaddr addr,
-  uint64_t val, unsigned size)
+static MemTxResult virt_iocsr_misc_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size,
+ MemTxAttrs attrs)
 {
 LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(opaque);
 uint64_t features;
@@ -875,12 +876,12 @@ static void virt_iocsr_misc_write(void *opaque, hwaddr 
addr,
 switch (addr) {
 case MISC_FUNC_REG:
 if (!virt_is_veiointc_enabled(lvms)) {
-return;
+return MEMTX_OK;
 }
 
 features = address_space_ldl(>as_iocsr,
  EXTIOI_VIRT_BASE + EXTIOI_VIRT_CONFIG,
- MEMTXATTRS_UNSPECIFIED, NULL);
+ attrs, NULL);
 if (val & BIT_ULL(IOCSRM_EXTIOI_EN)) {
 features |= BIT(EXTIOI_ENABLE);
 }
@@ -890,11 +891,15 @@ static void virt_iocsr_misc_write(void *opaque, hwaddr 
addr,
 
 address_space_stl(>as_iocsr,
   EXTIOI_VIRT_BASE + EXTIOI_VIRT_CONFIG,
-  features, MEMTXATTRS_UNSPECIFIED, NULL);
+  features, attrs, NULL);
 }
+
+return MEMTX_OK;
 }
 
-static uint64_t virt_iocsr_misc_read(void *opaque, hwaddr addr, unsigned size)
+static MemTxResult virt_iocsr_misc_read(void *opaque, hwaddr addr,
+uint64_t *data,
+unsigned size, MemTxAttrs attrs)
 {
 LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(opaque);
 uint64_t ret = 0;
@@ -924,7 +929,7 @@ static uint64_t virt_iocsr_misc_read(void *opaque, hwaddr 
addr, unsigned size)
 
 features = address_space_ldl(>as_iocsr,
  EXTIOI_VIRT_BASE + EXTIOI_VIRT_CONFIG,
- MEMTXATTRS_UNSPECIFIED, NULL);
+ attrs, NULL);
 if (features & BIT(EXTIOI_ENABLE)) {
 ret |= BIT_ULL(IOCSRM_EXTIOI_EN);
 }
@@ -933,12 +938,13 @@ static uint64_t virt_iocsr_misc_read(void *opaque, hwaddr 
addr, unsigned size)
 }
 }
 
-return ret;
+*data = ret;
+return MEMTX_OK;
 }
 
 static const MemoryRegionOps virt_iocsr_misc_ops = {
-.read  = virt_iocsr_misc_read,
-.write = virt_iocsr_misc_write,
+.read_with_attrs  = virt_iocsr_misc_read,
+.write_with_attrs = virt_iocsr_misc_write,
 .endianness = DEVICE_LITTLE_ENDIAN,
 .valid = {
 .min_access_size = 4,
-- 
2.34.1




[PATCH v3 1/3] hw/intc/loongarch_extioi: Add extioi virt extension definition

2024-05-21 Thread Song Gao
On LoongArch, IRQs can be routed to four vcpus with hardware extioi.
This patch adds the extioi virt extension definition so that the IRQ can
route to 256 vcpus.

Signed-off-by: Song Gao 
---
 include/hw/intc/loongarch_extioi.h | 21 +++
 hw/intc/loongarch_extioi.c | 88 --
 2 files changed, 105 insertions(+), 4 deletions(-)

diff --git a/include/hw/intc/loongarch_extioi.h 
b/include/hw/intc/loongarch_extioi.h
index 410c6e1121..eccc2e0d18 100644
--- a/include/hw/intc/loongarch_extioi.h
+++ b/include/hw/intc/loongarch_extioi.h
@@ -41,6 +41,24 @@
 #define EXTIOI_COREMAP_END   (0xD00 - APIC_OFFSET)
 #define EXTIOI_SIZE  0x800
 
+#define EXTIOI_VIRT_BASE (0x4000)
+#define EXTIOI_VIRT_SIZE (0x1000)
+#define EXTIOI_VIRT_FEATURES (0x0)
+#define  EXTIOI_HAS_VIRT_EXTENSION   (0)
+#define  EXTIOI_HAS_ENABLE_OPTION(1)
+#define  EXTIOI_HAS_INT_ENCODE   (2)
+#define  EXTIOI_HAS_CPU_ENCODE   (3)
+#define  EXTIOI_VIRT_HAS_FEATURES(BIT(EXTIOI_HAS_VIRT_EXTENSION)  \
+  | BIT(EXTIOI_HAS_ENABLE_OPTION) \
+  | BIT(EXTIOI_HAS_INT_ENCODE)\
+  | BIT(EXTIOI_HAS_CPU_ENCODE))
+#define EXTIOI_VIRT_CONFIG   (0x4)
+#define  EXTIOI_ENABLE   (1)
+#define  EXTIOI_ENABLE_INT_ENCODE(2)
+#define  EXTIOI_ENABLE_CPU_ENCODE(3)
+#define EXTIOI_VIRT_COREMAP_START(0x40)
+#define EXTIOI_VIRT_COREMAP_END  (0x240)
+
 typedef struct ExtIOICore {
 uint32_t coreisr[EXTIOI_IRQS_GROUP_COUNT];
 DECLARE_BITMAP(sw_isr[LS3A_INTC_IP], EXTIOI_IRQS);
@@ -52,6 +70,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(LoongArchExtIOI, LOONGARCH_EXTIOI)
 struct LoongArchExtIOI {
 SysBusDevice parent_obj;
 uint32_t num_cpu;
+uint32_t features;
+uint32_t status;
 /* hardware state */
 uint32_t nodetype[EXTIOI_IRQS_NODETYPE_COUNT / 2];
 uint32_t bounce[EXTIOI_IRQS_GROUP_COUNT];
@@ -65,5 +85,6 @@ struct LoongArchExtIOI {
 qemu_irq irq[EXTIOI_IRQS];
 ExtIOICore *cpu;
 MemoryRegion extioi_system_mem;
+MemoryRegion virt_extend;
 };
 #endif /* LOONGARCH_EXTIOI_H */
diff --git a/hw/intc/loongarch_extioi.c b/hw/intc/loongarch_extioi.c
index 0b358548eb..e605ca64d5 100644
--- a/hw/intc/loongarch_extioi.c
+++ b/hw/intc/loongarch_extioi.c
@@ -143,10 +143,13 @@ static inline void 
extioi_update_sw_coremap(LoongArchExtIOI *s, int irq,
 
 for (i = 0; i < 4; i++) {
 cpu = val & 0xff;
-cpu = ctz32(cpu);
-cpu = (cpu >= 4) ? 0 : cpu;
 val = val >> 8;
 
+if (!(s->status & BIT(EXTIOI_ENABLE_CPU_ENCODE))) {
+cpu = ctz32(cpu);
+cpu = (cpu >= 4) ? 0 : cpu;
+}
+
 if (s->sw_coremap[irq + i] == cpu) {
 continue;
 }
@@ -265,6 +268,61 @@ static const MemoryRegionOps extioi_ops = {
 .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
+static MemTxResult extioi_virt_readw(void *opaque, hwaddr addr, uint64_t *data,
+ unsigned size, MemTxAttrs attrs)
+{
+LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
+
+switch (addr) {
+case EXTIOI_VIRT_FEATURES:
+*data = s->features;
+break;
+case EXTIOI_VIRT_CONFIG:
+*data = s->status;
+break;
+default:
+break;
+}
+
+return MEMTX_OK;
+}
+
+static MemTxResult extioi_virt_writew(void *opaque, hwaddr addr,
+  uint64_t val, unsigned size,
+  MemTxAttrs attrs)
+{
+LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
+
+switch (addr) {
+case EXTIOI_VIRT_FEATURES:
+return MEMTX_ACCESS_ERROR;
+
+case EXTIOI_VIRT_CONFIG:
+/*
+ * extioi features can only be set at disabled status
+ */
+if ((s->status & BIT(EXTIOI_ENABLE)) && val) {
+return MEMTX_ACCESS_ERROR;
+}
+
+s->status = val & s->features;
+break;
+default:
+break;
+}
+return MEMTX_OK;
+}
+
+static const MemoryRegionOps extioi_virt_ops = {
+.read_with_attrs = extioi_virt_readw,
+.write_with_attrs = extioi_virt_writew,
+.impl.min_access_size = 4,
+.impl.max_access_size = 4,
+.valid.min_access_size = 4,
+.valid.max_access_size = 8,
+.endianness = DEVICE_LITTLE_ENDIAN,
+};
+
 static void loongarch_extioi_realize(DeviceState *dev, Error **errp)
 {
 LoongArchExtIOI *s = LOONGARCH_EXTIOI(dev);
@@ -284,6 +342,16 @@ static void loongarch_extioi_realize(DeviceState *dev, 
Error **errp)
 memory_region_init_io(>extioi_system_mem, OBJECT(s), _ops,
   s, "extioi_system_mem", 0x900);
 sysbus_init_mmio(sbd, >extioi_system_mem);
+
+if (s->features & BIT(EXTIOI_HAS_VIRT_EXTENSION)) {
+memory_region_init_io(>virt_extend, O

[PATCH v3 2/3] hw/loongarch/virt: Enable extioi virt extension

2024-05-21 Thread Song Gao
This patch adds a new board attribute 'v-eiointc'.
A value of true enables the virt extended I/O interrupt controller.
VMs working in kvm mode have 'v-eiointc' enabled by default.

Signed-off-by: Song Gao 
---
 include/hw/loongarch/virt.h |   1 +
 target/loongarch/cpu.h  |   1 +
 hw/loongarch/virt.c | 100 
 3 files changed, 93 insertions(+), 9 deletions(-)

diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h
index 2c4f5cf9c8..8fdfacf268 100644
--- a/include/hw/loongarch/virt.h
+++ b/include/hw/loongarch/virt.h
@@ -50,6 +50,7 @@ struct LoongArchVirtMachineState {
 Notifier machine_done;
 Notifier powerdown_notifier;
 OnOffAutoacpi;
+OnOffAutoveiointc;
 char *oem_id;
 char *oem_table_id;
 DeviceState  *acpi_ged;
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index 41b8e6d96d..6c41fafb70 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -36,6 +36,7 @@
 #define CPUNAME_REG 0x20
 #define MISC_FUNC_REG   0x420
 #define IOCSRM_EXTIOI_EN48
+#define IOCSRM_EXTIOI_INT_ENCODE 49
 
 #define IOCSR_MEM_SIZE  0x428
 
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 95f9ed5cae..e7edc6c9f9 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -11,6 +11,7 @@
 #include "hw/boards.h"
 #include "hw/char/serial.h"
 #include "sysemu/kvm.h"
+#include "sysemu/tcg.h"
 #include "sysemu/sysemu.h"
 #include "sysemu/qtest.h"
 #include "sysemu/runstate.h"
@@ -47,6 +48,31 @@
 #include "hw/block/flash.h"
 #include "qemu/error-report.h"
 
+static bool virt_is_veiointc_enabled(LoongArchVirtMachineState *lvms)
+{
+if (lvms->veiointc == ON_OFF_AUTO_OFF) {
+return false;
+}
+return true;
+}
+
+static void virt_get_veiointc(Object *obj, Visitor *v, const char *name,
+  void *opaque, Error **errp)
+{
+LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(obj);
+OnOffAuto veiointc = lvms->veiointc;
+
+visit_type_OnOffAuto(v, name, , errp);
+}
+
+static void virt_set_veiointc(Object *obj, Visitor *v, const char *name,
+  void *opaque, Error **errp)
+{
+LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(obj);
+
+visit_type_OnOffAuto(v, name, >veiointc, errp);
+}
+
 static PFlashCFI01 *virt_flash_create1(LoongArchVirtMachineState *lvms,
const char *name,
const char *alias_prop_name)
@@ -724,9 +750,16 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms)
 /* Create EXTIOI device */
 extioi = qdev_new(TYPE_LOONGARCH_EXTIOI);
 qdev_prop_set_uint32(extioi, "num-cpu", ms->smp.cpus);
+if (virt_is_veiointc_enabled(lvms)) {
+qdev_prop_set_bit(extioi, "has-virtualization-extension", true);
+}
 sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi), _fatal);
 memory_region_add_subregion(>system_iocsr, APIC_BASE,
-   sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 0));
+sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 0));
+if (virt_is_veiointc_enabled(lvms)) {
+memory_region_add_subregion(>system_iocsr, EXTIOI_VIRT_BASE,
+sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 1));
+}
 
 /*
  * connect ext irq to the cpu irq
@@ -833,33 +866,74 @@ static void virt_firmware_init(LoongArchVirtMachineState 
*lvms)
 }
 }
 
-
 static void virt_iocsr_misc_write(void *opaque, hwaddr addr,
   uint64_t val, unsigned size)
 {
+LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(opaque);
+uint64_t features;
+
+switch (addr) {
+case MISC_FUNC_REG:
+if (!virt_is_veiointc_enabled(lvms)) {
+return;
+}
+
+features = address_space_ldl(>as_iocsr,
+ EXTIOI_VIRT_BASE + EXTIOI_VIRT_CONFIG,
+ MEMTXATTRS_UNSPECIFIED, NULL);
+if (val & BIT_ULL(IOCSRM_EXTIOI_EN)) {
+features |= BIT(EXTIOI_ENABLE);
+}
+if (val & BIT_ULL(IOCSRM_EXTIOI_INT_ENCODE)) {
+features |= BIT(EXTIOI_ENABLE_INT_ENCODE);
+}
+
+address_space_stl(>as_iocsr,
+  EXTIOI_VIRT_BASE + EXTIOI_VIRT_CONFIG,
+  features, MEMTXATTRS_UNSPECIFIED, NULL);
+}
 }
 
 static uint64_t virt_iocsr_misc_read(void *opaque, hwaddr addr, unsigned size)
 {
-uint64_t ret;
+LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(opaque);
+uint64_t ret = 0;
+int features;
 
 switch (addr) {
 case VERSION_REG:
-return 0x11ULL;
+ret = 0x11ULL;
+break;
 case FEATURE_

[PATCH v3 0/3] Add extioi virt extension support

2024-05-21 Thread Song Gao
On LoongArch, IRQs can be routed to four vcpus with hardware extioi.
This patch adds the extioi virt extension support so that the IRQ can
route to 256 vcpus.

v3:
- Split patch2 to two small patch.
- remove unused code.
- loongarch_extioi_reset() clear status without checking virt extioi
  features.
- Link to v2: 
https://patchew.org/QEMU/20240514090756.988096-1-gaos...@loongson.cn/

v2:
- Split the patch to two small patch.
- Drop 'RFC' title. extioi virt extension suport only enable on kvm
  mode and  the extioi driver need patch[1].
  but this series do not affect the old codes in any way.
- Link to v1: 
https://lore.kernel.org/all/20240116022526.498613-1-gaos...@loongson.cn/#r

[1]: 
https://gitee.com/openeuler/kernel/commit/5d97cff72f91f4f20a536efd60eca75bfcb78a64

Thanks.
Song Gao

Song Gao (3):
  hw/intc/loongarch_extioi: Add extioi virt extension definition
  hw/loongarch/virt: Enable extioi virt extension
  hw/loongarch/virt: Use MemTxAttrs interface for misc ops

 include/hw/intc/loongarch_extioi.h |  21 ++
 include/hw/loongarch/virt.h|   2 +
 target/loongarch/cpu.h |   1 +
 hw/intc/loongarch_extioi.c |  88 +-
 hw/loongarch/virt.c| 116 +
 5 files changed, 210 insertions(+), 18 deletions(-)

-- 
2.34.1




[PULL 4/5] target/loongarch/kvm: Fix VM recovery from disk failures

2024-05-16 Thread Song Gao
vmstate does not save kvm_state_conter,
which can cause VM recovery from disk to fail.

Cc: qemu-sta...@nongnu.org
Signed-off-by: Song Gao 
Acked-by: Peter Xu 
Message-Id: <20240508024732.3127792-1-gaos...@loongson.cn>
---
 target/loongarch/machine.c | 6 --
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/target/loongarch/machine.c b/target/loongarch/machine.c
index 9cd9e848d6..08a7fa5370 100644
--- a/target/loongarch/machine.c
+++ b/target/loongarch/machine.c
@@ -145,8 +145,8 @@ static const VMStateDescription vmstate_tlb = {
 /* LoongArch CPU state */
 const VMStateDescription vmstate_loongarch_cpu = {
 .name = "cpu",
-.version_id = 1,
-.minimum_version_id = 1,
+.version_id = 2,
+.minimum_version_id = 2,
 .fields = (const VMStateField[]) {
 VMSTATE_UINTTL_ARRAY(env.gpr, LoongArchCPU, 32),
 VMSTATE_UINTTL(env.pc, LoongArchCPU),
@@ -208,6 +208,8 @@ const VMStateDescription vmstate_loongarch_cpu = {
 VMSTATE_UINT64(env.CSR_DERA, LoongArchCPU),
 VMSTATE_UINT64(env.CSR_DSAVE, LoongArchCPU),
 
+VMSTATE_UINT64(kvm_state_counter, LoongArchCPU),
+
 VMSTATE_END_OF_LIST()
 },
 .subsections = (const VMStateDescription * const []) {
-- 
2.34.1




[PULL 5/5] target/loongarch/kvm: fpu save the vreg registers high 192bit

2024-05-16 Thread Song Gao
On kvm side, get_fpu/set_fpu save the vreg registers high 192bits,
but QEMU missing.

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240514110752.989572-1-gaos...@loongson.cn>
---
 target/loongarch/kvm/kvm.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
index bc75552d0f..8e6e27c8bf 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -436,6 +436,9 @@ static int kvm_loongarch_get_regs_fp(CPUState *cs)
 env->fcsr0 = fpu.fcsr;
 for (i = 0; i < 32; i++) {
 env->fpr[i].vreg.UD[0] = fpu.fpr[i].val64[0];
+env->fpr[i].vreg.UD[1] = fpu.fpr[i].val64[1];
+env->fpr[i].vreg.UD[2] = fpu.fpr[i].val64[2];
+env->fpr[i].vreg.UD[3] = fpu.fpr[i].val64[3];
 }
 for (i = 0; i < 8; i++) {
 env->cf[i] = fpu.fcc & 0xFF;
@@ -455,6 +458,9 @@ static int kvm_loongarch_put_regs_fp(CPUState *cs)
 fpu.fcc = 0;
 for (i = 0; i < 32; i++) {
 fpu.fpr[i].val64[0] = env->fpr[i].vreg.UD[0];
+fpu.fpr[i].val64[1] = env->fpr[i].vreg.UD[1];
+fpu.fpr[i].val64[2] = env->fpr[i].vreg.UD[2];
+fpu.fpr[i].val64[3] = env->fpr[i].vreg.UD[3];
 }
 
 for (i = 0; i < 8; i++) {
-- 
2.34.1




[PULL 0/5] loongarch-to-apply queue

2024-05-16 Thread Song Gao
The following changes since commit 922582ace2df59572a671f5c0c5c6c5c706995e5:

  Merge tag 'pull-hppa-20240515' of https://gitlab.com/rth7680/qemu into 
staging (2024-05-15 11:46:58 +0200)

are available in the Git repository at:

  https://gitlab.com/gaosong/qemu.git tags/pull-loongarch-20240516

for you to fetch changes up to d55d16700a2e2b36c7e34724d4d77f4a75c5243a:

  target/loongarch/kvm: fpu save the vreg registers high 192bit (2024-05-16 
16:32:35 +0800)


pull-loongarch-20240516


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

Song Gao (2):
  target/loongarch/kvm: Fix VM recovery from disk failures
  target/loongarch/kvm: fpu save the vreg registers high 192bit

 hw/loongarch/virt.c  | 66 +++-
 target/loongarch/kvm/kvm.c   |  6 +++
 target/loongarch/machine.c   |  6 ++-
 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 +
 10 files changed, 156 insertions(+), 22 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




[PULL 1/5] hw/loongarch: Add compat machine for 9.1

2024-05-16 Thread Song Gao
From: 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 
Reviewed-by: Song Gao 
Message-Id: <20240511034220.3030560-2-maob...@loongson.cn>
Signed-off-by: Song Gao 
---
 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.34.1




[PULL 3/5] tests: Add migration test for loongarch64

2024-05-16 Thread Song Gao
From: 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 
Reviewed-by: Song Gao 
Tested-by: Song Gao 
Message-Id: <20240511034220.3030560-4-maob...@loongson.cn>
Signed-off-by: Song Gao 
---
 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
+};

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

2024-05-16 Thread Song Gao
From: 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 
Reviewed-by: Song Gao 
Message-Id: <20240511034220.3030560-3-maob...@loongson.cn>
Signed-off-by: Song Gao 
---
 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.34.1




[RFC PATCH v2] target/loongarch/kvm: Add pmu support

2024-05-14 Thread Song Gao
This patch adds PMU support, We just sets some cpucfg6 default value
to PMU config on kvm mode, and then check the PMU config with kvm ioctl
KVM_GET_DEVICE_ATTR.
  e.g
'...  -cpu max,pmu=on' (enable PMU)'
'...  -cpu max,pmu=off' (disable PMU)'

Signed-off-by: Song Gao 
---
v2:
 - Drop the property 'pmnum'.
 - Link to v1: 
https://patchew.org/QEMU/20240514094630.988617-1-gaos...@loongson.cn/

This patch adds the 'RFC' heading because it requires
the kernel to merge into patch[1] first

[1]: https://lore.kernel.org/all/20240507120140.3119714-1-gaos...@loongson.cn/

 target/loongarch/cpu.c| 27 ++
 target/loongarch/kvm/kvm.c| 53 ++-
 target/loongarch/loongarch-qmp-cmds.c |  2 +-
 3 files changed, 80 insertions(+), 2 deletions(-)

diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index a0cad53676..fde0d2a816 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -421,6 +421,14 @@ static void loongarch_la464_initfn(Object *obj)
 data = FIELD_DP32(data, CPUCFG5, CC_DIV, 1);
 env->cpucfg[5] = data;
 
+if (kvm_enabled()) {
+data = 0;
+data = FIELD_DP32(data, CPUCFG6, PMP, 1);
+data = FIELD_DP32(data, CPUCFG6, PMNUM, 3);
+data = FIELD_DP32(data, CPUCFG6, PMBITS, 63);
+env->cpucfg[6] = data;
+}
+
 data = 0;
 data = FIELD_DP32(data, CPUCFG16, L1_IUPRE, 1);
 data = FIELD_DP32(data, CPUCFG16, L1_DPRE, 1);
@@ -643,6 +651,20 @@ static void loongarch_set_lasx(Object *obj, bool value, 
Error **errp)
 }
 }
 
+static bool loongarch_get_pmu(Object *obj, Error **errp)
+{
+LoongArchCPU *cpu = LOONGARCH_CPU(obj);
+
+return  !!(FIELD_EX32(cpu->env.cpucfg[6], CPUCFG6, PMP));
+}
+
+static void loongarch_set_pmu(Object *obj, bool value,  Error **errp)
+{
+LoongArchCPU *cpu = LOONGARCH_CPU(obj);
+
+cpu->env.cpucfg[6] = FIELD_DP32(cpu->env.cpucfg[6], CPUCFG6, PMP, value);
+}
+
 void loongarch_cpu_post_init(Object *obj)
 {
 LoongArchCPU *cpu = LOONGARCH_CPU(obj);
@@ -655,6 +677,11 @@ void loongarch_cpu_post_init(Object *obj)
 object_property_add_bool(obj, "lasx", loongarch_get_lasx,
  loongarch_set_lasx);
 }
+
+if (kvm_enabled()) {
+object_property_add_bool(obj, "pmu", loongarch_get_pmu,
+ loongarch_set_pmu);
+}
 }
 
 static void loongarch_cpu_init(Object *obj)
diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
index bc75552d0f..3e46203b15 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -556,6 +556,51 @@ static int kvm_check_cpucfg2(CPUState *cs)
 return ret;
 }
 
+static int kvm_check_cpucfg6(CPUState *cs)
+{
+int ret;
+uint64_t val;
+struct kvm_device_attr attr = {
+.group = KVM_LOONGARCH_VCPU_CPUCFG,
+.attr = 6,
+.addr = (uint64_t),
+};
+LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+CPULoongArchState *env = >env;
+
+ret = kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, );
+if (!ret) {
+kvm_vcpu_ioctl(cs, KVM_GET_DEVICE_ATTR, );
+
+if (FIELD_EX32(env->cpucfg[6], CPUCFG6, PMP)) {
+ /* Check PMP */
+ if (!FIELD_EX32(val, CPUCFG6, PMP)) {
+ error_report("'pmu' feature not supported by KVM on this host"
+  " Please disable 'pmu' with "
+  "'... -cpu XXX,pmu=off ...'\n");
+ exit(EXIT_FAILURE);
+ }
+ /* Check PMNUM */
+ int guest_pmnum = FIELD_EX32(env->cpucfg[6], CPUCFG6, PMNUM);
+ int host_pmnum = FIELD_EX32(val, CPUCFG6, PMNUM);
+ if (guest_pmnum > host_pmnum){
+ error_report("The guest pmnum %d larger than KVM support 
%d\n",
+  guest_pmnum, host_pmnum);
+ exit(EXIT_FAILURE);
+ }
+ /* Check PMBITS */
+ int guest_pmbits = FIELD_EX32(env->cpucfg[6], CPUCFG6, PMBITS);
+ int host_pmbits = FIELD_EX32(val, CPUCFG6, PMBITS);
+ if (guest_pmbits != host_pmbits) {
+ exit_report("The host not support PMBITS %d\n", guest_pmbits);
+ exit(EXIT_FAILURE);
+ }
+}
+}
+
+return ret;
+}
+
 static int kvm_loongarch_put_cpucfg(CPUState *cs)
 {
 int i, ret = 0;
@@ -568,7 +613,13 @@ static int kvm_loongarch_put_cpucfg(CPUState *cs)
 if (ret) {
 return ret;
 }
-   }
+}
+if (i == 6) {
+ret = kvm_check_cpucfg6(cs);
+if (ret) {
+return ret;
+}
+}
 val = env->cpucfg[i];
 ret = kvm_set_one_reg(cs, KVM_IOC_CPUCFG(i), );
 if (ret < 0) {
diff --git a/target/loongarch/loongarch-qmp-cmds.c 
b/

[PATCH] target/loongarch/kvm: fpu save the vreg registers high 192bit

2024-05-14 Thread Song Gao
On kvm side, get_fpu/set_fpu save the vreg registers high 192bits,
but QEMU missing.

Signed-off-by: Song Gao 
---
 target/loongarch/kvm/kvm.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
index a9f9020071..0b5dbb7ed8 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -436,6 +436,9 @@ static int kvm_loongarch_get_regs_fp(CPUState *cs)
 env->fcsr0 = fpu.fcsr;
 for (i = 0; i < 32; i++) {
 env->fpr[i].vreg.UD[0] = fpu.fpr[i].val64[0];
+env->fpr[i].vreg.UD[1] = fpu.fpr[i].val64[1];
+env->fpr[i].vreg.UD[2] = fpu.fpr[i].val64[2];
+env->fpr[i].vreg.UD[3] = fpu.fpr[i].val64[3];
 }
 for (i = 0; i < 8; i++) {
 env->cf[i] = fpu.fcc & 0xFF;
@@ -455,6 +458,9 @@ static int kvm_loongarch_put_regs_fp(CPUState *cs)
 fpu.fcc = 0;
 for (i = 0; i < 32; i++) {
 fpu.fpr[i].val64[0] = env->fpr[i].vreg.UD[0];
+fpu.fpr[i].val64[1] = env->fpr[i].vreg.UD[1];
+fpu.fpr[i].val64[2] = env->fpr[i].vreg.UD[2];
+fpu.fpr[i].val64[3] = env->fpr[i].vreg.UD[3];
 }
 
 for (i = 0; i < 8; i++) {
-- 
2.25.1




[RFC PATCH] target/loongarch/kvm: Add pmu support

2024-05-14 Thread Song Gao
This patch adds PMU support, We just sets some cpucfg6 default value
to PMU config on kvm mode, and then check the PMU config with kvm ioctl
KVM_GET_DEVICE_ATTR.
  e.g
'...  -cpu max,pmu=on,pmnum=[1-16]';
'...  -cpu max,pmu=on' (default pmnum = 4);
'...  -cpu max,pmu=off' (disable PMU)

Signed-off-by: Song Gao 
---

This patch adds the 'RFC' heading because it requires
the kernel to merge into patch[1] first

[1]: https://lore.kernel.org/all/20240507120140.3119714-1-gaos...@loongson.cn/


 target/loongarch/cpu.h|  2 +
 target/loongarch/cpu.c| 64 +++
 target/loongarch/kvm/kvm.c| 55 ++-
 target/loongarch/loongarch-qmp-cmds.c |  2 +-
 4 files changed, 121 insertions(+), 2 deletions(-)

diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index 6c41fafb70..d834649106 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -184,6 +184,8 @@ FIELD(CPUCFG6, PMNUM, 4, 4)
 FIELD(CPUCFG6, PMBITS, 8, 6)
 FIELD(CPUCFG6, UPM, 14, 1)
 
+#define PMNUM_MAX 16
+
 /* cpucfg[16] bits */
 FIELD(CPUCFG16, L1_IUPRE, 0, 1)
 FIELD(CPUCFG16, L1_IUUNIFY, 1, 1)
diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index a0cad53676..c78ee3f0b1 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -8,6 +8,7 @@
 #include "qemu/osdep.h"
 #include "qemu/log.h"
 #include "qemu/qemu-print.h"
+#include "qemu/error-report.h"
 #include "qapi/error.h"
 #include "qemu/module.h"
 #include "sysemu/qtest.h"
@@ -19,6 +20,7 @@
 #include "internals.h"
 #include "fpu/softfloat-helpers.h"
 #include "cpu-csr.h"
+#include "qapi/visitor.h"
 #ifndef CONFIG_USER_ONLY
 #include "sysemu/reset.h"
 #endif
@@ -421,6 +423,14 @@ static void loongarch_la464_initfn(Object *obj)
 data = FIELD_DP32(data, CPUCFG5, CC_DIV, 1);
 env->cpucfg[5] = data;
 
+if (kvm_enabled()) {
+data = 0;
+data = FIELD_DP32(data, CPUCFG6, PMP, 1);
+data = FIELD_DP32(data, CPUCFG6, PMNUM, 3);
+data = FIELD_DP32(data, CPUCFG6, PMBITS, 63);
+env->cpucfg[6] = data;
+}
+
 data = 0;
 data = FIELD_DP32(data, CPUCFG16, L1_IUPRE, 1);
 data = FIELD_DP32(data, CPUCFG16, L1_DPRE, 1);
@@ -643,6 +653,48 @@ static void loongarch_set_lasx(Object *obj, bool value, 
Error **errp)
 }
 }
 
+static bool loongarch_get_pmu(Object *obj, Error **errp)
+{
+LoongArchCPU *cpu = LOONGARCH_CPU(obj);
+
+return  !!(FIELD_EX32(cpu->env.cpucfg[6], CPUCFG6, PMP));
+}
+
+static void loongarch_set_pmu(Object *obj, bool value,  Error **errp)
+{
+LoongArchCPU *cpu = LOONGARCH_CPU(obj);
+
+cpu->env.cpucfg[6] = FIELD_DP32(cpu->env.cpucfg[6], CPUCFG6, PMP, value);
+}
+
+static void loongarch_get_pmnum(Object *obj, Visitor *v,
+const char *name, void *opaque,
+Error **errp)
+{
+LoongArchCPU *cpu = LOONGARCH_CPU(obj);
+uint32_t value = FIELD_EX32(cpu->env.cpucfg[6], CPUCFG6, PMNUM);
+
+visit_type_uint32(v, name, , errp);
+}
+
+static void loongarch_set_pmnum(Object *obj, Visitor *v,
+const char *name, void *opaque,
+Error **errp)
+{
+LoongArchCPU *cpu = LOONGARCH_CPU(obj);
+uint32_t *value= opaque;
+
+if (!visit_type_uint32(v, name, value, errp)) {
+return;
+}
+if ((*value <= PMNUM_MAX) && (*value > 0)) {
+cpu->env.cpucfg[6] = FIELD_DP32(cpu->env.cpucfg[6], CPUCFG6, PMNUM, 
*value -1);
+} else {
+error_report("Performance counter number need be in [1- %d]\n", 
PMNUM_MAX);
+exit(EXIT_FAILURE);
+}
+}
+
 void loongarch_cpu_post_init(Object *obj)
 {
 LoongArchCPU *cpu = LOONGARCH_CPU(obj);
@@ -655,6 +707,18 @@ void loongarch_cpu_post_init(Object *obj)
 object_property_add_bool(obj, "lasx", loongarch_get_lasx,
  loongarch_set_lasx);
 }
+
+if (kvm_enabled()) {
+object_property_add_bool(obj, "pmu", loongarch_get_pmu,
+ loongarch_set_pmu);
+if (FIELD_EX32(cpu->env.cpucfg[6], CPUCFG6, PMP)) {
+uint32_t value = 4;
+object_property_add(obj, "pmnum", "uint32",
+loongarch_get_pmnum,
+loongarch_set_pmnum, NULL,
+(void *));
+}
+}
 }
 
 static void loongarch_cpu_init(Object *obj)
diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
index bc75552d0f..a9f9020071 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -556,6 +556,53 @@ static int kvm_check_cpucfg2(CPUState *cs)
 return ret;
 }
 
+static int kvm_check_cpucfg6(CPUState *cs)
+{
+ 

[PATCH v2 2/2] hw/loongarch/virt: Enable extioi virt extension

2024-05-14 Thread Song Gao
This patch adds a new board attribute 'v-eiointc'.
A value of true enables the virt extended I/O interrupt controller.
VMs working in kvm mode have 'v-eiointc' enabled by default.

Signed-off-by: Song Gao 
---
 include/hw/loongarch/virt.h |   2 +
 target/loongarch/cpu.h  |   1 +
 hw/loongarch/virt.c | 117 +++-
 3 files changed, 106 insertions(+), 14 deletions(-)

diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h
index 2c4f5cf9c8..433e7dd7f7 100644
--- a/include/hw/loongarch/virt.h
+++ b/include/hw/loongarch/virt.h
@@ -50,11 +50,13 @@ struct LoongArchVirtMachineState {
 Notifier machine_done;
 Notifier powerdown_notifier;
 OnOffAutoacpi;
+OnOffAutoveiointc;
 char *oem_id;
 char *oem_table_id;
 DeviceState  *acpi_ged;
 int  fdt_size;
 DeviceState *platform_bus_dev;
+DeviceState  *extioi;
 PCIBus   *pci_bus;
 PFlashCFI01  *flash[2];
 MemoryRegion system_iocsr;
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index 41b8e6d96d..6c41fafb70 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -36,6 +36,7 @@
 #define CPUNAME_REG 0x20
 #define MISC_FUNC_REG   0x420
 #define IOCSRM_EXTIOI_EN48
+#define IOCSRM_EXTIOI_INT_ENCODE 49
 
 #define IOCSR_MEM_SIZE  0x428
 
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 95f9ed5cae..f7468d61ae 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -11,6 +11,7 @@
 #include "hw/boards.h"
 #include "hw/char/serial.h"
 #include "sysemu/kvm.h"
+#include "sysemu/tcg.h"
 #include "sysemu/sysemu.h"
 #include "sysemu/qtest.h"
 #include "sysemu/runstate.h"
@@ -47,6 +48,31 @@
 #include "hw/block/flash.h"
 #include "qemu/error-report.h"
 
+static bool virt_is_veiointc_enabled(LoongArchVirtMachineState *lvms)
+{
+if (lvms->veiointc == ON_OFF_AUTO_OFF) {
+return false;
+}
+return true;
+}
+
+static void virt_get_veiointc(Object *obj, Visitor *v, const char *name,
+  void *opaque, Error **errp)
+{
+LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(obj);
+OnOffAuto veiointc = lvms->veiointc;
+
+visit_type_OnOffAuto(v, name, , errp);
+}
+
+static void virt_set_veiointc(Object *obj, Visitor *v, const char *name,
+  void *opaque, Error **errp)
+{
+LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(obj);
+
+visit_type_OnOffAuto(v, name, >veiointc, errp);
+}
+
 static PFlashCFI01 *virt_flash_create1(LoongArchVirtMachineState *lvms,
const char *name,
const char *alias_prop_name)
@@ -724,9 +750,17 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms)
 /* Create EXTIOI device */
 extioi = qdev_new(TYPE_LOONGARCH_EXTIOI);
 qdev_prop_set_uint32(extioi, "num-cpu", ms->smp.cpus);
+if (virt_is_veiointc_enabled(lvms)) {
+qdev_prop_set_bit(extioi, "has-virtualization-extension", true);
+}
 sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi), _fatal);
 memory_region_add_subregion(>system_iocsr, APIC_BASE,
-   sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 0));
+sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 0));
+if (virt_is_veiointc_enabled(lvms)) {
+memory_region_add_subregion(>system_iocsr, EXTIOI_VIRT_BASE,
+sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 1));
+}
+lvms->extioi = extioi;
 
 /*
  * connect ext irq to the cpu irq
@@ -833,38 +867,85 @@ static void virt_firmware_init(LoongArchVirtMachineState 
*lvms)
 }
 }
 
-
-static void virt_iocsr_misc_write(void *opaque, hwaddr addr,
-  uint64_t val, unsigned size)
+static MemTxResult virt_iocsr_misc_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size,
+ MemTxAttrs attrs)
 {
+LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(opaque);
+uint64_t features;
+
+switch (addr) {
+case MISC_FUNC_REG:
+if (!virt_is_veiointc_enabled(lvms)) {
+return MEMTX_OK;
+}
+
+features = address_space_ldl(>as_iocsr,
+ EXTIOI_VIRT_BASE + EXTIOI_VIRT_CONFIG,
+ attrs, NULL);
+if (val & BIT_ULL(IOCSRM_EXTIOI_EN)) {
+features |= BIT(EXTIOI_ENABLE);
+}
+if (val & BIT_ULL(IOCSRM_EXTIOI_INT_ENCODE)) {
+features |= BIT(EXTIOI_ENABLE_INT_ENCODE);
+}
+
+address_space_stl(>as_iocsr,
+  EXTIOI_VIRT_BASE + EXTIOI_VIRT_CONFIG,
+  fe

[PATCH v2 0/2] Add extioi virt extension support

2024-05-14 Thread Song Gao
Base-on: <20240514025109.3238398-1-maob...@loongson.cn>

On LoongArch, IRQs can be routed to four vcpus with hardware extioi.
This patch adds the extioi virt extension support so that the IRQ can
route to 256 vcpus.  

v2:
- Split the patch to two small patch.
- Drop 'RFC' title. extioi virt extension suport only enable on kvm
  mode and  the extioi driver need patch[1].
  but this series do not affect the old codes in any way.
- Link to v1: 
https://lore.kernel.org/all/20240116022526.498613-1-gaos...@loongson.cn/#r

[1]: 
https://gitee.com/openeuler/kernel/commit/5d97cff72f91f4f20a536efd60eca75bfcb78a64

Thanks.
Song Gao.

Song Gao (2):
  hw/intc/loongarch_extioi: Add extioi virt extension definition
  hw/loongarch/virt: Enable extioi virt extension

 include/hw/intc/loongarch_extioi.h |  21 ++
 include/hw/loongarch/virt.h|   2 +
 target/loongarch/cpu.h |   1 +
 hw/intc/loongarch_extioi.c |  92 ++-
 hw/loongarch/virt.c| 117 +
 5 files changed, 215 insertions(+), 18 deletions(-)

-- 
2.25.1




[PATCH v2 1/2] hw/intc/loongarch_extioi: Add extioi virt extension definition

2024-05-14 Thread Song Gao
On LoongArch, IRQs can be routed to four vcpus with hardware extioi.
This patch adds the extioi virt extension definition so that the IRQ can
route to 256 vcpus.

Signed-off-by: Song Gao 
---
 include/hw/intc/loongarch_extioi.h | 21 +++
 hw/intc/loongarch_extioi.c | 92 --
 2 files changed, 109 insertions(+), 4 deletions(-)

diff --git a/include/hw/intc/loongarch_extioi.h 
b/include/hw/intc/loongarch_extioi.h
index 410c6e1121..d4646fab9f 100644
--- a/include/hw/intc/loongarch_extioi.h
+++ b/include/hw/intc/loongarch_extioi.h
@@ -41,6 +41,24 @@
 #define EXTIOI_COREMAP_END   (0xD00 - APIC_OFFSET)
 #define EXTIOI_SIZE  0x800
 
+#define EXTIOI_VIRT_BASE (0x4000)
+#define EXTIOI_VIRT_SIZE (0x1000)
+#define EXTIOI_VIRT_FEATURES (0x0)
+#define  EXTIOI_HAS_VIRT_EXTENSION (0)
+#define  EXTIOI_HAS_ENABLE_OPTION  (1)
+#define  EXTIOI_HAS_INT_ENCODE (2)
+#define  EXTIOI_HAS_CPU_ENCODE (3)
+#define  EXTIOI_VIRT_HAS_FEATURES  (BIT(EXTIOI_HAS_VIRT_EXTENSION)  \
+| BIT(EXTIOI_HAS_ENABLE_OPTION) \
+| BIT(EXTIOI_HAS_INT_ENCODE)\
+   | BIT(EXTIOI_HAS_CPU_ENCODE))
+#define EXTIOI_VIRT_CONFIG   (0x4)
+#define  EXTIOI_ENABLE (1)
+#define  EXTIOI_ENABLE_INT_ENCODE  (2)
+#define  EXTIOI_ENABLE_CPU_ENCODE  (3)
+#define EXTIOI_VIRT_COREMAP_START(0x40)
+#define EXTIOI_VIRT_COREMAP_END  (0x240)
+
 typedef struct ExtIOICore {
 uint32_t coreisr[EXTIOI_IRQS_GROUP_COUNT];
 DECLARE_BITMAP(sw_isr[LS3A_INTC_IP], EXTIOI_IRQS);
@@ -52,6 +70,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(LoongArchExtIOI, LOONGARCH_EXTIOI)
 struct LoongArchExtIOI {
 SysBusDevice parent_obj;
 uint32_t num_cpu;
+uint32_t features;
+uint32_t status;
 /* hardware state */
 uint32_t nodetype[EXTIOI_IRQS_NODETYPE_COUNT / 2];
 uint32_t bounce[EXTIOI_IRQS_GROUP_COUNT];
@@ -65,5 +85,6 @@ struct LoongArchExtIOI {
 qemu_irq irq[EXTIOI_IRQS];
 ExtIOICore *cpu;
 MemoryRegion extioi_system_mem;
+MemoryRegion virt_extend;
 };
 #endif /* LOONGARCH_EXTIOI_H */
diff --git a/hw/intc/loongarch_extioi.c b/hw/intc/loongarch_extioi.c
index 0b358548eb..89afdb1c3c 100644
--- a/hw/intc/loongarch_extioi.c
+++ b/hw/intc/loongarch_extioi.c
@@ -143,10 +143,13 @@ static inline void 
extioi_update_sw_coremap(LoongArchExtIOI *s, int irq,
 
 for (i = 0; i < 4; i++) {
 cpu = val & 0xff;
-cpu = ctz32(cpu);
-cpu = (cpu >= 4) ? 0 : cpu;
 val = val >> 8;
 
+if (!(s->status & BIT(EXTIOI_ENABLE_CPU_ENCODE))) {
+cpu = ctz32(cpu);
+cpu = (cpu >= 4) ? 0 : cpu;
+}
+
 if (s->sw_coremap[irq + i] == cpu) {
 continue;
 }
@@ -265,6 +268,61 @@ static const MemoryRegionOps extioi_ops = {
 .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
+static MemTxResult extioi_virt_readw(void *opaque, hwaddr addr, uint64_t *data,
+ unsigned size, MemTxAttrs attrs)
+{
+LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
+
+switch (addr) {
+case EXTIOI_VIRT_FEATURES:
+*data = s->features;
+break;
+case EXTIOI_VIRT_CONFIG:
+*data = s->status;
+break;
+default:
+break;
+}
+
+return MEMTX_OK;
+}
+
+static MemTxResult extioi_virt_writew(void *opaque, hwaddr addr,
+  uint64_t val, unsigned size,
+  MemTxAttrs attrs)
+{
+LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
+
+switch (addr) {
+case EXTIOI_VIRT_FEATURES:
+return MEMTX_ACCESS_ERROR;
+
+case EXTIOI_VIRT_CONFIG:
+/*
+ * extioi features can only be set at disabled status
+ */
+if ((s->status & BIT(EXTIOI_ENABLE)) && val) {
+return MEMTX_ACCESS_ERROR;
+}
+
+s->status = val & s->features;
+break;
+default:
+break;
+}
+return MEMTX_OK;
+}
+
+static const MemoryRegionOps extioi_virt_ops = {
+.read_with_attrs = extioi_virt_readw,
+.write_with_attrs = extioi_virt_writew,
+.impl.min_access_size = 4,
+.impl.max_access_size = 4,
+.valid.min_access_size = 4,
+.valid.max_access_size = 8,
+.endianness = DEVICE_LITTLE_ENDIAN,
+};
+
 static void loongarch_extioi_realize(DeviceState *dev, Error **errp)
 {
 LoongArchExtIOI *s = LOONGARCH_EXTIOI(dev);
@@ -284,6 +342,16 @@ static void loongarch_extioi_realize(DeviceState *dev, 
Error **errp)
 memory_region_init_io(>extioi_system_mem, OBJECT(s), _ops,
   s, "extioi_system_mem", 0x900);
 sysbus_init_mmio(sbd, >extioi_system_mem);
+
+if (s->features & BIT(EXTIOI_HAS_VIRT_EXTENSION)) {
+memory_region_init_io

[PULL 0/3] loongarch-to-apply queue

2024-05-09 Thread Song Gao
The following changes since commit 4e66a08546a2588a4667766a1edab9caccf24ce3:

  Merge tag 'for-upstream' of https://gitlab.com/bonzini/qemu into staging 
(2024-05-07 09:26:30 -0700)

are available in the Git repository at:

  https://gitlab.com/gaosong/qemu.git tags/pull-loongarch-20240509

for you to fetch changes up to 5872966db7abaa7f8753541b7a9f242df9752b50:

  target/loongarch: Put cpucfg operation before CSR register (2024-05-09 
15:19:22 +0800)


pull-loongarch-20240509


Bibo Mao (3):
  hw/loongarch: Refine default numa id calculation
  target/loongarch: Add TCG macro in structure CPUArchState
  target/loongarch: Put cpucfg operation before CSR register

 hw/loongarch/virt.c   | 11 +--
 target/loongarch/cpu.c|  7 +--
 target/loongarch/cpu.h| 16 ++--
 target/loongarch/cpu_helper.c |  9 +
 target/loongarch/kvm/kvm.c| 16 
 target/loongarch/machine.c| 30 +-
 6 files changed, 62 insertions(+), 27 deletions(-)




[PULL 2/3] target/loongarch: Add TCG macro in structure CPUArchState

2024-05-09 Thread Song Gao
From: 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 
Message-Id: <20240506011912.2108842-1-maob...@loongson.cn>
Signed-off-by: Song Gao 
---
 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 96da1a685e..a0cad53676 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 @@ static const VMStateDescription vmstate_lasx = {
 },
 };
 
+#if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY)
+static bool tlb_needed(void *opaque)
+{
+return tcg_enabled();
+}
+
 /* TLB state */
-const VMStateDescription vmstate_tlb = {
-.name = "cpu/tlb",
+static const VMStateDescription vms

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

2024-05-09 Thread Song Gao
From: 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 
Reviewed-by: Song Gao 
Message-Id: <20240428031651.1354587-1-maob...@loongson.cn>
Signed-off-by: Song Gao 
---
 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;
 }
 
-- 
2.25.1




[PULL 1/3] hw/loongarch: Refine default numa id calculation

2024-05-09 Thread Song Gao
From: 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 
Reviewed-by: Song Gao 
Message-Id: <20240319022606.2994565-1-maob...@loongson.cn>
Signed-off-by: Song Gao 
---
 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 c0999878df..12d20055fe 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -1192,15 +1192,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.25.1




[PATCH v2] target/loongarch/kvm: Fix VM recovery from disk failures

2024-05-07 Thread Song Gao
vmstate does not save kvm_state_conter,
which can cause VM recovery from disk to fail.

Signed-off-by: Song Gao 
---
v2:
  - Update the version.
  - Link to v1: 
https://patchew.org/QEMU/20240430012356.2620763-1-gaos...@loongson.cn/
 target/loongarch/machine.c | 6 --
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/target/loongarch/machine.c b/target/loongarch/machine.c
index c7029fb9b4..d6109e3b20 100644
--- a/target/loongarch/machine.c
+++ b/target/loongarch/machine.c
@@ -125,8 +125,8 @@ const VMStateDescription vmstate_tlb = {
 /* LoongArch CPU state */
 const VMStateDescription vmstate_loongarch_cpu = {
 .name = "cpu",
-.version_id = 1,
-.minimum_version_id = 1,
+.version_id = 2,
+.minimum_version_id = 2,
 .fields = (const VMStateField[]) {
 VMSTATE_UINTTL_ARRAY(env.gpr, LoongArchCPU, 32),
 VMSTATE_UINTTL(env.pc, LoongArchCPU),
@@ -191,6 +191,8 @@ const VMStateDescription vmstate_loongarch_cpu = {
 VMSTATE_STRUCT_ARRAY(env.tlb, LoongArchCPU, LOONGARCH_TLB_MAX,
  0, vmstate_tlb, LoongArchTLB),
 
+VMSTATE_UINT64(kvm_state_counter, LoongArchCPU),
+
 VMSTATE_END_OF_LIST()
 },
 .subsections = (const VMStateDescription * const []) {
-- 
2.25.1




[PATCH v2] hw/loongarch/virt: Fix memory leak

2024-05-07 Thread Song Gao
The char pointer 'ramName' point to a block of memory, but never free it.
Use a small fixed-size buffer for 'ramName'.

Resolves: Coverity CID 1544773

Fixes: 0cf1478d6 ("hw/loongarch: Add numa support")
Signed-off-by: Song Gao 
---
v2:
  - Use a small fixed-size buffer for 'ramName'.
  - Link to V1: 
https://patchew.org/QEMU/20240507022239.3113987-1-gaos...@loongson.cn/ 

 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 c0999878df..ee690ad981 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -887,7 +887,7 @@ static void loongarch_init(MachineState *machine)
 const CPUArchIdList *possible_cpus;
 MachineClass *mc = MACHINE_GET_CLASS(machine);
 CPUState *cpu;
-char *ramName = NULL;
+char ramName[32];
 
 if (!cpu_model) {
 cpu_model = LOONGARCH_CPU_TYPE_NAME("la464");
@@ -946,7 +946,7 @@ static void loongarch_init(MachineState *machine)
 
 for (i = 1; i < nb_numa_nodes; i++) {
 MemoryRegion *nodemem = g_new(MemoryRegion, 1);
-ramName = g_strdup_printf("loongarch.node%d.ram", i);
+sprintf(ramName, "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);
-- 
2.25.1




[PATCH] hw/loongarch/virt: Fix memory leak

2024-05-06 Thread Song Gao
The char pointer 'ramName' point to a block of memory,
but never free it. Use 'g_autofree' to automatically free it.

Resolves: Coverity CID 1544773

Fixes: 0cf1478d6 ("hw/loongarch: Add numa support")
Signed-off-by: Song Gao 
---
 hw/loongarch/virt.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index c0999878df..ea5100be6d 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -887,7 +887,6 @@ static void loongarch_init(MachineState *machine)
 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");
@@ -946,7 +945,7 @@ static void loongarch_init(MachineState *machine)
 
 for (i = 1; i < nb_numa_nodes; i++) {
 MemoryRegion *nodemem = g_new(MemoryRegion, 1);
-ramName = g_strdup_printf("loongarch.node%d.ram", i);
+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);
-- 
2.25.1




[PATCH] target/loongarch/kvm: Fix VM recovery from disk failures

2024-04-29 Thread Song Gao
vmstate does not save kvm_state_conter,
which can cause VM recovery from disk to fail.

Signed-off-by: Song Gao 
---
 target/loongarch/machine.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/target/loongarch/machine.c b/target/loongarch/machine.c
index c7029fb9b4..4cd1bf06ff 100644
--- a/target/loongarch/machine.c
+++ b/target/loongarch/machine.c
@@ -191,6 +191,8 @@ const VMStateDescription vmstate_loongarch_cpu = {
 VMSTATE_STRUCT_ARRAY(env.tlb, LoongArchCPU, LOONGARCH_TLB_MAX,
  0, vmstate_tlb, LoongArchTLB),
 
+VMSTATE_UINT64(kvm_state_counter, LoongArchCPU),
+
 VMSTATE_END_OF_LIST()
 },
 .subsections = (const VMStateDescription * const []) {
-- 
2.25.1




[PULL v2 06/17] hw/loongarch: Init efi_boot_memmap table

2024-04-28 Thread Song Gao
The efi_system_table adds a efi_boot_memmap configuration table.

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-7-gaos...@loongson.cn>
---
 hw/loongarch/boot.c | 40 +
 hw/loongarch/virt.c | 11 ++
 include/hw/loongarch/boot.h | 27 +
 include/hw/loongarch/virt.h | 10 ++
 4 files changed, 79 insertions(+), 9 deletions(-)

diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index 59889dbc90..527fc9c0be 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -63,8 +63,41 @@ static const unsigned int slave_boot_code[] = {
 0x4c20,   /* jirl   $zero, $ra,0   */
 };
 
+static inline void *guidcpy(void *dst, const void *src)
+{
+return memcpy(dst, src, sizeof(efi_guid_t));
+}
+
+static void init_efi_boot_memmap(struct efi_system_table *systab,
+ void *p, void *start)
+{
+unsigned i;
+struct efi_boot_memmap *boot_memmap = p;
+efi_guid_t tbl_guid = LINUX_EFI_BOOT_MEMMAP_GUID;
+
+/* efi_configuration_table 1 */
+guidcpy(>tables[0].guid, _guid);
+systab->tables[0].table = (struct efi_configuration_table *)(p - start);
+systab->nr_tables = 1;
+
+boot_memmap->desc_size = sizeof(efi_memory_desc_t);
+boot_memmap->desc_ver = 1;
+boot_memmap->map_size = 0;
+
+efi_memory_desc_t *map = p + sizeof(struct efi_boot_memmap);
+for (i = 0; i < memmap_entries; i++) {
+map = (void *)boot_memmap + sizeof(*map);
+map[i].type = memmap_table[i].type;
+map[i].phys_addr = ROUND_UP(memmap_table[i].address, 64 * KiB);
+map[i].num_pages = ROUND_DOWN(memmap_table[i].address +
+memmap_table[i].length - map[i].phys_addr, 64 * KiB);
+p += sizeof(efi_memory_desc_t);
+}
+}
+
 static void init_systab(struct loongarch_boot_info *info, void *p, void *start)
 {
+void *bp_tables_start;
 struct efi_system_table *systab = p;
 
 info->a2 = p - start;
@@ -80,6 +113,13 @@ static void init_systab(struct loongarch_boot_info *info, 
void *p, void *start)
 p += ROUND_UP(sizeof(struct efi_system_table), 64 * KiB);
 
 systab->tables = p;
+bp_tables_start = p;
+
+init_efi_boot_memmap(systab, p, start);
+p += ROUND_UP(sizeof(struct efi_boot_memmap) +
+  sizeof(efi_memory_desc_t) * memmap_entries, 64 * KiB);
+
+systab->tables = (struct efi_configuration_table *)(bp_tables_start - 
start);
 }
 
 static void init_cmdline(struct loongarch_boot_info *info, void *p, void 
*start)
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index bfb88aedab..708aa8bc60 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -378,15 +378,8 @@ static void virt_powerdown_req(Notifier *notifier, void 
*opaque)
 acpi_send_event(s->acpi_ged, ACPI_POWER_DOWN_STATUS);
 }
 
-struct memmap_entry {
-uint64_t address;
-uint64_t length;
-uint32_t type;
-uint32_t reserved;
-};
-
-static struct memmap_entry *memmap_table;
-static unsigned memmap_entries;
+struct memmap_entry *memmap_table;
+unsigned memmap_entries;
 
 static void memmap_add_entry(uint64_t address, uint64_t length, uint32_t type)
 {
diff --git a/include/hw/loongarch/boot.h b/include/hw/loongarch/boot.h
index cf0e4d4f91..76622af2e2 100644
--- a/include/hw/loongarch/boot.h
+++ b/include/hw/loongarch/boot.h
@@ -21,6 +21,15 @@ typedef struct {
 uint8_t b[16];
 } efi_guid_t QEMU_ALIGNED(8);
 
+#define EFI_GUID(a, b, c, d...) (efi_guid_t){ {
\
+(a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, 
\
+(b) & 0xff, ((b) >> 8) & 0xff, 
\
+(c) & 0xff, ((c) >> 8) & 0xff, d } }
+
+#define LINUX_EFI_BOOT_MEMMAP_GUID \
+EFI_GUID(0x800f683f, 0xd08b, 0x423a,  0xa2, 0x93, \
+ 0x96, 0x5c, 0x3c, 0x6f, 0xe2, 0xb4)
+
 struct efi_config_table {
 efi_guid_t guid;
 uint64_t *ptr;
@@ -56,6 +65,24 @@ struct efi_system_table {
 struct efi_configuration_table *tables;
 };
 
+typedef struct {
+uint32_t type;
+uint32_t pad;
+uint64_t phys_addr;
+uint64_t virt_addr;
+uint64_t num_pages;
+uint64_t attribute;
+} efi_memory_desc_t;
+
+struct efi_boot_memmap {
+uint64_t map_size;
+uint64_t desc_size;
+uint32_t desc_ver;
+uint64_t map_key;
+uint64_t buff_size;
+efi_memory_desc_t map[32];
+};
+
 struct loongarch_boot_info {
 uint64_t ram_size;
 const char *kernel_filename;
diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h
index d7a074d69f..8a9fe4053d 100644
--- a/include/hw/loongarch/virt.h
+++ b/include/hw/loongarch/virt.h
@@ -35,6 +35,16 @@
 
 #define COMMAND_LINE_SIZE   512
 
+extern struct memmap_entry *memmap_table;
+extern unsigned mem

[PULL v2 08/17] hw/loongarch: Init efi_fdt table

2024-04-28 Thread Song Gao
The efi_system_table adds a efi_fdt configuration table.

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-9-gaos...@loongson.cn>
---
 hw/loongarch/boot.c | 11 +++
 hw/loongarch/virt.c |  6 ++
 include/hw/loongarch/boot.h |  4 
 include/hw/loongarch/virt.h |  2 ++
 4 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index c8b3e742b4..7d1630b2e7 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -113,6 +113,16 @@ static void init_efi_initrd_table(struct efi_system_table 
*systab,
 initrd_table->size = initrd_size;
 }
 
+static void init_efi_fdt_table(struct efi_system_table *systab)
+{
+efi_guid_t tbl_guid = DEVICE_TREE_GUID;
+
+/* efi_configuration_table 3 */
+guidcpy(>tables[2].guid, _guid);
+systab->tables[2].table = (void *)FDT_BASE;
+systab->nr_tables = 3;
+}
+
 static void init_systab(struct loongarch_boot_info *info, void *p, void *start)
 {
 void *bp_tables_start;
@@ -138,6 +148,7 @@ static void init_systab(struct loongarch_boot_info *info, 
void *p, void *start)
   sizeof(efi_memory_desc_t) * memmap_entries, 64 * KiB);
 init_efi_initrd_table(systab, p, start);
 p += ROUND_UP(sizeof(struct efi_initrd), 64 * KiB);
+init_efi_fdt_table(systab);
 
 systab->tables = (struct efi_configuration_table *)(bp_tables_start - 
start);
 }
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 708aa8bc60..42e5df8a24 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -727,7 +727,6 @@ static void loongarch_init(MachineState *machine)
 int nb_numa_nodes = machine->numa_state->num_nodes;
 NodeInfo *numa_info = machine->numa_state->nodes;
 int i;
-hwaddr fdt_base;
 const CPUArchIdList *possible_cpus;
 MachineClass *mc = MACHINE_GET_CLASS(machine);
 CPUState *cpu;
@@ -857,12 +856,11 @@ static void loongarch_init(MachineState *machine)
  * Put the FDT into the memory map as a ROM image: this will ensure
  * the FDT is copied again upon reset, even if addr points into RAM.
  */
-fdt_base = 1 * MiB;
 qemu_fdt_dumpdtb(machine->fdt, lams->fdt_size);
-rom_add_blob_fixed_as("fdt", machine->fdt, lams->fdt_size, fdt_base,
+rom_add_blob_fixed_as("fdt", machine->fdt, lams->fdt_size, FDT_BASE,
   _space_memory);
 qemu_register_reset_nosnapshotload(qemu_fdt_randomize_seeds,
-rom_ptr_for_as(_space_memory, fdt_base, lams->fdt_size));
+rom_ptr_for_as(_space_memory, FDT_BASE, lams->fdt_size));
 
 lams->bootinfo.ram_size = ram_size;
 loongarch_load_kernel(machine, >bootinfo);
diff --git a/include/hw/loongarch/boot.h b/include/hw/loongarch/boot.h
index 42d1ee3663..4ebcc89dcf 100644
--- a/include/hw/loongarch/boot.h
+++ b/include/hw/loongarch/boot.h
@@ -34,6 +34,10 @@ typedef struct {
 EFI_GUID(0x5568e427, 0x68fc, 0x4f3d,  0xac, 0x74, \
  0xca, 0x55, 0x52, 0x31, 0xcc, 0x68)
 
+#define DEVICE_TREE_GUID \
+EFI_GUID(0xb1b621d5, 0xf19c, 0x41a5,  0x83, 0x0b, \
+ 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0)
+
 struct efi_config_table {
 efi_guid_t guid;
 uint64_t *ptr;
diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h
index 8a9fe4053d..4e14bf6060 100644
--- a/include/hw/loongarch/virt.h
+++ b/include/hw/loongarch/virt.h
@@ -35,6 +35,8 @@
 
 #define COMMAND_LINE_SIZE   512
 
+#define FDT_BASE0x10
+
 extern struct memmap_entry *memmap_table;
 extern unsigned memmap_entries;
 
-- 
2.25.1




[PULL v2 03/17] hw/loongarch: Add slave cpu boot_code

2024-04-28 Thread Song Gao
Load the slave CPU boot code at pflash0 and set
the slave CPU elf_address to VIRT_FLASH0_BASE.

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-4-gaos...@loongson.cn>
---
 hw/loongarch/boot.c | 62 -
 1 file changed, 61 insertions(+), 1 deletion(-)

diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index a5135fe542..fb6effbaff 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -15,6 +15,54 @@
 #include "sysemu/reset.h"
 #include "sysemu/qtest.h"
 
+static const unsigned int slave_boot_code[] = {
+  /* Configure reset ebase.*/
+0x0400302c,   /* csrwr  $t0, LOONGARCH_CSR_EENTRY  */
+
+  /* Disable interrupt.*/
+0x0380100c,   /* ori$t0, $zero,0x4 */
+0x04000180,   /* csrxchg$zero, $t0, LOONGARCH_CSR_CRMD */
+
+  /* Clear mailbox.*/
+0x142d,   /* lu12i.w$t1, 1(0x1)*/
+0x038081ad,   /* ori$t1, $t1, CORE_BUF_20  */
+0x06481da0,   /* iocsrwr.d  $zero, $t1 */
+
+  /* Enable IPI interrupt. */
+0x142c,   /* lu12i.w$t0, 1(0x1)*/
+0x0400118c,   /* csrxchg$t0, $t0, LOONGARCH_CSR_ECFG   */
+0x02fffc0c,   /* addi.d $t0, $r0,-1(0xfff) */
+0x142d,   /* lu12i.w$t1, 1(0x1)*/
+0x038011ad,   /* ori$t1, $t1, CORE_EN_OFF  */
+0x064819ac,   /* iocsrwr.w  $t0, $t1   */
+0x142d,   /* lu12i.w$t1, 1(0x1)*/
+0x038081ad,   /* ori$t1, $t1, CORE_BUF_20  */
+
+  /* Wait for wakeup  <.L11>:  */
+0x06488000,   /* idle   0x0*/
+0x0340,   /* andi   $zero, $zero, 0x0  */
+0x064809ac,   /* iocsrrd.w  $t0, $t1   */
+0x43fff59f,   /* beqz   $t0, -12(0x74) # 48 <.L11> */
+
+  /* Read and clear IPI interrupt. */
+0x142d,   /* lu12i.w$t1, 1(0x1)*/
+0x064809ac,   /* iocsrrd.w  $t0, $t1   */
+0x142d,   /* lu12i.w$t1, 1(0x1)*/
+0x038031ad,   /* ori$t1, $t1, CORE_CLEAR_OFF   */
+0x064819ac,   /* iocsrwr.w  $t0, $t1   */
+
+  /* Disable  IPI interrupt.   */
+0x142c,   /* lu12i.w$t0, 1(0x1)*/
+0x04001180,   /* csrxchg$zero, $t0, LOONGARCH_CSR_ECFG */
+
+  /* Read mail buf and jump to specified entry */
+0x142d,   /* lu12i.w$t1, 1(0x1)*/
+0x038081ad,   /* ori$t1, $t1, CORE_BUF_20  */
+0x06480dac,   /* iocsrrd.d  $t0, $t1   */
+0x00150181,   /* move   $ra, $t0   */
+0x4c20,   /* jirl   $zero, $ra,0   */
+};
+
 static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr)
 {
 return addr & MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS);
@@ -125,11 +173,23 @@ static void loongarch_direct_kernel_boot(struct 
loongarch_boot_info *info)
 }
 }
 
+/* Load slave boot code at pflash0 . */
+void *boot_code = g_malloc0(VIRT_FLASH0_SIZE);
+memcpy(boot_code, _boot_code, sizeof(slave_boot_code));
+rom_add_blob_fixed("boot_code", boot_code, VIRT_FLASH0_SIZE, 
VIRT_FLASH0_BASE);
+
 CPU_FOREACH(cs) {
 lacpu = LOONGARCH_CPU(cs);
 lacpu->env.load_elf = true;
-lacpu->env.elf_address = kernel_addr;
+if (cs == first_cpu) {
+lacpu->env.elf_address = kernel_addr;
+} else {
+lacpu->env.elf_address = VIRT_FLASH0_BASE;
+}
+lacpu->env.boot_info = info;
 }
+
+g_free(boot_code);
 }
 
 void loongarch_load_kernel(MachineState *ms, struct loongarch_boot_info *info)
-- 
2.25.1




[PULL v2 12/17] hw/loongarch: fdt adds pch_pic Controller

2024-04-28 Thread Song Gao
fdt adds pch pic controller, we use 'loongson,pch-pic-1.0'

See:
https://github.com/torvalds/linux/blob/v6.7/drivers/irqchip/irq-loongson-pch-pic.c
https://lore.kernel.org/r/20200528152757.1028711-4-jiaxun.y...@flygoat.com

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-13-gaos...@loongson.cn>
---
 hw/loongarch/virt.c| 30 +-
 include/hw/pci-host/ls7a.h |  1 +
 2 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 094b9d2e60..5bef161d11 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -148,6 +148,31 @@ static void fdt_add_eiointc_node(LoongArchMachineState 
*lams,
 g_free(nodename);
 }
 
+static void fdt_add_pch_pic_node(LoongArchMachineState *lams,
+ uint32_t *eiointc_phandle,
+ uint32_t *pch_pic_phandle)
+{
+MachineState *ms = MACHINE(lams);
+char *nodename;
+hwaddr pch_pic_base = VIRT_PCH_REG_BASE;
+hwaddr pch_pic_size = VIRT_PCH_REG_SIZE;
+
+*pch_pic_phandle = qemu_fdt_alloc_phandle(ms->fdt);
+nodename = g_strdup_printf("/platic@%" PRIx64, pch_pic_base);
+qemu_fdt_add_subnode(ms->fdt, nodename);
+qemu_fdt_setprop_cell(ms->fdt,  nodename, "phandle", *pch_pic_phandle);
+qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
+"loongson,pch-pic-1.0");
+qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0,
+   pch_pic_base, 0, pch_pic_size);
+qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 2);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
+  *eiointc_phandle);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "loongson,pic-base-vec", 0);
+g_free(nodename);
+}
+
 static void fdt_add_flash_node(LoongArchMachineState *lams)
 {
 MachineState *ms = MACHINE(lams);
@@ -570,7 +595,7 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
 CPULoongArchState *env;
 CPUState *cpu_state;
 int cpu, pin, i, start, num;
-uint32_t cpuintc_phandle, eiointc_phandle;
+uint32_t cpuintc_phandle, eiointc_phandle, pch_pic_phandle;
 
 /*
  * The connection of interrupts:
@@ -661,6 +686,9 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
 qdev_connect_gpio_out(DEVICE(d), i, qdev_get_gpio_in(extioi, i));
 }
 
+/* Add PCH PIC node */
+fdt_add_pch_pic_node(lams, _phandle, _pic_phandle);
+
 pch_msi = qdev_new(TYPE_LOONGARCH_PCH_MSI);
 start   =  num;
 num = EXTIOI_IRQS - start;
diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h
index e753449593..fe260f0183 100644
--- a/include/hw/pci-host/ls7a.h
+++ b/include/hw/pci-host/ls7a.h
@@ -24,6 +24,7 @@
 #define VIRT_PCH_REG_BASE0x1000UL
 #define VIRT_IOAPIC_REG_BASE (VIRT_PCH_REG_BASE)
 #define VIRT_PCH_MSI_ADDR_LOW0x2FF0UL
+#define VIRT_PCH_REG_SIZE0x400
 
 /*
  * GSI_BASE is hard-coded with 64 in linux kernel, else kernel fails to boot
-- 
2.25.1




[PULL v2 07/17] hw/loongarch: Init efi_initrd table

2024-04-28 Thread Song Gao
The efi_system_table adds a efi_initrd configuration table.

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-8-gaos...@loongson.cn>
---
 hw/loongarch/boot.c | 23 +--
 include/hw/loongarch/boot.h |  9 +
 2 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index 527fc9c0be..c8b3e742b4 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -15,6 +15,9 @@
 #include "sysemu/reset.h"
 #include "sysemu/qtest.h"
 
+ram_addr_t initrd_offset;
+uint64_t initrd_size;
+
 static const unsigned int slave_boot_code[] = {
   /* Configure reset ebase.*/
 0x0400302c,   /* csrwr  $t0, LOONGARCH_CSR_EENTRY  */
@@ -95,6 +98,21 @@ static void init_efi_boot_memmap(struct efi_system_table 
*systab,
 }
 }
 
+static void init_efi_initrd_table(struct efi_system_table *systab,
+  void *p, void *start)
+{
+efi_guid_t tbl_guid = LINUX_EFI_INITRD_MEDIA_GUID;
+struct efi_initrd *initrd_table  = p;
+
+/* efi_configuration_table 2 */
+guidcpy(>tables[1].guid, _guid);
+systab->tables[1].table = (struct efi_configuration_table *)(p - start);
+systab->nr_tables = 2;
+
+initrd_table->base = initrd_offset;
+initrd_table->size = initrd_size;
+}
+
 static void init_systab(struct loongarch_boot_info *info, void *p, void *start)
 {
 void *bp_tables_start;
@@ -118,6 +136,8 @@ static void init_systab(struct loongarch_boot_info *info, 
void *p, void *start)
 init_efi_boot_memmap(systab, p, start);
 p += ROUND_UP(sizeof(struct efi_boot_memmap) +
   sizeof(efi_memory_desc_t) * memmap_entries, 64 * KiB);
+init_efi_initrd_table(systab, p, start);
+p += ROUND_UP(sizeof(struct efi_initrd), 64 * KiB);
 
 systab->tables = (struct efi_configuration_table *)(bp_tables_start - 
start);
 }
@@ -139,8 +159,7 @@ static uint64_t cpu_loongarch_virt_to_phys(void *opaque, 
uint64_t addr)
 
 static int64_t load_kernel_info(struct loongarch_boot_info *info)
 {
-uint64_t kernel_entry, kernel_low, kernel_high, initrd_size;
-ram_addr_t initrd_offset;
+uint64_t kernel_entry, kernel_low, kernel_high;
 ssize_t kernel_size;
 
 kernel_size = load_elf(info->kernel_filename, NULL,
diff --git a/include/hw/loongarch/boot.h b/include/hw/loongarch/boot.h
index 76622af2e2..42d1ee3663 100644
--- a/include/hw/loongarch/boot.h
+++ b/include/hw/loongarch/boot.h
@@ -30,6 +30,10 @@ typedef struct {
 EFI_GUID(0x800f683f, 0xd08b, 0x423a,  0xa2, 0x93, \
  0x96, 0x5c, 0x3c, 0x6f, 0xe2, 0xb4)
 
+#define LINUX_EFI_INITRD_MEDIA_GUID \
+EFI_GUID(0x5568e427, 0x68fc, 0x4f3d,  0xac, 0x74, \
+ 0xca, 0x55, 0x52, 0x31, 0xcc, 0x68)
+
 struct efi_config_table {
 efi_guid_t guid;
 uint64_t *ptr;
@@ -83,6 +87,11 @@ struct efi_boot_memmap {
 efi_memory_desc_t map[32];
 };
 
+struct efi_initrd {
+uint64_t base;
+uint64_t size;
+};
+
 struct loongarch_boot_info {
 uint64_t ram_size;
 const char *kernel_filename;
-- 
2.25.1




[PULL v2 02/17] hw/loongarch: Add load initrd

2024-04-28 Thread Song Gao
we load initrd ramdisk after kernel_high address

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-3-gaos...@loongson.cn>
---
 hw/loongarch/boot.c | 28 +++-
 1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index 9feed17db3..a5135fe542 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -22,7 +22,8 @@ static uint64_t cpu_loongarch_virt_to_phys(void *opaque, 
uint64_t addr)
 
 static int64_t load_kernel_info(struct loongarch_boot_info *info)
 {
-uint64_t kernel_entry, kernel_low, kernel_high;
+uint64_t kernel_entry, kernel_low, kernel_high, initrd_size;
+ram_addr_t initrd_offset;
 ssize_t kernel_size;
 
 kernel_size = load_elf(info->kernel_filename, NULL,
@@ -37,6 +38,31 @@ static int64_t load_kernel_info(struct loongarch_boot_info 
*info)
  load_elf_strerror(kernel_size));
 exit(1);
 }
+
+if (info->initrd_filename) {
+initrd_size = get_image_size(info->initrd_filename);
+if (initrd_size > 0) {
+initrd_offset = ROUND_UP(kernel_high + 4 * kernel_size, 64 * KiB);
+
+if (initrd_offset + initrd_size > info->ram_size) {
+error_report("memory too small for initial ram disk '%s'",
+ info->initrd_filename);
+exit(1);
+}
+
+initrd_size = load_image_targphys(info->initrd_filename, 
initrd_offset,
+  info->ram_size - initrd_offset);
+}
+
+if (initrd_size == (target_ulong)-1) {
+error_report("could not load initial ram disk '%s'",
+ info->initrd_filename);
+exit(1);
+}
+} else {
+initrd_size = 0;
+}
+
 return kernel_entry;
 }
 
-- 
2.25.1




[PULL v2 15/17] hw/loongarch: fdt remove unused irqchip node

2024-04-28 Thread Song Gao
This patch removes the unused fdt irqchip node.

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-16-gaos...@loongson.cn>
---
 hw/loongarch/virt.c | 31 +--
 1 file changed, 1 insertion(+), 30 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 91a55a81b6..48f73edd8e 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -446,34 +446,6 @@ static void fdt_add_pcie_node(const LoongArchMachineState 
*lams,
 g_free(nodename);
 }
 
-static void fdt_add_irqchip_node(LoongArchMachineState *lams)
-{
-MachineState *ms = MACHINE(lams);
-char *nodename;
-uint32_t irqchip_phandle;
-
-irqchip_phandle = qemu_fdt_alloc_phandle(ms->fdt);
-qemu_fdt_setprop_cell(ms->fdt, "/", "interrupt-parent", irqchip_phandle);
-
-nodename = g_strdup_printf("/intc@%lx", VIRT_IOAPIC_REG_BASE);
-qemu_fdt_add_subnode(ms->fdt, nodename);
-qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 3);
-qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
-qemu_fdt_setprop_cell(ms->fdt, nodename, "#address-cells", 0x2);
-qemu_fdt_setprop_cell(ms->fdt, nodename, "#size-cells", 0x2);
-qemu_fdt_setprop(ms->fdt, nodename, "ranges", NULL, 0);
-
-qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
-"loongarch,ls7a");
-
-qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
- 2, VIRT_IOAPIC_REG_BASE,
- 2, PCH_PIC_ROUTE_ENTRY_OFFSET);
-
-qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", irqchip_phandle);
-g_free(nodename);
-}
-
 static void fdt_add_memory_node(MachineState *ms,
 uint64_t base, uint64_t size, int node_id)
 {
@@ -1011,8 +983,7 @@ static void loongarch_init(MachineState *machine)
 
 /* Initialize the IO interrupt subsystem */
 loongarch_irq_init(lams);
-fdt_add_irqchip_node(lams);
-platform_bus_add_all_fdt_nodes(machine->fdt, "/intc",
+platform_bus_add_all_fdt_nodes(machine->fdt, "/platic",
VIRT_PLATFORM_BUS_BASEADDRESS,
VIRT_PLATFORM_BUS_SIZE,
VIRT_PLATFORM_BUS_IRQ);
-- 
2.25.1




[PULL v2 11/17] hw/loongarch: fdt adds Extend I/O Interrupt Controller

2024-04-28 Thread Song Gao
fdt adds Extend I/O Interrupt Controller,
we use 'loongson,ls2k2000-eiointc'.

See:
https://github.com/torvalds/linux/blob/v6.7/drivers/irqchip/irq-loongson-eiointc.c
https://lore.kernel.org/r/764e02d924094580ac0f1d15535f4b98308705c6.1683279769.git.zhoubin...@loongson.cn

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-12-gaos...@loongson.cn>
---
 hw/loongarch/virt.c| 30 +-
 include/hw/intc/loongarch_extioi.h |  1 +
 2 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 88cdcb6f91..094b9d2e60 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -123,6 +123,31 @@ static void fdt_add_cpuic_node(LoongArchMachineState *lams,
 g_free(nodename);
 }
 
+static void fdt_add_eiointc_node(LoongArchMachineState *lams,
+  uint32_t *cpuintc_phandle,
+  uint32_t *eiointc_phandle)
+{
+MachineState *ms = MACHINE(lams);
+char *nodename;
+hwaddr extioi_base = APIC_BASE;
+hwaddr extioi_size = EXTIOI_SIZE;
+
+*eiointc_phandle = qemu_fdt_alloc_phandle(ms->fdt);
+nodename = g_strdup_printf("/eiointc@%" PRIx64, extioi_base);
+qemu_fdt_add_subnode(ms->fdt, nodename);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *eiointc_phandle);
+qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
+"loongson,ls2k2000-eiointc");
+qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 1);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
+  *cpuintc_phandle);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupts", 3);
+qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0x0,
+   extioi_base, 0x0, extioi_size);
+g_free(nodename);
+}
+
 static void fdt_add_flash_node(LoongArchMachineState *lams)
 {
 MachineState *ms = MACHINE(lams);
@@ -545,7 +570,7 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
 CPULoongArchState *env;
 CPUState *cpu_state;
 int cpu, pin, i, start, num;
-uint32_t cpuintc_phandle;
+uint32_t cpuintc_phandle, eiointc_phandle;
 
 /*
  * The connection of interrupts:
@@ -614,6 +639,9 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
 }
 }
 
+/* Add Extend I/O Interrupt Controller node */
+fdt_add_eiointc_node(lams, _phandle, _phandle);
+
 pch_pic = qdev_new(TYPE_LOONGARCH_PCH_PIC);
 num = VIRT_PCH_PIC_IRQ_NUM;
 qdev_prop_set_uint32(pch_pic, "pch_pic_irq_num", num);
diff --git a/include/hw/intc/loongarch_extioi.h 
b/include/hw/intc/loongarch_extioi.h
index a0a46b888c..410c6e1121 100644
--- a/include/hw/intc/loongarch_extioi.h
+++ b/include/hw/intc/loongarch_extioi.h
@@ -39,6 +39,7 @@
 #define EXTIOI_COREISR_END   (0xB20 - APIC_OFFSET)
 #define EXTIOI_COREMAP_START (0xC00 - APIC_OFFSET)
 #define EXTIOI_COREMAP_END   (0xD00 - APIC_OFFSET)
+#define EXTIOI_SIZE  0x800
 
 typedef struct ExtIOICore {
 uint32_t coreisr[EXTIOI_IRQS_GROUP_COUNT];
-- 
2.25.1




[PULL v2 17/17] hw/loongarch: Add cells missing from rtc node

2024-04-28 Thread Song Gao
rtc node need interrupts and interrupt-parent cells.

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-18-gaos...@loongson.cn>
---
 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 dbd7928759..c0999878df 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -231,7 +231,8 @@ static void fdt_add_flash_node(LoongArchMachineState *lams)
 g_free(nodename);
 }
 
-static void fdt_add_rtc_node(LoongArchMachineState *lams)
+static void fdt_add_rtc_node(LoongArchMachineState *lams,
+ uint32_t *pch_pic_phandle)
 {
 char *nodename;
 hwaddr base = VIRT_RTC_REG_BASE;
@@ -240,8 +241,13 @@ static void fdt_add_rtc_node(LoongArchMachineState *lams)
 
 nodename = g_strdup_printf("/rtc@%" PRIx64, base);
 qemu_fdt_add_subnode(ms->fdt, nodename);
-qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", 
"loongson,ls7a-rtc");
+qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
+"loongson,ls7a-rtc");
 qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", 2, base, 2, size);
+qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts",
+   VIRT_RTC_IRQ - VIRT_GSI_BASE , 0x4);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
+  *pch_pic_phandle);
 g_free(nodename);
 }
 
@@ -648,7 +654,7 @@ static void loongarch_devices_init(DeviceState *pch_pic,
 sysbus_create_simple("ls7a_rtc", VIRT_RTC_REG_BASE,
  qdev_get_gpio_in(pch_pic,
  VIRT_RTC_IRQ - VIRT_GSI_BASE));
-fdt_add_rtc_node(lams);
+fdt_add_rtc_node(lams, pch_pic_phandle);
 
 /* acpi ged */
 lams->acpi_ged = create_acpi_ged(pch_pic, lams);
-- 
2.25.1




[PULL v2 09/17] hw/loongarch: Fix fdt memory node wrong 'reg'

2024-04-28 Thread Song Gao
The right fdt memory node like [1], not [2]

  [1]
memory@0 {
device_type = "memory";
reg = <0x00 0x00 0x00 0x1000>;
};
  [2]
memory@0 {
device_type = "memory";
reg = <0x02 0x00 0x02 0x1000>;
};

Reviewed-by: Bibo Mao 
Signed-off-by: Song Gao 
Message-Id: <20240426091551.2397867-10-gaos...@loongson.cn>
---
 hw/loongarch/virt.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 42e5df8a24..032f5f2ddf 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -325,7 +325,7 @@ static void fdt_add_memory_node(MachineState *ms,
 char *nodename = g_strdup_printf("/memory@%" PRIx64, base);
 
 qemu_fdt_add_subnode(ms->fdt, nodename);
-qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 2, base, 2, size);
+qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0, base, 0, size);
 qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "memory");
 
 if (ms->numa_state && ms->numa_state->num_nodes) {
-- 
2.25.1




[PULL v2 16/17] hw/loongarch: Add cells missing from uart node

2024-04-28 Thread Song Gao
uart node need interrupts and interrupt-parent cells.

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-17-gaos...@loongson.cn>
---
 hw/loongarch/virt.c | 9 +++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 48f73edd8e..dbd7928759 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -245,7 +245,8 @@ static void fdt_add_rtc_node(LoongArchMachineState *lams)
 g_free(nodename);
 }
 
-static void fdt_add_uart_node(LoongArchMachineState *lams)
+static void fdt_add_uart_node(LoongArchMachineState *lams,
+  uint32_t *pch_pic_phandle)
 {
 char *nodename;
 hwaddr base = VIRT_UART_BASE;
@@ -258,6 +259,10 @@ static void fdt_add_uart_node(LoongArchMachineState *lams)
 qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0x0, base, 0x0, size);
 qemu_fdt_setprop_cell(ms->fdt, nodename, "clock-frequency", 1);
 qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", nodename);
+qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts",
+   VIRT_UART_IRQ - VIRT_GSI_BASE, 0x4);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
+  *pch_pic_phandle);
 g_free(nodename);
 }
 
@@ -630,7 +635,7 @@ static void loongarch_devices_init(DeviceState *pch_pic,
qdev_get_gpio_in(pch_pic,
 VIRT_UART_IRQ - VIRT_GSI_BASE),
115200, serial_hd(0), DEVICE_LITTLE_ENDIAN);
-fdt_add_uart_node(lams);
+fdt_add_uart_node(lams, pch_pic_phandle);
 
 /* Network init */
 pci_init_nic_devices(pci_bus, mc->default_nic);
-- 
2.25.1




[PULL v2 04/17] hw/loongarch: Add init_cmdline

2024-04-28 Thread Song Gao
Add init_cmline and set boot_info->a0, a1

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-5-gaos...@loongson.cn>
---
 hw/loongarch/boot.c | 30 ++
 include/hw/loongarch/virt.h |  2 ++
 target/loongarch/cpu.h  |  2 ++
 3 files changed, 34 insertions(+)

diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index fb6effbaff..127085bcc4 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -63,6 +63,16 @@ static const unsigned int slave_boot_code[] = {
 0x4c20,   /* jirl   $zero, $ra,0   */
 };
 
+static void init_cmdline(struct loongarch_boot_info *info, void *p, void 
*start)
+{
+hwaddr cmdline_addr = p - start;
+
+info->a0 = 1;
+info->a1 = cmdline_addr;
+
+memcpy(p, info->kernel_cmdline, COMMAND_LINE_SIZE);
+}
+
 static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr)
 {
 return addr & MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS);
@@ -121,6 +131,10 @@ static void reset_load_elf(void *opaque)
 
 cpu_reset(CPU(cpu));
 if (env->load_elf) {
+   if (cpu == LOONGARCH_CPU(first_cpu)) {
+env->gpr[4] = env->boot_info->a0;
+env->gpr[5] = env->boot_info->a1;
+}
 cpu_set_pc(CPU(cpu), env->elf_address);
 }
 }
@@ -158,8 +172,17 @@ static void loongarch_firmware_boot(LoongArchMachineState 
*lams,
 fw_cfg_add_kernel_info(info, lams->fw_cfg);
 }
 
+static void init_boot_rom(struct loongarch_boot_info *info, void *p)
+{
+void *start = p;
+
+init_cmdline(info, p, start);
+p += COMMAND_LINE_SIZE;
+}
+
 static void loongarch_direct_kernel_boot(struct loongarch_boot_info *info)
 {
+void *p, *bp;
 int64_t kernel_addr = 0;
 LoongArchCPU *lacpu;
 CPUState *cs;
@@ -173,6 +196,12 @@ static void loongarch_direct_kernel_boot(struct 
loongarch_boot_info *info)
 }
 }
 
+/* Load cmdline and system tables at [0 - 1 MiB] */
+p = g_malloc0(1 * MiB);
+bp = p;
+init_boot_rom(info, p);
+rom_add_blob_fixed_as("boot_info", bp, 1 * MiB, 0, _space_memory);
+
 /* Load slave boot code at pflash0 . */
 void *boot_code = g_malloc0(VIRT_FLASH0_SIZE);
 memcpy(boot_code, _boot_code, sizeof(slave_boot_code));
@@ -190,6 +219,7 @@ static void loongarch_direct_kernel_boot(struct 
loongarch_boot_info *info)
 }
 
 g_free(boot_code);
+g_free(bp);
 }
 
 void loongarch_load_kernel(MachineState *ms, struct loongarch_boot_info *info)
diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h
index cf2f2bfb19..d7a074d69f 100644
--- a/include/hw/loongarch/virt.h
+++ b/include/hw/loongarch/virt.h
@@ -33,6 +33,8 @@
 #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)
 
+#define COMMAND_LINE_SIZE   512
+
 struct LoongArchMachineState {
 /*< private >*/
 MachineState parent_obj;
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index abb01b2cc7..c5722670f5 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -359,6 +359,8 @@ typedef struct CPUArchState {
 uint32_t mp_state;
 /* Store ipistate to access from this struct */
 DeviceState *ipistate;
+
+struct loongarch_boot_info *boot_info;
 #endif
 } CPULoongArchState;
 
-- 
2.25.1




[PULL v2 14/17] hw/loongarch: fdt adds pcie irq_map node

2024-04-28 Thread Song Gao
This patch adds pcie irq_map node for FDT.

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-15-gaos...@loongson.cn>
---
 hw/loongarch/virt.c | 73 ++---
 1 file changed, 69 insertions(+), 4 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 566f86e741..91a55a81b6 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -352,7 +352,62 @@ static void fdt_add_fw_cfg_node(const 
LoongArchMachineState *lams)
 g_free(nodename);
 }
 
-static void fdt_add_pcie_node(const LoongArchMachineState *lams)
+static void fdt_add_pcie_irq_map_node(const LoongArchMachineState *lams,
+  char *nodename,
+  uint32_t *pch_pic_phandle)
+{
+int pin, dev;
+uint32_t irq_map_stride = 0;
+uint32_t full_irq_map[GPEX_NUM_IRQS *GPEX_NUM_IRQS * 10] = {};
+uint32_t *irq_map = full_irq_map;
+const MachineState *ms = MACHINE(lams);
+
+/* This code creates a standard swizzle of interrupts such that
+ * each device's first interrupt is based on it's PCI_SLOT number.
+ * (See pci_swizzle_map_irq_fn())
+ *
+ * We only need one entry per interrupt in the table (not one per
+ * possible slot) seeing the interrupt-map-mask will allow the table
+ * to wrap to any number of devices.
+ */
+
+for (dev = 0; dev < GPEX_NUM_IRQS; dev++) {
+int devfn = dev * 0x8;
+
+for (pin = 0; pin  < GPEX_NUM_IRQS; pin++) {
+int irq_nr = 16 + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_IRQS);
+int i = 0;
+
+/* Fill PCI address cells */
+irq_map[i] = cpu_to_be32(devfn << 8);
+i += 3;
+
+/* Fill PCI Interrupt cells */
+irq_map[i] = cpu_to_be32(pin + 1);
+i += 1;
+
+/* Fill interrupt controller phandle and cells */
+irq_map[i++] = cpu_to_be32(*pch_pic_phandle);
+irq_map[i++] = cpu_to_be32(irq_nr);
+
+if (!irq_map_stride) {
+irq_map_stride = i;
+}
+irq_map += irq_map_stride;
+}
+}
+
+
+qemu_fdt_setprop(ms->fdt, nodename, "interrupt-map", full_irq_map,
+ GPEX_NUM_IRQS * GPEX_NUM_IRQS *
+ irq_map_stride * sizeof(uint32_t));
+qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupt-map-mask",
+ 0x1800, 0, 0, 0x7);
+}
+
+static void fdt_add_pcie_node(const LoongArchMachineState *lams,
+  uint32_t *pch_pic_phandle,
+  uint32_t *pch_msi_phandle)
 {
 char *nodename;
 hwaddr base_mmio = VIRT_PCI_MEM_BASE;
@@ -383,6 +438,11 @@ static void fdt_add_pcie_node(const LoongArchMachineState 
*lams)
  2, base_pio, 2, size_pio,
  1, FDT_PCI_RANGE_MMIO, 2, base_mmio,
  2, base_mmio, 2, size_mmio);
+qemu_fdt_setprop_cells(ms->fdt, nodename, "msi-map",
+   0, *pch_msi_phandle, 0, 0x1);
+
+fdt_add_pcie_irq_map_node(lams, nodename, pch_pic_phandle);
+
 g_free(nodename);
 }
 
@@ -542,7 +602,10 @@ static DeviceState *create_platform_bus(DeviceState 
*pch_pic)
 return dev;
 }
 
-static void loongarch_devices_init(DeviceState *pch_pic, LoongArchMachineState 
*lams)
+static void loongarch_devices_init(DeviceState *pch_pic,
+   LoongArchMachineState *lams,
+   uint32_t *pch_pic_phandle,
+   uint32_t *pch_msi_phandle)
 {
 MachineClass *mc = MACHINE_GET_CLASS(lams);
 DeviceState *gpex_dev;
@@ -588,6 +651,9 @@ static void loongarch_devices_init(DeviceState *pch_pic, 
LoongArchMachineState *
 gpex_set_irq_num(GPEX_HOST(gpex_dev), i, 16 + i);
 }
 
+/* Add pcie node */
+fdt_add_pcie_node(lams, pch_pic_phandle, pch_msi_phandle);
+
 serial_mm_init(get_system_memory(), VIRT_UART_BASE, 0,
qdev_get_gpio_in(pch_pic,
 VIRT_UART_IRQ - VIRT_GSI_BASE),
@@ -734,7 +800,7 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
 /* Add PCH MSI node */
 fdt_add_pch_msi_node(lams, _phandle, _msi_phandle);
 
-loongarch_devices_init(pch_pic, lams);
+loongarch_devices_init(pch_pic, lams, _pic_phandle, _msi_phandle);
 }
 
 static void loongarch_firmware_init(LoongArchMachineState *lams)
@@ -956,7 +1022,6 @@ static void loongarch_init(MachineState *machine)
 lams->powerdown_notifier.notify = virt_powerdown_req;
 qemu_register_powerdown_notifier(>powerdown_notifier);
 
-fdt_add_pcie_node(lams);
 /*
  * Since lowmem region starts from 0 and Linux kernel legacy start address
  * at 2 MiB, FDT base address is located at 1 MiB to avoid NULL pointer
-- 
2.25.1




[PULL v2 10/17] hw/loongarch: fdt adds cpu interrupt controller node

2024-04-28 Thread Song Gao
fdt adds cpu interrupt controller node,
we use 'loongson,cpu-interrupt-controller'.

See:
https://github.com/torvalds/linux/blob/v6.7/drivers/irqchip/irq-loongarch-cpu.c
https://lore.kernel.org/r/20221114113824.1880-2-liupei...@loongson.cn

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-11-gaos...@loongson.cn>
---
 hw/loongarch/virt.c | 21 +
 1 file changed, 21 insertions(+)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 032f5f2ddf..88cdcb6f91 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -106,6 +106,23 @@ static void virt_flash_map(LoongArchMachineState *lams,
 virt_flash_map1(flash1, VIRT_FLASH1_BASE, VIRT_FLASH1_SIZE, sysmem);
 }
 
+static void fdt_add_cpuic_node(LoongArchMachineState *lams,
+   uint32_t *cpuintc_phandle)
+{
+MachineState *ms = MACHINE(lams);
+char *nodename;
+
+*cpuintc_phandle = qemu_fdt_alloc_phandle(ms->fdt);
+nodename = g_strdup_printf("/cpuic");
+qemu_fdt_add_subnode(ms->fdt, nodename);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *cpuintc_phandle);
+qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
+"loongson,cpu-interrupt-controller");
+qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 1);
+g_free(nodename);
+}
+
 static void fdt_add_flash_node(LoongArchMachineState *lams)
 {
 MachineState *ms = MACHINE(lams);
@@ -528,6 +545,7 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
 CPULoongArchState *env;
 CPUState *cpu_state;
 int cpu, pin, i, start, num;
+uint32_t cpuintc_phandle;
 
 /*
  * The connection of interrupts:
@@ -562,6 +580,9 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
 memory_region_add_subregion(>system_iocsr, MAIL_SEND_ADDR,
sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 1));
 
+/* Add cpu interrupt-controller */
+fdt_add_cpuic_node(lams, _phandle);
+
 for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
 cpu_state = qemu_get_cpu(cpu);
 cpudev = DEVICE(cpu_state);
-- 
2.25.1




[PULL v2 05/17] hw/loongarch: Init efi_system_table

2024-04-28 Thread Song Gao
Add init_systab and set boot_info->a2

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-6-gaos...@loongson.cn>
---
 hw/loongarch/boot.c | 22 +
 include/hw/loongarch/boot.h | 48 +
 2 files changed, 70 insertions(+)

diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index 127085bcc4..59889dbc90 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -63,6 +63,25 @@ static const unsigned int slave_boot_code[] = {
 0x4c20,   /* jirl   $zero, $ra,0   */
 };
 
+static void init_systab(struct loongarch_boot_info *info, void *p, void *start)
+{
+struct efi_system_table *systab = p;
+
+info->a2 = p - start;
+
+systab->hdr.signature = EFI_SYSTEM_TABLE_SIGNATURE;
+systab->hdr.revision = EFI_SPECIFICATION_VERSION;
+systab->hdr.revision = sizeof(struct efi_system_table),
+systab->fw_revision = FW_VERSION << 16 | FW_PATCHLEVEL << 8;
+systab->runtime = 0;
+systab->boottime = 0;
+systab->nr_tables = 0;
+
+p += ROUND_UP(sizeof(struct efi_system_table), 64 * KiB);
+
+systab->tables = p;
+}
+
 static void init_cmdline(struct loongarch_boot_info *info, void *p, void 
*start)
 {
 hwaddr cmdline_addr = p - start;
@@ -134,6 +153,7 @@ static void reset_load_elf(void *opaque)
if (cpu == LOONGARCH_CPU(first_cpu)) {
 env->gpr[4] = env->boot_info->a0;
 env->gpr[5] = env->boot_info->a1;
+env->gpr[6] = env->boot_info->a2;
 }
 cpu_set_pc(CPU(cpu), env->elf_address);
 }
@@ -178,6 +198,8 @@ static void init_boot_rom(struct loongarch_boot_info *info, 
void *p)
 
 init_cmdline(info, p, start);
 p += COMMAND_LINE_SIZE;
+
+init_systab(info, p, start);
 }
 
 static void loongarch_direct_kernel_boot(struct loongarch_boot_info *info)
diff --git a/include/hw/loongarch/boot.h b/include/hw/loongarch/boot.h
index 3275c1e295..cf0e4d4f91 100644
--- a/include/hw/loongarch/boot.h
+++ b/include/hw/loongarch/boot.h
@@ -8,6 +8,54 @@
 #ifndef HW_LOONGARCH_BOOT_H
 #define HW_LOONGARCH_BOOT_H
 
+/* UEFI 2.10 */
+#define EFI_SYSTEM_TABLE_SIGNATURE   0x5453595320494249
+#define EFI_2_100_SYSTEM_TABLE_REVISION  ((2<<16) | (100))
+#define EFI_SPECIFICATION_VERSIONEFI_SYSTEM_TABLE_REVISION
+#define EFI_SYSTEM_TABLE_REVISIONEFI_2_100_SYSTEM_TABLE_REVISION
+
+#define FW_VERSION 0x1
+#define FW_PATCHLEVEL 0x0
+
+typedef struct {
+uint8_t b[16];
+} efi_guid_t QEMU_ALIGNED(8);
+
+struct efi_config_table {
+efi_guid_t guid;
+uint64_t *ptr;
+const char name[16];
+};
+
+typedef struct {
+uint64_t signature;
+uint32_t revision;
+uint32_t headersize;
+uint32_t crc32;
+uint32_t reserved;
+} efi_table_hdr_t;
+
+struct efi_configuration_table {
+efi_guid_t guid;
+void *table;
+};
+
+struct efi_system_table {
+efi_table_hdr_t hdr;
+uint64_t fw_vendor;/* physical addr of CHAR16 vendor string */
+uint32_t fw_revision;
+uint64_t con_in_handle;
+uint64_t *con_in;
+uint64_t con_out_handle;
+uint64_t *con_out;
+uint64_t stderr_handle;
+uint64_t stderr_placeholder;
+uint64_t *runtime;
+uint64_t *boottime;
+uint64_t nr_tables;
+struct efi_configuration_table *tables;
+};
+
 struct loongarch_boot_info {
 uint64_t ram_size;
 const char *kernel_filename;
-- 
2.25.1




[PULL v2 01/17] hw/loongarch: Move boot functions to boot.c

2024-04-28 Thread Song Gao
Move some boot functions to boot.c and struct
loongarch_boot_info into struct LoongArchMachineState.

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Reviewed-by: Philippe Mathieu-Daudé 
Message-Id: <20240426091551.2397867-2-gaos...@loongson.cn>
---
 hw/loongarch/boot.c | 128 
 hw/loongarch/meson.build|   1 +
 hw/loongarch/virt.c | 121 +++---
 include/hw/loongarch/boot.h |  21 ++
 include/hw/loongarch/virt.h |   2 +
 5 files changed, 160 insertions(+), 113 deletions(-)
 create mode 100644 hw/loongarch/boot.c
 create mode 100644 include/hw/loongarch/boot.h

diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
new file mode 100644
index 00..9feed17db3
--- /dev/null
+++ b/hw/loongarch/boot.c
@@ -0,0 +1,128 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * LoongArch boot helper functions.
+ *
+ * Copyright (c) 2023 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "target/loongarch/cpu.h"
+#include "hw/loongarch/virt.h"
+#include "hw/loader.h"
+#include "elf.h"
+#include "qemu/error-report.h"
+#include "sysemu/reset.h"
+#include "sysemu/qtest.h"
+
+static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr)
+{
+return addr & MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS);
+}
+
+static int64_t load_kernel_info(struct loongarch_boot_info *info)
+{
+uint64_t kernel_entry, kernel_low, kernel_high;
+ssize_t kernel_size;
+
+kernel_size = load_elf(info->kernel_filename, NULL,
+   cpu_loongarch_virt_to_phys, NULL,
+   _entry, _low,
+   _high, NULL, 0,
+   EM_LOONGARCH, 1, 0);
+
+if (kernel_size < 0) {
+error_report("could not load kernel '%s': %s",
+ info->kernel_filename,
+ load_elf_strerror(kernel_size));
+exit(1);
+}
+return kernel_entry;
+}
+
+static void reset_load_elf(void *opaque)
+{
+LoongArchCPU *cpu = opaque;
+CPULoongArchState *env = >env;
+
+cpu_reset(CPU(cpu));
+if (env->load_elf) {
+cpu_set_pc(CPU(cpu), env->elf_address);
+}
+}
+
+static void fw_cfg_add_kernel_info(struct loongarch_boot_info *info,
+   FWCfgState *fw_cfg)
+{
+/*
+ * Expose the kernel, the command line, and the initrd in fw_cfg.
+ * We don't process them here at all, it's all left to the
+ * firmware.
+ */
+load_image_to_fw_cfg(fw_cfg,
+ FW_CFG_KERNEL_SIZE, FW_CFG_KERNEL_DATA,
+ info->kernel_filename,
+ false);
+
+if (info->initrd_filename) {
+load_image_to_fw_cfg(fw_cfg,
+ FW_CFG_INITRD_SIZE, FW_CFG_INITRD_DATA,
+ info->initrd_filename, false);
+}
+
+if (info->kernel_cmdline) {
+fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE,
+   strlen(info->kernel_cmdline) + 1);
+fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA,
+  info->kernel_cmdline);
+}
+}
+
+static void loongarch_firmware_boot(LoongArchMachineState *lams,
+struct loongarch_boot_info *info)
+{
+fw_cfg_add_kernel_info(info, lams->fw_cfg);
+}
+
+static void loongarch_direct_kernel_boot(struct loongarch_boot_info *info)
+{
+int64_t kernel_addr = 0;
+LoongArchCPU *lacpu;
+CPUState *cs;
+
+if (info->kernel_filename) {
+kernel_addr = load_kernel_info(info);
+} else {
+if(!qtest_enabled()) {
+error_report("Need kernel filename\n");
+exit(1);
+}
+}
+
+CPU_FOREACH(cs) {
+lacpu = LOONGARCH_CPU(cs);
+lacpu->env.load_elf = true;
+lacpu->env.elf_address = kernel_addr;
+}
+}
+
+void loongarch_load_kernel(MachineState *ms, struct loongarch_boot_info *info)
+{
+LoongArchMachineState *lams = LOONGARCH_MACHINE(ms);
+int i;
+
+/* register reset function */
+for (i = 0; i < ms->smp.cpus; i++) {
+qemu_register_reset(reset_load_elf, LOONGARCH_CPU(qemu_get_cpu(i)));
+}
+
+info->kernel_filename = ms->kernel_filename;
+info->kernel_cmdline = ms->kernel_cmdline;
+info->initrd_filename = ms->initrd_filename;
+
+if (lams->bios_loaded) {
+loongarch_firmware_boot(lams, info);
+} else {
+loongarch_direct_kernel_boot(info);
+}
+}
diff --git a/hw/loongarch/meson.build b/hw/loongarch/meson.build
index c0421502ab..d306d82c2e 100644
--- a/hw/loongarch/meson.build
+++ b/hw/loongarch/meson.build
@@ -1,6 +1,7 @@
 loongarch_ss = ss.source_set()
 loongarch_ss.add(files(
 'fw_c

[PULL v2 13/17] hw/loongarch: fdt adds pch_msi Controller

2024-04-28 Thread Song Gao
fdt adds pch msi controller, we use 'loongson,pch-msi-1.0'.

See:
https://github.com/torvalds/linux/blob/v6.7/drivers/irqchip/irq-loongson-pch-msi.c
https://lore.kernel.org/r/20200528152757.1028711-6-jiaxun.y...@flygoat.com

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-14-gaos...@loongson.cn>
---
 hw/loongarch/virt.c| 33 -
 include/hw/pci-host/ls7a.h |  1 +
 2 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 5bef161d11..566f86e741 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -173,6 +173,34 @@ static void fdt_add_pch_pic_node(LoongArchMachineState 
*lams,
 g_free(nodename);
 }
 
+static void fdt_add_pch_msi_node(LoongArchMachineState *lams,
+ uint32_t *eiointc_phandle,
+ uint32_t *pch_msi_phandle)
+{
+MachineState *ms = MACHINE(lams);
+char *nodename;
+hwaddr pch_msi_base = VIRT_PCH_MSI_ADDR_LOW;
+hwaddr pch_msi_size = VIRT_PCH_MSI_SIZE;
+
+*pch_msi_phandle = qemu_fdt_alloc_phandle(ms->fdt);
+nodename = g_strdup_printf("/msi@%" PRIx64, pch_msi_base);
+qemu_fdt_add_subnode(ms->fdt, nodename);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *pch_msi_phandle);
+qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
+"loongson,pch-msi-1.0");
+qemu_fdt_setprop_cells(ms->fdt, nodename, "reg",
+   0, pch_msi_base,
+   0, pch_msi_size);
+qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
+  *eiointc_phandle);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "loongson,msi-base-vec",
+  VIRT_PCH_PIC_IRQ_NUM);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "loongson,msi-num-vecs",
+  EXTIOI_IRQS - VIRT_PCH_PIC_IRQ_NUM);
+g_free(nodename);
+}
+
 static void fdt_add_flash_node(LoongArchMachineState *lams)
 {
 MachineState *ms = MACHINE(lams);
@@ -595,7 +623,7 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
 CPULoongArchState *env;
 CPUState *cpu_state;
 int cpu, pin, i, start, num;
-uint32_t cpuintc_phandle, eiointc_phandle, pch_pic_phandle;
+uint32_t cpuintc_phandle, eiointc_phandle, pch_pic_phandle, 
pch_msi_phandle;
 
 /*
  * The connection of interrupts:
@@ -703,6 +731,9 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
   qdev_get_gpio_in(extioi, i + start));
 }
 
+/* Add PCH MSI node */
+fdt_add_pch_msi_node(lams, _phandle, _msi_phandle);
+
 loongarch_devices_init(pch_pic, lams);
 }
 
diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h
index fe260f0183..cd7c9ec7bc 100644
--- a/include/hw/pci-host/ls7a.h
+++ b/include/hw/pci-host/ls7a.h
@@ -25,6 +25,7 @@
 #define VIRT_IOAPIC_REG_BASE (VIRT_PCH_REG_BASE)
 #define VIRT_PCH_MSI_ADDR_LOW0x2FF0UL
 #define VIRT_PCH_REG_SIZE0x400
+#define VIRT_PCH_MSI_SIZE0x8
 
 /*
  * GSI_BASE is hard-coded with 64 in linux kernel, else kernel fails to boot
-- 
2.25.1




[PULL v2 00/17] loongarch-to-apply queue

2024-04-28 Thread Song Gao
The following changes since commit fd87be1dada5672f877e03c2ca8504458292c479:

  Merge tag 'accel-20240426' of https://github.com/philmd/qemu into staging 
(2024-04-26 15:28:13 -0700)

are available in the Git repository at:

  https://gitlab.com/gaosong/qemu.git tags/pull-loongarch-20240429

for you to fetch changes up to 841ef2c9df5317e32de590424b0c5c36fbb4de78:

  hw/loongarch: Add cells missing from rtc node (2024-04-29 10:25:56 +0800)


Add boot LoongArch elf kernel with FDT

v2: Fix 'make check-tcg' failed.


Song Gao (17):
  hw/loongarch: Move boot functions to boot.c
  hw/loongarch: Add load initrd
  hw/loongarch: Add slave cpu boot_code
  hw/loongarch: Add init_cmdline
  hw/loongarch: Init efi_system_table
  hw/loongarch: Init efi_boot_memmap table
  hw/loongarch: Init efi_initrd table
  hw/loongarch: Init efi_fdt table
  hw/loongarch: Fix fdt memory node wrong 'reg'
  hw/loongarch: fdt adds cpu interrupt controller node
  hw/loongarch: fdt adds Extend I/O Interrupt Controller
  hw/loongarch: fdt adds pch_pic Controller
  hw/loongarch: fdt adds pch_msi Controller
  hw/loongarch: fdt adds pcie irq_map node
  hw/loongarch: fdt remove unused irqchip node
  hw/loongarch: Add cells missing from uart node
  hw/loongarch: Add cells missing from rtc node

 hw/loongarch/boot.c| 336 ++
 hw/loongarch/meson.build   |   1 +
 hw/loongarch/virt.c| 365 +
 include/hw/intc/loongarch_extioi.h |   1 +
 include/hw/loongarch/boot.h| 109 +++
 include/hw/loongarch/virt.h|  16 ++
 include/hw/pci-host/ls7a.h |   2 +
 target/loongarch/cpu.h |   2 +
 8 files changed, 670 insertions(+), 162 deletions(-)
 create mode 100644 hw/loongarch/boot.c
 create mode 100644 include/hw/loongarch/boot.h




[PULL 12/17] hw/loongarch: fdt adds pch_pic Controller

2024-04-28 Thread Song Gao
fdt adds pch pic controller, we use 'loongson,pch-pic-1.0'

See:
https://github.com/torvalds/linux/blob/v6.7/drivers/irqchip/irq-loongson-pch-pic.c
https://lore.kernel.org/r/20200528152757.1028711-4-jiaxun.y...@flygoat.com

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-13-gaos...@loongson.cn>
---
 hw/loongarch/virt.c| 30 +-
 include/hw/pci-host/ls7a.h |  1 +
 2 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 094b9d2e60..5bef161d11 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -148,6 +148,31 @@ static void fdt_add_eiointc_node(LoongArchMachineState 
*lams,
 g_free(nodename);
 }
 
+static void fdt_add_pch_pic_node(LoongArchMachineState *lams,
+ uint32_t *eiointc_phandle,
+ uint32_t *pch_pic_phandle)
+{
+MachineState *ms = MACHINE(lams);
+char *nodename;
+hwaddr pch_pic_base = VIRT_PCH_REG_BASE;
+hwaddr pch_pic_size = VIRT_PCH_REG_SIZE;
+
+*pch_pic_phandle = qemu_fdt_alloc_phandle(ms->fdt);
+nodename = g_strdup_printf("/platic@%" PRIx64, pch_pic_base);
+qemu_fdt_add_subnode(ms->fdt, nodename);
+qemu_fdt_setprop_cell(ms->fdt,  nodename, "phandle", *pch_pic_phandle);
+qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
+"loongson,pch-pic-1.0");
+qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0,
+   pch_pic_base, 0, pch_pic_size);
+qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 2);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
+  *eiointc_phandle);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "loongson,pic-base-vec", 0);
+g_free(nodename);
+}
+
 static void fdt_add_flash_node(LoongArchMachineState *lams)
 {
 MachineState *ms = MACHINE(lams);
@@ -570,7 +595,7 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
 CPULoongArchState *env;
 CPUState *cpu_state;
 int cpu, pin, i, start, num;
-uint32_t cpuintc_phandle, eiointc_phandle;
+uint32_t cpuintc_phandle, eiointc_phandle, pch_pic_phandle;
 
 /*
  * The connection of interrupts:
@@ -661,6 +686,9 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
 qdev_connect_gpio_out(DEVICE(d), i, qdev_get_gpio_in(extioi, i));
 }
 
+/* Add PCH PIC node */
+fdt_add_pch_pic_node(lams, _phandle, _pic_phandle);
+
 pch_msi = qdev_new(TYPE_LOONGARCH_PCH_MSI);
 start   =  num;
 num = EXTIOI_IRQS - start;
diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h
index e753449593..fe260f0183 100644
--- a/include/hw/pci-host/ls7a.h
+++ b/include/hw/pci-host/ls7a.h
@@ -24,6 +24,7 @@
 #define VIRT_PCH_REG_BASE0x1000UL
 #define VIRT_IOAPIC_REG_BASE (VIRT_PCH_REG_BASE)
 #define VIRT_PCH_MSI_ADDR_LOW0x2FF0UL
+#define VIRT_PCH_REG_SIZE0x400
 
 /*
  * GSI_BASE is hard-coded with 64 in linux kernel, else kernel fails to boot
-- 
2.25.1




[PULL 16/17] hw/loongarch: Add cells missing from uart node

2024-04-28 Thread Song Gao
uart node need interrupts and interrupt-parent cells.

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-17-gaos...@loongson.cn>
---
 hw/loongarch/virt.c | 9 +++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 48f73edd8e..dbd7928759 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -245,7 +245,8 @@ static void fdt_add_rtc_node(LoongArchMachineState *lams)
 g_free(nodename);
 }
 
-static void fdt_add_uart_node(LoongArchMachineState *lams)
+static void fdt_add_uart_node(LoongArchMachineState *lams,
+  uint32_t *pch_pic_phandle)
 {
 char *nodename;
 hwaddr base = VIRT_UART_BASE;
@@ -258,6 +259,10 @@ static void fdt_add_uart_node(LoongArchMachineState *lams)
 qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0x0, base, 0x0, size);
 qemu_fdt_setprop_cell(ms->fdt, nodename, "clock-frequency", 1);
 qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", nodename);
+qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts",
+   VIRT_UART_IRQ - VIRT_GSI_BASE, 0x4);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
+  *pch_pic_phandle);
 g_free(nodename);
 }
 
@@ -630,7 +635,7 @@ static void loongarch_devices_init(DeviceState *pch_pic,
qdev_get_gpio_in(pch_pic,
 VIRT_UART_IRQ - VIRT_GSI_BASE),
115200, serial_hd(0), DEVICE_LITTLE_ENDIAN);
-fdt_add_uart_node(lams);
+fdt_add_uart_node(lams, pch_pic_phandle);
 
 /* Network init */
 pci_init_nic_devices(pci_bus, mc->default_nic);
-- 
2.25.1




[PULL 05/17] hw/loongarch: Init efi_system_table

2024-04-28 Thread Song Gao
Add init_systab and set boot_info->a2

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-6-gaos...@loongson.cn>
---
 hw/loongarch/boot.c | 22 +
 include/hw/loongarch/boot.h | 48 +
 2 files changed, 70 insertions(+)

diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index aca5ad388e..46a241a04c 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -63,6 +63,25 @@ static const unsigned int slave_boot_code[] = {
 0x4c20,   /* jirl   $zero, $ra,0   */
 };
 
+static void init_systab(struct loongarch_boot_info *info, void *p, void *start)
+{
+struct efi_system_table *systab = p;
+
+info->a2 = (uint64_t)p - (uint64_t)start;
+
+systab->hdr.signature = EFI_SYSTEM_TABLE_SIGNATURE;
+systab->hdr.revision = EFI_SPECIFICATION_VERSION;
+systab->hdr.revision = sizeof(struct efi_system_table),
+systab->fw_revision = FW_VERSION << 16 | FW_PATCHLEVEL << 8;
+systab->runtime = 0;
+systab->boottime = 0;
+systab->nr_tables = 0;
+
+p += ROUND_UP(sizeof(struct efi_system_table), 64 * KiB);
+
+systab->tables = p;
+}
+
 static void init_cmdline(struct loongarch_boot_info *info, void *p, void 
*start)
 {
 hwaddr cmdline_addr = (hwaddr)p - (hwaddr)start;
@@ -135,6 +154,7 @@ static void reset_load_elf(void *opaque)
if (cpu == LOONGARCH_CPU(first_cpu)) {
 env->gpr[4] = env->boot_info->a0;
 env->gpr[5] = env->boot_info->a1;
+env->gpr[6] = env->boot_info->a2;
 }
 cpu_set_pc(CPU(cpu), env->elf_address);
 }
@@ -179,6 +199,8 @@ static void init_boot_rom(struct loongarch_boot_info *info, 
void *p)
 
 init_cmdline(info, p, start);
 p += COMMAND_LINE_SIZE;
+
+init_systab(info, p, start);
 }
 
 static void loongarch_direct_kernel_boot(struct loongarch_boot_info *info)
diff --git a/include/hw/loongarch/boot.h b/include/hw/loongarch/boot.h
index 3275c1e295..cf0e4d4f91 100644
--- a/include/hw/loongarch/boot.h
+++ b/include/hw/loongarch/boot.h
@@ -8,6 +8,54 @@
 #ifndef HW_LOONGARCH_BOOT_H
 #define HW_LOONGARCH_BOOT_H
 
+/* UEFI 2.10 */
+#define EFI_SYSTEM_TABLE_SIGNATURE   0x5453595320494249
+#define EFI_2_100_SYSTEM_TABLE_REVISION  ((2<<16) | (100))
+#define EFI_SPECIFICATION_VERSIONEFI_SYSTEM_TABLE_REVISION
+#define EFI_SYSTEM_TABLE_REVISIONEFI_2_100_SYSTEM_TABLE_REVISION
+
+#define FW_VERSION 0x1
+#define FW_PATCHLEVEL 0x0
+
+typedef struct {
+uint8_t b[16];
+} efi_guid_t QEMU_ALIGNED(8);
+
+struct efi_config_table {
+efi_guid_t guid;
+uint64_t *ptr;
+const char name[16];
+};
+
+typedef struct {
+uint64_t signature;
+uint32_t revision;
+uint32_t headersize;
+uint32_t crc32;
+uint32_t reserved;
+} efi_table_hdr_t;
+
+struct efi_configuration_table {
+efi_guid_t guid;
+void *table;
+};
+
+struct efi_system_table {
+efi_table_hdr_t hdr;
+uint64_t fw_vendor;/* physical addr of CHAR16 vendor string */
+uint32_t fw_revision;
+uint64_t con_in_handle;
+uint64_t *con_in;
+uint64_t con_out_handle;
+uint64_t *con_out;
+uint64_t stderr_handle;
+uint64_t stderr_placeholder;
+uint64_t *runtime;
+uint64_t *boottime;
+uint64_t nr_tables;
+struct efi_configuration_table *tables;
+};
+
 struct loongarch_boot_info {
 uint64_t ram_size;
 const char *kernel_filename;
-- 
2.25.1




[PULL 11/17] hw/loongarch: fdt adds Extend I/O Interrupt Controller

2024-04-28 Thread Song Gao
fdt adds Extend I/O Interrupt Controller,
we use 'loongson,ls2k2000-eiointc'.

See:
https://github.com/torvalds/linux/blob/v6.7/drivers/irqchip/irq-loongson-eiointc.c
https://lore.kernel.org/r/764e02d924094580ac0f1d15535f4b98308705c6.1683279769.git.zhoubin...@loongson.cn

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-12-gaos...@loongson.cn>
---
 hw/loongarch/virt.c| 30 +-
 include/hw/intc/loongarch_extioi.h |  1 +
 2 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 88cdcb6f91..094b9d2e60 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -123,6 +123,31 @@ static void fdt_add_cpuic_node(LoongArchMachineState *lams,
 g_free(nodename);
 }
 
+static void fdt_add_eiointc_node(LoongArchMachineState *lams,
+  uint32_t *cpuintc_phandle,
+  uint32_t *eiointc_phandle)
+{
+MachineState *ms = MACHINE(lams);
+char *nodename;
+hwaddr extioi_base = APIC_BASE;
+hwaddr extioi_size = EXTIOI_SIZE;
+
+*eiointc_phandle = qemu_fdt_alloc_phandle(ms->fdt);
+nodename = g_strdup_printf("/eiointc@%" PRIx64, extioi_base);
+qemu_fdt_add_subnode(ms->fdt, nodename);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *eiointc_phandle);
+qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
+"loongson,ls2k2000-eiointc");
+qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 1);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
+  *cpuintc_phandle);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupts", 3);
+qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0x0,
+   extioi_base, 0x0, extioi_size);
+g_free(nodename);
+}
+
 static void fdt_add_flash_node(LoongArchMachineState *lams)
 {
 MachineState *ms = MACHINE(lams);
@@ -545,7 +570,7 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
 CPULoongArchState *env;
 CPUState *cpu_state;
 int cpu, pin, i, start, num;
-uint32_t cpuintc_phandle;
+uint32_t cpuintc_phandle, eiointc_phandle;
 
 /*
  * The connection of interrupts:
@@ -614,6 +639,9 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
 }
 }
 
+/* Add Extend I/O Interrupt Controller node */
+fdt_add_eiointc_node(lams, _phandle, _phandle);
+
 pch_pic = qdev_new(TYPE_LOONGARCH_PCH_PIC);
 num = VIRT_PCH_PIC_IRQ_NUM;
 qdev_prop_set_uint32(pch_pic, "pch_pic_irq_num", num);
diff --git a/include/hw/intc/loongarch_extioi.h 
b/include/hw/intc/loongarch_extioi.h
index a0a46b888c..410c6e1121 100644
--- a/include/hw/intc/loongarch_extioi.h
+++ b/include/hw/intc/loongarch_extioi.h
@@ -39,6 +39,7 @@
 #define EXTIOI_COREISR_END   (0xB20 - APIC_OFFSET)
 #define EXTIOI_COREMAP_START (0xC00 - APIC_OFFSET)
 #define EXTIOI_COREMAP_END   (0xD00 - APIC_OFFSET)
+#define EXTIOI_SIZE  0x800
 
 typedef struct ExtIOICore {
 uint32_t coreisr[EXTIOI_IRQS_GROUP_COUNT];
-- 
2.25.1




[PULL 09/17] hw/loongarch: Fix fdt memory node wrong 'reg'

2024-04-28 Thread Song Gao
The right fdt memory node like [1], not [2]

  [1]
memory@0 {
device_type = "memory";
reg = <0x00 0x00 0x00 0x1000>;
};
  [2]
memory@0 {
device_type = "memory";
reg = <0x02 0x00 0x02 0x1000>;
};

Reviewed-by: Bibo Mao 
Signed-off-by: Song Gao 
Message-Id: <20240426091551.2397867-10-gaos...@loongson.cn>
---
 hw/loongarch/virt.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 42e5df8a24..032f5f2ddf 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -325,7 +325,7 @@ static void fdt_add_memory_node(MachineState *ms,
 char *nodename = g_strdup_printf("/memory@%" PRIx64, base);
 
 qemu_fdt_add_subnode(ms->fdt, nodename);
-qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 2, base, 2, size);
+qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0, base, 0, size);
 qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "memory");
 
 if (ms->numa_state && ms->numa_state->num_nodes) {
-- 
2.25.1




[PULL 13/17] hw/loongarch: fdt adds pch_msi Controller

2024-04-28 Thread Song Gao
fdt adds pch msi controller, we use 'loongson,pch-msi-1.0'.

See:
https://github.com/torvalds/linux/blob/v6.7/drivers/irqchip/irq-loongson-pch-msi.c
https://lore.kernel.org/r/20200528152757.1028711-6-jiaxun.y...@flygoat.com

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-14-gaos...@loongson.cn>
---
 hw/loongarch/virt.c| 33 -
 include/hw/pci-host/ls7a.h |  1 +
 2 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 5bef161d11..566f86e741 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -173,6 +173,34 @@ static void fdt_add_pch_pic_node(LoongArchMachineState 
*lams,
 g_free(nodename);
 }
 
+static void fdt_add_pch_msi_node(LoongArchMachineState *lams,
+ uint32_t *eiointc_phandle,
+ uint32_t *pch_msi_phandle)
+{
+MachineState *ms = MACHINE(lams);
+char *nodename;
+hwaddr pch_msi_base = VIRT_PCH_MSI_ADDR_LOW;
+hwaddr pch_msi_size = VIRT_PCH_MSI_SIZE;
+
+*pch_msi_phandle = qemu_fdt_alloc_phandle(ms->fdt);
+nodename = g_strdup_printf("/msi@%" PRIx64, pch_msi_base);
+qemu_fdt_add_subnode(ms->fdt, nodename);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *pch_msi_phandle);
+qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
+"loongson,pch-msi-1.0");
+qemu_fdt_setprop_cells(ms->fdt, nodename, "reg",
+   0, pch_msi_base,
+   0, pch_msi_size);
+qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
+  *eiointc_phandle);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "loongson,msi-base-vec",
+  VIRT_PCH_PIC_IRQ_NUM);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "loongson,msi-num-vecs",
+  EXTIOI_IRQS - VIRT_PCH_PIC_IRQ_NUM);
+g_free(nodename);
+}
+
 static void fdt_add_flash_node(LoongArchMachineState *lams)
 {
 MachineState *ms = MACHINE(lams);
@@ -595,7 +623,7 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
 CPULoongArchState *env;
 CPUState *cpu_state;
 int cpu, pin, i, start, num;
-uint32_t cpuintc_phandle, eiointc_phandle, pch_pic_phandle;
+uint32_t cpuintc_phandle, eiointc_phandle, pch_pic_phandle, 
pch_msi_phandle;
 
 /*
  * The connection of interrupts:
@@ -703,6 +731,9 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
   qdev_get_gpio_in(extioi, i + start));
 }
 
+/* Add PCH MSI node */
+fdt_add_pch_msi_node(lams, _phandle, _msi_phandle);
+
 loongarch_devices_init(pch_pic, lams);
 }
 
diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h
index fe260f0183..cd7c9ec7bc 100644
--- a/include/hw/pci-host/ls7a.h
+++ b/include/hw/pci-host/ls7a.h
@@ -25,6 +25,7 @@
 #define VIRT_IOAPIC_REG_BASE (VIRT_PCH_REG_BASE)
 #define VIRT_PCH_MSI_ADDR_LOW0x2FF0UL
 #define VIRT_PCH_REG_SIZE0x400
+#define VIRT_PCH_MSI_SIZE0x8
 
 /*
  * GSI_BASE is hard-coded with 64 in linux kernel, else kernel fails to boot
-- 
2.25.1




[PULL 03/17] hw/loongarch: Add slave cpu boot_code

2024-04-28 Thread Song Gao
Load the slave CPU boot code at pflash0 and set
the slave CPU elf_address to VIRT_FLASH0_BASE.

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-4-gaos...@loongson.cn>
---
 hw/loongarch/boot.c | 62 -
 1 file changed, 61 insertions(+), 1 deletion(-)

diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index a9522d6912..d1a8434127 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -15,6 +15,54 @@
 #include "sysemu/reset.h"
 #include "sysemu/qtest.h"
 
+static const unsigned int slave_boot_code[] = {
+  /* Configure reset ebase.*/
+0x0400302c,   /* csrwr  $t0, LOONGARCH_CSR_EENTRY  */
+
+  /* Disable interrupt.*/
+0x0380100c,   /* ori$t0, $zero,0x4 */
+0x04000180,   /* csrxchg$zero, $t0, LOONGARCH_CSR_CRMD */
+
+  /* Clear mailbox.*/
+0x142d,   /* lu12i.w$t1, 1(0x1)*/
+0x038081ad,   /* ori$t1, $t1, CORE_BUF_20  */
+0x06481da0,   /* iocsrwr.d  $zero, $t1 */
+
+  /* Enable IPI interrupt. */
+0x142c,   /* lu12i.w$t0, 1(0x1)*/
+0x0400118c,   /* csrxchg$t0, $t0, LOONGARCH_CSR_ECFG   */
+0x02fffc0c,   /* addi.d $t0, $r0,-1(0xfff) */
+0x142d,   /* lu12i.w$t1, 1(0x1)*/
+0x038011ad,   /* ori$t1, $t1, CORE_EN_OFF  */
+0x064819ac,   /* iocsrwr.w  $t0, $t1   */
+0x142d,   /* lu12i.w$t1, 1(0x1)*/
+0x038081ad,   /* ori$t1, $t1, CORE_BUF_20  */
+
+  /* Wait for wakeup  <.L11>:  */
+0x06488000,   /* idle   0x0*/
+0x0340,   /* andi   $zero, $zero, 0x0  */
+0x064809ac,   /* iocsrrd.w  $t0, $t1   */
+0x43fff59f,   /* beqz   $t0, -12(0x74) # 48 <.L11> */
+
+  /* Read and clear IPI interrupt. */
+0x142d,   /* lu12i.w$t1, 1(0x1)*/
+0x064809ac,   /* iocsrrd.w  $t0, $t1   */
+0x142d,   /* lu12i.w$t1, 1(0x1)*/
+0x038031ad,   /* ori$t1, $t1, CORE_CLEAR_OFF   */
+0x064819ac,   /* iocsrwr.w  $t0, $t1   */
+
+  /* Disable  IPI interrupt.   */
+0x142c,   /* lu12i.w$t0, 1(0x1)*/
+0x04001180,   /* csrxchg$zero, $t0, LOONGARCH_CSR_ECFG */
+
+  /* Read mail buf and jump to specified entry */
+0x142d,   /* lu12i.w$t1, 1(0x1)*/
+0x038081ad,   /* ori$t1, $t1, CORE_BUF_20  */
+0x06480dac,   /* iocsrrd.d  $t0, $t1   */
+0x00150181,   /* move   $ra, $t0   */
+0x4c20,   /* jirl   $zero, $ra,0   */
+};
+
 static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr)
 {
 return addr & MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS);
@@ -126,11 +174,23 @@ static void loongarch_direct_kernel_boot(struct 
loongarch_boot_info *info)
 }
 }
 
+/* Load slave boot code at pflash0 . */
+void *boot_code = g_malloc0(VIRT_FLASH0_SIZE);
+memcpy(boot_code, _boot_code, sizeof(slave_boot_code));
+rom_add_blob_fixed("boot_code", boot_code, VIRT_FLASH0_SIZE, 
VIRT_FLASH0_BASE);
+
 CPU_FOREACH(cs) {
 lacpu = LOONGARCH_CPU(cs);
 lacpu->env.load_elf = true;
-lacpu->env.elf_address = kernel_addr;
+if (cs == first_cpu) {
+lacpu->env.elf_address = kernel_addr;
+} else {
+lacpu->env.elf_address = VIRT_FLASH0_BASE;
+}
+lacpu->env.boot_info = info;
 }
+
+g_free(boot_code);
 }
 
 void loongarch_load_kernel(MachineState *ms, struct loongarch_boot_info *info)
-- 
2.25.1




[PULL 17/17] hw/loongarch: Add cells missing from rtc node

2024-04-28 Thread Song Gao
rtc node need interrupts and interrupt-parent cells.

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-18-gaos...@loongson.cn>
---
 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 dbd7928759..c0999878df 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -231,7 +231,8 @@ static void fdt_add_flash_node(LoongArchMachineState *lams)
 g_free(nodename);
 }
 
-static void fdt_add_rtc_node(LoongArchMachineState *lams)
+static void fdt_add_rtc_node(LoongArchMachineState *lams,
+ uint32_t *pch_pic_phandle)
 {
 char *nodename;
 hwaddr base = VIRT_RTC_REG_BASE;
@@ -240,8 +241,13 @@ static void fdt_add_rtc_node(LoongArchMachineState *lams)
 
 nodename = g_strdup_printf("/rtc@%" PRIx64, base);
 qemu_fdt_add_subnode(ms->fdt, nodename);
-qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", 
"loongson,ls7a-rtc");
+qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
+"loongson,ls7a-rtc");
 qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", 2, base, 2, size);
+qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts",
+   VIRT_RTC_IRQ - VIRT_GSI_BASE , 0x4);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
+  *pch_pic_phandle);
 g_free(nodename);
 }
 
@@ -648,7 +654,7 @@ static void loongarch_devices_init(DeviceState *pch_pic,
 sysbus_create_simple("ls7a_rtc", VIRT_RTC_REG_BASE,
  qdev_get_gpio_in(pch_pic,
  VIRT_RTC_IRQ - VIRT_GSI_BASE));
-fdt_add_rtc_node(lams);
+fdt_add_rtc_node(lams, pch_pic_phandle);
 
 /* acpi ged */
 lams->acpi_ged = create_acpi_ged(pch_pic, lams);
-- 
2.25.1




[PULL 08/17] hw/loongarch: Init efi_fdt table

2024-04-28 Thread Song Gao
The efi_system_table adds a efi_fdt configuration table.

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-9-gaos...@loongson.cn>
---
 hw/loongarch/boot.c | 11 +++
 hw/loongarch/virt.c |  6 ++
 include/hw/loongarch/boot.h |  4 
 include/hw/loongarch/virt.h |  2 ++
 4 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index 1f6cb8ddd7..82d171c318 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -113,6 +113,16 @@ static void init_efi_initrd_table(struct efi_system_table 
*systab,
 initrd_table->size = initrd_size;
 }
 
+static void init_efi_fdt_table(struct efi_system_table *systab)
+{
+efi_guid_t tbl_guid = DEVICE_TREE_GUID;
+
+/* efi_configuration_table 3 */
+guidcpy(>tables[2].guid, _guid);
+systab->tables[2].table = (void *)FDT_BASE;
+systab->nr_tables = 3;
+}
+
 static void init_systab(struct loongarch_boot_info *info, void *p, void *start)
 {
 void *bp_tables_start;
@@ -138,6 +148,7 @@ static void init_systab(struct loongarch_boot_info *info, 
void *p, void *start)
   sizeof(efi_memory_desc_t) * memmap_entries, 64 * KiB);
 init_efi_initrd_table(systab, p, start);
 p += ROUND_UP(sizeof(struct efi_initrd), 64 * KiB);
+init_efi_fdt_table(systab);
 
 systab->tables = (struct efi_configuration_table *)(bp_tables_start - 
start);
 }
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 708aa8bc60..42e5df8a24 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -727,7 +727,6 @@ static void loongarch_init(MachineState *machine)
 int nb_numa_nodes = machine->numa_state->num_nodes;
 NodeInfo *numa_info = machine->numa_state->nodes;
 int i;
-hwaddr fdt_base;
 const CPUArchIdList *possible_cpus;
 MachineClass *mc = MACHINE_GET_CLASS(machine);
 CPUState *cpu;
@@ -857,12 +856,11 @@ static void loongarch_init(MachineState *machine)
  * Put the FDT into the memory map as a ROM image: this will ensure
  * the FDT is copied again upon reset, even if addr points into RAM.
  */
-fdt_base = 1 * MiB;
 qemu_fdt_dumpdtb(machine->fdt, lams->fdt_size);
-rom_add_blob_fixed_as("fdt", machine->fdt, lams->fdt_size, fdt_base,
+rom_add_blob_fixed_as("fdt", machine->fdt, lams->fdt_size, FDT_BASE,
   _space_memory);
 qemu_register_reset_nosnapshotload(qemu_fdt_randomize_seeds,
-rom_ptr_for_as(_space_memory, fdt_base, lams->fdt_size));
+rom_ptr_for_as(_space_memory, FDT_BASE, lams->fdt_size));
 
 lams->bootinfo.ram_size = ram_size;
 loongarch_load_kernel(machine, >bootinfo);
diff --git a/include/hw/loongarch/boot.h b/include/hw/loongarch/boot.h
index 42d1ee3663..4ebcc89dcf 100644
--- a/include/hw/loongarch/boot.h
+++ b/include/hw/loongarch/boot.h
@@ -34,6 +34,10 @@ typedef struct {
 EFI_GUID(0x5568e427, 0x68fc, 0x4f3d,  0xac, 0x74, \
  0xca, 0x55, 0x52, 0x31, 0xcc, 0x68)
 
+#define DEVICE_TREE_GUID \
+EFI_GUID(0xb1b621d5, 0xf19c, 0x41a5,  0x83, 0x0b, \
+ 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0)
+
 struct efi_config_table {
 efi_guid_t guid;
 uint64_t *ptr;
diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h
index 8a9fe4053d..4e14bf6060 100644
--- a/include/hw/loongarch/virt.h
+++ b/include/hw/loongarch/virt.h
@@ -35,6 +35,8 @@
 
 #define COMMAND_LINE_SIZE   512
 
+#define FDT_BASE0x10
+
 extern struct memmap_entry *memmap_table;
 extern unsigned memmap_entries;
 
-- 
2.25.1




[PULL 10/17] hw/loongarch: fdt adds cpu interrupt controller node

2024-04-28 Thread Song Gao
fdt adds cpu interrupt controller node,
we use 'loongson,cpu-interrupt-controller'.

See:
https://github.com/torvalds/linux/blob/v6.7/drivers/irqchip/irq-loongarch-cpu.c
https://lore.kernel.org/r/20221114113824.1880-2-liupei...@loongson.cn

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-11-gaos...@loongson.cn>
---
 hw/loongarch/virt.c | 21 +
 1 file changed, 21 insertions(+)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 032f5f2ddf..88cdcb6f91 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -106,6 +106,23 @@ static void virt_flash_map(LoongArchMachineState *lams,
 virt_flash_map1(flash1, VIRT_FLASH1_BASE, VIRT_FLASH1_SIZE, sysmem);
 }
 
+static void fdt_add_cpuic_node(LoongArchMachineState *lams,
+   uint32_t *cpuintc_phandle)
+{
+MachineState *ms = MACHINE(lams);
+char *nodename;
+
+*cpuintc_phandle = qemu_fdt_alloc_phandle(ms->fdt);
+nodename = g_strdup_printf("/cpuic");
+qemu_fdt_add_subnode(ms->fdt, nodename);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *cpuintc_phandle);
+qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
+"loongson,cpu-interrupt-controller");
+qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 1);
+g_free(nodename);
+}
+
 static void fdt_add_flash_node(LoongArchMachineState *lams)
 {
 MachineState *ms = MACHINE(lams);
@@ -528,6 +545,7 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
 CPULoongArchState *env;
 CPUState *cpu_state;
 int cpu, pin, i, start, num;
+uint32_t cpuintc_phandle;
 
 /*
  * The connection of interrupts:
@@ -562,6 +580,9 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
 memory_region_add_subregion(>system_iocsr, MAIL_SEND_ADDR,
sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 1));
 
+/* Add cpu interrupt-controller */
+fdt_add_cpuic_node(lams, _phandle);
+
 for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
 cpu_state = qemu_get_cpu(cpu);
 cpudev = DEVICE(cpu_state);
-- 
2.25.1




[PULL 14/17] hw/loongarch: fdt adds pcie irq_map node

2024-04-28 Thread Song Gao
This patch adds pcie irq_map node for FDT.

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-15-gaos...@loongson.cn>
---
 hw/loongarch/virt.c | 73 ++---
 1 file changed, 69 insertions(+), 4 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 566f86e741..91a55a81b6 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -352,7 +352,62 @@ static void fdt_add_fw_cfg_node(const 
LoongArchMachineState *lams)
 g_free(nodename);
 }
 
-static void fdt_add_pcie_node(const LoongArchMachineState *lams)
+static void fdt_add_pcie_irq_map_node(const LoongArchMachineState *lams,
+  char *nodename,
+  uint32_t *pch_pic_phandle)
+{
+int pin, dev;
+uint32_t irq_map_stride = 0;
+uint32_t full_irq_map[GPEX_NUM_IRQS *GPEX_NUM_IRQS * 10] = {};
+uint32_t *irq_map = full_irq_map;
+const MachineState *ms = MACHINE(lams);
+
+/* This code creates a standard swizzle of interrupts such that
+ * each device's first interrupt is based on it's PCI_SLOT number.
+ * (See pci_swizzle_map_irq_fn())
+ *
+ * We only need one entry per interrupt in the table (not one per
+ * possible slot) seeing the interrupt-map-mask will allow the table
+ * to wrap to any number of devices.
+ */
+
+for (dev = 0; dev < GPEX_NUM_IRQS; dev++) {
+int devfn = dev * 0x8;
+
+for (pin = 0; pin  < GPEX_NUM_IRQS; pin++) {
+int irq_nr = 16 + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_IRQS);
+int i = 0;
+
+/* Fill PCI address cells */
+irq_map[i] = cpu_to_be32(devfn << 8);
+i += 3;
+
+/* Fill PCI Interrupt cells */
+irq_map[i] = cpu_to_be32(pin + 1);
+i += 1;
+
+/* Fill interrupt controller phandle and cells */
+irq_map[i++] = cpu_to_be32(*pch_pic_phandle);
+irq_map[i++] = cpu_to_be32(irq_nr);
+
+if (!irq_map_stride) {
+irq_map_stride = i;
+}
+irq_map += irq_map_stride;
+}
+}
+
+
+qemu_fdt_setprop(ms->fdt, nodename, "interrupt-map", full_irq_map,
+ GPEX_NUM_IRQS * GPEX_NUM_IRQS *
+ irq_map_stride * sizeof(uint32_t));
+qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupt-map-mask",
+ 0x1800, 0, 0, 0x7);
+}
+
+static void fdt_add_pcie_node(const LoongArchMachineState *lams,
+  uint32_t *pch_pic_phandle,
+  uint32_t *pch_msi_phandle)
 {
 char *nodename;
 hwaddr base_mmio = VIRT_PCI_MEM_BASE;
@@ -383,6 +438,11 @@ static void fdt_add_pcie_node(const LoongArchMachineState 
*lams)
  2, base_pio, 2, size_pio,
  1, FDT_PCI_RANGE_MMIO, 2, base_mmio,
  2, base_mmio, 2, size_mmio);
+qemu_fdt_setprop_cells(ms->fdt, nodename, "msi-map",
+   0, *pch_msi_phandle, 0, 0x1);
+
+fdt_add_pcie_irq_map_node(lams, nodename, pch_pic_phandle);
+
 g_free(nodename);
 }
 
@@ -542,7 +602,10 @@ static DeviceState *create_platform_bus(DeviceState 
*pch_pic)
 return dev;
 }
 
-static void loongarch_devices_init(DeviceState *pch_pic, LoongArchMachineState 
*lams)
+static void loongarch_devices_init(DeviceState *pch_pic,
+   LoongArchMachineState *lams,
+   uint32_t *pch_pic_phandle,
+   uint32_t *pch_msi_phandle)
 {
 MachineClass *mc = MACHINE_GET_CLASS(lams);
 DeviceState *gpex_dev;
@@ -588,6 +651,9 @@ static void loongarch_devices_init(DeviceState *pch_pic, 
LoongArchMachineState *
 gpex_set_irq_num(GPEX_HOST(gpex_dev), i, 16 + i);
 }
 
+/* Add pcie node */
+fdt_add_pcie_node(lams, pch_pic_phandle, pch_msi_phandle);
+
 serial_mm_init(get_system_memory(), VIRT_UART_BASE, 0,
qdev_get_gpio_in(pch_pic,
 VIRT_UART_IRQ - VIRT_GSI_BASE),
@@ -734,7 +800,7 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
 /* Add PCH MSI node */
 fdt_add_pch_msi_node(lams, _phandle, _msi_phandle);
 
-loongarch_devices_init(pch_pic, lams);
+loongarch_devices_init(pch_pic, lams, _pic_phandle, _msi_phandle);
 }
 
 static void loongarch_firmware_init(LoongArchMachineState *lams)
@@ -956,7 +1022,6 @@ static void loongarch_init(MachineState *machine)
 lams->powerdown_notifier.notify = virt_powerdown_req;
 qemu_register_powerdown_notifier(>powerdown_notifier);
 
-fdt_add_pcie_node(lams);
 /*
  * Since lowmem region starts from 0 and Linux kernel legacy start address
  * at 2 MiB, FDT base address is located at 1 MiB to avoid NULL pointer
-- 
2.25.1




[PULL 01/17] hw/loongarch: Move boot functions to boot.c

2024-04-28 Thread Song Gao
Move some boot functions to boot.c and struct
loongarch_boot_info into struct LoongArchMachineState.

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Reviewed-by: Philippe Mathieu-Daudé 
Message-Id: <20240426091551.2397867-2-gaos...@loongson.cn>
---
 hw/loongarch/boot.c | 128 
 hw/loongarch/meson.build|   1 +
 hw/loongarch/virt.c | 121 +++---
 include/hw/loongarch/boot.h |  21 ++
 include/hw/loongarch/virt.h |   2 +
 5 files changed, 160 insertions(+), 113 deletions(-)
 create mode 100644 hw/loongarch/boot.c
 create mode 100644 include/hw/loongarch/boot.h

diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
new file mode 100644
index 00..9feed17db3
--- /dev/null
+++ b/hw/loongarch/boot.c
@@ -0,0 +1,128 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * LoongArch boot helper functions.
+ *
+ * Copyright (c) 2023 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "target/loongarch/cpu.h"
+#include "hw/loongarch/virt.h"
+#include "hw/loader.h"
+#include "elf.h"
+#include "qemu/error-report.h"
+#include "sysemu/reset.h"
+#include "sysemu/qtest.h"
+
+static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr)
+{
+return addr & MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS);
+}
+
+static int64_t load_kernel_info(struct loongarch_boot_info *info)
+{
+uint64_t kernel_entry, kernel_low, kernel_high;
+ssize_t kernel_size;
+
+kernel_size = load_elf(info->kernel_filename, NULL,
+   cpu_loongarch_virt_to_phys, NULL,
+   _entry, _low,
+   _high, NULL, 0,
+   EM_LOONGARCH, 1, 0);
+
+if (kernel_size < 0) {
+error_report("could not load kernel '%s': %s",
+ info->kernel_filename,
+ load_elf_strerror(kernel_size));
+exit(1);
+}
+return kernel_entry;
+}
+
+static void reset_load_elf(void *opaque)
+{
+LoongArchCPU *cpu = opaque;
+CPULoongArchState *env = >env;
+
+cpu_reset(CPU(cpu));
+if (env->load_elf) {
+cpu_set_pc(CPU(cpu), env->elf_address);
+}
+}
+
+static void fw_cfg_add_kernel_info(struct loongarch_boot_info *info,
+   FWCfgState *fw_cfg)
+{
+/*
+ * Expose the kernel, the command line, and the initrd in fw_cfg.
+ * We don't process them here at all, it's all left to the
+ * firmware.
+ */
+load_image_to_fw_cfg(fw_cfg,
+ FW_CFG_KERNEL_SIZE, FW_CFG_KERNEL_DATA,
+ info->kernel_filename,
+ false);
+
+if (info->initrd_filename) {
+load_image_to_fw_cfg(fw_cfg,
+ FW_CFG_INITRD_SIZE, FW_CFG_INITRD_DATA,
+ info->initrd_filename, false);
+}
+
+if (info->kernel_cmdline) {
+fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE,
+   strlen(info->kernel_cmdline) + 1);
+fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA,
+  info->kernel_cmdline);
+}
+}
+
+static void loongarch_firmware_boot(LoongArchMachineState *lams,
+struct loongarch_boot_info *info)
+{
+fw_cfg_add_kernel_info(info, lams->fw_cfg);
+}
+
+static void loongarch_direct_kernel_boot(struct loongarch_boot_info *info)
+{
+int64_t kernel_addr = 0;
+LoongArchCPU *lacpu;
+CPUState *cs;
+
+if (info->kernel_filename) {
+kernel_addr = load_kernel_info(info);
+} else {
+if(!qtest_enabled()) {
+error_report("Need kernel filename\n");
+exit(1);
+}
+}
+
+CPU_FOREACH(cs) {
+lacpu = LOONGARCH_CPU(cs);
+lacpu->env.load_elf = true;
+lacpu->env.elf_address = kernel_addr;
+}
+}
+
+void loongarch_load_kernel(MachineState *ms, struct loongarch_boot_info *info)
+{
+LoongArchMachineState *lams = LOONGARCH_MACHINE(ms);
+int i;
+
+/* register reset function */
+for (i = 0; i < ms->smp.cpus; i++) {
+qemu_register_reset(reset_load_elf, LOONGARCH_CPU(qemu_get_cpu(i)));
+}
+
+info->kernel_filename = ms->kernel_filename;
+info->kernel_cmdline = ms->kernel_cmdline;
+info->initrd_filename = ms->initrd_filename;
+
+if (lams->bios_loaded) {
+loongarch_firmware_boot(lams, info);
+} else {
+loongarch_direct_kernel_boot(info);
+}
+}
diff --git a/hw/loongarch/meson.build b/hw/loongarch/meson.build
index c0421502ab..d306d82c2e 100644
--- a/hw/loongarch/meson.build
+++ b/hw/loongarch/meson.build
@@ -1,6 +1,7 @@
 loongarch_ss = ss.source_set()
 loongarch_ss.add(files(
 'fw_c

[PULL 15/17] hw/loongarch: fdt remove unused irqchip node

2024-04-28 Thread Song Gao
This patch removes the unused fdt irqchip node.

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-16-gaos...@loongson.cn>
---
 hw/loongarch/virt.c | 31 +--
 1 file changed, 1 insertion(+), 30 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 91a55a81b6..48f73edd8e 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -446,34 +446,6 @@ static void fdt_add_pcie_node(const LoongArchMachineState 
*lams,
 g_free(nodename);
 }
 
-static void fdt_add_irqchip_node(LoongArchMachineState *lams)
-{
-MachineState *ms = MACHINE(lams);
-char *nodename;
-uint32_t irqchip_phandle;
-
-irqchip_phandle = qemu_fdt_alloc_phandle(ms->fdt);
-qemu_fdt_setprop_cell(ms->fdt, "/", "interrupt-parent", irqchip_phandle);
-
-nodename = g_strdup_printf("/intc@%lx", VIRT_IOAPIC_REG_BASE);
-qemu_fdt_add_subnode(ms->fdt, nodename);
-qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 3);
-qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
-qemu_fdt_setprop_cell(ms->fdt, nodename, "#address-cells", 0x2);
-qemu_fdt_setprop_cell(ms->fdt, nodename, "#size-cells", 0x2);
-qemu_fdt_setprop(ms->fdt, nodename, "ranges", NULL, 0);
-
-qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
-"loongarch,ls7a");
-
-qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
- 2, VIRT_IOAPIC_REG_BASE,
- 2, PCH_PIC_ROUTE_ENTRY_OFFSET);
-
-qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", irqchip_phandle);
-g_free(nodename);
-}
-
 static void fdt_add_memory_node(MachineState *ms,
 uint64_t base, uint64_t size, int node_id)
 {
@@ -1011,8 +983,7 @@ static void loongarch_init(MachineState *machine)
 
 /* Initialize the IO interrupt subsystem */
 loongarch_irq_init(lams);
-fdt_add_irqchip_node(lams);
-platform_bus_add_all_fdt_nodes(machine->fdt, "/intc",
+platform_bus_add_all_fdt_nodes(machine->fdt, "/platic",
VIRT_PLATFORM_BUS_BASEADDRESS,
VIRT_PLATFORM_BUS_SIZE,
VIRT_PLATFORM_BUS_IRQ);
-- 
2.25.1




[PULL 07/17] hw/loongarch: Init efi_initrd table

2024-04-28 Thread Song Gao
The efi_system_table adds a efi_initrd configuration table.

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-8-gaos...@loongson.cn>
---
 hw/loongarch/boot.c | 23 +--
 include/hw/loongarch/boot.h |  9 +
 2 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index 18aae3434d..1f6cb8ddd7 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -15,6 +15,9 @@
 #include "sysemu/reset.h"
 #include "sysemu/qtest.h"
 
+ram_addr_t initrd_offset;
+uint64_t initrd_size;
+
 static const unsigned int slave_boot_code[] = {
   /* Configure reset ebase.*/
 0x0400302c,   /* csrwr  $t0, LOONGARCH_CSR_EENTRY  */
@@ -95,6 +98,21 @@ static void init_efi_boot_memmap(struct efi_system_table 
*systab,
 }
 }
 
+static void init_efi_initrd_table(struct efi_system_table *systab,
+  void *p, void *start)
+{
+efi_guid_t tbl_guid = LINUX_EFI_INITRD_MEDIA_GUID;
+struct efi_initrd *initrd_table  = p;
+
+/* efi_configuration_table 2 */
+guidcpy(>tables[1].guid, _guid);
+systab->tables[1].table = (struct efi_configuration_table *)(p - start);
+systab->nr_tables = 2;
+
+initrd_table->base = initrd_offset;
+initrd_table->size = initrd_size;
+}
+
 static void init_systab(struct loongarch_boot_info *info, void *p, void *start)
 {
 void *bp_tables_start;
@@ -118,6 +136,8 @@ static void init_systab(struct loongarch_boot_info *info, 
void *p, void *start)
 init_efi_boot_memmap(systab, p, start);
 p += ROUND_UP(sizeof(struct efi_boot_memmap) +
   sizeof(efi_memory_desc_t) * memmap_entries, 64 * KiB);
+init_efi_initrd_table(systab, p, start);
+p += ROUND_UP(sizeof(struct efi_initrd), 64 * KiB);
 
 systab->tables = (struct efi_configuration_table *)(bp_tables_start - 
start);
 }
@@ -139,8 +159,7 @@ static uint64_t cpu_loongarch_virt_to_phys(void *opaque, 
uint64_t addr)
 
 static int64_t load_kernel_info(struct loongarch_boot_info *info)
 {
-uint64_t kernel_entry, kernel_low, kernel_high, initrd_size;
-ram_addr_t initrd_offset;
+uint64_t kernel_entry, kernel_low, kernel_high;
 ssize_t kernel_size;
 
 kernel_size = load_elf(info->kernel_filename, NULL,
diff --git a/include/hw/loongarch/boot.h b/include/hw/loongarch/boot.h
index 76622af2e2..42d1ee3663 100644
--- a/include/hw/loongarch/boot.h
+++ b/include/hw/loongarch/boot.h
@@ -30,6 +30,10 @@ typedef struct {
 EFI_GUID(0x800f683f, 0xd08b, 0x423a,  0xa2, 0x93, \
  0x96, 0x5c, 0x3c, 0x6f, 0xe2, 0xb4)
 
+#define LINUX_EFI_INITRD_MEDIA_GUID \
+EFI_GUID(0x5568e427, 0x68fc, 0x4f3d,  0xac, 0x74, \
+ 0xca, 0x55, 0x52, 0x31, 0xcc, 0x68)
+
 struct efi_config_table {
 efi_guid_t guid;
 uint64_t *ptr;
@@ -83,6 +87,11 @@ struct efi_boot_memmap {
 efi_memory_desc_t map[32];
 };
 
+struct efi_initrd {
+uint64_t base;
+uint64_t size;
+};
+
 struct loongarch_boot_info {
 uint64_t ram_size;
 const char *kernel_filename;
-- 
2.25.1




[PULL 02/17] hw/loongarch: Add load initrd

2024-04-28 Thread Song Gao
we load initrd ramdisk after kernel_high address

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-3-gaos...@loongson.cn>
---
 hw/loongarch/boot.c | 29 -
 1 file changed, 28 insertions(+), 1 deletion(-)

diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index 9feed17db3..a9522d6912 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -22,7 +22,8 @@ static uint64_t cpu_loongarch_virt_to_phys(void *opaque, 
uint64_t addr)
 
 static int64_t load_kernel_info(struct loongarch_boot_info *info)
 {
-uint64_t kernel_entry, kernel_low, kernel_high;
+uint64_t kernel_entry, kernel_low, kernel_high, initrd_size;
+ram_addr_t initrd_offset;
 ssize_t kernel_size;
 
 kernel_size = load_elf(info->kernel_filename, NULL,
@@ -37,6 +38,32 @@ static int64_t load_kernel_info(struct loongarch_boot_info 
*info)
  load_elf_strerror(kernel_size));
 exit(1);
 }
+
+if (info->initrd_filename) {
+initrd_size = get_image_size(info->initrd_filename);
+if (initrd_size > 0) {
+initrd_offset = ROUND_UP(kernel_high + 4 * kernel_size, 64 * KiB);
+
+if (initrd_offset + initrd_size > info->ram_size) {
+error_report("memory too small for initial ram disk '%s'",
+ info->initrd_filename);
+exit(1);
+}
+
+initrd_size = load_image_targphys(info->initrd_filename, 
initrd_offset,
+  info->ram_size - initrd_offset);
+}
+
+if (initrd_size == (target_ulong)-1) {
+error_report("could not load initial ram disk '%s'",
+ info->initrd_filename);
+exit(1);
+}
+} else {
+error_report("Need initrd!");
+exit(1);
+}
+
 return kernel_entry;
 }
 
-- 
2.25.1




[PULL 04/17] hw/loongarch: Add init_cmdline

2024-04-28 Thread Song Gao
Add init_cmline and set boot_info->a0, a1

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-5-gaos...@loongson.cn>
---
 hw/loongarch/boot.c | 30 ++
 include/hw/loongarch/virt.h |  2 ++
 target/loongarch/cpu.h  |  2 ++
 3 files changed, 34 insertions(+)

diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index d1a8434127..aca5ad388e 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -63,6 +63,16 @@ static const unsigned int slave_boot_code[] = {
 0x4c20,   /* jirl   $zero, $ra,0   */
 };
 
+static void init_cmdline(struct loongarch_boot_info *info, void *p, void 
*start)
+{
+hwaddr cmdline_addr = (hwaddr)p - (hwaddr)start;
+
+info->a0 = 1;
+info->a1 = cmdline_addr;
+
+memcpy(p, info->kernel_cmdline, COMMAND_LINE_SIZE);
+}
+
 static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr)
 {
 return addr & MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS);
@@ -122,6 +132,10 @@ static void reset_load_elf(void *opaque)
 
 cpu_reset(CPU(cpu));
 if (env->load_elf) {
+   if (cpu == LOONGARCH_CPU(first_cpu)) {
+env->gpr[4] = env->boot_info->a0;
+env->gpr[5] = env->boot_info->a1;
+}
 cpu_set_pc(CPU(cpu), env->elf_address);
 }
 }
@@ -159,8 +173,17 @@ static void loongarch_firmware_boot(LoongArchMachineState 
*lams,
 fw_cfg_add_kernel_info(info, lams->fw_cfg);
 }
 
+static void init_boot_rom(struct loongarch_boot_info *info, void *p)
+{
+void *start = p;
+
+init_cmdline(info, p, start);
+p += COMMAND_LINE_SIZE;
+}
+
 static void loongarch_direct_kernel_boot(struct loongarch_boot_info *info)
 {
+void *p, *bp;
 int64_t kernel_addr = 0;
 LoongArchCPU *lacpu;
 CPUState *cs;
@@ -174,6 +197,12 @@ static void loongarch_direct_kernel_boot(struct 
loongarch_boot_info *info)
 }
 }
 
+/* Load cmdline and system tables at [0 - 1 MiB] */
+p = g_malloc0(1 * MiB);
+bp = p;
+init_boot_rom(info, p);
+rom_add_blob_fixed_as("boot_info", bp, 1 * MiB, 0, _space_memory);
+
 /* Load slave boot code at pflash0 . */
 void *boot_code = g_malloc0(VIRT_FLASH0_SIZE);
 memcpy(boot_code, _boot_code, sizeof(slave_boot_code));
@@ -191,6 +220,7 @@ static void loongarch_direct_kernel_boot(struct 
loongarch_boot_info *info)
 }
 
 g_free(boot_code);
+g_free(bp);
 }
 
 void loongarch_load_kernel(MachineState *ms, struct loongarch_boot_info *info)
diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h
index cf2f2bfb19..d7a074d69f 100644
--- a/include/hw/loongarch/virt.h
+++ b/include/hw/loongarch/virt.h
@@ -33,6 +33,8 @@
 #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)
 
+#define COMMAND_LINE_SIZE   512
+
 struct LoongArchMachineState {
 /*< private >*/
 MachineState parent_obj;
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index abb01b2cc7..c5722670f5 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -359,6 +359,8 @@ typedef struct CPUArchState {
 uint32_t mp_state;
 /* Store ipistate to access from this struct */
 DeviceState *ipistate;
+
+struct loongarch_boot_info *boot_info;
 #endif
 } CPULoongArchState;
 
-- 
2.25.1




[PULL 00/17] loongarch-to-apply queue

2024-04-28 Thread Song Gao
The following changes since commit fd87be1dada5672f877e03c2ca8504458292c479:

  Merge tag 'accel-20240426' of https://github.com/philmd/qemu into staging 
(2024-04-26 15:28:13 -0700)

are available in the Git repository at:

  https://gitlab.com/gaosong/qemu.git tags/pull-loongarch-20240428

for you to fetch changes up to f3c05d222dc9ed3cd10383302ce51ab6cee06a97:

  hw/loongarch: Add cells missing from rtc node (2024-04-28 16:56:05 +0800)


Add boot LoongArch elf kernel with FDT


Song Gao (17):
  hw/loongarch: Move boot functions to boot.c
  hw/loongarch: Add load initrd
  hw/loongarch: Add slave cpu boot_code
  hw/loongarch: Add init_cmdline
  hw/loongarch: Init efi_system_table
  hw/loongarch: Init efi_boot_memmap table
  hw/loongarch: Init efi_initrd table
  hw/loongarch: Init efi_fdt table
  hw/loongarch: Fix fdt memory node wrong 'reg'
  hw/loongarch: fdt adds cpu interrupt controller node
  hw/loongarch: fdt adds Extend I/O Interrupt Controller
  hw/loongarch: fdt adds pch_pic Controller
  hw/loongarch: fdt adds pch_msi Controller
  hw/loongarch: fdt adds pcie irq_map node
  hw/loongarch: fdt remove unused irqchip node
  hw/loongarch: Add cells missing from uart node
  hw/loongarch: Add cells missing from rtc node

 hw/loongarch/boot.c| 337 ++
 hw/loongarch/meson.build   |   1 +
 hw/loongarch/virt.c| 365 +
 include/hw/intc/loongarch_extioi.h |   1 +
 include/hw/loongarch/boot.h| 109 +++
 include/hw/loongarch/virt.h|  16 ++
 include/hw/pci-host/ls7a.h |   2 +
 target/loongarch/cpu.h |   2 +
 8 files changed, 671 insertions(+), 162 deletions(-)
 create mode 100644 hw/loongarch/boot.c
 create mode 100644 include/hw/loongarch/boot.h




[PULL 06/17] hw/loongarch: Init efi_boot_memmap table

2024-04-28 Thread Song Gao
The efi_system_table adds a efi_boot_memmap configuration table.

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240426091551.2397867-7-gaos...@loongson.cn>
---
 hw/loongarch/boot.c | 40 +
 hw/loongarch/virt.c | 11 ++
 include/hw/loongarch/boot.h | 27 +
 include/hw/loongarch/virt.h | 10 ++
 4 files changed, 79 insertions(+), 9 deletions(-)

diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index 46a241a04c..18aae3434d 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -63,8 +63,41 @@ static const unsigned int slave_boot_code[] = {
 0x4c20,   /* jirl   $zero, $ra,0   */
 };
 
+static inline void *guidcpy(void *dst, const void *src)
+{
+return memcpy(dst, src, sizeof(efi_guid_t));
+}
+
+static void init_efi_boot_memmap(struct efi_system_table *systab,
+ void *p, void *start)
+{
+unsigned i;
+struct efi_boot_memmap *boot_memmap = p;
+efi_guid_t tbl_guid = LINUX_EFI_BOOT_MEMMAP_GUID;
+
+/* efi_configuration_table 1 */
+guidcpy(>tables[0].guid, _guid);
+systab->tables[0].table = (struct efi_configuration_table *)(p - start);
+systab->nr_tables = 1;
+
+boot_memmap->desc_size = sizeof(efi_memory_desc_t);
+boot_memmap->desc_ver = 1;
+boot_memmap->map_size = 0;
+
+efi_memory_desc_t *map = p + sizeof(struct efi_boot_memmap);
+for (i = 0; i < memmap_entries; i++) {
+map = (void *)boot_memmap + sizeof(*map);
+map[i].type = memmap_table[i].type;
+map[i].phys_addr = ROUND_UP(memmap_table[i].address, 64 * KiB);
+map[i].num_pages = ROUND_DOWN(memmap_table[i].address +
+memmap_table[i].length - map[i].phys_addr, 64 * KiB);
+p += sizeof(efi_memory_desc_t);
+}
+}
+
 static void init_systab(struct loongarch_boot_info *info, void *p, void *start)
 {
+void *bp_tables_start;
 struct efi_system_table *systab = p;
 
 info->a2 = (uint64_t)p - (uint64_t)start;
@@ -80,6 +113,13 @@ static void init_systab(struct loongarch_boot_info *info, 
void *p, void *start)
 p += ROUND_UP(sizeof(struct efi_system_table), 64 * KiB);
 
 systab->tables = p;
+bp_tables_start = p;
+
+init_efi_boot_memmap(systab, p, start);
+p += ROUND_UP(sizeof(struct efi_boot_memmap) +
+  sizeof(efi_memory_desc_t) * memmap_entries, 64 * KiB);
+
+systab->tables = (struct efi_configuration_table *)(bp_tables_start - 
start);
 }
 
 static void init_cmdline(struct loongarch_boot_info *info, void *p, void 
*start)
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index bfb88aedab..708aa8bc60 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -378,15 +378,8 @@ static void virt_powerdown_req(Notifier *notifier, void 
*opaque)
 acpi_send_event(s->acpi_ged, ACPI_POWER_DOWN_STATUS);
 }
 
-struct memmap_entry {
-uint64_t address;
-uint64_t length;
-uint32_t type;
-uint32_t reserved;
-};
-
-static struct memmap_entry *memmap_table;
-static unsigned memmap_entries;
+struct memmap_entry *memmap_table;
+unsigned memmap_entries;
 
 static void memmap_add_entry(uint64_t address, uint64_t length, uint32_t type)
 {
diff --git a/include/hw/loongarch/boot.h b/include/hw/loongarch/boot.h
index cf0e4d4f91..76622af2e2 100644
--- a/include/hw/loongarch/boot.h
+++ b/include/hw/loongarch/boot.h
@@ -21,6 +21,15 @@ typedef struct {
 uint8_t b[16];
 } efi_guid_t QEMU_ALIGNED(8);
 
+#define EFI_GUID(a, b, c, d...) (efi_guid_t){ {
\
+(a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, 
\
+(b) & 0xff, ((b) >> 8) & 0xff, 
\
+(c) & 0xff, ((c) >> 8) & 0xff, d } }
+
+#define LINUX_EFI_BOOT_MEMMAP_GUID \
+EFI_GUID(0x800f683f, 0xd08b, 0x423a,  0xa2, 0x93, \
+ 0x96, 0x5c, 0x3c, 0x6f, 0xe2, 0xb4)
+
 struct efi_config_table {
 efi_guid_t guid;
 uint64_t *ptr;
@@ -56,6 +65,24 @@ struct efi_system_table {
 struct efi_configuration_table *tables;
 };
 
+typedef struct {
+uint32_t type;
+uint32_t pad;
+uint64_t phys_addr;
+uint64_t virt_addr;
+uint64_t num_pages;
+uint64_t attribute;
+} efi_memory_desc_t;
+
+struct efi_boot_memmap {
+uint64_t map_size;
+uint64_t desc_size;
+uint32_t desc_ver;
+uint64_t map_key;
+uint64_t buff_size;
+efi_memory_desc_t map[32];
+};
+
 struct loongarch_boot_info {
 uint64_t ram_size;
 const char *kernel_filename;
diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h
index d7a074d69f..8a9fe4053d 100644
--- a/include/hw/loongarch/virt.h
+++ b/include/hw/loongarch/virt.h
@@ -35,6 +35,16 @@
 
 #define COMMAND_LINE_SIZE   512
 
+extern struct memmap_entry *memmap_table;

[PATCH v7 03/17] hw/loongarch: Add slave cpu boot_code

2024-04-26 Thread Song Gao
Signed-off-by: Song Gao 
Message-Id: <20240307164835.300412-4-gaos...@loongson.cn>
---
 hw/loongarch/boot.c | 62 -
 1 file changed, 61 insertions(+), 1 deletion(-)

diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index a9522d6912..d1a8434127 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -15,6 +15,54 @@
 #include "sysemu/reset.h"
 #include "sysemu/qtest.h"
 
+static const unsigned int slave_boot_code[] = {
+  /* Configure reset ebase.*/
+0x0400302c,   /* csrwr  $t0, LOONGARCH_CSR_EENTRY  */
+
+  /* Disable interrupt.*/
+0x0380100c,   /* ori$t0, $zero,0x4 */
+0x04000180,   /* csrxchg$zero, $t0, LOONGARCH_CSR_CRMD */
+
+  /* Clear mailbox.*/
+0x142d,   /* lu12i.w$t1, 1(0x1)*/
+0x038081ad,   /* ori$t1, $t1, CORE_BUF_20  */
+0x06481da0,   /* iocsrwr.d  $zero, $t1 */
+
+  /* Enable IPI interrupt. */
+0x142c,   /* lu12i.w$t0, 1(0x1)*/
+0x0400118c,   /* csrxchg$t0, $t0, LOONGARCH_CSR_ECFG   */
+0x02fffc0c,   /* addi.d $t0, $r0,-1(0xfff) */
+0x142d,   /* lu12i.w$t1, 1(0x1)*/
+0x038011ad,   /* ori$t1, $t1, CORE_EN_OFF  */
+0x064819ac,   /* iocsrwr.w  $t0, $t1   */
+0x142d,   /* lu12i.w$t1, 1(0x1)*/
+0x038081ad,   /* ori$t1, $t1, CORE_BUF_20  */
+
+  /* Wait for wakeup  <.L11>:  */
+0x06488000,   /* idle   0x0*/
+0x0340,   /* andi   $zero, $zero, 0x0  */
+0x064809ac,   /* iocsrrd.w  $t0, $t1   */
+0x43fff59f,   /* beqz   $t0, -12(0x74) # 48 <.L11> */
+
+  /* Read and clear IPI interrupt. */
+0x142d,   /* lu12i.w$t1, 1(0x1)*/
+0x064809ac,   /* iocsrrd.w  $t0, $t1   */
+0x142d,   /* lu12i.w$t1, 1(0x1)*/
+0x038031ad,   /* ori$t1, $t1, CORE_CLEAR_OFF   */
+0x064819ac,   /* iocsrwr.w  $t0, $t1   */
+
+  /* Disable  IPI interrupt.   */
+0x142c,   /* lu12i.w$t0, 1(0x1)*/
+0x04001180,   /* csrxchg$zero, $t0, LOONGARCH_CSR_ECFG */
+
+  /* Read mail buf and jump to specified entry */
+0x142d,   /* lu12i.w$t1, 1(0x1)*/
+0x038081ad,   /* ori$t1, $t1, CORE_BUF_20  */
+0x06480dac,   /* iocsrrd.d  $t0, $t1   */
+0x00150181,   /* move   $ra, $t0   */
+0x4c20,   /* jirl   $zero, $ra,0   */
+};
+
 static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr)
 {
 return addr & MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS);
@@ -126,11 +174,23 @@ static void loongarch_direct_kernel_boot(struct 
loongarch_boot_info *info)
 }
 }
 
+/* Load slave boot code at pflash0 . */
+void *boot_code = g_malloc0(VIRT_FLASH0_SIZE);
+memcpy(boot_code, _boot_code, sizeof(slave_boot_code));
+rom_add_blob_fixed("boot_code", boot_code, VIRT_FLASH0_SIZE, 
VIRT_FLASH0_BASE);
+
 CPU_FOREACH(cs) {
 lacpu = LOONGARCH_CPU(cs);
 lacpu->env.load_elf = true;
-lacpu->env.elf_address = kernel_addr;
+if (cs == first_cpu) {
+lacpu->env.elf_address = kernel_addr;
+} else {
+lacpu->env.elf_address = VIRT_FLASH0_BASE;
+}
+lacpu->env.boot_info = info;
 }
+
+g_free(boot_code);
 }
 
 void loongarch_load_kernel(MachineState *ms, struct loongarch_boot_info *info)
-- 
2.25.1




[PATCH v7 10/17] hw/loongarch: fdt adds cpu interrupt controller node

2024-04-26 Thread Song Gao
fdt adds cpu interrupt controller node,
we use 'loongson,cpu-interrupt-controller'.

See:
https://github.com/torvalds/linux/blob/v6.7/drivers/irqchip/irq-loongarch-cpu.c
https://lore.kernel.org/r/20221114113824.1880-2-liupei...@loongson.cn

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240307164835.300412-11-gaos...@loongson.cn>
---
 hw/loongarch/virt.c | 21 +
 1 file changed, 21 insertions(+)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 032f5f2ddf..88cdcb6f91 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -106,6 +106,23 @@ static void virt_flash_map(LoongArchMachineState *lams,
 virt_flash_map1(flash1, VIRT_FLASH1_BASE, VIRT_FLASH1_SIZE, sysmem);
 }
 
+static void fdt_add_cpuic_node(LoongArchMachineState *lams,
+   uint32_t *cpuintc_phandle)
+{
+MachineState *ms = MACHINE(lams);
+char *nodename;
+
+*cpuintc_phandle = qemu_fdt_alloc_phandle(ms->fdt);
+nodename = g_strdup_printf("/cpuic");
+qemu_fdt_add_subnode(ms->fdt, nodename);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *cpuintc_phandle);
+qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
+"loongson,cpu-interrupt-controller");
+qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 1);
+g_free(nodename);
+}
+
 static void fdt_add_flash_node(LoongArchMachineState *lams)
 {
 MachineState *ms = MACHINE(lams);
@@ -528,6 +545,7 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
 CPULoongArchState *env;
 CPUState *cpu_state;
 int cpu, pin, i, start, num;
+uint32_t cpuintc_phandle;
 
 /*
  * The connection of interrupts:
@@ -562,6 +580,9 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
 memory_region_add_subregion(>system_iocsr, MAIL_SEND_ADDR,
sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 1));
 
+/* Add cpu interrupt-controller */
+fdt_add_cpuic_node(lams, _phandle);
+
 for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
 cpu_state = qemu_get_cpu(cpu);
 cpudev = DEVICE(cpu_state);
-- 
2.25.1




[PATCH v7 04/17] hw/loongarch: Add init_cmdline

2024-04-26 Thread Song Gao
Add init_cmline and set boot_info->a0, a1

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240307164835.300412-5-gaos...@loongson.cn>
---
 include/hw/loongarch/virt.h |  2 ++
 target/loongarch/cpu.h  |  2 ++
 hw/loongarch/boot.c | 30 ++
 3 files changed, 34 insertions(+)

diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h
index cf2f2bfb19..d7a074d69f 100644
--- a/include/hw/loongarch/virt.h
+++ b/include/hw/loongarch/virt.h
@@ -33,6 +33,8 @@
 #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)
 
+#define COMMAND_LINE_SIZE   512
+
 struct LoongArchMachineState {
 /*< private >*/
 MachineState parent_obj;
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index ec37579fd6..ce02ef3979 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -361,6 +361,8 @@ typedef struct CPUArchState {
 uint32_t mp_state;
 /* Store ipistate to access from this struct */
 DeviceState *ipistate;
+
+struct loongarch_boot_info *boot_info;
 #endif
 } CPULoongArchState;
 
diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index d1a8434127..aca5ad388e 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -63,6 +63,16 @@ static const unsigned int slave_boot_code[] = {
 0x4c20,   /* jirl   $zero, $ra,0   */
 };
 
+static void init_cmdline(struct loongarch_boot_info *info, void *p, void 
*start)
+{
+hwaddr cmdline_addr = (hwaddr)p - (hwaddr)start;
+
+info->a0 = 1;
+info->a1 = cmdline_addr;
+
+memcpy(p, info->kernel_cmdline, COMMAND_LINE_SIZE);
+}
+
 static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr)
 {
 return addr & MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS);
@@ -122,6 +132,10 @@ static void reset_load_elf(void *opaque)
 
 cpu_reset(CPU(cpu));
 if (env->load_elf) {
+   if (cpu == LOONGARCH_CPU(first_cpu)) {
+env->gpr[4] = env->boot_info->a0;
+env->gpr[5] = env->boot_info->a1;
+}
 cpu_set_pc(CPU(cpu), env->elf_address);
 }
 }
@@ -159,8 +173,17 @@ static void loongarch_firmware_boot(LoongArchMachineState 
*lams,
 fw_cfg_add_kernel_info(info, lams->fw_cfg);
 }
 
+static void init_boot_rom(struct loongarch_boot_info *info, void *p)
+{
+void *start = p;
+
+init_cmdline(info, p, start);
+p += COMMAND_LINE_SIZE;
+}
+
 static void loongarch_direct_kernel_boot(struct loongarch_boot_info *info)
 {
+void *p, *bp;
 int64_t kernel_addr = 0;
 LoongArchCPU *lacpu;
 CPUState *cs;
@@ -174,6 +197,12 @@ static void loongarch_direct_kernel_boot(struct 
loongarch_boot_info *info)
 }
 }
 
+/* Load cmdline and system tables at [0 - 1 MiB] */
+p = g_malloc0(1 * MiB);
+bp = p;
+init_boot_rom(info, p);
+rom_add_blob_fixed_as("boot_info", bp, 1 * MiB, 0, _space_memory);
+
 /* Load slave boot code at pflash0 . */
 void *boot_code = g_malloc0(VIRT_FLASH0_SIZE);
 memcpy(boot_code, _boot_code, sizeof(slave_boot_code));
@@ -191,6 +220,7 @@ static void loongarch_direct_kernel_boot(struct 
loongarch_boot_info *info)
 }
 
 g_free(boot_code);
+g_free(bp);
 }
 
 void loongarch_load_kernel(MachineState *ms, struct loongarch_boot_info *info)
-- 
2.25.1




[PATCH v7 15/17] hw/loongarch: fdt remove unused irqchip node

2024-04-26 Thread Song Gao
Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240307164835.300412-16-gaos...@loongson.cn>
---
 hw/loongarch/virt.c | 31 +--
 1 file changed, 1 insertion(+), 30 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 91a55a81b6..48f73edd8e 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -446,34 +446,6 @@ static void fdt_add_pcie_node(const LoongArchMachineState 
*lams,
 g_free(nodename);
 }
 
-static void fdt_add_irqchip_node(LoongArchMachineState *lams)
-{
-MachineState *ms = MACHINE(lams);
-char *nodename;
-uint32_t irqchip_phandle;
-
-irqchip_phandle = qemu_fdt_alloc_phandle(ms->fdt);
-qemu_fdt_setprop_cell(ms->fdt, "/", "interrupt-parent", irqchip_phandle);
-
-nodename = g_strdup_printf("/intc@%lx", VIRT_IOAPIC_REG_BASE);
-qemu_fdt_add_subnode(ms->fdt, nodename);
-qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 3);
-qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
-qemu_fdt_setprop_cell(ms->fdt, nodename, "#address-cells", 0x2);
-qemu_fdt_setprop_cell(ms->fdt, nodename, "#size-cells", 0x2);
-qemu_fdt_setprop(ms->fdt, nodename, "ranges", NULL, 0);
-
-qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
-"loongarch,ls7a");
-
-qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
- 2, VIRT_IOAPIC_REG_BASE,
- 2, PCH_PIC_ROUTE_ENTRY_OFFSET);
-
-qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", irqchip_phandle);
-g_free(nodename);
-}
-
 static void fdt_add_memory_node(MachineState *ms,
 uint64_t base, uint64_t size, int node_id)
 {
@@ -1011,8 +983,7 @@ static void loongarch_init(MachineState *machine)
 
 /* Initialize the IO interrupt subsystem */
 loongarch_irq_init(lams);
-fdt_add_irqchip_node(lams);
-platform_bus_add_all_fdt_nodes(machine->fdt, "/intc",
+platform_bus_add_all_fdt_nodes(machine->fdt, "/platic",
VIRT_PLATFORM_BUS_BASEADDRESS,
VIRT_PLATFORM_BUS_SIZE,
VIRT_PLATFORM_BUS_IRQ);
-- 
2.25.1




[PATCH v7 17/17] hw/loongarch: Add cells missing from rtc node

2024-04-26 Thread Song Gao
rtc node need interrupts and interrupt-parent cells.

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240307164835.300412-18-gaos...@loongson.cn>
---
 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 dbd7928759..c0999878df 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -231,7 +231,8 @@ static void fdt_add_flash_node(LoongArchMachineState *lams)
 g_free(nodename);
 }
 
-static void fdt_add_rtc_node(LoongArchMachineState *lams)
+static void fdt_add_rtc_node(LoongArchMachineState *lams,
+ uint32_t *pch_pic_phandle)
 {
 char *nodename;
 hwaddr base = VIRT_RTC_REG_BASE;
@@ -240,8 +241,13 @@ static void fdt_add_rtc_node(LoongArchMachineState *lams)
 
 nodename = g_strdup_printf("/rtc@%" PRIx64, base);
 qemu_fdt_add_subnode(ms->fdt, nodename);
-qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", 
"loongson,ls7a-rtc");
+qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
+"loongson,ls7a-rtc");
 qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", 2, base, 2, size);
+qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts",
+   VIRT_RTC_IRQ - VIRT_GSI_BASE , 0x4);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
+  *pch_pic_phandle);
 g_free(nodename);
 }
 
@@ -648,7 +654,7 @@ static void loongarch_devices_init(DeviceState *pch_pic,
 sysbus_create_simple("ls7a_rtc", VIRT_RTC_REG_BASE,
  qdev_get_gpio_in(pch_pic,
  VIRT_RTC_IRQ - VIRT_GSI_BASE));
-fdt_add_rtc_node(lams);
+fdt_add_rtc_node(lams, pch_pic_phandle);
 
 /* acpi ged */
 lams->acpi_ged = create_acpi_ged(pch_pic, lams);
-- 
2.25.1




[PATCH v7 01/17] hw/loongarch: Move boot functions to boot.c

2024-04-26 Thread Song Gao
Move some boot functions to boot.c and struct
loongarch_boot_info into struct LoongArchMachineState.

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Reviewed-by: Philippe Mathieu-Daudé 
Message-Id: <20240307164835.300412-2-gaos...@loongson.cn>
---
 include/hw/loongarch/boot.h |  21 ++
 include/hw/loongarch/virt.h |   2 +
 hw/loongarch/boot.c | 128 
 hw/loongarch/virt.c | 121 +++---
 hw/loongarch/meson.build|   1 +
 5 files changed, 160 insertions(+), 113 deletions(-)
 create mode 100644 include/hw/loongarch/boot.h
 create mode 100644 hw/loongarch/boot.c

diff --git a/include/hw/loongarch/boot.h b/include/hw/loongarch/boot.h
new file mode 100644
index 00..3275c1e295
--- /dev/null
+++ b/include/hw/loongarch/boot.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Definitions for LoongArch boot.
+ *
+ * Copyright (C) 2023 Loongson Technology Corporation Limited
+ */
+
+#ifndef HW_LOONGARCH_BOOT_H
+#define HW_LOONGARCH_BOOT_H
+
+struct loongarch_boot_info {
+uint64_t ram_size;
+const char *kernel_filename;
+const char *kernel_cmdline;
+const char *initrd_filename;
+uint64_t a0, a1, a2;
+};
+
+void loongarch_load_kernel(MachineState *ms, struct loongarch_boot_info *info);
+
+#endif /* HW_LOONGARCH_BOOT_H */
diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h
index 252f7df7f4..cf2f2bfb19 100644
--- a/include/hw/loongarch/virt.h
+++ b/include/hw/loongarch/virt.h
@@ -13,6 +13,7 @@
 #include "qemu/queue.h"
 #include "hw/intc/loongarch_ipi.h"
 #include "hw/block/flash.h"
+#include "hw/loongarch/boot.h"
 
 #define LOONGARCH_MAX_CPUS  256
 
@@ -55,6 +56,7 @@ struct LoongArchMachineState {
 MemoryRegion system_iocsr;
 MemoryRegion iocsr_mem;
 AddressSpace as_iocsr;
+struct loongarch_boot_info bootinfo;
 };
 
 #define TYPE_LOONGARCH_MACHINE  MACHINE_TYPE_NAME("virt")
diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
new file mode 100644
index 00..9feed17db3
--- /dev/null
+++ b/hw/loongarch/boot.c
@@ -0,0 +1,128 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * LoongArch boot helper functions.
+ *
+ * Copyright (c) 2023 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "target/loongarch/cpu.h"
+#include "hw/loongarch/virt.h"
+#include "hw/loader.h"
+#include "elf.h"
+#include "qemu/error-report.h"
+#include "sysemu/reset.h"
+#include "sysemu/qtest.h"
+
+static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr)
+{
+return addr & MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS);
+}
+
+static int64_t load_kernel_info(struct loongarch_boot_info *info)
+{
+uint64_t kernel_entry, kernel_low, kernel_high;
+ssize_t kernel_size;
+
+kernel_size = load_elf(info->kernel_filename, NULL,
+   cpu_loongarch_virt_to_phys, NULL,
+   _entry, _low,
+   _high, NULL, 0,
+   EM_LOONGARCH, 1, 0);
+
+if (kernel_size < 0) {
+error_report("could not load kernel '%s': %s",
+ info->kernel_filename,
+ load_elf_strerror(kernel_size));
+exit(1);
+}
+return kernel_entry;
+}
+
+static void reset_load_elf(void *opaque)
+{
+LoongArchCPU *cpu = opaque;
+CPULoongArchState *env = >env;
+
+cpu_reset(CPU(cpu));
+if (env->load_elf) {
+cpu_set_pc(CPU(cpu), env->elf_address);
+}
+}
+
+static void fw_cfg_add_kernel_info(struct loongarch_boot_info *info,
+   FWCfgState *fw_cfg)
+{
+/*
+ * Expose the kernel, the command line, and the initrd in fw_cfg.
+ * We don't process them here at all, it's all left to the
+ * firmware.
+ */
+load_image_to_fw_cfg(fw_cfg,
+ FW_CFG_KERNEL_SIZE, FW_CFG_KERNEL_DATA,
+ info->kernel_filename,
+ false);
+
+if (info->initrd_filename) {
+load_image_to_fw_cfg(fw_cfg,
+ FW_CFG_INITRD_SIZE, FW_CFG_INITRD_DATA,
+ info->initrd_filename, false);
+}
+
+if (info->kernel_cmdline) {
+fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE,
+   strlen(info->kernel_cmdline) + 1);
+fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA,
+  info->kernel_cmdline);
+}
+}
+
+static void loongarch_firmware_boot(LoongArchMachineState *lams,
+struct loongarch_boot_info *info)
+{
+fw_cfg_add_kernel_info(info, lams->fw_cfg);
+}
+
+static void loongarch_direct_kernel_boot(struct loongarch_boot_info *info)
+{

[PATCH v7 12/17] hw/loongarch: fdt adds pch_pic Controller

2024-04-26 Thread Song Gao
fdt adds pch pic controller, we use 'loongson,pch-pic-1.0'

See:
https://github.com/torvalds/linux/blob/v6.7/drivers/irqchip/irq-loongson-pch-pic.c
https://lore.kernel.org/r/20200528152757.1028711-4-jiaxun.y...@flygoat.com

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240307164835.300412-13-gaos...@loongson.cn>
---
 include/hw/pci-host/ls7a.h |  1 +
 hw/loongarch/virt.c| 30 +-
 2 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h
index e753449593..fe260f0183 100644
--- a/include/hw/pci-host/ls7a.h
+++ b/include/hw/pci-host/ls7a.h
@@ -24,6 +24,7 @@
 #define VIRT_PCH_REG_BASE0x1000UL
 #define VIRT_IOAPIC_REG_BASE (VIRT_PCH_REG_BASE)
 #define VIRT_PCH_MSI_ADDR_LOW0x2FF0UL
+#define VIRT_PCH_REG_SIZE0x400
 
 /*
  * GSI_BASE is hard-coded with 64 in linux kernel, else kernel fails to boot
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 094b9d2e60..5bef161d11 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -148,6 +148,31 @@ static void fdt_add_eiointc_node(LoongArchMachineState 
*lams,
 g_free(nodename);
 }
 
+static void fdt_add_pch_pic_node(LoongArchMachineState *lams,
+ uint32_t *eiointc_phandle,
+ uint32_t *pch_pic_phandle)
+{
+MachineState *ms = MACHINE(lams);
+char *nodename;
+hwaddr pch_pic_base = VIRT_PCH_REG_BASE;
+hwaddr pch_pic_size = VIRT_PCH_REG_SIZE;
+
+*pch_pic_phandle = qemu_fdt_alloc_phandle(ms->fdt);
+nodename = g_strdup_printf("/platic@%" PRIx64, pch_pic_base);
+qemu_fdt_add_subnode(ms->fdt, nodename);
+qemu_fdt_setprop_cell(ms->fdt,  nodename, "phandle", *pch_pic_phandle);
+qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
+"loongson,pch-pic-1.0");
+qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0,
+   pch_pic_base, 0, pch_pic_size);
+qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 2);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
+  *eiointc_phandle);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "loongson,pic-base-vec", 0);
+g_free(nodename);
+}
+
 static void fdt_add_flash_node(LoongArchMachineState *lams)
 {
 MachineState *ms = MACHINE(lams);
@@ -570,7 +595,7 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
 CPULoongArchState *env;
 CPUState *cpu_state;
 int cpu, pin, i, start, num;
-uint32_t cpuintc_phandle, eiointc_phandle;
+uint32_t cpuintc_phandle, eiointc_phandle, pch_pic_phandle;
 
 /*
  * The connection of interrupts:
@@ -661,6 +686,9 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
 qdev_connect_gpio_out(DEVICE(d), i, qdev_get_gpio_in(extioi, i));
 }
 
+/* Add PCH PIC node */
+fdt_add_pch_pic_node(lams, _phandle, _pic_phandle);
+
 pch_msi = qdev_new(TYPE_LOONGARCH_PCH_MSI);
 start   =  num;
 num = EXTIOI_IRQS - start;
-- 
2.25.1




[PATCH v7 05/17] hw/loongarch: Init efi_system_table

2024-04-26 Thread Song Gao
Add init_systab and set boot_info->a2

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240307164835.300412-6-gaos...@loongson.cn>
---
 include/hw/loongarch/boot.h | 48 +
 hw/loongarch/boot.c | 22 +
 2 files changed, 70 insertions(+)

diff --git a/include/hw/loongarch/boot.h b/include/hw/loongarch/boot.h
index 3275c1e295..cf0e4d4f91 100644
--- a/include/hw/loongarch/boot.h
+++ b/include/hw/loongarch/boot.h
@@ -8,6 +8,54 @@
 #ifndef HW_LOONGARCH_BOOT_H
 #define HW_LOONGARCH_BOOT_H
 
+/* UEFI 2.10 */
+#define EFI_SYSTEM_TABLE_SIGNATURE   0x5453595320494249
+#define EFI_2_100_SYSTEM_TABLE_REVISION  ((2<<16) | (100))
+#define EFI_SPECIFICATION_VERSIONEFI_SYSTEM_TABLE_REVISION
+#define EFI_SYSTEM_TABLE_REVISIONEFI_2_100_SYSTEM_TABLE_REVISION
+
+#define FW_VERSION 0x1
+#define FW_PATCHLEVEL 0x0
+
+typedef struct {
+uint8_t b[16];
+} efi_guid_t QEMU_ALIGNED(8);
+
+struct efi_config_table {
+efi_guid_t guid;
+uint64_t *ptr;
+const char name[16];
+};
+
+typedef struct {
+uint64_t signature;
+uint32_t revision;
+uint32_t headersize;
+uint32_t crc32;
+uint32_t reserved;
+} efi_table_hdr_t;
+
+struct efi_configuration_table {
+efi_guid_t guid;
+void *table;
+};
+
+struct efi_system_table {
+efi_table_hdr_t hdr;
+uint64_t fw_vendor;/* physical addr of CHAR16 vendor string */
+uint32_t fw_revision;
+uint64_t con_in_handle;
+uint64_t *con_in;
+uint64_t con_out_handle;
+uint64_t *con_out;
+uint64_t stderr_handle;
+uint64_t stderr_placeholder;
+uint64_t *runtime;
+uint64_t *boottime;
+uint64_t nr_tables;
+struct efi_configuration_table *tables;
+};
+
 struct loongarch_boot_info {
 uint64_t ram_size;
 const char *kernel_filename;
diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index aca5ad388e..46a241a04c 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -63,6 +63,25 @@ static const unsigned int slave_boot_code[] = {
 0x4c20,   /* jirl   $zero, $ra,0   */
 };
 
+static void init_systab(struct loongarch_boot_info *info, void *p, void *start)
+{
+struct efi_system_table *systab = p;
+
+info->a2 = (uint64_t)p - (uint64_t)start;
+
+systab->hdr.signature = EFI_SYSTEM_TABLE_SIGNATURE;
+systab->hdr.revision = EFI_SPECIFICATION_VERSION;
+systab->hdr.revision = sizeof(struct efi_system_table),
+systab->fw_revision = FW_VERSION << 16 | FW_PATCHLEVEL << 8;
+systab->runtime = 0;
+systab->boottime = 0;
+systab->nr_tables = 0;
+
+p += ROUND_UP(sizeof(struct efi_system_table), 64 * KiB);
+
+systab->tables = p;
+}
+
 static void init_cmdline(struct loongarch_boot_info *info, void *p, void 
*start)
 {
 hwaddr cmdline_addr = (hwaddr)p - (hwaddr)start;
@@ -135,6 +154,7 @@ static void reset_load_elf(void *opaque)
if (cpu == LOONGARCH_CPU(first_cpu)) {
 env->gpr[4] = env->boot_info->a0;
 env->gpr[5] = env->boot_info->a1;
+env->gpr[6] = env->boot_info->a2;
 }
 cpu_set_pc(CPU(cpu), env->elf_address);
 }
@@ -179,6 +199,8 @@ static void init_boot_rom(struct loongarch_boot_info *info, 
void *p)
 
 init_cmdline(info, p, start);
 p += COMMAND_LINE_SIZE;
+
+init_systab(info, p, start);
 }
 
 static void loongarch_direct_kernel_boot(struct loongarch_boot_info *info)
-- 
2.25.1




[PATCH v7 11/17] hw/loongarch: fdt adds Extend I/O Interrupt Controller

2024-04-26 Thread Song Gao
fdt adds Extend I/O Interrupt Controller,
we use 'loongson,ls2k2000-eiointc'.

See:
https://github.com/torvalds/linux/blob/v6.7/drivers/irqchip/irq-loongson-eiointc.c
https://lore.kernel.org/r/764e02d924094580ac0f1d15535f4b98308705c6.1683279769.git.zhoubin...@loongson.cn

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240307164835.300412-12-gaos...@loongson.cn>
---
 include/hw/intc/loongarch_extioi.h |  1 +
 hw/loongarch/virt.c| 30 +-
 2 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/include/hw/intc/loongarch_extioi.h 
b/include/hw/intc/loongarch_extioi.h
index a0a46b888c..410c6e1121 100644
--- a/include/hw/intc/loongarch_extioi.h
+++ b/include/hw/intc/loongarch_extioi.h
@@ -39,6 +39,7 @@
 #define EXTIOI_COREISR_END   (0xB20 - APIC_OFFSET)
 #define EXTIOI_COREMAP_START (0xC00 - APIC_OFFSET)
 #define EXTIOI_COREMAP_END   (0xD00 - APIC_OFFSET)
+#define EXTIOI_SIZE  0x800
 
 typedef struct ExtIOICore {
 uint32_t coreisr[EXTIOI_IRQS_GROUP_COUNT];
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 88cdcb6f91..094b9d2e60 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -123,6 +123,31 @@ static void fdt_add_cpuic_node(LoongArchMachineState *lams,
 g_free(nodename);
 }
 
+static void fdt_add_eiointc_node(LoongArchMachineState *lams,
+  uint32_t *cpuintc_phandle,
+  uint32_t *eiointc_phandle)
+{
+MachineState *ms = MACHINE(lams);
+char *nodename;
+hwaddr extioi_base = APIC_BASE;
+hwaddr extioi_size = EXTIOI_SIZE;
+
+*eiointc_phandle = qemu_fdt_alloc_phandle(ms->fdt);
+nodename = g_strdup_printf("/eiointc@%" PRIx64, extioi_base);
+qemu_fdt_add_subnode(ms->fdt, nodename);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *eiointc_phandle);
+qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
+"loongson,ls2k2000-eiointc");
+qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 1);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
+  *cpuintc_phandle);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupts", 3);
+qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0x0,
+   extioi_base, 0x0, extioi_size);
+g_free(nodename);
+}
+
 static void fdt_add_flash_node(LoongArchMachineState *lams)
 {
 MachineState *ms = MACHINE(lams);
@@ -545,7 +570,7 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
 CPULoongArchState *env;
 CPUState *cpu_state;
 int cpu, pin, i, start, num;
-uint32_t cpuintc_phandle;
+uint32_t cpuintc_phandle, eiointc_phandle;
 
 /*
  * The connection of interrupts:
@@ -614,6 +639,9 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
 }
 }
 
+/* Add Extend I/O Interrupt Controller node */
+fdt_add_eiointc_node(lams, _phandle, _phandle);
+
 pch_pic = qdev_new(TYPE_LOONGARCH_PCH_PIC);
 num = VIRT_PCH_PIC_IRQ_NUM;
 qdev_prop_set_uint32(pch_pic, "pch_pic_irq_num", num);
-- 
2.25.1




[PATCH v7 07/17] hw/loongarch: Init efi_initrd table

2024-04-26 Thread Song Gao
Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240307164835.300412-8-gaos...@loongson.cn>
---
 include/hw/loongarch/boot.h |  9 +
 hw/loongarch/boot.c | 23 +--
 2 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/include/hw/loongarch/boot.h b/include/hw/loongarch/boot.h
index 76622af2e2..42d1ee3663 100644
--- a/include/hw/loongarch/boot.h
+++ b/include/hw/loongarch/boot.h
@@ -30,6 +30,10 @@ typedef struct {
 EFI_GUID(0x800f683f, 0xd08b, 0x423a,  0xa2, 0x93, \
  0x96, 0x5c, 0x3c, 0x6f, 0xe2, 0xb4)
 
+#define LINUX_EFI_INITRD_MEDIA_GUID \
+EFI_GUID(0x5568e427, 0x68fc, 0x4f3d,  0xac, 0x74, \
+ 0xca, 0x55, 0x52, 0x31, 0xcc, 0x68)
+
 struct efi_config_table {
 efi_guid_t guid;
 uint64_t *ptr;
@@ -83,6 +87,11 @@ struct efi_boot_memmap {
 efi_memory_desc_t map[32];
 };
 
+struct efi_initrd {
+uint64_t base;
+uint64_t size;
+};
+
 struct loongarch_boot_info {
 uint64_t ram_size;
 const char *kernel_filename;
diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index 18aae3434d..1f6cb8ddd7 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -15,6 +15,9 @@
 #include "sysemu/reset.h"
 #include "sysemu/qtest.h"
 
+ram_addr_t initrd_offset;
+uint64_t initrd_size;
+
 static const unsigned int slave_boot_code[] = {
   /* Configure reset ebase.*/
 0x0400302c,   /* csrwr  $t0, LOONGARCH_CSR_EENTRY  */
@@ -95,6 +98,21 @@ static void init_efi_boot_memmap(struct efi_system_table 
*systab,
 }
 }
 
+static void init_efi_initrd_table(struct efi_system_table *systab,
+  void *p, void *start)
+{
+efi_guid_t tbl_guid = LINUX_EFI_INITRD_MEDIA_GUID;
+struct efi_initrd *initrd_table  = p;
+
+/* efi_configuration_table 2 */
+guidcpy(>tables[1].guid, _guid);
+systab->tables[1].table = (struct efi_configuration_table *)(p - start);
+systab->nr_tables = 2;
+
+initrd_table->base = initrd_offset;
+initrd_table->size = initrd_size;
+}
+
 static void init_systab(struct loongarch_boot_info *info, void *p, void *start)
 {
 void *bp_tables_start;
@@ -118,6 +136,8 @@ static void init_systab(struct loongarch_boot_info *info, 
void *p, void *start)
 init_efi_boot_memmap(systab, p, start);
 p += ROUND_UP(sizeof(struct efi_boot_memmap) +
   sizeof(efi_memory_desc_t) * memmap_entries, 64 * KiB);
+init_efi_initrd_table(systab, p, start);
+p += ROUND_UP(sizeof(struct efi_initrd), 64 * KiB);
 
 systab->tables = (struct efi_configuration_table *)(bp_tables_start - 
start);
 }
@@ -139,8 +159,7 @@ static uint64_t cpu_loongarch_virt_to_phys(void *opaque, 
uint64_t addr)
 
 static int64_t load_kernel_info(struct loongarch_boot_info *info)
 {
-uint64_t kernel_entry, kernel_low, kernel_high, initrd_size;
-ram_addr_t initrd_offset;
+uint64_t kernel_entry, kernel_low, kernel_high;
 ssize_t kernel_size;
 
 kernel_size = load_elf(info->kernel_filename, NULL,
-- 
2.25.1




[PATCH v7 00/17] Add boot LoongArch elf kernel with FDT

2024-04-26 Thread Song Gao
Hi, All

We already support boot efi kernel with bios, but not support boot elf kernel.
This series adds boot elf kernel with FDT.

'LoongArch supports ACPI and FDT. The information that needs to be passed
 to the kernel includes the memmap, the initrd, the command line, optionally
 the ACPI/FDT tables, and so on'  see [1].

Patch 2-8 : Create efi system table, and three efi configuration table
boot_memmap, initd, FDT.
Patch 9-17 : Fixes FDT problems.

Test:
  - Start kernel
See [2] start_kernel.sh
  - Start qcow2
See [2] start_qcow2.sh

Patch 3 and Patch 6 need to be reviewed.

Thanks.
Song Gao

V7:
  - Rebase and R-b;
  - Patch3, replace reg_num with reg_name.
move slave boot code buf to pflash0;
  - Patch5: replace __aligned(8) with QEMU_ALIGNED(8);
  - Patch8: Use the macro FDT_BASE to indicate the fdt base size.

V6:
  - Fixes test/compilation failures; 

V5:
  - Rebase;

V4:
  - patch 3 change slave_boot_code[] to const, and 'static void *p ' to
'void *p';
  - patch 4 fixes build error;
  - patch 10-13, add project and commit link.

V3:
  - Load initrd at  kernel_high + 4 * kernel_size;
  - Load 'boot_rom' at [0 - 1M], the 'boot_rom' includes
slave_boot_code, cmdline_buf and systab_tables;
  - R-b and rebase.

V2:
  - FDT pcie node adds cells 'msi-map';


[1]: 
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/arch/loongarch/booting.rst?h=v6.7-rc4

[2]: https://github.com/gaosong-loongson/loongarch-binary/releases

Song Gao (17):
  hw/loongarch: Move boot functions to boot.c
  hw/loongarch: Add load initrd
  hw/loongarch: Add slave cpu boot_code
  hw/loongarch: Add init_cmdline
  hw/loongarch: Init efi_system_table
  hw/loongarch: Init efi_boot_memmap table
  hw/loongarch: Init efi_initrd table
  hw/loongarch: Init efi_fdt table
  hw/loongarch: Fix fdt memory node wrong 'reg'
  hw/loongarch: fdt adds cpu interrupt controller node
  hw/loongarch: fdt adds Extend I/O Interrupt Controller
  hw/loongarch: fdt adds pch_pic Controller
  hw/loongarch: fdt adds pch_msi Controller
  hw/loongarch: fdt adds pcie irq_map node
  hw/loongarch: fdt remove unused irqchip node
  hw/loongarch: Add cells missing from uart node
  hw/loongarch: Add cells missing from rtc node

 include/hw/intc/loongarch_extioi.h |   1 +
 include/hw/loongarch/boot.h| 109 +
 include/hw/loongarch/virt.h|  14 ++
 include/hw/pci-host/ls7a.h |   2 +
 target/loongarch/cpu.h |   2 +
 hw/loongarch/boot.c| 337 ++
 hw/loongarch/virt.c| 363 -
 hw/loongarch/meson.build   |   1 +
 8 files changed, 669 insertions(+), 160 deletions(-)
 create mode 100644 include/hw/loongarch/boot.h
 create mode 100644 hw/loongarch/boot.c

-- 
2.25.1




[PATCH v7 02/17] hw/loongarch: Add load initrd

2024-04-26 Thread Song Gao
we load initrd ramdisk after kernel_high address

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240307164835.300412-3-gaos...@loongson.cn>
---
 hw/loongarch/boot.c | 29 -
 1 file changed, 28 insertions(+), 1 deletion(-)

diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index 9feed17db3..a9522d6912 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -22,7 +22,8 @@ static uint64_t cpu_loongarch_virt_to_phys(void *opaque, 
uint64_t addr)
 
 static int64_t load_kernel_info(struct loongarch_boot_info *info)
 {
-uint64_t kernel_entry, kernel_low, kernel_high;
+uint64_t kernel_entry, kernel_low, kernel_high, initrd_size;
+ram_addr_t initrd_offset;
 ssize_t kernel_size;
 
 kernel_size = load_elf(info->kernel_filename, NULL,
@@ -37,6 +38,32 @@ static int64_t load_kernel_info(struct loongarch_boot_info 
*info)
  load_elf_strerror(kernel_size));
 exit(1);
 }
+
+if (info->initrd_filename) {
+initrd_size = get_image_size(info->initrd_filename);
+if (initrd_size > 0) {
+initrd_offset = ROUND_UP(kernel_high + 4 * kernel_size, 64 * KiB);
+
+if (initrd_offset + initrd_size > info->ram_size) {
+error_report("memory too small for initial ram disk '%s'",
+ info->initrd_filename);
+exit(1);
+}
+
+initrd_size = load_image_targphys(info->initrd_filename, 
initrd_offset,
+  info->ram_size - initrd_offset);
+}
+
+if (initrd_size == (target_ulong)-1) {
+error_report("could not load initial ram disk '%s'",
+ info->initrd_filename);
+exit(1);
+}
+} else {
+error_report("Need initrd!");
+exit(1);
+}
+
 return kernel_entry;
 }
 
-- 
2.25.1




[PATCH v7 16/17] hw/loongarch: Add cells missing from uart node

2024-04-26 Thread Song Gao
uart node need interrupts and interrupt-parent cells.

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240307164835.300412-17-gaos...@loongson.cn>
---
 hw/loongarch/virt.c | 9 +++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 48f73edd8e..dbd7928759 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -245,7 +245,8 @@ static void fdt_add_rtc_node(LoongArchMachineState *lams)
 g_free(nodename);
 }
 
-static void fdt_add_uart_node(LoongArchMachineState *lams)
+static void fdt_add_uart_node(LoongArchMachineState *lams,
+  uint32_t *pch_pic_phandle)
 {
 char *nodename;
 hwaddr base = VIRT_UART_BASE;
@@ -258,6 +259,10 @@ static void fdt_add_uart_node(LoongArchMachineState *lams)
 qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0x0, base, 0x0, size);
 qemu_fdt_setprop_cell(ms->fdt, nodename, "clock-frequency", 1);
 qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", nodename);
+qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts",
+   VIRT_UART_IRQ - VIRT_GSI_BASE, 0x4);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
+  *pch_pic_phandle);
 g_free(nodename);
 }
 
@@ -630,7 +635,7 @@ static void loongarch_devices_init(DeviceState *pch_pic,
qdev_get_gpio_in(pch_pic,
 VIRT_UART_IRQ - VIRT_GSI_BASE),
115200, serial_hd(0), DEVICE_LITTLE_ENDIAN);
-fdt_add_uart_node(lams);
+fdt_add_uart_node(lams, pch_pic_phandle);
 
 /* Network init */
 pci_init_nic_devices(pci_bus, mc->default_nic);
-- 
2.25.1




[PATCH v7 14/17] hw/loongarch: fdt adds pcie irq_map node

2024-04-26 Thread Song Gao
Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240307164835.300412-15-gaos...@loongson.cn>
---
 hw/loongarch/virt.c | 73 ++---
 1 file changed, 69 insertions(+), 4 deletions(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 566f86e741..91a55a81b6 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -352,7 +352,62 @@ static void fdt_add_fw_cfg_node(const 
LoongArchMachineState *lams)
 g_free(nodename);
 }
 
-static void fdt_add_pcie_node(const LoongArchMachineState *lams)
+static void fdt_add_pcie_irq_map_node(const LoongArchMachineState *lams,
+  char *nodename,
+  uint32_t *pch_pic_phandle)
+{
+int pin, dev;
+uint32_t irq_map_stride = 0;
+uint32_t full_irq_map[GPEX_NUM_IRQS *GPEX_NUM_IRQS * 10] = {};
+uint32_t *irq_map = full_irq_map;
+const MachineState *ms = MACHINE(lams);
+
+/* This code creates a standard swizzle of interrupts such that
+ * each device's first interrupt is based on it's PCI_SLOT number.
+ * (See pci_swizzle_map_irq_fn())
+ *
+ * We only need one entry per interrupt in the table (not one per
+ * possible slot) seeing the interrupt-map-mask will allow the table
+ * to wrap to any number of devices.
+ */
+
+for (dev = 0; dev < GPEX_NUM_IRQS; dev++) {
+int devfn = dev * 0x8;
+
+for (pin = 0; pin  < GPEX_NUM_IRQS; pin++) {
+int irq_nr = 16 + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_IRQS);
+int i = 0;
+
+/* Fill PCI address cells */
+irq_map[i] = cpu_to_be32(devfn << 8);
+i += 3;
+
+/* Fill PCI Interrupt cells */
+irq_map[i] = cpu_to_be32(pin + 1);
+i += 1;
+
+/* Fill interrupt controller phandle and cells */
+irq_map[i++] = cpu_to_be32(*pch_pic_phandle);
+irq_map[i++] = cpu_to_be32(irq_nr);
+
+if (!irq_map_stride) {
+irq_map_stride = i;
+}
+irq_map += irq_map_stride;
+}
+}
+
+
+qemu_fdt_setprop(ms->fdt, nodename, "interrupt-map", full_irq_map,
+ GPEX_NUM_IRQS * GPEX_NUM_IRQS *
+ irq_map_stride * sizeof(uint32_t));
+qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupt-map-mask",
+ 0x1800, 0, 0, 0x7);
+}
+
+static void fdt_add_pcie_node(const LoongArchMachineState *lams,
+  uint32_t *pch_pic_phandle,
+  uint32_t *pch_msi_phandle)
 {
 char *nodename;
 hwaddr base_mmio = VIRT_PCI_MEM_BASE;
@@ -383,6 +438,11 @@ static void fdt_add_pcie_node(const LoongArchMachineState 
*lams)
  2, base_pio, 2, size_pio,
  1, FDT_PCI_RANGE_MMIO, 2, base_mmio,
  2, base_mmio, 2, size_mmio);
+qemu_fdt_setprop_cells(ms->fdt, nodename, "msi-map",
+   0, *pch_msi_phandle, 0, 0x1);
+
+fdt_add_pcie_irq_map_node(lams, nodename, pch_pic_phandle);
+
 g_free(nodename);
 }
 
@@ -542,7 +602,10 @@ static DeviceState *create_platform_bus(DeviceState 
*pch_pic)
 return dev;
 }
 
-static void loongarch_devices_init(DeviceState *pch_pic, LoongArchMachineState 
*lams)
+static void loongarch_devices_init(DeviceState *pch_pic,
+   LoongArchMachineState *lams,
+   uint32_t *pch_pic_phandle,
+   uint32_t *pch_msi_phandle)
 {
 MachineClass *mc = MACHINE_GET_CLASS(lams);
 DeviceState *gpex_dev;
@@ -588,6 +651,9 @@ static void loongarch_devices_init(DeviceState *pch_pic, 
LoongArchMachineState *
 gpex_set_irq_num(GPEX_HOST(gpex_dev), i, 16 + i);
 }
 
+/* Add pcie node */
+fdt_add_pcie_node(lams, pch_pic_phandle, pch_msi_phandle);
+
 serial_mm_init(get_system_memory(), VIRT_UART_BASE, 0,
qdev_get_gpio_in(pch_pic,
 VIRT_UART_IRQ - VIRT_GSI_BASE),
@@ -734,7 +800,7 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
 /* Add PCH MSI node */
 fdt_add_pch_msi_node(lams, _phandle, _msi_phandle);
 
-loongarch_devices_init(pch_pic, lams);
+loongarch_devices_init(pch_pic, lams, _pic_phandle, _msi_phandle);
 }
 
 static void loongarch_firmware_init(LoongArchMachineState *lams)
@@ -956,7 +1022,6 @@ static void loongarch_init(MachineState *machine)
 lams->powerdown_notifier.notify = virt_powerdown_req;
 qemu_register_powerdown_notifier(>powerdown_notifier);
 
-fdt_add_pcie_node(lams);
 /*
  * Since lowmem region starts from 0 and Linux kernel legacy start address
  * at 2 MiB, FDT base address is located at 1 MiB to avoid NULL pointer
-- 
2.25.1




[PATCH v7 13/17] hw/loongarch: fdt adds pch_msi Controller

2024-04-26 Thread Song Gao
fdt adds pch msi controller, we use 'loongson,pch-msi-1.0'.

See:
https://github.com/torvalds/linux/blob/v6.7/drivers/irqchip/irq-loongson-pch-msi.c
https://lore.kernel.org/r/20200528152757.1028711-6-jiaxun.y...@flygoat.com

Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240307164835.300412-14-gaos...@loongson.cn>
---
 include/hw/pci-host/ls7a.h |  1 +
 hw/loongarch/virt.c| 33 -
 2 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h
index fe260f0183..cd7c9ec7bc 100644
--- a/include/hw/pci-host/ls7a.h
+++ b/include/hw/pci-host/ls7a.h
@@ -25,6 +25,7 @@
 #define VIRT_IOAPIC_REG_BASE (VIRT_PCH_REG_BASE)
 #define VIRT_PCH_MSI_ADDR_LOW0x2FF0UL
 #define VIRT_PCH_REG_SIZE0x400
+#define VIRT_PCH_MSI_SIZE0x8
 
 /*
  * GSI_BASE is hard-coded with 64 in linux kernel, else kernel fails to boot
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 5bef161d11..566f86e741 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -173,6 +173,34 @@ static void fdt_add_pch_pic_node(LoongArchMachineState 
*lams,
 g_free(nodename);
 }
 
+static void fdt_add_pch_msi_node(LoongArchMachineState *lams,
+ uint32_t *eiointc_phandle,
+ uint32_t *pch_msi_phandle)
+{
+MachineState *ms = MACHINE(lams);
+char *nodename;
+hwaddr pch_msi_base = VIRT_PCH_MSI_ADDR_LOW;
+hwaddr pch_msi_size = VIRT_PCH_MSI_SIZE;
+
+*pch_msi_phandle = qemu_fdt_alloc_phandle(ms->fdt);
+nodename = g_strdup_printf("/msi@%" PRIx64, pch_msi_base);
+qemu_fdt_add_subnode(ms->fdt, nodename);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *pch_msi_phandle);
+qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
+"loongson,pch-msi-1.0");
+qemu_fdt_setprop_cells(ms->fdt, nodename, "reg",
+   0, pch_msi_base,
+   0, pch_msi_size);
+qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent",
+  *eiointc_phandle);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "loongson,msi-base-vec",
+  VIRT_PCH_PIC_IRQ_NUM);
+qemu_fdt_setprop_cell(ms->fdt, nodename, "loongson,msi-num-vecs",
+  EXTIOI_IRQS - VIRT_PCH_PIC_IRQ_NUM);
+g_free(nodename);
+}
+
 static void fdt_add_flash_node(LoongArchMachineState *lams)
 {
 MachineState *ms = MACHINE(lams);
@@ -595,7 +623,7 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
 CPULoongArchState *env;
 CPUState *cpu_state;
 int cpu, pin, i, start, num;
-uint32_t cpuintc_phandle, eiointc_phandle, pch_pic_phandle;
+uint32_t cpuintc_phandle, eiointc_phandle, pch_pic_phandle, 
pch_msi_phandle;
 
 /*
  * The connection of interrupts:
@@ -703,6 +731,9 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
   qdev_get_gpio_in(extioi, i + start));
 }
 
+/* Add PCH MSI node */
+fdt_add_pch_msi_node(lams, _phandle, _msi_phandle);
+
 loongarch_devices_init(pch_pic, lams);
 }
 
-- 
2.25.1




[PATCH v7 06/17] hw/loongarch: Init efi_boot_memmap table

2024-04-26 Thread Song Gao
Signed-off-by: Song Gao 
Message-Id: <20240307164835.300412-7-gaos...@loongson.cn>
---
 include/hw/loongarch/boot.h | 27 +
 include/hw/loongarch/virt.h | 10 ++
 hw/loongarch/boot.c | 40 +
 hw/loongarch/virt.c | 11 ++
 4 files changed, 79 insertions(+), 9 deletions(-)

diff --git a/include/hw/loongarch/boot.h b/include/hw/loongarch/boot.h
index cf0e4d4f91..76622af2e2 100644
--- a/include/hw/loongarch/boot.h
+++ b/include/hw/loongarch/boot.h
@@ -21,6 +21,15 @@ typedef struct {
 uint8_t b[16];
 } efi_guid_t QEMU_ALIGNED(8);
 
+#define EFI_GUID(a, b, c, d...) (efi_guid_t){ {
\
+(a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, 
\
+(b) & 0xff, ((b) >> 8) & 0xff, 
\
+(c) & 0xff, ((c) >> 8) & 0xff, d } }
+
+#define LINUX_EFI_BOOT_MEMMAP_GUID \
+EFI_GUID(0x800f683f, 0xd08b, 0x423a,  0xa2, 0x93, \
+ 0x96, 0x5c, 0x3c, 0x6f, 0xe2, 0xb4)
+
 struct efi_config_table {
 efi_guid_t guid;
 uint64_t *ptr;
@@ -56,6 +65,24 @@ struct efi_system_table {
 struct efi_configuration_table *tables;
 };
 
+typedef struct {
+uint32_t type;
+uint32_t pad;
+uint64_t phys_addr;
+uint64_t virt_addr;
+uint64_t num_pages;
+uint64_t attribute;
+} efi_memory_desc_t;
+
+struct efi_boot_memmap {
+uint64_t map_size;
+uint64_t desc_size;
+uint32_t desc_ver;
+uint64_t map_key;
+uint64_t buff_size;
+efi_memory_desc_t map[32];
+};
+
 struct loongarch_boot_info {
 uint64_t ram_size;
 const char *kernel_filename;
diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h
index d7a074d69f..8a9fe4053d 100644
--- a/include/hw/loongarch/virt.h
+++ b/include/hw/loongarch/virt.h
@@ -35,6 +35,16 @@
 
 #define COMMAND_LINE_SIZE   512
 
+extern struct memmap_entry *memmap_table;
+extern unsigned memmap_entries;
+
+struct memmap_entry {
+uint64_t address;
+uint64_t length;
+uint32_t type;
+uint32_t reserved;
+};
+
 struct LoongArchMachineState {
 /*< private >*/
 MachineState parent_obj;
diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index 46a241a04c..18aae3434d 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -63,8 +63,41 @@ static const unsigned int slave_boot_code[] = {
 0x4c20,   /* jirl   $zero, $ra,0   */
 };
 
+static inline void *guidcpy(void *dst, const void *src)
+{
+return memcpy(dst, src, sizeof(efi_guid_t));
+}
+
+static void init_efi_boot_memmap(struct efi_system_table *systab,
+ void *p, void *start)
+{
+unsigned i;
+struct efi_boot_memmap *boot_memmap = p;
+efi_guid_t tbl_guid = LINUX_EFI_BOOT_MEMMAP_GUID;
+
+/* efi_configuration_table 1 */
+guidcpy(>tables[0].guid, _guid);
+systab->tables[0].table = (struct efi_configuration_table *)(p - start);
+systab->nr_tables = 1;
+
+boot_memmap->desc_size = sizeof(efi_memory_desc_t);
+boot_memmap->desc_ver = 1;
+boot_memmap->map_size = 0;
+
+efi_memory_desc_t *map = p + sizeof(struct efi_boot_memmap);
+for (i = 0; i < memmap_entries; i++) {
+map = (void *)boot_memmap + sizeof(*map);
+map[i].type = memmap_table[i].type;
+map[i].phys_addr = ROUND_UP(memmap_table[i].address, 64 * KiB);
+map[i].num_pages = ROUND_DOWN(memmap_table[i].address +
+memmap_table[i].length - map[i].phys_addr, 64 * KiB);
+p += sizeof(efi_memory_desc_t);
+}
+}
+
 static void init_systab(struct loongarch_boot_info *info, void *p, void *start)
 {
+void *bp_tables_start;
 struct efi_system_table *systab = p;
 
 info->a2 = (uint64_t)p - (uint64_t)start;
@@ -80,6 +113,13 @@ static void init_systab(struct loongarch_boot_info *info, 
void *p, void *start)
 p += ROUND_UP(sizeof(struct efi_system_table), 64 * KiB);
 
 systab->tables = p;
+bp_tables_start = p;
+
+init_efi_boot_memmap(systab, p, start);
+p += ROUND_UP(sizeof(struct efi_boot_memmap) +
+  sizeof(efi_memory_desc_t) * memmap_entries, 64 * KiB);
+
+systab->tables = (struct efi_configuration_table *)(bp_tables_start - 
start);
 }
 
 static void init_cmdline(struct loongarch_boot_info *info, void *p, void 
*start)
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index bfb88aedab..708aa8bc60 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -378,15 +378,8 @@ static void virt_powerdown_req(Notifier *notifier, void 
*opaque)
 acpi_send_event(s->acpi_ged, ACPI_POWER_DOWN_STATUS);
 }
 
-struct memmap_entry {
-uint64_t address;
-uint64_t length;
-uint32_t type;
-uint32_t reserved;
-};
-
-static struct memmap_entry *memmap_table;
-static unsigned memmap_entr

[PATCH v7 09/17] hw/loongarch: Fix fdt memory node wrong 'reg'

2024-04-26 Thread Song Gao
The right fdt memory node like [1], not [2]

  [1]
memory@0 {
device_type = "memory";
reg = <0x00 0x00 0x00 0x1000>;
};
  [2]
memory@0 {
device_type = "memory";
reg = <0x02 0x00 0x02 0x1000>;
};

Reviewed-by: Bibo Mao 
Signed-off-by: Song Gao 
Message-Id: <20240307164835.300412-10-gaos...@loongson.cn>
---
 hw/loongarch/virt.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 42e5df8a24..032f5f2ddf 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -325,7 +325,7 @@ static void fdt_add_memory_node(MachineState *ms,
 char *nodename = g_strdup_printf("/memory@%" PRIx64, base);
 
 qemu_fdt_add_subnode(ms->fdt, nodename);
-qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 2, base, 2, size);
+qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0, base, 0, size);
 qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "memory");
 
 if (ms->numa_state && ms->numa_state->num_nodes) {
-- 
2.25.1




[PATCH v7 08/17] hw/loongarch: Init efi_fdt table

2024-04-26 Thread Song Gao
Signed-off-by: Song Gao 
Reviewed-by: Bibo Mao 
Message-Id: <20240307164835.300412-9-gaos...@loongson.cn>
---
 include/hw/loongarch/boot.h |  4 
 include/hw/loongarch/virt.h |  2 ++
 hw/loongarch/boot.c | 11 +++
 hw/loongarch/virt.c |  6 ++
 4 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/include/hw/loongarch/boot.h b/include/hw/loongarch/boot.h
index 42d1ee3663..4ebcc89dcf 100644
--- a/include/hw/loongarch/boot.h
+++ b/include/hw/loongarch/boot.h
@@ -34,6 +34,10 @@ typedef struct {
 EFI_GUID(0x5568e427, 0x68fc, 0x4f3d,  0xac, 0x74, \
  0xca, 0x55, 0x52, 0x31, 0xcc, 0x68)
 
+#define DEVICE_TREE_GUID \
+EFI_GUID(0xb1b621d5, 0xf19c, 0x41a5,  0x83, 0x0b, \
+ 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0)
+
 struct efi_config_table {
 efi_guid_t guid;
 uint64_t *ptr;
diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h
index 8a9fe4053d..4e14bf6060 100644
--- a/include/hw/loongarch/virt.h
+++ b/include/hw/loongarch/virt.h
@@ -35,6 +35,8 @@
 
 #define COMMAND_LINE_SIZE   512
 
+#define FDT_BASE0x10
+
 extern struct memmap_entry *memmap_table;
 extern unsigned memmap_entries;
 
diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c
index 1f6cb8ddd7..82d171c318 100644
--- a/hw/loongarch/boot.c
+++ b/hw/loongarch/boot.c
@@ -113,6 +113,16 @@ static void init_efi_initrd_table(struct efi_system_table 
*systab,
 initrd_table->size = initrd_size;
 }
 
+static void init_efi_fdt_table(struct efi_system_table *systab)
+{
+efi_guid_t tbl_guid = DEVICE_TREE_GUID;
+
+/* efi_configuration_table 3 */
+guidcpy(>tables[2].guid, _guid);
+systab->tables[2].table = (void *)FDT_BASE;
+systab->nr_tables = 3;
+}
+
 static void init_systab(struct loongarch_boot_info *info, void *p, void *start)
 {
 void *bp_tables_start;
@@ -138,6 +148,7 @@ static void init_systab(struct loongarch_boot_info *info, 
void *p, void *start)
   sizeof(efi_memory_desc_t) * memmap_entries, 64 * KiB);
 init_efi_initrd_table(systab, p, start);
 p += ROUND_UP(sizeof(struct efi_initrd), 64 * KiB);
+init_efi_fdt_table(systab);
 
 systab->tables = (struct efi_configuration_table *)(bp_tables_start - 
start);
 }
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 708aa8bc60..42e5df8a24 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -727,7 +727,6 @@ static void loongarch_init(MachineState *machine)
 int nb_numa_nodes = machine->numa_state->num_nodes;
 NodeInfo *numa_info = machine->numa_state->nodes;
 int i;
-hwaddr fdt_base;
 const CPUArchIdList *possible_cpus;
 MachineClass *mc = MACHINE_GET_CLASS(machine);
 CPUState *cpu;
@@ -857,12 +856,11 @@ static void loongarch_init(MachineState *machine)
  * Put the FDT into the memory map as a ROM image: this will ensure
  * the FDT is copied again upon reset, even if addr points into RAM.
  */
-fdt_base = 1 * MiB;
 qemu_fdt_dumpdtb(machine->fdt, lams->fdt_size);
-rom_add_blob_fixed_as("fdt", machine->fdt, lams->fdt_size, fdt_base,
+rom_add_blob_fixed_as("fdt", machine->fdt, lams->fdt_size, FDT_BASE,
   _space_memory);
 qemu_register_reset_nosnapshotload(qemu_fdt_randomize_seeds,
-rom_ptr_for_as(_space_memory, fdt_base, lams->fdt_size));
+rom_ptr_for_as(_space_memory, FDT_BASE, lams->fdt_size));
 
 lams->bootinfo.ram_size = ram_size;
 loongarch_load_kernel(machine, >bootinfo);
-- 
2.25.1




[PULL 1/1] target/loongarch: Fix qemu-system-loongarch64 assert failed with the option '-d int'

2024-03-22 Thread Song Gao
qemu-system-loongarch64 assert failed with the option '-d int',
the helper_idle() raise an exception EXCP_HLT, but the exception name is 
undefined.

Signed-off-by: Song Gao 
Reviewed-by: Philippe Mathieu-Daudé 
Message-Id: <20240321123606.1704900-1-gaos...@loongson.cn>
---
 target/loongarch/cpu.c | 74 +++---
 1 file changed, 40 insertions(+), 34 deletions(-)

diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index f6ffb3aadb..203a349055 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -45,33 +45,45 @@ const char * const fregnames[32] = {
 "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
 };
 
-static const char * const excp_names[] = {
-[EXCCODE_INT] = "Interrupt",
-[EXCCODE_PIL] = "Page invalid exception for load",
-[EXCCODE_PIS] = "Page invalid exception for store",
-[EXCCODE_PIF] = "Page invalid exception for fetch",
-[EXCCODE_PME] = "Page modified exception",
-[EXCCODE_PNR] = "Page Not Readable exception",
-[EXCCODE_PNX] = "Page Not Executable exception",
-[EXCCODE_PPI] = "Page Privilege error",
-[EXCCODE_ADEF] = "Address error for instruction fetch",
-[EXCCODE_ADEM] = "Address error for Memory access",
-[EXCCODE_SYS] = "Syscall",
-[EXCCODE_BRK] = "Break",
-[EXCCODE_INE] = "Instruction Non-Existent",
-[EXCCODE_IPE] = "Instruction privilege error",
-[EXCCODE_FPD] = "Floating Point Disabled",
-[EXCCODE_FPE] = "Floating Point Exception",
-[EXCCODE_DBP] = "Debug breakpoint",
-[EXCCODE_BCE] = "Bound Check Exception",
-[EXCCODE_SXD] = "128 bit vector instructions Disable exception",
-[EXCCODE_ASXD] = "256 bit vector instructions Disable exception",
+struct TypeExcp {
+int32_t exccode;
+const char * const name;
+};
+
+static const struct TypeExcp excp_names[] = {
+{EXCCODE_INT, "Interrupt"},
+{EXCCODE_PIL, "Page invalid exception for load"},
+{EXCCODE_PIS, "Page invalid exception for store"},
+{EXCCODE_PIF, "Page invalid exception for fetch"},
+{EXCCODE_PME, "Page modified exception"},
+{EXCCODE_PNR, "Page Not Readable exception"},
+{EXCCODE_PNX, "Page Not Executable exception"},
+{EXCCODE_PPI, "Page Privilege error"},
+{EXCCODE_ADEF, "Address error for instruction fetch"},
+{EXCCODE_ADEM, "Address error for Memory access"},
+{EXCCODE_SYS, "Syscall"},
+{EXCCODE_BRK, "Break"},
+{EXCCODE_INE, "Instruction Non-Existent"},
+{EXCCODE_IPE, "Instruction privilege error"},
+{EXCCODE_FPD, "Floating Point Disabled"},
+{EXCCODE_FPE, "Floating Point Exception"},
+{EXCCODE_DBP, "Debug breakpoint"},
+{EXCCODE_BCE, "Bound Check Exception"},
+{EXCCODE_SXD, "128 bit vector instructions Disable exception"},
+{EXCCODE_ASXD, "256 bit vector instructions Disable exception"},
+{EXCP_HLT, "EXCP_HLT"},
 };
 
 const char *loongarch_exception_name(int32_t exception)
 {
-assert(excp_names[exception]);
-return excp_names[exception];
+int i;
+
+for (i = 0; i < ARRAY_SIZE(excp_names); i++) {
+if (excp_names[i].exccode == exception) {
+return excp_names[i].name;
+}
+}
+return "Unknown";
 }
 
 void G_NORETURN do_raise_exception(CPULoongArchState *env,
@@ -80,7 +92,7 @@ void G_NORETURN do_raise_exception(CPULoongArchState *env,
 {
 CPUState *cs = env_cpu(env);
 
-qemu_log_mask(CPU_LOG_INT, "%s: %d (%s)\n",
+qemu_log_mask(CPU_LOG_INT, "%s: expection: %d (%s)\n",
   __func__,
   exception,
   loongarch_exception_name(exception));
@@ -154,22 +166,16 @@ static void loongarch_cpu_do_interrupt(CPUState *cs)
 CPULoongArchState *env = cpu_env(cs);
 bool update_badinstr = 1;
 int cause = -1;
-const char *name;
 bool tlbfill = FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR);
 uint32_t vec_size = FIELD_EX64(env->CSR_ECFG, CSR_ECFG, VS);
 
 if (cs->exception_index != EXCCODE_INT) {
-if (cs->exception_index < 0 ||
-cs->exception_index >= ARRAY_SIZE(excp_names)) {
-name = "unknown";
-} else {
-name = excp_names[cs->exception_index];
-}
-
 qemu_log_mask(CPU_LOG_INT,
  "%s enter: pc " TARGET_FMT_lx " ERA " TARGET_FMT_lx
- " TLBRERA " TARGET_FMT_lx " %s exception\n", __func__,
- env->pc, env->CSR_ERA, env->CSR_TLBRERA, name);
+ " TLBRERA " TARGET_FMT_lx " exception: %d (%s)\n",
+ __func__, env->pc, env->CSR_ERA, env->CSR_TLBRERA,
+ cs->exception_index,
+ loongarch_exception_name(cs->exception_index));
 }
 
 switch (cs->exception_index) {
-- 
2.25.1




[PULL 0/1] loongarch fix for 9.0

2024-03-22 Thread Song Gao
The following changes since commit fea445e8fe9acea4f775a832815ee22bdf2b0222:

  Merge tag 'pull-maintainer-final-for-real-this-time-200324-1' of 
https://gitlab.com/stsquad/qemu into staging (2024-03-21 10:31:56 +)

are available in the Git repository at:

  https://gitlab.com/gaosong/qemu.git tags/pull-loongarch-20240322

for you to fetch changes up to 1590154ee4376819a8c6ee61e849ebf4a4e7cd02:

  target/loongarch: Fix qemu-system-loongarch64 assert failed with the option 
'-d int' (2024-03-22 17:57:49 +0800)


pull-loongarch-20240322


Song Gao (1):
  target/loongarch: Fix qemu-system-loongarch64 assert failed with the 
option '-d int'

 target/loongarch/cpu.c | 74 +++---
 1 file changed, 40 insertions(+), 34 deletions(-)




[PATCH v3] target/loongarch: Fix qemu-system-loongarch64 assert failed with the option '-d int'

2024-03-21 Thread Song Gao
qemu-system-loongarch64 assert failed with the option '-d int',
the helper_idle() raise an exception EXCP_HLT, but the exception name is 
undefined.

Signed-off-by: Song Gao 
---
 target/loongarch/cpu.c | 74 +++---
 1 file changed, 40 insertions(+), 34 deletions(-)

diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index f6ffb3aadb..4d681a733e 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -45,33 +45,45 @@ const char * const fregnames[32] = {
 "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
 };
 
-static const char * const excp_names[] = {
-[EXCCODE_INT] = "Interrupt",
-[EXCCODE_PIL] = "Page invalid exception for load",
-[EXCCODE_PIS] = "Page invalid exception for store",
-[EXCCODE_PIF] = "Page invalid exception for fetch",
-[EXCCODE_PME] = "Page modified exception",
-[EXCCODE_PNR] = "Page Not Readable exception",
-[EXCCODE_PNX] = "Page Not Executable exception",
-[EXCCODE_PPI] = "Page Privilege error",
-[EXCCODE_ADEF] = "Address error for instruction fetch",
-[EXCCODE_ADEM] = "Address error for Memory access",
-[EXCCODE_SYS] = "Syscall",
-[EXCCODE_BRK] = "Break",
-[EXCCODE_INE] = "Instruction Non-Existent",
-[EXCCODE_IPE] = "Instruction privilege error",
-[EXCCODE_FPD] = "Floating Point Disabled",
-[EXCCODE_FPE] = "Floating Point Exception",
-[EXCCODE_DBP] = "Debug breakpoint",
-[EXCCODE_BCE] = "Bound Check Exception",
-[EXCCODE_SXD] = "128 bit vector instructions Disable exception",
-[EXCCODE_ASXD] = "256 bit vector instructions Disable exception",
+struct TypeExcp {
+int32_t exccode;
+const char *name;
+};
+
+static const struct TypeExcp excp_names[] = {
+{EXCCODE_INT, "Interrupt"},
+{EXCCODE_PIL, "Page invalid exception for load"},
+{EXCCODE_PIS, "Page invalid exception for store"},
+{EXCCODE_PIF, "Page invalid exception for fetch"},
+{EXCCODE_PME, "Page modified exception"},
+{EXCCODE_PNR, "Page Not Readable exception"},
+{EXCCODE_PNX, "Page Not Executable exception"},
+{EXCCODE_PPI, "Page Privilege error"},
+{EXCCODE_ADEF, "Address error for instruction fetch"},
+{EXCCODE_ADEM, "Address error for Memory access"},
+{EXCCODE_SYS, "Syscall"},
+{EXCCODE_BRK, "Break"},
+{EXCCODE_INE, "Instruction Non-Existent"},
+{EXCCODE_IPE, "Instruction privilege error"},
+{EXCCODE_FPD, "Floating Point Disabled"},
+{EXCCODE_FPE, "Floating Point Exception"},
+{EXCCODE_DBP, "Debug breakpoint"},
+{EXCCODE_BCE, "Bound Check Exception"},
+{EXCCODE_SXD, "128 bit vector instructions Disable exception"},
+{EXCCODE_ASXD, "256 bit vector instructions Disable exception"},
+{EXCP_HLT, "EXCP_HLT"},
 };
 
 const char *loongarch_exception_name(int32_t exception)
 {
-assert(excp_names[exception]);
-return excp_names[exception];
+int i;
+
+for (i = 0; i < ARRAY_SIZE(excp_names); i++) {
+if (excp_names[i].exccode == exception) {
+return excp_names[i].name;
+}
+}
+return "Unknown";
 }
 
 void G_NORETURN do_raise_exception(CPULoongArchState *env,
@@ -80,7 +92,7 @@ void G_NORETURN do_raise_exception(CPULoongArchState *env,
 {
 CPUState *cs = env_cpu(env);
 
-qemu_log_mask(CPU_LOG_INT, "%s: %d (%s)\n",
+qemu_log_mask(CPU_LOG_INT, "%s: expection: %d (%s)\n",
   __func__,
   exception,
   loongarch_exception_name(exception));
@@ -154,22 +166,16 @@ static void loongarch_cpu_do_interrupt(CPUState *cs)
 CPULoongArchState *env = cpu_env(cs);
 bool update_badinstr = 1;
 int cause = -1;
-const char *name;
 bool tlbfill = FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR);
 uint32_t vec_size = FIELD_EX64(env->CSR_ECFG, CSR_ECFG, VS);
 
 if (cs->exception_index != EXCCODE_INT) {
-if (cs->exception_index < 0 ||
-cs->exception_index >= ARRAY_SIZE(excp_names)) {
-name = "unknown";
-} else {
-name = excp_names[cs->exception_index];
-}
-
 qemu_log_mask(CPU_LOG_INT,
  "%s enter: pc " TARGET_FMT_lx " ERA " TARGET_FMT_lx
- " TLBRERA " TARGET_FMT_lx " %s exception\n", __func__,
- env->pc, env->CSR_ERA, env->CSR_TLBRERA, name);
+ " TLBRERA " TARGET_FMT_lx " exception: %d (%s)\n",
+ __func__, env->pc, env->CSR_ERA, env->CSR_TLBRERA,
+ cs->exception_index,
+ loongarch_exception_name(cs->exception_index));
 }
 
 switch (cs->exception_index) {
-- 
2.25.1




[PATCH v2] target/loongarch: Fix qemu-system-loongarch64 assert failed with the option '-d int'

2024-03-21 Thread Song Gao
qemu-system-loongarch64 assert failed with the option '-d int',
the helper_idle() raise an exception EXCP_HLT, but the exception name is 
undefined.

Signed-off-by: Song Gao 
---
 target/loongarch/cpu.c | 76 +++---
 1 file changed, 42 insertions(+), 34 deletions(-)

diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index f6ffb3aadb..c56e606d28 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -45,33 +45,47 @@ const char * const fregnames[32] = {
 "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
 };
 
-static const char * const excp_names[] = {
-[EXCCODE_INT] = "Interrupt",
-[EXCCODE_PIL] = "Page invalid exception for load",
-[EXCCODE_PIS] = "Page invalid exception for store",
-[EXCCODE_PIF] = "Page invalid exception for fetch",
-[EXCCODE_PME] = "Page modified exception",
-[EXCCODE_PNR] = "Page Not Readable exception",
-[EXCCODE_PNX] = "Page Not Executable exception",
-[EXCCODE_PPI] = "Page Privilege error",
-[EXCCODE_ADEF] = "Address error for instruction fetch",
-[EXCCODE_ADEM] = "Address error for Memory access",
-[EXCCODE_SYS] = "Syscall",
-[EXCCODE_BRK] = "Break",
-[EXCCODE_INE] = "Instruction Non-Existent",
-[EXCCODE_IPE] = "Instruction privilege error",
-[EXCCODE_FPD] = "Floating Point Disabled",
-[EXCCODE_FPE] = "Floating Point Exception",
-[EXCCODE_DBP] = "Debug breakpoint",
-[EXCCODE_BCE] = "Bound Check Exception",
-[EXCCODE_SXD] = "128 bit vector instructions Disable exception",
-[EXCCODE_ASXD] = "256 bit vector instructions Disable exception",
+struct TypeExcp {
+int32_t exccode;
+const char *name;
+};
+
+static const struct TypeExcp excp_names[] = {
+{EXCCODE_INT, "Interrupt"},
+{EXCCODE_PIL, "Page invalid exception for load"},
+{EXCCODE_PIS, "Page invalid exception for store"},
+{EXCCODE_PIF, "Page invalid exception for fetch"},
+{EXCCODE_PME, "Page modified exception"},
+{EXCCODE_PNR, "Page Not Readable exception"},
+{EXCCODE_PNX, "Page Not Executable exception"},
+{EXCCODE_PPI, "Page Privilege error"},
+{EXCCODE_ADEF, "Address error for instruction fetch"},
+{EXCCODE_ADEM, "Address error for Memory access"},
+{EXCCODE_SYS, "Syscall"},
+{EXCCODE_BRK, "Break"},
+{EXCCODE_INE, "Instruction Non-Existent"},
+{EXCCODE_IPE, "Instruction privilege error"},
+{EXCCODE_FPD, "Floating Point Disabled"},
+{EXCCODE_FPE, "Floating Point Exception"},
+{EXCCODE_DBP, "Debug breakpoint"},
+{EXCCODE_BCE, "Bound Check Exception"},
+{EXCCODE_SXD, "128 bit vector instructions Disable exception"},
+{EXCCODE_ASXD, "256 bit vector instructions Disable exception"},
+{EXCP_HLT, "EXCP_HLT"},
 };
 
 const char *loongarch_exception_name(int32_t exception)
 {
-assert(excp_names[exception]);
-return excp_names[exception];
+int i;
+const char *name = NULL;
+
+for (i = 0; i < ARRAY_SIZE(excp_names); i++) {
+if (excp_names[i].exccode == exception) {
+name = excp_names[i].name;
+break;
+}
+}
+return name;
 }
 
 void G_NORETURN do_raise_exception(CPULoongArchState *env,
@@ -80,7 +94,7 @@ void G_NORETURN do_raise_exception(CPULoongArchState *env,
 {
 CPUState *cs = env_cpu(env);
 
-qemu_log_mask(CPU_LOG_INT, "%s: %d (%s)\n",
+qemu_log_mask(CPU_LOG_INT, "%s: expection: %d (%s)\n",
   __func__,
   exception,
   loongarch_exception_name(exception));
@@ -154,22 +168,16 @@ static void loongarch_cpu_do_interrupt(CPUState *cs)
 CPULoongArchState *env = cpu_env(cs);
 bool update_badinstr = 1;
 int cause = -1;
-const char *name;
 bool tlbfill = FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR);
 uint32_t vec_size = FIELD_EX64(env->CSR_ECFG, CSR_ECFG, VS);
 
 if (cs->exception_index != EXCCODE_INT) {
-if (cs->exception_index < 0 ||
-cs->exception_index >= ARRAY_SIZE(excp_names)) {
-name = "unknown";
-} else {
-name = excp_names[cs->exception_index];
-}
-
 qemu_log_mask(CPU_LOG_INT,
  "%s enter: pc " TARGET_FMT_lx " ERA " TARGET_FMT_lx
- " TLBRERA " TARGET_FMT_lx " %s exception\n", __func__,
- env->pc, env->CSR_ERA, env->CSR_TLBRERA, name);
+ " TLBRERA " TARGET_FMT_lx " exception: %d (%s)\n",
+ __func__, env->pc, env->CSR_ERA, env->CSR_TLBRERA,
+ cs->exception_index,
+ loongarch_exception_name(cs->exception_index));
 }
 
 switch (cs->exception_index) {
-- 
2.25.1




[PATCH v1] target/loongarch: Fix qemu-system-loongarch64 assert failed with the option '-d int'

2024-03-20 Thread Song Gao
qemu-system-loongarch64 assert failed with the option '-d int',
the helper_idle() raise an exception EXCP_HLT, but the exception name is 
undefined.

Signed-off-by: Song Gao 
---
 target/loongarch/cpu.c | 75 ++
 1 file changed, 46 insertions(+), 29 deletions(-)

diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index f6ffb3aadb..17a923de02 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -45,33 +45,46 @@ const char * const fregnames[32] = {
 "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
 };
 
-static const char * const excp_names[] = {
-[EXCCODE_INT] = "Interrupt",
-[EXCCODE_PIL] = "Page invalid exception for load",
-[EXCCODE_PIS] = "Page invalid exception for store",
-[EXCCODE_PIF] = "Page invalid exception for fetch",
-[EXCCODE_PME] = "Page modified exception",
-[EXCCODE_PNR] = "Page Not Readable exception",
-[EXCCODE_PNX] = "Page Not Executable exception",
-[EXCCODE_PPI] = "Page Privilege error",
-[EXCCODE_ADEF] = "Address error for instruction fetch",
-[EXCCODE_ADEM] = "Address error for Memory access",
-[EXCCODE_SYS] = "Syscall",
-[EXCCODE_BRK] = "Break",
-[EXCCODE_INE] = "Instruction Non-Existent",
-[EXCCODE_IPE] = "Instruction privilege error",
-[EXCCODE_FPD] = "Floating Point Disabled",
-[EXCCODE_FPE] = "Floating Point Exception",
-[EXCCODE_DBP] = "Debug breakpoint",
-[EXCCODE_BCE] = "Bound Check Exception",
-[EXCCODE_SXD] = "128 bit vector instructions Disable exception",
-[EXCCODE_ASXD] = "256 bit vector instructions Disable exception",
+struct TypeExcp {
+int32_t exccode;
+const char *name;
+};
+
+static const struct TypeExcp excp_names[] = {
+{EXCCODE_INT, "Interrupt"},
+{EXCCODE_PIL, "Page invalid exception for load"},
+{EXCCODE_PIS, "Page invalid exception for store"},
+{EXCCODE_PIF, "Page invalid exception for fetch"},
+{EXCCODE_PME, "Page modified exception"},
+{EXCCODE_PNR, "Page Not Readable exception"},
+{EXCCODE_PNX, "Page Not Executable exception"},
+{EXCCODE_PPI, "Page Privilege error"},
+{EXCCODE_ADEF, "Address error for instruction fetch"},
+{EXCCODE_ADEM, "Address error for Memory access"},
+{EXCCODE_SYS, "Syscall"},
+{EXCCODE_BRK, "Break"},
+{EXCCODE_INE, "Instruction Non-Existent"},
+{EXCCODE_IPE, "Instruction privilege error"},
+{EXCCODE_FPD, "Floating Point Disabled"},
+{EXCCODE_FPE, "Floating Point Exception"},
+{EXCCODE_DBP, "Debug breakpoint"},
+{EXCCODE_BCE, "Bound Check Exception"},
+{EXCCODE_SXD, "128 bit vector instructions Disable exception"},
+{EXCCODE_ASXD, "256 bit vector instructions Disable exception"},
 };
 
 const char *loongarch_exception_name(int32_t exception)
 {
-assert(excp_names[exception]);
-return excp_names[exception];
+int i;
+const char *name = "unknown";
+
+for (i = 0; i < ARRAY_SIZE(excp_names); i++) {
+if (excp_names[i].exccode == exception) {
+name = excp_names[i].name;
+break;
+}
+}
+return name;
 }
 
 void G_NORETURN do_raise_exception(CPULoongArchState *env,
@@ -79,11 +92,17 @@ void G_NORETURN do_raise_exception(CPULoongArchState *env,
uintptr_t pc)
 {
 CPUState *cs = env_cpu(env);
+const char *name;
 
+if (exception == EXCP_HLT) {
+name = "EXCP_HLT";
+} else {
+name = loongarch_exception_name(exception);
+}
 qemu_log_mask(CPU_LOG_INT, "%s: %d (%s)\n",
   __func__,
   exception,
-  loongarch_exception_name(exception));
+  name);
 cs->exception_index = exception;
 
 cpu_loop_exit_restore(cs, pc);
@@ -159,13 +178,11 @@ static void loongarch_cpu_do_interrupt(CPUState *cs)
 uint32_t vec_size = FIELD_EX64(env->CSR_ECFG, CSR_ECFG, VS);
 
 if (cs->exception_index != EXCCODE_INT) {
-if (cs->exception_index < 0 ||
-cs->exception_index >= ARRAY_SIZE(excp_names)) {
-name = "unknown";
+if (cs->exception_index == EXCP_HLT) {
+name = "EXCP_HLT";
 } else {
-name = excp_names[cs->exception_index];
+name = loongarch_exception_name(cs->exception_index);
 }
-
 qemu_log_mask(CPU_LOG_INT,
  "%s enter: pc " TARGET_FMT_lx " ERA " TARGET_FMT_lx
  " TLBRERA " TARGET_FMT_lx " %s exception\n", __func__,
-- 
2.25.1




[PULL 2/3] target/loongarch: Fix tlb huge page loading issue

2024-03-19 Thread Song Gao
From: Xianglai Li 

When we use qemu tcg simulation, the page size of bios is 4KB.
When using the level 2 super huge page (page size is 1G) to create the page 
table,
it is found that the content of the corresponding address space is abnormal,
resulting in the bios can not start the operating system and graphical 
interface normally.

The lddir and ldpte instruction emulation has
a problem with the use of super huge page processing above level 2.
The page size is not correctly calculated,
resulting in the wrong page size of the table entry found by tlb.

Signed-off-by: Xianglai Li 
Reviewed-by: Richard Henderson 
Signed-off-by: Song Gao 
Message-Id: <20240318070332.1273939-1-lixiang...@loongson.cn>
---
 target/loongarch/cpu-csr.h|   3 +
 target/loongarch/internals.h  |   5 --
 target/loongarch/tcg/tlb_helper.c | 113 +-
 3 files changed, 82 insertions(+), 39 deletions(-)

diff --git a/target/loongarch/cpu-csr.h b/target/loongarch/cpu-csr.h
index c59d7a9fcb..0834e91f30 100644
--- a/target/loongarch/cpu-csr.h
+++ b/target/loongarch/cpu-csr.h
@@ -67,6 +67,9 @@ FIELD(TLBENTRY, D, 1, 1)
 FIELD(TLBENTRY, PLV, 2, 2)
 FIELD(TLBENTRY, MAT, 4, 2)
 FIELD(TLBENTRY, G, 6, 1)
+FIELD(TLBENTRY, HUGE, 6, 1)
+FIELD(TLBENTRY, HGLOBAL, 12, 1)
+FIELD(TLBENTRY, LEVEL, 13, 2)
 FIELD(TLBENTRY_32, PPN, 8, 24)
 FIELD(TLBENTRY_64, PPN, 12, 36)
 FIELD(TLBENTRY_64, NR, 61, 1)
diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h
index a2fc54c8a7..944153b180 100644
--- a/target/loongarch/internals.h
+++ b/target/loongarch/internals.h
@@ -16,11 +16,6 @@
 #define TARGET_PHYS_MASK MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS)
 #define TARGET_VIRT_MASK MAKE_64BIT_MASK(0, TARGET_VIRT_ADDR_SPACE_BITS)
 
-/* Global bit used for lddir/ldpte */
-#define LOONGARCH_PAGE_HUGE_SHIFT   6
-/* Global bit for huge page */
-#define LOONGARCH_HGLOBAL_SHIFT 12
-
 void loongarch_translate_init(void);
 
 void loongarch_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
diff --git a/target/loongarch/tcg/tlb_helper.c 
b/target/loongarch/tcg/tlb_helper.c
index 22be031ac7..57f5308632 100644
--- a/target/loongarch/tcg/tlb_helper.c
+++ b/target/loongarch/tcg/tlb_helper.c
@@ -17,6 +17,34 @@
 #include "exec/log.h"
 #include "cpu-csr.h"
 
+static void get_dir_base_width(CPULoongArchState *env, uint64_t *dir_base,
+   uint64_t *dir_width, target_ulong level)
+{
+switch (level) {
+case 1:
+*dir_base = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR1_BASE);
+*dir_width = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR1_WIDTH);
+break;
+case 2:
+*dir_base = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR2_BASE);
+*dir_width = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR2_WIDTH);
+break;
+case 3:
+*dir_base = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR3_BASE);
+*dir_width = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR3_WIDTH);
+break;
+case 4:
+*dir_base = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR4_BASE);
+*dir_width = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR4_WIDTH);
+break;
+default:
+/* level may be zero for ldpte */
+*dir_base = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTBASE);
+*dir_width = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTWIDTH);
+break;
+}
+}
+
 static void raise_mmu_exception(CPULoongArchState *env, target_ulong address,
 MMUAccessType access_type, int tlb_error)
 {
@@ -485,7 +513,25 @@ target_ulong helper_lddir(CPULoongArchState *env, 
target_ulong base,
 target_ulong badvaddr, index, phys, ret;
 int shift;
 uint64_t dir_base, dir_width;
-bool huge = (base >> LOONGARCH_PAGE_HUGE_SHIFT) & 0x1;
+
+if (unlikely((level == 0) || (level > 4))) {
+qemu_log_mask(LOG_GUEST_ERROR,
+  "Attepted LDDIR with level %"PRId64"\n", level);
+return base;
+}
+
+if (FIELD_EX64(base, TLBENTRY, HUGE)) {
+if (unlikely(level == 4)) {
+qemu_log_mask(LOG_GUEST_ERROR,
+  "Attempted use of level 4 huge page\n");
+}
+
+if (FIELD_EX64(base, TLBENTRY, LEVEL)) {
+return base;
+} else {
+return FIELD_DP64(base, TLBENTRY, LEVEL, level);
+}
+}
 
 badvaddr = env->CSR_TLBRBADV;
 base = base & TARGET_PHYS_MASK;
@@ -494,30 +540,7 @@ target_ulong helper_lddir(CPULoongArchState *env, 
target_ulong base,
 shift = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTEWIDTH);
 shift = (shift + 1) * 3;
 
-if (huge) {
-return base;
-}
-switch (level) {
-case 1:
-dir_base = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR1_BASE);
-dir_width = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR1_WIDTH);
-break;
-case 2:
-dir_base = FIELD_EX64(env-&g

  1   2   3   4   5   6   7   8   9   10   >