mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20140226' into staging
target-arm queue: * fixes for various Coverity-spotted bugs * support new KVM device control API for VGIC * support KVM VGIC save/restore/migration * more AArch64 system mode foundations * support ARMv8 CRC instructions for A32/T32 * PL330 minor fixes and cleanup # gpg: Signature made Wed 26 Feb 2014 17:51:32 GMT using RSA key ID 14360CDE # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" * remotes/pmaydell/tags/pull-target-arm-20140226: (45 commits) dma/pl330: implement dmaadnh instruction dma/pl330: Fix buffer depth dma/pl330: Add event debugging printfs dma/pl330: Rename parent_obj dma/pl330: printf format type sweep. dma/pl330: Fix misleading type dma/pl330: Delete overly verbose debug printf target-arm: Add support for AArch32 ARMv8 CRC32 instructions include/qemu/crc32c.h: Rename include guards to match filename target-arm: Add utility function for checking AA32/64 state of an EL target-arm: Implement AArch64 view of CPACR target-arm: A64: Implement MSR (immediate) instructions target-arm: Store AIF bits in env->pstate for AArch32 target-arm: A64: Implement WFI target-arm: Get MMU index information correct for A64 code target-arm: Implement AArch64 OSLAR_EL1 sysreg as WI target-arm: Implement AArch64 dummy breakpoint and watchpoint registers target-arm: Implement AArch64 ID and feature registers target-arm: Implement AArch64 generic timers target-arm: Implement AArch64 MPIDR ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
@@ -1657,7 +1657,7 @@ EOF
|
||||
"Make sure to have the zlib libs and headers installed."
|
||||
fi
|
||||
fi
|
||||
libs_softmmu="$libs_softmmu -lz"
|
||||
LIBS="$LIBS -lz"
|
||||
|
||||
##########################################
|
||||
# libseccomp check
|
||||
|
||||
+2
-2
@@ -477,7 +477,7 @@ int cpu_exec(CPUArchState *env)
|
||||
}
|
||||
#elif defined(TARGET_ARM)
|
||||
if (interrupt_request & CPU_INTERRUPT_FIQ
|
||||
&& !(env->uncached_cpsr & CPSR_F)) {
|
||||
&& !(env->daif & PSTATE_F)) {
|
||||
env->exception_index = EXCP_FIQ;
|
||||
cc->do_interrupt(cpu);
|
||||
next_tb = 0;
|
||||
@@ -493,7 +493,7 @@ int cpu_exec(CPUArchState *env)
|
||||
pc contains a magic address. */
|
||||
if (interrupt_request & CPU_INTERRUPT_HARD
|
||||
&& ((IS_M(env) && env->regs[15] < 0xfffffff0)
|
||||
|| !(env->uncached_cpsr & CPSR_I))) {
|
||||
|| !(env->daif & PSTATE_I))) {
|
||||
env->exception_index = EXCP_IRQ;
|
||||
cc->do_interrupt(cpu);
|
||||
next_tb = 0;
|
||||
|
||||
+2
-4
@@ -92,8 +92,6 @@
|
||||
#define MP_ETH_CRDP3 0x4AC
|
||||
#define MP_ETH_CTDP0 0x4E0
|
||||
#define MP_ETH_CTDP1 0x4E4
|
||||
#define MP_ETH_CTDP2 0x4E8
|
||||
#define MP_ETH_CTDP3 0x4EC
|
||||
|
||||
/* MII PHY access */
|
||||
#define MP_ETH_SMIR_DATA 0x0000FFFF
|
||||
@@ -308,7 +306,7 @@ static uint64_t mv88w8618_eth_read(void *opaque, hwaddr offset,
|
||||
case MP_ETH_CRDP0 ... MP_ETH_CRDP3:
|
||||
return s->rx_queue[(offset - MP_ETH_CRDP0)/4];
|
||||
|
||||
case MP_ETH_CTDP0 ... MP_ETH_CTDP3:
|
||||
case MP_ETH_CTDP0 ... MP_ETH_CTDP1:
|
||||
return s->tx_queue[(offset - MP_ETH_CTDP0)/4];
|
||||
|
||||
default:
|
||||
@@ -362,7 +360,7 @@ static void mv88w8618_eth_write(void *opaque, hwaddr offset,
|
||||
s->cur_rx[(offset - MP_ETH_CRDP0)/4] = value;
|
||||
break;
|
||||
|
||||
case MP_ETH_CTDP0 ... MP_ETH_CTDP3:
|
||||
case MP_ETH_CTDP0 ... MP_ETH_CTDP1:
|
||||
s->tx_queue[(offset - MP_ETH_CTDP0)/4] = value;
|
||||
break;
|
||||
}
|
||||
|
||||
+3
-3
@@ -272,11 +272,11 @@ static void pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
goto message;
|
||||
|
||||
case 3:
|
||||
s->cpu->env.uncached_cpsr =
|
||||
ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I;
|
||||
s->cpu->env.uncached_cpsr = ARM_CPU_MODE_SVC;
|
||||
s->cpu->env.daif = PSTATE_A | PSTATE_F | PSTATE_I;
|
||||
s->cpu->env.cp15.c1_sys = 0;
|
||||
s->cpu->env.cp15.c1_coproc = 0;
|
||||
s->cpu->env.cp15.c2_base0 = 0;
|
||||
s->cpu->env.cp15.ttbr0_el1 = 0;
|
||||
s->cpu->env.cp15.c3 = 0;
|
||||
s->pm_regs[PSSR >> 2] |= 0x8; /* Set STS */
|
||||
s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */
|
||||
|
||||
+36
-19
@@ -227,7 +227,8 @@ static const VMStateDescription vmstate_pl330_queue = {
|
||||
};
|
||||
|
||||
struct PL330State {
|
||||
SysBusDevice busdev;
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion iomem;
|
||||
qemu_irq irq_abort;
|
||||
qemu_irq *irq;
|
||||
@@ -577,7 +578,7 @@ static inline void pl330_queue_remove_tagged(PL330Queue *s, uint8_t tag)
|
||||
|
||||
static inline void pl330_fault(PL330Chan *ch, uint32_t flags)
|
||||
{
|
||||
DB_PRINT("ch: %p, flags: %x\n", ch, flags);
|
||||
DB_PRINT("ch: %p, flags: %" PRIx32 "\n", ch, flags);
|
||||
ch->fault_type |= flags;
|
||||
if (ch->state == pl330_chan_fault) {
|
||||
return;
|
||||
@@ -600,10 +601,12 @@ static inline void pl330_fault(PL330Chan *ch, uint32_t flags)
|
||||
* LEN - number of elements in ARGS array
|
||||
*/
|
||||
|
||||
static void pl330_dmaaddh(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
|
||||
static void pl330_dmaadxh(PL330Chan *ch, uint8_t *args, bool ra, bool neg)
|
||||
{
|
||||
uint16_t im = (((uint16_t)args[1]) << 8) | ((uint16_t)args[0]);
|
||||
uint8_t ra = (opcode >> 1) & 1;
|
||||
uint32_t im = (args[1] << 8) | args[0];
|
||||
if (neg) {
|
||||
im |= 0xffffu << 16;
|
||||
}
|
||||
|
||||
if (ch->is_manager) {
|
||||
pl330_fault(ch, PL330_FAULT_UNDEF_INSTR);
|
||||
@@ -616,6 +619,16 @@ static void pl330_dmaaddh(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
|
||||
}
|
||||
}
|
||||
|
||||
static void pl330_dmaaddh(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
|
||||
{
|
||||
pl330_dmaadxh(ch, args, extract32(opcode, 1, 1), false);
|
||||
}
|
||||
|
||||
static void pl330_dmaadnh(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
|
||||
{
|
||||
pl330_dmaadxh(ch, args, extract32(opcode, 1, 1), true);
|
||||
}
|
||||
|
||||
static void pl330_dmaend(PL330Chan *ch, uint8_t opcode,
|
||||
uint8_t *args, int len)
|
||||
{
|
||||
@@ -723,7 +736,8 @@ static void pl330_dmald(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
|
||||
ch->stall = pl330_queue_put_insn(&ch->parent->read_queue, ch->src,
|
||||
size, num, inc, 0, ch->tag);
|
||||
if (!ch->stall) {
|
||||
DB_PRINT("channel:%d address:%08x size:%d num:%d %c\n",
|
||||
DB_PRINT("channel:%" PRId8 " address:%08" PRIx32 " size:%" PRIx32
|
||||
" num:%" PRId32 " %c\n",
|
||||
ch->tag, ch->src, size, num, inc ? 'Y' : 'N');
|
||||
ch->src += inc ? size * num - (ch->src & (size - 1)) : 0;
|
||||
}
|
||||
@@ -868,9 +882,10 @@ static void pl330_dmasev(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
|
||||
}
|
||||
if (ch->parent->inten & (1 << ev_id)) {
|
||||
ch->parent->int_status |= (1 << ev_id);
|
||||
DB_PRINT("event interrupt raised %d\n", ev_id);
|
||||
DB_PRINT("event interrupt raised %" PRId8 "\n", ev_id);
|
||||
qemu_irq_raise(ch->parent->irq[ev_id]);
|
||||
}
|
||||
DB_PRINT("event raised %" PRId8 "\n", ev_id);
|
||||
ch->parent->ev_status |= (1 << ev_id);
|
||||
}
|
||||
|
||||
@@ -895,7 +910,8 @@ static void pl330_dmast(PL330Chan *ch, uint8_t opcode, uint8_t *args, int len)
|
||||
ch->stall = pl330_queue_put_insn(&ch->parent->write_queue, ch->dst,
|
||||
size, num, inc, 0, ch->tag);
|
||||
if (!ch->stall) {
|
||||
DB_PRINT("channel:%d address:%08x size:%d num:%d %c\n",
|
||||
DB_PRINT("channel:%" PRId8 " address:%08" PRIx32 " size:%" PRIx32
|
||||
" num:%" PRId32 " %c\n",
|
||||
ch->tag, ch->dst, size, num, inc ? 'Y' : 'N');
|
||||
ch->dst += inc ? size * num - (ch->dst & (size - 1)) : 0;
|
||||
}
|
||||
@@ -972,6 +988,7 @@ static void pl330_dmawfe(PL330Chan *ch, uint8_t opcode,
|
||||
}
|
||||
}
|
||||
ch->parent->ev_status &= ~(1 << ev_id);
|
||||
DB_PRINT("event lowered %" PRIx8 "\n", ev_id);
|
||||
} else {
|
||||
ch->stall = 1;
|
||||
}
|
||||
@@ -1037,6 +1054,7 @@ static void pl330_dmawmb(PL330Chan *ch, uint8_t opcode,
|
||||
/* NULL terminated array of the instruction descriptions. */
|
||||
static const PL330InsnDesc insn_desc[] = {
|
||||
{ .opcode = 0x54, .opmask = 0xFD, .size = 3, .exec = pl330_dmaaddh, },
|
||||
{ .opcode = 0x5c, .opmask = 0xFD, .size = 3, .exec = pl330_dmaadnh, },
|
||||
{ .opcode = 0x00, .opmask = 0xFF, .size = 1, .exec = pl330_dmaend, },
|
||||
{ .opcode = 0x35, .opmask = 0xFF, .size = 2, .exec = pl330_dmaflushp, },
|
||||
{ .opcode = 0xA0, .opmask = 0xFD, .size = 6, .exec = pl330_dmago, },
|
||||
@@ -1108,7 +1126,6 @@ static int pl330_chan_exec(PL330Chan *ch)
|
||||
ch->state != pl330_chan_waiting_periph &&
|
||||
ch->state != pl330_chan_at_barrier &&
|
||||
ch->state != pl330_chan_waiting_event) {
|
||||
DB_PRINT("%d\n", ch->state);
|
||||
return 0;
|
||||
}
|
||||
ch->stall = 0;
|
||||
@@ -1155,7 +1172,7 @@ static int pl330_exec_cycle(PL330Chan *channel)
|
||||
|
||||
dma_memory_read(&address_space_memory, q->addr, buf, len);
|
||||
if (PL330_ERR_DEBUG > 1) {
|
||||
DB_PRINT("PL330 read from memory @%08x (size = %08x):\n",
|
||||
DB_PRINT("PL330 read from memory @%08" PRIx32 " (size = %08x):\n",
|
||||
q->addr, len);
|
||||
qemu_hexdump((char *)buf, stderr, "", len);
|
||||
}
|
||||
@@ -1187,8 +1204,8 @@ static int pl330_exec_cycle(PL330Chan *channel)
|
||||
if (fifo_res == PL330_FIFO_OK || q->z) {
|
||||
dma_memory_write(&address_space_memory, q->addr, buf, len);
|
||||
if (PL330_ERR_DEBUG > 1) {
|
||||
DB_PRINT("PL330 read from memory @%08x (size = %08x):\n",
|
||||
q->addr, len);
|
||||
DB_PRINT("PL330 read from memory @%08" PRIx32
|
||||
" (size = %08x):\n", q->addr, len);
|
||||
qemu_hexdump((char *)buf, stderr, "", len);
|
||||
}
|
||||
if (q->inc) {
|
||||
@@ -1277,7 +1294,7 @@ static void pl330_debug_exec(PL330State *s)
|
||||
args[2] = (s->dbg[1] >> 8) & 0xff;
|
||||
args[3] = (s->dbg[1] >> 16) & 0xff;
|
||||
args[4] = (s->dbg[1] >> 24) & 0xff;
|
||||
DB_PRINT("chan id: %d\n", chan_id);
|
||||
DB_PRINT("chan id: %" PRIx8 "\n", chan_id);
|
||||
if (s->dbg[0] & 1) {
|
||||
ch = &s->chan[chan_id];
|
||||
} else {
|
||||
@@ -1311,7 +1328,7 @@ static void pl330_iomem_write(void *opaque, hwaddr offset,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
PL330State *s = (PL330State *) opaque;
|
||||
uint32_t i;
|
||||
int i;
|
||||
|
||||
DB_PRINT("addr: %08x data: %08x\n", (unsigned)offset, (unsigned)value);
|
||||
|
||||
@@ -1467,8 +1484,8 @@ static inline uint32_t pl330_iomem_read_imp(void *opaque,
|
||||
static uint64_t pl330_iomem_read(void *opaque, hwaddr offset,
|
||||
unsigned size)
|
||||
{
|
||||
int ret = pl330_iomem_read_imp(opaque, offset);
|
||||
DB_PRINT("addr: %08x data: %08x\n", (unsigned)offset, ret);
|
||||
uint32_t ret = pl330_iomem_read_imp(opaque, offset);
|
||||
DB_PRINT("addr: %08" HWADDR_PRIx " data: %08" PRIx32 "\n", offset, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1554,7 +1571,7 @@ static void pl330_realize(DeviceState *dev, Error **errp)
|
||||
s->cfg[1] |= 5;
|
||||
break;
|
||||
default:
|
||||
error_setg(errp, "Bad value for i-cache_len property: %d\n",
|
||||
error_setg(errp, "Bad value for i-cache_len property: %" PRIx8 "\n",
|
||||
s->i_cache_len);
|
||||
return;
|
||||
}
|
||||
@@ -1589,7 +1606,7 @@ static void pl330_realize(DeviceState *dev, Error **errp)
|
||||
s->cfg[CFG_CRD] |= 0x4;
|
||||
break;
|
||||
default:
|
||||
error_setg(errp, "Bad value for data_width property: %d\n",
|
||||
error_setg(errp, "Bad value for data_width property: %" PRIx8 "\n",
|
||||
s->data_width);
|
||||
return;
|
||||
}
|
||||
@@ -1602,7 +1619,7 @@ static void pl330_realize(DeviceState *dev, Error **errp)
|
||||
|
||||
pl330_queue_init(&s->read_queue, s->rd_q_dep, s);
|
||||
pl330_queue_init(&s->write_queue, s->wr_q_dep, s);
|
||||
pl330_fifo_init(&s->fifo, s->data_buffer_dep);
|
||||
pl330_fifo_init(&s->fifo, s->data_width / 4 * s->data_buffer_dep);
|
||||
}
|
||||
|
||||
static Property pl330_properties[] = {
|
||||
|
||||
+442
-4
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* Copyright (c) 2012 Linaro Limited
|
||||
* Written by Peter Maydell
|
||||
* Save/Restore logic added by Christoffer Dall.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -23,6 +24,20 @@
|
||||
#include "kvm_arm.h"
|
||||
#include "gic_internal.h"
|
||||
|
||||
//#define DEBUG_GIC_KVM
|
||||
|
||||
#ifdef DEBUG_GIC_KVM
|
||||
static const int debug_gic_kvm = 1;
|
||||
#else
|
||||
static const int debug_gic_kvm = 0;
|
||||
#endif
|
||||
|
||||
#define DPRINTF(fmt, ...) do { \
|
||||
if (debug_gic_kvm) { \
|
||||
printf("arm_gic: " fmt , ## __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define TYPE_KVM_ARM_GIC "kvm-arm-gic"
|
||||
#define KVM_ARM_GIC(obj) \
|
||||
OBJECT_CHECK(GICState, (obj), TYPE_KVM_ARM_GIC)
|
||||
@@ -72,14 +87,419 @@ static void kvm_arm_gic_set_irq(void *opaque, int irq, int level)
|
||||
kvm_set_irq(kvm_state, kvm_irq, !!level);
|
||||
}
|
||||
|
||||
static bool kvm_arm_gic_can_save_restore(GICState *s)
|
||||
{
|
||||
return s->dev_fd >= 0;
|
||||
}
|
||||
|
||||
static void kvm_gic_access(GICState *s, int group, int offset,
|
||||
int cpu, uint32_t *val, bool write)
|
||||
{
|
||||
struct kvm_device_attr attr;
|
||||
int type;
|
||||
int err;
|
||||
|
||||
cpu = cpu & 0xff;
|
||||
|
||||
attr.flags = 0;
|
||||
attr.group = group;
|
||||
attr.attr = (((uint64_t)cpu << KVM_DEV_ARM_VGIC_CPUID_SHIFT) &
|
||||
KVM_DEV_ARM_VGIC_CPUID_MASK) |
|
||||
(((uint64_t)offset << KVM_DEV_ARM_VGIC_OFFSET_SHIFT) &
|
||||
KVM_DEV_ARM_VGIC_OFFSET_MASK);
|
||||
attr.addr = (uintptr_t)val;
|
||||
|
||||
if (write) {
|
||||
type = KVM_SET_DEVICE_ATTR;
|
||||
} else {
|
||||
type = KVM_GET_DEVICE_ATTR;
|
||||
}
|
||||
|
||||
err = kvm_device_ioctl(s->dev_fd, type, &attr);
|
||||
if (err < 0) {
|
||||
fprintf(stderr, "KVM_{SET/GET}_DEVICE_ATTR failed: %s\n",
|
||||
strerror(-err));
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void kvm_gicd_access(GICState *s, int offset, int cpu,
|
||||
uint32_t *val, bool write)
|
||||
{
|
||||
kvm_gic_access(s, KVM_DEV_ARM_VGIC_GRP_DIST_REGS,
|
||||
offset, cpu, val, write);
|
||||
}
|
||||
|
||||
static void kvm_gicc_access(GICState *s, int offset, int cpu,
|
||||
uint32_t *val, bool write)
|
||||
{
|
||||
kvm_gic_access(s, KVM_DEV_ARM_VGIC_GRP_CPU_REGS,
|
||||
offset, cpu, val, write);
|
||||
}
|
||||
|
||||
#define for_each_irq_reg(_ctr, _max_irq, _field_width) \
|
||||
for (_ctr = 0; _ctr < ((_max_irq) / (32 / (_field_width))); _ctr++)
|
||||
|
||||
/*
|
||||
* Translate from the in-kernel field for an IRQ value to/from the qemu
|
||||
* representation.
|
||||
*/
|
||||
typedef void (*vgic_translate_fn)(GICState *s, int irq, int cpu,
|
||||
uint32_t *field, bool to_kernel);
|
||||
|
||||
/* synthetic translate function used for clear/set registers to completely
|
||||
* clear a setting using a clear-register before setting the remaing bits
|
||||
* using a set-register */
|
||||
static void translate_clear(GICState *s, int irq, int cpu,
|
||||
uint32_t *field, bool to_kernel)
|
||||
{
|
||||
if (to_kernel) {
|
||||
*field = ~0;
|
||||
} else {
|
||||
/* does not make sense: qemu model doesn't use set/clear regs */
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void translate_enabled(GICState *s, int irq, int cpu,
|
||||
uint32_t *field, bool to_kernel)
|
||||
{
|
||||
int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK;
|
||||
|
||||
if (to_kernel) {
|
||||
*field = GIC_TEST_ENABLED(irq, cm);
|
||||
} else {
|
||||
if (*field & 1) {
|
||||
GIC_SET_ENABLED(irq, cm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void translate_pending(GICState *s, int irq, int cpu,
|
||||
uint32_t *field, bool to_kernel)
|
||||
{
|
||||
int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK;
|
||||
|
||||
if (to_kernel) {
|
||||
*field = gic_test_pending(s, irq, cm);
|
||||
} else {
|
||||
if (*field & 1) {
|
||||
GIC_SET_PENDING(irq, cm);
|
||||
/* TODO: Capture is level-line is held high in the kernel */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void translate_active(GICState *s, int irq, int cpu,
|
||||
uint32_t *field, bool to_kernel)
|
||||
{
|
||||
int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK;
|
||||
|
||||
if (to_kernel) {
|
||||
*field = GIC_TEST_ACTIVE(irq, cm);
|
||||
} else {
|
||||
if (*field & 1) {
|
||||
GIC_SET_ACTIVE(irq, cm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void translate_trigger(GICState *s, int irq, int cpu,
|
||||
uint32_t *field, bool to_kernel)
|
||||
{
|
||||
if (to_kernel) {
|
||||
*field = (GIC_TEST_EDGE_TRIGGER(irq)) ? 0x2 : 0x0;
|
||||
} else {
|
||||
if (*field & 0x2) {
|
||||
GIC_SET_EDGE_TRIGGER(irq);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void translate_priority(GICState *s, int irq, int cpu,
|
||||
uint32_t *field, bool to_kernel)
|
||||
{
|
||||
if (to_kernel) {
|
||||
*field = GIC_GET_PRIORITY(irq, cpu) & 0xff;
|
||||
} else {
|
||||
gic_set_priority(s, cpu, irq, *field & 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
static void translate_targets(GICState *s, int irq, int cpu,
|
||||
uint32_t *field, bool to_kernel)
|
||||
{
|
||||
if (to_kernel) {
|
||||
*field = s->irq_target[irq] & 0xff;
|
||||
} else {
|
||||
s->irq_target[irq] = *field & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
static void translate_sgisource(GICState *s, int irq, int cpu,
|
||||
uint32_t *field, bool to_kernel)
|
||||
{
|
||||
if (to_kernel) {
|
||||
*field = s->sgi_pending[irq][cpu] & 0xff;
|
||||
} else {
|
||||
s->sgi_pending[irq][cpu] = *field & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read a register group from the kernel VGIC */
|
||||
static void kvm_dist_get(GICState *s, uint32_t offset, int width,
|
||||
int maxirq, vgic_translate_fn translate_fn)
|
||||
{
|
||||
uint32_t reg;
|
||||
int i;
|
||||
int j;
|
||||
int irq;
|
||||
int cpu;
|
||||
int regsz = 32 / width; /* irqs per kernel register */
|
||||
uint32_t field;
|
||||
|
||||
for_each_irq_reg(i, maxirq, width) {
|
||||
irq = i * regsz;
|
||||
cpu = 0;
|
||||
while ((cpu < s->num_cpu && irq < GIC_INTERNAL) || cpu == 0) {
|
||||
kvm_gicd_access(s, offset, cpu, ®, false);
|
||||
for (j = 0; j < regsz; j++) {
|
||||
field = extract32(reg, j * width, width);
|
||||
translate_fn(s, irq + j, cpu, &field, false);
|
||||
}
|
||||
|
||||
cpu++;
|
||||
}
|
||||
offset += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write a register group to the kernel VGIC */
|
||||
static void kvm_dist_put(GICState *s, uint32_t offset, int width,
|
||||
int maxirq, vgic_translate_fn translate_fn)
|
||||
{
|
||||
uint32_t reg;
|
||||
int i;
|
||||
int j;
|
||||
int irq;
|
||||
int cpu;
|
||||
int regsz = 32 / width; /* irqs per kernel register */
|
||||
uint32_t field;
|
||||
|
||||
for_each_irq_reg(i, maxirq, width) {
|
||||
irq = i * regsz;
|
||||
cpu = 0;
|
||||
while ((cpu < s->num_cpu && irq < GIC_INTERNAL) || cpu == 0) {
|
||||
reg = 0;
|
||||
for (j = 0; j < regsz; j++) {
|
||||
translate_fn(s, irq + j, cpu, &field, true);
|
||||
reg = deposit32(reg, j * width, width, field);
|
||||
}
|
||||
kvm_gicd_access(s, offset, cpu, ®, true);
|
||||
|
||||
cpu++;
|
||||
}
|
||||
offset += 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void kvm_arm_gic_put(GICState *s)
|
||||
{
|
||||
/* TODO: there isn't currently a kernel interface to set the GIC state */
|
||||
uint32_t reg;
|
||||
int i;
|
||||
int cpu;
|
||||
int num_cpu;
|
||||
int num_irq;
|
||||
|
||||
if (!kvm_arm_gic_can_save_restore(s)) {
|
||||
DPRINTF("Cannot put kernel gic state, no kernel interface");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Note: We do the restore in a slightly different order than the save
|
||||
* (where the order doesn't matter and is simply ordered according to the
|
||||
* register offset values */
|
||||
|
||||
/*****************************************************************
|
||||
* Distributor State
|
||||
*/
|
||||
|
||||
/* s->enabled -> GICD_CTLR */
|
||||
reg = s->enabled;
|
||||
kvm_gicd_access(s, 0x0, 0, ®, true);
|
||||
|
||||
/* Sanity checking on GICD_TYPER and s->num_irq, s->num_cpu */
|
||||
kvm_gicd_access(s, 0x4, 0, ®, false);
|
||||
num_irq = ((reg & 0x1f) + 1) * 32;
|
||||
num_cpu = ((reg & 0xe0) >> 5) + 1;
|
||||
|
||||
if (num_irq < s->num_irq) {
|
||||
fprintf(stderr, "Restoring %u IRQs, but kernel supports max %d\n",
|
||||
s->num_irq, num_irq);
|
||||
abort();
|
||||
} else if (num_cpu != s->num_cpu) {
|
||||
fprintf(stderr, "Restoring %u CPU interfaces, kernel only has %d\n",
|
||||
s->num_cpu, num_cpu);
|
||||
/* Did we not create the VCPUs in the kernel yet? */
|
||||
abort();
|
||||
}
|
||||
|
||||
/* TODO: Consider checking compatibility with the IIDR ? */
|
||||
|
||||
/* irq_state[n].enabled -> GICD_ISENABLERn */
|
||||
kvm_dist_put(s, 0x180, 1, s->num_irq, translate_clear);
|
||||
kvm_dist_put(s, 0x100, 1, s->num_irq, translate_enabled);
|
||||
|
||||
/* s->irq_target[irq] -> GICD_ITARGETSRn
|
||||
* (restore targets before pending to ensure the pending state is set on
|
||||
* the appropriate CPU interfaces in the kernel) */
|
||||
kvm_dist_put(s, 0x800, 8, s->num_irq, translate_targets);
|
||||
|
||||
/* irq_state[n].pending + irq_state[n].level -> GICD_ISPENDRn */
|
||||
kvm_dist_put(s, 0x280, 1, s->num_irq, translate_clear);
|
||||
kvm_dist_put(s, 0x200, 1, s->num_irq, translate_pending);
|
||||
|
||||
/* irq_state[n].active -> GICD_ISACTIVERn */
|
||||
kvm_dist_put(s, 0x380, 1, s->num_irq, translate_clear);
|
||||
kvm_dist_put(s, 0x300, 1, s->num_irq, translate_active);
|
||||
|
||||
/* irq_state[n].trigger -> GICD_ICFRn */
|
||||
kvm_dist_put(s, 0xc00, 2, s->num_irq, translate_trigger);
|
||||
|
||||
/* s->priorityX[irq] -> ICD_IPRIORITYRn */
|
||||
kvm_dist_put(s, 0x400, 8, s->num_irq, translate_priority);
|
||||
|
||||
/* s->sgi_pending -> ICD_CPENDSGIRn */
|
||||
kvm_dist_put(s, 0xf10, 8, GIC_NR_SGIS, translate_clear);
|
||||
kvm_dist_put(s, 0xf20, 8, GIC_NR_SGIS, translate_sgisource);
|
||||
|
||||
|
||||
/*****************************************************************
|
||||
* CPU Interface(s) State
|
||||
*/
|
||||
|
||||
for (cpu = 0; cpu < s->num_cpu; cpu++) {
|
||||
/* s->cpu_enabled[cpu] -> GICC_CTLR */
|
||||
reg = s->cpu_enabled[cpu];
|
||||
kvm_gicc_access(s, 0x00, cpu, ®, true);
|
||||
|
||||
/* s->priority_mask[cpu] -> GICC_PMR */
|
||||
reg = (s->priority_mask[cpu] & 0xff);
|
||||
kvm_gicc_access(s, 0x04, cpu, ®, true);
|
||||
|
||||
/* s->bpr[cpu] -> GICC_BPR */
|
||||
reg = (s->bpr[cpu] & 0x7);
|
||||
kvm_gicc_access(s, 0x08, cpu, ®, true);
|
||||
|
||||
/* s->abpr[cpu] -> GICC_ABPR */
|
||||
reg = (s->abpr[cpu] & 0x7);
|
||||
kvm_gicc_access(s, 0x1c, cpu, ®, true);
|
||||
|
||||
/* s->apr[n][cpu] -> GICC_APRn */
|
||||
for (i = 0; i < 4; i++) {
|
||||
reg = s->apr[i][cpu];
|
||||
kvm_gicc_access(s, 0xd0 + i * 4, cpu, ®, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void kvm_arm_gic_get(GICState *s)
|
||||
{
|
||||
/* TODO: there isn't currently a kernel interface to get the GIC state */
|
||||
uint32_t reg;
|
||||
int i;
|
||||
int cpu;
|
||||
|
||||
if (!kvm_arm_gic_can_save_restore(s)) {
|
||||
DPRINTF("Cannot get kernel gic state, no kernel interface");
|
||||
return;
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
* Distributor State
|
||||
*/
|
||||
|
||||
/* GICD_CTLR -> s->enabled */
|
||||
kvm_gicd_access(s, 0x0, 0, ®, false);
|
||||
s->enabled = reg & 1;
|
||||
|
||||
/* Sanity checking on GICD_TYPER -> s->num_irq, s->num_cpu */
|
||||
kvm_gicd_access(s, 0x4, 0, ®, false);
|
||||
s->num_irq = ((reg & 0x1f) + 1) * 32;
|
||||
s->num_cpu = ((reg & 0xe0) >> 5) + 1;
|
||||
|
||||
if (s->num_irq > GIC_MAXIRQ) {
|
||||
fprintf(stderr, "Too many IRQs reported from the kernel: %d\n",
|
||||
s->num_irq);
|
||||
abort();
|
||||
}
|
||||
|
||||
/* GICD_IIDR -> ? */
|
||||
kvm_gicd_access(s, 0x8, 0, ®, false);
|
||||
|
||||
/* Verify no GROUP 1 interrupts configured in the kernel */
|
||||
for_each_irq_reg(i, s->num_irq, 1) {
|
||||
kvm_gicd_access(s, 0x80 + (i * 4), 0, ®, false);
|
||||
if (reg != 0) {
|
||||
fprintf(stderr, "Unsupported GICD_IGROUPRn value: %08x\n",
|
||||
reg);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear all the IRQ settings */
|
||||
for (i = 0; i < s->num_irq; i++) {
|
||||
memset(&s->irq_state[i], 0, sizeof(s->irq_state[0]));
|
||||
}
|
||||
|
||||
/* GICD_ISENABLERn -> irq_state[n].enabled */
|
||||
kvm_dist_get(s, 0x100, 1, s->num_irq, translate_enabled);
|
||||
|
||||
/* GICD_ISPENDRn -> irq_state[n].pending + irq_state[n].level */
|
||||
kvm_dist_get(s, 0x200, 1, s->num_irq, translate_pending);
|
||||
|
||||
/* GICD_ISACTIVERn -> irq_state[n].active */
|
||||
kvm_dist_get(s, 0x300, 1, s->num_irq, translate_active);
|
||||
|
||||
/* GICD_ICFRn -> irq_state[n].trigger */
|
||||
kvm_dist_get(s, 0xc00, 2, s->num_irq, translate_trigger);
|
||||
|
||||
/* GICD_IPRIORITYRn -> s->priorityX[irq] */
|
||||
kvm_dist_get(s, 0x400, 8, s->num_irq, translate_priority);
|
||||
|
||||
/* GICD_ITARGETSRn -> s->irq_target[irq] */
|
||||
kvm_dist_get(s, 0x800, 8, s->num_irq, translate_targets);
|
||||
|
||||
/* GICD_CPENDSGIRn -> s->sgi_pending */
|
||||
kvm_dist_get(s, 0xf10, 8, GIC_NR_SGIS, translate_sgisource);
|
||||
|
||||
|
||||
/*****************************************************************
|
||||
* CPU Interface(s) State
|
||||
*/
|
||||
|
||||
for (cpu = 0; cpu < s->num_cpu; cpu++) {
|
||||
/* GICC_CTLR -> s->cpu_enabled[cpu] */
|
||||
kvm_gicc_access(s, 0x00, cpu, ®, false);
|
||||
s->cpu_enabled[cpu] = (reg & 1);
|
||||
|
||||
/* GICC_PMR -> s->priority_mask[cpu] */
|
||||
kvm_gicc_access(s, 0x04, cpu, ®, false);
|
||||
s->priority_mask[cpu] = (reg & 0xff);
|
||||
|
||||
/* GICC_BPR -> s->bpr[cpu] */
|
||||
kvm_gicc_access(s, 0x08, cpu, ®, false);
|
||||
s->bpr[cpu] = (reg & 0x7);
|
||||
|
||||
/* GICC_ABPR -> s->abpr[cpu] */
|
||||
kvm_gicc_access(s, 0x1c, cpu, ®, false);
|
||||
s->abpr[cpu] = (reg & 0x7);
|
||||
|
||||
/* GICC_APRn -> s->apr[n][cpu] */
|
||||
for (i = 0; i < 4; i++) {
|
||||
kvm_gicc_access(s, 0xd0 + i * 4, cpu, ®, false);
|
||||
s->apr[i][cpu] = reg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void kvm_arm_gic_reset(DeviceState *dev)
|
||||
@@ -97,6 +517,7 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
|
||||
GICState *s = KVM_ARM_GIC(dev);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
KVMARMGICClass *kgc = KVM_ARM_GIC_GET_CLASS(s);
|
||||
int ret;
|
||||
|
||||
kgc->parent_realize(dev, errp);
|
||||
if (error_is_set(errp)) {
|
||||
@@ -119,13 +540,27 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
|
||||
for (i = 0; i < s->num_cpu; i++) {
|
||||
sysbus_init_irq(sbd, &s->parent_irq[i]);
|
||||
}
|
||||
|
||||
/* Try to create the device via the device control API */
|
||||
s->dev_fd = -1;
|
||||
ret = kvm_create_device(kvm_state, KVM_DEV_TYPE_ARM_VGIC_V2, false);
|
||||
if (ret >= 0) {
|
||||
s->dev_fd = ret;
|
||||
} else if (ret != -ENODEV && ret != -ENOTSUP) {
|
||||
error_setg_errno(errp, -ret, "error creating in-kernel VGIC");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Distributor */
|
||||
memory_region_init_reservation(&s->iomem, OBJECT(s),
|
||||
"kvm-gic_dist", 0x1000);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
kvm_arm_register_device(&s->iomem,
|
||||
(KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT)
|
||||
| KVM_VGIC_V2_ADDR_TYPE_DIST);
|
||||
| KVM_VGIC_V2_ADDR_TYPE_DIST,
|
||||
KVM_DEV_ARM_VGIC_GRP_ADDR,
|
||||
KVM_VGIC_V2_ADDR_TYPE_DIST,
|
||||
s->dev_fd);
|
||||
/* CPU interface for current core. Unlike arm_gic, we don't
|
||||
* provide the "interface for core #N" memory regions, because
|
||||
* cores with a VGIC don't have those.
|
||||
@@ -135,7 +570,10 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp)
|
||||
sysbus_init_mmio(sbd, &s->cpuiomem[0]);
|
||||
kvm_arm_register_device(&s->cpuiomem[0],
|
||||
(KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT)
|
||||
| KVM_VGIC_V2_ADDR_TYPE_CPU);
|
||||
| KVM_VGIC_V2_ADDR_TYPE_CPU,
|
||||
KVM_DEV_ARM_VGIC_GRP_ADDR,
|
||||
KVM_VGIC_V2_ADDR_TYPE_CPU,
|
||||
s->dev_fd);
|
||||
}
|
||||
|
||||
static void kvm_arm_gic_class_init(ObjectClass *klass, void *data)
|
||||
|
||||
@@ -418,7 +418,7 @@ static int exynos4210_combiner_init(SysBusDevice *sbd)
|
||||
qdev_init_gpio_in(dev, exynos4210_combiner_handler, IIC_NIRQ);
|
||||
|
||||
/* Connect SysBusDev irqs to device specific irqs */
|
||||
for (i = 0; i < IIC_NIRQ; i++) {
|
||||
for (i = 0; i < IIC_NGRP; i++) {
|
||||
sysbus_init_irq(sbd, &s->output_irq[i]);
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
#define GIC_SET_MODEL(irq) s->irq_state[irq].model = true
|
||||
#define GIC_CLEAR_MODEL(irq) s->irq_state[irq].model = false
|
||||
#define GIC_TEST_MODEL(irq) s->irq_state[irq].model
|
||||
#define GIC_SET_LEVEL(irq, cm) s->irq_state[irq].level = (cm)
|
||||
#define GIC_SET_LEVEL(irq, cm) s->irq_state[irq].level |= (cm)
|
||||
#define GIC_CLEAR_LEVEL(irq, cm) s->irq_state[irq].level &= ~(cm)
|
||||
#define GIC_TEST_LEVEL(irq, cm) ((s->irq_state[irq].level & (cm)) != 0)
|
||||
#define GIC_SET_EDGE_TRIGGER(irq) s->irq_state[irq].edge_trigger = true
|
||||
|
||||
@@ -276,7 +276,7 @@ static bool vexpress_cfgctrl_read(arm_sysctl_state *s, unsigned int dcc,
|
||||
}
|
||||
break;
|
||||
case SYS_CFG_OSC:
|
||||
if (site == SYS_CFG_SITE_MB && device < sizeof(s->mb_clock)) {
|
||||
if (site == SYS_CFG_SITE_MB && device < ARRAY_SIZE(s->mb_clock)) {
|
||||
/* motherboard clock */
|
||||
*val = s->mb_clock[device];
|
||||
return true;
|
||||
@@ -324,7 +324,7 @@ static bool vexpress_cfgctrl_write(arm_sysctl_state *s, unsigned int dcc,
|
||||
|
||||
switch (function) {
|
||||
case SYS_CFG_OSC:
|
||||
if (site == SYS_CFG_SITE_MB && device < sizeof(s->mb_clock)) {
|
||||
if (site == SYS_CFG_SITE_MB && device < ARRAY_SIZE(s->mb_clock)) {
|
||||
/* motherboard clock */
|
||||
s->mb_clock[device] = val;
|
||||
return true;
|
||||
|
||||
@@ -176,7 +176,8 @@ static uint64_t stellaris_enet_read(void *opaque, hwaddr offset,
|
||||
return val;
|
||||
case 0x14: /* IA0 */
|
||||
return s->conf.macaddr.a[0] | (s->conf.macaddr.a[1] << 8)
|
||||
| (s->conf.macaddr.a[2] << 16) | (s->conf.macaddr.a[3] << 24);
|
||||
| (s->conf.macaddr.a[2] << 16)
|
||||
| ((uint32_t)s->conf.macaddr.a[3] << 24);
|
||||
case 0x18: /* IA1 */
|
||||
return s->conf.macaddr.a[4] | (s->conf.macaddr.a[5] << 8);
|
||||
case 0x1c: /* THR */
|
||||
|
||||
@@ -320,6 +320,7 @@ static uint64_t icp_pit_read(void *opaque, hwaddr offset,
|
||||
n = offset >> 8;
|
||||
if (n > 2) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad timer %d\n", __func__, n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return arm_timer_read(s->timer[n], offset & 0xff);
|
||||
@@ -334,6 +335,7 @@ static void icp_pit_write(void *opaque, hwaddr offset,
|
||||
n = offset >> 8;
|
||||
if (n > 2) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad timer %d\n", __func__, n);
|
||||
return;
|
||||
}
|
||||
|
||||
arm_timer_write(s->timer[n], offset & 0xff, value);
|
||||
|
||||
@@ -104,6 +104,7 @@ typedef struct GICState {
|
||||
MemoryRegion cpuiomem[GIC_NCPU + 1]; /* CPU interfaces */
|
||||
uint32_t num_irq;
|
||||
uint32_t revision;
|
||||
int dev_fd; /* kvm device fd if backed by kvm vgic support */
|
||||
} GICState;
|
||||
|
||||
#define TYPE_ARM_GIC_COMMON "arm_gic_common"
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QEMU_CRC32_H
|
||||
#define QEMU_CRC32_H
|
||||
#ifndef QEMU_CRC32C_H
|
||||
#define QEMU_CRC32C_H
|
||||
|
||||
#include "qemu-common.h"
|
||||
|
||||
|
||||
@@ -194,6 +194,28 @@ int kvm_vm_ioctl(KVMState *s, int type, ...);
|
||||
|
||||
int kvm_vcpu_ioctl(CPUState *cpu, int type, ...);
|
||||
|
||||
/**
|
||||
* kvm_device_ioctl - call an ioctl on a kvm device
|
||||
* @fd: The KVM device file descriptor as returned from KVM_CREATE_DEVICE
|
||||
* @type: The device-ctrl ioctl number
|
||||
*
|
||||
* Returns: -errno on error, nonnegative on success
|
||||
*/
|
||||
int kvm_device_ioctl(int fd, int type, ...);
|
||||
|
||||
/**
|
||||
* kvm_create_device - create a KVM device for the device control API
|
||||
* @KVMState: The KVMState pointer
|
||||
* @type: The KVM device type (see Documentation/virtual/kvm/devices in the
|
||||
* kernel source)
|
||||
* @test: If true, only test if device can be created, but don't actually
|
||||
* create the device.
|
||||
*
|
||||
* Returns: -errno on error, nonnegative on success: @test ? 0 : device fd;
|
||||
*/
|
||||
int kvm_create_device(KVMState *s, uint64_t type, bool test);
|
||||
|
||||
|
||||
/* Arch specific hooks */
|
||||
|
||||
extern const KVMCapabilityInfo kvm_arch_required_capabilities[];
|
||||
@@ -319,4 +341,16 @@ int kvm_irqchip_remove_irqfd_notifier(KVMState *s, EventNotifier *n, int virq);
|
||||
void kvm_pc_gsi_handler(void *opaque, int n, int level);
|
||||
void kvm_pc_setup_irq_routing(bool pci_enabled);
|
||||
void kvm_init_irq_routing(KVMState *s);
|
||||
|
||||
/**
|
||||
* kvm_arch_irqchip_create:
|
||||
* @KVMState: The KVMState pointer
|
||||
*
|
||||
* Allow architectures to create an in-kernel irq chip themselves.
|
||||
*
|
||||
* Returns: < 0: error
|
||||
* 0: irq chip was not created
|
||||
* > 0: irq chip was created
|
||||
*/
|
||||
int kvm_arch_irqchip_create(KVMState *s);
|
||||
#endif
|
||||
|
||||
@@ -1298,10 +1298,17 @@ static int kvm_irqchip_create(KVMState *s)
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = kvm_vm_ioctl(s, KVM_CREATE_IRQCHIP);
|
||||
/* First probe and see if there's a arch-specific hook to create the
|
||||
* in-kernel irqchip for us */
|
||||
ret = kvm_arch_irqchip_create(s);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Create kernel irqchip failed\n");
|
||||
return ret;
|
||||
} else if (ret == 0) {
|
||||
ret = kvm_vm_ioctl(s, KVM_CREATE_IRQCHIP);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Create kernel irqchip failed\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
kvm_kernel_irqchip = true;
|
||||
@@ -1777,6 +1784,24 @@ int kvm_vcpu_ioctl(CPUState *cpu, int type, ...)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int kvm_device_ioctl(int fd, int type, ...)
|
||||
{
|
||||
int ret;
|
||||
void *arg;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, type);
|
||||
arg = va_arg(ap, void *);
|
||||
va_end(ap);
|
||||
|
||||
trace_kvm_device_ioctl(fd, type, arg);
|
||||
ret = ioctl(fd, type, arg);
|
||||
if (ret == -1) {
|
||||
ret = -errno;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int kvm_has_sync_mmu(void)
|
||||
{
|
||||
return kvm_check_extension(kvm_state, KVM_CAP_SYNC_MMU);
|
||||
@@ -2058,3 +2083,24 @@ int kvm_on_sigbus(int code, void *addr)
|
||||
{
|
||||
return kvm_arch_on_sigbus(code, addr);
|
||||
}
|
||||
|
||||
int kvm_create_device(KVMState *s, uint64_t type, bool test)
|
||||
{
|
||||
int ret;
|
||||
struct kvm_create_device create_dev;
|
||||
|
||||
create_dev.type = type;
|
||||
create_dev.fd = -1;
|
||||
create_dev.flags = test ? KVM_CREATE_DEVICE_TEST : 0;
|
||||
|
||||
if (!kvm_check_extension(s, KVM_CAP_DEVICE_CTRL)) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
ret = kvm_vm_ioctl(s, KVM_CREATE_DEVICE, &create_dev);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return test ? 0 : create_dev.fd;
|
||||
}
|
||||
|
||||
@@ -119,6 +119,26 @@ struct kvm_arch_memory_slot {
|
||||
#define KVM_REG_ARM_32_CRN_MASK 0x0000000000007800
|
||||
#define KVM_REG_ARM_32_CRN_SHIFT 11
|
||||
|
||||
#define ARM_CP15_REG_SHIFT_MASK(x,n) \
|
||||
(((x) << KVM_REG_ARM_ ## n ## _SHIFT) & KVM_REG_ARM_ ## n ## _MASK)
|
||||
|
||||
#define __ARM_CP15_REG(op1,crn,crm,op2) \
|
||||
(KVM_REG_ARM | (15 << KVM_REG_ARM_COPROC_SHIFT) | \
|
||||
ARM_CP15_REG_SHIFT_MASK(op1, OPC1) | \
|
||||
ARM_CP15_REG_SHIFT_MASK(crn, 32_CRN) | \
|
||||
ARM_CP15_REG_SHIFT_MASK(crm, CRM) | \
|
||||
ARM_CP15_REG_SHIFT_MASK(op2, 32_OPC2))
|
||||
|
||||
#define ARM_CP15_REG32(...) (__ARM_CP15_REG(__VA_ARGS__) | KVM_REG_SIZE_U32)
|
||||
|
||||
#define __ARM_CP15_REG64(op1,crm) \
|
||||
(__ARM_CP15_REG(op1, 0, crm, 0) | KVM_REG_SIZE_U64)
|
||||
#define ARM_CP15_REG64(...) __ARM_CP15_REG64(__VA_ARGS__)
|
||||
|
||||
#define KVM_REG_ARM_TIMER_CTL ARM_CP15_REG32(0, 14, 3, 1)
|
||||
#define KVM_REG_ARM_TIMER_CNT ARM_CP15_REG64(1, 14)
|
||||
#define KVM_REG_ARM_TIMER_CVAL ARM_CP15_REG64(3, 14)
|
||||
|
||||
/* Normal registers are mapped as coprocessor 16. */
|
||||
#define KVM_REG_ARM_CORE (0x0010 << KVM_REG_ARM_COPROC_SHIFT)
|
||||
#define KVM_REG_ARM_CORE_REG(name) (offsetof(struct kvm_regs, name) / 4)
|
||||
@@ -143,6 +163,14 @@ struct kvm_arch_memory_slot {
|
||||
#define KVM_REG_ARM_VFP_FPINST 0x1009
|
||||
#define KVM_REG_ARM_VFP_FPINST2 0x100A
|
||||
|
||||
/* Device Control API: ARM VGIC */
|
||||
#define KVM_DEV_ARM_VGIC_GRP_ADDR 0
|
||||
#define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1
|
||||
#define KVM_DEV_ARM_VGIC_GRP_CPU_REGS 2
|
||||
#define KVM_DEV_ARM_VGIC_CPUID_SHIFT 32
|
||||
#define KVM_DEV_ARM_VGIC_CPUID_MASK (0xffULL << KVM_DEV_ARM_VGIC_CPUID_SHIFT)
|
||||
#define KVM_DEV_ARM_VGIC_OFFSET_SHIFT 0
|
||||
#define KVM_DEV_ARM_VGIC_OFFSET_MASK (0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
|
||||
|
||||
/* KVM_IRQ_LINE irq field index values */
|
||||
#define KVM_ARM_IRQ_TYPE_SHIFT 24
|
||||
|
||||
@@ -55,8 +55,9 @@ struct kvm_regs {
|
||||
#define KVM_ARM_TARGET_AEM_V8 0
|
||||
#define KVM_ARM_TARGET_FOUNDATION_V8 1
|
||||
#define KVM_ARM_TARGET_CORTEX_A57 2
|
||||
#define KVM_ARM_TARGET_XGENE_POTENZA 3
|
||||
|
||||
#define KVM_ARM_NUM_TARGETS 3
|
||||
#define KVM_ARM_NUM_TARGETS 4
|
||||
|
||||
/* KVM_ARM_SET_DEVICE_ADDR ioctl id encoding */
|
||||
#define KVM_ARM_DEVICE_TYPE_SHIFT 0
|
||||
@@ -129,6 +130,33 @@ struct kvm_arch_memory_slot {
|
||||
#define KVM_REG_ARM64_SYSREG_OP2_MASK 0x0000000000000007
|
||||
#define KVM_REG_ARM64_SYSREG_OP2_SHIFT 0
|
||||
|
||||
#define ARM64_SYS_REG_SHIFT_MASK(x,n) \
|
||||
(((x) << KVM_REG_ARM64_SYSREG_ ## n ## _SHIFT) & \
|
||||
KVM_REG_ARM64_SYSREG_ ## n ## _MASK)
|
||||
|
||||
#define __ARM64_SYS_REG(op0,op1,crn,crm,op2) \
|
||||
(KVM_REG_ARM64 | KVM_REG_ARM64_SYSREG | \
|
||||
ARM64_SYS_REG_SHIFT_MASK(op0, OP0) | \
|
||||
ARM64_SYS_REG_SHIFT_MASK(op1, OP1) | \
|
||||
ARM64_SYS_REG_SHIFT_MASK(crn, CRN) | \
|
||||
ARM64_SYS_REG_SHIFT_MASK(crm, CRM) | \
|
||||
ARM64_SYS_REG_SHIFT_MASK(op2, OP2))
|
||||
|
||||
#define ARM64_SYS_REG(...) (__ARM64_SYS_REG(__VA_ARGS__) | KVM_REG_SIZE_U64)
|
||||
|
||||
#define KVM_REG_ARM_TIMER_CTL ARM64_SYS_REG(3, 3, 14, 3, 1)
|
||||
#define KVM_REG_ARM_TIMER_CNT ARM64_SYS_REG(3, 3, 14, 3, 2)
|
||||
#define KVM_REG_ARM_TIMER_CVAL ARM64_SYS_REG(3, 3, 14, 0, 2)
|
||||
|
||||
/* Device Control API: ARM VGIC */
|
||||
#define KVM_DEV_ARM_VGIC_GRP_ADDR 0
|
||||
#define KVM_DEV_ARM_VGIC_GRP_DIST_REGS 1
|
||||
#define KVM_DEV_ARM_VGIC_GRP_CPU_REGS 2
|
||||
#define KVM_DEV_ARM_VGIC_CPUID_SHIFT 32
|
||||
#define KVM_DEV_ARM_VGIC_CPUID_MASK (0xffULL << KVM_DEV_ARM_VGIC_CPUID_SHIFT)
|
||||
#define KVM_DEV_ARM_VGIC_OFFSET_SHIFT 0
|
||||
#define KVM_DEV_ARM_VGIC_OFFSET_MASK (0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
|
||||
|
||||
/* KVM_IRQ_LINE irq field index values */
|
||||
#define KVM_ARM_IRQ_TYPE_SHIFT 24
|
||||
#define KVM_ARM_IRQ_TYPE_MASK 0xff
|
||||
|
||||
@@ -545,6 +545,7 @@ struct kvm_get_htab_header {
|
||||
#define KVM_REG_PPC_TCSCR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb1)
|
||||
#define KVM_REG_PPC_PID (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb2)
|
||||
#define KVM_REG_PPC_ACOP (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb3)
|
||||
#define KVM_REG_PPC_WORT (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb4)
|
||||
|
||||
#define KVM_REG_PPC_VRSAVE (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb4)
|
||||
#define KVM_REG_PPC_LPCR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb5)
|
||||
@@ -553,6 +554,8 @@ struct kvm_get_htab_header {
|
||||
/* Architecture compatibility level */
|
||||
#define KVM_REG_PPC_ARCH_COMPAT (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb7)
|
||||
|
||||
#define KVM_REG_PPC_DABRX (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb8)
|
||||
|
||||
/* Transactional Memory checkpointed state:
|
||||
* This is all GPRs, all VSX regs and a subset of SPRs
|
||||
*/
|
||||
|
||||
@@ -28,6 +28,9 @@
|
||||
/* Partition Reference Counter (HV_X64_MSR_TIME_REF_COUNT) available*/
|
||||
#define HV_X64_MSR_TIME_REF_COUNT_AVAILABLE (1 << 1)
|
||||
|
||||
/* A partition's reference time stamp counter (TSC) page */
|
||||
#define HV_X64_MSR_REFERENCE_TSC 0x40000021
|
||||
|
||||
/*
|
||||
* There is a single feature flag that signifies the presence of the MSR
|
||||
* that can be used to retrieve both the local APIC Timer frequency as
|
||||
@@ -149,9 +152,6 @@
|
||||
/* MSR used to read the per-partition time reference counter */
|
||||
#define HV_X64_MSR_TIME_REF_COUNT 0x40000020
|
||||
|
||||
/* A partition's reference time stamp counter (TSC) page */
|
||||
#define HV_X64_MSR_REFERENCE_TSC 0x40000021
|
||||
|
||||
/* MSR used to retrieve the TSC frequency */
|
||||
#define HV_X64_MSR_TSC_FREQUENCY 0x40000022
|
||||
|
||||
@@ -201,6 +201,9 @@
|
||||
#define HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_MASK \
|
||||
(~((1ull << HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_SHIFT) - 1))
|
||||
|
||||
#define HV_X64_MSR_TSC_REFERENCE_ENABLE 0x00000001
|
||||
#define HV_X64_MSR_TSC_REFERENCE_ADDRESS_SHIFT 12
|
||||
|
||||
#define HV_PROCESSOR_POWER_STATE_C0 0
|
||||
#define HV_PROCESSOR_POWER_STATE_C1 1
|
||||
#define HV_PROCESSOR_POWER_STATE_C2 2
|
||||
@@ -213,4 +216,11 @@
|
||||
#define HV_STATUS_INVALID_ALIGNMENT 4
|
||||
#define HV_STATUS_INSUFFICIENT_BUFFERS 19
|
||||
|
||||
typedef struct _HV_REFERENCE_TSC_PAGE {
|
||||
__u32 tsc_sequence;
|
||||
__u32 res1;
|
||||
__u64 tsc_scale;
|
||||
__s64 tsc_offset;
|
||||
} HV_REFERENCE_TSC_PAGE, *PHV_REFERENCE_TSC_PAGE;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -854,6 +854,7 @@ struct kvm_device_attr {
|
||||
#define KVM_DEV_VFIO_GROUP 1
|
||||
#define KVM_DEV_VFIO_GROUP_ADD 1
|
||||
#define KVM_DEV_VFIO_GROUP_DEL 2
|
||||
#define KVM_DEV_TYPE_ARM_VGIC_V2 5
|
||||
|
||||
/*
|
||||
* ioctls for VM fds
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user