Compare commits
26 Commits
qemu-2.1.2
...
vfio-pci-f
Author | SHA1 | Date | |
---|---|---|---|
|
9b3af4c0e4 | ||
|
c048be5cc9 | ||
|
69f87f7130 | ||
|
dbb1fb277c | ||
|
dcd82c118c | ||
|
cdcf14057d | ||
|
63b60551a7 | ||
|
f2c30f42f5 | ||
|
2f0180c51b | ||
|
f151b123a3 | ||
|
98ea5615ab | ||
|
9208b9617f | ||
|
9db11cef8c | ||
|
fab4693239 | ||
|
a9047ec3f6 | ||
|
cc11a0623a | ||
|
924c09db51 | ||
|
7b13ff3f15 | ||
|
32ce1b4817 | ||
|
c617dd3b7e | ||
|
1efd6e072c | ||
|
c79805802b | ||
|
b33a5bbfba | ||
|
8677de2b4d | ||
|
74bc41511a | ||
|
bb9c3636d9 |
@@ -417,8 +417,12 @@ static void do_cpu_reset(void *opaque)
|
||||
if (info) {
|
||||
if (!info->is_linux) {
|
||||
/* Jump to the entry point. */
|
||||
env->regs[15] = info->entry & 0xfffffffe;
|
||||
env->thumb = info->entry & 1;
|
||||
if (env->aarch64) {
|
||||
env->pc = info->entry;
|
||||
} else {
|
||||
env->regs[15] = info->entry & 0xfffffffe;
|
||||
env->thumb = info->entry & 1;
|
||||
}
|
||||
} else {
|
||||
if (CPU(cpu) == first_cpu) {
|
||||
if (env->aarch64) {
|
||||
|
@@ -98,17 +98,17 @@ typedef struct VirtBoardInfo {
|
||||
*/
|
||||
static const MemMapEntry a15memmap[] = {
|
||||
/* Space up to 0x8000000 is reserved for a boot ROM */
|
||||
[VIRT_FLASH] = { 0, 0x8000000 },
|
||||
[VIRT_CPUPERIPHS] = { 0x8000000, 0x20000 },
|
||||
[VIRT_FLASH] = { 0, 0x08000000 },
|
||||
[VIRT_CPUPERIPHS] = { 0x08000000, 0x00020000 },
|
||||
/* GIC distributor and CPU interfaces sit inside the CPU peripheral space */
|
||||
[VIRT_GIC_DIST] = { 0x8000000, 0x10000 },
|
||||
[VIRT_GIC_CPU] = { 0x8010000, 0x10000 },
|
||||
[VIRT_UART] = { 0x9000000, 0x1000 },
|
||||
[VIRT_RTC] = { 0x9010000, 0x1000 },
|
||||
[VIRT_MMIO] = { 0xa000000, 0x200 },
|
||||
[VIRT_GIC_DIST] = { 0x08000000, 0x00010000 },
|
||||
[VIRT_GIC_CPU] = { 0x08010000, 0x00010000 },
|
||||
[VIRT_UART] = { 0x09000000, 0x00001000 },
|
||||
[VIRT_RTC] = { 0x09010000, 0x00001000 },
|
||||
[VIRT_MMIO] = { 0x0a000000, 0x00000200 },
|
||||
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
|
||||
/* 0x10000000 .. 0x40000000 reserved for PCI */
|
||||
[VIRT_MEM] = { 0x40000000, 30ULL * 1024 * 1024 * 1024 },
|
||||
[VIRT_MEM] = { 0x40000000, 30ULL * 1024 * 1024 * 1024 },
|
||||
};
|
||||
|
||||
static const int a15irqmap[] = {
|
||||
|
25
hw/i386/pc.c
25
hw/i386/pc.c
@@ -1190,6 +1190,31 @@ void pc_acpi_init(const char *default_dsdt)
|
||||
}
|
||||
}
|
||||
|
||||
FWCfgState *xen_load_linux(const char *kernel_filename,
|
||||
const char *kernel_cmdline,
|
||||
const char *initrd_filename,
|
||||
ram_addr_t below_4g_mem_size,
|
||||
PcGuestInfo *guest_info)
|
||||
{
|
||||
int i;
|
||||
FWCfgState *fw_cfg;
|
||||
|
||||
assert(kernel_filename != NULL);
|
||||
|
||||
fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0);
|
||||
rom_set_fw(fw_cfg);
|
||||
|
||||
load_linux(fw_cfg, kernel_filename, initrd_filename,
|
||||
kernel_cmdline, below_4g_mem_size);
|
||||
for (i = 0; i < nb_option_roms; i++) {
|
||||
assert(!strcmp(option_rom[i].name, "linuxboot.bin") ||
|
||||
!strcmp(option_rom[i].name, "multiboot.bin"));
|
||||
rom_add_option(option_rom[i].name, option_rom[i].bootindex);
|
||||
}
|
||||
guest_info->fw_cfg = fw_cfg;
|
||||
return fw_cfg;
|
||||
}
|
||||
|
||||
FWCfgState *pc_memory_init(MachineState *machine,
|
||||
MemoryRegion *system_memory,
|
||||
ram_addr_t below_4g_mem_size,
|
||||
|
@@ -182,6 +182,13 @@ static void pc_init1(MachineState *machine,
|
||||
fw_cfg = pc_memory_init(machine, system_memory,
|
||||
below_4g_mem_size, above_4g_mem_size,
|
||||
rom_memory, &ram_memory, guest_info);
|
||||
} else if (machine->kernel_filename != NULL) {
|
||||
/* For xen HVM direct kernel boot, load linux here */
|
||||
fw_cfg = xen_load_linux(machine->kernel_filename,
|
||||
machine->kernel_cmdline,
|
||||
machine->initrd_filename,
|
||||
below_4g_mem_size,
|
||||
guest_info);
|
||||
}
|
||||
|
||||
gsi_state = g_malloc0(sizeof(*gsi_state));
|
||||
|
@@ -40,6 +40,7 @@ static void xen_apic_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
APICCommonState *s = APIC_COMMON(dev);
|
||||
|
||||
s->vapic_control = 0;
|
||||
memory_region_init_io(&s->io_memory, OBJECT(s), &xen_apic_io_ops, s,
|
||||
"xen-apic-msi", APIC_SPACE_SIZE);
|
||||
|
||||
|
@@ -120,11 +120,19 @@ typedef struct VFIOINTx {
|
||||
} VFIOINTx;
|
||||
|
||||
typedef struct VFIOMSIVector {
|
||||
EventNotifier interrupt; /* eventfd triggered on interrupt */
|
||||
EventNotifier kvm_interrupt; /* eventfd triggered for KVM irqfd bypass */
|
||||
/*
|
||||
* Two interrupt paths are configured per vector. The first, is only used
|
||||
* for interrupts injected via QEMU. This is typically the non-accel path,
|
||||
* but may also be used when we want QEMU to handle masking and pending
|
||||
* bits. The KVM path bypasses QEMU and is therefore higher performance,
|
||||
* but requires masking at the device. virq is used to track the MSI route
|
||||
* through KVM, thus kvm_interrupt is only available when virq is set to a
|
||||
* valid (>= 0) value.
|
||||
*/
|
||||
EventNotifier interrupt;
|
||||
EventNotifier kvm_interrupt;
|
||||
struct VFIODevice *vdev; /* back pointer to device */
|
||||
MSIMessage msg; /* cache the MSI message so we know when it changes */
|
||||
int virq; /* KVM irqchip route for QEMU bypass */
|
||||
int virq;
|
||||
bool use;
|
||||
} VFIOMSIVector;
|
||||
|
||||
@@ -681,13 +689,24 @@ static int vfio_enable_vectors(VFIODevice *vdev, bool msix)
|
||||
fds = (int32_t *)&irq_set->data;
|
||||
|
||||
for (i = 0; i < vdev->nr_vectors; i++) {
|
||||
if (!vdev->msi_vectors[i].use) {
|
||||
fds[i] = -1;
|
||||
} else if (vdev->msi_vectors[i].virq >= 0) {
|
||||
fds[i] = event_notifier_get_fd(&vdev->msi_vectors[i].kvm_interrupt);
|
||||
} else {
|
||||
fds[i] = event_notifier_get_fd(&vdev->msi_vectors[i].interrupt);
|
||||
int fd = -1;
|
||||
|
||||
/*
|
||||
* MSI vs MSI-X - The guest has direct access to MSI mask and pending
|
||||
* bits, therefore we always use the KVM signaling path when setup.
|
||||
* MSI-X mask and pending bits are emulated, so we want to use the
|
||||
* KVM signaling path only when configured and unmasked.
|
||||
*/
|
||||
if (vdev->msi_vectors[i].use) {
|
||||
if (vdev->msi_vectors[i].virq < 0 ||
|
||||
(msix && msix_is_masked(&vdev->pdev, i))) {
|
||||
fd = event_notifier_get_fd(&vdev->msi_vectors[i].interrupt);
|
||||
} else {
|
||||
fd = event_notifier_get_fd(&vdev->msi_vectors[i].kvm_interrupt);
|
||||
}
|
||||
}
|
||||
|
||||
fds[i] = fd;
|
||||
}
|
||||
|
||||
ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set);
|
||||
@@ -724,7 +743,6 @@ static void vfio_add_kvm_msi_virq(VFIOMSIVector *vector, MSIMessage *msg,
|
||||
return;
|
||||
}
|
||||
|
||||
vector->msg = *msg;
|
||||
vector->virq = virq;
|
||||
}
|
||||
|
||||
@@ -740,7 +758,6 @@ static void vfio_remove_kvm_msi_virq(VFIOMSIVector *vector)
|
||||
static void vfio_update_kvm_msi_virq(VFIOMSIVector *vector, MSIMessage msg)
|
||||
{
|
||||
kvm_irqchip_update_msi_route(kvm_state, vector->virq, msg);
|
||||
vector->msg = msg;
|
||||
}
|
||||
|
||||
static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr,
|
||||
@@ -919,6 +936,7 @@ retry:
|
||||
|
||||
for (i = 0; i < vdev->nr_vectors; i++) {
|
||||
VFIOMSIVector *vector = &vdev->msi_vectors[i];
|
||||
MSIMessage msg = msi_get_message(&vdev->pdev, i);
|
||||
|
||||
vector->vdev = vdev;
|
||||
vector->virq = -1;
|
||||
@@ -931,13 +949,11 @@ retry:
|
||||
qemu_set_fd_handler(event_notifier_get_fd(&vector->interrupt),
|
||||
vfio_msi_interrupt, NULL, vector);
|
||||
|
||||
vector->msg = msi_get_message(&vdev->pdev, i);
|
||||
|
||||
/*
|
||||
* Attempt to enable route through KVM irqchip,
|
||||
* default to userspace handling if unavailable.
|
||||
*/
|
||||
vfio_add_kvm_msi_virq(vector, &vector->msg, false);
|
||||
vfio_add_kvm_msi_virq(vector, &msg, false);
|
||||
}
|
||||
|
||||
/* Set interrupt type prior to possible interrupts */
|
||||
|
@@ -702,7 +702,8 @@ static void sdhci_do_adma(SDHCIState *s)
|
||||
length -= block_size - begin;
|
||||
}
|
||||
dma_memory_read(&address_space_memory, dscr.addr,
|
||||
&s->fifo_buffer[begin], s->data_count);
|
||||
&s->fifo_buffer[begin],
|
||||
s->data_count - begin);
|
||||
dscr.addr += s->data_count - begin;
|
||||
if (s->data_count == block_size) {
|
||||
for (n = 0; n < block_size; n++) {
|
||||
|
@@ -142,8 +142,15 @@ static void virtio_rng_device_realize(DeviceState *dev, Error **errp)
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (!vrng->conf.period_ms > 0) {
|
||||
error_set(errp, QERR_INVALID_PARAMETER_VALUE, "period",
|
||||
"a positive number");
|
||||
error_setg(errp, "'period' parameter expects a positive integer");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Workaround: Property parsing does not enforce unsigned integers,
|
||||
* So this is a hack to reject such numbers. */
|
||||
if (vrng->conf.max_bytes > INT64_MAX) {
|
||||
error_setg(errp, "'max-bytes' parameter must be non-negative, "
|
||||
"and less than 2^63");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -171,23 +178,15 @@ static void virtio_rng_device_realize(DeviceState *dev, Error **errp)
|
||||
"rng", NULL);
|
||||
}
|
||||
|
||||
virtio_init(vdev, "virtio-rng", VIRTIO_ID_RNG, 0);
|
||||
|
||||
vrng->rng = vrng->conf.rng;
|
||||
if (vrng->rng == NULL) {
|
||||
error_set(errp, QERR_INVALID_PARAMETER_VALUE, "rng", "a valid object");
|
||||
error_setg(errp, "'rng' parameter expects a valid object");
|
||||
return;
|
||||
}
|
||||
|
||||
virtio_init(vdev, "virtio-rng", VIRTIO_ID_RNG, 0);
|
||||
|
||||
vrng->vq = virtio_add_queue(vdev, 8, handle_input);
|
||||
|
||||
/* Workaround: Property parsing does not enforce unsigned integers,
|
||||
* So this is a hack to reject such numbers. */
|
||||
if (vrng->conf.max_bytes > INT64_MAX) {
|
||||
error_set(errp, QERR_INVALID_PARAMETER_VALUE, "max-bytes",
|
||||
"a non-negative integer below 2^63");
|
||||
return;
|
||||
}
|
||||
vrng->quota_remaining = vrng->conf.max_bytes;
|
||||
|
||||
vrng->rate_limit_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL,
|
||||
|
@@ -188,6 +188,11 @@ PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size,
|
||||
void pc_pci_as_mapping_init(Object *owner, MemoryRegion *system_memory,
|
||||
MemoryRegion *pci_address_space);
|
||||
|
||||
FWCfgState *xen_load_linux(const char *kernel_filename,
|
||||
const char *kernel_cmdline,
|
||||
const char *initrd_filename,
|
||||
ram_addr_t below_4g_mem_size,
|
||||
PcGuestInfo *guest_info);
|
||||
FWCfgState *pc_memory_init(MachineState *machine,
|
||||
MemoryRegion *system_memory,
|
||||
ram_addr_t below_4g_mem_size,
|
||||
|
@@ -27,12 +27,13 @@
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
#ifdef __NetBSD__
|
||||
#if defined(__NetBSD__) || defined(__FreeBSD__)
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_tap.h>
|
||||
#endif
|
||||
|
||||
#ifndef __FreeBSD__
|
||||
int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
|
||||
int vnet_hdr_required, int mq_required)
|
||||
{
|
||||
@@ -108,6 +109,73 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
|
||||
return fd;
|
||||
}
|
||||
|
||||
#else /* __FreeBSD__ */
|
||||
|
||||
#define PATH_NET_TAP "/dev/tap"
|
||||
|
||||
int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
|
||||
int vnet_hdr_required, int mq_required)
|
||||
{
|
||||
int fd, s, ret;
|
||||
struct ifreq ifr;
|
||||
|
||||
TFR(fd = open(PATH_NET_TAP, O_RDWR));
|
||||
if (fd < 0) {
|
||||
error_report("could not open %s: %s", PATH_NET_TAP, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
|
||||
ret = ioctl(fd, TAPGIFNAME, (void *)&ifr);
|
||||
if (ret < 0) {
|
||||
error_report("could not get tap interface name");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (ifname[0] != '\0') {
|
||||
/* User requested the interface to have a specific name */
|
||||
s = socket(AF_LOCAL, SOCK_DGRAM, 0);
|
||||
if (s < 0) {
|
||||
error_report("could not open socket to set interface name");
|
||||
goto error;
|
||||
}
|
||||
ifr.ifr_data = ifname;
|
||||
ret = ioctl(s, SIOCSIFNAME, (void *)&ifr);
|
||||
close(s);
|
||||
if (ret < 0) {
|
||||
error_report("could not set tap interface name");
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
pstrcpy(ifname, ifname_size, ifr.ifr_name);
|
||||
}
|
||||
|
||||
if (*vnet_hdr) {
|
||||
/* BSD doesn't have IFF_VNET_HDR */
|
||||
*vnet_hdr = 0;
|
||||
|
||||
if (vnet_hdr_required && !*vnet_hdr) {
|
||||
error_report("vnet_hdr=1 requested, but no kernel "
|
||||
"support for IFF_VNET_HDR available");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
if (mq_required) {
|
||||
error_report("mq_required requested, but not kernel support"
|
||||
"for IFF_MULTI_QUEUE available");
|
||||
goto error;
|
||||
}
|
||||
|
||||
fcntl(fd, F_SETFL, O_NONBLOCK);
|
||||
return fd;
|
||||
|
||||
error:
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
#endif /* __FreeBSD__ */
|
||||
|
||||
int tap_set_sndbuf(int fd, const NetdevTapOptions *tap)
|
||||
{
|
||||
return 0;
|
||||
|
@@ -42,30 +42,44 @@ def check_fields_match(name, s_field, d_field):
|
||||
# Some fields changed names between qemu versions. This list
|
||||
# is used to whitelist such changes in each section / description.
|
||||
changed_names = {
|
||||
'apic': ['timer', 'timer_expiry'],
|
||||
'e1000': ['dev', 'parent_obj'],
|
||||
'ehci': ['dev', 'pcidev'],
|
||||
'I440FX': ['dev', 'parent_obj'],
|
||||
'ich9_ahci': ['card', 'parent_obj'],
|
||||
'ich9-ahci': ['ahci', 'ich9_ahci'],
|
||||
'ioh3420': ['PCIDevice', 'PCIEDevice'],
|
||||
'ioh-3240-express-root-port': ['port.br.dev',
|
||||
'parent_obj.parent_obj.parent_obj',
|
||||
'port.br.dev.exp.aer_log',
|
||||
'parent_obj.parent_obj.parent_obj.exp.aer_log'],
|
||||
'lsiscsi': ['dev', 'parent_obj'],
|
||||
'mch': ['d', 'parent_obj'],
|
||||
'pci_bridge': ['bridge.dev', 'parent_obj', 'bridge.dev.shpc', 'shpc'],
|
||||
'pcnet': ['pci_dev', 'parent_obj'],
|
||||
'PIIX3': ['pci_irq_levels', 'pci_irq_levels_vmstate'],
|
||||
'piix4_pm': ['dev', 'parent_obj', 'pci0_status',
|
||||
'acpi_pci_hotplug.acpi_pcihp_pci_status[0x0]'],
|
||||
'acpi_pci_hotplug.acpi_pcihp_pci_status[0x0]',
|
||||
'pm1a.sts', 'ar.pm1.evt.sts', 'pm1a.en', 'ar.pm1.evt.en',
|
||||
'pm1_cnt.cnt', 'ar.pm1.cnt.cnt',
|
||||
'tmr.timer', 'ar.tmr.timer',
|
||||
'tmr.overflow_time', 'ar.tmr.overflow_time',
|
||||
'gpe', 'ar.gpe'],
|
||||
'rtl8139': ['dev', 'parent_obj'],
|
||||
'qxl': ['num_surfaces', 'ssd.num_surfaces'],
|
||||
'usb-ccid': ['abProtocolDataStructure', 'abProtocolDataStructure.data'],
|
||||
'usb-host': ['dev', 'parent_obj'],
|
||||
'usb-mouse': ['usb-ptr-queue', 'HIDPointerEventQueue'],
|
||||
'usb-tablet': ['usb-ptr-queue', 'HIDPointerEventQueue'],
|
||||
'vmware_vga': ['card', 'parent_obj'],
|
||||
'vmware_vga_internal': ['depth', 'new_depth'],
|
||||
'xhci': ['pci_dev', 'parent_obj'],
|
||||
'x3130-upstream': ['PCIDevice', 'PCIEDevice'],
|
||||
'xio3130-express-downstream-port': ['port.br.dev',
|
||||
'parent_obj.parent_obj.parent_obj',
|
||||
'port.br.dev.exp.aer_log',
|
||||
'parent_obj.parent_obj.parent_obj.exp.aer_log'],
|
||||
'xio3130-downstream': ['PCIDevice', 'PCIEDevice'],
|
||||
'xio3130-express-upstream-port': ['br.dev', 'parent_obj.parent_obj',
|
||||
'br.dev.exp.aer_log',
|
||||
'parent_obj.parent_obj.exp.aer_log'],
|
||||
@@ -130,6 +144,7 @@ def check_fields(src_fields, dest_fields, desc, sec):
|
||||
|
||||
advance_src = True
|
||||
advance_dest = True
|
||||
unused_count = 0
|
||||
|
||||
while True:
|
||||
if advance_src:
|
||||
@@ -142,9 +157,10 @@ def check_fields(src_fields, dest_fields, desc, sec):
|
||||
s_iter = s_iter_list.pop()
|
||||
continue
|
||||
else:
|
||||
# We want to avoid advancing just once -- when entering a
|
||||
# dest substruct, or when exiting one.
|
||||
advance_src = True
|
||||
if unused_count == 0:
|
||||
# We want to avoid advancing just once -- when entering a
|
||||
# dest substruct, or when exiting one.
|
||||
advance_src = True
|
||||
|
||||
if advance_dest:
|
||||
try:
|
||||
@@ -163,7 +179,37 @@ def check_fields(src_fields, dest_fields, desc, sec):
|
||||
advance_src = False
|
||||
continue
|
||||
else:
|
||||
advance_dest = True
|
||||
if unused_count == 0:
|
||||
advance_dest = True
|
||||
|
||||
if unused_count > 0:
|
||||
if advance_dest == False:
|
||||
unused_count = unused_count - s_item["size"]
|
||||
if unused_count == 0:
|
||||
advance_dest = True
|
||||
continue
|
||||
if unused_count < 0:
|
||||
print "Section \"" + sec + "\",",
|
||||
print "Description \"" + desc + "\":",
|
||||
print "unused size mismatch near \"",
|
||||
print s_item["field"] + "\""
|
||||
bump_taint()
|
||||
break
|
||||
continue
|
||||
|
||||
if advance_src == False:
|
||||
unused_count = unused_count - d_item["size"]
|
||||
if unused_count == 0:
|
||||
advance_src = True
|
||||
continue
|
||||
if unused_count < 0:
|
||||
print "Section \"" + sec + "\",",
|
||||
print "Description \"" + desc + "\":",
|
||||
print "unused size mismatch near \"",
|
||||
print d_item["field"] + "\""
|
||||
bump_taint()
|
||||
break
|
||||
continue
|
||||
|
||||
if not check_fields_match(desc, s_item["field"], d_item["field"]):
|
||||
# Some fields were put in substructs, keeping the
|
||||
@@ -194,6 +240,20 @@ def check_fields(src_fields, dest_fields, desc, sec):
|
||||
advance_dest = False
|
||||
continue
|
||||
|
||||
if s_item["field"] == "unused" or d_item["field"] == "unused":
|
||||
if s_item["size"] == d_item["size"]:
|
||||
continue
|
||||
|
||||
if d_item["field"] == "unused":
|
||||
advance_dest = False
|
||||
unused_count = d_item["size"] - s_item["size"]
|
||||
continue
|
||||
|
||||
if s_item["field"] == "unused":
|
||||
advance_src = False
|
||||
unused_count = s_item["size"] - d_item["size"]
|
||||
continue
|
||||
|
||||
print "Section \"" + sec + "\",",
|
||||
print "Description \"" + desc + "\":",
|
||||
print "expected field \"" + s_item["field"] + "\",",
|
||||
|
@@ -447,7 +447,7 @@ static void arm1026_initfn(Object *obj)
|
||||
ARMCPRegInfo ifar = {
|
||||
.name = "IFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 1,
|
||||
.access = PL1_RW,
|
||||
.fieldoffset = offsetofhigh32(CPUARMState, cp15.far_el1),
|
||||
.fieldoffset = offsetofhigh32(CPUARMState, cp15.far_el[1]),
|
||||
.resetvalue = 0
|
||||
};
|
||||
define_one_arm_cp_reg(cpu, &ifar);
|
||||
|
@@ -185,9 +185,9 @@ typedef struct CPUARMState {
|
||||
uint32_t pmsav5_data_ap; /* PMSAv5 MPU data access permissions */
|
||||
uint32_t pmsav5_insn_ap; /* PMSAv5 MPU insn access permissions */
|
||||
uint32_t ifsr_el2; /* Fault status registers. */
|
||||
uint64_t esr_el[2];
|
||||
uint64_t esr_el[4];
|
||||
uint32_t c6_region[8]; /* MPU base/size registers. */
|
||||
uint64_t far_el1; /* Fault address registers. */
|
||||
uint64_t far_el[4]; /* Fault address registers. */
|
||||
uint64_t par_el1; /* Translation result. */
|
||||
uint32_t c9_insn; /* Cache lockdown registers. */
|
||||
uint32_t c9_data;
|
||||
|
@@ -465,13 +465,13 @@ void aarch64_cpu_do_interrupt(CPUState *cs)
|
||||
}
|
||||
|
||||
env->cp15.esr_el[1] = env->exception.syndrome;
|
||||
env->cp15.far_el1 = env->exception.vaddress;
|
||||
env->cp15.far_el[1] = env->exception.vaddress;
|
||||
|
||||
switch (cs->exception_index) {
|
||||
case EXCP_PREFETCH_ABORT:
|
||||
case EXCP_DATA_ABORT:
|
||||
qemu_log_mask(CPU_LOG_INT, "...with FAR 0x%" PRIx64 "\n",
|
||||
env->cp15.far_el1);
|
||||
env->cp15.far_el[1]);
|
||||
break;
|
||||
case EXCP_BKPT:
|
||||
case EXCP_UDEF:
|
||||
@@ -489,8 +489,7 @@ void aarch64_cpu_do_interrupt(CPUState *cs)
|
||||
|
||||
if (is_a64(env)) {
|
||||
env->banked_spsr[aarch64_banked_spsr_index(1)] = pstate_read(env);
|
||||
env->sp_el[arm_current_pl(env)] = env->xregs[31];
|
||||
env->xregs[31] = env->sp_el[1];
|
||||
aarch64_save_sp(env, arm_current_pl(env));
|
||||
env->elr_el[1] = env->pc;
|
||||
} else {
|
||||
env->banked_spsr[0] = cpsr_read(env);
|
||||
@@ -508,6 +507,7 @@ void aarch64_cpu_do_interrupt(CPUState *cs)
|
||||
|
||||
pstate_write(env, PSTATE_DAIF | PSTATE_MODE_EL1h);
|
||||
env->aarch64 = 1;
|
||||
aarch64_restore_sp(env, 1);
|
||||
|
||||
env->pc = addr;
|
||||
cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
|
||||
|
@@ -521,7 +521,7 @@ static const ARMCPRegInfo v6_cp_reginfo[] = {
|
||||
.access = PL0_W, .type = ARM_CP_NOP },
|
||||
{ .name = "IFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 2,
|
||||
.access = PL1_RW,
|
||||
.fieldoffset = offsetofhigh32(CPUARMState, cp15.far_el1),
|
||||
.fieldoffset = offsetofhigh32(CPUARMState, cp15.far_el[1]),
|
||||
.resetvalue = 0, },
|
||||
/* Watchpoint Fault Address Register : should actually only be present
|
||||
* for 1136, 1176, 11MPCore.
|
||||
@@ -1516,7 +1516,7 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = {
|
||||
/* 64-bit FAR; this entry also gives us the AArch32 DFAR */
|
||||
{ .name = "FAR_EL1", .state = ARM_CP_STATE_BOTH,
|
||||
.opc0 = 3, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0,
|
||||
.access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.far_el1),
|
||||
.access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.far_el[1]),
|
||||
.resetvalue = 0, },
|
||||
REGINFO_SENTINEL
|
||||
};
|
||||
@@ -1801,12 +1801,17 @@ static CPAccessResult aa64_cacheop_access(CPUARMState *env,
|
||||
return CP_ACCESS_OK;
|
||||
}
|
||||
|
||||
/* See: D4.7.2 TLB maintenance requirements and the TLB maintenance instructions
|
||||
* Page D4-1736 (DDI0487A.b)
|
||||
*/
|
||||
|
||||
static void tlbi_aa64_va_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
uint64_t value)
|
||||
{
|
||||
/* Invalidate by VA (AArch64 version) */
|
||||
ARMCPU *cpu = arm_env_get_cpu(env);
|
||||
uint64_t pageaddr = value << 12;
|
||||
uint64_t pageaddr = sextract64(value << 12, 0, 56);
|
||||
|
||||
tlb_flush_page(CPU(cpu), pageaddr);
|
||||
}
|
||||
|
||||
@@ -1815,7 +1820,8 @@ static void tlbi_aa64_vaa_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
{
|
||||
/* Invalidate by VA, all ASIDs (AArch64 version) */
|
||||
ARMCPU *cpu = arm_env_get_cpu(env);
|
||||
uint64_t pageaddr = value << 12;
|
||||
uint64_t pageaddr = sextract64(value << 12, 0, 56);
|
||||
|
||||
tlb_flush_page(CPU(cpu), pageaddr);
|
||||
}
|
||||
|
||||
@@ -1853,7 +1859,7 @@ static uint64_t aa64_dczid_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
|
||||
static CPAccessResult sp_el0_access(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
{
|
||||
if (!env->pstate & PSTATE_SP) {
|
||||
if (!(env->pstate & PSTATE_SP)) {
|
||||
/* Access to SP_EL0 is undefined if it's being used as
|
||||
* the stack pointer.
|
||||
*/
|
||||
@@ -2127,6 +2133,13 @@ static const ARMCPRegInfo v8_el2_cp_reginfo[] = {
|
||||
.opc0 = 3, .opc1 = 4, .crn = 4, .crm = 0, .opc2 = 1,
|
||||
.access = PL2_RW,
|
||||
.fieldoffset = offsetof(CPUARMState, elr_el[2]) },
|
||||
{ .name = "ESR_EL2", .state = ARM_CP_STATE_AA64,
|
||||
.type = ARM_CP_NO_MIGRATE,
|
||||
.opc0 = 3, .opc1 = 4, .crn = 5, .crm = 2, .opc2 = 0,
|
||||
.access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.esr_el[2]) },
|
||||
{ .name = "FAR_EL2", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 4, .crn = 6, .crm = 0, .opc2 = 0,
|
||||
.access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.far_el[2]) },
|
||||
{ .name = "SPSR_EL2", .state = ARM_CP_STATE_AA64,
|
||||
.type = ARM_CP_NO_MIGRATE,
|
||||
.opc0 = 3, .opc1 = 4, .crn = 4, .crm = 0, .opc2 = 0,
|
||||
@@ -2145,6 +2158,13 @@ static const ARMCPRegInfo v8_el3_cp_reginfo[] = {
|
||||
.opc0 = 3, .opc1 = 6, .crn = 4, .crm = 0, .opc2 = 1,
|
||||
.access = PL3_RW,
|
||||
.fieldoffset = offsetof(CPUARMState, elr_el[3]) },
|
||||
{ .name = "ESR_EL3", .state = ARM_CP_STATE_AA64,
|
||||
.type = ARM_CP_NO_MIGRATE,
|
||||
.opc0 = 3, .opc1 = 6, .crn = 5, .crm = 2, .opc2 = 0,
|
||||
.access = PL3_RW, .fieldoffset = offsetof(CPUARMState, cp15.esr_el[3]) },
|
||||
{ .name = "FAR_EL3", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 3, .opc1 = 6, .crn = 6, .crm = 0, .opc2 = 0,
|
||||
.access = PL3_RW, .fieldoffset = offsetof(CPUARMState, cp15.far_el[3]) },
|
||||
{ .name = "SPSR_EL3", .state = ARM_CP_STATE_AA64,
|
||||
.type = ARM_CP_NO_MIGRATE,
|
||||
.opc0 = 3, .opc1 = 6, .crn = 4, .crm = 0, .opc2 = 0,
|
||||
@@ -3425,8 +3445,8 @@ void arm_cpu_do_interrupt(CPUState *cs)
|
||||
/* Fall through to prefetch abort. */
|
||||
case EXCP_PREFETCH_ABORT:
|
||||
env->cp15.ifsr_el2 = env->exception.fsr;
|
||||
env->cp15.far_el1 = deposit64(env->cp15.far_el1, 32, 32,
|
||||
env->exception.vaddress);
|
||||
env->cp15.far_el[1] = deposit64(env->cp15.far_el[1], 32, 32,
|
||||
env->exception.vaddress);
|
||||
qemu_log_mask(CPU_LOG_INT, "...with IFSR 0x%x IFAR 0x%x\n",
|
||||
env->cp15.ifsr_el2, (uint32_t)env->exception.vaddress);
|
||||
new_mode = ARM_CPU_MODE_ABT;
|
||||
@@ -3436,8 +3456,8 @@ void arm_cpu_do_interrupt(CPUState *cs)
|
||||
break;
|
||||
case EXCP_DATA_ABORT:
|
||||
env->cp15.esr_el[1] = env->exception.fsr;
|
||||
env->cp15.far_el1 = deposit64(env->cp15.far_el1, 0, 32,
|
||||
env->exception.vaddress);
|
||||
env->cp15.far_el[1] = deposit64(env->cp15.far_el[1], 0, 32,
|
||||
env->exception.vaddress);
|
||||
qemu_log_mask(CPU_LOG_INT, "...with DFSR 0x%x DFAR 0x%x\n",
|
||||
(uint32_t)env->cp15.esr_el[1],
|
||||
(uint32_t)env->exception.vaddress);
|
||||
@@ -4142,8 +4162,8 @@ int arm_cpu_handle_mmu_fault(CPUState *cs, vaddr address,
|
||||
&page_size);
|
||||
if (ret == 0) {
|
||||
/* Map a single [sub]page. */
|
||||
phys_addr &= ~(hwaddr)0x3ff;
|
||||
address &= ~(target_ulong)0x3ff;
|
||||
phys_addr &= TARGET_PAGE_MASK;
|
||||
address &= TARGET_PAGE_MASK;
|
||||
tlb_set_page(cs, address, phys_addr, prot, mmu_idx, page_size);
|
||||
return 0;
|
||||
}
|
||||
|
@@ -105,6 +105,24 @@ enum arm_fprounding {
|
||||
|
||||
int arm_rmode_to_sf(int rmode);
|
||||
|
||||
static inline void aarch64_save_sp(CPUARMState *env, int el)
|
||||
{
|
||||
if (env->pstate & PSTATE_SP) {
|
||||
env->sp_el[el] = env->xregs[31];
|
||||
} else {
|
||||
env->sp_el[0] = env->xregs[31];
|
||||
}
|
||||
}
|
||||
|
||||
static inline void aarch64_restore_sp(CPUARMState *env, int el)
|
||||
{
|
||||
if (env->pstate & PSTATE_SP) {
|
||||
env->xregs[31] = env->sp_el[el];
|
||||
} else {
|
||||
env->xregs[31] = env->sp_el[0];
|
||||
}
|
||||
}
|
||||
|
||||
static inline void update_spsel(CPUARMState *env, uint32_t imm)
|
||||
{
|
||||
unsigned int cur_el = arm_current_pl(env);
|
||||
@@ -114,21 +132,14 @@ static inline void update_spsel(CPUARMState *env, uint32_t imm)
|
||||
if (!((imm ^ env->pstate) & PSTATE_SP)) {
|
||||
return;
|
||||
}
|
||||
aarch64_save_sp(env, cur_el);
|
||||
env->pstate = deposit32(env->pstate, 0, 1, imm);
|
||||
|
||||
/* We rely on illegal updates to SPsel from EL0 to get trapped
|
||||
* at translation time.
|
||||
*/
|
||||
assert(cur_el >= 1 && cur_el <= 3);
|
||||
if (env->pstate & PSTATE_SP) {
|
||||
/* Switch from using SP_EL0 to using SP_ELx */
|
||||
env->sp_el[0] = env->xregs[31];
|
||||
env->xregs[31] = env->sp_el[cur_el];
|
||||
} else {
|
||||
/* Switch from SP_EL0 to SP_ELx */
|
||||
env->sp_el[cur_el] = env->xregs[31];
|
||||
env->xregs[31] = env->sp_el[0];
|
||||
}
|
||||
aarch64_restore_sp(env, cur_el);
|
||||
}
|
||||
|
||||
/* Valid Syndrome Register EC field values */
|
||||
|
@@ -21,6 +21,7 @@
|
||||
#include "sysemu/kvm.h"
|
||||
#include "kvm_arm.h"
|
||||
#include "cpu.h"
|
||||
#include "internals.h"
|
||||
#include "hw/arm/arm.h"
|
||||
|
||||
static inline void set_feature(uint64_t *features, int feature)
|
||||
@@ -132,11 +133,7 @@ int kvm_arch_put_registers(CPUState *cs, int level)
|
||||
/* KVM puts SP_EL0 in regs.sp and SP_EL1 in regs.sp_el1. On the
|
||||
* QEMU side we keep the current SP in xregs[31] as well.
|
||||
*/
|
||||
if (env->pstate & PSTATE_SP) {
|
||||
env->sp_el[1] = env->xregs[31];
|
||||
} else {
|
||||
env->sp_el[0] = env->xregs[31];
|
||||
}
|
||||
aarch64_save_sp(env, 1);
|
||||
|
||||
reg.id = AARCH64_CORE_REG(regs.sp);
|
||||
reg.addr = (uintptr_t) &env->sp_el[0];
|
||||
@@ -235,11 +232,7 @@ int kvm_arch_get_registers(CPUState *cs)
|
||||
/* KVM puts SP_EL0 in regs.sp and SP_EL1 in regs.sp_el1. On the
|
||||
* QEMU side we keep the current SP in xregs[31] as well.
|
||||
*/
|
||||
if (env->pstate & PSTATE_SP) {
|
||||
env->xregs[31] = env->sp_el[1];
|
||||
} else {
|
||||
env->xregs[31] = env->sp_el[0];
|
||||
}
|
||||
aarch64_restore_sp(env, 1);
|
||||
|
||||
reg.id = AARCH64_CORE_REG(regs.pc);
|
||||
reg.addr = (uintptr_t) &env->pc;
|
||||
|
@@ -376,11 +376,7 @@ void HELPER(exception_return)(CPUARMState *env)
|
||||
uint32_t spsr = env->banked_spsr[spsr_idx];
|
||||
int new_el, i;
|
||||
|
||||
if (env->pstate & PSTATE_SP) {
|
||||
env->sp_el[cur_el] = env->xregs[31];
|
||||
} else {
|
||||
env->sp_el[0] = env->xregs[31];
|
||||
}
|
||||
aarch64_save_sp(env, cur_el);
|
||||
|
||||
env->exclusive_addr = -1;
|
||||
|
||||
@@ -414,7 +410,7 @@ void HELPER(exception_return)(CPUARMState *env)
|
||||
}
|
||||
env->aarch64 = 1;
|
||||
pstate_write(env, spsr);
|
||||
env->xregs[31] = env->sp_el[new_el];
|
||||
aarch64_restore_sp(env, new_el);
|
||||
env->pc = env->elr_el[cur_el];
|
||||
}
|
||||
|
||||
|
@@ -513,11 +513,14 @@ static void xen_sync_dirty_bitmap(XenIOState *state,
|
||||
start_addr >> TARGET_PAGE_BITS, npages,
|
||||
bitmap);
|
||||
if (rc < 0) {
|
||||
if (rc != -ENODATA) {
|
||||
#ifndef ENODATA
|
||||
#define ENODATA ENOENT
|
||||
#endif
|
||||
if (errno == ENODATA) {
|
||||
memory_region_set_dirty(framebuffer, 0, size);
|
||||
DPRINTF("xen: track_dirty_vram failed (0x" TARGET_FMT_plx
|
||||
", 0x" TARGET_FMT_plx "): %s\n",
|
||||
start_addr, start_addr + size, strerror(-rc));
|
||||
start_addr, start_addr + size, strerror(errno));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
Reference in New Issue
Block a user