- * [PATCH 1/8] hw/loongarch: Add default bios startup support
  2022-06-20  8:04 [PATCH 0/8] Add some functions for LoongArch Xiaojuan Yang
@ 2022-06-20  8:04 ` Xiaojuan Yang
  2022-06-20 10:04   ` chen huacai
  2022-06-20  8:04 ` [PATCH 2/8] hw/loongarch: Add -kernel and -initrd options support Xiaojuan Yang
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 12+ messages in thread
From: Xiaojuan Yang @ 2022-06-20  8:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: richard.henderson, gaosong, maobibo, mark.cave-ayland, mst,
	imammedo, ani, f4bug, peter.maydell, chenhuacai
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
---
 hw/loongarch/fw_cfg.c       | 33 +++++++++++++++
 hw/loongarch/fw_cfg.h       | 15 +++++++
 hw/loongarch/loongson3.c    | 81 ++++++++++++++++++++++++++++++++++++-
 include/hw/loongarch/virt.h |  7 ++++
 4 files changed, 135 insertions(+), 1 deletion(-)
 create mode 100644 hw/loongarch/fw_cfg.c
 create mode 100644 hw/loongarch/fw_cfg.h
diff --git a/hw/loongarch/fw_cfg.c b/hw/loongarch/fw_cfg.c
new file mode 100644
index 0000000000..a641f603b6
--- /dev/null
+++ b/hw/loongarch/fw_cfg.c
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * QEMU fw_cfg helpers (LoongArch specific)
+ *
+ * Copyright (C) 2021 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "hw/loongarch/fw_cfg.h"
+#include "hw/loongarch/virt.h"
+#include "hw/nvram/fw_cfg.h"
+#include "sysemu/sysemu.h"
+
+static void fw_cfg_boot_set(void *opaque, const char *boot_device,
+                            Error **errp)
+{
+    fw_cfg_modify_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
+}
+
+FWCfgState *loongarch_fw_cfg_init(ram_addr_t ram_size, MachineState *ms)
+{
+    FWCfgState *fw_cfg;
+    int max_cpus = ms->smp.max_cpus;
+    int smp_cpus = ms->smp.cpus;
+
+    fw_cfg = fw_cfg_init_mem_wide(FW_CFG_ADDR + 8, FW_CFG_ADDR, 8, 0, NULL);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
+    fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
+    fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)smp_cpus);
+
+    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
+    return fw_cfg;
+}
diff --git a/hw/loongarch/fw_cfg.h b/hw/loongarch/fw_cfg.h
new file mode 100644
index 0000000000..7c0de4db4a
--- /dev/null
+++ b/hw/loongarch/fw_cfg.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * QEMU fw_cfg helpers (LoongArch specific)
+ *
+ * Copyright (C) 2021 Loongson Technology Corporation Limited
+ */
+
+#ifndef HW_LOONGARCH_FW_CFG_H
+#define HW_LOONGARCH_FW_CFG_H
+
+#include "hw/boards.h"
+#include "hw/nvram/fw_cfg.h"
+
+FWCfgState *loongarch_fw_cfg_init(ram_addr_t ram_size, MachineState *ms);
+#endif
diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
index bd20ebbb78..1e2c69dd8e 100644
--- a/hw/loongarch/loongson3.c
+++ b/hw/loongarch/loongson3.c
@@ -28,13 +28,46 @@
 #include "hw/pci-host/ls7a.h"
 #include "hw/pci-host/gpex.h"
 #include "hw/misc/unimp.h"
-
+#include "hw/loongarch/fw_cfg.h"
 #include "target/loongarch/cpu.h"
 
 #define PM_BASE 0x10080000
 #define PM_SIZE 0x100
 #define PM_CTRL 0x10
 
+struct la_memmap_entry {
+    uint64_t address;
+    uint64_t length;
+    uint32_t type;
+    uint32_t reserved;
+};
+
+static struct la_memmap_entry *la_memmap_table;
+static unsigned la_memmap_entries;
+
+static int la_memmap_add_entry(uint64_t address, uint64_t length, uint32_t type)
+{
+    int i;
+
+    for (i = 0; i < la_memmap_entries; i++) {
+        if (la_memmap_table[i].address == address) {
+            fprintf(stderr, "%s address:0x%lx length:0x%lx already exists\n",
+                     __func__, address, length);
+            return 0;
+        }
+    }
+
+    la_memmap_table = g_renew(struct la_memmap_entry, la_memmap_table,
+                                                      la_memmap_entries + 1);
+    la_memmap_table[la_memmap_entries].address = cpu_to_le64(address);
+    la_memmap_table[la_memmap_entries].length = cpu_to_le64(length);
+    la_memmap_table[la_memmap_entries].type = cpu_to_le32(type);
+    la_memmap_entries++;
+
+    return la_memmap_entries;
+}
+
+
 /*
  * This is a placeholder for missing ACPI,
  * and will eventually be replaced.
@@ -279,6 +312,38 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
     loongarch_devices_init(pch_pic);
 }
 
+static bool loongarch_firmware_init(LoongArchMachineState *lams)
+{
+    char *filename = MACHINE(lams)->firmware;
+    char *bios_name = NULL;
+    bool loaded = false;
+    int bios_size;
+
+    if (filename) {
+        bios_name = qemu_find_file(QEMU_FILE_TYPE_BIOS, filename);
+        if (!bios_name) {
+            error_report("Could not find ROM image '%s'", filename);
+            exit(1);
+        }
+
+        bios_size = load_image_targphys(bios_name, LA_BIOS_BASE, LA_BIOS_SIZE);
+        if (bios_size < 0) {
+            error_report("Could not load ROM image '%s'", bios_name);
+            exit(1);
+        }
+
+        g_free(bios_name);
+
+        memory_region_init_ram(&lams->bios, NULL, "loongarch.bios",
+                               LA_BIOS_SIZE, &error_fatal);
+        memory_region_set_readonly(&lams->bios, true);
+        memory_region_add_subregion(get_system_memory(), LA_BIOS_BASE, &lams->bios);
+        loaded = true;
+    }
+
+    return loaded;
+}
+
 static void reset_load_elf(void *opaque)
 {
     LoongArchCPU *cpu = opaque;
@@ -301,6 +366,7 @@ static void loongarch_init(MachineState *machine)
     LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
     LoongArchCPU *lacpu;
     int i;
+    bool firmware_loaded;
     int64_t kernel_addr = 0;
 
     if (!cpu_model) {
@@ -327,15 +393,28 @@ static void loongarch_init(MachineState *machine)
                              machine->ram, 0, 256 * MiB);
     memory_region_add_subregion(address_space_mem, offset, &lams->lowmem);
     offset += 256 * MiB;
+    la_memmap_add_entry(0, 256 * MiB, 1);
     highram_size = ram_size - 256 * MiB;
     memory_region_init_alias(&lams->highmem, NULL, "loongarch.highmem",
                              machine->ram, offset, highram_size);
     memory_region_add_subregion(address_space_mem, 0x90000000, &lams->highmem);
+    la_memmap_add_entry(0x90000000, highram_size, 1);
     /* Add isa io region */
     memory_region_init_alias(&lams->isa_io, NULL, "isa-io",
                              get_system_io(), 0, LOONGARCH_ISA_IO_SIZE);
     memory_region_add_subregion(address_space_mem, LOONGARCH_ISA_IO_BASE,
                                 &lams->isa_io);
+    /* load the BIOS image. */
+    firmware_loaded = loongarch_firmware_init(lams);
+    lams->fw_cfg = loongarch_fw_cfg_init(ram_size, machine);
+    rom_set_fw(lams->fw_cfg);
+
+    if (lams->fw_cfg != NULL) {
+        fw_cfg_add_file(lams->fw_cfg, "etc/memmap",
+                        la_memmap_table,
+                        sizeof(struct la_memmap_entry) * (la_memmap_entries));
+    }
+
     if (kernel_filename) {
         loaderparams.ram_size = ram_size;
         loaderparams.kernel_filename = kernel_filename;
diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h
index 09a816191c..448f46fc6b 100644
--- a/include/hw/loongarch/virt.h
+++ b/include/hw/loongarch/virt.h
@@ -17,6 +17,9 @@
 
 #define LOONGARCH_ISA_IO_BASE   0x18000000UL
 #define LOONGARCH_ISA_IO_SIZE   0x0004000
+#define FW_CFG_ADDR             0x1e020000
+#define LA_BIOS_BASE            0x1c000000
+#define LA_BIOS_SIZE            (4 * MiB)
 
 struct LoongArchMachineState {
     /*< private >*/
@@ -26,6 +29,10 @@ struct LoongArchMachineState {
     MemoryRegion lowmem;
     MemoryRegion highmem;
     MemoryRegion isa_io;
+    MemoryRegion bios;
+
+    /* State for other subsystems/APIs: */
+    FWCfgState  *fw_cfg;
 };
 
 #define TYPE_LOONGARCH_MACHINE  MACHINE_TYPE_NAME("virt")
-- 
2.31.1
^ permalink raw reply related	[flat|nested] 12+ messages in thread
- * Re: [PATCH 1/8] hw/loongarch: Add default bios startup support
  2022-06-20  8:04 ` [PATCH 1/8] hw/loongarch: Add default bios startup support Xiaojuan Yang
@ 2022-06-20 10:04   ` chen huacai
  0 siblings, 0 replies; 12+ messages in thread
From: chen huacai @ 2022-06-20 10:04 UTC (permalink / raw)
  To: Xiaojuan Yang
  Cc: qemu-level, Richard Henderson, Song Gao, maobibo,
	mark.cave-ayland, Michael S. Tsirkin, imammedo, ani,
	Philippe Mathieu-Daudé, Peter Maydell, chenhuacai
Hi, Xiaojuan,
On Mon, Jun 20, 2022 at 4:21 PM Xiaojuan Yang <yangxiaojuan@loongson.cn> wrote:
>
> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
> ---
>  hw/loongarch/fw_cfg.c       | 33 +++++++++++++++
>  hw/loongarch/fw_cfg.h       | 15 +++++++
>  hw/loongarch/loongson3.c    | 81 ++++++++++++++++++++++++++++++++++++-
>  include/hw/loongarch/virt.h |  7 ++++
>  4 files changed, 135 insertions(+), 1 deletion(-)
>  create mode 100644 hw/loongarch/fw_cfg.c
>  create mode 100644 hw/loongarch/fw_cfg.h
>
> diff --git a/hw/loongarch/fw_cfg.c b/hw/loongarch/fw_cfg.c
> new file mode 100644
> index 0000000000..a641f603b6
> --- /dev/null
> +++ b/hw/loongarch/fw_cfg.c
> @@ -0,0 +1,33 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * QEMU fw_cfg helpers (LoongArch specific)
> + *
> + * Copyright (C) 2021 Loongson Technology Corporation Limited
> + */
> +
> +#include "qemu/osdep.h"
> +#include "hw/loongarch/fw_cfg.h"
> +#include "hw/loongarch/virt.h"
> +#include "hw/nvram/fw_cfg.h"
> +#include "sysemu/sysemu.h"
> +
> +static void fw_cfg_boot_set(void *opaque, const char *boot_device,
> +                            Error **errp)
> +{
> +    fw_cfg_modify_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
> +}
> +
> +FWCfgState *loongarch_fw_cfg_init(ram_addr_t ram_size, MachineState *ms)
> +{
> +    FWCfgState *fw_cfg;
> +    int max_cpus = ms->smp.max_cpus;
> +    int smp_cpus = ms->smp.cpus;
> +
> +    fw_cfg = fw_cfg_init_mem_wide(FW_CFG_ADDR + 8, FW_CFG_ADDR, 8, 0, NULL);
> +    fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
> +    fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
> +    fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)smp_cpus);
> +
> +    qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
> +    return fw_cfg;
> +}
> diff --git a/hw/loongarch/fw_cfg.h b/hw/loongarch/fw_cfg.h
> new file mode 100644
> index 0000000000..7c0de4db4a
> --- /dev/null
> +++ b/hw/loongarch/fw_cfg.h
> @@ -0,0 +1,15 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * QEMU fw_cfg helpers (LoongArch specific)
> + *
> + * Copyright (C) 2021 Loongson Technology Corporation Limited
> + */
> +
> +#ifndef HW_LOONGARCH_FW_CFG_H
> +#define HW_LOONGARCH_FW_CFG_H
> +
> +#include "hw/boards.h"
> +#include "hw/nvram/fw_cfg.h"
> +
> +FWCfgState *loongarch_fw_cfg_init(ram_addr_t ram_size, MachineState *ms);
> +#endif
> diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
> index bd20ebbb78..1e2c69dd8e 100644
> --- a/hw/loongarch/loongson3.c
> +++ b/hw/loongarch/loongson3.c
> @@ -28,13 +28,46 @@
>  #include "hw/pci-host/ls7a.h"
>  #include "hw/pci-host/gpex.h"
>  #include "hw/misc/unimp.h"
> -
> +#include "hw/loongarch/fw_cfg.h"
>  #include "target/loongarch/cpu.h"
>
>  #define PM_BASE 0x10080000
>  #define PM_SIZE 0x100
>  #define PM_CTRL 0x10
>
> +struct la_memmap_entry {
> +    uint64_t address;
> +    uint64_t length;
> +    uint32_t type;
> +    uint32_t reserved;
> +};
> +
> +static struct la_memmap_entry *la_memmap_table;
> +static unsigned la_memmap_entries;
Since they are static, we can drop the la_ prefix here. And if a
prefix is really needed, I prefer loongarch_ or larch rather than la_.
Huacai
> +
> +static int la_memmap_add_entry(uint64_t address, uint64_t length, uint32_t type)
> +{
> +    int i;
> +
> +    for (i = 0; i < la_memmap_entries; i++) {
> +        if (la_memmap_table[i].address == address) {
> +            fprintf(stderr, "%s address:0x%lx length:0x%lx already exists\n",
> +                     __func__, address, length);
> +            return 0;
> +        }
> +    }
> +
> +    la_memmap_table = g_renew(struct la_memmap_entry, la_memmap_table,
> +                                                      la_memmap_entries + 1);
> +    la_memmap_table[la_memmap_entries].address = cpu_to_le64(address);
> +    la_memmap_table[la_memmap_entries].length = cpu_to_le64(length);
> +    la_memmap_table[la_memmap_entries].type = cpu_to_le32(type);
> +    la_memmap_entries++;
> +
> +    return la_memmap_entries;
> +}
> +
> +
>  /*
>   * This is a placeholder for missing ACPI,
>   * and will eventually be replaced.
> @@ -279,6 +312,38 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
>      loongarch_devices_init(pch_pic);
>  }
>
> +static bool loongarch_firmware_init(LoongArchMachineState *lams)
> +{
> +    char *filename = MACHINE(lams)->firmware;
> +    char *bios_name = NULL;
> +    bool loaded = false;
> +    int bios_size;
> +
> +    if (filename) {
> +        bios_name = qemu_find_file(QEMU_FILE_TYPE_BIOS, filename);
> +        if (!bios_name) {
> +            error_report("Could not find ROM image '%s'", filename);
> +            exit(1);
> +        }
> +
> +        bios_size = load_image_targphys(bios_name, LA_BIOS_BASE, LA_BIOS_SIZE);
> +        if (bios_size < 0) {
> +            error_report("Could not load ROM image '%s'", bios_name);
> +            exit(1);
> +        }
> +
> +        g_free(bios_name);
> +
> +        memory_region_init_ram(&lams->bios, NULL, "loongarch.bios",
> +                               LA_BIOS_SIZE, &error_fatal);
> +        memory_region_set_readonly(&lams->bios, true);
> +        memory_region_add_subregion(get_system_memory(), LA_BIOS_BASE, &lams->bios);
> +        loaded = true;
> +    }
> +
> +    return loaded;
> +}
> +
>  static void reset_load_elf(void *opaque)
>  {
>      LoongArchCPU *cpu = opaque;
> @@ -301,6 +366,7 @@ static void loongarch_init(MachineState *machine)
>      LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
>      LoongArchCPU *lacpu;
>      int i;
> +    bool firmware_loaded;
>      int64_t kernel_addr = 0;
>
>      if (!cpu_model) {
> @@ -327,15 +393,28 @@ static void loongarch_init(MachineState *machine)
>                               machine->ram, 0, 256 * MiB);
>      memory_region_add_subregion(address_space_mem, offset, &lams->lowmem);
>      offset += 256 * MiB;
> +    la_memmap_add_entry(0, 256 * MiB, 1);
>      highram_size = ram_size - 256 * MiB;
>      memory_region_init_alias(&lams->highmem, NULL, "loongarch.highmem",
>                               machine->ram, offset, highram_size);
>      memory_region_add_subregion(address_space_mem, 0x90000000, &lams->highmem);
> +    la_memmap_add_entry(0x90000000, highram_size, 1);
>      /* Add isa io region */
>      memory_region_init_alias(&lams->isa_io, NULL, "isa-io",
>                               get_system_io(), 0, LOONGARCH_ISA_IO_SIZE);
>      memory_region_add_subregion(address_space_mem, LOONGARCH_ISA_IO_BASE,
>                                  &lams->isa_io);
> +    /* load the BIOS image. */
> +    firmware_loaded = loongarch_firmware_init(lams);
> +    lams->fw_cfg = loongarch_fw_cfg_init(ram_size, machine);
> +    rom_set_fw(lams->fw_cfg);
> +
> +    if (lams->fw_cfg != NULL) {
> +        fw_cfg_add_file(lams->fw_cfg, "etc/memmap",
> +                        la_memmap_table,
> +                        sizeof(struct la_memmap_entry) * (la_memmap_entries));
> +    }
> +
>      if (kernel_filename) {
>          loaderparams.ram_size = ram_size;
>          loaderparams.kernel_filename = kernel_filename;
> diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h
> index 09a816191c..448f46fc6b 100644
> --- a/include/hw/loongarch/virt.h
> +++ b/include/hw/loongarch/virt.h
> @@ -17,6 +17,9 @@
>
>  #define LOONGARCH_ISA_IO_BASE   0x18000000UL
>  #define LOONGARCH_ISA_IO_SIZE   0x0004000
> +#define FW_CFG_ADDR             0x1e020000
> +#define LA_BIOS_BASE            0x1c000000
> +#define LA_BIOS_SIZE            (4 * MiB)
>
>  struct LoongArchMachineState {
>      /*< private >*/
> @@ -26,6 +29,10 @@ struct LoongArchMachineState {
>      MemoryRegion lowmem;
>      MemoryRegion highmem;
>      MemoryRegion isa_io;
> +    MemoryRegion bios;
> +
> +    /* State for other subsystems/APIs: */
> +    FWCfgState  *fw_cfg;
>  };
>
>  #define TYPE_LOONGARCH_MACHINE  MACHINE_TYPE_NAME("virt")
> --
> 2.31.1
>
>
-- 
Huacai Chen
^ permalink raw reply	[flat|nested] 12+ messages in thread
 
- * [PATCH 2/8] hw/loongarch: Add -kernel and -initrd options support
  2022-06-20  8:04 [PATCH 0/8] Add some functions for LoongArch Xiaojuan Yang
  2022-06-20  8:04 ` [PATCH 1/8] hw/loongarch: Add default bios startup support Xiaojuan Yang
@ 2022-06-20  8:04 ` Xiaojuan Yang
  2022-06-20  8:04 ` [PATCH 3/8] hw/loongarch: Add LoongArch smbios support Xiaojuan Yang
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 12+ messages in thread
From: Xiaojuan Yang @ 2022-06-20  8:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: richard.henderson, gaosong, maobibo, mark.cave-ayland, mst,
	imammedo, ani, f4bug, peter.maydell, chenhuacai
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
---
 hw/loongarch/loongson3.c | 125 ++++++++++++++++++++++++++++++++++-----
 1 file changed, 110 insertions(+), 15 deletions(-)
diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
index 1e2c69dd8e..638280c4e7 100644
--- a/hw/loongarch/loongson3.c
+++ b/hw/loongarch/loongson3.c
@@ -109,6 +109,8 @@ static const MemoryRegionOps loongarch_virt_pm_ops = {
 static struct _loaderparams {
     uint64_t ram_size;
     const char *kernel_filename;
+    const char *kernel_cmdline;
+    const char *initrd_filename;
 } loaderparams;
 
 static uint64_t cpu_loongarch_virt_to_phys(void *opaque, uint64_t addr)
@@ -355,19 +357,114 @@ static void reset_load_elf(void *opaque)
     }
 }
 
+/**
+ * load_image_to_fw_cfg() - Load an image file into an fw_cfg entry identified
+ *                          by key.
+ * @fw_cfg:         The firmware config instance to store the data in.
+ * @size_key:       The firmware config key to store the size of the loaded
+ *                  data under, with fw_cfg_add_i32().
+ * @data_key:       The firmware config key to store the loaded data under,
+ *                  with fw_cfg_add_bytes().
+ * @image_name:     The name of the image file to load. If it is NULL, the
+ *                  function returns without doing anything.
+ * @try_decompress: Whether the image should be decompressed (gunzipped) before
+ *                  adding it to fw_cfg. If decompression fails, the image is
+ *                  loaded as-is.
+ *
+ * In case of failure, the function prints an error message to stderr and the
+ * process exits with status 1.
+ */
+static void load_image_to_fw_cfg(FWCfgState *fw_cfg, uint16_t size_key,
+                                 uint16_t data_key, const char *image_name,
+                                 bool try_decompress)
+{
+    size_t size = -1;
+    uint8_t *data;
+
+    if (image_name == NULL) {
+        return;
+    }
+
+    if (try_decompress) {
+        size = load_image_gzipped_buffer(image_name,
+                                         LOAD_IMAGE_MAX_GUNZIP_BYTES, &data);
+    }
+
+    if (size == (size_t)-1) {
+        gchar *contents;
+        gsize length;
+
+        if (!g_file_get_contents(image_name, &contents, &length, NULL)) {
+            error_report("failed to load \"%s\"", image_name);
+            exit(1);
+        }
+        size = length;
+        data = (uint8_t *)contents;
+    }
+
+    fw_cfg_add_i32(fw_cfg, size_key, size);
+    fw_cfg_add_bytes(fw_cfg, data_key, data, size);
+}
+
+static void fw_cfg_add_kernel_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,
+                         loaderparams.kernel_filename,
+                         false);
+
+    if (loaderparams.initrd_filename) {
+        load_image_to_fw_cfg(fw_cfg,
+                             FW_CFG_INITRD_SIZE, FW_CFG_INITRD_DATA,
+                             loaderparams.initrd_filename, false);
+    }
+
+    if (loaderparams.kernel_cmdline) {
+        fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE,
+                       strlen(loaderparams.kernel_cmdline) + 1);
+        fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA,
+                          loaderparams.kernel_cmdline);
+    }
+}
+
+static void loongarch_firmware_boot(LoongArchMachineState *lams, bool firmware_loaded)
+{
+    fw_cfg_add_kernel_info(lams->fw_cfg);
+}
+
+static void loongarch_direct_kernel_boot(LoongArchMachineState *lams)
+{
+    MachineState *machine = MACHINE(lams);
+    int64_t kernel_addr = 0;
+    LoongArchCPU *lacpu;
+    int i;
+
+    kernel_addr = load_kernel_info();
+    if (!machine->firmware) {
+        for (i = 0; i < machine->smp.cpus; i++) {
+            lacpu = LOONGARCH_CPU(qemu_get_cpu(i));
+            lacpu->env.load_elf = true;
+            lacpu->env.elf_address = kernel_addr;
+            qemu_register_reset(reset_load_elf, lacpu);
+        }
+    }
+}
+
 static void loongarch_init(MachineState *machine)
 {
     const char *cpu_model = machine->cpu_type;
-    const char *kernel_filename = machine->kernel_filename;
     ram_addr_t offset = 0;
     ram_addr_t ram_size = machine->ram_size;
     uint64_t highram_size = 0;
     MemoryRegion *address_space_mem = get_system_memory();
     LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
-    LoongArchCPU *lacpu;
     int i;
     bool firmware_loaded;
-    int64_t kernel_addr = 0;
 
     if (!cpu_model) {
         cpu_model = LOONGARCH_CPU_TYPE_NAME("la464");
@@ -414,18 +511,16 @@ static void loongarch_init(MachineState *machine)
                         la_memmap_table,
                         sizeof(struct la_memmap_entry) * (la_memmap_entries));
     }
-
-    if (kernel_filename) {
-        loaderparams.ram_size = ram_size;
-        loaderparams.kernel_filename = kernel_filename;
-        kernel_addr = load_kernel_info();
-        if (!machine->firmware) {
-            for (i = 0; i < machine->smp.cpus; i++) {
-                lacpu = LOONGARCH_CPU(qemu_get_cpu(i));
-                lacpu->env.load_elf = true;
-                lacpu->env.elf_address = kernel_addr;
-                qemu_register_reset(reset_load_elf, lacpu);
-            }
+    loaderparams.ram_size = ram_size;
+    loaderparams.kernel_filename = machine->kernel_filename;
+    loaderparams.kernel_cmdline = machine->kernel_cmdline;
+    loaderparams.initrd_filename = machine->initrd_filename;
+    /* Load the kernel. */
+    if (loaderparams.kernel_filename) {
+        if (firmware_loaded) {
+            loongarch_firmware_boot(lams, firmware_loaded);
+        } else {
+            loongarch_direct_kernel_boot(lams);
         }
     }
     /* Initialize the IO interrupt subsystem */
-- 
2.31.1
^ permalink raw reply related	[flat|nested] 12+ messages in thread
- * [PATCH 3/8] hw/loongarch: Add LoongArch smbios support
  2022-06-20  8:04 [PATCH 0/8] Add some functions for LoongArch Xiaojuan Yang
  2022-06-20  8:04 ` [PATCH 1/8] hw/loongarch: Add default bios startup support Xiaojuan Yang
  2022-06-20  8:04 ` [PATCH 2/8] hw/loongarch: Add -kernel and -initrd options support Xiaojuan Yang
@ 2022-06-20  8:04 ` Xiaojuan Yang
  2022-06-20  8:04 ` [PATCH 4/8] hw/loongarch: Add LoongArch acpi support Xiaojuan Yang
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 12+ messages in thread
From: Xiaojuan Yang @ 2022-06-20  8:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: richard.henderson, gaosong, maobibo, mark.cave-ayland, mst,
	imammedo, ani, f4bug, peter.maydell, chenhuacai
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
---
 hw/loongarch/Kconfig        |  1 +
 hw/loongarch/loongson3.c    | 38 +++++++++++++++++++++++++++++++++++++
 include/hw/loongarch/virt.h |  1 +
 3 files changed, 40 insertions(+)
diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
index 35b6680772..610552e522 100644
--- a/hw/loongarch/Kconfig
+++ b/hw/loongarch/Kconfig
@@ -14,3 +14,4 @@ config LOONGARCH_VIRT
     select LOONGARCH_PCH_MSI
     select LOONGARCH_EXTIOI
     select LS7A_RTC
+    select SMBIOS
diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
index 638280c4e7..b638d02eb5 100644
--- a/hw/loongarch/loongson3.c
+++ b/hw/loongarch/loongson3.c
@@ -30,11 +30,47 @@
 #include "hw/misc/unimp.h"
 #include "hw/loongarch/fw_cfg.h"
 #include "target/loongarch/cpu.h"
+#include "hw/misc/unimp.h"
+#include "hw/loongarch/fw_cfg.h"
+#include "hw/firmware/smbios.h"
 
 #define PM_BASE 0x10080000
 #define PM_SIZE 0x100
 #define PM_CTRL 0x10
 
+static void virt_build_smbios(LoongArchMachineState *lams)
+{
+    MachineState *ms = MACHINE(lams);
+    MachineClass *mc = MACHINE_GET_CLASS(lams);
+    uint8_t *smbios_tables, *smbios_anchor;
+    size_t smbios_tables_len, smbios_anchor_len;
+    const char *product = "QEMU Virtual Machine";
+
+    if (!lams->fw_cfg) {
+        return;
+    }
+
+    smbios_set_defaults("QEMU", product, mc->name, false,
+                        true, SMBIOS_ENTRY_POINT_TYPE_64);
+
+    smbios_get_tables(ms, NULL, 0, &smbios_tables, &smbios_tables_len,
+                      &smbios_anchor, &smbios_anchor_len, &error_fatal);
+
+    if (smbios_anchor) {
+        fw_cfg_add_file(lams->fw_cfg, "etc/smbios/smbios-tables",
+                        smbios_tables, smbios_tables_len);
+        fw_cfg_add_file(lams->fw_cfg, "etc/smbios/smbios-anchor",
+                        smbios_anchor, smbios_anchor_len);
+    }
+}
+
+static void virt_machine_done(Notifier *notifier, void *data)
+{
+    LoongArchMachineState *lams = container_of(notifier,
+                                        LoongArchMachineState, machine_done);
+    virt_build_smbios(lams);
+}
+
 struct la_memmap_entry {
     uint64_t address;
     uint64_t length;
@@ -525,6 +561,8 @@ static void loongarch_init(MachineState *machine)
     }
     /* Initialize the IO interrupt subsystem */
     loongarch_irq_init(lams);
+    lams->machine_done.notify = virt_machine_done;
+    qemu_add_machine_init_done_notifier(&lams->machine_done);
 }
 
 static void loongarch_class_init(ObjectClass *oc, void *data)
diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h
index 448f46fc6b..55bc2fe4e9 100644
--- a/include/hw/loongarch/virt.h
+++ b/include/hw/loongarch/virt.h
@@ -33,6 +33,7 @@ struct LoongArchMachineState {
 
     /* State for other subsystems/APIs: */
     FWCfgState  *fw_cfg;
+    Notifier machine_done;
 };
 
 #define TYPE_LOONGARCH_MACHINE  MACHINE_TYPE_NAME("virt")
-- 
2.31.1
^ permalink raw reply related	[flat|nested] 12+ messages in thread
- * [PATCH 4/8] hw/loongarch: Add LoongArch acpi support
  2022-06-20  8:04 [PATCH 0/8] Add some functions for LoongArch Xiaojuan Yang
                   ` (2 preceding siblings ...)
  2022-06-20  8:04 ` [PATCH 3/8] hw/loongarch: Add LoongArch smbios support Xiaojuan Yang
@ 2022-06-20  8:04 ` Xiaojuan Yang
  2022-06-20  8:04 ` [PATCH 5/8] hw/loongarch: Add fdt support Xiaojuan Yang
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 12+ messages in thread
From: Xiaojuan Yang @ 2022-06-20  8:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: richard.henderson, gaosong, maobibo, mark.cave-ayland, mst,
	imammedo, ani, f4bug, peter.maydell, chenhuacai
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
---
 hw/loongarch/Kconfig        |   2 +
 hw/loongarch/acpi-build.c   | 620 ++++++++++++++++++++++++++++++++++++
 hw/loongarch/loongson3.c    |  78 ++++-
 hw/loongarch/meson.build    |   4 +
 include/hw/loongarch/virt.h |  13 +
 include/hw/pci-host/ls7a.h  |   5 +
 6 files changed, 719 insertions(+), 3 deletions(-)
 create mode 100644 hw/loongarch/acpi-build.c
diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
index 610552e522..a99aa387c3 100644
--- a/hw/loongarch/Kconfig
+++ b/hw/loongarch/Kconfig
@@ -15,3 +15,5 @@ config LOONGARCH_VIRT
     select LOONGARCH_EXTIOI
     select LS7A_RTC
     select SMBIOS
+    select ACPI_PCI
+    select ACPI_HW_REDUCED
diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c
new file mode 100644
index 0000000000..008f661d7b
--- /dev/null
+++ b/hw/loongarch/acpi-build.c
@@ -0,0 +1,620 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Support for generating ACPI tables and passing them to Guests
+ *
+ * Copyright (C) 2021 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu/bitmap.h"
+#include "hw/pci/pci.h"
+#include "hw/core/cpu.h"
+#include "target/loongarch/cpu.h"
+#include "hw/acpi/acpi-defs.h"
+#include "hw/acpi/acpi.h"
+#include "hw/nvram/fw_cfg.h"
+#include "hw/acpi/bios-linker-loader.h"
+#include "migration/vmstate.h"
+#include "hw/mem/memory-device.h"
+#include "sysemu/reset.h"
+
+/* Supported chipsets: */
+#include "hw/pci-host/ls7a.h"
+#include "hw/loongarch/virt.h"
+#include "hw/acpi/aml-build.h"
+
+#include "hw/acpi/utils.h"
+#include "hw/acpi/pci.h"
+
+#include "qom/qom-qobject.h"
+
+#include "hw/acpi/generic_event_device.h"
+
+#define ACPI_BUILD_ALIGN_SIZE             0x1000
+#define ACPI_BUILD_TABLE_SIZE             0x20000
+
+#ifdef DEBUG_ACPI_BUILD
+#define ACPI_BUILD_DPRINTF(fmt, ...)        \
+    do {printf("ACPI_BUILD: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define ACPI_BUILD_DPRINTF(fmt, ...)
+#endif
+
+static void init_common_fadt_data(AcpiFadtData *data)
+{
+    AcpiFadtData fadt = {
+        /* ACPI 5.0: 4.1 Hardware-Reduced ACPI */
+        .rev = 5,
+        .flags = ((1 << ACPI_FADT_F_HW_REDUCED_ACPI) |
+                  (1 << ACPI_FADT_F_RESET_REG_SUP)),
+
+        /* ACPI 5.0: 4.8.3.7 Sleep Control and Status Registers */
+        .sleep_ctl = {
+            .space_id = AML_AS_SYSTEM_MEMORY,
+            .bit_width = 8,
+            .address = GED_REG_ADDR + ACPI_GED_REG_SLEEP_CTL,
+        },
+        .sleep_sts = {
+            .space_id = AML_AS_SYSTEM_MEMORY,
+            .bit_width = 8,
+            .address = GED_REG_ADDR + ACPI_GED_REG_SLEEP_STS,
+        },
+
+        /* ACPI 5.0: 4.8.3.6 Reset Register */
+        .reset_reg = {
+            .space_id = AML_AS_SYSTEM_MEMORY,
+            .bit_width = 8,
+            .address = GED_REG_ADDR + ACPI_GED_REG_RESET,
+        },
+        .reset_val = ACPI_GED_RESET_VALUE,
+    };
+    *data = fadt;
+}
+
+static void acpi_align_size(GArray *blob, unsigned align)
+{
+    /*
+     * Align size to multiple of given size. This reduces the chance
+     * we need to change size in the future (breaking cross version migration).
+     */
+    g_array_set_size(blob, ROUND_UP(acpi_data_len(blob), align));
+}
+
+/*
+ * Loongson CPU firmware and kernel interface specification V3.1.
+ * chapter 8.7 Firmware ACPI Control Structure
+ */
+static void
+build_facs(GArray *table_data)
+{
+    const char *sig = "FACS";
+    const uint8_t reserved[40] = {};
+
+    g_array_append_vals(table_data, sig, 4); /* Signature */
+    build_append_int_noprefix(table_data, 64, 4); /* Length */
+    build_append_int_noprefix(table_data, 0, 4); /* Hardware Signature */
+    build_append_int_noprefix(table_data, 0, 4); /* Firmware Waking Vector */
+    build_append_int_noprefix(table_data, 0, 4); /* Global Lock */
+    build_append_int_noprefix(table_data, 0, 4); /* Flags */
+    g_array_append_vals(table_data, reserved, 40); /* Reserved */
+}
+
+/*
+ * Loongson CPU firmware and kernel interface specification V3.1.
+ * chapter 8.3 Multiple APIC Description Table
+ */
+static void
+build_madt(GArray *table_data, BIOSLinker *linker, LoongArchMachineState *lams)
+{
+    MachineState *ms = MACHINE(lams);
+    int i;
+    AcpiTable table = { .sig = "APIC", .rev = 1, .oem_id = lams->oem_id,
+                        .oem_table_id = lams->oem_table_id };
+
+    acpi_table_begin(&table, table_data);
+
+    /* Local APIC Address */
+    build_append_int_noprefix(table_data, 0, 4);
+    build_append_int_noprefix(table_data, 1 /* PCAT_COMPAT */, 4); /* Flags */
+
+    for (i = 0; i < ms->smp.cpus; i++) {
+        /* Processor Core Interrupt Controller Structure */
+        build_append_int_noprefix(table_data, 17, 1);    /* Type */
+        build_append_int_noprefix(table_data, 15, 1);    /* Length */
+        build_append_int_noprefix(table_data, 1, 1);     /* Version */
+        build_append_int_noprefix(table_data, i + 1, 4); /* ACPI Processor ID */
+        build_append_int_noprefix(table_data, i, 4);     /* Core ID */
+        build_append_int_noprefix(table_data, 1, 4);     /* Flags */
+    }
+
+    /* Extend I/O Interrupt Controller Structure */
+    build_append_int_noprefix(table_data, 20, 1);        /* Type */
+    build_append_int_noprefix(table_data, 13, 1);        /* Length */
+    build_append_int_noprefix(table_data, 1, 1);         /* Version */
+    build_append_int_noprefix(table_data, 3, 1);         /* Cascade */
+    build_append_int_noprefix(table_data, 0, 1);         /* Node */
+    build_append_int_noprefix(table_data, 0xffff, 8);    /* Node map */
+
+    /* MSI Interrupt Controller Structure */
+    build_append_int_noprefix(table_data, 21, 1);        /* Type */
+    build_append_int_noprefix(table_data, 19, 1);        /* Length */
+    build_append_int_noprefix(table_data, 1, 1);         /* Version */
+    build_append_int_noprefix(table_data, LS7A_PCH_MSI_ADDR_LOW, 8);/* Address */
+    build_append_int_noprefix(table_data, 0x40, 4);      /* Start */
+    build_append_int_noprefix(table_data, 0xc0, 4);      /* Count */
+
+    /* Bridge I/O Interrupt Controller Structure */
+    build_append_int_noprefix(table_data, 22, 1);        /* Type */
+    build_append_int_noprefix(table_data, 17, 1);        /* Length */
+    build_append_int_noprefix(table_data, 1, 1);         /* Version */
+    build_append_int_noprefix(table_data, LS7A_PCH_REG_BASE, 8);/* Address */
+    build_append_int_noprefix(table_data, 0x1000, 2);    /* Size */
+    build_append_int_noprefix(table_data, 0, 2);         /* Id */
+    build_append_int_noprefix(table_data, 0x40, 2);      /* Base */
+
+    acpi_table_end(linker, &table);
+}
+
+/*
+ * Loongson CPU firmware and kernel interface specification V3.1.
+ * chapter 8.4 System Resource Affinity Table
+ */
+static void
+build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
+{
+    uint64_t i;
+    LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
+    MachineState *ms = MACHINE(lams);
+    AcpiTable table = { .sig = "SRAT", .rev = 1, .oem_id = lams->oem_id,
+                        .oem_table_id = lams->oem_table_id };
+
+    acpi_table_begin(&table, table_data);
+    build_append_int_noprefix(table_data, 1, 4); /* Reserved */
+    build_append_int_noprefix(table_data, 0, 8); /* Reserved */
+
+    for (i = 0; i < ms->smp.cpus; ++i) {
+        /* Processor Local APIC/SAPIC Affinity Structure */
+        build_append_int_noprefix(table_data, 0, 1);  /* Type  */
+        build_append_int_noprefix(table_data, 16, 1); /* Length */
+        /* Proximity Domain [7:0] */
+        build_append_int_noprefix(table_data, 0, 1);
+        build_append_int_noprefix(table_data, i, 1); /* APIC ID */
+        /* Flags, Table 5-36 */
+        build_append_int_noprefix(table_data, 1, 4);
+        build_append_int_noprefix(table_data, 0, 1); /* Local SAPIC EID */
+        /* Proximity Domain [31:8] */
+        build_append_int_noprefix(table_data, 0, 3);
+        build_append_int_noprefix(table_data, 0, 4); /* Reserved */
+    }
+
+    build_srat_memory(table_data, LOW_MEM_BASE, LOW_MEM_SIZE,
+                      0, MEM_AFFINITY_ENABLED);
+
+    build_srat_memory(table_data, HIGH_MEM_BASE, machine->ram_size - LOW_MEM_SIZE,
+                      0, MEM_AFFINITY_ENABLED);
+
+    acpi_table_end(linker, &table);
+}
+
+typedef
+struct AcpiBuildState {
+    /* Copy of table in RAM (for patching). */
+    MemoryRegion *table_mr;
+    /* Is table patched? */
+    uint8_t patched;
+    void *rsdp;
+    MemoryRegion *rsdp_mr;
+    MemoryRegion *linker_mr;
+} AcpiBuildState;
+
+static void build_gpex_pci0_int(Aml *table)
+{
+    Aml *sb_scope = aml_scope("_SB");
+    Aml *pci0_scope = aml_scope("PCI0");
+    Aml *prt_pkg = aml_varpackage(128);
+    int slot, pin;
+
+    for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
+        for (pin = 0; pin < PCI_NUM_PINS; pin++) {
+            Aml *pkg = aml_package(4);
+            aml_append(pkg, aml_int((slot << 16) | 0xFFFF));
+            aml_append(pkg, aml_int(pin));
+            aml_append(pkg, aml_int(0));
+            aml_append(pkg, aml_int(80 + (slot + pin) % 4));
+            aml_append(prt_pkg, pkg);
+        }
+    }
+    aml_append(pci0_scope, aml_name_decl("_PRT", prt_pkg));
+    aml_append(sb_scope, pci0_scope);
+    aml_append(table, sb_scope);
+}
+
+static void build_dbg_aml(Aml *table)
+{
+    Aml *field;
+    Aml *method;
+    Aml *while_ctx;
+    Aml *scope = aml_scope("\\");
+    Aml *buf = aml_local(0);
+    Aml *len = aml_local(1);
+    Aml *idx = aml_local(2);
+
+    aml_append(scope,
+       aml_operation_region("DBG", AML_SYSTEM_IO, aml_int(0x0402), 0x01));
+    field = aml_field("DBG", AML_BYTE_ACC, AML_NOLOCK, AML_PRESERVE);
+    aml_append(field, aml_named_field("DBGB", 8));
+    aml_append(scope, field);
+
+    method = aml_method("DBUG", 1, AML_NOTSERIALIZED);
+
+    aml_append(method, aml_to_hexstring(aml_arg(0), buf));
+    aml_append(method, aml_to_buffer(buf, buf));
+    aml_append(method, aml_subtract(aml_sizeof(buf), aml_int(1), len));
+    aml_append(method, aml_store(aml_int(0), idx));
+
+    while_ctx = aml_while(aml_lless(idx, len));
+    aml_append(while_ctx,
+        aml_store(aml_derefof(aml_index(buf, idx)), aml_name("DBGB")));
+    aml_append(while_ctx, aml_increment(idx));
+    aml_append(method, while_ctx);
+    aml_append(method, aml_store(aml_int(0x0A), aml_name("DBGB")));
+    aml_append(scope, method);
+    aml_append(table, scope);
+}
+
+static Aml *build_ls7a_osc_method(void)
+{
+    Aml *if_ctx;
+    Aml *if_ctx2;
+    Aml *else_ctx;
+    Aml *method;
+    Aml *a_cwd1 = aml_name("CDW1");
+    Aml *a_ctrl = aml_local(0);
+
+    method = aml_method("_OSC", 4, AML_NOTSERIALIZED);
+    aml_append(method, aml_create_dword_field(aml_arg(3), aml_int(0), "CDW1"));
+
+    if_ctx = aml_if(aml_equal(
+        aml_arg(0), aml_touuid("33DB4D5B-1FF7-401C-9657-7441C03DD766")));
+    aml_append(if_ctx, aml_create_dword_field(aml_arg(3), aml_int(4), "CDW2"));
+    aml_append(if_ctx, aml_create_dword_field(aml_arg(3), aml_int(8), "CDW3"));
+    aml_append(if_ctx, aml_store(aml_name("CDW3"), a_ctrl));
+
+    /*
+     * Always allow native PME, AER (no dependencies)
+     * Allow SHPC (PCI bridges can have SHPC controller)
+     */
+    aml_append(if_ctx, aml_and(a_ctrl, aml_int(0x1F), a_ctrl));
+
+    if_ctx2 = aml_if(aml_lnot(aml_equal(aml_arg(1), aml_int(1))));
+    /* Unknown revision */
+    aml_append(if_ctx2, aml_or(a_cwd1, aml_int(0x08), a_cwd1));
+    aml_append(if_ctx, if_ctx2);
+
+    if_ctx2 = aml_if(aml_lnot(aml_equal(aml_name("CDW3"), a_ctrl)));
+    /* Capabilities bits were masked */
+    aml_append(if_ctx2, aml_or(a_cwd1, aml_int(0x10), a_cwd1));
+    aml_append(if_ctx, if_ctx2);
+
+    /* Update DWORD3 in the buffer */
+    aml_append(if_ctx, aml_store(a_ctrl, aml_name("CDW3")));
+    aml_append(method, if_ctx);
+
+    else_ctx = aml_else();
+    /* Unrecognized UUID */
+    aml_append(else_ctx, aml_or(a_cwd1, aml_int(4), a_cwd1));
+    aml_append(method, else_ctx);
+
+    aml_append(method, aml_return(aml_arg(3)));
+    return method;
+}
+
+static void build_ls7a_uart_device_aml(Aml *table)
+{
+    Aml *dev;
+    Aml *crs;
+    Aml *pkg0, *pkg1, *pkg2;
+    uint32_t uart_irq = LS7A_UART_IRQ;
+
+    Aml *scope = aml_scope("_SB");
+    dev = aml_device("COMA");
+    aml_append(dev, aml_name_decl("_HID", aml_string("PNP0501")));
+    aml_append(dev, aml_name_decl("_UID", aml_int(0)));
+    aml_append(dev, aml_name_decl("_CCA", aml_int(1)));
+    crs = aml_resource_template();
+    aml_append(crs,
+        aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
+                         AML_NON_CACHEABLE, AML_READ_WRITE,
+                         0, 0x1FE001E0, 0x1FE001E7, 0, 0x8));
+    aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
+                                  AML_SHARED, &uart_irq, 1));
+    aml_append(dev, aml_name_decl("_CRS", crs));
+    pkg0 = aml_package(0x2);
+    aml_append(pkg0, aml_int(0x05F5E100));
+    aml_append(pkg0, aml_string("clock-frenquency"));
+    pkg1 = aml_package(0x1);
+    aml_append(pkg1, pkg0);
+    pkg2 = aml_package(0x2);
+    aml_append(pkg2, aml_touuid("DAFFD814-6EBA-4D8C-8A91-BC9BBF4AA301"));
+    aml_append(pkg2, pkg1);
+    aml_append(dev, aml_name_decl("_DSD", pkg2));
+    aml_append(scope, dev);
+    aml_append(table, scope);
+}
+
+/*
+ * Loongson CPU firmware and kernel interface specification V3.1.
+ * chapter 8.6 Differentiated System Description Table
+ */
+static void
+build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine)
+{
+    Aml *dsdt, *sb_scope, *scope, *dev, *crs, *pkg;
+    int root_bus_limit = 0x7F;
+    LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
+    AcpiTable table = { .sig = "DSDT", .rev = 1, .oem_id = lams->oem_id,
+                        .oem_table_id = lams->oem_table_id };
+
+    acpi_table_begin(&table, table_data);
+
+    dsdt = init_aml_allocator();
+
+    build_dbg_aml(dsdt);
+
+    sb_scope = aml_scope("_SB");
+    dev = aml_device("PCI0");
+    aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A08")));
+    aml_append(dev, aml_name_decl("_CID", aml_eisaid("PNP0A03")));
+    aml_append(dev, aml_name_decl("_ADR", aml_int(0)));
+    aml_append(dev, aml_name_decl("_BBN", aml_int(0)));
+    aml_append(dev, aml_name_decl("_UID", aml_int(1)));
+    aml_append(dev, build_ls7a_osc_method());
+    aml_append(sb_scope, dev);
+    aml_append(dsdt, sb_scope);
+
+    build_gpex_pci0_int(dsdt);
+    build_ls7a_uart_device_aml(dsdt);
+    if (lams->acpi_ged) {
+        build_ged_aml(dsdt, "\\_SB."GED_DEVICE,
+                      HOTPLUG_HANDLER(lams->acpi_ged),
+                      LS7A_SCI_IRQ - PCH_PIC_IRQ_OFFSET, AML_SYSTEM_MEMORY,
+                      GED_EVT_ADDR);
+    }
+
+    scope = aml_scope("\\_SB.PCI0");
+    /* Build PCI0._CRS */
+    crs = aml_resource_template();
+    aml_append(crs,
+        aml_word_bus_number(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE,
+                            0x0000, 0x0, root_bus_limit,
+                            0x0000, root_bus_limit + 1));
+    aml_append(crs,
+        aml_dword_io(AML_MIN_FIXED, AML_MAX_FIXED,
+                    AML_POS_DECODE, AML_ENTIRE_RANGE,
+                    0x0000, 0x0000, 0xFFFF, 0x18000000, 0x10000));
+    aml_append(crs,
+        aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
+                         AML_CACHEABLE, AML_READ_WRITE,
+                         0, LS7A_PCI_MEM_BASE,
+                         LS7A_PCI_MEM_BASE + LS7A_PCI_MEM_SIZE - 1,
+                         0, LS7A_PCI_MEM_BASE));
+    aml_append(scope, aml_name_decl("_CRS", crs));
+    aml_append(dsdt, scope);
+
+    /* System State Package */
+    scope = aml_scope("\\");
+    pkg = aml_package(4);
+    aml_append(pkg, aml_int(ACPI_GED_SLP_TYP_S5));
+    aml_append(pkg, aml_int(0)); /* ignored */
+    aml_append(pkg, aml_int(0)); /* reserved */
+    aml_append(pkg, aml_int(0)); /* reserved */
+    aml_append(scope, aml_name_decl("_S5", pkg));
+    aml_append(dsdt, scope);
+    /* Copy AML table into ACPI tables blob and patch header there */
+    g_array_append_vals(table_data, dsdt->buf->data, dsdt->buf->len);
+    acpi_table_end(linker, &table);
+    free_aml_allocator();
+}
+
+static void acpi_build(AcpiBuildTables *tables, MachineState *machine)
+{
+    LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
+    GArray *table_offsets;
+    AcpiFadtData fadt_data;
+    unsigned facs, rsdt, fadt, dsdt;
+    uint8_t *u;
+    size_t aml_len = 0;
+    GArray *tables_blob = tables->table_data;
+
+    init_common_fadt_data(&fadt_data);
+
+    table_offsets = g_array_new(false, true, sizeof(uint32_t));
+    ACPI_BUILD_DPRINTF("init ACPI tables\n");
+
+    bios_linker_loader_alloc(tables->linker,
+                             ACPI_BUILD_TABLE_FILE, tables_blob,
+                             64, false);
+
+    /*
+     * FACS is pointed to by FADT.
+     * We place it first since it's the only table that has alignment
+     * requirements.
+     */
+    facs = tables_blob->len;
+    build_facs(tables_blob);
+
+    /* DSDT is pointed to by FADT */
+    dsdt = tables_blob->len;
+    build_dsdt(tables_blob, tables->linker, machine);
+
+    /*
+     * Count the size of the DSDT, we will need it for
+     * legacy sizing of ACPI tables.
+     */
+    aml_len += tables_blob->len - dsdt;
+
+    /* ACPI tables pointed to by RSDT */
+    fadt = tables_blob->len;
+    acpi_add_table(table_offsets, tables_blob);
+    fadt_data.facs_tbl_offset = &facs;
+    fadt_data.dsdt_tbl_offset = &dsdt;
+    fadt_data.xdsdt_tbl_offset = &dsdt;
+    build_fadt(tables_blob, tables->linker, &fadt_data,
+               lams->oem_id, lams->oem_table_id);
+    aml_len += tables_blob->len - fadt;
+
+    acpi_add_table(table_offsets, tables_blob);
+    build_madt(tables_blob, tables->linker, lams);
+
+    acpi_add_table(table_offsets, tables_blob);
+    build_srat(tables_blob, tables->linker, machine);
+
+    acpi_add_table(table_offsets, tables_blob);
+    {
+        AcpiMcfgInfo mcfg = {
+           .base = cpu_to_le64(LS_PCIECFG_BASE),
+           .size = cpu_to_le64(LS_PCIECFG_SIZE),
+        };
+        build_mcfg(tables_blob, tables->linker, &mcfg, lams->oem_id,
+                   lams->oem_table_id);
+    }
+
+    /* Add tables supplied by user (if any) */
+    for (u = acpi_table_first(); u; u = acpi_table_next(u)) {
+        unsigned len = acpi_table_len(u);
+
+        acpi_add_table(table_offsets, tables_blob);
+        g_array_append_vals(tables_blob, u, len);
+    }
+
+    /* RSDT is pointed to by RSDP */
+    rsdt = tables_blob->len;
+    build_rsdt(tables_blob, tables->linker, table_offsets,
+               lams->oem_id, lams->oem_table_id);
+
+    /* RSDP is in FSEG memory, so allocate it separately */
+    {
+        AcpiRsdpData rsdp_data = {
+            .revision = 0,
+            .oem_id = lams->oem_id,
+            .xsdt_tbl_offset = NULL,
+            .rsdt_tbl_offset = &rsdt,
+        };
+        build_rsdp(tables->rsdp, tables->linker, &rsdp_data);
+    }
+
+    /*
+     * The align size is 128, warn if 64k is not enough therefore
+     * the align size could be resized.
+     */
+    if (tables_blob->len > ACPI_BUILD_TABLE_SIZE / 2) {
+        warn_report("ACPI table size %u exceeds %d bytes,"
+                    " migration may not work",
+                    tables_blob->len, ACPI_BUILD_TABLE_SIZE / 2);
+        error_printf("Try removing CPUs, NUMA nodes, memory slots"
+                     " or PCI bridges.");
+    }
+
+    acpi_align_size(tables->linker->cmd_blob, ACPI_BUILD_ALIGN_SIZE);
+
+    /* Cleanup memory that's no longer used. */
+    g_array_free(table_offsets, true);
+}
+
+static void acpi_ram_update(MemoryRegion *mr, GArray *data)
+{
+    uint32_t size = acpi_data_len(data);
+
+    /*
+     * Make sure RAM size is correct - in case it got changed
+     * e.g. by migration
+     */
+    memory_region_ram_resize(mr, size, &error_abort);
+
+    memcpy(memory_region_get_ram_ptr(mr), data->data, size);
+    memory_region_set_dirty(mr, 0, size);
+}
+
+static void acpi_build_update(void *build_opaque)
+{
+    AcpiBuildState *build_state = build_opaque;
+    AcpiBuildTables tables;
+
+    /* No state to update or already patched? Nothing to do. */
+    if (!build_state || build_state->patched) {
+        return;
+    }
+    build_state->patched = 1;
+
+    acpi_build_tables_init(&tables);
+
+    acpi_build(&tables, MACHINE(qdev_get_machine()));
+
+    acpi_ram_update(build_state->table_mr, tables.table_data);
+    acpi_ram_update(build_state->rsdp_mr, tables.rsdp);
+    acpi_ram_update(build_state->linker_mr, tables.linker->cmd_blob);
+
+    acpi_build_tables_cleanup(&tables, true);
+}
+
+static void acpi_build_reset(void *build_opaque)
+{
+    AcpiBuildState *build_state = build_opaque;
+    build_state->patched = 0;
+}
+
+static const VMStateDescription vmstate_acpi_build = {
+    .name = "acpi_build",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(patched, AcpiBuildState),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
+void loongarch_acpi_setup(LoongArchMachineState *lams)
+{
+    AcpiBuildTables tables;
+    AcpiBuildState *build_state;
+
+    if (!lams->fw_cfg) {
+        ACPI_BUILD_DPRINTF("No fw cfg. Bailing out.\n");
+        return;
+    }
+
+    if (!loongarch_is_acpi_enabled(lams)) {
+        ACPI_BUILD_DPRINTF("ACPI disabled. Bailing out.\n");
+        return;
+    }
+
+    build_state = g_malloc0(sizeof *build_state);
+
+    acpi_build_tables_init(&tables);
+    acpi_build(&tables, MACHINE(lams));
+
+    /* Now expose it all to Guest */
+    build_state->table_mr = acpi_add_rom_blob(acpi_build_update,
+                                              build_state, tables.table_data,
+                                              ACPI_BUILD_TABLE_FILE);
+    assert(build_state->table_mr != NULL);
+
+    build_state->linker_mr =
+        acpi_add_rom_blob(acpi_build_update, build_state,
+                          tables.linker->cmd_blob, ACPI_BUILD_LOADER_FILE);
+
+    build_state->rsdp_mr = acpi_add_rom_blob(acpi_build_update,
+                                             build_state, tables.rsdp,
+                                             ACPI_BUILD_RSDP_FILE);
+
+    qemu_register_reset(acpi_build_reset, build_state);
+    acpi_build_reset(build_state);
+    vmstate_register(NULL, 0, &vmstate_acpi_build, build_state);
+
+    /*
+     * Cleanup tables but don't free the memory: we track it
+     * in build_state.
+     */
+    acpi_build_tables_cleanup(&tables, false);
+}
diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
index b638d02eb5..cc449a12ae 100644
--- a/hw/loongarch/loongson3.c
+++ b/hw/loongarch/loongson3.c
@@ -33,6 +33,10 @@
 #include "hw/misc/unimp.h"
 #include "hw/loongarch/fw_cfg.h"
 #include "hw/firmware/smbios.h"
+#include "hw/acpi/aml-build.h"
+#include "qapi/qapi-visit-common.h"
+#include "hw/acpi/generic_event_device.h"
+#include "hw/mem/nvdimm.h"
 
 #define PM_BASE 0x10080000
 #define PM_SIZE 0x100
@@ -69,6 +73,7 @@ static void virt_machine_done(Notifier *notifier, void *data)
     LoongArchMachineState *lams = container_of(notifier,
                                         LoongArchMachineState, machine_done);
     virt_build_smbios(lams);
+    loongarch_acpi_setup(lams);
 }
 
 struct la_memmap_entry {
@@ -103,7 +108,6 @@ static int la_memmap_add_entry(uint64_t address, uint64_t length, uint32_t type)
     return la_memmap_entries;
 }
 
-
 /*
  * This is a placeholder for missing ACPI,
  * and will eventually be replaced.
@@ -174,7 +178,32 @@ static int64_t load_kernel_info(void)
     return kernel_entry;
 }
 
-static void loongarch_devices_init(DeviceState *pch_pic)
+static DeviceState *create_acpi_ged(DeviceState *pch_pic, LoongArchMachineState *lams)
+{
+    DeviceState *dev;
+    MachineState *ms = MACHINE(lams);
+    uint32_t event = ACPI_GED_PWR_DOWN_EVT;
+
+    if (ms->ram_slots) {
+        event |= ACPI_GED_MEM_HOTPLUG_EVT;
+    }
+    dev = qdev_new(TYPE_ACPI_GED);
+    qdev_prop_set_uint32(dev, "ged-event", event);
+
+    /* ged event */
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, GED_EVT_ADDR);
+    /* memory hotplug */
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, GED_MEM_ADDR);
+    /* ged regs used for reset and power down */
+    sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, GED_REG_ADDR);
+
+    sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0,
+                       qdev_get_gpio_in(pch_pic, LS7A_SCI_IRQ - PCH_PIC_IRQ_OFFSET));
+    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+    return dev;
+}
+
+static void loongarch_devices_init(DeviceState *pch_pic, LoongArchMachineState *lams)
 {
     DeviceState *gpex_dev;
     SysBusDevice *d;
@@ -250,6 +279,8 @@ static void loongarch_devices_init(DeviceState *pch_pic)
     memory_region_init_io(pm_mem, NULL, &loongarch_virt_pm_ops,
                           NULL, "loongarch_virt_pm", PM_SIZE);
     memory_region_add_subregion(get_system_memory(), PM_BASE, pm_mem);
+    /* acpi ged */
+    lams->acpi_ged = create_acpi_ged(pch_pic, lams);
 }
 
 static void loongarch_irq_init(LoongArchMachineState *lams)
@@ -347,7 +378,7 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
                               qdev_get_gpio_in(extioi, i + PCH_MSI_IRQ_START));
     }
 
-    loongarch_devices_init(pch_pic);
+    loongarch_devices_init(pch_pic, lams);
 }
 
 static bool loongarch_firmware_init(LoongArchMachineState *lams)
@@ -565,6 +596,40 @@ static void loongarch_init(MachineState *machine)
     qemu_add_machine_init_done_notifier(&lams->machine_done);
 }
 
+bool loongarch_is_acpi_enabled(LoongArchMachineState *lams)
+{
+    if (lams->acpi == ON_OFF_AUTO_OFF) {
+        return false;
+    }
+    return true;
+}
+
+static void loongarch_get_acpi(Object *obj, Visitor *v, const char *name,
+                               void *opaque, Error **errp)
+{
+    LoongArchMachineState *lams = LOONGARCH_MACHINE(obj);
+    OnOffAuto acpi = lams->acpi;
+
+    visit_type_OnOffAuto(v, name, &acpi, errp);
+}
+
+static void loongarch_set_acpi(Object *obj, Visitor *v, const char *name,
+                               void *opaque, Error **errp)
+{
+    LoongArchMachineState *lams = LOONGARCH_MACHINE(obj);
+
+    visit_type_OnOffAuto(v, name, &lams->acpi, errp);
+}
+
+static void loongarch_machine_initfn(Object *obj)
+{
+    LoongArchMachineState *lams = LOONGARCH_MACHINE(obj);
+
+    lams->acpi = ON_OFF_AUTO_AUTO;
+    lams->oem_id = g_strndup(ACPI_BUILD_APPNAME6, 6);
+    lams->oem_table_id = g_strndup(ACPI_BUILD_APPNAME8, 8);
+}
+
 static void loongarch_class_init(ObjectClass *oc, void *data)
 {
     MachineClass *mc = MACHINE_CLASS(oc);
@@ -580,6 +645,12 @@ static void loongarch_class_init(ObjectClass *oc, void *data)
     mc->block_default_type = IF_VIRTIO;
     mc->default_boot_order = "c";
     mc->no_cdrom = 1;
+
+    object_class_property_add(oc, "acpi", "OnOffAuto",
+        loongarch_get_acpi, loongarch_set_acpi,
+        NULL, NULL);
+    object_class_property_set_description(oc, "acpi",
+        "Enable ACPI");
 }
 
 static const TypeInfo loongarch_machine_types[] = {
@@ -588,6 +659,7 @@ static const TypeInfo loongarch_machine_types[] = {
         .parent         = TYPE_MACHINE,
         .instance_size  = sizeof(LoongArchMachineState),
         .class_init     = loongarch_class_init,
+        .instance_init = loongarch_machine_initfn,
     }
 };
 
diff --git a/hw/loongarch/meson.build b/hw/loongarch/meson.build
index cecb1a5d65..3e7cbcfc05 100644
--- a/hw/loongarch/meson.build
+++ b/hw/loongarch/meson.build
@@ -1,4 +1,8 @@
 loongarch_ss = ss.source_set()
+loongarch_ss.add(files(
+    'fw_cfg.c',
+))
 loongarch_ss.add(when: 'CONFIG_LOONGARCH_VIRT', if_true: files('loongson3.c'))
+loongarch_ss.add(when: 'CONFIG_ACPI', if_true: files('acpi-build.c'))
 
 hw_arch += {'loongarch': loongarch_ss}
diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h
index 55bc2fe4e9..63b6917c15 100644
--- a/include/hw/loongarch/virt.h
+++ b/include/hw/loongarch/virt.h
@@ -21,6 +21,13 @@
 #define LA_BIOS_BASE            0x1c000000
 #define LA_BIOS_SIZE            (4 * MiB)
 
+#define LOW_MEM_BASE 0
+#define LOW_MEM_SIZE 0x10000000
+#define HIGH_MEM_BASE 0x90000000
+#define GED_EVT_ADDR 0x100e0000
+#define GED_MEM_ADDR (GED_EVT_ADDR + ACPI_GED_EVT_SEL_LEN)
+#define GED_REG_ADDR (GED_MEM_ADDR + MEMORY_HOTPLUG_IO_LEN)
+
 struct LoongArchMachineState {
     /*< private >*/
     MachineState parent_obj;
@@ -34,8 +41,14 @@ struct LoongArchMachineState {
     /* State for other subsystems/APIs: */
     FWCfgState  *fw_cfg;
     Notifier machine_done;
+    OnOffAuto   acpi;
+    char        *oem_id;
+    char        *oem_table_id;
+    DeviceState *acpi_ged;
 };
 
 #define TYPE_LOONGARCH_MACHINE  MACHINE_TYPE_NAME("virt")
 OBJECT_DECLARE_SIMPLE_TYPE(LoongArchMachineState, LOONGARCH_MACHINE)
+bool loongarch_is_acpi_enabled(LoongArchMachineState *lams);
+void loongarch_acpi_setup(LoongArchMachineState *lams);
 #endif
diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h
index 08c5f78be2..f93c3e3287 100644
--- a/include/hw/pci-host/ls7a.h
+++ b/include/hw/pci-host/ls7a.h
@@ -23,6 +23,9 @@
 #define LS7A_PCI_IO_BASE        0x18004000UL
 #define LS7A_PCI_IO_SIZE        0xC000
 
+#define LS7A_PCI_MEM_BASE        0x40000000UL
+#define LS7A_PCI_MEM_SIZE        0x40000000UL
+
 #define LS7A_PCH_REG_BASE       0x10000000UL
 #define LS7A_IOAPIC_REG_BASE    (LS7A_PCH_REG_BASE)
 #define LS7A_PCH_MSI_ADDR_LOW   0x2FF00000UL
@@ -41,4 +44,6 @@
 #define LS7A_MISC_REG_BASE      (LS7A_PCH_REG_BASE + 0x00080000)
 #define LS7A_RTC_REG_BASE       (LS7A_MISC_REG_BASE + 0x00050100)
 #define LS7A_RTC_LEN            0x100
+#define LS7A_ACPI_REG_BASE      (LS7A_MISC_REG_BASE + 0x00050000)
+#define LS7A_SCI_IRQ            (PCH_PIC_IRQ_OFFSET + 4)
 #endif
-- 
2.31.1
^ permalink raw reply related	[flat|nested] 12+ messages in thread
- * [PATCH 5/8] hw/loongarch: Add fdt support
  2022-06-20  8:04 [PATCH 0/8] Add some functions for LoongArch Xiaojuan Yang
                   ` (3 preceding siblings ...)
  2022-06-20  8:04 ` [PATCH 4/8] hw/loongarch: Add LoongArch acpi support Xiaojuan Yang
@ 2022-06-20  8:04 ` Xiaojuan Yang
  2022-06-20 10:01   ` chen huacai
  2022-06-20  8:04 ` [PATCH 6/8] hw/loongarch: Fix loongarch ipi device Xiaojuan Yang
                   ` (3 subsequent siblings)
  8 siblings, 1 reply; 12+ messages in thread
From: Xiaojuan Yang @ 2022-06-20  8:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: richard.henderson, gaosong, maobibo, mark.cave-ayland, mst,
	imammedo, ani, f4bug, peter.maydell, chenhuacai
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
---
 hw/loongarch/loongson3.c    | 136 +++++++++++++++++++++++++++++++++++-
 include/hw/loongarch/virt.h |   4 ++
 target/loongarch/cpu.c      |   1 +
 target/loongarch/cpu.h      |   3 +
 4 files changed, 141 insertions(+), 3 deletions(-)
diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
index cc449a12ae..146f582dbe 100644
--- a/hw/loongarch/loongson3.c
+++ b/hw/loongarch/loongson3.c
@@ -37,6 +37,129 @@
 #include "qapi/qapi-visit-common.h"
 #include "hw/acpi/generic_event_device.h"
 #include "hw/mem/nvdimm.h"
+#include "sysemu/device_tree.h"
+#include <libfdt.h>
+
+static void create_fdt(LoongArchMachineState *lams)
+{
+    MachineState *ms = MACHINE(lams);
+
+    ms->fdt = create_device_tree(&lams->fdt_size);
+    if (!ms->fdt) {
+        error_report("create_device_tree() failed");
+        exit(1);
+    }
+
+    /* Header */
+    qemu_fdt_setprop_string(ms->fdt, "/", "compatible",
+                            "linux,dummy-loongson3");
+    qemu_fdt_setprop_cell(ms->fdt, "/", "#address-cells", 0x2);
+    qemu_fdt_setprop_cell(ms->fdt, "/", "#size-cells", 0x2);
+}
+
+static void fdt_add_cpu_nodes(const LoongArchMachineState *lams)
+{
+    int num;
+    const MachineState *ms = MACHINE(lams);
+    int smp_cpus = ms->smp.cpus;
+
+    qemu_fdt_add_subnode(ms->fdt, "/cpus");
+    qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#address-cells", 0x1);
+    qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#size-cells", 0x0);
+
+    /* cpu nodes */
+    for (num = smp_cpus - 1; num >= 0; num--) {
+        char *nodename = g_strdup_printf("/cpus/cpu@%d", num);
+        LoongArchCPU *cpu = LOONGARCH_CPU(qemu_get_cpu(num));
+
+        qemu_fdt_add_subnode(ms->fdt, nodename);
+        qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "cpu");
+        qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
+                                cpu->dtb_compatible);
+        qemu_fdt_setprop_cell(ms->fdt, nodename, "reg", num);
+        qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle",
+                              qemu_fdt_alloc_phandle(ms->fdt));
+        g_free(nodename);
+    }
+
+    /*cpu map */
+    qemu_fdt_add_subnode(ms->fdt, "/cpus/cpu-map");
+
+    for (num = smp_cpus - 1; num >= 0; num--) {
+        char *cpu_path = g_strdup_printf("/cpus/cpu@%d", num);
+        char *map_path;
+
+        if (ms->smp.threads > 1) {
+            map_path = g_strdup_printf(
+                "/cpus/cpu-map/socket%d/core%d/thread%d",
+                num / (ms->smp.cores * ms->smp.threads),
+                (num / ms->smp.threads) % ms->smp.cores,
+                num % ms->smp.threads);
+        } else {
+            map_path = g_strdup_printf(
+                "/cpus/cpu-map/socket%d/core%d",
+                num / ms->smp.cores,
+                num % ms->smp.cores);
+        }
+        qemu_fdt_add_path(ms->fdt, map_path);
+        qemu_fdt_setprop_phandle(ms->fdt, map_path, "cpu", cpu_path);
+
+        g_free(map_path);
+        g_free(cpu_path);
+    }
+}
+
+static void fdt_add_fw_cfg_node(const LoongArchMachineState *lams)
+{
+    char *nodename;
+    hwaddr base = FW_CFG_ADDR;
+    const MachineState *ms = MACHINE(lams);
+
+    nodename = g_strdup_printf("/fw_cfg@%" PRIx64, base);
+    qemu_fdt_add_subnode(ms->fdt, nodename);
+    qemu_fdt_setprop_string(ms->fdt, nodename,
+                            "compatible", "qemu,fw-cfg-mmio");
+    qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
+                                 2, base, 2, 0x8);
+    qemu_fdt_setprop(ms->fdt, nodename, "dma-coherent", NULL, 0);
+    g_free(nodename);
+}
+
+static void fdt_add_pcie_node(const LoongArchMachineState *lams)
+{
+    char *nodename;
+    hwaddr base_mmio = LS7A_PCI_MEM_BASE;
+    hwaddr size_mmio = LS7A_PCI_MEM_SIZE;
+    hwaddr base_pio = LS7A_PCI_IO_BASE;
+    hwaddr size_pio = LS7A_PCI_IO_SIZE;
+    hwaddr base_pcie = LS_PCIECFG_BASE;
+    hwaddr size_pcie = LS_PCIECFG_SIZE;
+    hwaddr base = base_pcie;
+
+    const MachineState *ms = MACHINE(lams);
+
+    nodename = g_strdup_printf("/pcie@%" PRIx64, base);
+    qemu_fdt_add_subnode(ms->fdt, nodename);
+    qemu_fdt_setprop_string(ms->fdt, nodename,
+                            "compatible", "pci-host-ecam-generic");
+    qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "pci");
+    qemu_fdt_setprop_cell(ms->fdt, nodename, "#address-cells", 3);
+    qemu_fdt_setprop_cell(ms->fdt, nodename, "#size-cells", 2);
+    qemu_fdt_setprop_cell(ms->fdt, nodename, "linux,pci-domain", 0);
+    qemu_fdt_setprop_cells(ms->fdt, nodename, "bus-range", 0,
+                           PCIE_MMCFG_BUS(LS_PCIECFG_SIZE - 1));
+    qemu_fdt_setprop(ms->fdt, nodename, "dma-coherent", NULL, 0);
+    qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
+                                 2, base_pcie, 2, size_pcie);
+    qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "ranges",
+                                 1, FDT_PCI_RANGE_IOPORT, 2, LS7A_PCI_IO_OFFSET,
+                                 2, base_pio, 2, size_pio,
+                                 1, FDT_PCI_RANGE_MMIO, 2, base_mmio,
+                                 2, base_mmio, 2, size_mmio);
+    g_free(nodename);
+    qemu_fdt_dumpdtb(ms->fdt, lams->fdt_size);
+}
+
 
 #define PM_BASE 0x10080000
 #define PM_SIZE 0x100
@@ -546,12 +669,12 @@ static void loongarch_init(MachineState *machine)
         error_report("ram_size must be greater than 1G.");
         exit(1);
     }
-
+    create_fdt(lams);
     /* Init CPUs */
     for (i = 0; i < machine->smp.cpus; i++) {
         cpu_create(machine->cpu_type);
     }
-
+    fdt_add_cpu_nodes(lams);
     /* Add memory region */
     memory_region_init_alias(&lams->lowmem, NULL, "loongarch.lowram",
                              machine->ram, 0, 256 * MiB);
@@ -572,12 +695,12 @@ static void loongarch_init(MachineState *machine)
     firmware_loaded = loongarch_firmware_init(lams);
     lams->fw_cfg = loongarch_fw_cfg_init(ram_size, machine);
     rom_set_fw(lams->fw_cfg);
-
     if (lams->fw_cfg != NULL) {
         fw_cfg_add_file(lams->fw_cfg, "etc/memmap",
                         la_memmap_table,
                         sizeof(struct la_memmap_entry) * (la_memmap_entries));
     }
+    fdt_add_fw_cfg_node(lams);
     loaderparams.ram_size = ram_size;
     loaderparams.kernel_filename = machine->kernel_filename;
     loaderparams.kernel_cmdline = machine->kernel_cmdline;
@@ -594,6 +717,13 @@ static void loongarch_init(MachineState *machine)
     loongarch_irq_init(lams);
     lams->machine_done.notify = virt_machine_done;
     qemu_add_machine_init_done_notifier(&lams->machine_done);
+    fdt_add_pcie_node(lams);
+
+    /* load fdt */
+    MemoryRegion *fdt_rom = g_new(MemoryRegion, 1);
+    memory_region_init_rom(fdt_rom, NULL, "fdt", LA_FDT_SIZE, &error_fatal);
+    memory_region_add_subregion(get_system_memory(), LA_FDT_BASE, fdt_rom);
+    rom_add_blob_fixed("fdt", machine->fdt, lams->fdt_size, LA_FDT_BASE);
 }
 
 bool loongarch_is_acpi_enabled(LoongArchMachineState *lams)
diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h
index 63b6917c15..e31ddde045 100644
--- a/include/hw/loongarch/virt.h
+++ b/include/hw/loongarch/virt.h
@@ -28,6 +28,9 @@
 #define GED_MEM_ADDR (GED_EVT_ADDR + ACPI_GED_EVT_SEL_LEN)
 #define GED_REG_ADDR (GED_MEM_ADDR + MEMORY_HOTPLUG_IO_LEN)
 
+#define LA_FDT_BASE             0x1c400000
+#define LA_FDT_SIZE             0x100000
+
 struct LoongArchMachineState {
     /*< private >*/
     MachineState parent_obj;
@@ -45,6 +48,7 @@ struct LoongArchMachineState {
     char        *oem_id;
     char        *oem_table_id;
     DeviceState *acpi_ged;
+    int fdt_size;
 };
 
 #define TYPE_LOONGARCH_MACHINE  MACHINE_TYPE_NAME("virt")
diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index 4c8f96bc3a..401d3fd30a 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -328,6 +328,7 @@ static void loongarch_la464_initfn(Object *obj)
         env->cpucfg[i] = 0x0;
     }
 
+    cpu->dtb_compatible = "loongarch,Loongson-3A5000";
     env->cpucfg[0] = 0x14c010;  /* PRID */
 
     uint32_t data = 0;
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index 71a5036c3c..ce394c3287 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -326,6 +326,9 @@ struct ArchCPU {
     CPUNegativeOffsetState neg;
     CPULoongArchState env;
     QEMUTimer timer;
+
+    /* 'compatible' string for this CPU for Linux device trees */
+    const char *dtb_compatible;
 };
 
 #define TYPE_LOONGARCH_CPU "loongarch-cpu"
-- 
2.31.1
^ permalink raw reply related	[flat|nested] 12+ messages in thread
- * Re: [PATCH 5/8] hw/loongarch: Add fdt support
  2022-06-20  8:04 ` [PATCH 5/8] hw/loongarch: Add fdt support Xiaojuan Yang
@ 2022-06-20 10:01   ` chen huacai
  0 siblings, 0 replies; 12+ messages in thread
From: chen huacai @ 2022-06-20 10:01 UTC (permalink / raw)
  To: Xiaojuan Yang
  Cc: qemu-level, Richard Henderson, Song Gao, maobibo,
	mark.cave-ayland, Michael S. Tsirkin, imammedo, ani,
	Philippe Mathieu-Daudé, Peter Maydell, chenhuacai
Hi, Xiaojuan,
On Mon, Jun 20, 2022 at 4:11 PM Xiaojuan Yang <yangxiaojuan@loongson.cn> wrote:
>
> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
> ---
>  hw/loongarch/loongson3.c    | 136 +++++++++++++++++++++++++++++++++++-
>  include/hw/loongarch/virt.h |   4 ++
>  target/loongarch/cpu.c      |   1 +
>  target/loongarch/cpu.h      |   3 +
>  4 files changed, 141 insertions(+), 3 deletions(-)
>
> diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
> index cc449a12ae..146f582dbe 100644
> --- a/hw/loongarch/loongson3.c
> +++ b/hw/loongarch/loongson3.c
> @@ -37,6 +37,129 @@
>  #include "qapi/qapi-visit-common.h"
>  #include "hw/acpi/generic_event_device.h"
>  #include "hw/mem/nvdimm.h"
> +#include "sysemu/device_tree.h"
> +#include <libfdt.h>
> +
> +static void create_fdt(LoongArchMachineState *lams)
> +{
> +    MachineState *ms = MACHINE(lams);
> +
> +    ms->fdt = create_device_tree(&lams->fdt_size);
> +    if (!ms->fdt) {
> +        error_report("create_device_tree() failed");
> +        exit(1);
> +    }
> +
> +    /* Header */
> +    qemu_fdt_setprop_string(ms->fdt, "/", "compatible",
> +                            "linux,dummy-loongson3");
> +    qemu_fdt_setprop_cell(ms->fdt, "/", "#address-cells", 0x2);
> +    qemu_fdt_setprop_cell(ms->fdt, "/", "#size-cells", 0x2);
> +}
> +
> +static void fdt_add_cpu_nodes(const LoongArchMachineState *lams)
> +{
> +    int num;
> +    const MachineState *ms = MACHINE(lams);
> +    int smp_cpus = ms->smp.cpus;
> +
> +    qemu_fdt_add_subnode(ms->fdt, "/cpus");
> +    qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#address-cells", 0x1);
> +    qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#size-cells", 0x0);
> +
> +    /* cpu nodes */
> +    for (num = smp_cpus - 1; num >= 0; num--) {
> +        char *nodename = g_strdup_printf("/cpus/cpu@%d", num);
> +        LoongArchCPU *cpu = LOONGARCH_CPU(qemu_get_cpu(num));
> +
> +        qemu_fdt_add_subnode(ms->fdt, nodename);
> +        qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "cpu");
> +        qemu_fdt_setprop_string(ms->fdt, nodename, "compatible",
> +                                cpu->dtb_compatible);
> +        qemu_fdt_setprop_cell(ms->fdt, nodename, "reg", num);
> +        qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle",
> +                              qemu_fdt_alloc_phandle(ms->fdt));
> +        g_free(nodename);
> +    }
> +
> +    /*cpu map */
> +    qemu_fdt_add_subnode(ms->fdt, "/cpus/cpu-map");
> +
> +    for (num = smp_cpus - 1; num >= 0; num--) {
> +        char *cpu_path = g_strdup_printf("/cpus/cpu@%d", num);
> +        char *map_path;
> +
> +        if (ms->smp.threads > 1) {
> +            map_path = g_strdup_printf(
> +                "/cpus/cpu-map/socket%d/core%d/thread%d",
> +                num / (ms->smp.cores * ms->smp.threads),
> +                (num / ms->smp.threads) % ms->smp.cores,
> +                num % ms->smp.threads);
> +        } else {
> +            map_path = g_strdup_printf(
> +                "/cpus/cpu-map/socket%d/core%d",
> +                num / ms->smp.cores,
> +                num % ms->smp.cores);
> +        }
> +        qemu_fdt_add_path(ms->fdt, map_path);
> +        qemu_fdt_setprop_phandle(ms->fdt, map_path, "cpu", cpu_path);
> +
> +        g_free(map_path);
> +        g_free(cpu_path);
> +    }
> +}
> +
> +static void fdt_add_fw_cfg_node(const LoongArchMachineState *lams)
> +{
> +    char *nodename;
> +    hwaddr base = FW_CFG_ADDR;
> +    const MachineState *ms = MACHINE(lams);
> +
> +    nodename = g_strdup_printf("/fw_cfg@%" PRIx64, base);
> +    qemu_fdt_add_subnode(ms->fdt, nodename);
> +    qemu_fdt_setprop_string(ms->fdt, nodename,
> +                            "compatible", "qemu,fw-cfg-mmio");
> +    qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
> +                                 2, base, 2, 0x8);
> +    qemu_fdt_setprop(ms->fdt, nodename, "dma-coherent", NULL, 0);
> +    g_free(nodename);
> +}
> +
> +static void fdt_add_pcie_node(const LoongArchMachineState *lams)
> +{
> +    char *nodename;
> +    hwaddr base_mmio = LS7A_PCI_MEM_BASE;
> +    hwaddr size_mmio = LS7A_PCI_MEM_SIZE;
> +    hwaddr base_pio = LS7A_PCI_IO_BASE;
> +    hwaddr size_pio = LS7A_PCI_IO_SIZE;
> +    hwaddr base_pcie = LS_PCIECFG_BASE;
> +    hwaddr size_pcie = LS_PCIECFG_SIZE;
Why not use LS7A_PCIECFG_BASE or even LS7A_PCI_CFG_BASE to keep consistency?
Huacai
> +    hwaddr base = base_pcie;
> +
> +    const MachineState *ms = MACHINE(lams);
> +
> +    nodename = g_strdup_printf("/pcie@%" PRIx64, base);
> +    qemu_fdt_add_subnode(ms->fdt, nodename);
> +    qemu_fdt_setprop_string(ms->fdt, nodename,
> +                            "compatible", "pci-host-ecam-generic");
> +    qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "pci");
> +    qemu_fdt_setprop_cell(ms->fdt, nodename, "#address-cells", 3);
> +    qemu_fdt_setprop_cell(ms->fdt, nodename, "#size-cells", 2);
> +    qemu_fdt_setprop_cell(ms->fdt, nodename, "linux,pci-domain", 0);
> +    qemu_fdt_setprop_cells(ms->fdt, nodename, "bus-range", 0,
> +                           PCIE_MMCFG_BUS(LS_PCIECFG_SIZE - 1));
> +    qemu_fdt_setprop(ms->fdt, nodename, "dma-coherent", NULL, 0);
> +    qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
> +                                 2, base_pcie, 2, size_pcie);
> +    qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "ranges",
> +                                 1, FDT_PCI_RANGE_IOPORT, 2, LS7A_PCI_IO_OFFSET,
> +                                 2, base_pio, 2, size_pio,
> +                                 1, FDT_PCI_RANGE_MMIO, 2, base_mmio,
> +                                 2, base_mmio, 2, size_mmio);
> +    g_free(nodename);
> +    qemu_fdt_dumpdtb(ms->fdt, lams->fdt_size);
> +}
> +
>
>  #define PM_BASE 0x10080000
>  #define PM_SIZE 0x100
> @@ -546,12 +669,12 @@ static void loongarch_init(MachineState *machine)
>          error_report("ram_size must be greater than 1G.");
>          exit(1);
>      }
> -
> +    create_fdt(lams);
>      /* Init CPUs */
>      for (i = 0; i < machine->smp.cpus; i++) {
>          cpu_create(machine->cpu_type);
>      }
> -
> +    fdt_add_cpu_nodes(lams);
>      /* Add memory region */
>      memory_region_init_alias(&lams->lowmem, NULL, "loongarch.lowram",
>                               machine->ram, 0, 256 * MiB);
> @@ -572,12 +695,12 @@ static void loongarch_init(MachineState *machine)
>      firmware_loaded = loongarch_firmware_init(lams);
>      lams->fw_cfg = loongarch_fw_cfg_init(ram_size, machine);
>      rom_set_fw(lams->fw_cfg);
> -
>      if (lams->fw_cfg != NULL) {
>          fw_cfg_add_file(lams->fw_cfg, "etc/memmap",
>                          la_memmap_table,
>                          sizeof(struct la_memmap_entry) * (la_memmap_entries));
>      }
> +    fdt_add_fw_cfg_node(lams);
>      loaderparams.ram_size = ram_size;
>      loaderparams.kernel_filename = machine->kernel_filename;
>      loaderparams.kernel_cmdline = machine->kernel_cmdline;
> @@ -594,6 +717,13 @@ static void loongarch_init(MachineState *machine)
>      loongarch_irq_init(lams);
>      lams->machine_done.notify = virt_machine_done;
>      qemu_add_machine_init_done_notifier(&lams->machine_done);
> +    fdt_add_pcie_node(lams);
> +
> +    /* load fdt */
> +    MemoryRegion *fdt_rom = g_new(MemoryRegion, 1);
> +    memory_region_init_rom(fdt_rom, NULL, "fdt", LA_FDT_SIZE, &error_fatal);
> +    memory_region_add_subregion(get_system_memory(), LA_FDT_BASE, fdt_rom);
> +    rom_add_blob_fixed("fdt", machine->fdt, lams->fdt_size, LA_FDT_BASE);
>  }
>
>  bool loongarch_is_acpi_enabled(LoongArchMachineState *lams)
> diff --git a/include/hw/loongarch/virt.h b/include/hw/loongarch/virt.h
> index 63b6917c15..e31ddde045 100644
> --- a/include/hw/loongarch/virt.h
> +++ b/include/hw/loongarch/virt.h
> @@ -28,6 +28,9 @@
>  #define GED_MEM_ADDR (GED_EVT_ADDR + ACPI_GED_EVT_SEL_LEN)
>  #define GED_REG_ADDR (GED_MEM_ADDR + MEMORY_HOTPLUG_IO_LEN)
>
> +#define LA_FDT_BASE             0x1c400000
> +#define LA_FDT_SIZE             0x100000
> +
>  struct LoongArchMachineState {
>      /*< private >*/
>      MachineState parent_obj;
> @@ -45,6 +48,7 @@ struct LoongArchMachineState {
>      char        *oem_id;
>      char        *oem_table_id;
>      DeviceState *acpi_ged;
> +    int fdt_size;
>  };
>
>  #define TYPE_LOONGARCH_MACHINE  MACHINE_TYPE_NAME("virt")
> diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
> index 4c8f96bc3a..401d3fd30a 100644
> --- a/target/loongarch/cpu.c
> +++ b/target/loongarch/cpu.c
> @@ -328,6 +328,7 @@ static void loongarch_la464_initfn(Object *obj)
>          env->cpucfg[i] = 0x0;
>      }
>
> +    cpu->dtb_compatible = "loongarch,Loongson-3A5000";
>      env->cpucfg[0] = 0x14c010;  /* PRID */
>
>      uint32_t data = 0;
> diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
> index 71a5036c3c..ce394c3287 100644
> --- a/target/loongarch/cpu.h
> +++ b/target/loongarch/cpu.h
> @@ -326,6 +326,9 @@ struct ArchCPU {
>      CPUNegativeOffsetState neg;
>      CPULoongArchState env;
>      QEMUTimer timer;
> +
> +    /* 'compatible' string for this CPU for Linux device trees */
> +    const char *dtb_compatible;
>  };
>
>  #define TYPE_LOONGARCH_CPU "loongarch-cpu"
> --
> 2.31.1
>
>
-- 
Huacai Chen
^ permalink raw reply	[flat|nested] 12+ messages in thread
 
- * [PATCH 6/8] hw/loongarch: Fix loongarch ipi device
  2022-06-20  8:04 [PATCH 0/8] Add some functions for LoongArch Xiaojuan Yang
                   ` (4 preceding siblings ...)
  2022-06-20  8:04 ` [PATCH 5/8] hw/loongarch: Add fdt support Xiaojuan Yang
@ 2022-06-20  8:04 ` Xiaojuan Yang
  2022-06-20  8:04 ` [PATCH 7/8] target/loongarch: Fix vector size of exception entry address Xiaojuan Yang
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 12+ messages in thread
From: Xiaojuan Yang @ 2022-06-20  8:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: richard.henderson, gaosong, maobibo, mark.cave-ayland, mst,
	imammedo, ani, f4bug, peter.maydell, chenhuacai
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
---
 hw/intc/loongarch_ipi.c         | 85 ++++++++++++++++++++++-----------
 hw/loongarch/loongson3.c        |  5 +-
 include/hw/intc/loongarch_ipi.h |  8 ++--
 3 files changed, 65 insertions(+), 33 deletions(-)
diff --git a/hw/intc/loongarch_ipi.c b/hw/intc/loongarch_ipi.c
index 66bee93675..57d7965289 100644
--- a/hw/intc/loongarch_ipi.c
+++ b/hw/intc/loongarch_ipi.c
@@ -50,35 +50,40 @@ static uint64_t loongarch_ipi_readl(void *opaque, hwaddr addr, unsigned size)
     return ret;
 }
 
-static int get_ipi_data(target_ulong val)
+static void send_ipi_data(CPULoongArchState *env, target_ulong val, target_ulong addr)
 {
     int i, mask, data;
 
-    data = val >> 32;
-    mask = (val >> 27) & 0xf;
-
+    data = address_space_ldl(&env->address_space_iocsr, addr,
+                             MEMTXATTRS_UNSPECIFIED, NULL);
+    mask  = 0;
     for (i = 0; i < 4; i++) {
-        if ((mask >> i) & 1) {
-            data &= ~(0xff << (i * 8));
+        /* bit 27 - 30 is mask for byte write */
+        if (val & (0x1UL << (27 + i))) {
+            mask |= 0xff << (i * 8);
         }
     }
-    return data;
+
+    data &= mask;
+    data |= (val >> 32) & ~mask;
+    address_space_stl(&env->address_space_iocsr, addr,
+                      data, MEMTXATTRS_UNSPECIFIED, NULL);
 }
 
 static void ipi_send(uint64_t val)
 {
     int cpuid, data;
     CPULoongArchState *env;
+    CPUState *cs;
+    LoongArchCPU *cpu;
 
     cpuid = (val >> 16) & 0x3ff;
     /* IPI status vector */
     data = 1 << (val & 0x1f);
-    qemu_mutex_lock_iothread();
-    CPUState *cs = qemu_get_cpu(cpuid);
-    LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+    cs = qemu_get_cpu(cpuid);
+    cpu = LOONGARCH_CPU(cs);
     env = &cpu->env;
     loongarch_cpu_set_irq(cpu, IRQ_IPI, 1);
-    qemu_mutex_unlock_iothread();
     address_space_stl(&env->address_space_iocsr, 0x1008,
                       data, MEMTXATTRS_UNSPECIFIED, NULL);
 
@@ -86,23 +91,23 @@ static void ipi_send(uint64_t val)
 
 static void mail_send(uint64_t val)
 {
-    int cpuid, data;
+    int cpuid;
     hwaddr addr;
     CPULoongArchState *env;
+    CPUState *cs;
+    LoongArchCPU *cpu;
 
     cpuid = (val >> 16) & 0x3ff;
     addr = 0x1020 + (val & 0x1c);
-    CPUState *cs = qemu_get_cpu(cpuid);
-    LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+    cs = qemu_get_cpu(cpuid);
+    cpu = LOONGARCH_CPU(cs);
     env = &cpu->env;
-    data = get_ipi_data(val);
-    address_space_stl(&env->address_space_iocsr, addr,
-                      data, MEMTXATTRS_UNSPECIFIED, NULL);
+    send_ipi_data(env, val, addr);
 }
 
 static void any_send(uint64_t val)
 {
-    int cpuid, data;
+    int cpuid;
     hwaddr addr;
     CPULoongArchState *env;
 
@@ -111,9 +116,7 @@ static void any_send(uint64_t val)
     CPUState *cs = qemu_get_cpu(cpuid);
     LoongArchCPU *cpu = LOONGARCH_CPU(cs);
     env = &cpu->env;
-    data = get_ipi_data(val);
-    address_space_stl(&env->address_space_iocsr, addr,
-                      data, MEMTXATTRS_UNSPECIFIED, NULL);
+    send_ipi_data(env, val, addr);
 }
 
 static void loongarch_ipi_writel(void *opaque, hwaddr addr, uint64_t val,
@@ -150,12 +153,6 @@ static void loongarch_ipi_writel(void *opaque, hwaddr addr, uint64_t val,
     case IOCSR_IPI_SEND:
         ipi_send(val);
         break;
-    case IOCSR_MAIL_SEND:
-        mail_send(val);
-        break;
-    case IOCSR_ANY_SEND:
-        any_send(val);
-        break;
     default:
         qemu_log_mask(LOG_UNIMP, "invalid write: %x", (uint32_t)addr);
         break;
@@ -172,6 +169,32 @@ static const MemoryRegionOps loongarch_ipi_ops = {
     .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
+/* mail send and any send only support writeq */
+static void loongarch_ipi_writeq(void *opaque, hwaddr addr, uint64_t val,
+                                 unsigned size)
+{
+    addr &= 0xfff;
+    switch (addr) {
+    case MAIL_SEND_OFFSET:
+        mail_send(val);
+        break;
+    case ANY_SEND_OFFSET:
+        any_send(val);
+        break;
+    default:
+       break;
+    }
+}
+
+static const MemoryRegionOps loongarch_ipi64_ops = {
+    .write = loongarch_ipi_writeq,
+    .impl.min_access_size = 8,
+    .impl.max_access_size = 8,
+    .valid.min_access_size = 4,
+    .valid.max_access_size = 8,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
 static void loongarch_ipi_init(Object *obj)
 {
     int cpu;
@@ -185,10 +208,16 @@ static void loongarch_ipi_init(Object *obj)
         return;
     }
     lams = LOONGARCH_MACHINE(machine);
+
     for (cpu = 0; cpu < MAX_IPI_CORE_NUM; cpu++) {
         memory_region_init_io(&s->ipi_iocsr_mem[cpu], obj, &loongarch_ipi_ops,
-                            &lams->ipi_core[cpu], "loongarch_ipi_iocsr", 0x100);
+                              &lams->ipi_core[cpu], "loongarch_ipi_iocsr", 0x48);
         sysbus_init_mmio(sbd, &s->ipi_iocsr_mem[cpu]);
+
+        memory_region_init_io(&s->ipi64_iocsr_mem[cpu], obj, &loongarch_ipi64_ops,
+                              &lams->ipi_core[cpu], "loongarch_ipi64_iocsr", 0x118);
+        sysbus_init_mmio(sbd, &s->ipi64_iocsr_mem[cpu]);
+
         qdev_init_gpio_out(DEVICE(obj), &lams->ipi_core[cpu].irq, 1);
     }
 }
diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
index 146f582dbe..c8bbe384d4 100644
--- a/hw/loongarch/loongson3.c
+++ b/hw/loongarch/loongson3.c
@@ -455,7 +455,10 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
         /* IPI iocsr memory region */
         memory_region_add_subregion(&env->system_iocsr, SMP_IPI_MAILBOX,
                                     sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi),
-                                    cpu));
+                                    cpu * 2));
+        memory_region_add_subregion(&env->system_iocsr, MAIL_SEND_ADDR,
+                                    sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi),
+                                    cpu * 2 + 1));
         /* extioi iocsr memory region */
         memory_region_add_subregion(&env->system_iocsr, APIC_BASE,
                                 sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi),
diff --git a/include/hw/intc/loongarch_ipi.h b/include/hw/intc/loongarch_ipi.h
index 996ed7ea93..a98c3dd4a3 100644
--- a/include/hw/intc/loongarch_ipi.h
+++ b/include/hw/intc/loongarch_ipi.h
@@ -23,9 +23,9 @@
 #define IOCSR_IPI_SEND        0x40
 #define IOCSR_MAIL_SEND       0x48
 #define IOCSR_ANY_SEND        0x158
-
-/* IPI system memory address */
-#define IPI_SYSTEM_MEM        0x1fe01000
+#define MAIL_SEND_ADDR        (SMP_IPI_MAILBOX + IOCSR_MAIL_SEND)
+#define MAIL_SEND_OFFSET      0
+#define ANY_SEND_OFFSET       (IOCSR_ANY_SEND - IOCSR_MAIL_SEND)
 
 #define MAX_IPI_CORE_NUM      4
 #define MAX_IPI_MBX_NUM       4
@@ -46,7 +46,7 @@ typedef struct IPICore {
 struct LoongArchIPI {
     SysBusDevice parent_obj;
     MemoryRegion ipi_iocsr_mem[MAX_IPI_CORE_NUM];
-    MemoryRegion ipi_system_mem[MAX_IPI_CORE_NUM];
+    MemoryRegion ipi64_iocsr_mem[MAX_IPI_CORE_NUM];
 };
 
 #endif
-- 
2.31.1
^ permalink raw reply related	[flat|nested] 12+ messages in thread
- * [PATCH 7/8] target/loongarch: Fix vector size of exception entry address
  2022-06-20  8:04 [PATCH 0/8] Add some functions for LoongArch Xiaojuan Yang
                   ` (5 preceding siblings ...)
  2022-06-20  8:04 ` [PATCH 6/8] hw/loongarch: Fix loongarch ipi device Xiaojuan Yang
@ 2022-06-20  8:04 ` Xiaojuan Yang
  2022-06-20  8:04 ` [PATCH 8/8] target/loongarch: Fix csrwr timer clear Xiaojuan Yang
  2022-06-20 17:16 ` [PATCH 0/8] Add some functions for LoongArch Richard Henderson
  8 siblings, 0 replies; 12+ messages in thread
From: Xiaojuan Yang @ 2022-06-20  8:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: richard.henderson, gaosong, maobibo, mark.cave-ayland, mst,
	imammedo, ani, f4bug, peter.maydell, chenhuacai
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
---
 target/loongarch/cpu.c | 4 ++++
 1 file changed, 4 insertions(+)
diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index 401d3fd30a..d1a87e8e1c 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -219,6 +219,10 @@ static void loongarch_cpu_do_interrupt(CPUState *cs)
     env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PLV, 0);
     env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, IE, 0);
 
+    if (vec_size) {
+        vec_size = (1 << vec_size) * 4;
+    }
+
     if  (cs->exception_index == EXCCODE_INT) {
         /* Interrupt */
         uint32_t vector = 0;
-- 
2.31.1
^ permalink raw reply related	[flat|nested] 12+ messages in thread
- * [PATCH 8/8] target/loongarch: Fix csrwr timer clear
  2022-06-20  8:04 [PATCH 0/8] Add some functions for LoongArch Xiaojuan Yang
                   ` (6 preceding siblings ...)
  2022-06-20  8:04 ` [PATCH 7/8] target/loongarch: Fix vector size of exception entry address Xiaojuan Yang
@ 2022-06-20  8:04 ` Xiaojuan Yang
  2022-06-20 17:16 ` [PATCH 0/8] Add some functions for LoongArch Richard Henderson
  8 siblings, 0 replies; 12+ messages in thread
From: Xiaojuan Yang @ 2022-06-20  8:04 UTC (permalink / raw)
  To: qemu-devel
  Cc: richard.henderson, gaosong, maobibo, mark.cave-ayland, mst,
	imammedo, ani, f4bug, peter.maydell, chenhuacai
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
---
 target/loongarch/csr_helper.c | 2 ++
 1 file changed, 2 insertions(+)
diff --git a/target/loongarch/csr_helper.c b/target/loongarch/csr_helper.c
index 24a9389364..7e02787895 100644
--- a/target/loongarch/csr_helper.c
+++ b/target/loongarch/csr_helper.c
@@ -81,7 +81,9 @@ target_ulong helper_csrwr_ticlr(CPULoongArchState *env, target_ulong val)
     int64_t old_v = 0;
 
     if (val & 0x1) {
+        qemu_mutex_lock_iothread();
         loongarch_cpu_set_irq(cpu, IRQ_TIMER, 0);
+        qemu_mutex_unlock_iothread();
     }
     return old_v;
 }
-- 
2.31.1
^ permalink raw reply related	[flat|nested] 12+ messages in thread
- * Re: [PATCH 0/8] Add some functions for LoongArch
  2022-06-20  8:04 [PATCH 0/8] Add some functions for LoongArch Xiaojuan Yang
                   ` (7 preceding siblings ...)
  2022-06-20  8:04 ` [PATCH 8/8] target/loongarch: Fix csrwr timer clear Xiaojuan Yang
@ 2022-06-20 17:16 ` Richard Henderson
  8 siblings, 0 replies; 12+ messages in thread
From: Richard Henderson @ 2022-06-20 17:16 UTC (permalink / raw)
  To: Xiaojuan Yang, qemu-devel
  Cc: gaosong, maobibo, mark.cave-ayland, mst, imammedo, ani, f4bug,
	peter.maydell, chenhuacai
On 6/20/22 01:04, Xiaojuan Yang wrote:
> In order to start the latest community BIOS and kernel of LoongArch,
> we have added the following patches.
> 
> This series add some functions for LoongArch, and fix some errors.
> Add bios, kernel, fdt, smbios and acpi options support.
> 
> The kernel file:
>     * https://github.com/loongson/linux/tree/loongarch-next
> The bios file:
>     * https://github.com/loongson/edk2
>     * https://github.com/loongson/edk2-platforms
> 
> 
> Xiaojuan Yang (8):
>    hw/loongarch: Add default bios startup support
>    hw/loongarch: Add -kernel and -initrd options support
>    hw/loongarch: Add LoongArch smbios support
>    hw/loongarch: Add LoongArch acpi support
>    hw/loongarch: Add fdt support
>    hw/loongarch: Fix loongarch ipi device
>    target/loongarch: Fix vector size of exception entry address
>    target/loongarch: Fix csrwr timer clear
Please fill in the patch descriptions for each of these.
r~
^ permalink raw reply	[flat|nested] 12+ messages in thread