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:
commit
5429a82cf8
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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")
|
||||
|
@ -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
|
||||
|
@ -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',
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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
768
target/loongarch/kvm/kvm.c
Normal 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, ®s);
|
||||
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, ®s);
|
||||
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)
|
||||
{
|
||||
}
|
16
target/loongarch/kvm/kvm_loongarch.h
Normal file
16
target/loongarch/kvm/kvm_loongarch.h
Normal 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
|
1
target/loongarch/kvm/meson.build
Normal file
1
target/loongarch/kvm/meson.build
Normal file
@ -0,0 +1 @@
|
||||
loongarch_ss.add(when: 'CONFIG_KVM', if_true: files('kvm.c'))
|
@ -18,3 +18,4 @@ subdir('tcg')
|
||||
|
||||
target_arch += {'loongarch': loongarch_ss}
|
||||
target_system_arch += {'loongarch': loongarch_system_ss}
|
||||
subdir('kvm')
|
||||
|
@ -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);
|
||||
}
|
||||
|
15
target/loongarch/trace-events
Normal file
15
target/loongarch/trace-events
Normal 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
1
target/loongarch/trace.h
Normal file
@ -0,0 +1 @@
|
||||
#include "trace/trace-target_loongarch.h"
|
Loading…
Reference in New Issue
Block a user