mirror of
https://github.com/utmapp/qemu.git
synced 2026-05-26 13:51:06 +00:00
Merge tag 'v8.0.2' into utm-edition
v8.0.2 release
This commit is contained in:
+1
-1
@@ -1830,7 +1830,7 @@ static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr,
|
||||
} else /* if (prot & PAGE_READ) */ {
|
||||
tlb_addr = tlbe->addr_read;
|
||||
if (!tlb_hit(tlb_addr, addr)) {
|
||||
if (!VICTIM_TLB_HIT(addr_write, addr)) {
|
||||
if (!VICTIM_TLB_HIT(addr_read, addr)) {
|
||||
tlb_fill(env_cpu(env), addr, size,
|
||||
MMU_DATA_LOAD, mmu_idx, retaddr);
|
||||
index = tlb_index(env, mmu_idx, addr);
|
||||
|
||||
@@ -680,7 +680,7 @@ int coroutine_fn bdrv_co_create_opts_simple(BlockDriver *drv,
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
blk_unref(blk);
|
||||
blk_co_unref(blk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -2018,7 +2018,15 @@ void blk_activate(BlockBackend *blk, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
bdrv_activate(bs, errp);
|
||||
/*
|
||||
* Migration code can call this function in coroutine context, so leave
|
||||
* coroutine context if necessary.
|
||||
*/
|
||||
if (qemu_in_coroutine()) {
|
||||
bdrv_co_activate(bs, errp);
|
||||
} else {
|
||||
bdrv_activate(bs, errp);
|
||||
}
|
||||
}
|
||||
|
||||
bool coroutine_fn blk_co_is_inserted(BlockBackend *blk)
|
||||
|
||||
+3
-3
@@ -355,7 +355,7 @@ block_crypto_co_create_generic(BlockDriverState *bs, int64_t size,
|
||||
ret = 0;
|
||||
cleanup:
|
||||
qcrypto_block_free(crypto);
|
||||
blk_unref(blk);
|
||||
blk_co_unref(blk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -661,7 +661,7 @@ block_crypto_co_create_luks(BlockdevCreateOptions *create_options, Error **errp)
|
||||
|
||||
ret = 0;
|
||||
fail:
|
||||
bdrv_unref(bs);
|
||||
bdrv_co_unref(bs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -730,7 +730,7 @@ fail:
|
||||
bdrv_co_delete_file_noerr(bs);
|
||||
}
|
||||
|
||||
bdrv_unref(bs);
|
||||
bdrv_co_unref(bs);
|
||||
qapi_free_QCryptoBlockCreateOptions(create_opts);
|
||||
qobject_unref(cryptoopts);
|
||||
return ret;
|
||||
|
||||
@@ -192,7 +192,10 @@ BlockExport *blk_exp_add(BlockExportOptions *export, Error **errp)
|
||||
return exp;
|
||||
|
||||
fail:
|
||||
blk_unref(blk);
|
||||
if (blk) {
|
||||
blk_set_dev_ops(blk, NULL, NULL);
|
||||
blk_unref(blk);
|
||||
}
|
||||
aio_context_release(ctx);
|
||||
if (exp) {
|
||||
g_free(exp->id);
|
||||
@@ -219,6 +222,7 @@ static void blk_exp_delete_bh(void *opaque)
|
||||
assert(exp->refcount == 0);
|
||||
QLIST_REMOVE(exp, next);
|
||||
exp->drv->delete(exp);
|
||||
blk_set_dev_ops(exp->blk, NULL, NULL);
|
||||
blk_unref(exp->blk);
|
||||
qapi_event_send_block_export_deleted(exp->id);
|
||||
g_free(exp->id);
|
||||
|
||||
@@ -346,7 +346,6 @@ static void vduse_blk_exp_delete(BlockExport *exp)
|
||||
|
||||
blk_remove_aio_context_notifier(exp->blk, blk_aio_attached, blk_aio_detach,
|
||||
vblk_exp);
|
||||
blk_set_dev_ops(exp->blk, NULL, NULL);
|
||||
ret = vduse_dev_destroy(vblk_exp->dev);
|
||||
if (ret != -EBUSY) {
|
||||
unlink(vblk_exp->recon_file);
|
||||
|
||||
@@ -30,8 +30,10 @@ BdrvGraphLock graph_lock;
|
||||
/* Protects the list of aiocontext and orphaned_reader_count */
|
||||
static QemuMutex aio_context_list_lock;
|
||||
|
||||
#if 0
|
||||
/* Written and read with atomic operations. */
|
||||
static int has_writer;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* A reader coroutine could move from an AioContext to another.
|
||||
@@ -88,6 +90,7 @@ void unregister_aiocontext(AioContext *ctx)
|
||||
g_free(ctx->bdrv_graph);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static uint32_t reader_count(void)
|
||||
{
|
||||
BdrvGraphRWlock *brdv_graph;
|
||||
@@ -105,10 +108,17 @@ static uint32_t reader_count(void)
|
||||
assert((int32_t)rd >= 0);
|
||||
return rd;
|
||||
}
|
||||
#endif
|
||||
|
||||
void bdrv_graph_wrlock(void)
|
||||
{
|
||||
GLOBAL_STATE_CODE();
|
||||
/*
|
||||
* TODO Some callers hold an AioContext lock when this is called, which
|
||||
* causes deadlocks. Reenable once the AioContext locking is cleaned up (or
|
||||
* AioContext locks are gone).
|
||||
*/
|
||||
#if 0
|
||||
assert(!qatomic_read(&has_writer));
|
||||
|
||||
/* Make sure that constantly arriving new I/O doesn't cause starvation */
|
||||
@@ -139,11 +149,13 @@ void bdrv_graph_wrlock(void)
|
||||
} while (reader_count() >= 1);
|
||||
|
||||
bdrv_drain_all_end();
|
||||
#endif
|
||||
}
|
||||
|
||||
void bdrv_graph_wrunlock(void)
|
||||
{
|
||||
GLOBAL_STATE_CODE();
|
||||
#if 0
|
||||
QEMU_LOCK_GUARD(&aio_context_list_lock);
|
||||
assert(qatomic_read(&has_writer));
|
||||
|
||||
@@ -155,10 +167,13 @@ void bdrv_graph_wrunlock(void)
|
||||
|
||||
/* Wake up all coroutine that are waiting to read the graph */
|
||||
qemu_co_enter_all(&reader_queue, &aio_context_list_lock);
|
||||
#endif
|
||||
}
|
||||
|
||||
void coroutine_fn bdrv_graph_co_rdlock(void)
|
||||
{
|
||||
/* TODO Reenable when wrlock is reenabled */
|
||||
#if 0
|
||||
BdrvGraphRWlock *bdrv_graph;
|
||||
bdrv_graph = qemu_get_current_aio_context()->bdrv_graph;
|
||||
|
||||
@@ -223,10 +238,12 @@ void coroutine_fn bdrv_graph_co_rdlock(void)
|
||||
qemu_co_queue_wait(&reader_queue, &aio_context_list_lock);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void coroutine_fn bdrv_graph_co_rdunlock(void)
|
||||
{
|
||||
#if 0
|
||||
BdrvGraphRWlock *bdrv_graph;
|
||||
bdrv_graph = qemu_get_current_aio_context()->bdrv_graph;
|
||||
|
||||
@@ -249,6 +266,7 @@ void coroutine_fn bdrv_graph_co_rdunlock(void)
|
||||
if (qatomic_read(&has_writer)) {
|
||||
aio_wait_kick();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void bdrv_graph_rdlock_main_loop(void)
|
||||
@@ -265,11 +283,20 @@ void bdrv_graph_rdunlock_main_loop(void)
|
||||
|
||||
void assert_bdrv_graph_readable(void)
|
||||
{
|
||||
/* reader_count() is slow due to aio_context_list_lock lock contention */
|
||||
/* TODO Reenable when wrlock is reenabled */
|
||||
#if 0
|
||||
#ifdef CONFIG_DEBUG_GRAPH_LOCK
|
||||
assert(qemu_in_main_thread() || reader_count());
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void assert_bdrv_graph_writable(void)
|
||||
{
|
||||
assert(qemu_in_main_thread());
|
||||
/* TODO Reenable when wrlock is reenabled */
|
||||
#if 0
|
||||
assert(qatomic_read(&has_writer));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -214,15 +214,17 @@ void hmp_commit(Monitor *mon, const QDict *qdict)
|
||||
error_report("Device '%s' not found", device);
|
||||
return;
|
||||
}
|
||||
if (!blk_is_available(blk)) {
|
||||
error_report("Device '%s' has no medium", device);
|
||||
return;
|
||||
}
|
||||
|
||||
bs = bdrv_skip_implicit_filters(blk_bs(blk));
|
||||
aio_context = bdrv_get_aio_context(bs);
|
||||
aio_context_acquire(aio_context);
|
||||
|
||||
if (!blk_is_available(blk)) {
|
||||
error_report("Device '%s' has no medium", device);
|
||||
aio_context_release(aio_context);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = bdrv_commit(bs);
|
||||
|
||||
aio_context_release(aio_context);
|
||||
|
||||
+3
-3
@@ -613,8 +613,8 @@ static int coroutine_fn parallels_co_create(BlockdevCreateOptions* opts,
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
blk_unref(blk);
|
||||
bdrv_unref(bs);
|
||||
blk_co_unref(blk);
|
||||
bdrv_co_unref(bs);
|
||||
return ret;
|
||||
|
||||
exit:
|
||||
@@ -691,7 +691,7 @@ parallels_co_create_opts(BlockDriver *drv, const char *filename,
|
||||
|
||||
done:
|
||||
qobject_unref(qdict);
|
||||
bdrv_unref(bs);
|
||||
bdrv_co_unref(bs);
|
||||
qapi_free_BlockdevCreateOptions(create_options);
|
||||
return ret;
|
||||
}
|
||||
|
||||
+3
-3
@@ -915,8 +915,8 @@ static int coroutine_fn qcow_co_create(BlockdevCreateOptions *opts,
|
||||
g_free(tmp);
|
||||
ret = 0;
|
||||
exit:
|
||||
blk_unref(qcow_blk);
|
||||
bdrv_unref(bs);
|
||||
blk_co_unref(qcow_blk);
|
||||
bdrv_co_unref(bs);
|
||||
qcrypto_block_free(crypto);
|
||||
return ret;
|
||||
}
|
||||
@@ -1015,7 +1015,7 @@ qcow_co_create_opts(BlockDriver *drv, const char *filename,
|
||||
fail:
|
||||
g_free(backing_fmt);
|
||||
qobject_unref(qdict);
|
||||
bdrv_unref(bs);
|
||||
bdrv_co_unref(bs);
|
||||
qapi_free_BlockdevCreateOptions(create_options);
|
||||
return ret;
|
||||
}
|
||||
|
||||
+7
-7
@@ -3705,7 +3705,7 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
|
||||
goto out;
|
||||
}
|
||||
|
||||
blk_unref(blk);
|
||||
blk_co_unref(blk);
|
||||
blk = NULL;
|
||||
|
||||
/*
|
||||
@@ -3785,7 +3785,7 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
blk_unref(blk);
|
||||
blk_co_unref(blk);
|
||||
blk = NULL;
|
||||
|
||||
/* Reopen the image without BDRV_O_NO_FLUSH to flush it before returning.
|
||||
@@ -3810,9 +3810,9 @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
blk_unref(blk);
|
||||
bdrv_unref(bs);
|
||||
bdrv_unref(data_bs);
|
||||
blk_co_unref(blk);
|
||||
bdrv_co_unref(bs);
|
||||
bdrv_co_unref(data_bs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -3943,8 +3943,8 @@ finish:
|
||||
}
|
||||
|
||||
qobject_unref(qdict);
|
||||
bdrv_unref(bs);
|
||||
bdrv_unref(data_bs);
|
||||
bdrv_co_unref(bs);
|
||||
bdrv_co_unref(data_bs);
|
||||
qapi_free_BlockdevCreateOptions(create_options);
|
||||
return ret;
|
||||
}
|
||||
|
||||
+3
-3
@@ -748,8 +748,8 @@ static int coroutine_fn bdrv_qed_co_create(BlockdevCreateOptions *opts,
|
||||
ret = 0; /* success */
|
||||
out:
|
||||
g_free(l1_table);
|
||||
blk_unref(blk);
|
||||
bdrv_unref(bs);
|
||||
blk_co_unref(blk);
|
||||
bdrv_co_unref(bs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -819,7 +819,7 @@ bdrv_qed_co_create_opts(BlockDriver *drv, const char *filename,
|
||||
|
||||
fail:
|
||||
qobject_unref(qdict);
|
||||
bdrv_unref(bs);
|
||||
bdrv_co_unref(bs);
|
||||
qapi_free_BlockdevCreateOptions(create_options);
|
||||
return ret;
|
||||
}
|
||||
|
||||
+3
-3
@@ -886,8 +886,8 @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options,
|
||||
|
||||
ret = 0;
|
||||
exit:
|
||||
blk_unref(blk);
|
||||
bdrv_unref(bs_file);
|
||||
blk_co_unref(blk);
|
||||
bdrv_co_unref(bs_file);
|
||||
g_free(bmap);
|
||||
return ret;
|
||||
}
|
||||
@@ -975,7 +975,7 @@ vdi_co_create_opts(BlockDriver *drv, const char *filename,
|
||||
done:
|
||||
qobject_unref(qdict);
|
||||
qapi_free_BlockdevCreateOptions(create_options);
|
||||
bdrv_unref(bs_file);
|
||||
bdrv_co_unref(bs_file);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -2053,8 +2053,8 @@ static int coroutine_fn vhdx_co_create(BlockdevCreateOptions *opts,
|
||||
|
||||
ret = 0;
|
||||
delete_and_exit:
|
||||
blk_unref(blk);
|
||||
bdrv_unref(bs);
|
||||
blk_co_unref(blk);
|
||||
bdrv_co_unref(bs);
|
||||
g_free(creator);
|
||||
return ret;
|
||||
}
|
||||
@@ -2144,7 +2144,7 @@ vhdx_co_create_opts(BlockDriver *drv, const char *filename,
|
||||
|
||||
fail:
|
||||
qobject_unref(qdict);
|
||||
bdrv_unref(bs);
|
||||
bdrv_co_unref(bs);
|
||||
qapi_free_BlockdevCreateOptions(create_options);
|
||||
return ret;
|
||||
}
|
||||
|
||||
+9
-9
@@ -2306,7 +2306,7 @@ exit:
|
||||
if (pbb) {
|
||||
*pbb = blk;
|
||||
} else {
|
||||
blk_unref(blk);
|
||||
blk_co_unref(blk);
|
||||
blk = NULL;
|
||||
}
|
||||
}
|
||||
@@ -2516,12 +2516,12 @@ vmdk_co_do_create(int64_t size,
|
||||
if (strcmp(blk_bs(backing)->drv->format_name, "vmdk")) {
|
||||
error_setg(errp, "Invalid backing file format: %s. Must be vmdk",
|
||||
blk_bs(backing)->drv->format_name);
|
||||
blk_unref(backing);
|
||||
blk_co_unref(backing);
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
ret = vmdk_read_cid(blk_bs(backing), 0, &parent_cid);
|
||||
blk_unref(backing);
|
||||
blk_co_unref(backing);
|
||||
if (ret) {
|
||||
error_setg(errp, "Failed to read parent CID");
|
||||
goto exit;
|
||||
@@ -2542,14 +2542,14 @@ vmdk_co_do_create(int64_t size,
|
||||
blk_bs(extent_blk)->filename);
|
||||
created_size += cur_size;
|
||||
extent_idx++;
|
||||
blk_unref(extent_blk);
|
||||
blk_co_unref(extent_blk);
|
||||
}
|
||||
|
||||
/* Check whether we got excess extents */
|
||||
extent_blk = extent_fn(-1, extent_idx, flat, split, compress, zeroed_grain,
|
||||
opaque, NULL);
|
||||
if (extent_blk) {
|
||||
blk_unref(extent_blk);
|
||||
blk_co_unref(extent_blk);
|
||||
error_setg(errp, "List of extents contains unused extents");
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
@@ -2590,7 +2590,7 @@ vmdk_co_do_create(int64_t size,
|
||||
ret = 0;
|
||||
exit:
|
||||
if (blk) {
|
||||
blk_unref(blk);
|
||||
blk_co_unref(blk);
|
||||
}
|
||||
g_free(desc);
|
||||
g_free(parent_desc_line);
|
||||
@@ -2641,7 +2641,7 @@ vmdk_co_create_opts_cb(int64_t size, int idx, bool flat, bool split,
|
||||
errp)) {
|
||||
goto exit;
|
||||
}
|
||||
bdrv_unref(bs);
|
||||
bdrv_co_unref(bs);
|
||||
exit:
|
||||
g_free(ext_filename);
|
||||
return blk;
|
||||
@@ -2797,12 +2797,12 @@ static BlockBackend * coroutine_fn vmdk_co_create_cb(int64_t size, int idx,
|
||||
return NULL;
|
||||
}
|
||||
blk_set_allow_write_beyond_eof(blk, true);
|
||||
bdrv_unref(bs);
|
||||
bdrv_co_unref(bs);
|
||||
|
||||
if (size != -1) {
|
||||
ret = vmdk_init_extent(blk, size, flat, compress, zeroed_grain, errp);
|
||||
if (ret) {
|
||||
blk_unref(blk);
|
||||
blk_co_unref(blk);
|
||||
blk = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -1082,8 +1082,8 @@ static int coroutine_fn vpc_co_create(BlockdevCreateOptions *opts,
|
||||
}
|
||||
|
||||
out:
|
||||
blk_unref(blk);
|
||||
bdrv_unref(bs);
|
||||
blk_co_unref(blk);
|
||||
bdrv_co_unref(bs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1162,7 +1162,7 @@ vpc_co_create_opts(BlockDriver *drv, const char *filename,
|
||||
|
||||
fail:
|
||||
qobject_unref(qdict);
|
||||
bdrv_unref(bs);
|
||||
bdrv_co_unref(bs);
|
||||
qapi_free_BlockdevCreateOptions(create_options);
|
||||
return ret;
|
||||
}
|
||||
|
||||
+16
-6
@@ -153,12 +153,22 @@ void blockdev_mark_auto_del(BlockBackend *blk)
|
||||
|
||||
JOB_LOCK_GUARD();
|
||||
|
||||
for (job = block_job_next_locked(NULL); job;
|
||||
job = block_job_next_locked(job)) {
|
||||
if (block_job_has_bdrv(job, blk_bs(blk))) {
|
||||
do {
|
||||
job = block_job_next_locked(NULL);
|
||||
while (job && (job->job.cancelled ||
|
||||
job->job.deferred_to_main_loop ||
|
||||
!block_job_has_bdrv(job, blk_bs(blk))))
|
||||
{
|
||||
job = block_job_next_locked(job);
|
||||
}
|
||||
if (job) {
|
||||
/*
|
||||
* This drops the job lock temporarily and polls, so we need to
|
||||
* restart processing the list from the start after this.
|
||||
*/
|
||||
job_cancel_locked(&job->job, false);
|
||||
}
|
||||
}
|
||||
} while (job);
|
||||
|
||||
dinfo->auto_del = 1;
|
||||
}
|
||||
@@ -2430,7 +2440,7 @@ void coroutine_fn qmp_block_resize(const char *device, const char *node_name,
|
||||
return;
|
||||
}
|
||||
|
||||
blk = blk_new_with_bs(bs, BLK_PERM_RESIZE, BLK_PERM_ALL, errp);
|
||||
blk = blk_co_new_with_bs(bs, BLK_PERM_RESIZE, BLK_PERM_ALL, errp);
|
||||
if (!blk) {
|
||||
return;
|
||||
}
|
||||
@@ -2445,7 +2455,7 @@ void coroutine_fn qmp_block_resize(const char *device, const char *node_name,
|
||||
|
||||
bdrv_co_lock(bs);
|
||||
bdrv_drained_end(bs);
|
||||
blk_unref(blk);
|
||||
blk_co_unref(blk);
|
||||
bdrv_co_unlock(bs);
|
||||
}
|
||||
|
||||
|
||||
@@ -807,6 +807,7 @@ for opt do
|
||||
--enable-debug)
|
||||
# Enable debugging options that aren't excessively noisy
|
||||
debug_tcg="yes"
|
||||
meson_option_parse --enable-debug-graph-lock ""
|
||||
meson_option_parse --enable-debug-mutex ""
|
||||
meson_option_add -Doptimization=0
|
||||
fortify_source="no"
|
||||
|
||||
@@ -111,6 +111,10 @@ Use ``-machine acpi=off`` instead.
|
||||
The HAXM project has been retired (see https://github.com/intel/haxm#status).
|
||||
Use "whpx" (on Windows) or "hvf" (on macOS) instead.
|
||||
|
||||
``-async-teardown`` (since 8.1)
|
||||
'''''''''''''''''''''''''''''''
|
||||
|
||||
Use ``-run-with async-teardown=on`` instead.
|
||||
|
||||
QEMU Machine Protocol (QMP) commands
|
||||
------------------------------------
|
||||
@@ -219,8 +223,8 @@ Use the more generic event ``DEVICE_UNPLUG_GUEST_ERROR`` instead.
|
||||
System emulator machines
|
||||
------------------------
|
||||
|
||||
Arm ``virt`` machine ``dtb-kaslr-seed`` property
|
||||
''''''''''''''''''''''''''''''''''''''''''''''''
|
||||
Arm ``virt`` machine ``dtb-kaslr-seed`` property (since 7.1)
|
||||
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
|
||||
|
||||
The ``dtb-kaslr-seed`` property on the ``virt`` board has been
|
||||
deprecated; use the new name ``dtb-randomness`` instead. The new name
|
||||
|
||||
@@ -99,7 +99,7 @@ depending on the guest architecture.
|
||||
- Yes
|
||||
- A configurable 32 bit soft core now owned by Cadence
|
||||
|
||||
A number of features are are only available when running under
|
||||
A number of features are only available when running under
|
||||
emulation including :ref:`Record/Replay<replay>` and :ref:`TCG Plugins`.
|
||||
|
||||
.. _Semihosting:
|
||||
|
||||
+1
-1
@@ -5135,7 +5135,7 @@ float32 float32_exp2(float32 a, float_status *status)
|
||||
float64_unpack_canonical(&rp, float64_one, status);
|
||||
for (i = 0 ; i < 15 ; i++) {
|
||||
float64_unpack_canonical(&tp, float32_exp2_coefficients[i], status);
|
||||
rp = *parts_muladd(&tp, &xp, &rp, 0, status);
|
||||
rp = *parts_muladd(&tp, &xnp, &rp, 0, status);
|
||||
xnp = *parts_mul(&xnp, &xp, status);
|
||||
}
|
||||
|
||||
|
||||
@@ -48,3 +48,9 @@ v9fs_readlink(uint16_t tag, uint8_t id, int32_t fid) "tag %d id %d fid %d"
|
||||
v9fs_readlink_return(uint16_t tag, uint8_t id, char* target) "tag %d id %d name %s"
|
||||
v9fs_setattr(uint16_t tag, uint8_t id, int32_t fid, int32_t valid, int32_t mode, int32_t uid, int32_t gid, int64_t size, int64_t atime_sec, int64_t mtime_sec) "tag %u id %u fid %d iattr={valid %d mode %d uid %d gid %d size %"PRId64" atime=%"PRId64" mtime=%"PRId64" }"
|
||||
v9fs_setattr_return(uint16_t tag, uint8_t id) "tag %u id %u"
|
||||
|
||||
# xen-9p-backend.c
|
||||
xen_9pfs_alloc(char *name) "name %s"
|
||||
xen_9pfs_connect(char *name) "name %s"
|
||||
xen_9pfs_disconnect(char *name) "name %s"
|
||||
xen_9pfs_free(char *name) "name %s"
|
||||
|
||||
+22
-13
@@ -25,6 +25,8 @@
|
||||
#include "qemu/iov.h"
|
||||
#include "fsdev/qemu-fsdev.h"
|
||||
|
||||
#include "trace.h"
|
||||
|
||||
#define VERSIONS "1"
|
||||
#define MAX_RINGS 8
|
||||
#define MAX_RING_ORDER 9
|
||||
@@ -336,6 +338,8 @@ static void xen_9pfs_disconnect(struct XenLegacyDevice *xendev)
|
||||
Xen9pfsDev *xen_9pdev = container_of(xendev, Xen9pfsDev, xendev);
|
||||
int i;
|
||||
|
||||
trace_xen_9pfs_disconnect(xendev->name);
|
||||
|
||||
for (i = 0; i < xen_9pdev->num_rings; i++) {
|
||||
if (xen_9pdev->rings[i].evtchndev != NULL) {
|
||||
qemu_set_fd_handler(qemu_xen_evtchn_fd(xen_9pdev->rings[i].evtchndev),
|
||||
@@ -344,40 +348,41 @@ static void xen_9pfs_disconnect(struct XenLegacyDevice *xendev)
|
||||
xen_9pdev->rings[i].local_port);
|
||||
xen_9pdev->rings[i].evtchndev = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int xen_9pfs_free(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
Xen9pfsDev *xen_9pdev = container_of(xendev, Xen9pfsDev, xendev);
|
||||
int i;
|
||||
|
||||
if (xen_9pdev->rings[0].evtchndev != NULL) {
|
||||
xen_9pfs_disconnect(xendev);
|
||||
}
|
||||
|
||||
for (i = 0; i < xen_9pdev->num_rings; i++) {
|
||||
if (xen_9pdev->rings[i].data != NULL) {
|
||||
xen_be_unmap_grant_refs(&xen_9pdev->xendev,
|
||||
xen_9pdev->rings[i].data,
|
||||
xen_9pdev->rings[i].intf->ref,
|
||||
(1 << xen_9pdev->rings[i].ring_order));
|
||||
xen_9pdev->rings[i].data = NULL;
|
||||
}
|
||||
if (xen_9pdev->rings[i].intf != NULL) {
|
||||
xen_be_unmap_grant_ref(&xen_9pdev->xendev,
|
||||
xen_9pdev->rings[i].intf,
|
||||
xen_9pdev->rings[i].ref);
|
||||
xen_9pdev->rings[i].intf = NULL;
|
||||
}
|
||||
if (xen_9pdev->rings[i].bh != NULL) {
|
||||
qemu_bh_delete(xen_9pdev->rings[i].bh);
|
||||
xen_9pdev->rings[i].bh = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
g_free(xen_9pdev->id);
|
||||
xen_9pdev->id = NULL;
|
||||
g_free(xen_9pdev->tag);
|
||||
xen_9pdev->tag = NULL;
|
||||
g_free(xen_9pdev->path);
|
||||
xen_9pdev->path = NULL;
|
||||
g_free(xen_9pdev->security_model);
|
||||
xen_9pdev->security_model = NULL;
|
||||
g_free(xen_9pdev->rings);
|
||||
xen_9pdev->rings = NULL;
|
||||
}
|
||||
|
||||
static int xen_9pfs_free(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
trace_xen_9pfs_free(xendev->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -389,6 +394,8 @@ static int xen_9pfs_connect(struct XenLegacyDevice *xendev)
|
||||
V9fsState *s = &xen_9pdev->state;
|
||||
QemuOpts *fsdev;
|
||||
|
||||
trace_xen_9pfs_connect(xendev->name);
|
||||
|
||||
if (xenstore_read_fe_int(&xen_9pdev->xendev, "num-rings",
|
||||
&xen_9pdev->num_rings) == -1 ||
|
||||
xen_9pdev->num_rings > MAX_RINGS || xen_9pdev->num_rings < 1) {
|
||||
@@ -496,6 +503,8 @@ out:
|
||||
|
||||
static void xen_9pfs_alloc(struct XenLegacyDevice *xendev)
|
||||
{
|
||||
trace_xen_9pfs_alloc(xendev->name);
|
||||
|
||||
xenstore_write_be_str(xendev, "versions", VERSIONS);
|
||||
xenstore_write_be_int(xendev, "max-rings", MAX_RINGS);
|
||||
xenstore_write_be_int(xendev, "max-ring-page-order", MAX_RING_ORDER);
|
||||
|
||||
@@ -357,6 +357,16 @@ void acpi_pcihp_device_unplug_request_cb(HotplugHandler *hotplug_dev,
|
||||
* acpi_pcihp_eject_slot() when the operation is completed.
|
||||
*/
|
||||
pdev->qdev.pending_deleted_event = true;
|
||||
/* if unplug was requested before OSPM is initialized,
|
||||
* linux kernel will clear GPE0.sts[] bits during boot, which effectively
|
||||
* hides unplug event. And than followup qmp_device_del() calls remain
|
||||
* blocked by above flag permanently.
|
||||
* Unblock qmp_device_del() by setting expire limit, so user can
|
||||
* repeat unplug request later when OSPM has been booted.
|
||||
*/
|
||||
pdev->qdev.pending_deleted_expires_ms =
|
||||
qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL); /* 1 msec */
|
||||
|
||||
s->acpi_pcihp_pci_status[bsel].down |= (1U << slot);
|
||||
acpi_send_event(DEVICE(hotplug_dev), ACPI_PCI_HOTPLUG_STATUS);
|
||||
}
|
||||
|
||||
+20
-18
@@ -200,33 +200,35 @@ struct AspeedMachineState {
|
||||
static void aspeed_write_smpboot(ARMCPU *cpu,
|
||||
const struct arm_boot_info *info)
|
||||
{
|
||||
static const uint32_t poll_mailbox_ready[] = {
|
||||
AddressSpace *as = arm_boot_address_space(cpu, info);
|
||||
static const ARMInsnFixup poll_mailbox_ready[] = {
|
||||
/*
|
||||
* r2 = per-cpu go sign value
|
||||
* r1 = AST_SMP_MBOX_FIELD_ENTRY
|
||||
* r0 = AST_SMP_MBOX_FIELD_GOSIGN
|
||||
*/
|
||||
0xee100fb0, /* mrc p15, 0, r0, c0, c0, 5 */
|
||||
0xe21000ff, /* ands r0, r0, #255 */
|
||||
0xe59f201c, /* ldr r2, [pc, #28] */
|
||||
0xe1822000, /* orr r2, r2, r0 */
|
||||
{ 0xee100fb0 }, /* mrc p15, 0, r0, c0, c0, 5 */
|
||||
{ 0xe21000ff }, /* ands r0, r0, #255 */
|
||||
{ 0xe59f201c }, /* ldr r2, [pc, #28] */
|
||||
{ 0xe1822000 }, /* orr r2, r2, r0 */
|
||||
|
||||
0xe59f1018, /* ldr r1, [pc, #24] */
|
||||
0xe59f0018, /* ldr r0, [pc, #24] */
|
||||
{ 0xe59f1018 }, /* ldr r1, [pc, #24] */
|
||||
{ 0xe59f0018 }, /* ldr r0, [pc, #24] */
|
||||
|
||||
0xe320f002, /* wfe */
|
||||
0xe5904000, /* ldr r4, [r0] */
|
||||
0xe1520004, /* cmp r2, r4 */
|
||||
0x1afffffb, /* bne <wfe> */
|
||||
0xe591f000, /* ldr pc, [r1] */
|
||||
AST_SMP_MBOX_GOSIGN,
|
||||
AST_SMP_MBOX_FIELD_ENTRY,
|
||||
AST_SMP_MBOX_FIELD_GOSIGN,
|
||||
{ 0xe320f002 }, /* wfe */
|
||||
{ 0xe5904000 }, /* ldr r4, [r0] */
|
||||
{ 0xe1520004 }, /* cmp r2, r4 */
|
||||
{ 0x1afffffb }, /* bne <wfe> */
|
||||
{ 0xe591f000 }, /* ldr pc, [r1] */
|
||||
{ AST_SMP_MBOX_GOSIGN },
|
||||
{ AST_SMP_MBOX_FIELD_ENTRY },
|
||||
{ AST_SMP_MBOX_FIELD_GOSIGN },
|
||||
{ 0, FIXUP_TERMINATOR }
|
||||
};
|
||||
static const uint32_t fixupcontext[FIXUP_MAX] = { 0 };
|
||||
|
||||
rom_add_blob_fixed("aspeed.smpboot", poll_mailbox_ready,
|
||||
sizeof(poll_mailbox_ready),
|
||||
info->smp_loader_start);
|
||||
arm_write_bootloader("aspeed.smpboot", as, info->smp_loader_start,
|
||||
poll_mailbox_ready, fixupcontext);
|
||||
}
|
||||
|
||||
static void aspeed_reset_secondary(ARMCPU *cpu,
|
||||
|
||||
+8
-27
@@ -60,26 +60,6 @@ AddressSpace *arm_boot_address_space(ARMCPU *cpu,
|
||||
return cpu_get_address_space(cs, asidx);
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
FIXUP_NONE = 0, /* do nothing */
|
||||
FIXUP_TERMINATOR, /* end of insns */
|
||||
FIXUP_BOARDID, /* overwrite with board ID number */
|
||||
FIXUP_BOARD_SETUP, /* overwrite with board specific setup code address */
|
||||
FIXUP_ARGPTR_LO, /* overwrite with pointer to kernel args */
|
||||
FIXUP_ARGPTR_HI, /* overwrite with pointer to kernel args (high half) */
|
||||
FIXUP_ENTRYPOINT_LO, /* overwrite with kernel entry point */
|
||||
FIXUP_ENTRYPOINT_HI, /* overwrite with kernel entry point (high half) */
|
||||
FIXUP_GIC_CPU_IF, /* overwrite with GIC CPU interface address */
|
||||
FIXUP_BOOTREG, /* overwrite with boot register address */
|
||||
FIXUP_DSB, /* overwrite with correct DSB insn for cpu */
|
||||
FIXUP_MAX,
|
||||
} FixupType;
|
||||
|
||||
typedef struct ARMInsnFixup {
|
||||
uint32_t insn;
|
||||
FixupType fixup;
|
||||
} ARMInsnFixup;
|
||||
|
||||
static const ARMInsnFixup bootloader_aarch64[] = {
|
||||
{ 0x580000c0 }, /* ldr x0, arg ; Load the lower 32-bits of DTB */
|
||||
{ 0xaa1f03e1 }, /* mov x1, xzr */
|
||||
@@ -150,9 +130,10 @@ static const ARMInsnFixup smpboot[] = {
|
||||
{ 0, FIXUP_TERMINATOR }
|
||||
};
|
||||
|
||||
static void write_bootloader(const char *name, hwaddr addr,
|
||||
const ARMInsnFixup *insns, uint32_t *fixupcontext,
|
||||
AddressSpace *as)
|
||||
void arm_write_bootloader(const char *name,
|
||||
AddressSpace *as, hwaddr addr,
|
||||
const ARMInsnFixup *insns,
|
||||
const uint32_t *fixupcontext)
|
||||
{
|
||||
/* Fix up the specified bootloader fragment and write it into
|
||||
* guest memory using rom_add_blob_fixed(). fixupcontext is
|
||||
@@ -214,8 +195,8 @@ static void default_write_secondary(ARMCPU *cpu,
|
||||
fixupcontext[FIXUP_DSB] = CP15_DSB_INSN;
|
||||
}
|
||||
|
||||
write_bootloader("smpboot", info->smp_loader_start,
|
||||
smpboot, fixupcontext, as);
|
||||
arm_write_bootloader("smpboot", as, info->smp_loader_start,
|
||||
smpboot, fixupcontext);
|
||||
}
|
||||
|
||||
void arm_write_secure_board_setup_dummy_smc(ARMCPU *cpu,
|
||||
@@ -1186,8 +1167,8 @@ static void arm_setup_direct_kernel_boot(ARMCPU *cpu,
|
||||
fixupcontext[FIXUP_ENTRYPOINT_LO] = entry;
|
||||
fixupcontext[FIXUP_ENTRYPOINT_HI] = entry >> 32;
|
||||
|
||||
write_bootloader("bootloader", info->loader_start,
|
||||
primary_loader, fixupcontext, as);
|
||||
arm_write_bootloader("bootloader", as, info->loader_start,
|
||||
primary_loader, fixupcontext);
|
||||
|
||||
if (info->write_board_setup) {
|
||||
info->write_board_setup(cpu, info);
|
||||
|
||||
+34
-30
@@ -16,6 +16,7 @@
|
||||
#include "qemu/units.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/arm/boot.h"
|
||||
#include "hw/arm/bcm2836.h"
|
||||
#include "hw/registerfields.h"
|
||||
#include "qemu/error-report.h"
|
||||
@@ -124,20 +125,22 @@ static const char *board_type(uint32_t board_rev)
|
||||
|
||||
static void write_smpboot(ARMCPU *cpu, const struct arm_boot_info *info)
|
||||
{
|
||||
static const uint32_t smpboot[] = {
|
||||
0xe1a0e00f, /* mov lr, pc */
|
||||
0xe3a0fe00 + (BOARDSETUP_ADDR >> 4), /* mov pc, BOARDSETUP_ADDR */
|
||||
0xee100fb0, /* mrc p15, 0, r0, c0, c0, 5;get core ID */
|
||||
0xe7e10050, /* ubfx r0, r0, #0, #2 ;extract LSB */
|
||||
0xe59f5014, /* ldr r5, =0x400000CC ;load mbox base */
|
||||
0xe320f001, /* 1: yield */
|
||||
0xe7953200, /* ldr r3, [r5, r0, lsl #4] ;read mbox for our core*/
|
||||
0xe3530000, /* cmp r3, #0 ;spin while zero */
|
||||
0x0afffffb, /* beq 1b */
|
||||
0xe7853200, /* str r3, [r5, r0, lsl #4] ;clear mbox */
|
||||
0xe12fff13, /* bx r3 ;jump to target */
|
||||
0x400000cc, /* (constant: mailbox 3 read/clear base) */
|
||||
static const ARMInsnFixup smpboot[] = {
|
||||
{ 0xe1a0e00f }, /* mov lr, pc */
|
||||
{ 0xe3a0fe00 + (BOARDSETUP_ADDR >> 4) }, /* mov pc, BOARDSETUP_ADDR */
|
||||
{ 0xee100fb0 }, /* mrc p15, 0, r0, c0, c0, 5;get core ID */
|
||||
{ 0xe7e10050 }, /* ubfx r0, r0, #0, #2 ;extract LSB */
|
||||
{ 0xe59f5014 }, /* ldr r5, =0x400000CC ;load mbox base */
|
||||
{ 0xe320f001 }, /* 1: yield */
|
||||
{ 0xe7953200 }, /* ldr r3, [r5, r0, lsl #4] ;read mbox for our core */
|
||||
{ 0xe3530000 }, /* cmp r3, #0 ;spin while zero */
|
||||
{ 0x0afffffb }, /* beq 1b */
|
||||
{ 0xe7853200 }, /* str r3, [r5, r0, lsl #4] ;clear mbox */
|
||||
{ 0xe12fff13 }, /* bx r3 ;jump to target */
|
||||
{ 0x400000cc }, /* (constant: mailbox 3 read/clear base) */
|
||||
{ 0, FIXUP_TERMINATOR }
|
||||
};
|
||||
static const uint32_t fixupcontext[FIXUP_MAX] = { 0 };
|
||||
|
||||
/* check that we don't overrun board setup vectors */
|
||||
QEMU_BUILD_BUG_ON(SMPBOOT_ADDR + sizeof(smpboot) > MVBAR_ADDR);
|
||||
@@ -145,9 +148,8 @@ static void write_smpboot(ARMCPU *cpu, const struct arm_boot_info *info)
|
||||
QEMU_BUILD_BUG_ON((BOARDSETUP_ADDR & 0xf) != 0
|
||||
|| (BOARDSETUP_ADDR >> 4) >= 0x100);
|
||||
|
||||
rom_add_blob_fixed_as("raspi_smpboot", smpboot, sizeof(smpboot),
|
||||
info->smp_loader_start,
|
||||
arm_boot_address_space(cpu, info));
|
||||
arm_write_bootloader("raspi_smpboot", arm_boot_address_space(cpu, info),
|
||||
info->smp_loader_start, smpboot, fixupcontext);
|
||||
}
|
||||
|
||||
static void write_smpboot64(ARMCPU *cpu, const struct arm_boot_info *info)
|
||||
@@ -161,26 +163,28 @@ static void write_smpboot64(ARMCPU *cpu, const struct arm_boot_info *info)
|
||||
* the primary CPU goes into the kernel. We put these variables inside
|
||||
* a rom blob, so that the reset for ROM contents zeroes them for us.
|
||||
*/
|
||||
static const uint32_t smpboot[] = {
|
||||
0xd2801b05, /* mov x5, 0xd8 */
|
||||
0xd53800a6, /* mrs x6, mpidr_el1 */
|
||||
0x924004c6, /* and x6, x6, #0x3 */
|
||||
0xd503205f, /* spin: wfe */
|
||||
0xf86678a4, /* ldr x4, [x5,x6,lsl #3] */
|
||||
0xb4ffffc4, /* cbz x4, spin */
|
||||
0xd2800000, /* mov x0, #0x0 */
|
||||
0xd2800001, /* mov x1, #0x0 */
|
||||
0xd2800002, /* mov x2, #0x0 */
|
||||
0xd2800003, /* mov x3, #0x0 */
|
||||
0xd61f0080, /* br x4 */
|
||||
static const ARMInsnFixup smpboot[] = {
|
||||
{ 0xd2801b05 }, /* mov x5, 0xd8 */
|
||||
{ 0xd53800a6 }, /* mrs x6, mpidr_el1 */
|
||||
{ 0x924004c6 }, /* and x6, x6, #0x3 */
|
||||
{ 0xd503205f }, /* spin: wfe */
|
||||
{ 0xf86678a4 }, /* ldr x4, [x5,x6,lsl #3] */
|
||||
{ 0xb4ffffc4 }, /* cbz x4, spin */
|
||||
{ 0xd2800000 }, /* mov x0, #0x0 */
|
||||
{ 0xd2800001 }, /* mov x1, #0x0 */
|
||||
{ 0xd2800002 }, /* mov x2, #0x0 */
|
||||
{ 0xd2800003 }, /* mov x3, #0x0 */
|
||||
{ 0xd61f0080 }, /* br x4 */
|
||||
{ 0, FIXUP_TERMINATOR }
|
||||
};
|
||||
static const uint32_t fixupcontext[FIXUP_MAX] = { 0 };
|
||||
|
||||
static const uint64_t spintables[] = {
|
||||
0, 0, 0, 0
|
||||
};
|
||||
|
||||
rom_add_blob_fixed_as("raspi_smpboot", smpboot, sizeof(smpboot),
|
||||
info->smp_loader_start, as);
|
||||
arm_write_bootloader("raspi_smpboot", as, info->smp_loader_start,
|
||||
smpboot, fixupcontext);
|
||||
rom_add_blob_fixed_as("raspi_spintables", spintables, sizeof(spintables),
|
||||
SPINTABLE_ADDR, as);
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ GlobalProperty hw_compat_7_2[] = {
|
||||
{ "e1000e", "migrate-timadj", "off" },
|
||||
{ "virtio-mem", "x-early-migration", "false" },
|
||||
{ "migration", "x-preempt-pre-7-2", "true" },
|
||||
{ TYPE_PCI_DEVICE, "x-pcie-err-unc-mask", "off" },
|
||||
};
|
||||
const size_t hw_compat_7_2_len = G_N_ELEMENTS(hw_compat_7_2);
|
||||
|
||||
@@ -1332,6 +1333,14 @@ void machine_run_board_init(MachineState *machine, const char *mem_path, Error *
|
||||
}
|
||||
} else if (machine_class->default_ram_id && machine->ram_size &&
|
||||
numa_uses_legacy_mem()) {
|
||||
if (object_property_find(object_get_objects_root(),
|
||||
machine_class->default_ram_id)) {
|
||||
error_setg(errp, "object name '%s' is reserved for the default"
|
||||
" RAM backend, it can't be used for any other purposes."
|
||||
" Change the object's 'id' to something else",
|
||||
machine_class->default_ram_id);
|
||||
return;
|
||||
}
|
||||
if (!create_default_memdev(current_machine, mem_path, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -49,12 +49,9 @@ static void aw_a10_pic_update(AwA10PICState *s)
|
||||
static void aw_a10_pic_set_irq(void *opaque, int irq, int level)
|
||||
{
|
||||
AwA10PICState *s = opaque;
|
||||
uint32_t *pending_reg = &s->irq_pending[irq / 32];
|
||||
|
||||
if (level) {
|
||||
set_bit(irq % 32, (void *)&s->irq_pending[irq / 32]);
|
||||
} else {
|
||||
clear_bit(irq % 32, (void *)&s->irq_pending[irq / 32]);
|
||||
}
|
||||
*pending_reg = deposit32(*pending_reg, irq % 32, 1, level);
|
||||
aw_a10_pic_update(s);
|
||||
}
|
||||
|
||||
|
||||
@@ -350,8 +350,13 @@ static void allwinner_sun8i_emac_get_desc(AwSun8iEmacState *s,
|
||||
FrameDescriptor *desc,
|
||||
uint32_t phys_addr)
|
||||
{
|
||||
dma_memory_read(&s->dma_as, phys_addr, desc, sizeof(*desc),
|
||||
uint32_t desc_words[4];
|
||||
dma_memory_read(&s->dma_as, phys_addr, &desc_words, sizeof(desc_words),
|
||||
MEMTXATTRS_UNSPECIFIED);
|
||||
desc->status = le32_to_cpu(desc_words[0]);
|
||||
desc->status2 = le32_to_cpu(desc_words[1]);
|
||||
desc->addr = le32_to_cpu(desc_words[2]);
|
||||
desc->next = le32_to_cpu(desc_words[3]);
|
||||
}
|
||||
|
||||
static uint32_t allwinner_sun8i_emac_next_desc(AwSun8iEmacState *s,
|
||||
@@ -400,10 +405,15 @@ static uint32_t allwinner_sun8i_emac_tx_desc(AwSun8iEmacState *s,
|
||||
}
|
||||
|
||||
static void allwinner_sun8i_emac_flush_desc(AwSun8iEmacState *s,
|
||||
FrameDescriptor *desc,
|
||||
const FrameDescriptor *desc,
|
||||
uint32_t phys_addr)
|
||||
{
|
||||
dma_memory_write(&s->dma_as, phys_addr, desc, sizeof(*desc),
|
||||
uint32_t desc_words[4];
|
||||
desc_words[0] = cpu_to_le32(desc->status);
|
||||
desc_words[1] = cpu_to_le32(desc->status2);
|
||||
desc_words[2] = cpu_to_le32(desc->addr);
|
||||
desc_words[3] = cpu_to_le32(desc->next);
|
||||
dma_memory_write(&s->dma_as, phys_addr, &desc_words, sizeof(desc_words),
|
||||
MEMTXATTRS_UNSPECIFIED);
|
||||
}
|
||||
|
||||
@@ -638,8 +648,7 @@ static uint64_t allwinner_sun8i_emac_read(void *opaque, hwaddr offset,
|
||||
break;
|
||||
case REG_TX_CUR_BUF: /* Transmit Current Buffer */
|
||||
if (s->tx_desc_curr != 0) {
|
||||
dma_memory_read(&s->dma_as, s->tx_desc_curr, &desc, sizeof(desc),
|
||||
MEMTXATTRS_UNSPECIFIED);
|
||||
allwinner_sun8i_emac_get_desc(s, &desc, s->tx_desc_curr);
|
||||
value = desc.addr;
|
||||
} else {
|
||||
value = 0;
|
||||
@@ -652,8 +661,7 @@ static uint64_t allwinner_sun8i_emac_read(void *opaque, hwaddr offset,
|
||||
break;
|
||||
case REG_RX_CUR_BUF: /* Receive Current Buffer */
|
||||
if (s->rx_desc_curr != 0) {
|
||||
dma_memory_read(&s->dma_as, s->rx_desc_curr, &desc, sizeof(desc),
|
||||
MEMTXATTRS_UNSPECIFIED);
|
||||
allwinner_sun8i_emac_get_desc(s, &desc, s->rx_desc_curr);
|
||||
value = desc.addr;
|
||||
} else {
|
||||
value = 0;
|
||||
|
||||
+5
-6
@@ -637,9 +637,8 @@ xmit_seg(E1000State *s)
|
||||
|
||||
e1000x_inc_reg_if_not_full(s->mac_reg, TPT);
|
||||
e1000x_grow_8reg_if_not_full(s->mac_reg, TOTL, s->tx.size + 4);
|
||||
s->mac_reg[GPTC] = s->mac_reg[TPT];
|
||||
s->mac_reg[GOTCL] = s->mac_reg[TOTL];
|
||||
s->mac_reg[GOTCH] = s->mac_reg[TOTH];
|
||||
e1000x_inc_reg_if_not_full(s->mac_reg, GPTC);
|
||||
e1000x_grow_8reg_if_not_full(s->mac_reg, GOTCL, s->tx.size + 4);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -827,12 +826,10 @@ receive_filter(E1000State *s, const uint8_t *buf, int size)
|
||||
}
|
||||
|
||||
if (ismcast && (rctl & E1000_RCTL_MPE)) { /* promiscuous mcast */
|
||||
e1000x_inc_reg_if_not_full(s->mac_reg, MPRC);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (isbcast && (rctl & E1000_RCTL_BAM)) { /* broadcast enabled */
|
||||
e1000x_inc_reg_if_not_full(s->mac_reg, BPRC);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -923,6 +920,7 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
|
||||
size_t desc_offset;
|
||||
size_t desc_size;
|
||||
size_t total_size;
|
||||
eth_pkt_types_e pkt_type;
|
||||
|
||||
if (!e1000x_hw_rx_enabled(s->mac_reg)) {
|
||||
return -1;
|
||||
@@ -972,6 +970,7 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
|
||||
size -= 4;
|
||||
}
|
||||
|
||||
pkt_type = get_eth_packet_type(PKT_GET_ETH_HDR(filter_buf));
|
||||
rdh_start = s->mac_reg[RDH];
|
||||
desc_offset = 0;
|
||||
total_size = size + e1000x_fcs_len(s->mac_reg);
|
||||
@@ -1037,7 +1036,7 @@ e1000_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt)
|
||||
}
|
||||
} while (desc_offset < total_size);
|
||||
|
||||
e1000x_update_rx_total_stats(s->mac_reg, size, total_size);
|
||||
e1000x_update_rx_total_stats(s->mac_reg, pkt_type, size, total_size);
|
||||
|
||||
n = E1000_ICS_RXT0;
|
||||
if ((rdt = s->mac_reg[RDT]) < s->mac_reg[RDH])
|
||||
|
||||
+15
-36
@@ -711,9 +711,8 @@ e1000e_on_tx_done_update_stats(E1000ECore *core, struct NetTxPkt *tx_pkt)
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
core->mac[GPTC] = core->mac[TPT];
|
||||
core->mac[GOTCL] = core->mac[TOTL];
|
||||
core->mac[GOTCH] = core->mac[TOTH];
|
||||
e1000x_inc_reg_if_not_full(core->mac, GPTC);
|
||||
e1000x_grow_8reg_if_not_full(core->mac, GOTCL, tot_len);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1488,24 +1487,10 @@ e1000e_write_to_rx_buffers(E1000ECore *core,
|
||||
}
|
||||
|
||||
static void
|
||||
e1000e_update_rx_stats(E1000ECore *core,
|
||||
size_t data_size,
|
||||
size_t data_fcs_size)
|
||||
e1000e_update_rx_stats(E1000ECore *core, size_t pkt_size, size_t pkt_fcs_size)
|
||||
{
|
||||
e1000x_update_rx_total_stats(core->mac, data_size, data_fcs_size);
|
||||
|
||||
switch (net_rx_pkt_get_packet_type(core->rx_pkt)) {
|
||||
case ETH_PKT_BCAST:
|
||||
e1000x_inc_reg_if_not_full(core->mac, BPRC);
|
||||
break;
|
||||
|
||||
case ETH_PKT_MCAST:
|
||||
e1000x_inc_reg_if_not_full(core->mac, MPRC);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
eth_pkt_types_e pkt_type = net_rx_pkt_get_packet_type(core->rx_pkt);
|
||||
e1000x_update_rx_total_stats(core->mac, pkt_type, pkt_size, pkt_fcs_size);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
@@ -1700,12 +1685,9 @@ static ssize_t
|
||||
e1000e_receive_internal(E1000ECore *core, const struct iovec *iov, int iovcnt,
|
||||
bool has_vnet)
|
||||
{
|
||||
static const int maximum_ethernet_hdr_len = (ETH_HLEN + 4);
|
||||
|
||||
uint32_t n = 0;
|
||||
uint8_t min_buf[ETH_ZLEN];
|
||||
uint8_t buf[ETH_ZLEN];
|
||||
struct iovec min_iov;
|
||||
uint8_t *filter_buf;
|
||||
size_t size, orig_size;
|
||||
size_t iov_ofs = 0;
|
||||
E1000E_RxRing rxr;
|
||||
@@ -1728,24 +1710,21 @@ e1000e_receive_internal(E1000ECore *core, const struct iovec *iov, int iovcnt,
|
||||
net_rx_pkt_unset_vhdr(core->rx_pkt);
|
||||
}
|
||||
|
||||
filter_buf = iov->iov_base + iov_ofs;
|
||||
orig_size = iov_size(iov, iovcnt);
|
||||
size = orig_size - iov_ofs;
|
||||
|
||||
/* Pad to minimum Ethernet frame length */
|
||||
if (size < sizeof(min_buf)) {
|
||||
iov_to_buf(iov, iovcnt, iov_ofs, min_buf, size);
|
||||
memset(&min_buf[size], 0, sizeof(min_buf) - size);
|
||||
if (size < sizeof(buf)) {
|
||||
iov_to_buf(iov, iovcnt, iov_ofs, buf, size);
|
||||
memset(&buf[size], 0, sizeof(buf) - size);
|
||||
e1000x_inc_reg_if_not_full(core->mac, RUC);
|
||||
min_iov.iov_base = filter_buf = min_buf;
|
||||
min_iov.iov_len = size = sizeof(min_buf);
|
||||
min_iov.iov_base = buf;
|
||||
min_iov.iov_len = size = sizeof(buf);
|
||||
iovcnt = 1;
|
||||
iov = &min_iov;
|
||||
iov_ofs = 0;
|
||||
} else if (iov->iov_len < maximum_ethernet_hdr_len) {
|
||||
/* This is very unlikely, but may happen. */
|
||||
iov_to_buf(iov, iovcnt, iov_ofs, min_buf, maximum_ethernet_hdr_len);
|
||||
filter_buf = min_buf;
|
||||
} else {
|
||||
iov_to_buf(iov, iovcnt, iov_ofs, buf, ETH_HLEN + 4);
|
||||
}
|
||||
|
||||
/* Discard oversized packets if !LPE and !SBP. */
|
||||
@@ -1754,9 +1733,9 @@ e1000e_receive_internal(E1000ECore *core, const struct iovec *iov, int iovcnt,
|
||||
}
|
||||
|
||||
net_rx_pkt_set_packet_type(core->rx_pkt,
|
||||
get_eth_packet_type(PKT_GET_ETH_HDR(filter_buf)));
|
||||
get_eth_packet_type(PKT_GET_ETH_HDR(buf)));
|
||||
|
||||
if (!e1000e_receive_filter(core, filter_buf, size)) {
|
||||
if (!e1000e_receive_filter(core, buf, size)) {
|
||||
trace_e1000e_rx_flt_dropped();
|
||||
return orig_size;
|
||||
}
|
||||
|
||||
+20
-8
@@ -80,7 +80,6 @@ bool e1000x_rx_group_filter(uint32_t *mac, const uint8_t *buf)
|
||||
f = mta_shift[(rctl >> E1000_RCTL_MO_SHIFT) & 3];
|
||||
f = (((buf[5] << 8) | buf[4]) >> f) & 0xfff;
|
||||
if (mac[MTA + (f >> 5)] & (1 << (f & 0x1f))) {
|
||||
e1000x_inc_reg_if_not_full(mac, MPRC);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -212,23 +211,36 @@ e1000x_rxbufsize(uint32_t rctl)
|
||||
|
||||
void
|
||||
e1000x_update_rx_total_stats(uint32_t *mac,
|
||||
size_t data_size,
|
||||
size_t data_fcs_size)
|
||||
eth_pkt_types_e pkt_type,
|
||||
size_t pkt_size,
|
||||
size_t pkt_fcs_size)
|
||||
{
|
||||
static const int PRCregs[6] = { PRC64, PRC127, PRC255, PRC511,
|
||||
PRC1023, PRC1522 };
|
||||
|
||||
e1000x_increase_size_stats(mac, PRCregs, data_fcs_size);
|
||||
e1000x_increase_size_stats(mac, PRCregs, pkt_fcs_size);
|
||||
e1000x_inc_reg_if_not_full(mac, TPR);
|
||||
mac[GPRC] = mac[TPR];
|
||||
e1000x_inc_reg_if_not_full(mac, GPRC);
|
||||
/* TOR - Total Octets Received:
|
||||
* This register includes bytes received in a packet from the <Destination
|
||||
* Address> field through the <CRC> field, inclusively.
|
||||
* Always include FCS length (4) in size.
|
||||
*/
|
||||
e1000x_grow_8reg_if_not_full(mac, TORL, data_size + 4);
|
||||
mac[GORCL] = mac[TORL];
|
||||
mac[GORCH] = mac[TORH];
|
||||
e1000x_grow_8reg_if_not_full(mac, TORL, pkt_size + 4);
|
||||
e1000x_grow_8reg_if_not_full(mac, GORCL, pkt_size + 4);
|
||||
|
||||
switch (pkt_type) {
|
||||
case ETH_PKT_BCAST:
|
||||
e1000x_inc_reg_if_not_full(mac, BPRC);
|
||||
break;
|
||||
|
||||
case ETH_PKT_MCAST:
|
||||
e1000x_inc_reg_if_not_full(mac, MPRC);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -91,8 +91,9 @@ e1000x_update_regs_on_link_up(uint32_t *mac, uint16_t *phy)
|
||||
}
|
||||
|
||||
void e1000x_update_rx_total_stats(uint32_t *mac,
|
||||
size_t data_size,
|
||||
size_t data_fcs_size);
|
||||
eth_pkt_types_e pkt_type,
|
||||
size_t pkt_size,
|
||||
size_t pkt_fcs_size);
|
||||
|
||||
void e1000x_core_prepare_eeprom(uint16_t *eeprom,
|
||||
const uint16_t *templ,
|
||||
|
||||
+56
-66
@@ -67,6 +67,11 @@ typedef struct IGBTxPktVmdqCallbackContext {
|
||||
NetClientState *nc;
|
||||
} IGBTxPktVmdqCallbackContext;
|
||||
|
||||
typedef struct L2Header {
|
||||
struct eth_header eth;
|
||||
struct vlan_header vlan;
|
||||
} L2Header;
|
||||
|
||||
static ssize_t
|
||||
igb_receive_internal(IGBCore *core, const struct iovec *iov, int iovcnt,
|
||||
bool has_vnet, bool *external_tx);
|
||||
@@ -402,7 +407,7 @@ igb_tx_insert_vlan(IGBCore *core, uint16_t qn, struct igb_tx *tx,
|
||||
}
|
||||
}
|
||||
|
||||
if (insert_vlan && e1000x_vlan_enabled(core->mac)) {
|
||||
if (insert_vlan) {
|
||||
net_tx_pkt_setup_vlan_header_ex(tx->tx_pkt, vlan,
|
||||
core->mac[VET] & 0xffff);
|
||||
}
|
||||
@@ -538,9 +543,8 @@ igb_on_tx_done_update_stats(IGBCore *core, struct NetTxPkt *tx_pkt, int qn)
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
core->mac[GPTC] = core->mac[TPT];
|
||||
core->mac[GOTCL] = core->mac[TOTL];
|
||||
core->mac[GOTCH] = core->mac[TOTH];
|
||||
e1000x_inc_reg_if_not_full(core->mac, GPTC);
|
||||
e1000x_grow_8reg_if_not_full(core->mac, GOTCL, tot_len);
|
||||
|
||||
if (core->mac[MRQC] & 1) {
|
||||
uint16_t pool = qn % IGB_NUM_VM_POOLS;
|
||||
@@ -961,15 +965,16 @@ igb_rx_is_oversized(IGBCore *core, uint16_t qn, size_t size)
|
||||
return size > (lpe ? max_ethernet_lpe_size : max_ethernet_vlan_size);
|
||||
}
|
||||
|
||||
static uint16_t igb_receive_assign(IGBCore *core, const struct eth_header *ehdr,
|
||||
static uint16_t igb_receive_assign(IGBCore *core, const L2Header *l2_header,
|
||||
size_t size, E1000E_RSSInfo *rss_info,
|
||||
bool *external_tx)
|
||||
{
|
||||
static const int ta_shift[] = { 4, 3, 2, 0 };
|
||||
const struct eth_header *ehdr = &l2_header->eth;
|
||||
uint32_t f, ra[2], *macp, rctl = core->mac[RCTL];
|
||||
uint16_t queues = 0;
|
||||
uint16_t oversized = 0;
|
||||
uint16_t vid = lduw_be_p(&PKT_GET_VLAN_HDR(ehdr)->h_tci) & VLAN_VID_MASK;
|
||||
uint16_t vid = be16_to_cpu(l2_header->vlan.h_tci) & VLAN_VID_MASK;
|
||||
bool accepted = false;
|
||||
int i;
|
||||
|
||||
@@ -1227,7 +1232,6 @@ igb_build_rx_metadata(IGBCore *core,
|
||||
struct virtio_net_hdr *vhdr;
|
||||
bool hasip4, hasip6;
|
||||
EthL4HdrProto l4hdr_proto;
|
||||
uint32_t pkt_type;
|
||||
|
||||
*status_flags = E1000_RXD_STAT_DD;
|
||||
|
||||
@@ -1266,28 +1270,29 @@ igb_build_rx_metadata(IGBCore *core,
|
||||
trace_e1000e_rx_metadata_ack();
|
||||
}
|
||||
|
||||
if (hasip6 && (core->mac[RFCTL] & E1000_RFCTL_IPV6_DIS)) {
|
||||
trace_e1000e_rx_metadata_ipv6_filtering_disabled();
|
||||
pkt_type = E1000_RXD_PKT_MAC;
|
||||
} else if (l4hdr_proto == ETH_L4_HDR_PROTO_TCP ||
|
||||
l4hdr_proto == ETH_L4_HDR_PROTO_UDP) {
|
||||
pkt_type = hasip4 ? E1000_RXD_PKT_IP4_XDP : E1000_RXD_PKT_IP6_XDP;
|
||||
} else if (hasip4 || hasip6) {
|
||||
pkt_type = hasip4 ? E1000_RXD_PKT_IP4 : E1000_RXD_PKT_IP6;
|
||||
} else {
|
||||
pkt_type = E1000_RXD_PKT_MAC;
|
||||
}
|
||||
|
||||
trace_e1000e_rx_metadata_pkt_type(pkt_type);
|
||||
|
||||
if (pkt_info) {
|
||||
if (rss_info->enabled) {
|
||||
*pkt_info = rss_info->type;
|
||||
*pkt_info = rss_info->enabled ? rss_info->type : 0;
|
||||
|
||||
if (hasip4) {
|
||||
*pkt_info |= E1000_ADVRXD_PKT_IP4;
|
||||
}
|
||||
|
||||
*pkt_info |= (pkt_type << 4);
|
||||
} else {
|
||||
*status_flags |= E1000_RXD_PKT_TYPE(pkt_type);
|
||||
if (hasip6) {
|
||||
*pkt_info |= E1000_ADVRXD_PKT_IP6;
|
||||
}
|
||||
|
||||
switch (l4hdr_proto) {
|
||||
case ETH_L4_HDR_PROTO_TCP:
|
||||
*pkt_info |= E1000_ADVRXD_PKT_TCP;
|
||||
break;
|
||||
|
||||
case ETH_L4_HDR_PROTO_UDP:
|
||||
*pkt_info |= E1000_ADVRXD_PKT_UDP;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hdr_info) {
|
||||
@@ -1438,29 +1443,17 @@ igb_write_to_rx_buffers(IGBCore *core,
|
||||
|
||||
static void
|
||||
igb_update_rx_stats(IGBCore *core, const E1000E_RingInfo *rxi,
|
||||
size_t data_size, size_t data_fcs_size)
|
||||
size_t pkt_size, size_t pkt_fcs_size)
|
||||
{
|
||||
e1000x_update_rx_total_stats(core->mac, data_size, data_fcs_size);
|
||||
|
||||
switch (net_rx_pkt_get_packet_type(core->rx_pkt)) {
|
||||
case ETH_PKT_BCAST:
|
||||
e1000x_inc_reg_if_not_full(core->mac, BPRC);
|
||||
break;
|
||||
|
||||
case ETH_PKT_MCAST:
|
||||
e1000x_inc_reg_if_not_full(core->mac, MPRC);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
eth_pkt_types_e pkt_type = net_rx_pkt_get_packet_type(core->rx_pkt);
|
||||
e1000x_update_rx_total_stats(core->mac, pkt_type, pkt_size, pkt_fcs_size);
|
||||
|
||||
if (core->mac[MRQC] & 1) {
|
||||
uint16_t pool = rxi->idx % IGB_NUM_VM_POOLS;
|
||||
|
||||
core->mac[PVFGORC0 + (pool * 64)] += data_size + 4;
|
||||
core->mac[PVFGORC0 + (pool * 64)] += pkt_size + 4;
|
||||
core->mac[PVFGPRC0 + (pool * 64)]++;
|
||||
if (net_rx_pkt_get_packet_type(core->rx_pkt) == ETH_PKT_MCAST) {
|
||||
if (pkt_type == ETH_PKT_MCAST) {
|
||||
core->mac[PVFMPRC0 + (pool * 64)]++;
|
||||
}
|
||||
}
|
||||
@@ -1602,14 +1595,13 @@ static ssize_t
|
||||
igb_receive_internal(IGBCore *core, const struct iovec *iov, int iovcnt,
|
||||
bool has_vnet, bool *external_tx)
|
||||
{
|
||||
static const int maximum_ethernet_hdr_len = (ETH_HLEN + 4);
|
||||
|
||||
uint16_t queues = 0;
|
||||
uint32_t n = 0;
|
||||
uint8_t min_buf[ETH_ZLEN];
|
||||
union {
|
||||
L2Header l2_header;
|
||||
uint8_t octets[ETH_ZLEN];
|
||||
} buf;
|
||||
struct iovec min_iov;
|
||||
struct eth_header *ehdr;
|
||||
uint8_t *filter_buf;
|
||||
size_t size, orig_size;
|
||||
size_t iov_ofs = 0;
|
||||
E1000E_RxRing rxr;
|
||||
@@ -1635,24 +1627,21 @@ igb_receive_internal(IGBCore *core, const struct iovec *iov, int iovcnt,
|
||||
net_rx_pkt_unset_vhdr(core->rx_pkt);
|
||||
}
|
||||
|
||||
filter_buf = iov->iov_base + iov_ofs;
|
||||
orig_size = iov_size(iov, iovcnt);
|
||||
size = orig_size - iov_ofs;
|
||||
|
||||
/* Pad to minimum Ethernet frame length */
|
||||
if (size < sizeof(min_buf)) {
|
||||
iov_to_buf(iov, iovcnt, iov_ofs, min_buf, size);
|
||||
memset(&min_buf[size], 0, sizeof(min_buf) - size);
|
||||
if (size < sizeof(buf)) {
|
||||
iov_to_buf(iov, iovcnt, iov_ofs, &buf, size);
|
||||
memset(&buf.octets[size], 0, sizeof(buf) - size);
|
||||
e1000x_inc_reg_if_not_full(core->mac, RUC);
|
||||
min_iov.iov_base = filter_buf = min_buf;
|
||||
min_iov.iov_len = size = sizeof(min_buf);
|
||||
min_iov.iov_base = &buf;
|
||||
min_iov.iov_len = size = sizeof(buf);
|
||||
iovcnt = 1;
|
||||
iov = &min_iov;
|
||||
iov_ofs = 0;
|
||||
} else if (iov->iov_len < maximum_ethernet_hdr_len) {
|
||||
/* This is very unlikely, but may happen. */
|
||||
iov_to_buf(iov, iovcnt, iov_ofs, min_buf, maximum_ethernet_hdr_len);
|
||||
filter_buf = min_buf;
|
||||
} else {
|
||||
iov_to_buf(iov, iovcnt, iov_ofs, &buf, sizeof(buf.l2_header));
|
||||
}
|
||||
|
||||
/* Discard oversized packets if !LPE and !SBP. */
|
||||
@@ -1660,11 +1649,12 @@ igb_receive_internal(IGBCore *core, const struct iovec *iov, int iovcnt,
|
||||
return orig_size;
|
||||
}
|
||||
|
||||
ehdr = PKT_GET_ETH_HDR(filter_buf);
|
||||
net_rx_pkt_set_packet_type(core->rx_pkt, get_eth_packet_type(ehdr));
|
||||
net_rx_pkt_set_protocols(core->rx_pkt, filter_buf, size);
|
||||
net_rx_pkt_set_packet_type(core->rx_pkt,
|
||||
get_eth_packet_type(&buf.l2_header.eth));
|
||||
net_rx_pkt_set_protocols(core->rx_pkt, iov, iovcnt, iov_ofs);
|
||||
|
||||
queues = igb_receive_assign(core, ehdr, size, &rss_info, external_tx);
|
||||
queues = igb_receive_assign(core, &buf.l2_header, size,
|
||||
&rss_info, external_tx);
|
||||
if (!queues) {
|
||||
trace_e1000e_rx_flt_dropped();
|
||||
return orig_size;
|
||||
@@ -2464,16 +2454,16 @@ igb_set_ims(IGBCore *core, int index, uint32_t val)
|
||||
static void igb_commit_icr(IGBCore *core)
|
||||
{
|
||||
/*
|
||||
* If GPIE.NSICR = 0, then the copy of IAM to IMS will occur only if at
|
||||
* If GPIE.NSICR = 0, then the clear of IMS will occur only if at
|
||||
* least one bit is set in the IMS and there is a true interrupt as
|
||||
* reflected in ICR.INTA.
|
||||
*/
|
||||
if ((core->mac[GPIE] & E1000_GPIE_NSICR) ||
|
||||
(core->mac[IMS] && (core->mac[ICR] & E1000_ICR_INT_ASSERTED))) {
|
||||
igb_set_ims(core, IMS, core->mac[IAM]);
|
||||
} else {
|
||||
igb_update_interrupt_state(core);
|
||||
igb_clear_ims_bits(core, core->mac[IAM]);
|
||||
}
|
||||
|
||||
igb_update_interrupt_state(core);
|
||||
}
|
||||
|
||||
static void igb_set_icr(IGBCore *core, int index, uint32_t val)
|
||||
|
||||
@@ -641,6 +641,11 @@ union e1000_adv_rx_desc {
|
||||
|
||||
#define E1000_STATUS_NUM_VFS_SHIFT 14
|
||||
|
||||
#define E1000_ADVRXD_PKT_IP4 BIT(4)
|
||||
#define E1000_ADVRXD_PKT_IP6 BIT(6)
|
||||
#define E1000_ADVRXD_PKT_TCP BIT(8)
|
||||
#define E1000_ADVRXD_PKT_UDP BIT(9)
|
||||
|
||||
static inline uint8_t igb_ivar_entry_rx(uint8_t i)
|
||||
{
|
||||
return i < 8 ? i * 4 : (i - 8) * 4 + 2;
|
||||
|
||||
+10
-6
@@ -118,14 +118,18 @@ static void emac_load_desc(MSF2EmacState *s, EmacDesc *d, hwaddr desc)
|
||||
d->next = le32_to_cpu(d->next);
|
||||
}
|
||||
|
||||
static void emac_store_desc(MSF2EmacState *s, EmacDesc *d, hwaddr desc)
|
||||
static void emac_store_desc(MSF2EmacState *s, const EmacDesc *d, hwaddr desc)
|
||||
{
|
||||
/* Convert from host endianness into LE. */
|
||||
d->pktaddr = cpu_to_le32(d->pktaddr);
|
||||
d->pktsize = cpu_to_le32(d->pktsize);
|
||||
d->next = cpu_to_le32(d->next);
|
||||
EmacDesc outd;
|
||||
/*
|
||||
* Convert from host endianness into LE. We use a local struct because
|
||||
* calling code may still want to look at the fields afterwards.
|
||||
*/
|
||||
outd.pktaddr = cpu_to_le32(d->pktaddr);
|
||||
outd.pktsize = cpu_to_le32(d->pktsize);
|
||||
outd.next = cpu_to_le32(d->next);
|
||||
|
||||
address_space_write(&s->dma_as, desc, MEMTXATTRS_UNSPECIFIED, d, sizeof *d);
|
||||
address_space_write(&s->dma_as, desc, MEMTXATTRS_UNSPECIFIED, &outd, sizeof outd);
|
||||
}
|
||||
|
||||
static void msf2_dma_tx(MSF2EmacState *s)
|
||||
|
||||
+5
-9
@@ -103,7 +103,7 @@ net_rx_pkt_pull_data(struct NetRxPkt *pkt,
|
||||
iov, iovcnt, ploff, pkt->tot_len);
|
||||
}
|
||||
|
||||
eth_get_protocols(pkt->vec, pkt->vec_len, &pkt->hasip4, &pkt->hasip6,
|
||||
eth_get_protocols(pkt->vec, pkt->vec_len, 0, &pkt->hasip4, &pkt->hasip6,
|
||||
&pkt->l3hdr_off, &pkt->l4hdr_off, &pkt->l5hdr_off,
|
||||
&pkt->ip6hdr_info, &pkt->ip4hdr_info, &pkt->l4hdr_info);
|
||||
|
||||
@@ -186,17 +186,13 @@ size_t net_rx_pkt_get_total_len(struct NetRxPkt *pkt)
|
||||
return pkt->tot_len;
|
||||
}
|
||||
|
||||
void net_rx_pkt_set_protocols(struct NetRxPkt *pkt, const void *data,
|
||||
size_t len)
|
||||
void net_rx_pkt_set_protocols(struct NetRxPkt *pkt,
|
||||
const struct iovec *iov, size_t iovcnt,
|
||||
size_t iovoff)
|
||||
{
|
||||
const struct iovec iov = {
|
||||
.iov_base = (void *)data,
|
||||
.iov_len = len
|
||||
};
|
||||
|
||||
assert(pkt);
|
||||
|
||||
eth_get_protocols(&iov, 1, &pkt->hasip4, &pkt->hasip6,
|
||||
eth_get_protocols(iov, iovcnt, iovoff, &pkt->hasip4, &pkt->hasip6,
|
||||
&pkt->l3hdr_off, &pkt->l4hdr_off, &pkt->l5hdr_off,
|
||||
&pkt->ip6hdr_info, &pkt->ip4hdr_info, &pkt->l4hdr_info);
|
||||
}
|
||||
|
||||
+6
-4
@@ -55,12 +55,14 @@ size_t net_rx_pkt_get_total_len(struct NetRxPkt *pkt);
|
||||
* parse and set packet analysis results
|
||||
*
|
||||
* @pkt: packet
|
||||
* @data: pointer to the data buffer to be parsed
|
||||
* @len: data length
|
||||
* @iov: received data scatter-gather list
|
||||
* @iovcnt: number of elements in iov
|
||||
* @iovoff: data start offset in the iov
|
||||
*
|
||||
*/
|
||||
void net_rx_pkt_set_protocols(struct NetRxPkt *pkt, const void *data,
|
||||
size_t len);
|
||||
void net_rx_pkt_set_protocols(struct NetRxPkt *pkt,
|
||||
const struct iovec *iov, size_t iovcnt,
|
||||
size_t iovoff);
|
||||
|
||||
/**
|
||||
* fetches packet analysis results
|
||||
|
||||
@@ -2154,6 +2154,9 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
|
||||
|
||||
int large_send_mss = (txdw0 >> CP_TC_LGSEN_MSS_SHIFT) &
|
||||
CP_TC_LGSEN_MSS_MASK;
|
||||
if (large_send_mss == 0) {
|
||||
goto skip_offload;
|
||||
}
|
||||
|
||||
DPRINTF("+++ C+ mode offloaded task TSO IP data %d "
|
||||
"frame data %d specified MSS=%d\n",
|
||||
|
||||
+5
-3
@@ -805,7 +805,6 @@ static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features,
|
||||
}
|
||||
|
||||
if (!get_vhost_net(nc->peer)) {
|
||||
virtio_add_feature(&features, VIRTIO_F_RING_RESET);
|
||||
return features;
|
||||
}
|
||||
|
||||
@@ -1835,9 +1834,12 @@ static int virtio_net_process_rss(NetClientState *nc, const uint8_t *buf,
|
||||
VIRTIO_NET_HASH_REPORT_UDPv6,
|
||||
VIRTIO_NET_HASH_REPORT_UDPv6_EX
|
||||
};
|
||||
struct iovec iov = {
|
||||
.iov_base = (void *)buf,
|
||||
.iov_len = size
|
||||
};
|
||||
|
||||
net_rx_pkt_set_protocols(pkt, buf + n->host_hdr_len,
|
||||
size - n->host_hdr_len);
|
||||
net_rx_pkt_set_protocols(pkt, &iov, 1, n->host_hdr_len);
|
||||
net_rx_pkt_get_protocols(pkt, &hasip4, &hasip6, &l4hdr_proto);
|
||||
net_hash_type = virtio_net_get_hash_type(hasip4, hasip6, l4hdr_proto,
|
||||
n->rss_data.hash_types);
|
||||
|
||||
+6
-1
@@ -2001,7 +2001,12 @@ vmxnet3_receive(NetClientState *nc, const uint8_t *buf, size_t size)
|
||||
get_eth_packet_type(PKT_GET_ETH_HDR(buf)));
|
||||
|
||||
if (vmxnet3_rx_filter_may_indicate(s, buf, size)) {
|
||||
net_rx_pkt_set_protocols(s->rx_pkt, buf, size);
|
||||
struct iovec iov = {
|
||||
.iov_base = (void *)buf,
|
||||
.iov_len = size
|
||||
};
|
||||
|
||||
net_rx_pkt_set_protocols(s->rx_pkt, &iov, 1, 0);
|
||||
vmxnet3_rx_need_csum_calculate(s->rx_pkt, buf, size);
|
||||
net_rx_pkt_attach_data(s->rx_pkt, buf, size, s->rx_vlan_stripping);
|
||||
bytes_indicated = vmxnet3_indicate_packet(s) ? size : -1;
|
||||
|
||||
@@ -311,7 +311,7 @@ static void pxb_cxl_dev_reset(DeviceState *dev)
|
||||
* The CXL specification allows for host bridges with no HDM decoders
|
||||
* if they only have a single root port.
|
||||
*/
|
||||
if (!PXB_DEV(dev)->hdm_for_passthrough) {
|
||||
if (!PXB_CXL_DEV(dev)->hdm_for_passthrough) {
|
||||
dsp_count = pcie_count_ds_ports(hb->bus);
|
||||
}
|
||||
/* Initial reset will have 0 dsp so wait until > 0 */
|
||||
|
||||
@@ -79,6 +79,8 @@ static Property pci_props[] = {
|
||||
DEFINE_PROP_STRING("failover_pair_id", PCIDevice,
|
||||
failover_pair_id),
|
||||
DEFINE_PROP_UINT32("acpi-index", PCIDevice, acpi_index, 0),
|
||||
DEFINE_PROP_BIT("x-pcie-err-unc-mask", PCIDevice, cap_present,
|
||||
QEMU_PCIE_ERR_UNC_MASK_BITNR, true),
|
||||
DEFINE_PROP_END_OF_LIST()
|
||||
};
|
||||
|
||||
|
||||
+7
-4
@@ -112,10 +112,13 @@ int pcie_aer_init(PCIDevice *dev, uint8_t cap_ver, uint16_t offset,
|
||||
|
||||
pci_set_long(dev->w1cmask + offset + PCI_ERR_UNCOR_STATUS,
|
||||
PCI_ERR_UNC_SUPPORTED);
|
||||
pci_set_long(dev->config + offset + PCI_ERR_UNCOR_MASK,
|
||||
PCI_ERR_UNC_MASK_DEFAULT);
|
||||
pci_set_long(dev->wmask + offset + PCI_ERR_UNCOR_MASK,
|
||||
PCI_ERR_UNC_SUPPORTED);
|
||||
|
||||
if (dev->cap_present & QEMU_PCIE_ERR_UNC_MASK) {
|
||||
pci_set_long(dev->config + offset + PCI_ERR_UNCOR_MASK,
|
||||
PCI_ERR_UNC_MASK_DEFAULT);
|
||||
pci_set_long(dev->wmask + offset + PCI_ERR_UNCOR_MASK,
|
||||
PCI_ERR_UNC_SUPPORTED);
|
||||
}
|
||||
|
||||
pci_set_long(dev->config + offset + PCI_ERR_UNCOR_SEVER,
|
||||
PCI_ERR_UNC_SEVERITY_DEFAULT);
|
||||
|
||||
+8
-2
@@ -13,6 +13,7 @@
|
||||
|
||||
#include <linux/kvm.h>
|
||||
|
||||
#include "qemu/units.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "sysemu/kvm.h"
|
||||
@@ -115,7 +116,7 @@ static void *s390_pv_do_unprot_async_fn(void *p)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool s390_pv_vm_try_disable_async(void)
|
||||
bool s390_pv_vm_try_disable_async(S390CcwMachineState *ms)
|
||||
{
|
||||
/*
|
||||
* t is only needed to create the thread; once qemu_thread_create
|
||||
@@ -123,7 +124,12 @@ bool s390_pv_vm_try_disable_async(void)
|
||||
*/
|
||||
QemuThread t;
|
||||
|
||||
if (!kvm_check_extension(kvm_state, KVM_CAP_S390_PROTECTED_ASYNC_DISABLE)) {
|
||||
/*
|
||||
* If the feature is not present or if the VM is not larger than 2 GiB,
|
||||
* KVM_PV_ASYNC_CLEANUP_PREPARE fill fail; no point in attempting it.
|
||||
*/
|
||||
if ((MACHINE(ms)->maxram_size <= 2 * GiB) ||
|
||||
!kvm_check_extension(kvm_state, KVM_CAP_S390_PROTECTED_ASYNC_DISABLE)) {
|
||||
return false;
|
||||
}
|
||||
if (s390_pv_cmd(KVM_PV_ASYNC_CLEANUP_PREPARE, NULL) != 0) {
|
||||
|
||||
@@ -330,7 +330,7 @@ static inline void s390_do_cpu_ipl(CPUState *cs, run_on_cpu_data arg)
|
||||
|
||||
static void s390_machine_unprotect(S390CcwMachineState *ms)
|
||||
{
|
||||
if (!s390_pv_vm_try_disable_async()) {
|
||||
if (!s390_pv_vm_try_disable_async(ms)) {
|
||||
s390_pv_vm_disable();
|
||||
}
|
||||
ms->pv = false;
|
||||
|
||||
+17
-6
@@ -1134,15 +1134,24 @@ static void lsi_execute_script(LSIState *s)
|
||||
uint32_t addr, addr_high;
|
||||
int opcode;
|
||||
int insn_processed = 0;
|
||||
static int reentrancy_level;
|
||||
|
||||
reentrancy_level++;
|
||||
|
||||
s->istat1 |= LSI_ISTAT1_SRUN;
|
||||
again:
|
||||
if (++insn_processed > LSI_MAX_INSN) {
|
||||
/* Some windows drivers make the device spin waiting for a memory
|
||||
location to change. If we have been executed a lot of code then
|
||||
assume this is the case and force an unexpected device disconnect.
|
||||
This is apparently sufficient to beat the drivers into submission.
|
||||
*/
|
||||
/*
|
||||
* Some windows drivers make the device spin waiting for a memory location
|
||||
* to change. If we have executed more than LSI_MAX_INSN instructions then
|
||||
* assume this is the case and force an unexpected device disconnect. This
|
||||
* is apparently sufficient to beat the drivers into submission.
|
||||
*
|
||||
* Another issue (CVE-2023-0330) can occur if the script is programmed to
|
||||
* trigger itself again and again. Avoid this problem by stopping after
|
||||
* being called multiple times in a reentrant way (8 is an arbitrary value
|
||||
* which should be enough for all valid use cases).
|
||||
*/
|
||||
if (++insn_processed > LSI_MAX_INSN || reentrancy_level > 8) {
|
||||
if (!(s->sien0 & LSI_SIST0_UDC)) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"lsi_scsi: inf. loop with UDC masked");
|
||||
@@ -1596,6 +1605,8 @@ again:
|
||||
}
|
||||
}
|
||||
trace_lsi_execute_script_stop();
|
||||
|
||||
reentrancy_level--;
|
||||
}
|
||||
|
||||
static uint8_t lsi_reg_readb(LSIState *s, int offset)
|
||||
|
||||
@@ -191,12 +191,16 @@ static int scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s, int len)
|
||||
if ((s->type == TYPE_DISK || s->type == TYPE_ZBC) &&
|
||||
(r->req.cmd.buf[1] & 0x01)) {
|
||||
page = r->req.cmd.buf[2];
|
||||
if (page == 0xb0) {
|
||||
if (page == 0xb0 && r->buflen >= 8) {
|
||||
uint8_t buf[16] = {};
|
||||
uint8_t buf_used = MIN(r->buflen, 16);
|
||||
uint64_t max_transfer = calculate_max_transfer(s);
|
||||
stl_be_p(&r->buf[8], max_transfer);
|
||||
/* Also take care of the opt xfer len. */
|
||||
stl_be_p(&r->buf[12],
|
||||
MIN_NON_ZERO(max_transfer, ldl_be_p(&r->buf[12])));
|
||||
|
||||
memcpy(buf, r->buf, buf_used);
|
||||
stl_be_p(&buf[8], max_transfer);
|
||||
stl_be_p(&buf[12], MIN_NON_ZERO(max_transfer, ldl_be_p(&buf[12])));
|
||||
memcpy(r->buf + 8, buf + 8, buf_used - 8);
|
||||
|
||||
} else if (s->needs_vpd_bl_emulation && page == 0x00 && r->buflen >= 4) {
|
||||
/*
|
||||
* Now we're capable of supplying the VPD Block Limits
|
||||
|
||||
@@ -302,6 +302,30 @@ static void allwinner_sdhost_auto_stop(AwSdHostState *s)
|
||||
}
|
||||
}
|
||||
|
||||
static void read_descriptor(AwSdHostState *s, hwaddr desc_addr,
|
||||
TransferDescriptor *desc)
|
||||
{
|
||||
uint32_t desc_words[4];
|
||||
dma_memory_read(&s->dma_as, desc_addr, &desc_words, sizeof(desc_words),
|
||||
MEMTXATTRS_UNSPECIFIED);
|
||||
desc->status = le32_to_cpu(desc_words[0]);
|
||||
desc->size = le32_to_cpu(desc_words[1]);
|
||||
desc->addr = le32_to_cpu(desc_words[2]);
|
||||
desc->next = le32_to_cpu(desc_words[3]);
|
||||
}
|
||||
|
||||
static void write_descriptor(AwSdHostState *s, hwaddr desc_addr,
|
||||
const TransferDescriptor *desc)
|
||||
{
|
||||
uint32_t desc_words[4];
|
||||
desc_words[0] = cpu_to_le32(desc->status);
|
||||
desc_words[1] = cpu_to_le32(desc->size);
|
||||
desc_words[2] = cpu_to_le32(desc->addr);
|
||||
desc_words[3] = cpu_to_le32(desc->next);
|
||||
dma_memory_write(&s->dma_as, desc_addr, &desc_words, sizeof(desc_words),
|
||||
MEMTXATTRS_UNSPECIFIED);
|
||||
}
|
||||
|
||||
static uint32_t allwinner_sdhost_process_desc(AwSdHostState *s,
|
||||
hwaddr desc_addr,
|
||||
TransferDescriptor *desc,
|
||||
@@ -312,9 +336,7 @@ static uint32_t allwinner_sdhost_process_desc(AwSdHostState *s,
|
||||
uint32_t num_bytes = max_bytes;
|
||||
uint8_t buf[1024];
|
||||
|
||||
/* Read descriptor */
|
||||
dma_memory_read(&s->dma_as, desc_addr, desc, sizeof(*desc),
|
||||
MEMTXATTRS_UNSPECIFIED);
|
||||
read_descriptor(s, desc_addr, desc);
|
||||
if (desc->size == 0) {
|
||||
desc->size = klass->max_desc_size;
|
||||
} else if (desc->size > klass->max_desc_size) {
|
||||
@@ -356,8 +378,7 @@ static uint32_t allwinner_sdhost_process_desc(AwSdHostState *s,
|
||||
|
||||
/* Clear hold flag and flush descriptor */
|
||||
desc->status &= ~DESC_STATUS_HOLD;
|
||||
dma_memory_write(&s->dma_as, desc_addr, desc, sizeof(*desc),
|
||||
MEMTXATTRS_UNSPECIFIED);
|
||||
write_descriptor(s, desc_addr, desc);
|
||||
|
||||
return num_done;
|
||||
}
|
||||
|
||||
+1
-1
@@ -179,7 +179,7 @@ static void imx_epit_update_compare_timer(IMXEPITState *s)
|
||||
* the compare value. Otherwise it may fire at most once in the
|
||||
* current round.
|
||||
*/
|
||||
bool is_oneshot = (limit >= s->cmp);
|
||||
is_oneshot = (limit < s->cmp);
|
||||
if (counter >= s->cmp) {
|
||||
/* The compare timer fires in the current round. */
|
||||
counter -= s->cmp;
|
||||
|
||||
@@ -1239,6 +1239,8 @@ static void ohci_frame_boundary(void *opaque)
|
||||
/* Increment frame number and take care of endianness. */
|
||||
ohci->frame_number = (ohci->frame_number + 1) & 0xffff;
|
||||
hcca.frame = cpu_to_le16(ohci->frame_number);
|
||||
/* When the HC updates frame number, set pad to 0. Ref OHCI Spec 4.4.1*/
|
||||
hcca.pad = 0;
|
||||
|
||||
if (ohci->done_count == 0 && !(ohci->intr_status & OHCI_INTR_WD)) {
|
||||
if (!ohci->done) {
|
||||
|
||||
@@ -68,7 +68,7 @@ bool vhost_svq_valid_features(uint64_t features, Error **errp)
|
||||
*/
|
||||
static uint16_t vhost_svq_available_slots(const VhostShadowVirtqueue *svq)
|
||||
{
|
||||
return svq->vring.num - (svq->shadow_avail_idx - svq->shadow_used_idx);
|
||||
return svq->num_free;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -263,6 +263,7 @@ int vhost_svq_add(VhostShadowVirtqueue *svq, const struct iovec *out_sg,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
svq->num_free -= ndescs;
|
||||
svq->desc_state[qemu_head].elem = elem;
|
||||
svq->desc_state[qemu_head].ndescs = ndescs;
|
||||
vhost_svq_kick(svq);
|
||||
@@ -449,6 +450,7 @@ static VirtQueueElement *vhost_svq_get_buf(VhostShadowVirtqueue *svq,
|
||||
last_used_chain = vhost_svq_last_desc_of_chain(svq, num, used_elem.id);
|
||||
svq->desc_next[last_used_chain] = svq->free_head;
|
||||
svq->free_head = used_elem.id;
|
||||
svq->num_free += num;
|
||||
|
||||
*len = used_elem.len;
|
||||
return g_steal_pointer(&svq->desc_state[used_elem.id].elem);
|
||||
@@ -659,6 +661,7 @@ void vhost_svq_start(VhostShadowVirtqueue *svq, VirtIODevice *vdev,
|
||||
svq->iova_tree = iova_tree;
|
||||
|
||||
svq->vring.num = virtio_queue_get_num(vdev, virtio_get_queue_index(vq));
|
||||
svq->num_free = svq->vring.num;
|
||||
driver_size = vhost_svq_driver_area_size(svq);
|
||||
device_size = vhost_svq_device_area_size(svq);
|
||||
svq->vring.desc = qemu_memalign(qemu_real_host_page_size(), driver_size);
|
||||
|
||||
@@ -107,6 +107,9 @@ typedef struct VhostShadowVirtqueue {
|
||||
|
||||
/* Next head to consume from the device */
|
||||
uint16_t last_used_idx;
|
||||
|
||||
/* Size of SVQ vring free descriptors */
|
||||
uint16_t num_free;
|
||||
} VhostShadowVirtqueue;
|
||||
|
||||
bool vhost_svq_valid_features(uint64_t features, Error **errp);
|
||||
|
||||
@@ -476,15 +476,17 @@ static void virtio_crypto_free_request(VirtIOCryptoReq *req)
|
||||
size_t max_len;
|
||||
CryptoDevBackendSymOpInfo *op_info = req->op_info.u.sym_op_info;
|
||||
|
||||
max_len = op_info->iv_len +
|
||||
op_info->aad_len +
|
||||
op_info->src_len +
|
||||
op_info->dst_len +
|
||||
op_info->digest_result_len;
|
||||
if (op_info) {
|
||||
max_len = op_info->iv_len +
|
||||
op_info->aad_len +
|
||||
op_info->src_len +
|
||||
op_info->dst_len +
|
||||
op_info->digest_result_len;
|
||||
|
||||
/* Zeroize and free request data structure */
|
||||
memset(op_info, 0, sizeof(*op_info) + max_len);
|
||||
g_free(op_info);
|
||||
/* Zeroize and free request data structure */
|
||||
memset(op_info, 0, sizeof(*op_info) + max_len);
|
||||
g_free(op_info);
|
||||
}
|
||||
} else if (req->flags == QCRYPTODEV_BACKEND_ALG_ASYM) {
|
||||
CryptoDevBackendAsymOpInfo *op_info = req->op_info.u.asym_op_info;
|
||||
if (op_info) {
|
||||
|
||||
@@ -666,7 +666,7 @@ VirtioDeviceFeatures *qmp_decode_features(uint16_t device_id, uint64_t bitmap)
|
||||
VirtioInfoList *qmp_x_query_virtio(Error **errp)
|
||||
{
|
||||
VirtioInfoList *list = NULL;
|
||||
VirtioInfoList *node;
|
||||
VirtioInfo *node;
|
||||
VirtIODevice *vdev;
|
||||
|
||||
QTAILQ_FOREACH(vdev, &virtio_list, next) {
|
||||
@@ -680,11 +680,10 @@ VirtioInfoList *qmp_x_query_virtio(Error **errp)
|
||||
if (!strncmp(is_realized->str, "false", 4)) {
|
||||
QTAILQ_REMOVE(&virtio_list, vdev, next);
|
||||
} else {
|
||||
node = g_new0(VirtioInfoList, 1);
|
||||
node->value = g_new(VirtioInfo, 1);
|
||||
node->value->path = g_strdup(dev->canonical_path);
|
||||
node->value->name = g_strdup(vdev->name);
|
||||
QAPI_LIST_PREPEND(list, node->value);
|
||||
node = g_new(VirtioInfo, 1);
|
||||
node->path = g_strdup(dev->canonical_path);
|
||||
node->name = g_strdup(vdev->name);
|
||||
QAPI_LIST_PREPEND(list, node);
|
||||
}
|
||||
g_string_free(is_realized, true);
|
||||
}
|
||||
|
||||
@@ -166,7 +166,11 @@ int bdrv_amend_options(BlockDriverState *bs_new, QemuOpts *opts,
|
||||
BlockDriverState *check_to_replace_node(BlockDriverState *parent_bs,
|
||||
const char *node_name, Error **errp);
|
||||
|
||||
int bdrv_activate(BlockDriverState *bs, Error **errp);
|
||||
int no_coroutine_fn bdrv_activate(BlockDriverState *bs, Error **errp);
|
||||
|
||||
int coroutine_fn no_co_wrapper
|
||||
bdrv_co_activate(BlockDriverState *bs, Error **errp);
|
||||
|
||||
void bdrv_activate_all(Error **errp);
|
||||
int bdrv_inactivate_all(void);
|
||||
|
||||
@@ -214,7 +218,8 @@ void bdrv_img_create(const char *filename, const char *fmt,
|
||||
bool quiet, Error **errp);
|
||||
|
||||
void bdrv_ref(BlockDriverState *bs);
|
||||
void bdrv_unref(BlockDriverState *bs);
|
||||
void no_coroutine_fn bdrv_unref(BlockDriverState *bs);
|
||||
void coroutine_fn no_co_wrapper bdrv_co_unref(BlockDriverState *bs);
|
||||
void bdrv_unref_child(BlockDriverState *parent, BdrvChild *child);
|
||||
BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
|
||||
BlockDriverState *child_bs,
|
||||
|
||||
@@ -183,4 +183,53 @@ void arm_write_secure_board_setup_dummy_smc(ARMCPU *cpu,
|
||||
const struct arm_boot_info *info,
|
||||
hwaddr mvbar_addr);
|
||||
|
||||
typedef enum {
|
||||
FIXUP_NONE = 0, /* do nothing */
|
||||
FIXUP_TERMINATOR, /* end of insns */
|
||||
FIXUP_BOARDID, /* overwrite with board ID number */
|
||||
FIXUP_BOARD_SETUP, /* overwrite with board specific setup code address */
|
||||
FIXUP_ARGPTR_LO, /* overwrite with pointer to kernel args */
|
||||
FIXUP_ARGPTR_HI, /* overwrite with pointer to kernel args (high half) */
|
||||
FIXUP_ENTRYPOINT_LO, /* overwrite with kernel entry point */
|
||||
FIXUP_ENTRYPOINT_HI, /* overwrite with kernel entry point (high half) */
|
||||
FIXUP_GIC_CPU_IF, /* overwrite with GIC CPU interface address */
|
||||
FIXUP_BOOTREG, /* overwrite with boot register address */
|
||||
FIXUP_DSB, /* overwrite with correct DSB insn for cpu */
|
||||
FIXUP_MAX,
|
||||
} FixupType;
|
||||
|
||||
typedef struct ARMInsnFixup {
|
||||
uint32_t insn;
|
||||
FixupType fixup;
|
||||
} ARMInsnFixup;
|
||||
|
||||
/**
|
||||
* arm_write_bootloader - write a bootloader to guest memory
|
||||
* @name: name of the bootloader blob
|
||||
* @as: AddressSpace to write the bootloader
|
||||
* @addr: guest address to write it
|
||||
* @insns: the blob to be loaded
|
||||
* @fixupcontext: context to be used for any fixups in @insns
|
||||
*
|
||||
* Write a bootloader to guest memory at address @addr in the address
|
||||
* space @as. @name is the name to use for the resulting ROM blob, so
|
||||
* it should be unique in the system and reasonably identifiable for debugging.
|
||||
*
|
||||
* @insns must be an array of ARMInsnFixup structs, each of which has
|
||||
* one 32-bit value to be written to the guest memory, and a fixup to be
|
||||
* applied to the value. FIXUP_NONE (do nothing) is value 0, so effectively
|
||||
* the fixup is optional when writing a struct initializer.
|
||||
* The final entry in the array must be { 0, FIXUP_TERMINATOR }.
|
||||
*
|
||||
* All other supported fixup types have the semantics "ignore insn
|
||||
* and instead use the value from the array element @fixupcontext[fixup]".
|
||||
* The caller should therefore provide @fixupcontext as an array of
|
||||
* size FIXUP_MAX whose elements have been initialized for at least
|
||||
* the entries that @insns refers to.
|
||||
*/
|
||||
void arm_write_bootloader(const char *name,
|
||||
AddressSpace *as, hwaddr addr,
|
||||
const ARMInsnFixup *insns,
|
||||
const uint32_t *fixupcontext);
|
||||
|
||||
#endif /* HW_ARM_BOOT_H */
|
||||
|
||||
@@ -207,6 +207,8 @@ enum {
|
||||
QEMU_PCIE_EXTCAP_INIT = (1 << QEMU_PCIE_EXTCAP_INIT_BITNR),
|
||||
#define QEMU_PCIE_CXL_BITNR 10
|
||||
QEMU_PCIE_CAP_CXL = (1 << QEMU_PCIE_CXL_BITNR),
|
||||
#define QEMU_PCIE_ERR_UNC_MASK_BITNR 11
|
||||
QEMU_PCIE_ERR_UNC_MASK = (1 << QEMU_PCIE_ERR_UNC_MASK_BITNR),
|
||||
};
|
||||
|
||||
typedef struct PCIINTxRoute {
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
|
||||
#include "qapi/error.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "hw/s390x/s390-virtio-ccw.h"
|
||||
|
||||
#ifdef CONFIG_KVM
|
||||
#include "cpu.h"
|
||||
#include "hw/s390x/s390-virtio-ccw.h"
|
||||
|
||||
static inline bool s390_is_pv(void)
|
||||
{
|
||||
@@ -41,7 +41,7 @@ static inline bool s390_is_pv(void)
|
||||
int s390_pv_query_info(void);
|
||||
int s390_pv_vm_enable(void);
|
||||
void s390_pv_vm_disable(void);
|
||||
bool s390_pv_vm_try_disable_async(void);
|
||||
bool s390_pv_vm_try_disable_async(S390CcwMachineState *ms);
|
||||
int s390_pv_set_sec_parms(uint64_t origin, uint64_t length);
|
||||
int s390_pv_unpack(uint64_t addr, uint64_t size, uint64_t tweak);
|
||||
void s390_pv_prep_reset(void);
|
||||
@@ -61,7 +61,7 @@ static inline bool s390_is_pv(void) { return false; }
|
||||
static inline int s390_pv_query_info(void) { return 0; }
|
||||
static inline int s390_pv_vm_enable(void) { return 0; }
|
||||
static inline void s390_pv_vm_disable(void) {}
|
||||
static inline bool s390_pv_vm_try_disable_async(void) { return false; }
|
||||
static inline bool s390_pv_vm_try_disable_async(S390CcwMachineState *ms) { return false; }
|
||||
static inline int s390_pv_set_sec_parms(uint64_t origin, uint64_t length) { return 0; }
|
||||
static inline int s390_pv_unpack(uint64_t addr, uint64_t size, uint64_t tweak) { return 0; }
|
||||
static inline void s390_pv_prep_reset(void) {}
|
||||
|
||||
@@ -757,6 +757,16 @@ void qio_channel_detach_aio_context(QIOChannel *ioc);
|
||||
void coroutine_fn qio_channel_yield(QIOChannel *ioc,
|
||||
GIOCondition condition);
|
||||
|
||||
/**
|
||||
* qio_channel_wake_read:
|
||||
* @ioc: the channel object
|
||||
*
|
||||
* If qio_channel_yield() is currently waiting for the channel to become
|
||||
* readable, interrupt it and reenter immediately. This function is safe to call
|
||||
* from any thread.
|
||||
*/
|
||||
void qio_channel_wake_read(QIOChannel *ioc);
|
||||
|
||||
/**
|
||||
* qio_channel_wait:
|
||||
* @ioc: the channel object
|
||||
|
||||
+3
-3
@@ -312,10 +312,10 @@ eth_get_l2_hdr_length(const void *p)
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
eth_get_l2_hdr_length_iov(const struct iovec *iov, int iovcnt)
|
||||
eth_get_l2_hdr_length_iov(const struct iovec *iov, size_t iovcnt, size_t iovoff)
|
||||
{
|
||||
uint8_t p[sizeof(struct eth_header) + sizeof(struct vlan_header)];
|
||||
size_t copied = iov_to_buf(iov, iovcnt, 0, p, ARRAY_SIZE(p));
|
||||
size_t copied = iov_to_buf(iov, iovcnt, iovoff, p, ARRAY_SIZE(p));
|
||||
|
||||
if (copied < ARRAY_SIZE(p)) {
|
||||
return copied;
|
||||
@@ -397,7 +397,7 @@ typedef struct eth_l4_hdr_info_st {
|
||||
bool has_tcp_data;
|
||||
} eth_l4_hdr_info;
|
||||
|
||||
void eth_get_protocols(const struct iovec *iov, int iovcnt,
|
||||
void eth_get_protocols(const struct iovec *iov, size_t iovcnt, size_t iovoff,
|
||||
bool *hasip4, bool *hasip6,
|
||||
size_t *l3hdr_off,
|
||||
size_t *l4hdr_off,
|
||||
|
||||
@@ -42,7 +42,10 @@ blk_co_new_open(const char *filename, const char *reference, QDict *options,
|
||||
|
||||
int blk_get_refcnt(BlockBackend *blk);
|
||||
void blk_ref(BlockBackend *blk);
|
||||
void blk_unref(BlockBackend *blk);
|
||||
|
||||
void no_coroutine_fn blk_unref(BlockBackend *blk);
|
||||
void coroutine_fn no_co_wrapper blk_co_unref(BlockBackend *blk);
|
||||
|
||||
void blk_remove_all_bs(void);
|
||||
BlockBackend *blk_by_name(const char *name);
|
||||
BlockBackend *blk_next(BlockBackend *blk);
|
||||
|
||||
+27
-6
@@ -19,6 +19,7 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "block/aio-wait.h"
|
||||
#include "io/channel.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/main-loop.h"
|
||||
@@ -514,7 +515,11 @@ int qio_channel_flush(QIOChannel *ioc,
|
||||
static void qio_channel_restart_read(void *opaque)
|
||||
{
|
||||
QIOChannel *ioc = opaque;
|
||||
Coroutine *co = ioc->read_coroutine;
|
||||
Coroutine *co = qatomic_xchg(&ioc->read_coroutine, NULL);
|
||||
|
||||
if (!co) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Assert that aio_co_wake() reenters the coroutine directly */
|
||||
assert(qemu_get_current_aio_context() ==
|
||||
@@ -525,7 +530,11 @@ static void qio_channel_restart_read(void *opaque)
|
||||
static void qio_channel_restart_write(void *opaque)
|
||||
{
|
||||
QIOChannel *ioc = opaque;
|
||||
Coroutine *co = ioc->write_coroutine;
|
||||
Coroutine *co = qatomic_xchg(&ioc->write_coroutine, NULL);
|
||||
|
||||
if (!co) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Assert that aio_co_wake() reenters the coroutine directly */
|
||||
assert(qemu_get_current_aio_context() ==
|
||||
@@ -568,7 +577,11 @@ void qio_channel_detach_aio_context(QIOChannel *ioc)
|
||||
void coroutine_fn qio_channel_yield(QIOChannel *ioc,
|
||||
GIOCondition condition)
|
||||
{
|
||||
AioContext *ioc_ctx = ioc->ctx ?: qemu_get_aio_context();
|
||||
|
||||
assert(qemu_in_coroutine());
|
||||
assert(in_aio_context_home_thread(ioc_ctx));
|
||||
|
||||
if (condition == G_IO_IN) {
|
||||
assert(!ioc->read_coroutine);
|
||||
ioc->read_coroutine = qemu_coroutine_self();
|
||||
@@ -580,18 +593,26 @@ void coroutine_fn qio_channel_yield(QIOChannel *ioc,
|
||||
}
|
||||
qio_channel_set_aio_fd_handlers(ioc);
|
||||
qemu_coroutine_yield();
|
||||
assert(in_aio_context_home_thread(ioc_ctx));
|
||||
|
||||
/* Allow interrupting the operation by reentering the coroutine other than
|
||||
* through the aio_fd_handlers. */
|
||||
if (condition == G_IO_IN && ioc->read_coroutine) {
|
||||
ioc->read_coroutine = NULL;
|
||||
if (condition == G_IO_IN) {
|
||||
assert(ioc->read_coroutine == NULL);
|
||||
qio_channel_set_aio_fd_handlers(ioc);
|
||||
} else if (condition == G_IO_OUT && ioc->write_coroutine) {
|
||||
ioc->write_coroutine = NULL;
|
||||
} else if (condition == G_IO_OUT) {
|
||||
assert(ioc->write_coroutine == NULL);
|
||||
qio_channel_set_aio_fd_handlers(ioc);
|
||||
}
|
||||
}
|
||||
|
||||
void qio_channel_wake_read(QIOChannel *ioc)
|
||||
{
|
||||
Coroutine *co = qatomic_xchg(&ioc->read_coroutine, NULL);
|
||||
if (co) {
|
||||
aio_co_wake(co);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean qio_channel_wait_complete(QIOChannel *ioc,
|
||||
GIOCondition condition,
|
||||
|
||||
@@ -290,7 +290,10 @@ void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
|
||||
env->CP0_Status |= (1 << CP0St_FR);
|
||||
env->hflags |= MIPS_HFLAG_F64;
|
||||
}
|
||||
} else if (!prog_req.fre && !prog_req.frdefault &&
|
||||
} else if (prog_req.fr1) {
|
||||
env->CP0_Status |= (1 << CP0St_FR);
|
||||
env->hflags |= MIPS_HFLAG_F64;
|
||||
} else if (!prog_req.fre && !prog_req.frdefault &&
|
||||
!prog_req.fr1 && !prog_req.single && !prog_req.soft) {
|
||||
fprintf(stderr, "qemu: Can't find a matching FPU mode\n");
|
||||
exit(1);
|
||||
|
||||
+71
-34
@@ -11475,39 +11475,58 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
|
||||
{
|
||||
int gidsetsize = arg1;
|
||||
target_id *target_grouplist;
|
||||
gid_t *grouplist;
|
||||
g_autofree gid_t *grouplist = NULL;
|
||||
int i;
|
||||
|
||||
grouplist = alloca(gidsetsize * sizeof(gid_t));
|
||||
ret = get_errno(getgroups(gidsetsize, grouplist));
|
||||
if (gidsetsize == 0)
|
||||
return ret;
|
||||
if (!is_error(ret)) {
|
||||
target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * sizeof(target_id), 0);
|
||||
if (!target_grouplist)
|
||||
return -TARGET_EFAULT;
|
||||
for(i = 0;i < ret; i++)
|
||||
target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
|
||||
unlock_user(target_grouplist, arg2, gidsetsize * sizeof(target_id));
|
||||
if (gidsetsize > NGROUPS_MAX) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
if (gidsetsize > 0) {
|
||||
grouplist = g_try_new(gid_t, gidsetsize);
|
||||
if (!grouplist) {
|
||||
return -TARGET_ENOMEM;
|
||||
}
|
||||
}
|
||||
ret = get_errno(getgroups(gidsetsize, grouplist));
|
||||
if (!is_error(ret) && gidsetsize > 0) {
|
||||
target_grouplist = lock_user(VERIFY_WRITE, arg2,
|
||||
gidsetsize * sizeof(target_id), 0);
|
||||
if (!target_grouplist) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
for (i = 0; i < ret; i++) {
|
||||
target_grouplist[i] = tswapid(high2lowgid(grouplist[i]));
|
||||
}
|
||||
unlock_user(target_grouplist, arg2,
|
||||
gidsetsize * sizeof(target_id));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
case TARGET_NR_setgroups:
|
||||
{
|
||||
int gidsetsize = arg1;
|
||||
target_id *target_grouplist;
|
||||
gid_t *grouplist = NULL;
|
||||
g_autofree gid_t *grouplist = NULL;
|
||||
int i;
|
||||
if (gidsetsize) {
|
||||
grouplist = alloca(gidsetsize * sizeof(gid_t));
|
||||
target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * sizeof(target_id), 1);
|
||||
|
||||
if (gidsetsize > NGROUPS_MAX || gidsetsize < 0) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
if (gidsetsize > 0) {
|
||||
grouplist = g_try_new(gid_t, gidsetsize);
|
||||
if (!grouplist) {
|
||||
return -TARGET_ENOMEM;
|
||||
}
|
||||
target_grouplist = lock_user(VERIFY_READ, arg2,
|
||||
gidsetsize * sizeof(target_id), 1);
|
||||
if (!target_grouplist) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
for (i = 0; i < gidsetsize; i++) {
|
||||
grouplist[i] = low2highgid(tswapid(target_grouplist[i]));
|
||||
}
|
||||
unlock_user(target_grouplist, arg2, 0);
|
||||
unlock_user(target_grouplist, arg2,
|
||||
gidsetsize * sizeof(target_id));
|
||||
}
|
||||
return get_errno(setgroups(gidsetsize, grouplist));
|
||||
}
|
||||
@@ -11792,41 +11811,59 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
|
||||
{
|
||||
int gidsetsize = arg1;
|
||||
uint32_t *target_grouplist;
|
||||
gid_t *grouplist;
|
||||
g_autofree gid_t *grouplist = NULL;
|
||||
int i;
|
||||
|
||||
grouplist = alloca(gidsetsize * sizeof(gid_t));
|
||||
if (gidsetsize > NGROUPS_MAX) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
if (gidsetsize > 0) {
|
||||
grouplist = g_try_new(gid_t, gidsetsize);
|
||||
if (!grouplist) {
|
||||
return -TARGET_ENOMEM;
|
||||
}
|
||||
}
|
||||
ret = get_errno(getgroups(gidsetsize, grouplist));
|
||||
if (gidsetsize == 0)
|
||||
return ret;
|
||||
if (!is_error(ret)) {
|
||||
target_grouplist = lock_user(VERIFY_WRITE, arg2, gidsetsize * 4, 0);
|
||||
if (!is_error(ret) && gidsetsize > 0) {
|
||||
target_grouplist = lock_user(VERIFY_WRITE, arg2,
|
||||
gidsetsize * 4, 0);
|
||||
if (!target_grouplist) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
for(i = 0;i < ret; i++)
|
||||
for (i = 0; i < ret; i++) {
|
||||
target_grouplist[i] = tswap32(grouplist[i]);
|
||||
}
|
||||
unlock_user(target_grouplist, arg2, gidsetsize * 4);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
#endif
|
||||
#ifdef TARGET_NR_setgroups32
|
||||
case TARGET_NR_setgroups32:
|
||||
{
|
||||
int gidsetsize = arg1;
|
||||
uint32_t *target_grouplist;
|
||||
gid_t *grouplist;
|
||||
g_autofree gid_t *grouplist = NULL;
|
||||
int i;
|
||||
|
||||
grouplist = alloca(gidsetsize * sizeof(gid_t));
|
||||
target_grouplist = lock_user(VERIFY_READ, arg2, gidsetsize * 4, 1);
|
||||
if (!target_grouplist) {
|
||||
return -TARGET_EFAULT;
|
||||
if (gidsetsize > NGROUPS_MAX || gidsetsize < 0) {
|
||||
return -TARGET_EINVAL;
|
||||
}
|
||||
if (gidsetsize > 0) {
|
||||
grouplist = g_try_new(gid_t, gidsetsize);
|
||||
if (!grouplist) {
|
||||
return -TARGET_ENOMEM;
|
||||
}
|
||||
target_grouplist = lock_user(VERIFY_READ, arg2,
|
||||
gidsetsize * 4, 1);
|
||||
if (!target_grouplist) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
for (i = 0; i < gidsetsize; i++) {
|
||||
grouplist[i] = tswap32(target_grouplist[i]);
|
||||
}
|
||||
unlock_user(target_grouplist, arg2, 0);
|
||||
}
|
||||
for(i = 0;i < gidsetsize; i++)
|
||||
grouplist[i] = tswap32(target_grouplist[i]);
|
||||
unlock_user(target_grouplist, arg2, 0);
|
||||
return get_errno(setgroups(gidsetsize, grouplist));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2050,6 +2050,7 @@ if get_option('debug_stack_usage') and have_coroutine_pool
|
||||
have_coroutine_pool = false
|
||||
endif
|
||||
config_host_data.set10('CONFIG_COROUTINE_POOL', have_coroutine_pool)
|
||||
config_host_data.set('CONFIG_DEBUG_GRAPH_LOCK', get_option('debug_graph_lock'))
|
||||
config_host_data.set('CONFIG_DEBUG_MUTEX', get_option('debug_mutex'))
|
||||
config_host_data.set('CONFIG_DEBUG_STACK_USAGE', get_option('debug_stack_usage'))
|
||||
config_host_data.set('CONFIG_GPROF', get_option('gprof'))
|
||||
@@ -3322,6 +3323,10 @@ modinfo_files = []
|
||||
block_mods = []
|
||||
softmmu_mods = []
|
||||
foreach d, list : modules
|
||||
if not (d == 'block' ? have_block : have_system)
|
||||
continue
|
||||
endif
|
||||
|
||||
foreach m, module_ss : list
|
||||
if enable_modules and targetos != 'windows'
|
||||
module_ss = module_ss.apply(config_all, strict: false)
|
||||
@@ -3975,6 +3980,7 @@ summary_info += {'PIE': get_option('b_pie')}
|
||||
summary_info += {'static build': config_host.has_key('CONFIG_STATIC')}
|
||||
summary_info += {'malloc trim support': has_malloc_trim}
|
||||
summary_info += {'membarrier': have_membarrier}
|
||||
summary_info += {'debug graph lock': get_option('debug_graph_lock')}
|
||||
summary_info += {'debug stack usage': get_option('debug_stack_usage')}
|
||||
summary_info += {'mutex debugging': get_option('debug_mutex')}
|
||||
summary_info += {'memory allocator': get_option('malloc')}
|
||||
|
||||
@@ -317,6 +317,8 @@ option('rng_none', type: 'boolean', value: false,
|
||||
description: 'dummy RNG, avoid using /dev/(u)random and getrandom()')
|
||||
option('coroutine_pool', type: 'boolean', value: true,
|
||||
description: 'coroutine freelist (better performance)')
|
||||
option('debug_graph_lock', type: 'boolean', value: false,
|
||||
description: 'graph lock debugging support')
|
||||
option('debug_mutex', type: 'boolean', value: false,
|
||||
description: 'mutex debugging support')
|
||||
option('debug_stack_usage', type: 'boolean', value: false,
|
||||
|
||||
+16
-14
@@ -3436,7 +3436,6 @@ static void migration_completion(MigrationState *s)
|
||||
ret = global_state_store();
|
||||
|
||||
if (!ret) {
|
||||
bool inactivate = !migrate_colo_enabled();
|
||||
ret = vm_stop_force_state(RUN_STATE_FINISH_MIGRATE);
|
||||
trace_migration_completion_vm_stop(ret);
|
||||
if (ret >= 0) {
|
||||
@@ -3444,12 +3443,15 @@ static void migration_completion(MigrationState *s)
|
||||
MIGRATION_STATUS_DEVICE);
|
||||
}
|
||||
if (ret >= 0) {
|
||||
/*
|
||||
* Inactivate disks except in COLO, and track that we
|
||||
* have done so in order to remember to reactivate
|
||||
* them if migration fails or is cancelled.
|
||||
*/
|
||||
s->block_inactive = !migrate_colo_enabled();
|
||||
qemu_file_set_rate_limit(s->to_dst_file, INT64_MAX);
|
||||
ret = qemu_savevm_state_complete_precopy(s->to_dst_file, false,
|
||||
inactivate);
|
||||
}
|
||||
if (inactivate && ret >= 0) {
|
||||
s->block_inactive = true;
|
||||
s->block_inactive);
|
||||
}
|
||||
}
|
||||
qemu_mutex_unlock_iothread();
|
||||
@@ -3490,13 +3492,13 @@ static void migration_completion(MigrationState *s)
|
||||
rp_error = await_return_path_close_on_source(s);
|
||||
trace_migration_return_path_end_after(rp_error);
|
||||
if (rp_error) {
|
||||
goto fail_invalidate;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (qemu_file_get_error(s->to_dst_file)) {
|
||||
trace_migration_completion_file_err();
|
||||
goto fail_invalidate;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (migrate_colo_enabled() && s->state == MIGRATION_STATUS_ACTIVE) {
|
||||
@@ -3510,12 +3512,13 @@ static void migration_completion(MigrationState *s)
|
||||
|
||||
return;
|
||||
|
||||
fail_invalidate:
|
||||
/* If not doing postcopy, vm_start() will be called: let's regain
|
||||
* control on images.
|
||||
*/
|
||||
if (s->state == MIGRATION_STATUS_ACTIVE ||
|
||||
s->state == MIGRATION_STATUS_DEVICE) {
|
||||
fail:
|
||||
if (s->block_inactive && (s->state == MIGRATION_STATUS_ACTIVE ||
|
||||
s->state == MIGRATION_STATUS_DEVICE)) {
|
||||
/*
|
||||
* If not doing postcopy, vm_start() will be called: let's
|
||||
* regain control on images.
|
||||
*/
|
||||
Error *local_err = NULL;
|
||||
|
||||
qemu_mutex_lock_iothread();
|
||||
@@ -3528,7 +3531,6 @@ fail_invalidate:
|
||||
qemu_mutex_unlock_iothread();
|
||||
}
|
||||
|
||||
fail:
|
||||
migrate_set_state(&s->state, current_active_state,
|
||||
MIGRATION_STATUS_FAILED);
|
||||
}
|
||||
|
||||
+1
-2
@@ -1599,8 +1599,7 @@ static bool nbd_drained_poll(void *opaque)
|
||||
* enter it here so we don't depend on the client to wake it up.
|
||||
*/
|
||||
if (client->recv_coroutine != NULL && client->read_yielding) {
|
||||
qemu_aio_coroutine_enter(exp->common.ctx,
|
||||
client->recv_coroutine);
|
||||
qio_channel_wake_read(client->ioc);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -136,7 +136,7 @@ _eth_tcp_has_data(bool is_ip4,
|
||||
return l4len > TCP_HEADER_DATA_OFFSET(tcp);
|
||||
}
|
||||
|
||||
void eth_get_protocols(const struct iovec *iov, int iovcnt,
|
||||
void eth_get_protocols(const struct iovec *iov, size_t iovcnt, size_t iovoff,
|
||||
bool *hasip4, bool *hasip6,
|
||||
size_t *l3hdr_off,
|
||||
size_t *l4hdr_off,
|
||||
@@ -147,26 +147,24 @@ void eth_get_protocols(const struct iovec *iov, int iovcnt,
|
||||
{
|
||||
int proto;
|
||||
bool fragment = false;
|
||||
size_t l2hdr_len = eth_get_l2_hdr_length_iov(iov, iovcnt);
|
||||
size_t input_size = iov_size(iov, iovcnt);
|
||||
size_t copied;
|
||||
uint8_t ip_p;
|
||||
|
||||
*hasip4 = *hasip6 = false;
|
||||
*l3hdr_off = iovoff + eth_get_l2_hdr_length_iov(iov, iovcnt, iovoff);
|
||||
l4hdr_info->proto = ETH_L4_HDR_PROTO_INVALID;
|
||||
|
||||
proto = eth_get_l3_proto(iov, iovcnt, l2hdr_len);
|
||||
|
||||
*l3hdr_off = l2hdr_len;
|
||||
proto = eth_get_l3_proto(iov, iovcnt, *l3hdr_off);
|
||||
|
||||
if (proto == ETH_P_IP) {
|
||||
struct ip_header *iphdr = &ip4hdr_info->ip4_hdr;
|
||||
|
||||
if (input_size < l2hdr_len) {
|
||||
if (input_size < *l3hdr_off) {
|
||||
return;
|
||||
}
|
||||
|
||||
copied = iov_to_buf(iov, iovcnt, l2hdr_len, iphdr, sizeof(*iphdr));
|
||||
copied = iov_to_buf(iov, iovcnt, *l3hdr_off, iphdr, sizeof(*iphdr));
|
||||
if (copied < sizeof(*iphdr) ||
|
||||
IP_HEADER_VERSION(iphdr) != IP_HEADER_VERSION_4) {
|
||||
return;
|
||||
@@ -175,17 +173,17 @@ void eth_get_protocols(const struct iovec *iov, int iovcnt,
|
||||
*hasip4 = true;
|
||||
ip_p = iphdr->ip_p;
|
||||
ip4hdr_info->fragment = IP4_IS_FRAGMENT(iphdr);
|
||||
*l4hdr_off = l2hdr_len + IP_HDR_GET_LEN(iphdr);
|
||||
*l4hdr_off = *l3hdr_off + IP_HDR_GET_LEN(iphdr);
|
||||
|
||||
fragment = ip4hdr_info->fragment;
|
||||
} else if (proto == ETH_P_IPV6) {
|
||||
if (!eth_parse_ipv6_hdr(iov, iovcnt, l2hdr_len, ip6hdr_info)) {
|
||||
if (!eth_parse_ipv6_hdr(iov, iovcnt, *l3hdr_off, ip6hdr_info)) {
|
||||
return;
|
||||
}
|
||||
|
||||
*hasip6 = true;
|
||||
ip_p = ip6hdr_info->l4proto;
|
||||
*l4hdr_off = l2hdr_len + ip6hdr_info->full_hdr_len;
|
||||
*l4hdr_off = *l3hdr_off + ip6hdr_info->full_hdr_len;
|
||||
fragment = ip6hdr_info->fragment;
|
||||
} else {
|
||||
return;
|
||||
|
||||
+14
@@ -36,6 +36,8 @@
|
||||
#include "qemu/log.h"
|
||||
#include "sysemu/runstate.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qemu/config-file.h"
|
||||
#include "qemu/option.h"
|
||||
|
||||
#ifdef CONFIG_LINUX
|
||||
#include <sys/prctl.h>
|
||||
@@ -152,9 +154,21 @@ int os_parse_cmd_args(int index, const char *optarg)
|
||||
daemonize = 1;
|
||||
break;
|
||||
#if defined(CONFIG_LINUX)
|
||||
/* deprecated */
|
||||
case QEMU_OPTION_asyncteardown:
|
||||
init_async_teardown();
|
||||
break;
|
||||
case QEMU_OPTION_run_with: {
|
||||
QemuOpts *opts = qemu_opts_parse_noisily(qemu_find_opts("run-with"),
|
||||
optarg, false);
|
||||
if (!opts) {
|
||||
exit(1);
|
||||
}
|
||||
if (qemu_opt_get_bool(opts, "async-teardown", false)) {
|
||||
init_async_teardown();
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
return -1;
|
||||
|
||||
+45
-13
@@ -1143,10 +1143,22 @@ have gone through several iterations as the feature set and complexity
|
||||
of the block layer have grown. Many online guides to QEMU often
|
||||
reference older and deprecated options, which can lead to confusion.
|
||||
|
||||
The recommended modern way to describe disks is to use a combination of
|
||||
The most explicit way to describe disks is to use a combination of
|
||||
``-device`` to specify the hardware device and ``-blockdev`` to
|
||||
describe the backend. The device defines what the guest sees and the
|
||||
backend describes how QEMU handles the data.
|
||||
backend describes how QEMU handles the data. It is the only guaranteed
|
||||
stable interface for describing block devices and as such is
|
||||
recommended for management tools and scripting.
|
||||
|
||||
The ``-drive`` option combines the device and backend into a single
|
||||
command line option which is a more human friendly. There is however no
|
||||
interface stability guarantee although some older board models still
|
||||
need updating to work with the modern blockdev forms.
|
||||
|
||||
Older options like ``-hda`` are essentially macros which expand into
|
||||
``-drive`` options for various drive interfaces. The original forms
|
||||
bake in a lot of assumptions from the days when QEMU was emulating a
|
||||
legacy PC, they are not recommended for modern configurations.
|
||||
|
||||
ERST
|
||||
|
||||
@@ -1639,6 +1651,14 @@ SRST
|
||||
the raw disk image you use is not written back. You can however
|
||||
force the write back by pressing C-a s (see the :ref:`disk images`
|
||||
chapter in the System Emulation Users Guide).
|
||||
|
||||
.. warning::
|
||||
snapshot is incompatible with ``-blockdev`` (instead use qemu-img
|
||||
to manually create snapshot images to attach to your blockdev).
|
||||
If you have mixed ``-blockdev`` and ``-drive`` declarations you
|
||||
can use the 'snapshot' property on your drive declarations
|
||||
instead of this global option.
|
||||
|
||||
ERST
|
||||
|
||||
DEF("fsdev", HAS_ARG, QEMU_OPTION_fsdev,
|
||||
@@ -4766,20 +4786,32 @@ DEF("qtest-log", HAS_ARG, QEMU_OPTION_qtest_log, "", QEMU_ARCH_ALL)
|
||||
DEF("async-teardown", 0, QEMU_OPTION_asyncteardown,
|
||||
"-async-teardown enable asynchronous teardown\n",
|
||||
QEMU_ARCH_ALL)
|
||||
#endif
|
||||
SRST
|
||||
``-async-teardown``
|
||||
Enable asynchronous teardown. A new process called "cleanup/<QEMU_PID>"
|
||||
will be created at startup sharing the address space with the main qemu
|
||||
process, using clone. It will wait for the main qemu process to
|
||||
terminate completely, and then exit.
|
||||
This allows qemu to terminate very quickly even if the guest was
|
||||
huge, leaving the teardown of the address space to the cleanup
|
||||
process. Since the cleanup process shares the same cgroups as the
|
||||
main qemu process, accounting is performed correctly. This only
|
||||
works if the cleanup process is not forcefully killed with SIGKILL
|
||||
before the main qemu process has terminated completely.
|
||||
This option is deprecated and should no longer be used. The new option
|
||||
``-run-with async-teardown=on`` is a replacement.
|
||||
ERST
|
||||
DEF("run-with", HAS_ARG, QEMU_OPTION_run_with,
|
||||
"-run-with async-teardown[=on|off]\n"
|
||||
" misc QEMU process lifecycle options\n"
|
||||
" async-teardown=on enables asynchronous teardown\n",
|
||||
QEMU_ARCH_ALL)
|
||||
SRST
|
||||
``-run-with``
|
||||
Set QEMU process lifecycle options.
|
||||
|
||||
``async-teardown=on`` enables asynchronous teardown. A new process called
|
||||
"cleanup/<QEMU_PID>" will be created at startup sharing the address
|
||||
space with the main QEMU process, using clone. It will wait for the
|
||||
main QEMU process to terminate completely, and then exit. This allows
|
||||
QEMU to terminate very quickly even if the guest was huge, leaving the
|
||||
teardown of the address space to the cleanup process. Since the cleanup
|
||||
process shares the same cgroups as the main QEMU process, accounting is
|
||||
performed correctly. This only works if the cleanup process is not
|
||||
forcefully killed with SIGKILL before the main QEMU process has
|
||||
terminated completely.
|
||||
ERST
|
||||
#endif
|
||||
|
||||
DEF("msg", HAS_ARG, QEMU_OPTION_msg,
|
||||
"-msg [timestamp[=on|off]][,guest-name=[on|off]]\n"
|
||||
|
||||
@@ -21,6 +21,8 @@ meson_options_help() {
|
||||
printf "%s\n" ' QEMU'
|
||||
printf "%s\n" ' --enable-cfi Control-Flow Integrity (CFI)'
|
||||
printf "%s\n" ' --enable-cfi-debug Verbose errors in case of CFI violation'
|
||||
printf "%s\n" ' --enable-debug-graph-lock'
|
||||
printf "%s\n" ' graph lock debugging support'
|
||||
printf "%s\n" ' --enable-debug-mutex mutex debugging support'
|
||||
printf "%s\n" ' --enable-debug-stack-usage'
|
||||
printf "%s\n" ' measure coroutine stack usage'
|
||||
@@ -254,6 +256,8 @@ _meson_option_parse() {
|
||||
--datadir=*) quote_sh "-Ddatadir=$2" ;;
|
||||
--enable-dbus-display) printf "%s" -Ddbus_display=enabled ;;
|
||||
--disable-dbus-display) printf "%s" -Ddbus_display=disabled ;;
|
||||
--enable-debug-graph-lock) printf "%s" -Ddebug_graph_lock=true ;;
|
||||
--disable-debug-graph-lock) printf "%s" -Ddebug_graph_lock=false ;;
|
||||
--enable-debug-mutex) printf "%s" -Ddebug_mutex=true ;;
|
||||
--disable-debug-mutex) printf "%s" -Ddebug_mutex=false ;;
|
||||
--enable-debug-stack-usage) printf "%s" -Ddebug_stack_usage=true ;;
|
||||
|
||||
@@ -233,7 +233,7 @@ int aarch64_gdb_get_pauth_reg(CPUARMState *env, GByteArray *buf, int reg)
|
||||
ARMMMUIdx mmu_idx = arm_stage1_mmu_idx(env);
|
||||
ARMVAParameters param;
|
||||
|
||||
param = aa64_va_parameters(env, -is_high, mmu_idx, is_data);
|
||||
param = aa64_va_parameters(env, -is_high, mmu_idx, is_data, false);
|
||||
return gdb_get_reg64(buf, pauth_ptr_mask(param));
|
||||
}
|
||||
default:
|
||||
|
||||
+13
-2
@@ -4904,7 +4904,7 @@ static TLBIRange tlbi_aa64_get_range(CPUARMState *env, ARMMMUIdx mmuidx,
|
||||
unsigned int page_size_granule, page_shift, num, scale, exponent;
|
||||
/* Extract one bit to represent the va selector in use. */
|
||||
uint64_t select = sextract64(value, 36, 1);
|
||||
ARMVAParameters param = aa64_va_parameters(env, select, mmuidx, true);
|
||||
ARMVAParameters param = aa64_va_parameters(env, select, mmuidx, true, false);
|
||||
TLBIRange ret = { };
|
||||
ARMGranuleSize gran;
|
||||
|
||||
@@ -11193,7 +11193,8 @@ static ARMGranuleSize sanitize_gran_size(ARMCPU *cpu, ARMGranuleSize gran,
|
||||
}
|
||||
|
||||
ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
|
||||
ARMMMUIdx mmu_idx, bool data)
|
||||
ARMMMUIdx mmu_idx, bool data,
|
||||
bool el1_is_aa32)
|
||||
{
|
||||
uint64_t tcr = regime_tcr(env, mmu_idx);
|
||||
bool epd, hpd, tsz_oob, ds, ha, hd;
|
||||
@@ -11289,6 +11290,16 @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
|
||||
}
|
||||
}
|
||||
|
||||
if (stage2 && el1_is_aa32) {
|
||||
/*
|
||||
* For AArch32 EL1 the min txsz (and thus max IPA size) requirements
|
||||
* are loosened: a configured IPA of 40 bits is permitted even if
|
||||
* the implemented PA is less than that (and so a 40 bit IPA would
|
||||
* fault for an AArch64 EL1). See R_DTLMN.
|
||||
*/
|
||||
min_tsz = MIN(min_tsz, 24);
|
||||
}
|
||||
|
||||
if (tsz > max_tsz) {
|
||||
tsz = max_tsz;
|
||||
tsz_oob = true;
|
||||
|
||||
+11
-1
@@ -1091,8 +1091,18 @@ typedef struct ARMVAParameters {
|
||||
ARMGranuleSize gran : 2;
|
||||
} ARMVAParameters;
|
||||
|
||||
/**
|
||||
* aa64_va_parameters: Return parameters for an AArch64 virtual address
|
||||
* @env: CPU
|
||||
* @va: virtual address to look up
|
||||
* @mmu_idx: determines translation regime to use
|
||||
* @data: true if this is a data access
|
||||
* @el1_is_aa32: true if we are asking about stage 2 when EL1 is AArch32
|
||||
* (ignored if @mmu_idx is for a stage 1 regime; only affects tsz/tsz_oob)
|
||||
*/
|
||||
ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va,
|
||||
ARMMMUIdx mmu_idx, bool data);
|
||||
ARMMMUIdx mmu_idx, bool data,
|
||||
bool el1_is_aa32);
|
||||
|
||||
int aa64_va_parameter_tbi(uint64_t tcr, ARMMMUIdx mmu_idx);
|
||||
int aa64_va_parameter_tbid(uint64_t tcr, ARMMMUIdx mmu_idx);
|
||||
|
||||
@@ -280,6 +280,8 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
|
||||
}
|
||||
}
|
||||
|
||||
kvm_arm_init_debug(s);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
+4
-14
@@ -74,24 +74,16 @@ GArray *hw_breakpoints, *hw_watchpoints;
|
||||
#define get_hw_bp(i) (&g_array_index(hw_breakpoints, HWBreakpoint, i))
|
||||
#define get_hw_wp(i) (&g_array_index(hw_watchpoints, HWWatchpoint, i))
|
||||
|
||||
/**
|
||||
* kvm_arm_init_debug() - check for guest debug capabilities
|
||||
* @cs: CPUState
|
||||
*
|
||||
* kvm_check_extension returns the number of debug registers we have
|
||||
* or 0 if we have none.
|
||||
*
|
||||
*/
|
||||
static void kvm_arm_init_debug(CPUState *cs)
|
||||
void kvm_arm_init_debug(KVMState *s)
|
||||
{
|
||||
have_guest_debug = kvm_check_extension(cs->kvm_state,
|
||||
have_guest_debug = kvm_check_extension(s,
|
||||
KVM_CAP_SET_GUEST_DEBUG);
|
||||
|
||||
max_hw_wps = kvm_check_extension(cs->kvm_state, KVM_CAP_GUEST_DEBUG_HW_WPS);
|
||||
max_hw_wps = kvm_check_extension(s, KVM_CAP_GUEST_DEBUG_HW_WPS);
|
||||
hw_watchpoints = g_array_sized_new(true, true,
|
||||
sizeof(HWWatchpoint), max_hw_wps);
|
||||
|
||||
max_hw_bps = kvm_check_extension(cs->kvm_state, KVM_CAP_GUEST_DEBUG_HW_BPS);
|
||||
max_hw_bps = kvm_check_extension(s, KVM_CAP_GUEST_DEBUG_HW_BPS);
|
||||
hw_breakpoints = g_array_sized_new(true, true,
|
||||
sizeof(HWBreakpoint), max_hw_bps);
|
||||
return;
|
||||
@@ -920,8 +912,6 @@ int kvm_arch_init_vcpu(CPUState *cs)
|
||||
}
|
||||
cpu->mp_affinity = mpidr & ARM64_AFFINITY_MASK;
|
||||
|
||||
kvm_arm_init_debug(cs);
|
||||
|
||||
/* Check whether user space can specify guest syndrome value */
|
||||
kvm_arm_init_serror_injection(cs);
|
||||
|
||||
|
||||
@@ -18,6 +18,14 @@
|
||||
#define KVM_ARM_VGIC_V2 (1 << 0)
|
||||
#define KVM_ARM_VGIC_V3 (1 << 1)
|
||||
|
||||
/**
|
||||
* kvm_arm_init_debug() - initialize guest debug capabilities
|
||||
* @s: KVMState
|
||||
*
|
||||
* Should be called only once before using guest debug capabilities.
|
||||
*/
|
||||
void kvm_arm_init_debug(KVMState *s);
|
||||
|
||||
/**
|
||||
* kvm_arm_vcpu_init:
|
||||
* @cs: CPUState
|
||||
|
||||
+53
-37
@@ -103,6 +103,37 @@ ARMMMUIdx arm_stage1_mmu_idx(CPUARMState *env)
|
||||
return stage_1_mmu_idx(arm_mmu_idx(env));
|
||||
}
|
||||
|
||||
/*
|
||||
* Return where we should do ptw loads from for a stage 2 walk.
|
||||
* This depends on whether the address we are looking up is a
|
||||
* Secure IPA or a NonSecure IPA, which we know from whether this is
|
||||
* Stage2 or Stage2_S.
|
||||
* If this is the Secure EL1&0 regime we need to check the NSW and SW bits.
|
||||
*/
|
||||
static ARMMMUIdx ptw_idx_for_stage_2(CPUARMState *env, ARMMMUIdx stage2idx)
|
||||
{
|
||||
bool s2walk_secure;
|
||||
|
||||
/*
|
||||
* We're OK to check the current state of the CPU here because
|
||||
* (1) we always invalidate all TLBs when the SCR_EL3.NS bit changes
|
||||
* (2) there's no way to do a lookup that cares about Stage 2 for a
|
||||
* different security state to the current one for AArch64, and AArch32
|
||||
* never has a secure EL2. (AArch32 ATS12NSO[UP][RW] allow EL3 to do
|
||||
* an NS stage 1+2 lookup while the NS bit is 0.)
|
||||
*/
|
||||
if (!arm_is_secure_below_el3(env) || !arm_el_is_aa64(env, 3)) {
|
||||
return ARMMMUIdx_Phys_NS;
|
||||
}
|
||||
if (stage2idx == ARMMMUIdx_Stage2_S) {
|
||||
s2walk_secure = !(env->cp15.vstcr_el2 & VSTCR_SW);
|
||||
} else {
|
||||
s2walk_secure = !(env->cp15.vtcr_el2 & VTCR_NSW);
|
||||
}
|
||||
return s2walk_secure ? ARMMMUIdx_Phys_S : ARMMMUIdx_Phys_NS;
|
||||
|
||||
}
|
||||
|
||||
static bool regime_translation_big_endian(CPUARMState *env, ARMMMUIdx mmu_idx)
|
||||
{
|
||||
return (regime_sctlr(env, mmu_idx) & SCTLR_EE) != 0;
|
||||
@@ -220,7 +251,6 @@ static bool S1_ptw_translate(CPUARMState *env, S1Translate *ptw,
|
||||
ARMMMUIdx mmu_idx = ptw->in_mmu_idx;
|
||||
ARMMMUIdx s2_mmu_idx = ptw->in_ptw_idx;
|
||||
uint8_t pte_attrs;
|
||||
bool pte_secure;
|
||||
|
||||
ptw->out_virt = addr;
|
||||
|
||||
@@ -232,8 +262,8 @@ static bool S1_ptw_translate(CPUARMState *env, S1Translate *ptw,
|
||||
if (regime_is_stage2(s2_mmu_idx)) {
|
||||
S1Translate s2ptw = {
|
||||
.in_mmu_idx = s2_mmu_idx,
|
||||
.in_ptw_idx = is_secure ? ARMMMUIdx_Phys_S : ARMMMUIdx_Phys_NS,
|
||||
.in_secure = is_secure,
|
||||
.in_ptw_idx = ptw_idx_for_stage_2(env, s2_mmu_idx),
|
||||
.in_secure = s2_mmu_idx == ARMMMUIdx_Stage2_S,
|
||||
.in_debug = true,
|
||||
};
|
||||
GetPhysAddrResult s2 = { };
|
||||
@@ -244,12 +274,12 @@ static bool S1_ptw_translate(CPUARMState *env, S1Translate *ptw,
|
||||
}
|
||||
ptw->out_phys = s2.f.phys_addr;
|
||||
pte_attrs = s2.cacheattrs.attrs;
|
||||
pte_secure = s2.f.attrs.secure;
|
||||
ptw->out_secure = s2.f.attrs.secure;
|
||||
} else {
|
||||
/* Regime is physical. */
|
||||
ptw->out_phys = addr;
|
||||
pte_attrs = 0;
|
||||
pte_secure = is_secure;
|
||||
ptw->out_secure = s2_mmu_idx == ARMMMUIdx_Phys_S;
|
||||
}
|
||||
ptw->out_host = NULL;
|
||||
ptw->out_rw = false;
|
||||
@@ -270,7 +300,7 @@ static bool S1_ptw_translate(CPUARMState *env, S1Translate *ptw,
|
||||
ptw->out_phys = full->phys_addr | (addr & ~TARGET_PAGE_MASK);
|
||||
ptw->out_rw = full->prot & PAGE_WRITE;
|
||||
pte_attrs = full->pte_attrs;
|
||||
pte_secure = full->attrs.secure;
|
||||
ptw->out_secure = full->attrs.secure;
|
||||
#else
|
||||
g_assert_not_reached();
|
||||
#endif
|
||||
@@ -293,11 +323,6 @@ static bool S1_ptw_translate(CPUARMState *env, S1Translate *ptw,
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if page table walk is to secure or non-secure PA space. */
|
||||
ptw->out_secure = (is_secure
|
||||
&& !(pte_secure
|
||||
? env->cp15.vstcr_el2 & VSTCR_SW
|
||||
: env->cp15.vtcr_el2 & VTCR_NSW));
|
||||
ptw->out_be = regime_translation_big_endian(env, mmu_idx);
|
||||
return true;
|
||||
|
||||
@@ -1097,17 +1122,6 @@ static int check_s2_mmu_setup(ARMCPU *cpu, bool is_aa64, uint64_t tcr,
|
||||
|
||||
sl0 = extract32(tcr, 6, 2);
|
||||
if (is_aa64) {
|
||||
/*
|
||||
* AArch64.S2InvalidTxSZ: While we checked tsz_oob near the top of
|
||||
* get_phys_addr_lpae, that used aa64_va_parameters which apply
|
||||
* to aarch64. If Stage1 is aarch32, the min_txsz is larger.
|
||||
* See AArch64.S2MinTxSZ, where min_tsz is 24, translated to
|
||||
* inputsize is 64 - 24 = 40.
|
||||
*/
|
||||
if (iasize < 40 && !arm_el_is_aa64(&cpu->env, 1)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/*
|
||||
* AArch64.S2InvalidSL: Interpretation of SL depends on the page size,
|
||||
* so interleave AArch64.S2StartLevel.
|
||||
@@ -1247,7 +1261,8 @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw,
|
||||
int ps;
|
||||
|
||||
param = aa64_va_parameters(env, address, mmu_idx,
|
||||
access_type != MMU_INST_FETCH);
|
||||
access_type != MMU_INST_FETCH,
|
||||
!arm_el_is_aa64(env, 1));
|
||||
level = 0;
|
||||
|
||||
/*
|
||||
@@ -2713,7 +2728,7 @@ static bool get_phys_addr_twostage(CPUARMState *env, S1Translate *ptw,
|
||||
hwaddr ipa;
|
||||
int s1_prot, s1_lgpgsz;
|
||||
bool is_secure = ptw->in_secure;
|
||||
bool ret, ipa_secure, s2walk_secure;
|
||||
bool ret, ipa_secure;
|
||||
ARMCacheAttrs cacheattrs1;
|
||||
bool is_el0;
|
||||
uint64_t hcr;
|
||||
@@ -2727,20 +2742,11 @@ static bool get_phys_addr_twostage(CPUARMState *env, S1Translate *ptw,
|
||||
|
||||
ipa = result->f.phys_addr;
|
||||
ipa_secure = result->f.attrs.secure;
|
||||
if (is_secure) {
|
||||
/* Select TCR based on the NS bit from the S1 walk. */
|
||||
s2walk_secure = !(ipa_secure
|
||||
? env->cp15.vstcr_el2 & VSTCR_SW
|
||||
: env->cp15.vtcr_el2 & VTCR_NSW);
|
||||
} else {
|
||||
assert(!ipa_secure);
|
||||
s2walk_secure = false;
|
||||
}
|
||||
|
||||
is_el0 = ptw->in_mmu_idx == ARMMMUIdx_Stage1_E0;
|
||||
ptw->in_mmu_idx = s2walk_secure ? ARMMMUIdx_Stage2_S : ARMMMUIdx_Stage2;
|
||||
ptw->in_ptw_idx = s2walk_secure ? ARMMMUIdx_Phys_S : ARMMMUIdx_Phys_NS;
|
||||
ptw->in_secure = s2walk_secure;
|
||||
ptw->in_mmu_idx = ipa_secure ? ARMMMUIdx_Stage2_S : ARMMMUIdx_Stage2;
|
||||
ptw->in_secure = ipa_secure;
|
||||
ptw->in_ptw_idx = ptw_idx_for_stage_2(env, ptw->in_mmu_idx);
|
||||
|
||||
/*
|
||||
* S1 is done, now do S2 translation.
|
||||
@@ -2848,6 +2854,16 @@ static bool get_phys_addr_with_struct(CPUARMState *env, S1Translate *ptw,
|
||||
ptw->in_ptw_idx = is_secure ? ARMMMUIdx_Stage2_S : ARMMMUIdx_Stage2;
|
||||
break;
|
||||
|
||||
case ARMMMUIdx_Stage2:
|
||||
case ARMMMUIdx_Stage2_S:
|
||||
/*
|
||||
* Second stage lookup uses physical for ptw; whether this is S or
|
||||
* NS may depend on the SW/NSW bits if this is a stage 2 lookup for
|
||||
* the Secure EL2&0 regime.
|
||||
*/
|
||||
ptw->in_ptw_idx = ptw_idx_for_stage_2(env, mmu_idx);
|
||||
break;
|
||||
|
||||
case ARMMMUIdx_E10_0:
|
||||
s1_mmu_idx = ARMMMUIdx_Stage1_E0;
|
||||
goto do_twostage;
|
||||
@@ -2871,7 +2887,7 @@ static bool get_phys_addr_with_struct(CPUARMState *env, S1Translate *ptw,
|
||||
/* fall through */
|
||||
|
||||
default:
|
||||
/* Single stage and second stage uses physical for ptw. */
|
||||
/* Single stage uses physical for ptw. */
|
||||
ptw->in_ptw_idx = is_secure ? ARMMMUIdx_Phys_S : ARMMMUIdx_Phys_NS;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -293,7 +293,7 @@ static uint64_t pauth_addpac(CPUARMState *env, uint64_t ptr, uint64_t modifier,
|
||||
ARMPACKey *key, bool data)
|
||||
{
|
||||
ARMMMUIdx mmu_idx = arm_stage1_mmu_idx(env);
|
||||
ARMVAParameters param = aa64_va_parameters(env, ptr, mmu_idx, data);
|
||||
ARMVAParameters param = aa64_va_parameters(env, ptr, mmu_idx, data, false);
|
||||
uint64_t pac, ext_ptr, ext, test;
|
||||
int bot_bit, top_bit;
|
||||
|
||||
@@ -355,7 +355,7 @@ static uint64_t pauth_auth(CPUARMState *env, uint64_t ptr, uint64_t modifier,
|
||||
ARMPACKey *key, bool data, int keynumber)
|
||||
{
|
||||
ARMMMUIdx mmu_idx = arm_stage1_mmu_idx(env);
|
||||
ARMVAParameters param = aa64_va_parameters(env, ptr, mmu_idx, data);
|
||||
ARMVAParameters param = aa64_va_parameters(env, ptr, mmu_idx, data, false);
|
||||
int bot_bit, top_bit;
|
||||
uint64_t pac, orig_ptr, test;
|
||||
|
||||
@@ -379,7 +379,7 @@ static uint64_t pauth_auth(CPUARMState *env, uint64_t ptr, uint64_t modifier,
|
||||
static uint64_t pauth_strip(CPUARMState *env, uint64_t ptr, bool data)
|
||||
{
|
||||
ARMMMUIdx mmu_idx = arm_stage1_mmu_idx(env);
|
||||
ARMVAParameters param = aa64_va_parameters(env, ptr, mmu_idx, data);
|
||||
ARMVAParameters param = aa64_va_parameters(env, ptr, mmu_idx, data, false);
|
||||
|
||||
return pauth_original_ptr(ptr, param);
|
||||
}
|
||||
|
||||
@@ -6727,6 +6727,7 @@ void sve_ldff1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm,
|
||||
intptr_t reg_off;
|
||||
SVEHostPage info;
|
||||
target_ulong addr, in_page;
|
||||
ARMVectorReg scratch;
|
||||
|
||||
/* Skip to the first true predicate. */
|
||||
reg_off = find_next_active(vg, 0, reg_max, esz);
|
||||
@@ -6736,6 +6737,11 @@ void sve_ldff1_z(CPUARMState *env, void *vd, uint64_t *vg, void *vm,
|
||||
return;
|
||||
}
|
||||
|
||||
/* Protect against overlap between vd and vm. */
|
||||
if (unlikely(vd == vm)) {
|
||||
vm = memcpy(&scratch, vm, reg_max);
|
||||
}
|
||||
|
||||
/*
|
||||
* Probe the first element, allowing faults.
|
||||
*/
|
||||
|
||||
@@ -2816,7 +2816,7 @@ static bool msr_banked_access_decode(DisasContext *s, int r, int sysm, int rn,
|
||||
if (arm_dc_feature(s, ARM_FEATURE_AARCH64) &&
|
||||
dc_isar_feature(aa64_sel2, s)) {
|
||||
/* Target EL is EL<3 minus SCR_EL3.EEL2> */
|
||||
tcg_el = load_cpu_field(cp15.scr_el3);
|
||||
tcg_el = load_cpu_field_low32(cp15.scr_el3);
|
||||
tcg_gen_sextract_i32(tcg_el, tcg_el, ctz32(SCR_EEL2), 1);
|
||||
tcg_gen_addi_i32(tcg_el, tcg_el, 3);
|
||||
} else {
|
||||
@@ -6396,7 +6396,7 @@ static bool trans_ERET(DisasContext *s, arg_ERET *a)
|
||||
}
|
||||
if (s->current_el == 2) {
|
||||
/* ERET from Hyp uses ELR_Hyp, not LR */
|
||||
tmp = load_cpu_field(elr_el[2]);
|
||||
tmp = load_cpu_field_low32(elr_el[2]);
|
||||
} else {
|
||||
tmp = load_reg(s, 14);
|
||||
}
|
||||
|
||||
@@ -61,6 +61,13 @@ static inline TCGv_i32 load_cpu_offset(int offset)
|
||||
|
||||
#define load_cpu_field(name) load_cpu_offset(offsetof(CPUARMState, name))
|
||||
|
||||
/* Load from the low half of a 64-bit field to a TCGv_i32 */
|
||||
#define load_cpu_field_low32(name) \
|
||||
({ \
|
||||
QEMU_BUILD_BUG_ON(sizeof_field(CPUARMState, name) != 8); \
|
||||
load_cpu_offset(offsetoflow32(CPUARMState, name)); \
|
||||
})
|
||||
|
||||
void store_cpu_offset(TCGv_i32 var, int offset, int size);
|
||||
|
||||
#define store_cpu_field(var, name) \
|
||||
|
||||
+2
-2
@@ -5718,8 +5718,8 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
|
||||
} else {
|
||||
*eax &= env->features[FEAT_SGX_12_1_EAX];
|
||||
*ebx &= 0; /* ebx reserve */
|
||||
*ecx &= env->features[FEAT_XSAVE_XSS_LO];
|
||||
*edx &= env->features[FEAT_XSAVE_XSS_HI];
|
||||
*ecx &= env->features[FEAT_XSAVE_XCR0_LO];
|
||||
*edx &= env->features[FEAT_XSAVE_XCR0_HI];
|
||||
|
||||
/* FP and SSE are always allowed regardless of XSAVE/XCR0. */
|
||||
*ecx |= XSTATE_FP_MASK | XSTATE_SSE_MASK;
|
||||
|
||||
@@ -2497,6 +2497,14 @@ void helper_vpermdq_ymm(Reg *d, Reg *v, Reg *s, uint32_t order)
|
||||
d->Q(1) = r1;
|
||||
d->Q(2) = r2;
|
||||
d->Q(3) = r3;
|
||||
if (order & 0x8) {
|
||||
d->Q(0) = 0;
|
||||
d->Q(1) = 0;
|
||||
}
|
||||
if (order & 0x80) {
|
||||
d->Q(2) = 0;
|
||||
d->Q(3) = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void helper_vpermq_ymm(Reg *d, Reg *s, uint32_t order)
|
||||
|
||||
@@ -783,6 +783,17 @@ static void decode_0F2D(DisasContext *s, CPUX86State *env, X86OpEntry *entry, ui
|
||||
*entry = *decode_by_prefix(s, opcodes_0F2D);
|
||||
}
|
||||
|
||||
static void decode_VxCOMISx(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b)
|
||||
{
|
||||
/*
|
||||
* VUCOMISx and VCOMISx are different and use no-prefix and 0x66 for SS and SD
|
||||
* respectively. Scalar values usually are associated with 0xF2 and 0xF3, for
|
||||
* which X86_VEX_REPScalar exists, but here it has to be decoded by hand.
|
||||
*/
|
||||
entry->s1 = entry->s2 = (s->prefix & PREFIX_DATA ? X86_SIZE_sd : X86_SIZE_ss);
|
||||
entry->gen = (*b == 0x2E ? gen_VUCOMI : gen_VCOMI);
|
||||
}
|
||||
|
||||
static void decode_sse_unary(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b)
|
||||
{
|
||||
if (!(s->prefix & (PREFIX_REPZ | PREFIX_REPNZ))) {
|
||||
@@ -871,8 +882,8 @@ static const X86OpEntry opcodes_0F[256] = {
|
||||
[0x2B] = X86_OP_GROUP0(0F2B),
|
||||
[0x2C] = X86_OP_GROUP0(0F2C),
|
||||
[0x2D] = X86_OP_GROUP0(0F2D),
|
||||
[0x2E] = X86_OP_ENTRY3(VUCOMI, None,None, V,x, W,x, vex4 p_00_66),
|
||||
[0x2F] = X86_OP_ENTRY3(VCOMI, None,None, V,x, W,x, vex4 p_00_66),
|
||||
[0x2E] = X86_OP_GROUP3(VxCOMISx, None,None, V,x, W,x, vex3 p_00_66), /* VUCOMISS/SD */
|
||||
[0x2F] = X86_OP_GROUP3(VxCOMISx, None,None, V,x, W,x, vex3 p_00_66), /* VCOMISS/SD */
|
||||
|
||||
[0x38] = X86_OP_GROUP0(0F38),
|
||||
[0x3a] = X86_OP_GROUP0(0F3A),
|
||||
|
||||
@@ -2285,7 +2285,7 @@ static void gen_VZEROALL(DisasContext *s, CPUX86State *env, X86DecodedInsn *deco
|
||||
{
|
||||
TCGv_ptr ptr = tcg_temp_new_ptr();
|
||||
|
||||
tcg_gen_addi_ptr(ptr, cpu_env, offsetof(CPUX86State, xmm_t0));
|
||||
tcg_gen_addi_ptr(ptr, cpu_env, offsetof(CPUX86State, xmm_regs));
|
||||
gen_helper_memset(ptr, ptr, tcg_constant_i32(0),
|
||||
tcg_constant_ptr(CPU_NB_REGS * sizeof(ZMMReg)));
|
||||
}
|
||||
|
||||
@@ -2058,7 +2058,7 @@ static bool trans_VEXPANDQM(DisasContext *ctx, arg_VX_tb *a)
|
||||
static bool do_vextractm(DisasContext *ctx, arg_VX_tb *a, unsigned vece)
|
||||
{
|
||||
const uint64_t elem_width = 8 << vece, elem_count_half = 8 >> vece,
|
||||
mask = dup_const(vece, 1 << (elem_width - 1));
|
||||
mask = dup_const(vece, 1ULL << (elem_width - 1));
|
||||
uint64_t i, j;
|
||||
TCGv_i64 lo, hi, t0, t1;
|
||||
|
||||
|
||||
+9
-2
@@ -3797,6 +3797,11 @@ static inline RISCVException riscv_csrrw_check(CPURISCVState *env,
|
||||
return RISCV_EXCP_ILLEGAL_INST;
|
||||
}
|
||||
|
||||
/* ensure CSR is implemented by checking predicate */
|
||||
if (!csr_ops[csrno].predicate) {
|
||||
return RISCV_EXCP_ILLEGAL_INST;
|
||||
}
|
||||
|
||||
/* privileged spec version check */
|
||||
if (env->priv_ver < csr_min_priv) {
|
||||
return RISCV_EXCP_ILLEGAL_INST;
|
||||
@@ -3814,7 +3819,6 @@ static inline RISCVException riscv_csrrw_check(CPURISCVState *env,
|
||||
* illegal instruction exception should be triggered instead of virtual
|
||||
* instruction exception. Hence this comes after the read / write check.
|
||||
*/
|
||||
g_assert(csr_ops[csrno].predicate != NULL);
|
||||
RISCVException ret = csr_ops[csrno].predicate(env, csrno);
|
||||
if (ret != RISCV_EXCP_NONE) {
|
||||
return ret;
|
||||
@@ -3991,7 +3995,10 @@ RISCVException riscv_csrrw_debug(CPURISCVState *env, int csrno,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Control and Status Register function table */
|
||||
/*
|
||||
* Control and Status Register function table
|
||||
* riscv_csr_operations::predicate() must be provided for an implemented CSR
|
||||
*/
|
||||
riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
|
||||
/* User Floating-Point CSRs */
|
||||
[CSR_FFLAGS] = { "fflags", fs, read_fflags, write_fflags },
|
||||
|
||||
@@ -77,6 +77,9 @@ static bool trans_sret(DisasContext *ctx, arg_sret *a)
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
if (has_ext(ctx, RVS)) {
|
||||
decode_save_opc(ctx);
|
||||
if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
|
||||
gen_io_start();
|
||||
}
|
||||
gen_helper_sret(cpu_pc, cpu_env);
|
||||
exit_tb(ctx); /* no chaining */
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
@@ -93,6 +96,9 @@ static bool trans_mret(DisasContext *ctx, arg_mret *a)
|
||||
{
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
decode_save_opc(ctx);
|
||||
if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
|
||||
gen_io_start();
|
||||
}
|
||||
gen_helper_mret(cpu_pc, cpu_env);
|
||||
exit_tb(ctx); /* no chaining */
|
||||
ctx->base.is_jmp = DISAS_NORETURN;
|
||||
|
||||
@@ -606,7 +606,7 @@
|
||||
F(0xed04, LDEB, RXE, Z, 0, m2_32u, new, f1, ldeb, 0, IF_BFP)
|
||||
F(0xed05, LXDB, RXE, Z, 0, m2_64, new_x, x1, lxdb, 0, IF_BFP)
|
||||
F(0xed06, LXEB, RXE, Z, 0, m2_32u, new_x, x1, lxeb, 0, IF_BFP)
|
||||
F(0xb324, LDER, RXE, Z, 0, e2, new, f1, lde, 0, IF_AFP1)
|
||||
F(0xb324, LDER, RRE, Z, 0, e2, new, f1, lde, 0, IF_AFP1)
|
||||
F(0xed24, LDE, RXE, Z, 0, m2_32u, new, f1, lde, 0, IF_AFP1)
|
||||
/* LOAD ROUNDED */
|
||||
F(0xb344, LEDBR, RRF_e, Z, 0, f2, new, e1, ledb, 0, IF_BFP)
|
||||
|
||||
@@ -1534,18 +1534,51 @@ static DisasJumpType op_bal(DisasContext *s, DisasOps *o)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Disassemble the target of a branch. The results are returned in a form
|
||||
* suitable for passing into help_branch():
|
||||
*
|
||||
* - bool IS_IMM reflects whether the target is fixed or computed. Non-EXECUTEd
|
||||
* branches, whose DisasContext *S contains the relative immediate field RI,
|
||||
* are considered fixed. All the other branches are considered computed.
|
||||
* - int IMM is the value of RI.
|
||||
* - TCGv_i64 CDEST is the address of the computed target.
|
||||
*/
|
||||
#define disas_jdest(s, ri, is_imm, imm, cdest) do { \
|
||||
if (have_field(s, ri)) { \
|
||||
if (unlikely(s->ex_value)) { \
|
||||
cdest = tcg_temp_new_i64(); \
|
||||
tcg_gen_ld_i64(cdest, cpu_env, offsetof(CPUS390XState, ex_target));\
|
||||
tcg_gen_addi_i64(cdest, cdest, (int64_t)get_field(s, ri) * 2); \
|
||||
is_imm = false; \
|
||||
} else { \
|
||||
is_imm = true; \
|
||||
} \
|
||||
} else { \
|
||||
is_imm = false; \
|
||||
} \
|
||||
imm = is_imm ? get_field(s, ri) : 0; \
|
||||
} while (false)
|
||||
|
||||
static DisasJumpType op_basi(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
DisasCompare c;
|
||||
bool is_imm;
|
||||
int imm;
|
||||
|
||||
pc_to_link_info(o->out, s, s->pc_tmp);
|
||||
return help_goto_direct(s, s->base.pc_next + (int64_t)get_field(s, i2) * 2);
|
||||
|
||||
disas_jdest(s, i2, is_imm, imm, o->in2);
|
||||
disas_jcc(s, &c, 0xf);
|
||||
return help_branch(s, &c, is_imm, imm, o->in2);
|
||||
}
|
||||
|
||||
static DisasJumpType op_bc(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
int m1 = get_field(s, m1);
|
||||
bool is_imm = have_field(s, i2);
|
||||
int imm = is_imm ? get_field(s, i2) : 0;
|
||||
DisasCompare c;
|
||||
bool is_imm;
|
||||
int imm;
|
||||
|
||||
/* BCR with R2 = 0 causes no branching */
|
||||
if (have_field(s, r2) && get_field(s, r2) == 0) {
|
||||
@@ -1562,6 +1595,7 @@ static DisasJumpType op_bc(DisasContext *s, DisasOps *o)
|
||||
return DISAS_NEXT;
|
||||
}
|
||||
|
||||
disas_jdest(s, i2, is_imm, imm, o->in2);
|
||||
disas_jcc(s, &c, m1);
|
||||
return help_branch(s, &c, is_imm, imm, o->in2);
|
||||
}
|
||||
@@ -1569,10 +1603,10 @@ static DisasJumpType op_bc(DisasContext *s, DisasOps *o)
|
||||
static DisasJumpType op_bct32(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
int r1 = get_field(s, r1);
|
||||
bool is_imm = have_field(s, i2);
|
||||
int imm = is_imm ? get_field(s, i2) : 0;
|
||||
DisasCompare c;
|
||||
bool is_imm;
|
||||
TCGv_i64 t;
|
||||
int imm;
|
||||
|
||||
c.cond = TCG_COND_NE;
|
||||
c.is_64 = false;
|
||||
@@ -1584,6 +1618,7 @@ static DisasJumpType op_bct32(DisasContext *s, DisasOps *o)
|
||||
c.u.s32.b = tcg_constant_i32(0);
|
||||
tcg_gen_extrl_i64_i32(c.u.s32.a, t);
|
||||
|
||||
disas_jdest(s, i2, is_imm, imm, o->in2);
|
||||
return help_branch(s, &c, is_imm, imm, o->in2);
|
||||
}
|
||||
|
||||
@@ -1611,9 +1646,9 @@ static DisasJumpType op_bcth(DisasContext *s, DisasOps *o)
|
||||
static DisasJumpType op_bct64(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
int r1 = get_field(s, r1);
|
||||
bool is_imm = have_field(s, i2);
|
||||
int imm = is_imm ? get_field(s, i2) : 0;
|
||||
DisasCompare c;
|
||||
bool is_imm;
|
||||
int imm;
|
||||
|
||||
c.cond = TCG_COND_NE;
|
||||
c.is_64 = true;
|
||||
@@ -1622,6 +1657,7 @@ static DisasJumpType op_bct64(DisasContext *s, DisasOps *o)
|
||||
c.u.s64.a = regs[r1];
|
||||
c.u.s64.b = tcg_constant_i64(0);
|
||||
|
||||
disas_jdest(s, i2, is_imm, imm, o->in2);
|
||||
return help_branch(s, &c, is_imm, imm, o->in2);
|
||||
}
|
||||
|
||||
@@ -1629,10 +1665,10 @@ static DisasJumpType op_bx32(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
int r1 = get_field(s, r1);
|
||||
int r3 = get_field(s, r3);
|
||||
bool is_imm = have_field(s, i2);
|
||||
int imm = is_imm ? get_field(s, i2) : 0;
|
||||
DisasCompare c;
|
||||
bool is_imm;
|
||||
TCGv_i64 t;
|
||||
int imm;
|
||||
|
||||
c.cond = (s->insn->data ? TCG_COND_LE : TCG_COND_GT);
|
||||
c.is_64 = false;
|
||||
@@ -1645,6 +1681,7 @@ static DisasJumpType op_bx32(DisasContext *s, DisasOps *o)
|
||||
tcg_gen_extrl_i64_i32(c.u.s32.b, regs[r3 | 1]);
|
||||
store_reg32_i64(r1, t);
|
||||
|
||||
disas_jdest(s, i2, is_imm, imm, o->in2);
|
||||
return help_branch(s, &c, is_imm, imm, o->in2);
|
||||
}
|
||||
|
||||
@@ -1652,9 +1689,9 @@ static DisasJumpType op_bx64(DisasContext *s, DisasOps *o)
|
||||
{
|
||||
int r1 = get_field(s, r1);
|
||||
int r3 = get_field(s, r3);
|
||||
bool is_imm = have_field(s, i2);
|
||||
int imm = is_imm ? get_field(s, i2) : 0;
|
||||
DisasCompare c;
|
||||
bool is_imm;
|
||||
int imm;
|
||||
|
||||
c.cond = (s->insn->data ? TCG_COND_LE : TCG_COND_GT);
|
||||
c.is_64 = true;
|
||||
@@ -1668,6 +1705,7 @@ static DisasJumpType op_bx64(DisasContext *s, DisasOps *o)
|
||||
tcg_gen_add_i64(regs[r1], regs[r1], regs[r3]);
|
||||
c.u.s64.a = regs[r1];
|
||||
|
||||
disas_jdest(s, i2, is_imm, imm, o->in2);
|
||||
return help_branch(s, &c, is_imm, imm, o->in2);
|
||||
}
|
||||
|
||||
@@ -1685,10 +1723,9 @@ static DisasJumpType op_cj(DisasContext *s, DisasOps *o)
|
||||
c.u.s64.a = o->in1;
|
||||
c.u.s64.b = o->in2;
|
||||
|
||||
is_imm = have_field(s, i4);
|
||||
if (is_imm) {
|
||||
imm = get_field(s, i4);
|
||||
} else {
|
||||
o->out = NULL;
|
||||
disas_jdest(s, i4, is_imm, imm, o->out);
|
||||
if (!is_imm && !o->out) {
|
||||
imm = 0;
|
||||
o->out = get_address(s, 0, get_field(s, b4),
|
||||
get_field(s, d4));
|
||||
@@ -5774,15 +5811,13 @@ static void in2_a2(DisasContext *s, DisasOps *o)
|
||||
|
||||
static TCGv gen_ri2(DisasContext *s)
|
||||
{
|
||||
int64_t delta = (int64_t)get_field(s, i2) * 2;
|
||||
TCGv ri2;
|
||||
TCGv ri2 = NULL;
|
||||
bool is_imm;
|
||||
int imm;
|
||||
|
||||
if (unlikely(s->ex_value)) {
|
||||
ri2 = tcg_temp_new_i64();
|
||||
tcg_gen_ld_i64(ri2, cpu_env, offsetof(CPUS390XState, ex_target));
|
||||
tcg_gen_addi_i64(ri2, ri2, delta);
|
||||
} else {
|
||||
ri2 = tcg_constant_i64(s->base.pc_next + delta);
|
||||
disas_jdest(s, i2, is_imm, imm, ri2);
|
||||
if (is_imm) {
|
||||
ri2 = tcg_constant_i64(s->base.pc_next + imm * 2);
|
||||
}
|
||||
|
||||
return ri2;
|
||||
|
||||
@@ -1083,7 +1083,7 @@ static void tcg_out_addi_ptr(TCGContext *s, TCGReg rd, TCGReg rs,
|
||||
{
|
||||
/* This function is only used for passing structs by reference. */
|
||||
tcg_debug_assert(imm == (int32_t)imm);
|
||||
tcg_out_modrm_offset(s, OPC_LEA, rd, rs, imm);
|
||||
tcg_out_modrm_offset(s, OPC_LEA | P_REXW, rd, rs, imm);
|
||||
}
|
||||
|
||||
static inline void tcg_out_pushi(TCGContext *s, tcg_target_long val)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# using a prebuilt toolchains for Xtensa cores from:
|
||||
# https://github.com/foss-xtensa/toolchain/releases
|
||||
#
|
||||
FROM docker.io/library/debian:stretch-slim
|
||||
FROM docker.io/library/debian:11-slim
|
||||
|
||||
RUN apt-get update && \
|
||||
DEBIAN_FRONTEND=noninteractive apt install -yy eatmydata && \
|
||||
|
||||
@@ -8,6 +8,36 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "libqtest.h"
|
||||
|
||||
/*
|
||||
* This used to trigger a DMA reentrancy issue
|
||||
* leading to memory corruption bugs like stack
|
||||
* overflow or use-after-free
|
||||
* https://gitlab.com/qemu-project/qemu/-/issues/1563
|
||||
*/
|
||||
static void test_lsi_dma_reentrancy(void)
|
||||
{
|
||||
QTestState *s;
|
||||
|
||||
s = qtest_init("-M q35 -m 512M -nodefaults "
|
||||
"-blockdev driver=null-co,node-name=null0 "
|
||||
"-device lsi53c810 -device scsi-cd,drive=null0");
|
||||
|
||||
qtest_outl(s, 0xcf8, 0x80000804); /* PCI Command Register */
|
||||
qtest_outw(s, 0xcfc, 0x7); /* Enables accesses */
|
||||
qtest_outl(s, 0xcf8, 0x80000814); /* Memory Bar 1 */
|
||||
qtest_outl(s, 0xcfc, 0xff100000); /* Set MMIO Address*/
|
||||
qtest_outl(s, 0xcf8, 0x80000818); /* Memory Bar 2 */
|
||||
qtest_outl(s, 0xcfc, 0xff000000); /* Set RAM Address*/
|
||||
qtest_writel(s, 0xff000000, 0xc0000024);
|
||||
qtest_writel(s, 0xff000114, 0x00000080);
|
||||
qtest_writel(s, 0xff00012c, 0xff000000);
|
||||
qtest_writel(s, 0xff000004, 0xff000114);
|
||||
qtest_writel(s, 0xff000008, 0xff100014);
|
||||
qtest_writel(s, 0xff10002f, 0x000000ff);
|
||||
|
||||
qtest_quit(s);
|
||||
}
|
||||
|
||||
/*
|
||||
* This used to trigger a UAF in lsi_do_msgout()
|
||||
* https://gitlab.com/qemu-project/qemu/-/issues/972
|
||||
@@ -124,5 +154,8 @@ int main(int argc, char **argv)
|
||||
qtest_add_func("fuzz/lsi53c895a/lsi_do_msgout_cancel_req",
|
||||
test_lsi_do_msgout_cancel_req);
|
||||
|
||||
qtest_add_func("fuzz/lsi53c895a/lsi_dma_reentrancy",
|
||||
test_lsi_dma_reentrancy);
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
|
||||
@@ -114,7 +114,10 @@ if have_block
|
||||
tests += {'test-crypto-xts': [crypto, io]}
|
||||
endif
|
||||
if 'CONFIG_POSIX' in config_host
|
||||
tests += {'test-image-locking': [testblock]}
|
||||
tests += {
|
||||
'test-image-locking': [testblock],
|
||||
'test-nested-aio-poll': [testblock],
|
||||
}
|
||||
endif
|
||||
if config_host_data.get('CONFIG_REPLICATION')
|
||||
tests += {'test-replication': [testblock]}
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Test that poll handlers are not re-entrant in nested aio_poll()
|
||||
*
|
||||
* Copyright Red Hat
|
||||
*
|
||||
* Poll handlers are usually level-triggered. That means they continue firing
|
||||
* until the condition is reset (e.g. a virtqueue becomes empty). If a poll
|
||||
* handler calls nested aio_poll() before the condition is reset, then infinite
|
||||
* recursion occurs.
|
||||
*
|
||||
* aio_poll() is supposed to prevent this by disabling poll handlers in nested
|
||||
* aio_poll() calls. This test case checks that this is indeed what happens.
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "block/aio.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
typedef struct {
|
||||
AioContext *ctx;
|
||||
|
||||
/* This is the EventNotifier that drives the test */
|
||||
EventNotifier poll_notifier;
|
||||
|
||||
/* This EventNotifier is only used to wake aio_poll() */
|
||||
EventNotifier dummy_notifier;
|
||||
|
||||
bool nested;
|
||||
} TestData;
|
||||
|
||||
static void io_read(EventNotifier *notifier)
|
||||
{
|
||||
fprintf(stderr, "%s %p\n", __func__, notifier);
|
||||
event_notifier_test_and_clear(notifier);
|
||||
}
|
||||
|
||||
static bool io_poll_true(void *opaque)
|
||||
{
|
||||
fprintf(stderr, "%s %p\n", __func__, opaque);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool io_poll_false(void *opaque)
|
||||
{
|
||||
fprintf(stderr, "%s %p\n", __func__, opaque);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void io_poll_ready(EventNotifier *notifier)
|
||||
{
|
||||
TestData *td = container_of(notifier, TestData, poll_notifier);
|
||||
|
||||
fprintf(stderr, "> %s\n", __func__);
|
||||
|
||||
g_assert(!td->nested);
|
||||
td->nested = true;
|
||||
|
||||
/* Wake the following nested aio_poll() call */
|
||||
event_notifier_set(&td->dummy_notifier);
|
||||
|
||||
/* This nested event loop must not call io_poll()/io_poll_ready() */
|
||||
g_assert(aio_poll(td->ctx, true));
|
||||
|
||||
td->nested = false;
|
||||
|
||||
fprintf(stderr, "< %s\n", __func__);
|
||||
}
|
||||
|
||||
/* dummy_notifier never triggers */
|
||||
static void io_poll_never_ready(EventNotifier *notifier)
|
||||
{
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
static void test(void)
|
||||
{
|
||||
TestData td = {
|
||||
.ctx = aio_context_new(&error_abort),
|
||||
};
|
||||
|
||||
qemu_set_current_aio_context(td.ctx);
|
||||
|
||||
/* Enable polling */
|
||||
aio_context_set_poll_params(td.ctx, 1000000, 2, 2, &error_abort);
|
||||
|
||||
/*
|
||||
* The GSource is unused but this has the side-effect of changing the fdmon
|
||||
* that AioContext uses.
|
||||
*/
|
||||
aio_get_g_source(td.ctx);
|
||||
|
||||
/* Make the event notifier active (set) right away */
|
||||
event_notifier_init(&td.poll_notifier, 1);
|
||||
aio_set_event_notifier(td.ctx, &td.poll_notifier, false,
|
||||
io_read, io_poll_true, io_poll_ready);
|
||||
|
||||
/* This event notifier will be used later */
|
||||
event_notifier_init(&td.dummy_notifier, 0);
|
||||
aio_set_event_notifier(td.ctx, &td.dummy_notifier, false,
|
||||
io_read, io_poll_false, io_poll_never_ready);
|
||||
|
||||
/* Consume aio_notify() */
|
||||
g_assert(!aio_poll(td.ctx, false));
|
||||
|
||||
/*
|
||||
* Run the io_read() handler. This has the side-effect of activating
|
||||
* polling in future aio_poll() calls.
|
||||
*/
|
||||
g_assert(aio_poll(td.ctx, true));
|
||||
|
||||
/* The second time around the io_poll()/io_poll_ready() handler runs */
|
||||
g_assert(aio_poll(td.ctx, true));
|
||||
|
||||
/* Run io_poll()/io_poll_ready() one more time to show it keeps working */
|
||||
g_assert(aio_poll(td.ctx, true));
|
||||
|
||||
aio_set_event_notifier(td.ctx, &td.dummy_notifier, false,
|
||||
NULL, NULL, NULL);
|
||||
aio_set_event_notifier(td.ctx, &td.poll_notifier, false, NULL, NULL, NULL);
|
||||
event_notifier_cleanup(&td.dummy_notifier);
|
||||
event_notifier_cleanup(&td.poll_notifier);
|
||||
aio_context_unref(td.ctx);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
g_test_add_func("/nested-aio-poll", test);
|
||||
return g_test_run();
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user