mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging
* KVM: synic support, split irqchip support * memory: cleanups, optimizations, ioeventfd emulation * SCSI: small fixes, vmw_pvscsi compatibility improvements * qemu_log cleanups * Coverity model improvements # gpg: Signature made Thu 17 Dec 2015 16:35:21 GMT using RSA key ID 78C7AE83 # gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" # gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" * remotes/bonzini/tags/for-upstream: (45 commits) coverity: Model g_memdup() coverity: Model g_poll() scsi: always call notifier on async cancellation scsi: use scsi_req_cancel_async when purging requests target-i386: kvm: clear unusable segments' flags in migration rcu: optimize rcu_read_lock memory: try to inline constant-length reads memory: inline a few small accessors memory: extract first iteration of address_space_read and address_space_write memory: split address_space_read and address_space_write memory: avoid unnecessary object_ref/unref memory: reorder MemoryRegion fields exec: make qemu_ram_ptr_length more similar to qemu_get_ram_ptr exec: always call qemu_get_ram_ptr within rcu_read_lock linux-user: convert DEBUG_SIGNAL logging to tracepoints linux-user: avoid "naked" qemu_log user: introduce "-d page" xtensa: avoid "naked" qemu_log tricore: avoid "naked" qemu_log ppc: cleanup logging ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
+2
-2
@@ -938,7 +938,7 @@ int main(int argc, char **argv)
|
||||
unsigned long tmp;
|
||||
if (fscanf(fp, "%lu", &tmp) == 1) {
|
||||
mmap_min_addr = tmp;
|
||||
qemu_log("host mmap_min_addr=0x%lx\n", mmap_min_addr);
|
||||
qemu_log_mask(CPU_LOG_PAGE, "host mmap_min_addr=0x%lx\n", mmap_min_addr);
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
@@ -955,7 +955,7 @@ int main(int argc, char **argv)
|
||||
|
||||
free(target_environ);
|
||||
|
||||
if (qemu_log_enabled()) {
|
||||
if (qemu_loglevel_mask(CPU_LOG_PAGE)) {
|
||||
qemu_log("guest_base 0x%lx\n", guest_base);
|
||||
log_page_dump();
|
||||
|
||||
|
||||
@@ -26,8 +26,6 @@
|
||||
#include "qemu.h"
|
||||
#include "target_signal.h"
|
||||
|
||||
//#define DEBUG_SIGNAL
|
||||
|
||||
void signal_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -50,3 +50,4 @@ CONFIG_XIO3130=y
|
||||
CONFIG_IOH3420=y
|
||||
CONFIG_I82801B11=y
|
||||
CONFIG_SMBIOS=y
|
||||
CONFIG_HYPERV_TESTDEV=$(CONFIG_KVM)
|
||||
|
||||
@@ -50,3 +50,4 @@ CONFIG_XIO3130=y
|
||||
CONFIG_IOH3420=y
|
||||
CONFIG_I82801B11=y
|
||||
CONFIG_SMBIOS=y
|
||||
CONFIG_HYPERV_TESTDEV=$(CONFIG_KVM)
|
||||
|
||||
@@ -88,9 +88,6 @@ static MemoryRegion io_mem_unassigned;
|
||||
*/
|
||||
#define RAM_RESIZEABLE (1 << 2)
|
||||
|
||||
/* RAM is backed by an mmapped file.
|
||||
*/
|
||||
#define RAM_FILE (1 << 3)
|
||||
#endif
|
||||
|
||||
struct CPUTailQ cpus = QTAILQ_HEAD_INITIALIZER(cpus);
|
||||
@@ -393,18 +390,6 @@ address_space_translate_internal(AddressSpaceDispatch *d, hwaddr addr, hwaddr *x
|
||||
return section;
|
||||
}
|
||||
|
||||
static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write)
|
||||
{
|
||||
if (memory_region_is_ram(mr)) {
|
||||
return !(is_write && mr->readonly);
|
||||
}
|
||||
if (memory_region_is_romd(mr)) {
|
||||
return !is_write;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Called from RCU critical section */
|
||||
MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr,
|
||||
hwaddr *xlat, hwaddr *plen,
|
||||
@@ -873,7 +858,7 @@ void cpu_abort(CPUState *cpu, const char *fmt, ...)
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, "\n");
|
||||
cpu_dump_state(cpu, stderr, fprintf, CPU_DUMP_FPU | CPU_DUMP_CCOP);
|
||||
if (qemu_log_enabled()) {
|
||||
if (qemu_log_separate()) {
|
||||
qemu_log("qemu: fatal: ");
|
||||
qemu_log_vprintf(fmt, ap2);
|
||||
qemu_log("\n");
|
||||
@@ -1601,7 +1586,6 @@ ram_addr_t qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr,
|
||||
new_block->used_length = size;
|
||||
new_block->max_length = size;
|
||||
new_block->flags = share ? RAM_SHARED : 0;
|
||||
new_block->flags |= RAM_FILE;
|
||||
new_block->host = file_ram_alloc(new_block, size,
|
||||
mem_path, errp);
|
||||
if (!new_block->host) {
|
||||
@@ -1676,25 +1660,6 @@ ram_addr_t qemu_ram_alloc_resizeable(ram_addr_t size, ram_addr_t maxsz,
|
||||
return qemu_ram_alloc_internal(size, maxsz, resized, NULL, true, mr, errp);
|
||||
}
|
||||
|
||||
void qemu_ram_free_from_ptr(ram_addr_t addr)
|
||||
{
|
||||
RAMBlock *block;
|
||||
|
||||
qemu_mutex_lock_ramlist();
|
||||
QLIST_FOREACH_RCU(block, &ram_list.blocks, next) {
|
||||
if (addr == block->offset) {
|
||||
QLIST_REMOVE_RCU(block, next);
|
||||
ram_list.mru_block = NULL;
|
||||
/* Write list before version */
|
||||
smp_wmb();
|
||||
ram_list.version++;
|
||||
g_free_rcu(block, rcu);
|
||||
break;
|
||||
}
|
||||
}
|
||||
qemu_mutex_unlock_ramlist();
|
||||
}
|
||||
|
||||
static void reclaim_ramblock(RAMBlock *block)
|
||||
{
|
||||
if (block->flags & RAM_PREALLOC) {
|
||||
@@ -1703,11 +1668,7 @@ static void reclaim_ramblock(RAMBlock *block)
|
||||
xen_invalidate_map_cache_entry(block->host);
|
||||
#ifndef _WIN32
|
||||
} else if (block->fd >= 0) {
|
||||
if (block->flags & RAM_FILE) {
|
||||
qemu_ram_munmap(block->host, block->max_length);
|
||||
} else {
|
||||
munmap(block->host, block->max_length);
|
||||
}
|
||||
qemu_ram_munmap(block->host, block->max_length);
|
||||
close(block->fd);
|
||||
#endif
|
||||
} else {
|
||||
@@ -1813,19 +1774,11 @@ void *qemu_get_ram_block_host_ptr(ram_addr_t addr)
|
||||
* or address_space_rw instead. For local memory (e.g. video ram) that the
|
||||
* device owns, use memory_region_get_ram_ptr.
|
||||
*
|
||||
* By the time this function returns, the returned pointer is not protected
|
||||
* by RCU anymore. If the caller is not within an RCU critical section and
|
||||
* does not hold the iothread lock, it must have other means of protecting the
|
||||
* pointer, such as a reference to the region that includes the incoming
|
||||
* ram_addr_t.
|
||||
* Called within RCU critical section.
|
||||
*/
|
||||
void *qemu_get_ram_ptr(ram_addr_t addr)
|
||||
{
|
||||
RAMBlock *block;
|
||||
void *ptr;
|
||||
|
||||
rcu_read_lock();
|
||||
block = qemu_get_ram_block(addr);
|
||||
RAMBlock *block = qemu_get_ram_block(addr);
|
||||
|
||||
if (xen_enabled() && block->host == NULL) {
|
||||
/* We need to check if the requested address is in the RAM
|
||||
@@ -1833,52 +1786,44 @@ void *qemu_get_ram_ptr(ram_addr_t addr)
|
||||
* In that case just map until the end of the page.
|
||||
*/
|
||||
if (block->offset == 0) {
|
||||
ptr = xen_map_cache(addr, 0, 0);
|
||||
goto unlock;
|
||||
return xen_map_cache(addr, 0, 0);
|
||||
}
|
||||
|
||||
block->host = xen_map_cache(block->offset, block->max_length, 1);
|
||||
}
|
||||
ptr = ramblock_ptr(block, addr - block->offset);
|
||||
|
||||
unlock:
|
||||
rcu_read_unlock();
|
||||
return ptr;
|
||||
return ramblock_ptr(block, addr - block->offset);
|
||||
}
|
||||
|
||||
/* Return a host pointer to guest's ram. Similar to qemu_get_ram_ptr
|
||||
* but takes a size argument.
|
||||
*
|
||||
* By the time this function returns, the returned pointer is not protected
|
||||
* by RCU anymore. If the caller is not within an RCU critical section and
|
||||
* does not hold the iothread lock, it must have other means of protecting the
|
||||
* pointer, such as a reference to the region that includes the incoming
|
||||
* ram_addr_t.
|
||||
* Called within RCU critical section.
|
||||
*/
|
||||
static void *qemu_ram_ptr_length(ram_addr_t addr, hwaddr *size)
|
||||
{
|
||||
void *ptr;
|
||||
RAMBlock *block;
|
||||
ram_addr_t offset_inside_block;
|
||||
if (*size == 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (xen_enabled()) {
|
||||
return xen_map_cache(addr, *size, 1);
|
||||
} else {
|
||||
RAMBlock *block;
|
||||
rcu_read_lock();
|
||||
QLIST_FOREACH_RCU(block, &ram_list.blocks, next) {
|
||||
if (addr - block->offset < block->max_length) {
|
||||
if (addr - block->offset + *size > block->max_length)
|
||||
*size = block->max_length - addr + block->offset;
|
||||
ptr = ramblock_ptr(block, addr - block->offset);
|
||||
rcu_read_unlock();
|
||||
return ptr;
|
||||
}
|
||||
|
||||
block = qemu_get_ram_block(addr);
|
||||
offset_inside_block = addr - block->offset;
|
||||
*size = MIN(*size, block->max_length - offset_inside_block);
|
||||
|
||||
if (xen_enabled() && block->host == NULL) {
|
||||
/* We need to check if the requested address is in the RAM
|
||||
* because we don't want to map the entire memory in QEMU.
|
||||
* In that case just map the requested area.
|
||||
*/
|
||||
if (block->offset == 0) {
|
||||
return xen_map_cache(addr, *size, 1);
|
||||
}
|
||||
|
||||
fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr);
|
||||
abort();
|
||||
block->host = xen_map_cache(block->offset, block->max_length, 1);
|
||||
}
|
||||
|
||||
return ramblock_ptr(block, offset_inside_block);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1981,6 +1926,7 @@ MemoryRegion *qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr)
|
||||
return block->mr;
|
||||
}
|
||||
|
||||
/* Called within RCU critical section. */
|
||||
static void notdirty_mem_write(void *opaque, hwaddr ram_addr,
|
||||
uint64_t val, unsigned size)
|
||||
{
|
||||
@@ -2511,101 +2457,58 @@ static bool prepare_mmio_access(MemoryRegion *mr)
|
||||
return release_lock;
|
||||
}
|
||||
|
||||
MemTxResult address_space_rw(AddressSpace *as, hwaddr addr, MemTxAttrs attrs,
|
||||
uint8_t *buf, int len, bool is_write)
|
||||
/* Called within RCU critical section. */
|
||||
static MemTxResult address_space_write_continue(AddressSpace *as, hwaddr addr,
|
||||
MemTxAttrs attrs,
|
||||
const uint8_t *buf,
|
||||
int len, hwaddr addr1,
|
||||
hwaddr l, MemoryRegion *mr)
|
||||
{
|
||||
hwaddr l;
|
||||
uint8_t *ptr;
|
||||
uint64_t val;
|
||||
hwaddr addr1;
|
||||
MemoryRegion *mr;
|
||||
MemTxResult result = MEMTX_OK;
|
||||
bool release_lock = false;
|
||||
|
||||
rcu_read_lock();
|
||||
while (len > 0) {
|
||||
l = len;
|
||||
mr = address_space_translate(as, addr, &addr1, &l, is_write);
|
||||
|
||||
if (is_write) {
|
||||
if (!memory_access_is_direct(mr, is_write)) {
|
||||
release_lock |= prepare_mmio_access(mr);
|
||||
l = memory_access_size(mr, l, addr1);
|
||||
/* XXX: could force current_cpu to NULL to avoid
|
||||
potential bugs */
|
||||
switch (l) {
|
||||
case 8:
|
||||
/* 64 bit write access */
|
||||
val = ldq_p(buf);
|
||||
result |= memory_region_dispatch_write(mr, addr1, val, 8,
|
||||
attrs);
|
||||
break;
|
||||
case 4:
|
||||
/* 32 bit write access */
|
||||
val = ldl_p(buf);
|
||||
result |= memory_region_dispatch_write(mr, addr1, val, 4,
|
||||
attrs);
|
||||
break;
|
||||
case 2:
|
||||
/* 16 bit write access */
|
||||
val = lduw_p(buf);
|
||||
result |= memory_region_dispatch_write(mr, addr1, val, 2,
|
||||
attrs);
|
||||
break;
|
||||
case 1:
|
||||
/* 8 bit write access */
|
||||
val = ldub_p(buf);
|
||||
result |= memory_region_dispatch_write(mr, addr1, val, 1,
|
||||
attrs);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
} else {
|
||||
addr1 += memory_region_get_ram_addr(mr);
|
||||
/* RAM case */
|
||||
ptr = qemu_get_ram_ptr(addr1);
|
||||
memcpy(ptr, buf, l);
|
||||
invalidate_and_set_dirty(mr, addr1, l);
|
||||
for (;;) {
|
||||
if (!memory_access_is_direct(mr, true)) {
|
||||
release_lock |= prepare_mmio_access(mr);
|
||||
l = memory_access_size(mr, l, addr1);
|
||||
/* XXX: could force current_cpu to NULL to avoid
|
||||
potential bugs */
|
||||
switch (l) {
|
||||
case 8:
|
||||
/* 64 bit write access */
|
||||
val = ldq_p(buf);
|
||||
result |= memory_region_dispatch_write(mr, addr1, val, 8,
|
||||
attrs);
|
||||
break;
|
||||
case 4:
|
||||
/* 32 bit write access */
|
||||
val = ldl_p(buf);
|
||||
result |= memory_region_dispatch_write(mr, addr1, val, 4,
|
||||
attrs);
|
||||
break;
|
||||
case 2:
|
||||
/* 16 bit write access */
|
||||
val = lduw_p(buf);
|
||||
result |= memory_region_dispatch_write(mr, addr1, val, 2,
|
||||
attrs);
|
||||
break;
|
||||
case 1:
|
||||
/* 8 bit write access */
|
||||
val = ldub_p(buf);
|
||||
result |= memory_region_dispatch_write(mr, addr1, val, 1,
|
||||
attrs);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
} else {
|
||||
if (!memory_access_is_direct(mr, is_write)) {
|
||||
/* I/O case */
|
||||
release_lock |= prepare_mmio_access(mr);
|
||||
l = memory_access_size(mr, l, addr1);
|
||||
switch (l) {
|
||||
case 8:
|
||||
/* 64 bit read access */
|
||||
result |= memory_region_dispatch_read(mr, addr1, &val, 8,
|
||||
attrs);
|
||||
stq_p(buf, val);
|
||||
break;
|
||||
case 4:
|
||||
/* 32 bit read access */
|
||||
result |= memory_region_dispatch_read(mr, addr1, &val, 4,
|
||||
attrs);
|
||||
stl_p(buf, val);
|
||||
break;
|
||||
case 2:
|
||||
/* 16 bit read access */
|
||||
result |= memory_region_dispatch_read(mr, addr1, &val, 2,
|
||||
attrs);
|
||||
stw_p(buf, val);
|
||||
break;
|
||||
case 1:
|
||||
/* 8 bit read access */
|
||||
result |= memory_region_dispatch_read(mr, addr1, &val, 1,
|
||||
attrs);
|
||||
stb_p(buf, val);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
} else {
|
||||
/* RAM case */
|
||||
ptr = qemu_get_ram_ptr(mr->ram_addr + addr1);
|
||||
memcpy(buf, ptr, l);
|
||||
}
|
||||
addr1 += memory_region_get_ram_addr(mr);
|
||||
/* RAM case */
|
||||
ptr = qemu_get_ram_ptr(addr1);
|
||||
memcpy(ptr, buf, l);
|
||||
invalidate_and_set_dirty(mr, addr1, l);
|
||||
}
|
||||
|
||||
if (release_lock) {
|
||||
@@ -2616,8 +2519,14 @@ MemTxResult address_space_rw(AddressSpace *as, hwaddr addr, MemTxAttrs attrs,
|
||||
len -= l;
|
||||
buf += l;
|
||||
addr += l;
|
||||
|
||||
if (!len) {
|
||||
break;
|
||||
}
|
||||
|
||||
l = len;
|
||||
mr = address_space_translate(as, addr, &addr1, &l, true);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -2625,15 +2534,122 @@ MemTxResult address_space_rw(AddressSpace *as, hwaddr addr, MemTxAttrs attrs,
|
||||
MemTxResult address_space_write(AddressSpace *as, hwaddr addr, MemTxAttrs attrs,
|
||||
const uint8_t *buf, int len)
|
||||
{
|
||||
return address_space_rw(as, addr, attrs, (uint8_t *)buf, len, true);
|
||||
hwaddr l;
|
||||
hwaddr addr1;
|
||||
MemoryRegion *mr;
|
||||
MemTxResult result = MEMTX_OK;
|
||||
|
||||
if (len > 0) {
|
||||
rcu_read_lock();
|
||||
l = len;
|
||||
mr = address_space_translate(as, addr, &addr1, &l, true);
|
||||
result = address_space_write_continue(as, addr, attrs, buf, len,
|
||||
addr1, l, mr);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
MemTxResult address_space_read(AddressSpace *as, hwaddr addr, MemTxAttrs attrs,
|
||||
uint8_t *buf, int len)
|
||||
/* Called within RCU critical section. */
|
||||
MemTxResult address_space_read_continue(AddressSpace *as, hwaddr addr,
|
||||
MemTxAttrs attrs, uint8_t *buf,
|
||||
int len, hwaddr addr1, hwaddr l,
|
||||
MemoryRegion *mr)
|
||||
{
|
||||
return address_space_rw(as, addr, attrs, buf, len, false);
|
||||
uint8_t *ptr;
|
||||
uint64_t val;
|
||||
MemTxResult result = MEMTX_OK;
|
||||
bool release_lock = false;
|
||||
|
||||
for (;;) {
|
||||
if (!memory_access_is_direct(mr, false)) {
|
||||
/* I/O case */
|
||||
release_lock |= prepare_mmio_access(mr);
|
||||
l = memory_access_size(mr, l, addr1);
|
||||
switch (l) {
|
||||
case 8:
|
||||
/* 64 bit read access */
|
||||
result |= memory_region_dispatch_read(mr, addr1, &val, 8,
|
||||
attrs);
|
||||
stq_p(buf, val);
|
||||
break;
|
||||
case 4:
|
||||
/* 32 bit read access */
|
||||
result |= memory_region_dispatch_read(mr, addr1, &val, 4,
|
||||
attrs);
|
||||
stl_p(buf, val);
|
||||
break;
|
||||
case 2:
|
||||
/* 16 bit read access */
|
||||
result |= memory_region_dispatch_read(mr, addr1, &val, 2,
|
||||
attrs);
|
||||
stw_p(buf, val);
|
||||
break;
|
||||
case 1:
|
||||
/* 8 bit read access */
|
||||
result |= memory_region_dispatch_read(mr, addr1, &val, 1,
|
||||
attrs);
|
||||
stb_p(buf, val);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
} else {
|
||||
/* RAM case */
|
||||
ptr = qemu_get_ram_ptr(mr->ram_addr + addr1);
|
||||
memcpy(buf, ptr, l);
|
||||
}
|
||||
|
||||
if (release_lock) {
|
||||
qemu_mutex_unlock_iothread();
|
||||
release_lock = false;
|
||||
}
|
||||
|
||||
len -= l;
|
||||
buf += l;
|
||||
addr += l;
|
||||
|
||||
if (!len) {
|
||||
break;
|
||||
}
|
||||
|
||||
l = len;
|
||||
mr = address_space_translate(as, addr, &addr1, &l, false);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
MemTxResult address_space_read_full(AddressSpace *as, hwaddr addr,
|
||||
MemTxAttrs attrs, uint8_t *buf, int len)
|
||||
{
|
||||
hwaddr l;
|
||||
hwaddr addr1;
|
||||
MemoryRegion *mr;
|
||||
MemTxResult result = MEMTX_OK;
|
||||
|
||||
if (len > 0) {
|
||||
rcu_read_lock();
|
||||
l = len;
|
||||
mr = address_space_translate(as, addr, &addr1, &l, false);
|
||||
result = address_space_read_continue(as, addr, attrs, buf, len,
|
||||
addr1, l, mr);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
MemTxResult address_space_rw(AddressSpace *as, hwaddr addr, MemTxAttrs attrs,
|
||||
uint8_t *buf, int len, bool is_write)
|
||||
{
|
||||
if (is_write) {
|
||||
return address_space_write(as, addr, attrs, (uint8_t *)buf, len);
|
||||
} else {
|
||||
return address_space_read(as, addr, attrs, (uint8_t *)buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
void cpu_physical_memory_rw(hwaddr addr, uint8_t *buf,
|
||||
int len, int is_write)
|
||||
@@ -2825,6 +2841,7 @@ void *address_space_map(AddressSpace *as,
|
||||
hwaddr l, xlat, base;
|
||||
MemoryRegion *mr, *this_mr;
|
||||
ram_addr_t raddr;
|
||||
void *ptr;
|
||||
|
||||
if (len == 0) {
|
||||
return NULL;
|
||||
@@ -2876,9 +2893,11 @@ void *address_space_map(AddressSpace *as,
|
||||
}
|
||||
|
||||
memory_region_ref(mr);
|
||||
rcu_read_unlock();
|
||||
*plen = done;
|
||||
return qemu_ram_ptr_length(raddr + base, plen);
|
||||
ptr = qemu_ram_ptr_length(raddr + base, plen);
|
||||
rcu_read_unlock();
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* Unmaps a memory region previously mapped by address_space_map().
|
||||
|
||||
+2
-1
@@ -10,6 +10,7 @@
|
||||
#include "alpha_sys.h"
|
||||
#include "qemu/log.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "trace.h"
|
||||
|
||||
|
||||
/* Fallback for unassigned PCI I/O operations. Avoids MCHK. */
|
||||
@@ -73,7 +74,7 @@ static uint64_t iack_read(void *opaque, hwaddr addr, unsigned size)
|
||||
static void special_write(void *opaque, hwaddr addr,
|
||||
uint64_t val, unsigned size)
|
||||
{
|
||||
qemu_log("pci: special write cycle");
|
||||
trace_alpha_pci_iack_write();
|
||||
}
|
||||
|
||||
const MemoryRegionOps alpha_pci_iack_ops = {
|
||||
|
||||
@@ -165,7 +165,7 @@ static void serial_receive(void *opaque, const uint8_t *buf, int size)
|
||||
|
||||
/* Got a byte. */
|
||||
if (s->rx_fifo_len >= 16) {
|
||||
qemu_log("WARNING: UART dropped char.\n");
|
||||
D(qemu_log("WARNING: UART dropped char.\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+41
-8
@@ -11,6 +11,7 @@
|
||||
*/
|
||||
|
||||
#include "hw/boards.h"
|
||||
#include "qapi-visit.h"
|
||||
#include "qapi/visitor.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
@@ -31,12 +32,39 @@ static void machine_set_accel(Object *obj, const char *value, Error **errp)
|
||||
ms->accel = g_strdup(value);
|
||||
}
|
||||
|
||||
static void machine_set_kernel_irqchip(Object *obj, bool value, Error **errp)
|
||||
static void machine_set_kernel_irqchip(Object *obj, Visitor *v,
|
||||
void *opaque, const char *name,
|
||||
Error **errp)
|
||||
{
|
||||
Error *err = NULL;
|
||||
MachineState *ms = MACHINE(obj);
|
||||
OnOffSplit mode;
|
||||
|
||||
ms->kernel_irqchip_allowed = value;
|
||||
ms->kernel_irqchip_required = value;
|
||||
visit_type_OnOffSplit(v, &mode, name, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
} else {
|
||||
switch (mode) {
|
||||
case ON_OFF_SPLIT_ON:
|
||||
ms->kernel_irqchip_allowed = true;
|
||||
ms->kernel_irqchip_required = true;
|
||||
ms->kernel_irqchip_split = false;
|
||||
break;
|
||||
case ON_OFF_SPLIT_OFF:
|
||||
ms->kernel_irqchip_allowed = false;
|
||||
ms->kernel_irqchip_required = false;
|
||||
ms->kernel_irqchip_split = false;
|
||||
break;
|
||||
case ON_OFF_SPLIT_SPLIT:
|
||||
ms->kernel_irqchip_allowed = true;
|
||||
ms->kernel_irqchip_required = true;
|
||||
ms->kernel_irqchip_split = true;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void machine_get_kvm_shadow_mem(Object *obj, Visitor *v,
|
||||
@@ -341,12 +369,12 @@ static void machine_initfn(Object *obj)
|
||||
object_property_set_description(obj, "accel",
|
||||
"Accelerator list",
|
||||
NULL);
|
||||
object_property_add_bool(obj, "kernel-irqchip",
|
||||
NULL,
|
||||
machine_set_kernel_irqchip,
|
||||
NULL);
|
||||
object_property_add(obj, "kernel-irqchip", "OnOffSplit",
|
||||
NULL,
|
||||
machine_set_kernel_irqchip,
|
||||
NULL, NULL, NULL);
|
||||
object_property_set_description(obj, "kernel-irqchip",
|
||||
"Use KVM in-kernel irqchip",
|
||||
"Configure KVM in-kernel irqchip",
|
||||
NULL);
|
||||
object_property_add(obj, "kvm-shadow-mem", "int",
|
||||
machine_get_kvm_shadow_mem,
|
||||
@@ -472,6 +500,11 @@ bool machine_kernel_irqchip_required(MachineState *machine)
|
||||
return machine->kernel_irqchip_required;
|
||||
}
|
||||
|
||||
bool machine_kernel_irqchip_split(MachineState *machine)
|
||||
{
|
||||
return machine->kernel_irqchip_split;
|
||||
}
|
||||
|
||||
int machine_kvm_shadow_mem(MachineState *machine)
|
||||
{
|
||||
return machine->kvm_shadow_mem;
|
||||
|
||||
@@ -146,14 +146,14 @@ static uint64_t virtio_gpu_get_features(VirtIODevice *vdev, uint64_t features,
|
||||
VirtIOGPU *g = VIRTIO_GPU(vdev);
|
||||
|
||||
if (virtio_gpu_virgl_enabled(g->conf)) {
|
||||
features |= (1 << VIRTIO_GPU_FEATURE_VIRGL);
|
||||
features |= (1 << VIRTIO_GPU_F_VIRGL);
|
||||
}
|
||||
return features;
|
||||
}
|
||||
|
||||
static void virtio_gpu_set_features(VirtIODevice *vdev, uint64_t features)
|
||||
{
|
||||
static const uint32_t virgl = (1 << VIRTIO_GPU_FEATURE_VIRGL);
|
||||
static const uint32_t virgl = (1 << VIRTIO_GPU_F_VIRGL);
|
||||
VirtIOGPU *g = VIRTIO_GPU(vdev);
|
||||
|
||||
g->use_virgl_renderer = ((features & virgl) == virgl);
|
||||
|
||||
+3
-2
@@ -65,6 +65,7 @@
|
||||
#include "hw/mem/pc-dimm.h"
|
||||
#include "qapi/visitor.h"
|
||||
#include "qapi-visit.h"
|
||||
#include "qom/cpu.h"
|
||||
|
||||
/* debug PC/ISA interrupts */
|
||||
//#define DEBUG_IRQ
|
||||
@@ -1517,7 +1518,7 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
|
||||
qemu_register_boot_set(pc_boot_set, *rtc_state);
|
||||
|
||||
if (!xen_enabled()) {
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
if (kvm_pit_in_kernel()) {
|
||||
pit = kvm_pit_init(isa_bus, 0x40);
|
||||
} else {
|
||||
pit = pit_init(isa_bus, 0x40, pit_isa_irq, pit_alt_irq);
|
||||
@@ -1592,7 +1593,7 @@ void ioapic_init_gsi(GSIState *gsi_state, const char *parent_name)
|
||||
SysBusDevice *d;
|
||||
unsigned int i;
|
||||
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
if (kvm_ioapic_in_kernel()) {
|
||||
dev = qdev_create(NULL, "kvm-ioapic");
|
||||
} else {
|
||||
dev = qdev_create(NULL, "ioapic");
|
||||
|
||||
+3
-2
@@ -53,6 +53,7 @@
|
||||
#include "hw/xen/xen_pt.h"
|
||||
#endif
|
||||
#include "migration/migration.h"
|
||||
#include "kvm_i386.h"
|
||||
|
||||
#define MAX_IDE_BUS 2
|
||||
|
||||
@@ -181,7 +182,7 @@ static void pc_init1(MachineState *machine,
|
||||
}
|
||||
|
||||
gsi_state = g_malloc0(sizeof(*gsi_state));
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
if (kvm_ioapic_in_kernel()) {
|
||||
kvm_pc_setup_irq_routing(pci_enabled);
|
||||
gsi = qemu_allocate_irqs(kvm_pc_gsi_handler, gsi_state,
|
||||
GSI_NUM_PINS);
|
||||
@@ -205,7 +206,7 @@ static void pc_init1(MachineState *machine,
|
||||
}
|
||||
isa_bus_irqs(isa_bus, gsi);
|
||||
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
if (kvm_pic_in_kernel()) {
|
||||
i8259 = kvm_i8259_init(isa_bus);
|
||||
} else if (xen_enabled()) {
|
||||
i8259 = xen_interrupt_controller_init();
|
||||
|
||||
+66
-2
@@ -25,6 +25,8 @@
|
||||
#include "hw/i386/pc.h"
|
||||
#include "hw/i386/ioapic.h"
|
||||
#include "hw/i386/ioapic_internal.h"
|
||||
#include "include/hw/pci/msi.h"
|
||||
#include "sysemu/kvm.h"
|
||||
|
||||
//#define DEBUG_IOAPIC
|
||||
|
||||
@@ -35,6 +37,10 @@
|
||||
#define DPRINTF(fmt, ...)
|
||||
#endif
|
||||
|
||||
#define APIC_DELIVERY_MODE_SHIFT 8
|
||||
#define APIC_POLARITY_SHIFT 14
|
||||
#define APIC_TRIG_MODE_SHIFT 15
|
||||
|
||||
static IOAPICCommonState *ioapics[MAX_IOAPICS];
|
||||
|
||||
/* global variable from ioapic_common.c */
|
||||
@@ -54,6 +60,8 @@ static void ioapic_service(IOAPICCommonState *s)
|
||||
for (i = 0; i < IOAPIC_NUM_PINS; i++) {
|
||||
mask = 1 << i;
|
||||
if (s->irr & mask) {
|
||||
int coalesce = 0;
|
||||
|
||||
entry = s->ioredtbl[i];
|
||||
if (!(entry & IOAPIC_LVT_MASKED)) {
|
||||
trig_mode = ((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1);
|
||||
@@ -64,6 +72,7 @@ static void ioapic_service(IOAPICCommonState *s)
|
||||
if (trig_mode == IOAPIC_TRIGGER_EDGE) {
|
||||
s->irr &= ~mask;
|
||||
} else {
|
||||
coalesce = s->ioredtbl[i] & IOAPIC_LVT_REMOTE_IRR;
|
||||
s->ioredtbl[i] |= IOAPIC_LVT_REMOTE_IRR;
|
||||
}
|
||||
if (delivery_mode == IOAPIC_DM_EXTINT) {
|
||||
@@ -71,8 +80,23 @@ static void ioapic_service(IOAPICCommonState *s)
|
||||
} else {
|
||||
vector = entry & IOAPIC_VECTOR_MASK;
|
||||
}
|
||||
apic_deliver_irq(dest, dest_mode, delivery_mode,
|
||||
vector, trig_mode);
|
||||
#ifdef CONFIG_KVM
|
||||
if (kvm_irqchip_is_split()) {
|
||||
if (trig_mode == IOAPIC_TRIGGER_EDGE) {
|
||||
kvm_set_irq(kvm_state, i, 1);
|
||||
kvm_set_irq(kvm_state, i, 0);
|
||||
} else {
|
||||
if (!coalesce) {
|
||||
kvm_set_irq(kvm_state, i, 1);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
#else
|
||||
(void)coalesce;
|
||||
#endif
|
||||
apic_deliver_irq(dest, dest_mode, delivery_mode, vector,
|
||||
trig_mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -116,6 +140,44 @@ static void ioapic_set_irq(void *opaque, int vector, int level)
|
||||
}
|
||||
}
|
||||
|
||||
static void ioapic_update_kvm_routes(IOAPICCommonState *s)
|
||||
{
|
||||
#ifdef CONFIG_KVM
|
||||
int i;
|
||||
|
||||
if (kvm_irqchip_is_split()) {
|
||||
for (i = 0; i < IOAPIC_NUM_PINS; i++) {
|
||||
uint64_t entry = s->ioredtbl[i];
|
||||
uint8_t trig_mode;
|
||||
uint8_t delivery_mode;
|
||||
uint8_t dest;
|
||||
uint8_t dest_mode;
|
||||
uint64_t pin_polarity;
|
||||
MSIMessage msg;
|
||||
|
||||
trig_mode = ((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1);
|
||||
dest = entry >> IOAPIC_LVT_DEST_SHIFT;
|
||||
dest_mode = (entry >> IOAPIC_LVT_DEST_MODE_SHIFT) & 1;
|
||||
pin_polarity = (entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1;
|
||||
delivery_mode =
|
||||
(entry >> IOAPIC_LVT_DELIV_MODE_SHIFT) & IOAPIC_DM_MASK;
|
||||
|
||||
msg.address = APIC_DEFAULT_ADDRESS;
|
||||
msg.address |= dest_mode << 2;
|
||||
msg.address |= dest << 12;
|
||||
|
||||
msg.data = entry & IOAPIC_VECTOR_MASK;
|
||||
msg.data |= delivery_mode << APIC_DELIVERY_MODE_SHIFT;
|
||||
msg.data |= pin_polarity << APIC_POLARITY_SHIFT;
|
||||
msg.data |= trig_mode << APIC_TRIG_MODE_SHIFT;
|
||||
|
||||
kvm_irqchip_update_msi_route(kvm_state, i, msg, NULL);
|
||||
}
|
||||
kvm_irqchip_commit_routes(kvm_state);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ioapic_eoi_broadcast(int vector)
|
||||
{
|
||||
IOAPICCommonState *s;
|
||||
@@ -229,6 +291,8 @@ ioapic_mem_write(void *opaque, hwaddr addr, uint64_t val,
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ioapic_update_kvm_routes(s);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps ioapic_io_ops = {
|
||||
|
||||
@@ -43,3 +43,4 @@ obj-$(CONFIG_STM32F2XX_SYSCFG) += stm32f2xx_syscfg.o
|
||||
|
||||
obj-$(CONFIG_PVPANIC) += pvpanic.o
|
||||
obj-$(CONFIG_EDU) += edu.o
|
||||
obj-$(CONFIG_HYPERV_TESTDEV) += hyperv_testdev.o
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* QEMU KVM Hyper-V test device to support Hyper-V kvm-unit-tests
|
||||
*
|
||||
* Copyright (C) 2015 Andrey Smetanin <asmetanin@virtuozzo.com>
|
||||
*
|
||||
* Authors:
|
||||
* Andrey Smetanin <asmetanin@virtuozzo.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "hw/hw.h"
|
||||
#include "hw/qdev.h"
|
||||
#include "hw/isa/isa.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "linux/kvm.h"
|
||||
#include "target-i386/hyperv.h"
|
||||
#include "kvm_i386.h"
|
||||
|
||||
#define HV_TEST_DEV_MAX_SINT_ROUTES 64
|
||||
|
||||
struct HypervTestDev {
|
||||
ISADevice parent_obj;
|
||||
MemoryRegion sint_control;
|
||||
HvSintRoute *sint_route[HV_TEST_DEV_MAX_SINT_ROUTES];
|
||||
};
|
||||
typedef struct HypervTestDev HypervTestDev;
|
||||
|
||||
#define TYPE_HYPERV_TEST_DEV "hyperv-testdev"
|
||||
#define HYPERV_TEST_DEV(obj) \
|
||||
OBJECT_CHECK(HypervTestDev, (obj), TYPE_HYPERV_TEST_DEV)
|
||||
|
||||
enum {
|
||||
HV_TEST_DEV_SINT_ROUTE_CREATE = 1,
|
||||
HV_TEST_DEV_SINT_ROUTE_DESTROY,
|
||||
HV_TEST_DEV_SINT_ROUTE_SET_SINT
|
||||
};
|
||||
|
||||
static int alloc_sint_route_index(HypervTestDev *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dev->sint_route); i++) {
|
||||
if (dev->sint_route[i] == NULL) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void free_sint_route_index(HypervTestDev *dev, int i)
|
||||
{
|
||||
assert(i >= 0 && i < ARRAY_SIZE(dev->sint_route));
|
||||
dev->sint_route[i] = NULL;
|
||||
}
|
||||
|
||||
static int find_sint_route_index(HypervTestDev *dev, uint32_t vcpu_id,
|
||||
uint32_t sint)
|
||||
{
|
||||
HvSintRoute *sint_route;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dev->sint_route); i++) {
|
||||
sint_route = dev->sint_route[i];
|
||||
if (sint_route && sint_route->vcpu_id == vcpu_id &&
|
||||
sint_route->sint == sint) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void hv_synic_test_dev_control(HypervTestDev *dev, uint32_t ctl,
|
||||
uint32_t vcpu_id, uint32_t sint)
|
||||
{
|
||||
int i;
|
||||
HvSintRoute *sint_route;
|
||||
|
||||
switch (ctl) {
|
||||
case HV_TEST_DEV_SINT_ROUTE_CREATE:
|
||||
i = alloc_sint_route_index(dev);
|
||||
assert(i >= 0);
|
||||
sint_route = kvm_hv_sint_route_create(vcpu_id, sint, NULL);
|
||||
assert(sint_route);
|
||||
dev->sint_route[i] = sint_route;
|
||||
break;
|
||||
case HV_TEST_DEV_SINT_ROUTE_DESTROY:
|
||||
i = find_sint_route_index(dev, vcpu_id, sint);
|
||||
assert(i >= 0);
|
||||
sint_route = dev->sint_route[i];
|
||||
kvm_hv_sint_route_destroy(sint_route);
|
||||
free_sint_route_index(dev, i);
|
||||
break;
|
||||
case HV_TEST_DEV_SINT_ROUTE_SET_SINT:
|
||||
i = find_sint_route_index(dev, vcpu_id, sint);
|
||||
assert(i >= 0);
|
||||
sint_route = dev->sint_route[i];
|
||||
kvm_hv_sint_route_set_sint(sint_route);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void hv_test_dev_control(void *opaque, hwaddr addr, uint64_t data,
|
||||
uint32_t len)
|
||||
{
|
||||
HypervTestDev *dev = HYPERV_TEST_DEV(opaque);
|
||||
uint8_t ctl;
|
||||
|
||||
ctl = (data >> 16ULL) & 0xFF;
|
||||
switch (ctl) {
|
||||
case HV_TEST_DEV_SINT_ROUTE_CREATE:
|
||||
case HV_TEST_DEV_SINT_ROUTE_DESTROY:
|
||||
case HV_TEST_DEV_SINT_ROUTE_SET_SINT: {
|
||||
uint8_t sint = data & 0xFF;
|
||||
uint8_t vcpu_id = (data >> 8ULL) & 0xFF;
|
||||
hv_synic_test_dev_control(dev, ctl, vcpu_id, sint);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps synic_test_sint_ops = {
|
||||
.write = hv_test_dev_control,
|
||||
.valid.min_access_size = 4,
|
||||
.valid.max_access_size = 4,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static void hv_test_dev_realizefn(DeviceState *d, Error **errp)
|
||||
{
|
||||
ISADevice *isa = ISA_DEVICE(d);
|
||||
HypervTestDev *dev = HYPERV_TEST_DEV(d);
|
||||
MemoryRegion *io = isa_address_space_io(isa);
|
||||
|
||||
memset(dev->sint_route, 0, sizeof(dev->sint_route));
|
||||
memory_region_init_io(&dev->sint_control, OBJECT(dev),
|
||||
&synic_test_sint_ops, dev,
|
||||
"hyperv-testdev-ctl", 4);
|
||||
memory_region_add_subregion(io, 0x3000, &dev->sint_control);
|
||||
}
|
||||
|
||||
static void hv_test_dev_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
||||
dc->realize = hv_test_dev_realizefn;
|
||||
}
|
||||
|
||||
static const TypeInfo hv_test_dev_info = {
|
||||
.name = TYPE_HYPERV_TEST_DEV,
|
||||
.parent = TYPE_ISA_DEVICE,
|
||||
.instance_size = sizeof(HypervTestDev),
|
||||
.class_init = hv_test_dev_class_init,
|
||||
};
|
||||
|
||||
static void hv_test_dev_register_types(void)
|
||||
{
|
||||
type_register_static(&hv_test_dev_info);
|
||||
}
|
||||
type_init(hv_test_dev_register_types);
|
||||
+4
-5
@@ -1759,9 +1759,6 @@ void scsi_req_cancel_async(SCSIRequest *req, Notifier *notifier)
|
||||
if (notifier) {
|
||||
notifier_list_add(&req->cancel_notifiers, notifier);
|
||||
}
|
||||
if (req->io_canceled) {
|
||||
return;
|
||||
}
|
||||
scsi_req_ref(req);
|
||||
scsi_req_dequeue(req);
|
||||
req->io_canceled = true;
|
||||
@@ -1841,11 +1838,13 @@ void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense)
|
||||
{
|
||||
SCSIRequest *req;
|
||||
|
||||
aio_context_acquire(blk_get_aio_context(sdev->conf.blk));
|
||||
while (!QTAILQ_EMPTY(&sdev->requests)) {
|
||||
req = QTAILQ_FIRST(&sdev->requests);
|
||||
scsi_req_cancel(req);
|
||||
scsi_req_cancel_async(req, NULL);
|
||||
}
|
||||
|
||||
blk_drain(sdev->conf.blk);
|
||||
aio_context_release(blk_get_aio_context(sdev->conf.blk));
|
||||
scsi_device_set_ua(sdev, sense);
|
||||
}
|
||||
|
||||
|
||||
+90
-6
@@ -32,7 +32,6 @@
|
||||
#include "trace.h"
|
||||
|
||||
|
||||
#define PVSCSI_MSI_OFFSET (0x50)
|
||||
#define PVSCSI_USE_64BIT (true)
|
||||
#define PVSCSI_PER_VECTOR_MASK (false)
|
||||
|
||||
@@ -49,9 +48,33 @@
|
||||
(stl_le_pci_dma(&container_of(m, PVSCSIState, rings)->parent_obj, \
|
||||
(m)->rs_pa + offsetof(struct PVSCSIRingsState, field), val))
|
||||
|
||||
typedef struct PVSCSIClass {
|
||||
PCIDeviceClass parent_class;
|
||||
DeviceRealize parent_dc_realize;
|
||||
} PVSCSIClass;
|
||||
|
||||
#define TYPE_PVSCSI "pvscsi"
|
||||
#define PVSCSI(obj) OBJECT_CHECK(PVSCSIState, (obj), TYPE_PVSCSI)
|
||||
|
||||
#define PVSCSI_DEVICE_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(PVSCSIClass, (klass), TYPE_PVSCSI)
|
||||
#define PVSCSI_DEVICE_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(PVSCSIClass, (obj), TYPE_PVSCSI)
|
||||
|
||||
/* Compatability flags for migration */
|
||||
#define PVSCSI_COMPAT_OLD_PCI_CONFIGURATION_BIT 0
|
||||
#define PVSCSI_COMPAT_OLD_PCI_CONFIGURATION \
|
||||
(1 << PVSCSI_COMPAT_OLD_PCI_CONFIGURATION_BIT)
|
||||
#define PVSCSI_COMPAT_DISABLE_PCIE_BIT 1
|
||||
#define PVSCSI_COMPAT_DISABLE_PCIE \
|
||||
(1 << PVSCSI_COMPAT_DISABLE_PCIE_BIT)
|
||||
|
||||
#define PVSCSI_USE_OLD_PCI_CONFIGURATION(s) \
|
||||
((s)->compat_flags & PVSCSI_COMPAT_OLD_PCI_CONFIGURATION)
|
||||
#define PVSCSI_MSI_OFFSET(s) \
|
||||
(PVSCSI_USE_OLD_PCI_CONFIGURATION(s) ? 0x50 : 0x7c)
|
||||
#define PVSCSI_EXP_EP_OFFSET (0x40)
|
||||
|
||||
typedef struct PVSCSIRingInfo {
|
||||
uint64_t rs_pa;
|
||||
uint32_t txr_len_mask;
|
||||
@@ -100,6 +123,8 @@ typedef struct {
|
||||
|
||||
PVSCSIRingInfo rings; /* Data transfer rings manager */
|
||||
uint32_t resetting; /* Reset in progress */
|
||||
|
||||
uint32_t compat_flags;
|
||||
} PVSCSIState;
|
||||
|
||||
typedef struct PVSCSIRequest {
|
||||
@@ -1019,7 +1044,7 @@ pvscsi_init_msi(PVSCSIState *s)
|
||||
int res;
|
||||
PCIDevice *d = PCI_DEVICE(s);
|
||||
|
||||
res = msi_init(d, PVSCSI_MSI_OFFSET, PVSCSI_MSIX_NUM_VECTORS,
|
||||
res = msi_init(d, PVSCSI_MSI_OFFSET(s), PVSCSI_MSIX_NUM_VECTORS,
|
||||
PVSCSI_USE_64BIT, PVSCSI_PER_VECTOR_MASK);
|
||||
if (res < 0) {
|
||||
trace_pvscsi_init_msi_fail(res);
|
||||
@@ -1069,9 +1094,16 @@ pvscsi_init(PCIDevice *pci_dev)
|
||||
|
||||
trace_pvscsi_state("init");
|
||||
|
||||
/* PCI subsystem ID */
|
||||
pci_dev->config[PCI_SUBSYSTEM_ID] = 0x00;
|
||||
pci_dev->config[PCI_SUBSYSTEM_ID + 1] = 0x10;
|
||||
/* PCI subsystem ID, subsystem vendor ID, revision */
|
||||
if (PVSCSI_USE_OLD_PCI_CONFIGURATION(s)) {
|
||||
pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID, 0x1000);
|
||||
} else {
|
||||
pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID,
|
||||
PCI_VENDOR_ID_VMWARE);
|
||||
pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID,
|
||||
PCI_DEVICE_ID_VMWARE_PVSCSI);
|
||||
pci_config_set_revision(pci_dev->config, 0x2);
|
||||
}
|
||||
|
||||
/* PCI latency timer = 255 */
|
||||
pci_dev->config[PCI_LATENCY_TIMER] = 0xff;
|
||||
@@ -1085,6 +1117,10 @@ pvscsi_init(PCIDevice *pci_dev)
|
||||
|
||||
pvscsi_init_msi(s);
|
||||
|
||||
if (pci_is_express(pci_dev) && pci_bus_is_express(pci_dev->bus)) {
|
||||
pcie_endpoint_cap_init(pci_dev, PVSCSI_EXP_EP_OFFSET);
|
||||
}
|
||||
|
||||
s->completion_worker = qemu_bh_new(pvscsi_process_completion_queue, s);
|
||||
if (!s->completion_worker) {
|
||||
pvscsi_cleanup_msi(s);
|
||||
@@ -1139,6 +1175,27 @@ pvscsi_post_load(void *opaque, int version_id)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool pvscsi_vmstate_need_pcie_device(void *opaque)
|
||||
{
|
||||
PVSCSIState *s = PVSCSI(opaque);
|
||||
|
||||
return !(s->compat_flags & PVSCSI_COMPAT_DISABLE_PCIE);
|
||||
}
|
||||
|
||||
static bool pvscsi_vmstate_test_pci_device(void *opaque, int version_id)
|
||||
{
|
||||
return !pvscsi_vmstate_need_pcie_device(opaque);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_pvscsi_pcie_device = {
|
||||
.name = "pvscsi/pcie",
|
||||
.needed = pvscsi_vmstate_need_pcie_device,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_PCIE_DEVICE(parent_obj, PVSCSIState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_pvscsi = {
|
||||
.name = "pvscsi",
|
||||
.version_id = 0,
|
||||
@@ -1146,7 +1203,9 @@ static const VMStateDescription vmstate_pvscsi = {
|
||||
.pre_save = pvscsi_pre_save,
|
||||
.post_load = pvscsi_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_PCI_DEVICE(parent_obj, PVSCSIState),
|
||||
VMSTATE_STRUCT_TEST(parent_obj, PVSCSIState,
|
||||
pvscsi_vmstate_test_pci_device, 0,
|
||||
vmstate_pci_device, PCIDevice),
|
||||
VMSTATE_UINT8(msi_used, PVSCSIState),
|
||||
VMSTATE_UINT32(resetting, PVSCSIState),
|
||||
VMSTATE_UINT64(reg_interrupt_status, PVSCSIState),
|
||||
@@ -1171,18 +1230,40 @@ static const VMStateDescription vmstate_pvscsi = {
|
||||
VMSTATE_UINT64(rings.filled_cmp_ptr, PVSCSIState),
|
||||
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
.subsections = (const VMStateDescription*[]) {
|
||||
&vmstate_pvscsi_pcie_device,
|
||||
NULL
|
||||
}
|
||||
};
|
||||
|
||||
static Property pvscsi_properties[] = {
|
||||
DEFINE_PROP_UINT8("use_msg", PVSCSIState, use_msg, 1),
|
||||
DEFINE_PROP_BIT("x-old-pci-configuration", PVSCSIState, compat_flags,
|
||||
PVSCSI_COMPAT_OLD_PCI_CONFIGURATION_BIT, false),
|
||||
DEFINE_PROP_BIT("x-disable-pcie", PVSCSIState, compat_flags,
|
||||
PVSCSI_COMPAT_DISABLE_PCIE_BIT, false),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void pvscsi_realize(DeviceState *qdev, Error **errp)
|
||||
{
|
||||
PVSCSIClass *pvs_c = PVSCSI_DEVICE_GET_CLASS(qdev);
|
||||
PCIDevice *pci_dev = PCI_DEVICE(qdev);
|
||||
PVSCSIState *s = PVSCSI(qdev);
|
||||
|
||||
if (!(s->compat_flags & PVSCSI_COMPAT_DISABLE_PCIE)) {
|
||||
pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS;
|
||||
}
|
||||
|
||||
pvs_c->parent_dc_realize(qdev, errp);
|
||||
}
|
||||
|
||||
static void pvscsi_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
||||
PVSCSIClass *pvs_k = PVSCSI_DEVICE_CLASS(klass);
|
||||
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
|
||||
|
||||
k->init = pvscsi_init;
|
||||
@@ -1191,6 +1272,8 @@ static void pvscsi_class_init(ObjectClass *klass, void *data)
|
||||
k->device_id = PCI_DEVICE_ID_VMWARE_PVSCSI;
|
||||
k->class_id = PCI_CLASS_STORAGE_SCSI;
|
||||
k->subsystem_id = 0x1000;
|
||||
pvs_k->parent_dc_realize = dc->realize;
|
||||
dc->realize = pvscsi_realize;
|
||||
dc->reset = pvscsi_reset;
|
||||
dc->vmsd = &vmstate_pvscsi;
|
||||
dc->props = pvscsi_properties;
|
||||
@@ -1202,6 +1285,7 @@ static void pvscsi_class_init(ObjectClass *klass, void *data)
|
||||
static const TypeInfo pvscsi_info = {
|
||||
.name = TYPE_PVSCSI,
|
||||
.parent = TYPE_PCI_DEVICE,
|
||||
.class_size = sizeof(PVSCSIClass),
|
||||
.instance_size = sizeof(PVSCSIState),
|
||||
.class_init = pvscsi_class_init,
|
||||
.interfaces = (InterfaceInfo[]) {
|
||||
|
||||
+103
-33
@@ -159,27 +159,33 @@ typedef struct MemoryRegionIoeventfd MemoryRegionIoeventfd;
|
||||
|
||||
struct MemoryRegion {
|
||||
Object parent_obj;
|
||||
|
||||
/* All fields are private - violators will be prosecuted */
|
||||
const MemoryRegionOps *ops;
|
||||
|
||||
/* The following fields should fit in a cache line */
|
||||
bool romd_mode;
|
||||
bool ram;
|
||||
bool subpage;
|
||||
bool readonly; /* For RAM regions */
|
||||
bool rom_device;
|
||||
bool flush_coalesced_mmio;
|
||||
bool global_locking;
|
||||
uint8_t dirty_log_mask;
|
||||
ram_addr_t ram_addr;
|
||||
Object *owner;
|
||||
const MemoryRegionIOMMUOps *iommu_ops;
|
||||
|
||||
const MemoryRegionOps *ops;
|
||||
void *opaque;
|
||||
MemoryRegion *container;
|
||||
Int128 size;
|
||||
hwaddr addr;
|
||||
void (*destructor)(MemoryRegion *mr);
|
||||
ram_addr_t ram_addr;
|
||||
uint64_t align;
|
||||
bool subpage;
|
||||
bool terminates;
|
||||
bool romd_mode;
|
||||
bool ram;
|
||||
bool skip_dump;
|
||||
bool readonly; /* For RAM regions */
|
||||
bool enabled;
|
||||
bool rom_device;
|
||||
bool warning_printed; /* For reservations */
|
||||
bool flush_coalesced_mmio;
|
||||
bool global_locking;
|
||||
uint8_t vga_logging_count;
|
||||
MemoryRegion *alias;
|
||||
hwaddr alias_offset;
|
||||
@@ -189,7 +195,6 @@ struct MemoryRegion {
|
||||
QTAILQ_ENTRY(MemoryRegion) subregions_link;
|
||||
QTAILQ_HEAD(coalesced_ranges, CoalescedMemoryRange) coalesced;
|
||||
const char *name;
|
||||
uint8_t dirty_log_mask;
|
||||
unsigned ioeventfd_nb;
|
||||
MemoryRegionIoeventfd *ioeventfds;
|
||||
NotifierList iommu_notify;
|
||||
@@ -518,7 +523,10 @@ uint64_t memory_region_size(MemoryRegion *mr);
|
||||
*
|
||||
* @mr: the memory region being queried
|
||||
*/
|
||||
bool memory_region_is_ram(MemoryRegion *mr);
|
||||
static inline bool memory_region_is_ram(MemoryRegion *mr)
|
||||
{
|
||||
return mr->ram;
|
||||
}
|
||||
|
||||
/**
|
||||
* memory_region_is_skip_dump: check whether a memory region should not be
|
||||
@@ -558,7 +566,11 @@ static inline bool memory_region_is_romd(MemoryRegion *mr)
|
||||
*
|
||||
* @mr: the memory region being queried
|
||||
*/
|
||||
bool memory_region_is_iommu(MemoryRegion *mr);
|
||||
static inline bool memory_region_is_iommu(MemoryRegion *mr)
|
||||
{
|
||||
return mr->iommu_ops;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* memory_region_notify_iommu: notify a change in an IOMMU translation entry.
|
||||
@@ -640,7 +652,11 @@ uint8_t memory_region_get_dirty_log_mask(MemoryRegion *mr);
|
||||
*
|
||||
* @mr: the memory region being queried
|
||||
*/
|
||||
bool memory_region_is_rom(MemoryRegion *mr);
|
||||
static inline bool memory_region_is_rom(MemoryRegion *mr)
|
||||
{
|
||||
return mr->ram && mr->readonly;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* memory_region_get_fd: Get a file descriptor backing a RAM memory region.
|
||||
@@ -656,8 +672,13 @@ int memory_region_get_fd(MemoryRegion *mr);
|
||||
* memory_region_get_ram_ptr: Get a pointer into a RAM memory region.
|
||||
*
|
||||
* Returns a host pointer to a RAM memory region (created with
|
||||
* memory_region_init_ram() or memory_region_init_ram_ptr()). Use with
|
||||
* care.
|
||||
* memory_region_init_ram() or memory_region_init_ram_ptr()).
|
||||
*
|
||||
* Use with care; by the time this function returns, the returned pointer is
|
||||
* not protected by RCU anymore. If the caller is not within an RCU critical
|
||||
* section and does not hold the iothread lock, it must have other means of
|
||||
* protecting the pointer, such as a reference to the region that includes
|
||||
* the incoming ram_addr_t.
|
||||
*
|
||||
* @mr: the memory region being queried.
|
||||
*/
|
||||
@@ -960,7 +981,10 @@ void memory_region_add_subregion_overlap(MemoryRegion *mr,
|
||||
* DO NOT USE THIS FUNCTION. This is a temporary workaround while the Xen
|
||||
* code is being reworked.
|
||||
*/
|
||||
ram_addr_t memory_region_get_ram_addr(MemoryRegion *mr);
|
||||
static inline ram_addr_t memory_region_get_ram_addr(MemoryRegion *mr)
|
||||
{
|
||||
return mr->ram_addr;
|
||||
}
|
||||
|
||||
uint64_t memory_region_get_alignment(const MemoryRegion *mr);
|
||||
/**
|
||||
@@ -1210,23 +1234,7 @@ MemTxResult address_space_write(AddressSpace *as, hwaddr addr,
|
||||
MemTxAttrs attrs,
|
||||
const uint8_t *buf, int len);
|
||||
|
||||
/**
|
||||
* address_space_read: read from an address space.
|
||||
*
|
||||
* Return a MemTxResult indicating whether the operation succeeded
|
||||
* or failed (eg unassigned memory, device rejected the transaction,
|
||||
* IOMMU fault).
|
||||
*
|
||||
* @as: #AddressSpace to be accessed
|
||||
* @addr: address within that address space
|
||||
* @attrs: memory transaction attributes
|
||||
* @buf: buffer with the data transferred
|
||||
*/
|
||||
MemTxResult address_space_read(AddressSpace *as, hwaddr addr, MemTxAttrs attrs,
|
||||
uint8_t *buf, int len);
|
||||
|
||||
/**
|
||||
* address_space_ld*: load from an address space
|
||||
/* address_space_ld*: load from an address space
|
||||
* address_space_st*: store to an address space
|
||||
*
|
||||
* These functions perform a load or store of the byte, word,
|
||||
@@ -1356,6 +1364,68 @@ void address_space_unmap(AddressSpace *as, void *buffer, hwaddr len,
|
||||
int is_write, hwaddr access_len);
|
||||
|
||||
|
||||
/* Internal functions, part of the implementation of address_space_read. */
|
||||
MemTxResult address_space_read_continue(AddressSpace *as, hwaddr addr,
|
||||
MemTxAttrs attrs, uint8_t *buf,
|
||||
int len, hwaddr addr1, hwaddr l,
|
||||
MemoryRegion *mr);
|
||||
MemTxResult address_space_read_full(AddressSpace *as, hwaddr addr,
|
||||
MemTxAttrs attrs, uint8_t *buf, int len);
|
||||
void *qemu_get_ram_ptr(ram_addr_t addr);
|
||||
|
||||
static inline bool memory_access_is_direct(MemoryRegion *mr, bool is_write)
|
||||
{
|
||||
if (is_write) {
|
||||
return memory_region_is_ram(mr) && !mr->readonly;
|
||||
} else {
|
||||
return memory_region_is_ram(mr) || memory_region_is_romd(mr);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* address_space_read: read from an address space.
|
||||
*
|
||||
* Return a MemTxResult indicating whether the operation succeeded
|
||||
* or failed (eg unassigned memory, device rejected the transaction,
|
||||
* IOMMU fault).
|
||||
*
|
||||
* @as: #AddressSpace to be accessed
|
||||
* @addr: address within that address space
|
||||
* @attrs: memory transaction attributes
|
||||
* @buf: buffer with the data transferred
|
||||
*/
|
||||
static inline __attribute__((__always_inline__))
|
||||
MemTxResult address_space_read(AddressSpace *as, hwaddr addr, MemTxAttrs attrs,
|
||||
uint8_t *buf, int len)
|
||||
{
|
||||
MemTxResult result = MEMTX_OK;
|
||||
hwaddr l, addr1;
|
||||
void *ptr;
|
||||
MemoryRegion *mr;
|
||||
|
||||
if (__builtin_constant_p(len)) {
|
||||
if (len) {
|
||||
rcu_read_lock();
|
||||
l = len;
|
||||
mr = address_space_translate(as, addr, &addr1, &l, false);
|
||||
if (len == l && memory_access_is_direct(mr, false)) {
|
||||
addr1 += memory_region_get_ram_addr(mr);
|
||||
ptr = qemu_get_ram_ptr(addr1);
|
||||
memcpy(buf, ptr, len);
|
||||
} else {
|
||||
result = address_space_read_continue(as, addr, attrs, buf, len,
|
||||
addr1, l, mr);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
} else {
|
||||
result = address_space_read_full(as, addr, attrs, buf, len);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -73,9 +73,7 @@ ram_addr_t qemu_ram_alloc_resizeable(ram_addr_t size, ram_addr_t max_size,
|
||||
MemoryRegion *mr, Error **errp);
|
||||
int qemu_get_ram_fd(ram_addr_t addr);
|
||||
void *qemu_get_ram_block_host_ptr(ram_addr_t addr);
|
||||
void *qemu_get_ram_ptr(ram_addr_t addr);
|
||||
void qemu_ram_free(ram_addr_t addr);
|
||||
void qemu_ram_free_from_ptr(ram_addr_t addr);
|
||||
|
||||
int qemu_ram_resize(ram_addr_t base, ram_addr_t newsize, Error **errp);
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ extern MachineState *current_machine;
|
||||
bool machine_usb(MachineState *machine);
|
||||
bool machine_kernel_irqchip_allowed(MachineState *machine);
|
||||
bool machine_kernel_irqchip_required(MachineState *machine);
|
||||
bool machine_kernel_irqchip_split(MachineState *machine);
|
||||
int machine_kvm_shadow_mem(MachineState *machine);
|
||||
int machine_phandle_start(MachineState *machine);
|
||||
bool machine_dump_guest_core(MachineState *machine);
|
||||
@@ -111,6 +112,7 @@ struct MachineState {
|
||||
char *accel;
|
||||
bool kernel_irqchip_allowed;
|
||||
bool kernel_irqchip_required;
|
||||
bool kernel_irqchip_split;
|
||||
int kvm_shadow_mem;
|
||||
char *dtb;
|
||||
char *dumpdtb;
|
||||
|
||||
@@ -6,6 +6,14 @@
|
||||
.driver = "virtio-blk-device",\
|
||||
.property = "scsi",\
|
||||
.value = "true",\
|
||||
},{\
|
||||
.driver = "pvscsi",\
|
||||
.property = "x-old-pci-configuration",\
|
||||
.value = "on",\
|
||||
},{\
|
||||
.driver = "pvscsi",\
|
||||
.property = "x-disable-pcie",\
|
||||
.value = "on",\
|
||||
},{\
|
||||
.driver = "e1000",\
|
||||
.property = "extra_mac_registers",\
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user