[Qemu-devel] [PATCH] block/mirror: fix fail to cancel when VM has heavy BLK IO
We found that when doing drive mirror to a low speed shared storage, if there was heavy BLK IO write workload in VM after the 'ready' event, drive mirror block job can't be canceled immediately, it would keep running until the heavy BLK IO workload stopped in the VM. This patch fixed this issue. Cc: Paolo BonziniCc: Jeff Cody Cc: Kevin Wolf Cc: Max Reitz Signed-off-by: Huaitong Han Signed-off-by: Liang Li --- block/mirror.c | 10 -- 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/block/mirror.c b/block/mirror.c index c9badc1..3bc49a5 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -869,11 +869,9 @@ static void coroutine_fn mirror_run(void *opaque) ret = 0; trace_mirror_before_sleep(s, cnt, s->synced, delay_ns); -if (!s->synced) { -block_job_sleep_ns(>common, delay_ns); -if (block_job_is_cancelled(>common)) { -break; -} + +if (block_job_is_cancelled(>common)) { +break; } else if (!should_complete) { delay_ns = (s->in_flight == 0 && cnt == 0 ? SLICE_TIME : 0); block_job_sleep_ns(>common, delay_ns); @@ -887,7 +885,7 @@ immediate_exit: * or it was cancelled prematurely so that we do not guarantee that * the target is a copy of the source. */ -assert(ret < 0 || (!s->synced && block_job_is_cancelled(>common))); +assert(ret < 0 || block_job_is_cancelled(>common)); assert(need_drain); mirror_wait_for_all_io(s); } -- 1.8.3.1
Re: [Qemu-devel] [PATCH v5 00/28] Migration: postcopy failure recovery
On Fri, Jan 12, 2018 at 12:27:42PM +, Dr. David Alan Gilbert wrote: > * Peter Xu (pet...@redhat.com) wrote: > > On Thu, Jan 11, 2018 at 04:59:32PM +, Dr. David Alan Gilbert wrote: > > > * Peter Xu (pet...@redhat.com) wrote: > > > > Tree is pushed here for better reference and testing (online tree > > > > includes monitor OOB series): > > > > > > > > https://github.com/xzpeter/qemu/tree/postcopy-recover-all > > > > > > > > This version removed quite a few patches related to migrate-incoming, > > > > instead I introduced a new command "migrate-recover" to trigger the > > > > recovery channel on destination side to simplify the code. > > > > > > I've got this setup on a couple of my test hosts, and I'm using > > > iptables to try breaking the connection. > > > > > > See below for where I got stuck. > > > > > > > To test this two series altogether, please checkout above tree and > > > > build. Note: to test on small and single host, one need to disable > > > > full bandwidth postcopy migration otherwise it'll complete very fast. > > > > Basically a simple patch like this would help: > > > > > > > > diff --git a/migration/migration.c b/migration/migration.c > > > > index 4de3b551fe..c0206023d7 100644 > > > > --- a/migration/migration.c > > > > +++ b/migration/migration.c > > > > @@ -1904,7 +1904,7 @@ static int postcopy_start(MigrationState *ms, > > > > bool *old_vm_running) > > > > * will notice we're in POSTCOPY_ACTIVE and not actually > > > > * wrap their state up here > > > > */ > > > > -qemu_file_set_rate_limit(ms->to_dst_file, INT64_MAX); > > > > +// qemu_file_set_rate_limit(ms->to_dst_file, INT64_MAX); > > > > if (migrate_postcopy_ram()) { > > > > /* Ping just for debugging, helps line traces up */ > > > > qemu_savevm_send_ping(ms->to_dst_file, 2); > > > > > > > > This patch is included already in above github tree. Please feel free > > > > to drop this patch when want to test on big machines and between real > > > > hosts. > > > > > > > > Detailed Test Procedures (QMP only) > > > > === > > > > > > > > 1. start source QEMU. > > > > > > > > $qemu -M q35,kernel-irqchip=split -enable-kvm -snapshot \ > > > > -smp 4 -m 1G -qmp stdio \ > > > > -name peter-vm,debug-threads=on \ > > > > -netdev user,id=net0 \ > > > > -device e1000,netdev=net0 \ > > > > -global migration.x-max-bandwidth=4096 \ > > > > -global migration.x-postcopy-ram=on \ > > > > /images/fedora-25.qcow2 > > > > > > > > 2. start destination QEMU. > > > > > > > > $qemu -M q35,kernel-irqchip=split -enable-kvm -snapshot \ > > > > -smp 4 -m 1G -qmp stdio \ > > > > -name peter-vm,debug-threads=on \ > > > > -netdev user,id=net0 \ > > > > -device e1000,netdev=net0 \ > > > > -global migration.x-max-bandwidth=4096 \ > > > > -global migration.x-postcopy-ram=on \ > > > > -incoming tcp:0.0.0.0: \ > > > > /images/fedora-25.qcow2 > > > > > > I'm using: > > > ./x86_64-softmmu/qemu-system-x86_64 -nographic -M pc,accel=kvm -smp 4 -m > > > 16G -drive file=/home/vms/rhel71.qcow2,id=d,cache=none,if=none -device > > > virtio-blk,drive=d -vnc 0:0 -incoming tcp:0: -chardev > > > socket,port=4000,host=0,id=mon,server,nowait,telnet -mon > > > chardev=mon,id=mon,mode=control -nographic -chardev stdio,mux=on,id=monh > > > -mon chardev=monh,mode=readline --device isa-serial,chardev=monh > > > and I've got both the HMP on the stdio, and the QMP via a telnet > > > > > > > > > > > 3. On source, do QMP handshake as normal: > > > > > > > > {"execute": "qmp_capabilities"} > > > > {"return": {}} > > > > > > > > 4. On destination, do QMP handshake to enable OOB: > > > > > > > > {"execute": "qmp_capabilities", "arguments": { "enable": [ "oob" ] } } > > > > {"return": {}} > > > > > > > > 5. On source, trigger initial migrate command, switch to postcopy: > > > > > > > > {"execute": "migrate", "arguments": { "uri": "tcp:localhost:" } } > > > > {"return": {}} > > > > {"execute": "query-migrate"} > > > > {"return": {"expected-downtime": 300, "status": "active", ...}} > > > > {"execute": "migrate-start-postcopy"} > > > > {"return": {}} > > > > {"timestamp": {"seconds": 1512454728, "microseconds": 768096}, > > > > "event": "STOP"} > > > > {"execute": "query-migrate"} > > > > {"return": {"expected-downtime": 44472, "status": "postcopy-active", > > > > ...}} > > > > > > > > 6. On source, manually trigger a "fake network down" using > > > >"migrate-cancel" command: > > > > > > > > {"execute": "migrate_cancel"} > > > > {"return": {}} > > > > > > Before I do that, I'm breaking the network connection by running on the > > > source: > > > iptables -A INPUT -p tcp --source-port -j DROP > > > iptables -A INPUT -p tcp --destination-port -j DROP > > > > This is tricky... I think tcp keepalive may help, but for sure I > > think we do need a way to
[Qemu-devel] [PATCH v7 23/23] tests: qmp-test: add oob test
Test the new OOB capability. Here we used the new "x-oob-test" command. Firstly, we send a lock=true and oob=false command to hang the main thread. Then send another lock=false and oob=true command (which will be run inside parser this time) to free that hanged command. Reviewed-by: Stefan HajnocziSigned-off-by: Peter Xu --- tests/qmp-test.c | 65 1 file changed, 65 insertions(+) diff --git a/tests/qmp-test.c b/tests/qmp-test.c index 19fa774486..c41e8305b6 100644 --- a/tests/qmp-test.c +++ b/tests/qmp-test.c @@ -160,6 +160,70 @@ static void test_qmp_protocol(void) qtest_end(); } +/* Tests for Out-Of-Band support. */ +static void test_qmp_oob(void) +{ +QDict *resp; +int acks = 0; +const char *cmd_id; + +global_qtest = qtest_init_without_qmp_handshake(common_args); + +/* Ignore the greeting message. */ +resp = qmp_receive(); +g_assert(qdict_get_qdict(resp, "QMP")); +QDECREF(resp); + +/* Try a fake capability, it should fail. */ +resp = qmp("{ 'execute': 'qmp_capabilities', " + " 'arguments': { 'enable': [ 'cap-does-not-exist' ] } }"); +g_assert(qdict_haskey(resp, "error")); +QDECREF(resp); + +/* Now, enable OOB in current QMP session, it should success. */ +resp = qmp("{ 'execute': 'qmp_capabilities', " + " 'arguments': { 'enable': [ 'oob' ] } }"); +g_assert(qdict_haskey(resp, "return")); +QDECREF(resp); + +/* + * Try any command that does not support OOB but with OOB flag. We + * should get failure. + */ +resp = qmp("{ 'execute': 'query-cpus'," + " 'control': { 'run-oob': true } }"); +g_assert(qdict_haskey(resp, "error")); +QDECREF(resp); + +/* + * Firstly send the "x-oob-test" command with lock=true and + * oob=false, it should hang the dispatcher and main thread; + * later, we send another lock=false with oob=true to continue + * that thread processing. Finally we should receive replies from + * both commands. + */ +qmp_async("{ 'execute': 'x-oob-test'," + " 'arguments': { 'lock': true }, " + " 'id': 'lock-cmd'}"); +qmp_async("{ 'execute': 'x-oob-test', " + " 'arguments': { 'lock': false }, " + " 'control': { 'run-oob': true }, " + " 'id': 'unlock-cmd' }"); + +/* Ignore all events. Wait for 2 acks */ +while (acks < 2) { +resp = qmp_receive(); +cmd_id = qdict_get_str(resp, "id"); +if (!g_strcmp0(cmd_id, "lock-cmd") || +!g_strcmp0(cmd_id, "unlock-cmd")) { +acks++; +} +QDECREF(resp); +} + +qtest_end(); +} + static int query_error_class(const char *cmd) { static struct { @@ -339,6 +403,7 @@ int main(int argc, char *argv[]) g_test_init(, , NULL); qtest_add_func("qmp/protocol", test_qmp_protocol); +qtest_add_func("qmp/oob", test_qmp_oob); qmp_schema_init(); add_query_tests(); -- 2.14.3
[Qemu-devel] [PATCH v7 22/23] tests: qmp-test: verify command batching
OOB introduced DROP event for flow control. This should not affect old QMP clients. Add a command batching check to make sure of it. Reviewed-by: Stefan HajnocziSigned-off-by: Peter Xu --- tests/qmp-test.c | 22 ++ 1 file changed, 22 insertions(+) diff --git a/tests/qmp-test.c b/tests/qmp-test.c index 11b384c829..19fa774486 100644 --- a/tests/qmp-test.c +++ b/tests/qmp-test.c @@ -78,6 +78,7 @@ static void test_qmp_protocol(void) QList *capabilities; const QListEntry *entry; QString *qstr; +int i; global_qtest = qtest_init_without_qmp_handshake(common_args); @@ -135,6 +136,27 @@ static void test_qmp_protocol(void) g_assert_cmpint(qdict_get_int(resp, "id"), ==, 2); QDECREF(resp); +/* + * Test command batching. In current test OOB is not enabled, we + * should be able to run as many commands in batch as we like. + * Using 16 (>8, which is OOB queue length) to make sure OOB won't + * break existing clients. Note: this test does not control the + * scheduling of QEMU's QMP command processing threads so it may + * not really trigger batching inside QEMU. This is just a + * best-effort test. + */ +for (i = 0; i < 16; i++) { +qmp_async("{ 'execute': 'query-version' }"); +} +/* Verify the replies to make sure no command is dropped. */ +for (i = 0; i < 16; i++) { +resp = qmp_receive(); +/* It should never be dropped. Each of them should be a reply. */ +g_assert(qdict_haskey(resp, "return")); +g_assert(!qdict_haskey(resp, "event")); +QDECREF(resp); +} + qtest_end(); } -- 2.14.3
[Qemu-devel] [PATCH v7 17/23] qapi: introduce new cmd option "allow-oob"
Here "oob" stands for "Out-Of-Band". When "allow-oob" is set, it means the command allows out-of-band execution. The "oob" idea is proposed by Markus Armbruster in following thread: https://lists.gnu.org/archive/html/qemu-devel/2017-09/msg02057.html This new "allow-oob" boolean will be exposed by "query-qmp-schema" as well for command entries, so that QMP clients can know which command can be used as out-of-band calls. For example the command "migrate" originally looks like: {"name": "migrate", "ret-type": "17", "meta-type": "command", "arg-type": "86"} And it'll be changed into: {"name": "migrate", "ret-type": "17", "allow-oob": false, "meta-type": "command", "arg-type": "86"} This patch only provides the QMP interface level changes. It does not contains the real out-of-band execution implementation yet. Suggested-by: Markus ArmbrusterReviewed-by: Stefan Hajnoczi Reviewed-by: Fam Zheng Signed-off-by: Peter Xu --- include/qapi/qmp/dispatch.h| 1 + qapi/introspect.json | 6 +- scripts/qapi-commands.py | 19 ++- scripts/qapi-introspect.py | 10 -- scripts/qapi.py| 15 ++- scripts/qapi2texi.py | 2 +- tests/qapi-schema/test-qapi.py | 2 +- 7 files changed, 40 insertions(+), 15 deletions(-) diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h index 20578dcd48..b76798800c 100644 --- a/include/qapi/qmp/dispatch.h +++ b/include/qapi/qmp/dispatch.h @@ -23,6 +23,7 @@ typedef enum QmpCommandOptions { QCO_NO_OPTIONS = 0x0, QCO_NO_SUCCESS_RESP = 0x1, +QCO_ALLOW_OOB = 0x2, } QmpCommandOptions; typedef struct QmpCommand diff --git a/qapi/introspect.json b/qapi/introspect.json index 5b3e6e9d78..c7f67b7d78 100644 --- a/qapi/introspect.json +++ b/qapi/introspect.json @@ -259,12 +259,16 @@ # # @ret-type: the name of the command's result type. # +# @allow-oob: whether the command allows out-of-band execution. +# (Since: 2.12) +# # TODO: @success-response (currently irrelevant, because it's QGA, not QMP) # # Since: 2.5 ## { 'struct': 'SchemaInfoCommand', - 'data': { 'arg-type': 'str', 'ret-type': 'str' } } + 'data': { 'arg-type': 'str', 'ret-type': 'str', +'allow-oob': 'bool' } } ## # @SchemaInfoEvent: diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py index 974d0a4a80..b2b0bc0510 100644 --- a/scripts/qapi-commands.py +++ b/scripts/qapi-commands.py @@ -192,10 +192,18 @@ out: return ret -def gen_register_command(name, success_response): -options = 'QCO_NO_OPTIONS' +def gen_register_command(name, success_response, allow_oob): +options = [] + if not success_response: -options = 'QCO_NO_SUCCESS_RESP' +options += ['QCO_NO_SUCCESS_RESP'] +if allow_oob: +options += ['QCO_ALLOW_OOB'] + +if not options: +options = ['QCO_NO_OPTIONS'] + +options = " | ".join(options) ret = mcgen(''' qmp_register_command(cmds, "%(name)s", @@ -241,7 +249,7 @@ class QAPISchemaGenCommandVisitor(QAPISchemaVisitor): self._visited_ret_types = None def visit_command(self, name, info, arg_type, ret_type, - gen, success_response, boxed): + gen, success_response, boxed, allow_oob): if not gen: return self.decl += gen_command_decl(name, arg_type, boxed, ret_type) @@ -250,7 +258,8 @@ class QAPISchemaGenCommandVisitor(QAPISchemaVisitor): self.defn += gen_marshal_output(ret_type) self.decl += gen_marshal_decl(name) self.defn += gen_marshal(name, arg_type, boxed, ret_type) -self._regy += gen_register_command(name, success_response) +self._regy += gen_register_command(name, success_response, + allow_oob) (input_file, output_dir, do_c, do_h, prefix, opts) = parse_command_line() diff --git a/scripts/qapi-introspect.py b/scripts/qapi-introspect.py index 032bcea491..9fbf88b644 100644 --- a/scripts/qapi-introspect.py +++ b/scripts/qapi-introspect.py @@ -28,6 +28,11 @@ def to_json(obj, level=0): to_json(obj[key], level + 1)) for key in sorted(obj.keys())] ret = '{' + ', '.join(elts) + '}' +elif isinstance(obj, bool): +if obj: +ret = 'true' +else: +ret = 'false' else: assert False# not implemented if level == 1: @@ -154,12 +159,13 @@ const char %(c_name)s[] = %(c_string)s; for m in variants.variants]}) def visit_command(self, name, info, arg_type, ret_type, - gen, success_response, boxed): + gen, success_response, boxed, allow_oob): arg_type = arg_type or self._schema.the_empty_object_type ret_type =
[Qemu-devel] [PATCH v7 20/23] monitor: enable IO thread for (qmp & !mux) typed
Start to use dedicate IO thread for QMP monitors that are not using MUXed chardev. Reviewed-by: Fam ZhengReviewed-by: Stefan Hajnoczi Signed-off-by: Peter Xu --- monitor.c | 5 - 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/monitor.c b/monitor.c index eac92c9b86..5b7da2b574 100644 --- a/monitor.c +++ b/monitor.c @@ -36,6 +36,7 @@ #include "net/slirp.h" #include "chardev/char-fe.h" #include "chardev/char-io.h" +#include "chardev/char-mux.h" #include "ui/qemu-spice.h" #include "sysemu/numa.h" #include "monitor/monitor.h" @@ -4579,8 +4580,10 @@ static void monitor_qmp_setup_handlers(void *data) void monitor_init(Chardev *chr, int flags) { Monitor *mon = g_malloc(sizeof(*mon)); +/* Enable IOThread for QMPs that are not using MUX chardev backends. */ +bool use_io_thr = (!CHARDEV_IS_MUX(chr)) && (flags & MONITOR_USE_CONTROL); -monitor_data_init(mon, false, false); +monitor_data_init(mon, false, use_io_thr); qemu_chr_fe_init(>chr, chr, _abort); mon->flags = flags; -- 2.14.3
[Qemu-devel] [PATCH v7 16/23] monitor: send event when command queue full
Set maximum QMP command queue length to 8. If queue full, instead of queue the command, we directly return a "command-dropped" event, telling client that specific command is dropped. Note that this flow control mechanism is only valid if OOB is enabled. If it's not, the effective queue length will always be 1, which strictly follows original behavior of QMP command handling (which never drop messages). Signed-off-by: Peter Xu--- monitor.c | 18 +- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/monitor.c b/monitor.c index 51d12412fa..bf0f3d1662 100644 --- a/monitor.c +++ b/monitor.c @@ -4055,6 +4055,8 @@ static void monitor_qmp_bh_dispatcher(void *data) } } +#define QMP_REQ_QUEUE_LEN_MAX (8) + static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens) { QObject *req, *id = NULL; @@ -4088,6 +4090,9 @@ static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens) req_obj->req = req; req_obj->need_resume = false; +/* Protect qmp_requests and fetching its length. */ +qemu_mutex_lock(>qmp.qmp_queue_lock); + /* * If OOB is not enabled on current monitor, we'll emulate the old * behavior that we won't process current monitor any more until @@ -4097,6 +4102,18 @@ static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens) if (!qmp_oob_enabled(mon)) { monitor_suspend(mon); req_obj->need_resume = true; +} else { +/* Drop the request if queue is full. */ +if (mon->qmp.qmp_requests->length >= QMP_REQ_QUEUE_LEN_MAX) { +qemu_mutex_unlock(>qmp.qmp_queue_lock); +qapi_event_send_command_dropped(id, +COMMAND_DROP_REASON_QUEUE_FULL, +NULL); +qobject_decref(id); +qobject_decref(req); +g_free(req_obj); +return; +} } /* @@ -4104,7 +4121,6 @@ static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens) * handled in time order. Ownership for req_obj, req, id, * etc. will be delivered to the handler side. */ -qemu_mutex_lock(>qmp.qmp_queue_lock); g_queue_push_tail(mon->qmp.qmp_requests, req_obj); qemu_mutex_unlock(>qmp.qmp_queue_lock); -- 2.14.3
[Qemu-devel] [PATCH v7 19/23] qmp: isolate responses into io thread
For those monitors who have enabled IO thread, we'll offload the responding procedure into IO thread. The main reason is that chardev is not thread safe, and we need to do all the read/write IOs in the same thread. For use_io_thr=true monitors, that thread is the IO thread. We do this isolation in similar pattern as what we have done to the request queue: we first create one response queue for each monitor, then instead of replying directly in the main thread, we queue the responses and kick the IO thread to do the rest of the job for us. A funny thing after doing this is that, when the QMP clients send "quit" to QEMU, it's possible that we close the IOThread even earlier than replying to that "quit". So another thing we need to do before cleaning up the monitors is that we need to flush the response queue (we don't need to do that for command queue; after all we are quitting) to make sure replies for handled commands are always flushed back to clients. Reviewed-by: Fam ZhengSigned-off-by: Peter Xu --- monitor.c | 96 ++- 1 file changed, 95 insertions(+), 1 deletion(-) diff --git a/monitor.c b/monitor.c index d31da3fd1b..eac92c9b86 100644 --- a/monitor.c +++ b/monitor.c @@ -175,6 +175,8 @@ typedef struct { QemuMutex qmp_queue_lock; /* Input queue that holds all the parsed QMP requests */ GQueue *qmp_requests; +/* Output queue contains all the QMP responses in order */ +GQueue *qmp_responses; } MonitorQMP; /* @@ -201,6 +203,7 @@ struct Monitor { bool skip_flush; bool use_io_thr; +/* We can't access guest memory when holding the lock */ QemuMutex out_lock; QString *outbuf; guint out_watch; @@ -223,6 +226,8 @@ static struct { IOThread *mon_iothread; /* Bottom half to dispatch the requests received from IO thread */ QEMUBH *qmp_dispatcher_bh; +/* Bottom half to deliver the responses back to clients */ +QEMUBH *qmp_respond_bh; } mon_global; /* QMP checker flags */ @@ -412,7 +417,8 @@ int monitor_fprintf(FILE *stream, const char *fmt, ...) return 0; } -static void monitor_json_emitter(Monitor *mon, const QObject *data) +static void monitor_json_emitter_raw(Monitor *mon, + QObject *data) { QString *json; @@ -426,6 +432,71 @@ static void monitor_json_emitter(Monitor *mon, const QObject *data) QDECREF(json); } +static void monitor_json_emitter(Monitor *mon, QObject *data) +{ +if (mon->use_io_thr) { +/* + * If using IO thread, we need to queue the item so that IO + * thread will do the rest for us. Take refcount so that + * caller won't free the data (which will be finally freed in + * responder thread). + */ +qobject_incref(data); +qemu_mutex_lock(>qmp.qmp_queue_lock); +g_queue_push_tail(mon->qmp.qmp_responses, (void *)data); +qemu_mutex_unlock(>qmp.qmp_queue_lock); +qemu_bh_schedule(mon_global.qmp_respond_bh); +} else { +/* + * If not using monitor IO thread, then we are in main thread. + * Do the emission right away. + */ +monitor_json_emitter_raw(mon, data); +} +} + +struct QMPResponse { +Monitor *mon; +QObject *data; +}; +typedef struct QMPResponse QMPResponse; + +/* + * Return one QMPResponse. The response is only valid if + * response.data is not NULL. + */ +static QMPResponse monitor_qmp_response_pop_one(void) +{ +Monitor *mon; +QObject *data = NULL; + +qemu_mutex_lock(_lock); +QTAILQ_FOREACH(mon, _list, entry) { +qemu_mutex_lock(>qmp.qmp_queue_lock); +data = g_queue_pop_head(mon->qmp.qmp_responses); +qemu_mutex_unlock(>qmp.qmp_queue_lock); +if (data) { +break; +} +} +qemu_mutex_unlock(_lock); +return (QMPResponse) { .mon = mon, .data = data }; +} + +static void monitor_qmp_bh_responder(void *opaque) +{ +QMPResponse response; + +while (true) { +response = monitor_qmp_response_pop_one(); +if (!response.data) { +break; +} +monitor_json_emitter_raw(response.mon, response.data); +qobject_decref(response.data); +} +} + static MonitorQAPIEventConf monitor_qapi_event_conf[QAPI_EVENT__MAX] = { /* Limit guest-triggerable events to 1 per second */ [QAPI_EVENT_RTC_CHANGE]= { 1000 * SCALE_MS }, @@ -612,6 +683,7 @@ static void monitor_data_init(Monitor *mon, bool skip_flush, mon->skip_flush = skip_flush; mon->use_io_thr = use_io_thr; mon->qmp.qmp_requests = g_queue_new(); +mon->qmp.qmp_responses = g_queue_new(); } static void monitor_data_destroy(Monitor *mon) @@ -626,6 +698,7 @@ static void monitor_data_destroy(Monitor *mon) qemu_mutex_destroy(>out_lock); qemu_mutex_destroy(>qmp.qmp_queue_lock);
[Qemu-devel] [PATCH v7 15/23] qmp: add new event "command-dropped"
This event will be emitted if one QMP command is dropped. Along, declare an enum for the reasons. Reviewed-by: Fam ZhengSigned-off-by: Peter Xu --- qapi-schema.json | 37 + 1 file changed, 37 insertions(+) diff --git a/qapi-schema.json b/qapi-schema.json index 2490d5188e..d6c89efc0d 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3215,3 +3215,40 @@ # Since: 2.11 ## { 'command': 'watchdog-set-action', 'data' : {'action': 'WatchdogAction'} } + +## +# @CommandDropReason: +# +# Reasons that caused one command to be dropped. +# +# @queue-full: the command queue is full. This can only occur when +# the client sends a new non-oob command before the +# response to the previous non-oob command has been +# received. +# +# Since: 2.12 +## +{ 'enum': 'CommandDropReason', + 'data': [ 'queue-full' ] } + +## +# @COMMAND_DROPPED: +# +# Emitted when a command is dropped due to some reason. Commands can +# only be dropped when the oob capability is enabled. +# +# @id: The dropped command's "id" field. +# +# @reason: The reason why the command is dropped. +# +# Since: 2.12 +# +# Example: +# +# { "event": "COMMAND_DROPPED", +# "data": {"result": {"id": "libvirt-102", +# "reason": "queue-full" } } } +# +## +{ 'event': 'COMMAND_DROPPED' , + 'data': { 'id': 'any', 'reason': 'CommandDropReason' } } -- 2.14.3
[Qemu-devel] [PATCH v7 18/23] qmp: support out-of-band (oob) execution
Having "allow-oob" to true for a command does not mean that this command will always be run in out-of-band mode. The out-of-band quick path will only be executed if we specify the extra "run-oob" flag when sending the QMP request: { "execute": "command-that-allows-oob", "arguments": { ... }, "control": { "run-oob": true } } The "control" key is introduced to store this extra flag. "control" field is used to store arguments that are shared by all the commands, rather than command specific arguments. Let "run-oob" be the first. Note that in the patch I exported qmp_dispatch_check_obj() to be used to check the request earlier, and at the same time allowed "id" field to be there since actually we always allow that. Signed-off-by: Peter Xu--- include/qapi/qmp/dispatch.h | 2 ++ monitor.c | 84 - qapi/qmp-dispatch.c | 32 - trace-events| 2 ++ 4 files changed, 110 insertions(+), 10 deletions(-) diff --git a/include/qapi/qmp/dispatch.h b/include/qapi/qmp/dispatch.h index b76798800c..d8d913b338 100644 --- a/include/qapi/qmp/dispatch.h +++ b/include/qapi/qmp/dispatch.h @@ -49,6 +49,8 @@ bool qmp_command_is_enabled(const QmpCommand *cmd); const char *qmp_command_name(const QmpCommand *cmd); bool qmp_has_success_response(const QmpCommand *cmd); QObject *qmp_build_error_object(Error *err); +QDict *qmp_dispatch_check_obj(const QObject *request, Error **errp); +bool qmp_is_oob(QDict *dict); typedef void (*qmp_cmd_callback_fn)(QmpCommand *cmd, void *opaque); diff --git a/monitor.c b/monitor.c index bf0f3d1662..d31da3fd1b 100644 --- a/monitor.c +++ b/monitor.c @@ -1106,6 +1106,44 @@ static void qmp_caps_apply(Monitor *mon, QMPCapabilityList *list) } } +/* + * Return true if check successful, or false otherwise. When false is + * returned, detailed error will be in errp if provided. + */ +static bool qmp_cmd_oob_check(Monitor *mon, QDict *req, Error **errp) +{ +const char *command; +QmpCommand *cmd; + +command = qdict_get_try_str(req, "execute"); +if (!command) { +error_setg(errp, "Command field 'execute' missing"); +return false; +} + +cmd = qmp_find_command(mon->qmp.commands, command); +if (!cmd) { +error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND, + "The command %s has not been found", command); +return false; +} + +if (qmp_is_oob(req)) { +if (!qmp_oob_enabled(mon)) { +error_setg(errp, "Please enable Out-Of-Band first " + "for the session during capabilities negociation"); +return false; +} +if (!(cmd->options & QCO_ALLOW_OOB)) { +error_setg(errp, "The command %s does not support OOB", + command); +return false; +} +} + +return true; +} + void qmp_qmp_capabilities(bool has_enable, QMPCapabilityList *enable, Error **errp) { @@ -4049,6 +4087,7 @@ static void monitor_qmp_bh_dispatcher(void *data) QMPRequest *req_obj = monitor_qmp_requests_pop_one(); if (req_obj) { +trace_monitor_qmp_cmd_in_band(qobject_get_try_str(req_obj->id) ?: ""); monitor_qmp_dispatch_one(req_obj); /* Reschedule instead of looping so the main loop stays responsive */ qemu_bh_schedule(mon_global.qmp_dispatcher_bh); @@ -4072,17 +4111,31 @@ static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens) error_setg(, QERR_JSON_PARSING); } if (err) { -monitor_qmp_respond(mon, NULL, err, NULL); -qobject_decref(req); -return; +goto err; +} + +/* Check against the request in general layout */ +qdict = qmp_dispatch_check_obj(req, ); +if (!qdict) { +goto err; } -qdict = qobject_to_qdict(req); -if (qdict) { -id = qdict_get(qdict, "id"); -qobject_incref(id); -qdict_del(qdict, "id"); -} /* else will fail qmp_dispatch() */ +/* Check against OOB specific */ +if (!qmp_cmd_oob_check(mon, qdict, )) { +goto err; +} + +id = qdict_get(qdict, "id"); + +/* When OOB is enabled, the "id" field is mandatory. */ +if (qmp_oob_enabled(mon) && !id) { +error_setg(, "Out-Of-Band capability requires that " + "every command contains an 'id' field"); +goto err; +} + +qobject_incref(id); +qdict_del(qdict, "id"); req_obj = g_new0(QMPRequest, 1); req_obj->mon = mon; @@ -4090,6 +4143,14 @@ static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens) req_obj->req = req; req_obj->need_resume = false; +if (qmp_is_oob(qdict)) { +/* Out-Of-Band (OOB) requests are executed directly in parser. */ +trace_monitor_qmp_cmd_out_of_band(qobject_get_try_str(req_obj->id) +
[Qemu-devel] [PATCH v7 11/23] monitor: introduce monitor_qmp_respond()
A tiny refactoring, preparing to split the QMP dispatcher away. Reviewed-by: Fam ZhengReviewed-by: Stefan Hajnoczi Signed-off-by: Peter Xu --- monitor.c | 50 +- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/monitor.c b/monitor.c index 3e07798442..92114aaa80 100644 --- a/monitor.c +++ b/monitor.c @@ -3867,6 +3867,38 @@ static int monitor_can_read(void *opaque) return (mon->suspend_cnt == 0) ? 1 : 0; } +/* + * 1. This function takes ownership of rsp, err, and id. + * 2. rsp, err, and id may be NULL. + * 3. If err != NULL then rsp must be NULL. + */ +static void monitor_qmp_respond(Monitor *mon, QObject *rsp, +Error *err, QObject *id) +{ +QDict *qdict = NULL; + +if (err) { +assert(!rsp); +qdict = qdict_new(); +qdict_put_obj(qdict, "error", qmp_build_error_object(err)); +error_free(err); +rsp = QOBJECT(qdict); +} + +if (rsp) { +if (id) { +/* This is for the qdict below. */ +qobject_incref(id); +qdict_put_obj(qobject_to_qdict(rsp), "id", id); +} + +monitor_json_emitter(mon, rsp); +} + +qobject_decref(id); +qobject_decref(rsp); +} + static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens) { QObject *req, *rsp = NULL, *id = NULL; @@ -3918,24 +3950,8 @@ static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens) } err_out: -if (err) { -qdict = qdict_new(); -qdict_put_obj(qdict, "error", qmp_build_error_object(err)); -error_free(err); -rsp = QOBJECT(qdict); -} +monitor_qmp_respond(mon, rsp, err, id); -if (rsp) { -if (id) { -qdict_put_obj(qobject_to_qdict(rsp), "id", id); -id = NULL; -} - -monitor_json_emitter(mon, rsp); -} - -qobject_decref(id); -qobject_decref(rsp); qobject_decref(req); } -- 2.14.3
[Qemu-devel] [PATCH v7 13/23] monitor: let suspend/resume work even with QMPs
This patches allows QMP monitors to be suspended/resumed. One thing to mention is that for QMPs that are using IOThreads, we need an explicit kick for the IOThread in case it is sleeping. Meanwhile, we need to take special care on non-interactive HMPs. Currently only gdbserver is using that. For these monitors, we still don't allow suspend/resume operations. Since at it, add traces for the operations. Signed-off-by: Peter Xu--- monitor.c| 45 ++--- trace-events | 1 + 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/monitor.c b/monitor.c index 60bcf67b3a..76137ba2a4 100644 --- a/monitor.c +++ b/monitor.c @@ -246,6 +246,21 @@ static inline bool monitor_is_qmp(const Monitor *mon) return (mon->flags & MONITOR_USE_CONTROL); } +/** + * Whether @mon is using readline? Note: not all HMP monitors can are + * using readline, e.g., gdbserver has non-interactive HMP monitor, so + * readline is not used there. + */ +static inline bool monitor_uses_readline(const Monitor *mon) +{ +return mon->flags & MONITOR_USE_READLINE; +} + +static inline bool monitor_is_hmp_non_interactive(const Monitor *mon) +{ +return !monitor_is_qmp(mon) && !monitor_uses_readline(mon); +} + /** * Is the current monitor, if any, a QMP monitor? */ @@ -3994,19 +4009,43 @@ static void monitor_command_cb(void *opaque, const char *cmdline, int monitor_suspend(Monitor *mon) { -if (!mon->rs) +if (monitor_is_hmp_non_interactive(mon)) { return -ENOTTY; +} + +if (monitor_is_qmp(mon)) { +/* + * Kick iothread to make sure this takes effect. It'll be + * evaluated again in prepare() of the watch object. + */ +aio_notify(iothread_get_aio_context(mon_global.mon_iothread)); +} atomic_inc(>suspend_cnt); +trace_monitor_suspend(mon, 1); return 0; } void monitor_resume(Monitor *mon) { -if (!mon->rs) +if (monitor_is_hmp_non_interactive(mon)) { return; +} + if (atomic_dec_fetch(>suspend_cnt) == 0) { -readline_show_prompt(mon->rs); +if (monitor_is_qmp(mon)) { +/* + * For QMP monitors that are running in IOThread, let's + * kick the thread in case it's sleeping. + */ +if (mon->use_io_thr) { +aio_notify(iothread_get_aio_context(mon_global.mon_iothread)); +} +} else { +assert(mon->rs); +readline_show_prompt(mon->rs); +} } +trace_monitor_suspend(mon, -1); } static QObject *get_qmp_greeting(Monitor *mon) diff --git a/trace-events b/trace-events index ec95e67089..eecb68b1d5 100644 --- a/trace-events +++ b/trace-events @@ -47,6 +47,7 @@ monitor_protocol_event_emit(uint32_t event, void *data) "event=%d data=%p" monitor_protocol_event_queue(uint32_t event, void *qdict, uint64_t rate) "event=%d data=%p rate=%" PRId64 handle_hmp_command(void *mon, const char *cmdline) "mon %p cmdline: %s" handle_qmp_command(void *mon, const char *req) "mon %p req: %s" +monitor_suspend(void *ptr, int cnt) "mon %p: %d" # dma-helpers.c dma_blk_io(void *dbs, void *bs, int64_t offset, bool to_dev) "dbs=%p bs=%p offset=%" PRId64 " to_dev=%d" -- 2.14.3
[Qemu-devel] [PATCH v7 14/23] monitor: separate QMP parser and dispatcher
Originally QMP goes through these steps: JSON Parser --> QMP Dispatcher --> Respond /|\(2)(3) | (1) | \|/ (4) +- main thread + This patch does this: JSON Parser QMP Dispatcher --> Respond /|\ | /|\ (4) | | | (2)| (3)| (5) (1) | +-> | \|/ +- main thread <---+ So the parsing job and the dispatching job is isolated now. It gives us a chance in following up patches to totally move the parser outside. The isolation is done using one QEMUBH. Only one dispatcher QEMUBH is used for all the monitors. Signed-off-by: Peter Xu--- monitor.c | 201 +++--- 1 file changed, 178 insertions(+), 23 deletions(-) diff --git a/monitor.c b/monitor.c index 76137ba2a4..51d12412fa 100644 --- a/monitor.c +++ b/monitor.c @@ -168,6 +168,13 @@ typedef struct { */ QmpCommandList *commands; bool qmp_caps[QMP_CAPABILITY__MAX]; +/* + * Protects qmp request/response queue. Please take monitor_lock + * first when used together. + */ +QemuMutex qmp_queue_lock; +/* Input queue that holds all the parsed QMP requests */ +GQueue *qmp_requests; } MonitorQMP; /* @@ -214,6 +221,8 @@ struct Monitor { /* Let's add monitor global variables to this struct. */ static struct { IOThread *mon_iothread; +/* Bottom half to dispatch the requests received from IO thread */ +QEMUBH *qmp_dispatcher_bh; } mon_global; /* QMP checker flags */ @@ -596,11 +605,13 @@ static void monitor_data_init(Monitor *mon, bool skip_flush, { memset(mon, 0, sizeof(Monitor)); qemu_mutex_init(>out_lock); +qemu_mutex_init(>qmp.qmp_queue_lock); mon->outbuf = qstring_new(); /* Use *mon_cmds by default. */ mon->cmd_table = mon_cmds; mon->skip_flush = skip_flush; mon->use_io_thr = use_io_thr; +mon->qmp.qmp_requests = g_queue_new(); } static void monitor_data_destroy(Monitor *mon) @@ -613,6 +624,8 @@ static void monitor_data_destroy(Monitor *mon) readline_free(mon->rs); QDECREF(mon->outbuf); qemu_mutex_destroy(>out_lock); +qemu_mutex_destroy(>qmp.qmp_queue_lock); +g_queue_free(mon->qmp.qmp_requests); } char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index, @@ -1052,6 +1065,16 @@ static void monitor_init_qmp_commands(void) qmp_marshal_qmp_capabilities, QCO_NO_OPTIONS); } +static bool qmp_cap_enabled(Monitor *mon, QMPCapability cap) +{ +return mon->qmp.qmp_caps[cap]; +} + +static bool qmp_oob_enabled(Monitor *mon) +{ +return qmp_cap_enabled(mon, QMP_CAPABILITY_OOB); +} + static void qmp_caps_check(Monitor *mon, QMPCapabilityList *list, Error **errp) { @@ -3914,30 +3937,39 @@ static void monitor_qmp_respond(Monitor *mon, QObject *rsp, qobject_decref(rsp); } -static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens) +struct QMPRequest { +/* Owner of the request */ +Monitor *mon; +/* "id" field of the request */ +QObject *id; +/* Request object to be handled */ +QObject *req; +/* + * Whether we need to resume the monitor afterward. This flag is + * used to emulate the old QMP server behavior that the current + * command must be completed before execution of the next one. + */ +bool need_resume; +}; +typedef struct QMPRequest QMPRequest; + +/* + * Dispatch one single QMP request. The function will free the req_obj + * and objects inside it before return. + */ +static void monitor_qmp_dispatch_one(QMPRequest *req_obj) { -QObject *req, *rsp = NULL, *id = NULL; +Monitor *mon, *old_mon; +QObject *req, *rsp = NULL, *id; QDict *qdict = NULL; -MonitorQMP *mon_qmp = container_of(parser, MonitorQMP, parser); -Monitor *old_mon, *mon = container_of(mon_qmp, Monitor, qmp); - -Error *err = NULL; +bool need_resume; -req = json_parser_parse_err(tokens, NULL, ); -if (!req && !err) { -/* json_parser_parse_err() sucks: can fail without setting @err */ -error_setg(, QERR_JSON_PARSING); -} -if (err) { -goto err_out; -} +req = req_obj->req; +mon = req_obj->mon; +id = req_obj->id; +need_resume = req_obj->need_resume; -qdict = qobject_to_qdict(req); -if (qdict) { -id = qdict_get(qdict, "id"); -qobject_incref(id); -qdict_del(qdict, "id"); -} /* else will fail qmp_dispatch() */ +g_free(req_obj); if (trace_event_get_state_backends(TRACE_HANDLE_QMP_COMMAND)) { QString *req_json = qobject_to_json(req); @@ -3948,7 +3980,7 @@ static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens) old_mon = cur_mon; cur_mon = mon; -rsp = qmp_dispatch(cur_mon->qmp.commands,
[Qemu-devel] [PATCH v7 09/23] monitor: allow using IO thread for parsing
For each Monitor, add one field "use_io_thr" to show whether it will be using the dedicated monitor IO thread to handle input/output. When set, monitor IO parsing work will be offloaded to the dedicated monitor IO thread, rather than the original main loop thread. This only works for QMP. HMP will always be run on the main loop thread. Currently we're still keeping use_io_thr off always. Will turn it on later at some point. One thing to mention is that we cannot set use_io_thr for every QMP monitor. The problem is that MUXed typed chardevs may not work well with it now. When MUX is used, frontend of chardev can be the monitor plus something else. The only thing we know would be safe to be run outside main thread so far is the monitor frontend. All the rest of the frontends should still be run in main thread only. Signed-off-by: Peter Xu--- monitor.c | 107 +- 1 file changed, 99 insertions(+), 8 deletions(-) diff --git a/monitor.c b/monitor.c index cef71d5c45..fd6e9a6d28 100644 --- a/monitor.c +++ b/monitor.c @@ -35,6 +35,7 @@ #include "net/net.h" #include "net/slirp.h" #include "chardev/char-fe.h" +#include "chardev/char-io.h" #include "ui/qemu-spice.h" #include "sysemu/numa.h" #include "monitor/monitor.h" @@ -75,6 +76,7 @@ #include "qmp-introspect.h" #include "sysemu/qtest.h" #include "sysemu/cpus.h" +#include "sysemu/iothread.h" #include "qemu/cutils.h" #include "qapi/qmp/dispatch.h" @@ -189,6 +191,7 @@ struct Monitor { int flags; int suspend_cnt; bool skip_flush; +bool use_io_thr; QemuMutex out_lock; QString *outbuf; @@ -207,6 +210,11 @@ struct Monitor { QTAILQ_ENTRY(Monitor) entry; }; +/* Let's add monitor global variables to this struct. */ +static struct { +IOThread *mon_iothread; +} mon_global; + /* QMP checker flags */ #define QMP_ACCEPT_UNKNOWNS 1 @@ -567,7 +575,8 @@ static void monitor_qapi_event_init(void) static void handle_hmp_command(Monitor *mon, const char *cmdline); -static void monitor_data_init(Monitor *mon, bool skip_flush) +static void monitor_data_init(Monitor *mon, bool skip_flush, + bool use_io_thr) { memset(mon, 0, sizeof(Monitor)); qemu_mutex_init(>out_lock); @@ -575,6 +584,7 @@ static void monitor_data_init(Monitor *mon, bool skip_flush) /* Use *mon_cmds by default. */ mon->cmd_table = mon_cmds; mon->skip_flush = skip_flush; +mon->use_io_thr = use_io_thr; } static void monitor_data_destroy(Monitor *mon) @@ -595,7 +605,7 @@ char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index, char *output = NULL; Monitor *old_mon, hmp; -monitor_data_init(, true); +monitor_data_init(, true, false); old_mon = cur_mon; cur_mon = @@ -4034,12 +4044,29 @@ static void sortcmdlist(void) qsort((void *)info_cmds, array_num, elem_size, compare_mon_cmd); } +static GMainContext *monitor_io_context_get(void) +{ +return iothread_get_g_main_context(mon_global.mon_iothread); +} + +static AioContext *monitor_aio_context_get(void) +{ +return iothread_get_aio_context(mon_global.mon_iothread); +} + +static void monitor_iothread_init(void) +{ +mon_global.mon_iothread = iothread_create("mon_iothread", + _abort); +} + void monitor_init_globals(void) { monitor_init_qmp_commands(); monitor_qapi_event_init(); sortcmdlist(); qemu_mutex_init(_lock); +monitor_iothread_init(); } /* These functions just adapt the readline interface in a typesafe way. We @@ -4082,11 +4109,41 @@ void error_vprintf_unless_qmp(const char *fmt, va_list ap) } } +static void monitor_list_append(Monitor *mon) +{ +qemu_mutex_lock(_lock); +QTAILQ_INSERT_HEAD(_list, mon, entry); +qemu_mutex_unlock(_lock); +} + +static void monitor_qmp_setup_handlers(void *data) +{ +Monitor *mon = data; +GMainContext *context; + +if (mon->use_io_thr) { +/* + * When use_io_thr is set, we use the global shared dedicated + * IO thread for this monitor to handle input/output. + */ +context = monitor_io_context_get(); +/* We should have inited globals before reaching here. */ +assert(context); +} else { +/* The default main loop, which is the main thread */ +context = NULL; +} + +qemu_chr_fe_set_handlers(>chr, monitor_can_read, monitor_qmp_read, + monitor_qmp_event, NULL, mon, context, true); +monitor_list_append(mon); +} + void monitor_init(Chardev *chr, int flags) { Monitor *mon = g_malloc(sizeof(*mon)); -monitor_data_init(mon, false); +monitor_data_init(mon, false, false); qemu_chr_fe_init(>chr, chr, _abort); mon->flags = flags; @@ -4099,24 +4156,55 @@ void monitor_init(Chardev *chr, int flags) } if (monitor_is_qmp(mon))
[Qemu-devel] [PATCH v7 12/23] monitor: let suspend_cnt be thread safe
Monitor code now can be run in more than one thread. Let it be thread safe when accessing suspend_cnt counter. Reviewed-by: Eric BlakeSigned-off-by: Peter Xu --- monitor.c | 15 --- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/monitor.c b/monitor.c index 92114aaa80..60bcf67b3a 100644 --- a/monitor.c +++ b/monitor.c @@ -190,7 +190,7 @@ struct Monitor { CharBackend chr; int reset_seen; int flags; -int suspend_cnt; +int suspend_cnt;/* Needs to be accessed atomically */ bool skip_flush; bool use_io_thr; @@ -3864,7 +3864,7 @@ static int monitor_can_read(void *opaque) { Monitor *mon = opaque; -return (mon->suspend_cnt == 0) ? 1 : 0; +return !atomic_mb_read(>suspend_cnt); } /* @@ -3996,7 +3996,7 @@ int monitor_suspend(Monitor *mon) { if (!mon->rs) return -ENOTTY; -mon->suspend_cnt++; +atomic_inc(>suspend_cnt); return 0; } @@ -4004,8 +4004,9 @@ void monitor_resume(Monitor *mon) { if (!mon->rs) return; -if (--mon->suspend_cnt == 0) +if (atomic_dec_fetch(>suspend_cnt) == 0) { readline_show_prompt(mon->rs); +} } static QObject *get_qmp_greeting(Monitor *mon) @@ -4070,19 +4071,19 @@ static void monitor_event(void *opaque, int event) monitor_resume(mon); monitor_flush(mon); } else { -mon->suspend_cnt = 0; +atomic_mb_set(>suspend_cnt, 0); } break; case CHR_EVENT_MUX_OUT: if (mon->reset_seen) { -if (mon->suspend_cnt == 0) { +if (atomic_mb_read(>suspend_cnt) == 0) { monitor_printf(mon, "\n"); } monitor_flush(mon); monitor_suspend(mon); } else { -mon->suspend_cnt++; +atomic_inc(>suspend_cnt); } qemu_mutex_lock(>out_lock); mon->mux_out = 1; -- 2.14.3
[Qemu-devel] [PATCH v7 21/23] qmp: add command "x-oob-test"
This command is only used to test OOB functionality. It should not be used for any other purposes. Reviewed-by: Stefan HajnocziReviewed-by: Fam Zheng Signed-off-by: Peter Xu --- qapi-schema.json | 18 ++ qmp.c| 16 2 files changed, 34 insertions(+) diff --git a/qapi-schema.json b/qapi-schema.json index d6c89efc0d..59ea3e2051 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3252,3 +3252,21 @@ ## { 'event': 'COMMAND_DROPPED' , 'data': { 'id': 'any', 'reason': 'CommandDropReason' } } + +## +# @x-oob-test: +# +# Test OOB functionality. When send this command with lock=true, +# it'll try to hang the dispatcher. When send it with lock=false, +# it'll try to notify the locked thread to continue. Note: it should +# only be used by QMP test program rather than anything else. +# +# Since: 2.12 +# +# Example: +# +# { "execute": "x-oob-test", +# "arguments": { "lock": true } } +## +{ 'command': 'x-oob-test', 'data' : { 'lock': 'bool' }, + 'allow-oob': true } diff --git a/qmp.c b/qmp.c index 52cfd2d81c..c7dcbe72e3 100644 --- a/qmp.c +++ b/qmp.c @@ -717,3 +717,19 @@ MemoryInfo *qmp_query_memory_size_summary(Error **errp) return mem_info; } + +static QemuSemaphore x_oob_test_sem; + +static void __attribute__((constructor)) x_oob_test_init(void) +{ +qemu_sem_init(_oob_test_sem, 0); +} + +void qmp_x_oob_test(bool lock, Error **errp) +{ +if (lock) { +qemu_sem_wait(_oob_test_sem); +} else { +qemu_sem_post(_oob_test_sem); +} +} -- 2.14.3
[Qemu-devel] [PATCH v7 10/23] qmp: introduce QMPCapability
There were no QMP capabilities defined. Define the first "oob" as capability to allow out-of-band messages. After this patch, we will allow QMP clients to enable QMP capabilities when sending the first "qmp_capabilities" command. Originally we are starting QMP session with no arguments like: { "execute": "qmp_capabilities" } Now we can enable some QMP capabilities using (take OOB as example, which is the only one capability that we support): { "execute": "qmp_capabilities", "argument": { "enable": [ "oob" ] } } When the "argument" key is not provided, no capability is enabled. For capability "oob", the monitor needs to be run on dedicated IO thread, otherwise the command will fail. For example, trying to enable OOB on a MUXed typed QMP monitor will fail. One thing to mention is that, QMP capabilities are per-monitor, and also when the connection is closed due to some reason, the capabilities will be reset. Also, touch up qmp-test.c to test the new bits. Signed-off-by: Peter Xu--- monitor.c| 76 qapi-schema.json | 32 +--- tests/qmp-test.c | 10 +++- 3 files changed, 109 insertions(+), 9 deletions(-) diff --git a/monitor.c b/monitor.c index fd6e9a6d28..3e07798442 100644 --- a/monitor.c +++ b/monitor.c @@ -167,6 +167,7 @@ typedef struct { * mode. */ QmpCommandList *commands; +bool qmp_caps[QMP_CAPABILITY__MAX]; } MonitorQMP; /* @@ -1036,8 +1037,42 @@ static void monitor_init_qmp_commands(void) qmp_marshal_qmp_capabilities, QCO_NO_OPTIONS); } -void qmp_qmp_capabilities(Error **errp) +static void qmp_caps_check(Monitor *mon, QMPCapabilityList *list, + Error **errp) +{ +for (; list; list = list->next) { +assert(list->value < QMP_CAPABILITY__MAX); +switch (list->value) { +case QMP_CAPABILITY_OOB: +if (!mon->use_io_thr) { +/* + * Out-Of-Band only works with monitors that are + * running on dedicated IOThread. + */ +error_setg(errp, "This monitor does not support " + "Out-Of-Band (OOB)"); +return; +} +break; +default: +break; +} +} +} + +/* This function should only be called after capabilities are checked. */ +static void qmp_caps_apply(Monitor *mon, QMPCapabilityList *list) { +for (; list; list = list->next) { +mon->qmp.qmp_caps[list->value] = true; +} +} + +void qmp_qmp_capabilities(bool has_enable, QMPCapabilityList *enable, + Error **errp) +{ +Error *local_err = NULL; + if (cur_mon->qmp.commands == _commands) { error_set(errp, ERROR_CLASS_COMMAND_NOT_FOUND, "Capabilities negotiation is already complete, command " @@ -1045,6 +1080,21 @@ void qmp_qmp_capabilities(Error **errp) return; } +/* Enable QMP capabilities provided by the client if applicable. */ +if (has_enable) { +qmp_caps_check(cur_mon, enable, _err); +if (local_err) { +/* + * Failed check on any of the capabilities will fail the + * entire command (and thus not apply any of the other + * capabilities that were also requested). + */ +error_propagate(errp, local_err); +return; +} +qmp_caps_apply(cur_mon, enable); +} + cur_mon->qmp.commands = _commands; } @@ -3942,14 +3992,29 @@ void monitor_resume(Monitor *mon) readline_show_prompt(mon->rs); } -static QObject *get_qmp_greeting(void) +static QObject *get_qmp_greeting(Monitor *mon) { +QList *cap_list = qlist_new(); QObject *ver = NULL; +QMPCapability cap; qmp_marshal_query_version(NULL, , NULL); -return qobject_from_jsonf("{'QMP': {'version': %p, 'capabilities': []}}", - ver); +for (cap = 0; cap < QMP_CAPABILITY__MAX; cap++) { +if (!mon->use_io_thr && cap == QMP_CAPABILITY_OOB) { +/* Monitors that are not using IOThread won't support OOB */ +continue; +} +qlist_append(cap_list, qstring_from_str(QMPCapability_str(cap))); +} + +return qobject_from_jsonf("{'QMP': {'version': %p, 'capabilities': %p}}", + ver, cap_list); +} + +static void monitor_qmp_caps_reset(Monitor *mon) +{ +memset(mon->qmp.qmp_caps, 0, sizeof(mon->qmp.qmp_caps)); } static void monitor_qmp_event(void *opaque, int event) @@ -3960,7 +4025,8 @@ static void monitor_qmp_event(void *opaque, int event) switch (event) { case CHR_EVENT_OPENED: mon->qmp.commands = _cap_negotiation_commands; -data = get_qmp_greeting(); +monitor_qmp_caps_reset(mon); +data = get_qmp_greeting(mon);
[Qemu-devel] [PATCH v7 07/23] monitor: unify global init
There are many places where the monitor initializes its globals: - monitor_init_qmp_commands() at the very beginning - single function to init monitor_lock - in the first entry of monitor_init() using "is_first_init" Unify them a bit. monitor_lock is not used before monitor_init() (as confirmed by code analysis and gdb watchpoints); so we are safe delaying what was a constructor-time initialization of the mutex into the later first call to monitor_init(). Reviewed-by: Fam ZhengReviewed-by: Stefan Hajnoczi Reviewed-by: Eric Blake Signed-off-by: Peter Xu --- include/monitor/monitor.h | 2 +- monitor.c | 25 ++--- vl.c | 7 ++- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h index 83ea4a1aaf..3a5128ab1b 100644 --- a/include/monitor/monitor.h +++ b/include/monitor/monitor.h @@ -16,7 +16,7 @@ extern Monitor *cur_mon; bool monitor_cur_is_qmp(void); -void monitor_init_qmp_commands(void); +void monitor_init_globals(void); void monitor_init(Chardev *chr, int flags); void monitor_cleanup(void); diff --git a/monitor.c b/monitor.c index 253be6871a..f32187b991 100644 --- a/monitor.c +++ b/monitor.c @@ -1000,7 +1000,7 @@ static void qmp_unregister_commands_hack(void) #endif } -void monitor_init_qmp_commands(void) +static void monitor_init_qmp_commands(void) { /* * Two command lists: @@ -4034,6 +4034,14 @@ static void sortcmdlist(void) qsort((void *)info_cmds, array_num, elem_size, compare_mon_cmd); } +void monitor_init_globals(void) +{ +monitor_init_qmp_commands(); +monitor_qapi_event_init(); +sortcmdlist(); +qemu_mutex_init(_lock); +} + /* These functions just adapt the readline interface in a typesafe way. We * could cast function pointers but that discards compiler checks. */ @@ -4074,23 +4082,10 @@ void error_vprintf_unless_qmp(const char *fmt, va_list ap) } } -static void __attribute__((constructor)) monitor_lock_init(void) -{ -qemu_mutex_init(_lock); -} - void monitor_init(Chardev *chr, int flags) { -static int is_first_init = 1; -Monitor *mon; - -if (is_first_init) { -monitor_qapi_event_init(); -sortcmdlist(); -is_first_init = 0; -} +Monitor *mon = g_malloc(sizeof(*mon)); -mon = g_malloc(sizeof(*mon)); monitor_data_init(mon, false); qemu_chr_fe_init(>chr, chr, _abort); diff --git a/vl.c b/vl.c index e725ecbc08..095769e6c9 100644 --- a/vl.c +++ b/vl.c @@ -3098,7 +3098,6 @@ int main(int argc, char **argv, char **envp) qemu_init_exec_dir(argv[0]); module_call_init(MODULE_INIT_QOM); -monitor_init_qmp_commands(); qemu_add_opts(_drive_opts); qemu_add_drive_opts(_legacy_drive_opts); @@ -4562,6 +4561,12 @@ int main(int argc, char **argv, char **envp) default_drive(default_floppy, snapshot, IF_FLOPPY, 0, FD_OPTS); default_drive(default_sdcard, snapshot, IF_SD, 0, SD_OPTS); +/* + * Note: qtest_enabled() (which is used in monitor_qapi_event_init()) + * depends on configure_accelerator() above. + */ +monitor_init_globals(); + if (qemu_opts_foreach(qemu_find_opts("mon"), mon_init_func, NULL, NULL)) { exit(1); -- 2.14.3
[Qemu-devel] [PATCH v7 08/23] monitor: let mon_list be tail queue
It was QLIST. I want to use this list to do monitor priority job later, which need tail insertion ability. So switching to a tail queue. Reviewed-by: Fam ZhengReviewed-by: Stefan Hajnoczi Signed-off-by: Peter Xu --- monitor.c | 12 ++-- 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/monitor.c b/monitor.c index f32187b991..cef71d5c45 100644 --- a/monitor.c +++ b/monitor.c @@ -204,7 +204,7 @@ struct Monitor { void *password_opaque; mon_cmd_t *cmd_table; QLIST_HEAD(,mon_fd_t) fds; -QLIST_ENTRY(Monitor) entry; +QTAILQ_ENTRY(Monitor) entry; }; /* QMP checker flags */ @@ -213,7 +213,7 @@ struct Monitor { /* Protects mon_list, monitor_event_state. */ static QemuMutex monitor_lock; -static QLIST_HEAD(mon_list, Monitor) mon_list; +static QTAILQ_HEAD(mon_list, Monitor) mon_list; static QLIST_HEAD(mon_fdsets, MonFdset) mon_fdsets; static int mon_refcount; @@ -414,7 +414,7 @@ static void monitor_qapi_event_emit(QAPIEvent event, QDict *qdict) Monitor *mon; trace_monitor_protocol_event_emit(event, qdict); -QLIST_FOREACH(mon, _list, entry) { +QTAILQ_FOREACH(mon, _list, entry) { if (monitor_is_qmp(mon) && mon->qmp.commands != _cap_negotiation_commands) { monitor_json_emitter(mon, QOBJECT(qdict)); @@ -4109,7 +4109,7 @@ void monitor_init(Chardev *chr, int flags) } qemu_mutex_lock(_lock); -QLIST_INSERT_HEAD(_list, mon, entry); +QTAILQ_INSERT_HEAD(_list, mon, entry); qemu_mutex_unlock(_lock); } @@ -4118,8 +4118,8 @@ void monitor_cleanup(void) Monitor *mon, *next; qemu_mutex_lock(_lock); -QLIST_FOREACH_SAFE(mon, _list, entry, next) { -QLIST_REMOVE(mon, entry); +QTAILQ_FOREACH_SAFE(mon, _list, entry, next) { +QTAILQ_REMOVE(_list, mon, entry); monitor_data_destroy(mon); g_free(mon); } -- 2.14.3
[Qemu-devel] [PATCH v7 06/23] monitor: move the cur_mon hack deeper for QMP
In monitor_qmp_read(), we have the hack to temporarily replace the cur_mon pointer. Now we move this hack deeper inside the QMP dispatcher routine since the Monitor pointer can be actually obtained using container_of() upon the parser object, just like most of the other JSON parser users do. This does not make much sense as a single patch. However, this will be a big step for the next patch, when the QMP dispatcher routine will be split from the QMP parser. Reviewed-by: Stefan HajnocziReviewed-by: Eric Blake Signed-off-by: Peter Xu --- monitor.c | 17 ++--- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/monitor.c b/monitor.c index 3a28a6d935..253be6871a 100644 --- a/monitor.c +++ b/monitor.c @@ -3811,7 +3811,9 @@ static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens) { QObject *req, *rsp = NULL, *id = NULL; QDict *qdict = NULL; -Monitor *mon = cur_mon; +MonitorQMP *mon_qmp = container_of(parser, MonitorQMP, parser); +Monitor *old_mon, *mon = container_of(mon_qmp, Monitor, qmp); + Error *err = NULL; req = json_parser_parse_err(tokens, NULL, ); @@ -3836,8 +3838,13 @@ static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens) QDECREF(req_json); } +old_mon = cur_mon; +cur_mon = mon; + rsp = qmp_dispatch(cur_mon->qmp.commands, req); +cur_mon = old_mon; + if (mon->qmp.commands == _cap_negotiation_commands) { qdict = qdict_get_qdict(qobject_to_qdict(rsp), "error"); if (qdict @@ -3874,13 +3881,9 @@ err_out: static void monitor_qmp_read(void *opaque, const uint8_t *buf, int size) { -Monitor *old_mon = cur_mon; - -cur_mon = opaque; - -json_message_parser_feed(_mon->qmp.parser, (const char *) buf, size); +Monitor *mon = opaque; -cur_mon = old_mon; +json_message_parser_feed(>qmp.parser, (const char *) buf, size); } static void monitor_read(void *opaque, const uint8_t *buf, int size) -- 2.14.3
[Qemu-devel] [PATCH v7 03/23] qobject: introduce qobject_get_try_str()
A quick way to fetch string from qobject when it's a QString. Reviewed-by: Fam ZhengReviewed-by: Stefan Hajnoczi Signed-off-by: Peter Xu --- include/qapi/qmp/qstring.h | 1 + qobject/qstring.c | 11 +++ 2 files changed, 12 insertions(+) diff --git a/include/qapi/qmp/qstring.h b/include/qapi/qmp/qstring.h index a145c8ca00..6517d8e377 100644 --- a/include/qapi/qmp/qstring.h +++ b/include/qapi/qmp/qstring.h @@ -28,6 +28,7 @@ QString *qstring_from_substr(const char *str, int start, int end); size_t qstring_get_length(const QString *qstring); const char *qstring_get_str(const QString *qstring); const char *qstring_get_try_str(const QString *qstring); +const char *qobject_get_try_str(const QObject *qstring); void qstring_append_int(QString *qstring, int64_t value); void qstring_append(QString *qstring, const char *str); void qstring_append_chr(QString *qstring, int c); diff --git a/qobject/qstring.c b/qobject/qstring.c index 7638ab990d..e556b1afdf 100644 --- a/qobject/qstring.c +++ b/qobject/qstring.c @@ -138,6 +138,17 @@ const char *qstring_get_try_str(const QString *qstring) return qstring ? qstring_get_str(qstring) : NULL; } +/** + * qobject_get_try_str(): Return a pointer to the corresponding string + * + * NOTE: the string will only be returned if the object is valid, and + * its type is QString, otherwise NULL is returned. + */ +const char *qobject_get_try_str(const QObject *qstring) +{ +return qstring_get_try_str(qobject_to_qstring(qstring)); +} + /** * qstring_is_equal(): Test whether the two QStrings are equal */ -- 2.14.3
[Qemu-devel] [PATCH v7 01/23] docs: update QMP documents for OOB commands
Update both the developer and spec for the new QMP OOB (Out-Of-Band) command. Signed-off-by: Peter Xu--- docs/devel/qapi-code-gen.txt | 68 docs/interop/qmp-spec.txt| 30 --- 2 files changed, 89 insertions(+), 9 deletions(-) diff --git a/docs/devel/qapi-code-gen.txt b/docs/devel/qapi-code-gen.txt index 06ab699066..4d3db0ad39 100644 --- a/docs/devel/qapi-code-gen.txt +++ b/docs/devel/qapi-code-gen.txt @@ -554,9 +554,12 @@ following example objects: === Commands === +--- General Command Layout --- + Usage: { 'command': STRING, '*data': COMPLEX-TYPE-NAME-OR-DICT, '*returns': TYPE-NAME, '*boxed': true, - '*gen': false, '*success-response': false } + '*gen': false, '*success-response': false, + '*allow-oob': false } Commands are defined by using a dictionary containing several members, where three members are most common. The 'command' member is a @@ -636,6 +639,59 @@ possible, the command expression should include the optional key 'success-response' with boolean value false. So far, only QGA makes use of this member. +A command can be declared to support Out-Of-Band (OOB) execution. By +default, commands do not support OOB. To declare a command to support +it, we need an extra 'allow-oob' field. For example: + + { 'command': 'migrate_recover', + 'data': { 'uri': 'str' }, 'allow-oob': true } + +To execute a command in Out-Of-Band way, we need to specify the +"control" field in the request, with "run-oob" set to true. Example: + + => { "execute": "command-support-oob", + "arguments": { ... }, + "control": { "run-oob": true } } + <= { "return": { } } + +Without it, even the commands that support out-of-band execution will +still be run In-Band. + +Please read the "Out-Of-Band Command Execution" section below for more +information on how OOB execution works. + +--- About Out-Of-Band (OOB) Command Execution --- + +Out-Of-Band does not mean a special kind of command. Instead, it's a +special way to execute the command. One normal command can be +declared to support Out-Of-Band execution when 'allow-oob' field is +set to true when defining the command. With that, it can be run in an +Out-Of-Band way if 'run-oob' is specified in 'control' field of +command request. + +When we say normal QMP command executions, it means basically the +following: + +- They are executed in order, +- They run only in main thread of QEMU, +- They have the BQL taken during execution. + +For OOB command executions, they differ in the following: + +- They can be executed before an existing command, +- They run in a monitor dedicated thread, +- They do not take the BQL during execution. + +OOB command handlers must satisfy the following conditions: + +- It executes extremely fast, +- It does not take any lock, or, it can take very small locks if all + critical regions also follow the rules for OOB command handler code, +- It does not invoke system calls that may block, +- It does not access guest RAM that may block when userfaultfd is + enabled for postcopy live migration. + +If in doubt, do not implement OOB execution support. === Events === @@ -739,10 +795,12 @@ references by name. QAPI schema definitions not reachable that way are omitted. The SchemaInfo for a command has meta-type "command", and variant -members "arg-type" and "ret-type". On the wire, the "arguments" -member of a client's "execute" command must conform to the object type -named by "arg-type". The "return" member that the server passes in a -success response conforms to the type named by "ret-type". +members "arg-type", "ret-type" and "allow-oob". On the wire, the +"arguments" member of a client's "execute" command must conform to the +object type named by "arg-type". The "return" member that the server +passes in a success response conforms to the type named by +"ret-type". When "allow-oob" is set, it means the command supports +out-of-band execution. If the command takes no arguments, "arg-type" names an object type without members. Likewise, if the command returns nothing, "ret-type" diff --git a/docs/interop/qmp-spec.txt b/docs/interop/qmp-spec.txt index f8b5356015..e20163c138 100644 --- a/docs/interop/qmp-spec.txt +++ b/docs/interop/qmp-spec.txt @@ -83,16 +83,27 @@ The greeting message format is: 2.2.1 Capabilities -- -As of the date this document was last revised, no server or client -capability strings have been defined. +Currently supported capabilities are: +- "oob": it means the QMP server supports "Out-Of-Band" command + execution. For more detail, please see "run-oob" parameter in + "Issuing Commands" section below. Not all commands allow this "oob" + execution. One can know whether one command supports "oob" by + "query-qmp-schema" command. + +QMP clients can get a list of supported QMP capabilities of the QMP +server in the greeting message mentioned
[Qemu-devel] [PATCH v7 05/23] monitor: move skip_flush into monitor_data_init
It's part of the data init. Collect it. Reviewed-by: Dr. David Alan GilbertReviewed-by: Fam Zheng Reviewed-by: Stefan Hajnoczi Signed-off-by: Peter Xu --- monitor.c | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/monitor.c b/monitor.c index b9da5e20d1..3a28a6d935 100644 --- a/monitor.c +++ b/monitor.c @@ -567,13 +567,14 @@ static void monitor_qapi_event_init(void) static void handle_hmp_command(Monitor *mon, const char *cmdline); -static void monitor_data_init(Monitor *mon) +static void monitor_data_init(Monitor *mon, bool skip_flush) { memset(mon, 0, sizeof(Monitor)); qemu_mutex_init(>out_lock); mon->outbuf = qstring_new(); /* Use *mon_cmds by default. */ mon->cmd_table = mon_cmds; +mon->skip_flush = skip_flush; } static void monitor_data_destroy(Monitor *mon) @@ -594,8 +595,7 @@ char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index, char *output = NULL; Monitor *old_mon, hmp; -monitor_data_init(); -hmp.skip_flush = true; +monitor_data_init(, true); old_mon = cur_mon; cur_mon = @@ -4088,7 +4088,7 @@ void monitor_init(Chardev *chr, int flags) } mon = g_malloc(sizeof(*mon)); -monitor_data_init(mon); +monitor_data_init(mon, false); qemu_chr_fe_init(>chr, chr, _abort); mon->flags = flags; -- 2.14.3
[Qemu-devel] [PATCH v7 04/23] qobject: let object_property_get_str() use new API
We can simplify object_property_get_str() using the new qobject_get_try_str(). Reviewed-by: Fam ZhengReviewed-by: Stefan Hajnoczi Reviewed-by: Eric Blake Signed-off-by: Peter Xu --- qom/object.c | 9 +++-- 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/qom/object.c b/qom/object.c index c58c52d518..9cbeb51f0b 100644 --- a/qom/object.c +++ b/qom/object.c @@ -1116,18 +1116,15 @@ char *object_property_get_str(Object *obj, const char *name, Error **errp) { QObject *ret = object_property_get_qobject(obj, name, errp); -QString *qstring; char *retval; if (!ret) { return NULL; } -qstring = qobject_to_qstring(ret); -if (!qstring) { + +retval = g_strdup(qobject_get_try_str(ret)); +if (!retval) { error_setg(errp, QERR_INVALID_PARAMETER_TYPE, name, "string"); -retval = NULL; -} else { -retval = g_strdup(qstring_get_str(qstring)); } qobject_decref(ret); -- 2.14.3
[Qemu-devel] [PATCH v7 02/23] qobject: introduce qstring_get_try_str()
The only difference from qstring_get_str() is that it allows the qstring to be NULL. If so, NULL is returned. CC: Eric BlakeCC: Markus Armbruster Reviewed-by: Fam Zheng Reviewed-by: Stefan Hajnoczi Reviewed-by: Eric Blake Signed-off-by: Peter Xu --- include/qapi/qmp/qstring.h | 1 + qobject/qstring.c | 10 ++ 2 files changed, 11 insertions(+) diff --git a/include/qapi/qmp/qstring.h b/include/qapi/qmp/qstring.h index 65c05a9be5..a145c8ca00 100644 --- a/include/qapi/qmp/qstring.h +++ b/include/qapi/qmp/qstring.h @@ -27,6 +27,7 @@ QString *qstring_from_str(const char *str); QString *qstring_from_substr(const char *str, int start, int end); size_t qstring_get_length(const QString *qstring); const char *qstring_get_str(const QString *qstring); +const char *qstring_get_try_str(const QString *qstring); void qstring_append_int(QString *qstring, int64_t value); void qstring_append(QString *qstring, const char *str); void qstring_append_chr(QString *qstring, int c); diff --git a/qobject/qstring.c b/qobject/qstring.c index 74182a1c02..7638ab990d 100644 --- a/qobject/qstring.c +++ b/qobject/qstring.c @@ -128,6 +128,16 @@ const char *qstring_get_str(const QString *qstring) return qstring->string; } +/** + * qstring_get_try_str(): Return a pointer to the stored string + * + * NOTE: will return NULL if qstring is not provided. + */ +const char *qstring_get_try_str(const QString *qstring) +{ +return qstring ? qstring_get_str(qstring) : NULL; +} + /** * qstring_is_equal(): Test whether the two QStrings are equal */ -- 2.14.3
[Qemu-devel] [PATCH v7 00/23] QMP: out-of-band (OOB) execution support
This version should have addressed all comments in previous one, also fixed another race condition after I addressed all the comments (a new race condition introduced by addressing the comments...). For some more details of the race condition, please see the last entry of change log, and please refer to patch 9 for the code change. I removed RFC tag from this version. Please review. Thanks. v7: - add some r-bs, and remove some. - remove the chardev fix since already queued by Paolo - use local var in qemu_chr_fe_add_watch [Stefan] - move doc patch to front, mention it in some patches [Eric] - Quite a few of English fixes [Eric] - fix unlock missing in handle_qmp_command [Stefan] - squash some patches according to the review comments - don't break gdbserver usage on HMP non-interactive mode by fixing up the suspend/resume logic [Fam, Stefan] - move the qemu_chr_fe_set_handlers() call in monitor_init() into a bottom half to avoid race between the call itself and iothread. [Stefan] - spent quite a lot of time debugging another assertion failure in io_watch_poll_finalize() after above change is made (ouch! I really hoped we always have the latest glib): when QEMU inits chardevs in chardev_init_func() it's possible that QEMU registers the chardev handlers there, even before CharBackend is connected to that chardev in monitor_init(). Then, when we reach monitor_init() we must make sure we unregister that old one first, or there can have one orphan GSource still in default gcontext (note that this can really happen when we start to use QEMUBH to setup chardev frontends, which is above change). v6: - add r-bs - s/negociate/negotiate/ [Dave] - let mon_global be anonymous struct [Stefan] - in monitor_init(): call qemu_chr_fe_set_handlers() later than init parser, then it's safe [Stefan] - drop patch "qjson: add "opaque" field to JSONMessageParser", re-write the following one to use container_of(). [Stefan] - keep get_qmp_greeting() the old way, add cap list [Stefan, Fam] - fix the iothread_stop() comment since that's not really related to the glib bug [Stefan] - when do qmp greeting, don't expose oob capability if iothread not used [Stefan, Fam] - squash "qmp: introduce some capability helpers" into patch "monitor: separate QMP parser and dispatcher" [Fam] - tune comments for monitor_qmp_respond(). [Stefan] - use atomic_mb_{read|set}() where proper instead of no-mb ones [Stefan] - add patch to let monitor suspend/resume really support QMP. Notify iothread when needed, in both suspend/resume. [Stefan] - add comment for qmp_queue_lock on lock taking ordering. [Stefan] - refactor monitor_qmp_bh_dispatcher() to not loop, instead queue itself after each request. [Stefan] - rename "request" into "command" in the new qmp event [Stefan] - in handle_qmp_command() protect the queue length fetch with qmp_queue_lock [Stefan] - one more s/2.11/2.12/. [Fam] - when isolating response queue, not only flush the queue, but also flush the monitor out buffer [Stefan] - document rewrite [Stefan] - some other touch-ups that I forgot to mention and some tiny new patches... anyway, rbs will be gone if any of the patch is touched up. Please have a look! v5 - rename "monitor_iothread" to "mon_iothread" [Dave] - add comment in monitor_cleanup(), note that when the hacks can be removed. [Dan] - add a note section in qmp-spec.txt, mentioning about how to migrate existing QMP command to oob-capable command. [Dave] - drop patch "qmp: let migrate-incoming allow out-of-band". All migration related changes will all be put into postcopy-recovery series. v4: - drop first patch to fix IOWatchPool [Stefan, Dan] - add s-o-b where missing, and newly got r-bs - fix English error in commit msg [Fam] - some tunes on request-dropped event: [Stefan] - firstly let 'id' be any type, meanwhile make sure "id" is there as long as OOB is enabled for the monitor. - some comments fix - add new command "x-oob-test" for testing oob commands [Stefan] - simplify the test codes to use new x-oob-test - flush response queue before cleanup monitors This series was born from this one: https://lists.gnu.org/archive/html/qemu-devel/2017-08/msg04310.html The idea comes from Markus Armbruster and the discussion we had in the thread. It's not a super ideal solution (I believe Markus had been thinking hard to keep everything in order meanwhile trying to satisfy the migration requirement), but AFAIU it's currently the best. What is OOB? It's the shortcut of Out-Of-Band execution, its name is given by Markus. It's a way to quickly execute a QMP request. Say, originally QMP is going throw these steps: JSON Parser --> QMP Dispatcher --> Respond /|\(2)(3) | (1) | \|/ (4) +- main thread + The requests are executed by the so-called QMP-dispatcher after the JSON is parsed. If OOB is
[Qemu-devel] [PATCH] iotests: Fix CID for VMDK afl image
The descriptor block in the image, which includes the CID to verify, has been invalid since the reference image was added. Since commit 9877860e7bd we report this error earlier than the "file too large", so 059.out mismatches. Instead of fixing the output, we fix the image descriptor, because the code path we want to exercise is actually the invalid image size. The binary change is generated along the operations of: $ bunzip2 afl9.vmdk.bz2 $ qemu-img create -f qcow2 fix.vmdk 1G $ dd if=afl9.vmdk.bz2 of=fix.vmdk bs=512 count=1 conv=notrunc $ mv fix.vmdk afl9.vmdk $ bzip2 afl9.vmdk Signed-off-by: Fam Zheng--- tests/qemu-iotests/sample_images/afl9.vmdk.bz2 | Bin 178 -> 618 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tests/qemu-iotests/sample_images/afl9.vmdk.bz2 b/tests/qemu-iotests/sample_images/afl9.vmdk.bz2 index 03615d36a12425cf4240bab86f4cfe648db14572..9fcd0af45a815431acf4689e0845ecf2d333cd58 100644 GIT binary patch literal 618 zcmV-w0+szjT4*^jL0KkKSvgW7ssIN3|NsBH-Q9UpfAhclU70`s-*NE~5QvC~h=_=Y zh>D2n*q*=vygR634445h35k;?00h9835kMW4$iPepVE{Bqk)uhJ^wfGLr=)3s zhM5CR88jLh7)B;cA*K)*6GmuECPU3o4NWG5O#pg>Ak#xY8Z^CrMt}oD38Ns$ z02n}M0LdjZ&}cLPqd+nPKmn$j0iXe(02%-d27nnJriN-uE+X@Bj4BBfd|yV!NB zwqkL}nW3AI5x^jp=t%^F1pxqp)v#n#)j$zcm1xqv(!$2d*5%vF{5RPWnOV8-^tE<( zU~%&}Y0uNu*9Wt=yS^8PkC%IG;aD{l#sG` m4Ho*fsHXdM
Re: [Qemu-devel] [Qemu-block] [PATCH] block/vmdk: Report failures in vmdk_read_cid()
On Fri, Jan 19, 2018 at 7:35 PM, Paolo Bonziniwrote: > On 28/07/2017 14:54, Kevin Wolf wrote: >> Am 09.07.2017 um 19:06 hat Peter Maydell geschrieben: >>> The function vmdk_read_cid() can fail if the read on the underlying >>> block device fails, or if there's a format error in the VMDK file. >>> However its API doesn't provide a mechanism to report these errors, >>> and in some cases we were returning a CID of 0 and in some cases a >>> CID of 0x, either of which might potentially be valid values. >>> >>> Change the function to return 0 on success or a negative errno, and >>> return the CID via a uint32_t* argument. Update the callsites to >>> handle and propagate the error appropriately. >>> >>> This fixes in passing a Coverity-spotted issue (CID 1350038) where >>> we weren't checking the return value from sscanf(). >>> >>> Signed-off-by: Peter Maydell >> >> Fam, this is the commit that introduced the qemu-iotests 059 failure for >> vmdk. I think what's happening is that we use an image produced by a >> fuzzer, and with the additional checks introduced in this patch, we now >> fail earlier and don't test the condition any more that we wanted to >> test. >> >> So do we need a new version of sample_images/afl9.vmdk.bz2 that has a >> valid CID? I'll send a patch to fix the CID today. Fam > > This has never been fixed, has it? I still see the failure. > > Paolo
Re: [Qemu-devel] [PATCH v5 0/4] cryptodev: add vhost support
On Fri, Jan 19, 2018 at 4:13 PM, Zhoujian (jay)wrote: > [...] > >> Configure options: >> --enable-werror --target-list=x86_64-softmmu,aarch64-softmmu -- >> prefix=/tmp/qemu-test/install > [...] > >> KVM support yes >> HAX support no >> HVF support no >> TCG support yes >> TCG debug enabled no >> TCG interpreter no >> malloc trim support yes >> RDMA support yes >> fdt support yes >> preadv supportyes >> fdatasync yes >> madvise yes >> posix_madvise yes >> libcap-ng support no >> vhost-net support yes >> vhost-crypto support yes >> vhost-scsi support yes >> vhost-vsock support yes >> vhost-user support yes > [...] > >> make[1]: *** No rule to make target `../backends/cryptodev-vhost-user.o', >> needed by `qemu-system-x86_64'. Stop. >> make[1]: *** Waiting for unfinished jobs > > But it's successfully compiled using centos7 and mingw32 locally, and I > couldn't > reproduce this. Is it related to docker? (I don't have docker environment in > hand) > I don't know, maybe it's related to the -j8 parallelism? If you simply do: $ sudo yum install docker $ sudo systemctl start docker You'll have a docker environment ready. (you should be root or make sure passwordless sudo works in order to run docker commands). Then: $ make docker-test-build@min-glib V=1 J=8 If it fails, add DEBUG=1 to the command line and start again. If will prompt you in a shell before building QEMU. Press ctrl-d to start building. When error happens, you'll be in the shell again to do usual things (debug, edit-build-run...). (We should add a docs/devel/docker-testing.txt describing the steps). Fam
Re: [Qemu-devel] [PATCH v2 0/4] coroutine-lock: polymorphic CoQueue
On Tue, Jan 16, 2018 at 10:23 PM, Paolo Bonziniwrote: > There are cases in which a queued coroutine must be restarted from > non-coroutine context (with qemu_co_enter_next). In this cases, > qemu_co_enter_next also needs to be thread-safe, but it cannot use a > CoMutex and so cannot qemu_co_queue_wait. This happens in curl (which > right now is rolling its own list of Coroutines) and will happen in > Fam's NVMe driver as well. > > This series extracts the idea of a polymorphic lockable object > from my "scoped lock guard" proposal, and applies it to CoQueue. > The implementation of QemuLockable is similar to C11 _Generic, but > redone using the preprocessor and GCC builtins for compatibility. > > In general, while a bit on the esoteric side, the functionality used > to emulate _Generic is fairly old in GCC, and the builtins are already > used by include/qemu/atomic.h; the series was tested with Fedora 27 (boot > Damn Small Linux via http) and CentOS 6 (compiled only). > > Paolo > > v1->v2: fix typos and copyright year Reviewed-by: Fam Zheng Should I include this series in my pull request for the NVMe driver?
Re: [Qemu-devel] [PATCH v10 2/4] fw_cfg: do DMA read operation
On Tue, Jan 23, 2018 at 05:40:39PM +0100, Marc-André Lureau wrote: > Modify fw_cfg_read_blob() to use DMA if the device supports it. > Return errors, because the operation may fail. > > The DMA operation is expected to run synchronously with today qemu, > but the specification states that it may become async, so we run > "control" field check in a loop for eventual changes. > > We may want to switch all the *buf addresses to use only kmalloc'ed > buffers (instead of using stack/image addresses with dma=false). > > Signed-off-by: Marc-André Lureau> --- > drivers/firmware/qemu_fw_cfg.c | 131 > ++--- > 1 file changed, 111 insertions(+), 20 deletions(-) > > diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c > index 740df0df2260..686f0e839858 100644 > --- a/drivers/firmware/qemu_fw_cfg.c > +++ b/drivers/firmware/qemu_fw_cfg.c > @@ -33,6 +33,7 @@ > #include > #include > #include > +#include > > MODULE_AUTHOR("Gabriel L. Somlo "); > MODULE_DESCRIPTION("QEMU fw_cfg sysfs support"); > @@ -43,12 +44,22 @@ MODULE_LICENSE("GPL"); > #define FW_CFG_ID 0x01 > #define FW_CFG_FILE_DIR 0x19 > > +#define FW_CFG_VERSION_DMA 0x02 > +#define FW_CFG_DMA_CTL_ERROR 0x01 > +#define FW_CFG_DMA_CTL_READ0x02 > +#define FW_CFG_DMA_CTL_SKIP0x04 > +#define FW_CFG_DMA_CTL_SELECT 0x08 > +#define FW_CFG_DMA_CTL_WRITE 0x10 > + > /* size in bytes of fw_cfg signature */ > #define FW_CFG_SIG_SIZE 4 > > /* fw_cfg "file name" is up to 56 characters (including terminating nul) */ > #define FW_CFG_MAX_FILE_PATH 56 > > +/* fw_cfg revision attribute, in /sys/firmware/qemu_fw_cfg top-level dir. */ > +static u32 fw_cfg_rev; > + > /* fw_cfg file directory entry type */ > struct fw_cfg_file { > u32 size; > @@ -57,6 +68,12 @@ struct fw_cfg_file { > char name[FW_CFG_MAX_FILE_PATH]; > }; > > +struct fw_cfg_dma { > + u32 control; > + u32 length; > + u64 address; > +} __packed; > + > /* fw_cfg device i/o register addresses */ > static bool fw_cfg_is_mmio; > static phys_addr_t fw_cfg_p_base; > @@ -75,12 +92,68 @@ static inline u16 fw_cfg_sel_endianness(u16 key) > return fw_cfg_is_mmio ? cpu_to_be16(key) : cpu_to_le16(key); > } > > +static inline bool fw_cfg_dma_enabled(void) > +{ > + return fw_cfg_rev & FW_CFG_VERSION_DMA && fw_cfg_reg_dma; > +} > + > +/* qemu fw_cfg device is sync today, but spec says it may become async */ > +static void fw_cfg_wait_for_control(struct fw_cfg_dma *d) > +{ > + do { > + u32 ctrl = be32_to_cpu(READ_ONCE(d->control)); > + > + if ((ctrl & ~FW_CFG_DMA_CTL_ERROR) == 0) > + return; > + > + usleep_range(50, 100); > + } while (true); > +} > + > +static ssize_t fw_cfg_dma_transfer(struct device *dev, > + void *address, u32 length, u32 control) > +{ > + phys_addr_t dma; > + struct fw_cfg_dma *d = NULL; > + ssize_t ret = length; > + > + d = kmalloc(sizeof(*d), GFP_KERNEL); > + if (!d) { > + ret = -ENOMEM; > + goto end; > + } > + > + *d = (struct fw_cfg_dma) { > + .address = cpu_to_be64(virt_to_phys(address)), > + .length = cpu_to_be32(length), > + .control = cpu_to_be32(control) > + }; > + > + dma = virt_to_phys(d); > + > + iowrite32be((u64)dma >> 32, fw_cfg_reg_dma); > + iowrite32be(dma, fw_cfg_reg_dma + 4); We can do it with iowrite64be(virt_to_phys(d)) too? In all cases I think it's good enough and no worth for a repost. For the DMA transfer part: Acked-by: Peter Xu Thanks, -- Peter Xu
Re: [Qemu-devel] [PATCH v1 06/21] RISC-V FPU Support
On Tue, Jan 23, 2018 at 3:35 PM, Michael Clarkwrote: > We want minimum number (minnum). It's been added to the draft spec and will > be in riscv-spec-v2.3.pdf In the preface of the draft, it says • Defined the signed-zero behavior of FMIN.fmt and FMAX.fmt, and changed their behavior on signaling-NaN inputs to conform to the minimumNumber and maximumNumber operations in the proposed IEEE 754-201x specification. But if qemu doesn't have minimumNumber support yet, then yes minNum is correct. This is discussed a bit here https://github.com/riscv/riscv-isa-manual/issues/65 Jim
Re: [Qemu-devel] [PATCH v1 06/21] RISC-V FPU Support
On Tue, Jan 23, 2018 at 4:01 PM, Richard Henderson < richard.hender...@linaro.org> wrote: > On 01/23/2018 01:37 PM, Michael Clark wrote: > > > > > > On Wed, Jan 3, 2018 at 12:10 PM, Richard Henderson > >> > wrote: > > > > On 01/02/2018 04:44 PM, Michael Clark wrote: > > > +/* convert RISC-V rounding mode to IEEE library numbers */ > > > +unsigned int ieee_rm[] = { > > > > static const. > > > > > > Done. > > > > > +/* obtain rm value to use in computation > > > + * as the last step, convert rm codes to what the softfloat > library expects > > > + * Adapted from Spike's decode.h:RM > > > + */ > > > +#define RM ({ \ > > > +if (rm == 7) {\ > > > +rm = env->frm; \ > > > +} \ > > > +if (rm > 4) { \ > > > +helper_raise_exception(env, RISCV_EXCP_ILLEGAL_INST); \ > > > +} \ > > > +ieee_rm[rm]; }) > > > > Please use inline functions and not these macros. > > > > > > Done. > > > > In fact the previous code would, with normal control flow, dereference > > ieee_rm[rm] with an out of bounds round mode so assuming > helper_raise_exception > > does a longjmp, i've inserted g_assert_not_reached() after the > exception. An > > analyser could detect that ieee_rm has an out of bounds access assuming > normal > > control flow. e.g. > > > > static inline void set_fp_round_mode(CPURISCVState *env, uint64_t rm) > > { > > if (rm == 7) { > > rm = env->frm; > > } else if (rm > 4) { > > helper_raise_exception(env, RISCV_EXCP_ILLEGAL_INST); > > g_assert_not_reached(); > > Yes, raise_exception exits via longjmp. This is a good change. > > > Are translations not implicitly indexed by cpu_mmu_index? i.e. do we > also need > > to add cpu_mmu_index to cpu_get_tb_cpu_state flags to prevent code > translated > > for one value of mmu_index running in code with another value of > mmu_index (in > > the case of riscv, we currently return processor mode / privilege level > in > > cpu_mmu_index). > > No, there is no implicit indexing. That's why I've mentioned exactly this > at > least twice in review so far. > > There are two ways to do this correctly. One is to add all the bits that > specify processor state (e.g. Alpha stores pal_code bit and supervisor > bit). > Another is to actually encode the mmu_idx into the flags (e.g. ARM). I reviewed Stefan's patches. Stefan has some code that encoded processor flags in mmu_index however it removed some well-tested code paths and I was hesitant to make such a large change to get_physical_address at this point in time. I read Stefan's code and used some fragments from it but was relatively cautious with regard to changing relatively well tested code paths. I tried to make the most minimal change for the sake of correctness. For the meantime we've greatly simplified cpu_mmu_index to just return the processor mode as well as adding the processor mode to cpu_get_tb_cpu_state flags. cpu_mmu_index previously returned a permutation of env->priv (containing processer mode), mstatus.MPP (previous mode) and mstatus.MPRV. When MPRV is set, M mode loads and stores operate as per the mode in mstatus.MPP and the previous cpu_mmu_index function returned the mode the processor should do loads and stores as, not the current mode. This is problematic as mstatus.MPRV can be altered from user code via register values so there was a potential to re-enter a pre-existing trace with a different mmu_index. I believe we have eliminated that issue. These two changes should fix the issue and we've performed testing with these patches: - https://github.com/michaeljclark/riscv-qemu/commit/82012aef90e5c4500f926523b3b2ff621b0cd512 - https://github.com/michaeljclark/riscv-qemu/commit/abdb897a4a607d00cfce577ac37ca6119004658f There is a possibility to further improve this code and potentially avoid TLB flushes, by encoding more state in cpu_mmu_index and cpu_get_tb_cpu_state flags. I would say that mstatus.SUM flag is altered frequently in Linux's copy_to/from_user and is likely to result in decent performance improvement if we can eliminate the TLB flush when the SUM bit is changed (it is in concept similar to SMAP on x86). mstatus.MPRV is used by the monitor for handling misaligned loads and stores which should be relatively rare (the occasional use of structs with __attribute__((packed))). Eliminating the tlb_flush on mstatus.SUM changes likely will have the most positive performance impact We have increased performance somewhat already (~2.5X faster on dd if=/dev/zero of=/dev/null bs=1 count=10). We eliminated a tlb_flush on privilege level changes as this is included (now
Re: [Qemu-devel] Call for GSoC & Outreachy 2018 mentors & project ideas
On Thu, Jan 18, 2018 at 8:49 AM, David Hildenbrandwrote: > On 12.01.2018 00:25, Alistair Francis wrote: >> On Wed, Jan 10, 2018 at 4:52 AM, Stefan Hajnoczi wrote: >>> On Tue, Jan 9, 2018 at 9:45 PM, Alistair Francis >>> wrote: Can anyone who has done this before chime in. What do you think about getting someone to cleanup and improve the GDB support in QEMU? Would that be the right difficulty of task for a GSoC project? > > Don't understand that sentence. We already support multiple CPUs > (represented and switchable just like threads in GDB), no? We support multiple of the same CPU, such as multiple cores. What we don't support is multiple of different types of CPUs. Something like ARMs bit.LITTLE or Xilinx's 4xA53s and 2xR5s. Alistair > > An interesting thing to look at could be tracepoint support in GDB. > >>> >>> There is not enough information to give feedback on whether this >>> project idea is suitable. What are the specific tasks you'd like the >>> student to work on? >>> >>> In general, I'm sure there are well-defined 12-week project ideas >>> around the GDB stub. New features are easy to propose and are usually >>> well-defined (e.g. implement these commands that are documented in the >>> GDB protocol documentation). Cleaning up code is less clear and it >>> would depend on exactly what needs to be done. Interns will not have >>> a background in the QEMU codebase and may not be able to make >>> judgements about how to structure things, so I would be more careful >>> about refactoring/cleanup projects. >>> >>> Please see my talk about QEMU GSoC for guidelines on project ideas: >>> https://www.youtube.com/watch?v=xNVCX7YMUL8=19m11s >>> http://vmsplice.net/~stefan/stefanha-kvm-forum-2016.pdf >> >> That helps a lot, thanks for that. >> >> So for a more concrete solution, how would adding support for multi >> CPU support to the GDB server sound? >> >> This would allow GDB debugging for the A53 and the R5 on the Xilinx >> ZynqMP for example. This is something we have in the Xilinx tree, but >> it is in no state to go upstream and really needs to be re-write to be >> upstreamable and more generic. >> >> Alistair >> >>> >>> Hope this helps, >>> Stefan > > > -- > > Thanks, > > David / dhildenb
Re: [Qemu-devel] [PATCH v9 16/16] hw/arm/xilinx_zynq: fix the capabilities register to match the datasheet
On Mon, Jan 22, 2018 at 6:08 PM, Philippe Mathieu-Daudéwrote: > checking Xilinx datasheet "UG585" (v1.12.1) > > Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Alistair > --- > hw/arm/xilinx_zynq.c | 53 > > tests/sdhci-test.c | 5 + > 2 files changed, 34 insertions(+), 24 deletions(-) > > diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c > index 1836a4ed45..0f76333770 100644 > --- a/hw/arm/xilinx_zynq.c > +++ b/hw/arm/xilinx_zynq.c > @@ -61,6 +61,8 @@ static const int dma_irqs[8] = { > #define SLCR_XILINX_UNLOCK_KEY 0xdf0d > #define SLCR_XILINX_LOCK_KEY0x767b > > +#define ZYNQ_SDHCI_CAPABILITIES 0x69ec0080 /* Datasheet: UG585 (v1.12.1) */ > + > #define ARMV7_IMM16(x) (extract32((x), 0, 12) | \ > extract32((x), 12, 4) << 16) > > @@ -165,10 +167,8 @@ static void zynq_init(MachineState *machine) > MemoryRegion *address_space_mem = get_system_memory(); > MemoryRegion *ext_ram = g_new(MemoryRegion, 1); > MemoryRegion *ocm_ram = g_new(MemoryRegion, 1); > -DeviceState *dev, *carddev; > +DeviceState *dev; > SysBusDevice *busdev; > -DriveInfo *di; > -BlockBackend *blk; > qemu_irq pic[64]; > int n; > > @@ -247,27 +247,32 @@ static void zynq_init(MachineState *machine) > gem_init(_table[0], 0xE000B000, pic[54-IRQ_OFFSET]); > gem_init(_table[1], 0xE000C000, pic[77-IRQ_OFFSET]); > > -dev = qdev_create(NULL, TYPE_SYSBUS_SDHCI); > -qdev_init_nofail(dev); > -sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xE010); > -sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[56-IRQ_OFFSET]); > - > -di = drive_get_next(IF_SD); > -blk = di ? blk_by_legacy_dinfo(di) : NULL; > -carddev = qdev_create(qdev_get_child_bus(dev, "sd-bus"), TYPE_SD_CARD); > -qdev_prop_set_drive(carddev, "drive", blk, _fatal); > -object_property_set_bool(OBJECT(carddev), true, "realized", > _fatal); > - > -dev = qdev_create(NULL, TYPE_SYSBUS_SDHCI); > -qdev_init_nofail(dev); > -sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xE0101000); > -sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[79-IRQ_OFFSET]); > - > -di = drive_get_next(IF_SD); > -blk = di ? blk_by_legacy_dinfo(di) : NULL; > -carddev = qdev_create(qdev_get_child_bus(dev, "sd-bus"), TYPE_SD_CARD); > -qdev_prop_set_drive(carddev, "drive", blk, _fatal); > -object_property_set_bool(OBJECT(carddev), true, "realized", > _fatal); > +for (n = 0; n < 2; n++) { > +int hci_irq = n ? 79 : 56; > +hwaddr hci_addr = n ? 0xE0101000 : 0xE010; > +DriveInfo *di; > +BlockBackend *blk; > +DeviceState *carddev; > + > +/* Compatible with: > + * - SD Host Controller Specification Version 2.0 Part A2 > + * - SDIO Specification Version 2.0 > + * - MMC Specification Version 3.31 > + */ > +dev = qdev_create(NULL, TYPE_SYSBUS_SDHCI); > +qdev_prop_set_uint8(dev, "sd-spec-version", 2); > +qdev_prop_set_uint64(dev, "capareg", ZYNQ_SDHCI_CAPABILITIES); > +qdev_init_nofail(dev); > +sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, hci_addr); > +sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[hci_irq - > IRQ_OFFSET]); > + > +di = drive_get_next(IF_SD); > +blk = di ? blk_by_legacy_dinfo(di) : NULL; > +carddev = qdev_create(qdev_get_child_bus(dev, "sd-bus"), > TYPE_SD_CARD); > +qdev_prop_set_drive(carddev, "drive", blk, _fatal); > +object_property_set_bool(OBJECT(carddev), true, "realized", > + _fatal); > +} > > dev = qdev_create(NULL, TYPE_ZYNQ_XADC); > qdev_init_nofail(dev); > diff --git a/tests/sdhci-test.c b/tests/sdhci-test.c > index 094e0570e1..aae2cfc1b5 100644 > --- a/tests/sdhci-test.c > +++ b/tests/sdhci-test.c > @@ -41,6 +41,11 @@ static const struct sdhci_t { > /* Exynos4210 */ > { "arm","smdkc210", > {0x1251, 2, 0, {1, 0x5e80080} } }, > + > +/* Zynq-7000 */ > +{ "arm","xilinx-zynq-a9", /* Datasheet: UG585 (v1.12.1) */ > +{0xe010, 2, 0, {1, 0x69ec0080} } }, > + > }; > > static struct { > -- > 2.15.1 > >
Re: [Qemu-devel] [PATCH v9 09/16] sdhci: simplify sdhci_get_fifolen()
On Mon, Jan 22, 2018 at 6:08 PM, Philippe Mathieu-Daudéwrote: > Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Alistair > --- > hw/sd/sdhci-internal.h | 4 +++- > hw/sd/sdhci.c | 20 +--- > 2 files changed, 8 insertions(+), 16 deletions(-) > > diff --git a/hw/sd/sdhci-internal.h b/hw/sd/sdhci-internal.h > index b7751c815f..577ca9da54 100644 > --- a/hw/sd/sdhci-internal.h > +++ b/hw/sd/sdhci-internal.h > @@ -24,6 +24,8 @@ > #ifndef SDHCI_INTERNAL_H > #define SDHCI_INTERNAL_H > > +#include "hw/registerfields.h" > + > /* R/W SDMA System Address register 0x0 */ > #define SDHC_SYSAD 0x00 > > @@ -179,7 +181,7 @@ > #define SDHC_CAN_DO_ADMA2 0x0008 > #define SDHC_CAN_DO_ADMA1 0x0010 > #define SDHC_64_BIT_BUS_SUPPORT(1 << 28) > -#define SDHC_CAPAB_BLOCKSIZE(x)(((x) >> 16) & 0x3) > +FIELD(SDHC_CAPAB, MAXBLOCKLENGTH, 16, 2); > > /* HWInit Maximum Current Capabilities Register 0x0 */ > #define SDHC_MAXCURR 0x48 > diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c > index 1c781c4ba5..dce1a49af1 100644 > --- a/hw/sd/sdhci.c > +++ b/hw/sd/sdhci.c > @@ -59,6 +59,11 @@ > */ > #define SDHC_CAPAB_REG_DEFAULT 0x057834b4 > > +static inline unsigned int sdhci_get_fifolen(SDHCIState *s) > +{ > +return 1 << (9 + FIELD_EX32(s->capareg, SDHC_CAPAB, MAXBLOCKLENGTH)); > +} > + > static uint8_t sdhci_slotint(SDHCIState *s) > { > return (s->norintsts & s->norintsigen) || (s->errintsts & > s->errintsigen) || > @@ -1118,21 +1123,6 @@ static const MemoryRegionOps sdhci_mmio_ops = { > .endianness = DEVICE_LITTLE_ENDIAN, > }; > > -static inline unsigned int sdhci_get_fifolen(SDHCIState *s) > -{ > -switch (SDHC_CAPAB_BLOCKSIZE(s->capareg)) { > -case 0: > -return 512; > -case 1: > -return 1024; > -case 2: > -return 2048; > -default: > -hw_error("SDHC: unsupported value for maximum block size\n"); > -return 0; > -} > -} > - > static void sdhci_init_readonly_registers(SDHCIState *s, Error **errp) > { > if (s->sd_spec_version != 2) { > -- > 2.15.1 > >
Re: [Qemu-devel] [PATCH v9 14/16] hw/arm/exynos4210: access the 64-bit capareg with qdev_prop_set_uint64()
On Mon, Jan 22, 2018 at 6:08 PM, Philippe Mathieu-Daudéwrote: > We only set a 32-bit value, but this is a good practice in case this > code is used as reference. > > (missed in 5efc9016e52) > > Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Alistair > --- > hw/arm/exynos4210.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/hw/arm/exynos4210.c b/hw/arm/exynos4210.c > index e8e1d81e62..d89322c7ea 100644 > --- a/hw/arm/exynos4210.c > +++ b/hw/arm/exynos4210.c > @@ -378,7 +378,7 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem) > DriveInfo *di; > > dev = qdev_create(NULL, TYPE_SYSBUS_SDHCI); > -qdev_prop_set_uint32(dev, "capareg", EXYNOS4210_SDHCI_CAPABILITIES); > +qdev_prop_set_uint64(dev, "capareg", EXYNOS4210_SDHCI_CAPABILITIES); > qdev_init_nofail(dev); > > busdev = SYS_BUS_DEVICE(dev); > -- > 2.15.1 > >
Re: [Qemu-devel] [PATCH v3 05/12] sdcard: add more trace events
On Mon, Jan 22, 2018 at 7:21 PM, Philippe Mathieu-Daudéwrote: > Signed-off-by: Philippe Mathieu-Daudé Acked-by: Alistair Francis Alistair > --- > hw/sd/sd.c | 32 ++-- > hw/sd/trace-events | 13 + > 2 files changed, 39 insertions(+), 6 deletions(-) > > diff --git a/hw/sd/sd.c b/hw/sd/sd.c > index 03263e08ae..dc4b2329e4 100644 > --- a/hw/sd/sd.c > +++ b/hw/sd/sd.c > @@ -177,6 +177,8 @@ static bool sd_get_cmd_line(SDState *sd) > > static void sd_set_voltage(SDState *sd, uint16_t millivolts) > { > +trace_sdcard_set_voltage(millivolts); > + > switch (millivolts) { > case 3001 ... 3600: /* SD_VOLTAGE_3_3V */ > case 2001 ... 3000: /* SD_VOLTAGE_3_0V */ > @@ -272,6 +274,7 @@ static void sd_ocr_powerup(void *opaque) > { > SDState *sd = opaque; > > +trace_sdcard_powerup(); > /* Set powered up bit in OCR */ > assert(!(sd->ocr & OCR_POWER_UP)); > sd->ocr |= OCR_POWER_UP; > @@ -475,6 +478,7 @@ static void sd_reset(DeviceState *dev) > uint64_t size; > uint64_t sect; > > +trace_sdcard_reset(); > if (sd->blk) { > blk_get_geometry(sd->blk, ); > } else { > @@ -528,7 +532,10 @@ static void sd_cardchange(void *opaque, bool load, Error > **errp) > bool readonly = sd_get_readonly(sd); > > if (inserted) { > +trace_sdcard_inserted(readonly); > sd_reset(dev); > +} else { > +trace_sdcard_ejected(); > } > > /* The IRQ notification is for legacy non-QOM SD controller devices; > @@ -660,6 +667,7 @@ static void sd_erase(SDState *sd) > uint64_t erase_start = sd->erase_start; > uint64_t erase_end = sd->erase_end; > > +trace_sdcard_erase(); > if (!sd->erase_start || !sd->erase_end) { > sd->card_status |= ERASE_SEQ_ERROR; > return; > @@ -749,6 +757,11 @@ static void sd_lock_command(SDState *sd) > else > pwd_len = 0; > > +if (lock) { > +trace_sdcard_lock(); > +} else { > +trace_sdcard_unlock(); > +} > if (erase) { > if (!(sd->card_status & CARD_IS_LOCKED) || sd->blk_len > 1 || > set_pwd || clr_pwd || lock || sd->wp_switch || > @@ -1075,10 +1088,12 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, > case 16: /* CMD16: SET_BLOCKLEN */ > switch (sd->state) { > case sd_transfer_state: > -if (req.arg > (1 << HWBLOCK_SHIFT)) > +if (req.arg > (1 << HWBLOCK_SHIFT)) { > sd->card_status |= BLOCK_LEN_ERROR; > -else > +} else { > +trace_sdcard_set_blocklen(req.arg); > sd->blk_len = req.arg; > +} > > return sd_r1; > > @@ -1450,10 +1465,13 @@ static sd_rsp_type_t sd_app_command(SDState *sd, > if ((req.arg & ACMD41_ENQUIRY_MASK) != 0) { > timer_del(sd->ocr_power_timer); > sd_ocr_powerup(sd); > -} else if (!timer_pending(sd->ocr_power_timer)) { > -timer_mod_ns(sd->ocr_power_timer, > - (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) > - + OCR_POWER_DELAY_NS)); > +} else { > +trace_sdcard_inquiry_cmd41(); > +if (!timer_pending(sd->ocr_power_timer)) { > +timer_mod_ns(sd->ocr_power_timer, > + (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) > + + OCR_POWER_DELAY_NS)); > +} > } > } > > @@ -1666,6 +1684,7 @@ void sd_write_data(SDState *sd, uint8_t value) > if (sd->card_status & (ADDRESS_ERROR | WP_VIOLATION)) > return; > > +trace_sdcard_write_data(sd->current_cmd, value); > switch (sd->current_cmd) { > case 24: /* CMD24: WRITE_SINGLE_BLOCK */ > sd->data[sd->data_offset ++] = value; > @@ -1803,6 +1822,7 @@ uint8_t sd_read_data(SDState *sd) > > io_len = (sd->ocr & (1 << 30)) ? 512 : sd->blk_len; > > +trace_sdcard_read_data(sd->current_cmd, io_len); > switch (sd->current_cmd) { > case 6:/* CMD6: SWITCH_FUNCTION */ > ret = sd->data[sd->data_offset ++]; > diff --git a/hw/sd/trace-events b/hw/sd/trace-events > index b2aa19ec0d..3040d32560 100644 > --- a/hw/sd/trace-events > +++ b/hw/sd/trace-events > @@ -27,8 +27,21 @@ sdhci_capareg(const char *desc, uint16_t val) "%s: %u" > sdcard_normal_command(uint8_t cmd, uint32_t arg, const char *state) "CMD%d > arg 0x%08x (state %s)" > sdcard_app_command(uint8_t acmd, uint32_t arg) "ACMD%d arg 0x%08x" > sdcard_response(const char *rspdesc, int rsplen) "%s (sz:%d)" > +sdcard_powerup(void) "" > +sdcard_inquiry_cmd41(void) "" > +sdcard_set_enable(bool current_state, bool new_state) "%u -> %u" >
Re: [Qemu-devel] [PATCH v9 10/16] sdhci: check the Spec v1 capabilities correctness
On Mon, Jan 22, 2018 at 6:08 PM, Philippe Mathieu-Daudéwrote: > Incorrect value will throw an error. > > Note than Spec v2 is supported by default. > > Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Alistair > --- > hw/sd/sdhci-internal.h | 21 ++- > hw/sd/sdhci.c | 97 > +- > hw/sd/trace-events | 1 + > 3 files changed, 117 insertions(+), 2 deletions(-) > > diff --git a/hw/sd/sdhci-internal.h b/hw/sd/sdhci-internal.h > index 577ca9da54..c5e26bf8f3 100644 > --- a/hw/sd/sdhci-internal.h > +++ b/hw/sd/sdhci-internal.h > @@ -86,6 +86,9 @@ > > /* R/W Host control Register 0x0 */ > #define SDHC_HOSTCTL 0x28 > +FIELD(SDHC_HOSTCTL, LED_CTRL, 0, 1); > +FIELD(SDHC_HOSTCTL, DATATRANSFERWIDTH, 1, 1); /* SD mode only */ > +FIELD(SDHC_HOSTCTL, HIGH_SPEED,2, 1); > #define SDHC_CTRL_DMA_CHECK_MASK 0x18 > #define SDHC_CTRL_SDMA 0x00 > #define SDHC_CTRL_ADMA1_32 0x08 > @@ -96,6 +99,7 @@ > /* R/W Power Control Register 0x0 */ > #define SDHC_PWRCON0x29 > #define SDHC_POWER_ON (1 << 0) > +FIELD(SDHC_PWRCON, BUS_VOLTAGE,1, 3); > > /* R/W Block Gap Control Register 0x0 */ > #define SDHC_BLKGAP0x2A > @@ -118,6 +122,7 @@ > > /* R/W Timeout Control Register 0x0 */ > #define SDHC_TIMEOUTCON0x2E > +FIELD(SDHC_TIMEOUTCON, COUNTER,0, 4); > > /* R/W Software Reset Register 0x0 */ > #define SDHC_SWRST 0x2F > @@ -174,17 +179,31 @@ > > /* ROC Auto CMD12 error status register 0x0 */ > #define SDHC_ACMD12ERRSTS 0x3C > +FIELD(SDHC_ACMD12ERRSTS, TIMEOUT_ERR, 1, 1); > +FIELD(SDHC_ACMD12ERRSTS, CRC_ERR, 2, 1); > +FIELD(SDHC_ACMD12ERRSTS, INDEX_ERR,4, 1); > > /* HWInit Capabilities Register 0x05E80080 */ > #define SDHC_CAPAB 0x40 > -#define SDHC_CAN_DO_DMA0x0040 > #define SDHC_CAN_DO_ADMA2 0x0008 > #define SDHC_CAN_DO_ADMA1 0x0010 > #define SDHC_64_BIT_BUS_SUPPORT(1 << 28) > +FIELD(SDHC_CAPAB, TOCLKFREQ, 0, 6); > +FIELD(SDHC_CAPAB, TOUNIT, 7, 1); > +FIELD(SDHC_CAPAB, BASECLKFREQ, 8, 8); > FIELD(SDHC_CAPAB, MAXBLOCKLENGTH, 16, 2); > +FIELD(SDHC_CAPAB, HIGHSPEED, 21, 1); > +FIELD(SDHC_CAPAB, SDMA, 22, 1); > +FIELD(SDHC_CAPAB, SUSPRESUME, 23, 1); > +FIELD(SDHC_CAPAB, V33,24, 1); > +FIELD(SDHC_CAPAB, V30,25, 1); > +FIELD(SDHC_CAPAB, V18,26, 1); > > /* HWInit Maximum Current Capabilities Register 0x0 */ > #define SDHC_MAXCURR 0x48 > +FIELD(SDHC_MAXCURR, V33_VDD1, 0, 8); > +FIELD(SDHC_MAXCURR, V30_VDD1, 8, 8); > +FIELD(SDHC_MAXCURR, V18_VDD1, 16, 8); > > /* W Force Event Auto CMD12 Error Interrupt Register 0x */ > #define SDHC_FEAER 0x50 > diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c > index dce1a49af1..91dfd684d8 100644 > --- a/hw/sd/sdhci.c > +++ b/hw/sd/sdhci.c > @@ -23,6 +23,7 @@ > */ > > #include "qemu/osdep.h" > +#include "qemu/error-report.h" > #include "qapi/error.h" > #include "hw/hw.h" > #include "sysemu/block-backend.h" > @@ -64,6 +65,92 @@ static inline unsigned int sdhci_get_fifolen(SDHCIState *s) > return 1 << (9 + FIELD_EX32(s->capareg, SDHC_CAPAB, MAXBLOCKLENGTH)); > } > > +/* return true on error */ > +static bool sdhci_check_capab_freq_range(SDHCIState *s, const char *desc, > + uint8_t freq, Error **errp) > +{ > +switch (freq) { > +case 0: > +case 10 ... 63: > +break; > +default: > +error_setg(errp, "SD %s clock frequency can have value" > + "in range 0-63 only", desc); > +return true; > +} > +return false; > +} > + > +static void sdhci_check_capareg(SDHCIState *s, Error **errp) > +{ > +uint64_t msk = s->capareg; > +uint32_t val; > +bool y; > + > +switch (s->sd_spec_version) { > +case 2: /* default version */ > + > +/* fallback */ > +case 1: > +y = FIELD_EX64(s->capareg, SDHC_CAPAB, TOUNIT); > +msk = FIELD_DP64(msk, SDHC_CAPAB, TOUNIT, 0); > + > +val = FIELD_EX64(s->capareg, SDHC_CAPAB, TOCLKFREQ); > +trace_sdhci_capareg(y ? "timeout (MHz)" : "Timeout (KHz)", val); > +if (sdhci_check_capab_freq_range(s, "timeout", val, errp)) { > +return; > +} > +msk = FIELD_DP64(msk, SDHC_CAPAB, TOCLKFREQ, 0); > + > +val = FIELD_EX64(s->capareg, SDHC_CAPAB, BASECLKFREQ); > +trace_sdhci_capareg(y ? "base (MHz)" : "Base (KHz)", val); > +if (sdhci_check_capab_freq_range(s, "base", val, errp)) { > +return; > +} > +msk = FIELD_DP64(msk, SDHC_CAPAB,
Re: [Qemu-devel] [PATCH v1 06/21] RISC-V FPU Support
On 01/23/2018 03:15 PM, Michael Clark wrote: > > +uint64_t helper_fmsub_s(CPURISCVState *env, uint64_t frs1, uint64_t > frs2, > > +            uint64_t frs3, uint64_t rm) > > +{ > > +  require_fp; > > +  set_float_rounding_mode(RM, >fp_status); > > +  frs1 = float32_muladd(frs1, frs2, frs3 ^ (uint32_t)INT32_MIN, 0, > > +             >fp_status); > > Given that RISC-V always returns a default NaN, you obviously do not care > about > the sign of a NaN result. Therefore you should use float_muladd_negate_c > as > the fourth argument here and not perform the sign flip manually. > > > We do care about the sign of NaN results. > > Jim Wilson spotted this bug and removed a call to set_default_nan_mode > > https://github.com/riscv/riscv-qemu/commit/4223d89b0c5c671332d66bcd649db5c6f46559f5 Ok. Now it depends on what result you care about for madd specifically. If, like x86 and Power, fmsub returns the (silenced) original input NaN, you want the float_muladd_* flags. If, like ARM, fmsub returns the (silenced) negated input NaN, then you do need to change sign externally. If this is the case, please use float32_chs instead of open-coding it with xor. r~
Re: [Qemu-devel] [PATCH v1 06/21] RISC-V FPU Support
On 01/23/2018 01:37 PM, Michael Clark wrote: > > > On Wed, Jan 3, 2018 at 12:10 PM, Richard Henderson >> wrote: > > On 01/02/2018 04:44 PM, Michael Clark wrote: > > +/* convert RISC-V rounding mode to IEEE library numbers */ > > +unsigned int ieee_rm[] = { > > static const. > > > Done. > > > +/* obtain rm value to use in computation > > + * as the last step, convert rm codes to what the softfloat library > expects > > + * Adapted from Spike's decode.h:RM > > + */ > > +#define RM ({                       \ > > +if (rm == 7) {                      \ > > +  rm = env->frm;                \ > > +}                             \ > > +if (rm > 4) {                       \ > > +  helper_raise_exception(env, RISCV_EXCP_ILLEGAL_INST); \ > > +}                             \ > > +ieee_rm[rm]; }) > > Please use inline functions and not these macros. > > > Done. > > In fact the previous code would, with normal control flow, dereference > ieee_rm[rm] with an out of bounds round mode so assuming > helper_raise_exception > does a longjmp, i've inserted g_assert_not_reached() after the exception. An > analyser could detect that ieee_rm has an out of bounds access assuming normal > control flow. e.g. > > static inline void set_fp_round_mode(CPURISCVState *env, uint64_t rm) > { >   if (rm == 7) { >     rm = env->frm; >   } else if (rm > 4) { >     helper_raise_exception(env, RISCV_EXCP_ILLEGAL_INST); >     g_assert_not_reached(); Yes, raise_exception exits via longjmp. This is a good change. > Are translations not implicitly indexed by cpu_mmu_index? i.e. do we also need > to add cpu_mmu_index to cpu_get_tb_cpu_state flags to prevent code translated > for one value of mmu_index running in code with another value of mmu_index (in > the case of riscv, we currently return processor mode / privilege level in > cpu_mmu_index). No, there is no implicit indexing. That's why I've mentioned exactly this at least twice in review so far. There are two ways to do this correctly. One is to add all the bits that specify processor state (e.g. Alpha stores pal_code bit and supervisor bit). Another is to actually encode the mmu_idx into the flags (e.g. ARM). r~
[Qemu-devel] [PATCH 7/7] tests: virtio-9p: add FLUSH operation test
The idea is to send a victim request that will possibly block in the server and to send a flush request to cancel the victim request. This patch adds two test to verifiy that: - the server does not reply to a victim request that was actually cancelled - the server replies to the flush request after replying to the victim request if it could not cancel it 9p request cancellation reference: http://man.cat-v.org/plan_9/5/flush Signed-off-by: Greg Kurz--- hw/9pfs/9p-synth.c | 24 ++ hw/9pfs/9p-synth.h |5 ++ hw/9pfs/9p.c |1 tests/virtio-9p-test.c | 117 +++- 4 files changed, 134 insertions(+), 13 deletions(-) diff --git a/hw/9pfs/9p-synth.c b/hw/9pfs/9p-synth.c index f2d59a90a670..0a9940dfa23c 100644 --- a/hw/9pfs/9p-synth.c +++ b/hw/9pfs/9p-synth.c @@ -521,6 +521,24 @@ static ssize_t v9fs_synth_qtest_write(void *buf, int len, off_t offset, return len; } +static ssize_t v9fs_synth_qtest_flush_write(void *buf, int len, off_t offset, +void *arg) +{ +QtestV9fsSynthFlushData *data = buf; + +assert(len == sizeof(*data)); + +if (data->usec_timeout) { +usleep(data->usec_timeout); + +/* This will cause the server to call us again until we're cancelled */ +errno = EINTR; +return -1; +} + +return len; +} + static int synth_init(FsContext *ctx, Error **errp) { QLIST_INIT(_root.child); @@ -557,6 +575,12 @@ static int synth_init(FsContext *ctx, Error **errp) ret = qemu_v9fs_synth_add_file(NULL, 0, QTEST_V9FS_SYNTH_WRITE_FILE, NULL, v9fs_synth_qtest_write, ctx); assert(!ret); + +/* File for FLUSH test */ +ret = qemu_v9fs_synth_add_file(NULL, 0, QTEST_V9FS_SYNTH_FLUSH_FILE, + NULL, v9fs_synth_qtest_flush_write, + ctx); +assert(!ret); } return 0; diff --git a/hw/9pfs/9p-synth.h b/hw/9pfs/9p-synth.h index a74032d7bd9a..502ec6309a36 100644 --- a/hw/9pfs/9p-synth.h +++ b/hw/9pfs/9p-synth.h @@ -54,5 +54,10 @@ int qemu_v9fs_synth_add_file(V9fsSynthNode *parent, int mode, #define QTEST_V9FS_SYNTH_WALK_FILE "WALK%d" #define QTEST_V9FS_SYNTH_LOPEN_FILE "LOPEN" #define QTEST_V9FS_SYNTH_WRITE_FILE "WRITE" +#define QTEST_V9FS_SYNTH_FLUSH_FILE "FLUSH" + +typedef struct { +uint32_t usec_timeout; +} QtestV9fsSynthFlushData; #endif diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index 73dafffe239f..eae82db4ef60 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -24,6 +24,7 @@ #include "coth.h" #include "trace.h" #include "migration/blocker.h" +#include "sysemu/qtest.h" int open_fd_hw; int total_open_fd; diff --git a/tests/virtio-9p-test.c b/tests/virtio-9p-test.c index 57ae3a666c61..b234e09e252d 100644 --- a/tests/virtio-9p-test.c +++ b/tests/virtio-9p-test.c @@ -247,14 +247,15 @@ static const char *rmessage_name(uint8_t id) id == P9_RWALK ? "RWALK" : id == P9_RLOPEN ? "RLOPEN" : id == P9_RWRITE ? "RWRITE" : +id == P9_RFLUSH ? "RFLUSH" : ""; } -static void v9fs_req_wait_for_reply(P9Req *req) +static void v9fs_req_wait_for_reply(P9Req *req, uint32_t *len) { QVirtIO9P *v9p = req->v9p; -qvirtio_wait_used_elem(v9p->dev, v9p->vq, req->free_head, NULL, +qvirtio_wait_used_elem(v9p->dev, v9p->vq, req->free_head, len, QVIRTIO_9P_TIMEOUT_US); } @@ -451,6 +452,24 @@ static void v9fs_rwrite(P9Req *req, uint32_t *count) v9fs_req_free(req); } +/* size[4] Tflush tag[2] oldtag[2] */ +static P9Req *v9fs_tflush(QVirtIO9P *v9p, uint16_t oldtag, uint16_t tag) +{ +P9Req *req; + +req = v9fs_req_init(v9p, 2, P9_TFLUSH, tag); +v9fs_uint32_write(req, oldtag); +v9fs_req_send(req); +return req; +} + +/* size[4] Rflush tag[2] */ +static void v9fs_rflush(P9Req *req) +{ +v9fs_req_recv(req, P9_RFLUSH); +v9fs_req_free(req); +} + static void fs_version(QVirtIO9P *v9p) { const char *version = "9P2000.L"; @@ -459,7 +478,7 @@ static void fs_version(QVirtIO9P *v9p) P9Req *req; req = v9fs_tversion(v9p, P9_MAX_SIZE, version, P9_NOTAG); -v9fs_req_wait_for_reply(req); +v9fs_req_wait_for_reply(req, NULL); v9fs_rversion(req, _len, _version); g_assert_cmpmem(server_version, server_len, version, strlen(version)); @@ -473,7 +492,7 @@ static void fs_attach(QVirtIO9P *v9p) fs_version(v9p); req = v9fs_tattach(v9p, 0, getuid(), 0); -v9fs_req_wait_for_reply(req); +v9fs_req_wait_for_reply(req, NULL); v9fs_rattach(req, NULL); } @@ -491,7 +510,7 @@ static void fs_walk(QVirtIO9P *v9p) fs_attach(v9p); req = v9fs_twalk(v9p, 0, 1, P9_MAXWELEM, wnames, 0); -v9fs_req_wait_for_reply(req); +v9fs_req_wait_for_reply(req, NULL); v9fs_rwalk(req, , ); g_assert_cmpint(nwqid, ==,
[Qemu-devel] [PATCH 6/7] libqos/virtio: return length written into used descriptor
When a 9p request is flushed (ie, cancelled) by the guest, the device is expected to simply mark the request as used, without sending a 9p reply (ie, without writing anything into the used buffer). To be able to test this, we need access to the length written by the device into the used descriptor. This patch adds a uint32_t * argument to qvirtqueue_get_buf() and qvirtio_wait_used_elem() for this purpose. All existing users are updated accordingly. Signed-off-by: Greg Kurz--- tests/libqos/virtio.c| 25 + tests/libqos/virtio.h|3 ++- tests/virtio-9p-test.c |2 +- tests/virtio-blk-test.c | 24 +--- tests/virtio-net-test.c |6 +++--- tests/virtio-scsi-test.c |3 ++- 6 files changed, 38 insertions(+), 25 deletions(-) diff --git a/tests/libqos/virtio.c b/tests/libqos/virtio.c index 0879a621c8af..0dad5c19acde 100644 --- a/tests/libqos/virtio.c +++ b/tests/libqos/virtio.c @@ -119,6 +119,8 @@ uint8_t qvirtio_wait_status_byte_no_isr(QVirtioDevice *d, /* * qvirtio_wait_used_elem: * @desc_idx: The next expected vq->desc[] index in the used ring + * @len: A pointer that is filled with the length written into the buffer, may + * be NULL * @timeout_us: How many microseconds to wait before failing * * This function waits for the next completed request on the used ring. @@ -126,6 +128,7 @@ uint8_t qvirtio_wait_status_byte_no_isr(QVirtioDevice *d, void qvirtio_wait_used_elem(QVirtioDevice *d, QVirtQueue *vq, uint32_t desc_idx, +uint32_t *len, gint64 timeout_us) { gint64 start_time = g_get_monotonic_time(); @@ -136,7 +139,7 @@ void qvirtio_wait_used_elem(QVirtioDevice *d, clock_step(100); if (d->bus->get_queue_isr_status(d, vq) && -qvirtqueue_get_buf(vq, _desc_idx)) { +qvirtqueue_get_buf(vq, _desc_idx, len)) { g_assert_cmpint(got_desc_idx, ==, desc_idx); return; } @@ -304,30 +307,36 @@ void qvirtqueue_kick(QVirtioDevice *d, QVirtQueue *vq, uint32_t free_head) /* * qvirtqueue_get_buf: * @desc_idx: A pointer that is filled with the vq->desc[] index, may be NULL + * @len: A pointer that is filled with the length written into the buffer, may + * be NULL * * This function gets the next used element if there is one ready. * * Returns: true if an element was ready, false otherwise */ -bool qvirtqueue_get_buf(QVirtQueue *vq, uint32_t *desc_idx) +bool qvirtqueue_get_buf(QVirtQueue *vq, uint32_t *desc_idx, uint32_t *len) { uint16_t idx; +uint64_t elem_addr; idx = readw(vq->used + offsetof(struct vring_used, idx)); if (idx == vq->last_used_idx) { return false; } -if (desc_idx) { -uint64_t elem_addr; +elem_addr = vq->used + +offsetof(struct vring_used, ring) + +(vq->last_used_idx % vq->size) * +sizeof(struct vring_used_elem); -elem_addr = vq->used + -offsetof(struct vring_used, ring) + -(vq->last_used_idx % vq->size) * -sizeof(struct vring_used_elem); +if (desc_idx) { *desc_idx = readl(elem_addr + offsetof(struct vring_used_elem, id)); } +if (len) { +*len = readw(elem_addr + offsetof(struct vring_used_elem, len)); +} + vq->last_used_idx++; return true; } diff --git a/tests/libqos/virtio.h b/tests/libqos/virtio.h index 0a04740adfe1..69b5b13840e7 100644 --- a/tests/libqos/virtio.h +++ b/tests/libqos/virtio.h @@ -124,6 +124,7 @@ uint8_t qvirtio_wait_status_byte_no_isr(QVirtioDevice *d, void qvirtio_wait_used_elem(QVirtioDevice *d, QVirtQueue *vq, uint32_t desc_idx, +uint32_t *len, gint64 timeout_us); void qvirtio_wait_config_isr(QVirtioDevice *d, gint64 timeout_us); QVirtQueue *qvirtqueue_setup(QVirtioDevice *d, @@ -140,7 +141,7 @@ uint32_t qvirtqueue_add(QVirtQueue *vq, uint64_t data, uint32_t len, bool write, bool next); uint32_t qvirtqueue_add_indirect(QVirtQueue *vq, QVRingIndirectDesc *indirect); void qvirtqueue_kick(QVirtioDevice *d, QVirtQueue *vq, uint32_t free_head); -bool qvirtqueue_get_buf(QVirtQueue *vq, uint32_t *desc_idx); +bool qvirtqueue_get_buf(QVirtQueue *vq, uint32_t *desc_idx, uint32_t *len); void qvirtqueue_set_used_event(QVirtQueue *vq, uint16_t idx); diff --git a/tests/virtio-9p-test.c b/tests/virtio-9p-test.c index 5871a16dac73..57ae3a666c61 100644 --- a/tests/virtio-9p-test.c +++ b/tests/virtio-9p-test.c @@ -254,7 +254,7 @@ static void v9fs_req_wait_for_reply(P9Req *req) { QVirtIO9P *v9p = req->v9p; -qvirtio_wait_used_elem(v9p->dev, v9p->vq, req->free_head, +
[Qemu-devel] [PATCH 4/7] tests: virtio-9p: add LOPEN operation test
Trivial test of a successful open. Signed-off-by: Greg Kurz--- hw/9pfs/9p-synth.c |5 + hw/9pfs/9p-synth.h |1 + tests/virtio-9p-test.c | 47 +++ 3 files changed, 53 insertions(+) diff --git a/hw/9pfs/9p-synth.c b/hw/9pfs/9p-synth.c index dcbd320da17a..f17b74f44461 100644 --- a/hw/9pfs/9p-synth.c +++ b/hw/9pfs/9p-synth.c @@ -541,6 +541,11 @@ static int synth_init(FsContext *ctx, Error **errp) assert(!ret); g_free(name); } + +/* File for LOPEN test */ +ret = qemu_v9fs_synth_add_file(NULL, 0, QTEST_V9FS_SYNTH_LOPEN_FILE, + NULL, NULL, ctx); +assert(!ret); } return 0; diff --git a/hw/9pfs/9p-synth.h b/hw/9pfs/9p-synth.h index 876b4ef58288..2a8d6fd00d69 100644 --- a/hw/9pfs/9p-synth.h +++ b/hw/9pfs/9p-synth.h @@ -52,5 +52,6 @@ int qemu_v9fs_synth_add_file(V9fsSynthNode *parent, int mode, /* qtest stuff */ #define QTEST_V9FS_SYNTH_WALK_FILE "WALK%d" +#define QTEST_V9FS_SYNTH_LOPEN_FILE "LOPEN" #endif diff --git a/tests/virtio-9p-test.c b/tests/virtio-9p-test.c index 652198156731..6ba782e24f3a 100644 --- a/tests/virtio-9p-test.c +++ b/tests/virtio-9p-test.c @@ -238,6 +238,7 @@ static const char *rmessage_name(uint8_t id) id == P9_RVERSION ? "RVERSION" : id == P9_RATTACH ? "RATTACH" : id == P9_RWALK ? "RWALK" : +id == P9_RLOPEN ? "RLOPEN" : ""; } @@ -389,6 +390,34 @@ static void v9fs_rwalk(P9Req *req, uint16_t *nwqid, v9fs_qid **wqid) v9fs_req_free(req); } +/* size[4] Tlopen tag[2] fid[4] flags[4] */ +static P9Req *v9fs_tlopen(QVirtIO9P *v9p, uint32_t fid, uint32_t flags, + uint16_t tag) +{ +P9Req *req; + +req = v9fs_req_init(v9p, 4 + 4, P9_TLOPEN, tag); +v9fs_uint32_write(req, fid); +v9fs_uint32_write(req, flags); +v9fs_req_send(req); +return req; +} + +/* size[4] Rlopen tag[2] qid[13] iounit[4] */ +static void v9fs_rlopen(P9Req *req, v9fs_qid *qid, uint32_t *iounit) +{ +v9fs_req_recv(req, P9_RLOPEN); +if (qid) { +v9fs_memread(req, qid, 13); +} else { +v9fs_memskip(req, 13); +} +if (iounit) { +v9fs_uint32_read(req, iounit); +} +v9fs_req_free(req); +} + static void fs_version(QVirtIO9P *v9p) { const char *version = "9P2000.L"; @@ -478,6 +507,23 @@ static void fs_walk_dotdot(QVirtIO9P *v9p) g_free(wnames[0]); } +static void fs_lopen(QVirtIO9P *v9p) +{ +char *const wnames[] = { g_strdup(QTEST_V9FS_SYNTH_LOPEN_FILE) }; +P9Req *req; + +fs_attach(v9p); +req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0); +v9fs_req_wait_for_reply(req); +v9fs_rwalk(req, NULL, NULL); + +req = v9fs_tlopen(v9p, 1, O_WRONLY, 0); +v9fs_req_wait_for_reply(req); +v9fs_rlopen(req, NULL, NULL); + +g_free(wnames[0]); +} + typedef void (*v9fs_test_fn)(QVirtIO9P *v9p); static void v9fs_run_pci_test(gconstpointer data) @@ -507,6 +553,7 @@ int main(int argc, char **argv) v9fs_qtest_pci_add("/virtio/9p/pci/fs/walk/no_slash", fs_walk_no_slash); v9fs_qtest_pci_add("/virtio/9p/pci/fs/walk/dotdot_from_root", fs_walk_dotdot); +v9fs_qtest_pci_add("/virtio/9p/pci/fs/lopen/basic", fs_lopen); return g_test_run(); }
[Qemu-devel] [PATCH 5/7] tests: virtio-9p: add WRITE operation test
Trivial test of a successful write. Signed-off-by: Greg Kurz--- hw/9pfs/9p-synth.c | 11 + hw/9pfs/9p-synth.h |1 + tests/virtio-9p-test.c | 59 3 files changed, 71 insertions(+) diff --git a/hw/9pfs/9p-synth.c b/hw/9pfs/9p-synth.c index f17b74f44461..f2d59a90a670 100644 --- a/hw/9pfs/9p-synth.c +++ b/hw/9pfs/9p-synth.c @@ -515,6 +515,12 @@ static int synth_unlinkat(FsContext *ctx, V9fsPath *dir, return -1; } +static ssize_t v9fs_synth_qtest_write(void *buf, int len, off_t offset, + void *arg) +{ +return len; +} + static int synth_init(FsContext *ctx, Error **errp) { QLIST_INIT(_root.child); @@ -546,6 +552,11 @@ static int synth_init(FsContext *ctx, Error **errp) ret = qemu_v9fs_synth_add_file(NULL, 0, QTEST_V9FS_SYNTH_LOPEN_FILE, NULL, NULL, ctx); assert(!ret); + +/* File for WRITE test */ +ret = qemu_v9fs_synth_add_file(NULL, 0, QTEST_V9FS_SYNTH_WRITE_FILE, + NULL, v9fs_synth_qtest_write, ctx); +assert(!ret); } return 0; diff --git a/hw/9pfs/9p-synth.h b/hw/9pfs/9p-synth.h index 2a8d6fd00d69..a74032d7bd9a 100644 --- a/hw/9pfs/9p-synth.h +++ b/hw/9pfs/9p-synth.h @@ -53,5 +53,6 @@ int qemu_v9fs_synth_add_file(V9fsSynthNode *parent, int mode, #define QTEST_V9FS_SYNTH_WALK_FILE "WALK%d" #define QTEST_V9FS_SYNTH_LOPEN_FILE "LOPEN" +#define QTEST_V9FS_SYNTH_WRITE_FILE "WRITE" #endif diff --git a/tests/virtio-9p-test.c b/tests/virtio-9p-test.c index 6ba782e24f3a..5871a16dac73 100644 --- a/tests/virtio-9p-test.c +++ b/tests/virtio-9p-test.c @@ -150,6 +150,13 @@ static void v9fs_uint32_write(P9Req *req, uint32_t val) v9fs_memwrite(req, _val, 4); } +static void v9fs_uint64_write(P9Req *req, uint64_t val) +{ +uint64_t le_val = cpu_to_le64(val); + +v9fs_memwrite(req, _val, 8); +} + static void v9fs_uint32_read(P9Req *req, uint32_t *val) { v9fs_memread(req, val, 4); @@ -239,6 +246,7 @@ static const char *rmessage_name(uint8_t id) id == P9_RATTACH ? "RATTACH" : id == P9_RWALK ? "RWALK" : id == P9_RLOPEN ? "RLOPEN" : +id == P9_RWRITE ? "RWRITE" : ""; } @@ -418,6 +426,31 @@ static void v9fs_rlopen(P9Req *req, v9fs_qid *qid, uint32_t *iounit) v9fs_req_free(req); } +/* size[4] Twrite tag[2] fid[4] offset[8] count[4] data[count] */ +static P9Req *v9fs_twrite(QVirtIO9P *v9p, uint32_t fid, uint64_t offset, + uint32_t count, const void *data, uint16_t tag) +{ +P9Req *req; + +req = v9fs_req_init(v9p, 4 + 8 + 4 + count, P9_TWRITE, tag); +v9fs_uint32_write(req, fid); +v9fs_uint64_write(req, offset); +v9fs_uint32_write(req, count); +v9fs_memwrite(req, data, count); +v9fs_req_send(req); +return req; +} + +/* size[4] Rwrite tag[2] count[4] */ +static void v9fs_rwrite(P9Req *req, uint32_t *count) +{ +v9fs_req_recv(req, P9_RWRITE); +if (count) { +v9fs_uint32_read(req, count); +} +v9fs_req_free(req); +} + static void fs_version(QVirtIO9P *v9p) { const char *version = "9P2000.L"; @@ -524,6 +557,31 @@ static void fs_lopen(QVirtIO9P *v9p) g_free(wnames[0]); } +static void fs_write(QVirtIO9P *v9p) +{ +static const uint32_t write_count = P9_MAX_SIZE / 2; +char *const wnames[] = { g_strdup(QTEST_V9FS_SYNTH_WRITE_FILE) }; +char *buf = g_malloc(write_count); +uint32_t count; +P9Req *req; + +fs_attach(v9p); +req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0); +v9fs_req_wait_for_reply(req); +v9fs_rwalk(req, NULL, NULL); + +req = v9fs_tlopen(v9p, 1, O_WRONLY, 0); +v9fs_req_wait_for_reply(req); +v9fs_rlopen(req, NULL, NULL); + +req = v9fs_twrite(v9p, 1, 0, write_count, buf, 0); +v9fs_req_wait_for_reply(req); +v9fs_rwrite(req, ); +g_assert_cmpint(count, ==, write_count); + +g_free(wnames[0]); +} + typedef void (*v9fs_test_fn)(QVirtIO9P *v9p); static void v9fs_run_pci_test(gconstpointer data) @@ -554,6 +612,7 @@ int main(int argc, char **argv) v9fs_qtest_pci_add("/virtio/9p/pci/fs/walk/dotdot_from_root", fs_walk_dotdot); v9fs_qtest_pci_add("/virtio/9p/pci/fs/lopen/basic", fs_lopen); +v9fs_qtest_pci_add("/virtio/9p/pci/fs/write/basic", fs_write); return g_test_run(); }
[Qemu-devel] [PATCH 1/7] tests: virtio-9p: move request tag to the test functions
It doesn't really makes sense to hide the request tag from the test functions. It prevents to test the 9p server behavior when passed a wrong tag (ie, still in use or different from P9_NOTAG for a version request). Also the spec says that a tag is reusable as soon as the corresponding request was replied or flushed: no need to always increment tags like we do now. And finaly, an upcoming test of the flush command will need to manipulate tags explicitely. This simply changes all request functions to have a tag argument. Except for the version request which needs P9_NOTAG, all other tests can pass 0 since they wait for the reply before sending another request. Signed-off-by: Greg Kurz--- tests/virtio-9p-test.c | 28 ++-- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/virtio-9p-test.c b/tests/virtio-9p-test.c index 00f00f7246e9..5ada2839b9ae 100644 --- a/tests/virtio-9p-test.c +++ b/tests/virtio-9p-test.c @@ -27,7 +27,6 @@ typedef struct { QOSState *qs; QVirtQueue *vq; char *test_share; -uint16_t p9_req_tag; } QVirtIO9P; static QVirtIO9P *qvirtio_9p_start(const char *driver) @@ -294,10 +293,11 @@ static void v9fs_rlerror(P9Req *req, uint32_t *err) } /* size[4] Tversion tag[2] msize[4] version[s] */ -static P9Req *v9fs_tversion(QVirtIO9P *v9p, uint32_t msize, const char *version) +static P9Req *v9fs_tversion(QVirtIO9P *v9p, uint32_t msize, const char *version, +uint16_t tag) { P9Req *req = v9fs_req_init(v9p, 4 + v9fs_string_size(version), P9_TVERSION, - P9_NOTAG); + tag); v9fs_uint32_write(req, msize); v9fs_string_write(req, version); @@ -323,12 +323,12 @@ static void v9fs_rversion(P9Req *req, uint16_t *len, char **version) } /* size[4] Tattach tag[2] fid[4] afid[4] uname[s] aname[s] n_uname[4] */ -static P9Req *v9fs_tattach(QVirtIO9P *v9p, uint32_t fid, uint32_t n_uname) +static P9Req *v9fs_tattach(QVirtIO9P *v9p, uint32_t fid, uint32_t n_uname, + uint16_t tag) { const char *uname = ""; /* ignored by QEMU */ const char *aname = ""; /* ignored by QEMU */ -P9Req *req = v9fs_req_init(v9p, 4 + 4 + 2 + 2 + 4, P9_TATTACH, - ++(v9p->p9_req_tag)); +P9Req *req = v9fs_req_init(v9p, 4 + 4 + 2 + 2 + 4, P9_TATTACH, tag); v9fs_uint32_write(req, fid); v9fs_uint32_write(req, P9_NOFID); @@ -353,7 +353,7 @@ static void v9fs_rattach(P9Req *req, v9fs_qid *qid) /* size[4] Twalk tag[2] fid[4] newfid[4] nwname[2] nwname*(wname[s]) */ static P9Req *v9fs_twalk(QVirtIO9P *v9p, uint32_t fid, uint32_t newfid, - uint16_t nwname, char *const wnames[]) + uint16_t nwname, char *const wnames[], uint16_t tag) { P9Req *req; int i; @@ -362,7 +362,7 @@ static P9Req *v9fs_twalk(QVirtIO9P *v9p, uint32_t fid, uint32_t newfid, for (i = 0; i < nwname; i++) { size += v9fs_string_size(wnames[i]); } -req = v9fs_req_init(v9p, size, P9_TWALK, ++(v9p->p9_req_tag)); +req = v9fs_req_init(v9p, size, P9_TWALK, tag); v9fs_uint32_write(req, fid); v9fs_uint32_write(req, newfid); v9fs_uint16_write(req, nwname); @@ -397,7 +397,7 @@ static void fs_version(QVirtIO9P *v9p) char *server_version; P9Req *req; -req = v9fs_tversion(v9p, P9_MAX_SIZE, version); +req = v9fs_tversion(v9p, P9_MAX_SIZE, version, P9_NOTAG); v9fs_rversion(req, _len, _version); g_assert_cmpmem(server_version, server_len, version, strlen(version)); @@ -410,7 +410,7 @@ static void fs_attach(QVirtIO9P *v9p) P9Req *req; fs_version(v9p); -req = v9fs_tattach(v9p, 0, getuid()); +req = v9fs_tattach(v9p, 0, getuid(), 0); v9fs_rattach(req, NULL); } @@ -430,7 +430,7 @@ static void fs_walk(QVirtIO9P *v9p) } fs_attach(v9p); -req = v9fs_twalk(v9p, 0, 1, P9_MAXWELEM, wnames); +req = v9fs_twalk(v9p, 0, 1, P9_MAXWELEM, wnames, 0); v9fs_rwalk(req, , ); g_assert_cmpint(nwqid, ==, P9_MAXWELEM); @@ -451,7 +451,7 @@ static void fs_walk_no_slash(QVirtIO9P *v9p) uint32_t err; fs_attach(v9p); -req = v9fs_twalk(v9p, 0, 1, 1, wnames); +req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0); v9fs_rlerror(req, ); g_assert_cmpint(err, ==, ENOENT); @@ -466,10 +466,10 @@ static void fs_walk_dotdot(QVirtIO9P *v9p) P9Req *req; fs_version(v9p); -req = v9fs_tattach(v9p, 0, getuid()); +req = v9fs_tattach(v9p, 0, getuid(), 0); v9fs_rattach(req, _qid); -req = v9fs_twalk(v9p, 0, 1, 1, wnames); +req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0); v9fs_rwalk(req, NULL, ); /* We now we'll get one qid */ g_assert_cmpmem(_qid, 13, wqid[0], 13);
[Qemu-devel] [PATCH 3/7] tests: virtio-9p: use the synth backend
The purpose of virtio-9p-test is to test the virtio-9p device, especially the 9p server state machine. We don't really care what fsdev backend we're using. Moreover, if we want to be able to test the flush request or a device reset with in-flights I/O, it is close to impossible to achieve with a physical backend because we cannot ask it reliably to put an I/O on hold at a specific point in time. Fortunately, we can do that with the synthetic backend, which allows to register callbacks on read/write accesses to a specific file. This will be used by a later patch to test the 9P flush request. The walk request test is converted to using the synth backend. Signed-off-by: Greg Kurz--- hw/9pfs/9p-synth.c | 16 hw/9pfs/9p-synth.h |4 tests/virtio-9p-test.c | 22 ++ 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/hw/9pfs/9p-synth.c b/hw/9pfs/9p-synth.c index 8f255e91c00f..dcbd320da17a 100644 --- a/hw/9pfs/9p-synth.c +++ b/hw/9pfs/9p-synth.c @@ -19,6 +19,7 @@ #include "qemu/rcu.h" #include "qemu/rcu_queue.h" #include "qemu/cutils.h" +#include "sysemu/qtest.h" /* Root node for synth file system */ static V9fsSynthNode synth_root = { @@ -527,6 +528,21 @@ static int synth_init(FsContext *ctx, Error **errp) /* Mark the subsystem is ready for use */ synth_fs = 1; + +if (qtest_enabled()) { +V9fsSynthNode *node = NULL; +int i, ret; + +/* Directory hierarchy for WALK test */ +for (i = 0; i < P9_MAXWELEM; i++) { +char *name = g_strdup_printf(QTEST_V9FS_SYNTH_WALK_FILE, i); + +ret = qemu_v9fs_synth_mkdir(node, 0700, name, ); +assert(!ret); +g_free(name); +} +} + return 0; } diff --git a/hw/9pfs/9p-synth.h b/hw/9pfs/9p-synth.h index 49c2fc7b274e..876b4ef58288 100644 --- a/hw/9pfs/9p-synth.h +++ b/hw/9pfs/9p-synth.h @@ -49,4 +49,8 @@ int qemu_v9fs_synth_add_file(V9fsSynthNode *parent, int mode, const char *name, v9fs_synth_read read, v9fs_synth_write write, void *arg); +/* qtest stuff */ + +#define QTEST_V9FS_SYNTH_WALK_FILE "WALK%d" + #endif diff --git a/tests/virtio-9p-test.c b/tests/virtio-9p-test.c index cb086315a36e..652198156731 100644 --- a/tests/virtio-9p-test.c +++ b/tests/virtio-9p-test.c @@ -17,6 +17,7 @@ #include "standard-headers/linux/virtio_ids.h" #include "standard-headers/linux/virtio_pci.h" #include "hw/9pfs/9p.h" +#include "hw/9pfs/9p-synth.h" #define QVIRTIO_9P_TIMEOUT_US (10 * 1000 * 1000) @@ -26,23 +27,19 @@ typedef struct { QVirtioDevice *dev; QOSState *qs; QVirtQueue *vq; -char *test_share; } QVirtIO9P; static QVirtIO9P *qvirtio_9p_start(const char *driver) { const char *arch = qtest_get_arch(); -const char *cmd = "-fsdev local,id=fsdev0,security_model=none,path=%s " +const char *cmd = "-fsdev synth,id=fsdev0 " "-device %s,fsdev=fsdev0,mount_tag=%s"; QVirtIO9P *v9p = g_new0(QVirtIO9P, 1); -v9p->test_share = g_strdup("/tmp/qtest.XX"); -g_assert_nonnull(mkdtemp(v9p->test_share)); - if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { -v9p->qs = qtest_pc_boot(cmd, v9p->test_share, driver, mount_tag); +v9p->qs = qtest_pc_boot(cmd, driver, mount_tag); } else if (strcmp(arch, "ppc64") == 0) { -v9p->qs = qtest_spapr_boot(cmd, v9p->test_share, driver, mount_tag); +v9p->qs = qtest_spapr_boot(cmd, driver, mount_tag); } else { g_printerr("virtio-9p tests are only available on x86 or ppc64\n"); exit(EXIT_FAILURE); @@ -54,8 +51,6 @@ static QVirtIO9P *qvirtio_9p_start(const char *driver) static void qvirtio_9p_stop(QVirtIO9P *v9p) { qtest_shutdown(v9p->qs); -rmdir(v9p->test_share); -g_free(v9p->test_share); g_free(v9p); } @@ -422,17 +417,14 @@ static void fs_attach(QVirtIO9P *v9p) static void fs_walk(QVirtIO9P *v9p) { -char *wnames[P9_MAXWELEM], *paths[P9_MAXWELEM]; -char *last_path = v9p->test_share; +char *wnames[P9_MAXWELEM]; uint16_t nwqid; v9fs_qid *wqid; int i; P9Req *req; for (i = 0; i < P9_MAXWELEM; i++) { -wnames[i] = g_strdup_printf("%s%d", __func__, i); -last_path = paths[i] = g_strdup_printf("%s/%s", last_path, wnames[i]); -g_assert(!mkdir(paths[i], 0700)); +wnames[i] = g_strdup_printf(QTEST_V9FS_SYNTH_WALK_FILE, i); } fs_attach(v9p); @@ -443,8 +435,6 @@ static void fs_walk(QVirtIO9P *v9p) g_assert_cmpint(nwqid, ==, P9_MAXWELEM); for (i = 0; i < P9_MAXWELEM; i++) { -rmdir(paths[P9_MAXWELEM - i - 1]); -g_free(paths[P9_MAXWELEM - i - 1]); g_free(wnames[i]); }
[Qemu-devel] [PATCH 2/7] tests: virtio-9p: wait for completion in the test code
In order to test request cancellation, we will need to send multiple requests and wait for the associated replies. Since we poll the ISR to know if a request completed, we may have several replies to parse when we detect ISR was set to 1. This patch moves the waiting out of the reply parsing path, up into the functional tests. Signed-off-by: Greg Kurz--- tests/virtio-9p-test.c | 14 -- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/tests/virtio-9p-test.c b/tests/virtio-9p-test.c index 5ada2839b9ae..cb086315a36e 100644 --- a/tests/virtio-9p-test.c +++ b/tests/virtio-9p-test.c @@ -246,13 +246,17 @@ static const char *rmessage_name(uint8_t id) ""; } -static void v9fs_req_recv(P9Req *req, uint8_t id) +static void v9fs_req_wait_for_reply(P9Req *req) { QVirtIO9P *v9p = req->v9p; -P9Hdr hdr; qvirtio_wait_used_elem(v9p->dev, v9p->vq, req->free_head, QVIRTIO_9P_TIMEOUT_US); +} + +static void v9fs_req_recv(P9Req *req, uint8_t id) +{ +P9Hdr hdr; v9fs_memread(req, , 7); hdr.size = ldl_le_p(); @@ -398,6 +402,7 @@ static void fs_version(QVirtIO9P *v9p) P9Req *req; req = v9fs_tversion(v9p, P9_MAX_SIZE, version, P9_NOTAG); +v9fs_req_wait_for_reply(req); v9fs_rversion(req, _len, _version); g_assert_cmpmem(server_version, server_len, version, strlen(version)); @@ -411,6 +416,7 @@ static void fs_attach(QVirtIO9P *v9p) fs_version(v9p); req = v9fs_tattach(v9p, 0, getuid(), 0); +v9fs_req_wait_for_reply(req); v9fs_rattach(req, NULL); } @@ -431,6 +437,7 @@ static void fs_walk(QVirtIO9P *v9p) fs_attach(v9p); req = v9fs_twalk(v9p, 0, 1, P9_MAXWELEM, wnames, 0); +v9fs_req_wait_for_reply(req); v9fs_rwalk(req, , ); g_assert_cmpint(nwqid, ==, P9_MAXWELEM); @@ -452,6 +459,7 @@ static void fs_walk_no_slash(QVirtIO9P *v9p) fs_attach(v9p); req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0); +v9fs_req_wait_for_reply(req); v9fs_rlerror(req, ); g_assert_cmpint(err, ==, ENOENT); @@ -467,9 +475,11 @@ static void fs_walk_dotdot(QVirtIO9P *v9p) fs_version(v9p); req = v9fs_tattach(v9p, 0, getuid(), 0); +v9fs_req_wait_for_reply(req); v9fs_rattach(req, _qid); req = v9fs_twalk(v9p, 0, 1, 1, wnames, 0); +v9fs_req_wait_for_reply(req); v9fs_rwalk(req, NULL, ); /* We now we'll get one qid */ g_assert_cmpmem(_qid, 13, wqid[0], 13);
[Qemu-devel] [PATCH 0/7] tests: virtio-9p: test request cancellation
This series does several changes to virtio-9p-test in order to be able to test request cancellation (flush in 9p wording): patches 1-2: preparatory work, basically doing things in the test code, rather that in the common code for flexibility and clarity patch 3: the cornerstone of the series, switch to using the synth fsdev backend, which allows to associate specific write/read ops to a given file. Since this backend never got used since it was merged, it looks like an ideal vehicle to add QTEST aware code in QEMU patches 4-5: trivial open & write tests, since the flush test will need to open a file and write to it patch 6: another important patch that allows to know the length written by the guest into a used buffer patch 7: the goal of this series, two request cancellation tests This series depends on the following patch: https://lists.nongnu.org/archive/html/qemu-devel/2018-01/msg05604.html Please comment. Cheers, -- Greg --- Greg Kurz (7): tests: virtio-9p: move request tag to the test functions tests: virtio-9p: wait for completion in the test code tests: virtio-9p: use the synth backend tests: virtio-9p: add LOPEN operation test tests: virtio-9p: add WRITE operation test libqos/virtio: return length written into used descriptor tests: virtio-9p: add FLUSH operation test hw/9pfs/9p-synth.c | 56 ++ hw/9pfs/9p-synth.h | 11 ++ hw/9pfs/9p.c |1 tests/libqos/virtio.c| 25 +++- tests/libqos/virtio.h|3 - tests/virtio-9p-test.c | 263 -- tests/virtio-blk-test.c | 24 ++-- tests/virtio-net-test.c |6 + tests/virtio-scsi-test.c |3 - 9 files changed, 335 insertions(+), 57 deletions(-)
Re: [Qemu-devel] [PATCH v1 06/21] RISC-V FPU Support
On Tue, Jan 23, 2018 at 3:15 PM, Michael Clarkwrote: > > > On Wed, Jan 3, 2018 at 12:10 PM, Richard Henderson < > richard.hender...@linaro.org> wrote: > >> On 01/02/2018 04:44 PM, Michael Clark wrote: >> > +/* convert RISC-V rounding mode to IEEE library numbers */ >> > +unsigned int ieee_rm[] = { >> >> static const. >> >> > +/* obtain rm value to use in computation >> > + * as the last step, convert rm codes to what the softfloat library >> expects >> > + * Adapted from Spike's decode.h:RM >> > + */ >> > +#define RM ({ \ >> > +if (rm == 7) {\ >> > +rm = env->frm; \ >> > +} \ >> > +if (rm > 4) { \ >> > +helper_raise_exception(env, RISCV_EXCP_ILLEGAL_INST); \ >> > +} \ >> > +ieee_rm[rm]; }) >> >> Please use inline functions and not these macros. >> >> Probably this applies to some of the helpers that I've already reviewed, >> but >> you're going to need to use an exception raising function that also >> performs an >> unwind (usually via cpu_loop_exit_restore). The GETPC() that feeds the >> unwind >> must be placed in the outer-most helper (including inlines). >> >> > +#ifndef CONFIG_USER_ONLY >> > +#define require_fp if (!(env->mstatus & MSTATUS_FS)) { \ >> > +helper_raise_exception(env, RISCV_EXCP_ILLEGAL_INST); \ >> > +} >> >> If you included MSTATUS_FS in cpu_get_tb_cpu_state flags, then you could >> be >> checking for this at translation time instead of at run time. >> >> > +/* convert softfloat library flag numbers to RISC-V */ >> > +unsigned int softfloat_flags_to_riscv(unsigned int flags) >> > +{ >> > +int rv_flags = 0; >> > +rv_flags |= (flags & float_flag_inexact) ? 1 : 0; >> > +rv_flags |= (flags & float_flag_underflow) ? 2 : 0; >> > +rv_flags |= (flags & float_flag_overflow) ? 4 : 0; >> > +rv_flags |= (flags & float_flag_divbyzero) ? 8 : 0; >> > +rv_flags |= (flags & float_flag_invalid) ? 16 : 0; >> >> FPEXC_NX et al. >> >> > +/* adapted from Spike's decode.h:set_fp_exceptions */ >> > +#define set_fp_exceptions() do { \ >> > +env->fflags |= softfloat_flags_to_riscv(get_f >> loat_exception_flags(\ >> > +>fp_status)); \ >> > +set_float_exception_flags(0, >fp_status); \ >> > +} while (0) >> >> inline function. Usually written as >> >> int flags = get_float_exception_flags(>fp_status); >> if (flags) { >> set_float_exception_flags(0, >fp_status); >> env->fflags |= softfloat_flags_to_riscv(flags); >> } >> >> since we really do expect exceptions to be exceptional. >> >> > +uint64_t helper_fmsub_s(CPURISCVState *env, uint64_t frs1, uint64_t >> frs2, >> > +uint64_t frs3, uint64_t rm) >> > +{ >> > +require_fp; >> > +set_float_rounding_mode(RM, >fp_status); >> > +frs1 = float32_muladd(frs1, frs2, frs3 ^ (uint32_t)INT32_MIN, 0, >> > + >fp_status); >> >> Given that RISC-V always returns a default NaN, you obviously do not care >> about >> the sign of a NaN result. Therefore you should use float_muladd_negate_c >> as >> the fourth argument here and not perform the sign flip manually. > > > We do care about the sign of NaN results. > > Jim Wilson spotted this bug and removed a call to set_default_nan_mode > > https://github.com/riscv/riscv-qemu/commit/4223d89b0c5c671332d66bcd649db5 > c6f46559f5 > > >> > +uint64_t helper_fnmsub_s(CPURISCVState *env, uint64_t frs1, uint64_t >> frs2, >> > + uint64_t frs3, uint64_t rm) >> > +{ >> > +require_fp; >> > +set_float_rounding_mode(RM, >fp_status); >> > +frs1 = float32_muladd(frs1 ^ (uint32_t)INT32_MIN, frs2, frs3, 0, >> > + >fp_status); >> >> float_muladd_negate_product. >> >> > +uint64_t helper_fnmadd_s(CPURISCVState *env, uint64_t frs1, uint64_t >> frs2, >> > + uint64_t frs3, uint64_t rm) >> > +{ >> > +require_fp; >> > +set_float_rounding_mode(RM, >fp_status); >> > +frs1 = float32_muladd(frs1 ^ (uint32_t)INT32_MIN, frs2, >> > + frs3 ^ (uint32_t)INT32_MIN, 0, >> >fp_status); >> >> float_muladd_negate_c | float_muladd_negate_product >> >> > +uint64_t helper_fmin_s(CPURISCVState *env, uint64_t frs1, uint64_t >> frs2) >> > +{ >> > +require_fp; >> > +frs1 = float32_minnum(frs1, frs2, >fp_status); >> >> If you want minnum and not min, riscv-spec-v2.2.pdf could use some more >> verbage >> to specify that. > > > We'll look at Spike (riscv-isa-sim)... Spike has the correct behavior. > We want minimum number (minnum). It's been added to the draft spec and will be in riscv-spec-v2.3.pdf Section 8.6 in the draft spec says: " Floating-point minimum-number and maximum-number instructions FMIN.S and FMAX.S write,
Re: [Qemu-devel] [PATCH v1 06/21] RISC-V FPU Support
On Wed, Jan 3, 2018 at 12:10 PM, Richard Henderson < richard.hender...@linaro.org> wrote: > On 01/02/2018 04:44 PM, Michael Clark wrote: > > +/* convert RISC-V rounding mode to IEEE library numbers */ > > +unsigned int ieee_rm[] = { > > static const. > > > +/* obtain rm value to use in computation > > + * as the last step, convert rm codes to what the softfloat library > expects > > + * Adapted from Spike's decode.h:RM > > + */ > > +#define RM ({ \ > > +if (rm == 7) {\ > > +rm = env->frm; \ > > +} \ > > +if (rm > 4) { \ > > +helper_raise_exception(env, RISCV_EXCP_ILLEGAL_INST); \ > > +} \ > > +ieee_rm[rm]; }) > > Please use inline functions and not these macros. > > Probably this applies to some of the helpers that I've already reviewed, > but > you're going to need to use an exception raising function that also > performs an > unwind (usually via cpu_loop_exit_restore). The GETPC() that feeds the > unwind > must be placed in the outer-most helper (including inlines). > > > +#ifndef CONFIG_USER_ONLY > > +#define require_fp if (!(env->mstatus & MSTATUS_FS)) { \ > > +helper_raise_exception(env, RISCV_EXCP_ILLEGAL_INST); \ > > +} > > If you included MSTATUS_FS in cpu_get_tb_cpu_state flags, then you could be > checking for this at translation time instead of at run time. > > > +/* convert softfloat library flag numbers to RISC-V */ > > +unsigned int softfloat_flags_to_riscv(unsigned int flags) > > +{ > > +int rv_flags = 0; > > +rv_flags |= (flags & float_flag_inexact) ? 1 : 0; > > +rv_flags |= (flags & float_flag_underflow) ? 2 : 0; > > +rv_flags |= (flags & float_flag_overflow) ? 4 : 0; > > +rv_flags |= (flags & float_flag_divbyzero) ? 8 : 0; > > +rv_flags |= (flags & float_flag_invalid) ? 16 : 0; > > FPEXC_NX et al. > > > +/* adapted from Spike's decode.h:set_fp_exceptions */ > > +#define set_fp_exceptions() do { \ > > +env->fflags |= softfloat_flags_to_riscv(get_float_exception_flags(\ > > +>fp_status)); \ > > +set_float_exception_flags(0, >fp_status); \ > > +} while (0) > > inline function. Usually written as > > int flags = get_float_exception_flags(>fp_status); > if (flags) { > set_float_exception_flags(0, >fp_status); > env->fflags |= softfloat_flags_to_riscv(flags); > } > > since we really do expect exceptions to be exceptional. > > > +uint64_t helper_fmsub_s(CPURISCVState *env, uint64_t frs1, uint64_t > frs2, > > +uint64_t frs3, uint64_t rm) > > +{ > > +require_fp; > > +set_float_rounding_mode(RM, >fp_status); > > +frs1 = float32_muladd(frs1, frs2, frs3 ^ (uint32_t)INT32_MIN, 0, > > + >fp_status); > > Given that RISC-V always returns a default NaN, you obviously do not care > about > the sign of a NaN result. Therefore you should use float_muladd_negate_c > as > the fourth argument here and not perform the sign flip manually. We do care about the sign of NaN results. Jim Wilson spotted this bug and removed a call to set_default_nan_mode https://github.com/riscv/riscv-qemu/commit/4223d89b0c5c671332d66bcd649db5c6f46559f5 > > +uint64_t helper_fnmsub_s(CPURISCVState *env, uint64_t frs1, uint64_t > frs2, > > + uint64_t frs3, uint64_t rm) > > +{ > > +require_fp; > > +set_float_rounding_mode(RM, >fp_status); > > +frs1 = float32_muladd(frs1 ^ (uint32_t)INT32_MIN, frs2, frs3, 0, > > + >fp_status); > > float_muladd_negate_product. > > > +uint64_t helper_fnmadd_s(CPURISCVState *env, uint64_t frs1, uint64_t > frs2, > > + uint64_t frs3, uint64_t rm) > > +{ > > +require_fp; > > +set_float_rounding_mode(RM, >fp_status); > > +frs1 = float32_muladd(frs1 ^ (uint32_t)INT32_MIN, frs2, > > + frs3 ^ (uint32_t)INT32_MIN, 0, > >fp_status); > > float_muladd_negate_c | float_muladd_negate_product > > > +uint64_t helper_fmin_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2) > > +{ > > +require_fp; > > +frs1 = float32_minnum(frs1, frs2, >fp_status); > > If you want minnum and not min, riscv-spec-v2.2.pdf could use some more > verbage > to specify that. We'll look at Spike (riscv-isa-sim)... Spike has the correct behavior. > > +/* adapted from spike */ > > +#define isNaNF32UI(ui) (0xFF00 < (uint32_t)((uint_fast32_t)ui << 1)) > > float32_is_any_nan > > > +#define signF32UI(a) ((bool)((uint32_t)a >> 31)) > > float32_is_neg > > > +#define expF32UI(a) ((int_fast16_t)(a >> 23) & 0xFF) > > +#define fracF32UI(a) (a & 0x007F) > > Either float32_is_infinity or float32_is_zero_or_denormal. > > > +union ui32_f32 { uint32_t ui; uint32_t f; }; > > This is just silly. > > >
Re: [Qemu-devel] [PATCH] pl110: Implement vertical compare/next base interrupts
Hi, This series seems to have some coding style problems. See output below for more information: Type: series Message-id: 20180123225654.5764-1-linus.wall...@linaro.org Subject: [Qemu-devel] [PATCH] pl110: Implement vertical compare/next base interrupts === TEST SCRIPT BEGIN === #!/bin/bash BASE=base n=1 total=$(git log --oneline $BASE.. | wc -l) failed=0 git config --local diff.renamelimit 0 git config --local diff.renames True commits="$(git log --format=%H --reverse $BASE..)" for c in $commits; do echo "Checking PATCH $n/$total: $(git log -n 1 --format=%s $c)..." if ! git show $c --format=email | ./scripts/checkpatch.pl --mailback -; then failed=1 echo fi n=$((n+1)) done exit $failed === TEST SCRIPT END === Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384 From https://github.com/patchew-project/qemu * [new tag] patchew/20180123225654.5764-1-linus.wall...@linaro.org -> patchew/20180123225654.5764-1-linus.wall...@linaro.org Switched to a new branch 'test' 2512b151b6 pl110: Implement vertical compare/next base interrupts === OUTPUT BEGIN === Checking PATCH 1/1: pl110: Implement vertical compare/next base interrupts... WARNING: line over 80 characters #76: FILE: hw/display/pl110.c:342: + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + NANOSECONDS_PER_SECOND / 60); ERROR: line over 90 characters #86: FILE: hw/display/pl110.c:453: + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + NANOSECONDS_PER_SECOND / 60); WARNING: line over 80 characters #96: FILE: hw/display/pl110.c:501: +s->vblank_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, pl110_vblank_interrupt, s); total: 1 errors, 2 warnings, 63 lines checked Your patch has style problems, please review. If any of these errors are false positives report them to the maintainer, see CHECKPATCH in MAINTAINERS. === OUTPUT END === Test command exited with code: 1 --- Email generated automatically by Patchew [http://patchew.org/]. Please send your feedback to patchew-de...@freelists.org
[Qemu-devel] [PATCH] pl110: Implement vertical compare/next base interrupts
This implements rudimentary support for interrupt generation on the PL110. I am working on a new DRI/KMS driver for Linux and since that uses the blanking interrupt, we need something to fire here. Without any interrupt support Linux waits for a while and then gives ugly messages about the vblank not working in the console (it does not hang perpetually or anything though, DRI is pretty forgiving). I solved it for now by setting up a timer to fire at 60Hz and pull the interrupts for "vertical compare" and "next memory base" at this interval. This works fine and fires roughly the same number of IRQs on QEMU as on the hardware and leaves the console clean and nice. People who want to create more accurate emulation can probably work on top of this if need be. It is certainly closer to the hardware behaviour than what we have today anyway. Cc: Peter MaydellSigned-off-by: Linus Walleij --- hw/display/pl110.c | 27 ++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/hw/display/pl110.c b/hw/display/pl110.c index 8c7dcc6f0a69..777bb3f44503 100644 --- a/hw/display/pl110.c +++ b/hw/display/pl110.c @@ -12,6 +12,7 @@ #include "ui/console.h" #include "framebuffer.h" #include "ui/pixel_ops.h" +#include "qemu/timer.h" #include "qemu/log.h" #define PL110_CR_EN 0x001 @@ -19,6 +20,8 @@ #define PL110_CR_BEBO 0x200 #define PL110_CR_BEPO 0x400 #define PL110_CR_PWR 0x800 +#define PL110_IE_NB 0x004 +#define PL110_IE_VC 0x008 enum pl110_bppmode { @@ -50,6 +53,7 @@ typedef struct PL110State { MemoryRegion iomem; MemoryRegionSection fbsection; QemuConsole *con; +QEMUTimer *vblank_timer; int version; uint32_t timing[4]; @@ -320,7 +324,23 @@ static void pl110_resize(PL110State *s, int width, int height) /* Update interrupts. */ static void pl110_update(PL110State *s) { - /* TODO: Implement interrupts. */ +/* Raise IRQ if enabled and any status bit is 1 */ +if (s->int_status & s->int_mask) { +qemu_irq_raise(s->irq); +} else { +qemu_irq_lower(s->irq); +} +} + +static void pl110_vblank_interrupt(void *opaque) +{ +PL110State *s = opaque; + +/* Fire the vertical compare and next base IRQs and re-arm */ +s->int_status |= (PL110_IE_NB | PL110_IE_VC); +timer_mod(s->vblank_timer, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + NANOSECONDS_PER_SECOND / 60); +pl110_update(s); } static uint64_t pl110_read(void *opaque, hwaddr offset, @@ -429,6 +449,10 @@ static void pl110_write(void *opaque, hwaddr offset, s->bpp = (val >> 1) & 7; if (pl110_enabled(s)) { qemu_console_resize(s->con, s->cols, s->rows); +timer_mod(s->vblank_timer, + qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + NANOSECONDS_PER_SECOND / 60); +} else { +timer_del(s->vblank_timer); } break; case 10: /* LCDICR */ @@ -474,6 +498,7 @@ static void pl110_realize(DeviceState *dev, Error **errp) memory_region_init_io(>iomem, OBJECT(s), _ops, s, "pl110", 0x1000); sysbus_init_mmio(sbd, >iomem); sysbus_init_irq(sbd, >irq); +s->vblank_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, pl110_vblank_interrupt, s); qdev_init_gpio_in(dev, pl110_mux_ctrl_set, 1); s->con = graphic_console_init(dev, 0, _gfx_ops, s); } -- 2.14.3
Re: [Qemu-devel] [PATCH v3 12/12] sdcard: use the registerfields API to access the OCR register
On Mon, Jan 22, 2018 at 7:21 PM, Philippe Mathieu-Daudéwrote: > Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Alistair > --- > include/hw/sd/sd.h | 1 - > hw/sd/sd.c | 21 + > 2 files changed, 13 insertions(+), 9 deletions(-) > > diff --git a/include/hw/sd/sd.h b/include/hw/sd/sd.h > index bf1eb0713c..9bdb3c9285 100644 > --- a/include/hw/sd/sd.h > +++ b/include/hw/sd/sd.h > @@ -53,7 +53,6 @@ > #define READY_FOR_DATA (1 << 8) > #define APP_CMD(1 << 5) > #define AKE_SEQ_ERROR (1 << 3) > -#define OCR_CCS_BITN30 > > typedef enum { > SD_VOLTAGE_0_4V = 400, /* currently not supported */ > diff --git a/hw/sd/sd.c b/hw/sd/sd.c > index f87e543f8f..437ce25f79 100644 > --- a/hw/sd/sd.c > +++ b/hw/sd/sd.c > @@ -32,6 +32,7 @@ > #include "qemu/osdep.h" > #include "hw/qdev.h" > #include "hw/hw.h" > +#include "hw/registerfields.h" > #include "sysemu/block-backend.h" > #include "hw/sd/sd.h" > #include "qapi/error.h" > @@ -47,8 +48,6 @@ > //#define DEBUG_SD 1 > > #define ACMD41_ENQUIRY_MASK 0x00ff > -#define OCR_POWER_UP0x8000 > -#define OCR_POWER_DELAY_NS 50 /* 0.5ms */ > > typedef enum { > sd_r0 = 0,/* no response */ > @@ -270,6 +269,11 @@ static uint16_t sd_crc16(void *message, size_t width) > return shift_reg; > } > > +#define OCR_POWER_DELAY_NS 50 /* 0.5ms */ > + > +FIELD(OCR, CARD_CAPACITY, 30, 1) /* 0:SDSC, 1:SDHC/SDXC */ > +FIELD(OCR, CARD_POWER_UP, 31, 1) > + > static void sd_reset_ocr(SDState *sd) > { > /* All voltages OK, Standard Capacity SD Memory Card, not yet powered up > */ > @@ -281,9 +285,10 @@ static void sd_ocr_powerup(void *opaque) > SDState *sd = opaque; > > trace_sdcard_powerup(); > -/* Set powered up bit in OCR */ > -assert(!(sd->ocr & OCR_POWER_UP)); > -sd->ocr |= OCR_POWER_UP; > +assert(!FIELD_EX32(sd->ocr, OCR, CARD_POWER_UP)); > + > +/* card power-up OK */ > +sd->ocr = FIELD_DP32(sd->ocr, OCR, CARD_POWER_UP, 1); > } > > static void sd_reset_scr(SDState *sd) > @@ -574,7 +579,7 @@ static bool sd_ocr_vmstate_needed(void *opaque) > SDState *sd = opaque; > > /* Include the OCR state (and timer) if it is not yet powered up */ > -return !(sd->ocr & OCR_POWER_UP); > +return !FIELD_EX32(sd->ocr, OCR, CARD_POWER_UP); > } > > static const VMStateDescription sd_ocr_vmstate = { > @@ -684,7 +689,7 @@ static void sd_erase(SDState *sd) > return; > } > > -if (extract32(sd->ocr, OCR_CCS_BITN, 1)) { > +if (FIELD_EX32(sd->ocr, OCR, CARD_CAPACITY)) { > /* High capacity memory card: erase units are 512 byte blocks */ > erase_start *= 512; > erase_end *= 512; > @@ -1476,7 +1481,7 @@ static sd_rsp_type_t sd_app_command(SDState *sd, > * UEFI, which sends an initial enquiry ACMD41, but > * assumes that the card is in ready state as soon as it > * sees the power up bit set. */ > -if (!(sd->ocr & OCR_POWER_UP)) { > +if (!FIELD_EX32(sd->ocr, OCR, CARD_POWER_UP)) { > if ((req.arg & ACMD41_ENQUIRY_MASK) != 0) { > timer_del(sd->ocr_power_timer); > sd_ocr_powerup(sd); > -- > 2.15.1 > >
Re: [Qemu-devel] [PATCH v3 06/12] sdcard: do not trace CMD55 when expecting ACMD
On Mon, Jan 22, 2018 at 7:21 PM, Philippe Mathieu-Daudéwrote: > Signed-off-by: Philippe Mathieu-Daudé Acked-by: Alistair Francis Alistair > --- > hw/sd/sd.c | 8 +--- > 1 file changed, 5 insertions(+), 3 deletions(-) > > diff --git a/hw/sd/sd.c b/hw/sd/sd.c > index dc4b2329e4..27c08aa894 100644 > --- a/hw/sd/sd.c > +++ b/hw/sd/sd.c > @@ -816,13 +816,15 @@ static void sd_lock_command(SDState *sd) > sd->card_status &= ~CARD_IS_LOCKED; > } > > -static sd_rsp_type_t sd_normal_command(SDState *sd, > - SDRequest req) > +static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) > { > uint32_t rca = 0x; > uint64_t addr = (sd->ocr & (1 << 30)) ? (uint64_t) req.arg << 9 : > req.arg; > > -trace_sdcard_normal_command(req.cmd, req.arg, sd_state_name(sd->state)); > +if (req.cmd != 55 || sd->expecting_acmd) { > +trace_sdcard_normal_command(req.cmd, req.arg, > +sd_state_name(sd->state)); > +} > > /* Not interpreting this as an app command */ > sd->card_status &= ~APP_CMD; > -- > 2.15.1 > >
Re: [Qemu-devel] [PATCH v3 04/12] sdcard: replace fprintf() by qemu_hexdump()
On Mon, Jan 22, 2018 at 7:21 PM, Philippe Mathieu-Daudéwrote: > Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Alistair > --- > hw/sd/sd.c | 15 +-- > 1 file changed, 1 insertion(+), 14 deletions(-) > > diff --git a/hw/sd/sd.c b/hw/sd/sd.c > index 3590099ce8..03263e08ae 100644 > --- a/hw/sd/sd.c > +++ b/hw/sd/sd.c > @@ -44,13 +44,6 @@ > > //#define DEBUG_SD 1 > > -#ifdef DEBUG_SD > -#define DPRINTF(fmt, ...) \ > -do { fprintf(stderr, "SD: " fmt , ## __VA_ARGS__); } while (0) > -#else > -#define DPRINTF(fmt, ...) do {} while(0) > -#endif > - > #define ACMD41_ENQUIRY_MASK 0x00ff > #define OCR_POWER_UP0x8000 > #define OCR_POWER_DELAY_NS 50 /* 0.5ms */ > @@ -1630,13 +1623,7 @@ send_response: > } > > #ifdef DEBUG_SD > -if (rsplen) { > -int i; > -DPRINTF("Response:"); > -for (i = 0; i < rsplen; i++) > -fprintf(stderr, " %02x", response[i]); > -fputc('\n', stderr); > -} > +qemu_hexdump((const char *)response, stderr, "Response", rsplen); > #endif > > return rsplen; > -- > 2.15.1 > >
Re: [Qemu-devel] [PATCH v8 10/14] hw/arm/xilinx_zynqmp: fix the capabilities/spec version to match the datasheet
On Mon, Jan 22, 2018 at 7:06 PM, Philippe Mathieu-Daudéwrote: > checking Xilinx datasheet "UG1085" (v1.7) > > Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Alistair > --- > hw/arm/xlnx-zynqmp.c | 29 ++--- > 1 file changed, 18 insertions(+), 11 deletions(-) > > diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c > index 325642058b..33d5fe53d8 100644 > --- a/hw/arm/xlnx-zynqmp.c > +++ b/hw/arm/xlnx-zynqmp.c > @@ -50,6 +50,8 @@ > #define DPDMA_ADDR 0xfd4c > #define DPDMA_IRQ 116 > > +#define SDHCI_CAPABILITIES 0x280737ec6481 /* Datasheet: UG1085 (v1.7) */ > + > static const uint64_t gem_addr[XLNX_ZYNQMP_NUM_GEMS] = { > 0xFF0B, 0xFF0C, 0xFF0D, 0xFF0E, > }; > @@ -381,22 +383,27 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error > **errp) > sysbus_connect_irq(SYS_BUS_DEVICE(>sata), 0, gic_spi[SATA_INTR]); > > for (i = 0; i < XLNX_ZYNQMP_NUM_SDHCI; i++) { > -char *bus_name; > - > -object_property_set_bool(OBJECT(>sdhci[i]), true, > - "realized", ); > +char *bus_name = g_strdup_printf("sd-bus%d", i); > +SysBusDevice *sbd = SYS_BUS_DEVICE(>sdhci[i]); > +Object *sdhci = OBJECT(>sdhci[i]); > + > +/* Compatible with: > + * - SD Host Controller Specification Version 3.00 > + * - SDIO Specification Version 3.0 > + * - eMMC Specification Version 4.51 > + */ > +object_property_set_uint(sdhci, 3, "sd-spec-version", ); > +object_property_set_uint(sdhci, SDHCI_CAPABILITIES, "capareg", ); > +object_property_set_bool(sdhci, true, "realized", ); > if (err) { > error_propagate(errp, err); > return; > } > -sysbus_mmio_map(SYS_BUS_DEVICE(>sdhci[i]), 0, > -sdhci_addr[i]); > -sysbus_connect_irq(SYS_BUS_DEVICE(>sdhci[i]), 0, > - gic_spi[sdhci_intr[i]]); > +sysbus_mmio_map(sbd, 0, sdhci_addr[i]); > +sysbus_connect_irq(sbd, 0, gic_spi[sdhci_intr[i]]); > + > /* Alias controller SD bus to the SoC itself */ > -bus_name = g_strdup_printf("sd-bus%d", i); > -object_property_add_alias(OBJECT(s), bus_name, > - OBJECT(>sdhci[i]), "sd-bus", > +object_property_add_alias(OBJECT(s), bus_name, sdhci, "sd-bus", >_abort); > g_free(bus_name); > } > -- > 2.15.1 > >
Re: [Qemu-devel] [PATCH v8 09/14] hw/arm/fsl-imx6: implement SDHCI Spec. v3
On Mon, Jan 22, 2018 at 7:06 PM, Philippe Mathieu-Daudéwrote: > Signed-off-by: Philippe Mathieu-Daudé Acked-by: Alistair Francis Alistair > --- > various FreeBSD console output from google search show this register having > a value of 0x0377c800. > > hw/arm/fsl-imx6.c | 7 +++ > 1 file changed, 7 insertions(+) > > diff --git a/hw/arm/fsl-imx6.c b/hw/arm/fsl-imx6.c > index b0d4088290..1f4607f206 100644 > --- a/hw/arm/fsl-imx6.c > +++ b/hw/arm/fsl-imx6.c > @@ -27,6 +27,8 @@ > #include "chardev/char.h" > #include "qemu/error-report.h" > > +#define IMX6_ESDHC_CAPABILITIES 0x057834b4 > + > #define NAME_SIZE 20 > > static void fsl_imx6_init(Object *obj) > @@ -348,6 +350,11 @@ static void fsl_imx6_realize(DeviceState *dev, Error > **errp) > { FSL_IMX6_uSDHC4_ADDR, FSL_IMX6_uSDHC4_IRQ }, > }; > > +/* UHS-I SDIO3.0 SDR104 1.8V ADMA */ > +object_property_set_uint(OBJECT(>esdhc[i]), 3, "sd-spec-version", > + ); > +object_property_set_uint(OBJECT(>esdhc[i]), > IMX6_ESDHC_CAPABILITIES, > + "capareg", ); > object_property_set_bool(OBJECT(>esdhc[i]), true, "realized", > ); > if (err) { > error_propagate(errp, err); > -- > 2.15.1 > >
Re: [Qemu-devel] [PATCH v8 11/14] hw/arm/xilinx_zynqmp: enable the UHS-I mode
On Mon, Jan 22, 2018 at 7:06 PM, Philippe Mathieu-Daudéwrote: > see the Xilinx datasheet "UG1085" (v1.7) > > Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Alistair > --- > hw/arm/xlnx-zynqmp.c | 1 + > 1 file changed, 1 insertion(+) > > diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c > index 33d5fe53d8..bb4265a4ce 100644 > --- a/hw/arm/xlnx-zynqmp.c > +++ b/hw/arm/xlnx-zynqmp.c > @@ -394,6 +394,7 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error > **errp) > */ > object_property_set_uint(sdhci, 3, "sd-spec-version", ); > object_property_set_uint(sdhci, SDHCI_CAPABILITIES, "capareg", ); > +object_property_set_uint(sdhci, UHS_I, "uhs", ); > object_property_set_bool(sdhci, true, "realized", ); > if (err) { > error_propagate(errp, err); > -- > 2.15.1 > >
Re: [Qemu-devel] [PATCH v8 06/14] sdhci: implement CMD/DAT[] fields in the Present State register
On Mon, Jan 22, 2018 at 7:06 PM, Philippe Mathieu-Daudéwrote: > [based on a patch from Alistair Francis > from qemu/xilinx tag xilinx-v2015.2] > Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Alistair > --- > hw/sd/sdhci-internal.h | 2 ++ > include/hw/sd/sd.h | 4 > hw/sd/core.c | 34 ++ > hw/sd/sd.c | 16 > hw/sd/sdhci.c | 4 > hw/sd/trace-events | 2 ++ > 6 files changed, 62 insertions(+) > > diff --git a/hw/sd/sdhci-internal.h b/hw/sd/sdhci-internal.h > index e7cbea297f..514ecd4841 100644 > --- a/hw/sd/sdhci-internal.h > +++ b/hw/sd/sdhci-internal.h > @@ -82,6 +82,8 @@ > #define SDHC_CARD_PRESENT 0x0001 > #define SDHC_CARD_DETECT 0x0004 > #define SDHC_WRITE_PROTECT 0x0008 > +FIELD(SDHC_PRNSTS, DAT_LVL,20, 4); > +FIELD(SDHC_PRNSTS, CMD_LVL,24, 1); > #define TRANSFERRING_DATA(x) \ > ((x) & (SDHC_DOING_READ | SDHC_DOING_WRITE)) > > diff --git a/include/hw/sd/sd.h b/include/hw/sd/sd.h > index f086679493..bf1eb0713c 100644 > --- a/include/hw/sd/sd.h > +++ b/include/hw/sd/sd.h > @@ -103,6 +103,8 @@ typedef struct { > uint8_t (*read_data)(SDState *sd); > bool (*data_ready)(SDState *sd); > void (*set_voltage)(SDState *sd, uint16_t millivolts); > +uint8_t (*get_dat_lines)(SDState *sd); > +bool (*get_cmd_line)(SDState *sd); > void (*enable)(SDState *sd, bool enable); > bool (*get_inserted)(SDState *sd); > bool (*get_readonly)(SDState *sd); > @@ -150,6 +152,8 @@ void sd_enable(SDState *sd, bool enable); > * an SDBus rather than directly with SDState) > */ > void sdbus_set_voltage(SDBus *sdbus, uint16_t millivolts); > +uint8_t sdbus_get_dat_lines(SDBus *sdbus); > +bool sdbus_get_cmd_line(SDBus *sdbus); > int sdbus_do_command(SDBus *sd, SDRequest *req, uint8_t *response); > void sdbus_write_data(SDBus *sd, uint8_t value); > uint8_t sdbus_read_data(SDBus *sd); > diff --git a/hw/sd/core.c b/hw/sd/core.c > index 6d198ea775..3c6eae6c88 100644 > --- a/hw/sd/core.c > +++ b/hw/sd/core.c > @@ -41,6 +41,40 @@ static SDState *get_card(SDBus *sdbus) > return SD_CARD(kid->child); > } > > +uint8_t sdbus_get_dat_lines(SDBus *sdbus) > +{ > +SDState *slave = get_card(sdbus); > +uint8_t dat_lines = 0b; /* 4 bit bus width */ > + > +if (slave) { > +SDCardClass *sc = SD_CARD_GET_CLASS(slave); > + > +if (sc->get_dat_lines) { > +dat_lines = sc->get_dat_lines(slave); > +} > +} > +trace_sdbus_get_dat_lines(sdbus_name(sdbus), dat_lines); > + > +return dat_lines; > +} > + > +bool sdbus_get_cmd_line(SDBus *sdbus) > +{ > +SDState *slave = get_card(sdbus); > +bool cmd_line = true; > + > +if (slave) { > +SDCardClass *sc = SD_CARD_GET_CLASS(slave); > + > +if (sc->get_cmd_line) { > +cmd_line = sc->get_cmd_line(slave); > +} > +} > +trace_sdbus_get_cmd_line(sdbus_name(sdbus), cmd_line); > + > +return cmd_line; > +} > + > void sdbus_set_voltage(SDBus *sdbus, uint16_t millivolts) > { > SDState *card = get_card(sdbus); > diff --git a/hw/sd/sd.c b/hw/sd/sd.c > index 609b2da14f..ab9be561d2 100644 > --- a/hw/sd/sd.c > +++ b/hw/sd/sd.c > @@ -126,8 +126,20 @@ struct SDState { > BlockBackend *blk; > > bool enable; > +uint8_t dat_lines; > +bool cmd_line; > }; > > +static uint8_t sd_get_dat_lines(SDState *sd) > +{ > +return sd->enable ? sd->dat_lines : 0; > +} > + > +static bool sd_get_cmd_line(SDState *sd) > +{ > +return sd->enable ? sd->cmd_line : false; > +} > + > static void sd_set_voltage(SDState *sd, uint16_t millivolts) > { > switch (millivolts) { > @@ -457,6 +469,8 @@ static void sd_reset(DeviceState *dev) > sd->blk_len = 0x200; > sd->pwd_len = 0; > sd->expecting_acmd = false; > +sd->dat_lines = 0xf; > +sd->cmd_line = true; > sd->multi_blk_cnt = 0; > } > > @@ -1938,6 +1952,8 @@ static void sd_class_init(ObjectClass *klass, void > *data) > dc->bus_type = TYPE_SD_BUS; > > sc->set_voltage = sd_set_voltage; > +sc->get_dat_lines = sd_get_dat_lines; > +sc->get_cmd_line = sd_get_cmd_line; > sc->do_command = sd_do_command; > sc->write_data = sd_write_data; > sc->read_data = sd_read_data; > diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c > index aec6ca4d14..b7fb262750 100644 > --- a/hw/sd/sdhci.c > +++ b/hw/sd/sdhci.c > @@ -1003,6 +1003,10 @@ static uint64_t sdhci_read(void *opaque, hwaddr > offset, unsigned size) > break; > case SDHC_PRNSTS: > ret = s->prnsts; > +ret = FIELD_DP32(ret, SDHC_PRNSTS, DAT_LVL, > + sdbus_get_dat_lines(>sdbus)); > +ret = FIELD_DP32(ret, SDHC_PRNSTS, CMD_LVL, > +
Re: [Qemu-devel] [PATCH v8 08/14] hw/arm/bcm2835_peripherals: change maximum block size to 1kB
On Mon, Jan 22, 2018 at 7:06 PM, Philippe Mathieu-Daudéwrote: > following the datasheet. > > Signed-off-by: Philippe Mathieu-Daudé Acked-by: Alistair Francis Alistair > --- > hw/arm/bcm2835_peripherals.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c > index 0570cc4ad3..6b86a99b14 100644 > --- a/hw/arm/bcm2835_peripherals.c > +++ b/hw/arm/bcm2835_peripherals.c > @@ -19,7 +19,7 @@ > #define BCM2835_VC_PERI_BASE 0x7e00 > > /* Capabilities for SD controller: no DMA, high-speed, default clocks etc. */ > -#define BCM2835_SDHC_CAPAREG 0x52034b4 > +#define BCM2835_SDHC_CAPAREG 0x52134b4 > > static void bcm2835_peripherals_init(Object *obj) > { > -- > 2.15.1 > >
Re: [Qemu-devel] [PATCH v8 07/14] hw/arm/bcm2835_peripherals: implement SDHCI Spec. v3
On Mon, Jan 22, 2018 at 7:06 PM, Philippe Mathieu-DaudĂ©wrote: > Signed-off-by: Philippe Mathieu-DaudĂ© > --- > hw/arm/bcm2835_peripherals.c | 21 + > 1 file changed, 13 insertions(+), 8 deletions(-) > > diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c > index 12e0dd11af..0570cc4ad3 100644 > --- a/hw/arm/bcm2835_peripherals.c > +++ b/hw/arm/bcm2835_peripherals.c > @@ -254,14 +254,19 @@ static void bcm2835_peripherals_realize(DeviceState > *dev, Error **errp) > memory_region_add_subregion(>peri_mr, RNG_OFFSET, > sysbus_mmio_get_region(SYS_BUS_DEVICE(>rng), 0)); > > -/* Extended Mass Media Controller */ > -object_property_set_int(OBJECT(>sdhci), BCM2835_SDHC_CAPAREG, > "capareg", > -); > -if (err) { > -error_propagate(errp, err); > -return; > -} > - > +/* Extended Mass Media Controller > + * > + * Compatible with: > + * - SD Host Controller Specification Version 3.0 Draft 1.0 > + * - SDIO Specification Version 3.0 > + * - MMC Specification Version 4.4 > + * > + * For the exact details please refer to the Arasan documentation: > + * SD3.0_Host_AHB_eMMC4.4_Usersguide_ver5.9_jan11_10.pdf ¯\_(ăƒ„)_/¯ I don't think we need the shrugging face in the comments. Otherwise: Reviewed-by: Alistair Francis Alistair > + */ > +object_property_set_uint(OBJECT(>sdhci), 3, "sd-spec-version", ); > +object_property_set_uint(OBJECT(>sdhci), BCM2835_SDHC_CAPAREG, > "capareg", > + ); > object_property_set_bool(OBJECT(>sdhci), true, "pending-insert-quirk", > ); > if (err) { > -- > 2.15.1 > >
[Qemu-devel] [PULL 0/1] virtio: quick fix
This is just a quick bugfix so people can make progress. Will send a pull req with more patches queues later this week. The following changes since commit 52483b067cce4a88ffbf8fbeea26de7549d2ad23: Merge remote-tracking branch 'remotes/huth/tags/pull-request-2018-01-22' into staging (2018-01-23 10:15:09 +) are available in the git repository at: git://git.kernel.org/pub/scm/virt/kvm/mst/qemu.git tags/for_upstream for you to fetch changes up to 3e59a4745a1668eeec94d142b0f5a7847b866a87: kvm-all: Partially reverts 4fe6d78b2e to remove the cleanup call (2018-01-24 00:41:50 +0200) virtio: quick fix Fixes a regression in virtio that's causing issues for many people. Signed-off-by: Michael S. TsirkinJose Ricardo Ziviani (1): kvm-all: Partially reverts 4fe6d78b2e to remove the cleanup call accel/kvm/kvm-all.c | 4 1 file changed, 4 deletions(-)
[Qemu-devel] [PULL 1/1] kvm-all: Partially reverts 4fe6d78b2e to remove the cleanup call
From: Jose Ricardo ZivianiThis commit partially reverts the commit 4fe6d78b2e because of issues reported in the virtio. Examples: $ qemu-system-ppc64 -cpu POWER8 -nographic -vga none -m 4G \ -M pseries,accel=kvm -netdev type=user,id=net0 \ -device virtio-net-pci,netdev=net0 -drive file=../disk.qcow2,if=virtio Populating /vdevice/nvram@7101 Populating /vdevice/v-scsi@7102 SCSI: Looking for devices 8200 CD-ROM : "QEMU QEMU CD-ROM 2.5+" Populating /pci@8002000 00 (D) : 1af4 1000virtio [ net ] Aborted $ qemu-system-x86_64 -m 4G -enable-kvm -drive file=util.qcow2,if=virtio Running QEMU with GTK 2.x is deprecated, and will be removed in a future release. Please switch to GTK 3.x instead [1]5282 abort Reference http://lists.nongnu.org/archive/html/qemu-devel/2018-01/msg05457.html Reported-by: Anton Blanchard Signed-off-by: Jose Ricardo Ziviani Reviewed-by: Daniel Henrique Barboza Tested-by: Daniel Henrique Barboza Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- accel/kvm/kvm-all.c | 4 1 file changed, 4 deletions(-) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index 071f4f5..f290f48 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -812,10 +812,6 @@ static void kvm_mem_ioeventfd_del(MemoryListener *listener, if (r < 0) { abort(); } - -if (e->cleanup) { -e->cleanup(e); -} } static void kvm_io_ioeventfd_add(MemoryListener *listener, -- MST
Re: [Qemu-devel] [PATCH v8 05/14] sdhci: implement UHS-I voltage switch
On Mon, Jan 22, 2018 at 7:06 PM, Philippe Mathieu-Daudéwrote: > [based on a patch from Alistair Francis > from qemu/xilinx tag xilinx-v2015.2] > Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Alistair > --- > include/hw/sd/sd.h| 16 > include/hw/sd/sdhci.h | 1 + > hw/sd/core.c | 13 + > hw/sd/sd.c| 13 + > hw/sd/sdhci.c | 12 +++- > hw/sd/trace-events| 1 + > 6 files changed, 55 insertions(+), 1 deletion(-) > > diff --git a/include/hw/sd/sd.h b/include/hw/sd/sd.h > index 96caefe373..f086679493 100644 > --- a/include/hw/sd/sd.h > +++ b/include/hw/sd/sd.h > @@ -55,6 +55,20 @@ > #define AKE_SEQ_ERROR (1 << 3) > #define OCR_CCS_BITN30 > > +typedef enum { > +SD_VOLTAGE_0_4V = 400, /* currently not supported */ > +SD_VOLTAGE_1_8V = 1800, > +SD_VOLTAGE_3_0V = 3000, > +SD_VOLTAGE_3_3V = 3300, > +} sd_voltage_mv_t; > + > +typedef enum { > +UHS_NOT_SUPPORTED = 0, > +UHS_I = 1, > +UHS_II = 2,/* currently not supported */ > +UHS_III = 3,/* currently not supported */ > +} sd_uhs_mode_t; > + > typedef enum { > sd_none = -1, > sd_bc = 0, /* broadcast -- no response */ > @@ -88,6 +102,7 @@ typedef struct { > void (*write_data)(SDState *sd, uint8_t value); > uint8_t (*read_data)(SDState *sd); > bool (*data_ready)(SDState *sd); > +void (*set_voltage)(SDState *sd, uint16_t millivolts); > void (*enable)(SDState *sd, bool enable); > bool (*get_inserted)(SDState *sd); > bool (*get_readonly)(SDState *sd); > @@ -134,6 +149,7 @@ void sd_enable(SDState *sd, bool enable); > /* Functions to be used by qdevified callers (working via > * an SDBus rather than directly with SDState) > */ > +void sdbus_set_voltage(SDBus *sdbus, uint16_t millivolts); > int sdbus_do_command(SDBus *sd, SDRequest *req, uint8_t *response); > void sdbus_write_data(SDBus *sd, uint8_t value); > uint8_t sdbus_read_data(SDBus *sd); > diff --git a/include/hw/sd/sdhci.h b/include/hw/sd/sdhci.h > index 0fff941a98..06e3784e54 100644 > --- a/include/hw/sd/sdhci.h > +++ b/include/hw/sd/sdhci.h > @@ -93,6 +93,7 @@ typedef struct SDHCIState { > /* Configurable properties */ > bool pending_insert_quirk; /* Quirk for Raspberry Pi card insert int */ > uint8_t sd_spec_version; > +uint8_t uhs_mode; > } SDHCIState; > > #define TYPE_PCI_SDHCI "sdhci-pci" > diff --git a/hw/sd/core.c b/hw/sd/core.c > index 498284f109..6d198ea775 100644 > --- a/hw/sd/core.c > +++ b/hw/sd/core.c > @@ -41,6 +41,19 @@ static SDState *get_card(SDBus *sdbus) > return SD_CARD(kid->child); > } > > +void sdbus_set_voltage(SDBus *sdbus, uint16_t millivolts) > +{ > +SDState *card = get_card(sdbus); > + > +trace_sdbus_set_voltage(sdbus_name(sdbus), millivolts); > +if (card) { > +SDCardClass *sc = SD_CARD_GET_CLASS(card); > + > +assert(sc->set_voltage); > +sc->set_voltage(card, millivolts); > +} > +} > + > int sdbus_do_command(SDBus *sdbus, SDRequest *req, uint8_t *response) > { > SDState *card = get_card(sdbus); > diff --git a/hw/sd/sd.c b/hw/sd/sd.c > index 35347a5bbc..609b2da14f 100644 > --- a/hw/sd/sd.c > +++ b/hw/sd/sd.c > @@ -128,6 +128,18 @@ struct SDState { > bool enable; > }; > > +static void sd_set_voltage(SDState *sd, uint16_t millivolts) > +{ > +switch (millivolts) { > +case 3001 ... 3600: /* SD_VOLTAGE_3_3V */ > +case 2001 ... 3000: /* SD_VOLTAGE_3_0V */ > +break; > +default: > +qemu_log_mask(LOG_GUEST_ERROR, "SD card voltage not supported: > %.3fV", > + millivolts / 1000.f); > +} > +} > + > static void sd_set_mode(SDState *sd) > { > switch (sd->state) { > @@ -1925,6 +1937,7 @@ static void sd_class_init(ObjectClass *klass, void > *data) > dc->reset = sd_reset; > dc->bus_type = TYPE_SD_BUS; > > +sc->set_voltage = sd_set_voltage; > sc->do_command = sd_do_command; > sc->write_data = sd_write_data; > sc->read_data = sd_read_data; > diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c > index b7e69fbc22..aec6ca4d14 100644 > --- a/hw/sd/sdhci.c > +++ b/hw/sd/sdhci.c > @@ -1255,7 +1255,16 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, > unsigned size) > sdhci_update_irq(s); > break; > case SDHC_ACMD12ERRSTS: > -MASKED_WRITE(s->acmd12errsts, mask, value); > +MASKED_WRITE(s->acmd12errsts, mask, value & UINT16_MAX); > +if (s->uhs_mode >= UHS_I) { > +MASKED_WRITE(s->hostctl2, mask >> 16, value >> 16); > + > +if (FIELD_EX32(s->hostctl2, SDHC_HOSTCTL2, V18_ENA)) { > +sdbus_set_voltage(>sdbus, SD_VOLTAGE_1_8V); > +} else { > +
Re: [Qemu-devel] [PATCH v8 03/14] sdhci: implement the Host Control 2 register (tuning sequence)
On Mon, Jan 22, 2018 at 7:06 PM, Philippe Mathieu-Daudéwrote: > [based on a patch from Alistair Francis > from qemu/xilinx tag xilinx-v2015.2] > Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Alistair > --- > hw/sd/sdhci-internal.h | 10 ++ > include/hw/sd/sdhci.h | 1 + > hw/sd/sdhci.c | 22 +++--- > 3 files changed, 30 insertions(+), 3 deletions(-) > > diff --git a/hw/sd/sdhci-internal.h b/hw/sd/sdhci-internal.h > index 9111f6856a..e7cbea297f 100644 > --- a/hw/sd/sdhci-internal.h > +++ b/hw/sd/sdhci-internal.h > @@ -184,6 +184,16 @@ FIELD(SDHC_ACMD12ERRSTS, TIMEOUT_ERR, 1, 1); > FIELD(SDHC_ACMD12ERRSTS, CRC_ERR, 2, 1); > FIELD(SDHC_ACMD12ERRSTS, INDEX_ERR,4, 1); > > +/* Host Control Register 2 (since v3) */ > +#define SDHC_HOSTCTL2 0x3E > +FIELD(SDHC_HOSTCTL2, UHS_MODE_SEL, 0, 3); > +FIELD(SDHC_HOSTCTL2, V18_ENA, 3, 1); /* UHS-I only */ > +FIELD(SDHC_HOSTCTL2, DRIVER_STRENGTH, 4, 2); /* UHS-I only */ > +FIELD(SDHC_HOSTCTL2, EXECUTE_TUNING, 6, 1); /* UHS-I only */ > +FIELD(SDHC_HOSTCTL2, SAMPLING_CLKSEL, 7, 1); /* UHS-I only */ > +FIELD(SDHC_HOSTCTL2, ASYNC_INT, 14, 1); > +FIELD(SDHC_HOSTCTL2, PRESET_ENA, 15, 1); > + > /* HWInit Capabilities Register 0x05E80080 */ > #define SDHC_CAPAB 0x40 > FIELD(SDHC_CAPAB, TOCLKFREQ, 0, 6); > diff --git a/include/hw/sd/sdhci.h b/include/hw/sd/sdhci.h > index 5af9e0dc5a..0fff941a98 100644 > --- a/include/hw/sd/sdhci.h > +++ b/include/hw/sd/sdhci.h > @@ -71,6 +71,7 @@ typedef struct SDHCIState { > uint16_t norintsigen; /* Normal Interrupt Signal Enable Register */ > uint16_t errintsigen; /* Error Interrupt Signal Enable Register */ > uint16_t acmd12errsts; /* Auto CMD12 error status register */ > +uint16_t hostctl2; /* Host Control 2 */ > uint64_t admasysaddr; /* ADMA System Address Register */ > > /* Read-only registers */ > diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c > index 013c35e585..b7e69fbc22 100644 > --- a/hw/sd/sdhci.c > +++ b/hw/sd/sdhci.c > @@ -408,14 +408,29 @@ static void sdhci_end_transfer(SDHCIState *s) > static void sdhci_read_block_from_card(SDHCIState *s) > { > int index = 0; > +uint8_t data; > +const uint16_t blk_size = s->blksize & BLOCK_SIZE_MASK; > > if ((s->trnmod & SDHC_TRNS_MULTI) && > (s->trnmod & SDHC_TRNS_BLK_CNT_EN) && (s->blkcnt == 0)) { > return; > } > > -for (index = 0; index < (s->blksize & BLOCK_SIZE_MASK); index++) { > -s->fifo_buffer[index] = sdbus_read_data(>sdbus); > +for (index = 0; index < blk_size; index++) { > +data = sdbus_read_data(>sdbus); > +if (!FIELD_EX32(s->hostctl2, SDHC_HOSTCTL2, EXECUTE_TUNING)) { > +/* Device is not in tunning */ > +s->fifo_buffer[index] = data; > +} > +} > + > +if (FIELD_EX32(s->hostctl2, SDHC_HOSTCTL2, EXECUTE_TUNING)) { > +/* Device is in tunning */ > +s->hostctl2 &= ~R_SDHC_HOSTCTL2_EXECUTE_TUNING_MASK; > +s->hostctl2 |= R_SDHC_HOSTCTL2_SAMPLING_CLKSEL_MASK; > +s->prnsts &= ~(SDHC_DAT_LINE_ACTIVE | SDHC_DOING_READ | > + SDHC_DATA_INHIBIT); > +goto read_done; > } > > /* New data now available for READ through Buffer Port Register */ > @@ -440,6 +455,7 @@ static void sdhci_read_block_from_card(SDHCIState *s) > } > } > > +read_done: > sdhci_update_irq(s); > } > > @@ -1005,7 +1021,7 @@ static uint64_t sdhci_read(void *opaque, hwaddr offset, > unsigned size) > ret = s->norintsigen | (s->errintsigen << 16); > break; > case SDHC_ACMD12ERRSTS: > -ret = s->acmd12errsts; > +ret = s->acmd12errsts | (s->hostctl2 << 16); > break; > case SDHC_CAPAB: > ret = (uint32_t)s->capareg; > -- > 2.15.1 > >
Re: [Qemu-devel] [PATCH v8 04/14] sdbus: add trace events
On Mon, Jan 22, 2018 at 7:06 PM, Philippe Mathieu-Daudéwrote: > Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Alistair > --- > hw/sd/core.c | 14 -- > hw/sd/trace-events | 5 + > 2 files changed, 17 insertions(+), 2 deletions(-) > > diff --git a/hw/sd/core.c b/hw/sd/core.c > index 295dc44ab7..498284f109 100644 > --- a/hw/sd/core.c > +++ b/hw/sd/core.c > @@ -23,6 +23,12 @@ > #include "hw/qdev-core.h" > #include "sysemu/block-backend.h" > #include "hw/sd/sd.h" > +#include "trace.h" > + > +static inline const char *sdbus_name(SDBus *sdbus) > +{ > +return sdbus->qbus.name; > +} > > static SDState *get_card(SDBus *sdbus) > { > @@ -39,6 +45,7 @@ int sdbus_do_command(SDBus *sdbus, SDRequest *req, uint8_t > *response) > { > SDState *card = get_card(sdbus); > > +trace_sdbus_command(sdbus_name(sdbus), req->cmd, req->arg, req->crc); > if (card) { > SDCardClass *sc = SD_CARD_GET_CLASS(card); > > @@ -52,6 +59,7 @@ void sdbus_write_data(SDBus *sdbus, uint8_t value) > { > SDState *card = get_card(sdbus); > > +trace_sdbus_write(sdbus_name(sdbus), value); > if (card) { > SDCardClass *sc = SD_CARD_GET_CLASS(card); > > @@ -62,14 +70,16 @@ void sdbus_write_data(SDBus *sdbus, uint8_t value) > uint8_t sdbus_read_data(SDBus *sdbus) > { > SDState *card = get_card(sdbus); > +uint8_t value = 0; > > if (card) { > SDCardClass *sc = SD_CARD_GET_CLASS(card); > > -return sc->read_data(card); > +value = sc->read_data(card); > } > +trace_sdbus_read(sdbus_name(sdbus), value); > > -return 0; > +return value; > } > > bool sdbus_data_ready(SDBus *sdbus) > diff --git a/hw/sd/trace-events b/hw/sd/trace-events > index 78d8707669..ea2746c8b7 100644 > --- a/hw/sd/trace-events > +++ b/hw/sd/trace-events > @@ -1,5 +1,10 @@ > # See docs/devel/tracing.txt for syntax documentation. > > +# hw/sd/core.c > +sdbus_command(const char *bus_name, uint8_t cmd, uint32_t arg, uint8_t crc) > "@%s CMD%02d arg 0x%08x crc 0x%02x" > +sdbus_read(const char *bus_name, uint8_t value) "@%s value 0x%02x" > +sdbus_write(const char *bus_name, uint8_t value) "@%s value 0x%02x" > + > # hw/sd/sdhci.c > sdhci_set_inserted(const char *level) "card state changed: %s" > sdhci_send_command(uint8_t cmd, uint32_t arg) "CMD%02u ARG[0x%08x]" > -- > 2.15.1 > >
Re: [Qemu-devel] [qemu-s390x] [PATCH v4 04/10] s390-ccw: update libc
On 01/23/2018 02:23 PM, Eric Blake wrote: On 01/23/2018 12:26 PM, Collin L. Walling wrote: [...] +/** + * atoi: + * @str: the string to be converted. + * + * Given a string @str, convert it to an integer. Leading whitespace is + * ignored. The first character (after any whitespace) is checked for the + * negative sign. Any other non-numerical value will terminate the + * conversion. + * + * Returns: an integer converted from the string @str. + */ +int atoi(const char *str) +{ +int val = 0; +int sign = 1; + +if (!str || !str[0]) { +return 0; +} + +while (*str == ' ') { +str++; +} That's not "any whitespace", but only spaces. A fully compliant implementation would be checking isspace(), but I don't expect you to implement that; at a minimum, also checking '\t' would get you closer (but not all the way to) compliance. I'll fix the comment to be more clear. I think it's okay to just have the menu code treat any other kind of whitespace as an error (it will check before calling atoi). I added support for negatives in bothfunctions because it was easy enough to do so and for the sakeof completeness. However, I worry trying to be 100% compliant will just bloat the code when we only need it for very specific use cases. Would you say what we have (along with the fix to itostr below) is sufficient enough? +static char *_itostr(int num, char *str, size_t len) +{ +int num_idx = 0; +int tmp = num; +char sign = 0; + +if (!str) { +return NULL; +} + +/* Get index to ones place */ +while ((tmp /= 10) != 0) { +num_idx++; +} + +if (num < 0) { +num *= -1; +sign = 1; +} If num == INT_MIN, then num is still negative at this point... + +/* Check if we have enough space for num, sign, and null */ +if (len <= num_idx + sign + 1) { +return NULL; +} + +str[num_idx + sign + 1] = '\0'; + +/* Convert int to string */ +while (num_idx >= 0) { +str[num_idx + sign] = num % 10 + '0'; ...which breaks this. Either make it work, or document the corner case as unsupported. Might as well just make it work at this point: #define INT32_MIN 0x8000 static char *itostr(int num, char *str, size_t len) { Â Â Â int num_idx = 0; Â Â Â int tmp = num; Â Â Â char sign = !!(num & INT32_MIN); Â Â Â if (!str) { Â Â Â return NULL; Â Â Â } Â Â Â /* Get index to ones place */ Â Â Â while ((tmp /= 10) != 0) { Â Â Â num_idx++; Â Â Â } Â Â Â /* Check if we have enough space for num, sign, and null */ Â Â Â if (len <= num_idx + sign + 1) { Â Â Â return NULL; Â Â Â } Â Â Â str[num_idx + sign + 1] = '\0'; Â Â Â if (sign) { Â Â Â str[0] = '-'; Â Â Â if (num == INT32_MIN) { Â Â Â str[num_idx + sign] = '8'; Â Â Â num /= 10; Â Â Â num_idx--; Â Â Â } Â Â Â num *= -1; Â Â Â } Â Â Â /* Convert int to string */ Â Â Â while (num_idx >= 0) { Â Â Â str[num_idx + sign] = num % 10 + '0'; Â Â Â num /= 10; Â Â Â num_idx--; Â Â Â } Â Â Â return str; } Thoughts? -- - Collin L Walling
[Qemu-devel] [PATCH v5 2/3] xlnx-zynqmp-rtc: Add basic time support
Allow the guest to determine the time set from the QEMU command line. This includes adding a trace event to debug the new time. Signed-off-by: Alistair Francis--- V5: - Recalculate tick_offset after migration V4: - Use the .unimp property V3: - Store an offset value - Use mktimegm() - Log unimplemented writes V2: - Convert DB_PRINT() macro to trace include/hw/timer/xlnx-zynqmp-rtc.h | 3 +++ hw/timer/xlnx-zynqmp-rtc.c | 52 ++ hw/timer/trace-events | 3 +++ 3 files changed, 58 insertions(+) diff --git a/include/hw/timer/xlnx-zynqmp-rtc.h b/include/hw/timer/xlnx-zynqmp-rtc.h index 87649836cc..2867563bdd 100644 --- a/include/hw/timer/xlnx-zynqmp-rtc.h +++ b/include/hw/timer/xlnx-zynqmp-rtc.h @@ -79,6 +79,9 @@ typedef struct XlnxZynqMPRTC { qemu_irq irq_rtc_int; qemu_irq irq_addr_error_int; +struct tm current_tm; +uint32_t tick_offset; + uint32_t regs[XLNX_ZYNQMP_RTC_R_MAX]; RegisterInfo regs_info[XLNX_ZYNQMP_RTC_R_MAX]; } XlnxZynqMPRTC; diff --git a/hw/timer/xlnx-zynqmp-rtc.c b/hw/timer/xlnx-zynqmp-rtc.c index 707f145027..1d229870c5 100644 --- a/hw/timer/xlnx-zynqmp-rtc.c +++ b/hw/timer/xlnx-zynqmp-rtc.c @@ -29,6 +29,10 @@ #include "hw/register.h" #include "qemu/bitops.h" #include "qemu/log.h" +#include "hw/ptimer.h" +#include "qemu/cutils.h" +#include "sysemu/sysemu.h" +#include "trace.h" #include "hw/timer/xlnx-zynqmp-rtc.h" #ifndef XLNX_ZYNQMP_RTC_ERR_DEBUG @@ -47,6 +51,19 @@ static void addr_error_int_update_irq(XlnxZynqMPRTC *s) qemu_set_irq(s->irq_addr_error_int, pending); } +static uint32_t rtc_get_count(XlnxZynqMPRTC *s) +{ +int64_t now = qemu_clock_get_ns(rtc_clock); +return s->tick_offset + now / NANOSECONDS_PER_SECOND; +} + +static uint64_t current_time_postr(RegisterInfo *reg, uint64_t val64) +{ +XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque); + +return rtc_get_count(s); +} + static void rtc_int_status_postw(RegisterInfo *reg, uint64_t val64) { XlnxZynqMPRTC *s = XLNX_ZYNQMP_RTC(reg->opaque); @@ -97,13 +114,17 @@ static uint64_t addr_error_int_dis_prew(RegisterInfo *reg, uint64_t val64) static const RegisterAccessInfo rtc_regs_info[] = { { .name = "SET_TIME_WRITE", .addr = A_SET_TIME_WRITE, +.unimp = MAKE_64BIT_MASK(0, 32), },{ .name = "SET_TIME_READ", .addr = A_SET_TIME_READ, .ro = 0x, +.post_read = current_time_postr, },{ .name = "CALIB_WRITE", .addr = A_CALIB_WRITE, +.unimp = MAKE_64BIT_MASK(0, 32), },{ .name = "CALIB_READ", .addr = A_CALIB_READ, .ro = 0x1f, },{ .name = "CURRENT_TIME", .addr = A_CURRENT_TIME, .ro = 0x, +.post_read = current_time_postr, },{ .name = "CURRENT_TICK", .addr = A_CURRENT_TICK, .ro = 0x, },{ .name = "ALARM", .addr = A_ALARM, @@ -143,6 +164,10 @@ static void rtc_reset(DeviceState *dev) register_reset(>regs_info[i]); } +trace_xlnx_zynqmp_rtc_gettime(s->current_tm.tm_year, s->current_tm.tm_mon, + s->current_tm.tm_mday, s->current_tm.tm_hour, + s->current_tm.tm_min, s->current_tm.tm_sec); + rtc_int_update_irq(s); addr_error_int_update_irq(s); } @@ -178,14 +203,41 @@ static void rtc_init(Object *obj) sysbus_init_mmio(sbd, >iomem); sysbus_init_irq(sbd, >irq_rtc_int); sysbus_init_irq(sbd, >irq_addr_error_int); + +qemu_get_timedate(>current_tm, 0); +s->tick_offset = mktimegm(>current_tm) - +qemu_clock_get_ns(rtc_clock) / NANOSECONDS_PER_SECOND; +} + +static int rtc_post_load(void *opaque, int version_id) +{ +XlnxZynqMPRTC *s = opaque; + +/* The tick_offset is added to the current time to determine the guest + * time. After migration we don't want to use the original time as that + * will indicate to the guest that time has passed, so we need to + * recalculate the tick_offset here. + */ +s->tick_offset = mktimegm(>current_tm) - +qemu_clock_get_ns(rtc_clock) / NANOSECONDS_PER_SECOND; + +return 0; } static const VMStateDescription vmstate_rtc = { .name = TYPE_XLNX_ZYNQMP_RTC, .version_id = 1, .minimum_version_id = 1, +.post_load = rtc_post_load, .fields = (VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, XlnxZynqMPRTC, XLNX_ZYNQMP_RTC_R_MAX), +VMSTATE_INT32(current_tm.tm_sec, XlnxZynqMPRTC), +VMSTATE_INT32(current_tm.tm_min, XlnxZynqMPRTC), +VMSTATE_INT32(current_tm.tm_hour, XlnxZynqMPRTC), +VMSTATE_INT32(current_tm.tm_wday, XlnxZynqMPRTC), +VMSTATE_INT32(current_tm.tm_mday, XlnxZynqMPRTC), +VMSTATE_INT32(current_tm.tm_mon, XlnxZynqMPRTC), +VMSTATE_INT32(current_tm.tm_year, XlnxZynqMPRTC), VMSTATE_END_OF_LIST(), } }; diff --git a/hw/timer/trace-events b/hw/timer/trace-events index 640722b5d1..e6e042fddb
[Qemu-devel] [PATCH v5 3/3] xlnx-zynqmp: Connect the RTC device
Signed-off-by: Alistair FrancisReviewed-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé --- include/hw/arm/xlnx-zynqmp.h | 2 ++ hw/arm/xlnx-zynqmp.c | 14 ++ 2 files changed, 16 insertions(+) diff --git a/include/hw/arm/xlnx-zynqmp.h b/include/hw/arm/xlnx-zynqmp.h index 3e6fb9b7bd..9e8c9e18dd 100644 --- a/include/hw/arm/xlnx-zynqmp.h +++ b/include/hw/arm/xlnx-zynqmp.h @@ -28,6 +28,7 @@ #include "hw/ssi/xilinx_spips.h" #include "hw/dma/xlnx_dpdma.h" #include "hw/display/xlnx_dp.h" +#include "hw/timer/xlnx-zynqmp-rtc.h" #define TYPE_XLNX_ZYNQMP "xlnx,zynqmp" #define XLNX_ZYNQMP(obj) OBJECT_CHECK(XlnxZynqMPState, (obj), \ @@ -90,6 +91,7 @@ typedef struct XlnxZynqMPState { XlnxZynqMPQSPIPS qspi; XlnxDPState dp; XlnxDPDMAState dpdma; +XlnxZynqMPRTC rtc; char *boot_cpu; ARMCPU *boot_cpu_ptr; diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c index 325642058b..deef583c2a 100644 --- a/hw/arm/xlnx-zynqmp.c +++ b/hw/arm/xlnx-zynqmp.c @@ -50,6 +50,9 @@ #define DPDMA_ADDR 0xfd4c #define DPDMA_IRQ 116 +#define RTC_ADDR0xffa6 +#define RTC_IRQ 26 + static const uint64_t gem_addr[XLNX_ZYNQMP_NUM_GEMS] = { 0xFF0B, 0xFF0C, 0xFF0D, 0xFF0E, }; @@ -183,6 +186,9 @@ static void xlnx_zynqmp_init(Object *obj) object_initialize(>dpdma, sizeof(s->dpdma), TYPE_XLNX_DPDMA); qdev_set_parent_bus(DEVICE(>dpdma), sysbus_get_default()); + +object_initialize(>rtc, sizeof(s->rtc), TYPE_XLNX_ZYNQMP_RTC); +qdev_set_parent_bus(DEVICE(>rtc), sysbus_get_default()); } static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) @@ -454,6 +460,14 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) _abort); sysbus_mmio_map(SYS_BUS_DEVICE(>dpdma), 0, DPDMA_ADDR); sysbus_connect_irq(SYS_BUS_DEVICE(>dpdma), 0, gic_spi[DPDMA_IRQ]); + +object_property_set_bool(OBJECT(>rtc), true, "realized", ); +if (err) { +error_propagate(errp, err); +return; +} +sysbus_mmio_map(SYS_BUS_DEVICE(>rtc), 0, RTC_ADDR); +sysbus_connect_irq(SYS_BUS_DEVICE(>rtc), 0, gic_spi[RTC_IRQ]); } static Property xlnx_zynqmp_props[] = { -- 2.14.1
[Qemu-devel] [PATCH v5 1/3] xlnx-zynqmp-rtc: Initial commit
Initial commit of the ZynqMP RTC device. Signed-off-by: Alistair FrancisReviewed-by: Philippe Mathieu-Daudé --- v5: - Don't use intermediate val V2: - Delete unused realise function - Remove DB_PRINT() include/hw/timer/xlnx-zynqmp-rtc.h | 84 +++ hw/timer/xlnx-zynqmp-rtc.c | 214 + hw/timer/Makefile.objs | 1 + 3 files changed, 299 insertions(+) create mode 100644 include/hw/timer/xlnx-zynqmp-rtc.h create mode 100644 hw/timer/xlnx-zynqmp-rtc.c diff --git a/include/hw/timer/xlnx-zynqmp-rtc.h b/include/hw/timer/xlnx-zynqmp-rtc.h new file mode 100644 index 00..87649836cc --- /dev/null +++ b/include/hw/timer/xlnx-zynqmp-rtc.h @@ -0,0 +1,84 @@ +/* + * QEMU model of the Xilinx ZynqMP Real Time Clock (RTC). + * + * Copyright (c) 2017 Xilinx Inc. + * + * Written-by: Alistair Francis + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "hw/register.h" + +#define TYPE_XLNX_ZYNQMP_RTC "xlnx-zynmp.rtc" + +#define XLNX_ZYNQMP_RTC(obj) \ + OBJECT_CHECK(XlnxZynqMPRTC, (obj), TYPE_XLNX_ZYNQMP_RTC) + +REG32(SET_TIME_WRITE, 0x0) +REG32(SET_TIME_READ, 0x4) +REG32(CALIB_WRITE, 0x8) +FIELD(CALIB_WRITE, FRACTION_EN, 20, 1) +FIELD(CALIB_WRITE, FRACTION_DATA, 16, 4) +FIELD(CALIB_WRITE, MAX_TICK, 0, 16) +REG32(CALIB_READ, 0xc) +FIELD(CALIB_READ, FRACTION_EN, 20, 1) +FIELD(CALIB_READ, FRACTION_DATA, 16, 4) +FIELD(CALIB_READ, MAX_TICK, 0, 16) +REG32(CURRENT_TIME, 0x10) +REG32(CURRENT_TICK, 0x14) +FIELD(CURRENT_TICK, VALUE, 0, 16) +REG32(ALARM, 0x18) +REG32(RTC_INT_STATUS, 0x20) +FIELD(RTC_INT_STATUS, ALARM, 1, 1) +FIELD(RTC_INT_STATUS, SECONDS, 0, 1) +REG32(RTC_INT_MASK, 0x24) +FIELD(RTC_INT_MASK, ALARM, 1, 1) +FIELD(RTC_INT_MASK, SECONDS, 0, 1) +REG32(RTC_INT_EN, 0x28) +FIELD(RTC_INT_EN, ALARM, 1, 1) +FIELD(RTC_INT_EN, SECONDS, 0, 1) +REG32(RTC_INT_DIS, 0x2c) +FIELD(RTC_INT_DIS, ALARM, 1, 1) +FIELD(RTC_INT_DIS, SECONDS, 0, 1) +REG32(ADDR_ERROR, 0x30) +FIELD(ADDR_ERROR, STATUS, 0, 1) +REG32(ADDR_ERROR_INT_MASK, 0x34) +FIELD(ADDR_ERROR_INT_MASK, MASK, 0, 1) +REG32(ADDR_ERROR_INT_EN, 0x38) +FIELD(ADDR_ERROR_INT_EN, MASK, 0, 1) +REG32(ADDR_ERROR_INT_DIS, 0x3c) +FIELD(ADDR_ERROR_INT_DIS, MASK, 0, 1) +REG32(CONTROL, 0x40) +FIELD(CONTROL, BATTERY_DISABLE, 31, 1) +FIELD(CONTROL, OSC_CNTRL, 24, 4) +FIELD(CONTROL, SLVERR_ENABLE, 0, 1) +REG32(SAFETY_CHK, 0x50) + +#define XLNX_ZYNQMP_RTC_R_MAX (R_SAFETY_CHK + 1) + +typedef struct XlnxZynqMPRTC { +SysBusDevice parent_obj; +MemoryRegion iomem; +qemu_irq irq_rtc_int; +qemu_irq irq_addr_error_int; + +uint32_t regs[XLNX_ZYNQMP_RTC_R_MAX]; +RegisterInfo regs_info[XLNX_ZYNQMP_RTC_R_MAX]; +} XlnxZynqMPRTC; diff --git a/hw/timer/xlnx-zynqmp-rtc.c b/hw/timer/xlnx-zynqmp-rtc.c new file mode 100644 index 00..707f145027 --- /dev/null +++ b/hw/timer/xlnx-zynqmp-rtc.c @@ -0,0 +1,214 @@ +/* + * QEMU model of the Xilinx ZynqMP Real Time Clock (RTC). + * + * Copyright (c) 2017 Xilinx Inc. + * + * Written-by: Alistair Francis + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
[Qemu-devel] [PATCH v5 0/3] Add and connect the ZynqMP RTC
V5: - Recalculate tick_offset after migration V4: - Use the RegisterAccessInfo .unimp functionality V3: - Store an offset value - Use mktimegm() - Log unimplemented writes V2: - Delete unused realise function - Add cover letter - Convert DB_PRINT() macro to trace Alistair Francis (3): xlnx-zynqmp-rtc: Initial commit xlnx-zynqmp-rtc: Add basic time support xlnx-zynqmp: Connect the RTC device include/hw/arm/xlnx-zynqmp.h | 2 + include/hw/timer/xlnx-zynqmp-rtc.h | 87 hw/arm/xlnx-zynqmp.c | 14 ++ hw/timer/xlnx-zynqmp-rtc.c | 266 + hw/timer/Makefile.objs | 1 + hw/timer/trace-events | 3 + 6 files changed, 373 insertions(+) create mode 100644 include/hw/timer/xlnx-zynqmp-rtc.h create mode 100644 hw/timer/xlnx-zynqmp-rtc.c -- 2.14.1
Re: [Qemu-devel] [PATCH v4 1/7] accel/tcg: add size paremeter in tlb_fill()
Le 18/01/2018 à 20:38, Laurent Vivier a écrit : > The MC68040 MMU provides the size of the access that > triggers the page fault. > > This size is set in the Special Status Word which > is written in the stack frame of the access fault > exception. > > So we need the size in m68k_cpu_unassigned_access() and > m68k_cpu_handle_mmu_fault(). > > To be able to do that, this patch modifies the prototype of > handle_mmu_fault handler, tlb_fill() and probe_write(). > do_unassigned_access() already includes a size parameter. I'd like to send a pull request for m68k MMU series, and 68040 MMU relies on this patch. If someone disagrees with this change, it's time to say it! Thanks, Laurent
Re: [Qemu-devel] [PATCH V4 0/7] CAN bus support for QEMU (SJA1000 PCI so far)
Hello Philippe, On Monday 22 of January 2018 12:35:33 Philippe Mathieu-Daudé wrote: > Hi Pavel, > > On 01/14/2018 05:14 PM, p...@cmp.felk.cvut.cz wrote: > > I think your series is quite ready to get accepted, although I'm not > sure through with tree it will goes. > > Most of my review comments are not blocking issues and might get > addressed later (like having an abstract sja1000). Great, I would be happy to reach acceptable state when development can switch to incremental mode as time allows. I hope than even actual state is usable from reports (at least for some usescases). > The principal issue I'd like to discuss with Paolo/Marc-André is the > chardev backend, they might say it's OK to accept it in this current > state and refactor the CANBus backend later. Do you think QOM based? I would like it to be implemented that way but I need some assistance where to look how this object kind should be implemented and from which base object inherit from. But I prefer to left that for later work. I would definitely like to use some mechanism which allows to get rid of externally visible pointer and need to assign it in the stub. It has been my initial idea and your review sumbled across this hack as well. But I need suggestion what is the preferred way for QEMU. When Linux specific object file is linked in then some local function needs to be called before QOM instances population. I know how to do that GCC specific/non-portable way static void __attribute__((constructor)) can_socketcan_setup_variant(void) { } but I expect that something like module_init() in can_socketcan.c should be used. Problem is that there is not module_init type for plain function in include/qemu/module.h MODULE_INIT_BLOCK, MODULE_INIT_OPTS, MODULE_INIT_QOM, MODULE_INIT_TRACE, MODULE_INIT_MAX I expect that QOM object would solve that in future but I would be happy to left it simple for now. What is preferred solution there? > I'd still avoid using directly the socket() syscall and use the QEMU > socket API instead (also suggested by Daniel). I have already switched to qemu_socket(), implementation looks fine and I have tested that it works. I have tested functionality and updated can-pci branch. > I have been thinking a bit about how to test some frame operations > (rather than the PCI devices) and the Linux vcan driver might be a good > option (Virtual Local CAN Interface). This is also useful to test this > series without having CAN hardware. How to use vcan might be worth his > own paragraph in docs/can.txt. > > Do you think some of your tests can be added in the QEMU test suite > (qtests)? I have added some more infomation into docs file + The CAN interface of the host system has to be configured for proper + bitrate and set up. Configuration is not propagated from emulated + devices through bus to the physical host device. Example configuration + for 1 Mbit/s + + ip link set can0 type can bitrate 100 + ip link set can0 up + + Virtual (host local only) can interface can be used on the host + side instead of physical interface + + ip link add dev can0 type vcan + + The CAN interface on the host side can be used to analyze CAN + traffic with "candump" command which is included in "can-utils". + + candump can0 As for the automatic testing, iproute2 tools are required on host and guest side (considering use of Linux) and kernel with CAN drivers support. Root access is required on the host side to setup CAN interface. Some simple tool is required. It can be based on can-utils code or our older canping code for example. Best wishes, Pavel
Re: [Qemu-devel] [PATCH v1 06/21] RISC-V FPU Support
On Wed, Jan 3, 2018 at 12:10 PM, Richard Henderson < richard.hender...@linaro.org> wrote: > On 01/02/2018 04:44 PM, Michael Clark wrote: > > +/* convert RISC-V rounding mode to IEEE library numbers */ > > +unsigned int ieee_rm[] = { > > static const. Done. > +/* obtain rm value to use in computation > > + * as the last step, convert rm codes to what the softfloat library > expects > > + * Adapted from Spike's decode.h:RM > > + */ > > +#define RM ({ \ > > +if (rm == 7) {\ > > +rm = env->frm; \ > > +} \ > > +if (rm > 4) { \ > > +helper_raise_exception(env, RISCV_EXCP_ILLEGAL_INST); \ > > +} \ > > +ieee_rm[rm]; }) > > Please use inline functions and not these macros. > Done. In fact the previous code would, with normal control flow, dereference ieee_rm[rm] with an out of bounds round mode so assuming helper_raise_exception does a longjmp, i've inserted g_assert_not_reached() after the exception. An analyser could detect that ieee_rm has an out of bounds access assuming normal control flow. e.g. static inline void set_fp_round_mode(CPURISCVState *env, uint64_t rm) { if (rm == 7) { rm = env->frm; } else if (rm > 4) { helper_raise_exception(env, RISCV_EXCP_ILLEGAL_INST); g_assert_not_reached(); } set_float_rounding_mode(ieee_rm[rm], >fp_status); } > Probably this applies to some of the helpers that I've already reviewed, > but > you're going to need to use an exception raising function that also > performs an > unwind (usually via cpu_loop_exit_restore). The GETPC() that feeds the > unwind > must be placed in the outer-most helper (including inlines). > > > +#ifndef CONFIG_USER_ONLY > > +#define require_fp if (!(env->mstatus & MSTATUS_FS)) { \ > > +helper_raise_exception(env, RISCV_EXCP_ILLEGAL_INST); \ > > +} > > If you included MSTATUS_FS in cpu_get_tb_cpu_state flags, then you could be > checking for this at translation time instead of at run time. I'll keep a note of this but I might attempt this later. We have some other changes in this area with repsect to cpu_mmu_index. Are translations not implicitly indexed by cpu_mmu_index? i.e. do we also need to add cpu_mmu_index to cpu_get_tb_cpu_state flags to prevent code translated for one value of mmu_index running in code with another value of mmu_index (in the case of riscv, we currently return processor mode / privilege level in cpu_mmu_index). > > +/* convert softfloat library flag numbers to RISC-V */ > > +unsigned int softfloat_flags_to_riscv(unsigned int flags) > > +{ > > +int rv_flags = 0; > > +rv_flags |= (flags & float_flag_inexact) ? 1 : 0; > > +rv_flags |= (flags & float_flag_underflow) ? 2 : 0; > > +rv_flags |= (flags & float_flag_overflow) ? 4 : 0; > > +rv_flags |= (flags & float_flag_divbyzero) ? 8 : 0; > > +rv_flags |= (flags & float_flag_invalid) ? 16 : 0; > > FPEXC_NX et al. > > > +/* adapted from Spike's decode.h:set_fp_exceptions */ > > +#define set_fp_exceptions() do { \ > > +env->fflags |= softfloat_flags_to_riscv(get_float_exception_flags(\ > > +>fp_status)); \ > > +set_float_exception_flags(0, >fp_status); \ > > +} while (0) > > inline function. Usually written as > > int flags = get_float_exception_flags(>fp_status); > if (flags) { > set_float_exception_flags(0, >fp_status); > env->fflags |= softfloat_flags_to_riscv(flags); > } > > since we really do expect exceptions to be exceptional. Done. > +uint64_t helper_fmsub_s(CPURISCVState *env, uint64_t frs1, uint64_t frs2, > > +uint64_t frs3, uint64_t rm) > > +{ > > +require_fp; > > +set_float_rounding_mode(RM, >fp_status); > > +frs1 = float32_muladd(frs1, frs2, frs3 ^ (uint32_t)INT32_MIN, 0, > > + >fp_status); > > Given that RISC-V always returns a default NaN, you obviously do not care > about > the sign of a NaN result. Therefore you should use float_muladd_negate_c > as > the fourth argument here and not perform the sign flip manually. Now working on feedback from here on... Here is the WIP changelog for the v4 spin... v4 - Move code to set round mode into set_fp_round_mode function - Convert set_fp_exceptions from a macro to an inline function - Convert round mode helper into an inline function - Make fpu_helper ieee_rm array static const - Include cpu_mmu_index in cpu_get_tb_cpu_state flags - Eliminate MPRV influence on mmu_index - Remove unrecoverable do_unassigned_access function - Only update PTE accessed and dirty bits if necessary - Remove unnecessary tlb_flush in set_mode as mode is in mmu_idx - Remove buggy support for misa writes. misa writes are optional and are not implemented in any known
Re: [Qemu-devel] [RFC PATCH v5 00/24] replay additions
Hi, This series failed docker-quick@centos6 build test. Please find the testing commands and their output below. If you have Docker installed, you can probably reproduce it locally. Type: series Message-id: 20180123085319.3419.97865.stgit@pasha-VirtualBox Subject: [Qemu-devel] [RFC PATCH v5 00/24] replay additions === TEST SCRIPT BEGIN === #!/bin/bash set -e git submodule update --init dtc # Let docker tests dump environment info export SHOW_ENV=1 export J=8 time make docker-test-quick@centos6 === TEST SCRIPT END === Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384 Switched to a new branch 'test' 7bf3acd69e replay: don't drain/flush bdrv queue while RR is working 118caf566c replay: save vmstate of the asynchronous events b6fa3637ca replay: don't process async events when warping the clock 0e1e55563f scripts/replay-dump.py: replay log dumper 3489724f30 replay: avoid recursive call of checkpoints 75a73acfa7 replay: check return values of fwrite 3d3262c821 replay: don't destroy mutex at exit 4d2655dec4 replay: push replay_mutex_lock up the call tree b9c7226ddc replay: make locking visible outside replay code a47cfc4db0 replay/replay-internal.c: track holding of replay_lock c657632acd replay/replay.c: bump REPLAY_VERSION again c521dd3598 kvm: remove BQL lock/unlock 2be8734669 hax: remove BQL lock/unlock 30c15c0df4 cpus: push BQL lock to qemu_*_wait_io_event 78f277557a target/arm/arm-powertctl: drop BQL assertions 08be174c57 replay: save prior value of the host clock 3e3d5ca056 replay: added replay log format description f3669453d9 replay: fix save/load vm for non-empty queue d937b951cd replay: fixed replay_enable_events 5db02472ff replay: fix processing async events 402642f588 replay: disable default snapshot for record/replay b7ef6d1c7c blkreplay: create temporary overlay for underlaying devices 70ce7a5b5e block: implement bdrv_snapshot_goto for blkreplay 72412e52b0 cpu-exec: fix exception_index handling === OUTPUT BEGIN === Submodule 'dtc' (git://git.qemu-project.org/dtc.git) registered for path 'dtc' Cloning into '/var/tmp/patchew-tester-tmp-j6fnd_ns/src/dtc'... Submodule path 'dtc': checked out 'e54388015af1fb4bf04d0bca99caba1074d9cc42' BUILD centos6 GEN /var/tmp/patchew-tester-tmp-j6fnd_ns/src/docker-src.2018-01-23-04.28.37.5337/qemu.tar Cloning into '/var/tmp/patchew-tester-tmp-j6fnd_ns/src/docker-src.2018-01-23-04.28.37.5337/qemu.tar.vroot'... done. Your branch is up-to-date with 'origin/test'. Submodule 'dtc' (git://git.qemu-project.org/dtc.git) registered for path 'dtc' Cloning into '/var/tmp/patchew-tester-tmp-j6fnd_ns/src/docker-src.2018-01-23-04.28.37.5337/qemu.tar.vroot/dtc'... Submodule path 'dtc': checked out 'e54388015af1fb4bf04d0bca99caba1074d9cc42' Submodule 'ui/keycodemapdb' (git://git.qemu.org/keycodemapdb.git) registered for path 'ui/keycodemapdb' Cloning into '/var/tmp/patchew-tester-tmp-j6fnd_ns/src/docker-src.2018-01-23-04.28.37.5337/qemu.tar.vroot/ui/keycodemapdb'... Submodule path 'ui/keycodemapdb': checked out '10739aa26051a5d49d88132604539d3ed085e72e' COPYRUNNER RUN test-quick in qemu:centos6 Packages installed: SDL-devel-1.2.14-7.el6_7.1.x86_64 bison-2.4.1-5.el6.x86_64 bzip2-devel-1.0.5-7.el6_0.x86_64 ccache-3.1.6-2.el6.x86_64 csnappy-devel-0-6.20150729gitd7bc683.el6.x86_64 flex-2.5.35-9.el6.x86_64 gcc-4.4.7-18.el6.x86_64 gettext-0.17-18.el6.x86_64 git-1.7.1-9.el6_9.x86_64 glib2-devel-2.28.8-9.el6.x86_64 libepoxy-devel-1.2-3.el6.x86_64 libfdt-devel-1.4.0-1.el6.x86_64 librdmacm-devel-1.0.21-0.el6.x86_64 lzo-devel-2.03-3.1.el6_5.1.x86_64 make-3.81-23.el6.x86_64 mesa-libEGL-devel-11.0.7-4.el6.x86_64 mesa-libgbm-devel-11.0.7-4.el6.x86_64 package g++ is not installed pixman-devel-0.32.8-1.el6.x86_64 spice-glib-devel-0.26-8.el6.x86_64 spice-server-devel-0.12.4-16.el6.x86_64 tar-1.23-15.el6_8.x86_64 vte-devel-0.25.1-9.el6.x86_64 xen-devel-4.6.6-2.el6.x86_64 zlib-devel-1.2.3-29.el6.x86_64 Environment variables: PACKAGES=bison bzip2-devel ccache csnappy-devel flex g++ gcc gettext git glib2-devel libepoxy-devel libfdt-devel librdmacm-devel lzo-devel make mesa-libEGL-devel mesa-libgbm-devel pixman-devel SDL-devel spice-glib-devel spice-server-devel tar vte-devel xen-devel zlib-devel HOSTNAME=a3014d90fb2c MAKEFLAGS= -j8 J=8 CCACHE_DIR=/var/tmp/ccache EXTRA_CONFIGURE_OPTS= V= SHOW_ENV=1 PATH=/usr/lib/ccache:/usr/lib64/ccache:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin PWD=/ TARGET_LIST= SHLVL=1 HOME=/root TEST_DIR=/tmp/qemu-test FEATURES= dtc DEBUG= _=/usr/bin/env Configure options: --enable-werror --target-list=x86_64-softmmu,aarch64-softmmu --prefix=/tmp/qemu-test/install No C++ compiler available; disabling C++ specific optional code Install prefix/tmp/qemu-test/install BIOS directory/tmp/qemu-test/install/share/qemu firmware path /tmp/qemu-test/install/share/qemu-firmware binary directory /tmp/qemu-test/install/bin library
Re: [Qemu-devel] [PULL 13/13] linux-user: implement renameat2
On Tue, 23 Jan 2018 12:13:07 PST (-0800), laur...@vivier.eu wrote: Le 23/01/2018 à 20:13, Palmer Dabbelt a écrit : On Tue, 23 Jan 2018 06:48:07 PST (-0800), laur...@vivier.eu wrote: From: Andreas SchwabThis is needed for new architectures like RISC-V which do not provide any other rename-like syscall. Signed-off-by: Andreas Schwab Reviewed-by: Laurent Vivier Message-Id: Signed-off-by: Laurent Vivier ---  linux-user/syscall.c | 34 ++  1 file changed, 34 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 104408c050..74378947f0 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -600,6 +600,24 @@ static int sys_utimensat(int dirfd, const char *pathname,  #endif  #endif /* TARGET_NR_utimensat */ +#ifdef TARGET_NR_renameat2 +#if defined(__NR_renameat2) +#define __NR_sys_renameat2 __NR_renameat2 +_syscall5(int, sys_renameat2, int, oldfd, const char *, old, int, newfd, + const char *, new, unsigned int, flags) +#else +static int sys_renameat2(int oldfd, const char *old, + int newfd, const char *new, int flags) +{ +   if (flags == 0) { +   return renameat(oldfd, old, newfd, new); +   } +   errno = ENOSYS; +   return -1; +} +#endif +#endif /* TARGET_NR_renameat2 */ +  #ifdef CONFIG_INOTIFY  #include @@ -8426,6 +8444,22 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } break;  #endif +#if defined(TARGET_NR_renameat2) +   case TARGET_NR_renameat2: +   { +   void *p2; +   p = lock_user_string(arg2); +   p2 = lock_user_string(arg4); +   if (!p || !p2) { +   ret = -TARGET_EFAULT; +   } else { +   ret = get_errno(sys_renameat2(arg1, p, arg3, p2, arg5)); +   } +   unlock_user(p2, arg4, 0); +   unlock_user(p, arg2, 0); +   } +   break; +#endif  #ifdef TARGET_NR_mkdir case TARGET_NR_mkdir: if (!(p = lock_user_string(arg1))) Thanks! My patch got lost in the shuffle, but I think these are functionally identical. Feel free to add my I've seen your patch, but Andreas has implemented what was requested by Peter (use renameat() when flags == 0), so I took his one. Ya, I wrote another one do to that bug forgot to send it :) Reviewed-by: Palmer Dabbelt To late for that (it's a pull request), sorry. OK, no problem. I'm a bit new to QEMU. Thanks! Thank you, Laurent
[Qemu-devel] [PATCH] target/arm: implement SM4 instructions
This implements emulation of the new SM4 instructions that have been added as an optional extension to the ARMv8 Crypto Extensions in ARM v8.2. Signed-off-by: Ard Biesheuvel--- I went ahead and did the implementation according to the pseudocode in the ARM ARM, even though i have no test code or reference vectors to compare it against. (There is some example code in the ARM ARM as well, but I haven't played with that) target/arm/cpu.h | 1 + target/arm/crypto_helper.c | 91 target/arm/helper.h| 3 + target/arm/translate-a64.c | 8 ++ 4 files changed, 103 insertions(+) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 18383666e02d..bad13a76d06c 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -1375,6 +1375,7 @@ enum arm_features { ARM_FEATURE_V8_SHA512, /* implements SHA512 part of v8 Crypto Extensions */ ARM_FEATURE_V8_SHA3, /* implements SHA3 part of v8 Crypto Extensions */ ARM_FEATURE_V8_SM3, /* implements SM3 part of v8 Crypto Extensions */ +ARM_FEATURE_V8_SM4, /* implements SM4 part of v8 Crypto Extensions */ }; static inline int arm_feature(CPUARMState *env, int feature) diff --git a/target/arm/crypto_helper.c b/target/arm/crypto_helper.c index c1d9f765cd40..b42c7e046ba3 100644 --- a/target/arm/crypto_helper.c +++ b/target/arm/crypto_helper.c @@ -609,3 +609,94 @@ void HELPER(crypto_sm3tt)(void *vd, void *vn, void *vm, uint32_t imm2, rd[0] = d.l[0]; rd[1] = d.l[1]; } + +static uint8_t const sm4_sbox[] = { +0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, +0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05, +0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, +0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99, +0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, +0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62, +0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, +0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6, +0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, +0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8, +0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, +0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35, +0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, +0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87, +0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, +0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e, +0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, +0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1, +0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, +0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3, +0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, +0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f, +0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, +0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51, +0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, +0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8, +0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, +0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0, +0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, +0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84, +0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, +0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48, +}; + +void HELPER(crypto_sm4e)(void *vd, void *vn) +{ +uint64_t *rd = vd; +uint64_t *rn = vn; +union CRYPTO_STATE d = { .l = { rd[0], rd[1] } }; +union CRYPTO_STATE n = { .l = { rn[0], rn[1] } }; +uint32_t t, i; + +for (i = 0; i < 3; i++) { +t = CR_ST_WORD(d, (i + 1) % 4) ^ +CR_ST_WORD(d, (i + 2) % 4) ^ +CR_ST_WORD(d, (i + 3) % 4) ^ +CR_ST_WORD(n, i); + +t = sm4_sbox[t & 0xff] | +sm4_sbox[(t >> 8) & 0xff] << 8 | +sm4_sbox[(t >> 16) & 0xff] << 16 | +sm4_sbox[(t >> 24) & 0xff] << 24; + +CR_ST_WORD(d, i) ^= t ^ rol32(t, 2) ^ rol32(t, 10) ^ rol32(t, 18) ^ +rol32(t, 24); +} + +rd[0] = d.l[0]; +rd[1] = d.l[1]; +} + +void HELPER(crypto_sm4ekey)(void *vd, void *vn, void* vm) +{ +uint64_t *rd = vd; +uint64_t *rn = vn; +uint64_t *rm = vm; +union CRYPTO_STATE d; +union CRYPTO_STATE n = { .l = { rn[0], rn[1] } }; +union CRYPTO_STATE m = { .l = { rm[0], rm[1] } }; +uint32_t t, i; + +d = n; +for (i = 0; i < 3; i++) { +t = CR_ST_WORD(d, (i + 1) % 4) ^ +CR_ST_WORD(d, (i + 2) % 4) ^ +CR_ST_WORD(d, (i + 3) % 4) ^ +CR_ST_WORD(m, i); + +t = sm4_sbox[t & 0xff] | +sm4_sbox[(t >> 8) & 0xff] << 8 | +sm4_sbox[(t >> 16) & 0xff] << 16 | +sm4_sbox[(t >> 24) & 0xff] << 24; + +CR_ST_WORD(d, i) ^= t ^ rol32(t, 13) ^ rol32(t, 23); +} + +rd[0] = d.l[0]; +rd[1] = d.l[1]; +} diff --git a/target/arm/helper.h b/target/arm/helper.h index 2d0bba10c006..ee5b0e98f624 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -544,6 +544,9 @@
Re: [Qemu-devel] [PATCH v10 05/14] migration: Create ram_multifd_page
* Juan Quintela (quint...@redhat.com) wrote: > The function still don't use multifd, but we have simplified > ram_save_page, xbzrle and RDMA stuff is gone. We have added a new > counter and a new flag for this type of pages. > > Signed-off-by: Juan Quintela> > -- > Add last_page parameter > Add commets for done and address > Remove multifd field, it is the same than normal pages > Merge next patch, now we send multiple pages at a time > Remove counter for multifd pages, it is identical to normal pages > Use iovec's instead of creating the equivalent. > Clear memory used by pages (dave) > Use g_new0(danp) > define MULTIFD_CONTINUE > now pages member is a pointer > Fix off-by-one in number of pages in one packet > --- > migration/ram.c| 159 > - > migration/trace-events | 2 + > 2 files changed, 160 insertions(+), 1 deletion(-) > > diff --git a/migration/ram.c b/migration/ram.c > index aef5a323f3..5d6b46ac23 100644 > --- a/migration/ram.c > +++ b/migration/ram.c > @@ -52,6 +52,7 @@ > #include "migration/block.h" > #include "sysemu/sysemu.h" > #include "qemu/uuid.h" > +#include "qemu/iov.h" > > /***/ > /* ram save/restore */ > @@ -71,6 +72,7 @@ > #define RAM_SAVE_FLAG_XBZRLE 0x40 > /* 0x80 is reserved in migration.h start with 0x100 next */ > #define RAM_SAVE_FLAG_COMPRESS_PAGE0x100 > +#define RAM_SAVE_FLAG_MULTIFD_PAGE 0x200 > > static inline bool is_zero_range(uint8_t *p, uint64_t size) > { > @@ -395,14 +397,36 @@ static void compress_threads_save_setup(void) > > /* Multiple fd's */ > > +/* used to continue on the same multifd group */ > +#define MULTIFD_CONTINUE UINT16_MAX > + > +typedef struct { > +/* number of used pages */ Telling us it's used doesn't help much; if I understand right, this is for accumulating them into one large block before actually sending them? > +uint32_t used; > +/* number of allocated pages */ > +uint32_t allocated; > +/* global number of generated multifd packets */ > +uint32_t seq; > +struct iovec *iov; > +RAMBlock *block; > +} multifd_pages_t; > + > struct MultiFDSendParams { > +/* not changed */ ??? > uint8_t id; > char *name; > QemuThread thread; > QIOChannel *c; > QemuSemaphore sem; > QemuMutex mutex; > +/* protected by param mutex */ > bool quit; > +multifd_pages_t *pages; > +/* how many patches has sent this channel */ s/patches/packets/ > +uint32_t packets_sent; > +/* protected by multifd mutex */ > +/* has the thread finish the last submitted job */ > +bool done; > }; > typedef struct MultiFDSendParams MultiFDSendParams; > > @@ -410,8 +434,31 @@ struct { > MultiFDSendParams *params; > /* number of created threads */ > int count; > +QemuMutex mutex; > +QemuSemaphore sem; > +multifd_pages_t *pages; > } *multifd_send_state; > > +static void multifd_pages_init(multifd_pages_t **ppages, size_t size) What is the 'size' here - it's allocated pages for something? > +{ > +multifd_pages_t *pages = g_new0(multifd_pages_t, 1); > + > +pages->allocated = size; > +pages->iov = g_new0(struct iovec, size); > +*ppages = pages; > +} > + > +static void multifd_pages_clear(multifd_pages_t *pages) > +{ > +pages->used = 0; > +pages->allocated = 0; > +pages->seq = 0; > +pages->block = NULL; > +g_free(pages->iov); > +pages->iov = NULL; > +g_free(pages); > +} > + > static void terminate_multifd_send_threads(Error *errp) > { > int i; > @@ -453,9 +500,13 @@ int multifd_save_cleanup(Error **errp) > socket_send_channel_destroy(p->c); > g_free(p->name); > p->name = NULL; > +multifd_pages_clear(p->pages); > +p->pages = NULL; > } > g_free(multifd_send_state->params); > multifd_send_state->params = NULL; > +multifd_pages_clear(multifd_send_state->pages); > +multifd_send_state->pages = NULL; > g_free(multifd_send_state); > multifd_send_state = NULL; > return ret; > @@ -482,6 +533,7 @@ static void *multifd_send_thread(void *opaque) > terminate_multifd_send_threads(local_err); > return NULL; > } > +qemu_sem_post(_send_state->sem); > > while (true) { > qemu_mutex_lock(>mutex); > @@ -489,9 +541,24 @@ static void *multifd_send_thread(void *opaque) > qemu_mutex_unlock(>mutex); > break; > } > +if (p->pages->used) { > +p->pages->used = 0; > +qemu_mutex_unlock(>mutex); > + > +trace_multifd_send(p->id, p->pages->seq, p->pages->used); but p->pages->used is just been set to 0? > +/* ToDo: send page here */ > + > +qemu_mutex_lock(_send_state->mutex); > +p->done = true; > +p->packets_sent++; > +
Re: [Qemu-devel] [PULL 13/13] linux-user: implement renameat2
Le 23/01/2018 à 20:13, Palmer Dabbelt a écrit : > On Tue, 23 Jan 2018 06:48:07 PST (-0800), laur...@vivier.eu wrote: >> From: Andreas Schwab>> >> This is needed for new architectures like RISC-V which do not provide any >> other rename-like syscall. >> >> Signed-off-by: Andreas Schwab >> Reviewed-by: Laurent Vivier >> Message-Id: >> Signed-off-by: Laurent Vivier >> --- >>  linux-user/syscall.c | 34 ++ >>  1 file changed, 34 insertions(+) >> >> diff --git a/linux-user/syscall.c b/linux-user/syscall.c >> index 104408c050..74378947f0 100644 >> --- a/linux-user/syscall.c >> +++ b/linux-user/syscall.c >> @@ -600,6 +600,24 @@ static int sys_utimensat(int dirfd, const char >> *pathname, >>  #endif >>  #endif /* TARGET_NR_utimensat */ >> >> +#ifdef TARGET_NR_renameat2 >> +#if defined(__NR_renameat2) >> +#define __NR_sys_renameat2 __NR_renameat2 >> +_syscall5(int, sys_renameat2, int, oldfd, const char *, old, int, newfd, >> + const char *, new, unsigned int, flags) >> +#else >> +static int sys_renameat2(int oldfd, const char *old, >> + int newfd, const char *new, int flags) >> +{ >> +   if (flags == 0) { >> +   return renameat(oldfd, old, newfd, new); >> +   } >> +   errno = ENOSYS; >> +   return -1; >> +} >> +#endif >> +#endif /* TARGET_NR_renameat2 */ >> + >>  #ifdef CONFIG_INOTIFY >>  #include >> >> @@ -8426,6 +8444,22 @@ abi_long do_syscall(void *cpu_env, int num, >> abi_long arg1, >> } >> break; >>  #endif >> +#if defined(TARGET_NR_renameat2) >> +   case TARGET_NR_renameat2: >> +   { >> +   void *p2; >> +   p = lock_user_string(arg2); >> +   p2 = lock_user_string(arg4); >> +   if (!p || !p2) { >> +   ret = -TARGET_EFAULT; >> +   } else { >> +   ret = get_errno(sys_renameat2(arg1, p, arg3, p2, arg5)); >> +   } >> +   unlock_user(p2, arg4, 0); >> +   unlock_user(p, arg2, 0); >> +   } >> +   break; >> +#endif >>  #ifdef TARGET_NR_mkdir >> case TARGET_NR_mkdir: >> if (!(p = lock_user_string(arg1))) > > Thanks! My patch got lost in the shuffle, but I think these are > functionally identical. Feel free to add my I've seen your patch, but Andreas has implemented what was requested by Peter (use renameat() when flags == 0), so I took his one. > Reviewed-by: Palmer Dabbelt To late for that (it's a pull request), sorry. Thank you, Laurent
Re: [Qemu-devel] [PATCH v5 2/4] target/arm: implement SHA-3 instructions
On 22 January 2018 at 17:26, Ard Biesheuvelwrote: > This implements emulation of the new SHA-3 instructions that have > been added as an optional extensions to the ARMv8 Crypto Extensions > in ARM v8.2. > > Signed-off-by: Ard Biesheuvel > --- > target/arm/cpu.h | 1 + > target/arm/translate-a64.c | 148 +++- > 2 files changed, 145 insertions(+), 4 deletions(-) > > diff --git a/target/arm/cpu.h b/target/arm/cpu.h > index 32a18510e70b..d0b19e0cbc88 100644 > --- a/target/arm/cpu.h > +++ b/target/arm/cpu.h > @@ -1373,6 +1373,7 @@ enum arm_features { > ARM_FEATURE_JAZELLE, /* has (trivial) Jazelle implementation */ > ARM_FEATURE_SVE, /* has Scalable Vector Extension */ > ARM_FEATURE_V8_SHA512, /* implements SHA512 part of v8 Crypto Extensions > */ > +ARM_FEATURE_V8_SHA3, /* implements SHA3 part of v8 Crypto Extensions */ > }; > > static inline int arm_feature(CPUARMState *env, int feature) > diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c > index 888f5a39a283..10f2e518f303 100644 > --- a/target/arm/translate-a64.c > +++ b/target/arm/translate-a64.c > @@ -11162,9 +11162,10 @@ static void > disas_crypto_three_reg_sha512(DisasContext *s, uint32_t insn) > feature = ARM_FEATURE_V8_SHA512; > genfn = gen_helper_crypto_sha512su1; > break; > -default: > -unallocated_encoding(s); > -return; > +case 3: /* RAX1 */ > +feature = ARM_FEATURE_V8_SHA3; > +genfn = NULL; > +break; > } > } else { > unallocated_encoding(s); > @@ -11193,7 +11194,28 @@ static void > disas_crypto_three_reg_sha512(DisasContext *s, uint32_t insn) > tcg_temp_free_ptr(tcg_rn_ptr); > tcg_temp_free_ptr(tcg_rm_ptr); > } else { > -g_assert_not_reached(); > +TCGv_i64 tcg_op1, tcg_op2, tcg_res[2]; > +int pass; > + > +tcg_op1 = tcg_temp_new_i64(); > +tcg_op2 = tcg_temp_new_i64(); > +tcg_res[0] = tcg_temp_new_i64(); > +tcg_res[1] = tcg_temp_new_i64(); > + > +for (pass = 0; pass < 2; pass++) { > +read_vec_element(s, tcg_op1, rn, pass, MO_64); > +read_vec_element(s, tcg_op2, rm, pass, MO_64); > + > +tcg_gen_rotli_i64(tcg_res[pass], tcg_op2, 1); > +tcg_gen_xor_i64(tcg_res[pass], tcg_res[pass], tcg_op1); > +} > +write_vec_element(s, tcg_res[0], rd, 0, MO_64); > +write_vec_element(s, tcg_res[1], rd, 1, MO_64); > + > +tcg_temp_free(tcg_op1); > +tcg_temp_free(tcg_op2); > +tcg_temp_free(tcg_res[0]); > +tcg_temp_free(tcg_res[1]); > } > } > > @@ -11240,6 +11262,122 @@ static void > disas_crypto_two_reg_sha512(DisasContext *s, uint32_t insn) > tcg_temp_free_ptr(tcg_rn_ptr); > } > > +/* Crypto four-register > + * 31 23 22 21 20 16 15 14 10 95 40 > + * +---+-+--+---+--+--+--+ > + * | 1 1 0 0 1 1 1 0 0 | Op0 | Rm | 0 | Ra | Rn | Rd | > + * +---+-+--+---+--+--+--+ > + */ > +static void disas_crypto_four_reg(DisasContext *s, uint32_t insn) > +{ > +int op0 = extract32(insn, 21, 2); > +int rm = extract32(insn, 16, 5); > +int ra = extract32(insn, 10, 5); > +int rn = extract32(insn, 5, 5); > +int rd = extract32(insn, 0, 5); > +int feature; > + > +switch (op0) { > +case 0: /* EOR3 */ > +case 1: /* BCAX */ > +feature = ARM_FEATURE_V8_SHA3; > +break; > +default: > +unallocated_encoding(s); > +return; > +} > + > +if (!arm_dc_feature(s, feature)) { > +unallocated_encoding(s); > +return; > +} > + > +if (!fp_access_check(s)) { > +return; > +} > + > +if (op0 < 2) { > +TCG_i64 tcg_op1, tcg_op2, tcg_op3, tcg_res[2]; Apologies, there's a typo here: TCGv_i64 not TCG_i64 Let me know if I need to resend. > +int pass; > + > +tcg_op1 = tcg_temp_new_i64(); > +tcg_op2 = tcg_temp_new_i64(); > +tcg_op3 = tcg_temp_new_i64(); > +tcg_res[0] = tcg_temp_new_i64(); > +tcg_res[1] = tcg_temp_new_i64(); > + > +for (pass = 0; pass < 2; pass++) { > +read_vec_element(s, tcg_op1, rn, pass, MO_64); > +read_vec_element(s, tcg_op2, rm, pass, MO_64); > +read_vec_element(s, tcg_op3, ra, pass, MO_64); > + > +if (op0 == 0) { > +/* EOR3 */ > +tcg_gen_xor_i64(tcg_res[pass], tcg_op2, tcg_op3); > +} else { > +/* BCAX */ > +tcg_gen_andc_i64(tcg_res[pass], tcg_op2, tcg_op3); > +} > +tcg_gen_xor_i64(tcg_res[pass], tcg_res[pass], tcg_op1); > +} > +write_vec_element(s, tcg_res[0], rd, 0, MO_64); > +
Re: [Qemu-devel] [PATCH v2 11/20] fpu/softfloat: re-factor add/sub
Peter Maydellwrites: > >> +float_status *status) >> +{ >> +if (part.exp == parm->exp_max) { >> +if (part.frac == 0) { >> +part.cls = float_class_inf; >> +} else { >> +#ifdef NO_SIGNALING_NANS > > The old code didn't seem to need to ifdef this; why's the new > code different? (at some point we'll want to make this a runtime > setting so we can support one binary handling CPUs with it both > set and unset, but that is a far future thing we can ignore for now) It does, but it's hidden behind propagateFloatXXNaN which in turn calls floatXX_is_quiet/signalling_nan which are altered by the #ifdefs. > >> +part.cls = float_class_qnan; >> +#else >> +int64_t msb = part.frac << (parm->frac_shift + 2); >> +if ((msb < 0) == status->snan_bit_is_one) { >> +part.cls = float_class_snan; >> +} else { >> +part.cls = float_class_qnan; >> +} >> +#endif >> +} >> +} else if (part.exp == 0) { >> +if (likely(part.frac == 0)) { >> +part.cls = float_class_zero; >> +} else if (status->flush_inputs_to_zero) { >> +float_raise(float_flag_input_denormal, status); >> +part.cls = float_class_zero; >> +part.frac = 0; >> +} else { >> +int shift = clz64(part.frac) - 1; >> +part.cls = float_class_normal; > > This is really confusing. This is a *denormal*, but we're setting > the classification to "normal" ? (It's particularly confusing in > the code that uses the decomposed numbers, because it looks like > "if (a.cls == float_class_normal...)" is handling the normal-number > case and denormals are going to be in a later if branch, but actually > it's dealing with both.) The code deals with canonicalized numbers - so unless we explicitly flush denormals to zero they can be treated like any other for the rest of the code. What would you prefer? A comment in FloatClass? >> + >> +static float16 float16_round_pack_canonical(decomposed_parts p, >> float_status *s) >> +{ >> +switch (p.cls) { >> +case float_class_dnan: >> +return float16_default_nan(s); >> +case float_class_msnan: >> +return float16_maybe_silence_nan(float16_pack_raw(p), s); > > I think you will find that doing the silencing of the NaNs like this > isn't quite the right approach. Specifically, for Arm targets we > currently have a bug in float-to-float conversion from a wider > format to a narrower one when the input is a signaling NaN that we > want to silence, and its non-zero mantissa bits are all at the > less-significant end of the mantissa such that they don't fit into > the narrower format. If you pack the float into a float16 first and > then call maybe_silence_nan() on it you've lost the info about those > low bits which the silence function needs to know to return the > right answer. What you want to do instead is pass the silence_nan > function the decomposed value. So this is an inherited bug from softfloat-specialize.h? I guess we need a common specific decomposed specialisation we can use for all the sizes. > > (The effect of this bug is that we return a default NaN, with the > sign bit clear, but the Arm FPConvertNaN pseudocode says that we > should effectively get the default NaN but with the same sign bit > as the input SNaN.) > > Given that this is a bug currently in the version we have, we don't > necessarily need to fix it now, but I thought I'd mention it since > the redesign has almost but not quite managed to deliver the right > information to the silencing code to allow us to fix it soon :-) So comment for now? Currently all the information for decomposed is kept internal to softfloat.c - I'm not sure we want to expose the internals to a wider audience? Especially as these inline helpers in specialize.h are also used by helpers. >> + >> + >> +/* >> + * Returns the result of adding the absolute values of the >> + * floating-point values `a' and `b'. If `subtract' is set, the sum is >> + * negated before being returned. `subtract' is ignored if the result >> + * is a NaN. The addition is performed according to the IEC/IEEE >> + * Standard for Binary Floating-Point Arithmetic. >> + */ > > This comment doesn't seem to match what the code is doing, > because it says it adds the absolute values of 'a' and 'b', > but the code looks at a_sign and b_sign to decide whether it's > doing an addition or subtraction rather than ignoring the signs > (as you would for absolute arithmetic). > > Put another way, this comment has been copied from the old addFloat64Sigs() > and not updated to account for the way the new function includes handling > of subFloat64Sigs(). > >> + >> +static decomposed_parts add_decomposed(decomposed_parts a, decomposed_parts >> b, >> + bool subtract, float_status *s) >> +{ >>
Re: [Qemu-devel] [PATCH qemu v2] RFC: vfio-pci: Allow mmap of MSIX BAR
On Fri, 19 Jan 2018 14:15:43 +0100 Auger Ericwrote: > Hi, > > On 19/01/18 04:25, Alex Williamson wrote: > > On Fri, 19 Jan 2018 13:41:41 +1100 > > Alexey Kardashevskiy wrote: > > > >> On 19/01/18 08:59, Alex Williamson wrote: > >>> On Tue, 16 Jan 2018 16:17:58 +1100 > >>> Alexey Kardashevskiy wrote: > >>> > On 06/01/18 02:29, Alex Williamson wrote: > > On Fri, 5 Jan 2018 10:48:07 +0100 > > Auger Eric wrote: > > > >> Hi Alexey, > >> > >> On 15/12/17 07:29, Alexey Kardashevskiy wrote: > >>> This makes use of a new VFIO_REGION_INFO_CAP_MSIX_MAPPABLE capability > >>> which tells that a region with MSIX data can be mapped entirely, i.e. > >>> the VFIO PCI driver won't prevent MSIX vectors area from being mapped. > >>> > >>> With this change, all BARs are mapped in a single chunk and MSIX > >>> vectors > >>> are emulated on top unless the machine requests not to by defining and > >>> enabling a new "vfio-no-msix-emulation" property. At the moment only > >>> sPAPR machine does so - it prohibits MSIX emulation and does not allow > >>> enabling it as it does not define the "set" callback for the new > >>> property; > >>> the new property also does not appear in "-machine pseries,help". > >>> > >>> If the new capability is present, this puts MSIX IO memory region > >>> under > >>> mapped memory region. If the capability is not there, it falls back to > >>> the old behaviour with the sparse capability. > >>> > >>> In MSIX vectors section is not aligned to the page size, the KVM > >>> memory > >>> listener does not register it with the KVM as a memory slot and MSIX > >>> is > >>> emulated by QEMU as before. > >>> > >>> This requires the kernel change - "vfio-pci: Allow mapping MSIX BAR" - > >>> for the new capability: > >>> https://www.spinics.net/lists/kvm/msg160282.html > >>> > >>> Signed-off-by: Alexey Kardashevskiy > >>> --- > >>> > >>> This is mtree and flatview BEFORE this patch: > >>> > >>> "info mtree": > >>> memory-region: p...@8002000.mmio > >>> - (prio 0, i/o): > >>> p...@8002000.mmio > >>> 2100-2100 (prio 1, i/o): 0001:03:00.0 BAR > >>> 1 > >>> 2100e000-2100e5ff (prio 0, i/o): msix-table > >>> 2100f000-2100f00f (prio 0, i/o): msix-pba > >>> [disabled] > >>> 2104-2107 (prio 1, i/o): 0001:03:00.0 BAR > >>> 3 > >>> 2104-2107 (prio 0, ramd): 0001:03:00.0 > >>> BAR 3 mmaps[0] > >>> > >>> "info mtree -f": > >>> FlatView #0 > >>> AS "memory", root: system > >>> AS "cpu-memory", root: system > >>> Root memory region: system > >>> -7fff (prio 0, ram): ppc_spapr.ram > >>> 2100-2100dfff (prio 1, i/o): 0001:03:00.0 BAR 1 > >>> 2100e000-2100e5ff (prio 0, i/o): msix-table > >>> 2100e600-2100 (prio 1, i/o): 0001:03:00.0 BAR 1 > >>> @e600 > >>> 2104-2107 (prio 0, ramd): 0001:03:00.0 BAR > >>> 3 mmaps[0] > >>> > >>> > >>> > >>> This is AFTER this patch applied: > >>> > >>> "info mtree": > >>> memory-region: p...@8002000.mmio > >>> - (prio 0, i/o): > >>> p...@8002000.mmio > >>> 2100-2100 (prio 1, i/o): 0001:03:00.0 BAR > >>> 1 > >>> 2100-2100 (prio 0, ramd): 0001:03:00.0 > >>> BAR 1 mmaps[0] > >>> 2100e000-2100e5ff (prio 0, i/o): msix-table > >>> [disabled] > >>> 2100f000-2100f00f (prio 0, i/o): msix-pba > >>> [disabled] > >>> 2104-2107 (prio 1, i/o): 0001:03:00.0 BAR > >>> 3 > >>> 2104-2107 (prio 0, ramd): 0001:03:00.0 > >>> BAR 3 mmaps[0] > >>> > >>> > >>> "info mtree -f": > >>> FlatView #2 > >>> AS "memory", root: system > >>> AS "cpu-memory", root: system > >>> Root memory region: system > >>> -7fff (prio 0, ram): ppc_spapr.ram > >>> 2100-2100 (prio 0, ramd): 0001:03:00.0 BAR > >>> 1 mmaps[0] > >>> 2104-2107 (prio 0, ramd): 0001:03:00.0 BAR > >>> 3 mmaps[0] > >>> > >>> > >>> > >>> This is AFTER this patch applied AND spapr_get_msix_emulation() > >>> patched > >>> to enable emulation: > >>> > >>> "info mtree": > >>> memory-region:
Re: [Qemu-devel] [PATCH qemu v3] RFC: vfio-pci: Allow mmap of MSIX BAR
On Tue, 23 Jan 2018 16:34:34 +0100 Auger Ericwrote: > Hi Alexey, > On 23/01/18 02:22, Alexey Kardashevskiy wrote: > > This makes use of a new VFIO_REGION_INFO_CAP_MSIX_MAPPABLE capability > > which tells that a region with MSIX data can be mapped entirely, i.e. > > the VFIO PCI driver won't prevent MSIX vectors area from being mapped. > > > > With this change, all BARs are mapped in a single chunk and MSIX vectors > > are emulated on top unless the machine requests not to by defining and > > enabling a new "vfio-no-msix-emulation" property. At the moment only > > sPAPR machine does so - it prohibits MSIX emulation and does not allow > > enabling it as it does not define the "set" callback for the new property; > > the new property also does not appear in "-machine pseries,help". > > > > If MSIX vectors section is not aligned to the page size, the KVM memory > > listener does not register it with the KVM as a memory slot and MSIX is > > emulated by QEMU as before. This may create MMIO RAM memory sections with > > an address or/and a size not aligned which will make vfio_dma_map() fail; > > to address this, this makes treats such failures as non-fatal. > > > > This requires the kernel change - "vfio-pci: Allow mapping MSIX BAR" - > > for the new capability: https://www.spinics.net/lists/kvm/msg160282.html > > > > Signed-off-by: Alexey Kardashevskiy > > --- > > Changes: > > v3: > > * vfio_listener_region_add() won't make qemu exit if failed on MMIO MR > > > > --- > > include/hw/vfio/vfio-common.h | 1 + > > linux-headers/linux/vfio.h| 5 + > > hw/ppc/spapr.c| 7 +++ > > hw/vfio/common.c | 19 +++ > > hw/vfio/pci.c | 10 ++ > > 5 files changed, 42 insertions(+) > > > > diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h > > index f3a2ac9..927d600 100644 > > --- a/include/hw/vfio/vfio-common.h > > +++ b/include/hw/vfio/vfio-common.h > > @@ -171,6 +171,7 @@ int vfio_get_region_info(VFIODevice *vbasedev, int > > index, > > struct vfio_region_info **info); > > int vfio_get_dev_region_info(VFIODevice *vbasedev, uint32_t type, > > uint32_t subtype, struct vfio_region_info > > **info); > > +bool vfio_is_cap_present(VFIODevice *vbasedev, uint16_t cap_type, int > > region); > > #endif > > extern const MemoryListener vfio_prereg_listener; > > > > diff --git a/linux-headers/linux/vfio.h b/linux-headers/linux/vfio.h > > index 4312e96..b45182e 100644 > > --- a/linux-headers/linux/vfio.h > > +++ b/linux-headers/linux/vfio.h > > @@ -301,6 +301,11 @@ struct vfio_region_info_cap_type { > > #define VFIO_REGION_SUBTYPE_INTEL_IGD_HOST_CFG (2) > > #define VFIO_REGION_SUBTYPE_INTEL_IGD_LPC_CFG (3) > > > > +/* > > + * The MSIX mappable capability informs that MSIX data of a BAR can be > > mmapped. > > + */ > > +#define VFIO_REGION_INFO_CAP_MSIX_MAPPABLE 3 > > + > > /** > > * VFIO_DEVICE_GET_IRQ_INFO - _IOWR(VFIO_TYPE, VFIO_BASE + 9, > > * struct vfio_irq_info) > > diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c > > index d1acfe8..5ff43ce 100644 > > --- a/hw/ppc/spapr.c > > +++ b/hw/ppc/spapr.c > > @@ -2789,6 +2789,11 @@ static void spapr_set_modern_hotplug_events(Object > > *obj, bool value, > > spapr->use_hotplug_event_source = value; > > } > > > > +static bool spapr_get_msix_emulation(Object *obj, Error **errp) > > +{ > > +return true; > > +} > > + > > static char *spapr_get_resize_hpt(Object *obj, Error **errp) > > { > > sPAPRMachineState *spapr = SPAPR_MACHINE(obj); > > @@ -2870,6 +2875,8 @@ static void spapr_instance_init(Object *obj) > > object_property_set_description(obj, "vsmt", > > "Virtual SMT: KVM behaves as if this > > were" > > " the host's SMT mode", _abort); > > +object_property_add_bool(obj, "vfio-no-msix-emulation", > > + spapr_get_msix_emulation, NULL, NULL); > > } > > > > static void spapr_machine_finalizefn(Object *obj) > > diff --git a/hw/vfio/common.c b/hw/vfio/common.c > > index b77be3a..842c5b2 100644 > > --- a/hw/vfio/common.c > > +++ b/hw/vfio/common.c > > @@ -530,6 +530,10 @@ static void vfio_listener_region_add(MemoryListener > > *listener, > > return; > > > > fail: > > +if (memory_region_is_ram_device(section->mr)) { > > +error_report("failed to vfio_dma_map. pci p2p may not work"); > > +return; > > +} > > I don't think this is an acceptable solution as it produces plenty of > errors such as > > qemu-system-aarch64: VFIO_MAP_DMA: -22 > qemu-system-aarch64: vfio_dma_map(0x30a7ab90, 0x80, 0x2000, > 0xfffd79a0) = -22 (Invalid argument) This much of the error above could be avoided by looking at the type1 page size bitmap before trying to perform the mapping. >
Re: [Qemu-devel] [PATCH v2 0/4] Updates based on feedback.
On Mon, Jan 22, 2018 at 01:07:45PM -0800, Justin Terry (VM) wrote: > Updates based on review feedback. > > 1. Fixes style issues and properly ran the scripts/checkpatch pre submission. > 2. Added migration blockers for CPUID, dirty memory tracking, and > XSAVE/XRSTOR. > 3. Fixed some bugs around register states when using bios vs efi. For reference to others, v1 seems to be: Subject: [PATCH 0/4] Implements the Windows Hypervisor Platform accelerator https://www.mail-archive.com/qemu-devel@nongnu.org/msg505710.html > > Justin Terry (VM) (4): > Add the Windows Hypervisor Platform accelerator. > Add the WHPX vcpu API > Introduce the WHPX impl > Add the WHPX acceleration enlightenments > > accel/stubs/Makefile.objs |9 +- > accel/stubs/whpx-stub.c | 48 ++ > configure | 48 +- > cpus.c| 66 ++- > include/sysemu/hw_accel.h | 13 + > include/sysemu/whpx.h | 40 ++ > qemu-options.hx |8 +- > target/i386/Makefile.objs |1 + > target/i386/helper.c |2 +- > target/i386/whpx-all.c| 1366 > + > 10 files changed, 1590 insertions(+), 11 deletions(-) > create mode 100644 accel/stubs/whpx-stub.c > create mode 100644 include/sysemu/whpx.h > create mode 100644 target/i386/whpx-all.c > > -- > 2.7.4 > -- Eduardo
Re: [Qemu-devel] [PATCH v10 04/14] migration: Start of multiple fd work
* Juan Quintela (quint...@redhat.com) wrote: > We create new channels for each new thread created. We send through > them in a packed struct. This way we can check we connect the right > channels in both sides. > > Signed-off-by: Juan QuintelaGeneral comment; given it's reasonably large, it would be nice to split this into a send and a receive patch. Some tracing wouldn't do any harm - it's going to be fun debugging failures where some sockets connect and then fail, so tracing would help. > -- > Split SocketArgs into incoming and outgoing args > > Use UUID's on the initial message, so we are sure we are connecting to > the right channel. > > Remove init semaphore. Now that we use uuids on the init message, we > know that this is our channel. > > Fix recv socket destwroy, we were destroying send channels. > This was very interesting, because we were using an unreferred object > without problems. > > Move to struct of pointers > init channel sooner. > split recv thread creation. > listen on main thread > We count the number of created threads to know when we need to stop listening > Use g_strdup_printf > report channel id on errors > Add name parameter > Use local_err > Add Error * parameter to socket_send_channel_create() > Use qio_channel_*_all > Use asynchronous connect > Use an struct to send all fields > Use default uuid > Fix local_err = NULL (dave) > Make lines 80 lines long (checkpatch) > Move multifd_new_channel() and multifd_recv_thread() to later patches > when used. > Add __attribute__(packad) > Use UUIDs are opaques isntead of the ASCII represantation > rename migrate_new_channel_async to migrate_new_send_channel_async > rename recv_channel_destroy to _unref. And create the pairing _ref. > --- > migration/migration.c | 7 +++- > migration/ram.c | 114 > +++--- > migration/ram.h | 3 ++ > migration/socket.c| 39 - > migration/socket.h| 10 + > 5 files changed, 137 insertions(+), 36 deletions(-) > > diff --git a/migration/migration.c b/migration/migration.c > index e506b9c2c6..77fc17f723 100644 > --- a/migration/migration.c > +++ b/migration/migration.c > @@ -426,7 +426,7 @@ void migration_ioc_process_incoming(QIOChannel *ioc) > QEMUFile *f = qemu_fopen_channel_input(ioc); > migration_fd_process_incoming(f); > } > -/* We still only have a single channel. Nothing to do here yet */ > +multifd_recv_new_channel(ioc); OK, that looks a little odd at the moment - do we grow the recv_new_channel and still leave the first one in there? > } > > /** > @@ -437,6 +437,11 @@ void migration_ioc_process_incoming(QIOChannel *ioc) > */ > bool migration_has_all_channels(void) > { > +if (migrate_use_multifd()) { > +int thread_count = migrate_multifd_channels(); > + > +return thread_count == multifd_created_channels(); > +} > return true; > } > > diff --git a/migration/ram.c b/migration/ram.c > index 5a109efeda..aef5a323f3 100644 > --- a/migration/ram.c > +++ b/migration/ram.c > @@ -36,6 +36,7 @@ > #include "xbzrle.h" > #include "ram.h" > #include "migration.h" > +#include "socket.h" > #include "migration/register.h" > #include "migration/misc.h" > #include "qemu-file.h" > @@ -49,6 +50,8 @@ > #include "qemu/rcu_queue.h" > #include "migration/colo.h" > #include "migration/block.h" > +#include "sysemu/sysemu.h" > +#include "qemu/uuid.h" > > /***/ > /* ram save/restore */ > @@ -396,6 +399,7 @@ struct MultiFDSendParams { > uint8_t id; > char *name; > QemuThread thread; > +QIOChannel *c; > QemuSemaphore sem; > QemuMutex mutex; > bool quit; > @@ -412,6 +416,15 @@ static void terminate_multifd_send_threads(Error *errp) > { > int i; > > +if (errp) { > +MigrationState *s = migrate_get_current(); > +migrate_set_error(s, errp); > +if (s->state == MIGRATION_STATUS_SETUP || > +s->state == MIGRATION_STATUS_ACTIVE) { > +migrate_set_state(>state, s->state, > + MIGRATION_STATUS_FAILED); > +} > +} > for (i = 0; i < multifd_send_state->count; i++) { > MultiFDSendParams *p = _send_state->params[i]; > > @@ -437,6 +450,7 @@ int multifd_save_cleanup(Error **errp) > qemu_thread_join(>thread); > qemu_mutex_destroy(>mutex); > qemu_sem_destroy(>sem); > +socket_send_channel_destroy(p->c); > g_free(p->name); > p->name = NULL; > } > @@ -447,9 +461,27 @@ int multifd_save_cleanup(Error **errp) > return ret; > } > > +typedef struct { > +uint32_t version; > +unsigned char uuid[16]; /* QemuUUID */ > +uint8_t id; > +} __attribute__((packed)) MultiFDInit_t; > + > static void *multifd_send_thread(void *opaque) > { > MultiFDSendParams *p = opaque; > +
Re: [Qemu-devel] [PULL 0/8] x86 queue, 2018-01-17
On Tue, Jan 23, 2018 at 12:15:27PM -0600, Michael Roth wrote: > Quoting Christian Borntraeger (2018-01-23 03:59:39) > > > > > > On 01/23/2018 09:40 AM, Christian Ehrhardt wrote: > > > On Thu, Jan 18, 2018 at 2:51 PM, Peter Maydell> > > wrote: > > >> On 18 January 2018 at 02:01, Eduardo Habkost wrote: > > >>> The following changes since commit > > >>> 8e5dc9ba49743b46d955ec7dacb04e42ae7ada7c: > > >>> > > >>> Merge remote-tracking branch 'remotes/rth/tags/pull-tcg-20180116' > > >>> into staging (2018-01-16 17:36:39 +) > > >>> > > >>> are available in the Git repository at: > > >>> > > >>> git://github.com/ehabkost/qemu.git tags/x86-pull-request > > >>> > > >>> for you to fetch changes up to 6cfbc54e8903a9bcc0346119949162d040c144c1: > > >>> > > >>> i386: Add EPYC-IBPB CPU model (2018-01-17 23:54:39 -0200) > > >>> > > >>> > > >>> x86 queue, 2018-01-17 > > >>> > > >>> Highlight: new CPU models that expose CPU features that guests > > >>> can use to mitigate CVE-2017-5715 (Spectre variant #2). > > >>> > > >> > > >> Applied, thanks. > > >> > > >> -- PMM > > >> > > > > > > Hi, > > > I was kind of clinging to [1] so far and had the expectation that all > > > those would be wrapped up in 2.11.1 once ready. > > > I see that the s390x changes are targeted to qemu-stable (well to > > > admit I suggested so referring the article above). > > > So I'd expected to see this series to show up on qemu-stable as well > > > but haven't seen it so far. > > > > > > Therefore I wanted to ask if there was a change of plans in that > > > regard or if it needs just a few days more to see (part of) this > > > series on qemu-stable and on its way into 2.11.1? > > > > > > [1]: https://www.qemu.org/2018/01/04/spectre/ > > > > Adding Michael, > > > > Yes, I think it makes sense to have the guest enablement for the spectre > > mitigations available in 2.11.1 for all architectures that provide it. > > (this queue for x86, Connies pending S390 patches, whatever Power > > and arm will do). > > That's my plan as well, but IIUC the QEMU side of these patches rely on > a KVM flag that in turn relies on this series: > > https://lkml.org/lkml/2018/1/20/158 Actually it depends on: https://lkml.org/lkml/2018/1/9/329 ([PATCH v2 0/8] KVM: x86: expose CVE-2017-5715 ("Spectre variant 2") mitigations to guest) The ability to expose IBRS to guests doesn't seem to depend on the host kernel using IBRS to protect itself. But I guess it will be easier to merge that code after Linux developers decide what they'll do. Paolo, what's your take on this? Note that there are released OSes that use IBRS (Windows and RHEL), so even if upstream Linux decide to not rely on IBRS, users will probably want to expose IBRS to VMs as soon as KVM becomes able to do that. BUT: > > But that's still in RFC and Linus seems to have reservations with the > current code. Since coordinating these all this to users/downstreams is > somewhat of a mess I was thinking we should accompany the 2.11.1 release > with a blog post on the various options/backports/microcode needed throughout > the stack to enable the fixes, but until there's a stable patchset on > the linux side I'm not sure there's much worth in putting out the 2.11.1 > release (if I'm missing something here please let me know). I'm inclined to agree. I merged the -IBRS CPU models expecting that the fixes would be included quickly in upstream Linux too, but it was not the case. To be honest, I don't think adding new CPU models are the proper solution for the problem. They are just a quick solution that doesn't require intrusive changes in the management stack. Meltdown & Spectre made us painfully aware of limitations of management stacks out there (esp. OpenStack): they normally don't have an easy mechanism to enable CPU features that are not part of an existing CPU model name. A good management stack would be able to use, e.g., "-cpu Westmere,+spec-ctrl" instead of "Westmere-IBRS" if it knows all the hosts on a given cluster/migration-set/whatever-it-is-called support the feature. The same applies to other flags like ibpb and pcid. There's work being done on OpenStack to fix this, e.g.: https://review.openstack.org/#/c/534384/ That said, we will probably want to include MSR code and the CPU feature flag names (spec-ctrl and ibpb) on the stable branch as soon as possible. This way, people will have the option to manually enable those features (or make them automatically available using "-cpu host") before a decision is made regarding CPU model names. I can send a patch series to -stable including only those patches, if it makes the work easier. > > There's also the testing aspect of this, which I'd at least like to cover > on the x86 side. I've be doing some basic testing on top of early versions > of the IBRS patches and KVM patches, but I'd really like to make
Re: [Qemu-devel] [PATCH v4 04/10] s390-ccw: update libc
On 01/23/2018 12:26 PM, Collin L. Walling wrote: > Moved: > memcmp from bootmap.h to libc.h (renamed from _memcmp) > strlen from sclp.c to libc.h (renamed from _strlen) > > Added C standard functions: > atoi > isdigit > > Added non C-standard function: > itostr > > Signed-off-by: Collin L. Walling> Acked-by: Christian Borntraeger > Reviewed-by: Janosch Frank > --- > +/** > + * atoi: > + * @str: the string to be converted. > + * > + * Given a string @str, convert it to an integer. Leading whitespace is > + * ignored. The first character (after any whitespace) is checked for the > + * negative sign. Any other non-numerical value will terminate the > + * conversion. > + * > + * Returns: an integer converted from the string @str. > + */ > +int atoi(const char *str) > +{ > +int val = 0; > +int sign = 1; > + > +if (!str || !str[0]) { > +return 0; > +} > + > +while (*str == ' ') { > +str++; > +} That's not "any whitespace", but only spaces. A fully compliant implementation would be checking isspace(), but I don't expect you to implement that; at a minimum, also checking '\t' would get you closer (but not all the way to) compliance. > +static char *_itostr(int num, char *str, size_t len) > +{ > +int num_idx = 0; > +int tmp = num; > +char sign = 0; > + > +if (!str) { > +return NULL; > +} > + > +/* Get index to ones place */ > +while ((tmp /= 10) != 0) { > +num_idx++; > +} > + > +if (num < 0) { > +num *= -1; > +sign = 1; > +} If num == INT_MIN, then num is still negative at this point... > + > +/* Check if we have enough space for num, sign, and null */ > +if (len <= num_idx + sign + 1) { > +return NULL; > +} > + > +str[num_idx + sign + 1] = '\0'; > + > +/* Convert int to string */ > +while (num_idx >= 0) { > +str[num_idx + sign] = num % 10 + '0'; ...which breaks this. Either make it work, or document the corner case as unsupported. -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3266 Virtualization: qemu.org | libvirt.org signature.asc Description: OpenPGP digital signature
Re: [Qemu-devel] [PATCH v4 00/10] Interactive Boot Menu for DASD and SCSI Guests on s390x
On 01/23/2018 12:26 PM, Collin L. Walling wrote: > --- [v4] --- > > This round mostly includes some general cleanup to bootmap.c. Checkpatch did > not like any variation of "strtoi", so I properly implemented atoi instead. strtol is actually a better interface than atoi (as it can report errors); but for a fallback code used only on known boot parameters, implementing the simpler atoi is probably fine. > > - itostr and atoi now handle negative numbers (though not necessary > for these patches, it is available for robustness) -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3266 Virtualization: qemu.org | libvirt.org signature.asc Description: OpenPGP digital signature
Re: [Qemu-devel] [PULL 13/13] linux-user: implement renameat2
On Tue, 23 Jan 2018 06:48:07 PST (-0800), laur...@vivier.eu wrote: From: Andreas SchwabThis is needed for new architectures like RISC-V which do not provide any other rename-like syscall. Signed-off-by: Andreas Schwab Reviewed-by: Laurent Vivier Message-Id: Signed-off-by: Laurent Vivier --- linux-user/syscall.c | 34 ++ 1 file changed, 34 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 104408c050..74378947f0 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -600,6 +600,24 @@ static int sys_utimensat(int dirfd, const char *pathname, #endif #endif /* TARGET_NR_utimensat */ +#ifdef TARGET_NR_renameat2 +#if defined(__NR_renameat2) +#define __NR_sys_renameat2 __NR_renameat2 +_syscall5(int, sys_renameat2, int, oldfd, const char *, old, int, newfd, + const char *, new, unsigned int, flags) +#else +static int sys_renameat2(int oldfd, const char *old, + int newfd, const char *new, int flags) +{ +if (flags == 0) { +return renameat(oldfd, old, newfd, new); +} +errno = ENOSYS; +return -1; +} +#endif +#endif /* TARGET_NR_renameat2 */ + #ifdef CONFIG_INOTIFY #include @@ -8426,6 +8444,22 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, } break; #endif +#if defined(TARGET_NR_renameat2) +case TARGET_NR_renameat2: +{ +void *p2; +p = lock_user_string(arg2); +p2 = lock_user_string(arg4); +if (!p || !p2) { +ret = -TARGET_EFAULT; +} else { +ret = get_errno(sys_renameat2(arg1, p, arg3, p2, arg5)); +} +unlock_user(p2, arg4, 0); +unlock_user(p, arg2, 0); +} +break; +#endif #ifdef TARGET_NR_mkdir case TARGET_NR_mkdir: if (!(p = lock_user_string(arg1))) Thanks! My patch got lost in the shuffle, but I think these are functionally identical. Feel free to add my Reviewed-by: Palmer Dabbelt
Re: [Qemu-devel] [PATCH v1 1/2] Revert "build-sys: silence make by default or V=0"
On 01/23/2018 10:47 AM, Daniel P. Berrange wrote: > This reverts commit 42a77f1ce4934b243df003f95bda88530631387a. > > The primary intention of this change was to silence messages > like > > make[1]: '/home/berrange/src/virt/qemu/capstone/libcapstone.a' is up to > date. > > which we get when calling make recursively with explicit > targets. > > The problem is that this change affected every make target, > not merely the targets that triggered these "is up to date" > messages. As a result any targets that were not invoking > commands via "$(call quiet-command ...)" suddenly become > silent. This is particularly bad for "make install" which > now appears todo nothing. > > Rather than go through every make rule and try to identify > places where we now need to explicitly print a message to > show work taking place, just revert the change. > > To address the original problem of silencing "is up to date" > messages, we simply add --quiet to the SUBDIR_MAKEVARS > variable, so it only affects us on recursive make calls. As for solving the original intended issue, this patch silences the message about libcapstone, and reverting back to a known state is more conservative, so I'm okay with this going in. Tested-by: Eric Blake-- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3266 Virtualization: qemu.org | libvirt.org signature.asc Description: OpenPGP digital signature
Re: [Qemu-devel] [PATCH v1 2/2] make: fix help message reference to bogus V=0 variable
On 01/23/2018 10:47 AM, Daniel P. Berrange wrote: > The make rules for building QEMU are mostly silent by default. They can > be made verbose by setting the variable V=1. The default state does not > however correspond to a V=0 setting - $(V) must be undefined / empty to > get the default quiet build. Makefiles generated by automake support V=0; how hard would it be to instead tweak things so that 'V=' and 'V=0' have the same effect? > > Signed-off-by: Daniel P. Berrange> --- > Makefile | 3 ++- > 1 file changed, 2 insertions(+), 1 deletion(-) > > diff --git a/Makefile b/Makefile > index c263190b8d..554ba69ced 100644 > --- a/Makefile > +++ b/Makefile > @@ -940,4 +940,5 @@ ifdef QEMU_GA_MSI_ENABLED > endif > @echo '' > endif > - @echo ' $(MAKE) V=0|1 [targets] 0 => quiet build (default), 1 => > verbose build' > + @echo ' $(MAKE) [targets] (quiet build, default)' > + @echo ' $(MAKE) V=1 [targets] (verbose build)' > -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3266 Virtualization: qemu.org | libvirt.org signature.asc Description: OpenPGP digital signature
Re: [Qemu-devel] [qemu-s390x] [PULL 0/8] x86 queue, 2018-01-17
Quoting Cornelia Huck (2018-01-23 04:50:45) > On Tue, 23 Jan 2018 11:34:18 +0100 > Christian Ehrhardtwrote: > > > On Tue, Jan 23, 2018 at 10:59 AM, Christian Borntraeger > > wrote: > > > > > > > > > On 01/23/2018 09:40 AM, Christian Ehrhardt wrote: > > >> On Thu, Jan 18, 2018 at 2:51 PM, Peter Maydell > > >> wrote: > > >>> On 18 January 2018 at 02:01, Eduardo Habkost > > >>> wrote: > > The following changes since commit > > 8e5dc9ba49743b46d955ec7dacb04e42ae7ada7c: > > > > Merge remote-tracking branch 'remotes/rth/tags/pull-tcg-20180116' > > into staging (2018-01-16 17:36:39 +) > > > > are available in the Git repository at: > > > > git://github.com/ehabkost/qemu.git tags/x86-pull-request > > > > for you to fetch changes up to > > 6cfbc54e8903a9bcc0346119949162d040c144c1: > > > > i386: Add EPYC-IBPB CPU model (2018-01-17 23:54:39 -0200) > > > > > > x86 queue, 2018-01-17 > > > > Highlight: new CPU models that expose CPU features that guests > > can use to mitigate CVE-2017-5715 (Spectre variant #2). > > > > >>> > > >>> Applied, thanks. > > >>> > > >>> -- PMM > > >>> > > >> > > >> Hi, > > >> I was kind of clinging to [1] so far and had the expectation that all > > >> those would be wrapped up in 2.11.1 once ready. > > >> I see that the s390x changes are targeted to qemu-stable (well to > > >> admit I suggested so referring the article above). > > >> So I'd expected to see this series to show up on qemu-stable as well > > >> but haven't seen it so far. > > >> > > >> Therefore I wanted to ask if there was a change of plans in that > > >> regard or if it needs just a few days more to see (part of) this > > >> series on qemu-stable and on its way into 2.11.1? > > >> > > >> [1]: https://www.qemu.org/2018/01/04/spectre/ > > > > > > Adding Michael, > > > > > > Yes, I think it makes sense to have the guest enablement for the spectre > > > mitigations available in 2.11.1 for all architectures that provide it. > > > (this queue for x86, Connies pending S390 patches, whatever Power > > > and arm will do). > > > > Also adding Suraj for a statement in this regard about his "[QEMU-PPC] > > [PATCH V5 0/7] target/ppc: Rework spapr_caps" series which I think is > > the PPC version of all of this right? > > Not sure who to add for Arm :-/ > > > > @Cornelia - the consumers of these stable changes in particular IMHO > > are Distributions for security updates. > > Seeing at least one backport into 2.11.1 would be very helpful to > > avoid issues that would not apply to a forward thinking 2.12 commit. > > Such a (even short distance) backport being done by the Author would > > have the lowest risk of such issues creeping in. > > I'm not so sure on 2.(<11).x - but one backport at least into the > > latest release would be very nice to fulfill the [1] announcement > > referenced above and provide a first release of these important > > changes available earlier than full 2.12. > > I agree that a backport unto 2.11.x is useful. > > But I still think we should clarify the purpose of our stable tree -- > not necessarily in this thread, though. > Generally the idea is a development cycle's worth of bug/security fixes that a distro that bases on, say, 2.11, can pull in without any other changes throughout their stack. Stuff like this is somewhat of an exceptional case because it doesn't have any benefit to someone who just drops it into their existing stack, but if it seems likely they'll become reliant on it then it makes sense. We've done this in the past to fix stuff like migration breakages that were discovered after release and required new machine options. Certainly not an ideal situation though.
Re: [Qemu-devel] [PATCH v2] kvm-all: Partially reverts 4fe6d78b2e to remove the cleanup call
On 01/23/2018 03:54 PM, Jose Ricardo Ziviani wrote: This commit partially reverts the commit 4fe6d78b2e because of issues reported in the virtio. Examples: $ qemu-system-ppc64 -cpu POWER8 -nographic -vga none -m 4G \ -M pseries,accel=kvm -netdev type=user,id=net0 \ -device virtio-net-pci,netdev=net0 -drive file=../disk.qcow2,if=virtio Populating /vdevice/nvram@7101 Populating /vdevice/v-scsi@7102 SCSI: Looking for devices 8200 CD-ROM : "QEMU QEMU CD-ROM 2.5+" Populating /pci@8002000 00 (D) : 1af4 1000virtio [ net ] Aborted $ qemu-system-x86_64 -m 4G -enable-kvm -drive file=util.qcow2,if=virtio Running QEMU with GTK 2.x is deprecated, and will be removed in a future release. Please switch to GTK 3.x instead [1]5282 abort Reference http://lists.nongnu.org/archive/html/qemu-devel/2018-01/msg05457.html Reported-by: Anton BlanchardSigned-off-by: Jose Ricardo Ziviani --- This patch also fixed a migration problem I was investigating today. Turns out 4fe6d78b2e is also to be blamed for this P8 -> P8 migration being broken in current master: $ sudo ./qemu-system-ppc64 --enable-kvm --nographic -vga none -machine pseries -m 4G,slots=32,maxmem=32G -smp 1,maxcpus=32 -device virtio-blk-pci,drive=rootdisk -drive file=/home/danielhb/vm_imgs/f26.qcow2,if=none,cache=none,format=qcow2,id=rootdisk -incoming tcp:0: qemu-system-ppc64: load of migration failed: Input/output error Reverting 4fe6d78b2e or applying this patch fixes this migration issue too. Reviewed-by: Daniel Henrique Barboza Tested-by: Daniel Henrique Barboza accel/kvm/kvm-all.c | 4 1 file changed, 4 deletions(-) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index 071f4f57c0..f290f487a5 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -812,10 +812,6 @@ static void kvm_mem_ioeventfd_del(MemoryListener *listener, if (r < 0) { abort(); } - -if (e->cleanup) { -e->cleanup(e); -} } static void kvm_io_ioeventfd_add(MemoryListener *listener,
Re: [Qemu-devel] [PATCH v2 2/5] tpm: replace GThreadPool with AIO threadpool
On 01/19/2018 09:11 AM, Marc-André Lureau wrote: The TPM backend uses a GThreadPool to handle IO in a seperate thread. However, GThreadPool isn't integrated with Qemu main loops, making it unnecessarily complicated to deal with. Qemu has a AIO threadpool, that is better integrated with loops and various IO functions, provides completion BH by default etc. Remove the only user of GThreadPool from qemu, use AIO threadpool. Note that the backend: - no longer accepts queing multiple requests (unneeded so far) - increase ref to itself when handling a command, for extra safety - tpm_backend_thread_end() is renamed tpm_backend_finish_sync() and will wait for completion of BH (request_completed), which will help migration handling. Signed-off-by: Marc-André LureauI have been using this for a while: Tested-by: Stefan Berger Reviewed-by: Stefan Berger --- include/sysemu/tpm_backend.h | 12 -- backends/tpm.c | 52 +++- 2 files changed, 37 insertions(+), 27 deletions(-) diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h index 0d6c994a62..a69593e0cd 100644 --- a/include/sysemu/tpm_backend.h +++ b/include/sysemu/tpm_backend.h @@ -45,9 +45,8 @@ struct TPMBackend { /*< protected >*/ TPMIf *tpmif; bool opened; -GThreadPool *thread_pool; bool had_startup_error; -QEMUBH *bh; +TPMBackendCmd *cmd; /* */ char *id; @@ -196,6 +195,15 @@ TPMVersion tpm_backend_get_tpm_version(TPMBackend *s); */ size_t tpm_backend_get_buffer_size(TPMBackend *s); +/** + * tpm_backend_finish_sync: + * @s: the backend to call into + * + * Finish the pending command synchronously (this will call aio_poll() + * on qemu main AIOContext until it ends) + */ +void tpm_backend_finish_sync(TPMBackend *s); + /** * tpm_backend_query_tpm: * @s: the backend diff --git a/backends/tpm.c b/backends/tpm.c index 91222c5164..143807aa37 100644 --- a/backends/tpm.c +++ b/backends/tpm.c @@ -19,30 +19,35 @@ #include "sysemu/tpm.h" #include "qemu/thread.h" #include "qemu/main-loop.h" +#include "block/thread-pool.h" +#include "qemu/error-report.h" -static void tpm_backend_request_completed_bh(void *opaque) +static void tpm_backend_request_completed(void *opaque, int ret) { TPMBackend *s = TPM_BACKEND(opaque); TPMIfClass *tic = TPM_IF_GET_CLASS(s->tpmif); tic->request_completed(s->tpmif); + +/* no need for atomic, as long the BQL is taken */ +s->cmd = NULL; +object_unref(OBJECT(s)); } -static void tpm_backend_worker_thread(gpointer data, gpointer user_data) +static int tpm_backend_worker_thread(gpointer data) { -TPMBackend *s = TPM_BACKEND(user_data); +TPMBackend *s = TPM_BACKEND(data); TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); -k->handle_request(s, (TPMBackendCmd *)data); +k->handle_request(s, s->cmd); -qemu_bh_schedule(s->bh); +return 0; } -static void tpm_backend_thread_end(TPMBackend *s) +void tpm_backend_finish_sync(TPMBackend *s) { -if (s->thread_pool) { -g_thread_pool_free(s->thread_pool, FALSE, TRUE); -s->thread_pool = NULL; +while (s->cmd) { +aio_poll(qemu_get_aio_context(), true); } } @@ -74,10 +79,7 @@ int tpm_backend_startup_tpm(TPMBackend *s, size_t buffersize) TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); /* terminate a running TPM */ -tpm_backend_thread_end(s); - -s->thread_pool = g_thread_pool_new(tpm_backend_worker_thread, s, 1, TRUE, - NULL); +tpm_backend_finish_sync(s); res = k->startup_tpm ? k->startup_tpm(s, buffersize) : 0; @@ -93,7 +95,17 @@ bool tpm_backend_had_startup_error(TPMBackend *s) void tpm_backend_deliver_request(TPMBackend *s, TPMBackendCmd *cmd) { -g_thread_pool_push(s->thread_pool, cmd, NULL); +ThreadPool *pool = aio_get_thread_pool(qemu_get_aio_context()); + +if (s->cmd != NULL) { +error_report("There is a TPM request pending"); +return; +} + +s->cmd = cmd; +object_ref(OBJECT(s)); +thread_pool_submit_aio(pool, tpm_backend_worker_thread, s, + tpm_backend_request_completed, s); } void tpm_backend_reset(TPMBackend *s) @@ -104,7 +116,7 @@ void tpm_backend_reset(TPMBackend *s) k->reset(s); } -tpm_backend_thread_end(s); +tpm_backend_finish_sync(s); s->had_startup_error = false; } @@ -159,28 +171,18 @@ TPMInfo *tpm_backend_query_tpm(TPMBackend *s) return info; } -static void tpm_backend_instance_init(Object *obj) -{ -TPMBackend *s = TPM_BACKEND(obj); - -s->bh = qemu_bh_new(tpm_backend_request_completed_bh, s); -} - static void tpm_backend_instance_finalize(Object *obj) { TPMBackend *s = TPM_BACKEND(obj); object_unref(OBJECT(s->tpmif)); g_free(s->id);
[Qemu-devel] [PATCH v4 07/10] s390-ccw: read stage2 boot loader data to find menu
Read the stage2 boot loader data block-by-block. We scan the current block for the string "zIPL" to detect the start of the boot menu banner. We then load the adjacent blocks (previous block and next block) to account for the possibility of menu data spanning multiple blocks. Signed-off-by: Collin L. Walling--- pc-bios/s390-ccw/bootmap.c | 94 +++--- pc-bios/s390-ccw/bootmap.h | 1 + pc-bios/s390-ccw/menu.c| 5 +++ pc-bios/s390-ccw/menu.h| 1 + 4 files changed, 96 insertions(+), 5 deletions(-) diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c index 0da4c7f..7d7e0c5 100644 --- a/pc-bios/s390-ccw/bootmap.c +++ b/pc-bios/s390-ccw/bootmap.c @@ -13,6 +13,7 @@ #include "bootmap.h" #include "virtio.h" #include "bswap.h" +#include "menu.h" #ifdef DEBUG /* #define DEBUG_FALLBACK */ @@ -83,6 +84,10 @@ static void jump_to_IPL_code(uint64_t address) static unsigned char _bprs[8*1024]; /* guessed "max" ECKD sector size */ static const int max_bprs_entries = sizeof(_bprs) / sizeof(ExtEckdBlockPtr); +static uint8_t _s2[MAX_SECTOR_SIZE * 3] __attribute__((__aligned__(PAGE_SIZE))); +static void *s2_prev_blk = _s2; +static void *s2_cur_blk = _s2 + MAX_SECTOR_SIZE; +static void *s2_next_blk = _s2 + MAX_SECTOR_SIZE * 2; static inline void verify_boot_info(BootInfo *bip) { @@ -182,7 +187,76 @@ static block_number_t load_eckd_segments(block_number_t blk, uint64_t *address) return block_nr; } -static void run_eckd_boot_script(block_number_t bmt_block_nr) +static bool find_zipl_boot_menu_banner(int *offset) +{ +int i; + +/* Menu banner starts with "zIPL" */ +for (i = 0; i < virtio_get_block_size() - 4; i++) { +if (magic_match(s2_cur_blk + i, ZIPL_MAGIC_EBCDIC)) { +*offset = i; +return true; +} +} + +return false; +} + +static int eckd_get_boot_menu_index(block_number_t s1b_block_nr) +{ +block_number_t cur_block_nr; +block_number_t prev_block_nr = 0; +block_number_t next_block_nr = 0; +EckdStage1b *s1b = (void *)sec; +int offset; +int i; + +/* Get Stage1b data */ +memset(sec, FREE_SPACE_FILLER, sizeof(sec)); +read_block(s1b_block_nr, s1b, "Cannot read stage1b boot loader"); + +memset(_s2, FREE_SPACE_FILLER, sizeof(_s2)); + +/* Get Stage2 data */ +for (i = 0; i < STAGE2_BLK_CNT_MAX; i++) { +cur_block_nr = eckd_block_num(s1b->seek[i].chs); + +if (!cur_block_nr) { +break; +} + +read_block(cur_block_nr, s2_cur_blk, "Cannot read stage2 boot loader"); + +if (find_zipl_boot_menu_banner()) { +/* Load the adjacent blocks to account for the + * possibility of menu data spanning multiple blocks. + */ +if (prev_block_nr) { +read_block(prev_block_nr, s2_prev_blk, + "Cannot read stage2 boot loader"); +} + +if (i + 1 < STAGE2_BLK_CNT_MAX) { +next_block_nr = eckd_block_num(s1b->seek[i + 1].chs); +} + +if (next_block_nr) { +read_block(next_block_nr, s2_next_blk, + "Cannot read stage2 boot loader"); +} + +return menu_get_zipl_boot_index(s2_cur_blk, offset); +} + +prev_block_nr = cur_block_nr; +} + +sclp_print("No zipl boot menu data found. Booting default entry."); +return 0; +} + +static void run_eckd_boot_script(block_number_t bmt_block_nr, + block_number_t s1b_block_nr) { int i; unsigned int loadparm = get_loadparm_index(); @@ -191,6 +265,10 @@ static void run_eckd_boot_script(block_number_t bmt_block_nr) BootMapTable *bmt = (void *)sec; BootMapScript *bms = (void *)sec; +if (menu_check_flags(BOOT_MENU_FLAG_BOOT_OPTS | BOOT_MENU_FLAG_ZIPL_OPTS)) { +loadparm = eckd_get_boot_menu_index(s1b_block_nr); +} + debug_print_int("loadparm", loadparm); IPL_assert(loadparm < 31, "loadparm value greater than" " maximum number of boot entries allowed"); @@ -223,7 +301,7 @@ static void ipl_eckd_cdl(void) XEckdMbr *mbr; EckdCdlIpl2 *ipl2 = (void *)sec; IplVolumeLabel *vlbl = (void *)sec; -block_number_t bmt_block_nr; +block_number_t bmt_block_nr, s1b_block_nr; /* we have just read the block #0 and recognized it as "IPL1" */ sclp_print("CDL\n"); @@ -241,6 +319,9 @@ static void ipl_eckd_cdl(void) /* save pointer to Boot Map Table */ bmt_block_nr = eckd_block_num(mbr->blockptr.xeckd.bptr.chs); +/* save pointer to Stage1b Data */ +s1b_block_nr = eckd_block_num(ipl2->stage1.seek[0].chs); + memset(sec, FREE_SPACE_FILLER, sizeof(sec)); read_block(2, vlbl, "Cannot read Volume Label at block 2"); IPL_assert(magic_match(vlbl->key, VOL1_MAGIC), @@ -249,7 +330,7 @@ static void
[Qemu-devel] [PATCH v4 09/10] s390-ccw: read user input for boot index via the SCLP console
Implements an sclp_read function to capture input from the console and a wrapper function that handles parsing certain characters and adding input to a buffer. The input is checked for any erroneous values and is handled appropriately. A prompt will persist until input is entered or the timeout expires (if one was set). Example: Please choose (default will boot in 10 seconds): Correct input will boot the respective boot index. If the user's input is empty, 0, or if the timeout expires, then the default zipl entry will be chosen. If the input is within the range of available boot entries, then the selection will be booted. Any erroneous input will cancel the timeout and re-prompt the user. Signed-off-by: Collin L. Walling--- pc-bios/s390-ccw/menu.c | 152 +++- pc-bios/s390-ccw/s390-ccw.h | 2 + pc-bios/s390-ccw/sclp.c | 20 ++ pc-bios/s390-ccw/virtio.c | 2 +- 4 files changed, 172 insertions(+), 4 deletions(-) diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c index 174285e..24d4bba 100644 --- a/pc-bios/s390-ccw/menu.c +++ b/pc-bios/s390-ccw/menu.c @@ -12,16 +12,162 @@ #include "menu.h" #include "s390-ccw.h" -static uint8_t flags; -static uint64_t timeout; +#define KEYCODE_NO_INP '\0' +#define KEYCODE_ESCAPE '\033' +#define KEYCODE_BACKSP '\177' +#define KEYCODE_ENTER '\r' /* Offsets from zipl fields to zipl banner start */ #define ZIPL_TIMEOUT_OFFSET 138 #define ZIPL_FLAG_OFFSET140 +#define TOD_CLOCK_SECOND0xf424 + +static uint8_t flags; +static uint64_t timeout; + +static inline void enable_clock_int(void) +{ +uint64_t tmp = 0; + +asm volatile( +"stctg 0,0,%0\n" +"oi 6+%0, 0x8\n" +"lctlg 0,0,%0" +: : "Q" (tmp) : "memory" +); +} + +static inline void disable_clock_int(void) +{ +uint64_t tmp = 0; + +asm volatile( +"stctg 0,0,%0\n" +"ni 6+%0, 0xf7\n" +"lctlg 0,0,%0" +: : "Q" (tmp) : "memory" +); +} + +static inline void set_clock_comparator(uint64_t time) +{ +asm volatile("sckc %0" : : "Q" (time)); +} + +static inline bool check_clock_int(void) +{ +uint16_t *code = (uint16_t *)0x86; /* low-core external interrupt code */ + +consume_sclp_int(); + +return *code == 0x1004; +} + +static int read_prompt(char *buf, size_t len) +{ +char inp[2] = {}; +uint8_t idx = 0; +uint64_t time; + +if (timeout) { +time = get_clock() + (timeout * TOD_CLOCK_SECOND); +set_clock_comparator(time); +enable_clock_int(); +timeout = 0; +} + +while (!check_clock_int()) { + +/* Process only one character at a time */ +sclp_read(inp, 1); + +switch (inp[0]) { +case KEYCODE_NO_INP: +case KEYCODE_ESCAPE: +continue; +case KEYCODE_BACKSP: +if (idx > 0) { +buf[--idx] = 0; +sclp_print("\b \b"); +} +continue; +case KEYCODE_ENTER: +disable_clock_int(); +return idx; +} + +/* Echo input and add to buffer */ +if (idx < len) { +buf[idx] = inp[0]; +sclp_print(inp); +idx++; +} +} + +disable_clock_int(); +*buf = 0; + +return 0; +} + +static int get_index(void) +{ +char buf[10]; +int len; +int i; + +memset(buf, 0, sizeof(buf)); + +len = read_prompt(buf, sizeof(buf)); + +/* If no input, boot default */ +if (len == 0) { +return 0; +} + +/* Check for erroneous input */ +for (i = 0; i < len; i++) { +if (!isdigit(buf[i])) { +return -1; +} +} + +return atoi(buf); +} + +static void boot_menu_prompt(bool retry) +{ +char tmp[6]; + +if (retry) { +sclp_print("\nError: undefined configuration" + "\nPlease choose:\n"); +} else if (timeout > 0) { +sclp_print("Please choose (default will boot in "); +sclp_print(itostr(timeout, tmp, sizeof(tmp))); +sclp_print(" seconds):\n"); +} else { +sclp_print("Please choose:\n"); +} +} + static int get_boot_index(int entries) { -return 0; /* Implemented next patch */ +int boot_index; +bool retry = false; +char tmp[5]; + +do { +boot_menu_prompt(retry); +boot_index = get_index(); +retry = true; +} while (boot_index < 0 || boot_index >= entries); + +sclp_print("\nBooting entry #"); +sclp_print(itostr(boot_index, tmp, sizeof(tmp))); + +return boot_index; } static void zipl_println(const char *data, size_t len) diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h index 25d4d21..df4bc88 100644 --- a/pc-bios/s390-ccw/s390-ccw.h +++ b/pc-bios/s390-ccw/s390-ccw.h @@ -71,6 +71,7 @@ unsigned int get_loadparm_index(void); void
[Qemu-devel] [PATCH v4 03/10] s390-ccw: refactor IPL structs
ECKD DASDs have different IPL structures for CDL and LDL formats. The current Ipl1 and Ipl2 structs follow the CDL format, so we prepend "EckdCdl" to them. Boot info for LDL has been moved to a new struct: EckdLdlIpl1. Also introduce structs for IPL stages 1 and 1b. Signed-off-by: Collin L. WallingAcked-by: Janosch Frank --- pc-bios/s390-ccw/bootmap.c | 12 +- pc-bios/s390-ccw/bootmap.h | 55 -- 2 files changed, 45 insertions(+), 22 deletions(-) diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c index 621adbe..b01e0f6 100644 --- a/pc-bios/s390-ccw/bootmap.c +++ b/pc-bios/s390-ccw/bootmap.c @@ -221,7 +221,7 @@ static void run_eckd_boot_script(block_number_t bmt_block_nr) static void ipl_eckd_cdl(void) { XEckdMbr *mbr; -Ipl2 *ipl2 = (void *)sec; +EckdCdlIpl2 *ipl2 = (void *)sec; IplVolumeLabel *vlbl = (void *)sec; block_number_t bmt_block_nr; @@ -231,7 +231,7 @@ static void ipl_eckd_cdl(void) memset(sec, FREE_SPACE_FILLER, sizeof(sec)); read_block(1, ipl2, "Cannot read IPL2 record at block 1"); -mbr = >u.x.mbr; +mbr = >mbr; IPL_assert(magic_match(mbr, ZIPL_MAGIC), "No zIPL section in IPL2 record."); IPL_assert(block_size_ok(mbr->blockptr.xeckd.bptr.size), "Bad block size in zIPL section of IPL2 record."); @@ -281,7 +281,7 @@ static void print_eckd_ldl_msg(ECKD_IPL_mode_t mode) static void ipl_eckd_ldl(ECKD_IPL_mode_t mode) { block_number_t bmt_block_nr; -BootInfo *bip = (void *)(sec + 0x70); /* BootInfo is MBR for LDL */ +EckdLdlIpl1 *ipl1 = (void *)sec; if (mode != ECKD_LDL_UNLABELED) { print_eckd_ldl_msg(mode); @@ -292,15 +292,15 @@ static void ipl_eckd_ldl(ECKD_IPL_mode_t mode) memset(sec, FREE_SPACE_FILLER, sizeof(sec)); read_block(0, sec, "Cannot read block 0 to grab boot info."); if (mode == ECKD_LDL_UNLABELED) { -if (!magic_match(bip->magic, ZIPL_MAGIC)) { +if (!magic_match(ipl1->bip.magic, ZIPL_MAGIC)) { return; /* not applicable layout */ } sclp_print("unlabeled LDL.\n"); } -verify_boot_info(bip); +verify_boot_info(>bip); /* save pointer to Boot Map Table */ -bmt_block_nr = eckd_block_num(bip->bp.ipl.bm_ptr.eckd.bptr.chs); +bmt_block_nr = eckd_block_num(ipl1->bip.bp.ipl.bm_ptr.eckd.bptr.chs); run_eckd_boot_script(bmt_block_nr); /* no return */ diff --git a/pc-bios/s390-ccw/bootmap.h b/pc-bios/s390-ccw/bootmap.h index 260ac2a..460ec1a 100644 --- a/pc-bios/s390-ccw/bootmap.h +++ b/pc-bios/s390-ccw/bootmap.h @@ -237,22 +237,45 @@ typedef struct BootInfo { /* @ 0x70, record #0 */ } bp; } __attribute__ ((packed)) BootInfo; /* see also XEckdMbr */ -typedef struct Ipl1 { -unsigned char key[4]; /* == "IPL1" */ -unsigned char data[24]; -} __attribute__((packed)) Ipl1; - -typedef struct Ipl2 { -unsigned char key[4]; /* == "IPL2" */ -union { -unsigned char data[144]; -struct { -unsigned char reserved1[92-4]; -XEckdMbr mbr; -unsigned char reserved2[144-(92-4)-sizeof(XEckdMbr)]; -} x; -} u; -} __attribute__((packed)) Ipl2; +/* + * Structs for IPL + */ +#define STAGE2_BLK_CNT_MAX 24 /* Stage 1b can load up to 24 blocks */ + +typedef struct EckdCdlIpl1 { +uint8_t key[4]; /* == "IPL1" */ +uint8_t data[24]; +} __attribute__((packed)) EckdCdlIpl1; + +typedef struct EckdSeekArg { +uint16_t pad; +EckdCHS chs; +uint8_t pad2; +} __attribute__ ((packed)) EckdSeekArg; + +typedef struct EckdStage1b { +uint8_t reserved[32 * STAGE2_BLK_CNT_MAX]; +struct EckdSeekArg seek[STAGE2_BLK_CNT_MAX]; +uint8_t unused[64]; +} __attribute__ ((packed)) EckdStage1b; + +typedef struct EckdStage1 { +uint8_t reserved[72]; +struct EckdSeekArg seek[2]; +} __attribute__ ((packed)) EckdStage1; + +typedef struct EckdCdlIpl2 { +uint8_t key[4]; /* == "IPL2" */ +struct EckdStage1 stage1; +XEckdMbr mbr; +uint8_t reserved[24]; +} __attribute__((packed)) EckdCdlIpl2; + +typedef struct EckdLdlIpl1 { +uint8_t reserved[24]; +struct EckdStage1 stage1; +BootInfo bip; /* BootInfo is MBR for LDL */ +} __attribute__((packed)) EckdLdlIpl1; typedef struct IplVolumeLabel { unsigned char key[4]; /* == "VOL1" */ -- 2.7.4
[Qemu-devel] [PATCH v4 08/10] s390-ccw: print zipl boot menu
When the boot menu options are present and the guest's disk has been configured by the zipl tool, then the user will be presented with an interactive boot menu with labeled entries. An example of what the menu might look like: zIPL v1.37.1-build-20170714 interactive boot menu. 0. default (linux-4.13.0) 1. linux-4.13.0 2. performance 3. kvm Signed-off-by: Collin L. Walling--- pc-bios/s390-ccw/menu.c | 51 - 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/pc-bios/s390-ccw/menu.c b/pc-bios/s390-ccw/menu.c index de12c73..174285e 100644 --- a/pc-bios/s390-ccw/menu.c +++ b/pc-bios/s390-ccw/menu.c @@ -10,13 +10,62 @@ */ #include "menu.h" +#include "s390-ccw.h" static uint8_t flags; static uint64_t timeout; +/* Offsets from zipl fields to zipl banner start */ +#define ZIPL_TIMEOUT_OFFSET 138 +#define ZIPL_FLAG_OFFSET140 + +static int get_boot_index(int entries) +{ +return 0; /* Implemented next patch */ +} + +static void zipl_println(const char *data, size_t len) +{ +char buf[len + 2]; + +ebcdic_to_ascii(data, buf, len); +buf[len] = '\n'; +buf[len + 1] = '\0'; + +sclp_print(buf); +} + int menu_get_zipl_boot_index(const void *stage2, int offset) { -return 0; /* implemented next patch */ +const char *data = stage2 + offset; +uint16_t flag; +size_t len; +int ct; + +flag = *(uint16_t *)(data - ZIPL_FLAG_OFFSET); + +if (flags & BOOT_MENU_FLAG_ZIPL_OPTS) { +if (flag) { +timeout = *(uint16_t *)(data - ZIPL_TIMEOUT_OFFSET); +} else { +return 0; /* Boot default */ +} +} + +/* Print and count all menu items, including the banner */ +for (ct = 0; *data; ct++) { +len = strlen(data); +zipl_println(data, len); +data += len + 1; + +if (ct < 2) { +sclp_print("\n"); +} +} + +sclp_print("\n"); + +return get_boot_index(ct - 1); } void menu_set_parms(uint8_t boot_menu_flag, uint16_t boot_menu_timeout) -- 2.7.4
[Qemu-devel] [PATCH v4 05/10] s390-ccw: parse and set boot menu options
Set boot menu options for an s390 guest and store them in the iplb. These options are set via the QEMU command line option: -boot menu=on|off[,splash-time=X] or via the libvirt domain xml: Where X represents some positive integer representing milliseconds. Any value set for loadparm will override all boot menu options. If loadparm=PROMPT, then the menu will be enabled without a timeout. The absence of any boot options on the command line will flag to later use the zipl boot loader values. Signed-off-by: Collin L. WallingReviewed-by: Janosch Frank Reviewed-by: Thomas Huth --- hw/s390x/ipl.c | 55 + hw/s390x/ipl.h | 11 -- pc-bios/s390-ccw/iplb.h | 8 +-- 3 files changed, 70 insertions(+), 4 deletions(-) diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c index 0d06fc1..a1eb8fe 100644 --- a/hw/s390x/ipl.c +++ b/hw/s390x/ipl.c @@ -23,6 +23,8 @@ #include "hw/s390x/ebcdic.h" #include "ipl.h" #include "qemu/error-report.h" +#include "qemu/config-file.h" +#include "qemu/cutils.h" #define KERN_IMAGE_START0x01UL #define KERN_PARM_AREA 0x010480UL @@ -219,6 +221,56 @@ static Property s390_ipl_properties[] = { DEFINE_PROP_END_OF_LIST(), }; +static void s390_ipl_set_boot_menu(IplParameterBlock *iplb) +{ +QemuOptsList *plist = qemu_find_opts("boot-opts"); +QemuOpts *opts = QTAILQ_FIRST(>head); +uint8_t *flags; +uint16_t *timeout; +const char *tmp; +unsigned long result = 0; + +switch (iplb->pbt) { +case S390_IPL_TYPE_CCW: +flags = >ccw.boot_menu_flags; +timeout = >ccw.boot_menu_timeout; +break; +case S390_IPL_TYPE_QEMU_SCSI: +flags = >scsi.boot_menu_flags; +timeout = >scsi.boot_menu_timeout; +break; +default: +error_report("boot menu is not supported for this device type."); +return; +} + +/* In the absence of -boot menu, use zipl parameters */ +if (!qemu_opt_get(opts, "menu")) { +*flags = BOOT_MENU_FLAG_ZIPL_OPTS; +} else if (boot_menu) { +*flags = BOOT_MENU_FLAG_BOOT_OPTS; + +tmp = qemu_opt_get(opts, "splash-time"); + +if (tmp && qemu_strtoul(tmp, NULL, 10, )) { +error_report("splash-time value is invalid, forcing it to 0."); +*timeout = 0; +return; +} + +result = (result + 500) / 1000; /* Round and convert to seconds */ + +if (result > 0x) { +error_report("splash-time value is greater than 65535000," + " forcing it to 65535000."); +*timeout = 0x; +return; +} + +*timeout = cpu_to_be16(result); +} +} + static bool s390_gen_initial_iplb(S390IPLState *ipl) { DeviceState *dev_st; @@ -273,6 +325,9 @@ static bool s390_gen_initial_iplb(S390IPLState *ipl) if (!s390_ipl_set_loadparm(ipl->iplb.loadparm)) { ipl->iplb.flags |= DIAG308_FLAGS_LP_VALID; } + +s390_ipl_set_boot_menu(>iplb); + return true; } diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h index 8a705e0..48e82cf 100644 --- a/hw/s390x/ipl.h +++ b/hw/s390x/ipl.h @@ -15,9 +15,14 @@ #include "hw/qdev.h" #include "cpu.h" +#define BOOT_MENU_FLAG_BOOT_OPTS 0x80 +#define BOOT_MENU_FLAG_ZIPL_OPTS 0x40 + struct IplBlockCcw { uint64_t netboot_start_addr; -uint8_t reserved0[77]; +uint8_t reserved0[74]; +uint16_t boot_menu_timeout; +uint8_t boot_menu_flags; uint8_t ssid; uint16_t devno; uint8_t vm_flags; @@ -51,7 +56,9 @@ struct IplBlockQemuScsi { uint32_t lun; uint16_t target; uint16_t channel; -uint8_t reserved0[77]; +uint8_t reserved0[74]; +uint16_t boot_menu_timeout; +uint8_t boot_menu_flags; uint8_t ssid; uint16_t devno; } QEMU_PACKED; diff --git a/pc-bios/s390-ccw/iplb.h b/pc-bios/s390-ccw/iplb.h index 890aed9..fe909d2 100644 --- a/pc-bios/s390-ccw/iplb.h +++ b/pc-bios/s390-ccw/iplb.h @@ -14,7 +14,9 @@ struct IplBlockCcw { uint64_t netboot_start_addr; -uint8_t reserved0[77]; +uint8_t reserved0[74]; +uint16_t boot_menu_timeout; +uint8_t boot_menu_flags; uint8_t ssid; uint16_t devno; uint8_t vm_flags; @@ -48,7 +50,9 @@ struct IplBlockQemuScsi { uint32_t lun; uint16_t target; uint16_t channel; -uint8_t reserved0[77]; +uint8_t reserved0[74]; +uint16_t boot_menu_timeout; +uint8_t boot_menu_flags; uint8_t ssid; uint16_t devno; } __attribute__ ((packed)); -- 2.7.4