mirror of
https://github.com/Motorhead1991/qemu.git
synced 2026-02-11 19:39:26 -07:00
pull-loongarch-20250619
-----BEGIN PGP SIGNATURE----- iLMEAAEIAB0WIQTKRzxE1qCcGJoZP81FK5aFKyaCFgUCaFPPIgAKCRBFK5aFKyaC Fq67BACc5EYLK/T0Q2DxDmI84ZmK83GBAsQoB/81CLCDwA4ihotLAjqTB1liKFvY oFexqza3GBxpiyyw+zAUyrx1X/arnSrCAlgPOF2SIZgj1WnHm/jZb+8mdpgFGZc5 6TkB4Dr5rmSa8OJLYIiC7gKYu9K3zEO/Dprgx9nj3D4tb8xRDQ== =601X -----END PGP SIGNATURE----- Merge tag 'pull-loongarch-20250619' of https://github.com/gaosong715/qemu into staging pull-loongarch-20250619 # -----BEGIN PGP SIGNATURE----- # # iLMEAAEIAB0WIQTKRzxE1qCcGJoZP81FK5aFKyaCFgUCaFPPIgAKCRBFK5aFKyaC # Fq67BACc5EYLK/T0Q2DxDmI84ZmK83GBAsQoB/81CLCDwA4ihotLAjqTB1liKFvY # oFexqza3GBxpiyyw+zAUyrx1X/arnSrCAlgPOF2SIZgj1WnHm/jZb+8mdpgFGZc5 # 6TkB4Dr5rmSa8OJLYIiC7gKYu9K3zEO/Dprgx9nj3D4tb8xRDQ== # =601X # -----END PGP SIGNATURE----- # gpg: Signature made Thu 19 Jun 2025 04:49:38 EDT # gpg: using RSA key CA473C44D6A09C189A193FCD452B96852B268216 # gpg: Good signature from "Song Gao <gaosong@loongson.cn>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: CA47 3C44 D6A0 9C18 9A19 3FCD 452B 9685 2B26 8216 * tag 'pull-loongarch-20250619' of https://github.com/gaosong715/qemu: target/loongarch: fix vldi/xvldi raise wrong error hw/loongarch/virt: Add kernel irqchip support hw/loongarch/virt: Disable emulation with IOCSR misc register target/loongarch: Report error with split kernel_irqchip option hw/loongarch/virt: Add reset support for kernel irqchip hw/intc/loongarch_pch: Inject irq line interrupt to kernel hw/intc/loongarch_pch: Add kernel irqchip save and restore function hw/intc/loongarch_pch: Add kernel irqchip realize function hw/intc/loongarch_pch_msi: Inject MSI interrupt to kernel hw/intc/loongarch_ipi: Add kernel irqchip save and restore function hw/intc/loongson_ipi: Add load and save interface with ipi_common class hw/intc/loongarch_ipi: Add kernel irqchip realize function hw/intc/loongarch_extioi: Add kernel irqchip save and restore function hw/intc/loongarch_extioi: Add kernel irqchip realize function Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
commit
d01d42ccc9
18 changed files with 563 additions and 43 deletions
|
|
@ -12,6 +12,7 @@
|
|||
#include "hw/irq.h"
|
||||
#include "hw/loongarch/virt.h"
|
||||
#include "system/address-spaces.h"
|
||||
#include "system/kvm.h"
|
||||
#include "hw/intc/loongarch_extioi.h"
|
||||
#include "trace.h"
|
||||
|
||||
|
|
@ -351,23 +352,29 @@ static void loongarch_extioi_realize(DeviceState *dev, Error **errp)
|
|||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < EXTIOI_IRQS; i++) {
|
||||
sysbus_init_irq(sbd, &s->irq[i]);
|
||||
}
|
||||
|
||||
qdev_init_gpio_in(dev, extioi_setirq, EXTIOI_IRQS);
|
||||
memory_region_init_io(&s->extioi_system_mem, OBJECT(s), &extioi_ops,
|
||||
s, "extioi_system_mem", 0x900);
|
||||
sysbus_init_mmio(sbd, &s->extioi_system_mem);
|
||||
|
||||
if (s->features & BIT(EXTIOI_HAS_VIRT_EXTENSION)) {
|
||||
memory_region_init_io(&s->virt_extend, OBJECT(s), &extioi_virt_ops,
|
||||
s, "extioi_virt", EXTIOI_VIRT_SIZE);
|
||||
sysbus_init_mmio(sbd, &s->virt_extend);
|
||||
s->features |= EXTIOI_VIRT_HAS_FEATURES;
|
||||
} else {
|
||||
s->status |= BIT(EXTIOI_ENABLE);
|
||||
}
|
||||
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
kvm_extioi_realize(dev, errp);
|
||||
} else {
|
||||
for (i = 0; i < EXTIOI_IRQS; i++) {
|
||||
sysbus_init_irq(sbd, &s->irq[i]);
|
||||
}
|
||||
|
||||
qdev_init_gpio_in(dev, extioi_setirq, EXTIOI_IRQS);
|
||||
memory_region_init_io(&s->extioi_system_mem, OBJECT(s), &extioi_ops,
|
||||
s, "extioi_system_mem", 0x900);
|
||||
sysbus_init_mmio(sbd, &s->extioi_system_mem);
|
||||
if (s->features & BIT(EXTIOI_HAS_VIRT_EXTENSION)) {
|
||||
memory_region_init_io(&s->virt_extend, OBJECT(s), &extioi_virt_ops,
|
||||
s, "extioi_virt", EXTIOI_VIRT_SIZE);
|
||||
sysbus_init_mmio(sbd, &s->virt_extend);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void loongarch_extioi_unrealize(DeviceState *dev)
|
||||
|
|
@ -384,6 +391,19 @@ static void loongarch_extioi_reset_hold(Object *obj, ResetType type)
|
|||
if (lec->parent_phases.hold) {
|
||||
lec->parent_phases.hold(obj, type);
|
||||
}
|
||||
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
kvm_extioi_put(obj, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static int vmstate_extioi_pre_save(void *opaque)
|
||||
{
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
return kvm_extioi_get(opaque);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vmstate_extioi_post_load(void *opaque, int version_id)
|
||||
|
|
@ -391,6 +411,10 @@ static int vmstate_extioi_post_load(void *opaque, int version_id)
|
|||
LoongArchExtIOICommonState *s = LOONGARCH_EXTIOI_COMMON(opaque);
|
||||
int i, start_irq;
|
||||
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
return kvm_extioi_put(opaque, version_id);
|
||||
}
|
||||
|
||||
for (i = 0; i < (EXTIOI_IRQS / 4); i++) {
|
||||
start_irq = i * 4;
|
||||
extioi_update_sw_coremap(s, start_irq, s->coremap[i], false);
|
||||
|
|
@ -416,6 +440,7 @@ static void loongarch_extioi_class_init(ObjectClass *klass, const void *data)
|
|||
&lec->parent_unrealize);
|
||||
resettable_class_set_parent_phases(rc, NULL, loongarch_extioi_reset_hold,
|
||||
NULL, &lec->parent_phases);
|
||||
lecc->pre_save = vmstate_extioi_pre_save;
|
||||
lecc->post_load = vmstate_extioi_post_load;
|
||||
}
|
||||
|
||||
|
|
|
|||
140
hw/intc/loongarch_extioi_kvm.c
Normal file
140
hw/intc/loongarch_extioi_kvm.c
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* LoongArch EXTIOI interrupt kvm support
|
||||
*
|
||||
* Copyright (C) 2025 Loongson Technology Corporation Limited
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/typedefs.h"
|
||||
#include "hw/intc/loongarch_extioi.h"
|
||||
#include "linux/kvm.h"
|
||||
#include "qapi/error.h"
|
||||
#include "system/kvm.h"
|
||||
|
||||
static void kvm_extioi_access_reg(int fd, uint64_t addr, void *val, bool write)
|
||||
{
|
||||
kvm_device_access(fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS,
|
||||
addr, val, write, &error_abort);
|
||||
}
|
||||
|
||||
static void kvm_extioi_access_sw_state(int fd, uint64_t addr,
|
||||
void *val, bool write)
|
||||
{
|
||||
kvm_device_access(fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_SW_STATUS,
|
||||
addr, val, write, &error_abort);
|
||||
}
|
||||
|
||||
static void kvm_extioi_access_sw_status(void *opaque, bool write)
|
||||
{
|
||||
LoongArchExtIOICommonState *lecs = LOONGARCH_EXTIOI_COMMON(opaque);
|
||||
LoongArchExtIOIState *les = LOONGARCH_EXTIOI(opaque);
|
||||
int addr;
|
||||
|
||||
addr = KVM_DEV_LOONGARCH_EXTIOI_SW_STATUS_STATE;
|
||||
kvm_extioi_access_sw_state(les->dev_fd, addr, &lecs->status, write);
|
||||
}
|
||||
|
||||
static void kvm_extioi_access_regs(void *opaque, bool write)
|
||||
{
|
||||
LoongArchExtIOICommonState *lecs = LOONGARCH_EXTIOI_COMMON(opaque);
|
||||
LoongArchExtIOIState *les = LOONGARCH_EXTIOI(opaque);
|
||||
int fd = les->dev_fd;
|
||||
int addr, offset, cpu;
|
||||
|
||||
for (addr = EXTIOI_NODETYPE_START; addr < EXTIOI_NODETYPE_END; addr += 4) {
|
||||
offset = (addr - EXTIOI_NODETYPE_START) / 4;
|
||||
kvm_extioi_access_reg(fd, addr, &lecs->nodetype[offset], write);
|
||||
}
|
||||
|
||||
for (addr = EXTIOI_IPMAP_START; addr < EXTIOI_IPMAP_END; addr += 4) {
|
||||
offset = (addr - EXTIOI_IPMAP_START) / 4;
|
||||
kvm_extioi_access_reg(fd, addr, &lecs->ipmap[offset], write);
|
||||
}
|
||||
|
||||
for (addr = EXTIOI_ENABLE_START; addr < EXTIOI_ENABLE_END; addr += 4) {
|
||||
offset = (addr - EXTIOI_ENABLE_START) / 4;
|
||||
kvm_extioi_access_reg(fd, addr, &lecs->enable[offset], write);
|
||||
}
|
||||
|
||||
for (addr = EXTIOI_BOUNCE_START; addr < EXTIOI_BOUNCE_END; addr += 4) {
|
||||
offset = (addr - EXTIOI_BOUNCE_START) / 4;
|
||||
kvm_extioi_access_reg(fd, addr, &lecs->bounce[offset], write);
|
||||
}
|
||||
|
||||
for (addr = EXTIOI_ISR_START; addr < EXTIOI_ISR_END; addr += 4) {
|
||||
offset = (addr - EXTIOI_ISR_START) / 4;
|
||||
kvm_extioi_access_reg(fd, addr, &lecs->isr[offset], write);
|
||||
}
|
||||
|
||||
for (addr = EXTIOI_COREMAP_START; addr < EXTIOI_COREMAP_END; addr += 4) {
|
||||
offset = (addr - EXTIOI_COREMAP_START) / 4;
|
||||
kvm_extioi_access_reg(fd, addr, &lecs->coremap[offset], write);
|
||||
}
|
||||
|
||||
for (cpu = 0; cpu < lecs->num_cpu; cpu++) {
|
||||
for (addr = EXTIOI_COREISR_START;
|
||||
addr < EXTIOI_COREISR_END; addr += 4) {
|
||||
offset = (addr - EXTIOI_COREISR_START) / 4;
|
||||
kvm_extioi_access_reg(fd, (cpu << 16) | addr,
|
||||
&lecs->cpu[cpu].coreisr[offset], write);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int kvm_extioi_get(void *opaque)
|
||||
{
|
||||
kvm_extioi_access_regs(opaque, false);
|
||||
kvm_extioi_access_sw_status(opaque, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kvm_extioi_put(void *opaque, int version_id)
|
||||
{
|
||||
LoongArchExtIOIState *les = LOONGARCH_EXTIOI(opaque);
|
||||
int fd = les->dev_fd;
|
||||
|
||||
if (fd == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
kvm_extioi_access_regs(opaque, true);
|
||||
kvm_extioi_access_sw_status(opaque, true);
|
||||
kvm_device_access(fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_CTRL,
|
||||
KVM_DEV_LOONGARCH_EXTIOI_CTRL_LOAD_FINISHED,
|
||||
NULL, true, &error_abort);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kvm_extioi_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
LoongArchExtIOICommonState *lecs = LOONGARCH_EXTIOI_COMMON(dev);
|
||||
LoongArchExtIOIState *les = LOONGARCH_EXTIOI(dev);
|
||||
int ret;
|
||||
|
||||
ret = kvm_create_device(kvm_state, KVM_DEV_TYPE_LOONGARCH_EIOINTC, false);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "create KVM_LOONGARCH_EIOINTC failed: %s\n",
|
||||
strerror(-ret));
|
||||
abort();
|
||||
}
|
||||
|
||||
les->dev_fd = ret;
|
||||
ret = kvm_device_access(les->dev_fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_CTRL,
|
||||
KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_NUM_CPU,
|
||||
&lecs->num_cpu, true, NULL);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "KVM_LOONGARCH_EXTIOI_INIT_NUM_CPU failed: %s\n",
|
||||
strerror(-ret));
|
||||
abort();
|
||||
}
|
||||
|
||||
ret = kvm_device_access(les->dev_fd, KVM_DEV_LOONGARCH_EXTIOI_GRP_CTRL,
|
||||
KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_FEATURE,
|
||||
&lecs->features, true, NULL);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "KVM_LOONGARCH_EXTIOI_INIT_FEATURE failed: %s\n",
|
||||
strerror(-ret));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@
|
|||
#include "qapi/error.h"
|
||||
#include "hw/intc/loongarch_ipi.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "system/kvm.h"
|
||||
#include "target/loongarch/cpu.h"
|
||||
|
||||
static AddressSpace *get_iocsr_as(CPUState *cpu)
|
||||
|
|
@ -91,6 +92,10 @@ static void loongarch_ipi_realize(DeviceState *dev, Error **errp)
|
|||
lics->cpu[i].ipi = lics;
|
||||
qdev_init_gpio_out(dev, &lics->cpu[i].irq, 1);
|
||||
}
|
||||
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
kvm_ipi_realize(dev, errp);
|
||||
}
|
||||
}
|
||||
|
||||
static void loongarch_ipi_reset_hold(Object *obj, ResetType type)
|
||||
|
|
@ -117,6 +122,10 @@ static void loongarch_ipi_reset_hold(Object *obj, ResetType type)
|
|||
core->clear = 0;
|
||||
memset(core->buf, 0, sizeof(core->buf));
|
||||
}
|
||||
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
kvm_ipi_put(obj, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void loongarch_ipi_cpu_plug(HotplugHandler *hotplug_dev,
|
||||
|
|
@ -166,6 +175,24 @@ static void loongarch_ipi_cpu_unplug(HotplugHandler *hotplug_dev,
|
|||
core->cpu = NULL;
|
||||
}
|
||||
|
||||
static int loongarch_ipi_pre_save(void *opaque)
|
||||
{
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
return kvm_ipi_get(opaque);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int loongarch_ipi_post_load(void *opaque, int version_id)
|
||||
{
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
return kvm_ipi_put(opaque, version_id);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void loongarch_ipi_class_init(ObjectClass *klass, const void *data)
|
||||
{
|
||||
LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_CLASS(klass);
|
||||
|
|
@ -182,6 +209,8 @@ static void loongarch_ipi_class_init(ObjectClass *klass, const void *data)
|
|||
licc->cpu_by_arch_id = loongarch_cpu_by_arch_id;
|
||||
hc->plug = loongarch_ipi_cpu_plug;
|
||||
hc->unplug = loongarch_ipi_cpu_unplug;
|
||||
licc->pre_save = loongarch_ipi_pre_save;
|
||||
licc->post_load = loongarch_ipi_post_load;
|
||||
}
|
||||
|
||||
static const TypeInfo loongarch_ipi_types[] = {
|
||||
|
|
|
|||
85
hw/intc/loongarch_ipi_kvm.c
Normal file
85
hw/intc/loongarch_ipi_kvm.c
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* LoongArch IPI interrupt KVM support
|
||||
*
|
||||
* Copyright (C) 2025 Loongson Technology Corporation Limited
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/intc/loongarch_ipi.h"
|
||||
#include "system/kvm.h"
|
||||
#include "target/loongarch/cpu.h"
|
||||
|
||||
static void kvm_ipi_access_reg(int fd, uint64_t addr, uint32_t *val, bool write)
|
||||
{
|
||||
kvm_device_access(fd, KVM_DEV_LOONGARCH_IPI_GRP_REGS,
|
||||
addr, val, write, &error_abort);
|
||||
}
|
||||
|
||||
static void kvm_ipi_access_regs(void *opaque, bool write)
|
||||
{
|
||||
LoongsonIPICommonState *ipi = (LoongsonIPICommonState *)opaque;
|
||||
LoongarchIPIState *lis = LOONGARCH_IPI(opaque);
|
||||
IPICore *core;
|
||||
uint64_t attr;
|
||||
int cpu, fd = lis->dev_fd;
|
||||
|
||||
if (fd == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (cpu = 0; cpu < ipi->num_cpu; cpu++) {
|
||||
core = &ipi->cpu[cpu];
|
||||
attr = (cpu << 16) | CORE_STATUS_OFF;
|
||||
kvm_ipi_access_reg(fd, attr, &core->status, write);
|
||||
|
||||
attr = (cpu << 16) | CORE_EN_OFF;
|
||||
kvm_ipi_access_reg(fd, attr, &core->en, write);
|
||||
|
||||
attr = (cpu << 16) | CORE_SET_OFF;
|
||||
kvm_ipi_access_reg(fd, attr, &core->set, write);
|
||||
|
||||
attr = (cpu << 16) | CORE_CLEAR_OFF;
|
||||
kvm_ipi_access_reg(fd, attr, &core->clear, write);
|
||||
|
||||
attr = (cpu << 16) | CORE_BUF_20;
|
||||
kvm_ipi_access_reg(fd, attr, &core->buf[0], write);
|
||||
|
||||
attr = (cpu << 16) | CORE_BUF_28;
|
||||
kvm_ipi_access_reg(fd, attr, &core->buf[2], write);
|
||||
|
||||
attr = (cpu << 16) | CORE_BUF_30;
|
||||
kvm_ipi_access_reg(fd, attr, &core->buf[4], write);
|
||||
|
||||
attr = (cpu << 16) | CORE_BUF_38;
|
||||
kvm_ipi_access_reg(fd, attr, &core->buf[6], write);
|
||||
}
|
||||
}
|
||||
|
||||
int kvm_ipi_get(void *opaque)
|
||||
{
|
||||
kvm_ipi_access_regs(opaque, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kvm_ipi_put(void *opaque, int version_id)
|
||||
{
|
||||
kvm_ipi_access_regs(opaque, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kvm_ipi_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
LoongarchIPIState *lis = LOONGARCH_IPI(dev);
|
||||
int ret;
|
||||
|
||||
ret = kvm_create_device(kvm_state, KVM_DEV_TYPE_LOONGARCH_IPI, false);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "IPI KVM_CREATE_DEVICE failed: %s\n",
|
||||
strerror(-ret));
|
||||
abort();
|
||||
}
|
||||
|
||||
lis->dev_fd = ret;
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@
|
|||
#include "hw/pci/msi.h"
|
||||
#include "hw/misc/unimp.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "system/kvm.h"
|
||||
#include "trace.h"
|
||||
|
||||
static uint64_t loongarch_msi_mem_read(void *opaque, hwaddr addr, unsigned size)
|
||||
|
|
@ -26,6 +27,15 @@ static void loongarch_msi_mem_write(void *opaque, hwaddr addr,
|
|||
LoongArchPCHMSI *s = (LoongArchPCHMSI *)opaque;
|
||||
int irq_num;
|
||||
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
MSIMessage msg;
|
||||
|
||||
msg.address = addr;
|
||||
msg.data = val;
|
||||
kvm_irqchip_send_msi(kvm_state, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* vector number is irq number from upper extioi intc
|
||||
* need subtract irq base to get msi vector offset
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include "qemu/log.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/intc/loongarch_pch_pic.h"
|
||||
#include "system/kvm.h"
|
||||
#include "trace.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
|
|
@ -48,6 +49,11 @@ static void pch_pic_irq_handler(void *opaque, int irq, int level)
|
|||
assert(irq < s->irq_num);
|
||||
trace_loongarch_pch_pic_irq_handler(irq, level);
|
||||
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
kvm_set_irq(kvm_state, irq, !!level);
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->intedge & mask) {
|
||||
/* Edge triggered */
|
||||
if (level) {
|
||||
|
|
@ -258,6 +264,10 @@ static void loongarch_pic_reset_hold(Object *obj, ResetType type)
|
|||
if (lpc->parent_phases.hold) {
|
||||
lpc->parent_phases.hold(obj, type);
|
||||
}
|
||||
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
kvm_pic_put(obj, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void loongarch_pic_realize(DeviceState *dev, Error **errp)
|
||||
|
|
@ -275,22 +285,49 @@ static void loongarch_pic_realize(DeviceState *dev, Error **errp)
|
|||
|
||||
qdev_init_gpio_out(dev, s->parent_irq, s->irq_num);
|
||||
qdev_init_gpio_in(dev, pch_pic_irq_handler, s->irq_num);
|
||||
memory_region_init_io(&s->iomem, OBJECT(dev),
|
||||
&loongarch_pch_pic_ops,
|
||||
s, TYPE_LOONGARCH_PIC, VIRT_PCH_REG_SIZE);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
kvm_pic_realize(dev, errp);
|
||||
} else {
|
||||
memory_region_init_io(&s->iomem, OBJECT(dev),
|
||||
&loongarch_pch_pic_ops,
|
||||
s, TYPE_LOONGARCH_PIC, VIRT_PCH_REG_SIZE);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
}
|
||||
}
|
||||
|
||||
static int loongarch_pic_pre_save(LoongArchPICCommonState *opaque)
|
||||
{
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
return kvm_pic_get(opaque);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int loongarch_pic_post_load(LoongArchPICCommonState *opaque,
|
||||
int version_id)
|
||||
{
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
return kvm_pic_put(opaque, version_id);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void loongarch_pic_class_init(ObjectClass *klass, const void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
LoongarchPICClass *lpc = LOONGARCH_PIC_CLASS(klass);
|
||||
LoongArchPICCommonClass *lpcc = LOONGARCH_PIC_COMMON_CLASS(klass);
|
||||
ResettableClass *rc = RESETTABLE_CLASS(klass);
|
||||
|
||||
resettable_class_set_parent_phases(rc, NULL, loongarch_pic_reset_hold,
|
||||
NULL, &lpc->parent_phases);
|
||||
device_class_set_parent_realize(dc, loongarch_pic_realize,
|
||||
&lpc->parent_realize);
|
||||
lpcc->pre_save = loongarch_pic_pre_save;
|
||||
lpcc->post_load = loongarch_pic_post_load;
|
||||
}
|
||||
|
||||
static const TypeInfo loongarch_pic_types[] = {
|
||||
|
|
|
|||
89
hw/intc/loongarch_pic_kvm.c
Normal file
89
hw/intc/loongarch_pic_kvm.c
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* LoongArch kvm pch pic interrupt support
|
||||
*
|
||||
* Copyright (C) 2025 Loongson Technology Corporation Limited
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/intc/loongarch_pch_pic.h"
|
||||
#include "hw/loongarch/virt.h"
|
||||
#include "hw/pci-host/ls7a.h"
|
||||
#include "system/kvm.h"
|
||||
|
||||
static void kvm_pch_pic_access_reg(int fd, uint64_t addr, void *val, bool write)
|
||||
{
|
||||
kvm_device_access(fd, KVM_DEV_LOONGARCH_PCH_PIC_GRP_REGS,
|
||||
addr, val, write, &error_abort);
|
||||
}
|
||||
|
||||
static void kvm_pch_pic_access(void *opaque, bool write)
|
||||
{
|
||||
LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(opaque);
|
||||
LoongarchPICState *lps = LOONGARCH_PIC(opaque);
|
||||
int fd = lps->dev_fd;
|
||||
int addr, offset;
|
||||
|
||||
if (fd == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
kvm_pch_pic_access_reg(fd, PCH_PIC_INT_MASK, &s->int_mask, write);
|
||||
kvm_pch_pic_access_reg(fd, PCH_PIC_HTMSI_EN, &s->htmsi_en, write);
|
||||
kvm_pch_pic_access_reg(fd, PCH_PIC_INT_EDGE, &s->intedge, write);
|
||||
kvm_pch_pic_access_reg(fd, PCH_PIC_AUTO_CTRL0, &s->auto_crtl0, write);
|
||||
kvm_pch_pic_access_reg(fd, PCH_PIC_AUTO_CTRL1, &s->auto_crtl1, write);
|
||||
|
||||
for (addr = PCH_PIC_ROUTE_ENTRY;
|
||||
addr < PCH_PIC_ROUTE_ENTRY_END; addr++) {
|
||||
offset = addr - PCH_PIC_ROUTE_ENTRY;
|
||||
kvm_pch_pic_access_reg(fd, addr, &s->route_entry[offset], write);
|
||||
}
|
||||
|
||||
for (addr = PCH_PIC_HTMSI_VEC; addr < PCH_PIC_HTMSI_VEC_END; addr++) {
|
||||
offset = addr - PCH_PIC_HTMSI_VEC;
|
||||
kvm_pch_pic_access_reg(fd, addr, &s->htmsi_vector[offset], write);
|
||||
}
|
||||
|
||||
kvm_pch_pic_access_reg(fd, PCH_PIC_INT_REQUEST, &s->intirr, write);
|
||||
kvm_pch_pic_access_reg(fd, PCH_PIC_INT_STATUS, &s->intisr, write);
|
||||
kvm_pch_pic_access_reg(fd, PCH_PIC_INT_POL, &s->int_polarity, write);
|
||||
}
|
||||
|
||||
int kvm_pic_get(void *opaque)
|
||||
{
|
||||
kvm_pch_pic_access(opaque, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kvm_pic_put(void *opaque, int version_id)
|
||||
{
|
||||
kvm_pch_pic_access(opaque, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kvm_pic_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
LoongarchPICState *lps = LOONGARCH_PIC(dev);
|
||||
uint64_t pch_pic_base = VIRT_PCH_REG_BASE;
|
||||
int ret;
|
||||
|
||||
ret = kvm_create_device(kvm_state, KVM_DEV_TYPE_LOONGARCH_PCHPIC, false);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Create KVM_LOONGARCH_PCHPIC failed: %s\n",
|
||||
strerror(-ret));
|
||||
abort();
|
||||
}
|
||||
|
||||
lps->dev_fd = ret;
|
||||
ret = kvm_device_access(lps->dev_fd, KVM_DEV_LOONGARCH_PCH_PIC_GRP_CTRL,
|
||||
KVM_DEV_LOONGARCH_PCH_PIC_CTRL_INIT,
|
||||
&pch_pic_base, true, NULL);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "KVM_LOONGARCH_PCH_PIC_INIT failed: %s\n",
|
||||
strerror(-ret));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@
|
|||
#include "hw/irq.h"
|
||||
#include "qemu/log.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "system/kvm.h"
|
||||
#include "trace.h"
|
||||
|
||||
MemTxResult loongson_ipi_core_readl(void *opaque, hwaddr addr, uint64_t *data,
|
||||
|
|
@ -255,6 +256,10 @@ static void loongson_ipi_common_realize(DeviceState *dev, Error **errp)
|
|||
LoongsonIPICommonState *s = LOONGSON_IPI_COMMON(dev);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
return;
|
||||
}
|
||||
|
||||
memory_region_init_io(&s->ipi_iocsr_mem, OBJECT(dev),
|
||||
&loongson_ipi_iocsr_ops,
|
||||
s, "loongson_ipi_iocsr", 0x48);
|
||||
|
|
@ -277,10 +282,38 @@ static void loongson_ipi_common_unrealize(DeviceState *dev)
|
|||
g_free(s->cpu);
|
||||
}
|
||||
|
||||
static int loongson_ipi_common_pre_save(void *opaque)
|
||||
{
|
||||
IPICore *ipicore = (IPICore *)opaque;
|
||||
LoongsonIPICommonState *s = ipicore->ipi;
|
||||
LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_GET_CLASS(s);
|
||||
|
||||
if (licc->pre_save) {
|
||||
return licc->pre_save(s);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int loongson_ipi_common_post_load(void *opaque, int version_id)
|
||||
{
|
||||
IPICore *ipicore = (IPICore *)opaque;
|
||||
LoongsonIPICommonState *s = ipicore->ipi;
|
||||
LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_GET_CLASS(s);
|
||||
|
||||
if (licc->post_load) {
|
||||
return licc->post_load(s, version_id);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_ipi_core = {
|
||||
.name = "ipi-single",
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 2,
|
||||
.pre_save = loongson_ipi_common_pre_save,
|
||||
.post_load = loongson_ipi_common_post_load,
|
||||
.fields = (const VMStateField[]) {
|
||||
VMSTATE_UINT32(status, IPICore),
|
||||
VMSTATE_UINT32(en, IPICore),
|
||||
|
|
|
|||
|
|
@ -71,6 +71,12 @@ specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c'))
|
|||
specific_ss.add(when: 'CONFIG_LOONGSON_IPI_COMMON', if_true: files('loongson_ipi_common.c'))
|
||||
specific_ss.add(when: 'CONFIG_LOONGSON_IPI', if_true: files('loongson_ipi.c'))
|
||||
specific_ss.add(when: 'CONFIG_LOONGARCH_IPI', if_true: files('loongarch_ipi.c'))
|
||||
specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_LOONGARCH_IPI'],
|
||||
if_true: files('loongarch_ipi_kvm.c'))
|
||||
specific_ss.add(when: 'CONFIG_LOONGARCH_PCH_PIC', if_true: files('loongarch_pch_pic.c', 'loongarch_pic_common.c'))
|
||||
specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_LOONGARCH_PCH_PIC'],
|
||||
if_true: files('loongarch_pic_kvm.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', 'loongarch_extioi_common.c'))
|
||||
specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_LOONGARCH_EXTIOI'],
|
||||
if_true: files('loongarch_extioi_kvm.c'))
|
||||
|
|
|
|||
|
|
@ -414,12 +414,6 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms)
|
|||
lvms->ipi = ipi;
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi), &error_fatal);
|
||||
|
||||
/* IPI iocsr memory region */
|
||||
memory_region_add_subregion(&lvms->system_iocsr, SMP_IPI_MAILBOX,
|
||||
sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 0));
|
||||
memory_region_add_subregion(&lvms->system_iocsr, MAIL_SEND_ADDR,
|
||||
sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 1));
|
||||
|
||||
/* Create EXTIOI device */
|
||||
extioi = qdev_new(TYPE_LOONGARCH_EXTIOI);
|
||||
lvms->extioi = extioi;
|
||||
|
|
@ -427,12 +421,6 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms)
|
|||
qdev_prop_set_bit(extioi, "has-virtualization-extension", true);
|
||||
}
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi), &error_fatal);
|
||||
memory_region_add_subregion(&lvms->system_iocsr, APIC_BASE,
|
||||
sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 0));
|
||||
if (virt_is_veiointc_enabled(lvms)) {
|
||||
memory_region_add_subregion(&lvms->system_iocsr, EXTIOI_VIRT_BASE,
|
||||
sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 1));
|
||||
}
|
||||
|
||||
virt_cpu_irq_init(lvms);
|
||||
pch_pic = qdev_new(TYPE_LOONGARCH_PIC);
|
||||
|
|
@ -440,13 +428,6 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms)
|
|||
qdev_prop_set_uint32(pch_pic, "pch_pic_irq_num", num);
|
||||
d = SYS_BUS_DEVICE(pch_pic);
|
||||
sysbus_realize_and_unref(d, &error_fatal);
|
||||
memory_region_add_subregion(get_system_memory(), VIRT_IOAPIC_REG_BASE,
|
||||
sysbus_mmio_get_region(d, 0));
|
||||
|
||||
/* Connect pch_pic irqs to extioi */
|
||||
for (i = 0; i < num; i++) {
|
||||
qdev_connect_gpio_out(DEVICE(d), i, qdev_get_gpio_in(extioi, i));
|
||||
}
|
||||
|
||||
pch_msi = qdev_new(TYPE_LOONGARCH_PCH_MSI);
|
||||
start = num;
|
||||
|
|
@ -456,12 +437,40 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms)
|
|||
d = SYS_BUS_DEVICE(pch_msi);
|
||||
sysbus_realize_and_unref(d, &error_fatal);
|
||||
sysbus_mmio_map(d, 0, VIRT_PCH_MSI_ADDR_LOW);
|
||||
for (i = 0; i < num; i++) {
|
||||
/* Connect pch_msi irqs to extioi */
|
||||
qdev_connect_gpio_out(DEVICE(d), i,
|
||||
qdev_get_gpio_in(extioi, i + start));
|
||||
}
|
||||
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
kvm_loongarch_init_irq_routing();
|
||||
} else {
|
||||
/* IPI iocsr memory region */
|
||||
memory_region_add_subregion(&lvms->system_iocsr, SMP_IPI_MAILBOX,
|
||||
sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 0));
|
||||
memory_region_add_subregion(&lvms->system_iocsr, MAIL_SEND_ADDR,
|
||||
sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 1));
|
||||
|
||||
/* EXTIOI iocsr memory region */
|
||||
memory_region_add_subregion(&lvms->system_iocsr, APIC_BASE,
|
||||
sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 0));
|
||||
if (virt_is_veiointc_enabled(lvms)) {
|
||||
memory_region_add_subregion(&lvms->system_iocsr, EXTIOI_VIRT_BASE,
|
||||
sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 1));
|
||||
}
|
||||
|
||||
/* PCH_PIC memory region */
|
||||
memory_region_add_subregion(get_system_memory(), VIRT_IOAPIC_REG_BASE,
|
||||
sysbus_mmio_get_region(SYS_BUS_DEVICE(pch_pic), 0));
|
||||
|
||||
/* Connect pch_pic irqs to extioi */
|
||||
for (i = 0; i < VIRT_PCH_PIC_IRQ_NUM; i++) {
|
||||
qdev_connect_gpio_out(DEVICE(pch_pic), i,
|
||||
qdev_get_gpio_in(extioi, i));
|
||||
}
|
||||
|
||||
for (i = VIRT_PCH_PIC_IRQ_NUM; i < EXTIOI_IRQS; i++) {
|
||||
/* Connect pch_msi irqs to extioi */
|
||||
qdev_connect_gpio_out(DEVICE(pch_msi), i - VIRT_PCH_PIC_IRQ_NUM,
|
||||
qdev_get_gpio_in(extioi, i));
|
||||
}
|
||||
}
|
||||
virt_devices_init(pch_pic, lvms);
|
||||
}
|
||||
|
||||
|
|
@ -522,6 +531,10 @@ static MemTxResult virt_iocsr_misc_write(void *opaque, hwaddr addr,
|
|||
|
||||
switch (addr) {
|
||||
case MISC_FUNC_REG:
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
return MEMTX_OK;
|
||||
}
|
||||
|
||||
if (!virt_is_veiointc_enabled(lvms)) {
|
||||
return MEMTX_OK;
|
||||
}
|
||||
|
|
@ -572,6 +585,10 @@ static MemTxResult virt_iocsr_misc_read(void *opaque, hwaddr addr,
|
|||
ret = 0x303030354133ULL; /* "3A5000" */
|
||||
break;
|
||||
case MISC_FUNC_REG:
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
return MEMTX_OK;
|
||||
}
|
||||
|
||||
if (!virt_is_veiointc_enabled(lvms)) {
|
||||
ret |= BIT_ULL(IOCSRM_EXTIOI_EN);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ OBJECT_DECLARE_TYPE(LoongArchExtIOIState, LoongArchExtIOIClass, LOONGARCH_EXTIOI
|
|||
|
||||
struct LoongArchExtIOIState {
|
||||
LoongArchExtIOICommonState parent_obj;
|
||||
int dev_fd;
|
||||
};
|
||||
|
||||
struct LoongArchExtIOIClass {
|
||||
|
|
@ -25,4 +26,8 @@ struct LoongArchExtIOIClass {
|
|||
ResettablePhases parent_phases;
|
||||
};
|
||||
|
||||
void kvm_extioi_realize(DeviceState *dev, Error **errp);
|
||||
int kvm_extioi_get(void *opaque);
|
||||
int kvm_extioi_put(void *opaque, int version_id);
|
||||
|
||||
#endif /* LOONGARCH_EXTIOI_H */
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ OBJECT_DECLARE_TYPE(LoongarchIPIState, LoongarchIPIClass, LOONGARCH_IPI)
|
|||
|
||||
struct LoongarchIPIState {
|
||||
LoongsonIPICommonState parent_obj;
|
||||
int dev_fd;
|
||||
};
|
||||
|
||||
struct LoongarchIPIClass {
|
||||
|
|
@ -24,4 +25,8 @@ struct LoongarchIPIClass {
|
|||
ResettablePhases parent_phases;
|
||||
};
|
||||
|
||||
void kvm_ipi_realize(DeviceState *dev, Error **errp);
|
||||
int kvm_ipi_get(void *opaque);
|
||||
int kvm_ipi_put(void *opaque, int version_id);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ OBJECT_DECLARE_TYPE(LoongarchPICState, LoongarchPICClass, LOONGARCH_PIC)
|
|||
|
||||
struct LoongarchPICState {
|
||||
LoongArchPICCommonState parent_obj;
|
||||
int dev_fd;
|
||||
};
|
||||
|
||||
struct LoongarchPICClass {
|
||||
|
|
@ -25,4 +26,8 @@ struct LoongarchPICClass {
|
|||
ResettablePhases parent_phases;
|
||||
};
|
||||
|
||||
void kvm_pic_realize(DeviceState *dev, Error **errp);
|
||||
int kvm_pic_get(void *opaque);
|
||||
int kvm_pic_put(void *opaque, int version_id);
|
||||
|
||||
#endif /* HW_LOONGARCH_PCH_PIC_H */
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#define PCH_PIC_ROUTE_ENTRY_END 0x13f
|
||||
#define PCH_PIC_HTMSI_VEC 0x200
|
||||
#define PCH_PIC_HTMSI_VEC_END 0x23f
|
||||
#define PCH_PIC_INT_REQUEST 0x380
|
||||
#define PCH_PIC_INT_STATUS 0x3a0
|
||||
#define PCH_PIC_INT_POL 0x3e0
|
||||
|
||||
|
|
|
|||
|
|
@ -48,6 +48,8 @@ struct LoongsonIPICommonClass {
|
|||
AddressSpace *(*get_iocsr_as)(CPUState *cpu);
|
||||
int (*cpu_by_arch_id)(LoongsonIPICommonState *lics, int64_t id,
|
||||
int *index, CPUState **pcs);
|
||||
int (*pre_save)(void *opaque);
|
||||
int (*post_load)(void *opaque, int version_id);
|
||||
};
|
||||
|
||||
MemTxResult loongson_ipi_core_readl(void *opaque, hwaddr addr, uint64_t *data,
|
||||
|
|
|
|||
|
|
@ -503,5 +503,6 @@ static inline void kvm_loongarch_cpu_post_init(LoongArchCPU *cpu)
|
|||
{
|
||||
}
|
||||
#endif
|
||||
void kvm_loongarch_init_irq_routing(void);
|
||||
|
||||
#endif /* LOONGARCH_CPU_H */
|
||||
|
|
|
|||
|
|
@ -1240,6 +1240,22 @@ void kvm_arch_init_irq_routing(KVMState *s)
|
|||
{
|
||||
}
|
||||
|
||||
void kvm_loongarch_init_irq_routing(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
kvm_async_interrupts_allowed = true;
|
||||
kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled();
|
||||
if (kvm_has_gsi_routing()) {
|
||||
for (i = 0; i < KVM_IRQCHIP_NUM_PINS; ++i) {
|
||||
kvm_irqchip_add_irq_route(kvm_state, i, 0, i);
|
||||
}
|
||||
|
||||
kvm_gsi_routing_allowed = true;
|
||||
kvm_irqchip_commit_routes(kvm_state);
|
||||
}
|
||||
}
|
||||
|
||||
int kvm_arch_get_default_type(MachineState *ms)
|
||||
{
|
||||
return 0;
|
||||
|
|
@ -1253,7 +1269,12 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
|
|||
|
||||
int kvm_arch_irqchip_create(KVMState *s)
|
||||
{
|
||||
return 0;
|
||||
if (kvm_kernel_irqchip_split()) {
|
||||
error_report("kernel_irqchip=split is not supported on LoongArch");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return kvm_check_extension(s, KVM_CAP_DEVICE_CTRL);
|
||||
}
|
||||
|
||||
void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run)
|
||||
|
|
|
|||
|
|
@ -3465,7 +3465,7 @@ TRANS(xvmsknz_b, LASX, gen_xx, gen_helper_vmsknz_b)
|
|||
static uint64_t vldi_get_value(DisasContext *ctx, uint32_t imm)
|
||||
{
|
||||
int mode;
|
||||
uint64_t data, t;
|
||||
uint64_t data = 0, t;
|
||||
|
||||
/*
|
||||
* imm bit [11:8] is mode, mode value is 0-12.
|
||||
|
|
@ -3570,17 +3570,26 @@ static uint64_t vldi_get_value(DisasContext *ctx, uint32_t imm)
|
|||
}
|
||||
break;
|
||||
default:
|
||||
generate_exception(ctx, EXCCODE_INE);
|
||||
g_assert_not_reached();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
static bool check_valid_vldi_mode(arg_vldi *a)
|
||||
{
|
||||
return extract32(a->imm, 8, 4) <= 12;
|
||||
}
|
||||
|
||||
static bool gen_vldi(DisasContext *ctx, arg_vldi *a, uint32_t oprsz)
|
||||
{
|
||||
int sel, vece;
|
||||
uint64_t value;
|
||||
|
||||
if (!check_valid_vldi_mode(a)) {
|
||||
generate_exception(ctx, EXCCODE_INE);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!check_vec(ctx, oprsz)) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue