Compare commits
93
Commits
v2.4.0-rc3
...
stable-2.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
32d24131b2 | ||
|
|
fc63922556 | ||
|
|
36e1eee760 | ||
|
|
9137bd24c8 | ||
|
|
08231cbb76 | ||
|
|
70a4483abb | ||
|
|
39809852a7 | ||
|
|
db97d9d886 | ||
|
|
243b80c9c5 | ||
|
|
91232d98da | ||
|
|
d68ba3cab3 | ||
|
|
381a290266 | ||
|
|
696317f189 | ||
|
|
c2a550d3df | ||
|
|
a64d4cafa9 | ||
|
|
2f99c80963 | ||
|
|
f62c10bd20 | ||
|
|
8c4fa92d01 | ||
|
|
7c22dcdeb8 | ||
|
|
16514367ef | ||
|
|
55b4efb034 | ||
|
|
2874c6565e | ||
|
|
2d0583fc79 | ||
|
|
40161bf27b | ||
|
|
2935ae915a | ||
|
|
2f3c310818 | ||
|
|
1f21d3b8dc | ||
|
|
bac9ce97d3 | ||
|
|
33fca8589c | ||
|
|
a479b21c11 | ||
|
|
d11ff15fd5 | ||
|
|
1b8e1f7ad9 | ||
|
|
e00bf9ee70 | ||
|
|
78aeb6984c | ||
|
|
6d62d0e3dd | ||
|
|
5644f6f924 | ||
|
|
63d761388d | ||
|
|
c13b1c8314 | ||
|
|
052677b2c8 | ||
|
|
0fdf9f756f | ||
|
|
d077545dfe | ||
|
|
f6737604da | ||
|
|
d2b0f96fe2 | ||
|
|
a00431853f | ||
|
|
b51715e1c0 | ||
|
|
267bc47438 | ||
|
|
955ff148de | ||
|
|
71b685832d | ||
|
|
9a20ccaecd | ||
|
|
d9af73191c | ||
|
|
637dd0bb7c | ||
|
|
2ac9fa162e | ||
|
|
5b7d840e74 | ||
|
|
0de7d2b793 | ||
|
|
f399ea092e | ||
|
|
83c92b4514 | ||
|
|
5a1ccdfe44 | ||
|
|
7aa2bcad0c | ||
|
|
3a56af1fbc | ||
|
|
efec4dcd25 | ||
|
|
5c79ae3615 | ||
|
|
2d697366a1 | ||
|
|
0175409df4 | ||
|
|
e94867ed5f | ||
|
|
74aae7b22b | ||
|
|
2be4f242b5 | ||
|
|
27751aabd1 | ||
|
|
426d0e7b7e | ||
|
|
b7f26e5239 | ||
|
|
060ebfef1a | ||
|
|
260425ab40 | ||
|
|
e95edefbd0 | ||
|
|
8c6dc68f4c | ||
|
|
c69adea462 | ||
|
|
f60c87154a | ||
|
|
6cd387833d | ||
|
|
2a3612ccc1 | ||
|
|
8357946b15 | ||
|
|
4240be4563 | ||
|
|
c6296ea88d | ||
|
|
03247d43c5 | ||
|
|
e1c120a9c5 | ||
|
|
d6812d60e7 | ||
|
|
39b8e7dcaf | ||
|
|
bd80b5963f | ||
|
|
ff90f84e74 | ||
|
|
c99d69694a | ||
|
|
3c8691f568 | ||
|
|
4214a8cb7c | ||
|
|
e72c4fb81d | ||
|
|
91ced51446 | ||
|
|
0e826a061a | ||
|
|
cb48f67ad8 |
No files matched your search
@@ -1214,6 +1214,10 @@ static void iscsi_readcapacity_sync(IscsiLun *iscsilun, Error **errp)
|
||||
|
||||
if (task == NULL || task->status != SCSI_STATUS_GOOD) {
|
||||
error_setg(errp, "iSCSI: failed to send readcapacity10 command.");
|
||||
} else if (!iscsilun->block_size ||
|
||||
iscsilun->block_size % BDRV_SECTOR_SIZE) {
|
||||
error_setg(errp, "iSCSI: the target returned an invalid "
|
||||
"block size of %d.", iscsilun->block_size);
|
||||
}
|
||||
if (task) {
|
||||
scsi_free_scsi_task(task);
|
||||
|
||||
+10
-5
@@ -60,6 +60,7 @@ typedef struct MirrorBlockJob {
|
||||
int sectors_in_flight;
|
||||
int ret;
|
||||
bool unmap;
|
||||
bool waiting_for_io;
|
||||
} MirrorBlockJob;
|
||||
|
||||
typedef struct MirrorOp {
|
||||
@@ -114,11 +115,7 @@ static void mirror_iteration_done(MirrorOp *op, int ret)
|
||||
qemu_iovec_destroy(&op->qiov);
|
||||
g_slice_free(MirrorOp, op);
|
||||
|
||||
/* Enter coroutine when it is not sleeping. The coroutine sleeps to
|
||||
* rate-limit itself. The coroutine will eventually resume since there is
|
||||
* a sleep timeout so don't wake it early.
|
||||
*/
|
||||
if (s->common.busy) {
|
||||
if (s->waiting_for_io) {
|
||||
qemu_coroutine_enter(s->common.co, NULL);
|
||||
}
|
||||
}
|
||||
@@ -203,7 +200,9 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
|
||||
/* Wait for I/O to this cluster (from a previous iteration) to be done. */
|
||||
while (test_bit(next_chunk, s->in_flight_bitmap)) {
|
||||
trace_mirror_yield_in_flight(s, sector_num, s->in_flight);
|
||||
s->waiting_for_io = true;
|
||||
qemu_coroutine_yield();
|
||||
s->waiting_for_io = false;
|
||||
}
|
||||
|
||||
do {
|
||||
@@ -239,7 +238,9 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
|
||||
*/
|
||||
while (nb_chunks == 0 && s->buf_free_count < added_chunks) {
|
||||
trace_mirror_yield_buf_busy(s, nb_chunks, s->in_flight);
|
||||
s->waiting_for_io = true;
|
||||
qemu_coroutine_yield();
|
||||
s->waiting_for_io = false;
|
||||
}
|
||||
if (s->buf_free_count < nb_chunks + added_chunks) {
|
||||
trace_mirror_break_buf_busy(s, nb_chunks, s->in_flight);
|
||||
@@ -333,7 +334,9 @@ static void mirror_free_init(MirrorBlockJob *s)
|
||||
static void mirror_drain(MirrorBlockJob *s)
|
||||
{
|
||||
while (s->in_flight > 0) {
|
||||
s->waiting_for_io = true;
|
||||
qemu_coroutine_yield();
|
||||
s->waiting_for_io = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -506,7 +509,9 @@ static void coroutine_fn mirror_run(void *opaque)
|
||||
if (s->in_flight == MAX_IN_FLIGHT || s->buf_free_count == 0 ||
|
||||
(cnt == 0 && s->in_flight > 0)) {
|
||||
trace_mirror_yield(s, s->in_flight, s->buf_free_count, cnt);
|
||||
s->waiting_for_io = true;
|
||||
qemu_coroutine_yield();
|
||||
s->waiting_for_io = false;
|
||||
continue;
|
||||
} else if (cnt != 0) {
|
||||
delay_ns = mirror_iteration(s);
|
||||
|
||||
+1
-1
@@ -475,7 +475,7 @@ static int64_t nfs_get_allocated_file_size(BlockDriverState *bs)
|
||||
aio_poll(client->aio_context, true);
|
||||
}
|
||||
|
||||
return (task.ret < 0 ? task.ret : st.st_blocks * st.st_blksize);
|
||||
return (task.ret < 0 ? task.ret : st.st_blocks * 512);
|
||||
}
|
||||
|
||||
static int nfs_file_truncate(BlockDriverState *bs, int64_t offset)
|
||||
|
||||
+18
-10
@@ -298,7 +298,7 @@ fail:
|
||||
* as contiguous. (This allows it, for example, to stop at the first compressed
|
||||
* cluster which may require a different handling)
|
||||
*/
|
||||
static int count_contiguous_clusters(uint64_t nb_clusters, int cluster_size,
|
||||
static int count_contiguous_clusters(int nb_clusters, int cluster_size,
|
||||
uint64_t *l2_table, uint64_t stop_flags)
|
||||
{
|
||||
int i;
|
||||
@@ -321,7 +321,7 @@ static int count_contiguous_clusters(uint64_t nb_clusters, int cluster_size,
|
||||
return i;
|
||||
}
|
||||
|
||||
static int count_contiguous_free_clusters(uint64_t nb_clusters, uint64_t *l2_table)
|
||||
static int count_contiguous_free_clusters(int nb_clusters, uint64_t *l2_table)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -495,6 +495,7 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||
if (nb_needed > nb_available) {
|
||||
nb_needed = nb_available;
|
||||
}
|
||||
assert(nb_needed <= INT_MAX);
|
||||
|
||||
*cluster_offset = 0;
|
||||
|
||||
@@ -530,6 +531,8 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||
|
||||
l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1);
|
||||
*cluster_offset = be64_to_cpu(l2_table[l2_index]);
|
||||
|
||||
/* nb_needed <= INT_MAX, thus nb_clusters <= INT_MAX, too */
|
||||
nb_clusters = size_to_clusters(s, nb_needed << 9);
|
||||
|
||||
ret = qcow2_get_cluster_type(*cluster_offset);
|
||||
@@ -960,7 +963,7 @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset,
|
||||
int l2_index;
|
||||
uint64_t cluster_offset;
|
||||
uint64_t *l2_table;
|
||||
unsigned int nb_clusters;
|
||||
uint64_t nb_clusters;
|
||||
unsigned int keep_clusters;
|
||||
int ret;
|
||||
|
||||
@@ -979,6 +982,7 @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset,
|
||||
|
||||
l2_index = offset_to_l2_index(s, guest_offset);
|
||||
nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
|
||||
assert(nb_clusters <= INT_MAX);
|
||||
|
||||
/* Find L2 entry for the first involved cluster */
|
||||
ret = get_cluster_table(bs, guest_offset, &l2_table, &l2_index);
|
||||
@@ -1061,7 +1065,7 @@ out:
|
||||
* restarted, but the whole request should not be failed.
|
||||
*/
|
||||
static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset,
|
||||
uint64_t *host_offset, unsigned int *nb_clusters)
|
||||
uint64_t *host_offset, uint64_t *nb_clusters)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
|
||||
@@ -1079,7 +1083,7 @@ static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset,
|
||||
*host_offset = cluster_offset;
|
||||
return 0;
|
||||
} else {
|
||||
int ret = qcow2_alloc_clusters_at(bs, *host_offset, *nb_clusters);
|
||||
int64_t ret = qcow2_alloc_clusters_at(bs, *host_offset, *nb_clusters);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
@@ -1115,7 +1119,7 @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
|
||||
int l2_index;
|
||||
uint64_t *l2_table;
|
||||
uint64_t entry;
|
||||
unsigned int nb_clusters;
|
||||
uint64_t nb_clusters;
|
||||
int ret;
|
||||
|
||||
uint64_t alloc_cluster_offset;
|
||||
@@ -1133,6 +1137,7 @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
|
||||
|
||||
l2_index = offset_to_l2_index(s, guest_offset);
|
||||
nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
|
||||
assert(nb_clusters <= INT_MAX);
|
||||
|
||||
/* Find L2 entry for the first involved cluster */
|
||||
ret = get_cluster_table(bs, guest_offset, &l2_table, &l2_index);
|
||||
@@ -1426,7 +1431,8 @@ int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
|
||||
* clusters.
|
||||
*/
|
||||
static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
|
||||
unsigned int nb_clusters, enum qcow2_discard_type type, bool full_discard)
|
||||
uint64_t nb_clusters, enum qcow2_discard_type type,
|
||||
bool full_discard)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
uint64_t *l2_table;
|
||||
@@ -1441,6 +1447,7 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
|
||||
|
||||
/* Limit nb_clusters to one L2 table */
|
||||
nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
|
||||
assert(nb_clusters <= INT_MAX);
|
||||
|
||||
for (i = 0; i < nb_clusters; i++) {
|
||||
uint64_t old_l2_entry;
|
||||
@@ -1503,7 +1510,7 @@ int qcow2_discard_clusters(BlockDriverState *bs, uint64_t offset,
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
uint64_t end_offset;
|
||||
unsigned int nb_clusters;
|
||||
uint64_t nb_clusters;
|
||||
int ret;
|
||||
|
||||
end_offset = offset + (nb_sectors << BDRV_SECTOR_BITS);
|
||||
@@ -1545,7 +1552,7 @@ fail:
|
||||
* clusters.
|
||||
*/
|
||||
static int zero_single_l2(BlockDriverState *bs, uint64_t offset,
|
||||
unsigned int nb_clusters)
|
||||
uint64_t nb_clusters)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
uint64_t *l2_table;
|
||||
@@ -1560,6 +1567,7 @@ static int zero_single_l2(BlockDriverState *bs, uint64_t offset,
|
||||
|
||||
/* Limit nb_clusters to one L2 table */
|
||||
nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
|
||||
assert(nb_clusters <= INT_MAX);
|
||||
|
||||
for (i = 0; i < nb_clusters; i++) {
|
||||
uint64_t old_offset;
|
||||
@@ -1584,7 +1592,7 @@ static int zero_single_l2(BlockDriverState *bs, uint64_t offset,
|
||||
int qcow2_zero_clusters(BlockDriverState *bs, uint64_t offset, int nb_sectors)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
unsigned int nb_clusters;
|
||||
uint64_t nb_clusters;
|
||||
int ret;
|
||||
|
||||
/* The zero flag is only supported by version 3 and newer */
|
||||
|
||||
@@ -875,8 +875,8 @@ int64_t qcow2_alloc_clusters(BlockDriverState *bs, uint64_t size)
|
||||
return offset;
|
||||
}
|
||||
|
||||
int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
|
||||
int nb_clusters)
|
||||
int64_t qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
|
||||
int64_t nb_clusters)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
uint64_t cluster_index, refcount;
|
||||
@@ -1259,7 +1259,7 @@ static size_t refcount_array_byte_size(BDRVQcowState *s, uint64_t entries)
|
||||
static int realloc_refcount_array(BDRVQcowState *s, void **array,
|
||||
int64_t *size, int64_t new_size)
|
||||
{
|
||||
size_t old_byte_size, new_byte_size;
|
||||
int64_t old_byte_size, new_byte_size;
|
||||
void *new_ptr;
|
||||
|
||||
/* Round to clusters so the array can be directly written to disk */
|
||||
@@ -1275,13 +1275,17 @@ static int realloc_refcount_array(BDRVQcowState *s, void **array,
|
||||
|
||||
assert(new_byte_size > 0);
|
||||
|
||||
if (new_byte_size > SIZE_MAX) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
new_ptr = g_try_realloc(*array, new_byte_size);
|
||||
if (!new_ptr) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (new_byte_size > old_byte_size) {
|
||||
memset((void *)((uintptr_t)new_ptr + old_byte_size), 0,
|
||||
memset((char *)new_ptr + old_byte_size, 0,
|
||||
new_byte_size - old_byte_size);
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -412,7 +412,7 @@ static inline int64_t offset_into_cluster(BDRVQcowState *s, int64_t offset)
|
||||
return offset & (s->cluster_size - 1);
|
||||
}
|
||||
|
||||
static inline int size_to_clusters(BDRVQcowState *s, int64_t size)
|
||||
static inline uint64_t size_to_clusters(BDRVQcowState *s, uint64_t size)
|
||||
{
|
||||
return (size + (s->cluster_size - 1)) >> s->cluster_bits;
|
||||
}
|
||||
@@ -506,8 +506,8 @@ int qcow2_update_cluster_refcount(BlockDriverState *bs, int64_t cluster_index,
|
||||
enum qcow2_discard_type type);
|
||||
|
||||
int64_t qcow2_alloc_clusters(BlockDriverState *bs, uint64_t size);
|
||||
int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
|
||||
int nb_clusters);
|
||||
int64_t qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
|
||||
int64_t nb_clusters);
|
||||
int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size);
|
||||
void qcow2_free_clusters(BlockDriverState *bs,
|
||||
int64_t offset, int64_t size,
|
||||
|
||||
+4
-6
@@ -865,12 +865,6 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
int i;
|
||||
int ret = 0;
|
||||
|
||||
if (!qcrypto_hash_supports(QCRYPTO_HASH_ALG_SHA256)) {
|
||||
error_setg(errp,
|
||||
"SHA256 hash support is required for quorum device");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
qdict_flatten(options);
|
||||
|
||||
/* count how many different children are present */
|
||||
@@ -1061,6 +1055,10 @@ static BlockDriver bdrv_quorum = {
|
||||
|
||||
static void bdrv_quorum_init(void)
|
||||
{
|
||||
if (!qcrypto_hash_supports(QCRYPTO_HASH_ALG_SHA256)) {
|
||||
/* SHA256 hash support is required for quorum device */
|
||||
return;
|
||||
}
|
||||
bdrv_register(&bdrv_quorum);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -173,7 +173,7 @@ void cpu_loop(CPUX86State *env)
|
||||
//target_siginfo_t info;
|
||||
|
||||
for(;;) {
|
||||
trapnr = cpu_x86_exec(env);
|
||||
trapnr = cpu_x86_exec(cs);
|
||||
switch(trapnr) {
|
||||
case 0x80:
|
||||
/* syscall from int $0x80 */
|
||||
|
||||
@@ -1337,7 +1337,6 @@ disabled with --disable-FEATURE, default is enabled if available:
|
||||
vnc-sasl SASL encryption for VNC server
|
||||
vnc-jpeg JPEG lossy compression for VNC server
|
||||
vnc-png PNG compression for VNC server
|
||||
vnc-ws Websockets support for VNC server
|
||||
cocoa Cocoa UI (Mac OS X only)
|
||||
virtfs VirtFS
|
||||
xen xen backend driver support
|
||||
|
||||
@@ -1166,7 +1166,7 @@ void qemu_mutex_lock_iothread(void)
|
||||
* TCG code execution.
|
||||
*/
|
||||
if (!tcg_enabled() || qemu_in_vcpu_thread() ||
|
||||
!first_cpu || !first_cpu->thread) {
|
||||
!first_cpu || !first_cpu->created) {
|
||||
qemu_mutex_lock(&qemu_global_mutex);
|
||||
atomic_dec(&iothread_requesting_mutex);
|
||||
} else {
|
||||
|
||||
@@ -103,6 +103,12 @@ static void aw_a10_class_init(ObjectClass *oc, void *data)
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
dc->realize = aw_a10_realize;
|
||||
|
||||
/*
|
||||
* Reason: creates an ARM CPU, thus use after free(), see
|
||||
* arm_cpu_class_init()
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static const TypeInfo aw_a10_type_info = {
|
||||
|
||||
@@ -97,6 +97,12 @@ static void digic_class_init(ObjectClass *oc, void *data)
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
dc->realize = digic_realize;
|
||||
|
||||
/*
|
||||
* Reason: creates an ARM CPU, thus use after free(), see
|
||||
* arm_cpu_class_init()
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static const TypeInfo digic_type_info = {
|
||||
|
||||
+1
-1
@@ -1959,7 +1959,7 @@ static void pxa2xx_fir_instance_init(Object *obj)
|
||||
PXA2xxFIrState *s = PXA2XX_FIR(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
|
||||
memory_region_init_io(&s->iomem, NULL, &pxa2xx_fir_ops, s,
|
||||
memory_region_init_io(&s->iomem, obj, &pxa2xx_fir_ops, s,
|
||||
"pxa2xx-fir", 0x1000);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
|
||||
@@ -248,6 +248,12 @@ static void xlnx_zynqmp_class_init(ObjectClass *oc, void *data)
|
||||
|
||||
dc->props = xlnx_zynqmp_props;
|
||||
dc->realize = xlnx_zynqmp_realize;
|
||||
|
||||
/*
|
||||
* Reason: creates an ARM CPU, thus use after free(), see
|
||||
* arm_cpu_class_init()
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static const TypeInfo xlnx_zynqmp_type_info = {
|
||||
|
||||
@@ -731,7 +731,7 @@ static uint64_t virtio_blk_get_features(VirtIODevice *vdev, uint64_t features,
|
||||
virtio_add_feature(&features, VIRTIO_BLK_F_GEOMETRY);
|
||||
virtio_add_feature(&features, VIRTIO_BLK_F_TOPOLOGY);
|
||||
virtio_add_feature(&features, VIRTIO_BLK_F_BLK_SIZE);
|
||||
if (__virtio_has_feature(features, VIRTIO_F_VERSION_1)) {
|
||||
if (virtio_has_feature(features, VIRTIO_F_VERSION_1)) {
|
||||
if (s->conf.scsi) {
|
||||
error_setg(errp, "Please set scsi=off for virtio-blk devices in order to use virtio 1.0");
|
||||
return 0;
|
||||
@@ -782,10 +782,11 @@ static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status)
|
||||
*
|
||||
* s->blk would erroneously be placed in writethrough mode.
|
||||
*/
|
||||
if (!virtio_has_feature(vdev, VIRTIO_BLK_F_CONFIG_WCE)) {
|
||||
if (!virtio_vdev_has_feature(vdev, VIRTIO_BLK_F_CONFIG_WCE)) {
|
||||
aio_context_acquire(blk_get_aio_context(s->blk));
|
||||
blk_set_enable_write_cache(s->blk,
|
||||
virtio_has_feature(vdev, VIRTIO_BLK_F_WCE));
|
||||
virtio_vdev_has_feature(vdev,
|
||||
VIRTIO_BLK_F_WCE));
|
||||
aio_context_release(blk_get_aio_context(s->blk));
|
||||
}
|
||||
}
|
||||
@@ -793,6 +794,11 @@ static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status)
|
||||
static void virtio_blk_save(QEMUFile *f, void *opaque)
|
||||
{
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(opaque);
|
||||
VirtIOBlock *s = VIRTIO_BLK(vdev);
|
||||
|
||||
if (s->dataplane) {
|
||||
virtio_blk_data_plane_stop(s->dataplane);
|
||||
}
|
||||
|
||||
virtio_save(vdev, f);
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ static VirtIOSerialPort *find_port_by_name(char *name)
|
||||
static bool use_multiport(VirtIOSerial *vser)
|
||||
{
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(vser);
|
||||
return virtio_has_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT);
|
||||
return virtio_vdev_has_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT);
|
||||
}
|
||||
|
||||
static size_t write_to_port(VirtIOSerialPort *port,
|
||||
|
||||
+2
-2
@@ -280,12 +280,12 @@ static void cg3_initfn(Object *obj)
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
CG3State *s = CG3(obj);
|
||||
|
||||
memory_region_init_ram(&s->rom, NULL, "cg3.prom", FCODE_MAX_ROM_SIZE,
|
||||
memory_region_init_ram(&s->rom, obj, "cg3.prom", FCODE_MAX_ROM_SIZE,
|
||||
&error_abort);
|
||||
memory_region_set_readonly(&s->rom, true);
|
||||
sysbus_init_mmio(sbd, &s->rom);
|
||||
|
||||
memory_region_init_io(&s->reg, NULL, &cg3_reg_ops, s, "cg3.reg",
|
||||
memory_region_init_io(&s->reg, obj, &cg3_reg_ops, s, "cg3.reg",
|
||||
CG3_REG_SIZE);
|
||||
sysbus_init_mmio(sbd, &s->reg);
|
||||
}
|
||||
|
||||
+1
-1
@@ -944,7 +944,7 @@ static void tcx_initfn(Object *obj)
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
TCXState *s = TCX(obj);
|
||||
|
||||
memory_region_init_ram(&s->rom, NULL, "tcx.prom", FCODE_MAX_ROM_SIZE,
|
||||
memory_region_init_ram(&s->rom, OBJECT(s), "tcx.prom", FCODE_MAX_ROM_SIZE,
|
||||
&error_abort);
|
||||
memory_region_set_readonly(&s->rom, true);
|
||||
sysbus_init_mmio(sbd, &s->rom);
|
||||
|
||||
+7
-15
@@ -50,7 +50,6 @@ static void ahci_reset_port(AHCIState *s, int port);
|
||||
static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis);
|
||||
static void ahci_init_d2h(AHCIDevice *ad);
|
||||
static int ahci_dma_prepare_buf(IDEDMA *dma, int32_t limit);
|
||||
static void ahci_commit_buf(IDEDMA *dma, uint32_t tx_bytes);
|
||||
static bool ahci_map_clb_address(AHCIDevice *ad);
|
||||
static bool ahci_map_fis_address(AHCIDevice *ad);
|
||||
static void ahci_unmap_clb_address(AHCIDevice *ad);
|
||||
@@ -1290,7 +1289,7 @@ out:
|
||||
s->data_ptr = s->data_end;
|
||||
|
||||
/* Update number of transferred bytes, destroy sglist */
|
||||
ahci_commit_buf(dma, size);
|
||||
dma_buf_commit(s, size);
|
||||
|
||||
s->end_transfer_func(s);
|
||||
|
||||
@@ -1332,9 +1331,8 @@ static void ahci_restart(IDEDMA *dma)
|
||||
}
|
||||
|
||||
/**
|
||||
* Called in DMA R/W chains to read the PRDT, utilizing ahci_populate_sglist.
|
||||
* Not currently invoked by PIO R/W chains,
|
||||
* which invoke ahci_populate_sglist via ahci_start_transfer.
|
||||
* Called in DMA and PIO R/W chains to read the PRDT.
|
||||
* Not shared with NCQ pathways.
|
||||
*/
|
||||
static int32_t ahci_dma_prepare_buf(IDEDMA *dma, int32_t limit)
|
||||
{
|
||||
@@ -1353,21 +1351,16 @@ static int32_t ahci_dma_prepare_buf(IDEDMA *dma, int32_t limit)
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys the scatter-gather list,
|
||||
* and updates the command header with a bytes-read value.
|
||||
* called explicitly via ahci_dma_rw_buf (ATAPI DMA),
|
||||
* and ahci_start_transfer (PIO R/W),
|
||||
* and called via callback from ide_dma_cb for DMA R/W paths.
|
||||
* Updates the command header with a bytes-read value.
|
||||
* Called via dma_buf_commit, for both DMA and PIO paths.
|
||||
* sglist destruction is handled within dma_buf_commit.
|
||||
*/
|
||||
static void ahci_commit_buf(IDEDMA *dma, uint32_t tx_bytes)
|
||||
{
|
||||
AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
|
||||
IDEState *s = &ad->port.ifs[0];
|
||||
|
||||
tx_bytes += le32_to_cpu(ad->cur_cmd->status);
|
||||
ad->cur_cmd->status = cpu_to_le32(tx_bytes);
|
||||
|
||||
qemu_sglist_destroy(&s->sg);
|
||||
}
|
||||
|
||||
static int ahci_dma_rw_buf(IDEDMA *dma, int is_write)
|
||||
@@ -1388,10 +1381,9 @@ static int ahci_dma_rw_buf(IDEDMA *dma, int is_write)
|
||||
}
|
||||
|
||||
/* free sglist, update byte count */
|
||||
ahci_commit_buf(dma, l);
|
||||
dma_buf_commit(s, l);
|
||||
|
||||
s->io_buffer_index += l;
|
||||
s->io_buffer_offset += l;
|
||||
|
||||
DPRINTF(ad->port_no, "len=%#x\n", l);
|
||||
|
||||
|
||||
+1
-1
@@ -127,7 +127,7 @@
|
||||
#define PORT_CMD_SPIN_UP (1 << 1) /* Spin up device */
|
||||
#define PORT_CMD_START (1 << 0) /* Enable port DMA engine */
|
||||
|
||||
#define PORT_CMD_ICC_MASK (0xf << 28) /* i/f ICC state mask */
|
||||
#define PORT_CMD_ICC_MASK (0xfU << 28) /* i/f ICC state mask */
|
||||
#define PORT_CMD_ICC_ACTIVE (0x1 << 28) /* Put i/f in active state */
|
||||
#define PORT_CMD_ICC_PARTIAL (0x2 << 28) /* Put i/f in partial state */
|
||||
#define PORT_CMD_ICC_SLUMBER (0x6 << 28) /* Put i/f in slumber state */
|
||||
|
||||
+17
-18
@@ -591,7 +591,6 @@ static void ide_sector_read_cb(void *opaque, int ret)
|
||||
s->nsector -= n;
|
||||
/* Allow the guest to read the io_buffer */
|
||||
ide_transfer_start(s, s->io_buffer, n * BDRV_SECTOR_SIZE, ide_sector_read);
|
||||
s->io_buffer_offset += 512 * n;
|
||||
ide_set_irq(s->bus);
|
||||
}
|
||||
|
||||
@@ -635,11 +634,12 @@ static void ide_sector_read(IDEState *s)
|
||||
ide_sector_read_cb, s);
|
||||
}
|
||||
|
||||
static void dma_buf_commit(IDEState *s, uint32_t tx_bytes)
|
||||
void dma_buf_commit(IDEState *s, uint32_t tx_bytes)
|
||||
{
|
||||
if (s->bus->dma->ops->commit_buf) {
|
||||
s->bus->dma->ops->commit_buf(s->bus->dma, tx_bytes);
|
||||
}
|
||||
s->io_buffer_offset += tx_bytes;
|
||||
qemu_sglist_destroy(&s->sg);
|
||||
}
|
||||
|
||||
@@ -842,7 +842,6 @@ static void ide_sector_write_cb(void *opaque, int ret)
|
||||
n = s->req_nb_sectors;
|
||||
}
|
||||
s->nsector -= n;
|
||||
s->io_buffer_offset += 512 * n;
|
||||
|
||||
ide_set_sector(s, ide_get_sector(s) + n);
|
||||
if (s->nsector == 0) {
|
||||
@@ -1747,11 +1746,11 @@ static const struct {
|
||||
} ide_cmd_table[0x100] = {
|
||||
/* NOP not implemented, mandatory for CD */
|
||||
[CFA_REQ_EXT_ERROR_CODE] = { cmd_cfa_req_ext_error_code, CFA_OK },
|
||||
[WIN_DSM] = { cmd_data_set_management, ALL_OK },
|
||||
[WIN_DSM] = { cmd_data_set_management, HD_CFA_OK },
|
||||
[WIN_DEVICE_RESET] = { cmd_device_reset, CD_OK },
|
||||
[WIN_RECAL] = { cmd_nop, HD_CFA_OK | SET_DSC},
|
||||
[WIN_READ] = { cmd_read_pio, ALL_OK },
|
||||
[WIN_READ_ONCE] = { cmd_read_pio, ALL_OK },
|
||||
[WIN_READ_ONCE] = { cmd_read_pio, HD_CFA_OK },
|
||||
[WIN_READ_EXT] = { cmd_read_pio, HD_CFA_OK },
|
||||
[WIN_READDMA_EXT] = { cmd_read_dma, HD_CFA_OK },
|
||||
[WIN_READ_NATIVE_MAX_EXT] = { cmd_read_native_max, HD_CFA_OK | SET_DSC },
|
||||
@@ -1770,12 +1769,12 @@ static const struct {
|
||||
[CFA_TRANSLATE_SECTOR] = { cmd_cfa_translate_sector, CFA_OK },
|
||||
[WIN_DIAGNOSE] = { cmd_exec_dev_diagnostic, ALL_OK },
|
||||
[WIN_SPECIFY] = { cmd_nop, HD_CFA_OK | SET_DSC },
|
||||
[WIN_STANDBYNOW2] = { cmd_nop, ALL_OK },
|
||||
[WIN_IDLEIMMEDIATE2] = { cmd_nop, ALL_OK },
|
||||
[WIN_STANDBY2] = { cmd_nop, ALL_OK },
|
||||
[WIN_SETIDLE2] = { cmd_nop, ALL_OK },
|
||||
[WIN_CHECKPOWERMODE2] = { cmd_check_power_mode, ALL_OK | SET_DSC },
|
||||
[WIN_SLEEPNOW2] = { cmd_nop, ALL_OK },
|
||||
[WIN_STANDBYNOW2] = { cmd_nop, HD_CFA_OK },
|
||||
[WIN_IDLEIMMEDIATE2] = { cmd_nop, HD_CFA_OK },
|
||||
[WIN_STANDBY2] = { cmd_nop, HD_CFA_OK },
|
||||
[WIN_SETIDLE2] = { cmd_nop, HD_CFA_OK },
|
||||
[WIN_CHECKPOWERMODE2] = { cmd_check_power_mode, HD_CFA_OK | SET_DSC },
|
||||
[WIN_SLEEPNOW2] = { cmd_nop, HD_CFA_OK },
|
||||
[WIN_PACKETCMD] = { cmd_packet, CD_OK },
|
||||
[WIN_PIDENTIFY] = { cmd_identify_packet, CD_OK },
|
||||
[WIN_SMART] = { cmd_smart, HD_CFA_OK | SET_DSC },
|
||||
@@ -1789,19 +1788,19 @@ static const struct {
|
||||
[WIN_WRITEDMA] = { cmd_write_dma, HD_CFA_OK },
|
||||
[WIN_WRITEDMA_ONCE] = { cmd_write_dma, HD_CFA_OK },
|
||||
[CFA_WRITE_MULTI_WO_ERASE] = { cmd_write_multiple, CFA_OK },
|
||||
[WIN_STANDBYNOW1] = { cmd_nop, ALL_OK },
|
||||
[WIN_IDLEIMMEDIATE] = { cmd_nop, ALL_OK },
|
||||
[WIN_STANDBY] = { cmd_nop, ALL_OK },
|
||||
[WIN_SETIDLE1] = { cmd_nop, ALL_OK },
|
||||
[WIN_CHECKPOWERMODE1] = { cmd_check_power_mode, ALL_OK | SET_DSC },
|
||||
[WIN_SLEEPNOW1] = { cmd_nop, ALL_OK },
|
||||
[WIN_STANDBYNOW1] = { cmd_nop, HD_CFA_OK },
|
||||
[WIN_IDLEIMMEDIATE] = { cmd_nop, HD_CFA_OK },
|
||||
[WIN_STANDBY] = { cmd_nop, HD_CFA_OK },
|
||||
[WIN_SETIDLE1] = { cmd_nop, HD_CFA_OK },
|
||||
[WIN_CHECKPOWERMODE1] = { cmd_check_power_mode, HD_CFA_OK | SET_DSC },
|
||||
[WIN_SLEEPNOW1] = { cmd_nop, HD_CFA_OK },
|
||||
[WIN_FLUSH_CACHE] = { cmd_flush_cache, ALL_OK },
|
||||
[WIN_FLUSH_CACHE_EXT] = { cmd_flush_cache, HD_CFA_OK },
|
||||
[WIN_IDENTIFY] = { cmd_identify, ALL_OK },
|
||||
[WIN_SETFEATURES] = { cmd_set_features, ALL_OK | SET_DSC },
|
||||
[IBM_SENSE_CONDITION] = { cmd_ibm_sense_condition, CFA_OK | SET_DSC },
|
||||
[CFA_WEAR_LEVEL] = { cmd_cfa_erase_sectors, HD_CFA_OK | SET_DSC },
|
||||
[WIN_READ_NATIVE_MAX] = { cmd_read_native_max, ALL_OK | SET_DSC },
|
||||
[WIN_READ_NATIVE_MAX] = { cmd_read_native_max, HD_CFA_OK | SET_DSC },
|
||||
};
|
||||
|
||||
static bool ide_cmd_permitted(IDEState *s, uint32_t cmd)
|
||||
|
||||
@@ -536,6 +536,7 @@ int64_t ide_get_sector(IDEState *s);
|
||||
void ide_set_sector(IDEState *s, int64_t sector_num);
|
||||
|
||||
void ide_start_dma(IDEState *s, BlockCompletionFunc *cb);
|
||||
void dma_buf_commit(IDEState *s, uint32_t tx_bytes);
|
||||
void ide_dma_error(IDEState *s);
|
||||
|
||||
void ide_atapi_cmd_ok(IDEState *s);
|
||||
|
||||
@@ -208,6 +208,33 @@ static void pmac_dma_write(BlockBackend *blk,
|
||||
cb, io);
|
||||
}
|
||||
|
||||
static void pmac_dma_trim(BlockBackend *blk,
|
||||
int64_t offset, int bytes,
|
||||
void (*cb)(void *opaque, int ret), void *opaque)
|
||||
{
|
||||
DBDMA_io *io = opaque;
|
||||
MACIOIDEState *m = io->opaque;
|
||||
IDEState *s = idebus_active_if(&m->bus);
|
||||
dma_addr_t dma_addr, dma_len;
|
||||
void *mem;
|
||||
|
||||
qemu_iovec_destroy(&io->iov);
|
||||
qemu_iovec_init(&io->iov, io->len / MACIO_PAGE_SIZE + 1);
|
||||
|
||||
dma_addr = io->addr;
|
||||
dma_len = io->len;
|
||||
mem = dma_memory_map(&address_space_memory, dma_addr, &dma_len,
|
||||
DMA_DIRECTION_TO_DEVICE);
|
||||
|
||||
qemu_iovec_add(&io->iov, mem, io->len);
|
||||
s->io_buffer_size -= io->len;
|
||||
s->io_buffer_index += io->len;
|
||||
io->len = 0;
|
||||
|
||||
m->aiocb = ide_issue_trim(blk, (offset >> 9), &io->iov, (bytes >> 9),
|
||||
cb, io);
|
||||
}
|
||||
|
||||
static void pmac_ide_atapi_transfer_cb(void *opaque, int ret)
|
||||
{
|
||||
DBDMA_io *io = opaque;
|
||||
@@ -313,6 +340,7 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
|
||||
pmac_dma_write(s->blk, offset, io->len, pmac_ide_transfer_cb, io);
|
||||
break;
|
||||
case IDE_DMA_TRIM:
|
||||
pmac_dma_trim(s->blk, offset, io->len, pmac_ide_transfer_cb, io);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -169,6 +169,7 @@ int pci_piix3_xen_ide_unplug(DeviceState *dev)
|
||||
PCIIDEState *pci_ide;
|
||||
DriveInfo *di;
|
||||
int i;
|
||||
IDEDevice *idedev;
|
||||
|
||||
pci_ide = PCI_IDE(dev);
|
||||
|
||||
@@ -181,6 +182,12 @@ int pci_piix3_xen_ide_unplug(DeviceState *dev)
|
||||
blk_detach_dev(blk, ds);
|
||||
}
|
||||
pci_ide->bus[di->bus].ifs[di->unit].blk = NULL;
|
||||
if (!(i % 2)) {
|
||||
idedev = pci_ide->bus[di->bus].master;
|
||||
} else {
|
||||
idedev = pci_ide->bus[di->bus].slave;
|
||||
}
|
||||
idedev->conf.blk = NULL;
|
||||
blk_unref(blk);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,10 @@ void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event)
|
||||
unsigned have, need;
|
||||
int i, len;
|
||||
|
||||
if (!vinput->active) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* queue up events ... */
|
||||
if (vinput->qindex == vinput->qsize) {
|
||||
vinput->qsize++;
|
||||
|
||||
@@ -79,7 +79,7 @@ static void intdbg_control_init(Object *obj)
|
||||
SysBusDevice *sd = SYS_BUS_DEVICE(obj);
|
||||
IntegratorDebugState *s = INTEGRATOR_DEBUG(obj);
|
||||
|
||||
memory_region_init_io(&s->iomem, NULL, &intdbg_control_ops,
|
||||
memory_region_init_io(&s->iomem, obj, &intdbg_control_ops,
|
||||
NULL, "dbg-leds", 0x1000000);
|
||||
sysbus_init_mmio(sd, &s->iomem);
|
||||
}
|
||||
|
||||
@@ -713,7 +713,7 @@ static void cuda_initfn(Object *obj)
|
||||
CUDAState *s = CUDA(obj);
|
||||
int i;
|
||||
|
||||
memory_region_init_io(&s->mem, NULL, &cuda_ops, s, "cuda", 0x2000);
|
||||
memory_region_init_io(&s->mem, obj, &cuda_ops, s, "cuda", 0x2000);
|
||||
sysbus_init_mmio(d, &s->mem);
|
||||
sysbus_init_irq(d, &s->irq);
|
||||
|
||||
|
||||
@@ -590,10 +590,11 @@ dbdma_control_write(DBDMA_channel *ch)
|
||||
if ((ch->regs[DBDMA_STATUS] & RUN) && !(status & RUN)) {
|
||||
/* RUN is cleared */
|
||||
status &= ~(ACTIVE|DEAD);
|
||||
if ((status & FLUSH) && ch->flush) {
|
||||
ch->flush(&ch->io);
|
||||
status &= ~FLUSH;
|
||||
}
|
||||
}
|
||||
|
||||
if ((status & FLUSH) && ch->flush) {
|
||||
ch->flush(&ch->io);
|
||||
status &= ~FLUSH;
|
||||
}
|
||||
|
||||
DBDMA_DPRINTF(" status 0x%08x\n", status);
|
||||
@@ -603,9 +604,6 @@ dbdma_control_write(DBDMA_channel *ch)
|
||||
if (status & ACTIVE) {
|
||||
DBDMA_kick(dbdma_from_ch(ch));
|
||||
}
|
||||
if ((status & FLUSH) && ch->flush) {
|
||||
ch->flush(&ch->io);
|
||||
}
|
||||
}
|
||||
|
||||
static void dbdma_write(void *opaque, hwaddr addr,
|
||||
|
||||
@@ -105,10 +105,10 @@ static void macio_escc_legacy_setup(MacIOState *macio_state)
|
||||
0xF0, 0xE0,
|
||||
};
|
||||
|
||||
memory_region_init(escc_legacy, NULL, "escc-legacy", 256);
|
||||
memory_region_init(escc_legacy, OBJECT(macio_state), "escc-legacy", 256);
|
||||
for (i = 0; i < ARRAY_SIZE(maps); i += 2) {
|
||||
MemoryRegion *port = g_new(MemoryRegion, 1);
|
||||
memory_region_init_alias(port, NULL, "escc-legacy-port",
|
||||
memory_region_init_alias(port, OBJECT(macio_state), "escc-legacy-port",
|
||||
macio_state->escc_mem, maps[i+1], 0x2);
|
||||
memory_region_add_subregion(escc_legacy, maps[i], port);
|
||||
}
|
||||
@@ -131,6 +131,10 @@ static void macio_common_realize(PCIDevice *d, Error **errp)
|
||||
MacIOState *s = MACIO(d);
|
||||
SysBusDevice *sysbus_dev;
|
||||
Error *err = NULL;
|
||||
MemoryRegion *dbdma_mem;
|
||||
|
||||
s->dbdma = DBDMA_init(&dbdma_mem);
|
||||
memory_region_add_subregion(&s->bar, 0x08000, dbdma_mem);
|
||||
|
||||
object_property_set_bool(OBJECT(&s->cuda), true, "realized", &err);
|
||||
if (err) {
|
||||
@@ -328,16 +332,12 @@ static void macio_newworld_init(Object *obj)
|
||||
static void macio_instance_init(Object *obj)
|
||||
{
|
||||
MacIOState *s = MACIO(obj);
|
||||
MemoryRegion *dbdma_mem;
|
||||
|
||||
memory_region_init(&s->bar, NULL, "macio", 0x80000);
|
||||
memory_region_init(&s->bar, obj, "macio", 0x80000);
|
||||
|
||||
object_initialize(&s->cuda, sizeof(s->cuda), TYPE_CUDA);
|
||||
qdev_set_parent_bus(DEVICE(&s->cuda), sysbus_get_default());
|
||||
object_property_add_child(obj, "cuda", OBJECT(&s->cuda), NULL);
|
||||
|
||||
s->dbdma = DBDMA_init(&dbdma_mem);
|
||||
memory_region_add_subregion(&s->bar, 0x08000, dbdma_mem);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_macio_oldworld = {
|
||||
|
||||
+4
-4
@@ -393,12 +393,12 @@ static void zynq_slcr_write(void *opaque, hwaddr offset,
|
||||
return;
|
||||
}
|
||||
|
||||
if (!s->regs[LOCKSTA]) {
|
||||
s->regs[offset / 4] = val;
|
||||
} else {
|
||||
DB_PRINT("SCLR registers are locked. Unlock them first\n");
|
||||
if (s->regs[LOCKSTA]) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"SCLR registers are locked. Unlock them first\n");
|
||||
return;
|
||||
}
|
||||
s->regs[offset] = val;
|
||||
|
||||
switch (offset) {
|
||||
case PSS_RST_CTRL:
|
||||
|
||||
+2
-1
@@ -740,7 +740,8 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
|
||||
memmove(tp->data, tp->header, tp->hdr_len);
|
||||
tp->size = tp->hdr_len;
|
||||
}
|
||||
} while (split_size -= bytes);
|
||||
split_size -= bytes;
|
||||
} while (bytes && split_size);
|
||||
} else if (!tp->tse && tp->cptse) {
|
||||
// context descriptor TSE is not set, while data descriptor TSE is set
|
||||
DBGOUT(TXERR, "TCP segmentation error\n");
|
||||
|
||||
+16
-5
@@ -230,6 +230,9 @@ ssize_t ne2000_receive(NetClientState *nc, const uint8_t *buf, size_t size_)
|
||||
}
|
||||
|
||||
index = s->curpag << 8;
|
||||
if (index >= NE2000_PMEM_END) {
|
||||
index = s->start;
|
||||
}
|
||||
/* 4 bytes for header */
|
||||
total_len = size + 4;
|
||||
/* address for next packet (4 bytes for CRC) */
|
||||
@@ -253,7 +256,7 @@ ssize_t ne2000_receive(NetClientState *nc, const uint8_t *buf, size_t size_)
|
||||
if (index <= s->stop)
|
||||
avail = s->stop - index;
|
||||
else
|
||||
avail = 0;
|
||||
break;
|
||||
len = size;
|
||||
if (len > avail)
|
||||
len = avail;
|
||||
@@ -315,13 +318,19 @@ static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val)
|
||||
offset = addr | (page << 4);
|
||||
switch(offset) {
|
||||
case EN0_STARTPG:
|
||||
s->start = val << 8;
|
||||
if (val << 8 <= NE2000_PMEM_END) {
|
||||
s->start = val << 8;
|
||||
}
|
||||
break;
|
||||
case EN0_STOPPG:
|
||||
s->stop = val << 8;
|
||||
if (val << 8 <= NE2000_PMEM_END) {
|
||||
s->stop = val << 8;
|
||||
}
|
||||
break;
|
||||
case EN0_BOUNDARY:
|
||||
s->boundary = val;
|
||||
if (val << 8 < NE2000_PMEM_END) {
|
||||
s->boundary = val;
|
||||
}
|
||||
break;
|
||||
case EN0_IMR:
|
||||
s->imr = val;
|
||||
@@ -362,7 +371,9 @@ static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val)
|
||||
s->phys[offset - EN1_PHYS] = val;
|
||||
break;
|
||||
case EN1_CURPAG:
|
||||
s->curpag = val;
|
||||
if (val << 8 < NE2000_PMEM_END) {
|
||||
s->curpag = val;
|
||||
}
|
||||
break;
|
||||
case EN1_MULT ... EN1_MULT + 7:
|
||||
s->mult[offset - EN1_MULT] = val;
|
||||
|
||||
+211
-192
@@ -1148,7 +1148,9 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t
|
||||
|
||||
/* if receiver buffer is empty then avail == 0 */
|
||||
|
||||
if (avail != 0 && size + 8 >= avail)
|
||||
#define RX_ALIGN(x) (((x) + 3) & ~0x3)
|
||||
|
||||
if (avail != 0 && RX_ALIGN(size + 8) >= avail)
|
||||
{
|
||||
DPRINTF("rx overflow: rx buffer length %d head 0x%04x "
|
||||
"read 0x%04x === available 0x%04x need 0x%04x\n",
|
||||
@@ -1157,7 +1159,7 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t
|
||||
s->IntrStatus |= RxOverflow;
|
||||
++s->RxMissed;
|
||||
rtl8139_update_irq(s);
|
||||
return size_;
|
||||
return 0;
|
||||
}
|
||||
|
||||
packet_header |= RxStatusOK;
|
||||
@@ -1176,7 +1178,7 @@ static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t
|
||||
rtl8139_write_buffer(s, (uint8_t *)&val, 4);
|
||||
|
||||
/* correct buffer write pointer */
|
||||
s->RxBufAddr = MOD2((s->RxBufAddr + 3) & ~0x3, s->RxBufferSize);
|
||||
s->RxBufAddr = MOD2(RX_ALIGN(s->RxBufAddr), s->RxBufferSize);
|
||||
|
||||
/* now we can signal we have received something */
|
||||
|
||||
@@ -2150,6 +2152,11 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
|
||||
{
|
||||
DPRINTF("+++ C+ mode offloaded task checksum\n");
|
||||
|
||||
/* Large enough for Ethernet and IP headers? */
|
||||
if (saved_size < ETH_HLEN + sizeof(ip_header)) {
|
||||
goto skip_offload;
|
||||
}
|
||||
|
||||
/* ip packet header */
|
||||
ip_header *ip = NULL;
|
||||
int hlen = 0;
|
||||
@@ -2160,223 +2167,235 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
|
||||
size_t eth_payload_len = 0;
|
||||
|
||||
int proto = be16_to_cpu(*(uint16_t *)(saved_buffer + 12));
|
||||
if (proto == ETH_P_IP)
|
||||
if (proto != ETH_P_IP)
|
||||
{
|
||||
DPRINTF("+++ C+ mode has IP packet\n");
|
||||
|
||||
/* not aligned */
|
||||
eth_payload_data = saved_buffer + ETH_HLEN;
|
||||
eth_payload_len = saved_size - ETH_HLEN;
|
||||
|
||||
ip = (ip_header*)eth_payload_data;
|
||||
|
||||
if (IP_HEADER_VERSION(ip) != IP_HEADER_VERSION_4) {
|
||||
DPRINTF("+++ C+ mode packet has bad IP version %d "
|
||||
"expected %d\n", IP_HEADER_VERSION(ip),
|
||||
IP_HEADER_VERSION_4);
|
||||
ip = NULL;
|
||||
} else {
|
||||
hlen = IP_HEADER_LENGTH(ip);
|
||||
ip_protocol = ip->ip_p;
|
||||
ip_data_len = be16_to_cpu(ip->ip_len) - hlen;
|
||||
}
|
||||
goto skip_offload;
|
||||
}
|
||||
|
||||
if (ip)
|
||||
DPRINTF("+++ C+ mode has IP packet\n");
|
||||
|
||||
/* not aligned */
|
||||
eth_payload_data = saved_buffer + ETH_HLEN;
|
||||
eth_payload_len = saved_size - ETH_HLEN;
|
||||
|
||||
ip = (ip_header*)eth_payload_data;
|
||||
|
||||
if (IP_HEADER_VERSION(ip) != IP_HEADER_VERSION_4) {
|
||||
DPRINTF("+++ C+ mode packet has bad IP version %d "
|
||||
"expected %d\n", IP_HEADER_VERSION(ip),
|
||||
IP_HEADER_VERSION_4);
|
||||
goto skip_offload;
|
||||
}
|
||||
|
||||
hlen = IP_HEADER_LENGTH(ip);
|
||||
if (hlen < sizeof(ip_header) || hlen > eth_payload_len) {
|
||||
goto skip_offload;
|
||||
}
|
||||
|
||||
ip_protocol = ip->ip_p;
|
||||
|
||||
ip_data_len = be16_to_cpu(ip->ip_len);
|
||||
if (ip_data_len < hlen || ip_data_len > eth_payload_len) {
|
||||
goto skip_offload;
|
||||
}
|
||||
ip_data_len -= hlen;
|
||||
|
||||
if (txdw0 & CP_TX_IPCS)
|
||||
{
|
||||
if (txdw0 & CP_TX_IPCS)
|
||||
{
|
||||
DPRINTF("+++ C+ mode need IP checksum\n");
|
||||
DPRINTF("+++ C+ mode need IP checksum\n");
|
||||
|
||||
if (hlen<sizeof(ip_header) || hlen>eth_payload_len) {/* min header length */
|
||||
/* bad packet header len */
|
||||
/* or packet too short */
|
||||
}
|
||||
else
|
||||
{
|
||||
ip->ip_sum = 0;
|
||||
ip->ip_sum = ip_checksum(ip, hlen);
|
||||
DPRINTF("+++ C+ mode IP header len=%d checksum=%04x\n",
|
||||
hlen, ip->ip_sum);
|
||||
}
|
||||
ip->ip_sum = 0;
|
||||
ip->ip_sum = ip_checksum(ip, hlen);
|
||||
DPRINTF("+++ C+ mode IP header len=%d checksum=%04x\n",
|
||||
hlen, ip->ip_sum);
|
||||
}
|
||||
|
||||
if ((txdw0 & CP_TX_LGSEN) && ip_protocol == IP_PROTO_TCP)
|
||||
{
|
||||
/* Large enough for the TCP header? */
|
||||
if (ip_data_len < sizeof(tcp_header)) {
|
||||
goto skip_offload;
|
||||
}
|
||||
|
||||
if ((txdw0 & CP_TX_LGSEN) && ip_protocol == IP_PROTO_TCP)
|
||||
int large_send_mss = (txdw0 >> 16) & CP_TC_LGSEN_MSS_MASK;
|
||||
|
||||
DPRINTF("+++ C+ mode offloaded task TSO MTU=%d IP data %d "
|
||||
"frame data %d specified MSS=%d\n", ETH_MTU,
|
||||
ip_data_len, saved_size - ETH_HLEN, large_send_mss);
|
||||
|
||||
int tcp_send_offset = 0;
|
||||
int send_count = 0;
|
||||
|
||||
/* maximum IP header length is 60 bytes */
|
||||
uint8_t saved_ip_header[60];
|
||||
|
||||
/* save IP header template; data area is used in tcp checksum calculation */
|
||||
memcpy(saved_ip_header, eth_payload_data, hlen);
|
||||
|
||||
/* a placeholder for checksum calculation routine in tcp case */
|
||||
uint8_t *data_to_checksum = eth_payload_data + hlen - 12;
|
||||
// size_t data_to_checksum_len = eth_payload_len - hlen + 12;
|
||||
|
||||
/* pointer to TCP header */
|
||||
tcp_header *p_tcp_hdr = (tcp_header*)(eth_payload_data + hlen);
|
||||
|
||||
int tcp_hlen = TCP_HEADER_DATA_OFFSET(p_tcp_hdr);
|
||||
|
||||
/* Invalid TCP data offset? */
|
||||
if (tcp_hlen < sizeof(tcp_header) || tcp_hlen > ip_data_len) {
|
||||
goto skip_offload;
|
||||
}
|
||||
|
||||
/* ETH_MTU = ip header len + tcp header len + payload */
|
||||
int tcp_data_len = ip_data_len - tcp_hlen;
|
||||
int tcp_chunk_size = ETH_MTU - hlen - tcp_hlen;
|
||||
|
||||
DPRINTF("+++ C+ mode TSO IP data len %d TCP hlen %d TCP "
|
||||
"data len %d TCP chunk size %d\n", ip_data_len,
|
||||
tcp_hlen, tcp_data_len, tcp_chunk_size);
|
||||
|
||||
/* note the cycle below overwrites IP header data,
|
||||
but restores it from saved_ip_header before sending packet */
|
||||
|
||||
int is_last_frame = 0;
|
||||
|
||||
for (tcp_send_offset = 0; tcp_send_offset < tcp_data_len; tcp_send_offset += tcp_chunk_size)
|
||||
{
|
||||
int large_send_mss = (txdw0 >> 16) & CP_TC_LGSEN_MSS_MASK;
|
||||
uint16_t chunk_size = tcp_chunk_size;
|
||||
|
||||
DPRINTF("+++ C+ mode offloaded task TSO MTU=%d IP data %d "
|
||||
"frame data %d specified MSS=%d\n", ETH_MTU,
|
||||
ip_data_len, saved_size - ETH_HLEN, large_send_mss);
|
||||
|
||||
int tcp_send_offset = 0;
|
||||
int send_count = 0;
|
||||
|
||||
/* maximum IP header length is 60 bytes */
|
||||
uint8_t saved_ip_header[60];
|
||||
|
||||
/* save IP header template; data area is used in tcp checksum calculation */
|
||||
memcpy(saved_ip_header, eth_payload_data, hlen);
|
||||
|
||||
/* a placeholder for checksum calculation routine in tcp case */
|
||||
uint8_t *data_to_checksum = eth_payload_data + hlen - 12;
|
||||
// size_t data_to_checksum_len = eth_payload_len - hlen + 12;
|
||||
|
||||
/* pointer to TCP header */
|
||||
tcp_header *p_tcp_hdr = (tcp_header*)(eth_payload_data + hlen);
|
||||
|
||||
int tcp_hlen = TCP_HEADER_DATA_OFFSET(p_tcp_hdr);
|
||||
|
||||
/* ETH_MTU = ip header len + tcp header len + payload */
|
||||
int tcp_data_len = ip_data_len - tcp_hlen;
|
||||
int tcp_chunk_size = ETH_MTU - hlen - tcp_hlen;
|
||||
|
||||
DPRINTF("+++ C+ mode TSO IP data len %d TCP hlen %d TCP "
|
||||
"data len %d TCP chunk size %d\n", ip_data_len,
|
||||
tcp_hlen, tcp_data_len, tcp_chunk_size);
|
||||
|
||||
/* note the cycle below overwrites IP header data,
|
||||
but restores it from saved_ip_header before sending packet */
|
||||
|
||||
int is_last_frame = 0;
|
||||
|
||||
for (tcp_send_offset = 0; tcp_send_offset < tcp_data_len; tcp_send_offset += tcp_chunk_size)
|
||||
/* check if this is the last frame */
|
||||
if (tcp_send_offset + tcp_chunk_size >= tcp_data_len)
|
||||
{
|
||||
uint16_t chunk_size = tcp_chunk_size;
|
||||
|
||||
/* check if this is the last frame */
|
||||
if (tcp_send_offset + tcp_chunk_size >= tcp_data_len)
|
||||
{
|
||||
is_last_frame = 1;
|
||||
chunk_size = tcp_data_len - tcp_send_offset;
|
||||
}
|
||||
|
||||
DPRINTF("+++ C+ mode TSO TCP seqno %08x\n",
|
||||
be32_to_cpu(p_tcp_hdr->th_seq));
|
||||
|
||||
/* add 4 TCP pseudoheader fields */
|
||||
/* copy IP source and destination fields */
|
||||
memcpy(data_to_checksum, saved_ip_header + 12, 8);
|
||||
|
||||
DPRINTF("+++ C+ mode TSO calculating TCP checksum for "
|
||||
"packet with %d bytes data\n", tcp_hlen +
|
||||
chunk_size);
|
||||
|
||||
if (tcp_send_offset)
|
||||
{
|
||||
memcpy((uint8_t*)p_tcp_hdr + tcp_hlen, (uint8_t*)p_tcp_hdr + tcp_hlen + tcp_send_offset, chunk_size);
|
||||
}
|
||||
|
||||
/* keep PUSH and FIN flags only for the last frame */
|
||||
if (!is_last_frame)
|
||||
{
|
||||
TCP_HEADER_CLEAR_FLAGS(p_tcp_hdr, TCP_FLAG_PUSH|TCP_FLAG_FIN);
|
||||
}
|
||||
|
||||
/* recalculate TCP checksum */
|
||||
ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum;
|
||||
p_tcpip_hdr->zeros = 0;
|
||||
p_tcpip_hdr->ip_proto = IP_PROTO_TCP;
|
||||
p_tcpip_hdr->ip_payload = cpu_to_be16(tcp_hlen + chunk_size);
|
||||
|
||||
p_tcp_hdr->th_sum = 0;
|
||||
|
||||
int tcp_checksum = ip_checksum(data_to_checksum, tcp_hlen + chunk_size + 12);
|
||||
DPRINTF("+++ C+ mode TSO TCP checksum %04x\n",
|
||||
tcp_checksum);
|
||||
|
||||
p_tcp_hdr->th_sum = tcp_checksum;
|
||||
|
||||
/* restore IP header */
|
||||
memcpy(eth_payload_data, saved_ip_header, hlen);
|
||||
|
||||
/* set IP data length and recalculate IP checksum */
|
||||
ip->ip_len = cpu_to_be16(hlen + tcp_hlen + chunk_size);
|
||||
|
||||
/* increment IP id for subsequent frames */
|
||||
ip->ip_id = cpu_to_be16(tcp_send_offset/tcp_chunk_size + be16_to_cpu(ip->ip_id));
|
||||
|
||||
ip->ip_sum = 0;
|
||||
ip->ip_sum = ip_checksum(eth_payload_data, hlen);
|
||||
DPRINTF("+++ C+ mode TSO IP header len=%d "
|
||||
"checksum=%04x\n", hlen, ip->ip_sum);
|
||||
|
||||
int tso_send_size = ETH_HLEN + hlen + tcp_hlen + chunk_size;
|
||||
DPRINTF("+++ C+ mode TSO transferring packet size "
|
||||
"%d\n", tso_send_size);
|
||||
rtl8139_transfer_frame(s, saved_buffer, tso_send_size,
|
||||
0, (uint8_t *) dot1q_buffer);
|
||||
|
||||
/* add transferred count to TCP sequence number */
|
||||
p_tcp_hdr->th_seq = cpu_to_be32(chunk_size + be32_to_cpu(p_tcp_hdr->th_seq));
|
||||
++send_count;
|
||||
is_last_frame = 1;
|
||||
chunk_size = tcp_data_len - tcp_send_offset;
|
||||
}
|
||||
|
||||
/* Stop sending this frame */
|
||||
saved_size = 0;
|
||||
}
|
||||
else if (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS))
|
||||
{
|
||||
DPRINTF("+++ C+ mode need TCP or UDP checksum\n");
|
||||
|
||||
/* maximum IP header length is 60 bytes */
|
||||
uint8_t saved_ip_header[60];
|
||||
memcpy(saved_ip_header, eth_payload_data, hlen);
|
||||
|
||||
uint8_t *data_to_checksum = eth_payload_data + hlen - 12;
|
||||
// size_t data_to_checksum_len = eth_payload_len - hlen + 12;
|
||||
DPRINTF("+++ C+ mode TSO TCP seqno %08x\n",
|
||||
be32_to_cpu(p_tcp_hdr->th_seq));
|
||||
|
||||
/* add 4 TCP pseudoheader fields */
|
||||
/* copy IP source and destination fields */
|
||||
memcpy(data_to_checksum, saved_ip_header + 12, 8);
|
||||
|
||||
if ((txdw0 & CP_TX_TCPCS) && ip_protocol == IP_PROTO_TCP)
|
||||
DPRINTF("+++ C+ mode TSO calculating TCP checksum for "
|
||||
"packet with %d bytes data\n", tcp_hlen +
|
||||
chunk_size);
|
||||
|
||||
if (tcp_send_offset)
|
||||
{
|
||||
DPRINTF("+++ C+ mode calculating TCP checksum for "
|
||||
"packet with %d bytes data\n", ip_data_len);
|
||||
|
||||
ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum;
|
||||
p_tcpip_hdr->zeros = 0;
|
||||
p_tcpip_hdr->ip_proto = IP_PROTO_TCP;
|
||||
p_tcpip_hdr->ip_payload = cpu_to_be16(ip_data_len);
|
||||
|
||||
tcp_header* p_tcp_hdr = (tcp_header *) (data_to_checksum+12);
|
||||
|
||||
p_tcp_hdr->th_sum = 0;
|
||||
|
||||
int tcp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12);
|
||||
DPRINTF("+++ C+ mode TCP checksum %04x\n",
|
||||
tcp_checksum);
|
||||
|
||||
p_tcp_hdr->th_sum = tcp_checksum;
|
||||
memcpy((uint8_t*)p_tcp_hdr + tcp_hlen, (uint8_t*)p_tcp_hdr + tcp_hlen + tcp_send_offset, chunk_size);
|
||||
}
|
||||
else if ((txdw0 & CP_TX_UDPCS) && ip_protocol == IP_PROTO_UDP)
|
||||
|
||||
/* keep PUSH and FIN flags only for the last frame */
|
||||
if (!is_last_frame)
|
||||
{
|
||||
DPRINTF("+++ C+ mode calculating UDP checksum for "
|
||||
"packet with %d bytes data\n", ip_data_len);
|
||||
|
||||
ip_pseudo_header *p_udpip_hdr = (ip_pseudo_header *)data_to_checksum;
|
||||
p_udpip_hdr->zeros = 0;
|
||||
p_udpip_hdr->ip_proto = IP_PROTO_UDP;
|
||||
p_udpip_hdr->ip_payload = cpu_to_be16(ip_data_len);
|
||||
|
||||
udp_header *p_udp_hdr = (udp_header *) (data_to_checksum+12);
|
||||
|
||||
p_udp_hdr->uh_sum = 0;
|
||||
|
||||
int udp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12);
|
||||
DPRINTF("+++ C+ mode UDP checksum %04x\n",
|
||||
udp_checksum);
|
||||
|
||||
p_udp_hdr->uh_sum = udp_checksum;
|
||||
TCP_HEADER_CLEAR_FLAGS(p_tcp_hdr, TCP_FLAG_PUSH|TCP_FLAG_FIN);
|
||||
}
|
||||
|
||||
/* recalculate TCP checksum */
|
||||
ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum;
|
||||
p_tcpip_hdr->zeros = 0;
|
||||
p_tcpip_hdr->ip_proto = IP_PROTO_TCP;
|
||||
p_tcpip_hdr->ip_payload = cpu_to_be16(tcp_hlen + chunk_size);
|
||||
|
||||
p_tcp_hdr->th_sum = 0;
|
||||
|
||||
int tcp_checksum = ip_checksum(data_to_checksum, tcp_hlen + chunk_size + 12);
|
||||
DPRINTF("+++ C+ mode TSO TCP checksum %04x\n",
|
||||
tcp_checksum);
|
||||
|
||||
p_tcp_hdr->th_sum = tcp_checksum;
|
||||
|
||||
/* restore IP header */
|
||||
memcpy(eth_payload_data, saved_ip_header, hlen);
|
||||
|
||||
/* set IP data length and recalculate IP checksum */
|
||||
ip->ip_len = cpu_to_be16(hlen + tcp_hlen + chunk_size);
|
||||
|
||||
/* increment IP id for subsequent frames */
|
||||
ip->ip_id = cpu_to_be16(tcp_send_offset/tcp_chunk_size + be16_to_cpu(ip->ip_id));
|
||||
|
||||
ip->ip_sum = 0;
|
||||
ip->ip_sum = ip_checksum(eth_payload_data, hlen);
|
||||
DPRINTF("+++ C+ mode TSO IP header len=%d "
|
||||
"checksum=%04x\n", hlen, ip->ip_sum);
|
||||
|
||||
int tso_send_size = ETH_HLEN + hlen + tcp_hlen + chunk_size;
|
||||
DPRINTF("+++ C+ mode TSO transferring packet size "
|
||||
"%d\n", tso_send_size);
|
||||
rtl8139_transfer_frame(s, saved_buffer, tso_send_size,
|
||||
0, (uint8_t *) dot1q_buffer);
|
||||
|
||||
/* add transferred count to TCP sequence number */
|
||||
p_tcp_hdr->th_seq = cpu_to_be32(chunk_size + be32_to_cpu(p_tcp_hdr->th_seq));
|
||||
++send_count;
|
||||
}
|
||||
|
||||
/* Stop sending this frame */
|
||||
saved_size = 0;
|
||||
}
|
||||
else if (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS))
|
||||
{
|
||||
DPRINTF("+++ C+ mode need TCP or UDP checksum\n");
|
||||
|
||||
/* maximum IP header length is 60 bytes */
|
||||
uint8_t saved_ip_header[60];
|
||||
memcpy(saved_ip_header, eth_payload_data, hlen);
|
||||
|
||||
uint8_t *data_to_checksum = eth_payload_data + hlen - 12;
|
||||
// size_t data_to_checksum_len = eth_payload_len - hlen + 12;
|
||||
|
||||
/* add 4 TCP pseudoheader fields */
|
||||
/* copy IP source and destination fields */
|
||||
memcpy(data_to_checksum, saved_ip_header + 12, 8);
|
||||
|
||||
if ((txdw0 & CP_TX_TCPCS) && ip_protocol == IP_PROTO_TCP)
|
||||
{
|
||||
DPRINTF("+++ C+ mode calculating TCP checksum for "
|
||||
"packet with %d bytes data\n", ip_data_len);
|
||||
|
||||
ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum;
|
||||
p_tcpip_hdr->zeros = 0;
|
||||
p_tcpip_hdr->ip_proto = IP_PROTO_TCP;
|
||||
p_tcpip_hdr->ip_payload = cpu_to_be16(ip_data_len);
|
||||
|
||||
tcp_header* p_tcp_hdr = (tcp_header *) (data_to_checksum+12);
|
||||
|
||||
p_tcp_hdr->th_sum = 0;
|
||||
|
||||
int tcp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12);
|
||||
DPRINTF("+++ C+ mode TCP checksum %04x\n",
|
||||
tcp_checksum);
|
||||
|
||||
p_tcp_hdr->th_sum = tcp_checksum;
|
||||
}
|
||||
else if ((txdw0 & CP_TX_UDPCS) && ip_protocol == IP_PROTO_UDP)
|
||||
{
|
||||
DPRINTF("+++ C+ mode calculating UDP checksum for "
|
||||
"packet with %d bytes data\n", ip_data_len);
|
||||
|
||||
ip_pseudo_header *p_udpip_hdr = (ip_pseudo_header *)data_to_checksum;
|
||||
p_udpip_hdr->zeros = 0;
|
||||
p_udpip_hdr->ip_proto = IP_PROTO_UDP;
|
||||
p_udpip_hdr->ip_payload = cpu_to_be16(ip_data_len);
|
||||
|
||||
udp_header *p_udp_hdr = (udp_header *) (data_to_checksum+12);
|
||||
|
||||
p_udp_hdr->uh_sum = 0;
|
||||
|
||||
int udp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12);
|
||||
DPRINTF("+++ C+ mode UDP checksum %04x\n",
|
||||
udp_checksum);
|
||||
|
||||
p_udp_hdr->uh_sum = udp_checksum;
|
||||
}
|
||||
|
||||
/* restore IP header */
|
||||
memcpy(eth_payload_data, saved_ip_header, hlen);
|
||||
}
|
||||
}
|
||||
|
||||
skip_offload:
|
||||
/* update tally counter */
|
||||
++s->tally_counters.TxOk;
|
||||
|
||||
|
||||
+1
-1
@@ -197,7 +197,7 @@ static int vhost_net_set_vnet_endian(VirtIODevice *dev, NetClientState *peer,
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
if (virtio_has_feature(dev, VIRTIO_F_VERSION_1) ||
|
||||
if (virtio_vdev_has_feature(dev, VIRTIO_F_VERSION_1) ||
|
||||
(virtio_legacy_is_cross_endian(dev) && !virtio_is_big_endian(dev))) {
|
||||
r = qemu_set_vnet_le(peer, set);
|
||||
if (r) {
|
||||
|
||||
+37
-36
@@ -86,8 +86,8 @@ static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config)
|
||||
|
||||
memcpy(&netcfg, config, n->config_size);
|
||||
|
||||
if (!virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR) &&
|
||||
!virtio_has_feature(vdev, VIRTIO_F_VERSION_1) &&
|
||||
if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR) &&
|
||||
!virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1) &&
|
||||
memcmp(netcfg.mac, n->mac, ETH_ALEN)) {
|
||||
memcpy(n->mac, netcfg.mac, ETH_ALEN);
|
||||
qemu_format_nic_info_str(qemu_get_queue(n->nic), n->mac);
|
||||
@@ -304,7 +304,7 @@ static RxFilterInfo *virtio_net_query_rxfilter(NetClientState *nc)
|
||||
info->multicast_table = str_list;
|
||||
info->vlan_table = get_vlan_table(n);
|
||||
|
||||
if (!virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VLAN)) {
|
||||
if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_VLAN)) {
|
||||
info->vlan = RX_STATE_ALL;
|
||||
} else if (!info->vlan_table) {
|
||||
info->vlan = RX_STATE_NONE;
|
||||
@@ -529,13 +529,13 @@ static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features)
|
||||
int i;
|
||||
|
||||
virtio_net_set_multiqueue(n,
|
||||
__virtio_has_feature(features, VIRTIO_NET_F_MQ));
|
||||
virtio_has_feature(features, VIRTIO_NET_F_MQ));
|
||||
|
||||
virtio_net_set_mrg_rx_bufs(n,
|
||||
__virtio_has_feature(features,
|
||||
VIRTIO_NET_F_MRG_RXBUF),
|
||||
__virtio_has_feature(features,
|
||||
VIRTIO_F_VERSION_1));
|
||||
virtio_has_feature(features,
|
||||
VIRTIO_NET_F_MRG_RXBUF),
|
||||
virtio_has_feature(features,
|
||||
VIRTIO_F_VERSION_1));
|
||||
|
||||
if (n->has_vnet_hdr) {
|
||||
n->curr_guest_offloads =
|
||||
@@ -552,7 +552,7 @@ static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features)
|
||||
vhost_net_ack_features(get_vhost_net(nc->peer), features);
|
||||
}
|
||||
|
||||
if (__virtio_has_feature(features, VIRTIO_NET_F_CTRL_VLAN)) {
|
||||
if (virtio_has_feature(features, VIRTIO_NET_F_CTRL_VLAN)) {
|
||||
memset(n->vlans, 0, MAX_VLAN >> 3);
|
||||
} else {
|
||||
memset(n->vlans, 0xff, MAX_VLAN >> 3);
|
||||
@@ -599,7 +599,7 @@ static int virtio_net_handle_offloads(VirtIONet *n, uint8_t cmd,
|
||||
uint64_t offloads;
|
||||
size_t s;
|
||||
|
||||
if (!virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) {
|
||||
if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) {
|
||||
return VIRTIO_NET_ERR;
|
||||
}
|
||||
|
||||
@@ -1086,13 +1086,7 @@ static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t
|
||||
* must have consumed the complete packet.
|
||||
* Otherwise, drop it. */
|
||||
if (!n->mergeable_rx_bufs && offset < size) {
|
||||
#if 0
|
||||
error_report("virtio-net truncated non-mergeable packet: "
|
||||
"i %zd mergeable %d offset %zd, size %zd, "
|
||||
"guest hdr len %zd, host hdr len %zd",
|
||||
i, n->mergeable_rx_bufs,
|
||||
offset, size, n->guest_hdr_len, n->host_hdr_len);
|
||||
#endif
|
||||
virtqueue_discard(q->rx_vq, &elem, total);
|
||||
return size;
|
||||
}
|
||||
|
||||
@@ -1453,7 +1447,7 @@ static void virtio_net_save_device(VirtIODevice *vdev, QEMUFile *f)
|
||||
}
|
||||
}
|
||||
|
||||
if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) {
|
||||
if (virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) {
|
||||
qemu_put_be64(f, n->curr_guest_offloads);
|
||||
}
|
||||
}
|
||||
@@ -1462,11 +1456,33 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
VirtIONet *n = opaque;
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(n);
|
||||
int ret;
|
||||
|
||||
if (version_id < 2 || version_id > VIRTIO_NET_VM_VERSION)
|
||||
return -EINVAL;
|
||||
|
||||
return virtio_load(vdev, f, version_id);
|
||||
ret = virtio_load(vdev, f, version_id);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) {
|
||||
n->curr_guest_offloads = qemu_get_be64(f);
|
||||
} else {
|
||||
n->curr_guest_offloads = virtio_net_supported_guest_offloads(n);
|
||||
}
|
||||
|
||||
if (peer_has_vnet_hdr(n)) {
|
||||
virtio_net_apply_guest_offloads(n);
|
||||
}
|
||||
|
||||
if (virtio_vdev_has_feature(vdev, VIRTIO_NET_F_GUEST_ANNOUNCE) &&
|
||||
virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ)) {
|
||||
n->announce_counter = SELF_ANNOUNCE_ROUNDS;
|
||||
timer_mod(n->announce_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int virtio_net_load_device(VirtIODevice *vdev, QEMUFile *f,
|
||||
@@ -1479,7 +1495,8 @@ static int virtio_net_load_device(VirtIODevice *vdev, QEMUFile *f,
|
||||
n->vqs[0].tx_waiting = qemu_get_be32(f);
|
||||
|
||||
virtio_net_set_mrg_rx_bufs(n, qemu_get_be32(f),
|
||||
virtio_has_feature(vdev, VIRTIO_F_VERSION_1));
|
||||
virtio_vdev_has_feature(vdev,
|
||||
VIRTIO_F_VERSION_1));
|
||||
|
||||
if (version_id >= 3)
|
||||
n->status = qemu_get_be16(f);
|
||||
@@ -1562,16 +1579,6 @@ static int virtio_net_load_device(VirtIODevice *vdev, QEMUFile *f,
|
||||
}
|
||||
}
|
||||
|
||||
if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) {
|
||||
n->curr_guest_offloads = qemu_get_be64(f);
|
||||
} else {
|
||||
n->curr_guest_offloads = virtio_net_supported_guest_offloads(n);
|
||||
}
|
||||
|
||||
if (peer_has_vnet_hdr(n)) {
|
||||
virtio_net_apply_guest_offloads(n);
|
||||
}
|
||||
|
||||
virtio_net_set_queues(n);
|
||||
|
||||
/* Find the first multicast entry in the saved MAC filter */
|
||||
@@ -1589,12 +1596,6 @@ static int virtio_net_load_device(VirtIODevice *vdev, QEMUFile *f,
|
||||
qemu_get_subqueue(n->nic, i)->link_down = link_down;
|
||||
}
|
||||
|
||||
if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ANNOUNCE) &&
|
||||
virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ)) {
|
||||
n->announce_counter = SELF_ANNOUNCE_ROUNDS;
|
||||
timer_mod(n->announce_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1988,7 +1988,6 @@ static void vmxnet3_set_link_status(NetClientState *nc)
|
||||
static NetClientInfo net_vmxnet3_info = {
|
||||
.type = NET_CLIENT_OPTIONS_KIND_NIC,
|
||||
.size = sizeof(NICState),
|
||||
.can_receive = vmxnet3_can_receive,
|
||||
.receive = vmxnet3_receive,
|
||||
.link_status_changed = vmxnet3_set_link_status,
|
||||
};
|
||||
|
||||
@@ -500,6 +500,8 @@ static void pci_vpb_class_init(ObjectClass *klass, void *data)
|
||||
dc->reset = pci_vpb_reset;
|
||||
dc->vmsd = &pci_vpb_vmstate;
|
||||
dc->props = pci_vpb_properties;
|
||||
/* Reason: object_unref() hangs */
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static const TypeInfo pci_vpb_info = {
|
||||
@@ -521,10 +523,19 @@ static void pci_realview_init(Object *obj)
|
||||
s->mem_win_size[2] = 0x08000000;
|
||||
}
|
||||
|
||||
static void pci_realview_class_init(ObjectClass *class, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(class);
|
||||
|
||||
/* Reason: object_unref() hangs */
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static const TypeInfo pci_realview_info = {
|
||||
.name = "realview_pci",
|
||||
.parent = TYPE_VERSATILE_PCI,
|
||||
.instance_init = pci_realview_init,
|
||||
.class_init = pci_realview_class_init,
|
||||
};
|
||||
|
||||
static void versatile_pci_register_types(void)
|
||||
|
||||
+3
-3
@@ -163,7 +163,7 @@ static void pxa2xx_pcmcia_initfn(Object *obj)
|
||||
sysbus_init_mmio(sbd, &s->container_mem);
|
||||
|
||||
/* Socket I/O Memory Space */
|
||||
memory_region_init_io(&s->iomem, NULL, &pxa2xx_pcmcia_io_ops, s,
|
||||
memory_region_init_io(&s->iomem, obj, &pxa2xx_pcmcia_io_ops, s,
|
||||
"pxa2xx-pcmcia-io", 0x04000000);
|
||||
memory_region_add_subregion(&s->container_mem, 0x00000000,
|
||||
&s->iomem);
|
||||
@@ -171,13 +171,13 @@ static void pxa2xx_pcmcia_initfn(Object *obj)
|
||||
/* Then next 64 MB is reserved */
|
||||
|
||||
/* Socket Attribute Memory Space */
|
||||
memory_region_init_io(&s->attr_iomem, NULL, &pxa2xx_pcmcia_attr_ops, s,
|
||||
memory_region_init_io(&s->attr_iomem, obj, &pxa2xx_pcmcia_attr_ops, s,
|
||||
"pxa2xx-pcmcia-attribute", 0x04000000);
|
||||
memory_region_add_subregion(&s->container_mem, 0x08000000,
|
||||
&s->attr_iomem);
|
||||
|
||||
/* Socket Common Memory Space */
|
||||
memory_region_init_io(&s->common_iomem, NULL, &pxa2xx_pcmcia_common_ops, s,
|
||||
memory_region_init_io(&s->common_iomem, obj, &pxa2xx_pcmcia_common_ops, s,
|
||||
"pxa2xx-pcmcia-common", 0x04000000);
|
||||
memory_region_add_subregion(&s->container_mem, 0x0c000000,
|
||||
&s->common_iomem);
|
||||
|
||||
+10
-2
@@ -955,6 +955,7 @@ static int spapr_populate_pci_child_dt(PCIDevice *dev, void *fdt, int offset,
|
||||
int pci_status, err;
|
||||
char *buf = NULL;
|
||||
uint32_t drc_index = spapr_phb_get_pci_drc_index(sphb, dev);
|
||||
uint32_t max_msi, max_msix;
|
||||
|
||||
if (pci_default_read_config(dev, PCI_HEADER_TYPE, 1) ==
|
||||
PCI_HEADER_TYPE_BRIDGE) {
|
||||
@@ -1035,8 +1036,15 @@ static int spapr_populate_pci_child_dt(PCIDevice *dev, void *fdt, int offset,
|
||||
RESOURCE_CELLS_ADDRESS));
|
||||
_FDT(fdt_setprop_cell(fdt, offset, "#size-cells",
|
||||
RESOURCE_CELLS_SIZE));
|
||||
_FDT(fdt_setprop_cell(fdt, offset, "ibm,req#msi-x",
|
||||
RESOURCE_CELLS_SIZE));
|
||||
|
||||
max_msi = msi_nr_vectors_allocated(dev);
|
||||
if (max_msi) {
|
||||
_FDT(fdt_setprop_cell(fdt, offset, "ibm,req#msi", max_msi));
|
||||
}
|
||||
max_msix = dev->msix_entries_nr;
|
||||
if (max_msix) {
|
||||
_FDT(fdt_setprop_cell(fdt, offset, "ibm,req#msi-x", max_msix));
|
||||
}
|
||||
|
||||
populate_resource_props(dev, &rp);
|
||||
_FDT(fdt_setprop(fdt, offset, "reg", (uint8_t *)rp.reg, rp.reg_len));
|
||||
|
||||
@@ -392,6 +392,8 @@ static void sch_handle_start_func(SubchDev *sch, ORB *orb)
|
||||
path = 0x80;
|
||||
|
||||
if (!(s->ctrl & SCSW_ACTL_SUSP)) {
|
||||
s->cstat = 0;
|
||||
s->dstat = 0;
|
||||
/* Look at the orb and try to execute the channel program. */
|
||||
assert(orb != NULL); /* resume does not pass an orb */
|
||||
p->intparm = orb->intparm;
|
||||
|
||||
@@ -1683,6 +1683,10 @@ static void scsi_write_same_complete(void *opaque, int ret)
|
||||
if (data->iov.iov_len) {
|
||||
block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct,
|
||||
data->iov.iov_len, BLOCK_ACCT_WRITE);
|
||||
/* blk_aio_write doesn't like the qiov size being different from
|
||||
* nb_sectors, make sure they match.
|
||||
*/
|
||||
qemu_iovec_init_external(&data->qiov, &data->iov, 1);
|
||||
r->req.aiocb = blk_aio_writev(s->qdev.conf.blk, data->sector,
|
||||
&data->qiov, data->iov.iov_len / 512,
|
||||
scsi_write_same_complete, data);
|
||||
|
||||
@@ -291,7 +291,7 @@ static char *vhost_scsi_get_fw_dev_path(FWPathProvider *p, BusState *bus,
|
||||
{
|
||||
VHostSCSI *s = VHOST_SCSI(dev);
|
||||
/* format: channel@channel/vhost-scsi@target,lun */
|
||||
return g_strdup_printf("channel@%x/%s@%x,%x", s->channel,
|
||||
return g_strdup_printf("/channel@%x/%s@%x,%x", s->channel,
|
||||
qdev_fw_name(dev), s->target, s->lun);
|
||||
}
|
||||
|
||||
|
||||
@@ -145,7 +145,7 @@ static int virtio_scsi_parse_req(VirtIOSCSIReq *req,
|
||||
*
|
||||
* TODO: always disable this workaround for virtio 1.0 devices.
|
||||
*/
|
||||
if (!virtio_has_feature(vdev, VIRTIO_F_ANY_LAYOUT)) {
|
||||
if (!virtio_vdev_has_feature(vdev, VIRTIO_F_ANY_LAYOUT)) {
|
||||
if (req->elem.out_num) {
|
||||
req_size = req->elem.out_sg[0].iov_len;
|
||||
}
|
||||
@@ -662,6 +662,11 @@ static void virtio_scsi_reset(VirtIODevice *vdev)
|
||||
static void virtio_scsi_save(QEMUFile *f, void *opaque)
|
||||
{
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(opaque);
|
||||
VirtIOSCSI *s = VIRTIO_SCSI(vdev);
|
||||
|
||||
if (s->dataplane_started) {
|
||||
virtio_scsi_dataplane_stop(s);
|
||||
}
|
||||
virtio_save(vdev, f);
|
||||
}
|
||||
|
||||
@@ -754,7 +759,7 @@ static void virtio_scsi_change(SCSIBus *bus, SCSIDevice *dev, SCSISense sense)
|
||||
VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus);
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(s);
|
||||
|
||||
if (virtio_has_feature(vdev, VIRTIO_SCSI_F_CHANGE) &&
|
||||
if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_CHANGE) &&
|
||||
dev->type != TYPE_ROM) {
|
||||
virtio_scsi_push_event(s, dev, VIRTIO_SCSI_T_PARAM_CHANGE,
|
||||
sense.asc | (sense.ascq << 8));
|
||||
@@ -778,7 +783,7 @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||||
aio_context_release(s->ctx);
|
||||
}
|
||||
|
||||
if (virtio_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) {
|
||||
if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) {
|
||||
virtio_scsi_push_event(s, sd,
|
||||
VIRTIO_SCSI_T_TRANSPORT_RESET,
|
||||
VIRTIO_SCSI_EVT_RESET_RESCAN);
|
||||
@@ -792,7 +797,7 @@ static void virtio_scsi_hotunplug(HotplugHandler *hotplug_dev, DeviceState *dev,
|
||||
VirtIOSCSI *s = VIRTIO_SCSI(vdev);
|
||||
SCSIDevice *sd = SCSI_DEVICE(dev);
|
||||
|
||||
if (virtio_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) {
|
||||
if (virtio_vdev_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) {
|
||||
virtio_scsi_push_event(s, sd,
|
||||
VIRTIO_SCSI_T_TRANSPORT_RESET,
|
||||
VIRTIO_SCSI_EVT_RESET_REMOVED);
|
||||
|
||||
+58
-17
@@ -67,22 +67,53 @@ static void vring_unmap(void *buffer, bool is_write)
|
||||
/* Map the guest's vring to host memory */
|
||||
bool vring_setup(Vring *vring, VirtIODevice *vdev, int n)
|
||||
{
|
||||
hwaddr vring_addr = virtio_queue_get_ring_addr(vdev, n);
|
||||
hwaddr vring_size = virtio_queue_get_ring_size(vdev, n);
|
||||
void *vring_ptr;
|
||||
struct vring *vr = &vring->vr;
|
||||
hwaddr addr;
|
||||
hwaddr size;
|
||||
void *ptr;
|
||||
|
||||
vring->broken = false;
|
||||
vr->num = virtio_queue_get_num(vdev, n);
|
||||
|
||||
vring_ptr = vring_map(&vring->mr, vring_addr, vring_size, true);
|
||||
if (!vring_ptr) {
|
||||
error_report("Failed to map vring "
|
||||
"addr %#" HWADDR_PRIx " size %" HWADDR_PRIu,
|
||||
vring_addr, vring_size);
|
||||
vring->broken = true;
|
||||
return false;
|
||||
addr = virtio_queue_get_desc_addr(vdev, n);
|
||||
size = virtio_queue_get_desc_size(vdev, n);
|
||||
/* Map the descriptor area as read only */
|
||||
ptr = vring_map(&vring->mr_desc, addr, size, false);
|
||||
if (!ptr) {
|
||||
error_report("Failed to map 0x%" HWADDR_PRIx " byte for vring desc "
|
||||
"at 0x%" HWADDR_PRIx,
|
||||
size, addr);
|
||||
goto out_err_desc;
|
||||
}
|
||||
vr->desc = ptr;
|
||||
|
||||
vring_init(&vring->vr, virtio_queue_get_num(vdev, n), vring_ptr, 4096);
|
||||
addr = virtio_queue_get_avail_addr(vdev, n);
|
||||
size = virtio_queue_get_avail_size(vdev, n);
|
||||
/* Add the size of the used_event_idx */
|
||||
size += sizeof(uint16_t);
|
||||
/* Map the driver area as read only */
|
||||
ptr = vring_map(&vring->mr_avail, addr, size, false);
|
||||
if (!ptr) {
|
||||
error_report("Failed to map 0x%" HWADDR_PRIx " byte for vring avail "
|
||||
"at 0x%" HWADDR_PRIx,
|
||||
size, addr);
|
||||
goto out_err_avail;
|
||||
}
|
||||
vr->avail = ptr;
|
||||
|
||||
addr = virtio_queue_get_used_addr(vdev, n);
|
||||
size = virtio_queue_get_used_size(vdev, n);
|
||||
/* Add the size of the avail_event_idx */
|
||||
size += sizeof(uint16_t);
|
||||
/* Map the device area as read-write */
|
||||
ptr = vring_map(&vring->mr_used, addr, size, true);
|
||||
if (!ptr) {
|
||||
error_report("Failed to map 0x%" HWADDR_PRIx " byte for vring used "
|
||||
"at 0x%" HWADDR_PRIx,
|
||||
size, addr);
|
||||
goto out_err_used;
|
||||
}
|
||||
vr->used = ptr;
|
||||
|
||||
vring->last_avail_idx = virtio_queue_get_last_avail_idx(vdev, n);
|
||||
vring->last_used_idx = vring_get_used_idx(vdev, vring);
|
||||
@@ -92,6 +123,14 @@ bool vring_setup(Vring *vring, VirtIODevice *vdev, int n)
|
||||
trace_vring_setup(virtio_queue_get_ring_addr(vdev, n),
|
||||
vring->vr.desc, vring->vr.avail, vring->vr.used);
|
||||
return true;
|
||||
|
||||
out_err_used:
|
||||
memory_region_unref(vring->mr_avail);
|
||||
out_err_avail:
|
||||
memory_region_unref(vring->mr_desc);
|
||||
out_err_desc:
|
||||
vring->broken = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void vring_teardown(Vring *vring, VirtIODevice *vdev, int n)
|
||||
@@ -99,13 +138,15 @@ void vring_teardown(Vring *vring, VirtIODevice *vdev, int n)
|
||||
virtio_queue_set_last_avail_idx(vdev, n, vring->last_avail_idx);
|
||||
virtio_queue_invalidate_signalled_used(vdev, n);
|
||||
|
||||
memory_region_unref(vring->mr);
|
||||
memory_region_unref(vring->mr_desc);
|
||||
memory_region_unref(vring->mr_avail);
|
||||
memory_region_unref(vring->mr_used);
|
||||
}
|
||||
|
||||
/* Disable guest->host notifies */
|
||||
void vring_disable_notification(VirtIODevice *vdev, Vring *vring)
|
||||
{
|
||||
if (!virtio_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) {
|
||||
if (!virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) {
|
||||
vring_set_used_flags(vdev, vring, VRING_USED_F_NO_NOTIFY);
|
||||
}
|
||||
}
|
||||
@@ -116,7 +157,7 @@ void vring_disable_notification(VirtIODevice *vdev, Vring *vring)
|
||||
*/
|
||||
bool vring_enable_notification(VirtIODevice *vdev, Vring *vring)
|
||||
{
|
||||
if (virtio_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) {
|
||||
if (virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) {
|
||||
vring_avail_event(&vring->vr) = vring->vr.avail->idx;
|
||||
} else {
|
||||
vring_clear_used_flags(vdev, vring, VRING_USED_F_NO_NOTIFY);
|
||||
@@ -135,12 +176,12 @@ bool vring_should_notify(VirtIODevice *vdev, Vring *vring)
|
||||
* interrupts. */
|
||||
smp_mb();
|
||||
|
||||
if (virtio_has_feature(vdev, VIRTIO_F_NOTIFY_ON_EMPTY) &&
|
||||
if (virtio_vdev_has_feature(vdev, VIRTIO_F_NOTIFY_ON_EMPTY) &&
|
||||
unlikely(!vring_more_avail(vdev, vring))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!virtio_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) {
|
||||
if (!virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) {
|
||||
return !(vring_get_avail_flags(vdev, vring) &
|
||||
VRING_AVAIL_F_NO_INTERRUPT);
|
||||
}
|
||||
@@ -402,7 +443,7 @@ int vring_pop(VirtIODevice *vdev, Vring *vring,
|
||||
|
||||
/* On success, increment avail index. */
|
||||
vring->last_avail_idx++;
|
||||
if (virtio_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) {
|
||||
if (virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) {
|
||||
vring_avail_event(&vring->vr) =
|
||||
virtio_tswap16(vdev, vring->last_avail_idx);
|
||||
}
|
||||
|
||||
+2
-2
@@ -742,7 +742,7 @@ static int vhost_virtqueue_start(struct vhost_dev *dev,
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1) &&
|
||||
if (!virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1) &&
|
||||
virtio_legacy_is_cross_endian(vdev)) {
|
||||
r = vhost_virtqueue_set_vring_endian_legacy(dev,
|
||||
virtio_is_big_endian(vdev),
|
||||
@@ -839,7 +839,7 @@ static void vhost_virtqueue_stop(struct vhost_dev *dev,
|
||||
/* In the cross-endian case, we need to reset the vring endianness to
|
||||
* native as legacy devices expect so by default.
|
||||
*/
|
||||
if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1) &&
|
||||
if (!virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1) &&
|
||||
virtio_legacy_is_cross_endian(vdev)) {
|
||||
r = vhost_virtqueue_set_vring_endian_legacy(dev,
|
||||
!virtio_is_big_endian(vdev),
|
||||
|
||||
@@ -70,7 +70,7 @@ static inline void reset_stats(VirtIOBalloon *dev)
|
||||
static bool balloon_stats_supported(const VirtIOBalloon *s)
|
||||
{
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(s);
|
||||
return virtio_has_feature(vdev, VIRTIO_BALLOON_F_STATS_VQ);
|
||||
return virtio_vdev_has_feature(vdev, VIRTIO_BALLOON_F_STATS_VQ);
|
||||
}
|
||||
|
||||
static bool balloon_stats_enabled(const VirtIOBalloon *s)
|
||||
|
||||
+80
-11
@@ -220,7 +220,7 @@ static inline void vring_set_avail_event(VirtQueue *vq, uint16_t val)
|
||||
void virtio_queue_set_notification(VirtQueue *vq, int enable)
|
||||
{
|
||||
vq->notification = enable;
|
||||
if (virtio_has_feature(vq->vdev, VIRTIO_RING_F_EVENT_IDX)) {
|
||||
if (virtio_vdev_has_feature(vq->vdev, VIRTIO_RING_F_EVENT_IDX)) {
|
||||
vring_set_avail_event(vq, vring_avail_idx(vq));
|
||||
} else if (enable) {
|
||||
vring_used_flags_unset_bit(vq, VRING_USED_F_NO_NOTIFY);
|
||||
@@ -243,14 +243,12 @@ int virtio_queue_empty(VirtQueue *vq)
|
||||
return vring_avail_idx(vq) == vq->last_avail_idx;
|
||||
}
|
||||
|
||||
void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
|
||||
unsigned int len, unsigned int idx)
|
||||
static void virtqueue_unmap_sg(VirtQueue *vq, const VirtQueueElement *elem,
|
||||
unsigned int len)
|
||||
{
|
||||
unsigned int offset;
|
||||
int i;
|
||||
|
||||
trace_virtqueue_fill(vq, elem, len, idx);
|
||||
|
||||
offset = 0;
|
||||
for (i = 0; i < elem->in_num; i++) {
|
||||
size_t size = MIN(len - offset, elem->in_sg[i].iov_len);
|
||||
@@ -266,6 +264,21 @@ void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
|
||||
cpu_physical_memory_unmap(elem->out_sg[i].iov_base,
|
||||
elem->out_sg[i].iov_len,
|
||||
0, elem->out_sg[i].iov_len);
|
||||
}
|
||||
|
||||
void virtqueue_discard(VirtQueue *vq, const VirtQueueElement *elem,
|
||||
unsigned int len)
|
||||
{
|
||||
vq->last_avail_idx--;
|
||||
virtqueue_unmap_sg(vq, elem, len);
|
||||
}
|
||||
|
||||
void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
|
||||
unsigned int len, unsigned int idx)
|
||||
{
|
||||
trace_virtqueue_fill(vq, elem, len, idx);
|
||||
|
||||
virtqueue_unmap_sg(vq, elem, len);
|
||||
|
||||
idx = (idx + vring_used_idx(vq)) % vq->vring.num;
|
||||
|
||||
@@ -471,7 +484,7 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem)
|
||||
max = vq->vring.num;
|
||||
|
||||
i = head = virtqueue_get_head(vq, vq->last_avail_idx++);
|
||||
if (virtio_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) {
|
||||
if (virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) {
|
||||
vring_set_avail_event(vq, vq->last_avail_idx);
|
||||
}
|
||||
|
||||
@@ -560,7 +573,7 @@ int virtio_set_status(VirtIODevice *vdev, uint8_t val)
|
||||
VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
|
||||
trace_virtio_set_status(vdev, val);
|
||||
|
||||
if (virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) {
|
||||
if (virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) {
|
||||
if (!(vdev->status & VIRTIO_CONFIG_S_FEATURES_OK) &&
|
||||
val & VIRTIO_CONFIG_S_FEATURES_OK) {
|
||||
int ret = virtio_validate_features(vdev);
|
||||
@@ -898,7 +911,7 @@ void virtio_queue_set_align(VirtIODevice *vdev, int n, int align)
|
||||
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
|
||||
|
||||
/* virtio-1 compliant devices cannot change the alignment */
|
||||
if (virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) {
|
||||
if (virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) {
|
||||
error_report("tried to modify queue alignment for virtio-1 device");
|
||||
return;
|
||||
}
|
||||
@@ -993,12 +1006,12 @@ static bool vring_notify(VirtIODevice *vdev, VirtQueue *vq)
|
||||
/* We need to expose used array entries before checking used event. */
|
||||
smp_mb();
|
||||
/* Always notify when queue is empty (when feature acknowledge) */
|
||||
if (virtio_has_feature(vdev, VIRTIO_F_NOTIFY_ON_EMPTY) &&
|
||||
if (virtio_vdev_has_feature(vdev, VIRTIO_F_NOTIFY_ON_EMPTY) &&
|
||||
!vq->inuse && vring_avail_idx(vq) == vq->last_avail_idx) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!virtio_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) {
|
||||
if (!virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX)) {
|
||||
return !(vring_avail_flags(vq) & VRING_AVAIL_F_NO_INTERRUPT);
|
||||
}
|
||||
|
||||
@@ -1035,7 +1048,7 @@ static bool virtio_device_endian_needed(void *opaque)
|
||||
VirtIODevice *vdev = opaque;
|
||||
|
||||
assert(vdev->device_endian != VIRTIO_DEVICE_ENDIAN_UNKNOWN);
|
||||
if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) {
|
||||
if (!virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) {
|
||||
return vdev->device_endian != virtio_default_endian();
|
||||
}
|
||||
/* Devices conforming to VIRTIO 1.0 or later are always LE. */
|
||||
@@ -1049,6 +1062,61 @@ static bool virtio_64bit_features_needed(void *opaque)
|
||||
return (vdev->host_features >> 32) != 0;
|
||||
}
|
||||
|
||||
static bool virtio_virtqueue_needed(void *opaque)
|
||||
{
|
||||
VirtIODevice *vdev = opaque;
|
||||
|
||||
return virtio_host_has_feature(vdev, VIRTIO_F_VERSION_1);
|
||||
}
|
||||
|
||||
static void put_virtqueue_state(QEMUFile *f, void *pv, size_t size)
|
||||
{
|
||||
VirtIODevice *vdev = pv;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
|
||||
qemu_put_be64(f, vdev->vq[i].vring.avail);
|
||||
qemu_put_be64(f, vdev->vq[i].vring.used);
|
||||
}
|
||||
}
|
||||
|
||||
static int get_virtqueue_state(QEMUFile *f, void *pv, size_t size)
|
||||
{
|
||||
VirtIODevice *vdev = pv;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
|
||||
vdev->vq[i].vring.avail = qemu_get_be64(f);
|
||||
vdev->vq[i].vring.used = qemu_get_be64(f);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static VMStateInfo vmstate_info_virtqueue = {
|
||||
.name = "virtqueue_state",
|
||||
.get = get_virtqueue_state,
|
||||
.put = put_virtqueue_state,
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_virtio_virtqueues = {
|
||||
.name = "virtio/virtqueues",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.needed = &virtio_virtqueue_needed,
|
||||
.fields = (VMStateField[]) {
|
||||
{
|
||||
.name = "virtqueues",
|
||||
.version_id = 0,
|
||||
.field_exists = NULL,
|
||||
.size = 0,
|
||||
.info = &vmstate_info_virtqueue,
|
||||
.flags = VMS_SINGLE,
|
||||
.offset = 0,
|
||||
},
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_virtio_device_endian = {
|
||||
.name = "virtio/device_endian",
|
||||
.version_id = 1,
|
||||
@@ -1082,6 +1150,7 @@ static const VMStateDescription vmstate_virtio = {
|
||||
.subsections = (const VMStateDescription*[]) {
|
||||
&vmstate_virtio_device_endian,
|
||||
&vmstate_virtio_64bit_features,
|
||||
&vmstate_virtio_virtqueues,
|
||||
NULL
|
||||
}
|
||||
};
|
||||
|
||||
@@ -308,11 +308,7 @@ extern uintptr_t tci_tb_ptr;
|
||||
to indicate the compressed mode; subtracting two works around that. It
|
||||
is also the case that there are no host isas that contain a call insn
|
||||
smaller than 4 bytes, so we don't worry about special-casing this. */
|
||||
#if defined(CONFIG_TCG_INTERPRETER)
|
||||
# define GETPC_ADJ 0
|
||||
#else
|
||||
# define GETPC_ADJ 2
|
||||
#endif
|
||||
#define GETPC_ADJ 2
|
||||
|
||||
#define GETPC() (GETRA() - GETPC_ADJ)
|
||||
|
||||
|
||||
@@ -350,6 +350,10 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
|
||||
.driver = "SandyBridge" "-" TYPE_X86_CPU,\
|
||||
.property = "xlevel",\
|
||||
.value = stringify(0x8000000a),\
|
||||
},{\
|
||||
.driver = "IvyBridge" "-" TYPE_X86_CPU,\
|
||||
.property = "xlevel",\
|
||||
.value = stringify(0x8000000a),\
|
||||
},{\
|
||||
.driver = "Haswell" "-" TYPE_X86_CPU,\
|
||||
.property = "xlevel",\
|
||||
|
||||
@@ -114,6 +114,19 @@ typedef struct DeviceClass {
|
||||
* TODO remove once we're there
|
||||
*/
|
||||
bool cannot_instantiate_with_device_add_yet;
|
||||
/*
|
||||
* Does this device model survive object_unref(object_new(TNAME))?
|
||||
* All device models should, and this flag shouldn't exist. Some
|
||||
* devices crash in object_new(), some crash or hang in
|
||||
* object_unref(). Makes introspecting properties with
|
||||
* qmp_device_list_properties() dangerous. Bad, because it's used
|
||||
* by -device FOO,help. This flag serves to protect that code.
|
||||
* It should never be set without a comment explaining why it is
|
||||
* set.
|
||||
* TODO remove once we're there
|
||||
*/
|
||||
bool cannot_destroy_with_object_finalize_yet;
|
||||
|
||||
bool hotpluggable;
|
||||
|
||||
/* callbacks */
|
||||
|
||||
@@ -22,7 +22,9 @@
|
||||
#include "hw/virtio/virtio.h"
|
||||
|
||||
typedef struct {
|
||||
MemoryRegion *mr; /* memory region containing the vring */
|
||||
MemoryRegion *mr_desc; /* memory region for the vring desc */
|
||||
MemoryRegion *mr_avail; /* memory region for the vring avail */
|
||||
MemoryRegion *mr_used; /* memory region for the vring used */
|
||||
struct vring vr; /* virtqueue vring mapped to host memory */
|
||||
uint16_t last_avail_idx; /* last processed avail ring index */
|
||||
uint16_t last_used_idx; /* last processed used ring index */
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
static inline bool virtio_access_is_big_endian(VirtIODevice *vdev)
|
||||
{
|
||||
if (virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) {
|
||||
if (virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) {
|
||||
/* Devices conforming to VIRTIO 1.0 or later are always LE. */
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -146,6 +146,8 @@ void virtio_del_queue(VirtIODevice *vdev, int n);
|
||||
void virtqueue_push(VirtQueue *vq, const VirtQueueElement *elem,
|
||||
unsigned int len);
|
||||
void virtqueue_flush(VirtQueue *vq, unsigned int count);
|
||||
void virtqueue_discard(VirtQueue *vq, const VirtQueueElement *elem,
|
||||
unsigned int len);
|
||||
void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem,
|
||||
unsigned int len, unsigned int idx);
|
||||
|
||||
@@ -261,20 +263,27 @@ static inline void virtio_clear_feature(uint64_t *features, unsigned int fbit)
|
||||
*features &= ~(1ULL << fbit);
|
||||
}
|
||||
|
||||
static inline bool __virtio_has_feature(uint64_t features, unsigned int fbit)
|
||||
static inline bool virtio_has_feature(uint64_t features, unsigned int fbit)
|
||||
{
|
||||
assert(fbit < 64);
|
||||
return !!(features & (1ULL << fbit));
|
||||
}
|
||||
|
||||
static inline bool virtio_has_feature(VirtIODevice *vdev, unsigned int fbit)
|
||||
static inline bool virtio_vdev_has_feature(VirtIODevice *vdev,
|
||||
unsigned int fbit)
|
||||
{
|
||||
return __virtio_has_feature(vdev->guest_features, fbit);
|
||||
return virtio_has_feature(vdev->guest_features, fbit);
|
||||
}
|
||||
|
||||
static inline bool virtio_host_has_feature(VirtIODevice *vdev,
|
||||
unsigned int fbit)
|
||||
{
|
||||
return virtio_has_feature(vdev->host_features, fbit);
|
||||
}
|
||||
|
||||
static inline bool virtio_is_big_endian(VirtIODevice *vdev)
|
||||
{
|
||||
if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) {
|
||||
if (!virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) {
|
||||
assert(vdev->device_endian != VIRTIO_DEVICE_ENDIAN_UNKNOWN);
|
||||
return vdev->device_endian == VIRTIO_DEVICE_ENDIAN_BIG;
|
||||
}
|
||||
|
||||
@@ -203,4 +203,5 @@ void register_global_state(void);
|
||||
void global_state_set_optional(void);
|
||||
void savevm_skip_configuration(void);
|
||||
int global_state_store(void);
|
||||
void global_state_store_running(void);
|
||||
#endif
|
||||
@@ -887,8 +887,8 @@ struct input_keymap_entry {
|
||||
#define SW_ROTATE_LOCK 0x0c /* set = rotate locked/disabled */
|
||||
#define SW_LINEIN_INSERT 0x0d /* set = inserted */
|
||||
#define SW_MUTE_DEVICE 0x0e /* set = device disabled */
|
||||
#define SW_MAX 0x0f
|
||||
#define SW_CNT (SW_MAX+1)
|
||||
#define SW_MAX_ 0x0f
|
||||
#define SW_CNT (SW_MAX_+1)
|
||||
|
||||
/*
|
||||
* Misc events
|
||||
|
||||
@@ -1312,7 +1312,22 @@ static void memory_region_finalize(Object *obj)
|
||||
{
|
||||
MemoryRegion *mr = MEMORY_REGION(obj);
|
||||
|
||||
assert(QTAILQ_EMPTY(&mr->subregions));
|
||||
assert(!mr->container);
|
||||
|
||||
/* We know the region is not visible in any address space (it
|
||||
* does not have a container and cannot be a root either because
|
||||
* it has no references, so we can blindly clear mr->enabled.
|
||||
* memory_region_set_enabled instead could trigger a transaction
|
||||
* and cause an infinite loop.
|
||||
*/
|
||||
mr->enabled = false;
|
||||
memory_region_transaction_begin();
|
||||
while (!QTAILQ_EMPTY(&mr->subregions)) {
|
||||
MemoryRegion *subregion = QTAILQ_FIRST(&mr->subregions);
|
||||
memory_region_del_subregion(mr, subregion);
|
||||
}
|
||||
memory_region_transaction_commit();
|
||||
|
||||
mr->destructor(mr);
|
||||
memory_region_clear_coalescing(mr);
|
||||
g_free((char *)mr->name);
|
||||
|
||||
+14
-1
@@ -122,6 +122,13 @@ int global_state_store(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void global_state_store_running(void)
|
||||
{
|
||||
const char *state = RunState_lookup[RUN_STATE_RUNNING];
|
||||
strncpy((char *)global_state.runstate,
|
||||
state, sizeof(global_state.runstate));
|
||||
}
|
||||
|
||||
static bool global_state_received(void)
|
||||
{
|
||||
return global_state.received;
|
||||
@@ -279,12 +286,12 @@ static void process_incoming_migration_co(void *opaque)
|
||||
migrate_decompress_threads_join();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
migrate_generate_event(MIGRATION_STATUS_COMPLETED);
|
||||
qemu_announce_self();
|
||||
|
||||
/* Make sure all file formats flush their mutable metadata */
|
||||
bdrv_invalidate_cache_all(&local_err);
|
||||
if (local_err) {
|
||||
migrate_generate_event(MIGRATION_STATUS_FAILED);
|
||||
error_report_err(local_err);
|
||||
migrate_decompress_threads_join();
|
||||
exit(EXIT_FAILURE);
|
||||
@@ -305,6 +312,12 @@ static void process_incoming_migration_co(void *opaque)
|
||||
runstate_set(global_state_get_runstate());
|
||||
}
|
||||
migrate_decompress_threads_join();
|
||||
/*
|
||||
* This must happen after any state changes since as soon as an external
|
||||
* observer sees this event they might start to prod at the VM assuming
|
||||
* it's ready to use.
|
||||
*/
|
||||
migrate_generate_event(MIGRATION_STATUS_COMPLETED);
|
||||
}
|
||||
|
||||
void process_incoming_migration(QEMUFile *f)
|
||||
|
||||
@@ -1394,6 +1394,7 @@ void qmp_xen_save_devices_state(const char *filename, Error **errp)
|
||||
|
||||
saved_vm_running = runstate_is_running();
|
||||
vm_stop(RUN_STATE_SAVE_VM);
|
||||
global_state_store_running();
|
||||
|
||||
f = qemu_fopen(filename, "wb");
|
||||
if (!f) {
|
||||
|
||||
@@ -1131,12 +1131,6 @@ void nbd_export_close(NBDExport *exp)
|
||||
}
|
||||
nbd_export_set_name(exp, NULL);
|
||||
nbd_export_put(exp);
|
||||
if (exp->blk) {
|
||||
blk_remove_aio_context_notifier(exp->blk, blk_aio_attached,
|
||||
blk_aio_detach, exp);
|
||||
blk_unref(exp->blk);
|
||||
exp->blk = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void nbd_export_get(NBDExport *exp)
|
||||
@@ -1159,6 +1153,13 @@ void nbd_export_put(NBDExport *exp)
|
||||
exp->close(exp);
|
||||
}
|
||||
|
||||
if (exp->blk) {
|
||||
blk_remove_aio_context_notifier(exp->blk, blk_aio_attached,
|
||||
blk_aio_detach, exp);
|
||||
blk_unref(exp->blk);
|
||||
exp->blk = NULL;
|
||||
}
|
||||
|
||||
g_free(exp);
|
||||
}
|
||||
}
|
||||
@@ -1305,6 +1306,14 @@ static void nbd_trip(void *opaque)
|
||||
goto invalid_request;
|
||||
}
|
||||
|
||||
if (client->closing) {
|
||||
/*
|
||||
* The client may be closed when we are blocked in
|
||||
* nbd_co_receive_request()
|
||||
*/
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch (command) {
|
||||
case NBD_CMD_READ:
|
||||
TRACE("Request type is READ");
|
||||
|
||||
@@ -517,20 +517,28 @@ void qemu_set_vnet_hdr_len(NetClientState *nc, int len)
|
||||
|
||||
int qemu_set_vnet_le(NetClientState *nc, bool is_le)
|
||||
{
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
if (!nc || !nc->info->set_vnet_le) {
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
return nc->info->set_vnet_le(nc, is_le);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int qemu_set_vnet_be(NetClientState *nc, bool is_be)
|
||||
{
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
return 0;
|
||||
#else
|
||||
if (!nc || !nc->info->set_vnet_be) {
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
return nc->info->set_vnet_be(nc, is_be);
|
||||
#endif
|
||||
}
|
||||
|
||||
int qemu_can_send_packet(NetClientState *sender)
|
||||
|
||||
Binary file not shown.
+6
-3
@@ -237,9 +237,12 @@ int qdev_device_help(QemuOpts *opts)
|
||||
return 0;
|
||||
}
|
||||
|
||||
qdev_get_device_class(&driver, &local_err);
|
||||
if (local_err) {
|
||||
goto error;
|
||||
if (!object_class_by_name(driver)) {
|
||||
const char *typename = find_typename_by_alias(driver);
|
||||
|
||||
if (typename) {
|
||||
driver = typename;
|
||||
}
|
||||
}
|
||||
|
||||
prop_list = qmp_device_list_properties(driver, &local_err);
|
||||
|
||||
+2
-1
@@ -2931,7 +2931,7 @@ static int img_amend(int argc, char **argv)
|
||||
if (!is_valid_option_list(optarg)) {
|
||||
error_report("Invalid option list: %s", optarg);
|
||||
ret = -1;
|
||||
goto out;
|
||||
goto out_no_progress;
|
||||
}
|
||||
if (!options) {
|
||||
options = g_strdup(optarg);
|
||||
@@ -3031,6 +3031,7 @@ static int img_amend(int argc, char **argv)
|
||||
out:
|
||||
qemu_progress_end();
|
||||
|
||||
out_no_progress:
|
||||
blk_unref(blk);
|
||||
qemu_opts_del(opts);
|
||||
qemu_opts_free(create_opts);
|
||||
|
||||
@@ -514,6 +514,17 @@ DevicePropertyInfoList *qmp_device_list_properties(const char *typename,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (object_class_is_abstract(klass)) {
|
||||
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "name",
|
||||
"non-abstract device type");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (DEVICE_CLASS(klass)->cannot_destroy_with_object_finalize_yet) {
|
||||
error_setg(errp, "Can't list properties of device '%s'", typename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
obj = object_new(typename);
|
||||
|
||||
QTAILQ_FOREACH(prop, &obj->properties, node) {
|
||||
|
||||
+43
-10
@@ -1079,6 +1079,7 @@ typedef struct EnumProperty {
|
||||
int object_property_get_enum(Object *obj, const char *name,
|
||||
const char *typename, Error **errp)
|
||||
{
|
||||
Error *err = NULL;
|
||||
StringOutputVisitor *sov;
|
||||
StringInputVisitor *siv;
|
||||
char *str;
|
||||
@@ -1100,7 +1101,12 @@ int object_property_get_enum(Object *obj, const char *name,
|
||||
enumprop = prop->opaque;
|
||||
|
||||
sov = string_output_visitor_new(false);
|
||||
object_property_get(obj, string_output_get_visitor(sov), name, errp);
|
||||
object_property_get(obj, string_output_get_visitor(sov), name, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
string_output_visitor_cleanup(sov);
|
||||
return 0;
|
||||
}
|
||||
str = string_output_get_string(sov);
|
||||
siv = string_input_visitor_new(str);
|
||||
string_output_visitor_cleanup(sov);
|
||||
@@ -1116,21 +1122,27 @@ int object_property_get_enum(Object *obj, const char *name,
|
||||
void object_property_get_uint16List(Object *obj, const char *name,
|
||||
uint16List **list, Error **errp)
|
||||
{
|
||||
Error *err = NULL;
|
||||
StringOutputVisitor *ov;
|
||||
StringInputVisitor *iv;
|
||||
char *str;
|
||||
|
||||
ov = string_output_visitor_new(false);
|
||||
object_property_get(obj, string_output_get_visitor(ov),
|
||||
name, errp);
|
||||
name, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
goto out;
|
||||
}
|
||||
str = string_output_get_string(ov);
|
||||
iv = string_input_visitor_new(str);
|
||||
visit_type_uint16List(string_input_get_visitor(iv),
|
||||
list, NULL, errp);
|
||||
|
||||
g_free(str);
|
||||
string_output_visitor_cleanup(ov);
|
||||
string_input_visitor_cleanup(iv);
|
||||
out:
|
||||
string_output_visitor_cleanup(ov);
|
||||
}
|
||||
|
||||
void object_property_parse(Object *obj, const char *string,
|
||||
@@ -1581,12 +1593,16 @@ static void property_get_str(Object *obj, Visitor *v, void *opaque,
|
||||
{
|
||||
StringProperty *prop = opaque;
|
||||
char *value;
|
||||
Error *err = NULL;
|
||||
|
||||
value = prop->get(obj, errp);
|
||||
if (value) {
|
||||
visit_type_str(v, &value, name, errp);
|
||||
g_free(value);
|
||||
value = prop->get(obj, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
visit_type_str(v, &value, name, errp);
|
||||
g_free(value);
|
||||
}
|
||||
|
||||
static void property_set_str(Object *obj, Visitor *v, void *opaque,
|
||||
@@ -1646,8 +1662,14 @@ static void property_get_bool(Object *obj, Visitor *v, void *opaque,
|
||||
{
|
||||
BoolProperty *prop = opaque;
|
||||
bool value;
|
||||
Error *err = NULL;
|
||||
|
||||
value = prop->get(obj, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
value = prop->get(obj, errp);
|
||||
visit_type_bool(v, &value, name, errp);
|
||||
}
|
||||
|
||||
@@ -1701,8 +1723,14 @@ static void property_get_enum(Object *obj, Visitor *v, void *opaque,
|
||||
{
|
||||
EnumProperty *prop = opaque;
|
||||
int value;
|
||||
Error *err = NULL;
|
||||
|
||||
value = prop->get(obj, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
value = prop->get(obj, errp);
|
||||
visit_type_enum(v, &value, prop->strings, NULL, name, errp);
|
||||
}
|
||||
|
||||
@@ -1711,8 +1739,13 @@ static void property_set_enum(Object *obj, Visitor *v, void *opaque,
|
||||
{
|
||||
EnumProperty *prop = opaque;
|
||||
int value;
|
||||
Error *err = NULL;
|
||||
|
||||
visit_type_enum(v, &value, prop->strings, NULL, name, errp);
|
||||
visit_type_enum(v, &value, prop->strings, NULL, name, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
prop->set(obj, value, errp);
|
||||
}
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ shape and this command should mostly work."""
|
||||
def qemu_get_ram_block(self, ram_addr):
|
||||
ram_blocks = gdb.parse_and_eval("ram_list.blocks")
|
||||
for block in self.qlist_foreach(ram_blocks, "next"):
|
||||
if (ram_addr - block["offset"] < block["length"]):
|
||||
if (ram_addr - block["offset"] < block["used_length"]):
|
||||
return block
|
||||
raise gdb.GdbError("Bad ram offset %x" % ram_addr)
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ cp_virtio() {
|
||||
-e 's/__attribute__((packed))/QEMU_PACKED/' \
|
||||
-e 's/__inline__/inline/' \
|
||||
-e '/sys\/ioctl.h/d' \
|
||||
-e 's/SW_MAX/SW_MAX_/' \
|
||||
"$f" > "$to/$header";
|
||||
done
|
||||
fi
|
||||
|
||||
+7
-1
@@ -584,7 +584,13 @@ findso:
|
||||
goto cont_input;
|
||||
}
|
||||
|
||||
if((tcp_fconnect(so) == -1) && (errno != EINPROGRESS) && (errno != EWOULDBLOCK)) {
|
||||
if ((tcp_fconnect(so) == -1) &&
|
||||
#if defined(_WIN32)
|
||||
socket_error() != WSAEWOULDBLOCK
|
||||
#else
|
||||
(errno != EINPROGRESS) && (errno != EWOULDBLOCK)
|
||||
#endif
|
||||
) {
|
||||
u_char code=ICMP_UNREACH_NET;
|
||||
DEBUG_MISC((dfd, " tcp fconnect errno = %d-%s\n",
|
||||
errno,strerror(errno)));
|
||||
|
||||
@@ -298,6 +298,13 @@ static void alpha_cpu_class_init(ObjectClass *oc, void *data)
|
||||
dc->vmsd = &vmstate_alpha_cpu;
|
||||
#endif
|
||||
cc->gdb_num_core_regs = 67;
|
||||
|
||||
/*
|
||||
* Reason: alpha_cpu_initfn() calls cpu_exec_init(), which saves
|
||||
* the object in cpus -> dangling pointer after final
|
||||
* object_unref().
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static const TypeInfo alpha_cpu_type_info = {
|
||||
|
||||
@@ -260,7 +260,7 @@ uint32_t do_arm_semihosting(CPUARMState *env)
|
||||
return (uint32_t)-1;
|
||||
len = strlen(s);
|
||||
if (use_gdb_syscalls()) {
|
||||
gdb_do_syscall(arm_semi_cb, "write,2,%x,%x\n", args, len);
|
||||
gdb_do_syscall(arm_semi_cb, "write,2,%x,%x", args, len);
|
||||
ret = env->regs[0];
|
||||
} else {
|
||||
ret = write(STDERR_FILENO, s, len);
|
||||
|
||||
@@ -1403,6 +1403,17 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
|
||||
cc->debug_excp_handler = arm_debug_excp_handler;
|
||||
|
||||
cc->disas_set_info = arm_disas_set_info;
|
||||
|
||||
/*
|
||||
* Reason: arm_cpu_initfn() calls cpu_exec_init(), which saves
|
||||
* the object in cpus -> dangling pointer after final
|
||||
* object_unref().
|
||||
*
|
||||
* Once this is fixed, the devices that create ARM CPUs should be
|
||||
* updated not to set cannot_destroy_with_object_finalize_yet,
|
||||
* unless they still screw up something else.
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static void cpu_register(const ARMCPUInfo *info)
|
||||
|
||||
@@ -39,16 +39,9 @@
|
||||
|
||||
static TCGv_i64 cpu_X[32];
|
||||
static TCGv_i64 cpu_pc;
|
||||
static TCGv_i32 cpu_NF, cpu_ZF, cpu_CF, cpu_VF;
|
||||
|
||||
/* Load/store exclusive handling */
|
||||
static TCGv_i64 cpu_exclusive_addr;
|
||||
static TCGv_i64 cpu_exclusive_val;
|
||||
static TCGv_i64 cpu_exclusive_high;
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
static TCGv_i64 cpu_exclusive_test;
|
||||
static TCGv_i32 cpu_exclusive_info;
|
||||
#endif
|
||||
|
||||
static const char *regnames[] = {
|
||||
"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
|
||||
@@ -104,23 +97,8 @@ void a64_translate_init(void)
|
||||
regnames[i]);
|
||||
}
|
||||
|
||||
cpu_NF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, NF), "NF");
|
||||
cpu_ZF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, ZF), "ZF");
|
||||
cpu_CF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, CF), "CF");
|
||||
cpu_VF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, VF), "VF");
|
||||
|
||||
cpu_exclusive_addr = tcg_global_mem_new_i64(TCG_AREG0,
|
||||
offsetof(CPUARMState, exclusive_addr), "exclusive_addr");
|
||||
cpu_exclusive_val = tcg_global_mem_new_i64(TCG_AREG0,
|
||||
offsetof(CPUARMState, exclusive_val), "exclusive_val");
|
||||
cpu_exclusive_high = tcg_global_mem_new_i64(TCG_AREG0,
|
||||
offsetof(CPUARMState, exclusive_high), "exclusive_high");
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
cpu_exclusive_test = tcg_global_mem_new_i64(TCG_AREG0,
|
||||
offsetof(CPUARMState, exclusive_test), "exclusive_test");
|
||||
cpu_exclusive_info = tcg_global_mem_new_i32(TCG_AREG0,
|
||||
offsetof(CPUARMState, exclusive_info), "exclusive_info");
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline ARMMMUIdx get_a64_user_mem_index(DisasContext *s)
|
||||
|
||||
@@ -64,12 +64,12 @@ TCGv_ptr cpu_env;
|
||||
/* We reuse the same 64-bit temporaries for efficiency. */
|
||||
static TCGv_i64 cpu_V0, cpu_V1, cpu_M0;
|
||||
static TCGv_i32 cpu_R[16];
|
||||
static TCGv_i32 cpu_CF, cpu_NF, cpu_VF, cpu_ZF;
|
||||
static TCGv_i64 cpu_exclusive_addr;
|
||||
static TCGv_i64 cpu_exclusive_val;
|
||||
TCGv_i32 cpu_CF, cpu_NF, cpu_VF, cpu_ZF;
|
||||
TCGv_i64 cpu_exclusive_addr;
|
||||
TCGv_i64 cpu_exclusive_val;
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
static TCGv_i64 cpu_exclusive_test;
|
||||
static TCGv_i32 cpu_exclusive_info;
|
||||
TCGv_i64 cpu_exclusive_test;
|
||||
TCGv_i32 cpu_exclusive_info;
|
||||
#endif
|
||||
|
||||
/* FIXME: These should be removed. */
|
||||
|
||||
@@ -62,7 +62,15 @@ typedef struct DisasContext {
|
||||
TCGv_i64 tmp_a64[TMP_A64_MAX];
|
||||
} DisasContext;
|
||||
|
||||
/* Share the TCG temporaries common between 32 and 64 bit modes. */
|
||||
extern TCGv_ptr cpu_env;
|
||||
extern TCGv_i32 cpu_NF, cpu_ZF, cpu_CF, cpu_VF;
|
||||
extern TCGv_i64 cpu_exclusive_addr;
|
||||
extern TCGv_i64 cpu_exclusive_val;
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
extern TCGv_i64 cpu_exclusive_test;
|
||||
extern TCGv_i32 cpu_exclusive_info;
|
||||
#endif
|
||||
|
||||
static inline int arm_dc_feature(DisasContext *dc, int feature)
|
||||
{
|
||||
|
||||
@@ -308,6 +308,13 @@ static void cris_cpu_class_init(ObjectClass *oc, void *data)
|
||||
cc->gdb_stop_before_watchpoint = true;
|
||||
|
||||
cc->disas_set_info = cris_disas_set_info;
|
||||
|
||||
/*
|
||||
* Reason: cris_cpu_initfn() calls cpu_exec_init(), which saves
|
||||
* the object in cpus -> dangling pointer after final
|
||||
* object_unref().
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static const TypeInfo cris_cpu_type_info = {
|
||||
|
||||
@@ -1475,6 +1475,8 @@ static void host_x86_cpu_class_init(ObjectClass *oc, void *data)
|
||||
*/
|
||||
|
||||
dc->props = host_x86_cpu_properties;
|
||||
/* Reason: host_x86_cpu_initfn() dies when !kvm_enabled() */
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static void host_x86_cpu_initfn(Object *obj)
|
||||
@@ -3200,6 +3202,12 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
|
||||
#endif
|
||||
cc->cpu_exec_enter = x86_cpu_exec_enter;
|
||||
cc->cpu_exec_exit = x86_cpu_exec_exit;
|
||||
|
||||
/*
|
||||
* Reason: x86_cpu_initfn() calls cpu_exec_init(), which saves the
|
||||
* object in cpus -> dangling pointer after final object_unref().
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static const TypeInfo x86_cpu_type_info = {
|
||||
|
||||
@@ -275,6 +275,13 @@ static void lm32_cpu_class_init(ObjectClass *oc, void *data)
|
||||
cc->gdb_num_core_regs = 32 + 7;
|
||||
cc->gdb_stop_before_watchpoint = true;
|
||||
cc->debug_excp_handler = lm32_debug_excp_handler;
|
||||
|
||||
/*
|
||||
* Reason: lm32_cpu_initfn() calls cpu_exec_init(), which saves
|
||||
* the object in cpus -> dangling pointer after final
|
||||
* object_unref().
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static void lm32_register_cpu_type(const LM32CPUInfo *info)
|
||||
|
||||
@@ -212,6 +212,13 @@ static void m68k_cpu_class_init(ObjectClass *c, void *data)
|
||||
dc->vmsd = &vmstate_m68k_cpu;
|
||||
cc->gdb_num_core_regs = 18;
|
||||
cc->gdb_core_xml_file = "cf-core.xml";
|
||||
|
||||
/*
|
||||
* Reason: m68k_cpu_initfn() calls cpu_exec_init(), which saves
|
||||
* the object in cpus -> dangling pointer after final
|
||||
* object_unref().
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static void register_cpu_type(const M68kCPUInfo *info)
|
||||
|
||||
@@ -264,6 +264,12 @@ static void mb_cpu_class_init(ObjectClass *oc, void *data)
|
||||
cc->gdb_num_core_regs = 32 + 5;
|
||||
|
||||
cc->disas_set_info = mb_disas_set_info;
|
||||
|
||||
/*
|
||||
* Reason: mb_cpu_initfn() calls cpu_exec_init(), which saves the
|
||||
* object in cpus -> dangling pointer after final object_unref().
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static const TypeInfo mb_cpu_type_info = {
|
||||
|
||||
@@ -153,6 +153,13 @@ static void mips_cpu_class_init(ObjectClass *c, void *data)
|
||||
|
||||
cc->gdb_num_core_regs = 73;
|
||||
cc->gdb_stop_before_watchpoint = true;
|
||||
|
||||
/*
|
||||
* Reason: mips_cpu_initfn() calls cpu_exec_init(), which saves
|
||||
* the object in cpus -> dangling pointer after final
|
||||
* object_unref().
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static const TypeInfo mips_cpu_type_info = {
|
||||
|
||||
+32
-23
@@ -4750,48 +4750,53 @@ static void gen_bitops (DisasContext *ctx, uint32_t opc, int rt,
|
||||
gen_load_gpr(t1, rs);
|
||||
switch (opc) {
|
||||
case OPC_EXT:
|
||||
if (lsb + msb > 31)
|
||||
if (lsb + msb > 31) {
|
||||
goto fail;
|
||||
}
|
||||
tcg_gen_shri_tl(t0, t1, lsb);
|
||||
if (msb != 31) {
|
||||
tcg_gen_andi_tl(t0, t0, (1 << (msb + 1)) - 1);
|
||||
tcg_gen_andi_tl(t0, t0, (1U << (msb + 1)) - 1);
|
||||
} else {
|
||||
tcg_gen_ext32s_tl(t0, t0);
|
||||
}
|
||||
break;
|
||||
#if defined(TARGET_MIPS64)
|
||||
case OPC_DEXTM:
|
||||
tcg_gen_shri_tl(t0, t1, lsb);
|
||||
if (msb != 31) {
|
||||
tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1 + 32)) - 1);
|
||||
}
|
||||
break;
|
||||
case OPC_DEXTU:
|
||||
tcg_gen_shri_tl(t0, t1, lsb + 32);
|
||||
tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1)) - 1);
|
||||
break;
|
||||
lsb += 32;
|
||||
goto do_dext;
|
||||
case OPC_DEXTM:
|
||||
msb += 32;
|
||||
goto do_dext;
|
||||
case OPC_DEXT:
|
||||
do_dext:
|
||||
if (lsb + msb > 63) {
|
||||
goto fail;
|
||||
}
|
||||
tcg_gen_shri_tl(t0, t1, lsb);
|
||||
tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1)) - 1);
|
||||
if (msb != 63) {
|
||||
tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1)) - 1);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case OPC_INS:
|
||||
if (lsb > msb)
|
||||
if (lsb > msb) {
|
||||
goto fail;
|
||||
}
|
||||
gen_load_gpr(t0, rt);
|
||||
tcg_gen_deposit_tl(t0, t0, t1, lsb, msb - lsb + 1);
|
||||
tcg_gen_ext32s_tl(t0, t0);
|
||||
break;
|
||||
#if defined(TARGET_MIPS64)
|
||||
case OPC_DINSM:
|
||||
gen_load_gpr(t0, rt);
|
||||
tcg_gen_deposit_tl(t0, t0, t1, lsb, msb + 32 - lsb + 1);
|
||||
break;
|
||||
case OPC_DINSU:
|
||||
gen_load_gpr(t0, rt);
|
||||
tcg_gen_deposit_tl(t0, t0, t1, lsb + 32, msb - lsb + 1);
|
||||
break;
|
||||
lsb += 32;
|
||||
/* FALLTHRU */
|
||||
case OPC_DINSM:
|
||||
msb += 32;
|
||||
/* FALLTHRU */
|
||||
case OPC_DINS:
|
||||
if (lsb > msb) {
|
||||
goto fail;
|
||||
}
|
||||
gen_load_gpr(t0, rt);
|
||||
tcg_gen_deposit_tl(t0, t0, t1, lsb, msb - lsb + 1);
|
||||
break;
|
||||
@@ -13278,10 +13283,14 @@ static void gen_pool16c_r6_insn(DisasContext *ctx)
|
||||
break;
|
||||
case R6_SDBBP16:
|
||||
/* SDBBP16 */
|
||||
if (ctx->hflags & MIPS_HFLAG_SBRI) {
|
||||
generate_exception(ctx, EXCP_RI);
|
||||
if (is_uhi(extract32(ctx->opcode, 6, 4))) {
|
||||
gen_helper_do_semihosting(cpu_env);
|
||||
} else {
|
||||
generate_exception(ctx, EXCP_DBp);
|
||||
if (ctx->hflags & MIPS_HFLAG_SBRI) {
|
||||
generate_exception(ctx, EXCP_RI);
|
||||
} else {
|
||||
generate_exception(ctx, EXCP_DBp);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -114,6 +114,13 @@ static void moxie_cpu_class_init(ObjectClass *oc, void *data)
|
||||
cc->get_phys_page_debug = moxie_cpu_get_phys_page_debug;
|
||||
cc->vmsd = &vmstate_moxie_cpu;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Reason: moxie_cpu_initfn() calls cpu_exec_init(), which saves
|
||||
* the object in cpus -> dangling pointer after final
|
||||
* object_unref().
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static void moxielite_initfn(Object *obj)
|
||||
|
||||
@@ -177,6 +177,13 @@ static void openrisc_cpu_class_init(ObjectClass *oc, void *data)
|
||||
dc->vmsd = &vmstate_openrisc_cpu;
|
||||
#endif
|
||||
cc->gdb_num_core_regs = 32 + 3;
|
||||
|
||||
/*
|
||||
* Reason: openrisc_cpu_initfn() calls cpu_exec_init(), which saves
|
||||
* the object in cpus -> dangling pointer after final
|
||||
* object_unref().
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static void cpu_register(const OpenRISCCPUInfo *info)
|
||||
|
||||
+14
-5
@@ -2327,24 +2327,28 @@ void helper_vsbox(ppc_avr_t *r, ppc_avr_t *a)
|
||||
|
||||
void helper_vcipher(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
|
||||
{
|
||||
ppc_avr_t result;
|
||||
int i;
|
||||
|
||||
VECTOR_FOR_INORDER_I(i, u32) {
|
||||
r->AVRW(i) = b->AVRW(i) ^
|
||||
result.AVRW(i) = b->AVRW(i) ^
|
||||
(AES_Te0[a->AVRB(AES_shifts[4*i + 0])] ^
|
||||
AES_Te1[a->AVRB(AES_shifts[4*i + 1])] ^
|
||||
AES_Te2[a->AVRB(AES_shifts[4*i + 2])] ^
|
||||
AES_Te3[a->AVRB(AES_shifts[4*i + 3])]);
|
||||
}
|
||||
*r = result;
|
||||
}
|
||||
|
||||
void helper_vcipherlast(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
|
||||
{
|
||||
ppc_avr_t result;
|
||||
int i;
|
||||
|
||||
VECTOR_FOR_INORDER_I(i, u8) {
|
||||
r->AVRB(i) = b->AVRB(i) ^ (AES_sbox[a->AVRB(AES_shifts[i])]);
|
||||
result.AVRB(i) = b->AVRB(i) ^ (AES_sbox[a->AVRB(AES_shifts[i])]);
|
||||
}
|
||||
*r = result;
|
||||
}
|
||||
|
||||
void helper_vncipher(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
|
||||
@@ -2369,11 +2373,13 @@ void helper_vncipher(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
|
||||
|
||||
void helper_vncipherlast(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
|
||||
{
|
||||
ppc_avr_t result;
|
||||
int i;
|
||||
|
||||
VECTOR_FOR_INORDER_I(i, u8) {
|
||||
r->AVRB(i) = b->AVRB(i) ^ (AES_isbox[a->AVRB(AES_ishifts[i])]);
|
||||
result.AVRB(i) = b->AVRB(i) ^ (AES_isbox[a->AVRB(AES_ishifts[i])]);
|
||||
}
|
||||
*r = result;
|
||||
}
|
||||
|
||||
#define ROTRu32(v, n) (((v) >> (n)) | ((v) << (32-n)))
|
||||
@@ -2460,16 +2466,19 @@ void helper_vshasigmad(ppc_avr_t *r, ppc_avr_t *a, uint32_t st_six)
|
||||
|
||||
void helper_vpermxor(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
|
||||
{
|
||||
ppc_avr_t result;
|
||||
int i;
|
||||
|
||||
VECTOR_FOR_INORDER_I(i, u8) {
|
||||
int indexA = c->u8[i] >> 4;
|
||||
int indexB = c->u8[i] & 0xF;
|
||||
#if defined(HOST_WORDS_BIGENDIAN)
|
||||
r->u8[i] = a->u8[indexA] ^ b->u8[indexB];
|
||||
result.u8[i] = a->u8[indexA] ^ b->u8[indexB];
|
||||
#else
|
||||
r->u8[i] = a->u8[15-indexA] ^ b->u8[15-indexB];
|
||||
result.u8[i] = a->u8[15-indexA] ^ b->u8[15-indexB];
|
||||
#endif
|
||||
}
|
||||
*r = result;
|
||||
}
|
||||
|
||||
#undef VECTOR_FOR_INORDER_I
|
||||
|
||||
@@ -2188,6 +2188,7 @@ static void kvmppc_host_cpu_initfn(Object *obj)
|
||||
|
||||
static void kvmppc_host_cpu_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
|
||||
uint32_t vmx = kvmppc_get_vmx();
|
||||
uint32_t dfp = kvmppc_get_dfp();
|
||||
@@ -2214,6 +2215,9 @@ static void kvmppc_host_cpu_class_init(ObjectClass *oc, void *data)
|
||||
if (icache_size != -1) {
|
||||
pcc->l1_icache_size = icache_size;
|
||||
}
|
||||
|
||||
/* Reason: kvmppc_host_cpu_initfn() dies when !kvm_enabled() */
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
bool kvmppc_has_cap_epr(void)
|
||||
|
||||
@@ -10670,6 +10670,13 @@ GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 1, opc3, 0, PPC_NONE, fl2), \
|
||||
GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 2, opc3, 0, PPC_NONE, fl2), \
|
||||
GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 3, opc3, 0, PPC_NONE, fl2)
|
||||
|
||||
#undef GEN_XX2IFORM
|
||||
#define GEN_XX2IFORM(name, opc2, opc3, fl2) \
|
||||
GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0, opc3, 1, PPC_NONE, fl2), \
|
||||
GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 1, opc3, 1, PPC_NONE, fl2), \
|
||||
GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 2, opc3, 1, PPC_NONE, fl2), \
|
||||
GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 3, opc3, 1, PPC_NONE, fl2)
|
||||
|
||||
#undef GEN_XX3_RC_FORM
|
||||
#define GEN_XX3_RC_FORM(name, opc2, opc3, fl2) \
|
||||
GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x00, opc3 | 0x00, 0, PPC_NONE, fl2), \
|
||||
@@ -10731,8 +10738,8 @@ GEN_XX3FORM(xsnmaddadp, 0x04, 0x14, PPC2_VSX),
|
||||
GEN_XX3FORM(xsnmaddmdp, 0x04, 0x15, PPC2_VSX),
|
||||
GEN_XX3FORM(xsnmsubadp, 0x04, 0x16, PPC2_VSX),
|
||||
GEN_XX3FORM(xsnmsubmdp, 0x04, 0x17, PPC2_VSX),
|
||||
GEN_XX2FORM(xscmpodp, 0x0C, 0x05, PPC2_VSX),
|
||||
GEN_XX2FORM(xscmpudp, 0x0C, 0x04, PPC2_VSX),
|
||||
GEN_XX2IFORM(xscmpodp, 0x0C, 0x05, PPC2_VSX),
|
||||
GEN_XX2IFORM(xscmpudp, 0x0C, 0x04, PPC2_VSX),
|
||||
GEN_XX3FORM(xsmaxdp, 0x00, 0x14, PPC2_VSX),
|
||||
GEN_XX3FORM(xsmindp, 0x00, 0x15, PPC2_VSX),
|
||||
GEN_XX2FORM(xscvdpsp, 0x12, 0x10, PPC2_VSX),
|
||||
|
||||
@@ -353,6 +353,13 @@ static void s390_cpu_class_init(ObjectClass *oc, void *data)
|
||||
#endif
|
||||
cc->gdb_num_core_regs = S390_NUM_CORE_REGS;
|
||||
cc->gdb_core_xml_file = "s390x-core64.xml";
|
||||
|
||||
/*
|
||||
* Reason: s390_cpu_initfn() calls cpu_exec_init(), which saves
|
||||
* the object in cpus -> dangling pointer after final
|
||||
* object_unref().
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static const TypeInfo s390_cpu_type_info = {
|
||||
|
||||
@@ -2079,6 +2079,9 @@ void kvm_s390_crw_mchk(void)
|
||||
.u.mchk.cr14 = 1 << 28,
|
||||
.u.mchk.mcic = 0x00400f1d40330000ULL,
|
||||
};
|
||||
if (kvm_check_extension(kvm_state, KVM_CAP_S390_VECTOR_REGISTERS)) {
|
||||
irq.u.mchk.mcic |= 0x0000004000000000ULL;
|
||||
}
|
||||
kvm_s390_floating_interrupt(&irq);
|
||||
}
|
||||
|
||||
|
||||
@@ -290,6 +290,13 @@ static void superh_cpu_class_init(ObjectClass *oc, void *data)
|
||||
#endif
|
||||
dc->vmsd = &vmstate_sh_cpu;
|
||||
cc->gdb_num_core_regs = 59;
|
||||
|
||||
/*
|
||||
* Reason: superh_cpu_initfn() calls cpu_exec_init(), which saves
|
||||
* the object in cpus -> dangling pointer after final
|
||||
* object_unref().
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static const TypeInfo superh_cpu_type_info = {
|
||||
|
||||
@@ -854,6 +854,13 @@ static void sparc_cpu_class_init(ObjectClass *oc, void *data)
|
||||
#else
|
||||
cc->gdb_num_core_regs = 72;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Reason: sparc_cpu_initfn() calls cpu_exec_init(), which saves
|
||||
* the object in cpus -> dangling pointer after final
|
||||
* object_unref().
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static const TypeInfo sparc_cpu_type_info = {
|
||||
|
||||
@@ -170,6 +170,12 @@ static void tricore_cpu_class_init(ObjectClass *c, void *data)
|
||||
cc->set_pc = tricore_cpu_set_pc;
|
||||
cc->synchronize_from_tb = tricore_cpu_synchronize_from_tb;
|
||||
|
||||
/*
|
||||
* Reason: tricore_cpu_initfn() calls cpu_exec_init(), which saves
|
||||
* the object in cpus -> dangling pointer after final
|
||||
* object_unref().
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static void cpu_register(const TriCoreCPUInfo *info)
|
||||
|
||||
@@ -155,6 +155,13 @@ static void uc32_cpu_class_init(ObjectClass *oc, void *data)
|
||||
cc->get_phys_page_debug = uc32_cpu_get_phys_page_debug;
|
||||
#endif
|
||||
dc->vmsd = &vmstate_uc32_cpu;
|
||||
|
||||
/*
|
||||
* Reason: uc32_cpu_initfn() calls cpu_exec_init(), which saves
|
||||
* the object in cpus -> dangling pointer after final
|
||||
* object_unref().
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static void uc32_register_cpu_type(const UniCore32CPUInfo *info)
|
||||
|
||||
@@ -155,6 +155,13 @@ static void xtensa_cpu_class_init(ObjectClass *oc, void *data)
|
||||
#endif
|
||||
cc->debug_excp_handler = xtensa_breakpoint_handler;
|
||||
dc->vmsd = &vmstate_xtensa_cpu;
|
||||
|
||||
/*
|
||||
* Reason: xtensa_cpu_initfn() calls cpu_exec_init(), which saves
|
||||
* the object in cpus -> dangling pointer after final
|
||||
* object_unref().
|
||||
*/
|
||||
dc->cannot_destroy_with_object_finalize_yet = true;
|
||||
}
|
||||
|
||||
static const TypeInfo xtensa_cpu_type_info = {
|
||||
|
||||
@@ -1943,7 +1943,8 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
|
||||
switch (OP2) {
|
||||
case 0: /*L32E*/
|
||||
HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
|
||||
if (gen_check_privilege(dc)) {
|
||||
if (gen_check_privilege(dc) &&
|
||||
gen_window_check2(dc, RRR_S, RRR_T)) {
|
||||
TCGv_i32 addr = tcg_temp_new_i32();
|
||||
tcg_gen_addi_i32(addr, cpu_R[RRR_S],
|
||||
(0xffffffc0 | (RRR_R << 2)));
|
||||
@@ -1954,7 +1955,8 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc)
|
||||
|
||||
case 4: /*S32E*/
|
||||
HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
|
||||
if (gen_check_privilege(dc)) {
|
||||
if (gen_check_privilege(dc) &&
|
||||
gen_window_check2(dc, RRR_S, RRR_T)) {
|
||||
TCGv_i32 addr = tcg_temp_new_i32();
|
||||
tcg_gen_addi_i32(addr, cpu_R[RRR_S],
|
||||
(0xffffffc0 | (RRR_R << 2)));
|
||||
|
||||
@@ -56,6 +56,12 @@ static const int tcg_target_call_oarg_regs[1] = {
|
||||
#define TCG_REG_TMP TCG_REG_X30
|
||||
|
||||
#ifndef CONFIG_SOFTMMU
|
||||
/* Note that XZR cannot be encoded in the address base register slot,
|
||||
as that actaully encodes SP. So if we need to zero-extend the guest
|
||||
address, via the address index register slot, we need to load even
|
||||
a zero guest base into a register. */
|
||||
#define USE_GUEST_BASE (GUEST_BASE != 0 || TARGET_LONG_BITS == 32)
|
||||
|
||||
# ifdef CONFIG_USE_GUEST_BASE
|
||||
# define TCG_REG_GUEST_BASE TCG_REG_X28
|
||||
# else
|
||||
@@ -1216,9 +1222,13 @@ static void tcg_out_qemu_ld(TCGContext *s, TCGReg data_reg, TCGReg addr_reg,
|
||||
add_qemu_ldst_label(s, true, oi, ext, data_reg, addr_reg,
|
||||
s->code_ptr, label_ptr);
|
||||
#else /* !CONFIG_SOFTMMU */
|
||||
tcg_out_qemu_ld_direct(s, memop, ext, data_reg,
|
||||
GUEST_BASE ? TCG_REG_GUEST_BASE : TCG_REG_XZR,
|
||||
otype, addr_reg);
|
||||
if (USE_GUEST_BASE) {
|
||||
tcg_out_qemu_ld_direct(s, memop, ext, data_reg,
|
||||
TCG_REG_GUEST_BASE, otype, addr_reg);
|
||||
} else {
|
||||
tcg_out_qemu_ld_direct(s, memop, ext, data_reg,
|
||||
addr_reg, TCG_TYPE_I64, TCG_REG_XZR);
|
||||
}
|
||||
#endif /* CONFIG_SOFTMMU */
|
||||
}
|
||||
|
||||
@@ -1238,9 +1248,13 @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg data_reg, TCGReg addr_reg,
|
||||
add_qemu_ldst_label(s, false, oi, s_bits == MO_64, data_reg, addr_reg,
|
||||
s->code_ptr, label_ptr);
|
||||
#else /* !CONFIG_SOFTMMU */
|
||||
tcg_out_qemu_st_direct(s, memop, data_reg,
|
||||
GUEST_BASE ? TCG_REG_GUEST_BASE : TCG_REG_XZR,
|
||||
otype, addr_reg);
|
||||
if (USE_GUEST_BASE) {
|
||||
tcg_out_qemu_st_direct(s, memop, data_reg,
|
||||
TCG_REG_GUEST_BASE, otype, addr_reg);
|
||||
} else {
|
||||
tcg_out_qemu_st_direct(s, memop, data_reg,
|
||||
addr_reg, TCG_TYPE_I64, TCG_REG_XZR);
|
||||
}
|
||||
#endif /* CONFIG_SOFTMMU */
|
||||
}
|
||||
|
||||
@@ -1795,7 +1809,7 @@ static void tcg_target_qemu_prologue(TCGContext *s)
|
||||
CPU_TEMP_BUF_NLONGS * sizeof(long));
|
||||
|
||||
#if defined(CONFIG_USE_GUEST_BASE)
|
||||
if (GUEST_BASE) {
|
||||
if (USE_GUEST_BASE) {
|
||||
tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_GUEST_BASE, GUEST_BASE);
|
||||
tcg_regset_set_reg(s->reserved_regs, TCG_REG_GUEST_BASE);
|
||||
}
|
||||
|
||||
+20
-11
@@ -962,28 +962,34 @@ static void tcg_out_tlb_load(TCGContext *s, TCGReg base, TCGReg addrl,
|
||||
add_off -= 0x7ff0;
|
||||
}
|
||||
|
||||
/* Load the tlb comparator. */
|
||||
tcg_out_opc_imm(s, OPC_LW, TCG_TMP0, TCG_REG_A0, cmp_off + LO_OFF);
|
||||
if (TARGET_LONG_BITS == 64) {
|
||||
tcg_out_opc_imm(s, OPC_LW, base, TCG_REG_A0, cmp_off + HI_OFF);
|
||||
}
|
||||
/* Load the (low half) tlb comparator. */
|
||||
tcg_out_opc_imm(s, OPC_LW, TCG_TMP0, TCG_REG_A0,
|
||||
cmp_off + (TARGET_LONG_BITS == 64 ? LO_OFF : 0));
|
||||
|
||||
/* Mask the page bits, keeping the alignment bits to compare against.
|
||||
In between, load the tlb addend for the fast path. */
|
||||
In between on 32-bit targets, load the tlb addend for the fast path. */
|
||||
tcg_out_movi(s, TCG_TYPE_I32, TCG_TMP1,
|
||||
TARGET_PAGE_MASK | ((1 << s_bits) - 1));
|
||||
tcg_out_opc_imm(s, OPC_LW, TCG_REG_A0, TCG_REG_A0, add_off);
|
||||
if (TARGET_LONG_BITS == 32) {
|
||||
tcg_out_opc_imm(s, OPC_LW, TCG_REG_A0, TCG_REG_A0, add_off);
|
||||
}
|
||||
tcg_out_opc_reg(s, OPC_AND, TCG_TMP1, TCG_TMP1, addrl);
|
||||
|
||||
label_ptr[0] = s->code_ptr;
|
||||
tcg_out_opc_br(s, OPC_BNE, TCG_TMP1, TCG_TMP0);
|
||||
|
||||
/* Load and test the high half tlb comparator. */
|
||||
if (TARGET_LONG_BITS == 64) {
|
||||
/* delay slot */
|
||||
tcg_out_nop(s);
|
||||
tcg_out_opc_imm(s, OPC_LW, TCG_TMP0, TCG_REG_A0, cmp_off + HI_OFF);
|
||||
|
||||
/* Load the tlb addend for the fast path. We can't do it earlier with
|
||||
64-bit targets or we'll clobber a0 before reading the high half tlb
|
||||
comparator. */
|
||||
tcg_out_opc_imm(s, OPC_LW, TCG_REG_A0, TCG_REG_A0, add_off);
|
||||
|
||||
label_ptr[1] = s->code_ptr;
|
||||
tcg_out_opc_br(s, OPC_BNE, addrh, base);
|
||||
tcg_out_opc_br(s, OPC_BNE, addrh, TCG_TMP0);
|
||||
}
|
||||
|
||||
/* delay slot */
|
||||
@@ -1103,7 +1109,7 @@ static void tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
|
||||
static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg datalo, TCGReg datahi,
|
||||
TCGReg base, TCGMemOp opc)
|
||||
{
|
||||
switch (opc) {
|
||||
switch (opc & (MO_SSIZE | MO_BSWAP)) {
|
||||
case MO_UB:
|
||||
tcg_out_opc_imm(s, OPC_LBU, datalo, base, 0);
|
||||
break;
|
||||
@@ -1193,7 +1199,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is_64)
|
||||
static void tcg_out_qemu_st_direct(TCGContext *s, TCGReg datalo, TCGReg datahi,
|
||||
TCGReg base, TCGMemOp opc)
|
||||
{
|
||||
switch (opc) {
|
||||
switch (opc & (MO_SIZE | MO_BSWAP)) {
|
||||
case MO_8:
|
||||
tcg_out_opc_imm(s, OPC_SB, datalo, base, 0);
|
||||
break;
|
||||
@@ -1269,6 +1275,9 @@ static void tcg_out_addsub2(TCGContext *s, TCGReg rl, TCGReg rh, TCGReg al,
|
||||
if (cbl) {
|
||||
tcg_out_opc_imm(s, OPC_ADDIU, rl, al, bl);
|
||||
tcg_out_opc_imm(s, OPC_SLTIU, TCG_TMP0, rl, bl);
|
||||
} else if (rl == al && rl == bl) {
|
||||
tcg_out_opc_sa(s, OPC_SRL, TCG_TMP0, al, 31);
|
||||
tcg_out_opc_reg(s, OPC_ADDU, rl, al, bl);
|
||||
} else {
|
||||
tcg_out_opc_reg(s, OPC_ADDU, rl, al, bl);
|
||||
tcg_out_opc_reg(s, OPC_SLTU, TCG_TMP0, rl, (rl == bl ? al : bl));
|
||||
|
||||
@@ -1390,7 +1390,7 @@ static void tcg_out_call(TCGContext *s, tcg_insn_unit *dest)
|
||||
static void tcg_out_qemu_ld_direct(TCGContext *s, TCGMemOp opc, TCGReg data,
|
||||
TCGReg base, TCGReg index, int disp)
|
||||
{
|
||||
switch (opc) {
|
||||
switch (opc & (MO_SSIZE | MO_BSWAP)) {
|
||||
case MO_UB:
|
||||
tcg_out_insn(s, RXY, LLGC, data, base, index, disp);
|
||||
break;
|
||||
@@ -1449,7 +1449,7 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, TCGMemOp opc, TCGReg data,
|
||||
static void tcg_out_qemu_st_direct(TCGContext *s, TCGMemOp opc, TCGReg data,
|
||||
TCGReg base, TCGReg index, int disp)
|
||||
{
|
||||
switch (opc) {
|
||||
switch (opc & (MO_SIZE | MO_BSWAP)) {
|
||||
case MO_UB:
|
||||
if (disp >= 0 && disp < 0x1000) {
|
||||
tcg_out_insn(s, RX, STC, data, base, index, disp);
|
||||
|
||||
+12
-8
@@ -82,6 +82,9 @@ check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
|
||||
# All QTests for now are POSIX-only, but the dependencies are
|
||||
# really in libqtest, not in the testcases themselves.
|
||||
|
||||
check-qtest-generic-y = tests/device-introspect-test$(EXESUF)
|
||||
gcov-files-generic-y = qdev-monitor.c qmp.c
|
||||
|
||||
gcov-files-ipack-y += hw/ipack/ipack.c
|
||||
check-qtest-ipack-y += tests/ipoctal232-test$(EXESUF)
|
||||
gcov-files-ipack-y += hw/char/ipoctal232.c
|
||||
@@ -211,10 +214,7 @@ gcov-files-ppc64-y += ppc64-softmmu/hw/ppc/spapr_pci.c
|
||||
check-qtest-microblazeel-y = $(check-qtest-microblaze-y)
|
||||
check-qtest-xtensaeb-y = $(check-qtest-xtensa-y)
|
||||
|
||||
# qom-test works for all sysemu architectures:
|
||||
$(foreach target,$(SYSEMU_TARGET_LIST), \
|
||||
$(if $(findstring tests/qom-test$(EXESUF), $(check-qtest-$(target)-y)),, \
|
||||
$(eval check-qtest-$(target)-y += tests/qom-test$(EXESUF))))
|
||||
check-qtest-generic-y += tests/qom-test$(EXESUF)
|
||||
|
||||
check-qapi-schema-y := $(addprefix tests/qapi-schema/, \
|
||||
comments.json empty.json enum-empty.json enum-missing-data.json \
|
||||
@@ -357,6 +357,7 @@ libqos-omap-obj-y = $(libqos-obj-y) tests/libqos/i2c-omap.o
|
||||
libqos-usb-obj-y = $(libqos-pc-obj-y) tests/libqos/usb.o
|
||||
libqos-virtio-obj-y = $(libqos-pc-obj-y) tests/libqos/virtio.o tests/libqos/virtio-pci.o tests/libqos/virtio-mmio.o tests/libqos/malloc-generic.o
|
||||
|
||||
tests/device-introspect-test$(EXESUF): tests/device-introspect-test.o
|
||||
tests/rtc-test$(EXESUF): tests/rtc-test.o
|
||||
tests/m48t59-test$(EXESUF): tests/m48t59-test.o
|
||||
tests/endianness-test$(EXESUF): tests/endianness-test.o
|
||||
@@ -418,8 +419,11 @@ endif
|
||||
|
||||
TARGETS=$(patsubst %-softmmu,%, $(filter %-softmmu,$(TARGET_DIRS)))
|
||||
ifeq ($(CONFIG_POSIX),y)
|
||||
QTEST_TARGETS=$(foreach TARGET,$(TARGETS), $(if $(check-qtest-$(TARGET)-y), $(TARGET),))
|
||||
QTEST_TARGETS = $(TARGETS)
|
||||
check-qtest-y=$(foreach TARGET,$(TARGETS), $(check-qtest-$(TARGET)-y))
|
||||
check-qtest-y += $(check-qtest-generic-y)
|
||||
else
|
||||
QTEST_TARGETS =
|
||||
endif
|
||||
|
||||
qtest-obj-y = tests/libqtest.o libqemuutil.a libqemustub.a
|
||||
@@ -457,8 +461,8 @@ $(patsubst %, check-qtest-%, $(QTEST_TARGETS)): check-qtest-%: $(check-qtest-y)
|
||||
$(call quiet-command,QTEST_QEMU_BINARY=$*-softmmu/qemu-system-$* \
|
||||
QTEST_QEMU_IMG=qemu-img$(EXESUF) \
|
||||
MALLOC_PERTURB_=$${MALLOC_PERTURB_:-$$((RANDOM % 255 + 1))} \
|
||||
gtester $(GTESTER_OPTIONS) -m=$(SPEED) $(check-qtest-$*-y),"GTESTER $@")
|
||||
$(if $(CONFIG_GCOV),@for f in $(gcov-files-$*-y); do \
|
||||
gtester $(GTESTER_OPTIONS) -m=$(SPEED) $(check-qtest-$*-y) $(check-qtest-generic-y),"GTESTER $@")
|
||||
$(if $(CONFIG_GCOV),@for f in $(gcov-files-$*-y) $(gcov-files-generic-y); do \
|
||||
echo Gcov report for $$f:;\
|
||||
$(GCOV) $(GCOV_OPTIONS) $$f -o `dirname $$f`; \
|
||||
done,)
|
||||
@@ -469,7 +473,7 @@ $(patsubst %, check-%, $(check-unit-y)): check-%: %
|
||||
$(call quiet-command, \
|
||||
MALLOC_PERTURB_=$${MALLOC_PERTURB_:-$$((RANDOM % 255 + 1))} \
|
||||
gtester $(GTESTER_OPTIONS) -m=$(SPEED) $*,"GTESTER $*")
|
||||
$(if $(CONFIG_GCOV),@for f in $(gcov-files-$(subst tests/,,$*)-y); do \
|
||||
$(if $(CONFIG_GCOV),@for f in $(gcov-files-$(subst tests/,,$*)-y) $(gcov-files-generic-y); do \
|
||||
echo Gcov report for $$f:;\
|
||||
$(GCOV) $(GCOV_OPTIONS) $$f -o `dirname $$f`; \
|
||||
done,)
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Device introspection test cases
|
||||
*
|
||||
* Copyright (c) 2015 Red Hat Inc.
|
||||
*
|
||||
* Authors:
|
||||
* Markus Armbruster <armbru@redhat.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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Covers QMP device-list-properties and HMP device_add help. We
|
||||
* currently don't check that their output makes sense, only that QEMU
|
||||
* survives. Useful since we've had an astounding number of crash
|
||||
* bugs around here.
|
||||
*/
|
||||
|
||||
#include <glib.h>
|
||||
#include <stdarg.h>
|
||||
#include "qemu-common.h"
|
||||
#include "qapi/qmp/qstring.h"
|
||||
#include "libqtest.h"
|
||||
|
||||
const char common_args[] = "-nodefaults -machine none";
|
||||
|
||||
static QList *device_type_list(bool abstract)
|
||||
{
|
||||
QDict *resp;
|
||||
QList *ret;
|
||||
|
||||
resp = qmp("{'execute': 'qom-list-types',"
|
||||
" 'arguments': {'implements': 'device', 'abstract': %i}}",
|
||||
abstract);
|
||||
g_assert(qdict_haskey(resp, "return"));
|
||||
ret = qdict_get_qlist(resp, "return");
|
||||
QINCREF(ret);
|
||||
QDECREF(resp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void test_one_device(const char *type)
|
||||
{
|
||||
QDict *resp;
|
||||
char *help, *qom_tree;
|
||||
|
||||
/*
|
||||
* Skip this part for the abstract device test case, because
|
||||
* device-list-properties crashes for such devices.
|
||||
* FIXME fix it not to crash
|
||||
*/
|
||||
if (strcmp(type, "device")) {
|
||||
resp = qmp("{'execute': 'device-list-properties',"
|
||||
" 'arguments': {'typename': %s}}",
|
||||
type);
|
||||
QDECREF(resp);
|
||||
}
|
||||
|
||||
help = hmp("device_add \"%s,help\"", type);
|
||||
g_free(help);
|
||||
|
||||
/*
|
||||
* Some devices leave dangling pointers in QOM behind.
|
||||
* "info qom-tree" has a good chance at crashing then
|
||||
*/
|
||||
qom_tree = hmp("info qom-tree");
|
||||
g_free(qom_tree);
|
||||
}
|
||||
|
||||
static void test_device_intro_list(void)
|
||||
{
|
||||
QList *types;
|
||||
char *help;
|
||||
|
||||
qtest_start(common_args);
|
||||
|
||||
types = device_type_list(true);
|
||||
QDECREF(types);
|
||||
|
||||
help = hmp("device_add help");
|
||||
g_free(help);
|
||||
|
||||
qtest_end();
|
||||
}
|
||||
|
||||
static void test_device_intro_none(void)
|
||||
{
|
||||
qtest_start(common_args);
|
||||
test_one_device("nonexistent");
|
||||
qtest_end();
|
||||
}
|
||||
|
||||
static void test_device_intro_abstract(void)
|
||||
{
|
||||
qtest_start(common_args);
|
||||
test_one_device("device");
|
||||
qtest_end();
|
||||
}
|
||||
|
||||
static bool blacklisted(const char *type)
|
||||
{
|
||||
static const char *blacklist[] = {
|
||||
/* hang in object_unref(): */
|
||||
"realview_pci", "versatile_pci",
|
||||
/* create a CPU, thus use after free (see below): */
|
||||
"allwinner-a10", "digic", "fsl,imx25", "fsl,imx31", "xlnx,zynqmp",
|
||||
};
|
||||
size_t len = strlen(type);
|
||||
int i;
|
||||
|
||||
if (len >= 4 && !strcmp(type + len - 4, "-cpu")) {
|
||||
/* use after free: cpu_exec_init() saves CPUState in cpus */
|
||||
return true;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(blacklist); i++) {
|
||||
if (!strcmp(blacklist[i], type)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void test_device_intro_concrete(void)
|
||||
{
|
||||
QList *types;
|
||||
QListEntry *entry;
|
||||
const char *type;
|
||||
|
||||
qtest_start(common_args);
|
||||
types = device_type_list(false);
|
||||
|
||||
QLIST_FOREACH_ENTRY(types, entry) {
|
||||
type = qdict_get_try_str(qobject_to_qdict(qlist_entry_obj(entry)),
|
||||
"name");
|
||||
g_assert(type);
|
||||
if (blacklisted(type)) {
|
||||
continue; /* FIXME broken device, skip */
|
||||
}
|
||||
test_one_device(type);
|
||||
}
|
||||
|
||||
QDECREF(types);
|
||||
qtest_end();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
qtest_add_func("device/introspect/list", test_device_intro_list);
|
||||
qtest_add_func("device/introspect/none", test_device_intro_none);
|
||||
qtest_add_func("device/introspect/abstract", test_device_intro_abstract);
|
||||
qtest_add_func("device/introspect/concrete", test_device_intro_concrete);
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
Loaded 100 of 110 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user