* [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