pull-loongarch-20240111

-----BEGIN PGP SIGNATURE-----
 
 iLMEAAEKAB0WIQS4/x2g0v3LLaCcbCxAov/yOSY+3wUCZZ/QKgAKCRBAov/yOSY+
 34eqBADA48++Z9gETFNheLUHdYEaja2emn+gSaoHLFquyq/l53w8RfrUII+BzV1o
 T7D8xjlVQldAYZzqQn2pQe2S7r4ggfeNmxGxwJbCTW9sooGMwBnU8+Ix3ruSet7K
 gI+UHLU4oHk6jdrT384tux2EG+qUmlLN1c7j4G/z1OzKEwFv7Q==
 =+Pi0
 -----END PGP SIGNATURE-----

Merge tag 'pull-loongarch-20240111' of https://gitlab.com/gaosong/qemu into staging

pull-loongarch-20240111

# -----BEGIN PGP SIGNATURE-----
#
# iLMEAAEKAB0WIQS4/x2g0v3LLaCcbCxAov/yOSY+3wUCZZ/QKgAKCRBAov/yOSY+
# 34eqBADA48++Z9gETFNheLUHdYEaja2emn+gSaoHLFquyq/l53w8RfrUII+BzV1o
# T7D8xjlVQldAYZzqQn2pQe2S7r4ggfeNmxGxwJbCTW9sooGMwBnU8+Ix3ruSet7K
# gI+UHLU4oHk6jdrT384tux2EG+qUmlLN1c7j4G/z1OzKEwFv7Q==
# =+Pi0
# -----END PGP SIGNATURE-----
# gpg: Signature made Thu 11 Jan 2024 11:25:30 GMT
# gpg:                using RSA key B8FF1DA0D2FDCB2DA09C6C2C40A2FFF239263EDF
# gpg: Good signature from "Song Gao <m17746591750@163.com>" [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: B8FF 1DA0 D2FD CB2D A09C  6C2C 40A2 FFF2 3926 3EDF

* tag 'pull-loongarch-20240111' of https://gitlab.com/gaosong/qemu:
  hw/intc/loongarch_extioi: Add vmstate post_load support
  hw/intc/loongarch_extioi: Add dynamic cpu number support
  hw/loongarch/virt: Set iocsr address space per-board rather than percpu
  hw/intc/loongarch_ipi: Use MemTxAttrs interface for ipi ops
  target/loongarch: Add loongarch kvm into meson build
  target/loongarch: Implement set vcpu intr for kvm
  target/loongarch: Restrict TCG-specific code
  target/loongarch: Implement kvm_arch_handle_exit
  target/loongarch: Implement kvm_arch_init_vcpu
  target/loongarch: Implement kvm_arch_init function
  target/loongarch: Implement kvm get/set registers
  target/loongarch: Supplement vcpu env initial when vcpu reset
  target/loongarch: Define some kvm_arch interfaces
  linux-headers: Synchronize linux headers from linux v6.7.0-rc8

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2024-01-11 15:19:14 +00:00
commit 5429a82cf8
18 changed files with 1209 additions and 257 deletions

View File

@ -8,6 +8,7 @@
#include "qemu/osdep.h"
#include "qemu/module.h"
#include "qemu/log.h"
#include "qapi/error.h"
#include "hw/irq.h"
#include "hw/sysbus.h"
#include "hw/loongarch/virt.h"
@ -32,23 +33,23 @@ static void extioi_update_irq(LoongArchExtIOI *s, int irq, int level)
if (((s->enable[irq_index]) & irq_mask) == 0) {
return;
}
s->coreisr[cpu][irq_index] |= irq_mask;
found = find_first_bit(s->sw_isr[cpu][ipnum], EXTIOI_IRQS);
set_bit(irq, s->sw_isr[cpu][ipnum]);
s->cpu[cpu].coreisr[irq_index] |= irq_mask;
found = find_first_bit(s->cpu[cpu].sw_isr[ipnum], EXTIOI_IRQS);
set_bit(irq, s->cpu[cpu].sw_isr[ipnum]);
if (found < EXTIOI_IRQS) {
/* other irq is handling, need not update parent irq level */
return;
}
} else {
s->coreisr[cpu][irq_index] &= ~irq_mask;
clear_bit(irq, s->sw_isr[cpu][ipnum]);
found = find_first_bit(s->sw_isr[cpu][ipnum], EXTIOI_IRQS);
s->cpu[cpu].coreisr[irq_index] &= ~irq_mask;
clear_bit(irq, s->cpu[cpu].sw_isr[ipnum]);
found = find_first_bit(s->cpu[cpu].sw_isr[ipnum], EXTIOI_IRQS);
if (found < EXTIOI_IRQS) {
/* other irq is handling, need not update parent irq level */
return;
}
}
qemu_set_irq(s->parent_irq[cpu][ipnum], level);
qemu_set_irq(s->cpu[cpu].parent_irq[ipnum], level);
}
static void extioi_setirq(void *opaque, int irq, int level)
@ -96,7 +97,7 @@ static MemTxResult extioi_readw(void *opaque, hwaddr addr, uint64_t *data,
index = (offset - EXTIOI_COREISR_START) >> 2;
/* using attrs to get current cpu index */
cpu = attrs.requester_id;
*data = s->coreisr[cpu][index];
*data = s->cpu[cpu].coreisr[index];
break;
case EXTIOI_COREMAP_START ... EXTIOI_COREMAP_END - 1:
index = (offset - EXTIOI_COREMAP_START) >> 2;
@ -129,12 +130,66 @@ static inline void extioi_enable_irq(LoongArchExtIOI *s, int index,\
}
}
static inline void extioi_update_sw_coremap(LoongArchExtIOI *s, int irq,
uint64_t val, bool notify)
{
int i, cpu;
/*
* loongarch only support little endian,
* so we paresd the value with little endian.
*/
val = cpu_to_le64(val);
for (i = 0; i < 4; i++) {
cpu = val & 0xff;
cpu = ctz32(cpu);
cpu = (cpu >= 4) ? 0 : cpu;
val = val >> 8;
if (s->sw_coremap[irq + i] == cpu) {
continue;
}
if (notify && test_bit(irq, (unsigned long *)s->isr)) {
/*
* lower irq at old cpu and raise irq at new cpu
*/
extioi_update_irq(s, irq + i, 0);
s->sw_coremap[irq + i] = cpu;
extioi_update_irq(s, irq + i, 1);
} else {
s->sw_coremap[irq + i] = cpu;
}
}
}
static inline void extioi_update_sw_ipmap(LoongArchExtIOI *s, int index,
uint64_t val)
{
int i;
uint8_t ipnum;
/*
* loongarch only support little endian,
* so we paresd the value with little endian.
*/
val = cpu_to_le64(val);
for (i = 0; i < 4; i++) {
ipnum = val & 0xff;
ipnum = ctz32(ipnum);
ipnum = (ipnum >= 4) ? 0 : ipnum;
s->sw_ipmap[index * 4 + i] = ipnum;
val = val >> 8;
}
}
static MemTxResult extioi_writew(void *opaque, hwaddr addr,
uint64_t val, unsigned size,
MemTxAttrs attrs)
{
LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
int i, cpu, index, old_data, irq;
int cpu, index, old_data, irq;
uint32_t offset;
trace_loongarch_extioi_writew(addr, val);
@ -152,20 +207,7 @@ static MemTxResult extioi_writew(void *opaque, hwaddr addr,
*/
index = (offset - EXTIOI_IPMAP_START) >> 2;
s->ipmap[index] = val;
/*
* loongarch only support little endian,
* so we paresd the value with little endian.
*/
val = cpu_to_le64(val);
for (i = 0; i < 4; i++) {
uint8_t ipnum;
ipnum = val & 0xff;
ipnum = ctz32(ipnum);
ipnum = (ipnum >= 4) ? 0 : ipnum;
s->sw_ipmap[index * 4 + i] = ipnum;
val = val >> 8;
}
extioi_update_sw_ipmap(s, index, val);
break;
case EXTIOI_ENABLE_START ... EXTIOI_ENABLE_END - 1:
index = (offset - EXTIOI_ENABLE_START) >> 2;
@ -189,8 +231,8 @@ static MemTxResult extioi_writew(void *opaque, hwaddr addr,
index = (offset - EXTIOI_COREISR_START) >> 2;
/* using attrs to get current cpu index */
cpu = attrs.requester_id;
old_data = s->coreisr[cpu][index];
s->coreisr[cpu][index] = old_data & ~val;
old_data = s->cpu[cpu].coreisr[index];
s->cpu[cpu].coreisr[index] = old_data & ~val;
/* write 1 to clear interrupt */
old_data &= val;
irq = ctz32(old_data);
@ -204,33 +246,8 @@ static MemTxResult extioi_writew(void *opaque, hwaddr addr,
irq = offset - EXTIOI_COREMAP_START;
index = irq / 4;
s->coremap[index] = val;
/*
* loongarch only support little endian,
* so we paresd the value with little endian.
*/
val = cpu_to_le64(val);
for (i = 0; i < 4; i++) {
cpu = val & 0xff;
cpu = ctz32(cpu);
cpu = (cpu >= 4) ? 0 : cpu;
val = val >> 8;
if (s->sw_coremap[irq + i] == cpu) {
continue;
}
if (test_bit(irq, (unsigned long *)s->isr)) {
/*
* lower irq at old cpu and raise irq at new cpu
*/
extioi_update_irq(s, irq + i, 0);
s->sw_coremap[irq + i] = cpu;
extioi_update_irq(s, irq + i, 1);
} else {
s->sw_coremap[irq + i] = cpu;
}
}
extioi_update_sw_coremap(s, irq, val, true);
break;
default:
break;
@ -248,65 +265,112 @@ static const MemoryRegionOps extioi_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
static const VMStateDescription vmstate_loongarch_extioi = {
.name = TYPE_LOONGARCH_EXTIOI,
static void loongarch_extioi_realize(DeviceState *dev, Error **errp)
{
LoongArchExtIOI *s = LOONGARCH_EXTIOI(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
int i, pin;
if (s->num_cpu == 0) {
error_setg(errp, "num-cpu must be at least 1");
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);
s->cpu = g_new0(ExtIOICore, s->num_cpu);
if (s->cpu == NULL) {
error_setg(errp, "Memory allocation for ExtIOICore faile");
return;
}
for (i = 0; i < s->num_cpu; i++) {
for (pin = 0; pin < LS3A_INTC_IP; pin++) {
qdev_init_gpio_out(dev, &s->cpu[i].parent_irq[pin], 1);
}
}
}
static void loongarch_extioi_finalize(Object *obj)
{
LoongArchExtIOI *s = LOONGARCH_EXTIOI(obj);
g_free(s->cpu);
}
static int vmstate_extioi_post_load(void *opaque, int version_id)
{
LoongArchExtIOI *s = LOONGARCH_EXTIOI(opaque);
int i, start_irq;
for (i = 0; i < (EXTIOI_IRQS / 4); i++) {
start_irq = i * 4;
extioi_update_sw_coremap(s, start_irq, s->coremap[i], false);
}
for (i = 0; i < (EXTIOI_IRQS_IPMAP_SIZE / 4); i++) {
extioi_update_sw_ipmap(s, i, s->ipmap[i]);
}
return 0;
}
static const VMStateDescription vmstate_extioi_core = {
.name = "extioi-core",
.version_id = 1,
.minimum_version_id = 1,
.fields = (const VMStateField[]) {
VMSTATE_UINT32_ARRAY(coreisr, ExtIOICore, EXTIOI_IRQS_GROUP_COUNT),
VMSTATE_END_OF_LIST()
}
};
static const VMStateDescription vmstate_loongarch_extioi = {
.name = TYPE_LOONGARCH_EXTIOI,
.version_id = 2,
.minimum_version_id = 2,
.post_load = vmstate_extioi_post_load,
.fields = (const VMStateField[]) {
VMSTATE_UINT32_ARRAY(bounce, LoongArchExtIOI, EXTIOI_IRQS_GROUP_COUNT),
VMSTATE_UINT32_2DARRAY(coreisr, LoongArchExtIOI, EXTIOI_CPUS,
EXTIOI_IRQS_GROUP_COUNT),
VMSTATE_UINT32_ARRAY(nodetype, LoongArchExtIOI,
EXTIOI_IRQS_NODETYPE_COUNT / 2),
VMSTATE_UINT32_ARRAY(enable, LoongArchExtIOI, EXTIOI_IRQS / 32),
VMSTATE_UINT32_ARRAY(isr, LoongArchExtIOI, EXTIOI_IRQS / 32),
VMSTATE_UINT32_ARRAY(ipmap, LoongArchExtIOI, EXTIOI_IRQS_IPMAP_SIZE / 4),
VMSTATE_UINT32_ARRAY(coremap, LoongArchExtIOI, EXTIOI_IRQS / 4),
VMSTATE_UINT8_ARRAY(sw_ipmap, LoongArchExtIOI, EXTIOI_IRQS_IPMAP_SIZE),
VMSTATE_UINT8_ARRAY(sw_coremap, LoongArchExtIOI, EXTIOI_IRQS),
VMSTATE_STRUCT_VARRAY_POINTER_UINT32(cpu, LoongArchExtIOI, num_cpu,
vmstate_extioi_core, ExtIOICore),
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(dev, &s->irq[i]);
}
qdev_init_gpio_in(DEVICE(obj), extioi_setirq, EXTIOI_IRQS);
for (cpu = 0; cpu < EXTIOI_CPUS; cpu++) {
memory_region_init_io(&s->extioi_iocsr_mem[cpu], OBJECT(s), &extioi_ops,
s, "extioi_iocsr", 0x900);
sysbus_init_mmio(dev, &s->extioi_iocsr_mem[cpu]);
for (pin = 0; pin < LS3A_INTC_IP; pin++) {
qdev_init_gpio_out(DEVICE(obj), &s->parent_irq[cpu][pin], 1);
}
}
memory_region_init_io(&s->extioi_system_mem, OBJECT(s), &extioi_ops,
s, "extioi_system_mem", 0x900);
sysbus_init_mmio(dev, &s->extioi_system_mem);
}
static Property extioi_properties[] = {
DEFINE_PROP_UINT32("num-cpu", LoongArchExtIOI, num_cpu, 1),
DEFINE_PROP_END_OF_LIST(),
};
static void loongarch_extioi_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = loongarch_extioi_realize;
device_class_set_props(dc, extioi_properties);
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,
.instance_finalize = loongarch_extioi_finalize,
};
static void loongarch_extioi_register_types(void)

View File

@ -9,6 +9,7 @@
#include "hw/sysbus.h"
#include "hw/intc/loongarch_ipi.h"
#include "hw/irq.h"
#include "hw/qdev-properties.h"
#include "qapi/error.h"
#include "qemu/log.h"
#include "exec/address-spaces.h"
@ -17,14 +18,16 @@
#include "target/loongarch/internals.h"
#include "trace.h"
static void loongarch_ipi_writel(void *, hwaddr, uint64_t, unsigned);
static uint64_t loongarch_ipi_readl(void *opaque, hwaddr addr, unsigned size)
static MemTxResult loongarch_ipi_readl(void *opaque, hwaddr addr,
uint64_t *data,
unsigned size, MemTxAttrs attrs)
{
IPICore *s = opaque;
IPICore *s;
LoongArchIPI *ipi = opaque;
uint64_t ret = 0;
int index = 0;
s = &ipi->cpu[attrs.requester_id];
addr &= 0xff;
switch (addr) {
case CORE_STATUS_OFF:
@ -49,10 +52,12 @@ static uint64_t loongarch_ipi_readl(void *opaque, hwaddr addr, unsigned size)
}
trace_loongarch_ipi_read(size, (uint64_t)addr, ret);
return ret;
*data = ret;
return MEMTX_OK;
}
static void send_ipi_data(CPULoongArchState *env, uint64_t val, hwaddr addr)
static void send_ipi_data(CPULoongArchState *env, uint64_t val, hwaddr addr,
MemTxAttrs attrs)
{
int i, mask = 0, data = 0;
@ -61,8 +66,8 @@ static void send_ipi_data(CPULoongArchState *env, uint64_t val, hwaddr addr)
* if the mask is 0, we need not to do anything.
*/
if ((val >> 27) & 0xf) {
data = address_space_ldl(&env->address_space_iocsr, addr,
MEMTXATTRS_UNSPECIFIED, NULL);
data = address_space_ldl(env->address_space_iocsr, addr,
attrs, NULL);
for (i = 0; i < 4; i++) {
/* get mask for byte writing */
if (val & (0x1 << (27 + i))) {
@ -73,8 +78,8 @@ static void send_ipi_data(CPULoongArchState *env, uint64_t val, hwaddr addr)
data &= mask;
data |= (val >> 32) & ~mask;
address_space_stl(&env->address_space_iocsr, addr,
data, MEMTXATTRS_UNSPECIFIED, NULL);
address_space_stl(env->address_space_iocsr, addr,
data, attrs, NULL);
}
static int archid_cmp(const void *a, const void *b)
@ -103,80 +108,72 @@ static CPUState *ipi_getcpu(int arch_id)
CPUArchId *archid;
archid = find_cpu_by_archid(machine, arch_id);
return CPU(archid->cpu);
}
static void ipi_send(uint64_t val)
{
uint32_t cpuid;
uint8_t vector;
CPUState *cs;
LoongArchCPU *cpu;
LoongArchIPI *s;
cpuid = extract32(val, 16, 10);
if (cpuid >= LOONGARCH_MAX_CPUS) {
trace_loongarch_ipi_unsupported_cpuid("IOCSR_IPI_SEND", cpuid);
return;
if (archid) {
return CPU(archid->cpu);
}
/* IPI status vector */
vector = extract8(val, 0, 5);
cs = ipi_getcpu(cpuid);
cpu = LOONGARCH_CPU(cs);
s = LOONGARCH_IPI(cpu->env.ipistate);
loongarch_ipi_writel(&s->ipi_core, CORE_SET_OFF, BIT(vector), 4);
return NULL;
}
static void mail_send(uint64_t val)
static MemTxResult mail_send(uint64_t val, MemTxAttrs attrs)
{
uint32_t cpuid;
hwaddr addr;
CPULoongArchState *env;
CPUState *cs;
LoongArchCPU *cpu;
cpuid = extract32(val, 16, 10);
if (cpuid >= LOONGARCH_MAX_CPUS) {
trace_loongarch_ipi_unsupported_cpuid("IOCSR_MAIL_SEND", cpuid);
return;
return MEMTX_DECODE_ERROR;
}
addr = 0x1020 + (val & 0x1c);
cs = ipi_getcpu(cpuid);
cpu = LOONGARCH_CPU(cs);
env = &cpu->env;
send_ipi_data(env, val, addr);
if (cs == NULL) {
return MEMTX_DECODE_ERROR;
}
/* override requester_id */
addr = SMP_IPI_MAILBOX + CORE_BUF_20 + (val & 0x1c);
attrs.requester_id = cs->cpu_index;
send_ipi_data(&LOONGARCH_CPU(cs)->env, val, addr, attrs);
return MEMTX_OK;
}
static void any_send(uint64_t val)
static MemTxResult any_send(uint64_t val, MemTxAttrs attrs)
{
uint32_t cpuid;
hwaddr addr;
CPULoongArchState *env;
CPUState *cs;
LoongArchCPU *cpu;
cpuid = extract32(val, 16, 10);
if (cpuid >= LOONGARCH_MAX_CPUS) {
trace_loongarch_ipi_unsupported_cpuid("IOCSR_ANY_SEND", cpuid);
return;
return MEMTX_DECODE_ERROR;
}
addr = val & 0xffff;
cs = ipi_getcpu(cpuid);
cpu = LOONGARCH_CPU(cs);
env = &cpu->env;
send_ipi_data(env, val, addr);
if (cs == NULL) {
return MEMTX_DECODE_ERROR;
}
/* override requester_id */
addr = val & 0xffff;
attrs.requester_id = cs->cpu_index;
send_ipi_data(&LOONGARCH_CPU(cs)->env, val, addr, attrs);
return MEMTX_OK;
}
static void loongarch_ipi_writel(void *opaque, hwaddr addr, uint64_t val,
unsigned size)
static MemTxResult loongarch_ipi_writel(void *opaque, hwaddr addr, uint64_t val,
unsigned size, MemTxAttrs attrs)
{
IPICore *s = opaque;
LoongArchIPI *ipi = opaque;
IPICore *s;
int index = 0;
uint32_t cpuid;
uint8_t vector;
CPUState *cs;
s = &ipi->cpu[attrs.requester_id];
addr &= 0xff;
trace_loongarch_ipi_write(size, (uint64_t)addr, val);
switch (addr) {
@ -203,17 +200,34 @@ static void loongarch_ipi_writel(void *opaque, hwaddr addr, uint64_t val,
s->buf[index] = val;
break;
case IOCSR_IPI_SEND:
ipi_send(val);
cpuid = extract32(val, 16, 10);
if (cpuid >= LOONGARCH_MAX_CPUS) {
trace_loongarch_ipi_unsupported_cpuid("IOCSR_IPI_SEND", cpuid);
return MEMTX_DECODE_ERROR;
}
/* IPI status vector */
vector = extract8(val, 0, 5);
cs = ipi_getcpu(cpuid);
if (cs == NULL) {
return MEMTX_DECODE_ERROR;
}
/* override requester_id */
attrs.requester_id = cs->cpu_index;
loongarch_ipi_writel(ipi, CORE_SET_OFF, BIT(vector), 4, attrs);
break;
default:
qemu_log_mask(LOG_UNIMP, "invalid write: %x", (uint32_t)addr);
break;
}
return MEMTX_OK;
}
static const MemoryRegionOps loongarch_ipi_ops = {
.read = loongarch_ipi_readl,
.write = loongarch_ipi_writel,
.read_with_attrs = loongarch_ipi_readl,
.write_with_attrs = loongarch_ipi_writel,
.impl.min_access_size = 4,
.impl.max_access_size = 4,
.valid.min_access_size = 4,
@ -222,24 +236,28 @@ static const MemoryRegionOps loongarch_ipi_ops = {
};
/* mail send and any send only support writeq */
static void loongarch_ipi_writeq(void *opaque, hwaddr addr, uint64_t val,
unsigned size)
static MemTxResult loongarch_ipi_writeq(void *opaque, hwaddr addr, uint64_t val,
unsigned size, MemTxAttrs attrs)
{
MemTxResult ret = MEMTX_OK;
addr &= 0xfff;
switch (addr) {
case MAIL_SEND_OFFSET:
mail_send(val);
ret = mail_send(val, attrs);
break;
case ANY_SEND_OFFSET:
any_send(val);
ret = any_send(val, attrs);
break;
default:
break;
}
return ret;
}
static const MemoryRegionOps loongarch_ipi64_ops = {
.write = loongarch_ipi_writeq,
.write_with_attrs = loongarch_ipi_writeq,
.impl.min_access_size = 8,
.impl.max_access_size = 8,
.valid.min_access_size = 8,
@ -247,23 +265,39 @@ static const MemoryRegionOps loongarch_ipi64_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
static void loongarch_ipi_init(Object *obj)
static void loongarch_ipi_realize(DeviceState *dev, Error **errp)
{
LoongArchIPI *s = LOONGARCH_IPI(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
LoongArchIPI *s = LOONGARCH_IPI(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
int i;
memory_region_init_io(&s->ipi_iocsr_mem, obj, &loongarch_ipi_ops,
&s->ipi_core, "loongarch_ipi_iocsr", 0x48);
if (s->num_cpu == 0) {
error_setg(errp, "num-cpu must be at least 1");
return;
}
memory_region_init_io(&s->ipi_iocsr_mem, OBJECT(dev), &loongarch_ipi_ops,
s, "loongarch_ipi_iocsr", 0x48);
/* loongarch_ipi_iocsr performs re-entrant IO through ipi_send */
s->ipi_iocsr_mem.disable_reentrancy_guard = true;
sysbus_init_mmio(sbd, &s->ipi_iocsr_mem);
memory_region_init_io(&s->ipi64_iocsr_mem, obj, &loongarch_ipi64_ops,
&s->ipi_core, "loongarch_ipi64_iocsr", 0x118);
memory_region_init_io(&s->ipi64_iocsr_mem, OBJECT(dev),
&loongarch_ipi64_ops,
s, "loongarch_ipi64_iocsr", 0x118);
sysbus_init_mmio(sbd, &s->ipi64_iocsr_mem);
qdev_init_gpio_out(DEVICE(obj), &s->ipi_core.irq, 1);
s->cpu = g_new0(IPICore, s->num_cpu);
if (s->cpu == NULL) {
error_setg(errp, "Memory allocation for ExtIOICore faile");
return;
}
for (i = 0; i < s->num_cpu; i++) {
qdev_init_gpio_out(dev, &s->cpu[i].irq, 1);
}
}
static const VMStateDescription vmstate_ipi_core = {
@ -282,27 +316,42 @@ static const VMStateDescription vmstate_ipi_core = {
static const VMStateDescription vmstate_loongarch_ipi = {
.name = TYPE_LOONGARCH_IPI,
.version_id = 1,
.minimum_version_id = 1,
.version_id = 2,
.minimum_version_id = 2,
.fields = (const VMStateField[]) {
VMSTATE_STRUCT(ipi_core, LoongArchIPI, 0, vmstate_ipi_core, IPICore),
VMSTATE_STRUCT_VARRAY_POINTER_UINT32(cpu, LoongArchIPI, num_cpu,
vmstate_ipi_core, IPICore),
VMSTATE_END_OF_LIST()
}
};
static Property ipi_properties[] = {
DEFINE_PROP_UINT32("num-cpu", LoongArchIPI, num_cpu, 1),
DEFINE_PROP_END_OF_LIST(),
};
static void loongarch_ipi_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = loongarch_ipi_realize;
device_class_set_props(dc, ipi_properties);
dc->vmsd = &vmstate_loongarch_ipi;
}
static void loongarch_ipi_finalize(Object *obj)
{
LoongArchIPI *s = LOONGARCH_IPI(obj);
g_free(s->cpu);
}
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,
.instance_finalize = loongarch_ipi_finalize,
};
static void loongarch_ipi_register_types(void)

View File

@ -535,9 +535,6 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
CPUState *cpu_state;
int cpu, pin, i, start, num;
extioi = qdev_new(TYPE_LOONGARCH_EXTIOI);
sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi), &error_fatal);
/*
* The connection of interrupts:
* +-----+ +---------+ +-------+
@ -559,41 +556,42 @@ static void loongarch_irq_init(LoongArchMachineState *lams)
* | UARTs | | Devices | | Devices |
* +--------+ +---------+ +---------+
*/
/* Create IPI device */
ipi = qdev_new(TYPE_LOONGARCH_IPI);
qdev_prop_set_uint32(ipi, "num-cpu", ms->smp.cpus);
sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi), &error_fatal);
/* IPI iocsr memory region */
memory_region_add_subregion(&lams->system_iocsr, SMP_IPI_MAILBOX,
sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 0));
memory_region_add_subregion(&lams->system_iocsr, MAIL_SEND_ADDR,
sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi), 1));
for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
cpu_state = qemu_get_cpu(cpu);
cpudev = DEVICE(cpu_state);
lacpu = LOONGARCH_CPU(cpu_state);
env = &(lacpu->env);
ipi = qdev_new(TYPE_LOONGARCH_IPI);
sysbus_realize_and_unref(SYS_BUS_DEVICE(ipi), &error_fatal);
env->address_space_iocsr = &lams->as_iocsr;
/* connect ipi irq to cpu irq */
qdev_connect_gpio_out(ipi, 0, qdev_get_gpio_in(cpudev, IRQ_IPI));
/* IPI iocsr memory region */
memory_region_add_subregion(&env->system_iocsr, SMP_IPI_MAILBOX,
sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi),
0));
memory_region_add_subregion(&env->system_iocsr, MAIL_SEND_ADDR,
sysbus_mmio_get_region(SYS_BUS_DEVICE(ipi),
1));
/*
* extioi iocsr memory region
* only one extioi is added on loongarch virt machine
* external device interrupt can only be routed to cpu 0-3
*/
if (cpu < EXTIOI_CPUS)
memory_region_add_subregion(&env->system_iocsr, APIC_BASE,
sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi),
cpu));
qdev_connect_gpio_out(ipi, cpu, qdev_get_gpio_in(cpudev, IRQ_IPI));
env->ipistate = ipi;
}
/* Create EXTIOI device */
extioi = qdev_new(TYPE_LOONGARCH_EXTIOI);
qdev_prop_set_uint32(extioi, "num-cpu", ms->smp.cpus);
sysbus_realize_and_unref(SYS_BUS_DEVICE(extioi), &error_fatal);
memory_region_add_subregion(&lams->system_iocsr, APIC_BASE,
sysbus_mmio_get_region(SYS_BUS_DEVICE(extioi), 0));
/*
* connect ext irq to the cpu irq
* cpu_pin[9:2] <= intc_pin[7:0]
*/
for (cpu = 0; cpu < MIN(ms->smp.cpus, EXTIOI_CPUS); cpu++) {
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),
@ -733,6 +731,43 @@ static void loongarch_direct_kernel_boot(LoongArchMachineState *lams,
}
}
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)
{
switch (addr) {
case VERSION_REG:
return 0x11ULL;
case FEATURE_REG:
return 1ULL << IOCSRF_MSI | 1ULL << IOCSRF_EXTIOI |
1ULL << IOCSRF_CSRIPI;
case VENDOR_REG:
return 0x6e6f73676e6f6f4cULL; /* "Loongson" */
case CPUNAME_REG:
return 0x303030354133ULL; /* "3A5000" */
case MISC_FUNC_REG:
return 1ULL << IOCSRM_EXTIOI_EN;
}
return 0ULL;
}
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 = 8,
.max_access_size = 8,
},
};
static void loongarch_init(MachineState *machine)
{
LoongArchCPU *lacpu;
@ -761,8 +796,17 @@ static void loongarch_init(MachineState *machine)
exit(1);
}
create_fdt(lams);
/* Init CPUs */
/* Create IOCSR space */
memory_region_init_io(&lams->system_iocsr, OBJECT(machine), NULL,
machine, "iocsr", UINT64_MAX);
address_space_init(&lams->as_iocsr, &lams->system_iocsr, "IOCSR");
memory_region_init_io(&lams->iocsr_mem, OBJECT(machine),
&loongarch_qemu_ops,
machine, "iocsr_misc", 0x428);
memory_region_add_subregion(&lams->system_iocsr, 0, &lams->iocsr_mem);
/* Init CPUs */
possible_cpus = mc->possible_cpu_arch_ids(machine);
for (i = 0; i < possible_cpus->len; i++) {
cpu = cpu_create(machine->cpu_type);

View File

@ -40,25 +40,29 @@
#define EXTIOI_COREMAP_START (0xC00 - APIC_OFFSET)
#define EXTIOI_COREMAP_END (0xD00 - APIC_OFFSET)
typedef struct ExtIOICore {
uint32_t coreisr[EXTIOI_IRQS_GROUP_COUNT];
DECLARE_BITMAP(sw_isr[LS3A_INTC_IP], EXTIOI_IRQS);
qemu_irq parent_irq[LS3A_INTC_IP];
} ExtIOICore;
#define TYPE_LOONGARCH_EXTIOI "loongarch.extioi"
OBJECT_DECLARE_SIMPLE_TYPE(LoongArchExtIOI, LOONGARCH_EXTIOI)
struct LoongArchExtIOI {
SysBusDevice parent_obj;
uint32_t num_cpu;
/* hardware state */
uint32_t nodetype[EXTIOI_IRQS_NODETYPE_COUNT / 2];
uint32_t bounce[EXTIOI_IRQS_GROUP_COUNT];
uint32_t isr[EXTIOI_IRQS / 32];
uint32_t coreisr[EXTIOI_CPUS][EXTIOI_IRQS_GROUP_COUNT];
uint32_t enable[EXTIOI_IRQS / 32];
uint32_t ipmap[EXTIOI_IRQS_IPMAP_SIZE / 4];
uint32_t coremap[EXTIOI_IRQS / 4];
uint32_t sw_pending[EXTIOI_IRQS / 32];
DECLARE_BITMAP(sw_isr[EXTIOI_CPUS][LS3A_INTC_IP], EXTIOI_IRQS);
uint8_t sw_ipmap[EXTIOI_IRQS_IPMAP_SIZE];
uint8_t sw_coremap[EXTIOI_IRQS];
qemu_irq parent_irq[EXTIOI_CPUS][LS3A_INTC_IP];
qemu_irq irq[EXTIOI_IRQS];
MemoryRegion extioi_iocsr_mem[EXTIOI_CPUS];
ExtIOICore *cpu;
MemoryRegion extioi_system_mem;
};
#endif /* LOONGARCH_EXTIOI_H */

View File

@ -47,7 +47,8 @@ struct LoongArchIPI {
SysBusDevice parent_obj;
MemoryRegion ipi_iocsr_mem;
MemoryRegion ipi64_iocsr_mem;
IPICore ipi_core;
uint32_t num_cpu;
IPICore *cpu;
};
#endif

View File

@ -50,6 +50,9 @@ struct LoongArchMachineState {
DeviceState *platform_bus_dev;
PCIBus *pci_bus;
PFlashCFI01 *flash;
MemoryRegion system_iocsr;
MemoryRegion iocsr_mem;
AddressSpace as_iocsr;
};
#define TYPE_LOONGARCH_MACHINE MACHINE_TYPE_NAME("virt")

View File

@ -209,7 +209,7 @@
* - add FUSE_HAS_EXPIRE_ONLY
*
* 7.39
* - add FUSE_DIRECT_IO_RELAX
* - add FUSE_DIRECT_IO_ALLOW_MMAP
* - add FUSE_STATX and related structures
*/
@ -405,8 +405,7 @@ struct fuse_file_lock {
* FUSE_CREATE_SUPP_GROUP: add supplementary group info to create, mkdir,
* symlink and mknod (single group that matches parent)
* FUSE_HAS_EXPIRE_ONLY: kernel supports expiry-only entry invalidation
* FUSE_DIRECT_IO_RELAX: relax restrictions in FOPEN_DIRECT_IO mode, for now
* allow shared mmap
* FUSE_DIRECT_IO_ALLOW_MMAP: allow shared mmap in FOPEN_DIRECT_IO mode.
*/
#define FUSE_ASYNC_READ (1 << 0)
#define FUSE_POSIX_LOCKS (1 << 1)
@ -445,7 +444,10 @@ struct fuse_file_lock {
#define FUSE_HAS_INODE_DAX (1ULL << 33)
#define FUSE_CREATE_SUPP_GROUP (1ULL << 34)
#define FUSE_HAS_EXPIRE_ONLY (1ULL << 35)
#define FUSE_DIRECT_IO_RELAX (1ULL << 36)
#define FUSE_DIRECT_IO_ALLOW_MMAP (1ULL << 36)
/* Obsolete alias for FUSE_DIRECT_IO_ALLOW_MMAP */
#define FUSE_DIRECT_IO_RELAX FUSE_DIRECT_IO_ALLOW_MMAP
/**
* CUSE INIT request/reply flags

View File

@ -229,6 +229,8 @@ elif cpu in ['riscv32']
kvm_targets = ['riscv32-softmmu']
elif cpu in ['riscv64']
kvm_targets = ['riscv64-softmmu']
elif cpu in ['loongarch64']
kvm_targets = ['loongarch64-softmmu']
else
kvm_targets = []
endif
@ -3329,6 +3331,7 @@ if have_system or have_user
'target/hppa',
'target/i386',
'target/i386/kvm',
'target/loongarch',
'target/mips/tcg',
'target/nios2',
'target/ppc',

View File

@ -11,7 +11,9 @@
#include "qapi/error.h"
#include "qemu/module.h"
#include "sysemu/qtest.h"
#include "exec/cpu_ldst.h"
#include "sysemu/tcg.h"
#include "sysemu/kvm.h"
#include "kvm/kvm_loongarch.h"
#include "exec/exec-all.h"
#include "cpu.h"
#include "internals.h"
@ -20,8 +22,14 @@
#ifndef CONFIG_USER_ONLY
#include "sysemu/reset.h"
#endif
#include "tcg/tcg.h"
#include "vec.h"
#ifdef CONFIG_KVM
#include <linux/kvm.h>
#endif
#ifdef CONFIG_TCG
#include "exec/cpu_ldst.h"
#include "tcg/tcg.h"
#endif
const char * const regnames[32] = {
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
@ -110,12 +118,15 @@ void loongarch_cpu_set_irq(void *opaque, int irq, int level)
return;
}
env->CSR_ESTAT = deposit64(env->CSR_ESTAT, irq, 1, level != 0);
if (FIELD_EX64(env->CSR_ESTAT, CSR_ESTAT, IS)) {
cpu_interrupt(cs, CPU_INTERRUPT_HARD);
} else {
cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
if (kvm_enabled()) {
kvm_loongarch_set_interrupt(cpu, irq, level);
} else if (tcg_enabled()) {
env->CSR_ESTAT = deposit64(env->CSR_ESTAT, irq, 1, level != 0);
if (FIELD_EX64(env->CSR_ESTAT, CSR_ESTAT, IS)) {
cpu_interrupt(cs, CPU_INTERRUPT_HARD);
} else {
cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
}
}
}
@ -140,7 +151,10 @@ static inline bool cpu_loongarch_hw_interrupts_pending(CPULoongArchState *env)
return (pending & status) != 0;
}
#endif
#ifdef CONFIG_TCG
#ifndef CONFIG_USER_ONLY
static void loongarch_cpu_do_interrupt(CPUState *cs)
{
LoongArchCPU *cpu = LOONGARCH_CPU(cs);
@ -322,7 +336,6 @@ static bool loongarch_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
}
#endif
#ifdef CONFIG_TCG
static void loongarch_cpu_synchronize_from_tb(CPUState *cs,
const TranslationBlock *tb)
{
@ -518,10 +531,12 @@ static void loongarch_cpu_reset_hold(Object *obj)
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_CPUID = cs->cpu_index;
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);
env->CSR_TID = cs->cpu_index;
env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, TLB_TYPE, 2);
env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, MTLB_ENTRY, 63);
@ -538,9 +553,14 @@ static void loongarch_cpu_reset_hold(Object *obj)
#ifndef CONFIG_USER_ONLY
env->pc = 0x1c000000;
memset(env->tlb, 0, sizeof(env->tlb));
if (kvm_enabled()) {
kvm_arch_reset_vcpu(env);
}
#endif
#ifdef CONFIG_TCG
restore_fp_status(env);
#endif
cs->exception_index = -1;
}
@ -569,47 +589,6 @@ static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp)
lacc->parent_realize(dev, errp);
}
#ifndef CONFIG_USER_ONLY
static void loongarch_qemu_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
qemu_log_mask(LOG_UNIMP, "[%s]: Unimplemented reg 0x%" HWADDR_PRIx "\n",
__func__, addr);
}
static uint64_t loongarch_qemu_read(void *opaque, hwaddr addr, unsigned size)
{
switch (addr) {
case VERSION_REG:
return 0x11ULL;
case FEATURE_REG:
return 1ULL << IOCSRF_MSI | 1ULL << IOCSRF_EXTIOI |
1ULL << IOCSRF_CSRIPI;
case VENDOR_REG:
return 0x6e6f73676e6f6f4cULL; /* "Loongson" */
case CPUNAME_REG:
return 0x303030354133ULL; /* "3A5000" */
case MISC_FUNC_REG:
return 1ULL << IOCSRM_EXTIOI_EN;
}
return 0ULL;
}
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 = 8,
.max_access_size = 8,
},
};
#endif
static bool loongarch_get_lsx(Object *obj, Error **errp)
{
LoongArchCPU *cpu = LOONGARCH_CPU(obj);
@ -680,17 +659,12 @@ static void loongarch_cpu_init(Object *obj)
{
#ifndef CONFIG_USER_ONLY
LoongArchCPU *cpu = LOONGARCH_CPU(obj);
CPULoongArchState *env = &cpu->env;
qdev_init_gpio_in(DEVICE(cpu), loongarch_cpu_set_irq, N_IRQS);
#ifdef CONFIG_TCG
timer_init_ns(&cpu->timer, QEMU_CLOCK_VIRTUAL,
&loongarch_constant_timer_cb, cpu);
memory_region_init_io(&env->system_iocsr, OBJECT(cpu), NULL,
env, "iocsr", UINT64_MAX);
address_space_init(&env->address_space_iocsr, &env->system_iocsr, "IOCSR");
memory_region_init_io(&env->iocsr_mem, OBJECT(cpu), &loongarch_qemu_ops,
NULL, "iocsr_misc", 0x428);
memory_region_add_subregion(&env->system_iocsr, 0, &env->iocsr_mem);
#endif
#endif
}
@ -778,7 +752,9 @@ static struct TCGCPUOps loongarch_tcg_ops = {
#include "hw/core/sysemu-cpu-ops.h"
static const struct SysemuCPUOps loongarch_sysemu_ops = {
#ifdef CONFIG_TCG
.get_phys_page_debug = loongarch_cpu_get_phys_page_debug,
#endif
};
static int64_t loongarch_cpu_get_arch_id(CPUState *cs)

View File

@ -319,6 +319,7 @@ typedef struct CPUArchState {
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;
@ -350,16 +351,14 @@ typedef struct CPUArchState {
uint64_t CSR_DBG;
uint64_t CSR_DERA;
uint64_t CSR_DSAVE;
uint64_t CSR_CPUID;
#ifndef CONFIG_USER_ONLY
LoongArchTLB tlb[LOONGARCH_TLB_MAX];
AddressSpace address_space_iocsr;
MemoryRegion system_iocsr;
MemoryRegion iocsr_mem;
AddressSpace *address_space_iocsr;
bool load_elf;
uint64_t elf_address;
uint32_t mp_state;
/* Store ipistate to access from this struct */
DeviceState *ipistate;
#endif
@ -380,6 +379,8 @@ struct ArchCPU {
/* 'compatible' string for this CPU for Linux device trees */
const char *dtb_compatible;
/* used by KVM_REG_LOONGARCH_COUNTER ioctl to access guest time counters */
uint64_t kvm_state_counter;
};
/**

View File

@ -31,8 +31,10 @@ void G_NORETURN do_raise_exception(CPULoongArchState *env,
const char *loongarch_exception_name(int32_t exception);
#ifdef CONFIG_TCG
int ieee_ex_to_loongarch(int xcpt);
void restore_fp_status(CPULoongArchState *env);
#endif
#ifndef CONFIG_USER_ONLY
extern const VMStateDescription vmstate_loongarch_cpu;
@ -44,12 +46,13 @@ 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);
#ifdef CONFIG_TCG
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 /* !CONFIG_USER_ONLY */
uint64_t read_fcc(CPULoongArchState *env);

768
target/loongarch/kvm/kvm.c Normal file
View File

@ -0,0 +1,768 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* QEMU LoongArch KVM
*
* Copyright (c) 2023 Loongson Technology Corporation Limited
*/
#include "qemu/osdep.h"
#include <sys/ioctl.h>
#include <linux/kvm.h>
#include "qemu/timer.h"
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
#include "sysemu/sysemu.h"
#include "sysemu/kvm.h"
#include "sysemu/kvm_int.h"
#include "hw/pci/pci.h"
#include "exec/memattrs.h"
#include "exec/address-spaces.h"
#include "hw/boards.h"
#include "hw/irq.h"
#include "qemu/log.h"
#include "hw/loader.h"
#include "migration/migration.h"
#include "sysemu/runstate.h"
#include "cpu-csr.h"
#include "kvm_loongarch.h"
#include "trace.h"
static bool cap_has_mp_state;
const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
KVM_CAP_LAST_INFO
};
static int kvm_loongarch_get_regs_core(CPUState *cs)
{
int ret = 0;
int i;
struct kvm_regs regs;
LoongArchCPU *cpu = LOONGARCH_CPU(cs);
CPULoongArchState *env = &cpu->env;
/* Get the current register set as KVM seems it */
ret = kvm_vcpu_ioctl(cs, KVM_GET_REGS, &regs);
if (ret < 0) {
trace_kvm_failed_get_regs_core(strerror(errno));
return ret;
}
/* gpr[0] value is always 0 */
env->gpr[0] = 0;
for (i = 1; i < 32; i++) {
env->gpr[i] = regs.gpr[i];
}
env->pc = regs.pc;
return ret;
}
static int kvm_loongarch_put_regs_core(CPUState *cs)
{
int ret = 0;
int i;
struct kvm_regs regs;
LoongArchCPU *cpu = LOONGARCH_CPU(cs);
CPULoongArchState *env = &cpu->env;
/* Set the registers based on QEMU's view of things */
for (i = 0; i < 32; i++) {
regs.gpr[i] = env->gpr[i];
}
regs.pc = env->pc;
ret = kvm_vcpu_ioctl(cs, KVM_SET_REGS, &regs);
if (ret < 0) {
trace_kvm_failed_put_regs_core(strerror(errno));
}
return ret;
}
static int kvm_loongarch_get_csr(CPUState *cs)
{
int ret = 0;
LoongArchCPU *cpu = LOONGARCH_CPU(cs);
CPULoongArchState *env = &cpu->env;
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_CRMD),
&env->CSR_CRMD);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRMD),
&env->CSR_PRMD);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_EUEN),
&env->CSR_EUEN);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_MISC),
&env->CSR_MISC);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ECFG),
&env->CSR_ECFG);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ESTAT),
&env->CSR_ESTAT);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ERA),
&env->CSR_ERA);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_BADV),
&env->CSR_BADV);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_BADI),
&env->CSR_BADI);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_EENTRY),
&env->CSR_EENTRY);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBIDX),
&env->CSR_TLBIDX);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBEHI),
&env->CSR_TLBEHI);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBELO0),
&env->CSR_TLBELO0);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBELO1),
&env->CSR_TLBELO1);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ASID),
&env->CSR_ASID);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PGDL),
&env->CSR_PGDL);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PGDH),
&env->CSR_PGDH);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PGD),
&env->CSR_PGD);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PWCL),
&env->CSR_PWCL);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PWCH),
&env->CSR_PWCH);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_STLBPS),
&env->CSR_STLBPS);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_RVACFG),
&env->CSR_RVACFG);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_CPUID),
&env->CSR_CPUID);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRCFG1),
&env->CSR_PRCFG1);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRCFG2),
&env->CSR_PRCFG2);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRCFG3),
&env->CSR_PRCFG3);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(0)),
&env->CSR_SAVE[0]);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(1)),
&env->CSR_SAVE[1]);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(2)),
&env->CSR_SAVE[2]);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(3)),
&env->CSR_SAVE[3]);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(4)),
&env->CSR_SAVE[4]);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(5)),
&env->CSR_SAVE[5]);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(6)),
&env->CSR_SAVE[6]);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(7)),
&env->CSR_SAVE[7]);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TID),
&env->CSR_TID);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_CNTC),
&env->CSR_CNTC);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TICLR),
&env->CSR_TICLR);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_LLBCTL),
&env->CSR_LLBCTL);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_IMPCTL1),
&env->CSR_IMPCTL1);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_IMPCTL2),
&env->CSR_IMPCTL2);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRENTRY),
&env->CSR_TLBRENTRY);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRBADV),
&env->CSR_TLBRBADV);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRERA),
&env->CSR_TLBRERA);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRSAVE),
&env->CSR_TLBRSAVE);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRELO0),
&env->CSR_TLBRELO0);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRELO1),
&env->CSR_TLBRELO1);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBREHI),
&env->CSR_TLBREHI);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRPRMD),
&env->CSR_TLBRPRMD);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(0)),
&env->CSR_DMW[0]);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(1)),
&env->CSR_DMW[1]);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(2)),
&env->CSR_DMW[2]);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(3)),
&env->CSR_DMW[3]);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TVAL),
&env->CSR_TVAL);
ret |= kvm_get_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TCFG),
&env->CSR_TCFG);
return ret;
}
static int kvm_loongarch_put_csr(CPUState *cs)
{
int ret = 0;
LoongArchCPU *cpu = LOONGARCH_CPU(cs);
CPULoongArchState *env = &cpu->env;
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_CRMD),
&env->CSR_CRMD);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRMD),
&env->CSR_PRMD);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_EUEN),
&env->CSR_EUEN);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_MISC),
&env->CSR_MISC);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ECFG),
&env->CSR_ECFG);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ESTAT),
&env->CSR_ESTAT);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ERA),
&env->CSR_ERA);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_BADV),
&env->CSR_BADV);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_BADI),
&env->CSR_BADI);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_EENTRY),
&env->CSR_EENTRY);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBIDX),
&env->CSR_TLBIDX);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBEHI),
&env->CSR_TLBEHI);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBELO0),
&env->CSR_TLBELO0);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBELO1),
&env->CSR_TLBELO1);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_ASID),
&env->CSR_ASID);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PGDL),
&env->CSR_PGDL);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PGDH),
&env->CSR_PGDH);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PGD),
&env->CSR_PGD);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PWCL),
&env->CSR_PWCL);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PWCH),
&env->CSR_PWCH);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_STLBPS),
&env->CSR_STLBPS);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_RVACFG),
&env->CSR_RVACFG);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_CPUID),
&env->CSR_CPUID);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRCFG1),
&env->CSR_PRCFG1);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRCFG2),
&env->CSR_PRCFG2);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_PRCFG3),
&env->CSR_PRCFG3);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(0)),
&env->CSR_SAVE[0]);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(1)),
&env->CSR_SAVE[1]);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(2)),
&env->CSR_SAVE[2]);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(3)),
&env->CSR_SAVE[3]);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(4)),
&env->CSR_SAVE[4]);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(5)),
&env->CSR_SAVE[5]);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(6)),
&env->CSR_SAVE[6]);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_SAVE(7)),
&env->CSR_SAVE[7]);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TID),
&env->CSR_TID);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_CNTC),
&env->CSR_CNTC);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TICLR),
&env->CSR_TICLR);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_LLBCTL),
&env->CSR_LLBCTL);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_IMPCTL1),
&env->CSR_IMPCTL1);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_IMPCTL2),
&env->CSR_IMPCTL2);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRENTRY),
&env->CSR_TLBRENTRY);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRBADV),
&env->CSR_TLBRBADV);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRERA),
&env->CSR_TLBRERA);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRSAVE),
&env->CSR_TLBRSAVE);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRELO0),
&env->CSR_TLBRELO0);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRELO1),
&env->CSR_TLBRELO1);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBREHI),
&env->CSR_TLBREHI);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TLBRPRMD),
&env->CSR_TLBRPRMD);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(0)),
&env->CSR_DMW[0]);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(1)),
&env->CSR_DMW[1]);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(2)),
&env->CSR_DMW[2]);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_DMW(3)),
&env->CSR_DMW[3]);
/*
* timer cfg must be put at last since it is used to enable
* guest timer
*/
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TVAL),
&env->CSR_TVAL);
ret |= kvm_set_one_reg(cs, KVM_IOC_CSRID(LOONGARCH_CSR_TCFG),
&env->CSR_TCFG);
return ret;
}
static int kvm_loongarch_get_regs_fp(CPUState *cs)
{
int ret, i;
struct kvm_fpu fpu;
LoongArchCPU *cpu = LOONGARCH_CPU(cs);
CPULoongArchState *env = &cpu->env;
ret = kvm_vcpu_ioctl(cs, KVM_GET_FPU, &fpu);
if (ret < 0) {
trace_kvm_failed_get_fpu(strerror(errno));
return ret;
}
env->fcsr0 = fpu.fcsr;
for (i = 0; i < 32; i++) {
env->fpr[i].vreg.UD[0] = fpu.fpr[i].val64[0];
}
for (i = 0; i < 8; i++) {
env->cf[i] = fpu.fcc & 0xFF;
fpu.fcc = fpu.fcc >> 8;
}
return ret;
}
static int kvm_loongarch_put_regs_fp(CPUState *cs)
{
int ret, i;
struct kvm_fpu fpu;
LoongArchCPU *cpu = LOONGARCH_CPU(cs);
CPULoongArchState *env = &cpu->env;
fpu.fcsr = env->fcsr0;
fpu.fcc = 0;
for (i = 0; i < 32; i++) {
fpu.fpr[i].val64[0] = env->fpr[i].vreg.UD[0];
}
for (i = 0; i < 8; i++) {
fpu.fcc |= env->cf[i] << (8 * i);
}
ret = kvm_vcpu_ioctl(cs, KVM_SET_FPU, &fpu);
if (ret < 0) {
trace_kvm_failed_put_fpu(strerror(errno));
}
return ret;
}
void kvm_arch_reset_vcpu(CPULoongArchState *env)
{
env->mp_state = KVM_MP_STATE_RUNNABLE;
}
static int kvm_loongarch_get_mpstate(CPUState *cs)
{
int ret = 0;
struct kvm_mp_state mp_state;
LoongArchCPU *cpu = LOONGARCH_CPU(cs);
CPULoongArchState *env = &cpu->env;
if (cap_has_mp_state) {
ret = kvm_vcpu_ioctl(cs, KVM_GET_MP_STATE, &mp_state);
if (ret) {
trace_kvm_failed_get_mpstate(strerror(errno));
return ret;
}
env->mp_state = mp_state.mp_state;
}
return ret;
}
static int kvm_loongarch_put_mpstate(CPUState *cs)
{
int ret = 0;
LoongArchCPU *cpu = LOONGARCH_CPU(cs);
CPULoongArchState *env = &cpu->env;
struct kvm_mp_state mp_state = {
.mp_state = env->mp_state
};
if (cap_has_mp_state) {
ret = kvm_vcpu_ioctl(cs, KVM_SET_MP_STATE, &mp_state);
if (ret) {
trace_kvm_failed_put_mpstate(strerror(errno));
}
}
return ret;
}
static int kvm_loongarch_get_cpucfg(CPUState *cs)
{
int i, ret = 0;
uint64_t val;
LoongArchCPU *cpu = LOONGARCH_CPU(cs);
CPULoongArchState *env = &cpu->env;
for (i = 0; i < 21; i++) {
ret = kvm_get_one_reg(cs, KVM_IOC_CPUCFG(i), &val);
if (ret < 0) {
trace_kvm_failed_get_cpucfg(strerror(errno));
}
env->cpucfg[i] = (uint32_t)val;
}
return ret;
}
static int kvm_loongarch_put_cpucfg(CPUState *cs)
{
int i, ret = 0;
LoongArchCPU *cpu = LOONGARCH_CPU(cs);
CPULoongArchState *env = &cpu->env;
uint64_t val;
for (i = 0; i < 21; i++) {
val = env->cpucfg[i];
/* LSX and LASX and LBT are not supported in kvm now */
if (i == 2) {
val &= ~(BIT(R_CPUCFG2_LSX_SHIFT) | BIT(R_CPUCFG2_LASX_SHIFT));
val &= ~(BIT(R_CPUCFG2_LBT_X86_SHIFT) |
BIT(R_CPUCFG2_LBT_ARM_SHIFT) |
BIT(R_CPUCFG2_LBT_MIPS_SHIFT));
}
ret = kvm_set_one_reg(cs, KVM_IOC_CPUCFG(i), &val);
if (ret < 0) {
trace_kvm_failed_put_cpucfg(strerror(errno));
}
}
return ret;
}
int kvm_arch_get_registers(CPUState *cs)
{
int ret;
ret = kvm_loongarch_get_regs_core(cs);
if (ret) {
return ret;
}
ret = kvm_loongarch_get_csr(cs);
if (ret) {
return ret;
}
ret = kvm_loongarch_get_regs_fp(cs);
if (ret) {
return ret;
}
ret = kvm_loongarch_get_mpstate(cs);
if (ret) {
return ret;
}
ret = kvm_loongarch_get_cpucfg(cs);
return ret;
}
int kvm_arch_put_registers(CPUState *cs, int level)
{
int ret;
ret = kvm_loongarch_put_regs_core(cs);
if (ret) {
return ret;
}
ret = kvm_loongarch_put_csr(cs);
if (ret) {
return ret;
}
ret = kvm_loongarch_put_regs_fp(cs);
if (ret) {
return ret;
}
ret = kvm_loongarch_put_mpstate(cs);
if (ret) {
return ret;
}
ret = kvm_loongarch_put_cpucfg(cs);
return ret;
}
static void kvm_loongarch_vm_stage_change(void *opaque, bool running,
RunState state)
{
int ret;
CPUState *cs = opaque;
LoongArchCPU *cpu = LOONGARCH_CPU(cs);
if (running) {
ret = kvm_set_one_reg(cs, KVM_REG_LOONGARCH_COUNTER,
&cpu->kvm_state_counter);
if (ret < 0) {
trace_kvm_failed_put_counter(strerror(errno));
}
} else {
ret = kvm_get_one_reg(cs, KVM_REG_LOONGARCH_COUNTER,
&cpu->kvm_state_counter);
if (ret < 0) {
trace_kvm_failed_get_counter(strerror(errno));
}
}
}
int kvm_arch_init_vcpu(CPUState *cs)
{
qemu_add_vm_change_state_handler(kvm_loongarch_vm_stage_change, cs);
return 0;
}
int kvm_arch_destroy_vcpu(CPUState *cs)
{
return 0;
}
unsigned long kvm_arch_vcpu_id(CPUState *cs)
{
return cs->cpu_index;
}
int kvm_arch_release_virq_post(int virq)
{
return 0;
}
int kvm_arch_msi_data_to_gsi(uint32_t data)
{
abort();
}
int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route,
uint64_t address, uint32_t data, PCIDevice *dev)
{
return 0;
}
int kvm_arch_add_msi_route_post(struct kvm_irq_routing_entry *route,
int vector, PCIDevice *dev)
{
return 0;
}
void kvm_arch_init_irq_routing(KVMState *s)
{
}
int kvm_arch_get_default_type(MachineState *ms)
{
return 0;
}
int kvm_arch_init(MachineState *ms, KVMState *s)
{
cap_has_mp_state = kvm_check_extension(s, KVM_CAP_MP_STATE);
return 0;
}
int kvm_arch_irqchip_create(KVMState *s)
{
return 0;
}
void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run)
{
}
MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run)
{
return MEMTXATTRS_UNSPECIFIED;
}
int kvm_arch_process_async_events(CPUState *cs)
{
return cs->halted;
}
bool kvm_arch_stop_on_emulation_error(CPUState *cs)
{
return true;
}
bool kvm_arch_cpu_check_are_resettable(void)
{
return true;
}
int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
{
int ret = 0;
LoongArchCPU *cpu = LOONGARCH_CPU(cs);
CPULoongArchState *env = &cpu->env;
MemTxAttrs attrs = {};
attrs.requester_id = env_cpu(env)->cpu_index;
trace_kvm_arch_handle_exit(run->exit_reason);
switch (run->exit_reason) {
case KVM_EXIT_LOONGARCH_IOCSR:
address_space_rw(env->address_space_iocsr,
run->iocsr_io.phys_addr,
attrs,
run->iocsr_io.data,
run->iocsr_io.len,
run->iocsr_io.is_write);
break;
default:
ret = -1;
warn_report("KVM: unknown exit reason %d", run->exit_reason);
break;
}
return ret;
}
int kvm_loongarch_set_interrupt(LoongArchCPU *cpu, int irq, int level)
{
struct kvm_interrupt intr;
CPUState *cs = CPU(cpu);
if (level) {
intr.irq = irq;
} else {
intr.irq = -irq;
}
trace_kvm_set_intr(irq, level);
return kvm_vcpu_ioctl(cs, KVM_INTERRUPT, &intr);
}
void kvm_arch_accel_class_init(ObjectClass *oc)
{
}

View File

@ -0,0 +1,16 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* QEMU LoongArch kvm interface
*
* Copyright (c) 2023 Loongson Technology Corporation Limited
*/
#include "cpu.h"
#ifndef QEMU_KVM_LOONGARCH_H
#define QEMU_KVM_LOONGARCH_H
int kvm_loongarch_set_interrupt(LoongArchCPU *cpu, int irq, int level);
void kvm_arch_reset_vcpu(CPULoongArchState *env);
#endif

View File

@ -0,0 +1 @@
loongarch_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c'))

View File

@ -18,3 +18,4 @@ subdir('tcg')
target_arch += {'loongarch': loongarch_ss}
target_system_arch += {'loongarch': loongarch_system_ss}
subdir('kvm')

View File

@ -17,52 +17,52 @@
uint64_t helper_iocsrrd_b(CPULoongArchState *env, target_ulong r_addr)
{
return address_space_ldub(&env->address_space_iocsr, r_addr,
return address_space_ldub(env->address_space_iocsr, r_addr,
GET_MEMTXATTRS(env), NULL);
}
uint64_t helper_iocsrrd_h(CPULoongArchState *env, target_ulong r_addr)
{
return address_space_lduw(&env->address_space_iocsr, r_addr,
return address_space_lduw(env->address_space_iocsr, r_addr,
GET_MEMTXATTRS(env), NULL);
}
uint64_t helper_iocsrrd_w(CPULoongArchState *env, target_ulong r_addr)
{
return address_space_ldl(&env->address_space_iocsr, r_addr,
return address_space_ldl(env->address_space_iocsr, r_addr,
GET_MEMTXATTRS(env), NULL);
}
uint64_t helper_iocsrrd_d(CPULoongArchState *env, target_ulong r_addr)
{
return address_space_ldq(&env->address_space_iocsr, r_addr,
return address_space_ldq(env->address_space_iocsr, r_addr,
GET_MEMTXATTRS(env), NULL);
}
void helper_iocsrwr_b(CPULoongArchState *env, target_ulong w_addr,
target_ulong val)
{
address_space_stb(&env->address_space_iocsr, w_addr,
address_space_stb(env->address_space_iocsr, w_addr,
val, GET_MEMTXATTRS(env), NULL);
}
void helper_iocsrwr_h(CPULoongArchState *env, target_ulong w_addr,
target_ulong val)
{
address_space_stw(&env->address_space_iocsr, w_addr,
address_space_stw(env->address_space_iocsr, w_addr,
val, GET_MEMTXATTRS(env), NULL);
}
void helper_iocsrwr_w(CPULoongArchState *env, target_ulong w_addr,
target_ulong val)
{
address_space_stl(&env->address_space_iocsr, w_addr,
address_space_stl(env->address_space_iocsr, w_addr,
val, GET_MEMTXATTRS(env), NULL);
}
void helper_iocsrwr_d(CPULoongArchState *env, target_ulong w_addr,
target_ulong val)
{
address_space_stq(&env->address_space_iocsr, w_addr,
address_space_stq(env->address_space_iocsr, w_addr,
val, GET_MEMTXATTRS(env), NULL);
}

View File

@ -0,0 +1,15 @@
# See docs/devel/tracing.rst for syntax documentation.
#kvm.c
kvm_failed_get_regs_core(const char *msg) "Failed to get core regs from KVM: %s"
kvm_failed_put_regs_core(const char *msg) "Failed to put core regs into KVM: %s"
kvm_failed_get_fpu(const char *msg) "Failed to get fpu from KVM: %s"
kvm_failed_put_fpu(const char *msg) "Failed to put fpu into KVM: %s"
kvm_failed_get_mpstate(const char *msg) "Failed to get mp_state from KVM: %s"
kvm_failed_put_mpstate(const char *msg) "Failed to put mp_state into KVM: %s"
kvm_failed_get_counter(const char *msg) "Failed to get counter from KVM: %s"
kvm_failed_put_counter(const char *msg) "Failed to put counter into KVM: %s"
kvm_failed_get_cpucfg(const char *msg) "Failed to get cpucfg from KVM: %s"
kvm_failed_put_cpucfg(const char *msg) "Failed to put cpucfg into KVM: %s"
kvm_arch_handle_exit(int num) "kvm arch handle exit, the reason number: %d"
kvm_set_intr(int irq, int level) "kvm set interrupt, irq num: %d, level: %d"

1
target/loongarch/trace.h Normal file
View File

@ -0,0 +1 @@
#include "trace/trace-target_loongarch.h"