* [RFC PATCH v7 00/29] Add LoongArch softmmu support
@ 2022-03-28 12:57 Xiaojuan Yang
2022-03-28 12:57 ` [RFC PATCH v7 01/29] target/loongarch: Add system emulation introduction Xiaojuan Yang
` (29 more replies)
0 siblings, 30 replies; 71+ messages in thread
From: Xiaojuan Yang @ 2022-03-28 12:57 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland, richard.henderson
This series patch add softmmu support for LoongArch.
The latest kernel:
* https://github.com/loongson/linux/tree/loongarch-next
The latest uefi:
* https://github.com/loongson/edk2
* https://github.com/loongson/edk2-platforms
The manual:
* https://github.com/loongson/LoongArch-Documentation/releases/tag/2021.10.11
You can get LoongArch qemu series like this:
git clone https://github.com/loongson/qemu.git
git checkout tcg-dev
Changes for v7:
1. Moved extioi memory region init function to loongarch_extioi_instance_init.
2. Replaced DECLARE_INSTANCE_CHECKER with OBJECT_DECLARE_SIMPLE_TYPE.
3. Fixed the usage of typedef struct.
Changes for v6:
1. Add the new loongarch_cpu_init function.
2. Improved extioi memory region.
3. Replaced the original LS7A bridge with a new GPEX bridge.
Changes for v5:
1. Fix host bridge map irq function.
2. Move cpu timer init function into machine init.
3. Adjust memory region layout.
4. Add the documentation at docs/system/loongarch/loongson3.rst.
- Introduction to 3a5000 virt.
- Output of "info mtree".
Changes for v4:
1. Uefi code is open and add some fdt interface to pass info between qemu and uefi.
2. Use a per cpu address space for iocsr.
3. Modify the tlb emulation.
4. Machine and board code mainly follow Mark's advice.
5. Adjust pci host space map.
6. Use more memregion to simplify the interrupt controller's emulate.
Changes for v3:
1.Target code mainly follow Richard's code review comments.
2.Put the csr and iocsr read/write instruction emulate into 2 different patch.
3.Simply the tlb emulation.
4.Delete some unused csr registers defintion.
5.Machine and board code mainly follow Mark's advice, discard the obsolete interface.
6.NUMA function is removed for it is not completed.
7.Adjust some format problem and the Naming problem
Changes for v3:
1.Target code mainly follow Richard's code review comments.
2.Put the csr and iocsr read/write instruction emulate into 2 different patch.
3.Simply the tlb emulation.
4.Delete some unused csr registers defintion.
5.Machine and board code mainly follow Mark's advice, discard the obsolete interface.
6.NUMA function is removed for it is not completed.
7.Adjust some format problem and the Naming problem
Changes for v2:
1.Combine patch 2 and 3 into one.
2.Adjust the order of the patch.
3.Put all the binaries on the github.
4.Modify some emulate errors when use the kernel from the github.
5.Adjust some format problem and the Naming problem
6.Others mainly follow Richard's code review comments.
Please help review!
Thanks
Xiaojuan Yang (29):
target/loongarch: Add system emulation introduction
target/loongarch: Add CSRs definition
target/loongarch: Add basic vmstate description of CPU.
target/loongarch: Implement qmp_query_cpu_definitions()
target/loongarch: Add constant timer support
target/loongarch: Add MMU support for LoongArch CPU.
target/loongarch: Add LoongArch CSR instruction
target/loongarch: Add LoongArch IOCSR instruction
target/loongarch: Add TLB instruction support
target/loongarch: Add other core instructions support
target/loongarch: Add LoongArch interrupt and exception handle
target/loongarch: Add timer related instructions support.
target/loongarch: Add gdb support.
hw/loongarch: Add support loongson3 virt machine type.
hw/loongarch: Add LoongArch cpu interrupt support(CPUINTC)
hw/loongarch: Add LoongArch ipi interrupt support(IPI)
hw/intc: Add LoongArch ls7a interrupt controller support(PCH-PIC)
hw/intc: Add LoongArch ls7a msi interrupt controller support(PCH-MSI)
hw/intc: Add LoongArch extioi interrupt controller(EIOINTC)
hw/loongarch: Add irq hierarchy for the system
Enable common virtio pci support for LoongArch
hw/loongarch: Add some devices support for 3A5000.
hw/loongarch: Add LoongArch ls7a rtc device support
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.
tests/tcg/loongarch64: Add hello/memory test in loongarch64 system
MAINTAINERS | 20 +
.../devices/loongarch64-softmmu/default.mak | 3 +
configs/targets/loongarch64-softmmu.mak | 4 +
docs/system/loongarch/loongson3.rst | 37 +
gdb-xml/loongarch-base64.xml | 44 +
gdb-xml/loongarch-fpu64.xml | 57 ++
hw/Kconfig | 1 +
hw/acpi/Kconfig | 4 +
hw/acpi/ls7a.c | 374 +++++++++
hw/acpi/meson.build | 1 +
hw/intc/Kconfig | 15 +
hw/intc/loongarch_extioi.c | 408 ++++++++++
hw/intc/loongarch_ipi.c | 164 ++++
hw/intc/loongarch_pch_msi.c | 75 ++
hw/intc/loongarch_pch_pic.c | 488 +++++++++++
hw/intc/meson.build | 4 +
hw/intc/trace-events | 27 +
hw/loongarch/Kconfig | 23 +
hw/loongarch/acpi-build.c | 636 +++++++++++++++
hw/loongarch/fw_cfg.c | 33 +
hw/loongarch/fw_cfg.h | 15 +
hw/loongarch/loongson3.c | 752 +++++++++++++++++
hw/loongarch/meson.build | 6 +
hw/meson.build | 1 +
hw/rtc/Kconfig | 3 +
hw/rtc/ls7a_rtc.c | 323 ++++++++
hw/rtc/meson.build | 1 +
include/exec/poison.h | 2 +
include/hw/acpi/ls7a.h | 53 ++
include/hw/intc/loongarch_extioi.h | 77 ++
include/hw/intc/loongarch_ipi.h | 47 ++
include/hw/intc/loongarch_pch_msi.h | 21 +
include/hw/intc/loongarch_pch_pic.h | 80 ++
include/hw/loongarch/loongarch.h | 75 ++
include/hw/pci-host/ls7a.h | 48 ++
include/sysemu/arch_init.h | 1 +
linux-user/loongarch64/cpu_loop.c | 8 +-
qapi/machine-target.json | 6 +-
qapi/machine.json | 2 +-
softmmu/qdev-monitor.c | 3 +-
target/Kconfig | 1 +
target/loongarch/Kconfig | 2 +
target/loongarch/README | 28 +
target/loongarch/constant_timer.c | 62 ++
target/loongarch/cpu-csr.h | 236 ++++++
target/loongarch/cpu-param.h | 2 +-
target/loongarch/cpu.c | 363 ++++++++-
target/loongarch/cpu.h | 218 ++++-
target/loongarch/csr_helper.c | 112 +++
target/loongarch/disas.c | 57 ++
target/loongarch/fpu_helper.c | 2 +-
target/loongarch/gdbstub.c | 99 +++
target/loongarch/helper.h | 26 +
target/loongarch/insn_trans/trans_extra.c.inc | 36 +-
.../insn_trans/trans_privileged.c.inc | 410 ++++++++++
target/loongarch/insns.decode | 44 +
target/loongarch/internals.h | 28 +
target/loongarch/iocsr_helper.c | 139 ++++
target/loongarch/machine.c | 102 +++
target/loongarch/meson.build | 11 +
target/loongarch/op_helper.c | 52 ++
target/loongarch/tlb_helper.c | 767 ++++++++++++++++++
target/loongarch/translate.c | 9 +-
tests/tcg/loongarch64/Makefile.softmmu-target | 33 +
tests/tcg/loongarch64/system/boot.S | 56 ++
tests/tcg/loongarch64/system/kernel.ld | 30 +
tests/tcg/loongarch64/system/regdef.h | 86 ++
67 files changed, 6922 insertions(+), 31 deletions(-)
create mode 100644 configs/devices/loongarch64-softmmu/default.mak
create mode 100644 configs/targets/loongarch64-softmmu.mak
create mode 100644 docs/system/loongarch/loongson3.rst
create mode 100644 gdb-xml/loongarch-base64.xml
create mode 100644 gdb-xml/loongarch-fpu64.xml
create mode 100644 hw/acpi/ls7a.c
create mode 100644 hw/intc/loongarch_extioi.c
create mode 100644 hw/intc/loongarch_ipi.c
create mode 100644 hw/intc/loongarch_pch_msi.c
create mode 100644 hw/intc/loongarch_pch_pic.c
create mode 100644 hw/loongarch/Kconfig
create mode 100644 hw/loongarch/acpi-build.c
create mode 100644 hw/loongarch/fw_cfg.c
create mode 100644 hw/loongarch/fw_cfg.h
create mode 100644 hw/loongarch/loongson3.c
create mode 100644 hw/loongarch/meson.build
create mode 100644 hw/rtc/ls7a_rtc.c
create mode 100644 include/hw/acpi/ls7a.h
create mode 100644 include/hw/intc/loongarch_extioi.h
create mode 100644 include/hw/intc/loongarch_ipi.h
create mode 100644 include/hw/intc/loongarch_pch_msi.h
create mode 100644 include/hw/intc/loongarch_pch_pic.h
create mode 100644 include/hw/loongarch/loongarch.h
create mode 100644 include/hw/pci-host/ls7a.h
create mode 100644 target/loongarch/Kconfig
create mode 100644 target/loongarch/constant_timer.c
create mode 100644 target/loongarch/cpu-csr.h
create mode 100644 target/loongarch/csr_helper.c
create mode 100644 target/loongarch/gdbstub.c
create mode 100644 target/loongarch/insn_trans/trans_privileged.c.inc
create mode 100644 target/loongarch/iocsr_helper.c
create mode 100644 target/loongarch/machine.c
create mode 100644 target/loongarch/tlb_helper.c
create mode 100644 tests/tcg/loongarch64/Makefile.softmmu-target
create mode 100644 tests/tcg/loongarch64/system/boot.S
create mode 100644 tests/tcg/loongarch64/system/kernel.ld
create mode 100644 tests/tcg/loongarch64/system/regdef.h
--
2.31.1
^ permalink raw reply [flat|nested] 71+ messages in thread
* [RFC PATCH v7 01/29] target/loongarch: Add system emulation introduction
2022-03-28 12:57 [RFC PATCH v7 00/29] Add LoongArch softmmu support Xiaojuan Yang
@ 2022-03-28 12:57 ` Xiaojuan Yang
2022-03-28 12:57 ` [RFC PATCH v7 02/29] target/loongarch: Add CSRs definition Xiaojuan Yang
` (28 subsequent siblings)
29 siblings, 0 replies; 71+ messages in thread
From: Xiaojuan Yang @ 2022-03-28 12:57 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland, richard.henderson, Song Gao
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
MAINTAINERS | 8 +++++++
docs/system/loongarch/loongson3.rst | 37 +++++++++++++++++++++++++++++
target/loongarch/README | 28 ++++++++++++++++++++++
3 files changed, 73 insertions(+)
create mode 100644 docs/system/loongarch/loongson3.rst
diff --git a/MAINTAINERS b/MAINTAINERS
index 0d972447a8..7b61d9eb08 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1121,6 +1121,14 @@ F: hw/net/*i82596*
F: include/hw/net/lasi_82596.h
F: pc-bios/hppa-firmware.img
+LoongArch Machines
+------------------
+Virt
+M: Xiaojuan Yang <yangxiaojuan@loongson.cn>
+M: Song Gao <gaosong@loongson.cn>
+S: Maintained
+F: docs/system/loongarch/loongson3.rst
+
M68K Machines
-------------
an5206
diff --git a/docs/system/loongarch/loongson3.rst b/docs/system/loongarch/loongson3.rst
new file mode 100644
index 0000000000..367fff9d9d
--- /dev/null
+++ b/docs/system/loongarch/loongson3.rst
@@ -0,0 +1,37 @@
+loongson3 virt generic platform (``virt``)
+====================================================
+
+The ``virt`` machine use gpex host bridge, and there are some
+emulated devices on virt board, such as loongson7a RTC device,
+IOAPIC device, ACPI device and so on.
+
+Supported devices
+-----------------
+
+The ``virt`` machine supports:
+- Gpex host bridge
+- Ls7a RTC device
+- Ls7a IOAPIC device
+- Ls7a ACPI device
+- Fw_cfg device
+- PCI/PCIe devices
+- Memory device
+- CPU device. Type: Loongson-3A5000.
+
+CPU and machine Type
+--------------------
+
+The ``qemu-system-loongarch64`` provides emulation for virt
+machine. You can specify the machine type ``virt`` and
+cpu type ``Loongson-3A5000``.
+
+Boot options
+------------
+
+Now the ``virt`` machine can start using -bios parameter:
+
+.. code-block:: bash
+
+ $ qemu-system-loongarch64 -M virt -cpu Loongson-3A5000 -smp 2 -m 1G \
+ -display none -serial stdio \
+ -bios loongarch_bios.bin
diff --git a/target/loongarch/README b/target/loongarch/README
index 383db6cc15..de44d39561 100644
--- a/target/loongarch/README
+++ b/target/loongarch/README
@@ -71,6 +71,34 @@
./qemu-loongarch64 /opt/clfs/usr/bin/pwd
...
+- System emulation
+
+ Mainly emulate a virt 3A5000 board and ls7a bridge that is not exactly the same as the host.
+ 3A5000 support multiple interrupt cascading while here we just emulate the extioi interrupt
+ cascading. LS7A1000 host bridge support multiple devices, such as sata, gmac, uart, rtc
+ and so on. But we just realize the rtc. Others use the qemu common devices. It does not affect
+ the general use. We also introduced the emulation of devices at docs/system/loongarch/loongson3.rst.
+
+ You can compile the binaries by youself or just get all required binaries from the github for testing.
+
+ 1.Download kernel and the cross-tools.(vmlinux)
+
+ https://github.com/loongson/linux/tree/loongarch-next
+ https://github.com/loongson/build-tools/releases/latest/download/loongarch64-clfs-20211202-cross-tools.tar.xz
+
+ 2.Download uefi code.(loongarch_bios.bin)
+
+ https://github.com/loongson/edk2/tree/LoongArch
+ https://github.com/loongson/edk2-platforms
+
+ 3.Download the clfs-system and make a ramdisk with busybox.(ramdisk)
+
+ 4.Run with command,eg:
+
+ ./build/qemu-system-loongarch64 -m 4G -smp 4 --cpu Loongson-3A5000 --machine loongson3-ls7a -kernel ./vmlinux -initrd ./ramdisk -append "root=/dev/ram console=ttyS0,115200 rdinit=/sbin/init loglevel=8" -monitor tcp::4000,server,nowait -nographic
+
+All binaries can get from here directly:
+ git clone https://github.com/yangxiaojuan-loongson/qemu-binary
- Note.
We can get the latest LoongArch documents or LoongArch tools at https://github.com/loongson/
--
2.31.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [RFC PATCH v7 02/29] target/loongarch: Add CSRs definition
2022-03-28 12:57 [RFC PATCH v7 00/29] Add LoongArch softmmu support Xiaojuan Yang
2022-03-28 12:57 ` [RFC PATCH v7 01/29] target/loongarch: Add system emulation introduction Xiaojuan Yang
@ 2022-03-28 12:57 ` Xiaojuan Yang
2022-03-28 19:16 ` Richard Henderson
2022-03-28 12:57 ` [RFC PATCH v7 03/29] target/loongarch: Add basic vmstate description of CPU Xiaojuan Yang
` (27 subsequent siblings)
29 siblings, 1 reply; 71+ messages in thread
From: Xiaojuan Yang @ 2022-03-28 12:57 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland, richard.henderson, Song Gao
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
target/loongarch/cpu-csr.h | 236 +++++++++++++++++++++++++++++++++++++
target/loongarch/cpu.c | 35 ++++++
target/loongarch/cpu.h | 57 +++++++++
3 files changed, 328 insertions(+)
create mode 100644 target/loongarch/cpu-csr.h
diff --git a/target/loongarch/cpu-csr.h b/target/loongarch/cpu-csr.h
new file mode 100644
index 0000000000..8ad4c2ce70
--- /dev/null
+++ b/target/loongarch/cpu-csr.h
@@ -0,0 +1,236 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * QEMU LoongArch CSRs
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ */
+
+#ifndef LOONGARCH_CPU_CSR_H
+#define LOONGARCH_CPU_CSR_H
+
+/* Base on kernal definitions: arch/loongarch/include/asm/loongarch.h */
+
+/* Basic CSRs */
+#define LOONGARCH_CSR_CRMD 0x0 /* Current mode info */
+FIELD(CSR_CRMD, PLV, 0, 2)
+FIELD(CSR_CRMD, IE, 2, 1)
+FIELD(CSR_CRMD, DA, 3, 1)
+FIELD(CSR_CRMD, PG, 4, 1)
+FIELD(CSR_CRMD, DATF, 5, 2)
+FIELD(CSR_CRMD, DATM, 7, 2)
+FIELD(CSR_CRMD, WE, 9, 1)
+
+#define LOONGARCH_CSR_PRMD 0x1 /* Prev-exception mode info */
+FIELD(CSR_PRMD, PPLV, 0, 2)
+FIELD(CSR_PRMD, PIE, 2, 1)
+FIELD(CSR_PRMD, PWE, 3, 1)
+
+#define LOONGARCH_CSR_EUEN 0x2 /* Extended unit enable */
+FIELD(CSR_EUEN, FPE, 0, 1)
+FIELD(CSR_EUEN, SXE, 1, 1)
+FIELD(CSR_EUEN, ASXE, 2, 1)
+FIELD(CSR_EUEN, BTE, 3, 1)
+
+#define LOONGARCH_CSR_MISC 0x3 /* Misc config */
+
+#define LOONGARCH_CSR_ECFG 0x4 /* Exception config */
+FIELD(CSR_ECFG, LIE, 0, 13)
+FIELD(CSR_ECFG, VS, 16, 3)
+
+#define LOONGARCH_CSR_ESTAT 0x5 /* Exception status */
+FIELD(CSR_ESTAT, IS, 0, 13)
+FIELD(CSR_ESTAT, ECODE, 16, 6)
+FIELD(CSR_ESTAT, ESUBCODE, 22, 9)
+
+#define EXCCODE_EXTERNAL_INT 64 /* plus external interrupt number */
+#define EXCCODE_INT 0
+#define EXCCODE_PIL 1
+#define EXCCODE_PIS 2
+#define EXCCODE_PIF 3
+#define EXCCODE_PME 4
+#define EXCCODE_PNR 5
+#define EXCCODE_PNX 6
+#define EXCCODE_PPI 7
+#define EXCCODE_ADEF 8 /* Different exception subcode */
+#define EXCCODE_ADEM 8
+#define EXCCODE_ALE 9
+#define EXCCODE_BCE 10
+#define EXCCODE_SYS 11
+#define EXCCODE_BRK 12
+#define EXCCODE_INE 13
+#define EXCCODE_IPE 14
+#define EXCCODE_FPD 15
+#define EXCCODE_SXD 16
+#define EXCCODE_ASXD 17
+#define EXCCODE_FPE 18 /* Different exception subcode */
+#define EXCCODE_VFPE 18
+#define EXCCODE_WPEF 19 /* Different exception subcode */
+#define EXCCODE_WPEM 19
+#define EXCCODE_BTD 20
+#define EXCCODE_BTE 21
+#define EXCCODE_DBP 26 /* Reserved subcode used for debug */
+
+#define LOONGARCH_CSR_ERA 0x6 /* Exception return address */
+
+#define LOONGARCH_CSR_BADV 0x7 /* Bad virtual address */
+
+#define LOONGARCH_CSR_BADI 0x8 /* Bad instruction */
+
+#define LOONGARCH_CSR_EENTRY 0xc /* Exception entry address */
+
+/* TLB related CSRs */
+#define LOONGARCH_CSR_TLBIDX 0x10 /* TLB Index, EHINV, PageSize, NP */
+FIELD(CSR_TLBIDX, INDEX, 0, 12)
+FIELD(CSR_TLBIDX, PS, 24, 6)
+FIELD(CSR_TLBIDX, NE, 31, 1)
+
+#define LOONGARCH_CSR_TLBEHI 0x11 /* TLB EntryHi */
+FIELD(CSR_TLBEHI, VPPN, 13, 35)
+
+#define LOONGARCH_CSR_TLBELO0 0x12 /* TLB EntryLo0 */
+#define LOONGARCH_CSR_TLBELO1 0x13 /* TLB EntryLo1 */
+FIELD(TLBENTRY, V, 0, 1)
+FIELD(TLBENTRY, D, 1, 1)
+FIELD(TLBENTRY, PLV, 2, 2)
+FIELD(TLBENTRY, MAT, 4, 2)
+FIELD(TLBENTRY, G, 6, 1)
+FIELD(TLBENTRY, PPN, 12, 36)
+FIELD(TLBENTRY, NR, 61, 1)
+FIELD(TLBENTRY, NX, 62, 1)
+FIELD(TLBENTRY, RPLV, 63, 1)
+
+#define LOONGARCH_CSR_ASID 0x18 /* Address space identifier */
+FIELD(CSR_ASID, ASID, 0, 10)
+FIELD(CSR_ASID, ASIDBITS, 16, 8)
+
+/* Page table base address when badv[47] = 0 */
+#define LOONGARCH_CSR_PGDL 0x19
+/* Page table base address when badv[47] = 1 */
+#define LOONGARCH_CSR_PGDH 0x1a
+
+#define LOONGARCH_CSR_PGD 0x1b /* Page table base address */
+
+/* Page walk controller's low addr */
+#define LOONGARCH_CSR_PWCL 0x1c
+FIELD(CSR_PWCL, PTBASE, 0, 5)
+FIELD(CSR_PWCL, PTWIDTH, 5, 5)
+FIELD(CSR_PWCL, DIR1_BASE, 10, 5)
+FIELD(CSR_PWCL, DIR1_WIDTH, 15, 5)
+FIELD(CSR_PWCL, DIR2_BASE, 20, 5)
+FIELD(CSR_PWCL, DIR2_WIDTH, 25, 5)
+FIELD(CSR_PWCL, PTEWIDTH, 30, 2)
+
+/* Page walk controller's high addr */
+#define LOONGARCH_CSR_PWCH 0x1d
+FIELD(CSR_PWCH, DIR3_BASE, 0, 6)
+FIELD(CSR_PWCH, DIR3_WIDTH, 6, 6)
+FIELD(CSR_PWCH, DIR4_BASE, 12, 6)
+FIELD(CSR_PWCH, DIR4_WIDTH, 18, 6)
+
+#define LOONGARCH_CSR_STLBPS 0x1e /* Stlb page size */
+FIELD(CSR_STLBPS, PS, 0, 5)
+
+#define LOONGARCH_CSR_RVACFG 0x1f /* Reduced virtual address config */
+FIELD(CSR_RVACFG, RBITS, 0, 4)
+
+/* Config CSRs */
+#define LOONGARCH_CSR_CPUID 0x20 /* CPU core id */
+
+#define LOONGARCH_CSR_PRCFG1 0x21 /* Config1 */
+FIELD(CSR_PRCFG1, SAVE_NUM, 0, 4)
+FIELD(CSR_PRCFG1, TIMER_BITS, 4, 8)
+FIELD(CSR_PRCFG1, VSMAX, 12, 3)
+
+#define LOONGARCH_CSR_PRCFG2 0x22 /* Config2 */
+
+#define LOONGARCH_CSR_PRCFG3 0x23 /* Config3 */
+FIELD(CSR_PRCFG3, TLB_TYPE, 0, 4)
+FIELD(CSR_PRCFG3, MTLB_ENTRY, 4, 8)
+FIELD(CSR_PRCFG3, STLB_WAYS, 12, 8)
+FIELD(CSR_PRCFG3, STLB_SETS, 20, 8)
+
+/*
+ * Save registers count can read from PRCFG1.SAVE_NUM
+ * The Min count is 1. Max count is 15.
+ */
+#define LOONGARCH_CSR_SAVE(N) (0x30 + N)
+
+/* Timer CSRs */
+#define LOONGARCH_CSR_TID 0x40 /* Timer ID */
+
+#define LOONGARCH_CSR_TCFG 0x41 /* Timer config */
+FIELD(CSR_TCFG, EN, 0, 1)
+FIELD(CSR_TCFG, PERIODIC, 1, 1)
+FIELD(CSR_TCFG, INIT_VAL, 2, 46)
+
+#define LOONGARCH_CSR_TVAL 0x42 /* Timer ticks remain */
+
+#define LOONGARCH_CSR_CNTC 0x43 /* Timer offset */
+
+#define LOONGARCH_CSR_TICLR 0x44 /* Timer interrupt clear */
+
+/* LLBCTL CSRs */
+#define LOONGARCH_CSR_LLBCTL 0x60 /* LLBit control */
+FIELD(CSR_LLBCTL, ROLLB, 0, 1)
+FIELD(CSR_LLBCTL, WCLLB, 1, 1)
+FIELD(CSR_LLBCTL, KLO, 2, 1)
+
+/* Implement dependent */
+#define LOONGARCH_CSR_IMPCTL1 0x80 /* LoongArch config1 */
+
+#define LOONGARCH_CSR_IMPCTL2 0x81 /* LoongArch config2*/
+
+/* TLB Refill CSRs */
+#define LOONGARCH_CSR_TLBRENTRY 0x88 /* TLB refill exception address */
+#define LOONGARCH_CSR_TLBRBADV 0x89 /* TLB refill badvaddr */
+#define LOONGARCH_CSR_TLBRERA 0x8a /* TLB refill ERA */
+#define LOONGARCH_CSR_TLBRSAVE 0x8b /* KScratch for TLB refill */
+FIELD(CSR_TLBRERA, ISTLBR, 0, 1)
+FIELD(CSR_TLBRERA, PC, 2, 62)
+#define LOONGARCH_CSR_TLBRELO0 0x8c /* TLB refill entrylo0 */
+#define LOONGARCH_CSR_TLBRELO1 0x8d /* TLB refill entrylo1 */
+#define LOONGARCH_CSR_TLBREHI 0x8e /* TLB refill entryhi */
+FIELD(CSR_TLBREHI, PS, 0, 6)
+FIELD(CSR_TLBREHI, VPPN, 13, 35)
+#define LOONGARCH_CSR_TLBRPRMD 0x8f /* TLB refill mode info */
+FIELD(CSR_TLBRPRMD, PPLV, 0, 2)
+FIELD(CSR_TLBRPRMD, PIE, 2, 1)
+FIELD(CSR_TLBRPRMD, PWE, 4, 1)
+
+/* Machine Error CSRs */
+#define LOONGARCH_CSR_MERRCTL 0x90 /* ERRCTL */
+FIELD(CSR_MERRCTL, ISMERR, 0, 1)
+#define LOONGARCH_CSR_MERRINFO1 0x91
+#define LOONGARCH_CSR_MERRINFO2 0x92
+#define LOONGARCH_CSR_MERRENTRY 0x93 /* MError exception base */
+#define LOONGARCH_CSR_MERRERA 0x94 /* MError exception PC */
+#define LOONGARCH_CSR_MERRSAVE 0x95 /* KScratch for error exception */
+
+#define LOONGARCH_CSR_CTAG 0x98 /* TagLo + TagHi */
+
+/* Direct map windows CSRs*/
+#define LOONGARCH_CSR_DMW(N) (0x180 + N)
+FIELD(CSR_DMW, PLV0, 0, 1)
+FIELD(CSR_DMW, PLV1, 1, 1)
+FIELD(CSR_DMW, PLV2, 2, 1)
+FIELD(CSR_DMW, PLV3, 3, 1)
+FIELD(CSR_DMW, MAT, 4, 2)
+FIELD(CSR_DMW, VSEG, 60, 4)
+
+#define dmw_va2pa(va) \
+ (va & MAKE_64BIT_MASK(0, TARGET_VIRT_ADDR_SPACE_BITS))
+
+/* Debug CSRs */
+#define LOONGARCH_CSR_DBG 0x500 /* debug config */
+FIELD(CSR_DBG, DST, 0, 1)
+FIELD(CSR_DBG, DREV, 1, 7)
+FIELD(CSR_DBG, DEI, 8, 1)
+FIELD(CSR_DBG, DCL, 9, 1)
+FIELD(CSR_DBG, DFW, 10, 1)
+FIELD(CSR_DBG, DMW, 11, 1)
+FIELD(CSR_DBG, ECODE, 16, 6)
+
+#define LOONGARCH_CSR_DERA 0x501 /* Debug era */
+#define LOONGARCH_CSR_DSAVE 0x502 /* Debug save */
+
+#endif /* LOONGARCH_CPU_CSR_H */
diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index d8d61ef4bd..08455a72cf 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -164,6 +164,8 @@ static void loongarch_3a5000_initfn(Object *obj)
data = FIELD_DP32(data, CPUCFG20, L3IU_SETS, 14);
data = FIELD_DP32(data, CPUCFG20, L3IU_SETS, 6);
env->cpucfg[20] = data;
+
+ env->CSR_ASID = FIELD_DP64(0, CSR_ASID, ASIDBITS, 0xa);
}
static void loongarch_cpu_list_entry(gpointer data, gpointer user_data)
@@ -187,12 +189,45 @@ static void loongarch_cpu_reset(DeviceState *dev)
LoongArchCPU *cpu = LOONGARCH_CPU(cs);
LoongArchCPUClass *lacc = LOONGARCH_CPU_GET_CLASS(cpu);
CPULoongArchState *env = &cpu->env;
+ int n;
lacc->parent_reset(dev);
env->fcsr0_mask = FCSR0_M1 | FCSR0_M2 | FCSR0_M3;
env->fcsr0 = 0x0;
+ /* Set csr registers value after reset */
+ env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PLV, 0);
+ env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, IE, 0);
+ env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DA, 1);
+ env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PG, 0);
+ env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DATF, 1);
+ env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DATM, 1);
+
+ env->CSR_EUEN = FIELD_DP64(env->CSR_EUEN, CSR_EUEN, FPE, 0);
+ env->CSR_EUEN = FIELD_DP64(env->CSR_EUEN, CSR_EUEN, SXE, 0);
+ env->CSR_EUEN = FIELD_DP64(env->CSR_EUEN, CSR_EUEN, ASXE, 0);
+ env->CSR_EUEN = FIELD_DP64(env->CSR_EUEN, CSR_EUEN, BTE, 0);
+
+ env->CSR_MISC = 0;
+
+ env->CSR_ECFG = FIELD_DP64(env->CSR_ECFG, CSR_ECFG, VS, 0);
+ env->CSR_ECFG = FIELD_DP64(env->CSR_ECFG, CSR_ECFG, LIE, 0);
+
+ env->CSR_ESTAT = env->CSR_ESTAT & (~MAKE_64BIT_MASK(0, 2));
+ env->CSR_RVACFG = FIELD_DP64(env->CSR_RVACFG, CSR_RVACFG, RBITS, 0);
+ env->CSR_TCFG = FIELD_DP64(env->CSR_TCFG, CSR_TCFG, EN, 0);
+ env->CSR_LLBCTL = FIELD_DP64(env->CSR_LLBCTL, CSR_LLBCTL, KLO, 0);
+ env->CSR_TLBRERA = FIELD_DP64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR, 0);
+ env->CSR_MERRCTL = FIELD_DP64(env->CSR_MERRCTL, CSR_MERRCTL, ISMERR, 0);
+
+ for (n = 0; n < 4; n++) {
+ env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV0, 0);
+ env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV1, 0);
+ env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV2, 0);
+ env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV3, 0);
+ }
+
restore_fp_status(env);
cs->exception_index = EXCP_NONE;
}
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index 695d44803e..43be44c1a2 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -11,6 +11,7 @@
#include "exec/cpu-defs.h"
#include "fpu/softfloat-types.h"
#include "hw/registerfields.h"
+#include "cpu-csr.h"
#define TCG_GUEST_DEFAULT_MO (0)
@@ -164,6 +165,62 @@ typedef struct CPUArchState {
uint64_t llval;
uint64_t badaddr;
+
+ /* LoongArch CSRs */
+ uint64_t CSR_CRMD;
+ uint64_t CSR_PRMD;
+ uint64_t CSR_EUEN;
+ uint64_t CSR_MISC;
+ uint64_t CSR_ECFG;
+ uint64_t CSR_ESTAT;
+ uint64_t CSR_ERA;
+ uint64_t CSR_BADV;
+ uint64_t CSR_BADI;
+ uint64_t CSR_EENTRY;
+ uint64_t CSR_TLBIDX;
+ uint64_t CSR_TLBEHI;
+ uint64_t CSR_TLBELO0;
+ uint64_t CSR_TLBELO1;
+ uint64_t CSR_ASID;
+ uint64_t CSR_PGDL;
+ uint64_t CSR_PGDH;
+ uint64_t CSR_PGD;
+ uint64_t CSR_PWCL;
+ uint64_t CSR_PWCH;
+ uint64_t CSR_STLBPS;
+ uint64_t CSR_RVACFG;
+ uint64_t CSR_CPUID;
+ uint64_t CSR_PRCFG1;
+ uint64_t CSR_PRCFG2;
+ uint64_t CSR_PRCFG3;
+ uint64_t CSR_SAVE[16];
+ uint64_t CSR_TID;
+ uint64_t CSR_TCFG;
+ uint64_t CSR_TVAL;
+ uint64_t CSR_CNTC;
+ uint64_t CSR_TICLR;
+ uint64_t CSR_LLBCTL;
+ uint64_t CSR_IMPCTL1;
+ uint64_t CSR_IMPCTL2;
+ uint64_t CSR_TLBRENTRY;
+ uint64_t CSR_TLBRBADV;
+ uint64_t CSR_TLBRERA;
+ uint64_t CSR_TLBRSAVE;
+ uint64_t CSR_TLBRELO0;
+ uint64_t CSR_TLBRELO1;
+ uint64_t CSR_TLBREHI;
+ uint64_t CSR_TLBRPRMD;
+ uint64_t CSR_MERRCTL;
+ uint64_t CSR_MERRINFO1;
+ uint64_t CSR_MERRINFO2;
+ uint64_t CSR_MERRENTRY;
+ uint64_t CSR_MERRERA;
+ uint64_t CSR_MERRSAVE;
+ uint64_t CSR_CTAG;
+ uint64_t CSR_DMW[4];
+ uint64_t CSR_DBG;
+ uint64_t CSR_DERA;
+ uint64_t CSR_DSAVE;
} CPULoongArchState;
/**
--
2.31.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [RFC PATCH v7 03/29] target/loongarch: Add basic vmstate description of CPU.
2022-03-28 12:57 [RFC PATCH v7 00/29] Add LoongArch softmmu support Xiaojuan Yang
2022-03-28 12:57 ` [RFC PATCH v7 01/29] target/loongarch: Add system emulation introduction Xiaojuan Yang
2022-03-28 12:57 ` [RFC PATCH v7 02/29] target/loongarch: Add CSRs definition Xiaojuan Yang
@ 2022-03-28 12:57 ` Xiaojuan Yang
2022-03-28 12:57 ` [RFC PATCH v7 04/29] target/loongarch: Implement qmp_query_cpu_definitions() Xiaojuan Yang
` (26 subsequent siblings)
29 siblings, 0 replies; 71+ messages in thread
From: Xiaojuan Yang @ 2022-03-28 12:57 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland, richard.henderson, Song Gao
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
---
target/loongarch/cpu.c | 3 ++
target/loongarch/internals.h | 4 ++
target/loongarch/machine.c | 85 ++++++++++++++++++++++++++++++++++++
target/loongarch/meson.build | 6 +++
4 files changed, 98 insertions(+)
create mode 100644 target/loongarch/machine.c
diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index 08455a72cf..a78b24fd0a 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -328,6 +328,9 @@ static void loongarch_cpu_class_init(ObjectClass *c, void *data)
cc->has_work = loongarch_cpu_has_work;
cc->dump_state = loongarch_cpu_dump_state;
cc->set_pc = loongarch_cpu_set_pc;
+#ifndef CONFIG_USER_ONLY
+ dc->vmsd = &vmstate_loongarch_cpu;
+#endif
cc->disas_set_info = loongarch_cpu_disas_set_info;
#ifdef CONFIG_TCG
cc->tcg_ops = &loongarch_tcg_ops;
diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h
index 774a87ec80..c8e6f7012c 100644
--- a/target/loongarch/internals.h
+++ b/target/loongarch/internals.h
@@ -25,4 +25,8 @@ const char *loongarch_exception_name(int32_t exception);
void restore_fp_status(CPULoongArchState *env);
+#ifndef CONFIG_USER_ONLY
+extern const VMStateDescription vmstate_loongarch_cpu;
+#endif
+
#endif
diff --git a/target/loongarch/machine.c b/target/loongarch/machine.c
new file mode 100644
index 0000000000..d738c9c6f0
--- /dev/null
+++ b/target/loongarch/machine.c
@@ -0,0 +1,85 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * QEMU LoongArch Machine State
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "migration/cpu.h"
+
+/* LoongArch CPU state */
+
+const VMStateDescription vmstate_loongarch_cpu = {
+ .name = "cpu",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (VMStateField[]) {
+
+ VMSTATE_UINTTL_ARRAY(env.gpr, LoongArchCPU, 32),
+ VMSTATE_UINTTL(env.pc, LoongArchCPU),
+ VMSTATE_UINT64_ARRAY(env.fpr, LoongArchCPU, 32),
+ VMSTATE_UINT32(env.fcsr0, LoongArchCPU),
+
+ /* Remaining CSRs */
+ VMSTATE_UINT64(env.CSR_CRMD, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_PRMD, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_EUEN, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_MISC, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_ECFG, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_ESTAT, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_ERA, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_BADV, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_BADI, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_EENTRY, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_TLBIDX, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_TLBEHI, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_TLBELO0, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_TLBELO1, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_ASID, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_PGDL, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_PGDH, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_PGD, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_PWCL, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_PWCH, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_STLBPS, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_RVACFG, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_CPUID, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_PRCFG1, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_PRCFG2, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_PRCFG3, LoongArchCPU),
+ VMSTATE_UINT64_ARRAY(env.CSR_SAVE, LoongArchCPU, 16),
+ VMSTATE_UINT64(env.CSR_TID, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_TCFG, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_TVAL, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_CNTC, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_TICLR, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_LLBCTL, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_IMPCTL1, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_IMPCTL2, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_TLBRENTRY, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_TLBRBADV, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_TLBRERA, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_TLBRSAVE, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_TLBRELO0, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_TLBRELO1, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_TLBREHI, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_TLBRPRMD, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_MERRCTL, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_MERRINFO1, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_MERRINFO2, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_MERRENTRY, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_MERRERA, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_MERRSAVE, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_CTAG, LoongArchCPU),
+ VMSTATE_UINT64_ARRAY(env.CSR_DMW, LoongArchCPU, 4),
+
+ /* Debug CSRs */
+ VMSTATE_UINT64(env.CSR_DBG, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_DERA, LoongArchCPU),
+ VMSTATE_UINT64(env.CSR_DSAVE, LoongArchCPU),
+
+ VMSTATE_END_OF_LIST()
+ },
+};
diff --git a/target/loongarch/meson.build b/target/loongarch/meson.build
index bcb076e55f..103f36ee15 100644
--- a/target/loongarch/meson.build
+++ b/target/loongarch/meson.build
@@ -14,6 +14,12 @@ loongarch_tcg_ss.add(files(
))
loongarch_tcg_ss.add(zlib)
+loongarch_softmmu_ss = ss.source_set()
+loongarch_softmmu_ss.add(files(
+ 'machine.c',
+))
+
loongarch_ss.add_all(when: 'CONFIG_TCG', if_true: [loongarch_tcg_ss])
target_arch += {'loongarch': loongarch_ss}
+target_softmmu_arch += {'loongarch': loongarch_softmmu_ss}
--
2.31.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [RFC PATCH v7 04/29] target/loongarch: Implement qmp_query_cpu_definitions()
2022-03-28 12:57 [RFC PATCH v7 00/29] Add LoongArch softmmu support Xiaojuan Yang
` (2 preceding siblings ...)
2022-03-28 12:57 ` [RFC PATCH v7 03/29] target/loongarch: Add basic vmstate description of CPU Xiaojuan Yang
@ 2022-03-28 12:57 ` Xiaojuan Yang
2022-03-28 12:57 ` [RFC PATCH v7 05/29] target/loongarch: Add constant timer support Xiaojuan Yang
` (25 subsequent siblings)
29 siblings, 0 replies; 71+ messages in thread
From: Xiaojuan Yang @ 2022-03-28 12:57 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland, richard.henderson, Song Gao
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
---
qapi/machine-target.json | 6 ++++--
target/loongarch/cpu.c | 26 ++++++++++++++++++++++++++
2 files changed, 30 insertions(+), 2 deletions(-)
diff --git a/qapi/machine-target.json b/qapi/machine-target.json
index f5ec4bc172..682dc86b42 100644
--- a/qapi/machine-target.json
+++ b/qapi/machine-target.json
@@ -324,7 +324,8 @@
'TARGET_ARM',
'TARGET_I386',
'TARGET_S390X',
- 'TARGET_MIPS' ] } }
+ 'TARGET_MIPS',
+ 'TARGET_LOONGARCH64' ] } }
##
# @query-cpu-definitions:
@@ -340,4 +341,5 @@
'TARGET_ARM',
'TARGET_I386',
'TARGET_S390X',
- 'TARGET_MIPS' ] } }
+ 'TARGET_MIPS',
+ 'TARGET_LOONGARCH64' ] } }
diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index a78b24fd0a..d89fa3cc6b 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -359,3 +359,29 @@ static const TypeInfo loongarch_cpu_type_infos[] = {
};
DEFINE_TYPES(loongarch_cpu_type_infos)
+
+static void loongarch_cpu_add_definition(gpointer data, gpointer user_data)
+{
+ ObjectClass *oc = data;
+ CpuDefinitionInfoList **cpu_list = user_data;
+ CpuDefinitionInfo *info = g_new0(CpuDefinitionInfo, 1);
+ const char *typename = object_class_get_name(oc);
+
+ info->name = g_strndup(typename,
+ strlen(typename) - strlen("-" TYPE_LOONGARCH_CPU));
+ info->q_typename = g_strdup(typename);
+
+ QAPI_LIST_PREPEND(*cpu_list, info);
+}
+
+CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
+{
+ CpuDefinitionInfoList *cpu_list = NULL;
+ GSList *list;
+
+ list = object_class_get_list(TYPE_LOONGARCH_CPU, false);
+ g_slist_foreach(list, loongarch_cpu_add_definition, &cpu_list);
+ g_slist_free(list);
+
+ return cpu_list;
+}
--
2.31.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [RFC PATCH v7 05/29] target/loongarch: Add constant timer support
2022-03-28 12:57 [RFC PATCH v7 00/29] Add LoongArch softmmu support Xiaojuan Yang
` (3 preceding siblings ...)
2022-03-28 12:57 ` [RFC PATCH v7 04/29] target/loongarch: Implement qmp_query_cpu_definitions() Xiaojuan Yang
@ 2022-03-28 12:57 ` Xiaojuan Yang
2022-03-28 19:46 ` Richard Henderson
2022-03-28 20:58 ` Richard Henderson
2022-03-28 12:57 ` [RFC PATCH v7 06/29] target/loongarch: Add MMU support for LoongArch CPU Xiaojuan Yang
` (24 subsequent siblings)
29 siblings, 2 replies; 71+ messages in thread
From: Xiaojuan Yang @ 2022-03-28 12:57 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland, richard.henderson, Song Gao
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
target/loongarch/constant_timer.c | 62 +++++++++++++++++++++++++++++++
target/loongarch/cpu.h | 10 +++++
target/loongarch/meson.build | 1 +
3 files changed, 73 insertions(+)
create mode 100644 target/loongarch/constant_timer.c
diff --git a/target/loongarch/constant_timer.c b/target/loongarch/constant_timer.c
new file mode 100644
index 0000000000..8477f91f35
--- /dev/null
+++ b/target/loongarch/constant_timer.c
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * QEMU LoongArch constant timer support
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "hw/loongarch/loongarch.h"
+#include "qemu/timer.h"
+#include "cpu.h"
+
+#define TIMER_PERIOD 10 /* 10 ns period for 100 MHz frequency */
+#define CONSTANT_TIMER_TICK_MASK 0xfffffffffffcUL
+#define CONSTANT_TIMER_ENABLE 0x1UL
+
+uint64_t cpu_loongarch_get_constant_timer_counter(LoongArchCPU *cpu)
+{
+ return qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / TIMER_PERIOD;
+}
+
+uint64_t cpu_loongarch_get_constant_timer_ticks(LoongArchCPU *cpu)
+{
+ uint64_t now, expire;
+
+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ expire = timer_expire_time_ns(&cpu->timer);
+
+ return (expire - now) / TIMER_PERIOD;
+}
+
+void cpu_loongarch_store_constant_timer_config(LoongArchCPU *cpu,
+ uint64_t value)
+{
+ CPULoongArchState *env = &cpu->env;
+ uint64_t now, next;
+
+ env->CSR_TCFG = value;
+ if (value & CONSTANT_TIMER_ENABLE) {
+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ next = now + (value & CONSTANT_TIMER_TICK_MASK) * TIMER_PERIOD;
+ timer_mod(&cpu->timer, next);
+ }
+}
+
+void loongarch_constant_timer_cb(void *opaque)
+{
+ LoongArchCPU *cpu = opaque;
+ CPULoongArchState *env = &cpu->env;
+ uint64_t now, next;
+
+ if (FIELD_EX64(env->CSR_TCFG, CSR_TCFG, PERIODIC)) {
+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ next = now + (env->CSR_TCFG & CONSTANT_TIMER_TICK_MASK) * TIMER_PERIOD;
+ timer_mod(&cpu->timer, next);
+ } else {
+ env->CSR_TCFG = FIELD_DP64(env->CSR_TCFG, CSR_TCFG, EN, 0);
+ }
+
+ env->CSR_ESTAT |= 1 << IRQ_TIMER;
+ cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
+}
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index 43be44c1a2..39d9f9a6de 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -12,6 +12,7 @@
#include "fpu/softfloat-types.h"
#include "hw/registerfields.h"
#include "cpu-csr.h"
+#include "qemu/timer.h"
#define TCG_GUEST_DEFAULT_MO (0)
@@ -148,6 +149,9 @@ FIELD(CPUCFG20, L3IU_SIZE, 24, 7)
extern const char * const regnames[32];
extern const char * const fregnames[32];
+#define N_IRQS 14
+#define IRQ_TIMER 11
+
typedef struct CPUArchState {
uint64_t gpr[32];
uint64_t pc;
@@ -236,6 +240,7 @@ struct ArchCPU {
CPUNegativeOffsetState neg;
CPULoongArchState env;
+ QEMUTimer timer;
};
#define TYPE_LOONGARCH_CPU "loongarch-cpu"
@@ -297,4 +302,9 @@ enum {
#define LOONGARCH_CPU_TYPE_NAME(model) model LOONGARCH_CPU_TYPE_SUFFIX
#define CPU_RESOLVING_TYPE TYPE_LOONGARCH_CPU
+void loongarch_constant_timer_cb(void *opaque);
+uint64_t cpu_loongarch_get_constant_timer_counter(LoongArchCPU *cpu);
+uint64_t cpu_loongarch_get_constant_timer_ticks(LoongArchCPU *cpu);
+void cpu_loongarch_store_constant_timer_config(LoongArchCPU *cpu,
+ uint64_t value);
#endif /* LOONGARCH_CPU_H */
diff --git a/target/loongarch/meson.build b/target/loongarch/meson.build
index 103f36ee15..6168e910a0 100644
--- a/target/loongarch/meson.build
+++ b/target/loongarch/meson.build
@@ -17,6 +17,7 @@ loongarch_tcg_ss.add(zlib)
loongarch_softmmu_ss = ss.source_set()
loongarch_softmmu_ss.add(files(
'machine.c',
+ 'constant_timer.c',
))
loongarch_ss.add_all(when: 'CONFIG_TCG', if_true: [loongarch_tcg_ss])
--
2.31.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [RFC PATCH v7 06/29] target/loongarch: Add MMU support for LoongArch CPU.
2022-03-28 12:57 [RFC PATCH v7 00/29] Add LoongArch softmmu support Xiaojuan Yang
` (4 preceding siblings ...)
2022-03-28 12:57 ` [RFC PATCH v7 05/29] target/loongarch: Add constant timer support Xiaojuan Yang
@ 2022-03-28 12:57 ` Xiaojuan Yang
2022-03-28 20:06 ` Richard Henderson
2022-03-28 12:57 ` [RFC PATCH v7 07/29] target/loongarch: Add LoongArch CSR instruction Xiaojuan Yang
` (23 subsequent siblings)
29 siblings, 1 reply; 71+ messages in thread
From: Xiaojuan Yang @ 2022-03-28 12:57 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland, richard.henderson, Song Gao
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
target/loongarch/cpu-param.h | 2 +-
target/loongarch/cpu.c | 30 ++++
target/loongarch/cpu.h | 42 ++++-
target/loongarch/internals.h | 9 +
target/loongarch/machine.c | 17 ++
target/loongarch/meson.build | 1 +
target/loongarch/op_helper.c | 8 +
target/loongarch/tlb_helper.c | 316 ++++++++++++++++++++++++++++++++++
8 files changed, 423 insertions(+), 2 deletions(-)
create mode 100644 target/loongarch/tlb_helper.c
diff --git a/target/loongarch/cpu-param.h b/target/loongarch/cpu-param.h
index 9a769b67e0..414d8fff46 100644
--- a/target/loongarch/cpu-param.h
+++ b/target/loongarch/cpu-param.h
@@ -13,6 +13,6 @@
#define TARGET_VIRT_ADDR_SPACE_BITS 48
#define TARGET_PAGE_BITS 14
-#define NB_MMU_MODES 4
+#define NB_MMU_MODES 5
#endif
diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index d89fa3cc6b..880801fa51 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -294,6 +294,23 @@ void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags)
}
}
+#ifndef CONFIG_USER_ONLY
+ qemu_fprintf(f, "CRMD=%016" PRIx64 "\n", env->CSR_CRMD);
+ qemu_fprintf(f, "PRMD=%016" PRIx64 "\n", env->CSR_PRMD);
+ qemu_fprintf(f, "EUEN=%016" PRIx64 "\n", env->CSR_EUEN);
+ qemu_fprintf(f, "ESTAT=%016" PRIx64 "\n", env->CSR_ESTAT);
+ qemu_fprintf(f, "ERA=%016" PRIx64 "\n", env->CSR_ERA);
+ qemu_fprintf(f, "BADV=%016" PRIx64 "\n", env->CSR_BADV);
+ qemu_fprintf(f, "BADI=%016" PRIx64 "\n", env->CSR_BADI);
+ qemu_fprintf(f, "EENTRY=%016" PRIx64 "\n", env->CSR_EENTRY);
+ qemu_fprintf(f, "PRCFG1=%016" PRIx64 ", PRCFG2=%016" PRIx64 ","
+ " PRCFG3=%016" PRIx64 "\n",
+ env->CSR_PRCFG1, env->CSR_PRCFG3, env->CSR_PRCFG3);
+ qemu_fprintf(f, "TLBRENTRY=%016" PRIx64 "\n", env->CSR_TLBRENTRY);
+ qemu_fprintf(f, "TLBRBADV=%016" PRIx64 "\n", env->CSR_TLBRBADV);
+ qemu_fprintf(f, "TLBRERA=%016" PRIx64 "\n", env->CSR_TLBRERA);
+#endif
+
/* fpr */
if (flags & CPU_DUMP_FPU) {
for (i = 0; i < 32; i++) {
@@ -311,9 +328,21 @@ void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags)
static struct TCGCPUOps loongarch_tcg_ops = {
.initialize = loongarch_translate_init,
.synchronize_from_tb = loongarch_cpu_synchronize_from_tb,
+
+#if !defined(CONFIG_USER_ONLY)
+ .tlb_fill = loongarch_cpu_tlb_fill,
+#endif /* !CONFIG_USER_ONLY */
};
#endif /* CONFIG_TCG */
+#ifndef CONFIG_USER_ONLY
+#include "hw/core/sysemu-cpu-ops.h"
+
+static const struct SysemuCPUOps loongarch_sysemu_ops = {
+ .get_phys_page_debug = loongarch_cpu_get_phys_page_debug,
+};
+#endif
+
static void loongarch_cpu_class_init(ObjectClass *c, void *data)
{
LoongArchCPUClass *lacc = LOONGARCH_CPU_CLASS(c);
@@ -330,6 +359,7 @@ static void loongarch_cpu_class_init(ObjectClass *c, void *data)
cc->set_pc = loongarch_cpu_set_pc;
#ifndef CONFIG_USER_ONLY
dc->vmsd = &vmstate_loongarch_cpu;
+ cc->sysemu_ops = &loongarch_sysemu_ops;
#endif
cc->disas_set_info = loongarch_cpu_disas_set_info;
#ifdef CONFIG_TCG
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index 39d9f9a6de..0cced52565 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -152,6 +152,26 @@ extern const char * const fregnames[32];
#define N_IRQS 14
#define IRQ_TIMER 11
+#define LOONGARCH_STLB 2048 /* 2048 STLB */
+#define LOONGARCH_MTLB 64 /* 64 MTLB */
+#define LOONGARCH_TLB_MAX (LOONGARCH_STLB + LOONGARCH_MTLB)
+
+/*
+ * define the ASID PS E VPPN field of TLB
+ */
+FIELD(TLB_MISC, E, 0, 1)
+FIELD(TLB_MISC, ASID, 1, 10)
+FIELD(TLB_MISC, VPPN, 13, 35)
+FIELD(TLB_MISC, PS, 48, 6)
+
+struct LoongArchTLB {
+ uint64_t tlb_misc;
+ /* Fields corresponding to CSR_TLBELO0/1 */
+ uint64_t tlb_entry0;
+ uint64_t tlb_entry1;
+};
+typedef struct LoongArchTLB LoongArchTLB;
+
typedef struct CPUArchState {
uint64_t gpr[32];
uint64_t pc;
@@ -225,6 +245,10 @@ typedef struct CPUArchState {
uint64_t CSR_DBG;
uint64_t CSR_DERA;
uint64_t CSR_DSAVE;
+
+#ifndef CONFIG_USER_ONLY
+ LoongArchTLB tlb[LOONGARCH_TLB_MAX];
+#endif
} CPULoongArchState;
/**
@@ -264,11 +288,27 @@ struct LoongArchCPUClass {
DeviceReset parent_reset;
};
-#define MMU_USER_IDX 3
+/*
+ * LoongArch CPUs has 4 privilege levels.
+ * 0 for kernel mode, 3 for user mode.
+ * Define an extra index for DA(direct addressing) mode.
+ */
+#define MMU_KERNEL_IDX 0
+#define MMU_USER_IDX 3
+#define MMU_DA_IDX 4
static inline int cpu_mmu_index(CPULoongArchState *env, bool ifetch)
{
+#ifdef CONFIG_USER_ONLY
return MMU_USER_IDX;
+#else
+ uint8_t pg = FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PG);
+
+ if (!pg) {
+ return MMU_DA_IDX;
+ }
+ return FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PLV);
+#endif
}
static inline void cpu_get_tb_cpu_state(CPULoongArchState *env,
diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h
index c8e6f7012c..5fc1a4bb07 100644
--- a/target/loongarch/internals.h
+++ b/target/loongarch/internals.h
@@ -13,6 +13,9 @@
#define FCMP_UN 0b0100 /* unordered */
#define FCMP_GT 0b1000 /* fp0 > fp1 */
+#define TARGET_PHYS_MASK MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS)
+#define TARGET_VIRT_MASK MAKE_64BIT_MASK(0, TARGET_VIRT_ADDR_SPACE_BITS)
+
void loongarch_translate_init(void);
void loongarch_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
@@ -27,6 +30,12 @@ void restore_fp_status(CPULoongArchState *env);
#ifndef CONFIG_USER_ONLY
extern const VMStateDescription vmstate_loongarch_cpu;
+
+bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+ MMUAccessType access_type, int mmu_idx,
+ bool probe, uintptr_t retaddr);
+
+hwaddr loongarch_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
#endif
#endif
diff --git a/target/loongarch/machine.c b/target/loongarch/machine.c
index d738c9c6f0..e710f3480e 100644
--- a/target/loongarch/machine.c
+++ b/target/loongarch/machine.c
@@ -8,6 +8,20 @@
#include "qemu/osdep.h"
#include "cpu.h"
#include "migration/cpu.h"
+#include "internals.h"
+
+/* TLB state */
+const VMStateDescription vmstate_tlb = {
+ .name = "cpu/tlb",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT64(tlb_misc, LoongArchTLB),
+ VMSTATE_UINT64(tlb_entry0, LoongArchTLB),
+ VMSTATE_UINT64(tlb_entry1, LoongArchTLB),
+ VMSTATE_END_OF_LIST()
+ }
+};
/* LoongArch CPU state */
@@ -79,6 +93,9 @@ const VMStateDescription vmstate_loongarch_cpu = {
VMSTATE_UINT64(env.CSR_DBG, LoongArchCPU),
VMSTATE_UINT64(env.CSR_DERA, LoongArchCPU),
VMSTATE_UINT64(env.CSR_DSAVE, LoongArchCPU),
+ /* TLB */
+ VMSTATE_STRUCT_ARRAY(env.tlb, LoongArchCPU, LOONGARCH_TLB_MAX,
+ 0, vmstate_tlb, LoongArchTLB),
VMSTATE_END_OF_LIST()
},
diff --git a/target/loongarch/meson.build b/target/loongarch/meson.build
index 6168e910a0..6bf2d88104 100644
--- a/target/loongarch/meson.build
+++ b/target/loongarch/meson.build
@@ -18,6 +18,7 @@ loongarch_softmmu_ss = ss.source_set()
loongarch_softmmu_ss.add(files(
'machine.c',
'constant_timer.c',
+ 'tlb_helper.c',
))
loongarch_ss.add_all(when: 'CONFIG_TCG', if_true: [loongarch_tcg_ss])
diff --git a/target/loongarch/op_helper.c b/target/loongarch/op_helper.c
index 1083e39b7f..48c25e5a9b 100644
--- a/target/loongarch/op_helper.c
+++ b/target/loongarch/op_helper.c
@@ -47,16 +47,24 @@ target_ulong helper_bitswap(target_ulong v)
void helper_asrtle_d(CPULoongArchState *env, target_ulong rj, target_ulong rk)
{
if (rj > rk) {
+#ifdef CONFIG_USER_ONLY
cpu_loop_exit_sigsegv(env_cpu(env), GETPC(),
MMU_DATA_LOAD, true, GETPC());
+#else
+ do_raise_exception(env, EXCCODE_ADEM, GETPC());
+#endif
}
}
void helper_asrtgt_d(CPULoongArchState *env, target_ulong rj, target_ulong rk)
{
if (rj <= rk) {
+#ifdef CONFIG_USER_ONLY
cpu_loop_exit_sigsegv(env_cpu(env), GETPC(),
MMU_DATA_LOAD, true, GETPC());
+#else
+ do_raise_exception(env, EXCCODE_ADEM, GETPC());
+#endif
}
}
diff --git a/target/loongarch/tlb_helper.c b/target/loongarch/tlb_helper.c
new file mode 100644
index 0000000000..992d87493a
--- /dev/null
+++ b/target/loongarch/tlb_helper.c
@@ -0,0 +1,316 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * QEMU LoongArch TLB helpers
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ *
+ */
+
+#include "qemu/osdep.h"
+
+#include "cpu.h"
+#include "internals.h"
+#include "exec/exec-all.h"
+#include "exec/cpu_ldst.h"
+#include "exec/log.h"
+#include "cpu-csr.h"
+
+enum {
+ TLBRET_MATCH = 0,
+ TLBRET_BADADDR = 1,
+ TLBRET_NOMATCH = 2,
+ TLBRET_INVALID = 3,
+ TLBRET_DIRTY = 4,
+ TLBRET_RI = 5,
+ TLBRET_XI = 6,
+ TLBRET_PE = 7,
+};
+
+static int loongarch_map_tlb_entry(CPULoongArchState *env, hwaddr *physical,
+ int *prot, target_ulong address,
+ int access_type, int index, int mmu_idx)
+{
+ LoongArchTLB *tlb = &env->tlb[index];
+ uint64_t plv = mmu_idx;
+ uint64_t tlb_entry, tlb_ppn;
+ uint8_t tlb_ps, n, tlb_v, tlb_d, tlb_plv, tlb_nx, tlb_nr, tlb_rplv;
+
+ if (index >= LOONGARCH_STLB) {
+ tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS);
+ } else {
+ tlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS);
+ }
+ n = (address >> tlb_ps) & 0x1;/* Odd or even */
+
+ tlb_entry = n ? tlb->tlb_entry1 : tlb->tlb_entry0;
+ tlb_v = FIELD_EX64(tlb_entry, TLBENTRY, V);
+ tlb_d = FIELD_EX64(tlb_entry, TLBENTRY, D);
+ tlb_plv = FIELD_EX64(tlb_entry, TLBENTRY, PLV);
+ tlb_ppn = FIELD_EX64(tlb_entry, TLBENTRY, PPN);
+ tlb_nx = FIELD_EX64(tlb_entry, TLBENTRY, NX);
+ tlb_nr = FIELD_EX64(tlb_entry, TLBENTRY, NR);
+ tlb_rplv = FIELD_EX64(tlb_entry, TLBENTRY, RPLV);
+
+ /* Check access rights */
+ if (!tlb_v) {
+ return TLBRET_INVALID;
+ }
+
+ if (access_type == MMU_INST_FETCH && tlb_nx) {
+ return TLBRET_XI;
+ }
+
+ if (access_type == MMU_DATA_LOAD && tlb_nr) {
+ return TLBRET_RI;
+ }
+
+ if (((tlb_rplv == 0) && (plv > tlb_plv)) ||
+ ((tlb_rplv == 1) && (plv != tlb_plv))) {
+ return TLBRET_PE;
+ }
+
+ if ((access_type == MMU_DATA_STORE) && !tlb_d) {
+ return TLBRET_DIRTY;
+ }
+
+ /*
+ * tlb_entry contains ppn[47:12] while 16KiB ppn is [47:15]
+ * need adjust.
+ */
+ *physical = (tlb_ppn << R_TLBENTRY_PPN_SHIFT) |
+ (address & MAKE_64BIT_MASK(0, tlb_ps));
+ *prot = PAGE_READ;
+ if (tlb_d) {
+ *prot |= PAGE_WRITE;
+ }
+ if (!tlb_nx) {
+ *prot |= PAGE_EXEC;
+ }
+ return TLBRET_MATCH;
+}
+
+/*
+ * One tlb entry holds an adjacent odd/even pair, the vpn is the
+ * content of the virtual page number divided by 2. So the
+ * compare vpn is bit[47:15] for 16KiB page. while the vppn
+ * field in tlb entry contains bit[47:13], so need adjust.
+ * virt_vpn = vaddr[47:13]
+ */
+static bool loongarch_tlb_search(CPULoongArchState *env, target_ulong vaddr,
+ int *index)
+{
+ LoongArchTLB *tlb;
+ uint16_t csr_asid, tlb_asid, stlb_idx;
+ uint8_t tlb_e, tlb_ps, tlb_g, stlb_ps;
+ int i, compare_shift;
+ uint64_t vpn, tlb_vppn;
+
+ csr_asid = FIELD_EX64(env->CSR_ASID, CSR_ASID, ASID);
+ stlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS);
+ vpn = (vaddr & TARGET_VIRT_MASK) >> (stlb_ps + 1);
+ stlb_idx = vpn & 0xff; /* VA[25:15] <==> TLBIDX.index for 16KiB Page */
+ compare_shift = stlb_ps + 1 - R_TLB_MISC_VPPN_SHIFT;
+
+ /* Search STLB */
+ for (i = 0; i < 8; ++i) {
+ tlb = &env->tlb[i * 256 + stlb_idx];
+ tlb_e = FIELD_EX64(tlb->tlb_misc, TLB_MISC, E);
+ if (tlb_e) {
+ tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN);
+ tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID);
+ tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G);
+
+ if ((tlb_g == 1 || tlb_asid == csr_asid) &&
+ (vpn == (tlb_vppn >> compare_shift))) {
+ *index = i * 256 + stlb_idx;
+ return true;
+ }
+ }
+ }
+
+ /* Search MTLB */
+ for (i = LOONGARCH_STLB; i < LOONGARCH_TLB_MAX; ++i) {
+ tlb = &env->tlb[i];
+ tlb_e = FIELD_EX64(tlb->tlb_misc, TLB_MISC, E);
+ if (tlb_e) {
+ tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN);
+ tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS);
+ tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID);
+ tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G);
+ compare_shift = tlb_ps + 1 - R_TLB_MISC_VPPN_SHIFT;
+ vpn = (vaddr & TARGET_VIRT_MASK) >> (tlb_ps + 1);
+ if ((tlb_g == 1 || tlb_asid == csr_asid) &&
+ (vpn == (tlb_vppn >> compare_shift))) {
+ *index = i;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static int loongarch_map_address(CPULoongArchState *env, hwaddr *physical,
+ int *prot, target_ulong address,
+ MMUAccessType access_type, int mmu_idx)
+{
+ int index, match;
+
+ match = loongarch_tlb_search(env, address, &index);
+ if (match) {
+ return loongarch_map_tlb_entry(env, physical, prot,
+ address, access_type, index, mmu_idx);
+ }
+
+ return TLBRET_NOMATCH;
+}
+
+static int get_physical_address(CPULoongArchState *env, hwaddr *physical,
+ int *prot, target_ulong address,
+ MMUAccessType access_type, int mmu_idx)
+{
+ int user_mode = mmu_idx == MMU_USER_IDX;
+ int kernel_mode = mmu_idx == MMU_KERNEL_IDX;
+ uint32_t plv, base_c, base_v;
+ int64_t addr_high;
+ uint8_t da = FIELD_EX64(env->CSR_CRMD, CSR_CRMD, DA);
+ uint8_t pg = FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PG);
+
+ /* Check PG and DA */
+ if (da & !pg) {
+ *physical = address & TARGET_PHYS_MASK;
+ *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+ return TLBRET_MATCH;
+ }
+
+ plv = kernel_mode | (user_mode << R_CSR_DMW_PLV3_SHIFT);
+ base_v = address >> TARGET_VIRT_ADDR_SPACE_BITS;
+ /* Check direct map window */
+ for (int i = 0; i < 4; i++) {
+ base_c = env->CSR_DMW[i] >> TARGET_VIRT_ADDR_SPACE_BITS;
+ if ((plv & env->CSR_DMW[i]) && (base_c == base_v)) {
+ *physical = dmw_va2pa(address);
+ *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+ return TLBRET_MATCH;
+ }
+ }
+
+ /* Check valid extension */
+ addr_high = sextract64(address, TARGET_VIRT_ADDR_SPACE_BITS, 16);
+ if (!(addr_high == 0 || addr_high == -1)) {
+ return TLBRET_BADADDR;
+ }
+
+ /* Mapped address */
+ return loongarch_map_address(env, physical, prot, address,
+ access_type, mmu_idx);
+}
+
+hwaddr loongarch_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
+{
+ LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+ CPULoongArchState *env = &cpu->env;
+ hwaddr phys_addr;
+ int prot;
+
+ if (get_physical_address(env, &phys_addr, &prot, addr, MMU_DATA_LOAD,
+ cpu_mmu_index(env, false)) != 0) {
+ return -1;
+ }
+ return phys_addr;
+}
+
+static void raise_mmu_exception(CPULoongArchState *env, target_ulong address,
+ MMUAccessType access_type, int tlb_error)
+{
+ CPUState *cs = env_cpu(env);
+
+ switch (tlb_error) {
+ default:
+ case TLBRET_BADADDR:
+ cs->exception_index = EXCCODE_ADEM;
+ break;
+ case TLBRET_NOMATCH:
+ /* No TLB match for a mapped address */
+ if (access_type == MMU_DATA_LOAD) {
+ cs->exception_index = EXCCODE_PIL;
+ } else if (access_type == MMU_DATA_STORE) {
+ cs->exception_index = EXCCODE_PIS;
+ } else if (access_type == MMU_INST_FETCH) {
+ cs->exception_index = EXCCODE_PIF;
+ }
+ env->CSR_TLBRERA = FIELD_DP64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR, 1);
+ break;
+ case TLBRET_INVALID:
+ /* TLB match with no valid bit */
+ if (access_type == MMU_DATA_LOAD) {
+ cs->exception_index = EXCCODE_PIL;
+ } else if (access_type == MMU_DATA_STORE) {
+ cs->exception_index = EXCCODE_PIS;
+ } else if (access_type == MMU_INST_FETCH) {
+ cs->exception_index = EXCCODE_PIF;
+ }
+ break;
+ case TLBRET_DIRTY:
+ /* TLB match but 'D' bit is cleared */
+ cs->exception_index = EXCCODE_PME;
+ break;
+ case TLBRET_XI:
+ /* Execute-Inhibit Exception */
+ cs->exception_index = EXCCODE_PNX;
+ break;
+ case TLBRET_RI:
+ /* Read-Inhibit Exception */
+ cs->exception_index = EXCCODE_PNR;
+ break;
+ case TLBRET_PE:
+ /* Privileged Exception */
+ cs->exception_index = EXCCODE_PPI;
+ break;
+ }
+
+ if (tlb_error == TLBRET_NOMATCH) {
+ env->CSR_TLBRBADV = address;
+ env->CSR_TLBREHI = FIELD_DP64(env->CSR_TLBREHI, CSR_TLBREHI, VPPN,
+ extract64(address, 13, 35));
+ } else {
+ if (!FIELD_EX64(env->CSR_DBG, CSR_DBG, DST)) {
+ env->CSR_BADV = address;
+ }
+ env->CSR_TLBEHI = address & (TARGET_PAGE_MASK << 1);
+ }
+}
+
+bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+ MMUAccessType access_type, int mmu_idx,
+ bool probe, uintptr_t retaddr)
+{
+ LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+ CPULoongArchState *env = &cpu->env;
+ hwaddr physical;
+ int prot;
+ int ret = TLBRET_BADADDR;
+
+ /* Data access */
+ ret = get_physical_address(env, &physical, &prot, address,
+ access_type, mmu_idx);
+
+ if (ret == TLBRET_MATCH) {
+ tlb_set_page(cs, address & TARGET_PAGE_MASK,
+ physical & TARGET_PAGE_MASK, prot,
+ mmu_idx, TARGET_PAGE_SIZE);
+ qemu_log_mask(CPU_LOG_MMU,
+ "%s address=%" VADDR_PRIx " physical " TARGET_FMT_plx
+ " prot %d\n", __func__, address, physical, prot);
+ return true;
+ } else {
+ qemu_log_mask(CPU_LOG_MMU,
+ "%s address=%" VADDR_PRIx " ret %d\n", __func__, address,
+ ret);
+ }
+ if (probe) {
+ return false;
+ } else {
+ raise_mmu_exception(env, address, access_type, ret);
+ do_raise_exception(env, cs->exception_index, retaddr);
+ }
+}
--
2.31.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [RFC PATCH v7 07/29] target/loongarch: Add LoongArch CSR instruction
2022-03-28 12:57 [RFC PATCH v7 00/29] Add LoongArch softmmu support Xiaojuan Yang
` (5 preceding siblings ...)
2022-03-28 12:57 ` [RFC PATCH v7 06/29] target/loongarch: Add MMU support for LoongArch CPU Xiaojuan Yang
@ 2022-03-28 12:57 ` Xiaojuan Yang
2022-03-28 18:34 ` Richard Henderson
2022-03-28 12:57 ` [RFC PATCH v7 08/29] target/loongarch: Add LoongArch IOCSR instruction Xiaojuan Yang
` (22 subsequent siblings)
29 siblings, 1 reply; 71+ messages in thread
From: Xiaojuan Yang @ 2022-03-28 12:57 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland, richard.henderson, Song Gao
This includes:
- CSRRD
- CSRWR
- CSRXCHG
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
target/loongarch/cpu.h | 88 ++++++++++++
target/loongarch/csr_helper.c | 112 ++++++++++++++++
target/loongarch/disas.c | 15 +++
target/loongarch/helper.h | 7 +
.../insn_trans/trans_privileged.c.inc | 125 ++++++++++++++++++
target/loongarch/insns.decode | 13 ++
target/loongarch/meson.build | 1 +
target/loongarch/translate.c | 5 +
8 files changed, 366 insertions(+)
create mode 100644 target/loongarch/csr_helper.c
create mode 100644 target/loongarch/insn_trans/trans_privileged.c.inc
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index 0cced52565..f682dd33fe 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -251,6 +251,94 @@ typedef struct CPUArchState {
#endif
} CPULoongArchState;
+#define CSR_OFF(X) \
+ [LOONGARCH_CSR_##X] = offsetof(CPULoongArchState, CSR_##X)
+#define CSR_OFF_ARRAY(X, N) \
+ [LOONGARCH_CSR_##X(N)] = offsetof(CPULoongArchState, CSR_##X[N])
+
+static const int csr_offsets[] = {
+ CSR_OFF(CRMD),
+ CSR_OFF(PRMD),
+ CSR_OFF(EUEN),
+ CSR_OFF(MISC),
+ CSR_OFF(ECFG),
+ CSR_OFF(ESTAT),
+ CSR_OFF(ERA),
+ CSR_OFF(BADV),
+ CSR_OFF(BADI),
+ CSR_OFF(EENTRY),
+ CSR_OFF(TLBIDX),
+ CSR_OFF(TLBEHI),
+ CSR_OFF(TLBELO0),
+ CSR_OFF(TLBELO1),
+ CSR_OFF(ASID),
+ CSR_OFF(PGDL),
+ CSR_OFF(PGDH),
+ CSR_OFF(PGD),
+ CSR_OFF(PWCL),
+ CSR_OFF(PWCH),
+ CSR_OFF(STLBPS),
+ CSR_OFF(RVACFG),
+ CSR_OFF(CPUID),
+ CSR_OFF(PRCFG1),
+ CSR_OFF(PRCFG2),
+ CSR_OFF(PRCFG3),
+ CSR_OFF_ARRAY(SAVE, 0),
+ CSR_OFF_ARRAY(SAVE, 1),
+ CSR_OFF_ARRAY(SAVE, 2),
+ CSR_OFF_ARRAY(SAVE, 3),
+ CSR_OFF_ARRAY(SAVE, 4),
+ CSR_OFF_ARRAY(SAVE, 5),
+ CSR_OFF_ARRAY(SAVE, 6),
+ CSR_OFF_ARRAY(SAVE, 7),
+ CSR_OFF_ARRAY(SAVE, 8),
+ CSR_OFF_ARRAY(SAVE, 9),
+ CSR_OFF_ARRAY(SAVE, 10),
+ CSR_OFF_ARRAY(SAVE, 11),
+ CSR_OFF_ARRAY(SAVE, 12),
+ CSR_OFF_ARRAY(SAVE, 13),
+ CSR_OFF_ARRAY(SAVE, 14),
+ CSR_OFF_ARRAY(SAVE, 15),
+ CSR_OFF(TID),
+ CSR_OFF(TCFG),
+ CSR_OFF(TVAL),
+ CSR_OFF(CNTC),
+ CSR_OFF(TICLR),
+ CSR_OFF(LLBCTL),
+ CSR_OFF(IMPCTL1),
+ CSR_OFF(IMPCTL2),
+ CSR_OFF(TLBRENTRY),
+ CSR_OFF(TLBRBADV),
+ CSR_OFF(TLBRERA),
+ CSR_OFF(TLBRSAVE),
+ CSR_OFF(TLBRELO0),
+ CSR_OFF(TLBRELO1),
+ CSR_OFF(TLBREHI),
+ CSR_OFF(TLBRPRMD),
+ CSR_OFF(MERRCTL),
+ CSR_OFF(MERRINFO1),
+ CSR_OFF(MERRINFO2),
+ CSR_OFF(MERRENTRY),
+ CSR_OFF(MERRERA),
+ CSR_OFF(MERRSAVE),
+ CSR_OFF(CTAG),
+ CSR_OFF_ARRAY(DMW, 0),
+ CSR_OFF_ARRAY(DMW, 1),
+ CSR_OFF_ARRAY(DMW, 2),
+ CSR_OFF_ARRAY(DMW, 3),
+ CSR_OFF(DBG),
+ CSR_OFF(DERA),
+ CSR_OFF(DSAVE),
+};
+
+static inline int cpu_csr_offset(unsigned csr_num)
+{
+ if (csr_num < ARRAY_SIZE(csr_offsets)) {
+ return csr_offsets[csr_num];
+ }
+ return 0;
+}
+
/**
* LoongArchCPU:
* @env: #CPULoongArchState
diff --git a/target/loongarch/csr_helper.c b/target/loongarch/csr_helper.c
new file mode 100644
index 0000000000..8bbc56bda0
--- /dev/null
+++ b/target/loongarch/csr_helper.c
@@ -0,0 +1,112 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * LoongArch emulation helpers for CSRs
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/main-loop.h"
+#include "cpu.h"
+#include "internals.h"
+#include "qemu/host-utils.h"
+#include "exec/helper-proto.h"
+#include "exec/exec-all.h"
+#include "exec/cpu_ldst.h"
+#include "hw/irq.h"
+#include "cpu-csr.h"
+#include "hw/loongarch/loongarch.h"
+#include "tcg/tcg-ldst.h"
+
+target_ulong helper_csr_rdq(CPULoongArchState *env, uint64_t csr)
+{
+ LoongArchCPU *cpu;
+ int64_t v;
+
+ switch (csr) {
+ case LOONGARCH_CSR_PGD:
+ if (env->CSR_TLBRERA & 0x1) {
+ v = env->CSR_TLBRBADV;
+ } else {
+ v = env->CSR_BADV;
+ }
+
+ if ((v >> 63) & 0x1) {
+ v = env->CSR_PGDH;
+ } else {
+ v = env->CSR_PGDL;
+ }
+ break;
+ case LOONGARCH_CSR_CPUID:
+ v = (env_cpu(env))->cpu_index;
+ break;
+ case LOONGARCH_CSR_TVAL:
+ cpu = LOONGARCH_CPU(env_cpu(env));
+ v = cpu_loongarch_get_constant_timer_ticks(cpu);
+ break;
+ default:
+ break;
+ }
+
+ return v;
+}
+
+target_ulong helper_csr_wrq(CPULoongArchState *env, target_ulong val,
+ uint64_t csr)
+{
+ LoongArchCPU *cpu;
+ int64_t old_v = -1;
+
+ switch (csr) {
+ case LOONGARCH_CSR_ESTAT:
+ /* Only IS[1:0] can be write */
+ env->CSR_ESTAT = FIELD_DP64(env->CSR_ESTAT, CSR_ESTAT, IS, val & 0x3);
+ break;
+ case LOONGARCH_CSR_ASID:
+ old_v = env->CSR_ASID;
+ /* Only ASID filed of CSR_ASID can be write. */
+ env->CSR_ASID = FIELD_DP64(env->CSR_ASID, CSR_ASID, ASID,
+ val & R_CSR_ASID_ASID_MASK);
+ if (old_v != val) {
+ tlb_flush(env_cpu(env));
+ }
+ break;
+ case LOONGARCH_CSR_TCFG:
+ cpu = LOONGARCH_CPU(env_cpu(env));
+ old_v = env->CSR_TCFG;
+ cpu_loongarch_store_constant_timer_config(cpu, val);
+ break;
+ case LOONGARCH_CSR_TICLR:
+ old_v = 0;
+ env->CSR_ESTAT &= ~(1 << IRQ_TIMER);
+ cpu_reset_interrupt(env_cpu(env), CPU_INTERRUPT_HARD);
+ break;
+ default:
+ break;
+ }
+
+ return old_v;
+}
+
+target_ulong helper_csr_xchgq(CPULoongArchState *env, target_ulong new_val,
+ target_ulong mask, uint64_t csr_num)
+{
+ unsigned csr_offset = cpu_csr_offset(csr_num);
+ if (csr_offset == 0) {
+ /* Undefined CSR: read as 0, writes are ignored. */
+ return 0;
+ }
+
+ uint64_t *csr = (void *)env + csr_offset;
+ uint64_t old_val = *csr;
+
+ new_val = (new_val & mask) | (old_val & ~mask);
+
+ if (csr_num == LOONGARCH_CSR_TCFG) {
+ LoongArchCPU *cpu = LOONGARCH_CPU(env_cpu(env));
+ cpu_loongarch_store_constant_timer_config(cpu, new_val);
+ } else {
+ *csr = new_val;
+ }
+ return old_val;
+}
diff --git a/target/loongarch/disas.c b/target/loongarch/disas.c
index d441dd42dc..b83022468e 100644
--- a/target/loongarch/disas.c
+++ b/target/loongarch/disas.c
@@ -205,6 +205,18 @@ static void output_rr_offs(DisasContext *ctx, arg_rr_offs *a,
a->rd, a->offs, ctx->pc + a->offs);
}
+static void output_r_csr(DisasContext *ctx, arg_r_csr *a,
+ const char *mnemonic)
+{
+ output(ctx, mnemonic, "r%d, %d", a->rd, a->csr);
+}
+
+static void output_rr_csr(DisasContext *ctx, arg_rr_csr *a,
+ const char *mnemonic)
+{
+ output(ctx, mnemonic, "r%d, r%d, %d", a->rd, a->rj, a->csr);
+}
+
#define INSN(insn, type) \
static bool trans_##insn(DisasContext *ctx, arg_##type * a) \
{ \
@@ -517,6 +529,9 @@ INSN(blt, rr_offs)
INSN(bge, rr_offs)
INSN(bltu, rr_offs)
INSN(bgeu, rr_offs)
+INSN(csrrd, r_csr)
+INSN(csrwr, r_csr)
+INSN(csrxchg, rr_csr)
#define output_fcmp(C, PREFIX, SUFFIX) \
{ \
diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h
index da1a2bced7..036dbf31f8 100644
--- a/target/loongarch/helper.h
+++ b/target/loongarch/helper.h
@@ -92,3 +92,10 @@ DEF_HELPER_2(frint_s, i64, env, i64)
DEF_HELPER_2(frint_d, i64, env, i64)
DEF_HELPER_FLAGS_2(set_rounding_mode, TCG_CALL_NO_RWG, void, env, i32)
+
+/*Core functions */
+#ifndef CONFIG_USER_ONLY
+DEF_HELPER_2(csr_rdq, i64, env, i64)
+DEF_HELPER_3(csr_wrq, i64, env, tl, i64)
+DEF_HELPER_4(csr_xchgq, i64, env, tl, tl, i64)
+#endif /* !CONFIG_USER_ONLY */
diff --git a/target/loongarch/insn_trans/trans_privileged.c.inc b/target/loongarch/insn_trans/trans_privileged.c.inc
new file mode 100644
index 0000000000..9354697894
--- /dev/null
+++ b/target/loongarch/insn_trans/trans_privileged.c.inc
@@ -0,0 +1,125 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ *
+ * LoongArch translation routines for the privileged instructions.
+ */
+
+#include "cpu-csr.h"
+
+#ifdef CONFIG_USER_ONLY
+
+#define GEN_FALSE_TRANS(name) \
+static bool trans_##name(DisasContext *ctx, arg_##name * a) \
+{ \
+ return false; \
+}
+
+GEN_FALSE_TRANS(csrrd)
+GEN_FALSE_TRANS(csrwr)
+GEN_FALSE_TRANS(csrxchg)
+
+#else
+
+static bool check_plv(DisasContext *ctx)
+{
+ if (ctx->base.tb->flags == MMU_USER_IDX) {
+ generate_exception(ctx, EXCCODE_IPE);
+ return true;
+ }
+ return false;
+}
+
+static bool ro_csr(int csr_num)
+{
+ /*
+ * For now qemu does not support any features of the MISC
+ * bits yet treat as a RO CSR.
+ */
+ if ((csr_num == LOONGARCH_CSR_BADI) ||
+ (csr_num == LOONGARCH_CSR_CPUID) ||
+ (csr_num == LOONGARCH_CSR_PRCFG1) ||
+ (csr_num == LOONGARCH_CSR_PRCFG2) ||
+ (csr_num == LOONGARCH_CSR_PRCFG3) ||
+ (csr_num == LOONGARCH_CSR_PGD) ||
+ (csr_num == LOONGARCH_CSR_TVAL) ||
+ (csr_num == LOONGARCH_CSR_MISC)) {
+ return true;
+ }
+
+ return false;
+}
+
+static bool trans_csrrd(DisasContext *ctx, arg_csrrd *a)
+{
+ TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE);
+
+ if (check_plv(ctx)) {
+ return false;
+ }
+
+ unsigned csr_offset = cpu_csr_offset(a->csr);
+ if (csr_offset == 0) {
+ /* CSR is undefined: read as 0 */
+ dest = tcg_constant_tl(0);
+ return true;
+ }
+
+ if ((a->csr == LOONGARCH_CSR_PGD) || (a->csr == LOONGARCH_CSR_CPUID) ||
+ (a->csr == LOONGARCH_CSR_TVAL)) {
+ gen_helper_csr_rdq(dest, cpu_env, tcg_constant_i64(a->csr));
+ } else {
+ tcg_gen_ld_tl(dest, cpu_env, csr_offset);
+ }
+ return true;
+}
+
+static bool trans_csrwr(DisasContext *ctx, arg_csrwr *a)
+{
+ TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE);
+ TCGv src1 = gpr_src(ctx, a->rd, EXT_NONE);
+
+ if (check_plv(ctx) || ro_csr(a->csr)) {
+ return false;
+ }
+
+ unsigned csr_offset = cpu_csr_offset(a->csr);
+ if (csr_offset == 0) {
+ /* CSR is undefined: write ignored. */
+ return true;
+ }
+
+ if ((a->csr == LOONGARCH_CSR_ASID) || (a->csr == LOONGARCH_CSR_TCFG) ||
+ (a->csr == LOONGARCH_CSR_TICLR) || (a->csr == LOONGARCH_CSR_ESTAT)) {
+ gen_helper_csr_wrq(dest, cpu_env, src1, tcg_constant_i64(a->csr));
+ } else {
+ TCGv temp = tcg_temp_new();
+ tcg_gen_ld_tl(temp, cpu_env, csr_offset);
+ tcg_gen_st_tl(src1, cpu_env, csr_offset);
+ tcg_gen_mov_tl(dest, temp);
+ tcg_temp_free(temp);
+
+ /* Cpu state may be changed, need exit */
+ if ((a->csr == LOONGARCH_CSR_CRMD) || (a->csr == LOONGARCH_CSR_EUEN)) {
+ tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4);
+ ctx->base.is_jmp = DISAS_EXIT;
+ }
+ }
+
+ return true;
+}
+
+static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg *a)
+{
+ TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE);
+ TCGv src1 = gpr_src(ctx, a->rd, EXT_NONE);
+ TCGv src2 = gpr_src(ctx, a->rj, EXT_NONE);
+
+ if (check_plv(ctx) || ro_csr(a->csr)) {
+ return false;
+ }
+ gen_helper_csr_xchgq(dest, cpu_env, src1, src2, tcg_constant_i64(a->csr));
+ return true;
+}
+
+#endif
diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode
index 3379d22979..647fcb9def 100644
--- a/target/loongarch/insns.decode
+++ b/target/loongarch/insns.decode
@@ -45,6 +45,8 @@
&c_offs cj offs
&offs offs
&rr_offs rj rd offs
+&r_csr rd csr
+&rr_csr rd rj csr
#
# Formats
@@ -85,6 +87,8 @@
@c_offs21 .... .. ................ .. cj:3 ..... &c_offs offs=%offs21
@offs26 .... .. .......................... &offs offs=%offs26
@rr_offs16 .... .. ................ rj:5 rd:5 &rr_offs offs=%offs16
+@r_csr .... .... csr:14 ..... rd:5 &r_csr
+@rr_csr .... .... csr:14 rj:5 rd:5 &rr_csr
#
# Fixed point arithmetic operation instruction
@@ -440,3 +444,12 @@ blt 0110 00 ................ ..... ..... @rr_offs16
bge 0110 01 ................ ..... ..... @rr_offs16
bltu 0110 10 ................ ..... ..... @rr_offs16
bgeu 0110 11 ................ ..... ..... @rr_offs16
+
+#
+# Core instructions
+#
+{
+ csrrd 0000 0100 .............. 00000 ..... @r_csr
+ csrwr 0000 0100 .............. 00001 ..... @r_csr
+ csrxchg 0000 0100 .............. ..... ..... @rr_csr
+}
diff --git a/target/loongarch/meson.build b/target/loongarch/meson.build
index 6bf2d88104..5fb7542e88 100644
--- a/target/loongarch/meson.build
+++ b/target/loongarch/meson.build
@@ -19,6 +19,7 @@ loongarch_softmmu_ss.add(files(
'machine.c',
'constant_timer.c',
'tlb_helper.c',
+ 'csr_helper.c',
))
loongarch_ss.add_all(when: 'CONFIG_TCG', if_true: [loongarch_tcg_ss])
diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c
index 79fd95e787..438a3cb515 100644
--- a/target/loongarch/translate.c
+++ b/target/loongarch/translate.c
@@ -26,6 +26,7 @@ TCGv_i32 cpu_fcsr0;
TCGv_i64 cpu_fpr[32];
#define DISAS_STOP DISAS_TARGET_0
+#define DISAS_EXIT DISAS_TARGET_1
static inline int plus_1(DisasContext *ctx, int x)
{
@@ -172,6 +173,7 @@ static void gen_set_gpr(int reg_num, TCGv t, DisasExtend dst_ext)
#include "insn_trans/trans_fmov.c.inc"
#include "insn_trans/trans_fmemory.c.inc"
#include "insn_trans/trans_branch.c.inc"
+#include "insn_trans/trans_privileged.c.inc"
static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
{
@@ -209,6 +211,9 @@ static void loongarch_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
break;
case DISAS_NORETURN:
break;
+ case DISAS_EXIT:
+ tcg_gen_exit_tb(NULL, 0);
+ break;
default:
g_assert_not_reached();
}
--
2.31.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [RFC PATCH v7 08/29] target/loongarch: Add LoongArch IOCSR instruction
2022-03-28 12:57 [RFC PATCH v7 00/29] Add LoongArch softmmu support Xiaojuan Yang
` (6 preceding siblings ...)
2022-03-28 12:57 ` [RFC PATCH v7 07/29] target/loongarch: Add LoongArch CSR instruction Xiaojuan Yang
@ 2022-03-28 12:57 ` Xiaojuan Yang
2022-03-28 18:55 ` Richard Henderson
2022-03-28 12:57 ` [RFC PATCH v7 09/29] target/loongarch: Add TLB instruction support Xiaojuan Yang
` (21 subsequent siblings)
29 siblings, 1 reply; 71+ messages in thread
From: Xiaojuan Yang @ 2022-03-28 12:57 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland, richard.henderson, Song Gao
This includes:
- IOCSR{RD/WR}.{B/H/W/D}
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
target/loongarch/cpu.h | 4 +
target/loongarch/disas.c | 8 +
target/loongarch/helper.h | 2 +
.../insn_trans/trans_privileged.c.inc | 103 +++++++++++++
target/loongarch/insns.decode | 9 ++
target/loongarch/iocsr_helper.c | 139 ++++++++++++++++++
target/loongarch/meson.build | 1 +
7 files changed, 266 insertions(+)
create mode 100644 target/loongarch/iocsr_helper.c
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index f682dd33fe..08af634307 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -151,6 +151,7 @@ extern const char * const fregnames[32];
#define N_IRQS 14
#define IRQ_TIMER 11
+#define IRQ_IPI 12
#define LOONGARCH_STLB 2048 /* 2048 STLB */
#define LOONGARCH_MTLB 64 /* 64 MTLB */
@@ -248,6 +249,9 @@ typedef struct CPUArchState {
#ifndef CONFIG_USER_ONLY
LoongArchTLB tlb[LOONGARCH_TLB_MAX];
+
+ AddressSpace address_space_iocsr;
+ MemoryRegion system_iocsr;
#endif
} CPULoongArchState;
diff --git a/target/loongarch/disas.c b/target/loongarch/disas.c
index b83022468e..90f469bdc0 100644
--- a/target/loongarch/disas.c
+++ b/target/loongarch/disas.c
@@ -532,6 +532,14 @@ INSN(bgeu, rr_offs)
INSN(csrrd, r_csr)
INSN(csrwr, r_csr)
INSN(csrxchg, rr_csr)
+INSN(iocsrrd_b, rr)
+INSN(iocsrrd_h, rr)
+INSN(iocsrrd_w, rr)
+INSN(iocsrrd_d, rr)
+INSN(iocsrwr_b, rr)
+INSN(iocsrwr_h, rr)
+INSN(iocsrwr_w, rr)
+INSN(iocsrwr_d, rr)
#define output_fcmp(C, PREFIX, SUFFIX) \
{ \
diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h
index 036dbf31f8..1bcd082858 100644
--- a/target/loongarch/helper.h
+++ b/target/loongarch/helper.h
@@ -98,4 +98,6 @@ DEF_HELPER_FLAGS_2(set_rounding_mode, TCG_CALL_NO_RWG, void, env, i32)
DEF_HELPER_2(csr_rdq, i64, env, i64)
DEF_HELPER_3(csr_wrq, i64, env, tl, i64)
DEF_HELPER_4(csr_xchgq, i64, env, tl, tl, i64)
+DEF_HELPER_3(iocsr_read, i64, env, tl, i32)
+DEF_HELPER_4(iocsr_write, void, env, tl, tl, i32)
#endif /* !CONFIG_USER_ONLY */
diff --git a/target/loongarch/insn_trans/trans_privileged.c.inc b/target/loongarch/insn_trans/trans_privileged.c.inc
index 9354697894..30f1e688e8 100644
--- a/target/loongarch/insn_trans/trans_privileged.c.inc
+++ b/target/loongarch/insn_trans/trans_privileged.c.inc
@@ -18,6 +18,14 @@ static bool trans_##name(DisasContext *ctx, arg_##name * a) \
GEN_FALSE_TRANS(csrrd)
GEN_FALSE_TRANS(csrwr)
GEN_FALSE_TRANS(csrxchg)
+GEN_FALSE_TRANS(iocsrrd_b)
+GEN_FALSE_TRANS(iocsrrd_h)
+GEN_FALSE_TRANS(iocsrrd_w)
+GEN_FALSE_TRANS(iocsrrd_d)
+GEN_FALSE_TRANS(iocsrwr_b)
+GEN_FALSE_TRANS(iocsrwr_h)
+GEN_FALSE_TRANS(iocsrwr_w)
+GEN_FALSE_TRANS(iocsrwr_d)
#else
@@ -122,4 +130,99 @@ static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg *a)
return true;
}
+static bool trans_iocsrrd_b(DisasContext *ctx, arg_iocsrrd_b *a)
+{
+ TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE);
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+
+ if (check_plv(ctx)) {
+ return false;
+ }
+ gen_helper_iocsr_read(dest, cpu_env, src1, tcg_constant_i32(1));
+ return true;
+}
+
+static bool trans_iocsrrd_h(DisasContext *ctx, arg_iocsrrd_h *a)
+{
+ TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE);
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+
+ if (check_plv(ctx)) {
+ return false;
+ }
+ gen_helper_iocsr_read(dest, cpu_env, src1, tcg_constant_i32(2));
+ return true;
+}
+
+static bool trans_iocsrrd_w(DisasContext *ctx, arg_iocsrrd_w *a)
+{
+ TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE);
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+
+ if (check_plv(ctx)) {
+ return false;
+ }
+ gen_helper_iocsr_read(dest, cpu_env, src1, tcg_constant_i32(4));
+ return true;
+}
+
+static bool trans_iocsrrd_d(DisasContext *ctx, arg_iocsrrd_d *a)
+{
+ TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE);
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+
+ if (check_plv(ctx)) {
+ return false;
+ }
+ gen_helper_iocsr_read(dest, cpu_env, src1, tcg_constant_i32(8));
+ return true;
+}
+
+static bool trans_iocsrwr_b(DisasContext *ctx, arg_iocsrwr_b *a)
+{
+ TCGv val = gpr_src(ctx, a->rd, EXT_NONE);
+ TCGv addr = gpr_src(ctx, a->rj, EXT_NONE);
+
+ if (check_plv(ctx)) {
+ return false;
+ }
+ gen_helper_iocsr_write(cpu_env, addr, val, tcg_constant_i32(1));
+ return true;
+}
+
+static bool trans_iocsrwr_h(DisasContext *ctx, arg_iocsrwr_h *a)
+{
+ TCGv val = gpr_src(ctx, a->rd, EXT_NONE);
+ TCGv addr = gpr_src(ctx, a->rj, EXT_NONE);
+
+ if (check_plv(ctx)) {
+ return false;
+ }
+ gen_helper_iocsr_write(cpu_env, addr, val, tcg_constant_i32(2));
+ return true;
+}
+
+static bool trans_iocsrwr_w(DisasContext *ctx, arg_iocsrwr_w *a)
+{
+ TCGv val = gpr_src(ctx, a->rd, EXT_NONE);
+ TCGv addr = gpr_src(ctx, a->rj, EXT_NONE);
+
+ if (check_plv(ctx)) {
+ return false;
+ }
+ gen_helper_iocsr_write(cpu_env, addr, val, tcg_constant_i32(4));
+ return true;
+}
+
+static bool trans_iocsrwr_d(DisasContext *ctx, arg_iocsrwr_d *a)
+{
+ TCGv val = gpr_src(ctx, a->rd, EXT_NONE);
+ TCGv addr = gpr_src(ctx, a->rj, EXT_NONE);
+
+ if (check_plv(ctx)) {
+ return false;
+ }
+ gen_helper_iocsr_write(cpu_env, addr, val, tcg_constant_i32(8));
+ return true;
+}
#endif
diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode
index 647fcb9def..9a43f288c3 100644
--- a/target/loongarch/insns.decode
+++ b/target/loongarch/insns.decode
@@ -453,3 +453,12 @@ bgeu 0110 11 ................ ..... ..... @rr_offs16
csrwr 0000 0100 .............. 00001 ..... @r_csr
csrxchg 0000 0100 .............. ..... ..... @rr_csr
}
+
+iocsrrd_b 0000 01100100 10000 00000 ..... ..... @rr
+iocsrrd_h 0000 01100100 10000 00001 ..... ..... @rr
+iocsrrd_w 0000 01100100 10000 00010 ..... ..... @rr
+iocsrrd_d 0000 01100100 10000 00011 ..... ..... @rr
+iocsrwr_b 0000 01100100 10000 00100 ..... ..... @rr
+iocsrwr_h 0000 01100100 10000 00101 ..... ..... @rr
+iocsrwr_w 0000 01100100 10000 00110 ..... ..... @rr
+iocsrwr_d 0000 01100100 10000 00111 ..... ..... @rr
diff --git a/target/loongarch/iocsr_helper.c b/target/loongarch/iocsr_helper.c
new file mode 100644
index 0000000000..72ac3806b6
--- /dev/null
+++ b/target/loongarch/iocsr_helper.c
@@ -0,0 +1,139 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ *
+ * Helpers for IOCSR reads/writes
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/main-loop.h"
+#include "cpu.h"
+#include "internals.h"
+#include "qemu/host-utils.h"
+#include "exec/helper-proto.h"
+#include "exec/exec-all.h"
+#include "exec/cpu_ldst.h"
+#include "hw/irq.h"
+#include "cpu-csr.h"
+#include "hw/loongarch/loongarch.h"
+#include "tcg/tcg-ldst.h"
+
+uint64_t helper_iocsr_read(CPULoongArchState *env, target_ulong r_addr,
+ uint32_t size)
+{
+ int cpuid = env_cpu(env)->cpu_index;
+ CPUState *cs = qemu_get_cpu(cpuid);
+ env = cs->env_ptr;
+ uint64_t ret;
+
+ /*
+ * Adjust the per core address such as 0x10xx(IPI)/0x18xx(EXTIOI)
+ */
+ if (((r_addr & 0xff00) == 0x1000) || ((r_addr & 0xff00) == 0x1800)) {
+ r_addr = r_addr + ((target_ulong)(cpuid & 0x3) << 8);
+ }
+
+ switch (size) {
+ case 1:
+ ret = address_space_ldub(&env->address_space_iocsr, r_addr,
+ MEMTXATTRS_UNSPECIFIED, NULL);
+ break;
+ case 2:
+ ret = address_space_lduw(&env->address_space_iocsr, r_addr,
+ MEMTXATTRS_UNSPECIFIED, NULL);
+ break;
+ case 4:
+ ret = address_space_ldl(&env->address_space_iocsr, r_addr,
+ MEMTXATTRS_UNSPECIFIED, NULL);
+ break;
+ case 8:
+ ret = address_space_ldq(&env->address_space_iocsr, r_addr,
+ MEMTXATTRS_UNSPECIFIED, NULL);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+void helper_iocsr_write(CPULoongArchState *env, target_ulong w_addr,
+ target_ulong val, uint32_t size)
+{
+ int cpuid = env_cpu(env)->cpu_index;
+ CPUState *cs = qemu_get_cpu(cpuid);
+ int mask, i;
+ env = cs->env_ptr;
+
+ /*
+ * For IPI send, Mailbox send and ANY send, adjust the addr and
+ * val accordingly. The IOCSR writes are turned to different
+ * MMIO writes respectively
+ */
+ switch (w_addr) {
+ case 0x1040: /* IPI send */
+ cpuid = (val >> 16) & 0x3ff;
+ val = 1UL << (val & 0x1f);
+ if (val) {
+ qemu_mutex_lock_iothread();
+ cs = qemu_get_cpu(cpuid);
+ env = cs->env_ptr;
+ env->CSR_ESTAT |= 1 << IRQ_IPI;
+ cpu_interrupt(cs, CPU_INTERRUPT_HARD);
+ qemu_mutex_unlock_iothread();
+ }
+ break;
+ case 0x1048: /* Mail Send */
+ cpuid = (val >> 16) & 0x3ff;
+ w_addr = 0x1020 + (val & 0x1c);
+ val = val >> 32;
+ mask = (val >> 27) & 0xf;
+ size = 4;
+ env = (qemu_get_cpu(cpuid))->env_ptr;
+ break;
+ case 0x1158: /* ANY send */
+ cpuid = (val >> 16) & 0x3ff;
+ w_addr = val & 0xffff;
+ val = val >> 32;
+ mask = (val >> 27) & 0xf;
+ size = 1;
+ env = (qemu_get_cpu(cpuid))->env_ptr;
+
+ for (i = 0; i < 4; i++) {
+ if (!((mask >> i) & 1)) {
+ address_space_stb(&env->address_space_iocsr, w_addr,
+ val, MEMTXATTRS_UNSPECIFIED, NULL);
+ }
+ w_addr = w_addr + 1;
+ val = val >> 8;
+ }
+ return;
+ default:
+ break;
+ }
+
+ if (((w_addr & 0xff00) == 0x1000) || ((w_addr & 0xff00) == 0x1800)) {
+ w_addr = w_addr + ((target_ulong)(cpuid & 0x3) << 8);
+ }
+
+ switch (size) {
+ case 1:
+ address_space_stb(&env->address_space_iocsr, w_addr,
+ val, MEMTXATTRS_UNSPECIFIED, NULL);
+ break;
+ case 2:
+ address_space_stw(&env->address_space_iocsr, w_addr,
+ val, MEMTXATTRS_UNSPECIFIED, NULL);
+ break;
+ case 4:
+ address_space_stl(&env->address_space_iocsr, w_addr,
+ val, MEMTXATTRS_UNSPECIFIED, NULL);
+ break;
+ case 8:
+ address_space_stq(&env->address_space_iocsr, w_addr,
+ val, MEMTXATTRS_UNSPECIFIED, NULL);
+ break;
+ default:
+ break;
+ }
+}
diff --git a/target/loongarch/meson.build b/target/loongarch/meson.build
index 5fb7542e88..072684ca6d 100644
--- a/target/loongarch/meson.build
+++ b/target/loongarch/meson.build
@@ -20,6 +20,7 @@ loongarch_softmmu_ss.add(files(
'constant_timer.c',
'tlb_helper.c',
'csr_helper.c',
+ 'iocsr_helper.c',
))
loongarch_ss.add_all(when: 'CONFIG_TCG', if_true: [loongarch_tcg_ss])
--
2.31.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [RFC PATCH v7 09/29] target/loongarch: Add TLB instruction support
2022-03-28 12:57 [RFC PATCH v7 00/29] Add LoongArch softmmu support Xiaojuan Yang
` (7 preceding siblings ...)
2022-03-28 12:57 ` [RFC PATCH v7 08/29] target/loongarch: Add LoongArch IOCSR instruction Xiaojuan Yang
@ 2022-03-28 12:57 ` Xiaojuan Yang
2022-03-28 20:12 ` Richard Henderson
2022-03-28 22:50 ` Richard Henderson
2022-03-28 12:57 ` [RFC PATCH v7 10/29] target/loongarch: Add other core instructions support Xiaojuan Yang
` (20 subsequent siblings)
29 siblings, 2 replies; 71+ messages in thread
From: Xiaojuan Yang @ 2022-03-28 12:57 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland, richard.henderson, Song Gao
This includes:
- TLBSRCH
- TLBRD
- TLBWR
- TLBFILL
- TLBCLR
- TLBFLUSH
- INVTLB
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
target/loongarch/disas.c | 17 +
target/loongarch/helper.h | 12 +
.../insn_trans/trans_privileged.c.inc | 112 ++++++
target/loongarch/insns.decode | 11 +
target/loongarch/tlb_helper.c | 358 ++++++++++++++++++
5 files changed, 510 insertions(+)
diff --git a/target/loongarch/disas.c b/target/loongarch/disas.c
index 90f469bdc0..9b13554904 100644
--- a/target/loongarch/disas.c
+++ b/target/loongarch/disas.c
@@ -217,6 +217,16 @@ static void output_rr_csr(DisasContext *ctx, arg_rr_csr *a,
output(ctx, mnemonic, "r%d, r%d, %d", a->rd, a->rj, a->csr);
}
+static void output_empty(DisasContext *ctx, arg_empty *a,
+ const char *mnemonic)
+{
+}
+
+static void output_i_rr(DisasContext *ctx, arg_i_rr *a, const char *mnemonic)
+{
+ output(ctx, mnemonic, "%d, r%d, r%d", a->imm, a->rj, a->rk);
+}
+
#define INSN(insn, type) \
static bool trans_##insn(DisasContext *ctx, arg_##type * a) \
{ \
@@ -540,6 +550,13 @@ INSN(iocsrwr_b, rr)
INSN(iocsrwr_h, rr)
INSN(iocsrwr_w, rr)
INSN(iocsrwr_d, rr)
+INSN(tlbsrch, empty)
+INSN(tlbrd, empty)
+INSN(tlbwr, empty)
+INSN(tlbfill, empty)
+INSN(tlbclr, empty)
+INSN(tlbflush, empty)
+INSN(invtlb, i_rr)
#define output_fcmp(C, PREFIX, SUFFIX) \
{ \
diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h
index 1bcd082858..97af7ac8aa 100644
--- a/target/loongarch/helper.h
+++ b/target/loongarch/helper.h
@@ -100,4 +100,16 @@ DEF_HELPER_3(csr_wrq, i64, env, tl, i64)
DEF_HELPER_4(csr_xchgq, i64, env, tl, tl, i64)
DEF_HELPER_3(iocsr_read, i64, env, tl, i32)
DEF_HELPER_4(iocsr_write, void, env, tl, tl, i32)
+
+DEF_HELPER_1(tlbwr, void, env)
+DEF_HELPER_1(tlbfill, void, env)
+DEF_HELPER_1(tlbsrch, void, env)
+DEF_HELPER_1(tlbrd, void, env)
+DEF_HELPER_1(tlbclr, void, env)
+DEF_HELPER_1(tlbflush, void, env)
+DEF_HELPER_1(invtlb_all, void, env)
+DEF_HELPER_2(invtlb_all_g, void, env, i32)
+DEF_HELPER_2(invtlb_all_asid, void, env, tl)
+DEF_HELPER_3(invtlb_page_asid, void, env, tl, tl)
+DEF_HELPER_3(invtlb_page_asid_or_g, void, env, tl, tl)
#endif /* !CONFIG_USER_ONLY */
diff --git a/target/loongarch/insn_trans/trans_privileged.c.inc b/target/loongarch/insn_trans/trans_privileged.c.inc
index 30f1e688e8..8bc6dd6e51 100644
--- a/target/loongarch/insn_trans/trans_privileged.c.inc
+++ b/target/loongarch/insn_trans/trans_privileged.c.inc
@@ -26,6 +26,13 @@ GEN_FALSE_TRANS(iocsrwr_b)
GEN_FALSE_TRANS(iocsrwr_h)
GEN_FALSE_TRANS(iocsrwr_w)
GEN_FALSE_TRANS(iocsrwr_d)
+GEN_FALSE_TRANS(tlbsrch)
+GEN_FALSE_TRANS(tlbrd)
+GEN_FALSE_TRANS(tlbwr)
+GEN_FALSE_TRANS(tlbfill)
+GEN_FALSE_TRANS(tlbclr)
+GEN_FALSE_TRANS(tlbflush)
+GEN_FALSE_TRANS(invtlb)
#else
@@ -225,4 +232,109 @@ static bool trans_iocsrwr_d(DisasContext *ctx, arg_iocsrwr_d *a)
gen_helper_iocsr_write(cpu_env, addr, val, tcg_constant_i32(8));
return true;
}
+
+static bool trans_tlbsrch(DisasContext *ctx, arg_tlbsrch *a)
+{
+ if (check_plv(ctx)) {
+ return false;
+ }
+ gen_helper_tlbsrch(cpu_env);
+ return true;
+}
+
+static bool trans_tlbrd(DisasContext *ctx, arg_tlbrd *a)
+{
+ if (check_plv(ctx)) {
+ return false;
+ }
+ gen_helper_tlbrd(cpu_env);
+ return true;
+}
+
+static bool trans_tlbwr(DisasContext *ctx, arg_tlbwr *a)
+{
+ if (check_plv(ctx)) {
+ return false;
+ }
+ gen_helper_tlbwr(cpu_env);
+
+ if (ctx->mem_idx != MMU_DA_IDX) {
+ tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4);
+ ctx->base.is_jmp = DISAS_EXIT;
+ }
+ return true;
+}
+
+static bool trans_tlbfill(DisasContext *ctx, arg_tlbfill *a)
+{
+ if (check_plv(ctx)) {
+ return false;
+ }
+ gen_helper_tlbfill(cpu_env);
+
+ if (ctx->mem_idx != MMU_DA_IDX) {
+ tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4);
+ ctx->base.is_jmp = DISAS_EXIT;
+ }
+ return true;
+}
+
+static bool trans_tlbclr(DisasContext *ctx, arg_tlbclr *a)
+{
+ if (check_plv(ctx)) {
+ return false;
+ }
+ gen_helper_tlbclr(cpu_env);
+ tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4);
+ ctx->base.is_jmp = DISAS_EXIT;
+ return true;
+}
+
+static bool trans_tlbflush(DisasContext *ctx, arg_tlbflush *a)
+{
+ if (check_plv(ctx)) {
+ return false;
+ }
+ gen_helper_tlbflush(cpu_env);
+ tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4);
+ ctx->base.is_jmp = DISAS_EXIT;
+ return true;
+}
+
+static bool trans_invtlb(DisasContext *ctx, arg_invtlb *a)
+{
+ TCGv rj = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv rk = gpr_src(ctx, a->rk, EXT_NONE);
+
+ if (check_plv(ctx)) {
+ return false;
+ }
+
+ switch (a->imm) {
+ case 0:
+ case 1:
+ gen_helper_invtlb_all(cpu_env);
+ break;
+ case 2:
+ gen_helper_invtlb_all_g(cpu_env, tcg_constant_i32(1));
+ break;
+ case 3:
+ gen_helper_invtlb_all_g(cpu_env, tcg_constant_i32(0));
+ break;
+ case 4:
+ gen_helper_invtlb_all_asid(cpu_env, rj);
+ break;
+ case 5:
+ gen_helper_invtlb_page_asid(cpu_env, rj, rk);
+ break;
+ case 6:
+ gen_helper_invtlb_page_asid_or_g(cpu_env, rj, rk);
+ break;
+ default:
+ return false;
+ }
+ ctx->base.is_jmp = DISAS_STOP;
+ return true;
+}
+
#endif
diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode
index 9a43f288c3..6f2a814195 100644
--- a/target/loongarch/insns.decode
+++ b/target/loongarch/insns.decode
@@ -47,6 +47,8 @@
&rr_offs rj rd offs
&r_csr rd csr
&rr_csr rd rj csr
+&empty
+&i_rr imm rj rk
#
# Formats
@@ -89,6 +91,8 @@
@rr_offs16 .... .. ................ rj:5 rd:5 &rr_offs offs=%offs16
@r_csr .... .... csr:14 ..... rd:5 &r_csr
@rr_csr .... .... csr:14 rj:5 rd:5 &rr_csr
+@empty .... ........ ..... ..... ..... ..... &empty
+@i_rr ...... ...... ..... rk:5 rj:5 imm:5 &i_rr
#
# Fixed point arithmetic operation instruction
@@ -462,3 +466,10 @@ iocsrwr_b 0000 01100100 10000 00100 ..... ..... @rr
iocsrwr_h 0000 01100100 10000 00101 ..... ..... @rr
iocsrwr_w 0000 01100100 10000 00110 ..... ..... @rr
iocsrwr_d 0000 01100100 10000 00111 ..... ..... @rr
+tlbsrch 0000 01100100 10000 01010 00000 00000 @empty
+tlbrd 0000 01100100 10000 01011 00000 00000 @empty
+tlbwr 0000 01100100 10000 01100 00000 00000 @empty
+tlbfill 0000 01100100 10000 01101 00000 00000 @empty
+tlbclr 0000 01100100 10000 01000 00000 00000 @empty
+tlbflush 0000 01100100 10000 01001 00000 00000 @empty
+invtlb 0000 01100100 10011 ..... ..... ..... @i_rr
diff --git a/target/loongarch/tlb_helper.c b/target/loongarch/tlb_helper.c
index 992d87493a..899b4d700c 100644
--- a/target/loongarch/tlb_helper.c
+++ b/target/loongarch/tlb_helper.c
@@ -7,9 +7,11 @@
*/
#include "qemu/osdep.h"
+#include "qemu/guest-random.h"
#include "cpu.h"
#include "internals.h"
+#include "exec/helper-proto.h"
#include "exec/exec-all.h"
#include "exec/cpu_ldst.h"
#include "exec/log.h"
@@ -280,6 +282,362 @@ static void raise_mmu_exception(CPULoongArchState *env, target_ulong address,
}
}
+static void loongarch_invalidate_tlb_entry(CPULoongArchState *env,
+ int index)
+{
+ target_ulong addr, mask, pagesize;
+ uint8_t tlb_ps;
+ LoongArchTLB *tlb = &env->tlb[index];
+
+ int mmu_idx = cpu_mmu_index(env, false);
+ uint8_t tlb_v0 = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, V);
+ uint8_t tlb_v1 = FIELD_EX64(tlb->tlb_entry1, TLBENTRY, V);
+ uint64_t tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN);
+
+ if (index >= LOONGARCH_STLB) {
+ tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS);
+ } else {
+ tlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS);
+ }
+ pagesize = 1 << tlb_ps;
+ mask = MAKE_64BIT_MASK(0, tlb_ps + 1);
+
+ if (tlb_v0) {
+ addr = (tlb_vppn << R_TLB_MISC_VPPN_SHIFT) & ~mask; /* even */
+ tlb_flush_range_by_mmuidx(env_cpu(env), addr, pagesize,
+ mmu_idx, TARGET_LONG_BITS);
+ }
+
+ if (tlb_v1) {
+ addr = (tlb_vppn << R_TLB_MISC_VPPN_SHIFT) & pagesize; /* odd */
+ tlb_flush_range_by_mmuidx(env_cpu(env), addr, pagesize,
+ mmu_idx, TARGET_LONG_BITS);
+ }
+}
+
+static void loongarch_invalidate_tlb(CPULoongArchState *env, int index)
+{
+ LoongArchTLB *tlb;
+ uint16_t csr_asid, tlb_asid, tlb_g;
+
+ csr_asid = FIELD_EX64(env->CSR_ASID, CSR_ASID, ASID);
+ tlb = &env->tlb[index];
+ tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID);
+ tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G);
+ if (tlb_g == 0 && tlb_asid != csr_asid) {
+ return;
+ }
+ loongarch_invalidate_tlb_entry(env, index);
+}
+
+static void loongarch_fill_tlb_entry(CPULoongArchState *env, int index)
+{
+ LoongArchTLB *tlb = &env->tlb[index];
+ uint64_t lo0, lo1, csr_vppn;
+ uint16_t csr_asid;
+ uint8_t csr_ps;
+
+ if (FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR)) {
+ csr_ps = FIELD_EX64(env->CSR_TLBREHI, CSR_TLBREHI, PS);
+ csr_vppn = FIELD_EX64(env->CSR_TLBREHI, CSR_TLBREHI, VPPN);
+ lo0 = env->CSR_TLBRELO0;
+ lo1 = env->CSR_TLBRELO1;
+ } else {
+ csr_ps = FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, PS);
+ csr_vppn = FIELD_EX64(env->CSR_TLBEHI, CSR_TLBEHI, VPPN);
+ lo0 = env->CSR_TLBELO0;
+ lo1 = env->CSR_TLBELO1;
+ }
+
+ if (csr_ps == 0) {
+ qemu_log_mask(CPU_LOG_MMU, "page size is 0\n");
+ }
+
+ /* Only MTLB has the ps fields */
+ if (index >= LOONGARCH_STLB) {
+ tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, PS, csr_ps);
+ }
+
+ tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, VPPN, csr_vppn);
+ tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 1);
+ csr_asid = FIELD_EX64(env->CSR_ASID, CSR_ASID, ASID);
+ tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, ASID, csr_asid);
+
+ tlb->tlb_entry0 = lo0;
+ tlb->tlb_entry1 = lo1;
+}
+
+/* Return an random value between low and high */
+static uint32_t cpu_loongarch_get_random_loongarch_tlb(uint32_t low,
+ uint32_t high)
+{
+ uint32_t val;
+
+ qemu_guest_getrandom_nofail(&val, sizeof(val));
+ return val % (high - low + 1) + low;
+}
+
+void helper_tlbsrch(CPULoongArchState *env)
+{
+ int index, match;
+
+ if (FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR)) {
+ match = loongarch_tlb_search(env, env->CSR_TLBREHI, &index);
+ } else {
+ match = loongarch_tlb_search(env, env->CSR_TLBEHI, &index);
+ }
+
+ if (match) {
+ env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, INDEX, index);
+ env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, NE, 0);
+ return;
+ }
+
+ env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, NE, 1);
+}
+
+void helper_tlbrd(CPULoongArchState *env)
+{
+ LoongArchTLB *tlb;
+ int index;
+ uint8_t tlb_ps, tlb_e;
+
+ index = FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, INDEX);
+ tlb = &env->tlb[index];
+
+ if (index >= LOONGARCH_STLB) {
+ tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS);
+ } else {
+ tlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS);
+ }
+ tlb_e = FIELD_EX64(tlb->tlb_misc, TLB_MISC, E);
+
+ if (!tlb_e) {
+ /* Invalid TLB entry */
+ env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, NE, 1);
+ env->CSR_ASID = FIELD_DP64(env->CSR_ASID, CSR_ASID, ASID, 0);
+ env->CSR_TLBEHI = 0;
+ env->CSR_TLBELO0 = 0;
+ env->CSR_TLBELO1 = 0;
+ env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, PS, 0);
+ } else {
+ /* Valid TLB entry */
+ env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX, NE, 0);
+ env->CSR_TLBIDX = FIELD_DP64(env->CSR_TLBIDX, CSR_TLBIDX,
+ PS, (tlb_ps & 0x3f));
+ env->CSR_TLBEHI = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN) <<
+ R_TLB_MISC_VPPN_SHIFT;
+ env->CSR_TLBELO0 = tlb->tlb_entry0;
+ env->CSR_TLBELO1 = tlb->tlb_entry1;
+ }
+}
+
+void helper_tlbwr(CPULoongArchState *env)
+{
+ int index = FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, INDEX);
+
+ loongarch_invalidate_tlb(env, index);
+
+ if (FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, NE)) {
+ env->tlb[index].tlb_misc = FIELD_DP64(env->tlb[index].tlb_misc,
+ TLB_MISC, E, 0);
+ return;
+ }
+
+ loongarch_fill_tlb_entry(env, index);
+}
+
+void helper_tlbfill(CPULoongArchState *env)
+{
+ uint64_t address, entryhi;
+ int index, set, stlb_idx;
+ uint16_t pagesize, stlb_ps;
+
+ if (FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR)) {
+ entryhi = env->CSR_TLBREHI;
+ pagesize = FIELD_EX64(env->CSR_TLBREHI, CSR_TLBREHI, PS);
+ } else {
+ entryhi = env->CSR_TLBEHI;
+ pagesize = FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, PS);
+ }
+
+ stlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS);
+
+ if (pagesize == stlb_ps) {
+ /* Only write into STLB bits [47:13] */
+ address = entryhi & ~MAKE_64BIT_MASK(0, R_CSR_TLBEHI_VPPN_SHIFT);
+
+ /* Choose one set ramdomly */
+ set = cpu_loongarch_get_random_loongarch_tlb(0, 7);
+
+ /* Index in one set */
+ stlb_idx = (address >> (stlb_ps + 1)) & 0xff; /* [0,255] */
+
+ index = set * 256 + stlb_idx;
+ } else {
+ /* Only write into MTLB */
+ index = cpu_loongarch_get_random_loongarch_tlb(
+ LOONGARCH_STLB, LOONGARCH_TLB_MAX - 1);
+ }
+
+ loongarch_invalidate_tlb(env, index);
+ loongarch_fill_tlb_entry(env, index);
+}
+
+void helper_tlbclr(CPULoongArchState *env)
+{
+ LoongArchTLB *tlb;
+ int i, index;
+ uint16_t csr_asid, tlb_asid, tlb_g;
+
+ csr_asid = FIELD_EX64(env->CSR_ASID, CSR_ASID, ASID);
+ index = FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, INDEX);
+
+ if (index < LOONGARCH_STLB) {
+ /* STLB. One line per operation */
+ for (i = 0; i < 8; i++) {
+ tlb = &env->tlb[i * 256 + (index % 256)];
+ tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID);
+ tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G);
+ if (!tlb_g && tlb_asid == csr_asid) {
+ tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0);
+ }
+ }
+ } else if (index < LOONGARCH_TLB_MAX) {
+ /* All MTLB entries */
+ for (i = LOONGARCH_STLB; i < LOONGARCH_TLB_MAX; i++) {
+ tlb = &env->tlb[i];
+ tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID);
+ tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G);
+ if (!tlb_g && tlb_asid == csr_asid) {
+ tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0);
+ }
+ }
+ }
+
+ tlb_flush(env_cpu(env));
+}
+
+void helper_tlbflush(CPULoongArchState *env)
+{
+ int i, index;
+
+ index = FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, INDEX);
+
+ if (index < LOONGARCH_STLB) {
+ /* STLB. One line per operation */
+ for (i = 0; i < 8; i++) {
+ int index = i * 256 + (index % 256);
+ env->tlb[index].tlb_misc = FIELD_DP64(env->tlb[index].tlb_misc,
+ TLB_MISC, E, 0);
+ }
+ } else if (index < LOONGARCH_TLB_MAX) {
+ /* All MTLB entries */
+ for (i = LOONGARCH_STLB; i < LOONGARCH_TLB_MAX; i++) {
+ env->tlb[i].tlb_misc = FIELD_DP64(env->tlb[i].tlb_misc,
+ TLB_MISC, E, 0);
+ }
+ }
+
+ tlb_flush(env_cpu(env));
+}
+
+void helper_invtlb_all(CPULoongArchState *env)
+{
+ for (int i = 0; i < LOONGARCH_TLB_MAX; i++) {
+ env->tlb[i].tlb_misc = FIELD_DP64(env->tlb[i].tlb_misc,
+ TLB_MISC, E, 0);
+ }
+ tlb_flush(env_cpu(env));
+}
+
+void helper_invtlb_all_g(CPULoongArchState *env, uint32_t g)
+{
+ for (int i = 0; i < LOONGARCH_TLB_MAX; i++) {
+ LoongArchTLB *tlb = &env->tlb[i];
+ uint8_t tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G);
+
+ if (tlb_g == g) {
+ tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0);
+ }
+ }
+ tlb_flush(env_cpu(env));
+}
+
+void helper_invtlb_all_asid(CPULoongArchState *env, target_ulong info)
+{
+ uint16_t asid = info & R_CSR_ASID_ASID_MASK;
+
+ for (int i = 0; i < LOONGARCH_TLB_MAX; i++) {
+ LoongArchTLB *tlb = &env->tlb[i];
+ uint8_t tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G);
+ uint16_t tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID);
+
+ if (!tlb_g && (tlb_asid == asid)) {
+ tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0);
+ }
+ }
+ tlb_flush(env_cpu(env));
+}
+
+void helper_invtlb_page_asid(CPULoongArchState *env, target_ulong info,
+ target_ulong addr)
+{
+ uint16_t asid = info & 0x3ff;
+
+ for (int i = 0; i < LOONGARCH_TLB_MAX; i++) {
+ LoongArchTLB *tlb = &env->tlb[i];
+ uint8_t tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G);
+ uint16_t tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID);
+ uint64_t vpn, tlb_vppn;
+ uint8_t tlb_ps, compare_shift;
+
+ if (i >= LOONGARCH_STLB) {
+ tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS);
+ } else {
+ tlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS);
+ }
+ tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN);
+ vpn = (addr & TARGET_VIRT_MASK) >> (tlb_ps + 1);
+ compare_shift = tlb_ps + 1 - R_TLB_MISC_VPPN_SHIFT;
+
+ if (!tlb_g && (tlb_asid == asid) &&
+ (vpn == (tlb_vppn >> compare_shift))) {
+ tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0);
+ }
+ }
+ tlb_flush(env_cpu(env));
+}
+
+void helper_invtlb_page_asid_or_g(CPULoongArchState *env,
+ target_ulong info, target_ulong addr)
+{
+ uint16_t asid = info & 0x3ff;
+
+ for (int i = 0; i < LOONGARCH_TLB_MAX; i++) {
+ LoongArchTLB *tlb = &env->tlb[i];
+ uint8_t tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G);
+ uint16_t tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID);
+ uint64_t vpn, tlb_vppn;
+ uint8_t tlb_ps, compare_shift;
+
+ if (i >= LOONGARCH_STLB) {
+ tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS);
+ } else {
+ tlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS);
+ }
+ tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN);
+ vpn = (addr & TARGET_VIRT_MASK) >> (tlb_ps + 1);
+ compare_shift = tlb_ps + 1 - R_TLB_MISC_VPPN_SHIFT;
+
+ if ((tlb_g || (tlb_asid == asid)) &&
+ (vpn == (tlb_vppn >> compare_shift))) {
+ tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 0);
+ }
+ }
+ tlb_flush(env_cpu(env));
+}
+
bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
MMUAccessType access_type, int mmu_idx,
bool probe, uintptr_t retaddr)
--
2.31.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [RFC PATCH v7 10/29] target/loongarch: Add other core instructions support
2022-03-28 12:57 [RFC PATCH v7 00/29] Add LoongArch softmmu support Xiaojuan Yang
` (8 preceding siblings ...)
2022-03-28 12:57 ` [RFC PATCH v7 09/29] target/loongarch: Add TLB instruction support Xiaojuan Yang
@ 2022-03-28 12:57 ` Xiaojuan Yang
2022-03-28 20:16 ` Richard Henderson
2022-03-28 12:57 ` [RFC PATCH v7 11/29] target/loongarch: Add LoongArch interrupt and exception handle Xiaojuan Yang
` (19 subsequent siblings)
29 siblings, 1 reply; 71+ messages in thread
From: Xiaojuan Yang @ 2022-03-28 12:57 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland, richard.henderson, Song Gao
This includes:
-CACOP
-LDDIR
-LDPTE
-ERTN
-DBCL
-IDLE
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
target/loongarch/cpu.h | 2 +
target/loongarch/disas.c | 17 ++++
target/loongarch/helper.h | 4 +
.../insn_trans/trans_privileged.c.inc | 70 ++++++++++++++
target/loongarch/insns.decode | 11 +++
target/loongarch/internals.h | 5 +
target/loongarch/op_helper.c | 38 ++++++++
target/loongarch/tlb_helper.c | 93 +++++++++++++++++++
8 files changed, 240 insertions(+)
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index 08af634307..1bbe0caeac 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -430,6 +430,8 @@ enum {
EXCP_LAST = EXCP_FPE,
};
+#define CPU_INTERRUPT_WAKE CPU_INTERRUPT_TGT_INT_0
+
#define LOONGARCH_CPU_TYPE_SUFFIX "-" TYPE_LOONGARCH_CPU
#define LOONGARCH_CPU_TYPE_NAME(model) model LOONGARCH_CPU_TYPE_SUFFIX
#define CPU_RESOLVING_TYPE TYPE_LOONGARCH_CPU
diff --git a/target/loongarch/disas.c b/target/loongarch/disas.c
index 9b13554904..da005ec1c6 100644
--- a/target/loongarch/disas.c
+++ b/target/loongarch/disas.c
@@ -227,6 +227,17 @@ static void output_i_rr(DisasContext *ctx, arg_i_rr *a, const char *mnemonic)
output(ctx, mnemonic, "%d, r%d, r%d", a->imm, a->rj, a->rk);
}
+static void output_cop_r_i(DisasContext *ctx, arg_cop_r_i *a,
+ const char *mnemonic)
+{
+ output(ctx, mnemonic, "%d, r%d, %d", a->cop, a->rj, a->imm);
+}
+
+static void output_j_i(DisasContext *ctx, arg_j_i *a, const char *mnemonic)
+{
+ output(ctx, mnemonic, "r%d, %d", a->rj, a->imm);
+}
+
#define INSN(insn, type) \
static bool trans_##insn(DisasContext *ctx, arg_##type * a) \
{ \
@@ -557,6 +568,12 @@ INSN(tlbfill, empty)
INSN(tlbclr, empty)
INSN(tlbflush, empty)
INSN(invtlb, i_rr)
+INSN(cacop, cop_r_i)
+INSN(lddir, rr_i)
+INSN(ldpte, j_i)
+INSN(ertn, empty)
+INSN(idle, i)
+INSN(dbcl, i)
#define output_fcmp(C, PREFIX, SUFFIX) \
{ \
diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h
index 97af7ac8aa..c916f2650b 100644
--- a/target/loongarch/helper.h
+++ b/target/loongarch/helper.h
@@ -112,4 +112,8 @@ DEF_HELPER_2(invtlb_all_g, void, env, i32)
DEF_HELPER_2(invtlb_all_asid, void, env, tl)
DEF_HELPER_3(invtlb_page_asid, void, env, tl, tl)
DEF_HELPER_3(invtlb_page_asid_or_g, void, env, tl, tl)
+DEF_HELPER_4(lddir, tl, env, tl, tl, i32)
+DEF_HELPER_4(ldpte, void, env, tl, tl, i32)
+DEF_HELPER_1(ertn, void, env)
+DEF_HELPER_1(idle, void, env)
#endif /* !CONFIG_USER_ONLY */
diff --git a/target/loongarch/insn_trans/trans_privileged.c.inc b/target/loongarch/insn_trans/trans_privileged.c.inc
index 8bc6dd6e51..1bd3c8e985 100644
--- a/target/loongarch/insn_trans/trans_privileged.c.inc
+++ b/target/loongarch/insn_trans/trans_privileged.c.inc
@@ -33,6 +33,12 @@ GEN_FALSE_TRANS(tlbfill)
GEN_FALSE_TRANS(tlbclr)
GEN_FALSE_TRANS(tlbflush)
GEN_FALSE_TRANS(invtlb)
+GEN_FALSE_TRANS(cacop)
+GEN_FALSE_TRANS(ldpte)
+GEN_FALSE_TRANS(lddir)
+GEN_FALSE_TRANS(ertn)
+GEN_FALSE_TRANS(dbcl)
+GEN_FALSE_TRANS(idle)
#else
@@ -337,4 +343,68 @@ static bool trans_invtlb(DisasContext *ctx, arg_invtlb *a)
return true;
}
+static bool trans_cacop(DisasContext *ctx, arg_cacop *a)
+{
+ /* Treat the cacop as a nop */
+ if (check_plv(ctx)) {
+ return false;
+ }
+ return true;
+}
+
+static bool trans_ldpte(DisasContext *ctx, arg_ldpte *a)
+{
+ TCGv_i32 mem_idx = tcg_constant_i32(ctx->mem_idx);
+ TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
+
+ if (check_plv(ctx)) {
+ return false;
+ }
+ gen_helper_ldpte(cpu_env, src1, tcg_constant_tl(a->imm), mem_idx);
+ return true;
+}
+
+static bool trans_lddir(DisasContext *ctx, arg_lddir *a)
+{
+ TCGv_i32 mem_idx = tcg_constant_i32(ctx->mem_idx);
+ TCGv src = gpr_src(ctx, a->rj, EXT_NONE);
+ TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE);
+
+ if (check_plv(ctx)) {
+ return false;
+ }
+ gen_helper_lddir(dest, cpu_env, src, tcg_constant_tl(a->imm), mem_idx);
+ return true;
+}
+
+static bool trans_ertn(DisasContext *ctx, arg_ertn *a)
+{
+ if (check_plv(ctx)) {
+ return false;
+ }
+ gen_helper_ertn(cpu_env);
+ ctx->base.is_jmp = DISAS_EXIT;
+ return true;
+}
+
+static bool trans_dbcl(DisasContext *ctx, arg_dbcl *a)
+{
+ if (check_plv(ctx)) {
+ return false;
+ }
+ generate_exception(ctx, EXCCODE_DBP);
+ return true;
+}
+
+static bool trans_idle(DisasContext *ctx, arg_idle *a)
+{
+ if (check_plv(ctx)) {
+ return false;
+ }
+
+ tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4);
+ gen_helper_idle(cpu_env);
+ ctx->base.is_jmp = DISAS_NORETURN;
+ return true;
+}
#endif
diff --git a/target/loongarch/insns.decode b/target/loongarch/insns.decode
index 6f2a814195..3fdc6e148c 100644
--- a/target/loongarch/insns.decode
+++ b/target/loongarch/insns.decode
@@ -49,6 +49,8 @@
&rr_csr rd rj csr
&empty
&i_rr imm rj rk
+&cop_r_i cop rj imm
+&j_i rj imm
#
# Formats
@@ -60,6 +62,7 @@
@r_i20 .... ... imm:s20 rd:5 &r_i
@rr_ui5 .... ........ ..... imm:5 rj:5 rd:5 &rr_i
@rr_ui6 .... ........ .... imm:6 rj:5 rd:5 &rr_i
+@rr_ui8 .. ........ .... imm:8 rj:5 rd:5 &rr_i
@rr_i12 .... ...... imm:s12 rj:5 rd:5 &rr_i
@rr_ui12 .... ...... imm:12 rj:5 rd:5 &rr_i
@rr_i14s2 .... .... .............. rj:5 rd:5 &rr_i imm=%i14s2
@@ -93,6 +96,8 @@
@rr_csr .... .... csr:14 rj:5 rd:5 &rr_csr
@empty .... ........ ..... ..... ..... ..... &empty
@i_rr ...... ...... ..... rk:5 rj:5 imm:5 &i_rr
+@cop_r_i .... ...... imm:s12 rj:5 cop:5 &cop_r_i
+@j_i .... ........ .. imm:8 rj:5 ..... &j_i
#
# Fixed point arithmetic operation instruction
@@ -473,3 +478,9 @@ tlbfill 0000 01100100 10000 01101 00000 00000 @empty
tlbclr 0000 01100100 10000 01000 00000 00000 @empty
tlbflush 0000 01100100 10000 01001 00000 00000 @empty
invtlb 0000 01100100 10011 ..... ..... ..... @i_rr
+cacop 0000 011000 ............ ..... ..... @cop_r_i
+lddir 0000 01100100 00 ........ ..... ..... @rr_ui8
+ldpte 0000 01100100 01 ........ ..... 00000 @j_i
+ertn 0000 01100100 10000 01110 00000 00000 @empty
+idle 0000 01100100 10001 ............... @i15
+dbcl 0000 00000010 10101 ............... @i15
diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h
index 5fc1a4bb07..92f0a9aa5b 100644
--- a/target/loongarch/internals.h
+++ b/target/loongarch/internals.h
@@ -16,6 +16,11 @@
#define TARGET_PHYS_MASK MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS)
#define TARGET_VIRT_MASK MAKE_64BIT_MASK(0, TARGET_VIRT_ADDR_SPACE_BITS)
+/* Global bit used for lddir/ldpte */
+#define LOONGARCH_PAGE_HUGE_SHIFT 6
+/* Global bit for huge page */
+#define LOONGARCH_HGLOBAL_SHIFT 12
+
void loongarch_translate_init(void);
void loongarch_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
diff --git a/target/loongarch/op_helper.c b/target/loongarch/op_helper.c
index 48c25e5a9b..84175fbdcd 100644
--- a/target/loongarch/op_helper.c
+++ b/target/loongarch/op_helper.c
@@ -6,6 +6,7 @@
*/
#include "qemu/osdep.h"
+#include "qemu/log.h"
#include "qemu/main-loop.h"
#include "cpu.h"
#include "qemu/host-utils.h"
@@ -91,3 +92,40 @@ target_ulong helper_cpucfg(CPULoongArchState *env, target_ulong rj)
{
return rj > 21 ? 0 : env->cpucfg[rj];
}
+
+#ifndef CONFIG_USER_ONLY
+void helper_ertn(CPULoongArchState *env)
+{
+ uint64_t csr_pplv, csr_pie;
+ if (FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR)) {
+ csr_pplv = FIELD_EX64(env->CSR_TLBRPRMD, CSR_TLBRPRMD, PPLV);
+ csr_pie = FIELD_EX64(env->CSR_TLBRPRMD, CSR_TLBRPRMD, PIE);
+
+ env->CSR_TLBRERA = FIELD_DP64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR, 0);
+ env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DA, 0);
+ env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PG, 1);
+ env->pc = env->CSR_TLBRERA;
+ qemu_log_mask(CPU_LOG_INT, "%s: TLBRERA 0x%lx\n",
+ __func__, env->CSR_TLBRERA);
+ } else {
+ csr_pplv = FIELD_EX64(env->CSR_PRMD, CSR_PRMD, PPLV);
+ csr_pie = FIELD_EX64(env->CSR_PRMD, CSR_PRMD, PIE);
+
+ env->pc = env->CSR_ERA;
+ qemu_log_mask(CPU_LOG_INT, "%s: ERA 0x%lx\n", __func__, env->CSR_ERA);
+ }
+ env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PLV, csr_pplv);
+ env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, IE, csr_pie);
+
+ env->lladdr = 1;
+}
+
+void helper_idle(CPULoongArchState *env)
+{
+ CPUState *cs = env_cpu(env);
+
+ cs->halted = 1;
+ cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE);
+ do_raise_exception(env, EXCP_HLT, 0);
+}
+#endif /* !CONFIG_USER_ONLY */
diff --git a/target/loongarch/tlb_helper.c b/target/loongarch/tlb_helper.c
index 899b4d700c..7d5503b28d 100644
--- a/target/loongarch/tlb_helper.c
+++ b/target/loongarch/tlb_helper.c
@@ -672,3 +672,96 @@ bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
do_raise_exception(env, cs->exception_index, retaddr);
}
}
+
+target_ulong helper_lddir(CPULoongArchState *env, target_ulong base,
+ target_ulong level, uint32_t mem_idx)
+{
+ CPUState *cs = env_cpu(env);
+ target_ulong badvaddr, index, phys, ret;
+ int shift;
+ uint64_t dir_base, dir_width;
+ bool huge = (base >> LOONGARCH_PAGE_HUGE_SHIFT) & 0x1;
+
+ badvaddr = env->CSR_TLBRBADV;
+ base = base & TARGET_PHYS_MASK;
+
+ /* 0:64bit, 1:128bit, 2:192bit, 3:256bit */
+ shift = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTEWIDTH);
+ shift = (shift + 1) * 3;
+
+ if (huge) {
+ return base;
+ }
+ switch (level) {
+ case 1:
+ dir_base = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR1_BASE);
+ dir_width = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR1_WIDTH);
+ break;
+ case 2:
+ dir_base = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR2_BASE);
+ dir_width = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR2_WIDTH);
+ break;
+ case 3:
+ dir_base = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR3_BASE);
+ dir_width = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR3_WIDTH);
+ break;
+ case 4:
+ dir_base = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR4_BASE);
+ dir_width = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR4_WIDTH);
+ break;
+ default:
+ do_raise_exception(env, EXCCODE_INE, GETPC());
+ return 0;
+ }
+ index = (badvaddr >> dir_base) & ((1 << dir_width) - 1);
+ phys = base | index << shift;
+ ret = ldq_phys(cs->as, phys) & TARGET_PHYS_MASK;
+ return ret;
+}
+
+void helper_ldpte(CPULoongArchState *env, target_ulong base, target_ulong odd,
+ uint32_t mem_idx)
+{
+ CPUState *cs = env_cpu(env);
+ target_ulong phys, tmp0, ptindex, ptoffset0, ptoffset1, ps, badv;
+ int shift;
+ bool huge = (base >> LOONGARCH_PAGE_HUGE_SHIFT) & 0x1;
+ uint64_t ptbase = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTBASE);
+ uint64_t ptwidth = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTWIDTH);
+
+ base = base & TARGET_PHYS_MASK;
+
+ if (huge) {
+ /* Huge Page. base is paddr */
+ tmp0 = base ^ (1 << LOONGARCH_PAGE_HUGE_SHIFT);
+ /* Move Global bit */
+ tmp0 = ((tmp0 & (1 << LOONGARCH_HGLOBAL_SHIFT)) >>
+ LOONGARCH_HGLOBAL_SHIFT) << R_TLBENTRY_G_SHIFT |
+ (tmp0 & (~(1 << R_TLBENTRY_G_SHIFT)));
+ ps = ptbase + ptwidth - 1;
+ if (odd) {
+ tmp0 += (1 << ps);
+ }
+ } else {
+ /* 0:64bit, 1:128bit, 2:192bit, 3:256bit */
+ shift = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTEWIDTH);
+ shift = (shift + 1) * 3;
+ badv = env->CSR_TLBRBADV;
+
+ ptindex = (badv >> ptbase) & ((1 << ptwidth) - 1);
+ ptindex = ptindex & ~0x1; /* clear bit 0 */
+ ptoffset0 = ptindex << shift;
+ ptoffset1 = (ptindex + 1) << shift;
+
+ phys = base | (odd ? ptoffset1 : ptoffset0);
+ tmp0 = ldq_phys(cs->as, phys) & TARGET_PHYS_MASK;
+ ps = ptbase;
+ }
+
+ if (odd) {
+ env->CSR_TLBRELO1 = tmp0;
+ } else {
+ env->CSR_TLBRELO0 = tmp0;
+ }
+ env->CSR_TLBREHI = FIELD_DP64(env->CSR_TLBREHI, CSR_TLBREHI, PS, ps);
+}
--
2.31.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [RFC PATCH v7 11/29] target/loongarch: Add LoongArch interrupt and exception handle
2022-03-28 12:57 [RFC PATCH v7 00/29] Add LoongArch softmmu support Xiaojuan Yang
` (9 preceding siblings ...)
2022-03-28 12:57 ` [RFC PATCH v7 10/29] target/loongarch: Add other core instructions support Xiaojuan Yang
@ 2022-03-28 12:57 ` Xiaojuan Yang
2022-03-28 20:19 ` Richard Henderson
2022-03-28 12:57 ` [RFC PATCH v7 12/29] target/loongarch: Add timer related instructions support Xiaojuan Yang
` (18 subsequent siblings)
29 siblings, 1 reply; 71+ messages in thread
From: Xiaojuan Yang @ 2022-03-28 12:57 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland, richard.henderson, Song Gao
1.This patch Add loongarch interrupt and exception handle.
2.Rename the user excp to the exccode from the csr defintions.
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
linux-user/loongarch64/cpu_loop.c | 8 +-
target/loongarch/cpu.c | 260 +++++++++++++++++-
target/loongarch/cpu.h | 11 -
target/loongarch/fpu_helper.c | 2 +-
| 4 +-
target/loongarch/translate.c | 2 +-
6 files changed, 261 insertions(+), 26 deletions(-)
diff --git a/linux-user/loongarch64/cpu_loop.c b/linux-user/loongarch64/cpu_loop.c
index 6628d215ca..dd58eb048f 100644
--- a/linux-user/loongarch64/cpu_loop.c
+++ b/linux-user/loongarch64/cpu_loop.c
@@ -28,7 +28,7 @@ void cpu_loop(CPULoongArchState *env)
case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */
break;
- case EXCP_SYSCALL:
+ case EXCCODE_SYS:
env->pc += 4;
ret = do_syscall(env, env->gpr[11],
env->gpr[4], env->gpr[5],
@@ -48,10 +48,10 @@ void cpu_loop(CPULoongArchState *env)
}
env->gpr[4] = ret;
break;
- case EXCP_INE:
+ case EXCCODE_INE:
force_sig_fault(TARGET_SIGILL, 0, env->pc);
break;
- case EXCP_FPE:
+ case EXCCODE_FPE:
si_code = TARGET_FPE_FLTUNK;
if (GET_FP_CAUSE(env->fcsr0) & FP_INVALID) {
si_code = TARGET_FPE_FLTINV;
@@ -67,7 +67,7 @@ void cpu_loop(CPULoongArchState *env)
force_sig_fault(TARGET_SIGFPE, si_code, env->pc);
break;
case EXCP_DEBUG:
- case EXCP_BREAK:
+ case EXCCODE_BRK:
force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);
break;
case EXCP_ATOMIC:
diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index 880801fa51..0fc74a8b40 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -31,11 +31,23 @@ const char * const fregnames[32] = {
"f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
};
-static const char * const excp_names[EXCP_LAST + 1] = {
- [EXCP_SYSCALL] = "Syscall",
- [EXCP_BREAK] = "Break",
- [EXCP_INE] = "Instruction Non-Existent",
- [EXCP_FPE] = "Floating Point Exception",
+static const char * const excp_names[] = {
+ [EXCCODE_INT] = "Interrupt",
+ [EXCCODE_PIL] = "Page invalid exception for load",
+ [EXCCODE_PIS] = "Page invalid exception for store",
+ [EXCCODE_PIF] = "Page invalid exception for fetch",
+ [EXCCODE_PME] = "Page modified exception",
+ [EXCCODE_PNR] = "Page Not Readable exception",
+ [EXCCODE_PNX] = "Page Not Executable exception",
+ [EXCCODE_PPI] = "Page Privilege error",
+ [EXCCODE_ADEF] = "Address error for instruction fetch",
+ [EXCCODE_ADEM] = "Address error for Memory access",
+ [EXCCODE_SYS] = "Syscall",
+ [EXCCODE_BRK] = "Break",
+ [EXCCODE_INE] = "Instruction Non-Existent",
+ [EXCCODE_IPE] = "Instruction privilege error",
+ [EXCCODE_FPE] = "Floating Point Exception",
+ [EXCCODE_DBP] = "Debug breakpoint",
};
const char *loongarch_exception_name(int32_t exception)
@@ -67,6 +79,225 @@ static void loongarch_cpu_set_pc(CPUState *cs, vaddr value)
env->pc = value;
}
+#if !defined(CONFIG_USER_ONLY)
+static inline bool cpu_loongarch_hw_interrupts_enabled(CPULoongArchState *env)
+{
+ bool ret = 0;
+
+ ret = (FIELD_EX64(env->CSR_CRMD, CSR_CRMD, IE) &&
+ !(FIELD_EX64(env->CSR_DBG, CSR_DBG, DST)));
+
+ return ret;
+}
+
+/* Check if there is pending and not masked out interrupt */
+static inline bool cpu_loongarch_hw_interrupts_pending(CPULoongArchState *env)
+{
+ uint32_t pending;
+ uint32_t status;
+ bool r;
+
+ pending = FIELD_EX64(env->CSR_ESTAT, CSR_ESTAT, IS);
+ status = FIELD_EX64(env->CSR_ECFG, CSR_ECFG, LIE);
+
+ r = (pending & status) != 0;
+ return r;
+}
+
+static inline unsigned int get_vint_size(CPULoongArchState *env)
+{
+ uint64_t vs = FIELD_EX64(env->CSR_ECFG, CSR_ECFG, VS);
+ uint64_t size = 0;
+
+ if (vs == 0) {
+ return 0;
+ }
+
+ if (vs < 8) {
+ size = 1 << (vs + 2);
+ }
+
+ if (vs > 8) {
+ qemu_log("%s: unexpected value", __func__);
+ assert(0);
+ }
+
+ return size;
+}
+
+static void loongarch_cpu_do_interrupt(CPUState *cs)
+{
+ LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+ CPULoongArchState *env = &cpu->env;
+ bool update_badinstr = 1;
+ int cause = -1;
+ const char *name;
+ bool tlbfill = FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR);
+
+ if (cs->exception_index != EXCCODE_INT) {
+ if (cs->exception_index < 0 ||
+ cs->exception_index > ARRAY_SIZE(excp_names)) {
+ name = "unknown";
+ } else {
+ name = excp_names[cs->exception_index];
+ }
+
+ qemu_log_mask(CPU_LOG_INT,
+ "%s enter: pc " TARGET_FMT_lx " ERA " TARGET_FMT_lx
+ " TLBRERA " TARGET_FMT_lx " %s exception\n", __func__,
+ env->pc, env->CSR_ERA, env->CSR_TLBRERA, name);
+ }
+ if (cs->exception_index == EXCCODE_INT &&
+ (FIELD_EX64(env->CSR_DBG, CSR_DBG, DST))) {
+ env->CSR_DBG = FIELD_DP64(env->CSR_DBG, CSR_DBG, DEI, 1);
+ goto set_DERA;
+ }
+
+ switch (cs->exception_index) {
+ case EXCCODE_DBP:
+ env->CSR_DBG = FIELD_DP64(env->CSR_DBG, CSR_DBG, DCL, 1);
+ env->CSR_DBG = FIELD_DP64(env->CSR_DBG, CSR_DBG, ECODE, 0xC);
+ goto set_DERA;
+ set_DERA:
+ env->CSR_DERA = env->pc;
+ env->CSR_DBG = FIELD_DP64(env->CSR_DBG, CSR_DBG, DST, 1);
+ env->pc = env->CSR_EENTRY + 0x480;
+ break;
+ case EXCCODE_INT:
+ case EXCCODE_PIF:
+ cause = cs->exception_index;
+ update_badinstr = 0;
+ break;
+ case EXCCODE_ADEM:
+ case EXCCODE_SYS:
+ case EXCCODE_BRK:
+ case EXCCODE_PIL:
+ case EXCCODE_PIS:
+ case EXCCODE_PME:
+ case EXCCODE_PNR:
+ case EXCCODE_PNX:
+ case EXCCODE_PPI:
+ case EXCCODE_INE:
+ case EXCCODE_IPE:
+ case EXCCODE_FPE:
+ cause = cs->exception_index;
+ break;
+ default:
+ qemu_log("Error: exception(%d) '%s' has not been supported\n",
+ cs->exception_index, excp_names[cs->exception_index]);
+ abort();
+ }
+
+ if (update_badinstr) {
+ env->CSR_BADI = cpu_ldl_code(env, env->pc);
+ }
+
+ /* Save PLV and IE */
+ if (tlbfill) {
+ env->CSR_TLBRPRMD = FIELD_DP64(env->CSR_TLBRPRMD, CSR_TLBRPRMD, PPLV,
+ FIELD_EX64(env->CSR_CRMD,
+ CSR_CRMD, PLV));
+ env->CSR_TLBRPRMD = FIELD_DP64(env->CSR_TLBRPRMD, CSR_TLBRPRMD, PIE,
+ FIELD_EX64(env->CSR_CRMD, CSR_CRMD, IE));
+ /* set the DA mode */
+ env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DA, 1);
+ env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PG, 0);
+ env->CSR_TLBRERA = FIELD_DP64(env->CSR_TLBRERA, CSR_TLBRERA,
+ PC, (env->pc >> 2));
+ } else {
+ env->CSR_PRMD = FIELD_DP64(env->CSR_PRMD, CSR_PRMD, PPLV,
+ FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PLV));
+ env->CSR_PRMD = FIELD_DP64(env->CSR_PRMD, CSR_PRMD, PIE,
+ FIELD_EX64(env->CSR_CRMD, CSR_CRMD, IE));
+ env->CSR_ERA = env->pc;
+ }
+
+ env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PLV, 0);
+ env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, IE, 0);
+
+ uint32_t vec_size = get_vint_size(env);
+ env->pc = env->CSR_EENTRY;
+ env->pc += cause * vec_size;
+ if (tlbfill) {
+ /* TLB Refill */
+ env->pc = env->CSR_TLBRENTRY;
+ }
+ if (cs->exception_index == EXCCODE_INT) {
+ /* Interrupt */
+ uint32_t vector = 0;
+ uint32_t pending = FIELD_EX64(env->CSR_ESTAT, CSR_ESTAT, IS);
+ pending &= FIELD_EX64(env->CSR_ECFG, CSR_ECFG, LIE);
+
+ /* Find the highest-priority interrupt. */
+ while (pending >>= 1) {
+ vector++;
+ }
+ env->pc = env->CSR_EENTRY + (EXCCODE_EXTERNAL_INT + vector) * vec_size;
+ qemu_log_mask(CPU_LOG_INT,
+ "%s: PC " TARGET_FMT_lx " ERA " TARGET_FMT_lx
+ " cause %d\n" " A " TARGET_FMT_lx " D "
+ TARGET_FMT_lx " vector = %d ExC %08lx ExS %08lx\n",
+ __func__, env->pc, env->CSR_ERA,
+ cause, env->CSR_BADV, env->CSR_DERA, vector,
+ env->CSR_ECFG, env->CSR_ESTAT);
+ }
+
+ if (!tlbfill) {
+ env->CSR_ESTAT = FIELD_DP64(env->CSR_ESTAT, CSR_ESTAT, ECODE, cause);
+ }
+
+ if (cs->exception_index != EXCCODE_INT) {
+ qemu_log_mask(CPU_LOG_INT,
+ "%s: PC " TARGET_FMT_lx " ERA " TARGET_FMT_lx
+ " cause %d%s\n, ESTAT " TARGET_FMT_lx
+ " EXCFG " TARGET_FMT_lx " BADVA " TARGET_FMT_lx
+ "BADI " TARGET_FMT_lx " SYS_NUM " TARGET_FMT_lu
+ " cpu %d asid 0x%lx" "\n", __func__, env->pc,
+ tlbfill ? env->CSR_TLBRERA : env->CSR_ERA,
+ cause, tlbfill ? "(refill)" : "", env->CSR_ESTAT,
+ env->CSR_ECFG,
+ tlbfill ? env->CSR_TLBRBADV : env->CSR_BADV,
+ env->CSR_BADI, env->gpr[11], cs->cpu_index,
+ env->CSR_ASID);
+ }
+ cs->exception_index = -1;
+}
+
+static void loongarch_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
+ vaddr addr, unsigned size,
+ MMUAccessType access_type,
+ int mmu_idx, MemTxAttrs attrs,
+ MemTxResult response,
+ uintptr_t retaddr)
+{
+ LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+ CPULoongArchState *env = &cpu->env;
+
+ if (access_type == MMU_INST_FETCH) {
+ do_raise_exception(env, EXCCODE_ADEF, retaddr);
+ } else {
+ do_raise_exception(env, EXCCODE_ADEM, retaddr);
+ }
+}
+
+static bool loongarch_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
+{
+ if (interrupt_request & CPU_INTERRUPT_HARD) {
+ LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+ CPULoongArchState *env = &cpu->env;
+
+ if (cpu_loongarch_hw_interrupts_enabled(env) &&
+ cpu_loongarch_hw_interrupts_pending(env)) {
+ /* Raise it */
+ cs->exception_index = EXCCODE_INT;
+ loongarch_cpu_do_interrupt(cs);
+ return true;
+ }
+ }
+ return false;
+}
+#endif
+
#ifdef CONFIG_TCG
static void loongarch_cpu_synchronize_from_tb(CPUState *cs,
const TranslationBlock *tb)
@@ -83,7 +314,16 @@ static bool loongarch_cpu_has_work(CPUState *cs)
#ifdef CONFIG_USER_ONLY
return true;
#else
-#error System emulation TODO
+ LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+ CPULoongArchState *env = &cpu->env;
+ bool has_work = false;
+
+ if ((cs->interrupt_request & CPU_INTERRUPT_HARD) &&
+ cpu_loongarch_hw_interrupts_pending(env)) {
+ has_work = true;
+ }
+
+ return has_work;
#endif
}
@@ -228,8 +468,11 @@ static void loongarch_cpu_reset(DeviceState *dev)
env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV3, 0);
}
+#ifndef CONFIG_USER_ONLY
+ env->pc = 0x1c000000;
+#endif
restore_fp_status(env);
- cs->exception_index = EXCP_NONE;
+ cs->exception_index = -1;
}
static void loongarch_cpu_disas_set_info(CPUState *s, disassemble_info *info)
@@ -331,6 +574,9 @@ static struct TCGCPUOps loongarch_tcg_ops = {
#if !defined(CONFIG_USER_ONLY)
.tlb_fill = loongarch_cpu_tlb_fill,
+ .cpu_exec_interrupt = loongarch_cpu_exec_interrupt,
+ .do_interrupt = loongarch_cpu_do_interrupt,
+ .do_transaction_failed = loongarch_cpu_do_transaction_failed,
#endif /* !CONFIG_USER_ONLY */
};
#endif /* CONFIG_TCG */
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index 1bbe0caeac..29f0024b1f 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -419,17 +419,6 @@ void loongarch_cpu_list(void);
#include "exec/cpu-all.h"
-/* Exceptions */
-enum {
- EXCP_NONE = -1,
- EXCP_SYSCALL = 0,
- EXCP_BREAK,
- EXCP_INE,
- EXCP_FPE,
-
- EXCP_LAST = EXCP_FPE,
-};
-
#define CPU_INTERRUPT_WAKE CPU_INTERRUPT_TGT_INT_0
#define LOONGARCH_CPU_TYPE_SUFFIX "-" TYPE_LOONGARCH_CPU
diff --git a/target/loongarch/fpu_helper.c b/target/loongarch/fpu_helper.c
index 9f5235c4f8..1baf012ef7 100644
--- a/target/loongarch/fpu_helper.c
+++ b/target/loongarch/fpu_helper.c
@@ -74,7 +74,7 @@ static void update_fcsr0_mask(CPULoongArchState *env, uintptr_t pc, int mask)
}
if (GET_FP_ENABLES(env->fcsr0) & flags) {
- do_raise_exception(env, EXCP_FPE, pc);
+ do_raise_exception(env, EXCCODE_FPE, pc);
} else {
UPDATE_FP_FLAGS(env->fcsr0, flags);
}
--git a/target/loongarch/insn_trans/trans_extra.c.inc b/target/loongarch/insn_trans/trans_extra.c.inc
index bc622ced23..2ce95d3382 100644
--- a/target/loongarch/insn_trans/trans_extra.c.inc
+++ b/target/loongarch/insn_trans/trans_extra.c.inc
@@ -5,13 +5,13 @@
static bool trans_break(DisasContext *ctx, arg_break *a)
{
- generate_exception(ctx, EXCP_BREAK);
+ generate_exception(ctx, EXCCODE_BRK);
return true;
}
static bool trans_syscall(DisasContext *ctx, arg_syscall *a)
{
- generate_exception(ctx, EXCP_SYSCALL);
+ generate_exception(ctx, EXCCODE_SYS);
return true;
}
diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c
index 438a3cb515..c1cac2f006 100644
--- a/target/loongarch/translate.c
+++ b/target/loongarch/translate.c
@@ -185,7 +185,7 @@ static void loongarch_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
if (!decode(ctx, ctx->opcode)) {
qemu_log_mask(LOG_UNIMP, "Error: unknown opcode. 0x%lx: 0x%x\n",
ctx->base.pc_next, ctx->opcode);
- generate_exception(ctx, EXCP_INE);
+ generate_exception(ctx, EXCCODE_INE);
}
for (int i = ctx->ntemp - 1; i >= 0; --i) {
--
2.31.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [RFC PATCH v7 12/29] target/loongarch: Add timer related instructions support.
2022-03-28 12:57 [RFC PATCH v7 00/29] Add LoongArch softmmu support Xiaojuan Yang
` (10 preceding siblings ...)
2022-03-28 12:57 ` [RFC PATCH v7 11/29] target/loongarch: Add LoongArch interrupt and exception handle Xiaojuan Yang
@ 2022-03-28 12:57 ` Xiaojuan Yang
2022-03-28 20:33 ` Richard Henderson
2022-03-28 12:57 ` [RFC PATCH v7 13/29] target/loongarch: Add gdb support Xiaojuan Yang
` (17 subsequent siblings)
29 siblings, 1 reply; 71+ messages in thread
From: Xiaojuan Yang @ 2022-03-28 12:57 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland, richard.henderson, Song Gao
This includes:
-RDTIME{L/H}.W
-RDTIME.D
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
target/loongarch/helper.h | 1 +
| 32 +++++++++++++++++++
target/loongarch/op_helper.c | 6 ++++
target/loongarch/translate.c | 2 ++
4 files changed, 41 insertions(+)
diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h
index c916f2650b..035bd141ed 100644
--- a/target/loongarch/helper.h
+++ b/target/loongarch/helper.h
@@ -116,4 +116,5 @@ DEF_HELPER_4(lddir, tl, env, tl, tl, i32)
DEF_HELPER_4(ldpte, void, env, tl, tl, i32)
DEF_HELPER_1(ertn, void, env)
DEF_HELPER_1(idle, void, env)
+DEF_HELPER_1(rdtime_d, i64, env)
#endif /* !CONFIG_USER_ONLY */
--git a/target/loongarch/insn_trans/trans_extra.c.inc b/target/loongarch/insn_trans/trans_extra.c.inc
index 2ce95d3382..8d3425ba61 100644
--- a/target/loongarch/insn_trans/trans_extra.c.inc
+++ b/target/loongarch/insn_trans/trans_extra.c.inc
@@ -33,22 +33,54 @@ static bool trans_asrtgt_d(DisasContext *ctx, arg_asrtgt_d * a)
return true;
}
+#ifndef CONFIG_USER_ONLY
+static bool gen_rdtime(DisasContext *ctx, arg_rr *a,
+ bool word, bool high)
+{
+ TCGv dst1 = gpr_dst(ctx, a->rd, EXT_NONE);
+ TCGv dst2 = gpr_dst(ctx, a->rj, EXT_NONE);
+
+ if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
+ gen_io_start();
+ }
+ gen_helper_rdtime_d(dst1, cpu_env);
+ if (word) {
+ tcg_gen_sextract_tl(dst1, dst1, high ? 32 : 0, 32);
+ }
+ tcg_gen_ld_i64(dst2, cpu_env, offsetof(CPULoongArchState, CSR_TID));
+
+ return true;
+}
+#endif
+
static bool trans_rdtimel_w(DisasContext *ctx, arg_rdtimel_w *a)
{
+#ifdef CONFIG_USER_ONLY
tcg_gen_movi_tl(cpu_gpr[a->rd], 0);
return true;
+#else
+ return gen_rdtime(ctx, a, 1, 0);
+#endif
}
static bool trans_rdtimeh_w(DisasContext *ctx, arg_rdtimeh_w *a)
{
+#ifdef CONFIG_USER_ONLY
tcg_gen_movi_tl(cpu_gpr[a->rd], 0);
return true;
+#else
+ return gen_rdtime(ctx, a, 1, 1);
+#endif
}
static bool trans_rdtime_d(DisasContext *ctx, arg_rdtime_d *a)
{
+#ifdef CONFIG_USER_ONLY
tcg_gen_movi_tl(cpu_gpr[a->rd], 0);
return true;
+#else
+ return gen_rdtime(ctx, a, 0, 0);
+#endif
}
static bool trans_cpucfg(DisasContext *ctx, arg_cpucfg *a)
diff --git a/target/loongarch/op_helper.c b/target/loongarch/op_helper.c
index 84175fbdcd..7330014308 100644
--- a/target/loongarch/op_helper.c
+++ b/target/loongarch/op_helper.c
@@ -128,4 +128,10 @@ void helper_idle(CPULoongArchState *env)
cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE);
do_raise_exception(env, EXCP_HLT, 0);
}
+
+uint64_t helper_rdtime_d(CPULoongArchState *env)
+{
+ LoongArchCPU *cpu = LOONGARCH_CPU(env_cpu(env));
+ return cpu_loongarch_get_constant_timer_counter(cpu);
+}
#endif /* !CONFIG_USER_ONLY */
diff --git a/target/loongarch/translate.c b/target/loongarch/translate.c
index c1cac2f006..9ce003980d 100644
--- a/target/loongarch/translate.c
+++ b/target/loongarch/translate.c
@@ -25,6 +25,8 @@ static TCGv cpu_lladdr, cpu_llval;
TCGv_i32 cpu_fcsr0;
TCGv_i64 cpu_fpr[32];
+#include "exec/gen-icount.h"
+
#define DISAS_STOP DISAS_TARGET_0
#define DISAS_EXIT DISAS_TARGET_1
--
2.31.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [RFC PATCH v7 13/29] target/loongarch: Add gdb support.
2022-03-28 12:57 [RFC PATCH v7 00/29] Add LoongArch softmmu support Xiaojuan Yang
` (11 preceding siblings ...)
2022-03-28 12:57 ` [RFC PATCH v7 12/29] target/loongarch: Add timer related instructions support Xiaojuan Yang
@ 2022-03-28 12:57 ` Xiaojuan Yang
2022-03-28 20:35 ` Richard Henderson
2022-03-28 12:57 ` [RFC PATCH v7 14/29] hw/loongarch: Add support loongson3 virt machine type Xiaojuan Yang
` (16 subsequent siblings)
29 siblings, 1 reply; 71+ messages in thread
From: Xiaojuan Yang @ 2022-03-28 12:57 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland, richard.henderson, Song Gao
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
MAINTAINERS | 2 +
configs/targets/loongarch64-softmmu.mak | 1 +
gdb-xml/loongarch-base64.xml | 44 +++++++++++
gdb-xml/loongarch-fpu64.xml | 57 ++++++++++++++
target/loongarch/cpu.c | 9 ++-
target/loongarch/gdbstub.c | 99 +++++++++++++++++++++++++
target/loongarch/internals.h | 10 +++
target/loongarch/meson.build | 1 +
8 files changed, 222 insertions(+), 1 deletion(-)
create mode 100644 configs/targets/loongarch64-softmmu.mak
create mode 100644 gdb-xml/loongarch-base64.xml
create mode 100644 gdb-xml/loongarch-fpu64.xml
create mode 100644 target/loongarch/gdbstub.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 7b61d9eb08..83517a750b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1128,6 +1128,8 @@ M: Xiaojuan Yang <yangxiaojuan@loongson.cn>
M: Song Gao <gaosong@loongson.cn>
S: Maintained
F: docs/system/loongarch/loongson3.rst
+F: configs/targets/loongarch64-softmmu.mak
+F: gdb-xml/loongarch*.xml
M68K Machines
-------------
diff --git a/configs/targets/loongarch64-softmmu.mak b/configs/targets/loongarch64-softmmu.mak
new file mode 100644
index 0000000000..f33fa1590b
--- /dev/null
+++ b/configs/targets/loongarch64-softmmu.mak
@@ -0,0 +1 @@
+TARGET_XML_FILES= gdb-xml/loongarch-base64.xml gdb-xml/loongarch-fpu64.xml
diff --git a/gdb-xml/loongarch-base64.xml b/gdb-xml/loongarch-base64.xml
new file mode 100644
index 0000000000..4962bdbd28
--- /dev/null
+++ b/gdb-xml/loongarch-base64.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2021 Free Software Foundation, Inc.
+
+ Copying and distribution of this file, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved. -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.loongarch.base">
+ <reg name="r0" bitsize="64" type="uint64" group="general"/>
+ <reg name="r1" bitsize="64" type="uint64" group="general"/>
+ <reg name="r2" bitsize="64" type="uint64" group="general"/>
+ <reg name="r3" bitsize="64" type="uint64" group="general"/>
+ <reg name="r4" bitsize="64" type="uint64" group="general"/>
+ <reg name="r5" bitsize="64" type="uint64" group="general"/>
+ <reg name="r6" bitsize="64" type="uint64" group="general"/>
+ <reg name="r7" bitsize="64" type="uint64" group="general"/>
+ <reg name="r8" bitsize="64" type="uint64" group="general"/>
+ <reg name="r9" bitsize="64" type="uint64" group="general"/>
+ <reg name="r10" bitsize="64" type="uint64" group="general"/>
+ <reg name="r11" bitsize="64" type="uint64" group="general"/>
+ <reg name="r12" bitsize="64" type="uint64" group="general"/>
+ <reg name="r13" bitsize="64" type="uint64" group="general"/>
+ <reg name="r14" bitsize="64" type="uint64" group="general"/>
+ <reg name="r15" bitsize="64" type="uint64" group="general"/>
+ <reg name="r16" bitsize="64" type="uint64" group="general"/>
+ <reg name="r17" bitsize="64" type="uint64" group="general"/>
+ <reg name="r18" bitsize="64" type="uint64" group="general"/>
+ <reg name="r19" bitsize="64" type="uint64" group="general"/>
+ <reg name="r20" bitsize="64" type="uint64" group="general"/>
+ <reg name="r21" bitsize="64" type="uint64" group="general"/>
+ <reg name="r22" bitsize="64" type="uint64" group="general"/>
+ <reg name="r23" bitsize="64" type="uint64" group="general"/>
+ <reg name="r24" bitsize="64" type="uint64" group="general"/>
+ <reg name="r25" bitsize="64" type="uint64" group="general"/>
+ <reg name="r26" bitsize="64" type="uint64" group="general"/>
+ <reg name="r27" bitsize="64" type="uint64" group="general"/>
+ <reg name="r28" bitsize="64" type="uint64" group="general"/>
+ <reg name="r29" bitsize="64" type="uint64" group="general"/>
+ <reg name="r30" bitsize="64" type="uint64" group="general"/>
+ <reg name="r31" bitsize="64" type="uint64" group="general"/>
+ <reg name="pc" bitsize="64" type="code_ptr" group="general"/>
+ <reg name="badvaddr" bitsize="64" type="code_ptr" group="general"/>
+</feature>
diff --git a/gdb-xml/loongarch-fpu64.xml b/gdb-xml/loongarch-fpu64.xml
new file mode 100644
index 0000000000..e52cf89fbc
--- /dev/null
+++ b/gdb-xml/loongarch-fpu64.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2021 Free Software Foundation, Inc.
+
+ Copying and distribution of this file, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved. -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.loongarch.fpu">
+
+ <union id="fpu64type">
+ <field name="f" type="ieee_single"/>
+ <field name="d" type="ieee_double"/>
+ </union>
+
+ <reg name="f0" bitsize="64" type="fpu64type" group="float"/>
+ <reg name="f1" bitsize="64" type="fpu64type" group="float"/>
+ <reg name="f2" bitsize="64" type="fpu64type" group="float"/>
+ <reg name="f3" bitsize="64" type="fpu64type" group="float"/>
+ <reg name="f4" bitsize="64" type="fpu64type" group="float"/>
+ <reg name="f5" bitsize="64" type="fpu64type" group="float"/>
+ <reg name="f6" bitsize="64" type="fpu64type" group="float"/>
+ <reg name="f7" bitsize="64" type="fpu64type" group="float"/>
+ <reg name="f8" bitsize="64" type="fpu64type" group="float"/>
+ <reg name="f9" bitsize="64" type="fpu64type" group="float"/>
+ <reg name="f10" bitsize="64" type="fpu64type" group="float"/>
+ <reg name="f11" bitsize="64" type="fpu64type" group="float"/>
+ <reg name="f12" bitsize="64" type="fpu64type" group="float"/>
+ <reg name="f13" bitsize="64" type="fpu64type" group="float"/>
+ <reg name="f14" bitsize="64" type="fpu64type" group="float"/>
+ <reg name="f15" bitsize="64" type="fpu64type" group="float"/>
+ <reg name="f16" bitsize="64" type="fpu64type" group="float"/>
+ <reg name="f17" bitsize="64" type="fpu64type" group="float"/>
+ <reg name="f18" bitsize="64" type="fpu64type" group="float"/>
+ <reg name="f19" bitsize="64" type="fpu64type" group="float"/>
+ <reg name="f20" bitsize="64" type="fpu64type" group="float"/>
+ <reg name="f21" bitsize="64" type="fpu64type" group="float"/>
+ <reg name="f22" bitsize="64" type="fpu64type" group="float"/>
+ <reg name="f23" bitsize="64" type="fpu64type" group="float"/>
+ <reg name="f24" bitsize="64" type="fpu64type" group="float"/>
+ <reg name="f25" bitsize="64" type="fpu64type" group="float"/>
+ <reg name="f26" bitsize="64" type="fpu64type" group="float"/>
+ <reg name="f27" bitsize="64" type="fpu64type" group="float"/>
+ <reg name="f28" bitsize="64" type="fpu64type" group="float"/>
+ <reg name="f29" bitsize="64" type="fpu64type" group="float"/>
+ <reg name="f30" bitsize="64" type="fpu64type" group="float"/>
+ <reg name="f31" bitsize="64" type="fpu64type" group="float"/>
+ <reg name="fcc0" bitsize="8" type="uint8" group="float"/>
+ <reg name="fcc1" bitsize="8" type="uint8" group="float"/>
+ <reg name="fcc2" bitsize="8" type="uint8" group="float"/>
+ <reg name="fcc3" bitsize="8" type="uint8" group="float"/>
+ <reg name="fcc4" bitsize="8" type="uint8" group="float"/>
+ <reg name="fcc5" bitsize="8" type="uint8" group="float"/>
+ <reg name="fcc6" bitsize="8" type="uint8" group="float"/>
+ <reg name="fcc7" bitsize="8" type="uint8" group="float"/>
+ <reg name="fcsr" bitsize="32" type="uint32" group="float"/>
+</feature>
diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index 0fc74a8b40..deaa0b4f31 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -603,11 +603,18 @@ static void loongarch_cpu_class_init(ObjectClass *c, void *data)
cc->has_work = loongarch_cpu_has_work;
cc->dump_state = loongarch_cpu_dump_state;
cc->set_pc = loongarch_cpu_set_pc;
+ cc->gdb_read_register = loongarch_cpu_gdb_read_register;
+ cc->gdb_write_register = loongarch_cpu_gdb_write_register;
+ cc->disas_set_info = loongarch_cpu_disas_set_info;
+ cc->gdb_num_core_regs = 34;
+ cc->gdb_core_xml_file = "loongarch-base64.xml";
+ cc->gdb_stop_before_watchpoint = true;
+
#ifndef CONFIG_USER_ONLY
dc->vmsd = &vmstate_loongarch_cpu;
cc->sysemu_ops = &loongarch_sysemu_ops;
#endif
- cc->disas_set_info = loongarch_cpu_disas_set_info;
+
#ifdef CONFIG_TCG
cc->tcg_ops = &loongarch_tcg_ops;
#endif
diff --git a/target/loongarch/gdbstub.c b/target/loongarch/gdbstub.c
new file mode 100644
index 0000000000..5a70284d81
--- /dev/null
+++ b/target/loongarch/gdbstub.c
@@ -0,0 +1,99 @@
+/*
+ * LOONGARCH gdb server stub
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "cpu.h"
+#include "internals.h"
+#include "exec/gdbstub.h"
+#include "exec/helper-proto.h"
+
+int loongarch_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
+{
+ LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+ CPULoongArchState *env = &cpu->env;
+
+ if (0 <= n && n < 32) {
+ return gdb_get_regl(mem_buf, env->gpr[n]);
+ } else if (n == 32) {
+ return gdb_get_regl(mem_buf, env->pc);
+ } else if (n == 33) {
+ return gdb_get_regl(mem_buf, env->badaddr);
+ }
+ return 0;
+}
+
+int loongarch_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+ LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+ CPULoongArchState *env = &cpu->env;
+ target_ulong tmp = ldtul_p(mem_buf);
+
+ if (0 <= n && n < 32) {
+ return env->gpr[n] = tmp, sizeof(target_ulong);
+ } else if (n == 32) {
+ return env->pc = tmp, sizeof(target_ulong);
+ }
+ return 0;
+}
+
+static int loongarch_gdb_get_fpu(CPULoongArchState *env,
+ GByteArray *mem_buf, int n)
+{
+ if (0 <= n && n < 32) {
+ return gdb_get_reg64(mem_buf, env->fpr[n]);
+ } else if (32 <= n && n < 40) {
+ return gdb_get_reg8(mem_buf, env->cf[n - 32]);
+ } else if (n == 40) {
+ return gdb_get_reg32(mem_buf, env->fcsr0);
+ }
+ return 0;
+}
+
+static int loongarch_gdb_set_fpu(CPULoongArchState *env,
+ uint8_t *mem_buf, int n)
+{
+ if (0 <= n && n < 32) {
+ return env->fpr[n] = ldq_p(mem_buf), 8;
+ } else if (32 <= n && n < 40) {
+ return env->cf[n - 32] = ldub_p(mem_buf), 1;
+ } else if (n == 40) {
+ return env->fcsr0 = ldl_p(mem_buf), 4;
+ }
+ return 0;
+}
+
+void loongarch_cpu_register_gdb_regs_for_features(CPUState *cs)
+{
+ gdb_register_coprocessor(cs, loongarch_gdb_get_fpu, loongarch_gdb_set_fpu,
+ 41, "loongarch-fpu64.xml", 0);
+}
+
+int loongarch_read_qxfer(CPUState *cs, const char *annex, uint8_t *read_buf,
+ unsigned long offset, unsigned long len)
+{
+ if (strncmp(annex, "cpucfg", sizeof("cpucfg") - 1) == 0) {
+ if (offset % 4 != 0 || len % 4 != 0) {
+ return 0;
+ }
+
+ size_t i;
+ for (i = offset; i < offset + len; i += 4)
+ ((uint32_t *)read_buf)[(i - offset) / 4] =
+ helper_cpucfg(&(LOONGARCH_CPU(cs)->env), i / 4);
+ return 32 * 4;
+ }
+ return 0;
+}
+
+int loongarch_write_qxfer(CPUState *cs, const char *annex,
+ const uint8_t *write_buf, unsigned long offset,
+ unsigned long len)
+{
+ return 0;
+}
diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h
index 92f0a9aa5b..e3fa3d951f 100644
--- a/target/loongarch/internals.h
+++ b/target/loongarch/internals.h
@@ -42,5 +42,15 @@ bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
hwaddr loongarch_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
#endif
+int loongarch_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n);
+int loongarch_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n);
+int loongarch_read_qxfer(CPUState *cs, const char *annex,
+ uint8_t *read_buf,
+ unsigned long offset, unsigned long len);
+int loongarch_write_qxfer(CPUState *cs, const char *annex,
+ const uint8_t *write_buf,
+ unsigned long offset, unsigned long len);
+
+void loongarch_cpu_register_gdb_regs_for_features(CPUState *cs);
#endif
diff --git a/target/loongarch/meson.build b/target/loongarch/meson.build
index 072684ca6d..4fb0c96e52 100644
--- a/target/loongarch/meson.build
+++ b/target/loongarch/meson.build
@@ -11,6 +11,7 @@ loongarch_tcg_ss.add(files(
'fpu_helper.c',
'op_helper.c',
'translate.c',
+ 'gdbstub.c',
))
loongarch_tcg_ss.add(zlib)
--
2.31.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [RFC PATCH v7 14/29] hw/loongarch: Add support loongson3 virt machine type.
2022-03-28 12:57 [RFC PATCH v7 00/29] Add LoongArch softmmu support Xiaojuan Yang
` (12 preceding siblings ...)
2022-03-28 12:57 ` [RFC PATCH v7 13/29] target/loongarch: Add gdb support Xiaojuan Yang
@ 2022-03-28 12:57 ` Xiaojuan Yang
2022-03-28 20:49 ` Richard Henderson
2022-03-28 12:57 ` [RFC PATCH v7 15/29] hw/loongarch: Add LoongArch cpu interrupt support(CPUINTC) Xiaojuan Yang
` (15 subsequent siblings)
29 siblings, 1 reply; 71+ messages in thread
From: Xiaojuan Yang @ 2022-03-28 12:57 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland, richard.henderson, Song Gao
Emulate a 3A5000 board use the new loongarch instruction.
3A5000 belongs to the Loongson3 series processors.
The board consists of a 3A5000 cpu model and the virt
bridge. The host 3A5000 board is really complicated and
contains many functions.Now for the tcg softmmu mode
only part functions are emulated.
More detailed info you can see
https://github.com/loongson/LoongArch-Documentation
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
MAINTAINERS | 3 +
.../devices/loongarch64-softmmu/default.mak | 3 +
configs/targets/loongarch64-softmmu.mak | 3 +
hw/Kconfig | 1 +
hw/loongarch/Kconfig | 4 +
hw/loongarch/loongson3.c | 158 ++++++++++++++++++
hw/loongarch/meson.build | 4 +
hw/meson.build | 1 +
include/exec/poison.h | 2 +
include/hw/loongarch/loongarch.h | 51 ++++++
include/sysemu/arch_init.h | 1 +
qapi/machine.json | 2 +-
target/Kconfig | 1 +
target/loongarch/Kconfig | 2 +
target/loongarch/cpu.h | 3 +
15 files changed, 238 insertions(+), 1 deletion(-)
create mode 100644 configs/devices/loongarch64-softmmu/default.mak
create mode 100644 hw/loongarch/Kconfig
create mode 100644 hw/loongarch/loongson3.c
create mode 100644 hw/loongarch/meson.build
create mode 100644 include/hw/loongarch/loongarch.h
create mode 100644 target/loongarch/Kconfig
diff --git a/MAINTAINERS b/MAINTAINERS
index 83517a750b..a794f41913 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1129,7 +1129,10 @@ M: Song Gao <gaosong@loongson.cn>
S: Maintained
F: docs/system/loongarch/loongson3.rst
F: configs/targets/loongarch64-softmmu.mak
+F: configs/devices/loongarch64-softmmu/default.mak
F: gdb-xml/loongarch*.xml
+F: hw/loongarch/
+F: include/hw/loongarch/loongarch.h
M68K Machines
-------------
diff --git a/configs/devices/loongarch64-softmmu/default.mak b/configs/devices/loongarch64-softmmu/default.mak
new file mode 100644
index 0000000000..928bc117ef
--- /dev/null
+++ b/configs/devices/loongarch64-softmmu/default.mak
@@ -0,0 +1,3 @@
+# Default configuration for loongarch64-softmmu
+
+CONFIG_LOONGARCH_VIRT=y
diff --git a/configs/targets/loongarch64-softmmu.mak b/configs/targets/loongarch64-softmmu.mak
index f33fa1590b..7bc06c850c 100644
--- a/configs/targets/loongarch64-softmmu.mak
+++ b/configs/targets/loongarch64-softmmu.mak
@@ -1 +1,4 @@
+TARGET_ARCH=loongarch64
+TARGET_BASE_ARCH=loongarch
+TARGET_SUPPORTS_MTTCG=y
TARGET_XML_FILES= gdb-xml/loongarch-base64.xml gdb-xml/loongarch-fpu64.xml
diff --git a/hw/Kconfig b/hw/Kconfig
index ad20cce0a9..f71b2155ed 100644
--- a/hw/Kconfig
+++ b/hw/Kconfig
@@ -49,6 +49,7 @@ source avr/Kconfig
source cris/Kconfig
source hppa/Kconfig
source i386/Kconfig
+source loongarch/Kconfig
source m68k/Kconfig
source microblaze/Kconfig
source mips/Kconfig
diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
new file mode 100644
index 0000000000..13e8501897
--- /dev/null
+++ b/hw/loongarch/Kconfig
@@ -0,0 +1,4 @@
+config LOONGARCH_VIRT
+ bool
+ select PCI
+ select PCI_EXPRESS_GENERIC_BRIDGE
diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
new file mode 100644
index 0000000000..1cb7bf057c
--- /dev/null
+++ b/hw/loongarch/loongson3.c
@@ -0,0 +1,158 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * QEMU loongson 3a5000 develop board emulation
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ */
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "qemu/units.h"
+#include "qemu/datadir.h"
+#include "qapi/error.h"
+#include "hw/boards.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/qtest.h"
+#include "sysemu/runstate.h"
+#include "sysemu/reset.h"
+#include "sysemu/rtc.h"
+#include "hw/loongarch/loongarch.h"
+
+#include "target/loongarch/cpu.h"
+
+static void loongarch_cpu_reset(void *opaque)
+{
+ LoongArchCPU *cpu = opaque;
+
+ cpu_reset(CPU(cpu));
+}
+
+static void loongarch_qemu_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size)
+{
+}
+
+static uint64_t loongarch_qemu_read(void *opaque, hwaddr addr, unsigned size)
+{
+ uint64_t feature = 0UL;
+
+ switch (addr) {
+ case FEATURE_REG:
+ feature |= 1UL << IOCSRF_MSI | 1UL << IOCSRF_EXTIOI |
+ 1UL << IOCSRF_CSRIPI;
+ return feature ;
+ case VENDOR_REG:
+ return *(uint64_t *)"Loongson";
+ case CPUNAME_REG:
+ return *(uint64_t *)"3A5000";
+ case MISC_FUNC_REG:
+ return 1UL << IOCSRM_EXTIOI_EN;
+ }
+ return 0;
+}
+
+static const MemoryRegionOps loongarch_qemu_ops = {
+ .read = loongarch_qemu_read,
+ .write = loongarch_qemu_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 8,
+ },
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 8,
+ },
+};
+
+static void loongarch_cpu_init(LoongArchCPU *la_cpu, int cpu_num)
+{
+ CPULoongArchState *env;
+ env = &la_cpu->env;
+
+ memory_region_init_io(&env->system_iocsr, OBJECT(la_cpu), NULL,
+ env, "iocsr", UINT64_MAX);
+ address_space_init(&env->address_space_iocsr, &env->system_iocsr, "IOCSR");
+
+ timer_init_ns(&la_cpu->timer, QEMU_CLOCK_VIRTUAL,
+ &loongarch_constant_timer_cb, la_cpu);
+
+ qemu_register_reset(loongarch_cpu_reset, la_cpu);
+
+ memory_region_init_io(&env->iocsr_mem, OBJECT(la_cpu), &loongarch_qemu_ops,
+ NULL, "iocsr_misc", IOCSR_MEM_SIZE);
+
+ memory_region_add_subregion(&env->system_iocsr, 0, &env->iocsr_mem);
+}
+
+static void loongarch_init(MachineState *machine)
+{
+ const char *cpu_model = machine->cpu_type;
+ LoongArchCPU *la_cpu;
+ 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);
+ int i;
+
+ if (!cpu_model) {
+ cpu_model = LOONGARCH_CPU_TYPE_NAME("Loongson-3A5000");
+ }
+
+ if (!strstr(cpu_model, "Loongson-3A5000")) {
+ error_report("LoongArch/TCG needs cpu type Loongson-3A5000");
+ exit(1);
+ }
+
+ /* Init CPUs */
+ for (i = 0; i < machine->smp.cpus; i++) {
+ la_cpu = LOONGARCH_CPU(cpu_create(machine->cpu_type));
+ loongarch_cpu_init(la_cpu, i);
+ }
+
+ /* Add memory region */
+ memory_region_init_alias(&lams->lowmem, NULL, "loongarch.lowram",
+ machine->ram, 0, 256 * MiB);
+ memory_region_add_subregion(address_space_mem, offset, &lams->lowmem);
+ offset += 256 * MiB;
+
+ 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);
+ offset += highram_size;
+
+ /* 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);
+}
+
+static void loongarch_class_init(ObjectClass *oc, void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+
+ mc->desc = "Loongson-3A5000 LS7A1000 machine";
+ mc->init = loongarch_init;
+ mc->default_ram_size = 1 * GiB;
+ mc->default_cpu_type = LOONGARCH_CPU_TYPE_NAME("Loongson-3A5000");
+ mc->default_ram_id = "loongarch.ram";
+ mc->max_cpus = LOONGARCH_MAX_VCPUS;
+ mc->is_default = 1;
+ mc->default_kernel_irqchip_split = false;
+ mc->block_default_type = IF_VIRTIO;
+ mc->default_boot_order = "c";
+ mc->no_cdrom = 1;
+}
+
+static const TypeInfo loongarch_machine_types[] = {
+ {
+ .name = TYPE_LOONGARCH_MACHINE,
+ .parent = TYPE_MACHINE,
+ .instance_size = sizeof(LoongArchMachineState),
+ .class_init = loongarch_class_init,
+ }
+};
+
+DEFINE_TYPES(loongarch_machine_types)
diff --git a/hw/loongarch/meson.build b/hw/loongarch/meson.build
new file mode 100644
index 0000000000..cecb1a5d65
--- /dev/null
+++ b/hw/loongarch/meson.build
@@ -0,0 +1,4 @@
+loongarch_ss = ss.source_set()
+loongarch_ss.add(when: 'CONFIG_LOONGARCH_VIRT', if_true: files('loongson3.c'))
+
+hw_arch += {'loongarch': loongarch_ss}
diff --git a/hw/meson.build b/hw/meson.build
index b3366c888e..95202649b7 100644
--- a/hw/meson.build
+++ b/hw/meson.build
@@ -49,6 +49,7 @@ subdir('avr')
subdir('cris')
subdir('hppa')
subdir('i386')
+subdir('loongarch')
subdir('m68k')
subdir('microblaze')
subdir('mips')
diff --git a/include/exec/poison.h b/include/exec/poison.h
index 7c5c02f03f..c2583d5572 100644
--- a/include/exec/poison.h
+++ b/include/exec/poison.h
@@ -14,6 +14,7 @@
#pragma GCC poison TARGET_CRIS
#pragma GCC poison TARGET_HEXAGON
#pragma GCC poison TARGET_HPPA
+#pragma GCC poison TARGET_LOONGARCH64
#pragma GCC poison TARGET_M68K
#pragma GCC poison TARGET_MICROBLAZE
#pragma GCC poison TARGET_MIPS
@@ -71,6 +72,7 @@
#pragma GCC poison CONFIG_HPPA_DIS
#pragma GCC poison CONFIG_I386_DIS
#pragma GCC poison CONFIG_HEXAGON_DIS
+#pragma GCC poison CONFIG_LOONGARCH_DIS
#pragma GCC poison CONFIG_M68K_DIS
#pragma GCC poison CONFIG_MICROBLAZE_DIS
#pragma GCC poison CONFIG_MIPS_DIS
diff --git a/include/hw/loongarch/loongarch.h b/include/hw/loongarch/loongarch.h
new file mode 100644
index 0000000000..ffe10edc65
--- /dev/null
+++ b/include/hw/loongarch/loongarch.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Definitions for loongarch board emulation.
+ *
+ * Copyright (C) 2021 Loongson Technology Corporation Limited
+ */
+
+#ifndef HW_LOONGARCH_H
+#define HW_LOONGARCH_H
+
+#include "target/loongarch/cpu.h"
+#include "qemu-common.h"
+#include "hw/boards.h"
+#include "qemu/queue.h"
+
+#define LOONGARCH_MAX_VCPUS 4
+
+#define FEATURE_REG 0x8
+#define IOCSRF_TEMP 0
+#define IOCSRF_NODECNT 1
+#define IOCSRF_MSI 2
+#define IOCSRF_EXTIOI 3
+#define IOCSRF_CSRIPI 4
+#define IOCSRF_FREQCSR 5
+#define IOCSRF_FREQSCALE 6
+#define IOCSRF_DVFSV1 7
+#define IOCSRF_GMOD 9
+#define IOCSRF_VM 11
+
+#define IOCSR_MEM_SIZE 0x428
+
+#define VENDOR_REG 0x10
+#define CPUNAME_REG 0x20
+#define MISC_FUNC_REG 0x420
+#define IOCSRM_EXTIOI_EN 48
+
+#define LOONGARCH_ISA_IO_BASE 0x18000000UL
+#define LOONGARCH_ISA_IO_SIZE 0x0004000
+
+struct LoongArchMachineState {
+ /*< private >*/
+ MachineState parent_obj;
+
+ MemoryRegion lowmem;
+ MemoryRegion highmem;
+ MemoryRegion isa_io;
+};
+
+#define TYPE_LOONGARCH_MACHINE MACHINE_TYPE_NAME("virt")
+OBJECT_DECLARE_SIMPLE_TYPE(LoongArchMachineState, LOONGARCH_MACHINE)
+#endif
diff --git a/include/sysemu/arch_init.h b/include/sysemu/arch_init.h
index 79c2591425..8850cb1a14 100644
--- a/include/sysemu/arch_init.h
+++ b/include/sysemu/arch_init.h
@@ -24,6 +24,7 @@ enum {
QEMU_ARCH_RX = (1 << 20),
QEMU_ARCH_AVR = (1 << 21),
QEMU_ARCH_HEXAGON = (1 << 22),
+ QEMU_ARCH_LOONGARCH = (1 << 23),
};
extern const uint32_t arch_type;
diff --git a/qapi/machine.json b/qapi/machine.json
index 42fc68403d..52a6b08ebe 100644
--- a/qapi/machine.json
+++ b/qapi/machine.json
@@ -30,7 +30,7 @@
##
{ 'enum' : 'SysEmuTarget',
'data' : [ 'aarch64', 'alpha', 'arm', 'avr', 'cris', 'hppa', 'i386',
- 'm68k', 'microblaze', 'microblazeel', 'mips', 'mips64',
+ 'loongarch64', 'm68k', 'microblaze', 'microblazeel', 'mips', 'mips64',
'mips64el', 'mipsel', 'nios2', 'or1k', 'ppc',
'ppc64', 'riscv32', 'riscv64', 'rx', 's390x', 'sh4',
'sh4eb', 'sparc', 'sparc64', 'tricore',
diff --git a/target/Kconfig b/target/Kconfig
index ae7f24fc66..83da0bd293 100644
--- a/target/Kconfig
+++ b/target/Kconfig
@@ -4,6 +4,7 @@ source avr/Kconfig
source cris/Kconfig
source hppa/Kconfig
source i386/Kconfig
+source loongarch/Kconfig
source m68k/Kconfig
source microblaze/Kconfig
source mips/Kconfig
diff --git a/target/loongarch/Kconfig b/target/loongarch/Kconfig
new file mode 100644
index 0000000000..46b26b1a85
--- /dev/null
+++ b/target/loongarch/Kconfig
@@ -0,0 +1,2 @@
+config LOONGARCH64
+ bool
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index 29f0024b1f..15ea1dc43d 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -13,6 +13,8 @@
#include "hw/registerfields.h"
#include "cpu-csr.h"
#include "qemu/timer.h"
+#include "exec/memory.h"
+#include "hw/sysbus.h"
#define TCG_GUEST_DEFAULT_MO (0)
@@ -252,6 +254,7 @@ typedef struct CPUArchState {
AddressSpace address_space_iocsr;
MemoryRegion system_iocsr;
+ MemoryRegion iocsr_mem;
#endif
} CPULoongArchState;
--
2.31.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [RFC PATCH v7 15/29] hw/loongarch: Add LoongArch cpu interrupt support(CPUINTC)
2022-03-28 12:57 [RFC PATCH v7 00/29] Add LoongArch softmmu support Xiaojuan Yang
` (13 preceding siblings ...)
2022-03-28 12:57 ` [RFC PATCH v7 14/29] hw/loongarch: Add support loongson3 virt machine type Xiaojuan Yang
@ 2022-03-28 12:57 ` Xiaojuan Yang
2022-03-28 20:57 ` Richard Henderson
2022-03-28 12:57 ` [RFC PATCH v7 16/29] hw/loongarch: Add LoongArch ipi interrupt support(IPI) Xiaojuan Yang
` (14 subsequent siblings)
29 siblings, 1 reply; 71+ messages in thread
From: Xiaojuan Yang @ 2022-03-28 12:57 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland, richard.henderson, Song Gao
Loongson-3A5000 support 14 interrupts from 64 - 77(Timer->75 IPI->76)
Loongson-3A5000 and ls7a form a legacy model and extended model irq
hierarchy.Tcg mode emulate a simplified extended model which
has no Legacy I/O Interrupt Controller(LIOINTC) and LPC.
e.g:
| +-----+ +---------+ +-------+ |
| | IPI |--> | CPUINTC | <-- | Timer | |
| +-----+ +---------+ +-------+ |
| ^ |
| | |
| +---------+
| | EIOINTC |
| +---------+
| ^ ^ |
| | | |
| +---------+ +---------+ |
| | PCH-PIC | | PCH-MSI | |
| +---------+ +---------+ |
| ^ ^ ^ |
| | | | |
| +---------+ +---------+ +---------+ |
| | UARTs | | Devices | | Devices | |
| +---------+ +---------+ +---------+ |
| ^ |
The following series patch will realize the interrupt
controller in this model.
More detailed info can be found at the kernel doc or manual
1.https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/
linux-loongson.git/tree/Documentation/loongarch?h=loongarch-next
2.https://github.com/loongson/LoongArch-Documentation
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
hw/loongarch/loongson3.c | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
index 1cb7bf057c..7b4e77a6a6 100644
--- a/hw/loongarch/loongson3.c
+++ b/hw/loongarch/loongson3.c
@@ -19,6 +19,29 @@
#include "target/loongarch/cpu.h"
+static void loongarch_cpu_set_irq(void *opaque, int irq, int level)
+{
+ LoongArchCPU *cpu = opaque;
+ CPULoongArchState *env = &cpu->env;
+ CPUState *cs = CPU(cpu);
+
+ if (irq < 0 || irq > N_IRQS) {
+ return;
+ }
+
+ if (level) {
+ env->CSR_ESTAT |= 1 << irq;
+ } else {
+ env->CSR_ESTAT &= ~(1 << irq);
+ }
+
+ if (FIELD_EX64(env->CSR_ESTAT, CSR_ESTAT, IS)) {
+ cpu_interrupt(cs, CPU_INTERRUPT_HARD);
+ } else {
+ cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
+ }
+}
+
static void loongarch_cpu_reset(void *opaque)
{
LoongArchCPU *cpu = opaque;
@@ -69,6 +92,8 @@ static void loongarch_cpu_init(LoongArchCPU *la_cpu, int cpu_num)
CPULoongArchState *env;
env = &la_cpu->env;
+ qdev_init_gpio_in(DEVICE(la_cpu), loongarch_cpu_set_irq, N_IRQS);
+
memory_region_init_io(&env->system_iocsr, OBJECT(la_cpu), NULL,
env, "iocsr", UINT64_MAX);
address_space_init(&env->address_space_iocsr, &env->system_iocsr, "IOCSR");
--
2.31.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [RFC PATCH v7 16/29] hw/loongarch: Add LoongArch ipi interrupt support(IPI)
2022-03-28 12:57 [RFC PATCH v7 00/29] Add LoongArch softmmu support Xiaojuan Yang
` (14 preceding siblings ...)
2022-03-28 12:57 ` [RFC PATCH v7 15/29] hw/loongarch: Add LoongArch cpu interrupt support(CPUINTC) Xiaojuan Yang
@ 2022-03-28 12:57 ` Xiaojuan Yang
2022-03-28 20:15 ` Mark Cave-Ayland
` (2 more replies)
2022-03-28 12:57 ` [RFC PATCH v7 17/29] hw/intc: Add LoongArch ls7a interrupt controller support(PCH-PIC) Xiaojuan Yang
` (13 subsequent siblings)
29 siblings, 3 replies; 71+ messages in thread
From: Xiaojuan Yang @ 2022-03-28 12:57 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland, richard.henderson, Song Gao
This patch realize the IPI interrupt controller.
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
MAINTAINERS | 2 +
hw/intc/Kconfig | 3 +
hw/intc/loongarch_ipi.c | 164 ++++++++++++++++++++++++++++++++
hw/intc/meson.build | 1 +
hw/intc/trace-events | 4 +
hw/loongarch/Kconfig | 1 +
include/hw/intc/loongarch_ipi.h | 47 +++++++++
7 files changed, 222 insertions(+)
create mode 100644 hw/intc/loongarch_ipi.c
create mode 100644 include/hw/intc/loongarch_ipi.h
diff --git a/MAINTAINERS b/MAINTAINERS
index a794f41913..d83b90b5c5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1133,6 +1133,8 @@ F: configs/devices/loongarch64-softmmu/default.mak
F: gdb-xml/loongarch*.xml
F: hw/loongarch/
F: include/hw/loongarch/loongarch.h
+F: include/hw/intc/loongarch_*.h
+F: hw/intc/loongarch_*.c
M68K Machines
-------------
diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
index a7cf301eab..6c7e82da64 100644
--- a/hw/intc/Kconfig
+++ b/hw/intc/Kconfig
@@ -84,3 +84,6 @@ config GOLDFISH_PIC
config M68K_IRQC
bool
+
+config LOONGARCH_IPI
+ bool
diff --git a/hw/intc/loongarch_ipi.c b/hw/intc/loongarch_ipi.c
new file mode 100644
index 0000000000..89e9019112
--- /dev/null
+++ b/hw/intc/loongarch_ipi.c
@@ -0,0 +1,164 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * LoongArch ipi interrupt support
+ *
+ * Copyright (C) 2021 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "hw/sysbus.h"
+#include "hw/intc/loongarch_ipi.h"
+#include "hw/irq.h"
+#include "qapi/error.h"
+#include "qemu/log.h"
+#include "exec/address-spaces.h"
+#include "hw/loongarch/loongarch.h"
+#include "migration/vmstate.h"
+#include "trace.h"
+
+static uint64_t loongarch_ipi_readl(void *opaque, hwaddr addr, unsigned size)
+{
+ IPICore *s = opaque;
+ uint64_t ret = 0;
+ int index = 0;
+
+ addr &= 0xff;
+ switch (addr) {
+ case CORE_STATUS_OFF:
+ ret = s->status;
+ break;
+ case CORE_EN_OFF:
+ ret = s->en;
+ break;
+ case CORE_SET_OFF:
+ ret = 0;
+ break;
+ case CORE_CLEAR_OFF:
+ ret = 0;
+ break;
+ case CORE_BUF_20 ... CORE_BUF_38 + 4:
+ index = (addr - CORE_BUF_20) >> 2;
+ ret = s->buf[index];
+ break;
+ case IOCSR_IPI_SEND:
+ ret = s->status;
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP, "invalid read: %x", (uint32_t)addr);
+ break;
+ }
+
+ trace_loongarch_ipi_read(size, (uint64_t)addr, ret);
+ return ret;
+}
+
+static void loongarch_ipi_writel(void *opaque, hwaddr addr, uint64_t val,
+ unsigned size)
+{
+ IPICore *s = opaque;
+ int index = 0;
+
+ addr &= 0xff;
+ trace_loongarch_ipi_write(size, (uint64_t)addr, val);
+ switch (addr) {
+ case CORE_STATUS_OFF:
+ qemu_log_mask(LOG_GUEST_ERROR, "can not be written");
+ break;
+ case CORE_EN_OFF:
+ s->en = val;
+ break;
+ case CORE_SET_OFF:
+ s->status |= val;
+ if (s->status != 0) {
+ qemu_irq_raise(s->irq);
+ }
+ break;
+ case CORE_CLEAR_OFF:
+ s->status ^= val;
+ if (s->status == 0) {
+ qemu_irq_lower(s->irq);
+ }
+ break;
+ case CORE_BUF_20 ... CORE_BUF_38 + 4:
+ index = (addr - CORE_BUF_20) >> 2;
+ s->buf[index] = val;
+ break;
+ case IOCSR_IPI_SEND:
+ s->status |= val;
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP, "invalid write: %x", (uint32_t)addr);
+ break;
+ }
+}
+
+static const MemoryRegionOps loongarch_ipi_ops = {
+ .read = loongarch_ipi_readl,
+ .write = loongarch_ipi_writel,
+ .impl.min_access_size = 4,
+ .impl.max_access_size = 4,
+ .valid.min_access_size = 4,
+ .valid.max_access_size = 8,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void loongarch_ipi_init(Object *obj)
+{
+ LoongArchIPI *s = LOONGARCH_IPI(obj);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+ int cpu;
+
+ for (cpu = 0; cpu < MAX_IPI_CORE_NUM; cpu++) {
+ memory_region_init_io(&s->ipi_mmio[cpu], obj, &loongarch_ipi_ops,
+ &s->core[cpu], "loongarch_ipi", 0x100);
+ sysbus_init_mmio(sbd, &s->ipi_mmio[cpu]);
+ qdev_init_gpio_out(DEVICE(obj), &s->core[cpu].irq, 1);
+ }
+}
+
+static const VMStateDescription vmstate_ipi_core = {
+ .name = "ipi-single",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(status, IPICore),
+ VMSTATE_UINT32(en, IPICore),
+ VMSTATE_UINT32(set, IPICore),
+ VMSTATE_UINT32(clear, IPICore),
+ VMSTATE_UINT32_ARRAY(buf, IPICore, MAX_IPI_MBX_NUM * 2),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_loongarch_ipi = {
+ .name = TYPE_LOONGARCH_IPI,
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_STRUCT_ARRAY(core, LoongArchIPI, MAX_IPI_CORE_NUM, 0,
+ vmstate_ipi_core, IPICore),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void loongarch_ipi_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->vmsd = &vmstate_loongarch_ipi;
+}
+
+static const TypeInfo loongarch_ipi_info = {
+ .name = TYPE_LOONGARCH_IPI,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(LoongArchIPI),
+ .instance_init = loongarch_ipi_init,
+ .class_init = loongarch_ipi_class_init,
+};
+
+static void loongarch_ipi_register_types(void)
+{
+ type_register_static(&loongarch_ipi_info);
+}
+
+type_init(loongarch_ipi_register_types)
diff --git a/hw/intc/meson.build b/hw/intc/meson.build
index d6d012fb26..bf5ab44a78 100644
--- a/hw/intc/meson.build
+++ b/hw/intc/meson.build
@@ -62,3 +62,4 @@ specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XIVE'],
if_true: files('spapr_xive_kvm.c'))
specific_ss.add(when: 'CONFIG_GOLDFISH_PIC', if_true: files('goldfish_pic.c'))
specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c'))
+specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c'))
diff --git a/hw/intc/trace-events b/hw/intc/trace-events
index 53414aa197..6ae8917d99 100644
--- a/hw/intc/trace-events
+++ b/hw/intc/trace-events
@@ -275,3 +275,7 @@ sh_intc_register(const char *s, int id, unsigned short v, int c, int m) "%s %u -
sh_intc_read(unsigned size, uint64_t offset, unsigned long val) "size %u 0x%" PRIx64 " -> 0x%lx"
sh_intc_write(unsigned size, uint64_t offset, unsigned long val) "size %u 0x%" PRIx64 " <- 0x%lx"
sh_intc_set(int id, int enable) "setting interrupt group %d to %d"
+
+# loongarch_ipi.c
+loongarch_ipi_read(unsigned size, uint64_t addr, unsigned long val) "size: %u addr: 0x%"PRIx64 "val: 0x%"PRIx64
+loongarch_ipi_write(unsigned size, uint64_t addr, unsigned long val) "size: %u addr: 0x%"PRIx64 "val: 0x%"PRIx64
diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
index 13e8501897..f0dad3329a 100644
--- a/hw/loongarch/Kconfig
+++ b/hw/loongarch/Kconfig
@@ -2,3 +2,4 @@ config LOONGARCH_VIRT
bool
select PCI
select PCI_EXPRESS_GENERIC_BRIDGE
+ select LOONGARCH_IPI
diff --git a/include/hw/intc/loongarch_ipi.h b/include/hw/intc/loongarch_ipi.h
new file mode 100644
index 0000000000..0f3bca8a79
--- /dev/null
+++ b/include/hw/intc/loongarch_ipi.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * LoongArch ipi interrupt header files
+ *
+ * Copyright (C) 2021 Loongson Technology Corporation Limited
+ */
+
+#ifndef HW_LOONGARCH_IPI_H
+#define HW_LOONGARCH_IPI_H
+
+#include "hw/sysbus.h"
+
+/* Mainy used by iocsr read and write */
+#define SMP_IPI_MAILBOX 0x1000ULL
+#define CORE_STATUS_OFF 0x0
+#define CORE_EN_OFF 0x4
+#define CORE_SET_OFF 0x8
+#define CORE_CLEAR_OFF 0xc
+#define CORE_BUF_20 0x20
+#define CORE_BUF_28 0x28
+#define CORE_BUF_30 0x30
+#define CORE_BUF_38 0x38
+#define IOCSR_IPI_SEND 0x40
+
+#define MAX_IPI_CORE_NUM 16
+#define MAX_IPI_MBX_NUM 4
+
+#define TYPE_LOONGARCH_IPI "loongarch_ipi"
+OBJECT_DECLARE_SIMPLE_TYPE(LoongArchIPI, LOONGARCH_IPI)
+
+typedef struct IPICore {
+ uint32_t status;
+ uint32_t en;
+ uint32_t set;
+ uint32_t clear;
+ /* 64bit buf divide into 2 32bit buf */
+ uint32_t buf[MAX_IPI_MBX_NUM * 2];
+ qemu_irq irq;
+} IPICore;
+
+typedef struct LoongArchIPI {
+ SysBusDevice parent_obj;
+ IPICore core[MAX_IPI_CORE_NUM];
+ MemoryRegion ipi_mmio[MAX_IPI_CORE_NUM];
+} LoongArchIPI;
+
+#endif
--
2.31.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [RFC PATCH v7 17/29] hw/intc: Add LoongArch ls7a interrupt controller support(PCH-PIC)
2022-03-28 12:57 [RFC PATCH v7 00/29] Add LoongArch softmmu support Xiaojuan Yang
` (15 preceding siblings ...)
2022-03-28 12:57 ` [RFC PATCH v7 16/29] hw/loongarch: Add LoongArch ipi interrupt support(IPI) Xiaojuan Yang
@ 2022-03-28 12:57 ` Xiaojuan Yang
2022-03-28 20:18 ` Mark Cave-Ayland
2022-03-28 12:57 ` [RFC PATCH v7 18/29] hw/intc: Add LoongArch ls7a msi interrupt controller support(PCH-MSI) Xiaojuan Yang
` (12 subsequent siblings)
29 siblings, 1 reply; 71+ messages in thread
From: Xiaojuan Yang @ 2022-03-28 12:57 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland, richard.henderson, Song Gao
This patch realize the PCH-PIC interrupt controller.
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
hw/intc/Kconfig | 4 +
hw/intc/loongarch_pch_pic.c | 488 ++++++++++++++++++++++++++++
hw/intc/meson.build | 1 +
hw/intc/trace-events | 9 +
hw/loongarch/Kconfig | 1 +
include/hw/intc/loongarch_pch_pic.h | 80 +++++
6 files changed, 583 insertions(+)
create mode 100644 hw/intc/loongarch_pch_pic.c
create mode 100644 include/hw/intc/loongarch_pch_pic.h
diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
index 6c7e82da64..1fbba2e728 100644
--- a/hw/intc/Kconfig
+++ b/hw/intc/Kconfig
@@ -87,3 +87,7 @@ config M68K_IRQC
config LOONGARCH_IPI
bool
+
+config LOONGARCH_PCH_PIC
+ bool
+ select UNIMP
diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c
new file mode 100644
index 0000000000..04b9bdce36
--- /dev/null
+++ b/hw/intc/loongarch_pch_pic.c
@@ -0,0 +1,488 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * QEMU Loongson 7A1000 I/O interrupt controller.
+ *
+ * Copyright (C) 2021 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "hw/sysbus.h"
+#include "hw/loongarch/loongarch.h"
+#include "hw/irq.h"
+#include "hw/intc/loongarch_pch_pic.h"
+#include "migration/vmstate.h"
+#include "trace.h"
+
+static void pch_pic_update_irq(LoongArchPCHPIC *s, uint32_t mask,
+ int level, int hi)
+{
+ uint32_t val, irq;
+
+ if (level == 1) {
+ if (hi) {
+ val = mask & s->intirr_hi & (~s->int_mask_hi);
+ irq = find_first_bit((void *)&val, 32);
+ if (irq != 32) {
+ s->intisr_hi |= 1ULL << irq;
+ qemu_set_irq(s->parent_irq[s->htmsi_vector[irq + 32]], 1);
+ }
+ } else {
+ val = mask & s->intirr_lo & (~s->int_mask_lo);
+ irq = find_first_bit((void *)&val, 32);
+ if (irq != 32) {
+ s->intisr_lo |= 1ULL << irq;
+ qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 1);
+ }
+ }
+ } else {
+ if (hi) {
+ val = mask & s->intisr_hi;
+ irq = find_first_bit((void *)&val, 32);
+ if (irq != 32) {
+ s->intisr_hi &= ~(0x1ULL << irq);
+ qemu_set_irq(s->parent_irq[s->htmsi_vector[irq + 32]], 0);
+ }
+ } else {
+ val = mask & s->intisr_lo;
+ irq = find_first_bit((void *)&val, 32);
+ if (irq != 32) {
+ s->intisr_lo &= ~(0x1ULL << irq);
+ qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 0);
+ }
+ }
+ }
+}
+
+static void pch_pic_irq_handler(void *opaque, int irq, int level)
+{
+ LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
+ int hi = 0;
+ uint32_t mask;
+
+ assert(irq < PCH_PIC_IRQ_NUM);
+ trace_pch_pic_irq_handler(irq, level);
+
+ hi = (irq >= 32) ? 1 : 0;
+ if (hi) {
+ irq = irq - 32;
+ }
+
+ mask = 1ULL << irq;
+
+ if (hi) {
+ if (s->intedge_hi & mask) {
+ /* Edge triggered */
+ if (level) {
+ if ((s->last_intirr_hi & mask) == 0) {
+ s->intirr_hi |= mask;
+ }
+ s->last_intirr_hi |= mask;
+ } else {
+ s->last_intirr_hi &= ~mask;
+ }
+ } else {
+ /* Level triggered */
+ if (level) {
+ s->intirr_hi |= mask;
+ s->last_intirr_hi |= mask;
+ } else {
+ s->intirr_hi &= ~mask;
+ s->last_intirr_hi &= ~mask;
+ }
+ }
+ } else {
+ if (s->intedge_lo & mask) {
+ /* Edge triggered */
+ if (level) {
+ if ((s->last_intirr_lo & mask) == 0) {
+ s->intirr_lo |= mask;
+ }
+ s->last_intirr_lo |= mask;
+ } else {
+ s->last_intirr_lo &= ~mask;
+ }
+ } else {
+ /* Level triggered */
+ if (level) {
+ s->intirr_lo |= mask;
+ s->last_intirr_lo |= mask;
+ } else {
+ s->intirr_lo &= ~mask;
+ s->last_intirr_lo &= ~mask;
+ }
+
+ }
+ }
+ pch_pic_update_irq(s, mask, level, hi);
+}
+
+static uint64_t loongarch_pch_pic_low_readw(void *opaque, hwaddr addr,
+ unsigned size)
+{
+ LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
+ uint64_t val = 0;
+ uint32_t offset = addr & 0xfff;
+
+ switch (offset) {
+ case PCH_PIC_INT_ID_LO:
+ val = PCH_PIC_INT_ID_VAL;
+ break;
+ case PCH_PIC_INT_ID_HI:
+ val = PCH_PIC_INT_ID_NUM;
+ break;
+ case PCH_PIC_INT_MASK_LO:
+ val = s->int_mask_lo;
+ break;
+ case PCH_PIC_INT_MASK_HI:
+ val = s->int_mask_hi;
+ break;
+ case PCH_PIC_INT_EDGE_LO:
+ val = s->intedge_lo;
+ break;
+ case PCH_PIC_INT_EDGE_HI:
+ val = s->intedge_hi;
+ break;
+ case PCH_PIC_HTMSI_EN_LO:
+ val = s->htmsi_en_lo;
+ break;
+ case PCH_PIC_HTMSI_EN_HI:
+ val = s->htmsi_en_hi;
+ break;
+ case PCH_PIC_AUTO_CTRL0_LO:
+ case PCH_PIC_AUTO_CTRL0_HI:
+ case PCH_PIC_AUTO_CTRL1_LO:
+ case PCH_PIC_AUTO_CTRL1_HI:
+ break;
+ default:
+ break;
+ }
+
+ trace_loongarch_pch_pic_low_readw(size, (uint32_t)addr, val);
+ return val;
+}
+
+static void loongarch_pch_pic_low_writew(void *opaque, hwaddr addr,
+ uint64_t data, unsigned size)
+{
+ LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
+ uint32_t offset, old;
+ offset = addr & 0xfff;
+
+ trace_loongarch_pch_pic_low_writew(size, (uint32_t)addr, data);
+
+ switch (offset) {
+ case PCH_PIC_INT_MASK_LO:
+ old = s->int_mask_lo;
+ s->int_mask_lo = data;
+ if (old & ~data) {
+ pch_pic_update_irq(s, (old & ~data), 1, 0);
+ } else if (~old & data) {
+ pch_pic_update_irq(s, (~old & data), 0, 0);
+ }
+ break;
+ case PCH_PIC_INT_MASK_HI:
+ old = s->int_mask_hi;
+ s->int_mask_hi = data;
+ if (old & ~data) {
+ pch_pic_update_irq(s, (old & ~data), 1, 1);
+ } else if (~old & data) {
+ pch_pic_update_irq(s, (~old & data), 0, 1);
+ }
+ break;
+ case PCH_PIC_INT_EDGE_LO:
+ s->intedge_lo = data;
+ break;
+ case PCH_PIC_INT_EDGE_HI:
+ s->intedge_hi = data;
+ break;
+ case PCH_PIC_INT_CLEAR_LO:
+ if (s->intedge_lo & data) {
+ s->intirr_lo &= (~data);
+ pch_pic_update_irq(s, data, 0, 0);
+ s->intisr_lo &= (~data);
+ }
+ break;
+ case PCH_PIC_INT_CLEAR_HI:
+ if (s->intedge_hi & data) {
+ s->intirr_hi &= (~data);
+ pch_pic_update_irq(s, data, 0, 1);
+ s->intisr_hi &= (~data);
+ }
+ break;
+ case PCH_PIC_HTMSI_EN_LO:
+ s->htmsi_en_lo = data;
+ break;
+ case PCH_PIC_HTMSI_EN_HI:
+ s->htmsi_en_hi = data;
+ break;
+ case PCH_PIC_AUTO_CTRL0_LO:
+ case PCH_PIC_AUTO_CTRL0_HI:
+ case PCH_PIC_AUTO_CTRL1_LO:
+ case PCH_PIC_AUTO_CTRL1_HI:
+ break;
+ default:
+ break;
+ }
+}
+
+static uint64_t loongarch_pch_pic_high_readw(void *opaque, hwaddr addr,
+ unsigned size)
+{
+ LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
+ uint64_t val = 0;
+ uint32_t offset = addr & 0xfff;
+
+ switch (offset) {
+ case STATUS_LO_START:
+ val = s->intisr_lo & (~s->int_mask_lo);
+ break;
+ case STATUS_HI_START:
+ val = s->intisr_hi & (~s->int_mask_hi);
+ break;
+ case POL_LO_START:
+ val = s->int_polarity_lo;
+ break;
+ case POL_HI_START:
+ val = s->int_polarity_hi;
+ break;
+ default:
+ break;
+ }
+
+ trace_loongarch_pch_pic_high_readw(size, (uint32_t)addr, val);
+ return val;
+}
+
+static void loongarch_pch_pic_high_writew(void *opaque, hwaddr addr,
+ uint64_t data, unsigned size)
+{
+ LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
+ uint32_t offset;
+ offset = addr & 0xfff;
+
+ trace_loongarch_pch_pic_high_writew(size, (uint32_t)addr, data);
+
+ switch (offset) {
+ case STATUS_LO_START:
+ s->intisr_lo = data;
+ break;
+ case STATUS_HI_START:
+ s->intisr_hi = data;
+ break;
+ case POL_LO_START:
+ s->int_polarity_lo = data;
+ break;
+ case POL_HI_START:
+ s->int_polarity_hi = data;
+ break;
+ default:
+ break;
+ }
+}
+
+static uint64_t loongarch_pch_pic_readb(void *opaque, hwaddr addr,
+ unsigned size)
+{
+ LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
+ uint64_t val = 0;
+ uint32_t offset = (addr & 0xfff) + PCH_PIC_ROUTE_ENTRY_OFFSET;
+ int64_t offset_tmp;
+
+ switch (offset) {
+ case PCH_PIC_HTMSI_VEC_OFFSET ... PCH_PIC_HTMSI_VEC_END:
+ offset_tmp = offset - PCH_PIC_HTMSI_VEC_OFFSET;
+ if (offset_tmp >= 0 && offset_tmp < 64) {
+ val = s->htmsi_vector[offset_tmp];
+ }
+ break;
+ case PCH_PIC_ROUTE_ENTRY_OFFSET ... PCH_PIC_ROUTE_ENTRY_END:
+ offset_tmp = offset - PCH_PIC_ROUTE_ENTRY_OFFSET;
+ if (offset_tmp >= 0 && offset_tmp < 64) {
+ val = s->route_entry[offset_tmp];
+ }
+ break;
+ default:
+ break;
+ }
+
+ trace_loongarch_pch_pic_readb(size, (uint32_t)addr, val);
+ return val;
+}
+
+static void loongarch_pch_pic_writeb(void *opaque, hwaddr addr,
+ uint64_t data, unsigned size)
+{
+ LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
+ int32_t offset_tmp;
+ uint32_t offset = (addr & 0xfff) + PCH_PIC_ROUTE_ENTRY_OFFSET;
+
+ trace_loongarch_pch_pic_writeb(size, (uint32_t)addr, data);
+
+ switch (offset) {
+ case PCH_PIC_HTMSI_VEC_OFFSET ... PCH_PIC_HTMSI_VEC_END:
+ offset_tmp = offset - PCH_PIC_HTMSI_VEC_OFFSET;
+ if (offset_tmp >= 0 && offset_tmp < 64) {
+ s->htmsi_vector[offset_tmp] = (uint8_t)(data & 0xff);
+ }
+ break;
+ case PCH_PIC_ROUTE_ENTRY_OFFSET ... PCH_PIC_ROUTE_ENTRY_END:
+ offset_tmp = offset - PCH_PIC_ROUTE_ENTRY_OFFSET;
+ if (offset_tmp >= 0 && offset_tmp < 64) {
+ s->route_entry[offset_tmp] = (uint8_t)(data & 0xff);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static const MemoryRegionOps loongarch_pch_pic_reg32_low_ops = {
+ .read = loongarch_pch_pic_low_readw,
+ .write = loongarch_pch_pic_low_writew,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 8,
+ },
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static const MemoryRegionOps loongarch_pch_pic_reg32_high_ops = {
+ .read = loongarch_pch_pic_high_readw,
+ .write = loongarch_pch_pic_high_writew,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 8,
+ },
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static const MemoryRegionOps loongarch_pch_pic_reg8_ops = {
+ .read = loongarch_pch_pic_readb,
+ .write = loongarch_pch_pic_writeb,
+ .valid = {
+ .min_access_size = 1,
+ .max_access_size = 1,
+ },
+ .impl = {
+ .min_access_size = 1,
+ .max_access_size = 1,
+ },
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void loongarch_pch_pic_reset(DeviceState *d)
+{
+ LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(d);
+ int i;
+
+ s->int_mask_lo = -1;
+ s->int_mask_hi = -1;
+ s->htmsi_en_lo = 0x0;
+ s->htmsi_en_hi = 0x0;
+ s->intedge_lo = 0x0;
+ s->intedge_hi = 0x0;
+ s->intclr_lo = 0x0;
+ s->intclr_hi = 0x0;
+ s->auto_crtl0_lo = 0x0;
+ s->auto_crtl0_hi = 0x0;
+ s->auto_crtl1_lo = 0x0;
+ s->auto_crtl1_hi = 0x0;
+ for (i = 0; i < 64; i++) {
+ s->route_entry[i] = 0x1;
+ s->htmsi_vector[i] = 0x0;
+ }
+ s->intirr_lo = 0x0;
+ s->intirr_hi = 0x0;
+ s->intisr_lo = 0x0;
+ s->intisr_hi = 0x0;
+ s->last_intirr_lo = 0x0;
+ s->last_intirr_hi = 0x0;
+ s->int_polarity_lo = 0x0;
+ s->int_polarity_hi = 0x0;
+}
+
+static void loongarch_pch_pic_init(Object *obj)
+{
+ LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(obj);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+ int i;
+
+ memory_region_init_io(&s->iomem32_low, obj,
+ &loongarch_pch_pic_reg32_low_ops,
+ s, PCH_PIC_NAME(.reg32_part1), 0x100);
+ memory_region_init_io(&s->iomem8, obj, &loongarch_pch_pic_reg8_ops,
+ s, PCH_PIC_NAME(.reg8), 0x2a0);
+ memory_region_init_io(&s->iomem32_high, obj,
+ &loongarch_pch_pic_reg32_high_ops,
+ s, PCH_PIC_NAME(.reg32_part2), 0xc60);
+ sysbus_init_mmio(sbd, &s->iomem32_low);
+ sysbus_init_mmio(sbd, &s->iomem8);
+ sysbus_init_mmio(sbd, &s->iomem32_high);
+
+ for (i = 0; i < PCH_PIC_IRQ_NUM; i++) {
+ sysbus_init_irq(sbd, &s->parent_irq[i]);
+ }
+ qdev_init_gpio_in(DEVICE(obj), pch_pic_irq_handler, PCH_PIC_IRQ_NUM);
+}
+
+static const VMStateDescription vmstate_loongarch_pch_pic = {
+ .name = TYPE_LOONGARCH_PCH_PIC,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(int_mask_lo, LoongArchPCHPIC),
+ VMSTATE_UINT32(int_mask_hi, LoongArchPCHPIC),
+ VMSTATE_UINT32(htmsi_en_lo, LoongArchPCHPIC),
+ VMSTATE_UINT32(htmsi_en_hi, LoongArchPCHPIC),
+ VMSTATE_UINT32(intedge_lo, LoongArchPCHPIC),
+ VMSTATE_UINT32(intedge_hi, LoongArchPCHPIC),
+ VMSTATE_UINT32(intclr_lo, LoongArchPCHPIC),
+ VMSTATE_UINT32(intclr_hi, LoongArchPCHPIC),
+ VMSTATE_UINT32(auto_crtl0_lo, LoongArchPCHPIC),
+ VMSTATE_UINT32(auto_crtl0_hi, LoongArchPCHPIC),
+ VMSTATE_UINT32(auto_crtl1_lo, LoongArchPCHPIC),
+ VMSTATE_UINT32(auto_crtl1_hi, LoongArchPCHPIC),
+ VMSTATE_UINT8_ARRAY(route_entry, LoongArchPCHPIC, 64),
+ VMSTATE_UINT8_ARRAY(htmsi_vector, LoongArchPCHPIC, 64),
+ VMSTATE_UINT32(last_intirr_lo, LoongArchPCHPIC),
+ VMSTATE_UINT32(last_intirr_hi, LoongArchPCHPIC),
+ VMSTATE_UINT32(intirr_lo, LoongArchPCHPIC),
+ VMSTATE_UINT32(intirr_hi, LoongArchPCHPIC),
+ VMSTATE_UINT32(intisr_lo, LoongArchPCHPIC),
+ VMSTATE_UINT32(intisr_hi, LoongArchPCHPIC),
+ VMSTATE_UINT32(int_polarity_lo, LoongArchPCHPIC),
+ VMSTATE_UINT32(int_polarity_hi, LoongArchPCHPIC),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void loongarch_pch_pic_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->reset = loongarch_pch_pic_reset;
+ dc->vmsd = &vmstate_loongarch_pch_pic;
+}
+
+static const TypeInfo loongarch_pch_pic_info = {
+ .name = TYPE_LOONGARCH_PCH_PIC,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(LoongArchPCHPIC),
+ .instance_init = loongarch_pch_pic_init,
+ .class_init = loongarch_pch_pic_class_init,
+};
+
+static void loongarch_pch_pic_register_types(void)
+{
+ type_register_static(&loongarch_pch_pic_info);
+}
+
+type_init(loongarch_pch_pic_register_types)
diff --git a/hw/intc/meson.build b/hw/intc/meson.build
index bf5ab44a78..960ce81a92 100644
--- a/hw/intc/meson.build
+++ b/hw/intc/meson.build
@@ -63,3 +63,4 @@ specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XIVE'],
specific_ss.add(when: 'CONFIG_GOLDFISH_PIC', if_true: files('goldfish_pic.c'))
specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c'))
specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c'))
+specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_pic.c'))
diff --git a/hw/intc/trace-events b/hw/intc/trace-events
index 6ae8917d99..8c12bdd89f 100644
--- a/hw/intc/trace-events
+++ b/hw/intc/trace-events
@@ -279,3 +279,12 @@ sh_intc_set(int id, int enable) "setting interrupt group %d to %d"
# loongarch_ipi.c
loongarch_ipi_read(unsigned size, uint64_t addr, unsigned long val) "size: %u addr: 0x%"PRIx64 "val: 0x%"PRIx64
loongarch_ipi_write(unsigned size, uint64_t addr, unsigned long val) "size: %u addr: 0x%"PRIx64 "val: 0x%"PRIx64
+
+# loongarch_pch_pic.c
+pch_pic_irq_handler(int irq, int level) "irq %d level %d"
+loongarch_pch_pic_low_readw(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
+loongarch_pch_pic_low_writew(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
+loongarch_pch_pic_high_readw(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
+loongarch_pch_pic_high_writew(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
+loongarch_pch_pic_readb(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
+loongarch_pch_pic_writeb(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
index f0dad3329a..2df45f7e8f 100644
--- a/hw/loongarch/Kconfig
+++ b/hw/loongarch/Kconfig
@@ -3,3 +3,4 @@ config LOONGARCH_VIRT
select PCI
select PCI_EXPRESS_GENERIC_BRIDGE
select LOONGARCH_IPI
+ select LOONGARCH_PCH_PIC
diff --git a/include/hw/intc/loongarch_pch_pic.h b/include/hw/intc/loongarch_pch_pic.h
new file mode 100644
index 0000000000..8ca044be33
--- /dev/null
+++ b/include/hw/intc/loongarch_pch_pic.h
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * LoongArch 7A1000 I/O interrupt controller definitions
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ */
+
+#define TYPE_LOONGARCH_PCH_PIC "loongarch_pch_pic"
+#define PCH_PIC_NAME(name) TYPE_LOONGARCH_PCH_PIC#name
+OBJECT_DECLARE_SIMPLE_TYPE(LoongArchPCHPIC, LOONGARCH_PCH_PIC)
+
+#define PCH_PIC_IRQ_START 0
+#define PCH_PIC_IRQ_END 63
+#define PCH_PIC_IRQ_NUM 64
+#define PCH_PIC_INT_ID_VAL 0x7000000UL
+#define PCH_PIC_INT_ID_NUM 0x3f0001UL
+
+#define PCH_PIC_INT_ID_LO 0x00
+#define PCH_PIC_INT_ID_HI 0x04
+#define PCH_PIC_INT_MASK_LO 0x20
+#define PCH_PIC_INT_MASK_HI 0x24
+#define PCH_PIC_HTMSI_EN_LO 0x40
+#define PCH_PIC_HTMSI_EN_HI 0x44
+#define PCH_PIC_INT_EDGE_LO 0x60
+#define PCH_PIC_INT_EDGE_HI 0x64
+#define PCH_PIC_INT_CLEAR_LO 0x80
+#define PCH_PIC_INT_CLEAR_HI 0x84
+#define PCH_PIC_AUTO_CTRL0_LO 0xc0
+#define PCH_PIC_AUTO_CTRL0_HI 0xc4
+#define PCH_PIC_AUTO_CTRL1_LO 0xe0
+#define PCH_PIC_AUTO_CTRL1_HI 0xe4
+#define PCH_PIC_ROUTE_ENTRY_OFFSET 0x100
+#define PCH_PIC_ROUTE_ENTRY_END 0x13f
+#define PCH_PIC_HTMSI_VEC_OFFSET 0x200
+#define PCH_PIC_HTMSI_VEC_END 0x23f
+#define PCH_PIC_INT_STATUS_LO 0x3a0
+#define PCH_PIC_INT_STATUS_HI 0x3a4
+#define PCH_PIC_INT_POL_LO 0x3e0
+#define PCH_PIC_INT_POL_HI 0x3e4
+
+#define STATUS_LO_START 0
+#define STATUS_HI_START 0x4
+#define POL_LO_START 0x40
+#define POL_HI_START 0x44
+
+typedef struct LoongArchPCHPIC {
+ SysBusDevice parent_obj;
+ qemu_irq parent_irq[64];
+ uint32_t int_mask_lo; /*0x020 interrupt mask register*/
+ uint32_t int_mask_hi;
+ uint32_t htmsi_en_lo; /*0x040 1=msi*/
+ uint32_t htmsi_en_hi;
+ uint32_t intedge_lo; /*0x060 edge=1 level =0*/
+ uint32_t intedge_hi; /*0x060 edge=1 level =0*/
+ uint32_t intclr_lo; /*0x080 for clean edge int,set 1 clean,set 0 is noused*/
+ uint32_t intclr_hi; /*0x080 for clean edge int,set 1 clean,set 0 is noused*/
+ uint32_t auto_crtl0_lo; /*0x0c0*/
+ uint32_t auto_crtl0_hi; /*0x0c0*/
+ uint32_t auto_crtl1_lo; /*0x0e0*/
+ uint32_t auto_crtl1_hi; /*0x0e0*/
+ uint32_t last_intirr_lo; /* edge detection */
+ uint32_t last_intirr_hi; /* edge detection */
+ uint32_t intirr_lo; /* 0x380 interrupt request register */
+ uint32_t intirr_hi; /* 0x380 interrupt request register */
+ uint32_t intisr_lo; /* 0x3a0 interrupt service register */
+ uint32_t intisr_hi; /* 0x3a0 interrupt service register */
+ /*
+ * 0x3e0 interrupt level polarity selection
+ * register 0 for high level trigger
+ */
+ uint32_t int_polarity_lo;
+ uint32_t int_polarity_hi;
+
+ uint8_t route_entry[64]; /*0x100 - 0x138*/
+ uint8_t htmsi_vector[64]; /*0x200 - 0x238*/
+
+ MemoryRegion iomem32_low;
+ MemoryRegion iomem32_high;
+ MemoryRegion iomem8;
+} LoongArchPCHPIC;
--
2.31.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [RFC PATCH v7 18/29] hw/intc: Add LoongArch ls7a msi interrupt controller support(PCH-MSI)
2022-03-28 12:57 [RFC PATCH v7 00/29] Add LoongArch softmmu support Xiaojuan Yang
` (16 preceding siblings ...)
2022-03-28 12:57 ` [RFC PATCH v7 17/29] hw/intc: Add LoongArch ls7a interrupt controller support(PCH-PIC) Xiaojuan Yang
@ 2022-03-28 12:57 ` Xiaojuan Yang
2022-03-28 20:22 ` Mark Cave-Ayland
2022-03-28 12:57 ` [RFC PATCH v7 19/29] hw/intc: Add LoongArch extioi interrupt controller(EIOINTC) Xiaojuan Yang
` (11 subsequent siblings)
29 siblings, 1 reply; 71+ messages in thread
From: Xiaojuan Yang @ 2022-03-28 12:57 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland, richard.henderson, Song Gao
This patch realize PCH-MSI interrupt controller.
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
hw/intc/Kconfig | 5 ++
hw/intc/loongarch_pch_msi.c | 75 +++++++++++++++++++++++++++++
hw/intc/meson.build | 1 +
hw/intc/trace-events | 3 ++
hw/loongarch/Kconfig | 1 +
include/hw/intc/loongarch_pch_msi.h | 21 ++++++++
6 files changed, 106 insertions(+)
create mode 100644 hw/intc/loongarch_pch_msi.c
create mode 100644 include/hw/intc/loongarch_pch_msi.h
diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
index 1fbba2e728..71c04c328e 100644
--- a/hw/intc/Kconfig
+++ b/hw/intc/Kconfig
@@ -91,3 +91,8 @@ config LOONGARCH_IPI
config LOONGARCH_PCH_PIC
bool
select UNIMP
+
+config LOONGARCH_PCH_MSI
+ select MSI_NONBROKEN
+ bool
+ select UNIMP
diff --git a/hw/intc/loongarch_pch_msi.c b/hw/intc/loongarch_pch_msi.c
new file mode 100644
index 0000000000..57a894f3e5
--- /dev/null
+++ b/hw/intc/loongarch_pch_msi.c
@@ -0,0 +1,75 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * QEMU Loongson 7A1000 msi interrupt controller.
+ *
+ * Copyright (C) 2021 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "hw/sysbus.h"
+#include "hw/irq.h"
+#include "hw/intc/loongarch_pch_msi.h"
+#include "hw/intc/loongarch_pch_pic.h"
+#include "hw/pci/msi.h"
+#include "hw/misc/unimp.h"
+#include "migration/vmstate.h"
+#include "trace.h"
+
+static uint64_t loongarch_msi_mem_read(void *opaque, hwaddr addr, unsigned size)
+{
+ return 0;
+}
+
+static void loongarch_msi_mem_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size)
+{
+ LoongArchPCHMSI *s = LOONGARCH_PCH_MSI(opaque);
+ int irq_num = val & 0xff;
+
+ trace_loongarch_msi_set_irq(irq_num);
+ qemu_set_irq(s->pch_msi_irq[irq_num - PCH_PIC_IRQ_NUM], 1);
+}
+
+static const MemoryRegionOps loongarch_pch_msi_ops = {
+ .read = loongarch_msi_mem_read,
+ .write = loongarch_msi_mem_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void pch_msi_irq_handler(void *opaque, int irq, int level)
+{
+ LoongArchPCHMSI *s = LOONGARCH_PCH_MSI(opaque);
+
+ qemu_set_irq(s->pch_msi_irq[irq], level);
+}
+
+static void loongarch_pch_msi_init(Object *obj)
+{
+ LoongArchPCHMSI *s = LOONGARCH_PCH_MSI(obj);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+ int i;
+
+ memory_region_init_io(&s->msi_mmio, obj, &loongarch_pch_msi_ops,
+ s, TYPE_LOONGARCH_PCH_MSI, 0x8);
+ sysbus_init_mmio(sbd, &s->msi_mmio);
+ msi_nonbroken = true;
+
+ for (i = 0; i < PCH_MSI_IRQ_NUM; i++) {
+ sysbus_init_irq(sbd, &s->pch_msi_irq[i]);
+ }
+ qdev_init_gpio_in(DEVICE(obj), pch_msi_irq_handler, PCH_MSI_IRQ_NUM);
+}
+
+static const TypeInfo loongarch_pch_msi_info = {
+ .name = TYPE_LOONGARCH_PCH_MSI,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(LoongArchPCHMSI),
+ .instance_init = loongarch_pch_msi_init,
+};
+
+static void loongarch_pch_msi_register_types(void)
+{
+ type_register_static(&loongarch_pch_msi_info);
+}
+
+type_init(loongarch_pch_msi_register_types)
diff --git a/hw/intc/meson.build b/hw/intc/meson.build
index 960ce81a92..77a30cec33 100644
--- a/hw/intc/meson.build
+++ b/hw/intc/meson.build
@@ -64,3 +64,4 @@ specific_ss.add(when: 'CONFIG_GOLDFISH_PIC', if_true: files('goldfish_pic.c'))
specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c'))
specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c'))
specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_pic.c'))
+specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_MSI', if_true: files('loongarch_pch_msi.c'))
diff --git a/hw/intc/trace-events b/hw/intc/trace-events
index 8c12bdd89f..7c02f8d5f0 100644
--- a/hw/intc/trace-events
+++ b/hw/intc/trace-events
@@ -288,3 +288,6 @@ loongarch_pch_pic_high_readw(unsigned size, uint32_t addr, unsigned long val) "s
loongarch_pch_pic_high_writew(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
loongarch_pch_pic_readb(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
loongarch_pch_pic_writeb(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
+
+# loongarch_pch_msi.c
+loongarch_msi_set_irq(int irq_num) "set msi irq %d"
diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
index 2df45f7e8f..d814fc6103 100644
--- a/hw/loongarch/Kconfig
+++ b/hw/loongarch/Kconfig
@@ -4,3 +4,4 @@ config LOONGARCH_VIRT
select PCI_EXPRESS_GENERIC_BRIDGE
select LOONGARCH_IPI
select LOONGARCH_PCH_PIC
+ select LOONGARCH_PCH_MSI
diff --git a/include/hw/intc/loongarch_pch_msi.h b/include/hw/intc/loongarch_pch_msi.h
new file mode 100644
index 0000000000..68009d4b4a
--- /dev/null
+++ b/include/hw/intc/loongarch_pch_msi.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * LoongArch 7A1000 I/O interrupt controller definitions
+ *
+ * Copyright (C) 2021 Loongson Technology Corporation Limited
+ */
+
+#define TYPE_LOONGARCH_PCH_MSI "loongarch_pch_msi"
+DECLARE_INSTANCE_CHECKER(struct LoongArchPCHMSI, LOONGARCH_PCH_MSI,
+ TYPE_LOONGARCH_PCH_MSI)
+
+/* Msi irq start start from 64 to 255 */
+#define PCH_MSI_IRQ_START 64
+#define PCH_MSI_IRQ_END 255
+#define PCH_MSI_IRQ_NUM 192
+
+typedef struct LoongArchPCHMSI {
+ SysBusDevice parent_obj;
+ qemu_irq pch_msi_irq[PCH_MSI_IRQ_NUM];
+ MemoryRegion msi_mmio;
+} LoongArchPCHMSI;
--
2.31.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [RFC PATCH v7 19/29] hw/intc: Add LoongArch extioi interrupt controller(EIOINTC)
2022-03-28 12:57 [RFC PATCH v7 00/29] Add LoongArch softmmu support Xiaojuan Yang
` (17 preceding siblings ...)
2022-03-28 12:57 ` [RFC PATCH v7 18/29] hw/intc: Add LoongArch ls7a msi interrupt controller support(PCH-MSI) Xiaojuan Yang
@ 2022-03-28 12:57 ` Xiaojuan Yang
2022-03-28 20:27 ` Mark Cave-Ayland
` (2 more replies)
2022-03-28 12:57 ` [RFC PATCH v7 20/29] hw/loongarch: Add irq hierarchy for the system Xiaojuan Yang
` (10 subsequent siblings)
29 siblings, 3 replies; 71+ messages in thread
From: Xiaojuan Yang @ 2022-03-28 12:57 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland, richard.henderson, Song Gao
This patch realize the EIOINTC interrupt controller.
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
hw/intc/Kconfig | 3 +
hw/intc/loongarch_extioi.c | 408 +++++++++++++++++++++++++++++
hw/intc/meson.build | 1 +
hw/intc/trace-events | 11 +
hw/loongarch/Kconfig | 1 +
include/hw/intc/loongarch_extioi.h | 77 ++++++
6 files changed, 501 insertions(+)
create mode 100644 hw/intc/loongarch_extioi.c
create mode 100644 include/hw/intc/loongarch_extioi.h
diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
index 71c04c328e..28bd1f185d 100644
--- a/hw/intc/Kconfig
+++ b/hw/intc/Kconfig
@@ -96,3 +96,6 @@ config LOONGARCH_PCH_MSI
select MSI_NONBROKEN
bool
select UNIMP
+
+config LOONGARCH_EXTIOI
+ bool
diff --git a/hw/intc/loongarch_extioi.c b/hw/intc/loongarch_extioi.c
new file mode 100644
index 0000000000..af28e8d6e9
--- /dev/null
+++ b/hw/intc/loongarch_extioi.c
@@ -0,0 +1,408 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Loongson 3A5000 ext interrupt controller emulation
+ *
+ * Copyright (C) 2021 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/module.h"
+#include "qemu/log.h"
+#include "hw/irq.h"
+#include "hw/sysbus.h"
+#include "hw/loongarch/loongarch.h"
+#include "hw/qdev-properties.h"
+#include "exec/address-spaces.h"
+#include "hw/intc/loongarch_extioi.h"
+#include "migration/vmstate.h"
+#include "trace.h"
+
+static void extioi_update_irq(void *opaque, int irq_num, int level)
+{
+ LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
+ uint8_t ipnum, cpu;
+ unsigned long found1, found2;
+
+ ipnum = s->sw_ipmap[irq_num];
+ cpu = s->sw_coremap[irq_num];
+ if (level == 1) {
+ if (test_bit(irq_num, (void *)s->enable) == false) {
+ return;
+ }
+ bitmap_set((void *)s->coreisr[cpu], irq_num, 1);
+ found1 = find_next_bit((void *)&(s->sw_ipisr[cpu][ipnum]),
+ EXTIOI_IRQS, 0);
+ bitmap_set((void *)&(s->sw_ipisr[cpu][ipnum]), irq_num, 1);
+
+ if (found1 >= EXTIOI_IRQS) {
+ qemu_set_irq(s->parent_irq[cpu][ipnum], level);
+ }
+ } else {
+ bitmap_clear((void *)s->coreisr[cpu], irq_num, 1);
+ found1 = find_next_bit((void *)&(s->sw_ipisr[cpu][ipnum]),
+ EXTIOI_IRQS, 0);
+ bitmap_clear((void *)&(s->sw_ipisr[cpu][ipnum]), irq_num, 1);
+ found2 = find_next_bit((void *)&(s->sw_ipisr[cpu][ipnum]),
+ EXTIOI_IRQS, 0);
+
+ if ((found1 < EXTIOI_IRQS) && (found2 >= EXTIOI_IRQS)) {
+ qemu_set_irq(s->parent_irq[cpu][ipnum], level);
+ }
+ }
+}
+
+static void extioi_setirq(void *opaque, int irq, int level)
+{
+ LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
+ trace_extioi_setirq(irq, level);
+ extioi_update_irq(s, irq, level);
+}
+
+static uint64_t extioi_nodetype_readw(void *opaque, hwaddr addr, unsigned size)
+{
+ LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
+ unsigned long offset = addr & 0xffff;
+ uint32_t ret, index;
+
+ switch (offset) {
+ case EXTIOI_NODETYPE_START ... EXTIOI_NODETYPE_END - 1:
+ index = (offset - EXTIOI_NODETYPE_START) >> 2;
+ ret = s->nodetype[index];
+ break;
+ default:
+ break;
+ }
+
+ trace_loongarch_extioi_nodetype_readw((uint32_t)addr, ret);
+ return ret;
+}
+
+static void extioi_nodetype_writew(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size)
+{
+ LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
+ int index;
+ uint32_t offset;
+ trace_loongarch_extioi_nodetype_writew(size, (uint32_t)addr, val);
+
+ offset = addr & 0xffff;
+
+ switch (offset) {
+ case EXTIOI_NODETYPE_START ... EXTIOI_NODETYPE_END - 1:
+ index = (offset - EXTIOI_NODETYPE_START) >> 2;
+ s->nodetype[index] = val;
+ break;
+ default:
+ break;
+ }
+}
+
+static uint64_t extioi_ipmap_enable_read(void *opaque, hwaddr addr,
+ unsigned size)
+{
+ LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
+ uint8_t ret;
+
+ switch (addr) {
+ case EXTIOI_IPMAP_START ... EXTIOI_IPMAP_END - 1:
+ ret = s->ipmap[addr];
+ break;
+ case EXTIOI_ENABLE_START ... EXTIOI_ENABLE_END - 1:
+ addr -= EXTIOI_ENABLE_START;
+ ret = s->enable[addr];
+ break;
+ default:
+ break;
+ }
+
+ trace_loongarch_extioi_ipmap_enable_read((uint8_t)addr, ret);
+ return ret;
+}
+
+static void extioi_ipmap_enable_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+ LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
+ uint8_t old_data, val = value & 0xff;
+ int i, level, ipnum, irqnum;
+ trace_loongarch_extioi_ipmap_enable_write(size, (uint8_t)addr, val);
+
+ switch (addr) {
+ case EXTIOI_IPMAP_START ... EXTIOI_IPMAP_END - 1:
+ s->ipmap[addr] = val;
+ /* Routing in groups of 32 interrupt */
+ ipnum = find_first_bit((void *)&val, 4);
+ for (i = 0; i < 32; i++) {
+ irqnum = addr * 32 + i;
+ if (ipnum != 4) {
+ s->sw_ipmap[irqnum] = ipnum;
+ } else {
+ s->sw_ipmap[irqnum] = 0;
+ }
+ }
+ break;
+ case EXTIOI_ENABLE_START ... EXTIOI_ENABLE_END - 1:
+ addr -= EXTIOI_ENABLE_START;
+ old_data = s->enable[addr];
+ if (old_data != val) {
+ s->enable[addr] = val;
+ old_data = old_data ^ val;
+
+ while ((i = find_first_bit((void *)&old_data, 8)) != 8) {
+ level = test_bit(i, (unsigned long *)&val);
+ extioi_update_irq(s, i + addr * 8, level);
+ clear_bit(i, (void *)&old_data);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static uint64_t extioi_bounce_coreisr_readw(void *opaque, hwaddr addr,
+ unsigned size)
+{
+ LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
+ unsigned long offset = addr & 0xffff;
+ uint32_t ret, index;
+ int cpu;
+
+ switch (offset) {
+ case EXTIOI_BOUNCE_START ... EXTIOI_BOUNCE_END - 1:
+ index = (offset - EXTIOI_BOUNCE_START) >> 2;
+ ret = s->bounce[index];
+ break;
+ case EXTIOI_COREISR_START ... EXTIOI_COREISR_END - 1:
+ index = ((offset - EXTIOI_COREISR_START) & 0x1f) >> 2;
+ cpu = ((offset - EXTIOI_COREISR_START) >> 8) & 0x3;
+ ret = s->coreisr[cpu][index];
+ break;
+ default:
+ break;
+ }
+
+ trace_loongarch_extioi_bounce_coreisr_readw((uint32_t)addr, ret);
+ return ret;
+}
+
+static void extioi_bounce_coreisr_writew(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size)
+{
+ LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
+ int cpu, index;
+ uint32_t offset, old_data, i, j, bits;
+
+ offset = addr & 0xffff;
+ trace_loongarch_extioi_bounce_coreisr_writew(size, (uint32_t)addr, val);
+ switch (offset) {
+ case EXTIOI_BOUNCE_START ... EXTIOI_BOUNCE_END - 1:
+ index = (offset - EXTIOI_BOUNCE_START) >> 2;
+ s->bounce[index] = val;
+ break;
+ case EXTIOI_COREISR_START ... EXTIOI_COREISR_END - 1:
+ index = ((offset - EXTIOI_COREISR_START) & 0x1f) >> 2;
+ cpu = ((offset - EXTIOI_COREISR_START) >> 8) & 0x3;
+ old_data = s->coreisr[cpu][index];
+ s->coreisr[cpu][index] = old_data & ~val;
+ if (old_data != s->coreisr[cpu][index]) {
+ bits = size * 8;
+ while ((i = find_first_bit((void *)&val, bits)) != bits) {
+ j = test_bit(i, (unsigned long *)&old_data);
+ if (j) {
+ extioi_update_irq(s, i + index * 32, 0);
+ }
+ clear_bit(i, (void *)&val);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static uint64_t extioi_coremap_read(void *opaque, hwaddr addr, unsigned size)
+{
+ LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
+ uint8_t ret;
+
+ switch (addr) {
+ case EXTIOI_COREMAP_START ... EXTIOI_COREMAP_END - 1:
+ ret = s->coremap[addr];
+ break;
+ default:
+ break;
+ }
+
+ trace_loongarch_extioi_coremap_read((uint8_t)addr, ret);
+ return ret;
+}
+
+static void extioi_coremap_write(void *opaque, hwaddr addr,
+ uint64_t value, unsigned size)
+{
+ LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
+ uint8_t val = value & 0xff;
+ int cpu;
+
+ trace_loongarch_extioi_coremap_write(size, (uint8_t)addr, val);
+ switch (addr) {
+ case EXTIOI_COREMAP_START ... EXTIOI_COREMAP_END - 1:
+ s->coremap[addr] = val;
+
+ /* Only support 1 node now only handle the core map*/
+ if (val) {
+ cpu = find_first_bit((void *)&val, 4);
+ if (cpu != 4) {
+ s->sw_coremap[addr] = cpu;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static const MemoryRegionOps extioi_nodetype_ops = {
+ .read = extioi_nodetype_readw,
+ .write = extioi_nodetype_writew,
+ .impl.min_access_size = 4,
+ .impl.max_access_size = 4,
+ .valid.min_access_size = 4,
+ .valid.max_access_size = 8,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static const MemoryRegionOps extioi_ipmap_enable_ops = {
+ .read = extioi_ipmap_enable_read,
+ .write = extioi_ipmap_enable_write,
+ .impl.min_access_size = 1,
+ .impl.max_access_size = 1,
+ .valid.min_access_size = 1,
+ .valid.max_access_size = 8,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static const MemoryRegionOps extioi_bounce_coreisr_ops = {
+ .read = extioi_bounce_coreisr_readw,
+ .write = extioi_bounce_coreisr_writew,
+ .impl.min_access_size = 4,
+ .impl.max_access_size = 4,
+ .valid.min_access_size = 4,
+ .valid.max_access_size = 8,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static const MemoryRegionOps extioi_coremap_ops = {
+ .read = extioi_coremap_read,
+ .write = extioi_coremap_write,
+ .impl.min_access_size = 1,
+ .impl.max_access_size = 1,
+ .valid.min_access_size = 1,
+ .valid.max_access_size = 8,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_ext_sw_ipisr = {
+ .name = "ext_sw_ipisr",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8_ARRAY(irq, ext_sw_ipisr, EXTIOI_IRQS),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_loongarch_extioi = {
+ .name = TYPE_LOONGARCH_EXTIOI,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(bounce, LoongArchExtIOI, EXTIOI_IRQS_GROUP_COUNT),
+ VMSTATE_UINT32_2DARRAY(coreisr, LoongArchExtIOI, MAX_CORES,
+ EXTIOI_IRQS_GROUP_COUNT),
+ VMSTATE_UINT32_ARRAY(nodetype, LoongArchExtIOI,
+ EXTIOI_IRQS_NODETYPE_COUNT / 2),
+ VMSTATE_UINT8_ARRAY(enable, LoongArchExtIOI, EXTIOI_IRQS / 8),
+ VMSTATE_UINT8_ARRAY(ipmap, LoongArchExtIOI, 8),
+ VMSTATE_UINT8_ARRAY(coremap, LoongArchExtIOI, EXTIOI_IRQS),
+ VMSTATE_UINT8_ARRAY(sw_ipmap, LoongArchExtIOI, EXTIOI_IRQS),
+ VMSTATE_UINT8_ARRAY(sw_coremap, LoongArchExtIOI, EXTIOI_IRQS),
+ VMSTATE_STRUCT_2DARRAY(sw_ipisr, LoongArchExtIOI, MAX_CORES,
+ LS3A_INTC_IP, 1, vmstate_ext_sw_ipisr,
+ ext_sw_ipisr),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void loongarch_extioi_instance_init(Object *obj)
+{
+ SysBusDevice *dev = SYS_BUS_DEVICE(obj);
+ LoongArchExtIOI *s = LOONGARCH_EXTIOI(obj);
+ int i, cpu, pin;
+
+ for (i = 0; i < EXTIOI_IRQS; i++) {
+ sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[i]);
+ }
+
+ qdev_init_gpio_in(DEVICE(obj), extioi_setirq, EXTIOI_IRQS);
+
+ for (cpu = 0; cpu < MAX_CORES; cpu++) {
+ sysbus_init_mmio(dev, &s->mmio[cpu]);
+ for (pin = 0; pin < LS3A_INTC_IP; pin++) {
+ qdev_init_gpio_out(DEVICE(obj), &s->parent_irq[cpu][pin], 1);
+ }
+
+ memory_region_init(&s->mmio[cpu], OBJECT(s),
+ "loongarch_extioi", EXTIOI_SIZE);
+
+ memory_region_init_io(&s->mmio_nodetype[cpu], OBJECT(s),
+ &extioi_nodetype_ops, s,
+ EXTIOI_LINKNAME(.nodetype),
+ IPMAP_OFFSET - APIC_BASE);
+ memory_region_add_subregion(&s->mmio[cpu], 0, &s->mmio_nodetype[cpu]);
+
+ memory_region_init_io(&s->mmio_ipmap_enable[cpu], OBJECT(s),
+ &extioi_ipmap_enable_ops, s,
+ EXTIOI_LINKNAME(.ipmap_enable),
+ BOUNCE_OFFSET - IPMAP_OFFSET);
+ memory_region_add_subregion(&s->mmio[cpu], IPMAP_OFFSET - APIC_BASE,
+ &s->mmio_ipmap_enable[cpu]);
+
+ memory_region_init_io(&s->mmio_bounce_coreisr[cpu], OBJECT(s),
+ &extioi_bounce_coreisr_ops, s,
+ EXTIOI_LINKNAME(.bounce_coreisr),
+ COREMAP_OFFSET - BOUNCE_OFFSET);
+ memory_region_add_subregion(&s->mmio[cpu], BOUNCE_OFFSET - APIC_BASE,
+ &s->mmio_bounce_coreisr[cpu]);
+
+ memory_region_init_io(&s->mmio_coremap[cpu], OBJECT(s),
+ &extioi_coremap_ops, s,
+ EXTIOI_LINKNAME(.coremap),
+ EXTIOI_COREMAP_END);
+ memory_region_add_subregion(&s->mmio[cpu], COREMAP_OFFSET - APIC_BASE,
+ &s->mmio_coremap[cpu]);
+ }
+}
+
+static void loongarch_extioi_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->vmsd = &vmstate_loongarch_extioi;
+}
+
+static const TypeInfo loongarch_extioi_info = {
+ .name = TYPE_LOONGARCH_EXTIOI,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_init = loongarch_extioi_instance_init,
+ .instance_size = sizeof(struct LoongArchExtIOI),
+ .class_init = loongarch_extioi_class_init,
+};
+
+static void loongarch_extioi_register_types(void)
+{
+ type_register_static(&loongarch_extioi_info);
+}
+
+type_init(loongarch_extioi_register_types)
diff --git a/hw/intc/meson.build b/hw/intc/meson.build
index 77a30cec33..405e18f4bb 100644
--- a/hw/intc/meson.build
+++ b/hw/intc/meson.build
@@ -65,3 +65,4 @@ specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c'))
specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c'))
specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_pic.c'))
specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_MSI', if_true: files('loongarch_pch_msi.c'))
+specific_ss.add(when: 'CONFIG_LOONGARCH_EXTIOI', if_true: files('loongarch_extioi.c'))
diff --git a/hw/intc/trace-events b/hw/intc/trace-events
index 7c02f8d5f0..40da8312b0 100644
--- a/hw/intc/trace-events
+++ b/hw/intc/trace-events
@@ -291,3 +291,14 @@ loongarch_pch_pic_writeb(unsigned size, uint32_t addr, unsigned long val) "size:
# loongarch_pch_msi.c
loongarch_msi_set_irq(int irq_num) "set msi irq %d"
+
+# loongarch_extioi.c
+extioi_setirq(int irq, int level) "set extirq irq %d level %d"
+loongarch_extioi_nodetype_readw(uint32_t addr, uint32_t val) "addr: 0x%"PRIx32 "val: 0x%" PRIx32
+loongarch_extioi_nodetype_writew(unsigned size, uint32_t addr, uint32_t val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx32
+loongarch_extioi_ipmap_enable_read(uint8_t addr, uint8_t val) "addr: 0x%"PRIu8 "val: 0x%" PRIu8
+loongarch_extioi_ipmap_enable_write(unsigned size, uint8_t addr, uint8_t val) "size: %u addr: 0x%"PRIu8 "val: 0x%" PRIu8
+loongarch_extioi_bounce_coreisr_readw(uint32_t addr, uint32_t val) "addr: 0x%"PRIx32 "val: 0x%" PRIx32
+loongarch_extioi_bounce_coreisr_writew(unsigned size, uint32_t addr, uint32_t val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx32
+loongarch_extioi_coremap_read(uint8_t addr, uint8_t val) "addr: 0x%"PRIu8 "val: 0x%" PRIu8
+loongarch_extioi_coremap_write(unsigned size, uint8_t addr, uint8_t val) "size: %u addr: 0x%"PRIu8 "val: 0x%" PRIu8
diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
index d814fc6103..f779087416 100644
--- a/hw/loongarch/Kconfig
+++ b/hw/loongarch/Kconfig
@@ -5,3 +5,4 @@ config LOONGARCH_VIRT
select LOONGARCH_IPI
select LOONGARCH_PCH_PIC
select LOONGARCH_PCH_MSI
+ select LOONGARCH_EXTIOI
diff --git a/include/hw/intc/loongarch_extioi.h b/include/hw/intc/loongarch_extioi.h
new file mode 100644
index 0000000000..befec7bb5d
--- /dev/null
+++ b/include/hw/intc/loongarch_extioi.h
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * LoongArch 3A5000 ext interrupt controller definitions
+ *
+ * Copyright (C) 2021 Loongson Technology Corporation Limited
+ */
+
+#include "hw/sysbus.h"
+#include "hw/loongarch/loongarch.h"
+
+#ifndef LOONGARCH_EXTIOI_H
+#define LOONGARCH_EXTIOI_H
+
+#define LS3A_INTC_IP 8
+#define MAX_CORES LOONGARCH_MAX_VCPUS
+#define EXTIOI_IRQS (256)
+/* 32 irqs belong to a group */
+#define EXTIOI_IRQS_GROUP_COUNT (256 / 32)
+/* map to ipnum per 32 irqs */
+#define EXTIOI_IRQS_NODETYPE_COUNT 16
+
+#define APIC_BASE 0x1400
+#define ENABLE_OFFSET 0x1600
+#define IPMAP_OFFSET 0x14c0
+#define COREMAP_OFFSET 0x1c00
+#define NODETYPE_OFFSET 0x14a0
+#define BOUNCE_OFFSET 0x1680
+#define COREISR_OFFSET 0x1800
+
+#define EXTIOI_NODETYPE_START (0x14a0 - APIC_BASE)
+#define EXTIOI_NODETYPE_END (0x14c0 - APIC_BASE)
+#define EXTIOI_BOUNCE_START 0
+#define EXTIOI_BOUNCE_END (0x16a0 - BOUNCE_OFFSET)
+#define EXTIOI_COREISR_START (0x1800 - BOUNCE_OFFSET)
+#define EXTIOI_COREISR_END (0x1B20 - BOUNCE_OFFSET)
+
+#define EXTIOI_IPMAP_START 0
+#define EXTIOI_IPMAP_END (0x14c8 - IPMAP_OFFSET)
+#define EXTIOI_ENABLE_START (0x1600 - IPMAP_OFFSET)
+#define EXTIOI_ENABLE_END (0x1618 - IPMAP_OFFSET)
+
+#define EXTIOI_COREMAP_START 0
+#define EXTIOI_COREMAP_END (0x1d00 - COREMAP_OFFSET)
+#define EXTIOI_SIZE 0x900
+
+#define TYPE_LOONGARCH_EXTIOI "loongarch_extioi"
+#define EXTIOI_LINKNAME(name) TYPE_LOONGARCH_EXTIOI#name
+OBJECT_DECLARE_SIMPLE_TYPE(LoongArchExtIOI, LOONGARCH_EXTIOI)
+typedef struct ext_sw_ipisr {
+ uint8_t irq[EXTIOI_IRQS];
+} ext_sw_ipisr;
+
+typedef struct LoongArchExtIOI {
+ SysBusDevice parent_obj;
+ /* hardware state */
+ uint32_t nodetype[EXTIOI_IRQS_NODETYPE_COUNT / 2];
+ uint32_t bounce[EXTIOI_IRQS_GROUP_COUNT];
+ uint32_t coreisr[MAX_CORES][EXTIOI_IRQS_GROUP_COUNT];
+
+ uint8_t enable[EXTIOI_IRQS / 8];
+ uint8_t ipmap[8];
+ uint8_t coremap[EXTIOI_IRQS];
+ /*software state */
+ uint8_t sw_ipmap[EXTIOI_IRQS];
+ uint8_t sw_coremap[EXTIOI_IRQS];
+ ext_sw_ipisr sw_ipisr[MAX_CORES][LS3A_INTC_IP];
+
+ qemu_irq parent_irq[MAX_CORES][LS3A_INTC_IP];
+ qemu_irq irq[EXTIOI_IRQS];
+ MemoryRegion mmio[MAX_CORES];
+ MemoryRegion mmio_nodetype[MAX_CORES];
+ MemoryRegion mmio_ipmap_enable[MAX_CORES];
+ MemoryRegion mmio_bounce_coreisr[MAX_CORES];
+ MemoryRegion mmio_coremap[MAX_CORES];
+} LoongArchExtIOI;
+
+#endif /* LOONGARCH_EXTIOI_H */
--
2.31.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [RFC PATCH v7 20/29] hw/loongarch: Add irq hierarchy for the system
2022-03-28 12:57 [RFC PATCH v7 00/29] Add LoongArch softmmu support Xiaojuan Yang
` (18 preceding siblings ...)
2022-03-28 12:57 ` [RFC PATCH v7 19/29] hw/intc: Add LoongArch extioi interrupt controller(EIOINTC) Xiaojuan Yang
@ 2022-03-28 12:57 ` Xiaojuan Yang
2022-03-28 23:16 ` Richard Henderson
2022-03-28 12:57 ` [RFC PATCH v7 21/29] Enable common virtio pci support for LoongArch Xiaojuan Yang
` (9 subsequent siblings)
29 siblings, 1 reply; 71+ messages in thread
From: Xiaojuan Yang @ 2022-03-28 12:57 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland, richard.henderson, Song Gao
This patch add the irq hierarchy for the virt board.
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
MAINTAINERS | 1 +
hw/loongarch/loongson3.c | 99 ++++++++++++++++++++++++++++++++++++++
include/hw/pci-host/ls7a.h | 30 ++++++++++++
3 files changed, 130 insertions(+)
create mode 100644 include/hw/pci-host/ls7a.h
diff --git a/MAINTAINERS b/MAINTAINERS
index d83b90b5c5..5683531367 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1135,6 +1135,7 @@ F: hw/loongarch/
F: include/hw/loongarch/loongarch.h
F: include/hw/intc/loongarch_*.h
F: hw/intc/loongarch_*.c
+F: include/hw/pci-host/ls7a.h
M68K Machines
-------------
diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
index 7b4e77a6a6..17fdcc42ca 100644
--- a/hw/loongarch/loongson3.c
+++ b/hw/loongarch/loongson3.c
@@ -16,6 +16,11 @@
#include "sysemu/reset.h"
#include "sysemu/rtc.h"
#include "hw/loongarch/loongarch.h"
+#include "hw/intc/loongarch_ipi.h"
+#include "hw/intc/loongarch_extioi.h"
+#include "hw/intc/loongarch_pch_pic.h"
+#include "hw/intc/loongarch_pch_msi.h"
+#include "hw/pci-host/ls7a.h"
#include "target/loongarch/cpu.h"
@@ -87,8 +92,11 @@ static const MemoryRegionOps loongarch_qemu_ops = {
},
};
+static struct DeviceState *ipi, *extioi;
+
static void loongarch_cpu_init(LoongArchCPU *la_cpu, int cpu_num)
{
+ unsigned long ipi_addr;
CPULoongArchState *env;
env = &la_cpu->env;
@@ -107,12 +115,101 @@ static void loongarch_cpu_init(LoongArchCPU *la_cpu, int cpu_num)
NULL, "iocsr_misc", IOCSR_MEM_SIZE);
memory_region_add_subregion(&env->system_iocsr, 0, &env->iocsr_mem);
+ /* ipi memory region */
+ ipi_addr = SMP_IPI_MAILBOX + cpu_num * 0x100;
+ memory_region_add_subregion(&env->system_iocsr, ipi_addr,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi),
+ cpu_num));
+ /* extioi memory region */
+ memory_region_add_subregion(&env->system_iocsr, APIC_BASE,
+ sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi),
+ cpu_num));
+}
+
+static DeviceState *create_ipi(void)
+{
+ DeviceState *ipi;
+
+ ipi = qdev_new(TYPE_LOONGARCH_IPI);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi), &error_fatal);
+ return ipi;
+}
+
+static DeviceState *create_extioi(void)
+{
+ DeviceState *extioi;
+
+ extioi = qdev_new(TYPE_LOONGARCH_EXTIOI);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi), &error_fatal);
+ return extioi;
+}
+
+static void loongarch_irq_init(LoongArchMachineState *lams,
+ DeviceState *ipi, DeviceState *extioi)
+{
+ MachineState *ms = MACHINE(lams);
+ DeviceState *pch_pic, *pch_msi, *cpudev;
+
+ SysBusDevice *d;
+ int cpu, pin, i;
+
+ for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
+ cpudev = DEVICE(qemu_get_cpu(cpu));
+ /* connect ipi irq to cpu irq */
+ qdev_connect_gpio_out(ipi, cpu, qdev_get_gpio_in(cpudev, IRQ_IPI));
+ }
+
+ for (i = 0; i < EXTIOI_IRQS; i++) {
+ sysbus_connect_irq(SYS_BUS_DEVICE(extioi),
+ i, qdev_get_gpio_in(extioi, i));
+ }
+
+ /*
+ * connect ext irq to the cpu irq
+ * cpu_pin[9:2] <= intc_pin[7:0]
+ */
+ for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
+ cpudev = DEVICE(qemu_get_cpu(cpu));
+ for (pin = 0; pin < LS3A_INTC_IP; pin++) {
+ qdev_connect_gpio_out(extioi, (cpu * 8 + pin),
+ qdev_get_gpio_in(cpudev, pin + 2));
+ }
+ }
+
+ pch_pic = qdev_new(TYPE_LOONGARCH_PCH_PIC);
+ d = SYS_BUS_DEVICE(pch_pic);
+ sysbus_realize_and_unref(d, &error_fatal);
+ memory_region_add_subregion(get_system_memory(), LS7A_IOAPIC_REG_BASE,
+ sysbus_mmio_get_region(d, 0));
+ memory_region_add_subregion(get_system_memory(),
+ LS7A_IOAPIC_REG_BASE + PCH_PIC_ROUTE_ENTRY_OFFSET,
+ sysbus_mmio_get_region(d, 1));
+ memory_region_add_subregion(get_system_memory(),
+ LS7A_IOAPIC_REG_BASE + PCH_PIC_INT_STATUS_LO,
+ sysbus_mmio_get_region(d, 2));
+
+ /* Connect 64 pch_pic irqs to extioi */
+ for (int i = 0; i < PCH_PIC_IRQ_NUM; i++) {
+ sysbus_connect_irq(d, i, qdev_get_gpio_in(extioi, i));
+ }
+
+ pch_msi = qdev_new(TYPE_LOONGARCH_PCH_MSI);
+ d = SYS_BUS_DEVICE(pch_msi);
+ sysbus_realize_and_unref(d, &error_fatal);
+ sysbus_mmio_map(d, 0, LS7A_PCH_MSI_ADDR_LOW);
+ for (i = 0; i < PCH_MSI_IRQ_NUM; i++) {
+ /* Connect 192 pch_msi irqs to extioi */
+ sysbus_connect_irq(d, i,
+ qdev_get_gpio_in(extioi, i + PCH_MSI_IRQ_START));
+ }
}
static void loongarch_init(MachineState *machine)
{
const char *cpu_model = machine->cpu_type;
LoongArchCPU *la_cpu;
+ ipi = create_ipi();
+ extioi = create_extioi();
ram_addr_t offset = 0;
ram_addr_t ram_size = machine->ram_size;
uint64_t highram_size = 0;
@@ -152,6 +249,8 @@ static void loongarch_init(MachineState *machine)
get_system_io(), 0, LOONGARCH_ISA_IO_SIZE);
memory_region_add_subregion(address_space_mem, LOONGARCH_ISA_IO_BASE,
&lams->isa_io);
+ /* Initialize the IO interrupt subsystem */
+ loongarch_irq_init(lams, ipi, extioi);
}
static void loongarch_class_init(ObjectClass *oc, void *data)
diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h
new file mode 100644
index 0000000000..bf80e99ce1
--- /dev/null
+++ b/include/hw/pci-host/ls7a.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * QEMU LoongArch CPU
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ */
+
+#ifndef HW_LS7A_H
+#define HW_LS7A_H
+
+#include "hw/pci/pci.h"
+#include "hw/pci/pcie_host.h"
+#include "hw/pci-host/pam.h"
+#include "qemu/units.h"
+#include "qemu/range.h"
+#include "qom/object.h"
+
+#define LS7A_PCH_REG_BASE 0x10000000UL
+#define LS7A_IOAPIC_REG_BASE (LS7A_PCH_REG_BASE)
+#define LS7A_PCH_MSI_ADDR_LOW 0x2FF00000UL
+
+/*
+ * According to the kernel pch irq start from 64 offset
+ * 0 ~ 16 irqs used for non-pci device while 16 ~ 64 irqs
+ * used for pci device.
+ */
+#define PCH_PIC_IRQ_OFFSET 64
+#define LS7A_DEVICE_IRQS 16
+#define LS7A_PCI_IRQS 48
+#endif
--
2.31.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [RFC PATCH v7 21/29] Enable common virtio pci support for LoongArch
2022-03-28 12:57 [RFC PATCH v7 00/29] Add LoongArch softmmu support Xiaojuan Yang
` (19 preceding siblings ...)
2022-03-28 12:57 ` [RFC PATCH v7 20/29] hw/loongarch: Add irq hierarchy for the system Xiaojuan Yang
@ 2022-03-28 12:57 ` Xiaojuan Yang
2022-03-28 23:18 ` Richard Henderson
2022-03-28 12:57 ` [RFC PATCH v7 22/29] hw/loongarch: Add some devices support for 3A5000 Xiaojuan Yang
` (8 subsequent siblings)
29 siblings, 1 reply; 71+ messages in thread
From: Xiaojuan Yang @ 2022-03-28 12:57 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland, richard.henderson, Song Gao
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
softmmu/qdev-monitor.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c
index 12fe60c467..bb5897fc76 100644
--- a/softmmu/qdev-monitor.c
+++ b/softmmu/qdev-monitor.c
@@ -60,7 +60,8 @@ typedef struct QDevAlias
QEMU_ARCH_HPPA | QEMU_ARCH_I386 | \
QEMU_ARCH_MIPS | QEMU_ARCH_PPC | \
QEMU_ARCH_RISCV | QEMU_ARCH_SH4 | \
- QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA)
+ QEMU_ARCH_SPARC | QEMU_ARCH_XTENSA | \
+ QEMU_ARCH_LOONGARCH)
#define QEMU_ARCH_VIRTIO_CCW (QEMU_ARCH_S390X)
#define QEMU_ARCH_VIRTIO_MMIO (QEMU_ARCH_M68K)
--
2.31.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [RFC PATCH v7 22/29] hw/loongarch: Add some devices support for 3A5000.
2022-03-28 12:57 [RFC PATCH v7 00/29] Add LoongArch softmmu support Xiaojuan Yang
` (20 preceding siblings ...)
2022-03-28 12:57 ` [RFC PATCH v7 21/29] Enable common virtio pci support for LoongArch Xiaojuan Yang
@ 2022-03-28 12:57 ` Xiaojuan Yang
2022-03-28 12:57 ` [RFC PATCH v7 23/29] hw/loongarch: Add LoongArch ls7a rtc device support Xiaojuan Yang
` (7 subsequent siblings)
29 siblings, 0 replies; 71+ messages in thread
From: Xiaojuan Yang @ 2022-03-28 12:57 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland, richard.henderson, Song Gao
1.Add uart,virtio-net,vga and usb for 3A5000.
2.Add irq set and map for the pci host. Non pci device
use irq 0-16, pci device use 16-64.
3.Add some unimplented device to emulate guest unused
memory space.
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
hw/loongarch/Kconfig | 7 ++++
hw/loongarch/loongson3.c | 77 ++++++++++++++++++++++++++++++++++++++
include/hw/pci-host/ls7a.h | 8 ++++
3 files changed, 92 insertions(+)
diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
index f779087416..8552ff4bee 100644
--- a/hw/loongarch/Kconfig
+++ b/hw/loongarch/Kconfig
@@ -2,6 +2,13 @@ config LOONGARCH_VIRT
bool
select PCI
select PCI_EXPRESS_GENERIC_BRIDGE
+ imply VGA_PCI
+ imply VIRTIO_VGA
+ imply PCI_DEVICES
+ select ISA_BUS
+ select SERIAL
+ select SERIAL_ISA
+ select VIRTIO_PCI
select LOONGARCH_IPI
select LOONGARCH_PCH_PIC
select LOONGARCH_PCH_MSI
diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
index 17fdcc42ca..2c96efece7 100644
--- a/hw/loongarch/loongson3.c
+++ b/hw/loongarch/loongson3.c
@@ -10,17 +10,22 @@
#include "qemu/datadir.h"
#include "qapi/error.h"
#include "hw/boards.h"
+#include "hw/char/serial.h"
#include "sysemu/sysemu.h"
#include "sysemu/qtest.h"
#include "sysemu/runstate.h"
#include "sysemu/reset.h"
#include "sysemu/rtc.h"
+#include "hw/irq.h"
+#include "net/net.h"
#include "hw/loongarch/loongarch.h"
#include "hw/intc/loongarch_ipi.h"
#include "hw/intc/loongarch_extioi.h"
#include "hw/intc/loongarch_pch_pic.h"
#include "hw/intc/loongarch_pch_msi.h"
#include "hw/pci-host/ls7a.h"
+#include "hw/pci-host/gpex.h"
+#include "hw/misc/unimp.h"
#include "target/loongarch/cpu.h"
@@ -144,6 +149,76 @@ static DeviceState *create_extioi(void)
return extioi;
}
+static void loongarch_devices_init(DeviceState *pch_pic)
+{
+ DeviceState *gpex_dev;
+ SysBusDevice *d;
+ PCIBus *pci_bus;
+ MemoryRegion *ecam_alias, *ecam_reg, *pio_alias, *pio_reg;
+ MemoryRegion *mmio_alias, *mmio_reg;
+ int i;
+
+ gpex_dev = qdev_new(TYPE_GPEX_HOST);
+ d = SYS_BUS_DEVICE(gpex_dev);
+ sysbus_realize_and_unref(d, &error_fatal);
+ pci_bus = PCI_HOST_BRIDGE(gpex_dev)->bus;
+
+ /* Map only part size_ecam bytes of ECAM space */
+ ecam_alias = g_new0(MemoryRegion, 1);
+ ecam_reg = sysbus_mmio_get_region(d, 0);
+ memory_region_init_alias(ecam_alias, OBJECT(gpex_dev), "pcie-ecam",
+ ecam_reg, 0, LS_PCIECFG_SIZE);
+ memory_region_add_subregion(get_system_memory(), LS_PCIECFG_BASE,
+ ecam_alias);
+
+ /* Map PCI mem space */
+ mmio_alias = g_new0(MemoryRegion, 1);
+ mmio_reg = sysbus_mmio_get_region(d, 1);
+ memory_region_init_alias(mmio_alias, OBJECT(gpex_dev), "pcie-mmio",
+ mmio_reg, LS7A_PCI_MEM_BASE, LS7A_PCI_MEM_SIZE);
+ memory_region_add_subregion(get_system_memory(), LS7A_PCI_MEM_BASE,
+ mmio_alias);
+
+ /* Map PCI IO port space. */
+ pio_alias = g_new0(MemoryRegion, 1);
+ pio_reg = sysbus_mmio_get_region(d, 2);
+ memory_region_init_alias(pio_alias, OBJECT(gpex_dev), "pcie-io", pio_reg,
+ LS7A_PCI_IO_OFFSET, LS7A_PCI_IO_SIZE);
+ memory_region_add_subregion(get_system_memory(), LS7A_PCI_IO_BASE,
+ pio_alias);
+
+ for (i = 0; i < GPEX_NUM_IRQS; i++) {
+ sysbus_connect_irq(d, i,
+ qdev_get_gpio_in(pch_pic, 16 + i));
+ gpex_set_irq_num(GPEX_HOST(gpex_dev), i, 16 + i);
+ }
+
+ serial_mm_init(get_system_memory(), LS7A_UART_BASE, 0,
+ qdev_get_gpio_in(pch_pic,
+ LS7A_UART_IRQ - PCH_PIC_IRQ_OFFSET),
+ 115200, serial_hd(0), DEVICE_LITTLE_ENDIAN);
+
+ /* Network init */
+ for (i = 0; i < nb_nics; i++) {
+ NICInfo *nd = &nd_table[i];
+
+ if (!nd->model) {
+ nd->model = g_strdup("virtio");
+ }
+
+ pci_nic_init_nofail(nd, pci_bus, nd->model, NULL);
+ }
+
+ /* VGA setup */
+ pci_vga_init(pci_bus);
+
+ /*
+ * There are some invalid guest memory access.
+ * Create some unimplemented devices to emulate this.
+ */
+ create_unimplemented_device("pci-dma-cfg", 0x1001041c, 0x4);
+}
+
static void loongarch_irq_init(LoongArchMachineState *lams,
DeviceState *ipi, DeviceState *extioi)
{
@@ -202,6 +277,8 @@ static void loongarch_irq_init(LoongArchMachineState *lams,
sysbus_connect_irq(d, i,
qdev_get_gpio_in(extioi, i + PCH_MSI_IRQ_START));
}
+
+ loongarch_devices_init(pch_pic);
}
static void loongarch_init(MachineState *machine)
diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h
index bf80e99ce1..f57417b096 100644
--- a/include/hw/pci-host/ls7a.h
+++ b/include/hw/pci-host/ls7a.h
@@ -15,6 +15,12 @@
#include "qemu/range.h"
#include "qom/object.h"
+#define LS7A_PCI_IO_OFFSET 0x4000
+#define LS_PCIECFG_BASE 0x20000000
+#define LS_PCIECFG_SIZE 0x08000000
+#define LS7A_PCI_IO_BASE 0x18004000UL
+#define LS7A_PCI_IO_SIZE 0xC000
+
#define LS7A_PCH_REG_BASE 0x10000000UL
#define LS7A_IOAPIC_REG_BASE (LS7A_PCH_REG_BASE)
#define LS7A_PCH_MSI_ADDR_LOW 0x2FF00000UL
@@ -27,4 +33,6 @@
#define PCH_PIC_IRQ_OFFSET 64
#define LS7A_DEVICE_IRQS 16
#define LS7A_PCI_IRQS 48
+#define LS7A_UART_IRQ (PCH_PIC_IRQ_OFFSET + 2)
+#define LS7A_UART_BASE 0x1fe001e0
#endif
--
2.31.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [RFC PATCH v7 23/29] hw/loongarch: Add LoongArch ls7a rtc device support
2022-03-28 12:57 [RFC PATCH v7 00/29] Add LoongArch softmmu support Xiaojuan Yang
` (21 preceding siblings ...)
2022-03-28 12:57 ` [RFC PATCH v7 22/29] hw/loongarch: Add some devices support for 3A5000 Xiaojuan Yang
@ 2022-03-28 12:57 ` Xiaojuan Yang
2022-03-28 12:57 ` [RFC PATCH v7 24/29] hw/loongarch: Add default bios startup support Xiaojuan Yang
` (6 subsequent siblings)
29 siblings, 0 replies; 71+ messages in thread
From: Xiaojuan Yang @ 2022-03-28 12:57 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland, richard.henderson, Song Gao
This patch add ls7a rtc device support.
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
MAINTAINERS | 1 +
hw/loongarch/Kconfig | 1 +
hw/loongarch/loongson3.c | 4 +
hw/rtc/Kconfig | 3 +
hw/rtc/ls7a_rtc.c | 323 +++++++++++++++++++++++++++++++++++++
hw/rtc/meson.build | 1 +
include/hw/pci-host/ls7a.h | 4 +
7 files changed, 337 insertions(+)
create mode 100644 hw/rtc/ls7a_rtc.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 5683531367..d41a6f7044 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1136,6 +1136,7 @@ F: include/hw/loongarch/loongarch.h
F: include/hw/intc/loongarch_*.h
F: hw/intc/loongarch_*.c
F: include/hw/pci-host/ls7a.h
+F: hw/rtc/ls7a_rtc.c
M68K Machines
-------------
diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
index 8552ff4bee..35b6680772 100644
--- a/hw/loongarch/Kconfig
+++ b/hw/loongarch/Kconfig
@@ -13,3 +13,4 @@ config LOONGARCH_VIRT
select LOONGARCH_PCH_PIC
select LOONGARCH_PCH_MSI
select LOONGARCH_EXTIOI
+ select LS7A_RTC
diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
index 2c96efece7..975e8f991b 100644
--- a/hw/loongarch/loongson3.c
+++ b/hw/loongarch/loongson3.c
@@ -217,6 +217,10 @@ static void loongarch_devices_init(DeviceState *pch_pic)
* Create some unimplemented devices to emulate this.
*/
create_unimplemented_device("pci-dma-cfg", 0x1001041c, 0x4);
+
+ sysbus_create_simple("ls7a_rtc", LS7A_RTC_REG_BASE,
+ qdev_get_gpio_in(pch_pic,
+ LS7A_RTC_IRQ - PCH_PIC_IRQ_OFFSET));
}
static void loongarch_irq_init(LoongArchMachineState *lams,
diff --git a/hw/rtc/Kconfig b/hw/rtc/Kconfig
index 730c272bc5..d0d8dda084 100644
--- a/hw/rtc/Kconfig
+++ b/hw/rtc/Kconfig
@@ -27,3 +27,6 @@ config SUN4V_RTC
config GOLDFISH_RTC
bool
+
+config LS7A_RTC
+ bool
diff --git a/hw/rtc/ls7a_rtc.c b/hw/rtc/ls7a_rtc.c
new file mode 100644
index 0000000000..d4f30c0319
--- /dev/null
+++ b/hw/rtc/ls7a_rtc.c
@@ -0,0 +1,323 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Loongarch LS7A Real Time Clock emulation
+ *
+ * Copyright (C) 2021 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "hw/sysbus.h"
+#include "hw/irq.h"
+#include "include/hw/register.h"
+#include "qemu/timer.h"
+#include "sysemu/sysemu.h"
+#include "qemu/cutils.h"
+#include "qemu/log.h"
+#include "migration/vmstate.h"
+#include "hw/misc/unimp.h"
+#include "sysemu/rtc.h"
+
+#define SYS_TOYTRIM 0x20
+#define SYS_TOYWRITE0 0x24
+#define SYS_TOYWRITE1 0x28
+#define SYS_TOYREAD0 0x2C
+#define SYS_TOYREAD1 0x30
+#define SYS_TOYMATCH0 0x34
+#define SYS_TOYMATCH1 0x38
+#define SYS_TOYMATCH2 0x3C
+#define SYS_RTCCTRL 0x40
+#define SYS_RTCTRIM 0x60
+#define SYS_RTCWRTIE0 0x64
+#define SYS_RTCREAD0 0x68
+#define SYS_RTCMATCH0 0x6C
+#define SYS_RTCMATCH1 0x70
+#define SYS_RTCMATCH2 0x74
+
+/*
+ * Shift bits and filed mask
+ */
+#define TOY_MON_MASK 0x3f
+#define TOY_DAY_MASK 0x1f
+#define TOY_HOUR_MASK 0x1f
+#define TOY_MIN_MASK 0x3f
+#define TOY_SEC_MASK 0x3f
+#define TOY_MSEC_MASK 0xf
+
+#define TOY_MON_SHIFT 26
+#define TOY_DAY_SHIFT 21
+#define TOY_HOUR_SHIFT 16
+#define TOY_MIN_SHIFT 10
+#define TOY_SEC_SHIFT 4
+#define TOY_MSEC_SHIFT 0
+
+#define TOY_MATCH_YEAR_MASK 0x3f
+#define TOY_MATCH_MON_MASK 0xf
+#define TOY_MATCH_DAY_MASK 0x1f
+#define TOY_MATCH_HOUR_MASK 0x1f
+#define TOY_MATCH_MIN_MASK 0x3f
+#define TOY_MATCH_SEC_MASK 0x3f
+
+#define TOY_MATCH_YEAR_SHIFT 26
+#define TOY_MATCH_MON_SHIFT 22
+#define TOY_MATCH_DAY_SHIFT 17
+#define TOY_MATCH_HOUR_SHIFT 12
+#define TOY_MATCH_MIN_SHIFT 6
+#define TOY_MATCH_SEC_SHIFT 0
+
+#define TOY_ENABLE_BIT (1U << 11)
+
+#define TYPE_LS7A_RTC "ls7a_rtc"
+OBJECT_DECLARE_SIMPLE_TYPE(LS7ARtcState, LS7A_RTC)
+
+struct LS7ARtcState {
+ SysBusDevice parent_obj;
+
+ MemoryRegion iomem;
+ QEMUTimer *timer;
+ /*
+ * Needed to preserve the tick_count across migration, even if the
+ * absolute value of the rtc_clock is different on the source and
+ * destination.
+ */
+ int64_t offset;
+ int64_t data;
+ int64_t save_alarm_offset;
+ int tidx;
+ uint32_t toymatch[3];
+ uint32_t toytrim;
+ uint32_t cntrctl;
+ uint32_t rtctrim;
+ uint32_t rtccount;
+ uint32_t rtcmatch[3];
+ qemu_irq toy_irq;
+};
+
+enum {
+ TOYEN = 1UL << 11,
+ RTCEN = 1UL << 13,
+};
+
+static uint64_t ls7a_rtc_read(void *opaque, hwaddr addr, unsigned size)
+{
+ LS7ARtcState *s = LS7A_RTC(opaque);
+ struct tm tm;
+ unsigned int val;
+
+ val = 0;
+
+ switch (addr) {
+ case SYS_TOYREAD0:
+ qemu_get_timedate(&tm, s->offset);
+ val = (((tm.tm_mon + 1) & TOY_MON_MASK) << TOY_MON_SHIFT)
+ | (((tm.tm_mday) & TOY_DAY_MASK) << TOY_DAY_SHIFT)
+ | (((tm.tm_hour) & TOY_HOUR_MASK) << TOY_HOUR_SHIFT)
+ | (((tm.tm_min) & TOY_MIN_MASK) << TOY_MIN_SHIFT)
+ | (((tm.tm_sec) & TOY_SEC_MASK) << TOY_SEC_SHIFT) | 0x0;
+ break;
+ case SYS_TOYREAD1:
+ qemu_get_timedate(&tm, s->offset);
+ val = tm.tm_year;
+ break;
+ case SYS_TOYMATCH0:
+ val = s->toymatch[0];
+ break;
+ case SYS_TOYMATCH1:
+ val = s->toymatch[1];
+ break;
+ case SYS_TOYMATCH2:
+ val = s->toymatch[2];
+ break;
+ case SYS_RTCCTRL:
+ val = s->cntrctl;
+ break;
+ case SYS_RTCREAD0:
+ val = s->rtccount;
+ break;
+ case SYS_RTCMATCH0:
+ val = s->rtcmatch[0];
+ break;
+ case SYS_RTCMATCH1:
+ val = s->rtcmatch[1];
+ break;
+ case SYS_RTCMATCH2:
+ val = s->rtcmatch[2];
+ break;
+ default:
+ val = 0;
+ break;
+ }
+ return val;
+}
+
+static void ls7a_rtc_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size)
+{
+ LS7ARtcState *s = LS7A_RTC(opaque);
+ struct tm tm;
+ int64_t alarm_offset, year_diff, expire_time;
+
+ switch (addr) {
+ case SYS_TOYWRITE0:
+ qemu_get_timedate(&tm, s->offset);
+ tm.tm_sec = (val >> TOY_SEC_SHIFT) & TOY_SEC_MASK;
+ tm.tm_min = (val >> TOY_MIN_SHIFT) & TOY_MIN_MASK;
+ tm.tm_hour = (val >> TOY_HOUR_SHIFT) & TOY_HOUR_MASK;
+ tm.tm_mday = ((val >> TOY_DAY_SHIFT) & TOY_DAY_MASK);
+ tm.tm_mon = ((val >> TOY_MON_SHIFT) & TOY_MON_MASK) - 1;
+ s->offset = qemu_timedate_diff(&tm);
+ break;
+ case SYS_TOYWRITE1:
+ qemu_get_timedate(&tm, s->offset);
+ tm.tm_year = val;
+ s->offset = qemu_timedate_diff(&tm);
+ break;
+ case SYS_TOYMATCH0:
+ s->toymatch[0] = val;
+ qemu_get_timedate(&tm, s->offset);
+ tm.tm_sec = (val >> TOY_MATCH_SEC_SHIFT) & TOY_MATCH_SEC_MASK;
+ tm.tm_min = (val >> TOY_MATCH_MIN_SHIFT) & TOY_MATCH_MIN_MASK;
+ tm.tm_hour = ((val >> TOY_MATCH_HOUR_SHIFT) & TOY_MATCH_HOUR_MASK);
+ tm.tm_mday = ((val >> TOY_MATCH_DAY_SHIFT) & TOY_MATCH_DAY_MASK);
+ tm.tm_mon = ((val >> TOY_MATCH_MON_SHIFT) & TOY_MATCH_MON_MASK) - 1;
+ year_diff = ((val >> TOY_MATCH_YEAR_SHIFT) & TOY_MATCH_YEAR_MASK);
+ year_diff = year_diff - (tm.tm_year & TOY_MATCH_YEAR_MASK);
+ tm.tm_year = tm.tm_year + year_diff;
+ alarm_offset = qemu_timedate_diff(&tm) - s->offset;
+ if ((alarm_offset < 0) && (alarm_offset > -5)) {
+ alarm_offset = 0;
+ }
+ expire_time = qemu_clock_get_ms(rtc_clock);
+ expire_time += ((alarm_offset * 1000) + 100);
+ timer_mod(s->timer, expire_time);
+ break;
+ case SYS_TOYMATCH1:
+ s->toymatch[1] = val;
+ break;
+ case SYS_TOYMATCH2:
+ s->toymatch[2] = val;
+ break;
+ case SYS_RTCCTRL:
+ s->cntrctl = val;
+ break;
+ case SYS_RTCWRTIE0:
+ s->rtccount = val;
+ break;
+ case SYS_RTCMATCH0:
+ s->rtcmatch[0] = val;
+ break;
+ case SYS_RTCMATCH1:
+ val = s->rtcmatch[1];
+ break;
+ case SYS_RTCMATCH2:
+ val = s->rtcmatch[2];
+ break;
+ default:
+ break;
+ }
+}
+
+static const MemoryRegionOps ls7a_rtc_ops = {
+ .read = ls7a_rtc_read,
+ .write = ls7a_rtc_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+};
+
+static void toy_timer(void *opaque)
+{
+ LS7ARtcState *s = LS7A_RTC(opaque);
+
+ if (s->cntrctl & TOY_ENABLE_BIT) {
+ qemu_irq_pulse(s->toy_irq);
+ }
+}
+
+static void ls7a_rtc_realize(DeviceState *dev, Error **errp)
+{
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+ LS7ARtcState *d = LS7A_RTC(sbd);
+ memory_region_init_io(&d->iomem, NULL, &ls7a_rtc_ops,
+ (void *)d, "ls7a_rtc", 0x100);
+
+ sysbus_init_irq(sbd, &d->toy_irq);
+
+ sysbus_init_mmio(sbd, &d->iomem);
+ d->timer = timer_new_ms(rtc_clock, toy_timer, d);
+ timer_mod(d->timer, qemu_clock_get_ms(rtc_clock) + 100);
+ d->offset = 0;
+
+ create_unimplemented_device("mmio fallback 1", 0x10013ffc, 0x4);
+}
+
+static int ls7a_rtc_pre_save(void *opaque)
+{
+ LS7ARtcState *s = LS7A_RTC(opaque);
+ struct tm tm;
+ int64_t year_diff, value;
+
+ value = s->toymatch[0];
+ qemu_get_timedate(&tm, s->offset);
+ tm.tm_sec = (value >> TOY_MATCH_SEC_SHIFT) & TOY_MATCH_SEC_MASK;
+ tm.tm_min = (value >> TOY_MATCH_MIN_SHIFT) & TOY_MATCH_MIN_MASK;
+ tm.tm_hour = ((value >> TOY_MATCH_HOUR_SHIFT) & TOY_MATCH_HOUR_MASK);
+ tm.tm_mday = ((value >> TOY_MATCH_DAY_SHIFT) & TOY_MATCH_DAY_MASK);
+ tm.tm_mon = ((value >> TOY_MATCH_MON_SHIFT) & TOY_MATCH_MON_MASK) - 1;
+ year_diff = ((value >> TOY_MATCH_YEAR_SHIFT) & TOY_MATCH_YEAR_MASK);
+ year_diff = year_diff - (tm.tm_year & TOY_MATCH_YEAR_MASK);
+ tm.tm_year = tm.tm_year + year_diff;
+ s->save_alarm_offset = qemu_timedate_diff(&tm) - s->offset;
+
+ return 0;
+}
+
+static int ls7a_rtc_post_load(void *opaque, int version_id)
+{
+ LS7ARtcState *s = LS7A_RTC(opaque);
+ int64_t expire_time;
+
+ expire_time = qemu_clock_get_ms(rtc_clock) + (s->save_alarm_offset * 1000);
+ timer_mod(s->timer, expire_time);
+
+ return 0;
+}
+
+static const VMStateDescription vmstate_ls7a_rtc = {
+ .name = "ls7a_rtc",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .pre_save = ls7a_rtc_pre_save,
+ .post_load = ls7a_rtc_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_INT64(offset, LS7ARtcState),
+ VMSTATE_INT64(save_alarm_offset, LS7ARtcState),
+ VMSTATE_UINT32(toymatch[0], LS7ARtcState),
+ VMSTATE_UINT32(cntrctl, LS7ARtcState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void ls7a_rtc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ dc->vmsd = &vmstate_ls7a_rtc;
+ dc->realize = ls7a_rtc_realize;
+ dc->desc = "ls7a rtc";
+}
+
+static const TypeInfo ls7a_rtc_info = {
+ .name = TYPE_LS7A_RTC,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(LS7ARtcState),
+ .class_init = ls7a_rtc_class_init,
+};
+
+static void ls7a_rtc_register_types(void)
+{
+ type_register_static(&ls7a_rtc_info);
+}
+
+type_init(ls7a_rtc_register_types)
diff --git a/hw/rtc/meson.build b/hw/rtc/meson.build
index 7cecdee5dd..dc33973384 100644
--- a/hw/rtc/meson.build
+++ b/hw/rtc/meson.build
@@ -11,6 +11,7 @@ softmmu_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_rtc.c'))
softmmu_ss.add(when: 'CONFIG_SUN4V_RTC', if_true: files('sun4v-rtc.c'))
softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_rtc.c'))
softmmu_ss.add(when: 'CONFIG_GOLDFISH_RTC', if_true: files('goldfish_rtc.c'))
+softmmu_ss.add(when: 'CONFIG_LS7A_RTC', if_true: files('ls7a_rtc.c'))
softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-rtc.c'))
specific_ss.add(when: 'CONFIG_MC146818RTC', if_true: files('mc146818rtc.c'))
diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h
index f57417b096..1110d25306 100644
--- a/include/hw/pci-host/ls7a.h
+++ b/include/hw/pci-host/ls7a.h
@@ -35,4 +35,8 @@
#define LS7A_PCI_IRQS 48
#define LS7A_UART_IRQ (PCH_PIC_IRQ_OFFSET + 2)
#define LS7A_UART_BASE 0x1fe001e0
+#define LS7A_RTC_IRQ (PCH_PIC_IRQ_OFFSET + 3)
+#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
#endif
--
2.31.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [RFC PATCH v7 24/29] hw/loongarch: Add default bios startup support.
2022-03-28 12:57 [RFC PATCH v7 00/29] Add LoongArch softmmu support Xiaojuan Yang
` (22 preceding siblings ...)
2022-03-28 12:57 ` [RFC PATCH v7 23/29] hw/loongarch: Add LoongArch ls7a rtc device support Xiaojuan Yang
@ 2022-03-28 12:57 ` Xiaojuan Yang
2022-03-29 3:27 ` Richard Henderson
2022-03-28 12:57 ` [RFC PATCH v7 25/29] hw/loongarch: Add -kernel and -initrd options support Xiaojuan Yang
` (5 subsequent siblings)
29 siblings, 1 reply; 71+ messages in thread
From: Xiaojuan Yang @ 2022-03-28 12:57 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland, richard.henderson, Song Gao
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
hw/loongarch/Kconfig | 4 ++
hw/loongarch/fw_cfg.c | 33 ++++++++++++++
hw/loongarch/fw_cfg.h | 15 +++++++
hw/loongarch/loongson3.c | 76 +++++++++++++++++++++++++++++++-
hw/loongarch/meson.build | 1 +
include/hw/loongarch/loongarch.h | 8 ++++
6 files changed, 135 insertions(+), 2 deletions(-)
create mode 100644 hw/loongarch/fw_cfg.c
create mode 100644 hw/loongarch/fw_cfg.h
diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
index 35b6680772..33a9066586 100644
--- a/hw/loongarch/Kconfig
+++ b/hw/loongarch/Kconfig
@@ -14,3 +14,7 @@ config LOONGARCH_VIRT
select LOONGARCH_PCH_MSI
select LOONGARCH_EXTIOI
select LS7A_RTC
+ select FW_CFG_LOONGARCH
+
+config FW_CFG_LOONGARCH
+ bool
diff --git a/hw/loongarch/fw_cfg.c b/hw/loongarch/fw_cfg.c
new file mode 100644
index 0000000000..4cefffc896
--- /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/loongarch.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 975e8f991b..2795fcc895 100644
--- a/hw/loongarch/loongson3.c
+++ b/hw/loongarch/loongson3.c
@@ -18,6 +18,8 @@
#include "sysemu/rtc.h"
#include "hw/irq.h"
#include "net/net.h"
+#include "hw/loader.h"
+#include "elf.h"
#include "hw/loongarch/loongarch.h"
#include "hw/intc/loongarch_ipi.h"
#include "hw/intc/loongarch_extioi.h"
@@ -26,9 +28,44 @@
#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 LOONGSON3_BIOSNAME "loongarch_bios.bin"
+
+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;
+}
+
static void loongarch_cpu_set_irq(void *opaque, int irq, int level)
{
LoongArchCPU *cpu = opaque;
@@ -297,6 +334,8 @@ static void loongarch_init(MachineState *machine)
MemoryRegion *address_space_mem = get_system_memory();
LoongArchMachineState *lams = LOONGARCH_MACHINE(machine);
int i;
+ int bios_size;
+ char *filename;
if (!cpu_model) {
cpu_model = LOONGARCH_CPU_TYPE_NAME("Loongson-3A5000");
@@ -313,23 +352,55 @@ static void loongarch_init(MachineState *machine)
loongarch_cpu_init(la_cpu, i);
}
+ if (ram_size < 1 * GiB) {
+ error_report("ram_size must be greater than 1G.");
+ exit(1);
+ }
+
/* Add memory region */
memory_region_init_alias(&lams->lowmem, NULL, "loongarch.lowram",
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);
offset += highram_size;
-
+ 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. */
+ filename = qemu_find_file(QEMU_FILE_TYPE_BIOS,
+ machine->firmware ?: LOONGSON3_BIOSNAME);
+ if (filename) {
+ bios_size = load_image_targphys(filename, LA_BIOS_BASE, LA_BIOS_SIZE);
+ lams->fw_cfg = loongarch_fw_cfg_init(ram_size, machine);
+ rom_set_fw(lams->fw_cfg);
+ g_free(filename);
+ } else {
+ bios_size = -1;
+ }
+
+ if ((bios_size < 0 || bios_size > LA_BIOS_SIZE) && !qtest_enabled()) {
+ error_report("Could not load LOONGARCH bios '%s'", machine->firmware);
+ exit(1);
+ }
+
+ 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);
+ 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));
+ }
+
/* Initialize the IO interrupt subsystem */
loongarch_irq_init(lams, ipi, extioi);
}
@@ -345,6 +416,7 @@ static void loongarch_class_init(ObjectClass *oc, void *data)
mc->default_ram_id = "loongarch.ram";
mc->max_cpus = LOONGARCH_MAX_VCPUS;
mc->is_default = 1;
+ mc->default_machine_opts = "firmware=loongarch_bios.bin";
mc->default_kernel_irqchip_split = false;
mc->block_default_type = IF_VIRTIO;
mc->default_boot_order = "c";
diff --git a/hw/loongarch/meson.build b/hw/loongarch/meson.build
index cecb1a5d65..2ce560f060 100644
--- a/hw/loongarch/meson.build
+++ b/hw/loongarch/meson.build
@@ -1,4 +1,5 @@
loongarch_ss = ss.source_set()
loongarch_ss.add(when: 'CONFIG_LOONGARCH_VIRT', if_true: files('loongson3.c'))
+loongarch_ss.add(when: 'CONFIG_FW_CFG_LOONGARCH', if_true: files('fw_cfg.c'))
hw_arch += {'loongarch': loongarch_ss}
diff --git a/include/hw/loongarch/loongarch.h b/include/hw/loongarch/loongarch.h
index ffe10edc65..4d5aa349b3 100644
--- a/include/hw/loongarch/loongarch.h
+++ b/include/hw/loongarch/loongarch.h
@@ -38,12 +38,20 @@
#define LOONGARCH_ISA_IO_SIZE 0x0004000
struct LoongArchMachineState {
+#define FW_CFG_ADDR 0x1e020000
+#define LA_BIOS_BASE 0x1c000000
+#define LA_BIOS_SIZE (4 * 1024 * 1024)
+
/*< private >*/
MachineState parent_obj;
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] 71+ messages in thread
* [RFC PATCH v7 25/29] hw/loongarch: Add -kernel and -initrd options support
2022-03-28 12:57 [RFC PATCH v7 00/29] Add LoongArch softmmu support Xiaojuan Yang
` (23 preceding siblings ...)
2022-03-28 12:57 ` [RFC PATCH v7 24/29] hw/loongarch: Add default bios startup support Xiaojuan Yang
@ 2022-03-28 12:57 ` Xiaojuan Yang
2022-03-28 12:57 ` [RFC PATCH v7 26/29] hw/loongarch: Add LoongArch smbios support Xiaojuan Yang
` (4 subsequent siblings)
29 siblings, 0 replies; 71+ messages in thread
From: Xiaojuan Yang @ 2022-03-28 12:57 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland, richard.henderson, Song Gao
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
hw/loongarch/loongson3.c | 81 ++++++++++++++++++++++++++++++++
include/hw/loongarch/loongarch.h | 5 ++
2 files changed, 86 insertions(+)
diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
index 2795fcc895..9533057110 100644
--- a/hw/loongarch/loongson3.c
+++ b/hw/loongarch/loongson3.c
@@ -89,6 +89,76 @@ static void loongarch_cpu_set_irq(void *opaque, int irq, int level)
}
}
+static struct _loaderparams {
+ unsigned long 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)
+{
+ return addr & 0x1fffffffll;
+}
+
+static void fw_cfg_add_kernel_info(FWCfgState *fw_cfg)
+{
+ int64_t kernel_entry, kernel_low, kernel_high, initrd_size = 0;
+ long kernel_size;
+ ram_addr_t initrd_offset = 0;
+ void *cmdline_buf;
+ int ret = 0;
+
+ kernel_size = load_elf(loaderparams.kernel_filename, NULL,
+ cpu_loongarch_virt_to_phys, NULL,
+ (uint64_t *)&kernel_entry, (uint64_t *)&kernel_low,
+ (uint64_t *)&kernel_high, NULL, 0,
+ EM_LOONGARCH, 1, 0);
+
+ if (kernel_size < 0) {
+ error_report("could not load kernel '%s': %s",
+ loaderparams.kernel_filename,
+ load_elf_strerror(kernel_size));
+ exit(1);
+ }
+
+ fw_cfg_add_i64(fw_cfg, FW_CFG_KERNEL_ENTRY, kernel_entry);
+
+ if (loaderparams.initrd_filename) {
+ initrd_size = get_image_size(loaderparams.initrd_filename);
+
+ if (initrd_size > 0) {
+ initrd_offset = MAX(INITRD_BASE,
+ ROUND_UP(kernel_high, INITRD_PAGE_SIZE));
+ if (initrd_offset + initrd_size > 0x10000000) {
+ error_report("ramdisk '%s' is too big",
+ loaderparams.initrd_filename);
+ exit(1);
+ }
+ initrd_size = load_image_targphys(loaderparams.initrd_filename,
+ initrd_offset,
+ loaderparams.ram_size - initrd_offset);
+ }
+ if (initrd_size == (target_ulong) -1) {
+ error_report("could not load initial ram disk '%s'",
+ loaderparams.initrd_filename);
+ exit(1);
+ }
+ }
+
+ cmdline_buf = g_malloc0(COMMAND_LINE_SIZE);
+ if (initrd_size > 0)
+ ret = (1 + snprintf(cmdline_buf, COMMAND_LINE_SIZE,
+ "initrd=0x%lx,%li %s", initrd_offset,
+ initrd_size, loaderparams.kernel_cmdline));
+ else
+ ret = (1 + snprintf(cmdline_buf, COMMAND_LINE_SIZE, "%s",
+ loaderparams.kernel_cmdline));
+
+ fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, ret);
+ fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, (const char *)cmdline_buf);
+}
+
static void loongarch_cpu_reset(void *opaque)
{
LoongArchCPU *cpu = opaque;
@@ -325,6 +395,9 @@ static void loongarch_irq_init(LoongArchMachineState *lams,
static void loongarch_init(MachineState *machine)
{
const char *cpu_model = machine->cpu_type;
+ const char *kernel_filename = machine->kernel_filename;
+ const char *kernel_cmdline = machine->kernel_cmdline;
+ const char *initrd_filename = machine->initrd_filename;
LoongArchCPU *la_cpu;
ipi = create_ipi();
extioi = create_extioi();
@@ -391,6 +464,14 @@ static void loongarch_init(MachineState *machine)
exit(1);
}
+ if (kernel_filename) {
+ loaderparams.ram_size = ram_size;
+ loaderparams.kernel_filename = kernel_filename;
+ loaderparams.kernel_cmdline = kernel_cmdline;
+ loaderparams.initrd_filename = initrd_filename;
+ fw_cfg_add_kernel_info(lams->fw_cfg);
+ }
+
memory_region_init_ram(&lams->bios, NULL, "loongarch.bios",
LA_BIOS_SIZE, &error_fatal);
memory_region_set_readonly(&lams->bios, true);
diff --git a/include/hw/loongarch/loongarch.h b/include/hw/loongarch/loongarch.h
index 4d5aa349b3..aae1a42741 100644
--- a/include/hw/loongarch/loongarch.h
+++ b/include/hw/loongarch/loongarch.h
@@ -42,6 +42,11 @@ struct LoongArchMachineState {
#define LA_BIOS_BASE 0x1c000000
#define LA_BIOS_SIZE (4 * 1024 * 1024)
+/* Kernels can be configured with 64KB pages */
+#define INITRD_PAGE_SIZE (64 * KiB)
+#define INITRD_BASE 0x04000000
+#define COMMAND_LINE_SIZE 4096
+
/*< private >*/
MachineState parent_obj;
--
2.31.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [RFC PATCH v7 26/29] hw/loongarch: Add LoongArch smbios support
2022-03-28 12:57 [RFC PATCH v7 00/29] Add LoongArch softmmu support Xiaojuan Yang
` (24 preceding siblings ...)
2022-03-28 12:57 ` [RFC PATCH v7 25/29] hw/loongarch: Add -kernel and -initrd options support Xiaojuan Yang
@ 2022-03-28 12:57 ` Xiaojuan Yang
2022-03-28 12:57 ` [RFC PATCH v7 27/29] hw/loongarch: Add LoongArch acpi support Xiaojuan Yang
` (3 subsequent siblings)
29 siblings, 0 replies; 71+ messages in thread
From: Xiaojuan Yang @ 2022-03-28 12:57 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland, richard.henderson, Song Gao
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
hw/loongarch/Kconfig | 1 +
hw/loongarch/loongson3.c | 43 ++++++++++++++++++++++++++++++++
include/hw/loongarch/loongarch.h | 1 +
3 files changed, 45 insertions(+)
diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
index 33a9066586..26690dee48 100644
--- a/hw/loongarch/Kconfig
+++ b/hw/loongarch/Kconfig
@@ -15,6 +15,7 @@ config LOONGARCH_VIRT
select LOONGARCH_EXTIOI
select LS7A_RTC
select FW_CFG_LOONGARCH
+ select SMBIOS
config FW_CFG_LOONGARCH
bool
diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
index 9533057110..4189ffc34d 100644
--- a/hw/loongarch/loongson3.c
+++ b/hw/loongarch/loongson3.c
@@ -29,6 +29,9 @@
#include "hw/pci-host/gpex.h"
#include "hw/misc/unimp.h"
#include "hw/loongarch/fw_cfg.h"
+#include "hw/misc/unimp.h"
+#include "hw/loongarch/fw_cfg.h"
+#include "hw/firmware/smbios.h"
#include "target/loongarch/cpu.h"
@@ -159,6 +162,42 @@ static void fw_cfg_add_kernel_info(FWCfgState *fw_cfg)
fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, (const char *)cmdline_buf);
}
+static void loongarch_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;
+ }
+
+ product = "Loongson-3A5000-7A1000-TCG";
+
+ 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 loongarch_machine_done(Notifier *notifier, void *data)
+{
+ LoongArchMachineState *lams = container_of(notifier,
+ LoongArchMachineState, machine_done);
+ loongarch_build_smbios(lams);
+}
+
static void loongarch_cpu_reset(void *opaque)
{
LoongArchCPU *cpu = opaque;
@@ -484,6 +523,10 @@ static void loongarch_init(MachineState *machine)
/* Initialize the IO interrupt subsystem */
loongarch_irq_init(lams, ipi, extioi);
+
+ lams->machine_done.notify = loongarch_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/loongarch.h b/include/hw/loongarch/loongarch.h
index aae1a42741..50be07eeb2 100644
--- a/include/hw/loongarch/loongarch.h
+++ b/include/hw/loongarch/loongarch.h
@@ -56,6 +56,7 @@ struct LoongArchMachineState {
MemoryRegion bios;
/* State for other subsystems/APIs: */
+ Notifier machine_done;
FWCfgState *fw_cfg;
};
--
2.31.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [RFC PATCH v7 27/29] hw/loongarch: Add LoongArch acpi support
2022-03-28 12:57 [RFC PATCH v7 00/29] Add LoongArch softmmu support Xiaojuan Yang
` (25 preceding siblings ...)
2022-03-28 12:57 ` [RFC PATCH v7 26/29] hw/loongarch: Add LoongArch smbios support Xiaojuan Yang
@ 2022-03-28 12:57 ` Xiaojuan Yang
2022-03-28 12:57 ` [RFC PATCH v7 28/29] hw/loongarch: Add fdt support Xiaojuan Yang
` (2 subsequent siblings)
29 siblings, 0 replies; 71+ messages in thread
From: Xiaojuan Yang @ 2022-03-28 12:57 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland, richard.henderson, Song Gao
Add a simple acpi model for LoongArch cpu
More complex functions will be added later
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
MAINTAINERS | 2 +
hw/acpi/Kconfig | 4 +
hw/acpi/ls7a.c | 374 ++++++++++++++++++
hw/acpi/meson.build | 1 +
hw/loongarch/Kconfig | 2 +
hw/loongarch/acpi-build.c | 636 +++++++++++++++++++++++++++++++
hw/loongarch/loongson3.c | 61 ++-
hw/loongarch/meson.build | 1 +
include/hw/acpi/ls7a.h | 53 +++
include/hw/loongarch/loongarch.h | 6 +
include/hw/pci-host/ls7a.h | 6 +
11 files changed, 1144 insertions(+), 2 deletions(-)
create mode 100644 hw/acpi/ls7a.c
create mode 100644 hw/loongarch/acpi-build.c
create mode 100644 include/hw/acpi/ls7a.h
diff --git a/MAINTAINERS b/MAINTAINERS
index d41a6f7044..b5ad2c7d2a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1137,6 +1137,8 @@ F: include/hw/intc/loongarch_*.h
F: hw/intc/loongarch_*.c
F: include/hw/pci-host/ls7a.h
F: hw/rtc/ls7a_rtc.c
+F: include/hw/acpi/ls7a.h
+F: hw/acpi/ls7a.c
M68K Machines
-------------
diff --git a/hw/acpi/Kconfig b/hw/acpi/Kconfig
index 19caebde6c..ff9ceb2259 100644
--- a/hw/acpi/Kconfig
+++ b/hw/acpi/Kconfig
@@ -12,6 +12,10 @@ config ACPI_X86
select ACPI_PCIHP
select ACPI_ERST
+config ACPI_LOONGARCH
+ bool
+ select ACPI
+
config ACPI_X86_ICH
bool
select ACPI_X86
diff --git a/hw/acpi/ls7a.c b/hw/acpi/ls7a.c
new file mode 100644
index 0000000000..cc658422dd
--- /dev/null
+++ b/hw/acpi/ls7a.c
@@ -0,0 +1,374 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * LoongArch ACPI implementation
+ *
+ * Copyright (C) 2021 Loongson Technology Corporation Limited
+ */
+
+#include "qemu/osdep.h"
+#include "sysemu/sysemu.h"
+#include "hw/hw.h"
+#include "hw/irq.h"
+#include "sysemu/reset.h"
+#include "sysemu/runstate.h"
+#include "hw/acpi/acpi.h"
+#include "hw/acpi/ls7a.h"
+#include "hw/nvram/fw_cfg.h"
+#include "qemu/config-file.h"
+#include "qapi/opts-visitor.h"
+#include "qapi/qapi-events-run-state.h"
+#include "qapi/error.h"
+#include "hw/pci-host/ls7a.h"
+#include "hw/mem/pc-dimm.h"
+#include "hw/mem/nvdimm.h"
+#include "migration/vmstate.h"
+
+static void ls7a_pm_update_sci_fn(ACPIREGS *regs)
+{
+ LS7APMState *pm = container_of(regs, LS7APMState, acpi_regs);
+ acpi_update_sci(&pm->acpi_regs, pm->irq);
+}
+
+static uint64_t ls7a_gpe_readb(void *opaque, hwaddr addr, unsigned width)
+{
+ LS7APMState *pm = opaque;
+ return acpi_gpe_ioport_readb(&pm->acpi_regs, addr);
+}
+
+static void ls7a_gpe_writeb(void *opaque, hwaddr addr, uint64_t val,
+ unsigned width)
+{
+ LS7APMState *pm = opaque;
+ acpi_gpe_ioport_writeb(&pm->acpi_regs, addr, val);
+ acpi_update_sci(&pm->acpi_regs, pm->irq);
+}
+
+static const MemoryRegionOps ls7a_gpe_ops = {
+ .read = ls7a_gpe_readb,
+ .write = ls7a_gpe_writeb,
+ .valid.min_access_size = 1,
+ .valid.max_access_size = 8,
+ .impl.min_access_size = 1,
+ .impl.max_access_size = 1,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+#define VMSTATE_GPE_ARRAY(_field, _state) \
+ { \
+ .name = (stringify(_field)), \
+ .version_id = 0, \
+ .num = ACPI_GPE0_LEN, \
+ .info = &vmstate_info_uint8, \
+ .size = sizeof(uint8_t), \
+ .flags = VMS_ARRAY | VMS_POINTER, \
+ .offset = vmstate_offset_pointer(_state, _field, uint8_t), \
+ }
+
+static uint64_t ls7a_reset_readw(void *opaque, hwaddr addr, unsigned width)
+{
+ return 0;
+}
+
+static void ls7a_reset_writew(void *opaque, hwaddr addr, uint64_t val,
+ unsigned width)
+{
+ if (val & 1) {
+ qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
+ return;
+ }
+}
+
+static const MemoryRegionOps ls7a_reset_ops = {
+ .read = ls7a_reset_readw,
+ .write = ls7a_reset_writew,
+ .valid.min_access_size = 4,
+ .valid.max_access_size = 4,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+const VMStateDescription vmstate_ls7a_pm = {
+ .name = "ls7a_pm",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT16(acpi_regs.pm1.evt.sts, LS7APMState),
+ VMSTATE_UINT16(acpi_regs.pm1.evt.en, LS7APMState),
+ VMSTATE_UINT16(acpi_regs.pm1.cnt.cnt, LS7APMState),
+ VMSTATE_TIMER_PTR(acpi_regs.tmr.timer, LS7APMState),
+ VMSTATE_INT64(acpi_regs.tmr.overflow_time, LS7APMState),
+ VMSTATE_GPE_ARRAY(acpi_regs.gpe.sts, LS7APMState),
+ VMSTATE_GPE_ARRAY(acpi_regs.gpe.en, LS7APMState),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static inline int64_t acpi_pm_tmr_get_clock(void)
+{
+ return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), PM_TIMER_FREQUENCY,
+ NANOSECONDS_PER_SECOND);
+}
+
+static uint32_t acpi_pm_tmr_get(ACPIREGS *ar)
+{
+ uint32_t d = acpi_pm_tmr_get_clock();
+ return d & 0xffffff;
+}
+
+static void acpi_pm_tmr_timer(void *opaque)
+{
+ ACPIREGS *ar = opaque;
+ qemu_system_wakeup_request(QEMU_WAKEUP_REASON_PMTIMER, NULL);
+ ar->tmr.update_sci(ar);
+}
+
+static uint64_t acpi_pm_tmr_read(void *opaque, hwaddr addr, unsigned width)
+{
+ return acpi_pm_tmr_get(opaque);
+}
+
+static void acpi_pm_tmr_write(void *opaque, hwaddr addr, uint64_t val,
+ unsigned width)
+{
+}
+
+static const MemoryRegionOps acpi_pm_tmr_ops = {
+ .read = acpi_pm_tmr_read,
+ .write = acpi_pm_tmr_write,
+ .valid.min_access_size = 4,
+ .valid.max_access_size = 4,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void ls7a_pm_tmr_init(ACPIREGS *ar, acpi_update_sci_fn update_sci,
+ MemoryRegion *parent, uint64_t offset)
+{
+ ar->tmr.update_sci = update_sci;
+ ar->tmr.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, acpi_pm_tmr_timer, ar);
+ memory_region_init_io(&ar->tmr.io, memory_region_owner(parent),
+ &acpi_pm_tmr_ops, ar, "acpi-tmr", 4);
+ memory_region_add_subregion(parent, offset, &ar->tmr.io);
+}
+
+static void acpi_pm1_evt_write_sts(ACPIREGS *ar, uint16_t val)
+{
+ uint16_t pm1_sts = acpi_pm1_evt_get_sts(ar);
+ if (pm1_sts & val & ACPI_BITMASK_TIMER_STATUS) {
+ /* if TMRSTS is reset, then compute the new overflow time */
+ acpi_pm_tmr_calc_overflow_time(ar);
+ }
+ ar->pm1.evt.sts &= ~val;
+}
+
+static uint64_t acpi_pm_evt_read(void *opaque, hwaddr addr, unsigned width)
+{
+ ACPIREGS *ar = opaque;
+ switch (addr) {
+ case 0:
+ return acpi_pm1_evt_get_sts(ar);
+ case 4:
+ return ar->pm1.evt.en;
+ default:
+ return 0;
+ }
+}
+
+static void acpi_pm1_evt_write_en(ACPIREGS *ar, uint16_t val)
+{
+ ar->pm1.evt.en = val;
+ qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_RTC,
+ val & ACPI_BITMASK_RT_CLOCK_ENABLE);
+ qemu_system_wakeup_enable(QEMU_WAKEUP_REASON_PMTIMER,
+ val & ACPI_BITMASK_TIMER_ENABLE);
+}
+
+static void acpi_pm_evt_write(void *opaque, hwaddr addr, uint64_t val,
+ unsigned width)
+{
+ ACPIREGS *ar = opaque;
+ switch (addr) {
+ case 0:
+ acpi_pm1_evt_write_sts(ar, val);
+ ar->pm1.evt.update_sci(ar);
+ break;
+ case 4:
+ acpi_pm1_evt_write_en(ar, val);
+ ar->pm1.evt.update_sci(ar);
+ break;
+ }
+}
+
+static const MemoryRegionOps acpi_pm_evt_ops = {
+ .read = acpi_pm_evt_read,
+ .write = acpi_pm_evt_write,
+ .valid.min_access_size = 1,
+ .valid.max_access_size = 4,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void ls7a_pm1_evt_init(ACPIREGS *ar, acpi_update_sci_fn update_sci,
+ MemoryRegion *parent, uint64_t offset)
+{
+ ar->pm1.evt.update_sci = update_sci;
+ memory_region_init_io(&ar->pm1.evt.io, memory_region_owner(parent),
+ &acpi_pm_evt_ops, ar, "acpi-evt", 8);
+ memory_region_add_subregion(parent, offset, &ar->pm1.evt.io);
+}
+
+static uint64_t acpi_pm_cnt_read(void *opaque, hwaddr addr, unsigned width)
+{
+ ACPIREGS *ar = opaque;
+ return ar->pm1.cnt.cnt;
+}
+
+/* ACPI PM1aCNT */
+static void acpi_pm1_cnt_write(ACPIREGS *ar, uint16_t val)
+{
+ ar->pm1.cnt.cnt = val & ~(ACPI_BITMASK_SLEEP_ENABLE);
+
+ if (val & ACPI_BITMASK_SLEEP_ENABLE) {
+ /* Change suspend type */
+ uint16_t sus_typ = (val >> 10) & 7;
+ switch (sus_typ) {
+ /* Not support s3 s4 yet */
+ case 7: /* Soft power off */
+ qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static void acpi_pm_cnt_write(void *opaque, hwaddr addr, uint64_t val,
+ unsigned width)
+{
+ acpi_pm1_cnt_write(opaque, val);
+}
+
+static const MemoryRegionOps acpi_pm_cnt_ops = {
+ .read = acpi_pm_cnt_read,
+ .write = acpi_pm_cnt_write,
+ .valid.min_access_size = 1,
+ .valid.max_access_size = 4,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void acpi_notify_wakeup(Notifier *notifier, void *data)
+{
+ ACPIREGS *ar = container_of(notifier, ACPIREGS, wakeup);
+ WakeupReason *reason = data;
+
+ switch (*reason) {
+ case QEMU_WAKEUP_REASON_RTC:
+ ar->pm1.evt.sts |=
+ (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_RT_CLOCK_STATUS);
+ break;
+ case QEMU_WAKEUP_REASON_PMTIMER:
+ ar->pm1.evt.sts |=
+ (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_TIMER_STATUS);
+ break;
+ case QEMU_WAKEUP_REASON_OTHER:
+ /*
+ * ACPI_BITMASK_WAKE_STATUS should be set on resume.
+ * Pretend that resume was caused by power button
+ */
+ ar->pm1.evt.sts |=
+ (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_POWER_BUTTON_STATUS);
+ break;
+ default:
+ break;
+ }
+}
+
+static void ls7a_pm1_cnt_init(ACPIREGS *ar, MemoryRegion *parent,
+ uint64_t offset)
+{
+ ar->wakeup.notify = acpi_notify_wakeup;
+ qemu_register_wakeup_notifier(&ar->wakeup);
+ memory_region_init_io(&ar->pm1.cnt.io, memory_region_owner(parent),
+ &acpi_pm_cnt_ops, ar, "acpi-cnt", 4);
+ memory_region_add_subregion(parent, offset, &ar->pm1.cnt.io);
+}
+
+static void ls7a_pm_reset(DeviceState *d)
+{
+ LS7APMState *pm = LS7A_PM(d);
+
+ acpi_pm1_evt_reset(&pm->acpi_regs);
+ acpi_pm1_cnt_reset(&pm->acpi_regs);
+ acpi_pm_tmr_reset(&pm->acpi_regs);
+ acpi_gpe_reset(&pm->acpi_regs);
+
+ acpi_update_sci(&pm->acpi_regs, pm->irq);
+}
+
+static void pm_powerdown_req(Notifier *n, void *opaque)
+{
+ LS7APMState *pm = container_of(n, LS7APMState, powerdown_notifier);
+
+ acpi_pm1_evt_power_down(&pm->acpi_regs);
+}
+
+void ls7a_pm_init(DeviceState *ls7a_pm, qemu_irq pm_irq)
+{
+ LS7APMState *pm = LS7A_PM(ls7a_pm);
+ pm->irq = pm_irq;
+}
+
+static void ls7a_pm_realize(DeviceState *dev, Error **errp)
+{
+ LS7APMState *pm = LS7A_PM(dev);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+
+ /*
+ * ls7a board acpi hardware info, including
+ * acpi system io base address
+ * acpi gpe length
+ * acpi sci irq number
+ */
+
+ memory_region_init(&pm->iomem, OBJECT(pm), "ls7a_pm", ACPI_IO_SIZE);
+ sysbus_init_mmio(sbd, &pm->iomem);
+
+ ls7a_pm_tmr_init(&pm->acpi_regs, ls7a_pm_update_sci_fn,
+ &pm->iomem, LS7A_PM_TMR_BLK);
+ ls7a_pm1_evt_init(&pm->acpi_regs, ls7a_pm_update_sci_fn,
+ &pm->iomem, LS7A_PM_EVT_BLK);
+ ls7a_pm1_cnt_init(&pm->acpi_regs, &pm->iomem, LS7A_PM_CNT_BLK);
+
+ acpi_gpe_init(&pm->acpi_regs, ACPI_GPE0_LEN);
+ memory_region_init_io(&pm->iomem_gpe, OBJECT(pm), &ls7a_gpe_ops, pm,
+ "acpi-gpe0", ACPI_GPE0_LEN);
+ sysbus_init_mmio(sbd, &pm->iomem_gpe);
+
+ memory_region_init_io(&pm->iomem_reset, OBJECT(pm),
+ &ls7a_reset_ops, pm, "acpi-reset", 4);
+ sysbus_init_mmio(sbd, &pm->iomem_reset);
+
+ pm->powerdown_notifier.notify = pm_powerdown_req;
+ qemu_register_powerdown_notifier(&pm->powerdown_notifier);
+}
+
+static void ls7a_pm_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = ls7a_pm_realize;
+ dc->reset = ls7a_pm_reset;
+ dc->desc = "PM";
+ dc->vmsd = &vmstate_ls7a_pm;
+}
+
+static const TypeInfo ls7a_pm_info = {
+ .name = TYPE_LS7A_PM,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(LS7APMState),
+ .class_init = ls7a_pm_class_init,
+};
+
+static void ls7a_pm_register_types(void)
+{
+ type_register_static(&ls7a_pm_info);
+}
+
+type_init(ls7a_pm_register_types)
diff --git a/hw/acpi/meson.build b/hw/acpi/meson.build
index 8bea2e6933..e6b1ba6f3c 100644
--- a/hw/acpi/meson.build
+++ b/hw/acpi/meson.build
@@ -25,6 +25,7 @@ acpi_ss.add(when: 'CONFIG_ACPI_X86_ICH', if_true: files('ich9.c', 'tco.c'))
acpi_ss.add(when: 'CONFIG_ACPI_ERST', if_true: files('erst.c'))
acpi_ss.add(when: 'CONFIG_IPMI', if_true: files('ipmi.c'), if_false: files('ipmi-stub.c'))
acpi_ss.add(when: 'CONFIG_PC', if_false: files('acpi-x86-stub.c'))
+acpi_ss.add(when: 'CONFIG_ACPI_LOONGARCH', if_true: files('ls7a.c'))
if have_tpm
acpi_ss.add(files('tpm.c'))
endif
diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
index 26690dee48..6ce41e4b36 100644
--- a/hw/loongarch/Kconfig
+++ b/hw/loongarch/Kconfig
@@ -16,6 +16,8 @@ config LOONGARCH_VIRT
select LS7A_RTC
select FW_CFG_LOONGARCH
select SMBIOS
+ select ACPI_LOONGARCH
+ select ACPI_PCI
config FW_CFG_LOONGARCH
bool
diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c
new file mode 100644
index 0000000000..81e24cb851
--- /dev/null
+++ b/hw/loongarch/acpi-build.c
@@ -0,0 +1,636 @@
+/* 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/loongarch.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/ls7a.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)
+{
+ AmlAddressSpace as = AML_AS_SYSTEM_MEMORY;
+ uint64_t base = LS7A_ACPI_REG_BASE;
+ AcpiFadtData fadt = {
+ .rev = 3,
+ .flags =
+ (1 << ACPI_FADT_F_WBINVD) |
+ (1 << ACPI_FADT_F_PROC_C1) |
+ (1 << ACPI_FADT_F_SLP_BUTTON) |
+ (1 << ACPI_FADT_F_TMR_VAL_EXT) |
+ (1 << ACPI_FADT_F_RESET_REG_SUP),
+ /* C2 state not supported */
+ .plvl2_lat = 0xfff,
+ /* C3 state not supported */
+ .plvl3_lat = 0xfff,
+ .smi_cmd = 0x00,
+ .sci_int = ACPI_SCI_IRQ,
+ .acpi_enable_cmd = 0x00,
+ .acpi_disable_cmd = 0x00,
+ .pm1a_evt = { .space_id = as, .bit_width = 8 * 8,
+ .address = base + LS7A_PM_EVT_BLK },
+ .pm1a_cnt = { .space_id = as, .bit_width = 4 * 8,
+ .address = base + LS7A_PM_CNT_BLK },
+ .pm_tmr = { .space_id = as, .bit_width = 4 * 8,
+ .address = base + LS7A_PM_TMR_BLK },
+ .gpe0_blk = { .space_id = as, .bit_width = 8 * 8,
+ .address = base + LS7A_GPE0_STS_REG},
+ .reset_reg = { .space_id = as, .bit_width = 4 * 8,
+ .address = base + LS7A_GPE0_RESET_REG},
+ .reset_val = 0x1,
+ };
+ *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));
+}
+
+/*
+ * ACPI spec 1.0b,
+ * 5.2.6 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 */
+}
+
+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++) {
+ /* Rev 1.0b, Table 5-13 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 */
+ }
+
+ /* Rev 1.0b, Table 5-13 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 */
+
+ /* Rev 1.0b, Table 5-13 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, 0x2ff00000, 8);/* Address */
+ build_append_int_noprefix(table_data, 0x40, 4); /* Start */
+ build_append_int_noprefix(table_data, 0xc0, 4); /* Count */
+
+ /* Rev 1.0b, Table 5-13 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, 0x10000000, 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);
+}
+
+/*
+ * ACPI spec, Revision 3.0
+ * 5.2.15 System Resource Affinity Table (SRAT)
+ */
+static void
+build_srat(GArray *table_data, BIOSLinker *linker, MachineState *machine)
+{
+ uint64_t i, mem_len, mem_base;
+ 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) {
+ /* 5.2.15.1 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 */
+ }
+
+ mem_base = 0;
+ mem_len = 0x10000000;
+ build_srat_memory(table_data, mem_base, mem_len,
+ 0, MEM_AFFINITY_ENABLED);
+
+ mem_base = 0x90000000;
+ mem_len = machine->ram_size - 0x10000000;
+ build_srat_memory(table_data, mem_base, mem_len,
+ 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_ls7a_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);
+}
+
+static void
+build_dsdt(GArray *table_data, BIOSLinker *linker, MachineState *machine)
+{
+ Aml *dsdt, *sb_scope, *scope, *dev, *crs, *pkg;
+ uint64_t base = LS7A_ACPI_REG_BASE;
+ 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_ls7a_pci0_int(dsdt);
+ build_ls7a_uart_device_aml(dsdt);
+
+ scope = aml_scope("_GPE");
+ {
+ aml_append(scope, aml_name_decl("_HID", aml_string("ACPI0006")));
+ }
+ aml_append(dsdt, scope);
+
+ 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));
+
+ /* Reserve GPE0 block resources */
+ dev = aml_device("GPE0");
+ aml_append(dev, aml_name_decl("_HID", aml_string("PNP0A06")));
+ aml_append(dev, aml_name_decl("_UID", aml_string("GPE0 resources")));
+ /* Device present, functioning, decoding, not shown in UI */
+ aml_append(dev, aml_name_decl("_STA", aml_int(0xB)));
+ crs = aml_resource_template();
+ aml_append(crs,
+ aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
+ AML_CACHEABLE, AML_READ_WRITE,
+ 0, base + LS7A_GPE0_STS_REG,
+ base + LS7A_GPE0_STS_REG + 0x3, 0, 0x4));
+ aml_append(dev, aml_name_decl("_CRS", crs));
+ aml_append(scope, dev);
+ aml_append(dsdt, scope);
+
+ scope = aml_scope("\\");
+ pkg = aml_package(4);
+ aml_append(pkg, aml_int(7)); /* PM1a_CNT.SLP_TYP */
+ aml_append(pkg, aml_int(7)); /* PM1b_CNT.SLP_TYP not impl. */
+ 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 4189ffc34d..5f0dcfa419 100644
--- a/hw/loongarch/loongson3.c
+++ b/hw/loongarch/loongson3.c
@@ -32,6 +32,8 @@
#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 "target/loongarch/cpu.h"
@@ -195,6 +197,7 @@ void loongarch_machine_done(Notifier *notifier, void *data)
{
LoongArchMachineState *lams = container_of(notifier,
LoongArchMachineState, machine_done);
+ loongarch_acpi_setup(lams);
loongarch_build_smbios(lams);
}
@@ -297,11 +300,11 @@ static DeviceState *create_extioi(void)
static void loongarch_devices_init(DeviceState *pch_pic)
{
- DeviceState *gpex_dev;
+ DeviceState *gpex_dev, *ls7a_pm;
SysBusDevice *d;
PCIBus *pci_bus;
MemoryRegion *ecam_alias, *ecam_reg, *pio_alias, *pio_reg;
- MemoryRegion *mmio_alias, *mmio_reg;
+ MemoryRegion *mmio_alias, *mmio_reg, *pm_reg;
int i;
gpex_dev = qdev_new(TYPE_GPEX_HOST);
@@ -367,6 +370,19 @@ static void loongarch_devices_init(DeviceState *pch_pic)
sysbus_create_simple("ls7a_rtc", LS7A_RTC_REG_BASE,
qdev_get_gpio_in(pch_pic,
LS7A_RTC_IRQ - PCH_PIC_IRQ_OFFSET));
+
+ /* Init pm */
+ ls7a_pm = qdev_new(TYPE_LS7A_PM);
+ d = SYS_BUS_DEVICE(ls7a_pm);
+ sysbus_realize_and_unref(d, &error_fatal);
+ ls7a_pm_init(ls7a_pm, qdev_get_gpio_in(pch_pic,
+ ACPI_SCI_IRQ - PCH_PIC_IRQ_OFFSET));
+ pm_reg = sysbus_mmio_get_region(d, 0);
+ memory_region_add_subregion(get_system_memory(), ACPI_IO_BASE, pm_reg);
+ memory_region_add_subregion(pm_reg, LS7A_GPE0_STS_REG,
+ sysbus_mmio_get_region(d, 1));
+ memory_region_add_subregion(pm_reg, LS7A_GPE0_RESET_REG,
+ sysbus_mmio_get_region(d, 2));
}
static void loongarch_irq_init(LoongArchMachineState *lams,
@@ -529,6 +545,40 @@ static void loongarch_init(MachineState *machine)
}
+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);
@@ -545,6 +595,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[] = {
@@ -552,6 +608,7 @@ static const TypeInfo loongarch_machine_types[] = {
.name = TYPE_LOONGARCH_MACHINE,
.parent = TYPE_MACHINE,
.instance_size = sizeof(LoongArchMachineState),
+ .instance_init = loongarch_machine_initfn,
.class_init = loongarch_class_init,
}
};
diff --git a/hw/loongarch/meson.build b/hw/loongarch/meson.build
index 2ce560f060..e348d1e192 100644
--- a/hw/loongarch/meson.build
+++ b/hw/loongarch/meson.build
@@ -1,5 +1,6 @@
loongarch_ss = ss.source_set()
loongarch_ss.add(when: 'CONFIG_LOONGARCH_VIRT', if_true: files('loongson3.c'))
loongarch_ss.add(when: 'CONFIG_FW_CFG_LOONGARCH', if_true: files('fw_cfg.c'))
+loongarch_ss.add(when: 'CONFIG_ACPI', if_true: files('acpi-build.c'))
hw_arch += {'loongarch': loongarch_ss}
diff --git a/include/hw/acpi/ls7a.h b/include/hw/acpi/ls7a.h
new file mode 100644
index 0000000000..28fe23c8a3
--- /dev/null
+++ b/include/hw/acpi/ls7a.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * QEMU GMCH/LS7A PCI PM Emulation
+ *
+ * Copyright (C) 2021 Loongson Technology Corporation Limited
+ */
+
+#ifndef HW_ACPI_LS7A_H
+#define HW_ACPI_LS7A_H
+
+#include "hw/acpi/acpi.h"
+#include "hw/sysbus.h"
+
+#define LS7A_ACPI_IO_BASE 0x800
+#define LS7A_ACPI_IO_SIZE 0x100
+#define LS7A_PM_EVT_BLK (0x0C) /* 4 bytes */
+#define LS7A_PM_CNT_BLK (0x14) /* 2 bytes */
+#define LS7A_GPE0_STS_REG (0x28) /* 4 bytes */
+#define LS7A_GPE0_ENA_REG (0x2C) /* 4 bytes */
+#define LS7A_GPE0_RESET_REG (0x30) /* 4 bytes */
+#define LS7A_PM_TMR_BLK (0x18) /* 4 bytes */
+#define LS7A_GPE0_LEN (8)
+#define ACPI_IO_BASE (LS7A_ACPI_REG_BASE)
+#define ACPI_GPE0_LEN (LS7A_GPE0_LEN)
+#define ACPI_IO_SIZE (LS7A_ACPI_IO_SIZE)
+#define ACPI_SCI_IRQ (LS7A_SCI_IRQ)
+
+typedef struct LS7APMState {
+ SysBusDevice parent_obj;
+ /*
+ * In ls7a spec says that pm1_cnt register is 32bit width and
+ * that the upper 16bits are reserved and unused.
+ * PM1a_CNT_BLK = 2 in FADT so it is defined as uint16_t.
+ */
+ ACPIREGS acpi_regs;
+
+ MemoryRegion iomem;
+ MemoryRegion iomem_gpe;
+ MemoryRegion iomem_reset;
+
+ qemu_irq irq; /* SCI */
+
+ uint32_t pm_io_base;
+ Notifier powerdown_notifier;
+} LS7APMState;
+
+#define TYPE_LS7A_PM "ls7a_pm"
+DECLARE_INSTANCE_CHECKER(struct LS7APMState, LS7A_PM, TYPE_LS7A_PM)
+
+void ls7a_pm_init(DeviceState *ls7a_pm, qemu_irq irq);
+
+extern const VMStateDescription vmstate_ls7a_pm;
+#endif /* HW_ACPI_LS7A_H */
diff --git a/include/hw/loongarch/loongarch.h b/include/hw/loongarch/loongarch.h
index 50be07eeb2..689560dcde 100644
--- a/include/hw/loongarch/loongarch.h
+++ b/include/hw/loongarch/loongarch.h
@@ -58,8 +58,14 @@ struct LoongArchMachineState {
/* State for other subsystems/APIs: */
Notifier machine_done;
FWCfgState *fw_cfg;
+ OnOffAuto acpi;
+ char *oem_id;
+ char *oem_table_id;
};
#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 1110d25306..baf8dde84e 100644
--- a/include/hw/pci-host/ls7a.h
+++ b/include/hw/pci-host/ls7a.h
@@ -11,6 +11,7 @@
#include "hw/pci/pci.h"
#include "hw/pci/pcie_host.h"
#include "hw/pci-host/pam.h"
+#include "hw/acpi/ls7a.h"
#include "qemu/units.h"
#include "qemu/range.h"
#include "qom/object.h"
@@ -21,6 +22,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
@@ -39,4 +43,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] 71+ messages in thread
* [RFC PATCH v7 28/29] hw/loongarch: Add fdt support.
2022-03-28 12:57 [RFC PATCH v7 00/29] Add LoongArch softmmu support Xiaojuan Yang
` (26 preceding siblings ...)
2022-03-28 12:57 ` [RFC PATCH v7 27/29] hw/loongarch: Add LoongArch acpi support Xiaojuan Yang
@ 2022-03-28 12:57 ` Xiaojuan Yang
2022-03-28 12:57 ` [RFC PATCH v7 29/29] tests/tcg/loongarch64: Add hello/memory test in loongarch64 system Xiaojuan Yang
2022-03-28 18:13 ` [RFC PATCH v7 00/29] Add LoongArch softmmu support Richard Henderson
29 siblings, 0 replies; 71+ messages in thread
From: Xiaojuan Yang @ 2022-03-28 12:57 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland, richard.henderson, Song Gao
Add tree nodes for 3A5000 device tree.
- cpu nodes;
- fw_cfg nodes;
- pcie nodes.
The lastest loongarch bios have supported fdt.
- https://github.com/loongson/edk2
- https://github.com/loongson/edk2-platforms
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
hw/loongarch/loongson3.c | 136 +++++++++++++++++++++++++++++++
include/hw/loongarch/loongarch.h | 4 +
target/loongarch/cpu.c | 2 +
target/loongarch/cpu.h | 3 +
4 files changed, 145 insertions(+)
diff --git a/hw/loongarch/loongson3.c b/hw/loongarch/loongson3.c
index 5f0dcfa419..0ae6075a3e 100644
--- a/hw/loongarch/loongson3.c
+++ b/hw/loongarch/loongson3.c
@@ -34,6 +34,9 @@
#include "hw/firmware/smbios.h"
#include "hw/acpi/aml-build.h"
#include "qapi/qapi-visit-common.h"
+#include "sysemu/device_tree.h"
+
+#include <libfdt.h>
#include "target/loongarch/cpu.h"
@@ -447,6 +450,126 @@ static void loongarch_irq_init(LoongArchMachineState *lams,
loongarch_devices_init(pch_pic);
}
+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);
+}
+
static void loongarch_init(MachineState *machine)
{
const char *cpu_model = machine->cpu_type;
@@ -474,12 +597,16 @@ static void loongarch_init(MachineState *machine)
exit(1);
}
+ create_fdt(lams);
+
/* Init CPUs */
for (i = 0; i < machine->smp.cpus; i++) {
la_cpu = LOONGARCH_CPU(cpu_create(machine->cpu_type));
loongarch_cpu_init(la_cpu, i);
}
+ fdt_add_cpu_nodes(lams);
+
if (ram_size < 1 * GiB) {
error_report("ram_size must be greater than 1G.");
exit(1);
@@ -519,6 +646,8 @@ static void loongarch_init(MachineState *machine)
exit(1);
}
+ fdt_add_fw_cfg_node(lams);
+
if (kernel_filename) {
loaderparams.ram_size = ram_size;
loaderparams.kernel_filename = kernel_filename;
@@ -543,6 +672,13 @@ static void loongarch_init(MachineState *machine)
lams->machine_done.notify = loongarch_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/loongarch.h b/include/hw/loongarch/loongarch.h
index 689560dcde..96dae9205f 100644
--- a/include/hw/loongarch/loongarch.h
+++ b/include/hw/loongarch/loongarch.h
@@ -42,6 +42,9 @@ struct LoongArchMachineState {
#define LA_BIOS_BASE 0x1c000000
#define LA_BIOS_SIZE (4 * 1024 * 1024)
+#define LA_FDT_BASE 0x1c400000
+#define LA_FDT_SIZE 0x100000
+
/* Kernels can be configured with 64KB pages */
#define INITRD_PAGE_SIZE (64 * KiB)
#define INITRD_BASE 0x04000000
@@ -61,6 +64,7 @@ struct LoongArchMachineState {
OnOffAuto acpi;
char *oem_id;
char *oem_table_id;
+ int fdt_size;
};
#define TYPE_LOONGARCH_MACHINE MACHINE_TYPE_NAME("virt")
diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index deaa0b4f31..90106939a2 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -337,6 +337,8 @@ static void loongarch_3a5000_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 15ea1dc43d..e1add5af39 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -360,6 +360,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] 71+ messages in thread
* [RFC PATCH v7 29/29] tests/tcg/loongarch64: Add hello/memory test in loongarch64 system
2022-03-28 12:57 [RFC PATCH v7 00/29] Add LoongArch softmmu support Xiaojuan Yang
` (27 preceding siblings ...)
2022-03-28 12:57 ` [RFC PATCH v7 28/29] hw/loongarch: Add fdt support Xiaojuan Yang
@ 2022-03-28 12:57 ` Xiaojuan Yang
2022-03-29 3:29 ` Richard Henderson
2022-03-28 18:13 ` [RFC PATCH v7 00/29] Add LoongArch softmmu support Richard Henderson
29 siblings, 1 reply; 71+ messages in thread
From: Xiaojuan Yang @ 2022-03-28 12:57 UTC (permalink / raw)
To: qemu-devel; +Cc: mark.cave-ayland, richard.henderson, Song Gao
- We write a very minimal softmmu harness.
- This is a very simple smoke test with no need to run a full Linux/kernel.
- The Makefile.softmmu-target record the rule to run.
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
---
MAINTAINERS | 1 +
tests/tcg/loongarch64/Makefile.softmmu-target | 33 +++++++
tests/tcg/loongarch64/system/boot.S | 56 ++++++++++++
tests/tcg/loongarch64/system/kernel.ld | 30 +++++++
tests/tcg/loongarch64/system/regdef.h | 86 +++++++++++++++++++
5 files changed, 206 insertions(+)
create mode 100644 tests/tcg/loongarch64/Makefile.softmmu-target
create mode 100644 tests/tcg/loongarch64/system/boot.S
create mode 100644 tests/tcg/loongarch64/system/kernel.ld
create mode 100644 tests/tcg/loongarch64/system/regdef.h
diff --git a/MAINTAINERS b/MAINTAINERS
index b5ad2c7d2a..991172091a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -217,6 +217,7 @@ LoongArch TCG CPUs
M: Song Gao <gaosong@loongson.cn>
S: Maintained
F: target/loongarch/
+F: tests/tcg/loongarch64/
M68K TCG CPUs
M: Laurent Vivier <laurent@vivier.eu>
diff --git a/tests/tcg/loongarch64/Makefile.softmmu-target b/tests/tcg/loongarch64/Makefile.softmmu-target
new file mode 100644
index 0000000000..908f3a8c0f
--- /dev/null
+++ b/tests/tcg/loongarch64/Makefile.softmmu-target
@@ -0,0 +1,33 @@
+#
+# Loongarch64 system tests
+#
+
+LOONGARCH64_SYSTEM_SRC=$(SRC_PATH)/tests/tcg/loongarch64/system
+VPATH+=$(LOONGARCH64_SYSTEM_SRC)
+
+# These objects provide the basic boot code and helper functions for all tests
+CRT_OBJS=boot.o
+
+LOONGARCH64_TEST_SRCS=$(wildcard $(LOONGARCH64_SYSTEM_SRC)/*.c)
+LOONGARCH64_TESTS = $(patsubst $(LOONGARCH64_SYSTEM_SRC)/%.c, %, $(LOONGARCH64_TEST_SRCS))
+
+CRT_PATH=$(LOONGARCH64_SYSTEM_SRC)
+LINK_SCRIPT=$(LOONGARCH64_SYSTEM_SRC)/kernel.ld
+LDFLAGS=-Wl,-T$(LINK_SCRIPT)
+TESTS+=$(LOONGARCH64_TESTS) $(MULTIARCH_TESTS)
+CFLAGS+=-nostdlib -g -O1 -march=loongarch64 -mabi=lp64d $(MINILIB_INC)
+LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc
+
+# building head blobs
+.PRECIOUS: $(CRT_OBJS)
+
+%.o: $(CRT_PATH)/%.S
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -x assembler-with-cpp -c $< -o $@
+
+# Build and link the tests
+%: %.c $(LINK_SCRIPT) $(CRT_OBJS) $(MINILIB_OBJS)
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS)
+
+memory: CFLAGS+=-DCHECK_UNALIGNED=0
+# Running
+QEMU_OPTS+=-serial chardev:output -kernel
diff --git a/tests/tcg/loongarch64/system/boot.S b/tests/tcg/loongarch64/system/boot.S
new file mode 100644
index 0000000000..bf3622ed67
--- /dev/null
+++ b/tests/tcg/loongarch64/system/boot.S
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Minimal LoongArch system boot code.
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ */
+
+#include "regdef.h"
+
+ .global _start
+ .align 16
+_start:
+ bl main
+
+ .type _start 2
+ .size _start, .-_start
+
+ .global _exit
+ .align 16
+_exit:
+2: /* QEMU ACPI poweroff */
+ li.w t0, 0x3c00
+ li.w t1, 0x100d0014
+ st.w t0, t1, 0
+ idle 0
+ bl 2b
+
+ .type _exit 2
+ .size _exit, .-_exit
+
+ .global __sys_outc
+__sys_outc:
+ li.d t1, 1000000
+loop:
+ lu12i.w t2, 0x1fe00
+ ori t0, t2, 0x1e5
+ ld.bu t0, t0, 0
+ andi t0, t0, 0x20
+ ext.w.b t0, t0
+ bnez t0, in
+ addi.w t1, t1, -1
+ bnez t1, loop
+in:
+ ext.w.b a0, a0
+ lu12i.w t0, 0x1fe00
+ ori t0, t0, 0x1e0
+ st.b a0, t0, 0
+ jirl $r0, ra, 0
+
+ .data
+ .align 4
+stack:
+ .skip 65536
+$stack_end:
+ .type stack,@object
+ .size stack, . - stack
diff --git a/tests/tcg/loongarch64/system/kernel.ld b/tests/tcg/loongarch64/system/kernel.ld
new file mode 100644
index 0000000000..f1a7c0168c
--- /dev/null
+++ b/tests/tcg/loongarch64/system/kernel.ld
@@ -0,0 +1,30 @@
+ENTRY(_start)
+
+SECTIONS
+{
+ /* Linux kernel legacy start address. */
+ . = 0x9000000000200000;
+ _text = .;
+ .text : {
+ *(.text)
+ }
+ .rodata : {
+ *(.rodata)
+ }
+ _etext = .;
+
+ . = ALIGN(8192);
+ _data = .;
+ .got : {
+ *(.got)
+ }
+ .data : {
+ *(.sdata)
+ *(.data)
+ }
+ _edata = .;
+ .bss : {
+ *(.bss)
+ }
+ _end = .;
+}
diff --git a/tests/tcg/loongarch64/system/regdef.h b/tests/tcg/loongarch64/system/regdef.h
new file mode 100644
index 0000000000..faa09b2377
--- /dev/null
+++ b/tests/tcg/loongarch64/system/regdef.h
@@ -0,0 +1,86 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ */
+#ifndef _ASM_REGDEF_H
+#define _ASM_REGDEF_H
+
+#define zero $r0 /* wired zero */
+#define ra $r1 /* return address */
+#define tp $r2
+#define sp $r3 /* stack pointer */
+#define v0 $r4 /* return value - caller saved */
+#define v1 $r5
+#define a0 $r4 /* argument registers */
+#define a1 $r5
+#define a2 $r6
+#define a3 $r7
+#define a4 $r8
+#define a5 $r9
+#define a6 $r10
+#define a7 $r11
+#define t0 $r12 /* caller saved */
+#define t1 $r13
+#define t2 $r14
+#define t3 $r15
+#define t4 $r16
+#define t5 $r17
+#define t6 $r18
+#define t7 $r19
+#define t8 $r20
+ /* $r21: Temporarily reserved */
+#define fp $r22 /* frame pointer */
+#define s0 $r23 /* callee saved */
+#define s1 $r24
+#define s2 $r25
+#define s3 $r26
+#define s4 $r27
+#define s5 $r28
+#define s6 $r29
+#define s7 $r30
+#define s8 $r31
+
+#define gr0 $r0
+#define gr1 $r1
+#define gr2 $r2
+#define gr3 $r3
+#define gr4 $r4
+#define gr5 $r5
+#define gr6 $r6
+#define gr7 $r7
+#define gr8 $r8
+#define gr9 $r9
+#define gr10 $r10
+#define gr11 $r11
+#define gr12 $r12
+#define gr13 $r13
+#define gr14 $r14
+#define gr15 $r15
+#define gr16 $r16
+#define gr17 $r17
+#define gr18 $r18
+#define gr19 $r19
+#define gr20 $r20
+#define gr21 $r21
+#define gr22 $r22
+#define gr23 $r23
+#define gr24 $r24
+#define gr25 $r25
+#define gr26 $r26
+#define gr27 $r27
+#define gr28 $r28
+#define gr29 $r29
+#define gr30 $r30
+#define gr31 $r31
+
+#define STT_NOTYPE 0
+#define STT_OBJECT 1
+#define STT_FUNC 2
+#define STT_SECTION 3
+#define STT_FILE 4
+#define STT_COMMON 5
+#define STT_TLS 6
+
+#define ASM_NL ;
+
+#endif /* _ASM_REGDEF_H */
--
2.31.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 00/29] Add LoongArch softmmu support
2022-03-28 12:57 [RFC PATCH v7 00/29] Add LoongArch softmmu support Xiaojuan Yang
` (28 preceding siblings ...)
2022-03-28 12:57 ` [RFC PATCH v7 29/29] tests/tcg/loongarch64: Add hello/memory test in loongarch64 system Xiaojuan Yang
@ 2022-03-28 18:13 ` Richard Henderson
2022-03-30 9:34 ` yangxiaojuan
29 siblings, 1 reply; 71+ messages in thread
From: Richard Henderson @ 2022-03-28 18:13 UTC (permalink / raw)
To: Xiaojuan Yang, qemu-devel; +Cc: mark.cave-ayland
On 3/28/22 06:57, Xiaojuan Yang wrote:
> This series patch add softmmu support for LoongArch.
> The latest kernel:
> * https://github.com/loongson/linux/tree/loongarch-next
> The latest uefi:
> * https://github.com/loongson/edk2
> * https://github.com/loongson/edk2-platforms
> The manual:
> * https://github.com/loongson/LoongArch-Documentation/releases/tag/2021.10.11
>
> You can get LoongArch qemu series like this:
> git clone https://github.com/loongson/qemu.git
> git checkout tcg-dev
I strongly suggest that you rebase *without* the patches for linux-user/loongarch64/.
If you do not do this, you will be stalled until your linux kernel patches are merged.
Testing this rebase locally, there is only a minor patch conflict in
target/loongarch: Add LoongArch interrupt and exception handle
which suggests that the EXCP_* names be removed from
target/loongarch: Add core definition
The EXCCODE_* names be introduced early instead, and all of the uses updated.
r~
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 07/29] target/loongarch: Add LoongArch CSR instruction
2022-03-28 12:57 ` [RFC PATCH v7 07/29] target/loongarch: Add LoongArch CSR instruction Xiaojuan Yang
@ 2022-03-28 18:34 ` Richard Henderson
2022-03-30 10:01 ` yangxiaojuan
0 siblings, 1 reply; 71+ messages in thread
From: Richard Henderson @ 2022-03-28 18:34 UTC (permalink / raw)
To: Xiaojuan Yang, qemu-devel; +Cc: mark.cave-ayland, Song Gao
On 3/28/22 06:57, Xiaojuan Yang wrote:
> +#define CSR_OFF(X) \
> + [LOONGARCH_CSR_##X] = offsetof(CPULoongArchState, CSR_##X)
> +#define CSR_OFF_ARRAY(X, N) \
> + [LOONGARCH_CSR_##X(N)] = offsetof(CPULoongArchState, CSR_##X[N])
> +
> +static const int csr_offsets[] = {
You cannot put a variable data definition into a header file like this.
It has put this data structure into every object file.
This belongs in csr_helper.c, probably.
You should add
[LOONGARCH_CSR_CPUID] = offsetof(CPUState, cpu_index) - offsetof(ArchCPU, env),
rather than special-casing this in helper_csr_rdq.
> +static inline int cpu_csr_offset(unsigned csr_num)
> +{
> + if (csr_num < ARRAY_SIZE(csr_offsets)) {
> + return csr_offsets[csr_num];
> + }
> + return 0;
> +}
This does not need to be inline, and could easily live in csr_helper.c.
> +target_ulong helper_csr_rdq(CPULoongArchState *env, uint64_t csr)
> +{
> + LoongArchCPU *cpu;
> + int64_t v;
> +
> + switch (csr) {
> + case LOONGARCH_CSR_PGD:
> + if (env->CSR_TLBRERA & 0x1) {
> + v = env->CSR_TLBRBADV;
> + } else {
> + v = env->CSR_BADV;
> + }
> +
> + if ((v >> 63) & 0x1) {
> + v = env->CSR_PGDH;
> + } else {
> + v = env->CSR_PGDL;
> + }
> + break;
> + case LOONGARCH_CSR_CPUID:
> + v = (env_cpu(env))->cpu_index;
> + break;
> + case LOONGARCH_CSR_TVAL:
> + cpu = LOONGARCH_CPU(env_cpu(env));
> + v = cpu_loongarch_get_constant_timer_ticks(cpu);
> + break;
> + default:
> + break;
> + }
> +
> + return v;
> +}
You should have seen a compiler warning for 'v' uninitialized here, via the default path.
The default path should not be reachable, because of code in trans_csrrd, and so could be
written as g_assert_not_reachable(). However, I strongly suggest you split this function
so that you do not need a switch here at all. With CPUID now handled via cpu_csr_offset,
there are only two helpers needed.
> +target_ulong helper_csr_wrq(CPULoongArchState *env, target_ulong val,
> + uint64_t csr)
> +{
> + LoongArchCPU *cpu;
> + int64_t old_v = -1;
> +
> + switch (csr) {
> + case LOONGARCH_CSR_ESTAT:
> + /* Only IS[1:0] can be write */
"can be written", and then again below.
> + env->CSR_ESTAT = FIELD_DP64(env->CSR_ESTAT, CSR_ESTAT, IS, val & 0x3);
> + break;
> + case LOONGARCH_CSR_ASID:
> + old_v = env->CSR_ASID;
> + /* Only ASID filed of CSR_ASID can be write. */
> + env->CSR_ASID = FIELD_DP64(env->CSR_ASID, CSR_ASID, ASID,
> + val & R_CSR_ASID_ASID_MASK);
> + if (old_v != val) {
> + tlb_flush(env_cpu(env));
> + }
> + break;
> + case LOONGARCH_CSR_TCFG:
> + cpu = LOONGARCH_CPU(env_cpu(env));
> + old_v = env->CSR_TCFG;
> + cpu_loongarch_store_constant_timer_config(cpu, val);
> + break;
> + case LOONGARCH_CSR_TICLR:
> + old_v = 0;
> + env->CSR_ESTAT &= ~(1 << IRQ_TIMER);
> + cpu_reset_interrupt(env_cpu(env), CPU_INTERRUPT_HARD);
Surely the TIMER irq is not the only interrupt.
The placement of the reset looks incorrect.
And again, I suggest that you *not* use a switch, but use separate helper functions.
> +target_ulong helper_csr_xchgq(CPULoongArchState *env, target_ulong new_val,
> + target_ulong mask, uint64_t csr_num)
> +{
> + unsigned csr_offset = cpu_csr_offset(csr_num);
> + if (csr_offset == 0) {
> + /* Undefined CSR: read as 0, writes are ignored. */
> + return 0;
> + }
> +
> + uint64_t *csr = (void *)env + csr_offset;
> + uint64_t old_val = *csr;
> +
> + new_val = (new_val & mask) | (old_val & ~mask);
> +
> + if (csr_num == LOONGARCH_CSR_TCFG) {
> + LoongArchCPU *cpu = LOONGARCH_CPU(env_cpu(env));
> + cpu_loongarch_store_constant_timer_config(cpu, new_val);
> + } else {
> + *csr = new_val;
You're only handling one of the special cases from helper_csr_wrq, so I cannot believe
this is correct.
I think you should not have a helper_csr_xchgq function, but reuse the read/write
infrastructure from the other csr access instructions. Note this would also fix...
> +static bool trans_csrwr(DisasContext *ctx, arg_csrwr *a)
> +{
> + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE);
> + TCGv src1 = gpr_src(ctx, a->rd, EXT_NONE);
> +
> + if (check_plv(ctx) || ro_csr(a->csr)) {
> + return false;
> + }
> +
> + unsigned csr_offset = cpu_csr_offset(a->csr);
> + if (csr_offset == 0) {
> + /* CSR is undefined: write ignored. */
> + return true;
> + }
> +
> + if ((a->csr == LOONGARCH_CSR_ASID) || (a->csr == LOONGARCH_CSR_TCFG) ||
> + (a->csr == LOONGARCH_CSR_TICLR) || (a->csr == LOONGARCH_CSR_ESTAT)) {
> + gen_helper_csr_wrq(dest, cpu_env, src1, tcg_constant_i64(a->csr));
ASID change may result in page translation changes (which is why you did tlb_flush). This
also means that the page you are now executing could change translation, so you have to
exit the translation block.
> + } else {
> + TCGv temp = tcg_temp_new();
> + tcg_gen_ld_tl(temp, cpu_env, csr_offset);
> + tcg_gen_st_tl(src1, cpu_env, csr_offset);
> + tcg_gen_mov_tl(dest, temp);
> + tcg_temp_free(temp);
> +
> + /* Cpu state may be changed, need exit */
> + if ((a->csr == LOONGARCH_CSR_CRMD) || (a->csr == LOONGARCH_CSR_EUEN)) {
> + tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4);
> + ctx->base.is_jmp = DISAS_EXIT;
... like this.
> +static bool trans_csrxchg(DisasContext *ctx, arg_csrxchg *a)
> +{
> + TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE);
> + TCGv src1 = gpr_src(ctx, a->rd, EXT_NONE);
> + TCGv src2 = gpr_src(ctx, a->rj, EXT_NONE);
> +
> + if (check_plv(ctx) || ro_csr(a->csr)) {
> + return false;
> + }
> + gen_helper_csr_xchgq(dest, cpu_env, src1, src2, tcg_constant_i64(a->csr));
> + return true;
> +}
... back to xchg, you're not exiting the TB for any of the special cases above.
r~
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 08/29] target/loongarch: Add LoongArch IOCSR instruction
2022-03-28 12:57 ` [RFC PATCH v7 08/29] target/loongarch: Add LoongArch IOCSR instruction Xiaojuan Yang
@ 2022-03-28 18:55 ` Richard Henderson
2022-03-30 10:02 ` yangxiaojuan
0 siblings, 1 reply; 71+ messages in thread
From: Richard Henderson @ 2022-03-28 18:55 UTC (permalink / raw)
To: Xiaojuan Yang, qemu-devel; +Cc: mark.cave-ayland, Song Gao
On 3/28/22 06:57, Xiaojuan Yang wrote:
> +uint64_t helper_iocsr_read(CPULoongArchState *env, target_ulong r_addr,
> + uint32_t size)
> +{
> + int cpuid = env_cpu(env)->cpu_index;
> + CPUState *cs = qemu_get_cpu(cpuid);
> + env = cs->env_ptr;
> + uint64_t ret;
> +
> + /*
> + * Adjust the per core address such as 0x10xx(IPI)/0x18xx(EXTIOI)
> + */
> + if (((r_addr & 0xff00) == 0x1000) || ((r_addr & 0xff00) == 0x1800)) {
> + r_addr = r_addr + ((target_ulong)(cpuid & 0x3) << 8);
> + }
> +
> + switch (size) {
> + case 1:
> + ret = address_space_ldub(&env->address_space_iocsr, r_addr,
> + MEMTXATTRS_UNSPECIFIED, NULL);
> + break;
> + case 2:
> + ret = address_space_lduw(&env->address_space_iocsr, r_addr,
> + MEMTXATTRS_UNSPECIFIED, NULL);
> + break;
> + case 4:
> + ret = address_space_ldl(&env->address_space_iocsr, r_addr,
> + MEMTXATTRS_UNSPECIFIED, NULL);
> + break;
> + case 8:
> + ret = address_space_ldq(&env->address_space_iocsr, r_addr,
> + MEMTXATTRS_UNSPECIFIED, NULL);
> + break;
> + default:
> + break;
> + }
> +
> + return ret;
> +}
You should have seen an uninitialized use of 'ret' here.
The default case should be g_assert_not_reached().
And the same in helper_iocsr_write.
r~
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 02/29] target/loongarch: Add CSRs definition
2022-03-28 12:57 ` [RFC PATCH v7 02/29] target/loongarch: Add CSRs definition Xiaojuan Yang
@ 2022-03-28 19:16 ` Richard Henderson
2022-03-30 10:04 ` yangxiaojuan
0 siblings, 1 reply; 71+ messages in thread
From: Richard Henderson @ 2022-03-28 19:16 UTC (permalink / raw)
To: Xiaojuan Yang, qemu-devel; +Cc: mark.cave-ayland, Song Gao
On 3/28/22 06:57, Xiaojuan Yang wrote:
> +++ b/target/loongarch/cpu.h
> @@ -11,6 +11,7 @@
> #include "exec/cpu-defs.h"
> #include "fpu/softfloat-types.h"
> #include "hw/registerfields.h"
> +#include "cpu-csr.h"
Do you need this include here?
I would hope that there would be only a few extra files that need this.
Otherwise,
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
r~
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 05/29] target/loongarch: Add constant timer support
2022-03-28 12:57 ` [RFC PATCH v7 05/29] target/loongarch: Add constant timer support Xiaojuan Yang
@ 2022-03-28 19:46 ` Richard Henderson
2022-03-31 0:59 ` yangxiaojuan
2022-03-28 20:58 ` Richard Henderson
1 sibling, 1 reply; 71+ messages in thread
From: Richard Henderson @ 2022-03-28 19:46 UTC (permalink / raw)
To: Xiaojuan Yang, qemu-devel; +Cc: mark.cave-ayland, Song Gao
On 3/28/22 06:57, Xiaojuan Yang wrote:
> +void cpu_loongarch_store_constant_timer_config(LoongArchCPU *cpu,
> + uint64_t value)
> +{
> + CPULoongArchState *env = &cpu->env;
> + uint64_t now, next;
> +
> + env->CSR_TCFG = value;
> + if (value & CONSTANT_TIMER_ENABLE) {
> + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> + next = now + (value & CONSTANT_TIMER_TICK_MASK) * TIMER_PERIOD;
> + timer_mod(&cpu->timer, next);
> + }
If CONSTANT_TIMER_ENABLE is not set, you need to use timer_del() to turn off any existing
timer.
> +void loongarch_constant_timer_cb(void *opaque)
> +{
> + LoongArchCPU *cpu = opaque;
> + CPULoongArchState *env = &cpu->env;
> + uint64_t now, next;
> +
> + if (FIELD_EX64(env->CSR_TCFG, CSR_TCFG, PERIODIC)) {
> + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> + next = now + (env->CSR_TCFG & CONSTANT_TIMER_TICK_MASK) * TIMER_PERIOD;
> + timer_mod(&cpu->timer, next);
> + } else {
> + env->CSR_TCFG = FIELD_DP64(env->CSR_TCFG, CSR_TCFG, EN, 0);
> + }
> +
> + env->CSR_ESTAT |= 1 << IRQ_TIMER;
> + cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
I think this is wrong and you should be using loongarch_cpu_set_irq (which is misplaced
for you to be able to do so).
> @@ -297,4 +302,9 @@ enum {
> #define LOONGARCH_CPU_TYPE_NAME(model) model LOONGARCH_CPU_TYPE_SUFFIX
> #define CPU_RESOLVING_TYPE TYPE_LOONGARCH_CPU
>
> +void loongarch_constant_timer_cb(void *opaque);
> +uint64_t cpu_loongarch_get_constant_timer_counter(LoongArchCPU *cpu);
> +uint64_t cpu_loongarch_get_constant_timer_ticks(LoongArchCPU *cpu);
> +void cpu_loongarch_store_constant_timer_config(LoongArchCPU *cpu,
> + uint64_t value);
These can go in internals.h.
r~
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 06/29] target/loongarch: Add MMU support for LoongArch CPU.
2022-03-28 12:57 ` [RFC PATCH v7 06/29] target/loongarch: Add MMU support for LoongArch CPU Xiaojuan Yang
@ 2022-03-28 20:06 ` Richard Henderson
0 siblings, 0 replies; 71+ messages in thread
From: Richard Henderson @ 2022-03-28 20:06 UTC (permalink / raw)
To: Xiaojuan Yang, qemu-devel; +Cc: mark.cave-ayland, Song Gao
On 3/28/22 06:57, Xiaojuan Yang wrote:
> +bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
> + MMUAccessType access_type, int mmu_idx,
> + bool probe, uintptr_t retaddr)
> +{
> + LoongArchCPU *cpu = LOONGARCH_CPU(cs);
> + CPULoongArchState *env = &cpu->env;
> + hwaddr physical;
> + int prot;
> + int ret = TLBRET_BADADDR;
> +
> + /* Data access */
> + ret = get_physical_address(env, &physical, &prot, address,
> + access_type, mmu_idx);
> +
> + if (ret == TLBRET_MATCH) {
> + tlb_set_page(cs, address & TARGET_PAGE_MASK,
> + physical & TARGET_PAGE_MASK, prot,
> + mmu_idx, TARGET_PAGE_SIZE);
> + qemu_log_mask(CPU_LOG_MMU,
> + "%s address=%" VADDR_PRIx " physical " TARGET_FMT_plx
> + " prot %d\n", __func__, address, physical, prot);
> + return true;
> + } else {
> + qemu_log_mask(CPU_LOG_MMU,
> + "%s address=%" VADDR_PRIx " ret %d\n", __func__, address,
> + ret);
> + }
> + if (probe) {
> + return false;
> + } else {
Drop the else and unindent.
> + raise_mmu_exception(env, address, access_type, ret);
> + do_raise_exception(env, cs->exception_index, retaddr);
You do not need do_raise_exception here, as you have already assigned to
cs->exception_index (obviously). Just cpu_loop_exit_restore(cs, retaddr).
Otherwise,
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
r~
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 09/29] target/loongarch: Add TLB instruction support
2022-03-28 12:57 ` [RFC PATCH v7 09/29] target/loongarch: Add TLB instruction support Xiaojuan Yang
@ 2022-03-28 20:12 ` Richard Henderson
2022-03-31 1:09 ` yangxiaojuan
2022-03-28 22:50 ` Richard Henderson
1 sibling, 1 reply; 71+ messages in thread
From: Richard Henderson @ 2022-03-28 20:12 UTC (permalink / raw)
To: Xiaojuan Yang, qemu-devel; +Cc: mark.cave-ayland, Song Gao
On 3/28/22 06:57, Xiaojuan Yang wrote:
> +static void output_empty(DisasContext *ctx, arg_empty *a,
> + const char *mnemonic)
> +{
> +}
No, you must still do
output(ctx, mnemonic, "");
> +static bool trans_tlbwr(DisasContext *ctx, arg_tlbwr *a)
> +{
> + if (check_plv(ctx)) {
> + return false;
> + }
> + gen_helper_tlbwr(cpu_env);
> +
> + if (ctx->mem_idx != MMU_DA_IDX) {
> + tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4);
> + ctx->base.is_jmp = DISAS_EXIT;
> + }
You may want to create a helper function for this condition.
> +static bool trans_tlbclr(DisasContext *ctx, arg_tlbclr *a)
> +{
> + if (check_plv(ctx)) {
> + return false;
> + }
> + gen_helper_tlbclr(cpu_env);
> + tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4);
> + ctx->base.is_jmp = DISAS_EXIT;
Missing it here...
> +static bool trans_tlbflush(DisasContext *ctx, arg_tlbflush *a)
> +{
> + if (check_plv(ctx)) {
> + return false;
> + }
> + gen_helper_tlbflush(cpu_env);
> + tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4);
> + ctx->base.is_jmp = DISAS_EXIT;
> + return true;
> +}
... and here.
r~
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 16/29] hw/loongarch: Add LoongArch ipi interrupt support(IPI)
2022-03-28 12:57 ` [RFC PATCH v7 16/29] hw/loongarch: Add LoongArch ipi interrupt support(IPI) Xiaojuan Yang
@ 2022-03-28 20:15 ` Mark Cave-Ayland
2022-03-31 1:16 ` yangxiaojuan
2022-03-28 22:04 ` Richard Henderson
2022-03-28 22:06 ` Richard Henderson
2 siblings, 1 reply; 71+ messages in thread
From: Mark Cave-Ayland @ 2022-03-28 20:15 UTC (permalink / raw)
To: Xiaojuan Yang, qemu-devel; +Cc: richard.henderson, Song Gao
On 28/03/2022 13:57, Xiaojuan Yang wrote:
> This patch realize the IPI interrupt controller.
>
> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
> Signed-off-by: Song Gao <gaosong@loongson.cn>
> ---
> MAINTAINERS | 2 +
> hw/intc/Kconfig | 3 +
> hw/intc/loongarch_ipi.c | 164 ++++++++++++++++++++++++++++++++
> hw/intc/meson.build | 1 +
> hw/intc/trace-events | 4 +
> hw/loongarch/Kconfig | 1 +
> include/hw/intc/loongarch_ipi.h | 47 +++++++++
> 7 files changed, 222 insertions(+)
> create mode 100644 hw/intc/loongarch_ipi.c
> create mode 100644 include/hw/intc/loongarch_ipi.h
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index a794f41913..d83b90b5c5 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1133,6 +1133,8 @@ F: configs/devices/loongarch64-softmmu/default.mak
> F: gdb-xml/loongarch*.xml
> F: hw/loongarch/
> F: include/hw/loongarch/loongarch.h
> +F: include/hw/intc/loongarch_*.h
> +F: hw/intc/loongarch_*.c
>
> M68K Machines
> -------------
> diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
> index a7cf301eab..6c7e82da64 100644
> --- a/hw/intc/Kconfig
> +++ b/hw/intc/Kconfig
> @@ -84,3 +84,6 @@ config GOLDFISH_PIC
>
> config M68K_IRQC
> bool
> +
> +config LOONGARCH_IPI
> + bool
> diff --git a/hw/intc/loongarch_ipi.c b/hw/intc/loongarch_ipi.c
> new file mode 100644
> index 0000000000..89e9019112
> --- /dev/null
> +++ b/hw/intc/loongarch_ipi.c
> @@ -0,0 +1,164 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * LoongArch ipi interrupt support
> + *
> + * Copyright (C) 2021 Loongson Technology Corporation Limited
> + */
> +
> +#include "qemu/osdep.h"
> +#include "hw/sysbus.h"
> +#include "hw/intc/loongarch_ipi.h"
> +#include "hw/irq.h"
> +#include "qapi/error.h"
> +#include "qemu/log.h"
> +#include "exec/address-spaces.h"
> +#include "hw/loongarch/loongarch.h"
> +#include "migration/vmstate.h"
> +#include "trace.h"
> +
> +static uint64_t loongarch_ipi_readl(void *opaque, hwaddr addr, unsigned size)
> +{
> + IPICore *s = opaque;
> + uint64_t ret = 0;
> + int index = 0;
> +
> + addr &= 0xff;
> + switch (addr) {
> + case CORE_STATUS_OFF:
> + ret = s->status;
> + break;
> + case CORE_EN_OFF:
> + ret = s->en;
> + break;
> + case CORE_SET_OFF:
> + ret = 0;
> + break;
> + case CORE_CLEAR_OFF:
> + ret = 0;
> + break;
> + case CORE_BUF_20 ... CORE_BUF_38 + 4:
> + index = (addr - CORE_BUF_20) >> 2;
> + ret = s->buf[index];
> + break;
> + case IOCSR_IPI_SEND:
> + ret = s->status;
> + break;
> + default:
> + qemu_log_mask(LOG_UNIMP, "invalid read: %x", (uint32_t)addr);
> + break;
> + }
> +
> + trace_loongarch_ipi_read(size, (uint64_t)addr, ret);
> + return ret;
> +}
> +
> +static void loongarch_ipi_writel(void *opaque, hwaddr addr, uint64_t val,
> + unsigned size)
> +{
> + IPICore *s = opaque;
> + int index = 0;
> +
> + addr &= 0xff;
> + trace_loongarch_ipi_write(size, (uint64_t)addr, val);
> + switch (addr) {
> + case CORE_STATUS_OFF:
> + qemu_log_mask(LOG_GUEST_ERROR, "can not be written");
> + break;
> + case CORE_EN_OFF:
> + s->en = val;
> + break;
> + case CORE_SET_OFF:
> + s->status |= val;
> + if (s->status != 0) {
> + qemu_irq_raise(s->irq);
> + }
> + break;
> + case CORE_CLEAR_OFF:
> + s->status ^= val;
> + if (s->status == 0) {
> + qemu_irq_lower(s->irq);
> + }
> + break;
> + case CORE_BUF_20 ... CORE_BUF_38 + 4:
> + index = (addr - CORE_BUF_20) >> 2;
> + s->buf[index] = val;
> + break;
> + case IOCSR_IPI_SEND:
> + s->status |= val;
> + break;
> + default:
> + qemu_log_mask(LOG_UNIMP, "invalid write: %x", (uint32_t)addr);
> + break;
> + }
> +}
> +
> +static const MemoryRegionOps loongarch_ipi_ops = {
> + .read = loongarch_ipi_readl,
> + .write = loongarch_ipi_writel,
> + .impl.min_access_size = 4,
> + .impl.max_access_size = 4,
> + .valid.min_access_size = 4,
> + .valid.max_access_size = 8,
> + .endianness = DEVICE_LITTLE_ENDIAN,
> +};
> +
> +static void loongarch_ipi_init(Object *obj)
> +{
> + LoongArchIPI *s = LOONGARCH_IPI(obj);
> + SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
> + int cpu;
> +
> + for (cpu = 0; cpu < MAX_IPI_CORE_NUM; cpu++) {
> + memory_region_init_io(&s->ipi_mmio[cpu], obj, &loongarch_ipi_ops,
> + &s->core[cpu], "loongarch_ipi", 0x100);
> + sysbus_init_mmio(sbd, &s->ipi_mmio[cpu]);
> + qdev_init_gpio_out(DEVICE(obj), &s->core[cpu].irq, 1);
> + }
> +}
> +
> +static const VMStateDescription vmstate_ipi_core = {
> + .name = "ipi-single",
> + .version_id = 0,
> + .minimum_version_id = 0,
> + .fields = (VMStateField[]) {
> + VMSTATE_UINT32(status, IPICore),
> + VMSTATE_UINT32(en, IPICore),
> + VMSTATE_UINT32(set, IPICore),
> + VMSTATE_UINT32(clear, IPICore),
> + VMSTATE_UINT32_ARRAY(buf, IPICore, MAX_IPI_MBX_NUM * 2),
> + VMSTATE_END_OF_LIST()
> + }
> +};
> +
> +static const VMStateDescription vmstate_loongarch_ipi = {
> + .name = TYPE_LOONGARCH_IPI,
> + .version_id = 0,
> + .minimum_version_id = 0,
> + .fields = (VMStateField[]) {
> + VMSTATE_STRUCT_ARRAY(core, LoongArchIPI, MAX_IPI_CORE_NUM, 0,
> + vmstate_ipi_core, IPICore),
> + VMSTATE_END_OF_LIST()
> + }
> +};
> +
> +static void loongarch_ipi_class_init(ObjectClass *klass, void *data)
> +{
> + DeviceClass *dc = DEVICE_CLASS(klass);
> +
> + dc->vmsd = &vmstate_loongarch_ipi;
> +}
> +
> +static const TypeInfo loongarch_ipi_info = {
> + .name = TYPE_LOONGARCH_IPI,
> + .parent = TYPE_SYS_BUS_DEVICE,
> + .instance_size = sizeof(LoongArchIPI),
> + .instance_init = loongarch_ipi_init,
> + .class_init = loongarch_ipi_class_init,
> +};
> +
> +static void loongarch_ipi_register_types(void)
> +{
> + type_register_static(&loongarch_ipi_info);
> +}
> +
> +type_init(loongarch_ipi_register_types)
> diff --git a/hw/intc/meson.build b/hw/intc/meson.build
> index d6d012fb26..bf5ab44a78 100644
> --- a/hw/intc/meson.build
> +++ b/hw/intc/meson.build
> @@ -62,3 +62,4 @@ specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XIVE'],
> if_true: files('spapr_xive_kvm.c'))
> specific_ss.add(when: 'CONFIG_GOLDFISH_PIC', if_true: files('goldfish_pic.c'))
> specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c'))
> +specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c'))
> diff --git a/hw/intc/trace-events b/hw/intc/trace-events
> index 53414aa197..6ae8917d99 100644
> --- a/hw/intc/trace-events
> +++ b/hw/intc/trace-events
> @@ -275,3 +275,7 @@ sh_intc_register(const char *s, int id, unsigned short v, int c, int m) "%s %u -
> sh_intc_read(unsigned size, uint64_t offset, unsigned long val) "size %u 0x%" PRIx64 " -> 0x%lx"
> sh_intc_write(unsigned size, uint64_t offset, unsigned long val) "size %u 0x%" PRIx64 " <- 0x%lx"
> sh_intc_set(int id, int enable) "setting interrupt group %d to %d"
> +
> +# loongarch_ipi.c
> +loongarch_ipi_read(unsigned size, uint64_t addr, unsigned long val) "size: %u addr: 0x%"PRIx64 "val: 0x%"PRIx64
> +loongarch_ipi_write(unsigned size, uint64_t addr, unsigned long val) "size: %u addr: 0x%"PRIx64 "val: 0x%"PRIx64
> diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
> index 13e8501897..f0dad3329a 100644
> --- a/hw/loongarch/Kconfig
> +++ b/hw/loongarch/Kconfig
> @@ -2,3 +2,4 @@ config LOONGARCH_VIRT
> bool
> select PCI
> select PCI_EXPRESS_GENERIC_BRIDGE
> + select LOONGARCH_IPI
> diff --git a/include/hw/intc/loongarch_ipi.h b/include/hw/intc/loongarch_ipi.h
> new file mode 100644
> index 0000000000..0f3bca8a79
> --- /dev/null
> +++ b/include/hw/intc/loongarch_ipi.h
> @@ -0,0 +1,47 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * LoongArch ipi interrupt header files
> + *
> + * Copyright (C) 2021 Loongson Technology Corporation Limited
> + */
> +
> +#ifndef HW_LOONGARCH_IPI_H
> +#define HW_LOONGARCH_IPI_H
> +
> +#include "hw/sysbus.h"
> +
> +/* Mainy used by iocsr read and write */
> +#define SMP_IPI_MAILBOX 0x1000ULL
> +#define CORE_STATUS_OFF 0x0
> +#define CORE_EN_OFF 0x4
> +#define CORE_SET_OFF 0x8
> +#define CORE_CLEAR_OFF 0xc
> +#define CORE_BUF_20 0x20
> +#define CORE_BUF_28 0x28
> +#define CORE_BUF_30 0x30
> +#define CORE_BUF_38 0x38
> +#define IOCSR_IPI_SEND 0x40
> +
> +#define MAX_IPI_CORE_NUM 16
> +#define MAX_IPI_MBX_NUM 4
> +
> +#define TYPE_LOONGARCH_IPI "loongarch_ipi"
> +OBJECT_DECLARE_SIMPLE_TYPE(LoongArchIPI, LOONGARCH_IPI)
> +
> +typedef struct IPICore {
> + uint32_t status;
> + uint32_t en;
> + uint32_t set;
> + uint32_t clear;
> + /* 64bit buf divide into 2 32bit buf */
> + uint32_t buf[MAX_IPI_MBX_NUM * 2];
> + qemu_irq irq;
> +} IPICore;
> +
> +typedef struct LoongArchIPI {
> + SysBusDevice parent_obj;
> + IPICore core[MAX_IPI_CORE_NUM];
> + MemoryRegion ipi_mmio[MAX_IPI_CORE_NUM];
> +} LoongArchIPI;
> +
> +#endif
You missed the part in my original comment on patch 14 about dropping the typedef for
QOM structs that are defined using OBJECT_DECLARE_TYPE_SIMPLE() i.e.
#define TYPE_LOONGARCH_IPI "loongarch_ipi"
OBJECT_DECLARE_SIMPLE_TYPE(LoongArchIPI, LOONGARCH_IPI)
...
...
typedef struct IPICore {
uint32_t status;
uint32_t en;
uint32_t set;
uint32_t clear;
/* 64bit buf divide into 2 32bit buf */
uint32_t buf[MAX_IPI_MBX_NUM * 2];
qemu_irq irq;
} IPICore;
struct LoongArchIPI {
SysBusDevice parent_obj;
IPICore core[MAX_IPI_CORE_NUM];
MemoryRegion ipi_mmio[MAX_IPI_CORE_NUM];
};
ATB,
Mark.
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 10/29] target/loongarch: Add other core instructions support
2022-03-28 12:57 ` [RFC PATCH v7 10/29] target/loongarch: Add other core instructions support Xiaojuan Yang
@ 2022-03-28 20:16 ` Richard Henderson
2022-03-31 1:22 ` yangxiaojuan
0 siblings, 1 reply; 71+ messages in thread
From: Richard Henderson @ 2022-03-28 20:16 UTC (permalink / raw)
To: Xiaojuan Yang, qemu-devel; +Cc: mark.cave-ayland, Song Gao
On 3/28/22 06:57, Xiaojuan Yang wrote:
> +void helper_idle(CPULoongArchState *env)
> +{
> + CPUState *cs = env_cpu(env);
> +
> + cs->halted = 1;
> + cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE);
> + do_raise_exception(env, EXCP_HLT, 0);
> +}
Why are you messing with CPU_INTERRUPT_WAKE?
You only ever reset it, and never set it.
r~
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 17/29] hw/intc: Add LoongArch ls7a interrupt controller support(PCH-PIC)
2022-03-28 12:57 ` [RFC PATCH v7 17/29] hw/intc: Add LoongArch ls7a interrupt controller support(PCH-PIC) Xiaojuan Yang
@ 2022-03-28 20:18 ` Mark Cave-Ayland
2022-03-31 1:25 ` yangxiaojuan
0 siblings, 1 reply; 71+ messages in thread
From: Mark Cave-Ayland @ 2022-03-28 20:18 UTC (permalink / raw)
To: Xiaojuan Yang, qemu-devel; +Cc: richard.henderson, Song Gao
On 28/03/2022 13:57, Xiaojuan Yang wrote:
> This patch realize the PCH-PIC interrupt controller.
>
> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
> Signed-off-by: Song Gao <gaosong@loongson.cn>
> ---
> hw/intc/Kconfig | 4 +
> hw/intc/loongarch_pch_pic.c | 488 ++++++++++++++++++++++++++++
> hw/intc/meson.build | 1 +
> hw/intc/trace-events | 9 +
> hw/loongarch/Kconfig | 1 +
> include/hw/intc/loongarch_pch_pic.h | 80 +++++
> 6 files changed, 583 insertions(+)
> create mode 100644 hw/intc/loongarch_pch_pic.c
> create mode 100644 include/hw/intc/loongarch_pch_pic.h
>
> diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
> index 6c7e82da64..1fbba2e728 100644
> --- a/hw/intc/Kconfig
> +++ b/hw/intc/Kconfig
> @@ -87,3 +87,7 @@ config M68K_IRQC
>
> config LOONGARCH_IPI
> bool
> +
> +config LOONGARCH_PCH_PIC
> + bool
> + select UNIMP
> diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c
> new file mode 100644
> index 0000000000..04b9bdce36
> --- /dev/null
> +++ b/hw/intc/loongarch_pch_pic.c
> @@ -0,0 +1,488 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * QEMU Loongson 7A1000 I/O interrupt controller.
> + *
> + * Copyright (C) 2021 Loongson Technology Corporation Limited
> + */
> +
> +#include "qemu/osdep.h"
> +#include "hw/sysbus.h"
> +#include "hw/loongarch/loongarch.h"
> +#include "hw/irq.h"
> +#include "hw/intc/loongarch_pch_pic.h"
> +#include "migration/vmstate.h"
> +#include "trace.h"
> +
> +static void pch_pic_update_irq(LoongArchPCHPIC *s, uint32_t mask,
> + int level, int hi)
> +{
> + uint32_t val, irq;
> +
> + if (level == 1) {
> + if (hi) {
> + val = mask & s->intirr_hi & (~s->int_mask_hi);
> + irq = find_first_bit((void *)&val, 32);
> + if (irq != 32) {
> + s->intisr_hi |= 1ULL << irq;
> + qemu_set_irq(s->parent_irq[s->htmsi_vector[irq + 32]], 1);
> + }
> + } else {
> + val = mask & s->intirr_lo & (~s->int_mask_lo);
> + irq = find_first_bit((void *)&val, 32);
> + if (irq != 32) {
> + s->intisr_lo |= 1ULL << irq;
> + qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 1);
> + }
> + }
> + } else {
> + if (hi) {
> + val = mask & s->intisr_hi;
> + irq = find_first_bit((void *)&val, 32);
> + if (irq != 32) {
> + s->intisr_hi &= ~(0x1ULL << irq);
> + qemu_set_irq(s->parent_irq[s->htmsi_vector[irq + 32]], 0);
> + }
> + } else {
> + val = mask & s->intisr_lo;
> + irq = find_first_bit((void *)&val, 32);
> + if (irq != 32) {
> + s->intisr_lo &= ~(0x1ULL << irq);
> + qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 0);
> + }
> + }
> + }
> +}
> +
> +static void pch_pic_irq_handler(void *opaque, int irq, int level)
> +{
> + LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
> + int hi = 0;
> + uint32_t mask;
> +
> + assert(irq < PCH_PIC_IRQ_NUM);
> + trace_pch_pic_irq_handler(irq, level);
> +
> + hi = (irq >= 32) ? 1 : 0;
> + if (hi) {
> + irq = irq - 32;
> + }
> +
> + mask = 1ULL << irq;
> +
> + if (hi) {
> + if (s->intedge_hi & mask) {
> + /* Edge triggered */
> + if (level) {
> + if ((s->last_intirr_hi & mask) == 0) {
> + s->intirr_hi |= mask;
> + }
> + s->last_intirr_hi |= mask;
> + } else {
> + s->last_intirr_hi &= ~mask;
> + }
> + } else {
> + /* Level triggered */
> + if (level) {
> + s->intirr_hi |= mask;
> + s->last_intirr_hi |= mask;
> + } else {
> + s->intirr_hi &= ~mask;
> + s->last_intirr_hi &= ~mask;
> + }
> + }
> + } else {
> + if (s->intedge_lo & mask) {
> + /* Edge triggered */
> + if (level) {
> + if ((s->last_intirr_lo & mask) == 0) {
> + s->intirr_lo |= mask;
> + }
> + s->last_intirr_lo |= mask;
> + } else {
> + s->last_intirr_lo &= ~mask;
> + }
> + } else {
> + /* Level triggered */
> + if (level) {
> + s->intirr_lo |= mask;
> + s->last_intirr_lo |= mask;
> + } else {
> + s->intirr_lo &= ~mask;
> + s->last_intirr_lo &= ~mask;
> + }
> +
> + }
> + }
> + pch_pic_update_irq(s, mask, level, hi);
> +}
> +
> +static uint64_t loongarch_pch_pic_low_readw(void *opaque, hwaddr addr,
> + unsigned size)
> +{
> + LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
> + uint64_t val = 0;
> + uint32_t offset = addr & 0xfff;
> +
> + switch (offset) {
> + case PCH_PIC_INT_ID_LO:
> + val = PCH_PIC_INT_ID_VAL;
> + break;
> + case PCH_PIC_INT_ID_HI:
> + val = PCH_PIC_INT_ID_NUM;
> + break;
> + case PCH_PIC_INT_MASK_LO:
> + val = s->int_mask_lo;
> + break;
> + case PCH_PIC_INT_MASK_HI:
> + val = s->int_mask_hi;
> + break;
> + case PCH_PIC_INT_EDGE_LO:
> + val = s->intedge_lo;
> + break;
> + case PCH_PIC_INT_EDGE_HI:
> + val = s->intedge_hi;
> + break;
> + case PCH_PIC_HTMSI_EN_LO:
> + val = s->htmsi_en_lo;
> + break;
> + case PCH_PIC_HTMSI_EN_HI:
> + val = s->htmsi_en_hi;
> + break;
> + case PCH_PIC_AUTO_CTRL0_LO:
> + case PCH_PIC_AUTO_CTRL0_HI:
> + case PCH_PIC_AUTO_CTRL1_LO:
> + case PCH_PIC_AUTO_CTRL1_HI:
> + break;
> + default:
> + break;
> + }
> +
> + trace_loongarch_pch_pic_low_readw(size, (uint32_t)addr, val);
> + return val;
> +}
> +
> +static void loongarch_pch_pic_low_writew(void *opaque, hwaddr addr,
> + uint64_t data, unsigned size)
> +{
> + LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
> + uint32_t offset, old;
> + offset = addr & 0xfff;
> +
> + trace_loongarch_pch_pic_low_writew(size, (uint32_t)addr, data);
> +
> + switch (offset) {
> + case PCH_PIC_INT_MASK_LO:
> + old = s->int_mask_lo;
> + s->int_mask_lo = data;
> + if (old & ~data) {
> + pch_pic_update_irq(s, (old & ~data), 1, 0);
> + } else if (~old & data) {
> + pch_pic_update_irq(s, (~old & data), 0, 0);
> + }
> + break;
> + case PCH_PIC_INT_MASK_HI:
> + old = s->int_mask_hi;
> + s->int_mask_hi = data;
> + if (old & ~data) {
> + pch_pic_update_irq(s, (old & ~data), 1, 1);
> + } else if (~old & data) {
> + pch_pic_update_irq(s, (~old & data), 0, 1);
> + }
> + break;
> + case PCH_PIC_INT_EDGE_LO:
> + s->intedge_lo = data;
> + break;
> + case PCH_PIC_INT_EDGE_HI:
> + s->intedge_hi = data;
> + break;
> + case PCH_PIC_INT_CLEAR_LO:
> + if (s->intedge_lo & data) {
> + s->intirr_lo &= (~data);
> + pch_pic_update_irq(s, data, 0, 0);
> + s->intisr_lo &= (~data);
> + }
> + break;
> + case PCH_PIC_INT_CLEAR_HI:
> + if (s->intedge_hi & data) {
> + s->intirr_hi &= (~data);
> + pch_pic_update_irq(s, data, 0, 1);
> + s->intisr_hi &= (~data);
> + }
> + break;
> + case PCH_PIC_HTMSI_EN_LO:
> + s->htmsi_en_lo = data;
> + break;
> + case PCH_PIC_HTMSI_EN_HI:
> + s->htmsi_en_hi = data;
> + break;
> + case PCH_PIC_AUTO_CTRL0_LO:
> + case PCH_PIC_AUTO_CTRL0_HI:
> + case PCH_PIC_AUTO_CTRL1_LO:
> + case PCH_PIC_AUTO_CTRL1_HI:
> + break;
> + default:
> + break;
> + }
> +}
> +
> +static uint64_t loongarch_pch_pic_high_readw(void *opaque, hwaddr addr,
> + unsigned size)
> +{
> + LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
> + uint64_t val = 0;
> + uint32_t offset = addr & 0xfff;
> +
> + switch (offset) {
> + case STATUS_LO_START:
> + val = s->intisr_lo & (~s->int_mask_lo);
> + break;
> + case STATUS_HI_START:
> + val = s->intisr_hi & (~s->int_mask_hi);
> + break;
> + case POL_LO_START:
> + val = s->int_polarity_lo;
> + break;
> + case POL_HI_START:
> + val = s->int_polarity_hi;
> + break;
> + default:
> + break;
> + }
> +
> + trace_loongarch_pch_pic_high_readw(size, (uint32_t)addr, val);
> + return val;
> +}
> +
> +static void loongarch_pch_pic_high_writew(void *opaque, hwaddr addr,
> + uint64_t data, unsigned size)
> +{
> + LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
> + uint32_t offset;
> + offset = addr & 0xfff;
> +
> + trace_loongarch_pch_pic_high_writew(size, (uint32_t)addr, data);
> +
> + switch (offset) {
> + case STATUS_LO_START:
> + s->intisr_lo = data;
> + break;
> + case STATUS_HI_START:
> + s->intisr_hi = data;
> + break;
> + case POL_LO_START:
> + s->int_polarity_lo = data;
> + break;
> + case POL_HI_START:
> + s->int_polarity_hi = data;
> + break;
> + default:
> + break;
> + }
> +}
> +
> +static uint64_t loongarch_pch_pic_readb(void *opaque, hwaddr addr,
> + unsigned size)
> +{
> + LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
> + uint64_t val = 0;
> + uint32_t offset = (addr & 0xfff) + PCH_PIC_ROUTE_ENTRY_OFFSET;
> + int64_t offset_tmp;
> +
> + switch (offset) {
> + case PCH_PIC_HTMSI_VEC_OFFSET ... PCH_PIC_HTMSI_VEC_END:
> + offset_tmp = offset - PCH_PIC_HTMSI_VEC_OFFSET;
> + if (offset_tmp >= 0 && offset_tmp < 64) {
> + val = s->htmsi_vector[offset_tmp];
> + }
> + break;
> + case PCH_PIC_ROUTE_ENTRY_OFFSET ... PCH_PIC_ROUTE_ENTRY_END:
> + offset_tmp = offset - PCH_PIC_ROUTE_ENTRY_OFFSET;
> + if (offset_tmp >= 0 && offset_tmp < 64) {
> + val = s->route_entry[offset_tmp];
> + }
> + break;
> + default:
> + break;
> + }
> +
> + trace_loongarch_pch_pic_readb(size, (uint32_t)addr, val);
> + return val;
> +}
> +
> +static void loongarch_pch_pic_writeb(void *opaque, hwaddr addr,
> + uint64_t data, unsigned size)
> +{
> + LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
> + int32_t offset_tmp;
> + uint32_t offset = (addr & 0xfff) + PCH_PIC_ROUTE_ENTRY_OFFSET;
> +
> + trace_loongarch_pch_pic_writeb(size, (uint32_t)addr, data);
> +
> + switch (offset) {
> + case PCH_PIC_HTMSI_VEC_OFFSET ... PCH_PIC_HTMSI_VEC_END:
> + offset_tmp = offset - PCH_PIC_HTMSI_VEC_OFFSET;
> + if (offset_tmp >= 0 && offset_tmp < 64) {
> + s->htmsi_vector[offset_tmp] = (uint8_t)(data & 0xff);
> + }
> + break;
> + case PCH_PIC_ROUTE_ENTRY_OFFSET ... PCH_PIC_ROUTE_ENTRY_END:
> + offset_tmp = offset - PCH_PIC_ROUTE_ENTRY_OFFSET;
> + if (offset_tmp >= 0 && offset_tmp < 64) {
> + s->route_entry[offset_tmp] = (uint8_t)(data & 0xff);
> + }
> + break;
> + default:
> + break;
> + }
> +}
> +
> +static const MemoryRegionOps loongarch_pch_pic_reg32_low_ops = {
> + .read = loongarch_pch_pic_low_readw,
> + .write = loongarch_pch_pic_low_writew,
> + .valid = {
> + .min_access_size = 4,
> + .max_access_size = 8,
> + },
> + .impl = {
> + .min_access_size = 4,
> + .max_access_size = 4,
> + },
> + .endianness = DEVICE_LITTLE_ENDIAN,
> +};
> +
> +static const MemoryRegionOps loongarch_pch_pic_reg32_high_ops = {
> + .read = loongarch_pch_pic_high_readw,
> + .write = loongarch_pch_pic_high_writew,
> + .valid = {
> + .min_access_size = 4,
> + .max_access_size = 8,
> + },
> + .impl = {
> + .min_access_size = 4,
> + .max_access_size = 4,
> + },
> + .endianness = DEVICE_LITTLE_ENDIAN,
> +};
> +
> +static const MemoryRegionOps loongarch_pch_pic_reg8_ops = {
> + .read = loongarch_pch_pic_readb,
> + .write = loongarch_pch_pic_writeb,
> + .valid = {
> + .min_access_size = 1,
> + .max_access_size = 1,
> + },
> + .impl = {
> + .min_access_size = 1,
> + .max_access_size = 1,
> + },
> + .endianness = DEVICE_LITTLE_ENDIAN,
> +};
> +
> +static void loongarch_pch_pic_reset(DeviceState *d)
> +{
> + LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(d);
> + int i;
> +
> + s->int_mask_lo = -1;
> + s->int_mask_hi = -1;
> + s->htmsi_en_lo = 0x0;
> + s->htmsi_en_hi = 0x0;
> + s->intedge_lo = 0x0;
> + s->intedge_hi = 0x0;
> + s->intclr_lo = 0x0;
> + s->intclr_hi = 0x0;
> + s->auto_crtl0_lo = 0x0;
> + s->auto_crtl0_hi = 0x0;
> + s->auto_crtl1_lo = 0x0;
> + s->auto_crtl1_hi = 0x0;
> + for (i = 0; i < 64; i++) {
> + s->route_entry[i] = 0x1;
> + s->htmsi_vector[i] = 0x0;
> + }
> + s->intirr_lo = 0x0;
> + s->intirr_hi = 0x0;
> + s->intisr_lo = 0x0;
> + s->intisr_hi = 0x0;
> + s->last_intirr_lo = 0x0;
> + s->last_intirr_hi = 0x0;
> + s->int_polarity_lo = 0x0;
> + s->int_polarity_hi = 0x0;
> +}
> +
> +static void loongarch_pch_pic_init(Object *obj)
> +{
> + LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(obj);
> + SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
> + int i;
> +
> + memory_region_init_io(&s->iomem32_low, obj,
> + &loongarch_pch_pic_reg32_low_ops,
> + s, PCH_PIC_NAME(.reg32_part1), 0x100);
> + memory_region_init_io(&s->iomem8, obj, &loongarch_pch_pic_reg8_ops,
> + s, PCH_PIC_NAME(.reg8), 0x2a0);
> + memory_region_init_io(&s->iomem32_high, obj,
> + &loongarch_pch_pic_reg32_high_ops,
> + s, PCH_PIC_NAME(.reg32_part2), 0xc60);
> + sysbus_init_mmio(sbd, &s->iomem32_low);
> + sysbus_init_mmio(sbd, &s->iomem8);
> + sysbus_init_mmio(sbd, &s->iomem32_high);
> +
> + for (i = 0; i < PCH_PIC_IRQ_NUM; i++) {
> + sysbus_init_irq(sbd, &s->parent_irq[i]);
> + }
> + qdev_init_gpio_in(DEVICE(obj), pch_pic_irq_handler, PCH_PIC_IRQ_NUM);
> +}
> +
> +static const VMStateDescription vmstate_loongarch_pch_pic = {
> + .name = TYPE_LOONGARCH_PCH_PIC,
> + .version_id = 1,
> + .minimum_version_id = 1,
> + .fields = (VMStateField[]) {
> + VMSTATE_UINT32(int_mask_lo, LoongArchPCHPIC),
> + VMSTATE_UINT32(int_mask_hi, LoongArchPCHPIC),
> + VMSTATE_UINT32(htmsi_en_lo, LoongArchPCHPIC),
> + VMSTATE_UINT32(htmsi_en_hi, LoongArchPCHPIC),
> + VMSTATE_UINT32(intedge_lo, LoongArchPCHPIC),
> + VMSTATE_UINT32(intedge_hi, LoongArchPCHPIC),
> + VMSTATE_UINT32(intclr_lo, LoongArchPCHPIC),
> + VMSTATE_UINT32(intclr_hi, LoongArchPCHPIC),
> + VMSTATE_UINT32(auto_crtl0_lo, LoongArchPCHPIC),
> + VMSTATE_UINT32(auto_crtl0_hi, LoongArchPCHPIC),
> + VMSTATE_UINT32(auto_crtl1_lo, LoongArchPCHPIC),
> + VMSTATE_UINT32(auto_crtl1_hi, LoongArchPCHPIC),
> + VMSTATE_UINT8_ARRAY(route_entry, LoongArchPCHPIC, 64),
> + VMSTATE_UINT8_ARRAY(htmsi_vector, LoongArchPCHPIC, 64),
> + VMSTATE_UINT32(last_intirr_lo, LoongArchPCHPIC),
> + VMSTATE_UINT32(last_intirr_hi, LoongArchPCHPIC),
> + VMSTATE_UINT32(intirr_lo, LoongArchPCHPIC),
> + VMSTATE_UINT32(intirr_hi, LoongArchPCHPIC),
> + VMSTATE_UINT32(intisr_lo, LoongArchPCHPIC),
> + VMSTATE_UINT32(intisr_hi, LoongArchPCHPIC),
> + VMSTATE_UINT32(int_polarity_lo, LoongArchPCHPIC),
> + VMSTATE_UINT32(int_polarity_hi, LoongArchPCHPIC),
> + VMSTATE_END_OF_LIST()
> + }
> +};
> +
> +static void loongarch_pch_pic_class_init(ObjectClass *klass, void *data)
> +{
> + DeviceClass *dc = DEVICE_CLASS(klass);
> +
> + dc->reset = loongarch_pch_pic_reset;
> + dc->vmsd = &vmstate_loongarch_pch_pic;
> +}
> +
> +static const TypeInfo loongarch_pch_pic_info = {
> + .name = TYPE_LOONGARCH_PCH_PIC,
> + .parent = TYPE_SYS_BUS_DEVICE,
> + .instance_size = sizeof(LoongArchPCHPIC),
> + .instance_init = loongarch_pch_pic_init,
> + .class_init = loongarch_pch_pic_class_init,
> +};
> +
> +static void loongarch_pch_pic_register_types(void)
> +{
> + type_register_static(&loongarch_pch_pic_info);
> +}
> +
> +type_init(loongarch_pch_pic_register_types)
> diff --git a/hw/intc/meson.build b/hw/intc/meson.build
> index bf5ab44a78..960ce81a92 100644
> --- a/hw/intc/meson.build
> +++ b/hw/intc/meson.build
> @@ -63,3 +63,4 @@ specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XIVE'],
> specific_ss.add(when: 'CONFIG_GOLDFISH_PIC', if_true: files('goldfish_pic.c'))
> specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c'))
> specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c'))
> +specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_pic.c'))
> diff --git a/hw/intc/trace-events b/hw/intc/trace-events
> index 6ae8917d99..8c12bdd89f 100644
> --- a/hw/intc/trace-events
> +++ b/hw/intc/trace-events
> @@ -279,3 +279,12 @@ sh_intc_set(int id, int enable) "setting interrupt group %d to %d"
> # loongarch_ipi.c
> loongarch_ipi_read(unsigned size, uint64_t addr, unsigned long val) "size: %u addr: 0x%"PRIx64 "val: 0x%"PRIx64
> loongarch_ipi_write(unsigned size, uint64_t addr, unsigned long val) "size: %u addr: 0x%"PRIx64 "val: 0x%"PRIx64
> +
> +# loongarch_pch_pic.c
> +pch_pic_irq_handler(int irq, int level) "irq %d level %d"
> +loongarch_pch_pic_low_readw(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
> +loongarch_pch_pic_low_writew(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
> +loongarch_pch_pic_high_readw(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
> +loongarch_pch_pic_high_writew(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
> +loongarch_pch_pic_readb(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
> +loongarch_pch_pic_writeb(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
> diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
> index f0dad3329a..2df45f7e8f 100644
> --- a/hw/loongarch/Kconfig
> +++ b/hw/loongarch/Kconfig
> @@ -3,3 +3,4 @@ config LOONGARCH_VIRT
> select PCI
> select PCI_EXPRESS_GENERIC_BRIDGE
> select LOONGARCH_IPI
> + select LOONGARCH_PCH_PIC
> diff --git a/include/hw/intc/loongarch_pch_pic.h b/include/hw/intc/loongarch_pch_pic.h
> new file mode 100644
> index 0000000000..8ca044be33
> --- /dev/null
> +++ b/include/hw/intc/loongarch_pch_pic.h
> @@ -0,0 +1,80 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * LoongArch 7A1000 I/O interrupt controller definitions
> + *
> + * Copyright (c) 2021 Loongson Technology Corporation Limited
> + */
> +
> +#define TYPE_LOONGARCH_PCH_PIC "loongarch_pch_pic"
> +#define PCH_PIC_NAME(name) TYPE_LOONGARCH_PCH_PIC#name
> +OBJECT_DECLARE_SIMPLE_TYPE(LoongArchPCHPIC, LOONGARCH_PCH_PIC)
> +
> +#define PCH_PIC_IRQ_START 0
> +#define PCH_PIC_IRQ_END 63
> +#define PCH_PIC_IRQ_NUM 64
> +#define PCH_PIC_INT_ID_VAL 0x7000000UL
> +#define PCH_PIC_INT_ID_NUM 0x3f0001UL
> +
> +#define PCH_PIC_INT_ID_LO 0x00
> +#define PCH_PIC_INT_ID_HI 0x04
> +#define PCH_PIC_INT_MASK_LO 0x20
> +#define PCH_PIC_INT_MASK_HI 0x24
> +#define PCH_PIC_HTMSI_EN_LO 0x40
> +#define PCH_PIC_HTMSI_EN_HI 0x44
> +#define PCH_PIC_INT_EDGE_LO 0x60
> +#define PCH_PIC_INT_EDGE_HI 0x64
> +#define PCH_PIC_INT_CLEAR_LO 0x80
> +#define PCH_PIC_INT_CLEAR_HI 0x84
> +#define PCH_PIC_AUTO_CTRL0_LO 0xc0
> +#define PCH_PIC_AUTO_CTRL0_HI 0xc4
> +#define PCH_PIC_AUTO_CTRL1_LO 0xe0
> +#define PCH_PIC_AUTO_CTRL1_HI 0xe4
> +#define PCH_PIC_ROUTE_ENTRY_OFFSET 0x100
> +#define PCH_PIC_ROUTE_ENTRY_END 0x13f
> +#define PCH_PIC_HTMSI_VEC_OFFSET 0x200
> +#define PCH_PIC_HTMSI_VEC_END 0x23f
> +#define PCH_PIC_INT_STATUS_LO 0x3a0
> +#define PCH_PIC_INT_STATUS_HI 0x3a4
> +#define PCH_PIC_INT_POL_LO 0x3e0
> +#define PCH_PIC_INT_POL_HI 0x3e4
> +
> +#define STATUS_LO_START 0
> +#define STATUS_HI_START 0x4
> +#define POL_LO_START 0x40
> +#define POL_HI_START 0x44
> +
> +typedef struct LoongArchPCHPIC {
> + SysBusDevice parent_obj;
> + qemu_irq parent_irq[64];
> + uint32_t int_mask_lo; /*0x020 interrupt mask register*/
> + uint32_t int_mask_hi;
> + uint32_t htmsi_en_lo; /*0x040 1=msi*/
> + uint32_t htmsi_en_hi;
> + uint32_t intedge_lo; /*0x060 edge=1 level =0*/
> + uint32_t intedge_hi; /*0x060 edge=1 level =0*/
> + uint32_t intclr_lo; /*0x080 for clean edge int,set 1 clean,set 0 is noused*/
> + uint32_t intclr_hi; /*0x080 for clean edge int,set 1 clean,set 0 is noused*/
> + uint32_t auto_crtl0_lo; /*0x0c0*/
> + uint32_t auto_crtl0_hi; /*0x0c0*/
> + uint32_t auto_crtl1_lo; /*0x0e0*/
> + uint32_t auto_crtl1_hi; /*0x0e0*/
> + uint32_t last_intirr_lo; /* edge detection */
> + uint32_t last_intirr_hi; /* edge detection */
> + uint32_t intirr_lo; /* 0x380 interrupt request register */
> + uint32_t intirr_hi; /* 0x380 interrupt request register */
> + uint32_t intisr_lo; /* 0x3a0 interrupt service register */
> + uint32_t intisr_hi; /* 0x3a0 interrupt service register */
> + /*
> + * 0x3e0 interrupt level polarity selection
> + * register 0 for high level trigger
> + */
> + uint32_t int_polarity_lo;
> + uint32_t int_polarity_hi;
> +
> + uint8_t route_entry[64]; /*0x100 - 0x138*/
> + uint8_t htmsi_vector[64]; /*0x200 - 0x238*/
> +
> + MemoryRegion iomem32_low;
> + MemoryRegion iomem32_high;
> + MemoryRegion iomem8;
> +} LoongArchPCHPIC;
Same comment here about dropping the typedef for the QOM type.
ATB,
Mark.
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 11/29] target/loongarch: Add LoongArch interrupt and exception handle
2022-03-28 12:57 ` [RFC PATCH v7 11/29] target/loongarch: Add LoongArch interrupt and exception handle Xiaojuan Yang
@ 2022-03-28 20:19 ` Richard Henderson
2022-03-31 1:29 ` yangxiaojuan
0 siblings, 1 reply; 71+ messages in thread
From: Richard Henderson @ 2022-03-28 20:19 UTC (permalink / raw)
To: Xiaojuan Yang, qemu-devel; +Cc: mark.cave-ayland, Song Gao
On 3/28/22 06:57, Xiaojuan Yang wrote:
> 1.This patch Add loongarch interrupt and exception handle.
> 2.Rename the user excp to the exccode from the csr defintions.
>
> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
> Signed-off-by: Song Gao <gaosong@loongson.cn>
> ---
> linux-user/loongarch64/cpu_loop.c | 8 +-
> target/loongarch/cpu.c | 260 +++++++++++++++++-
> target/loongarch/cpu.h | 11 -
> target/loongarch/fpu_helper.c | 2 +-
> target/loongarch/insn_trans/trans_extra.c.inc | 4 +-
> target/loongarch/translate.c | 2 +-
> 6 files changed, 261 insertions(+), 26 deletions(-)
To repeat my response to the cover letter, the changes in this patch should be folded back
into the original patches defining the base architecture.
r~
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 18/29] hw/intc: Add LoongArch ls7a msi interrupt controller support(PCH-MSI)
2022-03-28 12:57 ` [RFC PATCH v7 18/29] hw/intc: Add LoongArch ls7a msi interrupt controller support(PCH-MSI) Xiaojuan Yang
@ 2022-03-28 20:22 ` Mark Cave-Ayland
0 siblings, 0 replies; 71+ messages in thread
From: Mark Cave-Ayland @ 2022-03-28 20:22 UTC (permalink / raw)
To: Xiaojuan Yang, qemu-devel; +Cc: richard.henderson, Song Gao
On 28/03/2022 13:57, Xiaojuan Yang wrote:
> This patch realize PCH-MSI interrupt controller.
>
> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
> Signed-off-by: Song Gao <gaosong@loongson.cn>
> ---
> hw/intc/Kconfig | 5 ++
> hw/intc/loongarch_pch_msi.c | 75 +++++++++++++++++++++++++++++
> hw/intc/meson.build | 1 +
> hw/intc/trace-events | 3 ++
> hw/loongarch/Kconfig | 1 +
> include/hw/intc/loongarch_pch_msi.h | 21 ++++++++
> 6 files changed, 106 insertions(+)
> create mode 100644 hw/intc/loongarch_pch_msi.c
> create mode 100644 include/hw/intc/loongarch_pch_msi.h
>
> diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
> index 1fbba2e728..71c04c328e 100644
> --- a/hw/intc/Kconfig
> +++ b/hw/intc/Kconfig
> @@ -91,3 +91,8 @@ config LOONGARCH_IPI
> config LOONGARCH_PCH_PIC
> bool
> select UNIMP
> +
> +config LOONGARCH_PCH_MSI
> + select MSI_NONBROKEN
> + bool
> + select UNIMP
> diff --git a/hw/intc/loongarch_pch_msi.c b/hw/intc/loongarch_pch_msi.c
> new file mode 100644
> index 0000000000..57a894f3e5
> --- /dev/null
> +++ b/hw/intc/loongarch_pch_msi.c
> @@ -0,0 +1,75 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * QEMU Loongson 7A1000 msi interrupt controller.
> + *
> + * Copyright (C) 2021 Loongson Technology Corporation Limited
> + */
> +
> +#include "qemu/osdep.h"
> +#include "hw/sysbus.h"
> +#include "hw/irq.h"
> +#include "hw/intc/loongarch_pch_msi.h"
> +#include "hw/intc/loongarch_pch_pic.h"
> +#include "hw/pci/msi.h"
> +#include "hw/misc/unimp.h"
> +#include "migration/vmstate.h"
> +#include "trace.h"
> +
> +static uint64_t loongarch_msi_mem_read(void *opaque, hwaddr addr, unsigned size)
> +{
> + return 0;
> +}
> +
> +static void loongarch_msi_mem_write(void *opaque, hwaddr addr,
> + uint64_t val, unsigned size)
> +{
> + LoongArchPCHMSI *s = LOONGARCH_PCH_MSI(opaque);
> + int irq_num = val & 0xff;
> +
> + trace_loongarch_msi_set_irq(irq_num);
> + qemu_set_irq(s->pch_msi_irq[irq_num - PCH_PIC_IRQ_NUM], 1);
> +}
> +
> +static const MemoryRegionOps loongarch_pch_msi_ops = {
> + .read = loongarch_msi_mem_read,
> + .write = loongarch_msi_mem_write,
> + .endianness = DEVICE_LITTLE_ENDIAN,
> +};
> +
> +static void pch_msi_irq_handler(void *opaque, int irq, int level)
> +{
> + LoongArchPCHMSI *s = LOONGARCH_PCH_MSI(opaque);
> +
> + qemu_set_irq(s->pch_msi_irq[irq], level);
> +}
> +
> +static void loongarch_pch_msi_init(Object *obj)
> +{
> + LoongArchPCHMSI *s = LOONGARCH_PCH_MSI(obj);
> + SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
> + int i;
> +
> + memory_region_init_io(&s->msi_mmio, obj, &loongarch_pch_msi_ops,
> + s, TYPE_LOONGARCH_PCH_MSI, 0x8);
> + sysbus_init_mmio(sbd, &s->msi_mmio);
> + msi_nonbroken = true;
> +
> + for (i = 0; i < PCH_MSI_IRQ_NUM; i++) {
> + sysbus_init_irq(sbd, &s->pch_msi_irq[i]);
> + }
> + qdev_init_gpio_in(DEVICE(obj), pch_msi_irq_handler, PCH_MSI_IRQ_NUM);
> +}
> +
> +static const TypeInfo loongarch_pch_msi_info = {
> + .name = TYPE_LOONGARCH_PCH_MSI,
> + .parent = TYPE_SYS_BUS_DEVICE,
> + .instance_size = sizeof(LoongArchPCHMSI),
> + .instance_init = loongarch_pch_msi_init,
> +};
> +
> +static void loongarch_pch_msi_register_types(void)
> +{
> + type_register_static(&loongarch_pch_msi_info);
> +}
> +
> +type_init(loongarch_pch_msi_register_types)
> diff --git a/hw/intc/meson.build b/hw/intc/meson.build
> index 960ce81a92..77a30cec33 100644
> --- a/hw/intc/meson.build
> +++ b/hw/intc/meson.build
> @@ -64,3 +64,4 @@ specific_ss.add(when: 'CONFIG_GOLDFISH_PIC', if_true: files('goldfish_pic.c'))
> specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c'))
> specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c'))
> specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_pic.c'))
> +specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_MSI', if_true: files('loongarch_pch_msi.c'))
> diff --git a/hw/intc/trace-events b/hw/intc/trace-events
> index 8c12bdd89f..7c02f8d5f0 100644
> --- a/hw/intc/trace-events
> +++ b/hw/intc/trace-events
> @@ -288,3 +288,6 @@ loongarch_pch_pic_high_readw(unsigned size, uint32_t addr, unsigned long val) "s
> loongarch_pch_pic_high_writew(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
> loongarch_pch_pic_readb(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
> loongarch_pch_pic_writeb(unsigned size, uint32_t addr, unsigned long val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
> +
> +# loongarch_pch_msi.c
> +loongarch_msi_set_irq(int irq_num) "set msi irq %d"
> diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
> index 2df45f7e8f..d814fc6103 100644
> --- a/hw/loongarch/Kconfig
> +++ b/hw/loongarch/Kconfig
> @@ -4,3 +4,4 @@ config LOONGARCH_VIRT
> select PCI_EXPRESS_GENERIC_BRIDGE
> select LOONGARCH_IPI
> select LOONGARCH_PCH_PIC
> + select LOONGARCH_PCH_MSI
> diff --git a/include/hw/intc/loongarch_pch_msi.h b/include/hw/intc/loongarch_pch_msi.h
> new file mode 100644
> index 0000000000..68009d4b4a
> --- /dev/null
> +++ b/include/hw/intc/loongarch_pch_msi.h
> @@ -0,0 +1,21 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * LoongArch 7A1000 I/O interrupt controller definitions
> + *
> + * Copyright (C) 2021 Loongson Technology Corporation Limited
> + */
> +
> +#define TYPE_LOONGARCH_PCH_MSI "loongarch_pch_msi"
> +DECLARE_INSTANCE_CHECKER(struct LoongArchPCHMSI, LOONGARCH_PCH_MSI,
> + TYPE_LOONGARCH_PCH_MSI)
I think this one got missed from the v7 update?
OBJECT_DECLARE_SIMPLE_TYPE(LoongArchPCHMSI, LOONGARCH_PCH_MSI)
> +/* Msi irq start start from 64 to 255 */
> +#define PCH_MSI_IRQ_START 64
> +#define PCH_MSI_IRQ_END 255
> +#define PCH_MSI_IRQ_NUM 192
> +
> +typedef struct LoongArchPCHMSI {
> + SysBusDevice parent_obj;
> + qemu_irq pch_msi_irq[PCH_MSI_IRQ_NUM];
> + MemoryRegion msi_mmio;
> +} LoongArchPCHMSI;
And drop the typedef again here too.
ATB,
Mark.
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 19/29] hw/intc: Add LoongArch extioi interrupt controller(EIOINTC)
2022-03-28 12:57 ` [RFC PATCH v7 19/29] hw/intc: Add LoongArch extioi interrupt controller(EIOINTC) Xiaojuan Yang
@ 2022-03-28 20:27 ` Mark Cave-Ayland
2022-03-28 22:43 ` Richard Henderson
2022-03-28 22:46 ` Richard Henderson
2 siblings, 0 replies; 71+ messages in thread
From: Mark Cave-Ayland @ 2022-03-28 20:27 UTC (permalink / raw)
To: Xiaojuan Yang, qemu-devel; +Cc: richard.henderson, Song Gao
On 28/03/2022 13:57, Xiaojuan Yang wrote:
> This patch realize the EIOINTC interrupt controller.
>
> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
> Signed-off-by: Song Gao <gaosong@loongson.cn>
> ---
> hw/intc/Kconfig | 3 +
> hw/intc/loongarch_extioi.c | 408 +++++++++++++++++++++++++++++
> hw/intc/meson.build | 1 +
> hw/intc/trace-events | 11 +
> hw/loongarch/Kconfig | 1 +
> include/hw/intc/loongarch_extioi.h | 77 ++++++
> 6 files changed, 501 insertions(+)
> create mode 100644 hw/intc/loongarch_extioi.c
> create mode 100644 include/hw/intc/loongarch_extioi.h
>
> diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
> index 71c04c328e..28bd1f185d 100644
> --- a/hw/intc/Kconfig
> +++ b/hw/intc/Kconfig
> @@ -96,3 +96,6 @@ config LOONGARCH_PCH_MSI
> select MSI_NONBROKEN
> bool
> select UNIMP
> +
> +config LOONGARCH_EXTIOI
> + bool
> diff --git a/hw/intc/loongarch_extioi.c b/hw/intc/loongarch_extioi.c
> new file mode 100644
> index 0000000000..af28e8d6e9
> --- /dev/null
> +++ b/hw/intc/loongarch_extioi.c
> @@ -0,0 +1,408 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * Loongson 3A5000 ext interrupt controller emulation
> + *
> + * Copyright (C) 2021 Loongson Technology Corporation Limited
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu/module.h"
> +#include "qemu/log.h"
> +#include "hw/irq.h"
> +#include "hw/sysbus.h"
> +#include "hw/loongarch/loongarch.h"
> +#include "hw/qdev-properties.h"
> +#include "exec/address-spaces.h"
> +#include "hw/intc/loongarch_extioi.h"
> +#include "migration/vmstate.h"
> +#include "trace.h"
> +
> +static void extioi_update_irq(void *opaque, int irq_num, int level)
> +{
> + LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
> + uint8_t ipnum, cpu;
> + unsigned long found1, found2;
> +
> + ipnum = s->sw_ipmap[irq_num];
> + cpu = s->sw_coremap[irq_num];
> + if (level == 1) {
> + if (test_bit(irq_num, (void *)s->enable) == false) {
> + return;
> + }
> + bitmap_set((void *)s->coreisr[cpu], irq_num, 1);
> + found1 = find_next_bit((void *)&(s->sw_ipisr[cpu][ipnum]),
> + EXTIOI_IRQS, 0);
> + bitmap_set((void *)&(s->sw_ipisr[cpu][ipnum]), irq_num, 1);
> +
> + if (found1 >= EXTIOI_IRQS) {
> + qemu_set_irq(s->parent_irq[cpu][ipnum], level);
> + }
> + } else {
> + bitmap_clear((void *)s->coreisr[cpu], irq_num, 1);
> + found1 = find_next_bit((void *)&(s->sw_ipisr[cpu][ipnum]),
> + EXTIOI_IRQS, 0);
> + bitmap_clear((void *)&(s->sw_ipisr[cpu][ipnum]), irq_num, 1);
> + found2 = find_next_bit((void *)&(s->sw_ipisr[cpu][ipnum]),
> + EXTIOI_IRQS, 0);
> +
> + if ((found1 < EXTIOI_IRQS) && (found2 >= EXTIOI_IRQS)) {
> + qemu_set_irq(s->parent_irq[cpu][ipnum], level);
> + }
> + }
> +}
> +
> +static void extioi_setirq(void *opaque, int irq, int level)
> +{
> + LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
> + trace_extioi_setirq(irq, level);
> + extioi_update_irq(s, irq, level);
> +}
> +
> +static uint64_t extioi_nodetype_readw(void *opaque, hwaddr addr, unsigned size)
> +{
> + LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
> + unsigned long offset = addr & 0xffff;
> + uint32_t ret, index;
> +
> + switch (offset) {
> + case EXTIOI_NODETYPE_START ... EXTIOI_NODETYPE_END - 1:
> + index = (offset - EXTIOI_NODETYPE_START) >> 2;
> + ret = s->nodetype[index];
> + break;
> + default:
> + break;
> + }
> +
> + trace_loongarch_extioi_nodetype_readw((uint32_t)addr, ret);
> + return ret;
> +}
> +
> +static void extioi_nodetype_writew(void *opaque, hwaddr addr,
> + uint64_t val, unsigned size)
> +{
> + LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
> + int index;
> + uint32_t offset;
> + trace_loongarch_extioi_nodetype_writew(size, (uint32_t)addr, val);
> +
> + offset = addr & 0xffff;
> +
> + switch (offset) {
> + case EXTIOI_NODETYPE_START ... EXTIOI_NODETYPE_END - 1:
> + index = (offset - EXTIOI_NODETYPE_START) >> 2;
> + s->nodetype[index] = val;
> + break;
> + default:
> + break;
> + }
> +}
> +
> +static uint64_t extioi_ipmap_enable_read(void *opaque, hwaddr addr,
> + unsigned size)
> +{
> + LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
> + uint8_t ret;
> +
> + switch (addr) {
> + case EXTIOI_IPMAP_START ... EXTIOI_IPMAP_END - 1:
> + ret = s->ipmap[addr];
> + break;
> + case EXTIOI_ENABLE_START ... EXTIOI_ENABLE_END - 1:
> + addr -= EXTIOI_ENABLE_START;
> + ret = s->enable[addr];
> + break;
> + default:
> + break;
> + }
> +
> + trace_loongarch_extioi_ipmap_enable_read((uint8_t)addr, ret);
> + return ret;
> +}
> +
> +static void extioi_ipmap_enable_write(void *opaque, hwaddr addr,
> + uint64_t value, unsigned size)
> +{
> + LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
> + uint8_t old_data, val = value & 0xff;
> + int i, level, ipnum, irqnum;
> + trace_loongarch_extioi_ipmap_enable_write(size, (uint8_t)addr, val);
> +
> + switch (addr) {
> + case EXTIOI_IPMAP_START ... EXTIOI_IPMAP_END - 1:
> + s->ipmap[addr] = val;
> + /* Routing in groups of 32 interrupt */
> + ipnum = find_first_bit((void *)&val, 4);
> + for (i = 0; i < 32; i++) {
> + irqnum = addr * 32 + i;
> + if (ipnum != 4) {
> + s->sw_ipmap[irqnum] = ipnum;
> + } else {
> + s->sw_ipmap[irqnum] = 0;
> + }
> + }
> + break;
> + case EXTIOI_ENABLE_START ... EXTIOI_ENABLE_END - 1:
> + addr -= EXTIOI_ENABLE_START;
> + old_data = s->enable[addr];
> + if (old_data != val) {
> + s->enable[addr] = val;
> + old_data = old_data ^ val;
> +
> + while ((i = find_first_bit((void *)&old_data, 8)) != 8) {
> + level = test_bit(i, (unsigned long *)&val);
> + extioi_update_irq(s, i + addr * 8, level);
> + clear_bit(i, (void *)&old_data);
> + }
> + }
> + break;
> + default:
> + break;
> + }
> +}
> +
> +static uint64_t extioi_bounce_coreisr_readw(void *opaque, hwaddr addr,
> + unsigned size)
> +{
> + LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
> + unsigned long offset = addr & 0xffff;
> + uint32_t ret, index;
> + int cpu;
> +
> + switch (offset) {
> + case EXTIOI_BOUNCE_START ... EXTIOI_BOUNCE_END - 1:
> + index = (offset - EXTIOI_BOUNCE_START) >> 2;
> + ret = s->bounce[index];
> + break;
> + case EXTIOI_COREISR_START ... EXTIOI_COREISR_END - 1:
> + index = ((offset - EXTIOI_COREISR_START) & 0x1f) >> 2;
> + cpu = ((offset - EXTIOI_COREISR_START) >> 8) & 0x3;
> + ret = s->coreisr[cpu][index];
> + break;
> + default:
> + break;
> + }
> +
> + trace_loongarch_extioi_bounce_coreisr_readw((uint32_t)addr, ret);
> + return ret;
> +}
> +
> +static void extioi_bounce_coreisr_writew(void *opaque, hwaddr addr,
> + uint64_t val, unsigned size)
> +{
> + LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
> + int cpu, index;
> + uint32_t offset, old_data, i, j, bits;
> +
> + offset = addr & 0xffff;
> + trace_loongarch_extioi_bounce_coreisr_writew(size, (uint32_t)addr, val);
> + switch (offset) {
> + case EXTIOI_BOUNCE_START ... EXTIOI_BOUNCE_END - 1:
> + index = (offset - EXTIOI_BOUNCE_START) >> 2;
> + s->bounce[index] = val;
> + break;
> + case EXTIOI_COREISR_START ... EXTIOI_COREISR_END - 1:
> + index = ((offset - EXTIOI_COREISR_START) & 0x1f) >> 2;
> + cpu = ((offset - EXTIOI_COREISR_START) >> 8) & 0x3;
> + old_data = s->coreisr[cpu][index];
> + s->coreisr[cpu][index] = old_data & ~val;
> + if (old_data != s->coreisr[cpu][index]) {
> + bits = size * 8;
> + while ((i = find_first_bit((void *)&val, bits)) != bits) {
> + j = test_bit(i, (unsigned long *)&old_data);
> + if (j) {
> + extioi_update_irq(s, i + index * 32, 0);
> + }
> + clear_bit(i, (void *)&val);
> + }
> + }
> + break;
> + default:
> + break;
> + }
> +}
> +
> +static uint64_t extioi_coremap_read(void *opaque, hwaddr addr, unsigned size)
> +{
> + LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
> + uint8_t ret;
> +
> + switch (addr) {
> + case EXTIOI_COREMAP_START ... EXTIOI_COREMAP_END - 1:
> + ret = s->coremap[addr];
> + break;
> + default:
> + break;
> + }
> +
> + trace_loongarch_extioi_coremap_read((uint8_t)addr, ret);
> + return ret;
> +}
> +
> +static void extioi_coremap_write(void *opaque, hwaddr addr,
> + uint64_t value, unsigned size)
> +{
> + LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
> + uint8_t val = value & 0xff;
> + int cpu;
> +
> + trace_loongarch_extioi_coremap_write(size, (uint8_t)addr, val);
> + switch (addr) {
> + case EXTIOI_COREMAP_START ... EXTIOI_COREMAP_END - 1:
> + s->coremap[addr] = val;
> +
> + /* Only support 1 node now only handle the core map*/
> + if (val) {
> + cpu = find_first_bit((void *)&val, 4);
> + if (cpu != 4) {
> + s->sw_coremap[addr] = cpu;
> + }
> + }
> + break;
> + default:
> + break;
> + }
> +}
> +
> +static const MemoryRegionOps extioi_nodetype_ops = {
> + .read = extioi_nodetype_readw,
> + .write = extioi_nodetype_writew,
> + .impl.min_access_size = 4,
> + .impl.max_access_size = 4,
> + .valid.min_access_size = 4,
> + .valid.max_access_size = 8,
> + .endianness = DEVICE_LITTLE_ENDIAN,
> +};
> +
> +static const MemoryRegionOps extioi_ipmap_enable_ops = {
> + .read = extioi_ipmap_enable_read,
> + .write = extioi_ipmap_enable_write,
> + .impl.min_access_size = 1,
> + .impl.max_access_size = 1,
> + .valid.min_access_size = 1,
> + .valid.max_access_size = 8,
> + .endianness = DEVICE_LITTLE_ENDIAN,
> +};
> +
> +static const MemoryRegionOps extioi_bounce_coreisr_ops = {
> + .read = extioi_bounce_coreisr_readw,
> + .write = extioi_bounce_coreisr_writew,
> + .impl.min_access_size = 4,
> + .impl.max_access_size = 4,
> + .valid.min_access_size = 4,
> + .valid.max_access_size = 8,
> + .endianness = DEVICE_LITTLE_ENDIAN,
> +};
> +
> +static const MemoryRegionOps extioi_coremap_ops = {
> + .read = extioi_coremap_read,
> + .write = extioi_coremap_write,
> + .impl.min_access_size = 1,
> + .impl.max_access_size = 1,
> + .valid.min_access_size = 1,
> + .valid.max_access_size = 8,
> + .endianness = DEVICE_LITTLE_ENDIAN,
> +};
> +
> +static const VMStateDescription vmstate_ext_sw_ipisr = {
> + .name = "ext_sw_ipisr",
> + .version_id = 1,
> + .minimum_version_id = 1,
> + .fields = (VMStateField[]) {
> + VMSTATE_UINT8_ARRAY(irq, ext_sw_ipisr, EXTIOI_IRQS),
> + VMSTATE_END_OF_LIST()
> + }
> +};
> +
> +static const VMStateDescription vmstate_loongarch_extioi = {
> + .name = TYPE_LOONGARCH_EXTIOI,
> + .version_id = 1,
> + .minimum_version_id = 1,
> + .fields = (VMStateField[]) {
> + VMSTATE_UINT32_ARRAY(bounce, LoongArchExtIOI, EXTIOI_IRQS_GROUP_COUNT),
> + VMSTATE_UINT32_2DARRAY(coreisr, LoongArchExtIOI, MAX_CORES,
> + EXTIOI_IRQS_GROUP_COUNT),
> + VMSTATE_UINT32_ARRAY(nodetype, LoongArchExtIOI,
> + EXTIOI_IRQS_NODETYPE_COUNT / 2),
> + VMSTATE_UINT8_ARRAY(enable, LoongArchExtIOI, EXTIOI_IRQS / 8),
> + VMSTATE_UINT8_ARRAY(ipmap, LoongArchExtIOI, 8),
> + VMSTATE_UINT8_ARRAY(coremap, LoongArchExtIOI, EXTIOI_IRQS),
> + VMSTATE_UINT8_ARRAY(sw_ipmap, LoongArchExtIOI, EXTIOI_IRQS),
> + VMSTATE_UINT8_ARRAY(sw_coremap, LoongArchExtIOI, EXTIOI_IRQS),
> + VMSTATE_STRUCT_2DARRAY(sw_ipisr, LoongArchExtIOI, MAX_CORES,
> + LS3A_INTC_IP, 1, vmstate_ext_sw_ipisr,
> + ext_sw_ipisr),
> + VMSTATE_END_OF_LIST()
> + }
> +};
> +
> +static void loongarch_extioi_instance_init(Object *obj)
> +{
> + SysBusDevice *dev = SYS_BUS_DEVICE(obj);
> + LoongArchExtIOI *s = LOONGARCH_EXTIOI(obj);
> + int i, cpu, pin;
> +
> + for (i = 0; i < EXTIOI_IRQS; i++) {
> + sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[i]);
> + }
> +
> + qdev_init_gpio_in(DEVICE(obj), extioi_setirq, EXTIOI_IRQS);
> +
> + for (cpu = 0; cpu < MAX_CORES; cpu++) {
> + sysbus_init_mmio(dev, &s->mmio[cpu]);
> + for (pin = 0; pin < LS3A_INTC_IP; pin++) {
> + qdev_init_gpio_out(DEVICE(obj), &s->parent_irq[cpu][pin], 1);
> + }
> +
> + memory_region_init(&s->mmio[cpu], OBJECT(s),
> + "loongarch_extioi", EXTIOI_SIZE);
> +
> + memory_region_init_io(&s->mmio_nodetype[cpu], OBJECT(s),
> + &extioi_nodetype_ops, s,
> + EXTIOI_LINKNAME(.nodetype),
> + IPMAP_OFFSET - APIC_BASE);
> + memory_region_add_subregion(&s->mmio[cpu], 0, &s->mmio_nodetype[cpu]);
> +
> + memory_region_init_io(&s->mmio_ipmap_enable[cpu], OBJECT(s),
> + &extioi_ipmap_enable_ops, s,
> + EXTIOI_LINKNAME(.ipmap_enable),
> + BOUNCE_OFFSET - IPMAP_OFFSET);
> + memory_region_add_subregion(&s->mmio[cpu], IPMAP_OFFSET - APIC_BASE,
> + &s->mmio_ipmap_enable[cpu]);
> +
> + memory_region_init_io(&s->mmio_bounce_coreisr[cpu], OBJECT(s),
> + &extioi_bounce_coreisr_ops, s,
> + EXTIOI_LINKNAME(.bounce_coreisr),
> + COREMAP_OFFSET - BOUNCE_OFFSET);
> + memory_region_add_subregion(&s->mmio[cpu], BOUNCE_OFFSET - APIC_BASE,
> + &s->mmio_bounce_coreisr[cpu]);
> +
> + memory_region_init_io(&s->mmio_coremap[cpu], OBJECT(s),
> + &extioi_coremap_ops, s,
> + EXTIOI_LINKNAME(.coremap),
> + EXTIOI_COREMAP_END);
> + memory_region_add_subregion(&s->mmio[cpu], COREMAP_OFFSET - APIC_BASE,
> + &s->mmio_coremap[cpu]);
> + }
> +}
> +
> +static void loongarch_extioi_class_init(ObjectClass *klass, void *data)
> +{
> + DeviceClass *dc = DEVICE_CLASS(klass);
> +
> + dc->vmsd = &vmstate_loongarch_extioi;
> +}
> +
> +static const TypeInfo loongarch_extioi_info = {
> + .name = TYPE_LOONGARCH_EXTIOI,
> + .parent = TYPE_SYS_BUS_DEVICE,
> + .instance_init = loongarch_extioi_instance_init,
> + .instance_size = sizeof(struct LoongArchExtIOI),
> + .class_init = loongarch_extioi_class_init,
> +};
> +
> +static void loongarch_extioi_register_types(void)
> +{
> + type_register_static(&loongarch_extioi_info);
> +}
> +
> +type_init(loongarch_extioi_register_types)
> diff --git a/hw/intc/meson.build b/hw/intc/meson.build
> index 77a30cec33..405e18f4bb 100644
> --- a/hw/intc/meson.build
> +++ b/hw/intc/meson.build
> @@ -65,3 +65,4 @@ specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c'))
> specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c'))
> specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_pic.c'))
> specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_MSI', if_true: files('loongarch_pch_msi.c'))
> +specific_ss.add(when: 'CONFIG_LOONGARCH_EXTIOI', if_true: files('loongarch_extioi.c'))
> diff --git a/hw/intc/trace-events b/hw/intc/trace-events
> index 7c02f8d5f0..40da8312b0 100644
> --- a/hw/intc/trace-events
> +++ b/hw/intc/trace-events
> @@ -291,3 +291,14 @@ loongarch_pch_pic_writeb(unsigned size, uint32_t addr, unsigned long val) "size:
>
> # loongarch_pch_msi.c
> loongarch_msi_set_irq(int irq_num) "set msi irq %d"
> +
> +# loongarch_extioi.c
> +extioi_setirq(int irq, int level) "set extirq irq %d level %d"
Should this be loongarch_extioi_setirq for consistency with all the other extioi
trace events?
> +loongarch_extioi_nodetype_readw(uint32_t addr, uint32_t val) "addr: 0x%"PRIx32 "val: 0x%" PRIx32
> +loongarch_extioi_nodetype_writew(unsigned size, uint32_t addr, uint32_t val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx32
> +loongarch_extioi_ipmap_enable_read(uint8_t addr, uint8_t val) "addr: 0x%"PRIu8 "val: 0x%" PRIu8
> +loongarch_extioi_ipmap_enable_write(unsigned size, uint8_t addr, uint8_t val) "size: %u addr: 0x%"PRIu8 "val: 0x%" PRIu8
> +loongarch_extioi_bounce_coreisr_readw(uint32_t addr, uint32_t val) "addr: 0x%"PRIx32 "val: 0x%" PRIx32
> +loongarch_extioi_bounce_coreisr_writew(unsigned size, uint32_t addr, uint32_t val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx32
> +loongarch_extioi_coremap_read(uint8_t addr, uint8_t val) "addr: 0x%"PRIu8 "val: 0x%" PRIu8
> +loongarch_extioi_coremap_write(unsigned size, uint8_t addr, uint8_t val) "size: %u addr: 0x%"PRIu8 "val: 0x%" PRIu8
> diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
> index d814fc6103..f779087416 100644
> --- a/hw/loongarch/Kconfig
> +++ b/hw/loongarch/Kconfig
> @@ -5,3 +5,4 @@ config LOONGARCH_VIRT
> select LOONGARCH_IPI
> select LOONGARCH_PCH_PIC
> select LOONGARCH_PCH_MSI
> + select LOONGARCH_EXTIOI
> diff --git a/include/hw/intc/loongarch_extioi.h b/include/hw/intc/loongarch_extioi.h
> new file mode 100644
> index 0000000000..befec7bb5d
> --- /dev/null
> +++ b/include/hw/intc/loongarch_extioi.h
> @@ -0,0 +1,77 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * LoongArch 3A5000 ext interrupt controller definitions
> + *
> + * Copyright (C) 2021 Loongson Technology Corporation Limited
> + */
> +
> +#include "hw/sysbus.h"
> +#include "hw/loongarch/loongarch.h"
> +
> +#ifndef LOONGARCH_EXTIOI_H
> +#define LOONGARCH_EXTIOI_H
> +
> +#define LS3A_INTC_IP 8
> +#define MAX_CORES LOONGARCH_MAX_VCPUS
> +#define EXTIOI_IRQS (256)
> +/* 32 irqs belong to a group */
> +#define EXTIOI_IRQS_GROUP_COUNT (256 / 32)
> +/* map to ipnum per 32 irqs */
> +#define EXTIOI_IRQS_NODETYPE_COUNT 16
> +
> +#define APIC_BASE 0x1400
> +#define ENABLE_OFFSET 0x1600
> +#define IPMAP_OFFSET 0x14c0
> +#define COREMAP_OFFSET 0x1c00
> +#define NODETYPE_OFFSET 0x14a0
> +#define BOUNCE_OFFSET 0x1680
> +#define COREISR_OFFSET 0x1800
> +
> +#define EXTIOI_NODETYPE_START (0x14a0 - APIC_BASE)
> +#define EXTIOI_NODETYPE_END (0x14c0 - APIC_BASE)
> +#define EXTIOI_BOUNCE_START 0
> +#define EXTIOI_BOUNCE_END (0x16a0 - BOUNCE_OFFSET)
> +#define EXTIOI_COREISR_START (0x1800 - BOUNCE_OFFSET)
> +#define EXTIOI_COREISR_END (0x1B20 - BOUNCE_OFFSET)
> +
> +#define EXTIOI_IPMAP_START 0
> +#define EXTIOI_IPMAP_END (0x14c8 - IPMAP_OFFSET)
> +#define EXTIOI_ENABLE_START (0x1600 - IPMAP_OFFSET)
> +#define EXTIOI_ENABLE_END (0x1618 - IPMAP_OFFSET)
> +
> +#define EXTIOI_COREMAP_START 0
> +#define EXTIOI_COREMAP_END (0x1d00 - COREMAP_OFFSET)
> +#define EXTIOI_SIZE 0x900
> +
> +#define TYPE_LOONGARCH_EXTIOI "loongarch_extioi"
> +#define EXTIOI_LINKNAME(name) TYPE_LOONGARCH_EXTIOI#name
> +OBJECT_DECLARE_SIMPLE_TYPE(LoongArchExtIOI, LOONGARCH_EXTIOI)
> +typedef struct ext_sw_ipisr {
> + uint8_t irq[EXTIOI_IRQS];
> +} ext_sw_ipisr;
Please can you use a CamelCase typedef here to match the struct below, perhaps
LoongArchExtSWIPISR?
> +typedef struct LoongArchExtIOI {
> + SysBusDevice parent_obj;
> + /* hardware state */
> + uint32_t nodetype[EXTIOI_IRQS_NODETYPE_COUNT / 2];
> + uint32_t bounce[EXTIOI_IRQS_GROUP_COUNT];
> + uint32_t coreisr[MAX_CORES][EXTIOI_IRQS_GROUP_COUNT];
> +
> + uint8_t enable[EXTIOI_IRQS / 8];
> + uint8_t ipmap[8];
> + uint8_t coremap[EXTIOI_IRQS];
> + /*software state */
> + uint8_t sw_ipmap[EXTIOI_IRQS];
> + uint8_t sw_coremap[EXTIOI_IRQS];
> + ext_sw_ipisr sw_ipisr[MAX_CORES][LS3A_INTC_IP];
You can use the typedef here.
> + qemu_irq parent_irq[MAX_CORES][LS3A_INTC_IP];
> + qemu_irq irq[EXTIOI_IRQS];
> + MemoryRegion mmio[MAX_CORES];
> + MemoryRegion mmio_nodetype[MAX_CORES];
> + MemoryRegion mmio_ipmap_enable[MAX_CORES];
> + MemoryRegion mmio_bounce_coreisr[MAX_CORES];
> + MemoryRegion mmio_coremap[MAX_CORES];
> +} LoongArchExtIOI;
> +
> +#endif /* LOONGARCH_EXTIOI_H */
And again drop the typedef on LoongArchExtIOI.
ATB,
Mark.
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 12/29] target/loongarch: Add timer related instructions support.
2022-03-28 12:57 ` [RFC PATCH v7 12/29] target/loongarch: Add timer related instructions support Xiaojuan Yang
@ 2022-03-28 20:33 ` Richard Henderson
0 siblings, 0 replies; 71+ messages in thread
From: Richard Henderson @ 2022-03-28 20:33 UTC (permalink / raw)
To: Xiaojuan Yang, qemu-devel; +Cc: mark.cave-ayland, Song Gao
On 3/28/22 06:57, Xiaojuan Yang wrote:
> +#ifndef CONFIG_USER_ONLY
> +static bool gen_rdtime(DisasContext *ctx, arg_rr *a,
> + bool word, bool high)
> +{
> + TCGv dst1 = gpr_dst(ctx, a->rd, EXT_NONE);
> + TCGv dst2 = gpr_dst(ctx, a->rj, EXT_NONE);
> +
> + if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
> + gen_io_start();
> + }
> + gen_helper_rdtime_d(dst1, cpu_env);
> + if (word) {
> + tcg_gen_sextract_tl(dst1, dst1, high ? 32 : 0, 32);
> + }
> + tcg_gen_ld_i64(dst2, cpu_env, offsetof(CPULoongArchState, CSR_TID));
> +
> + return true;
> +}
Remove all of the ifdefs.
> static bool trans_rdtimel_w(DisasContext *ctx, arg_rdtimel_w *a)
> {
> +#ifdef CONFIG_USER_ONLY
> tcg_gen_movi_tl(cpu_gpr[a->rd], 0);
> return true;
This (and all of the others) turns out to be a bug, as it fails to write to rj at all.
> +uint64_t helper_rdtime_d(CPULoongArchState *env)
> +{
> + LoongArchCPU *cpu = LOONGARCH_CPU(env_cpu(env));
> + return cpu_loongarch_get_constant_timer_counter(cpu);
> +}
Here, you could have
#ifdef CONFIG_USER_ONLY
return cpu_get_host_ticks();
#else
...
which is the fallback we use for other targets in user-mode.
You seem to be missing the checks on CSR.MISC.DRDTL* which would raise IPE.
r~
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 13/29] target/loongarch: Add gdb support.
2022-03-28 12:57 ` [RFC PATCH v7 13/29] target/loongarch: Add gdb support Xiaojuan Yang
@ 2022-03-28 20:35 ` Richard Henderson
0 siblings, 0 replies; 71+ messages in thread
From: Richard Henderson @ 2022-03-28 20:35 UTC (permalink / raw)
To: Xiaojuan Yang, qemu-devel; +Cc: mark.cave-ayland, Song Gao
On 3/28/22 06:57, Xiaojuan Yang wrote:
> +int loongarch_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
> +{
> + LoongArchCPU *cpu = LOONGARCH_CPU(cs);
> + CPULoongArchState *env = &cpu->env;
> + target_ulong tmp = ldtul_p(mem_buf);
> +
> + if (0 <= n && n < 32) {
> + return env->gpr[n] = tmp, sizeof(target_ulong);
Ew. Do not use the comma operator with return.
Split these into two statements, all through this file.
r~
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 14/29] hw/loongarch: Add support loongson3 virt machine type.
2022-03-28 12:57 ` [RFC PATCH v7 14/29] hw/loongarch: Add support loongson3 virt machine type Xiaojuan Yang
@ 2022-03-28 20:49 ` Richard Henderson
2022-03-28 21:02 ` Mark Cave-Ayland
0 siblings, 1 reply; 71+ messages in thread
From: Richard Henderson @ 2022-03-28 20:49 UTC (permalink / raw)
To: Xiaojuan Yang, qemu-devel; +Cc: mark.cave-ayland, Song Gao
On 3/28/22 06:57, Xiaojuan Yang wrote:
> +static uint64_t loongarch_qemu_read(void *opaque, hwaddr addr, unsigned size)
> +{
> + uint64_t feature = 0UL;
> +
> + switch (addr) {
> + case FEATURE_REG:
> + feature |= 1UL << IOCSRF_MSI | 1UL << IOCSRF_EXTIOI |
> + 1UL << IOCSRF_CSRIPI;
> + return feature ;
What's the point of the feature variable?
> + case VENDOR_REG:
> + return *(uint64_t *)"Loongson";
> + case CPUNAME_REG:
> + return *(uint64_t *)"3A5000";
This is definitely wrong, as (1) it depends on host endianness, and (2) you're reading 8
bytes from a 7 byte string.
> +static const MemoryRegionOps loongarch_qemu_ops = {
> + .read = loongarch_qemu_read,
> + .write = loongarch_qemu_write,
> + .endianness = DEVICE_LITTLE_ENDIAN,
> + .valid = {
> + .min_access_size = 4,
> + .max_access_size = 8,
> + },
> + .impl = {
> + .min_access_size = 4,
> + .max_access_size = 8,
> + },
The implementation above doesn't actually support access size 4; it only supports 8.
It doesn't seem like this should be a io region at all, but a ROM.
> +static void loongarch_cpu_init(LoongArchCPU *la_cpu, int cpu_num)
> +{
> + CPULoongArchState *env;
> + env = &la_cpu->env;
> +
> + memory_region_init_io(&env->system_iocsr, OBJECT(la_cpu), NULL,
> + env, "iocsr", UINT64_MAX);
> + address_space_init(&env->address_space_iocsr, &env->system_iocsr, "IOCSR");
> +
> + timer_init_ns(&la_cpu->timer, QEMU_CLOCK_VIRTUAL,
> + &loongarch_constant_timer_cb, la_cpu);
This timer belongs to the cpu, not the board model.
This init belongs over in target/loongarch/.
r~
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 15/29] hw/loongarch: Add LoongArch cpu interrupt support(CPUINTC)
2022-03-28 12:57 ` [RFC PATCH v7 15/29] hw/loongarch: Add LoongArch cpu interrupt support(CPUINTC) Xiaojuan Yang
@ 2022-03-28 20:57 ` Richard Henderson
0 siblings, 0 replies; 71+ messages in thread
From: Richard Henderson @ 2022-03-28 20:57 UTC (permalink / raw)
To: Xiaojuan Yang, qemu-devel; +Cc: mark.cave-ayland, Song Gao
On 3/28/22 06:57, Xiaojuan Yang wrote:
> +static void loongarch_cpu_set_irq(void *opaque, int irq, int level)
> +{
> + LoongArchCPU *cpu = opaque;
> + CPULoongArchState *env = &cpu->env;
> + CPUState *cs = CPU(cpu);
> +
> + if (irq < 0 || irq > N_IRQS) {
> + return;
> + }
> +
> + if (level) {
> + env->CSR_ESTAT |= 1 << irq;
> + } else {
> + env->CSR_ESTAT &= ~(1 << irq);
> + }
> +
> + if (FIELD_EX64(env->CSR_ESTAT, CSR_ESTAT, IS)) {
> + cpu_interrupt(cs, CPU_INTERRUPT_HARD);
> + } else {
> + cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
> + }
> +}
> +
> static void loongarch_cpu_reset(void *opaque)
> {
> LoongArchCPU *cpu = opaque;
> @@ -69,6 +92,8 @@ static void loongarch_cpu_init(LoongArchCPU *la_cpu, int cpu_num)
> CPULoongArchState *env;
> env = &la_cpu->env;
>
> + qdev_init_gpio_in(DEVICE(la_cpu), loongarch_cpu_set_irq, N_IRQS);
This all belongs over in target/loongarch/.
r~
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 05/29] target/loongarch: Add constant timer support
2022-03-28 12:57 ` [RFC PATCH v7 05/29] target/loongarch: Add constant timer support Xiaojuan Yang
2022-03-28 19:46 ` Richard Henderson
@ 2022-03-28 20:58 ` Richard Henderson
1 sibling, 0 replies; 71+ messages in thread
From: Richard Henderson @ 2022-03-28 20:58 UTC (permalink / raw)
To: Xiaojuan Yang, qemu-devel; +Cc: mark.cave-ayland, Song Gao
On 3/28/22 06:57, Xiaojuan Yang wrote:
> +#define N_IRQS 14
There are only 13 irqs, according to ESTAT.
r~
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 14/29] hw/loongarch: Add support loongson3 virt machine type.
2022-03-28 20:49 ` Richard Henderson
@ 2022-03-28 21:02 ` Mark Cave-Ayland
2022-04-15 7:52 ` yangxiaojuan
0 siblings, 1 reply; 71+ messages in thread
From: Mark Cave-Ayland @ 2022-03-28 21:02 UTC (permalink / raw)
To: Richard Henderson, Xiaojuan Yang, qemu-devel; +Cc: Song Gao
On 28/03/2022 21:49, Richard Henderson wrote:
> On 3/28/22 06:57, Xiaojuan Yang wrote:
>> +static uint64_t loongarch_qemu_read(void *opaque, hwaddr addr, unsigned size)
>> +{
>> + uint64_t feature = 0UL;
>> +
>> + switch (addr) {
>> + case FEATURE_REG:
>> + feature |= 1UL << IOCSRF_MSI | 1UL << IOCSRF_EXTIOI |
>> + 1UL << IOCSRF_CSRIPI;
>> + return feature ;
>
> What's the point of the feature variable?
>
>> + case VENDOR_REG:
>> + return *(uint64_t *)"Loongson";
>> + case CPUNAME_REG:
>> + return *(uint64_t *)"3A5000";
>
> This is definitely wrong, as (1) it depends on host endianness, and (2) you're
> reading 8 bytes from a 7 byte string.
>
>> +static const MemoryRegionOps loongarch_qemu_ops = {
>> + .read = loongarch_qemu_read,
>> + .write = loongarch_qemu_write,
>> + .endianness = DEVICE_LITTLE_ENDIAN,
>> + .valid = {
>> + .min_access_size = 4,
>> + .max_access_size = 8,
>> + },
>> + .impl = {
>> + .min_access_size = 4,
>> + .max_access_size = 8,
>> + },
>
> The implementation above doesn't actually support access size 4; it only supports 8.
> It doesn't seem like this should be a io region at all, but a ROM.
Strangely enough I had a similar requirement for my q800 patches, and when I tried to
implement a ROM memory region then the accesses didn't work as expected. I can't
remember the exact problem however...
>> +static void loongarch_cpu_init(LoongArchCPU *la_cpu, int cpu_num)
>> +{
>> + CPULoongArchState *env;
>> + env = &la_cpu->env;
>> +
>> + memory_region_init_io(&env->system_iocsr, OBJECT(la_cpu), NULL,
>> + env, "iocsr", UINT64_MAX);
>> + address_space_init(&env->address_space_iocsr, &env->system_iocsr, "IOCSR");
>> +
>> + timer_init_ns(&la_cpu->timer, QEMU_CLOCK_VIRTUAL,
>> + &loongarch_constant_timer_cb, la_cpu);
>
> This timer belongs to the cpu, not the board model.
> This init belongs over in target/loongarch/.
That's probably my fault; the example of splitting the non-user parts of the CPU into
a separate function was based upon SPARC64 and that code currently lives in
hw/sparc64. I do recall there were some recent discussions about moving such code
into target/* though.
ATB,
Mark.
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 16/29] hw/loongarch: Add LoongArch ipi interrupt support(IPI)
2022-03-28 12:57 ` [RFC PATCH v7 16/29] hw/loongarch: Add LoongArch ipi interrupt support(IPI) Xiaojuan Yang
2022-03-28 20:15 ` Mark Cave-Ayland
@ 2022-03-28 22:04 ` Richard Henderson
2022-03-28 22:06 ` Richard Henderson
2 siblings, 0 replies; 71+ messages in thread
From: Richard Henderson @ 2022-03-28 22:04 UTC (permalink / raw)
To: Xiaojuan Yang, qemu-devel; +Cc: mark.cave-ayland, Song Gao
On 3/28/22 06:57, Xiaojuan Yang wrote:
> +static void loongarch_ipi_writel(void *opaque, hwaddr addr, uint64_t val,
> + unsigned size)
> +{
> + IPICore *s = opaque;
> + int index = 0;
> +
> + addr &= 0xff;
> + trace_loongarch_ipi_write(size, (uint64_t)addr, val);
> + switch (addr) {
> + case CORE_STATUS_OFF:
> + qemu_log_mask(LOG_GUEST_ERROR, "can not be written");
> + break;
> + case CORE_EN_OFF:
> + s->en = val;
> + break;
Changes to s->en should affect irq.
> + case CORE_SET_OFF:
> + s->status |= val;
> + if (s->status != 0) {
> + qemu_irq_raise(s->irq);
> + }
I think s->en should be taken into account when raising irq.
> + break;
> + case CORE_CLEAR_OFF:
> + s->status ^= val;
Incorrect: status &= ~val.
> + if (s->status == 0) {
> + qemu_irq_lower(s->irq);
> + }
Likewise, s->en.
> + break;
> + case CORE_BUF_20 ... CORE_BUF_38 + 4:
> + index = (addr - CORE_BUF_20) >> 2;
> + s->buf[index] = val;
> + break;
> + case IOCSR_IPI_SEND:
> + s->status |= val;
I can't see where this comes from, but helper_iocsr_write is very confusing. It *appears*
as if this is never invoked, because IPI_SEND is handled directly in helper_iocsr_write
(which also seems wrong).
r~
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 16/29] hw/loongarch: Add LoongArch ipi interrupt support(IPI)
2022-03-28 12:57 ` [RFC PATCH v7 16/29] hw/loongarch: Add LoongArch ipi interrupt support(IPI) Xiaojuan Yang
2022-03-28 20:15 ` Mark Cave-Ayland
2022-03-28 22:04 ` Richard Henderson
@ 2022-03-28 22:06 ` Richard Henderson
2 siblings, 0 replies; 71+ messages in thread
From: Richard Henderson @ 2022-03-28 22:06 UTC (permalink / raw)
To: Xiaojuan Yang, qemu-devel; +Cc: mark.cave-ayland, Song Gao
On 3/28/22 06:57, Xiaojuan Yang wrote:
> +typedef struct LoongArchIPI {
> + SysBusDevice parent_obj;
> + IPICore core[MAX_IPI_CORE_NUM];
> + MemoryRegion ipi_mmio[MAX_IPI_CORE_NUM];
> +} LoongArchIPI;
Why does this have an array of cores?
Surely the IPI device itself should not have this, but the board model should have an
array of IPI devices, one for each CPU that it supports.
r~
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 19/29] hw/intc: Add LoongArch extioi interrupt controller(EIOINTC)
2022-03-28 12:57 ` [RFC PATCH v7 19/29] hw/intc: Add LoongArch extioi interrupt controller(EIOINTC) Xiaojuan Yang
2022-03-28 20:27 ` Mark Cave-Ayland
@ 2022-03-28 22:43 ` Richard Henderson
2022-03-31 12:28 ` yangxiaojuan
2022-03-28 22:46 ` Richard Henderson
2 siblings, 1 reply; 71+ messages in thread
From: Richard Henderson @ 2022-03-28 22:43 UTC (permalink / raw)
To: Xiaojuan Yang, qemu-devel; +Cc: mark.cave-ayland, Song Gao
On 3/28/22 06:57, Xiaojuan Yang wrote:
> This patch realize the EIOINTC interrupt controller.
>
> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
> Signed-off-by: Song Gao <gaosong@loongson.cn>
> ---
> hw/intc/Kconfig | 3 +
> hw/intc/loongarch_extioi.c | 408 +++++++++++++++++++++++++++++
> hw/intc/meson.build | 1 +
> hw/intc/trace-events | 11 +
> hw/loongarch/Kconfig | 1 +
> include/hw/intc/loongarch_extioi.h | 77 ++++++
> 6 files changed, 501 insertions(+)
> create mode 100644 hw/intc/loongarch_extioi.c
> create mode 100644 include/hw/intc/loongarch_extioi.h
>
> diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
> index 71c04c328e..28bd1f185d 100644
> --- a/hw/intc/Kconfig
> +++ b/hw/intc/Kconfig
> @@ -96,3 +96,6 @@ config LOONGARCH_PCH_MSI
> select MSI_NONBROKEN
> bool
> select UNIMP
> +
> +config LOONGARCH_EXTIOI
> + bool
> diff --git a/hw/intc/loongarch_extioi.c b/hw/intc/loongarch_extioi.c
> new file mode 100644
> index 0000000000..af28e8d6e9
> --- /dev/null
> +++ b/hw/intc/loongarch_extioi.c
> @@ -0,0 +1,408 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * Loongson 3A5000 ext interrupt controller emulation
> + *
> + * Copyright (C) 2021 Loongson Technology Corporation Limited
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu/module.h"
> +#include "qemu/log.h"
> +#include "hw/irq.h"
> +#include "hw/sysbus.h"
> +#include "hw/loongarch/loongarch.h"
> +#include "hw/qdev-properties.h"
> +#include "exec/address-spaces.h"
> +#include "hw/intc/loongarch_extioi.h"
> +#include "migration/vmstate.h"
> +#include "trace.h"
> +
> +static void extioi_update_irq(void *opaque, int irq_num, int level)
> +{
> + LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
I think this is not opaque anymore; you've already resolved it in the caller.
I think level should be 'bool'.
> + uint8_t ipnum, cpu;
> + unsigned long found1, found2;
> +
> + ipnum = s->sw_ipmap[irq_num];
> + cpu = s->sw_coremap[irq_num];
> + if (level == 1) {
Just if (level).
> + if (test_bit(irq_num, (void *)s->enable) == false) {
This, and every other cast you're using for bitops.h functions, is wrong. You would need
to declare these bitmaps properly as 'unsigned long name[BITS_TO_LONGS(N)];'.
That said, I would definitely use uint64_t, because that matches up with the description
of these registers in the manual.
> + return;
> + }
> + bitmap_set((void *)s->coreisr[cpu], irq_num, 1);
> + found1 = find_next_bit((void *)&(s->sw_ipisr[cpu][ipnum]),
> + EXTIOI_IRQS, 0);
find_next_bit with offset=0 is find_first_bit...
> + bitmap_set((void *)&(s->sw_ipisr[cpu][ipnum]), irq_num, 1);
> +
> + if (found1 >= EXTIOI_IRQS) {
> + qemu_set_irq(s->parent_irq[cpu][ipnum], level);
> + }
... but what's the bitmap search doing? It appears to be checking that there are *no*
bits set between 0 and EXTIOI_IRQS, and then raising the irq if no bits set. That seems
wrong.
> + } else {
> + bitmap_clear((void *)s->coreisr[cpu], irq_num, 1);
> + found1 = find_next_bit((void *)&(s->sw_ipisr[cpu][ipnum]),
> + EXTIOI_IRQS, 0);
> + bitmap_clear((void *)&(s->sw_ipisr[cpu][ipnum]), irq_num, 1);
> + found2 = find_next_bit((void *)&(s->sw_ipisr[cpu][ipnum]),
> + EXTIOI_IRQS, 0);
> +
> + if ((found1 < EXTIOI_IRQS) && (found2 >= EXTIOI_IRQS)) {
> + qemu_set_irq(s->parent_irq[cpu][ipnum], level);
> + }
> + }
> +}
It *seems* like all of this should be
uint64_t sum = 0;
s->isr[ipnum / 64] = deposit64(s->isr[ipnum / 64], ipnum % 64, 1, level);
for (int i = 0; i < ARRAY_SIZE(s->isr); i++) {
sum |= s->isr[i] & s->ena[i];
}
qemu_set_irq(parent, sum != 0);
If that's not the case, you need many more comments.
r~
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 19/29] hw/intc: Add LoongArch extioi interrupt controller(EIOINTC)
2022-03-28 12:57 ` [RFC PATCH v7 19/29] hw/intc: Add LoongArch extioi interrupt controller(EIOINTC) Xiaojuan Yang
2022-03-28 20:27 ` Mark Cave-Ayland
2022-03-28 22:43 ` Richard Henderson
@ 2022-03-28 22:46 ` Richard Henderson
2 siblings, 0 replies; 71+ messages in thread
From: Richard Henderson @ 2022-03-28 22:46 UTC (permalink / raw)
To: Xiaojuan Yang, qemu-devel; +Cc: mark.cave-ayland, Song Gao
On 3/28/22 06:57, Xiaojuan Yang wrote:
> +static uint64_t extioi_ipmap_enable_read(void *opaque, hwaddr addr,
> + unsigned size)
> +{
> + LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
> + uint8_t ret;
> +
> + switch (addr) {
> + case EXTIOI_IPMAP_START ... EXTIOI_IPMAP_END - 1:
> + ret = s->ipmap[addr];
> + break;
> + case EXTIOI_ENABLE_START ... EXTIOI_ENABLE_END - 1:
> + addr -= EXTIOI_ENABLE_START;
> + ret = s->enable[addr];
> + break;
> + default:
> + break;
> + }
> +
> + trace_loongarch_extioi_ipmap_enable_read((uint8_t)addr, ret);
> + return ret;
> +}
There are at least 4 instances of uninitialized use of 'ret' in this file, and this is
one. Are you compiling with --disable-werror? You must not do that.
r~
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 09/29] target/loongarch: Add TLB instruction support
2022-03-28 12:57 ` [RFC PATCH v7 09/29] target/loongarch: Add TLB instruction support Xiaojuan Yang
2022-03-28 20:12 ` Richard Henderson
@ 2022-03-28 22:50 ` Richard Henderson
1 sibling, 0 replies; 71+ messages in thread
From: Richard Henderson @ 2022-03-28 22:50 UTC (permalink / raw)
To: Xiaojuan Yang, qemu-devel; +Cc: mark.cave-ayland, Song Gao
On 3/28/22 06:57, Xiaojuan Yang wrote:
> +void helper_tlbflush(CPULoongArchState *env)
> +{
> + int i, index;
> +
> + index = FIELD_EX64(env->CSR_TLBIDX, CSR_TLBIDX, INDEX);
> +
> + if (index < LOONGARCH_STLB) {
> + /* STLB. One line per operation */
> + for (i = 0; i < 8; i++) {
> + int index = i * 256 + (index % 256);
Another uninitialized use Werror that you should have seen: You're shadowing the outer
'index' variable, which means this doesn't do what you intended.
r~
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 20/29] hw/loongarch: Add irq hierarchy for the system
2022-03-28 12:57 ` [RFC PATCH v7 20/29] hw/loongarch: Add irq hierarchy for the system Xiaojuan Yang
@ 2022-03-28 23:16 ` Richard Henderson
0 siblings, 0 replies; 71+ messages in thread
From: Richard Henderson @ 2022-03-28 23:16 UTC (permalink / raw)
To: Xiaojuan Yang, qemu-devel; +Cc: mark.cave-ayland, Song Gao
On 3/28/22 06:57, Xiaojuan Yang wrote:
> +static struct DeviceState *ipi, *extioi;
Static variables can't be right.
These need to be somewhere else, or ...
> @@ -107,12 +115,101 @@ static void loongarch_cpu_init(LoongArchCPU *la_cpu, int cpu_num)
> NULL, "iocsr_misc", IOCSR_MEM_SIZE);
>
> memory_region_add_subregion(&env->system_iocsr, 0, &env->iocsr_mem);
> + /* ipi memory region */
> + ipi_addr = SMP_IPI_MAILBOX + cpu_num * 0x100;
> + memory_region_add_subregion(&env->system_iocsr, ipi_addr,
> + sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi),
> + cpu_num));
> + /* extioi memory region */
> + memory_region_add_subregion(&env->system_iocsr, APIC_BASE,
> + sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi),
> + cpu_num));
... this code needs to be moved somewhere else.
> +static void loongarch_irq_init(LoongArchMachineState *lams,
> + DeviceState *ipi, DeviceState *extioi)
> +{
> + MachineState *ms = MACHINE(lams);
> + DeviceState *pch_pic, *pch_msi, *cpudev;
> +
> + SysBusDevice *d;
> + int cpu, pin, i;
> +
> + for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
> + cpudev = DEVICE(qemu_get_cpu(cpu));
> + /* connect ipi irq to cpu irq */
> + qdev_connect_gpio_out(ipi, cpu, qdev_get_gpio_in(cpudev, IRQ_IPI));
> + }
> +
> + for (i = 0; i < EXTIOI_IRQS; i++) {
> + sysbus_connect_irq(SYS_BUS_DEVICE(extioi),
> + i, qdev_get_gpio_in(extioi, i));
> + }
Um... connecting extioi to itself?
I think that graphic that you used in the description of patch 15 belongs here as a comment.
> diff --git a/include/hw/pci-host/ls7a.h b/include/hw/pci-host/ls7a.h
> new file mode 100644
> index 0000000000..bf80e99ce1
> --- /dev/null
> +++ b/include/hw/pci-host/ls7a.h
> @@ -0,0 +1,30 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * QEMU LoongArch CPU
> + *
> + * Copyright (c) 2021 Loongson Technology Corporation Limited
> + */
> +
> +#ifndef HW_LS7A_H
> +#define HW_LS7A_H
> +
> +#include "hw/pci/pci.h"
> +#include "hw/pci/pcie_host.h"
> +#include "hw/pci-host/pam.h"
> +#include "qemu/units.h"
> +#include "qemu/range.h"
> +#include "qom/object.h"
> +
> +#define LS7A_PCH_REG_BASE 0x10000000UL
> +#define LS7A_IOAPIC_REG_BASE (LS7A_PCH_REG_BASE)
> +#define LS7A_PCH_MSI_ADDR_LOW 0x2FF00000UL
> +
> +/*
> + * According to the kernel pch irq start from 64 offset
> + * 0 ~ 16 irqs used for non-pci device while 16 ~ 64 irqs
> + * used for pci device.
> + */
> +#define PCH_PIC_IRQ_OFFSET 64
> +#define LS7A_DEVICE_IRQS 16
> +#define LS7A_PCI_IRQS 48
> +#endif
Why is this file in this patch?
It seems like it should be in either patch 17 or 18?
r~
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 21/29] Enable common virtio pci support for LoongArch
2022-03-28 12:57 ` [RFC PATCH v7 21/29] Enable common virtio pci support for LoongArch Xiaojuan Yang
@ 2022-03-28 23:18 ` Richard Henderson
0 siblings, 0 replies; 71+ messages in thread
From: Richard Henderson @ 2022-03-28 23:18 UTC (permalink / raw)
To: Xiaojuan Yang, qemu-devel; +Cc: mark.cave-ayland, Song Gao
On 3/28/22 06:57, Xiaojuan Yang wrote:
> Signed-off-by: Xiaojuan Yang<yangxiaojuan@loongson.cn>
> Signed-off-by: Song Gao<gaosong@loongson.cn>
> ---
> softmmu/qdev-monitor.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
r~
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 24/29] hw/loongarch: Add default bios startup support.
2022-03-28 12:57 ` [RFC PATCH v7 24/29] hw/loongarch: Add default bios startup support Xiaojuan Yang
@ 2022-03-29 3:27 ` Richard Henderson
0 siblings, 0 replies; 71+ messages in thread
From: Richard Henderson @ 2022-03-29 3:27 UTC (permalink / raw)
To: Xiaojuan Yang, qemu-devel; +Cc: mark.cave-ayland, Song Gao
On 3/28/22 06:57, Xiaojuan Yang wrote:
> Signed-off-by: Xiaojuan Yang<yangxiaojuan@loongson.cn>
> Signed-off-by: Song Gao<gaosong@loongson.cn>
> ---
> hw/loongarch/Kconfig | 4 ++
> hw/loongarch/fw_cfg.c | 33 ++++++++++++++
> hw/loongarch/fw_cfg.h | 15 +++++++
> hw/loongarch/loongson3.c | 76 +++++++++++++++++++++++++++++++-
> hw/loongarch/meson.build | 1 +
> include/hw/loongarch/loongarch.h | 8 ++++
> 6 files changed, 135 insertions(+), 2 deletions(-)
> create mode 100644 hw/loongarch/fw_cfg.c
> create mode 100644 hw/loongarch/fw_cfg.h
Not within this patch, but you will want to create a submodule for this bios image, as we
do for roms/edk2 etc. You will want to commit a pre-built image as well, like we do for
other targets.
> + /* load the BIOS image. */
> + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS,
> + machine->firmware ?: LOONGSON3_BIOSNAME);
> + if (filename) {
> + bios_size = load_image_targphys(filename, LA_BIOS_BASE, LA_BIOS_SIZE);
> + lams->fw_cfg = loongarch_fw_cfg_init(ram_size, machine);
> + rom_set_fw(lams->fw_cfg);
> + g_free(filename);
> + } else {
> + bios_size = -1;
> + }
While loading the efi bios may be the most common usage, it's not efficient for simple
tests. I think you should attempt to load an elf image, and only if that fails treat it
as the firmware blob that efi builds.
Or not require a bios image if -kernel is present, or something.
At the moment one cannot run the tests/tcg/multiarch tests without loongarch.bios.
r~
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 29/29] tests/tcg/loongarch64: Add hello/memory test in loongarch64 system
2022-03-28 12:57 ` [RFC PATCH v7 29/29] tests/tcg/loongarch64: Add hello/memory test in loongarch64 system Xiaojuan Yang
@ 2022-03-29 3:29 ` Richard Henderson
0 siblings, 0 replies; 71+ messages in thread
From: Richard Henderson @ 2022-03-29 3:29 UTC (permalink / raw)
To: Xiaojuan Yang, qemu-devel; +Cc: mark.cave-ayland, Song Gao
On 3/28/22 06:57, Xiaojuan Yang wrote:
> + .global _start
> + .align 16
> +_start:
> + bl main
You must at least set up the stack. This must work only via some interaction with efi
bios? What we *want* is for this to run by itself on the raw virt machine.
r~
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 00/29] Add LoongArch softmmu support
2022-03-28 18:13 ` [RFC PATCH v7 00/29] Add LoongArch softmmu support Richard Henderson
@ 2022-03-30 9:34 ` yangxiaojuan
0 siblings, 0 replies; 71+ messages in thread
From: yangxiaojuan @ 2022-03-30 9:34 UTC (permalink / raw)
To: Richard Henderson, qemu-devel; +Cc: mark.cave-ayland, gaosong
Hi Richard.
On 2022/3/29 上午2:13, Richard Henderson wrote:
> On 3/28/22 06:57, Xiaojuan Yang wrote:
>> This series patch add softmmu support for LoongArch.
>> The latest kernel:
>> * https://github.com/loongson/linux/tree/loongarch-next
>> The latest uefi:
>> * https://github.com/loongson/edk2
>> * https://github.com/loongson/edk2-platforms
>> The manual:
>> *
>> https://github.com/loongson/LoongArch-Documentation/releases/tag/2021.10.11
>>
>> You can get LoongArch qemu series like this:
>> git clone https://github.com/loongson/qemu.git
>> git checkout tcg-dev
>
> I strongly suggest that you rebase *without* the patches for
> linux-user/loongarch64/.
> If you do not do this, you will be stalled until your linux kernel
> patches are merged.
>
> Testing this rebase locally, there is only a minor patch conflict in
>
> target/loongarch: Add LoongArch interrupt and exception handle
>
> which suggests that the EXCP_* names be removed from
>
> target/loongarch: Add core definition
>
> The EXCCODE_* names be introduced early instead, and all of the uses
> updated.
>
OK, Thanks for your advice, We will send a new series after solving
all problems.
Thanks.
Xiaojuan
>
> r~
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 07/29] target/loongarch: Add LoongArch CSR instruction
2022-03-28 18:34 ` Richard Henderson
@ 2022-03-30 10:01 ` yangxiaojuan
2022-03-30 13:46 ` Richard Henderson
0 siblings, 1 reply; 71+ messages in thread
From: yangxiaojuan @ 2022-03-30 10:01 UTC (permalink / raw)
To: Richard Henderson, qemu-devel; +Cc: mark.cave-ayland, Song Gao
[-- Attachment #1: Type: text/plain, Size: 1854 bytes --]
On 2022/3/29 上午2:34, Richard Henderson wrote:
>> +target_ulong helper_csr_rdq(CPULoongArchState *env, uint64_t csr)
>> +{
>> + LoongArchCPU *cpu;
>> + int64_t v;
>> +
>> + switch (csr) {
>> + case LOONGARCH_CSR_PGD:
>> + if (env->CSR_TLBRERA & 0x1) {
>> + v = env->CSR_TLBRBADV;
>> + } else {
>> + v = env->CSR_BADV;
>> + }
>> +
>> + if ((v >> 63) & 0x1) {
>> + v = env->CSR_PGDH;
>> + } else {
>> + v = env->CSR_PGDL;
>> + }
>> + break;
>> + case LOONGARCH_CSR_CPUID:
>> + v = (env_cpu(env))->cpu_index;
>> + break;
>> + case LOONGARCH_CSR_TVAL:
>> + cpu = LOONGARCH_CPU(env_cpu(env));
>> + v = cpu_loongarch_get_constant_timer_ticks(cpu);
>> + break;
>> + default:
>> + break;
>> + }
>> +
>> + return v;
>> +}
>
> You should have seen a compiler warning for 'v' uninitialized here,
> via the default path.
>
> The default path should not be reachable, because of code in
> trans_csrrd, and so could be written as g_assert_not_reachable().
> However, I strongly suggest you split this function so that you do not
> need a switch here at all. With CPUID now handled via cpu_csr_offset,
> there are only two helpers needed.
trans_csrrd {
...
switch(a->csr) {
case LOONGARCH_CSR_PGD:
gen_helper_csrrd_pgd();
break;
case LOONGARCH_CSR_TVAL:
gen_helper_csrrd_tval();
break;
case LOONGARCH_CSR_CPUID:
...
default:
...
}
}
And the same in trans_csrwr, is this right?
Thanks.
Xiaojuan
[-- Attachment #2: Type: text/html, Size: 3043 bytes --]
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 08/29] target/loongarch: Add LoongArch IOCSR instruction
2022-03-28 18:55 ` Richard Henderson
@ 2022-03-30 10:02 ` yangxiaojuan
0 siblings, 0 replies; 71+ messages in thread
From: yangxiaojuan @ 2022-03-30 10:02 UTC (permalink / raw)
To: Richard Henderson, qemu-devel; +Cc: mark.cave-ayland, Song Gao
On 2022/3/29 上午2:55, Richard Henderson wrote:
> On 3/28/22 06:57, Xiaojuan Yang wrote:
>> +uint64_t helper_iocsr_read(CPULoongArchState *env, target_ulong r_addr,
>> + uint32_t size)
>> +{
>> + int cpuid = env_cpu(env)->cpu_index;
>> + CPUState *cs = qemu_get_cpu(cpuid);
>> + env = cs->env_ptr;
>> + uint64_t ret;
>> +
>> + /*
>> + * Adjust the per core address such as 0x10xx(IPI)/0x18xx(EXTIOI)
>> + */
>> + if (((r_addr & 0xff00) == 0x1000) || ((r_addr & 0xff00) ==
>> 0x1800)) {
>> + r_addr = r_addr + ((target_ulong)(cpuid & 0x3) << 8);
>> + }
>> +
>> + switch (size) {
>> + case 1:
>> + ret = address_space_ldub(&env->address_space_iocsr, r_addr,
>> + MEMTXATTRS_UNSPECIFIED, NULL);
>> + break;
>> + case 2:
>> + ret = address_space_lduw(&env->address_space_iocsr, r_addr,
>> + MEMTXATTRS_UNSPECIFIED, NULL);
>> + break;
>> + case 4:
>> + ret = address_space_ldl(&env->address_space_iocsr, r_addr,
>> + MEMTXATTRS_UNSPECIFIED, NULL);
>> + break;
>> + case 8:
>> + ret = address_space_ldq(&env->address_space_iocsr, r_addr,
>> + MEMTXATTRS_UNSPECIFIED, NULL);
>> + break;
>> + default:
>> + break;
>> + }
>> +
>> + return ret;
>> +}
>
> You should have seen an uninitialized use of 'ret' here.
> The default case should be g_assert_not_reached().
> And the same in helper_iocsr_write.
>
OK.
Thanks.
Xiaojuan
>
> r~
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 02/29] target/loongarch: Add CSRs definition
2022-03-28 19:16 ` Richard Henderson
@ 2022-03-30 10:04 ` yangxiaojuan
0 siblings, 0 replies; 71+ messages in thread
From: yangxiaojuan @ 2022-03-30 10:04 UTC (permalink / raw)
To: Richard Henderson, qemu-devel; +Cc: mark.cave-ayland, Song Gao
On 2022/3/29 上午3:16, Richard Henderson wrote:
> On 3/28/22 06:57, Xiaojuan Yang wrote:
>> +++ b/target/loongarch/cpu.h
>> @@ -11,6 +11,7 @@
>> #include "exec/cpu-defs.h"
>> #include "fpu/softfloat-types.h"
>> #include "hw/registerfields.h"
>> +#include "cpu-csr.h"
>
> Do you need this include here?
No.
> I would hope that there would be only a few extra files that need this.
>
I will correct it.
Thanks.
Xiaojuan
> Otherwise,
> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
>
>
> r~
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 07/29] target/loongarch: Add LoongArch CSR instruction
2022-03-30 10:01 ` yangxiaojuan
@ 2022-03-30 13:46 ` Richard Henderson
0 siblings, 0 replies; 71+ messages in thread
From: Richard Henderson @ 2022-03-30 13:46 UTC (permalink / raw)
To: yangxiaojuan, qemu-devel; +Cc: mark.cave-ayland, Song Gao
On 3/30/22 04:01, yangxiaojuan wrote:
> trans_csrrd {
> ...
> switch(a->csr) {
> case LOONGARCH_CSR_PGD:
> gen_helper_csrrd_pgd();
> break;
> case LOONGARCH_CSR_TVAL:
> gen_helper_csrrd_tval();
> break;
> case LOONGARCH_CSR_CPUID:
> ...
> default:
> ...
> }
> }
> And the same in trans_csrwr, is this right?
That's the idea, yes. However, you'll want to pull these switches out to helper functions
within trans_privileged.c.inc so that you may reuse them for trans_csrxchg.
r~
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 05/29] target/loongarch: Add constant timer support
2022-03-28 19:46 ` Richard Henderson
@ 2022-03-31 0:59 ` yangxiaojuan
0 siblings, 0 replies; 71+ messages in thread
From: yangxiaojuan @ 2022-03-31 0:59 UTC (permalink / raw)
To: Richard Henderson, qemu-devel; +Cc: mark.cave-ayland, Song Gao
On 2022/3/29 上午3:46, Richard Henderson wrote:
> On 3/28/22 06:57, Xiaojuan Yang wrote:
>> +void cpu_loongarch_store_constant_timer_config(LoongArchCPU *cpu,
>> + uint64_t value)
>> +{
>> + CPULoongArchState *env = &cpu->env;
>> + uint64_t now, next;
>> +
>> + env->CSR_TCFG = value;
>> + if (value & CONSTANT_TIMER_ENABLE) {
>> + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
>> + next = now + (value & CONSTANT_TIMER_TICK_MASK) * TIMER_PERIOD;
>> + timer_mod(&cpu->timer, next);
>> + }
>
> If CONSTANT_TIMER_ENABLE is not set, you need to use timer_del() to
> turn off any existing timer.
>
OK
>
>> +void loongarch_constant_timer_cb(void *opaque)
>> +{
>> + LoongArchCPU *cpu = opaque;
>> + CPULoongArchState *env = &cpu->env;
>> + uint64_t now, next;
>> +
>> + if (FIELD_EX64(env->CSR_TCFG, CSR_TCFG, PERIODIC)) {
>> + now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
>> + next = now + (env->CSR_TCFG & CONSTANT_TIMER_TICK_MASK) *
>> TIMER_PERIOD;
>> + timer_mod(&cpu->timer, next);
>> + } else {
>> + env->CSR_TCFG = FIELD_DP64(env->CSR_TCFG, CSR_TCFG, EN, 0);
>> + }
>> +
>> + env->CSR_ESTAT |= 1 << IRQ_TIMER;
>> + cpu_interrupt(CPU(cpu), CPU_INTERRUPT_HARD);
>
> I think this is wrong and you should be using loongarch_cpu_set_irq
> (which is misplaced for you to be able to do so).
>
reuse loongarch_cpu_set_irq? like this:
void loongarch_constant_timer_cb(void *opaque)
{
...
if (FIELD_EX64(...)) {
...
} else {
...
}
loongarch_cpu_set_irq(opaque, IRQ_IMER, 1);
}
>> @@ -297,4 +302,9 @@ enum {
>> #define LOONGARCH_CPU_TYPE_NAME(model) model LOONGARCH_CPU_TYPE_SUFFIX
>> #define CPU_RESOLVING_TYPE TYPE_LOONGARCH_CPU
>> +void loongarch_constant_timer_cb(void *opaque);
>> +uint64_t cpu_loongarch_get_constant_timer_counter(LoongArchCPU *cpu);
>> +uint64_t cpu_loongarch_get_constant_timer_ticks(LoongArchCPU *cpu);
>> +void cpu_loongarch_store_constant_timer_config(LoongArchCPU *cpu,
>> + uint64_t value);
>
> These can go in internals.h.
>
OK
Thanks.
Xiaojuan
>
> r~
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 09/29] target/loongarch: Add TLB instruction support
2022-03-28 20:12 ` Richard Henderson
@ 2022-03-31 1:09 ` yangxiaojuan
0 siblings, 0 replies; 71+ messages in thread
From: yangxiaojuan @ 2022-03-31 1:09 UTC (permalink / raw)
To: Richard Henderson, qemu-devel; +Cc: mark.cave-ayland, Song Gao
On 2022/3/29 上午4:12, Richard Henderson wrote:
> On 3/28/22 06:57, Xiaojuan Yang wrote:
>> +static void output_empty(DisasContext *ctx, arg_empty *a,
>> + const char *mnemonic)
>> +{
>> +}
>
> No, you must still do
>
> output(ctx, mnemonic, "");
>
>> +static bool trans_tlbwr(DisasContext *ctx, arg_tlbwr *a)
>> +{
>> + if (check_plv(ctx)) {
>> + return false;
>> + }
>> + gen_helper_tlbwr(cpu_env);
>> +
>> + if (ctx->mem_idx != MMU_DA_IDX) {
>> + tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4);
>> + ctx->base.is_jmp = DISAS_EXIT;
>> + }
>
> You may want to create a helper function for this condition.
>
in translate.c, like this:
static void gen_disas_exit(DisasContext *ctx)
{
tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4);
ctx->base.is_jmp = DISAS_EXIT;
}
>> +static bool trans_tlbclr(DisasContext *ctx, arg_tlbclr *a)
>> +{
>> + if (check_plv(ctx)) {
>> + return false;
>> + }
>> + gen_helper_tlbclr(cpu_env);
>> + tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4);
>> + ctx->base.is_jmp = DISAS_EXIT;
>
> Missing it here...
>
gen_disas_exit()
>> +static bool trans_tlbflush(DisasContext *ctx, arg_tlbflush *a)
>> +{
>> + if (check_plv(ctx)) {
>> + return false;
>> + }
>> + gen_helper_tlbflush(cpu_env);
>> + tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4);
>> + ctx->base.is_jmp = DISAS_EXIT;
>> + return true;
>> +}
>
> ... and here.
>
The same.
Thanks.
Xiaojuan
>
> r~
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 16/29] hw/loongarch: Add LoongArch ipi interrupt support(IPI)
2022-03-28 20:15 ` Mark Cave-Ayland
@ 2022-03-31 1:16 ` yangxiaojuan
0 siblings, 0 replies; 71+ messages in thread
From: yangxiaojuan @ 2022-03-31 1:16 UTC (permalink / raw)
To: Mark Cave-Ayland, qemu-devel; +Cc: richard.henderson, Song Gao
[-- Attachment #1: Type: text/plain, Size: 1420 bytes --]
Hi Mark,
On 2022/3/29 上午4:15, Mark Cave-Ayland wrote:
>> +
>> +#define TYPE_LOONGARCH_IPI "loongarch_ipi"
>> +OBJECT_DECLARE_SIMPLE_TYPE(LoongArchIPI, LOONGARCH_IPI)
>> +
>> +typedef struct IPICore {
>> + uint32_t status;
>> + uint32_t en;
>> + uint32_t set;
>> + uint32_t clear;
>> + /* 64bit buf divide into 2 32bit buf */
>> + uint32_t buf[MAX_IPI_MBX_NUM * 2];
>> + qemu_irq irq;
>> +} IPICore;
>> +
>> +typedef struct LoongArchIPI {
>> + SysBusDevice parent_obj;
>> + IPICore core[MAX_IPI_CORE_NUM];
>> + MemoryRegion ipi_mmio[MAX_IPI_CORE_NUM];
>> +} LoongArchIPI;
>> +
>> +#endif
>
> You missed the part in my original comment on patch 14 about dropping
> the typedef for QOM structs that are defined using
> OBJECT_DECLARE_TYPE_SIMPLE() i.e.
>
>
> #define TYPE_LOONGARCH_IPI "loongarch_ipi"
> OBJECT_DECLARE_SIMPLE_TYPE(LoongArchIPI, LOONGARCH_IPI)
>
> ...
> ...
>
> typedef struct IPICore {
> uint32_t status;
> uint32_t en;
> uint32_t set;
> uint32_t clear;
> /* 64bit buf divide into 2 32bit buf */
> uint32_t buf[MAX_IPI_MBX_NUM * 2];
> qemu_irq irq;
> } IPICore;
>
> struct LoongArchIPI {
> SysBusDevice parent_obj;
> IPICore core[MAX_IPI_CORE_NUM];
> MemoryRegion ipi_mmio[MAX_IPI_CORE_NUM];
> };
>
Sorry for that, I will be more carefully.
Thanks.
Xiaojuan
>
> ATB,
>
> Mark.
[-- Attachment #2: Type: text/html, Size: 2712 bytes --]
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 10/29] target/loongarch: Add other core instructions support
2022-03-28 20:16 ` Richard Henderson
@ 2022-03-31 1:22 ` yangxiaojuan
0 siblings, 0 replies; 71+ messages in thread
From: yangxiaojuan @ 2022-03-31 1:22 UTC (permalink / raw)
To: Richard Henderson, qemu-devel; +Cc: mark.cave-ayland, Song Gao
On 2022/3/29 上午4:16, Richard Henderson wrote:
> On 3/28/22 06:57, Xiaojuan Yang wrote:
>> +void helper_idle(CPULoongArchState *env)
>> +{
>> + CPUState *cs = env_cpu(env);
>> +
>> + cs->halted = 1;
>> + cpu_reset_interrupt(cs, CPU_INTERRUPT_WAKE);
>> + do_raise_exception(env, EXCP_HLT, 0);
>> +}
>
> Why are you messing with CPU_INTERRUPT_WAKE?
> You only ever reset it, and never set it.
>
Useless code, we just need set cs->halted.
Thanks
Xiaojuan
>
> r~
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 17/29] hw/intc: Add LoongArch ls7a interrupt controller support(PCH-PIC)
2022-03-28 20:18 ` Mark Cave-Ayland
@ 2022-03-31 1:25 ` yangxiaojuan
0 siblings, 0 replies; 71+ messages in thread
From: yangxiaojuan @ 2022-03-31 1:25 UTC (permalink / raw)
To: Mark Cave-Ayland, qemu-devel; +Cc: richard.henderson, Song Gao
On 2022/3/29 上午4:18, Mark Cave-Ayland wrote:
> On 28/03/2022 13:57, Xiaojuan Yang wrote:
>> This patch realize the PCH-PIC interrupt controller.
>>
>> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
>> Signed-off-by: Song Gao <gaosong@loongson.cn>
>> ---
>> hw/intc/Kconfig | 4 +
>> hw/intc/loongarch_pch_pic.c | 488 ++++++++++++++++++++++++++++
>> hw/intc/meson.build | 1 +
>> hw/intc/trace-events | 9 +
>> hw/loongarch/Kconfig | 1 +
>> include/hw/intc/loongarch_pch_pic.h | 80 +++++
>> 6 files changed, 583 insertions(+)
>> create mode 100644 hw/intc/loongarch_pch_pic.c
>> create mode 100644 include/hw/intc/loongarch_pch_pic.h
>>
>> diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
>> index 6c7e82da64..1fbba2e728 100644
>> --- a/hw/intc/Kconfig
>> +++ b/hw/intc/Kconfig
>> @@ -87,3 +87,7 @@ config M68K_IRQC
>> config LOONGARCH_IPI
>> bool
>> +
>> +config LOONGARCH_PCH_PIC
>> + bool
>> + select UNIMP
>> diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c
>> new file mode 100644
>> index 0000000000..04b9bdce36
>> --- /dev/null
>> +++ b/hw/intc/loongarch_pch_pic.c
>> @@ -0,0 +1,488 @@
>> +/* SPDX-License-Identifier: GPL-2.0-or-later */
>> +/*
>> + * QEMU Loongson 7A1000 I/O interrupt controller.
>> + *
>> + * Copyright (C) 2021 Loongson Technology Corporation Limited
>> + */
>> +
>> +#include "qemu/osdep.h"
>> +#include "hw/sysbus.h"
>> +#include "hw/loongarch/loongarch.h"
>> +#include "hw/irq.h"
>> +#include "hw/intc/loongarch_pch_pic.h"
>> +#include "migration/vmstate.h"
>> +#include "trace.h"
>> +
>> +static void pch_pic_update_irq(LoongArchPCHPIC *s, uint32_t mask,
>> + int level, int hi)
>> +{
>> + uint32_t val, irq;
>> +
>> + if (level == 1) {
>> + if (hi) {
>> + val = mask & s->intirr_hi & (~s->int_mask_hi);
>> + irq = find_first_bit((void *)&val, 32);
>> + if (irq != 32) {
>> + s->intisr_hi |= 1ULL << irq;
>> + qemu_set_irq(s->parent_irq[s->htmsi_vector[irq + 32]], 1);
>> + }
>> + } else {
>> + val = mask & s->intirr_lo & (~s->int_mask_lo);
>> + irq = find_first_bit((void *)&val, 32);
>> + if (irq != 32) {
>> + s->intisr_lo |= 1ULL << irq;
>> + qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 1);
>> + }
>> + }
>> + } else {
>> + if (hi) {
>> + val = mask & s->intisr_hi;
>> + irq = find_first_bit((void *)&val, 32);
>> + if (irq != 32) {
>> + s->intisr_hi &= ~(0x1ULL << irq);
>> + qemu_set_irq(s->parent_irq[s->htmsi_vector[irq + 32]], 0);
>> + }
>> + } else {
>> + val = mask & s->intisr_lo;
>> + irq = find_first_bit((void *)&val, 32);
>> + if (irq != 32) {
>> + s->intisr_lo &= ~(0x1ULL << irq);
>> + qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 0);
>> + }
>> + }
>> + }
>> +}
>> +
>> +static void pch_pic_irq_handler(void *opaque, int irq, int level)
>> +{
>> + LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
>> + int hi = 0;
>> + uint32_t mask;
>> +
>> + assert(irq < PCH_PIC_IRQ_NUM);
>> + trace_pch_pic_irq_handler(irq, level);
>> +
>> + hi = (irq >= 32) ? 1 : 0;
>> + if (hi) {
>> + irq = irq - 32;
>> + }
>> +
>> + mask = 1ULL << irq;
>> +
>> + if (hi) {
>> + if (s->intedge_hi & mask) {
>> + /* Edge triggered */
>> + if (level) {
>> + if ((s->last_intirr_hi & mask) == 0) {
>> + s->intirr_hi |= mask;
>> + }
>> + s->last_intirr_hi |= mask;
>> + } else {
>> + s->last_intirr_hi &= ~mask;
>> + }
>> + } else {
>> + /* Level triggered */
>> + if (level) {
>> + s->intirr_hi |= mask;
>> + s->last_intirr_hi |= mask;
>> + } else {
>> + s->intirr_hi &= ~mask;
>> + s->last_intirr_hi &= ~mask;
>> + }
>> + }
>> + } else {
>> + if (s->intedge_lo & mask) {
>> + /* Edge triggered */
>> + if (level) {
>> + if ((s->last_intirr_lo & mask) == 0) {
>> + s->intirr_lo |= mask;
>> + }
>> + s->last_intirr_lo |= mask;
>> + } else {
>> + s->last_intirr_lo &= ~mask;
>> + }
>> + } else {
>> + /* Level triggered */
>> + if (level) {
>> + s->intirr_lo |= mask;
>> + s->last_intirr_lo |= mask;
>> + } else {
>> + s->intirr_lo &= ~mask;
>> + s->last_intirr_lo &= ~mask;
>> + }
>> +
>> + }
>> + }
>> + pch_pic_update_irq(s, mask, level, hi);
>> +}
>> +
>> +static uint64_t loongarch_pch_pic_low_readw(void *opaque, hwaddr addr,
>> + unsigned size)
>> +{
>> + LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
>> + uint64_t val = 0;
>> + uint32_t offset = addr & 0xfff;
>> +
>> + switch (offset) {
>> + case PCH_PIC_INT_ID_LO:
>> + val = PCH_PIC_INT_ID_VAL;
>> + break;
>> + case PCH_PIC_INT_ID_HI:
>> + val = PCH_PIC_INT_ID_NUM;
>> + break;
>> + case PCH_PIC_INT_MASK_LO:
>> + val = s->int_mask_lo;
>> + break;
>> + case PCH_PIC_INT_MASK_HI:
>> + val = s->int_mask_hi;
>> + break;
>> + case PCH_PIC_INT_EDGE_LO:
>> + val = s->intedge_lo;
>> + break;
>> + case PCH_PIC_INT_EDGE_HI:
>> + val = s->intedge_hi;
>> + break;
>> + case PCH_PIC_HTMSI_EN_LO:
>> + val = s->htmsi_en_lo;
>> + break;
>> + case PCH_PIC_HTMSI_EN_HI:
>> + val = s->htmsi_en_hi;
>> + break;
>> + case PCH_PIC_AUTO_CTRL0_LO:
>> + case PCH_PIC_AUTO_CTRL0_HI:
>> + case PCH_PIC_AUTO_CTRL1_LO:
>> + case PCH_PIC_AUTO_CTRL1_HI:
>> + break;
>> + default:
>> + break;
>> + }
>> +
>> + trace_loongarch_pch_pic_low_readw(size, (uint32_t)addr, val);
>> + return val;
>> +}
>> +
>> +static void loongarch_pch_pic_low_writew(void *opaque, hwaddr addr,
>> + uint64_t data, unsigned size)
>> +{
>> + LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
>> + uint32_t offset, old;
>> + offset = addr & 0xfff;
>> +
>> + trace_loongarch_pch_pic_low_writew(size, (uint32_t)addr, data);
>> +
>> + switch (offset) {
>> + case PCH_PIC_INT_MASK_LO:
>> + old = s->int_mask_lo;
>> + s->int_mask_lo = data;
>> + if (old & ~data) {
>> + pch_pic_update_irq(s, (old & ~data), 1, 0);
>> + } else if (~old & data) {
>> + pch_pic_update_irq(s, (~old & data), 0, 0);
>> + }
>> + break;
>> + case PCH_PIC_INT_MASK_HI:
>> + old = s->int_mask_hi;
>> + s->int_mask_hi = data;
>> + if (old & ~data) {
>> + pch_pic_update_irq(s, (old & ~data), 1, 1);
>> + } else if (~old & data) {
>> + pch_pic_update_irq(s, (~old & data), 0, 1);
>> + }
>> + break;
>> + case PCH_PIC_INT_EDGE_LO:
>> + s->intedge_lo = data;
>> + break;
>> + case PCH_PIC_INT_EDGE_HI:
>> + s->intedge_hi = data;
>> + break;
>> + case PCH_PIC_INT_CLEAR_LO:
>> + if (s->intedge_lo & data) {
>> + s->intirr_lo &= (~data);
>> + pch_pic_update_irq(s, data, 0, 0);
>> + s->intisr_lo &= (~data);
>> + }
>> + break;
>> + case PCH_PIC_INT_CLEAR_HI:
>> + if (s->intedge_hi & data) {
>> + s->intirr_hi &= (~data);
>> + pch_pic_update_irq(s, data, 0, 1);
>> + s->intisr_hi &= (~data);
>> + }
>> + break;
>> + case PCH_PIC_HTMSI_EN_LO:
>> + s->htmsi_en_lo = data;
>> + break;
>> + case PCH_PIC_HTMSI_EN_HI:
>> + s->htmsi_en_hi = data;
>> + break;
>> + case PCH_PIC_AUTO_CTRL0_LO:
>> + case PCH_PIC_AUTO_CTRL0_HI:
>> + case PCH_PIC_AUTO_CTRL1_LO:
>> + case PCH_PIC_AUTO_CTRL1_HI:
>> + break;
>> + default:
>> + break;
>> + }
>> +}
>> +
>> +static uint64_t loongarch_pch_pic_high_readw(void *opaque, hwaddr addr,
>> + unsigned size)
>> +{
>> + LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
>> + uint64_t val = 0;
>> + uint32_t offset = addr & 0xfff;
>> +
>> + switch (offset) {
>> + case STATUS_LO_START:
>> + val = s->intisr_lo & (~s->int_mask_lo);
>> + break;
>> + case STATUS_HI_START:
>> + val = s->intisr_hi & (~s->int_mask_hi);
>> + break;
>> + case POL_LO_START:
>> + val = s->int_polarity_lo;
>> + break;
>> + case POL_HI_START:
>> + val = s->int_polarity_hi;
>> + break;
>> + default:
>> + break;
>> + }
>> +
>> + trace_loongarch_pch_pic_high_readw(size, (uint32_t)addr, val);
>> + return val;
>> +}
>> +
>> +static void loongarch_pch_pic_high_writew(void *opaque, hwaddr addr,
>> + uint64_t data, unsigned size)
>> +{
>> + LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
>> + uint32_t offset;
>> + offset = addr & 0xfff;
>> +
>> + trace_loongarch_pch_pic_high_writew(size, (uint32_t)addr, data);
>> +
>> + switch (offset) {
>> + case STATUS_LO_START:
>> + s->intisr_lo = data;
>> + break;
>> + case STATUS_HI_START:
>> + s->intisr_hi = data;
>> + break;
>> + case POL_LO_START:
>> + s->int_polarity_lo = data;
>> + break;
>> + case POL_HI_START:
>> + s->int_polarity_hi = data;
>> + break;
>> + default:
>> + break;
>> + }
>> +}
>> +
>> +static uint64_t loongarch_pch_pic_readb(void *opaque, hwaddr addr,
>> + unsigned size)
>> +{
>> + LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
>> + uint64_t val = 0;
>> + uint32_t offset = (addr & 0xfff) + PCH_PIC_ROUTE_ENTRY_OFFSET;
>> + int64_t offset_tmp;
>> +
>> + switch (offset) {
>> + case PCH_PIC_HTMSI_VEC_OFFSET ... PCH_PIC_HTMSI_VEC_END:
>> + offset_tmp = offset - PCH_PIC_HTMSI_VEC_OFFSET;
>> + if (offset_tmp >= 0 && offset_tmp < 64) {
>> + val = s->htmsi_vector[offset_tmp];
>> + }
>> + break;
>> + case PCH_PIC_ROUTE_ENTRY_OFFSET ... PCH_PIC_ROUTE_ENTRY_END:
>> + offset_tmp = offset - PCH_PIC_ROUTE_ENTRY_OFFSET;
>> + if (offset_tmp >= 0 && offset_tmp < 64) {
>> + val = s->route_entry[offset_tmp];
>> + }
>> + break;
>> + default:
>> + break;
>> + }
>> +
>> + trace_loongarch_pch_pic_readb(size, (uint32_t)addr, val);
>> + return val;
>> +}
>> +
>> +static void loongarch_pch_pic_writeb(void *opaque, hwaddr addr,
>> + uint64_t data, unsigned size)
>> +{
>> + LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
>> + int32_t offset_tmp;
>> + uint32_t offset = (addr & 0xfff) + PCH_PIC_ROUTE_ENTRY_OFFSET;
>> +
>> + trace_loongarch_pch_pic_writeb(size, (uint32_t)addr, data);
>> +
>> + switch (offset) {
>> + case PCH_PIC_HTMSI_VEC_OFFSET ... PCH_PIC_HTMSI_VEC_END:
>> + offset_tmp = offset - PCH_PIC_HTMSI_VEC_OFFSET;
>> + if (offset_tmp >= 0 && offset_tmp < 64) {
>> + s->htmsi_vector[offset_tmp] = (uint8_t)(data & 0xff);
>> + }
>> + break;
>> + case PCH_PIC_ROUTE_ENTRY_OFFSET ... PCH_PIC_ROUTE_ENTRY_END:
>> + offset_tmp = offset - PCH_PIC_ROUTE_ENTRY_OFFSET;
>> + if (offset_tmp >= 0 && offset_tmp < 64) {
>> + s->route_entry[offset_tmp] = (uint8_t)(data & 0xff);
>> + }
>> + break;
>> + default:
>> + break;
>> + }
>> +}
>> +
>> +static const MemoryRegionOps loongarch_pch_pic_reg32_low_ops = {
>> + .read = loongarch_pch_pic_low_readw,
>> + .write = loongarch_pch_pic_low_writew,
>> + .valid = {
>> + .min_access_size = 4,
>> + .max_access_size = 8,
>> + },
>> + .impl = {
>> + .min_access_size = 4,
>> + .max_access_size = 4,
>> + },
>> + .endianness = DEVICE_LITTLE_ENDIAN,
>> +};
>> +
>> +static const MemoryRegionOps loongarch_pch_pic_reg32_high_ops = {
>> + .read = loongarch_pch_pic_high_readw,
>> + .write = loongarch_pch_pic_high_writew,
>> + .valid = {
>> + .min_access_size = 4,
>> + .max_access_size = 8,
>> + },
>> + .impl = {
>> + .min_access_size = 4,
>> + .max_access_size = 4,
>> + },
>> + .endianness = DEVICE_LITTLE_ENDIAN,
>> +};
>> +
>> +static const MemoryRegionOps loongarch_pch_pic_reg8_ops = {
>> + .read = loongarch_pch_pic_readb,
>> + .write = loongarch_pch_pic_writeb,
>> + .valid = {
>> + .min_access_size = 1,
>> + .max_access_size = 1,
>> + },
>> + .impl = {
>> + .min_access_size = 1,
>> + .max_access_size = 1,
>> + },
>> + .endianness = DEVICE_LITTLE_ENDIAN,
>> +};
>> +
>> +static void loongarch_pch_pic_reset(DeviceState *d)
>> +{
>> + LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(d);
>> + int i;
>> +
>> + s->int_mask_lo = -1;
>> + s->int_mask_hi = -1;
>> + s->htmsi_en_lo = 0x0;
>> + s->htmsi_en_hi = 0x0;
>> + s->intedge_lo = 0x0;
>> + s->intedge_hi = 0x0;
>> + s->intclr_lo = 0x0;
>> + s->intclr_hi = 0x0;
>> + s->auto_crtl0_lo = 0x0;
>> + s->auto_crtl0_hi = 0x0;
>> + s->auto_crtl1_lo = 0x0;
>> + s->auto_crtl1_hi = 0x0;
>> + for (i = 0; i < 64; i++) {
>> + s->route_entry[i] = 0x1;
>> + s->htmsi_vector[i] = 0x0;
>> + }
>> + s->intirr_lo = 0x0;
>> + s->intirr_hi = 0x0;
>> + s->intisr_lo = 0x0;
>> + s->intisr_hi = 0x0;
>> + s->last_intirr_lo = 0x0;
>> + s->last_intirr_hi = 0x0;
>> + s->int_polarity_lo = 0x0;
>> + s->int_polarity_hi = 0x0;
>> +}
>> +
>> +static void loongarch_pch_pic_init(Object *obj)
>> +{
>> + LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(obj);
>> + SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
>> + int i;
>> +
>> + memory_region_init_io(&s->iomem32_low, obj,
>> + &loongarch_pch_pic_reg32_low_ops,
>> + s, PCH_PIC_NAME(.reg32_part1), 0x100);
>> + memory_region_init_io(&s->iomem8, obj, &loongarch_pch_pic_reg8_ops,
>> + s, PCH_PIC_NAME(.reg8), 0x2a0);
>> + memory_region_init_io(&s->iomem32_high, obj,
>> + &loongarch_pch_pic_reg32_high_ops,
>> + s, PCH_PIC_NAME(.reg32_part2), 0xc60);
>> + sysbus_init_mmio(sbd, &s->iomem32_low);
>> + sysbus_init_mmio(sbd, &s->iomem8);
>> + sysbus_init_mmio(sbd, &s->iomem32_high);
>> +
>> + for (i = 0; i < PCH_PIC_IRQ_NUM; i++) {
>> + sysbus_init_irq(sbd, &s->parent_irq[i]);
>> + }
>> + qdev_init_gpio_in(DEVICE(obj), pch_pic_irq_handler,
>> PCH_PIC_IRQ_NUM);
>> +}
>> +
>> +static const VMStateDescription vmstate_loongarch_pch_pic = {
>> + .name = TYPE_LOONGARCH_PCH_PIC,
>> + .version_id = 1,
>> + .minimum_version_id = 1,
>> + .fields = (VMStateField[]) {
>> + VMSTATE_UINT32(int_mask_lo, LoongArchPCHPIC),
>> + VMSTATE_UINT32(int_mask_hi, LoongArchPCHPIC),
>> + VMSTATE_UINT32(htmsi_en_lo, LoongArchPCHPIC),
>> + VMSTATE_UINT32(htmsi_en_hi, LoongArchPCHPIC),
>> + VMSTATE_UINT32(intedge_lo, LoongArchPCHPIC),
>> + VMSTATE_UINT32(intedge_hi, LoongArchPCHPIC),
>> + VMSTATE_UINT32(intclr_lo, LoongArchPCHPIC),
>> + VMSTATE_UINT32(intclr_hi, LoongArchPCHPIC),
>> + VMSTATE_UINT32(auto_crtl0_lo, LoongArchPCHPIC),
>> + VMSTATE_UINT32(auto_crtl0_hi, LoongArchPCHPIC),
>> + VMSTATE_UINT32(auto_crtl1_lo, LoongArchPCHPIC),
>> + VMSTATE_UINT32(auto_crtl1_hi, LoongArchPCHPIC),
>> + VMSTATE_UINT8_ARRAY(route_entry, LoongArchPCHPIC, 64),
>> + VMSTATE_UINT8_ARRAY(htmsi_vector, LoongArchPCHPIC, 64),
>> + VMSTATE_UINT32(last_intirr_lo, LoongArchPCHPIC),
>> + VMSTATE_UINT32(last_intirr_hi, LoongArchPCHPIC),
>> + VMSTATE_UINT32(intirr_lo, LoongArchPCHPIC),
>> + VMSTATE_UINT32(intirr_hi, LoongArchPCHPIC),
>> + VMSTATE_UINT32(intisr_lo, LoongArchPCHPIC),
>> + VMSTATE_UINT32(intisr_hi, LoongArchPCHPIC),
>> + VMSTATE_UINT32(int_polarity_lo, LoongArchPCHPIC),
>> + VMSTATE_UINT32(int_polarity_hi, LoongArchPCHPIC),
>> + VMSTATE_END_OF_LIST()
>> + }
>> +};
>> +
>> +static void loongarch_pch_pic_class_init(ObjectClass *klass, void
>> *data)
>> +{
>> + DeviceClass *dc = DEVICE_CLASS(klass);
>> +
>> + dc->reset = loongarch_pch_pic_reset;
>> + dc->vmsd = &vmstate_loongarch_pch_pic;
>> +}
>> +
>> +static const TypeInfo loongarch_pch_pic_info = {
>> + .name = TYPE_LOONGARCH_PCH_PIC,
>> + .parent = TYPE_SYS_BUS_DEVICE,
>> + .instance_size = sizeof(LoongArchPCHPIC),
>> + .instance_init = loongarch_pch_pic_init,
>> + .class_init = loongarch_pch_pic_class_init,
>> +};
>> +
>> +static void loongarch_pch_pic_register_types(void)
>> +{
>> + type_register_static(&loongarch_pch_pic_info);
>> +}
>> +
>> +type_init(loongarch_pch_pic_register_types)
>> diff --git a/hw/intc/meson.build b/hw/intc/meson.build
>> index bf5ab44a78..960ce81a92 100644
>> --- a/hw/intc/meson.build
>> +++ b/hw/intc/meson.build
>> @@ -63,3 +63,4 @@ specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XIVE'],
>> specific_ss.add(when: 'CONFIG_GOLDFISH_PIC', if_true:
>> files('goldfish_pic.c'))
>> specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true:
>> files('m68k_irqc.c'))
>> specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true:
>> files('loongarch_ipi.c'))
>> +specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true:
>> files('loongarch_pch_pic.c'))
>> diff --git a/hw/intc/trace-events b/hw/intc/trace-events
>> index 6ae8917d99..8c12bdd89f 100644
>> --- a/hw/intc/trace-events
>> +++ b/hw/intc/trace-events
>> @@ -279,3 +279,12 @@ sh_intc_set(int id, int enable) "setting
>> interrupt group %d to %d"
>> # loongarch_ipi.c
>> loongarch_ipi_read(unsigned size, uint64_t addr, unsigned long val)
>> "size: %u addr: 0x%"PRIx64 "val: 0x%"PRIx64
>> loongarch_ipi_write(unsigned size, uint64_t addr, unsigned long
>> val) "size: %u addr: 0x%"PRIx64 "val: 0x%"PRIx64
>> +
>> +# loongarch_pch_pic.c
>> +pch_pic_irq_handler(int irq, int level) "irq %d level %d"
>> +loongarch_pch_pic_low_readw(unsigned size, uint32_t addr, unsigned
>> long val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
>> +loongarch_pch_pic_low_writew(unsigned size, uint32_t addr, unsigned
>> long val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
>> +loongarch_pch_pic_high_readw(unsigned size, uint32_t addr, unsigned
>> long val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
>> +loongarch_pch_pic_high_writew(unsigned size, uint32_t addr, unsigned
>> long val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
>> +loongarch_pch_pic_readb(unsigned size, uint32_t addr, unsigned long
>> val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
>> +loongarch_pch_pic_writeb(unsigned size, uint32_t addr, unsigned long
>> val) "size: %u addr: 0x%"PRIx32 "val: 0x%" PRIx64
>> diff --git a/hw/loongarch/Kconfig b/hw/loongarch/Kconfig
>> index f0dad3329a..2df45f7e8f 100644
>> --- a/hw/loongarch/Kconfig
>> +++ b/hw/loongarch/Kconfig
>> @@ -3,3 +3,4 @@ config LOONGARCH_VIRT
>> select PCI
>> select PCI_EXPRESS_GENERIC_BRIDGE
>> select LOONGARCH_IPI
>> + select LOONGARCH_PCH_PIC
>> diff --git a/include/hw/intc/loongarch_pch_pic.h
>> b/include/hw/intc/loongarch_pch_pic.h
>> new file mode 100644
>> index 0000000000..8ca044be33
>> --- /dev/null
>> +++ b/include/hw/intc/loongarch_pch_pic.h
>> @@ -0,0 +1,80 @@
>> +/* SPDX-License-Identifier: GPL-2.0-or-later */
>> +/*
>> + * LoongArch 7A1000 I/O interrupt controller definitions
>> + *
>> + * Copyright (c) 2021 Loongson Technology Corporation Limited
>> + */
>> +
>> +#define TYPE_LOONGARCH_PCH_PIC "loongarch_pch_pic"
>> +#define PCH_PIC_NAME(name) TYPE_LOONGARCH_PCH_PIC#name
>> +OBJECT_DECLARE_SIMPLE_TYPE(LoongArchPCHPIC, LOONGARCH_PCH_PIC)
>> +
>> +#define PCH_PIC_IRQ_START 0
>> +#define PCH_PIC_IRQ_END 63
>> +#define PCH_PIC_IRQ_NUM 64
>> +#define PCH_PIC_INT_ID_VAL 0x7000000UL
>> +#define PCH_PIC_INT_ID_NUM 0x3f0001UL
>> +
>> +#define PCH_PIC_INT_ID_LO 0x00
>> +#define PCH_PIC_INT_ID_HI 0x04
>> +#define PCH_PIC_INT_MASK_LO 0x20
>> +#define PCH_PIC_INT_MASK_HI 0x24
>> +#define PCH_PIC_HTMSI_EN_LO 0x40
>> +#define PCH_PIC_HTMSI_EN_HI 0x44
>> +#define PCH_PIC_INT_EDGE_LO 0x60
>> +#define PCH_PIC_INT_EDGE_HI 0x64
>> +#define PCH_PIC_INT_CLEAR_LO 0x80
>> +#define PCH_PIC_INT_CLEAR_HI 0x84
>> +#define PCH_PIC_AUTO_CTRL0_LO 0xc0
>> +#define PCH_PIC_AUTO_CTRL0_HI 0xc4
>> +#define PCH_PIC_AUTO_CTRL1_LO 0xe0
>> +#define PCH_PIC_AUTO_CTRL1_HI 0xe4
>> +#define PCH_PIC_ROUTE_ENTRY_OFFSET 0x100
>> +#define PCH_PIC_ROUTE_ENTRY_END 0x13f
>> +#define PCH_PIC_HTMSI_VEC_OFFSET 0x200
>> +#define PCH_PIC_HTMSI_VEC_END 0x23f
>> +#define PCH_PIC_INT_STATUS_LO 0x3a0
>> +#define PCH_PIC_INT_STATUS_HI 0x3a4
>> +#define PCH_PIC_INT_POL_LO 0x3e0
>> +#define PCH_PIC_INT_POL_HI 0x3e4
>> +
>> +#define STATUS_LO_START 0
>> +#define STATUS_HI_START 0x4
>> +#define POL_LO_START 0x40
>> +#define POL_HI_START 0x44
>> +
>> +typedef struct LoongArchPCHPIC {
>> + SysBusDevice parent_obj;
>> + qemu_irq parent_irq[64];
>> + uint32_t int_mask_lo; /*0x020 interrupt mask register*/
>> + uint32_t int_mask_hi;
>> + uint32_t htmsi_en_lo; /*0x040 1=msi*/
>> + uint32_t htmsi_en_hi;
>> + uint32_t intedge_lo; /*0x060 edge=1 level =0*/
>> + uint32_t intedge_hi; /*0x060 edge=1 level =0*/
>> + uint32_t intclr_lo; /*0x080 for clean edge int,set 1 clean,set 0
>> is noused*/
>> + uint32_t intclr_hi; /*0x080 for clean edge int,set 1 clean,set 0
>> is noused*/
>> + uint32_t auto_crtl0_lo; /*0x0c0*/
>> + uint32_t auto_crtl0_hi; /*0x0c0*/
>> + uint32_t auto_crtl1_lo; /*0x0e0*/
>> + uint32_t auto_crtl1_hi; /*0x0e0*/
>> + uint32_t last_intirr_lo; /* edge detection */
>> + uint32_t last_intirr_hi; /* edge detection */
>> + uint32_t intirr_lo; /* 0x380 interrupt request register */
>> + uint32_t intirr_hi; /* 0x380 interrupt request register */
>> + uint32_t intisr_lo; /* 0x3a0 interrupt service register */
>> + uint32_t intisr_hi; /* 0x3a0 interrupt service register */
>> + /*
>> + * 0x3e0 interrupt level polarity selection
>> + * register 0 for high level trigger
>> + */
>> + uint32_t int_polarity_lo;
>> + uint32_t int_polarity_hi;
>> +
>> + uint8_t route_entry[64]; /*0x100 - 0x138*/
>> + uint8_t htmsi_vector[64]; /*0x200 - 0x238*/
>> +
>> + MemoryRegion iomem32_low;
>> + MemoryRegion iomem32_high;
>> + MemoryRegion iomem8;
>> +} LoongArchPCHPIC;
>
> Same comment here about dropping the typedef for the QOM type.
>
OK, I will correct it.
Thanks.
Xiaojuan
>
> ATB,
>
> Mark.
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 11/29] target/loongarch: Add LoongArch interrupt and exception handle
2022-03-28 20:19 ` Richard Henderson
@ 2022-03-31 1:29 ` yangxiaojuan
0 siblings, 0 replies; 71+ messages in thread
From: yangxiaojuan @ 2022-03-31 1:29 UTC (permalink / raw)
To: Richard Henderson, qemu-devel; +Cc: mark.cave-ayland, Song Gao
On 2022/3/29 上午4:19, Richard Henderson wrote:
> On 3/28/22 06:57, Xiaojuan Yang wrote:
>> 1.This patch Add loongarch interrupt and exception handle.
>> 2.Rename the user excp to the exccode from the csr defintions.
>>
>> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
>> Signed-off-by: Song Gao <gaosong@loongson.cn>
>> ---
>> linux-user/loongarch64/cpu_loop.c | 8 +-
>> target/loongarch/cpu.c | 260 +++++++++++++++++-
>> target/loongarch/cpu.h | 11 -
>> target/loongarch/fpu_helper.c | 2 +-
>> target/loongarch/insn_trans/trans_extra.c.inc | 4 +-
>> target/loongarch/translate.c | 2 +-
>> 6 files changed, 261 insertions(+), 26 deletions(-)
>
> To repeat my response to the cover letter, the changes in this patch
> should be folded back into the original patches defining the base
> architecture.
>
Agreed, I think we can use this patch in new series, but we need
remove '2. Rename the user excp to the excode from the csr defintions'.
Thanks.
Xiaojuan
>
> r~
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 19/29] hw/intc: Add LoongArch extioi interrupt controller(EIOINTC)
2022-03-28 22:43 ` Richard Henderson
@ 2022-03-31 12:28 ` yangxiaojuan
0 siblings, 0 replies; 71+ messages in thread
From: yangxiaojuan @ 2022-03-31 12:28 UTC (permalink / raw)
To: Richard Henderson, qemu-devel; +Cc: mark.cave-ayland, Song Gao
On 2022/3/29 上午6:43, Richard Henderson wrote:
> On 3/28/22 06:57, Xiaojuan Yang wrote:
>> This patch realize the EIOINTC interrupt controller.
>>
>> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
>> Signed-off-by: Song Gao <gaosong@loongson.cn>
>> ---
>> hw/intc/Kconfig | 3 +
>> hw/intc/loongarch_extioi.c | 408 +++++++++++++++++++++++++++++
>> hw/intc/meson.build | 1 +
>> hw/intc/trace-events | 11 +
>> hw/loongarch/Kconfig | 1 +
>> include/hw/intc/loongarch_extioi.h | 77 ++++++
>> 6 files changed, 501 insertions(+)
>> create mode 100644 hw/intc/loongarch_extioi.c
>> create mode 100644 include/hw/intc/loongarch_extioi.h
>>
>> diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
>> index 71c04c328e..28bd1f185d 100644
>> --- a/hw/intc/Kconfig
>> +++ b/hw/intc/Kconfig
>> @@ -96,3 +96,6 @@ config LOONGARCH_PCH_MSI
>> select MSI_NONBROKEN
>> bool
>> select UNIMP
>> +
>> +config LOONGARCH_EXTIOI
>> + bool
>> diff --git a/hw/intc/loongarch_extioi.c b/hw/intc/loongarch_extioi.c
>> new file mode 100644
>> index 0000000000..af28e8d6e9
>> --- /dev/null
>> +++ b/hw/intc/loongarch_extioi.c
>> @@ -0,0 +1,408 @@
>> +/* SPDX-License-Identifier: GPL-2.0-or-later */
>> +/*
>> + * Loongson 3A5000 ext interrupt controller emulation
>> + *
>> + * Copyright (C) 2021 Loongson Technology Corporation Limited
>> + */
>> +
>> +#include "qemu/osdep.h"
>> +#include "qemu/module.h"
>> +#include "qemu/log.h"
>> +#include "hw/irq.h"
>> +#include "hw/sysbus.h"
>> +#include "hw/loongarch/loongarch.h"
>> +#include "hw/qdev-properties.h"
>> +#include "exec/address-spaces.h"
>> +#include "hw/intc/loongarch_extioi.h"
>> +#include "migration/vmstate.h"
>> +#include "trace.h"
>> +
>> +static void extioi_update_irq(void *opaque, int irq_num, int level)
>> +{
>> + LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
>
> I think this is not opaque anymore; you've already resolved it in the
> caller.
> I think level should be 'bool'.
>
OK.
>> + uint8_t ipnum, cpu;
>> + unsigned long found1, found2;
>> +
>> + ipnum = s->sw_ipmap[irq_num];
>> + cpu = s->sw_coremap[irq_num];
>> + if (level == 1) {
>
> Just if (level).
>
>> + if (test_bit(irq_num, (void *)s->enable) == false) {
>
> This, and every other cast you're using for bitops.h functions, is
> wrong. You would need to declare these bitmaps properly as 'unsigned
> long name[BITS_TO_LONGS(N)];'.
>
> That said, I would definitely use uint64_t, because that matches up
> with the description of these registers in the manual.
>
we may not declare these bitmaps as 'unsigned long
name[BITS_TO_LONGS(N)]. For example, ext_sw_ipisr
sw_ipisr[MAX_CORES][LS3A_INTC_IP] is a two-dimensional array,
and it has a specific meaning, memregion options also restrict its size
>> + return;
>> + }
>> + bitmap_set((void *)s->coreisr[cpu], irq_num, 1);
>> + found1 = find_next_bit((void *)&(s->sw_ipisr[cpu][ipnum]),
>> + EXTIOI_IRQS, 0);
>
> find_next_bit with offset=0 is find_first_bit...
>
OK.
>> + bitmap_set((void *)&(s->sw_ipisr[cpu][ipnum]), irq_num, 1);
>> +
>> + if (found1 >= EXTIOI_IRQS) {
>> + qemu_set_irq(s->parent_irq[cpu][ipnum], level);
>> + }
>
> ... but what's the bitmap search doing? It appears to be checking
> that there are *no* bits set between 0 and EXTIOI_IRQS, and then
> raising the irq if no bits set. That seems wrong.
>
found1 >= EXTIOI_IRQS says there is no interrupt at present, then the
new interrupt will be sent.
>
>> + } else {
>> + bitmap_clear((void *)s->coreisr[cpu], irq_num, 1);
>> + found1 = find_next_bit((void *)&(s->sw_ipisr[cpu][ipnum]),
>> + EXTIOI_IRQS, 0);
>> + bitmap_clear((void *)&(s->sw_ipisr[cpu][ipnum]), irq_num, 1);
>> + found2 = find_next_bit((void *)&(s->sw_ipisr[cpu][ipnum]),
>> + EXTIOI_IRQS, 0);
>> +
>> + if ((found1 < EXTIOI_IRQS) && (found2 >= EXTIOI_IRQS)) {
>> + qemu_set_irq(s->parent_irq[cpu][ipnum], level);
>> + }
>> + }
>> +}
>
if ((found1 < EXTIOI_IRQS) && (found2 >= EXTIOI_IRQS)) says if the
current interrupt number is equal to irq_num, then qemu_set_irq.
> It *seems* like all of this should be
>
> uint64_t sum = 0;
>
> s->isr[ipnum / 64] = deposit64(s->isr[ipnum / 64], ipnum % 64, 1,
> level);
>
> for (int i = 0; i < ARRAY_SIZE(s->isr); i++) {
> sum |= s->isr[i] & s->ena[i];
> }
> qemu_set_irq(parent, sum != 0);
>
> If that's not the case, you need many more comments.
>
Yes, we need more comments,
Thanks.
Xiaojuan
>
> r~
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v7 14/29] hw/loongarch: Add support loongson3 virt machine type.
2022-03-28 21:02 ` Mark Cave-Ayland
@ 2022-04-15 7:52 ` yangxiaojuan
0 siblings, 0 replies; 71+ messages in thread
From: yangxiaojuan @ 2022-04-15 7:52 UTC (permalink / raw)
To: Mark Cave-Ayland, Richard Henderson, qemu-devel; +Cc: Song Gao
[-- Attachment #1: Type: text/plain, Size: 1061 bytes --]
Hi,
On 2022/3/29 上午5:02, Mark Cave-Ayland wrote:
>>
>>> +static const MemoryRegionOps loongarch_qemu_ops = {
>>> + .read = loongarch_qemu_read,
>>> + .write = loongarch_qemu_write,
>>> + .endianness = DEVICE_LITTLE_ENDIAN,
>>> + .valid = {
>>> + .min_access_size = 4,
>>> + .max_access_size = 8,
>>> + },
>>> + .impl = {
>>> + .min_access_size = 4,
>>> + .max_access_size = 8,
>>> + },
>>
>> The implementation above doesn't actually support access size 4; it
>> only supports 8.
>> It doesn't seem like this should be a io region at all, but a ROM.
>
> Strangely enough I had a similar requirement for my q800 patches, and
> when I tried to implement a ROM memory region then the accesses didn't
> work as expected. I can't remember the exact problem however...
It seems that iocsr_misc may not use rom region, because the
MISC_FUNC_REG should be writen.
could I modify it as a device? and define its structure and memregion
options.
Thanks
Xiaojuan
[-- Attachment #2: Type: text/html, Size: 5394 bytes --]
^ permalink raw reply [flat|nested] 71+ messages in thread
end of thread, other threads:[~2022-04-15 7:54 UTC | newest]
Thread overview: 71+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-28 12:57 [RFC PATCH v7 00/29] Add LoongArch softmmu support Xiaojuan Yang
2022-03-28 12:57 ` [RFC PATCH v7 01/29] target/loongarch: Add system emulation introduction Xiaojuan Yang
2022-03-28 12:57 ` [RFC PATCH v7 02/29] target/loongarch: Add CSRs definition Xiaojuan Yang
2022-03-28 19:16 ` Richard Henderson
2022-03-30 10:04 ` yangxiaojuan
2022-03-28 12:57 ` [RFC PATCH v7 03/29] target/loongarch: Add basic vmstate description of CPU Xiaojuan Yang
2022-03-28 12:57 ` [RFC PATCH v7 04/29] target/loongarch: Implement qmp_query_cpu_definitions() Xiaojuan Yang
2022-03-28 12:57 ` [RFC PATCH v7 05/29] target/loongarch: Add constant timer support Xiaojuan Yang
2022-03-28 19:46 ` Richard Henderson
2022-03-31 0:59 ` yangxiaojuan
2022-03-28 20:58 ` Richard Henderson
2022-03-28 12:57 ` [RFC PATCH v7 06/29] target/loongarch: Add MMU support for LoongArch CPU Xiaojuan Yang
2022-03-28 20:06 ` Richard Henderson
2022-03-28 12:57 ` [RFC PATCH v7 07/29] target/loongarch: Add LoongArch CSR instruction Xiaojuan Yang
2022-03-28 18:34 ` Richard Henderson
2022-03-30 10:01 ` yangxiaojuan
2022-03-30 13:46 ` Richard Henderson
2022-03-28 12:57 ` [RFC PATCH v7 08/29] target/loongarch: Add LoongArch IOCSR instruction Xiaojuan Yang
2022-03-28 18:55 ` Richard Henderson
2022-03-30 10:02 ` yangxiaojuan
2022-03-28 12:57 ` [RFC PATCH v7 09/29] target/loongarch: Add TLB instruction support Xiaojuan Yang
2022-03-28 20:12 ` Richard Henderson
2022-03-31 1:09 ` yangxiaojuan
2022-03-28 22:50 ` Richard Henderson
2022-03-28 12:57 ` [RFC PATCH v7 10/29] target/loongarch: Add other core instructions support Xiaojuan Yang
2022-03-28 20:16 ` Richard Henderson
2022-03-31 1:22 ` yangxiaojuan
2022-03-28 12:57 ` [RFC PATCH v7 11/29] target/loongarch: Add LoongArch interrupt and exception handle Xiaojuan Yang
2022-03-28 20:19 ` Richard Henderson
2022-03-31 1:29 ` yangxiaojuan
2022-03-28 12:57 ` [RFC PATCH v7 12/29] target/loongarch: Add timer related instructions support Xiaojuan Yang
2022-03-28 20:33 ` Richard Henderson
2022-03-28 12:57 ` [RFC PATCH v7 13/29] target/loongarch: Add gdb support Xiaojuan Yang
2022-03-28 20:35 ` Richard Henderson
2022-03-28 12:57 ` [RFC PATCH v7 14/29] hw/loongarch: Add support loongson3 virt machine type Xiaojuan Yang
2022-03-28 20:49 ` Richard Henderson
2022-03-28 21:02 ` Mark Cave-Ayland
2022-04-15 7:52 ` yangxiaojuan
2022-03-28 12:57 ` [RFC PATCH v7 15/29] hw/loongarch: Add LoongArch cpu interrupt support(CPUINTC) Xiaojuan Yang
2022-03-28 20:57 ` Richard Henderson
2022-03-28 12:57 ` [RFC PATCH v7 16/29] hw/loongarch: Add LoongArch ipi interrupt support(IPI) Xiaojuan Yang
2022-03-28 20:15 ` Mark Cave-Ayland
2022-03-31 1:16 ` yangxiaojuan
2022-03-28 22:04 ` Richard Henderson
2022-03-28 22:06 ` Richard Henderson
2022-03-28 12:57 ` [RFC PATCH v7 17/29] hw/intc: Add LoongArch ls7a interrupt controller support(PCH-PIC) Xiaojuan Yang
2022-03-28 20:18 ` Mark Cave-Ayland
2022-03-31 1:25 ` yangxiaojuan
2022-03-28 12:57 ` [RFC PATCH v7 18/29] hw/intc: Add LoongArch ls7a msi interrupt controller support(PCH-MSI) Xiaojuan Yang
2022-03-28 20:22 ` Mark Cave-Ayland
2022-03-28 12:57 ` [RFC PATCH v7 19/29] hw/intc: Add LoongArch extioi interrupt controller(EIOINTC) Xiaojuan Yang
2022-03-28 20:27 ` Mark Cave-Ayland
2022-03-28 22:43 ` Richard Henderson
2022-03-31 12:28 ` yangxiaojuan
2022-03-28 22:46 ` Richard Henderson
2022-03-28 12:57 ` [RFC PATCH v7 20/29] hw/loongarch: Add irq hierarchy for the system Xiaojuan Yang
2022-03-28 23:16 ` Richard Henderson
2022-03-28 12:57 ` [RFC PATCH v7 21/29] Enable common virtio pci support for LoongArch Xiaojuan Yang
2022-03-28 23:18 ` Richard Henderson
2022-03-28 12:57 ` [RFC PATCH v7 22/29] hw/loongarch: Add some devices support for 3A5000 Xiaojuan Yang
2022-03-28 12:57 ` [RFC PATCH v7 23/29] hw/loongarch: Add LoongArch ls7a rtc device support Xiaojuan Yang
2022-03-28 12:57 ` [RFC PATCH v7 24/29] hw/loongarch: Add default bios startup support Xiaojuan Yang
2022-03-29 3:27 ` Richard Henderson
2022-03-28 12:57 ` [RFC PATCH v7 25/29] hw/loongarch: Add -kernel and -initrd options support Xiaojuan Yang
2022-03-28 12:57 ` [RFC PATCH v7 26/29] hw/loongarch: Add LoongArch smbios support Xiaojuan Yang
2022-03-28 12:57 ` [RFC PATCH v7 27/29] hw/loongarch: Add LoongArch acpi support Xiaojuan Yang
2022-03-28 12:57 ` [RFC PATCH v7 28/29] hw/loongarch: Add fdt support Xiaojuan Yang
2022-03-28 12:57 ` [RFC PATCH v7 29/29] tests/tcg/loongarch64: Add hello/memory test in loongarch64 system Xiaojuan Yang
2022-03-29 3:29 ` Richard Henderson
2022-03-28 18:13 ` [RFC PATCH v7 00/29] Add LoongArch softmmu support Richard Henderson
2022-03-30 9:34 ` yangxiaojuan
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.