Compare commits
110 Commits
master
...
stable-2.8
Author | SHA1 | Date |
---|---|---|
Michael Roth | d1b725ee12 | |
Greg Kurz | 96bae145e2 | |
Michael Roth | 7124ccf8b3 | |
Sam Bobroff | 08c48c731a | |
Gerd Hoffmann | 12110bf70e | |
Eric Blake | 07672ab003 | |
Stefan Weil | 877e2b016e | |
Eric Blake | 2f8ab9b1dd | |
Eric Blake | c15c6d2594 | |
Igor Mammedov | dd39c544f4 | |
Eric Blake | 879b6454be | |
Paolo Bonzini | ce37df91f4 | |
Gerd Hoffmann | dc35a13747 | |
Gerd Hoffmann | a290442234 | |
Gerd Hoffmann | 031700e452 | |
Gerd Hoffmann | 2f51fd1f73 | |
Gerd Hoffmann | 63fdb09491 | |
hangaohuai | 3328c14e63 | |
Gerd Hoffmann | a99fd943c4 | |
Gerd Hoffmann | 670ddcc0aa | |
Gerd Hoffmann | 8db38049c6 | |
Wolfgang Bumiller | 205a619563 | |
Wolfgang Bumiller | 5d26f91c89 | |
Greg Kurz | 1a184c3af3 | |
Greg Kurz | 7f515a96ab | |
Richard Henderson | d437262fa8 | |
Richard Henderson | 74b13f92c2 | |
Richard Henderson | 4bcb497c7e | |
Vladimir Sementsov-Ogievskiy | 8029d55a93 | |
Peter Lieven | a3aeb9f09d | |
Dong Jia Shi | 34e9c09d03 | |
Jason Wang | 9e9483dea9 | |
Li Qiang | ba9c51d225 | |
Paolo Bonzini | 495756ef9d | |
Dmitry Fleytman | 9ad26963bf | |
Dmitry Fleytman | 15ad066065 | |
Dmitry Fleytman | 7cfd9c114b | |
Dmitry Fleytman | bddf2232fc | |
Gerd Hoffmann | fc8e94c3e5 | |
Eric Blake | 5e4641777c | |
Peter Lieven | d5506b3128 | |
Paolo Bonzini | 823fb688eb | |
Pavel Dovgalyuk | 270a46ea0d | |
Richard Henderson | f61f76cb3f | |
QingFeng Hao | 8ac427cdd0 | |
Sam Bobroff | 1d1d9226d8 | |
Michael Tokarev | adf2c47aa2 | |
Prasad J Pandit | 1a156ae5d1 | |
Peter Lieven | 3b8f27fe0b | |
Peter Lieven | 44d24c7b4a | |
Christian Borntraeger | 5f4b9013e6 | |
David Hildenbrand | 5e40f283e5 | |
Ladi Prosek | d2b9063eb8 | |
Paolo Bonzini | d8dea6fbcb | |
Li Qiang | f054cead44 | |
Christian Borntraeger | 5fb07a7b6c | |
Peter Lieven | 3fb4b3c371 | |
Michael S. Tsirkin | a626117f6a | |
Daniel P. Berrange | 3b33cba69c | |
Richard Henderson | 50b468d421 | |
Richard Henderson | 028fbea477 | |
Marc-André Lureau | 6e8052f967 | |
Peter Xu | 5c60c6ef61 | |
Bruce Rogers | 2ab8276a1c | |
Roman Kapl | 662a97d74f | |
Gonglei | d6f119475d | |
Caoxinhua | f47bf0823b | |
Thomas Huth | 8a6562592f | |
Paolo Bonzini | 9f6cb916f2 | |
Hervé Poussineau | dc659e3aea | |
Igor Mammedov | 87ede19db3 | |
Greg Kurz | da95bfe06b | |
Halil Pasic | 7830be742a | |
Michael S. Tsirkin | 620a65dc44 | |
Dr. David Alan Gilbert | 9d14f0cd65 | |
Eduardo Habkost | 04cde530be | |
Greg Kurz | a15785cfbd | |
Greg Kurz | 3731a25a62 | |
Greg Kurz | 7e9a1c4914 | |
Greg Kurz | 059f751ec2 | |
Greg Kurz | bb07a379b5 | |
Greg Kurz | 719e6dd171 | |
Greg Kurz | 05a92c2005 | |
Greg Kurz | 9c5cb58970 | |
Greg Kurz | c8c9aab173 | |
Greg Kurz | 5b24a96cd2 | |
Greg Kurz | 9f4ba82b06 | |
Greg Kurz | 62d1dbbfce | |
Greg Kurz | ea9e59bdf6 | |
Greg Kurz | e314b1b1fb | |
Greg Kurz | d7322e13c6 | |
Greg Kurz | d93d06a2fc | |
Greg Kurz | 0f3490faa8 | |
Greg Kurz | cfe40e1485 | |
Greg Kurz | 3439290f9e | |
Greg Kurz | ec10eada04 | |
Greg Kurz | d3c54bf9e7 | |
Greg Kurz | 91225c670a | |
Greg Kurz | 4286f58bfc | |
Greg Kurz | 0bb99557e1 | |
Greg Kurz | a9f46b8b65 | |
Greg Kurz | ed6083afc2 | |
Greg Kurz | d10142c11b | |
Greg Kurz | 6c1e3a16bc | |
Greg Kurz | acf22d2264 | |
Greg Kurz | 54f951d634 | |
Greg Kurz | 984bd0a1b8 | |
Greg Kurz | 52d43ff72e | |
Greg Kurz | e103f9e7b4 | |
Greg Kurz | 2c4f0f6c11 |
|
@ -498,14 +498,18 @@ iscsi_allocmap_update(IscsiLun *iscsilun, int64_t sector_num,
|
||||||
if (allocated) {
|
if (allocated) {
|
||||||
bitmap_set(iscsilun->allocmap, cl_num_expanded, nb_cls_expanded);
|
bitmap_set(iscsilun->allocmap, cl_num_expanded, nb_cls_expanded);
|
||||||
} else {
|
} else {
|
||||||
bitmap_clear(iscsilun->allocmap, cl_num_shrunk, nb_cls_shrunk);
|
if (nb_cls_shrunk > 0) {
|
||||||
|
bitmap_clear(iscsilun->allocmap, cl_num_shrunk, nb_cls_shrunk);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iscsilun->allocmap_valid == NULL) {
|
if (iscsilun->allocmap_valid == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (valid) {
|
if (valid) {
|
||||||
bitmap_set(iscsilun->allocmap_valid, cl_num_shrunk, nb_cls_shrunk);
|
if (nb_cls_shrunk > 0) {
|
||||||
|
bitmap_set(iscsilun->allocmap_valid, cl_num_shrunk, nb_cls_shrunk);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
bitmap_clear(iscsilun->allocmap_valid, cl_num_expanded,
|
bitmap_clear(iscsilun->allocmap_valid, cl_num_expanded,
|
||||||
nb_cls_expanded);
|
nb_cls_expanded);
|
||||||
|
|
49
block/nfs.c
49
block/nfs.c
|
@ -108,12 +108,13 @@ static int nfs_parse_uri(const char *filename, QDict *options, Error **errp)
|
||||||
qdict_put(options, "path", qstring_from_str(uri->path));
|
qdict_put(options, "path", qstring_from_str(uri->path));
|
||||||
|
|
||||||
for (i = 0; i < qp->n; i++) {
|
for (i = 0; i < qp->n; i++) {
|
||||||
|
unsigned long long val;
|
||||||
if (!qp->p[i].value) {
|
if (!qp->p[i].value) {
|
||||||
error_setg(errp, "Value for NFS parameter expected: %s",
|
error_setg(errp, "Value for NFS parameter expected: %s",
|
||||||
qp->p[i].name);
|
qp->p[i].name);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (parse_uint_full(qp->p[i].value, NULL, 0)) {
|
if (parse_uint_full(qp->p[i].value, &val, 0)) {
|
||||||
error_setg(errp, "Illegal value for NFS parameter: %s",
|
error_setg(errp, "Illegal value for NFS parameter: %s",
|
||||||
qp->p[i].name);
|
qp->p[i].name);
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -357,27 +358,27 @@ static QemuOptsList runtime_opts = {
|
||||||
.help = "Path of the image on the host",
|
.help = "Path of the image on the host",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "uid",
|
.name = "user",
|
||||||
.type = QEMU_OPT_NUMBER,
|
.type = QEMU_OPT_NUMBER,
|
||||||
.help = "UID value to use when talking to the server",
|
.help = "UID value to use when talking to the server",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "gid",
|
.name = "group",
|
||||||
.type = QEMU_OPT_NUMBER,
|
.type = QEMU_OPT_NUMBER,
|
||||||
.help = "GID value to use when talking to the server",
|
.help = "GID value to use when talking to the server",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "tcp-syncnt",
|
.name = "tcp-syn-count",
|
||||||
.type = QEMU_OPT_NUMBER,
|
.type = QEMU_OPT_NUMBER,
|
||||||
.help = "Number of SYNs to send during the session establish",
|
.help = "Number of SYNs to send during the session establish",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "readahead",
|
.name = "readahead-size",
|
||||||
.type = QEMU_OPT_NUMBER,
|
.type = QEMU_OPT_NUMBER,
|
||||||
.help = "Set the readahead size in bytes",
|
.help = "Set the readahead size in bytes",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "pagecache",
|
.name = "page-cache-size",
|
||||||
.type = QEMU_OPT_NUMBER,
|
.type = QEMU_OPT_NUMBER,
|
||||||
.help = "Set the pagecache size in bytes",
|
.help = "Set the pagecache size in bytes",
|
||||||
},
|
},
|
||||||
|
@ -506,29 +507,29 @@ static int64_t nfs_client_open(NFSClient *client, QDict *options,
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qemu_opt_get(opts, "uid")) {
|
if (qemu_opt_get(opts, "user")) {
|
||||||
client->uid = qemu_opt_get_number(opts, "uid", 0);
|
client->uid = qemu_opt_get_number(opts, "user", 0);
|
||||||
nfs_set_uid(client->context, client->uid);
|
nfs_set_uid(client->context, client->uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qemu_opt_get(opts, "gid")) {
|
if (qemu_opt_get(opts, "group")) {
|
||||||
client->gid = qemu_opt_get_number(opts, "gid", 0);
|
client->gid = qemu_opt_get_number(opts, "group", 0);
|
||||||
nfs_set_gid(client->context, client->gid);
|
nfs_set_gid(client->context, client->gid);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qemu_opt_get(opts, "tcp-syncnt")) {
|
if (qemu_opt_get(opts, "tcp-syn-count")) {
|
||||||
client->tcp_syncnt = qemu_opt_get_number(opts, "tcp-syncnt", 0);
|
client->tcp_syncnt = qemu_opt_get_number(opts, "tcp-syn-count", 0);
|
||||||
nfs_set_tcp_syncnt(client->context, client->tcp_syncnt);
|
nfs_set_tcp_syncnt(client->context, client->tcp_syncnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef LIBNFS_FEATURE_READAHEAD
|
#ifdef LIBNFS_FEATURE_READAHEAD
|
||||||
if (qemu_opt_get(opts, "readahead")) {
|
if (qemu_opt_get(opts, "readahead-size")) {
|
||||||
if (open_flags & BDRV_O_NOCACHE) {
|
if (open_flags & BDRV_O_NOCACHE) {
|
||||||
error_setg(errp, "Cannot enable NFS readahead "
|
error_setg(errp, "Cannot enable NFS readahead "
|
||||||
"if cache.direct = on");
|
"if cache.direct = on");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
client->readahead = qemu_opt_get_number(opts, "readahead", 0);
|
client->readahead = qemu_opt_get_number(opts, "readahead-size", 0);
|
||||||
if (client->readahead > QEMU_NFS_MAX_READAHEAD_SIZE) {
|
if (client->readahead > QEMU_NFS_MAX_READAHEAD_SIZE) {
|
||||||
error_report("NFS Warning: Truncating NFS readahead "
|
error_report("NFS Warning: Truncating NFS readahead "
|
||||||
"size to %d", QEMU_NFS_MAX_READAHEAD_SIZE);
|
"size to %d", QEMU_NFS_MAX_READAHEAD_SIZE);
|
||||||
|
@ -543,13 +544,13 @@ static int64_t nfs_client_open(NFSClient *client, QDict *options,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef LIBNFS_FEATURE_PAGECACHE
|
#ifdef LIBNFS_FEATURE_PAGECACHE
|
||||||
if (qemu_opt_get(opts, "pagecache")) {
|
if (qemu_opt_get(opts, "page-cache-size")) {
|
||||||
if (open_flags & BDRV_O_NOCACHE) {
|
if (open_flags & BDRV_O_NOCACHE) {
|
||||||
error_setg(errp, "Cannot enable NFS pagecache "
|
error_setg(errp, "Cannot enable NFS pagecache "
|
||||||
"if cache.direct = on");
|
"if cache.direct = on");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
client->pagecache = qemu_opt_get_number(opts, "pagecache", 0);
|
client->pagecache = qemu_opt_get_number(opts, "page-cache-size", 0);
|
||||||
if (client->pagecache > QEMU_NFS_MAX_PAGECACHE_SIZE) {
|
if (client->pagecache > QEMU_NFS_MAX_PAGECACHE_SIZE) {
|
||||||
error_report("NFS Warning: Truncating NFS pagecache "
|
error_report("NFS Warning: Truncating NFS pagecache "
|
||||||
"size to %d pages", QEMU_NFS_MAX_PAGECACHE_SIZE);
|
"size to %d pages", QEMU_NFS_MAX_PAGECACHE_SIZE);
|
||||||
|
@ -802,22 +803,22 @@ static void nfs_refresh_filename(BlockDriverState *bs, QDict *options)
|
||||||
qdict_put(opts, "path", qstring_from_str(client->path));
|
qdict_put(opts, "path", qstring_from_str(client->path));
|
||||||
|
|
||||||
if (client->uid) {
|
if (client->uid) {
|
||||||
qdict_put(opts, "uid", qint_from_int(client->uid));
|
qdict_put(opts, "user", qint_from_int(client->uid));
|
||||||
}
|
}
|
||||||
if (client->gid) {
|
if (client->gid) {
|
||||||
qdict_put(opts, "gid", qint_from_int(client->gid));
|
qdict_put(opts, "group", qint_from_int(client->gid));
|
||||||
}
|
}
|
||||||
if (client->tcp_syncnt) {
|
if (client->tcp_syncnt) {
|
||||||
qdict_put(opts, "tcp-syncnt",
|
qdict_put(opts, "tcp-syn-cnt",
|
||||||
qint_from_int(client->tcp_syncnt));
|
qint_from_int(client->tcp_syncnt));
|
||||||
}
|
}
|
||||||
if (client->readahead) {
|
if (client->readahead) {
|
||||||
qdict_put(opts, "readahead",
|
qdict_put(opts, "readahead-size",
|
||||||
qint_from_int(client->readahead));
|
qint_from_int(client->readahead));
|
||||||
}
|
}
|
||||||
if (client->pagecache) {
|
if (client->pagecache) {
|
||||||
qdict_put(opts, "pagecache",
|
qdict_put(opts, "page-cache-size",
|
||||||
qint_from_int(client->pagecache));
|
qint_from_int(client->pagecache));
|
||||||
}
|
}
|
||||||
if (client->debug) {
|
if (client->debug) {
|
||||||
qdict_put(opts, "debug", qint_from_int(client->debug));
|
qdict_put(opts, "debug", qint_from_int(client->debug));
|
||||||
|
|
|
@ -1354,8 +1354,8 @@ static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
data->lba = offset >> BDRV_SECTOR_BITS;
|
data->lba = cpu_to_le64(offset >> BDRV_SECTOR_BITS);
|
||||||
data->size = buf_len;
|
data->size = cpu_to_le32(buf_len);
|
||||||
|
|
||||||
n_bytes = buf_len + sizeof(VmdkGrainMarker);
|
n_bytes = buf_len + sizeof(VmdkGrainMarker);
|
||||||
iov = (struct iovec) {
|
iov = (struct iovec) {
|
||||||
|
|
|
@ -491,7 +491,7 @@ static inline void cpu_handle_interrupt(CPUState *cpu,
|
||||||
X86CPU *x86_cpu = X86_CPU(cpu);
|
X86CPU *x86_cpu = X86_CPU(cpu);
|
||||||
CPUArchState *env = &x86_cpu->env;
|
CPUArchState *env = &x86_cpu->env;
|
||||||
replay_interrupt();
|
replay_interrupt();
|
||||||
cpu_svm_check_intercept_param(env, SVM_EXIT_INIT, 0);
|
cpu_svm_check_intercept_param(env, SVM_EXIT_INIT, 0, 0);
|
||||||
do_cpu_init(x86_cpu);
|
do_cpu_init(x86_cpu);
|
||||||
cpu->exception_index = EXCP_HALTED;
|
cpu->exception_index = EXCP_HALTED;
|
||||||
cpu_loop_exit(cpu);
|
cpu_loop_exit(cpu);
|
||||||
|
@ -542,7 +542,7 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
|
||||||
|
|
||||||
trace_exec_tb(tb, tb->pc);
|
trace_exec_tb(tb, tb->pc);
|
||||||
ret = cpu_tb_exec(cpu, tb);
|
ret = cpu_tb_exec(cpu, tb);
|
||||||
*last_tb = (TranslationBlock *)(ret & ~TB_EXIT_MASK);
|
tb = (TranslationBlock *)(ret & ~TB_EXIT_MASK);
|
||||||
*tb_exit = ret & TB_EXIT_MASK;
|
*tb_exit = ret & TB_EXIT_MASK;
|
||||||
switch (*tb_exit) {
|
switch (*tb_exit) {
|
||||||
case TB_EXIT_REQUESTED:
|
case TB_EXIT_REQUESTED:
|
||||||
|
@ -566,6 +566,7 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
|
||||||
abort();
|
abort();
|
||||||
#else
|
#else
|
||||||
int insns_left = cpu->icount_decr.u32;
|
int insns_left = cpu->icount_decr.u32;
|
||||||
|
*last_tb = NULL;
|
||||||
if (cpu->icount_extra && insns_left >= 0) {
|
if (cpu->icount_extra && insns_left >= 0) {
|
||||||
/* Refill decrementer and continue execution. */
|
/* Refill decrementer and continue execution. */
|
||||||
cpu->icount_extra += insns_left;
|
cpu->icount_extra += insns_left;
|
||||||
|
@ -575,17 +576,17 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
|
||||||
} else {
|
} else {
|
||||||
if (insns_left > 0) {
|
if (insns_left > 0) {
|
||||||
/* Execute remaining instructions. */
|
/* Execute remaining instructions. */
|
||||||
cpu_exec_nocache(cpu, insns_left, *last_tb, false);
|
cpu_exec_nocache(cpu, insns_left, tb, false);
|
||||||
align_clocks(sc, cpu);
|
align_clocks(sc, cpu);
|
||||||
}
|
}
|
||||||
cpu->exception_index = EXCP_INTERRUPT;
|
cpu->exception_index = EXCP_INTERRUPT;
|
||||||
*last_tb = NULL;
|
|
||||||
cpu_loop_exit(cpu);
|
cpu_loop_exit(cpu);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
*last_tb = tb;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
1
exec.c
1
exec.c
|
@ -2927,6 +2927,7 @@ bool address_space_access_valid(AddressSpace *as, hwaddr addr, int len, bool is_
|
||||||
if (!memory_access_is_direct(mr, is_write)) {
|
if (!memory_access_is_direct(mr, is_write)) {
|
||||||
l = memory_access_size(mr, l, addr);
|
l = memory_access_size(mr, l, addr);
|
||||||
if (!memory_region_access_valid(mr, xlat, l, is_write)) {
|
if (!memory_region_access_valid(mr, xlat, l, is_write)) {
|
||||||
|
rcu_read_unlock();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
6
hmp.c
6
hmp.c
|
@ -1551,6 +1551,7 @@ void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict)
|
||||||
{
|
{
|
||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
BlockIOThrottle throttle = {
|
BlockIOThrottle throttle = {
|
||||||
|
.has_device = true,
|
||||||
.device = (char *) qdict_get_str(qdict, "device"),
|
.device = (char *) qdict_get_str(qdict, "device"),
|
||||||
.bps = qdict_get_int(qdict, "bps"),
|
.bps = qdict_get_int(qdict, "bps"),
|
||||||
.bps_rd = qdict_get_int(qdict, "bps_rd"),
|
.bps_rd = qdict_get_int(qdict, "bps_rd"),
|
||||||
|
@ -1808,7 +1809,6 @@ void hmp_object_add(Monitor *mon, const QDict *qdict)
|
||||||
{
|
{
|
||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
QemuOpts *opts;
|
QemuOpts *opts;
|
||||||
Visitor *v;
|
|
||||||
Object *obj = NULL;
|
Object *obj = NULL;
|
||||||
|
|
||||||
opts = qemu_opts_from_qdict(qemu_find_opts("object"), qdict, &err);
|
opts = qemu_opts_from_qdict(qemu_find_opts("object"), qdict, &err);
|
||||||
|
@ -1817,9 +1817,7 @@ void hmp_object_add(Monitor *mon, const QDict *qdict)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
v = opts_visitor_new(opts);
|
obj = user_creatable_add_opts(opts, &err);
|
||||||
obj = user_creatable_add(qdict, v, &err);
|
|
||||||
visit_free(v);
|
|
||||||
qemu_opts_del(opts);
|
qemu_opts_del(opts);
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|
1040
hw/9pfs/9p-local.c
1040
hw/9pfs/9p-local.c
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* 9p local backend utilities
|
||||||
|
*
|
||||||
|
* Copyright IBM, Corp. 2017
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Greg Kurz <groug@kaod.org>
|
||||||
|
*
|
||||||
|
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||||
|
* See the COPYING file in the top-level directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef QEMU_9P_LOCAL_H
|
||||||
|
#define QEMU_9P_LOCAL_H
|
||||||
|
|
||||||
|
int local_open_nofollow(FsContext *fs_ctx, const char *path, int flags,
|
||||||
|
mode_t mode);
|
||||||
|
int local_opendir_nofollow(FsContext *fs_ctx, const char *path);
|
||||||
|
|
||||||
|
#endif
|
|
@ -25,13 +25,7 @@
|
||||||
static ssize_t mp_pacl_getxattr(FsContext *ctx, const char *path,
|
static ssize_t mp_pacl_getxattr(FsContext *ctx, const char *path,
|
||||||
const char *name, void *value, size_t size)
|
const char *name, void *value, size_t size)
|
||||||
{
|
{
|
||||||
char *buffer;
|
return local_getxattr_nofollow(ctx, path, MAP_ACL_ACCESS, value, size);
|
||||||
ssize_t ret;
|
|
||||||
|
|
||||||
buffer = rpath(ctx, path);
|
|
||||||
ret = lgetxattr(buffer, MAP_ACL_ACCESS, value, size);
|
|
||||||
g_free(buffer);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t mp_pacl_listxattr(FsContext *ctx, const char *path,
|
static ssize_t mp_pacl_listxattr(FsContext *ctx, const char *path,
|
||||||
|
@ -56,23 +50,16 @@ static ssize_t mp_pacl_listxattr(FsContext *ctx, const char *path,
|
||||||
static int mp_pacl_setxattr(FsContext *ctx, const char *path, const char *name,
|
static int mp_pacl_setxattr(FsContext *ctx, const char *path, const char *name,
|
||||||
void *value, size_t size, int flags)
|
void *value, size_t size, int flags)
|
||||||
{
|
{
|
||||||
char *buffer;
|
return local_setxattr_nofollow(ctx, path, MAP_ACL_ACCESS, value, size,
|
||||||
int ret;
|
flags);
|
||||||
|
|
||||||
buffer = rpath(ctx, path);
|
|
||||||
ret = lsetxattr(buffer, MAP_ACL_ACCESS, value, size, flags);
|
|
||||||
g_free(buffer);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mp_pacl_removexattr(FsContext *ctx,
|
static int mp_pacl_removexattr(FsContext *ctx,
|
||||||
const char *path, const char *name)
|
const char *path, const char *name)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
char *buffer;
|
|
||||||
|
|
||||||
buffer = rpath(ctx, path);
|
ret = local_removexattr_nofollow(ctx, path, MAP_ACL_ACCESS);
|
||||||
ret = lremovexattr(buffer, MAP_ACL_ACCESS);
|
|
||||||
if (ret == -1 && errno == ENODATA) {
|
if (ret == -1 && errno == ENODATA) {
|
||||||
/*
|
/*
|
||||||
* We don't get ENODATA error when trying to remove a
|
* We don't get ENODATA error when trying to remove a
|
||||||
|
@ -82,20 +69,13 @@ static int mp_pacl_removexattr(FsContext *ctx,
|
||||||
errno = 0;
|
errno = 0;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
g_free(buffer);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t mp_dacl_getxattr(FsContext *ctx, const char *path,
|
static ssize_t mp_dacl_getxattr(FsContext *ctx, const char *path,
|
||||||
const char *name, void *value, size_t size)
|
const char *name, void *value, size_t size)
|
||||||
{
|
{
|
||||||
char *buffer;
|
return local_getxattr_nofollow(ctx, path, MAP_ACL_DEFAULT, value, size);
|
||||||
ssize_t ret;
|
|
||||||
|
|
||||||
buffer = rpath(ctx, path);
|
|
||||||
ret = lgetxattr(buffer, MAP_ACL_DEFAULT, value, size);
|
|
||||||
g_free(buffer);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t mp_dacl_listxattr(FsContext *ctx, const char *path,
|
static ssize_t mp_dacl_listxattr(FsContext *ctx, const char *path,
|
||||||
|
@ -120,23 +100,16 @@ static ssize_t mp_dacl_listxattr(FsContext *ctx, const char *path,
|
||||||
static int mp_dacl_setxattr(FsContext *ctx, const char *path, const char *name,
|
static int mp_dacl_setxattr(FsContext *ctx, const char *path, const char *name,
|
||||||
void *value, size_t size, int flags)
|
void *value, size_t size, int flags)
|
||||||
{
|
{
|
||||||
char *buffer;
|
return local_setxattr_nofollow(ctx, path, MAP_ACL_DEFAULT, value, size,
|
||||||
int ret;
|
flags);
|
||||||
|
|
||||||
buffer = rpath(ctx, path);
|
|
||||||
ret = lsetxattr(buffer, MAP_ACL_DEFAULT, value, size, flags);
|
|
||||||
g_free(buffer);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mp_dacl_removexattr(FsContext *ctx,
|
static int mp_dacl_removexattr(FsContext *ctx,
|
||||||
const char *path, const char *name)
|
const char *path, const char *name)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
char *buffer;
|
|
||||||
|
|
||||||
buffer = rpath(ctx, path);
|
ret = local_removexattr_nofollow(ctx, path, MAP_ACL_DEFAULT);
|
||||||
ret = lremovexattr(buffer, MAP_ACL_DEFAULT);
|
|
||||||
if (ret == -1 && errno == ENODATA) {
|
if (ret == -1 && errno == ENODATA) {
|
||||||
/*
|
/*
|
||||||
* We don't get ENODATA error when trying to remove a
|
* We don't get ENODATA error when trying to remove a
|
||||||
|
@ -146,7 +119,6 @@ static int mp_dacl_removexattr(FsContext *ctx,
|
||||||
errno = 0;
|
errno = 0;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
g_free(buffer);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
* 9p utilities
|
||||||
|
*
|
||||||
|
* Copyright IBM, Corp. 2017
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Greg Kurz <groug@kaod.org>
|
||||||
|
*
|
||||||
|
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||||
|
* See the COPYING file in the top-level directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
#include "qemu/xattr.h"
|
||||||
|
#include "9p-util.h"
|
||||||
|
|
||||||
|
int relative_openat_nofollow(int dirfd, const char *path, int flags,
|
||||||
|
mode_t mode)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = dup(dirfd);
|
||||||
|
if (fd == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (*path) {
|
||||||
|
const char *c;
|
||||||
|
int next_fd;
|
||||||
|
char *head;
|
||||||
|
|
||||||
|
/* Only relative paths without consecutive slashes */
|
||||||
|
assert(path[0] != '/');
|
||||||
|
|
||||||
|
head = g_strdup(path);
|
||||||
|
c = strchr(path, '/');
|
||||||
|
if (c) {
|
||||||
|
head[c - path] = 0;
|
||||||
|
next_fd = openat_dir(fd, head);
|
||||||
|
} else {
|
||||||
|
next_fd = openat_file(fd, head, flags, mode);
|
||||||
|
}
|
||||||
|
g_free(head);
|
||||||
|
if (next_fd == -1) {
|
||||||
|
close_preserve_errno(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
fd = next_fd;
|
||||||
|
|
||||||
|
if (!c) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
path = c + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t fgetxattrat_nofollow(int dirfd, const char *filename, const char *name,
|
||||||
|
void *value, size_t size)
|
||||||
|
{
|
||||||
|
char *proc_path = g_strdup_printf("/proc/self/fd/%d/%s", dirfd, filename);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = lgetxattr(proc_path, name, value, size);
|
||||||
|
g_free(proc_path);
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* 9p utilities
|
||||||
|
*
|
||||||
|
* Copyright IBM, Corp. 2017
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Greg Kurz <groug@kaod.org>
|
||||||
|
*
|
||||||
|
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||||
|
* See the COPYING file in the top-level directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef QEMU_9P_UTIL_H
|
||||||
|
#define QEMU_9P_UTIL_H
|
||||||
|
|
||||||
|
static inline void close_preserve_errno(int fd)
|
||||||
|
{
|
||||||
|
int serrno = errno;
|
||||||
|
close(fd);
|
||||||
|
errno = serrno;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int openat_dir(int dirfd, const char *name)
|
||||||
|
{
|
||||||
|
#ifdef O_PATH
|
||||||
|
#define OPENAT_DIR_O_PATH O_PATH
|
||||||
|
#else
|
||||||
|
#define OPENAT_DIR_O_PATH 0
|
||||||
|
#endif
|
||||||
|
return openat(dirfd, name,
|
||||||
|
O_DIRECTORY | O_RDONLY | O_NOFOLLOW | OPENAT_DIR_O_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int openat_file(int dirfd, const char *name, int flags,
|
||||||
|
mode_t mode)
|
||||||
|
{
|
||||||
|
int fd, serrno, ret;
|
||||||
|
|
||||||
|
fd = openat(dirfd, name, flags | O_NOFOLLOW | O_NOCTTY | O_NONBLOCK,
|
||||||
|
mode);
|
||||||
|
if (fd == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
serrno = errno;
|
||||||
|
/* O_NONBLOCK was only needed to open the file. Let's drop it. */
|
||||||
|
ret = fcntl(fd, F_SETFL, flags);
|
||||||
|
assert(!ret);
|
||||||
|
errno = serrno;
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
int relative_openat_nofollow(int dirfd, const char *path, int flags,
|
||||||
|
mode_t mode);
|
||||||
|
ssize_t fgetxattrat_nofollow(int dirfd, const char *path, const char *name,
|
||||||
|
void *value, size_t size);
|
||||||
|
int fsetxattrat_nofollow(int dirfd, const char *path, const char *name,
|
||||||
|
void *value, size_t size, int flags);
|
||||||
|
|
||||||
|
#endif
|
|
@ -20,9 +20,6 @@
|
||||||
static ssize_t mp_user_getxattr(FsContext *ctx, const char *path,
|
static ssize_t mp_user_getxattr(FsContext *ctx, const char *path,
|
||||||
const char *name, void *value, size_t size)
|
const char *name, void *value, size_t size)
|
||||||
{
|
{
|
||||||
char *buffer;
|
|
||||||
ssize_t ret;
|
|
||||||
|
|
||||||
if (strncmp(name, "user.virtfs.", 12) == 0) {
|
if (strncmp(name, "user.virtfs.", 12) == 0) {
|
||||||
/*
|
/*
|
||||||
* Don't allow fetch of user.virtfs namesapce
|
* Don't allow fetch of user.virtfs namesapce
|
||||||
|
@ -31,10 +28,7 @@ static ssize_t mp_user_getxattr(FsContext *ctx, const char *path,
|
||||||
errno = ENOATTR;
|
errno = ENOATTR;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
buffer = rpath(ctx, path);
|
return local_getxattr_nofollow(ctx, path, name, value, size);
|
||||||
ret = lgetxattr(buffer, name, value, size);
|
|
||||||
g_free(buffer);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t mp_user_listxattr(FsContext *ctx, const char *path,
|
static ssize_t mp_user_listxattr(FsContext *ctx, const char *path,
|
||||||
|
@ -73,9 +67,6 @@ static ssize_t mp_user_listxattr(FsContext *ctx, const char *path,
|
||||||
static int mp_user_setxattr(FsContext *ctx, const char *path, const char *name,
|
static int mp_user_setxattr(FsContext *ctx, const char *path, const char *name,
|
||||||
void *value, size_t size, int flags)
|
void *value, size_t size, int flags)
|
||||||
{
|
{
|
||||||
char *buffer;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (strncmp(name, "user.virtfs.", 12) == 0) {
|
if (strncmp(name, "user.virtfs.", 12) == 0) {
|
||||||
/*
|
/*
|
||||||
* Don't allow fetch of user.virtfs namesapce
|
* Don't allow fetch of user.virtfs namesapce
|
||||||
|
@ -84,18 +75,12 @@ static int mp_user_setxattr(FsContext *ctx, const char *path, const char *name,
|
||||||
errno = EACCES;
|
errno = EACCES;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
buffer = rpath(ctx, path);
|
return local_setxattr_nofollow(ctx, path, name, value, size, flags);
|
||||||
ret = lsetxattr(buffer, name, value, size, flags);
|
|
||||||
g_free(buffer);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mp_user_removexattr(FsContext *ctx,
|
static int mp_user_removexattr(FsContext *ctx,
|
||||||
const char *path, const char *name)
|
const char *path, const char *name)
|
||||||
{
|
{
|
||||||
char *buffer;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (strncmp(name, "user.virtfs.", 12) == 0) {
|
if (strncmp(name, "user.virtfs.", 12) == 0) {
|
||||||
/*
|
/*
|
||||||
* Don't allow fetch of user.virtfs namesapce
|
* Don't allow fetch of user.virtfs namesapce
|
||||||
|
@ -104,10 +89,7 @@ static int mp_user_removexattr(FsContext *ctx,
|
||||||
errno = EACCES;
|
errno = EACCES;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
buffer = rpath(ctx, path);
|
return local_removexattr_nofollow(ctx, path, name);
|
||||||
ret = lremovexattr(buffer, name);
|
|
||||||
g_free(buffer);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
XattrOperations mapped_user_xattr = {
|
XattrOperations mapped_user_xattr = {
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
#include "9p.h"
|
#include "9p.h"
|
||||||
#include "fsdev/file-op-9p.h"
|
#include "fsdev/file-op-9p.h"
|
||||||
#include "9p-xattr.h"
|
#include "9p-xattr.h"
|
||||||
|
#include "9p-util.h"
|
||||||
|
#include "9p-local.h"
|
||||||
|
|
||||||
|
|
||||||
static XattrOperations *get_xattr_operations(XattrOperations **h,
|
static XattrOperations *get_xattr_operations(XattrOperations **h,
|
||||||
|
@ -58,6 +60,16 @@ ssize_t pt_listxattr(FsContext *ctx, const char *path,
|
||||||
return name_size;
|
return name_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ssize_t flistxattrat_nofollow(int dirfd, const char *filename,
|
||||||
|
char *list, size_t size)
|
||||||
|
{
|
||||||
|
char *proc_path = g_strdup_printf("/proc/self/fd/%d/%s", dirfd, filename);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = llistxattr(proc_path, list, size);
|
||||||
|
g_free(proc_path);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the list and pass to each layer to find out whether
|
* Get the list and pass to each layer to find out whether
|
||||||
|
@ -67,24 +79,37 @@ ssize_t v9fs_list_xattr(FsContext *ctx, const char *path,
|
||||||
void *value, size_t vsize)
|
void *value, size_t vsize)
|
||||||
{
|
{
|
||||||
ssize_t size = 0;
|
ssize_t size = 0;
|
||||||
char *buffer;
|
|
||||||
void *ovalue = value;
|
void *ovalue = value;
|
||||||
XattrOperations *xops;
|
XattrOperations *xops;
|
||||||
char *orig_value, *orig_value_start;
|
char *orig_value, *orig_value_start;
|
||||||
ssize_t xattr_len, parsed_len = 0, attr_len;
|
ssize_t xattr_len, parsed_len = 0, attr_len;
|
||||||
|
char *dirpath, *name;
|
||||||
|
int dirfd;
|
||||||
|
|
||||||
/* Get the actual len */
|
/* Get the actual len */
|
||||||
buffer = rpath(ctx, path);
|
dirpath = g_path_get_dirname(path);
|
||||||
xattr_len = llistxattr(buffer, value, 0);
|
dirfd = local_opendir_nofollow(ctx, dirpath);
|
||||||
|
g_free(dirpath);
|
||||||
|
if (dirfd == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
name = g_path_get_basename(path);
|
||||||
|
xattr_len = flistxattrat_nofollow(dirfd, name, value, 0);
|
||||||
if (xattr_len <= 0) {
|
if (xattr_len <= 0) {
|
||||||
g_free(buffer);
|
g_free(name);
|
||||||
|
close_preserve_errno(dirfd);
|
||||||
return xattr_len;
|
return xattr_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now fetch the xattr and find the actual size */
|
/* Now fetch the xattr and find the actual size */
|
||||||
orig_value = g_malloc(xattr_len);
|
orig_value = g_malloc(xattr_len);
|
||||||
xattr_len = llistxattr(buffer, orig_value, xattr_len);
|
xattr_len = flistxattrat_nofollow(dirfd, name, orig_value, xattr_len);
|
||||||
g_free(buffer);
|
g_free(name);
|
||||||
|
close_preserve_errno(dirfd);
|
||||||
|
if (xattr_len < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* store the orig pointer */
|
/* store the orig pointer */
|
||||||
orig_value_start = orig_value;
|
orig_value_start = orig_value;
|
||||||
|
@ -143,6 +168,135 @@ int v9fs_remove_xattr(FsContext *ctx,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t local_getxattr_nofollow(FsContext *ctx, const char *path,
|
||||||
|
const char *name, void *value, size_t size)
|
||||||
|
{
|
||||||
|
char *dirpath = g_path_get_dirname(path);
|
||||||
|
char *filename = g_path_get_basename(path);
|
||||||
|
int dirfd;
|
||||||
|
ssize_t ret = -1;
|
||||||
|
|
||||||
|
dirfd = local_opendir_nofollow(ctx, dirpath);
|
||||||
|
if (dirfd == -1) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = fgetxattrat_nofollow(dirfd, filename, name, value, size);
|
||||||
|
close_preserve_errno(dirfd);
|
||||||
|
out:
|
||||||
|
g_free(dirpath);
|
||||||
|
g_free(filename);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t pt_getxattr(FsContext *ctx, const char *path, const char *name,
|
||||||
|
void *value, size_t size)
|
||||||
|
{
|
||||||
|
return local_getxattr_nofollow(ctx, path, name, value, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fsetxattrat_nofollow(int dirfd, const char *filename, const char *name,
|
||||||
|
void *value, size_t size, int flags)
|
||||||
|
{
|
||||||
|
char *proc_path = g_strdup_printf("/proc/self/fd/%d/%s", dirfd, filename);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = lsetxattr(proc_path, name, value, size, flags);
|
||||||
|
g_free(proc_path);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t local_setxattr_nofollow(FsContext *ctx, const char *path,
|
||||||
|
const char *name, void *value, size_t size,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
char *dirpath = g_path_get_dirname(path);
|
||||||
|
char *filename = g_path_get_basename(path);
|
||||||
|
int dirfd;
|
||||||
|
ssize_t ret = -1;
|
||||||
|
|
||||||
|
dirfd = local_opendir_nofollow(ctx, dirpath);
|
||||||
|
if (dirfd == -1) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = fsetxattrat_nofollow(dirfd, filename, name, value, size, flags);
|
||||||
|
close_preserve_errno(dirfd);
|
||||||
|
out:
|
||||||
|
g_free(dirpath);
|
||||||
|
g_free(filename);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pt_setxattr(FsContext *ctx, const char *path, const char *name, void *value,
|
||||||
|
size_t size, int flags)
|
||||||
|
{
|
||||||
|
return local_setxattr_nofollow(ctx, path, name, value, size, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t fremovexattrat_nofollow(int dirfd, const char *filename,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
char *proc_path = g_strdup_printf("/proc/self/fd/%d/%s", dirfd, filename);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = lremovexattr(proc_path, name);
|
||||||
|
g_free(proc_path);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t local_removexattr_nofollow(FsContext *ctx, const char *path,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
char *dirpath = g_path_get_dirname(path);
|
||||||
|
char *filename = g_path_get_basename(path);
|
||||||
|
int dirfd;
|
||||||
|
ssize_t ret = -1;
|
||||||
|
|
||||||
|
dirfd = local_opendir_nofollow(ctx, dirpath);
|
||||||
|
if (dirfd == -1) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = fremovexattrat_nofollow(dirfd, filename, name);
|
||||||
|
close_preserve_errno(dirfd);
|
||||||
|
out:
|
||||||
|
g_free(dirpath);
|
||||||
|
g_free(filename);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pt_removexattr(FsContext *ctx, const char *path, const char *name)
|
||||||
|
{
|
||||||
|
return local_removexattr_nofollow(ctx, path, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t notsup_getxattr(FsContext *ctx, const char *path, const char *name,
|
||||||
|
void *value, size_t size)
|
||||||
|
{
|
||||||
|
errno = ENOTSUP;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int notsup_setxattr(FsContext *ctx, const char *path, const char *name,
|
||||||
|
void *value, size_t size, int flags)
|
||||||
|
{
|
||||||
|
errno = ENOTSUP;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t notsup_listxattr(FsContext *ctx, const char *path, char *name,
|
||||||
|
void *value, size_t size)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int notsup_removexattr(FsContext *ctx, const char *path, const char *name)
|
||||||
|
{
|
||||||
|
errno = ENOTSUP;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
XattrOperations *mapped_xattr_ops[] = {
|
XattrOperations *mapped_xattr_ops[] = {
|
||||||
&mapped_user_xattr,
|
&mapped_user_xattr,
|
||||||
&mapped_pacl_xattr,
|
&mapped_pacl_xattr,
|
||||||
|
|
|
@ -29,6 +29,13 @@ typedef struct xattr_operations
|
||||||
const char *path, const char *name);
|
const char *path, const char *name);
|
||||||
} XattrOperations;
|
} XattrOperations;
|
||||||
|
|
||||||
|
ssize_t local_getxattr_nofollow(FsContext *ctx, const char *path,
|
||||||
|
const char *name, void *value, size_t size);
|
||||||
|
ssize_t local_setxattr_nofollow(FsContext *ctx, const char *path,
|
||||||
|
const char *name, void *value, size_t size,
|
||||||
|
int flags);
|
||||||
|
ssize_t local_removexattr_nofollow(FsContext *ctx, const char *path,
|
||||||
|
const char *name);
|
||||||
|
|
||||||
extern XattrOperations mapped_user_xattr;
|
extern XattrOperations mapped_user_xattr;
|
||||||
extern XattrOperations passthrough_user_xattr;
|
extern XattrOperations passthrough_user_xattr;
|
||||||
|
@ -49,73 +56,21 @@ ssize_t v9fs_list_xattr(FsContext *ctx, const char *path, void *value,
|
||||||
int v9fs_set_xattr(FsContext *ctx, const char *path, const char *name,
|
int v9fs_set_xattr(FsContext *ctx, const char *path, const char *name,
|
||||||
void *value, size_t size, int flags);
|
void *value, size_t size, int flags);
|
||||||
int v9fs_remove_xattr(FsContext *ctx, const char *path, const char *name);
|
int v9fs_remove_xattr(FsContext *ctx, const char *path, const char *name);
|
||||||
|
|
||||||
ssize_t pt_listxattr(FsContext *ctx, const char *path, char *name, void *value,
|
ssize_t pt_listxattr(FsContext *ctx, const char *path, char *name, void *value,
|
||||||
size_t size);
|
size_t size);
|
||||||
|
ssize_t pt_getxattr(FsContext *ctx, const char *path, const char *name,
|
||||||
|
void *value, size_t size);
|
||||||
|
int pt_setxattr(FsContext *ctx, const char *path, const char *name, void *value,
|
||||||
|
size_t size, int flags);
|
||||||
|
int pt_removexattr(FsContext *ctx, const char *path, const char *name);
|
||||||
|
|
||||||
static inline ssize_t pt_getxattr(FsContext *ctx, const char *path,
|
ssize_t notsup_getxattr(FsContext *ctx, const char *path, const char *name,
|
||||||
const char *name, void *value, size_t size)
|
void *value, size_t size);
|
||||||
{
|
int notsup_setxattr(FsContext *ctx, const char *path, const char *name,
|
||||||
char *buffer;
|
void *value, size_t size, int flags);
|
||||||
ssize_t ret;
|
ssize_t notsup_listxattr(FsContext *ctx, const char *path, char *name,
|
||||||
|
void *value, size_t size);
|
||||||
buffer = rpath(ctx, path);
|
int notsup_removexattr(FsContext *ctx, const char *path, const char *name);
|
||||||
ret = lgetxattr(buffer, name, value, size);
|
|
||||||
g_free(buffer);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int pt_setxattr(FsContext *ctx, const char *path,
|
|
||||||
const char *name, void *value,
|
|
||||||
size_t size, int flags)
|
|
||||||
{
|
|
||||||
char *buffer;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
buffer = rpath(ctx, path);
|
|
||||||
ret = lsetxattr(buffer, name, value, size, flags);
|
|
||||||
g_free(buffer);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int pt_removexattr(FsContext *ctx,
|
|
||||||
const char *path, const char *name)
|
|
||||||
{
|
|
||||||
char *buffer;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
buffer = rpath(ctx, path);
|
|
||||||
ret = lremovexattr(path, name);
|
|
||||||
g_free(buffer);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline ssize_t notsup_getxattr(FsContext *ctx, const char *path,
|
|
||||||
const char *name, void *value,
|
|
||||||
size_t size)
|
|
||||||
{
|
|
||||||
errno = ENOTSUP;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int notsup_setxattr(FsContext *ctx, const char *path,
|
|
||||||
const char *name, void *value,
|
|
||||||
size_t size, int flags)
|
|
||||||
{
|
|
||||||
errno = ENOTSUP;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline ssize_t notsup_listxattr(FsContext *ctx, const char *path,
|
|
||||||
char *name, void *value, size_t size)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int notsup_removexattr(FsContext *ctx,
|
|
||||||
const char *path, const char *name)
|
|
||||||
{
|
|
||||||
errno = ENOTSUP;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
16
hw/9pfs/9p.c
16
hw/9pfs/9p.c
|
@ -2337,7 +2337,7 @@ static void v9fs_flush(void *opaque)
|
||||||
ssize_t err;
|
ssize_t err;
|
||||||
int16_t tag;
|
int16_t tag;
|
||||||
size_t offset = 7;
|
size_t offset = 7;
|
||||||
V9fsPDU *cancel_pdu;
|
V9fsPDU *cancel_pdu = NULL;
|
||||||
V9fsPDU *pdu = opaque;
|
V9fsPDU *pdu = opaque;
|
||||||
V9fsState *s = pdu->s;
|
V9fsState *s = pdu->s;
|
||||||
|
|
||||||
|
@ -2348,9 +2348,13 @@ static void v9fs_flush(void *opaque)
|
||||||
}
|
}
|
||||||
trace_v9fs_flush(pdu->tag, pdu->id, tag);
|
trace_v9fs_flush(pdu->tag, pdu->id, tag);
|
||||||
|
|
||||||
QLIST_FOREACH(cancel_pdu, &s->active_list, next) {
|
if (pdu->tag == tag) {
|
||||||
if (cancel_pdu->tag == tag) {
|
error_report("Warning: the guest sent a self-referencing 9P flush request");
|
||||||
break;
|
} else {
|
||||||
|
QLIST_FOREACH(cancel_pdu, &s->active_list, next) {
|
||||||
|
if (cancel_pdu->tag == tag) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (cancel_pdu) {
|
if (cancel_pdu) {
|
||||||
|
@ -3450,7 +3454,7 @@ int v9fs_device_realize_common(V9fsState *s, Error **errp)
|
||||||
/* initialize pdu allocator */
|
/* initialize pdu allocator */
|
||||||
QLIST_INIT(&s->free_list);
|
QLIST_INIT(&s->free_list);
|
||||||
QLIST_INIT(&s->active_list);
|
QLIST_INIT(&s->active_list);
|
||||||
for (i = 0; i < (MAX_REQ - 1); i++) {
|
for (i = 0; i < MAX_REQ; i++) {
|
||||||
QLIST_INSERT_HEAD(&s->free_list, &v->pdus[i], next);
|
QLIST_INSERT_HEAD(&s->free_list, &v->pdus[i], next);
|
||||||
v->pdus[i].s = s;
|
v->pdus[i].s = s;
|
||||||
v->pdus[i].idx = i;
|
v->pdus[i].idx = i;
|
||||||
|
@ -3521,7 +3525,7 @@ int v9fs_device_realize_common(V9fsState *s, Error **errp)
|
||||||
rc = 0;
|
rc = 0;
|
||||||
out:
|
out:
|
||||||
if (rc) {
|
if (rc) {
|
||||||
if (s->ops->cleanup && s->ctx.private) {
|
if (s->ops && s->ops->cleanup && s->ctx.private) {
|
||||||
s->ops->cleanup(&s->ctx);
|
s->ops->cleanup(&s->ctx);
|
||||||
}
|
}
|
||||||
g_free(s->tag);
|
g_free(s->tag);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
common-obj-y = 9p.o
|
common-obj-y = 9p.o 9p-util.o
|
||||||
common-obj-y += 9p-local.o 9p-xattr.o
|
common-obj-y += 9p-local.o 9p-xattr.o
|
||||||
common-obj-y += 9p-xattr-user.o 9p-posix-acl.o
|
common-obj-y += 9p-xattr-user.o 9p-posix-acl.o
|
||||||
common-obj-y += coth.o cofs.o codir.o cofile.o
|
common-obj-y += coth.o cofs.o codir.o cofile.o
|
||||||
|
|
|
@ -554,11 +554,31 @@ static void machine_class_finalize(ObjectClass *klass, void *data)
|
||||||
g_free(mc->name);
|
g_free(mc->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void register_compat_prop(const char *driver,
|
||||||
|
const char *property,
|
||||||
|
const char *value)
|
||||||
|
{
|
||||||
|
GlobalProperty *p = g_new0(GlobalProperty, 1);
|
||||||
|
/* Machine compat_props must never cause errors: */
|
||||||
|
p->errp = &error_abort;
|
||||||
|
p->driver = driver;
|
||||||
|
p->property = property;
|
||||||
|
p->value = value;
|
||||||
|
qdev_prop_register_global(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void machine_register_compat_for_subclass(ObjectClass *oc, void *opaque)
|
||||||
|
{
|
||||||
|
GlobalProperty *p = opaque;
|
||||||
|
register_compat_prop(object_class_get_name(oc), p->property, p->value);
|
||||||
|
}
|
||||||
|
|
||||||
void machine_register_compat_props(MachineState *machine)
|
void machine_register_compat_props(MachineState *machine)
|
||||||
{
|
{
|
||||||
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
MachineClass *mc = MACHINE_GET_CLASS(machine);
|
||||||
int i;
|
int i;
|
||||||
GlobalProperty *p;
|
GlobalProperty *p;
|
||||||
|
ObjectClass *oc;
|
||||||
|
|
||||||
if (!mc->compat_props) {
|
if (!mc->compat_props) {
|
||||||
return;
|
return;
|
||||||
|
@ -566,9 +586,22 @@ void machine_register_compat_props(MachineState *machine)
|
||||||
|
|
||||||
for (i = 0; i < mc->compat_props->len; i++) {
|
for (i = 0; i < mc->compat_props->len; i++) {
|
||||||
p = g_array_index(mc->compat_props, GlobalProperty *, i);
|
p = g_array_index(mc->compat_props, GlobalProperty *, i);
|
||||||
/* Machine compat_props must never cause errors: */
|
oc = object_class_by_name(p->driver);
|
||||||
p->errp = &error_abort;
|
if (oc && object_class_is_abstract(oc)) {
|
||||||
qdev_prop_register_global(p);
|
/* temporary hack to make sure we do not override
|
||||||
|
* globals set explicitly on -global: if an abstract class
|
||||||
|
* is on compat_props, register globals for all its
|
||||||
|
* non-abstract subtypes instead.
|
||||||
|
*
|
||||||
|
* This doesn't solve the problem for cases where
|
||||||
|
* a non-abstract typename mentioned on compat_props
|
||||||
|
* has subclasses, like spapr-pci-host-bridge.
|
||||||
|
*/
|
||||||
|
object_class_foreach(machine_register_compat_for_subclass,
|
||||||
|
p->driver, false, p);
|
||||||
|
} else {
|
||||||
|
register_compat_prop(p->driver, p->property, p->value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -177,11 +177,12 @@
|
||||||
|
|
||||||
struct CirrusVGAState;
|
struct CirrusVGAState;
|
||||||
typedef void (*cirrus_bitblt_rop_t) (struct CirrusVGAState *s,
|
typedef void (*cirrus_bitblt_rop_t) (struct CirrusVGAState *s,
|
||||||
uint8_t * dst, const uint8_t * src,
|
uint32_t dstaddr, uint32_t srcaddr,
|
||||||
int dstpitch, int srcpitch,
|
int dstpitch, int srcpitch,
|
||||||
int bltwidth, int bltheight);
|
int bltwidth, int bltheight);
|
||||||
typedef void (*cirrus_fill_t)(struct CirrusVGAState *s,
|
typedef void (*cirrus_fill_t)(struct CirrusVGAState *s,
|
||||||
uint8_t *dst, int dst_pitch, int width, int height);
|
uint32_t dstaddr, int dst_pitch,
|
||||||
|
int width, int height);
|
||||||
|
|
||||||
typedef struct CirrusVGAState {
|
typedef struct CirrusVGAState {
|
||||||
VGACommonState vga;
|
VGACommonState vga;
|
||||||
|
@ -277,10 +278,9 @@ static bool blit_region_is_unsafe(struct CirrusVGAState *s,
|
||||||
}
|
}
|
||||||
if (pitch < 0) {
|
if (pitch < 0) {
|
||||||
int64_t min = addr
|
int64_t min = addr
|
||||||
+ ((int64_t)s->cirrus_blt_height-1) * pitch;
|
+ ((int64_t)s->cirrus_blt_height - 1) * pitch
|
||||||
int32_t max = addr
|
- s->cirrus_blt_width;
|
||||||
+ s->cirrus_blt_width;
|
if (min < -1 || addr >= s->vga.vram_size) {
|
||||||
if (min < 0 || max > s->vga.vram_size) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -294,7 +294,7 @@ static bool blit_region_is_unsafe(struct CirrusVGAState *s,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool blit_is_unsafe(struct CirrusVGAState *s)
|
static bool blit_is_unsafe(struct CirrusVGAState *s, bool dst_only)
|
||||||
{
|
{
|
||||||
/* should be the case, see cirrus_bitblt_start */
|
/* should be the case, see cirrus_bitblt_start */
|
||||||
assert(s->cirrus_blt_width > 0);
|
assert(s->cirrus_blt_width > 0);
|
||||||
|
@ -305,11 +305,14 @@ static bool blit_is_unsafe(struct CirrusVGAState *s)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (blit_region_is_unsafe(s, s->cirrus_blt_dstpitch,
|
if (blit_region_is_unsafe(s, s->cirrus_blt_dstpitch,
|
||||||
s->cirrus_blt_dstaddr & s->cirrus_addr_mask)) {
|
s->cirrus_blt_dstaddr)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (dst_only) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (blit_region_is_unsafe(s, s->cirrus_blt_srcpitch,
|
if (blit_region_is_unsafe(s, s->cirrus_blt_srcpitch,
|
||||||
s->cirrus_blt_srcaddr & s->cirrus_addr_mask)) {
|
s->cirrus_blt_srcaddr)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,18 +320,57 @@ static bool blit_is_unsafe(struct CirrusVGAState *s)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cirrus_bitblt_rop_nop(CirrusVGAState *s,
|
static void cirrus_bitblt_rop_nop(CirrusVGAState *s,
|
||||||
uint8_t *dst,const uint8_t *src,
|
uint32_t dstaddr, uint32_t srcaddr,
|
||||||
int dstpitch,int srcpitch,
|
int dstpitch,int srcpitch,
|
||||||
int bltwidth,int bltheight)
|
int bltwidth,int bltheight)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cirrus_bitblt_fill_nop(CirrusVGAState *s,
|
static void cirrus_bitblt_fill_nop(CirrusVGAState *s,
|
||||||
uint8_t *dst,
|
uint32_t dstaddr,
|
||||||
int dstpitch, int bltwidth,int bltheight)
|
int dstpitch, int bltwidth,int bltheight)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline uint8_t cirrus_src(CirrusVGAState *s, uint32_t srcaddr)
|
||||||
|
{
|
||||||
|
if (s->cirrus_srccounter) {
|
||||||
|
/* cputovideo */
|
||||||
|
return s->cirrus_bltbuf[srcaddr & (CIRRUS_BLTBUFSIZE - 1)];
|
||||||
|
} else {
|
||||||
|
/* videotovideo */
|
||||||
|
return s->vga.vram_ptr[srcaddr & s->cirrus_addr_mask];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint16_t cirrus_src16(CirrusVGAState *s, uint32_t srcaddr)
|
||||||
|
{
|
||||||
|
uint16_t *src;
|
||||||
|
|
||||||
|
if (s->cirrus_srccounter) {
|
||||||
|
/* cputovideo */
|
||||||
|
src = (void *)&s->cirrus_bltbuf[srcaddr & (CIRRUS_BLTBUFSIZE - 1) & ~1];
|
||||||
|
} else {
|
||||||
|
/* videotovideo */
|
||||||
|
src = (void *)&s->vga.vram_ptr[srcaddr & s->cirrus_addr_mask & ~1];
|
||||||
|
}
|
||||||
|
return *src;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t cirrus_src32(CirrusVGAState *s, uint32_t srcaddr)
|
||||||
|
{
|
||||||
|
uint32_t *src;
|
||||||
|
|
||||||
|
if (s->cirrus_srccounter) {
|
||||||
|
/* cputovideo */
|
||||||
|
src = (void *)&s->cirrus_bltbuf[srcaddr & (CIRRUS_BLTBUFSIZE - 1) & ~3];
|
||||||
|
} else {
|
||||||
|
/* videotovideo */
|
||||||
|
src = (void *)&s->vga.vram_ptr[srcaddr & s->cirrus_addr_mask & ~3];
|
||||||
|
}
|
||||||
|
return *src;
|
||||||
|
}
|
||||||
|
|
||||||
#define ROP_NAME 0
|
#define ROP_NAME 0
|
||||||
#define ROP_FN(d, s) 0
|
#define ROP_FN(d, s) 0
|
||||||
#include "cirrus_vga_rop.h"
|
#include "cirrus_vga_rop.h"
|
||||||
|
@ -658,25 +700,51 @@ static void cirrus_invalidate_region(CirrusVGAState * s, int off_begin,
|
||||||
int off_cur;
|
int off_cur;
|
||||||
int off_cur_end;
|
int off_cur_end;
|
||||||
|
|
||||||
|
if (off_pitch < 0) {
|
||||||
|
off_begin -= bytesperline - 1;
|
||||||
|
}
|
||||||
|
|
||||||
for (y = 0; y < lines; y++) {
|
for (y = 0; y < lines; y++) {
|
||||||
off_cur = off_begin;
|
off_cur = off_begin;
|
||||||
off_cur_end = (off_cur + bytesperline) & s->cirrus_addr_mask;
|
off_cur_end = ((off_cur + bytesperline - 1) & s->cirrus_addr_mask) + 1;
|
||||||
|
assert(off_cur_end >= off_cur);
|
||||||
memory_region_set_dirty(&s->vga.vram, off_cur, off_cur_end - off_cur);
|
memory_region_set_dirty(&s->vga.vram, off_cur, off_cur_end - off_cur);
|
||||||
off_begin += off_pitch;
|
off_begin += off_pitch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s,
|
static int cirrus_bitblt_common_patterncopy(CirrusVGAState *s)
|
||||||
const uint8_t * src)
|
|
||||||
{
|
{
|
||||||
uint8_t *dst;
|
uint32_t patternsize;
|
||||||
|
bool videosrc = !s->cirrus_srccounter;
|
||||||
|
|
||||||
dst = s->vga.vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask);
|
if (videosrc) {
|
||||||
|
switch (s->vga.get_bpp(&s->vga)) {
|
||||||
|
case 8:
|
||||||
|
patternsize = 64;
|
||||||
|
break;
|
||||||
|
case 15:
|
||||||
|
case 16:
|
||||||
|
patternsize = 128;
|
||||||
|
break;
|
||||||
|
case 24:
|
||||||
|
case 32:
|
||||||
|
default:
|
||||||
|
patternsize = 256;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
s->cirrus_blt_srcaddr &= ~(patternsize - 1);
|
||||||
|
if (s->cirrus_blt_srcaddr + patternsize > s->vga.vram_size) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (blit_is_unsafe(s))
|
if (blit_is_unsafe(s, true)) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
(*s->cirrus_rop) (s, dst, src,
|
(*s->cirrus_rop) (s, s->cirrus_blt_dstaddr,
|
||||||
|
videosrc ? s->cirrus_blt_srcaddr : 0,
|
||||||
s->cirrus_blt_dstpitch, 0,
|
s->cirrus_blt_dstpitch, 0,
|
||||||
s->cirrus_blt_width, s->cirrus_blt_height);
|
s->cirrus_blt_width, s->cirrus_blt_height);
|
||||||
cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
|
cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
|
||||||
|
@ -691,11 +759,11 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop)
|
||||||
{
|
{
|
||||||
cirrus_fill_t rop_func;
|
cirrus_fill_t rop_func;
|
||||||
|
|
||||||
if (blit_is_unsafe(s)) {
|
if (blit_is_unsafe(s, true)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
rop_func = cirrus_fill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
|
rop_func = cirrus_fill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
|
||||||
rop_func(s, s->vga.vram_ptr + (s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
|
rop_func(s, s->cirrus_blt_dstaddr,
|
||||||
s->cirrus_blt_dstpitch,
|
s->cirrus_blt_dstpitch,
|
||||||
s->cirrus_blt_width, s->cirrus_blt_height);
|
s->cirrus_blt_width, s->cirrus_blt_height);
|
||||||
cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
|
cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
|
||||||
|
@ -713,9 +781,7 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop)
|
||||||
|
|
||||||
static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s)
|
static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s)
|
||||||
{
|
{
|
||||||
return cirrus_bitblt_common_patterncopy(s,
|
return cirrus_bitblt_common_patterncopy(s);
|
||||||
s->vga.vram_ptr + ((s->cirrus_blt_srcaddr & ~7) &
|
|
||||||
s->cirrus_addr_mask));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
|
static int cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
|
||||||
|
@ -764,23 +830,15 @@ static int cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* we have to flush all pending changes so that the copy
|
(*s->cirrus_rop) (s, s->cirrus_blt_dstaddr,
|
||||||
is generated at the appropriate moment in time */
|
s->cirrus_blt_srcaddr,
|
||||||
if (notify)
|
|
||||||
graphic_hw_update(s->vga.con);
|
|
||||||
|
|
||||||
(*s->cirrus_rop) (s, s->vga.vram_ptr +
|
|
||||||
(s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
|
|
||||||
s->vga.vram_ptr +
|
|
||||||
(s->cirrus_blt_srcaddr & s->cirrus_addr_mask),
|
|
||||||
s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch,
|
s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch,
|
||||||
s->cirrus_blt_width, s->cirrus_blt_height);
|
s->cirrus_blt_width, s->cirrus_blt_height);
|
||||||
|
|
||||||
if (notify) {
|
if (notify) {
|
||||||
qemu_console_copy(s->vga.con,
|
dpy_gfx_update(s->vga.con, dx, dy,
|
||||||
sx, sy, dx, dy,
|
s->cirrus_blt_width / depth,
|
||||||
s->cirrus_blt_width / depth,
|
s->cirrus_blt_height);
|
||||||
s->cirrus_blt_height);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* we don't have to notify the display that this portion has
|
/* we don't have to notify the display that this portion has
|
||||||
|
@ -795,7 +853,7 @@ static int cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
|
||||||
|
|
||||||
static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s)
|
static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s)
|
||||||
{
|
{
|
||||||
if (blit_is_unsafe(s))
|
if (blit_is_unsafe(s, false))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return cirrus_do_copy(s, s->cirrus_blt_dstaddr - s->vga.start_addr,
|
return cirrus_do_copy(s, s->cirrus_blt_dstaddr - s->vga.start_addr,
|
||||||
|
@ -816,16 +874,15 @@ static void cirrus_bitblt_cputovideo_next(CirrusVGAState * s)
|
||||||
|
|
||||||
if (s->cirrus_srccounter > 0) {
|
if (s->cirrus_srccounter > 0) {
|
||||||
if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
|
if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
|
||||||
cirrus_bitblt_common_patterncopy(s, s->cirrus_bltbuf);
|
cirrus_bitblt_common_patterncopy(s);
|
||||||
the_end:
|
the_end:
|
||||||
s->cirrus_srccounter = 0;
|
s->cirrus_srccounter = 0;
|
||||||
cirrus_bitblt_reset(s);
|
cirrus_bitblt_reset(s);
|
||||||
} else {
|
} else {
|
||||||
/* at least one scan line */
|
/* at least one scan line */
|
||||||
do {
|
do {
|
||||||
(*s->cirrus_rop)(s, s->vga.vram_ptr +
|
(*s->cirrus_rop)(s, s->cirrus_blt_dstaddr,
|
||||||
(s->cirrus_blt_dstaddr & s->cirrus_addr_mask),
|
0, 0, 0, s->cirrus_blt_width, 1);
|
||||||
s->cirrus_bltbuf, 0, 0, s->cirrus_blt_width, 1);
|
|
||||||
cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, 0,
|
cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, 0,
|
||||||
s->cirrus_blt_width, 1);
|
s->cirrus_blt_width, 1);
|
||||||
s->cirrus_blt_dstaddr += s->cirrus_blt_dstpitch;
|
s->cirrus_blt_dstaddr += s->cirrus_blt_dstpitch;
|
||||||
|
@ -871,6 +928,10 @@ static int cirrus_bitblt_cputovideo(CirrusVGAState * s)
|
||||||
{
|
{
|
||||||
int w;
|
int w;
|
||||||
|
|
||||||
|
if (blit_is_unsafe(s, true)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
s->cirrus_blt_mode &= ~CIRRUS_BLTMODE_MEMSYSSRC;
|
s->cirrus_blt_mode &= ~CIRRUS_BLTMODE_MEMSYSSRC;
|
||||||
s->cirrus_srcptr = &s->cirrus_bltbuf[0];
|
s->cirrus_srcptr = &s->cirrus_bltbuf[0];
|
||||||
s->cirrus_srcptr_end = &s->cirrus_bltbuf[0];
|
s->cirrus_srcptr_end = &s->cirrus_bltbuf[0];
|
||||||
|
@ -896,6 +957,10 @@ static int cirrus_bitblt_cputovideo(CirrusVGAState * s)
|
||||||
}
|
}
|
||||||
s->cirrus_srccounter = s->cirrus_blt_srcpitch * s->cirrus_blt_height;
|
s->cirrus_srccounter = s->cirrus_blt_srcpitch * s->cirrus_blt_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* the blit_is_unsafe call above should catch this */
|
||||||
|
assert(s->cirrus_blt_srcpitch <= CIRRUS_BLTBUFSIZE);
|
||||||
|
|
||||||
s->cirrus_srcptr = s->cirrus_bltbuf;
|
s->cirrus_srcptr = s->cirrus_bltbuf;
|
||||||
s->cirrus_srcptr_end = s->cirrus_bltbuf + s->cirrus_blt_srcpitch;
|
s->cirrus_srcptr_end = s->cirrus_bltbuf + s->cirrus_blt_srcpitch;
|
||||||
cirrus_update_memory_access(s);
|
cirrus_update_memory_access(s);
|
||||||
|
@ -943,6 +1008,9 @@ static void cirrus_bitblt_start(CirrusVGAState * s)
|
||||||
s->cirrus_blt_modeext = s->vga.gr[0x33];
|
s->cirrus_blt_modeext = s->vga.gr[0x33];
|
||||||
blt_rop = s->vga.gr[0x32];
|
blt_rop = s->vga.gr[0x32];
|
||||||
|
|
||||||
|
s->cirrus_blt_dstaddr &= s->cirrus_addr_mask;
|
||||||
|
s->cirrus_blt_srcaddr &= s->cirrus_addr_mask;
|
||||||
|
|
||||||
#ifdef DEBUG_BITBLT
|
#ifdef DEBUG_BITBLT
|
||||||
printf("rop=0x%02x mode=0x%02x modeext=0x%02x w=%d h=%d dpitch=%d spitch=%d daddr=0x%08x saddr=0x%08x writemask=0x%02x\n",
|
printf("rop=0x%02x mode=0x%02x modeext=0x%02x w=%d h=%d dpitch=%d spitch=%d daddr=0x%08x saddr=0x%08x writemask=0x%02x\n",
|
||||||
blt_rop,
|
blt_rop,
|
||||||
|
|
|
@ -22,31 +22,65 @@
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static inline void glue(rop_8_,ROP_NAME)(uint8_t *dst, uint8_t src)
|
static inline void glue(rop_8_, ROP_NAME)(CirrusVGAState *s,
|
||||||
|
uint32_t dstaddr, uint8_t src)
|
||||||
{
|
{
|
||||||
|
uint8_t *dst = &s->vga.vram_ptr[dstaddr & s->cirrus_addr_mask];
|
||||||
*dst = ROP_FN(*dst, src);
|
*dst = ROP_FN(*dst, src);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void glue(rop_16_,ROP_NAME)(uint16_t *dst, uint16_t src)
|
static inline void glue(rop_tr_8_, ROP_NAME)(CirrusVGAState *s,
|
||||||
|
uint32_t dstaddr, uint8_t src,
|
||||||
|
uint8_t transp)
|
||||||
{
|
{
|
||||||
|
uint8_t *dst = &s->vga.vram_ptr[dstaddr & s->cirrus_addr_mask];
|
||||||
|
uint8_t pixel = ROP_FN(*dst, src);
|
||||||
|
if (pixel != transp) {
|
||||||
|
*dst = pixel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void glue(rop_16_, ROP_NAME)(CirrusVGAState *s,
|
||||||
|
uint32_t dstaddr, uint16_t src)
|
||||||
|
{
|
||||||
|
uint16_t *dst = (uint16_t *)
|
||||||
|
(&s->vga.vram_ptr[dstaddr & s->cirrus_addr_mask & ~1]);
|
||||||
*dst = ROP_FN(*dst, src);
|
*dst = ROP_FN(*dst, src);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void glue(rop_32_,ROP_NAME)(uint32_t *dst, uint32_t src)
|
static inline void glue(rop_tr_16_, ROP_NAME)(CirrusVGAState *s,
|
||||||
|
uint32_t dstaddr, uint16_t src,
|
||||||
|
uint16_t transp)
|
||||||
{
|
{
|
||||||
|
uint16_t *dst = (uint16_t *)
|
||||||
|
(&s->vga.vram_ptr[dstaddr & s->cirrus_addr_mask & ~1]);
|
||||||
|
uint16_t pixel = ROP_FN(*dst, src);
|
||||||
|
if (pixel != transp) {
|
||||||
|
*dst = pixel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void glue(rop_32_, ROP_NAME)(CirrusVGAState *s,
|
||||||
|
uint32_t dstaddr, uint32_t src)
|
||||||
|
{
|
||||||
|
uint32_t *dst = (uint32_t *)
|
||||||
|
(&s->vga.vram_ptr[dstaddr & s->cirrus_addr_mask & ~3]);
|
||||||
*dst = ROP_FN(*dst, src);
|
*dst = ROP_FN(*dst, src);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ROP_OP(d, s) glue(rop_8_,ROP_NAME)(d, s)
|
#define ROP_OP(st, d, s) glue(rop_8_, ROP_NAME)(st, d, s)
|
||||||
#define ROP_OP_16(d, s) glue(rop_16_,ROP_NAME)(d, s)
|
#define ROP_OP_TR(st, d, s, t) glue(rop_tr_8_, ROP_NAME)(st, d, s, t)
|
||||||
#define ROP_OP_32(d, s) glue(rop_32_,ROP_NAME)(d, s)
|
#define ROP_OP_16(st, d, s) glue(rop_16_, ROP_NAME)(st, d, s)
|
||||||
|
#define ROP_OP_TR_16(st, d, s, t) glue(rop_tr_16_, ROP_NAME)(st, d, s, t)
|
||||||
|
#define ROP_OP_32(st, d, s) glue(rop_32_, ROP_NAME)(st, d, s)
|
||||||
#undef ROP_FN
|
#undef ROP_FN
|
||||||
|
|
||||||
static void
|
static void
|
||||||
glue(cirrus_bitblt_rop_fwd_, ROP_NAME)(CirrusVGAState *s,
|
glue(cirrus_bitblt_rop_fwd_, ROP_NAME)(CirrusVGAState *s,
|
||||||
uint8_t *dst,const uint8_t *src,
|
uint32_t dstaddr,
|
||||||
int dstpitch,int srcpitch,
|
uint32_t srcaddr,
|
||||||
int bltwidth,int bltheight)
|
int dstpitch, int srcpitch,
|
||||||
|
int bltwidth, int bltheight)
|
||||||
{
|
{
|
||||||
int x,y;
|
int x,y;
|
||||||
dstpitch -= bltwidth;
|
dstpitch -= bltwidth;
|
||||||
|
@ -58,134 +92,139 @@ glue(cirrus_bitblt_rop_fwd_, ROP_NAME)(CirrusVGAState *s,
|
||||||
|
|
||||||
for (y = 0; y < bltheight; y++) {
|
for (y = 0; y < bltheight; y++) {
|
||||||
for (x = 0; x < bltwidth; x++) {
|
for (x = 0; x < bltwidth; x++) {
|
||||||
ROP_OP(dst, *src);
|
ROP_OP(s, dstaddr, cirrus_src(s, srcaddr));
|
||||||
dst++;
|
dstaddr++;
|
||||||
src++;
|
srcaddr++;
|
||||||
}
|
}
|
||||||
dst += dstpitch;
|
dstaddr += dstpitch;
|
||||||
src += srcpitch;
|
srcaddr += srcpitch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
glue(cirrus_bitblt_rop_bkwd_, ROP_NAME)(CirrusVGAState *s,
|
glue(cirrus_bitblt_rop_bkwd_, ROP_NAME)(CirrusVGAState *s,
|
||||||
uint8_t *dst,const uint8_t *src,
|
uint32_t dstaddr,
|
||||||
int dstpitch,int srcpitch,
|
uint32_t srcaddr,
|
||||||
int bltwidth,int bltheight)
|
int dstpitch, int srcpitch,
|
||||||
|
int bltwidth, int bltheight)
|
||||||
{
|
{
|
||||||
int x,y;
|
int x,y;
|
||||||
dstpitch += bltwidth;
|
dstpitch += bltwidth;
|
||||||
srcpitch += bltwidth;
|
srcpitch += bltwidth;
|
||||||
for (y = 0; y < bltheight; y++) {
|
for (y = 0; y < bltheight; y++) {
|
||||||
for (x = 0; x < bltwidth; x++) {
|
for (x = 0; x < bltwidth; x++) {
|
||||||
ROP_OP(dst, *src);
|
ROP_OP(s, dstaddr, cirrus_src(s, srcaddr));
|
||||||
dst--;
|
dstaddr--;
|
||||||
src--;
|
srcaddr--;
|
||||||
}
|
}
|
||||||
dst += dstpitch;
|
dstaddr += dstpitch;
|
||||||
src += srcpitch;
|
srcaddr += srcpitch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
glue(glue(cirrus_bitblt_rop_fwd_transp_, ROP_NAME),_8)(CirrusVGAState *s,
|
glue(glue(cirrus_bitblt_rop_fwd_transp_, ROP_NAME),_8)(CirrusVGAState *s,
|
||||||
uint8_t *dst,const uint8_t *src,
|
uint32_t dstaddr,
|
||||||
int dstpitch,int srcpitch,
|
uint32_t srcaddr,
|
||||||
int bltwidth,int bltheight)
|
int dstpitch,
|
||||||
|
int srcpitch,
|
||||||
|
int bltwidth,
|
||||||
|
int bltheight)
|
||||||
{
|
{
|
||||||
int x,y;
|
int x,y;
|
||||||
uint8_t p;
|
uint8_t transp = s->vga.gr[0x34];
|
||||||
dstpitch -= bltwidth;
|
dstpitch -= bltwidth;
|
||||||
srcpitch -= bltwidth;
|
srcpitch -= bltwidth;
|
||||||
|
|
||||||
|
if (bltheight > 1 && (dstpitch < 0 || srcpitch < 0)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (y = 0; y < bltheight; y++) {
|
for (y = 0; y < bltheight; y++) {
|
||||||
for (x = 0; x < bltwidth; x++) {
|
for (x = 0; x < bltwidth; x++) {
|
||||||
p = *dst;
|
ROP_OP_TR(s, dstaddr, cirrus_src(s, srcaddr), transp);
|
||||||
ROP_OP(&p, *src);
|
dstaddr++;
|
||||||
if (p != s->vga.gr[0x34]) *dst = p;
|
srcaddr++;
|
||||||
dst++;
|
|
||||||
src++;
|
|
||||||
}
|
}
|
||||||
dst += dstpitch;
|
dstaddr += dstpitch;
|
||||||
src += srcpitch;
|
srcaddr += srcpitch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
glue(glue(cirrus_bitblt_rop_bkwd_transp_, ROP_NAME),_8)(CirrusVGAState *s,
|
glue(glue(cirrus_bitblt_rop_bkwd_transp_, ROP_NAME),_8)(CirrusVGAState *s,
|
||||||
uint8_t *dst,const uint8_t *src,
|
uint32_t dstaddr,
|
||||||
int dstpitch,int srcpitch,
|
uint32_t srcaddr,
|
||||||
int bltwidth,int bltheight)
|
int dstpitch,
|
||||||
|
int srcpitch,
|
||||||
|
int bltwidth,
|
||||||
|
int bltheight)
|
||||||
{
|
{
|
||||||
int x,y;
|
int x,y;
|
||||||
uint8_t p;
|
uint8_t transp = s->vga.gr[0x34];
|
||||||
dstpitch += bltwidth;
|
dstpitch += bltwidth;
|
||||||
srcpitch += bltwidth;
|
srcpitch += bltwidth;
|
||||||
for (y = 0; y < bltheight; y++) {
|
for (y = 0; y < bltheight; y++) {
|
||||||
for (x = 0; x < bltwidth; x++) {
|
for (x = 0; x < bltwidth; x++) {
|
||||||
p = *dst;
|
ROP_OP_TR(s, dstaddr, cirrus_src(s, srcaddr), transp);
|
||||||
ROP_OP(&p, *src);
|
dstaddr--;
|
||||||
if (p != s->vga.gr[0x34]) *dst = p;
|
srcaddr--;
|
||||||
dst--;
|
|
||||||
src--;
|
|
||||||
}
|
}
|
||||||
dst += dstpitch;
|
dstaddr += dstpitch;
|
||||||
src += srcpitch;
|
srcaddr += srcpitch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
glue(glue(cirrus_bitblt_rop_fwd_transp_, ROP_NAME),_16)(CirrusVGAState *s,
|
glue(glue(cirrus_bitblt_rop_fwd_transp_, ROP_NAME),_16)(CirrusVGAState *s,
|
||||||
uint8_t *dst,const uint8_t *src,
|
uint32_t dstaddr,
|
||||||
int dstpitch,int srcpitch,
|
uint32_t srcaddr,
|
||||||
int bltwidth,int bltheight)
|
int dstpitch,
|
||||||
|
int srcpitch,
|
||||||
|
int bltwidth,
|
||||||
|
int bltheight)
|
||||||
{
|
{
|
||||||
int x,y;
|
int x,y;
|
||||||
uint8_t p1, p2;
|
uint16_t transp = s->vga.gr[0x34] | (uint16_t)s->vga.gr[0x35] << 8;
|
||||||
dstpitch -= bltwidth;
|
dstpitch -= bltwidth;
|
||||||
srcpitch -= bltwidth;
|
srcpitch -= bltwidth;
|
||||||
|
|
||||||
|
if (bltheight > 1 && (dstpitch < 0 || srcpitch < 0)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (y = 0; y < bltheight; y++) {
|
for (y = 0; y < bltheight; y++) {
|
||||||
for (x = 0; x < bltwidth; x+=2) {
|
for (x = 0; x < bltwidth; x+=2) {
|
||||||
p1 = *dst;
|
ROP_OP_TR_16(s, dstaddr, cirrus_src16(s, srcaddr), transp);
|
||||||
p2 = *(dst+1);
|
dstaddr += 2;
|
||||||
ROP_OP(&p1, *src);
|
srcaddr += 2;
|
||||||
ROP_OP(&p2, *(src + 1));
|
|
||||||
if ((p1 != s->vga.gr[0x34]) || (p2 != s->vga.gr[0x35])) {
|
|
||||||
*dst = p1;
|
|
||||||
*(dst+1) = p2;
|
|
||||||
}
|
|
||||||
dst+=2;
|
|
||||||
src+=2;
|
|
||||||
}
|
}
|
||||||
dst += dstpitch;
|
dstaddr += dstpitch;
|
||||||
src += srcpitch;
|
srcaddr += srcpitch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
glue(glue(cirrus_bitblt_rop_bkwd_transp_, ROP_NAME),_16)(CirrusVGAState *s,
|
glue(glue(cirrus_bitblt_rop_bkwd_transp_, ROP_NAME),_16)(CirrusVGAState *s,
|
||||||
uint8_t *dst,const uint8_t *src,
|
uint32_t dstaddr,
|
||||||
int dstpitch,int srcpitch,
|
uint32_t srcaddr,
|
||||||
int bltwidth,int bltheight)
|
int dstpitch,
|
||||||
|
int srcpitch,
|
||||||
|
int bltwidth,
|
||||||
|
int bltheight)
|
||||||
{
|
{
|
||||||
int x,y;
|
int x,y;
|
||||||
uint8_t p1, p2;
|
uint16_t transp = s->vga.gr[0x34] | (uint16_t)s->vga.gr[0x35] << 8;
|
||||||
dstpitch += bltwidth;
|
dstpitch += bltwidth;
|
||||||
srcpitch += bltwidth;
|
srcpitch += bltwidth;
|
||||||
for (y = 0; y < bltheight; y++) {
|
for (y = 0; y < bltheight; y++) {
|
||||||
for (x = 0; x < bltwidth; x+=2) {
|
for (x = 0; x < bltwidth; x+=2) {
|
||||||
p1 = *(dst-1);
|
ROP_OP_TR_16(s, dstaddr - 1, cirrus_src16(s, srcaddr - 1), transp);
|
||||||
p2 = *dst;
|
dstaddr -= 2;
|
||||||
ROP_OP(&p1, *(src - 1));
|
srcaddr -= 2;
|
||||||
ROP_OP(&p2, *src);
|
|
||||||
if ((p1 != s->vga.gr[0x34]) || (p2 != s->vga.gr[0x35])) {
|
|
||||||
*(dst-1) = p1;
|
|
||||||
*dst = p2;
|
|
||||||
}
|
|
||||||
dst-=2;
|
|
||||||
src-=2;
|
|
||||||
}
|
}
|
||||||
dst += dstpitch;
|
dstaddr += dstpitch;
|
||||||
src += srcpitch;
|
srcaddr += srcpitch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,30 +23,32 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if DEPTH == 8
|
#if DEPTH == 8
|
||||||
#define PUTPIXEL() ROP_OP(&d[0], col)
|
#define PUTPIXEL(s, a, c) ROP_OP(s, a, c)
|
||||||
#elif DEPTH == 16
|
#elif DEPTH == 16
|
||||||
#define PUTPIXEL() ROP_OP_16((uint16_t *)&d[0], col)
|
#define PUTPIXEL(s, a, c) ROP_OP_16(s, a, c)
|
||||||
#elif DEPTH == 24
|
#elif DEPTH == 24
|
||||||
#define PUTPIXEL() ROP_OP(&d[0], col); \
|
#define PUTPIXEL(s, a, c) do { \
|
||||||
ROP_OP(&d[1], (col >> 8)); \
|
ROP_OP(s, a, c); \
|
||||||
ROP_OP(&d[2], (col >> 16))
|
ROP_OP(s, a + 1, (col >> 8)); \
|
||||||
|
ROP_OP(s, a + 2, (col >> 16)); \
|
||||||
|
} while (0)
|
||||||
#elif DEPTH == 32
|
#elif DEPTH == 32
|
||||||
#define PUTPIXEL() ROP_OP_32(((uint32_t *)&d[0]), col)
|
#define PUTPIXEL(s, a, c) ROP_OP_32(s, a, c)
|
||||||
#else
|
#else
|
||||||
#error unsupported DEPTH
|
#error unsupported DEPTH
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void
|
static void
|
||||||
glue(glue(glue(cirrus_patternfill_, ROP_NAME), _),DEPTH)
|
glue(glue(glue(cirrus_patternfill_, ROP_NAME), _),DEPTH)
|
||||||
(CirrusVGAState * s, uint8_t * dst,
|
(CirrusVGAState *s, uint32_t dstaddr,
|
||||||
const uint8_t * src,
|
uint32_t srcaddr,
|
||||||
int dstpitch, int srcpitch,
|
int dstpitch, int srcpitch,
|
||||||
int bltwidth, int bltheight)
|
int bltwidth, int bltheight)
|
||||||
{
|
{
|
||||||
uint8_t *d;
|
uint32_t addr;
|
||||||
int x, y, pattern_y, pattern_pitch, pattern_x;
|
int x, y, pattern_y, pattern_pitch, pattern_x;
|
||||||
unsigned int col;
|
unsigned int col;
|
||||||
const uint8_t *src1;
|
uint32_t src1addr;
|
||||||
#if DEPTH == 24
|
#if DEPTH == 24
|
||||||
int skipleft = s->vga.gr[0x2f] & 0x1f;
|
int skipleft = s->vga.gr[0x2f] & 0x1f;
|
||||||
#else
|
#else
|
||||||
|
@ -63,42 +65,44 @@ glue(glue(glue(cirrus_patternfill_, ROP_NAME), _),DEPTH)
|
||||||
pattern_y = s->cirrus_blt_srcaddr & 7;
|
pattern_y = s->cirrus_blt_srcaddr & 7;
|
||||||
for(y = 0; y < bltheight; y++) {
|
for(y = 0; y < bltheight; y++) {
|
||||||
pattern_x = skipleft;
|
pattern_x = skipleft;
|
||||||
d = dst + skipleft;
|
addr = dstaddr + skipleft;
|
||||||
src1 = src + pattern_y * pattern_pitch;
|
src1addr = srcaddr + pattern_y * pattern_pitch;
|
||||||
for (x = skipleft; x < bltwidth; x += (DEPTH / 8)) {
|
for (x = skipleft; x < bltwidth; x += (DEPTH / 8)) {
|
||||||
#if DEPTH == 8
|
#if DEPTH == 8
|
||||||
col = src1[pattern_x];
|
col = cirrus_src(s, src1addr + pattern_x);
|
||||||
pattern_x = (pattern_x + 1) & 7;
|
pattern_x = (pattern_x + 1) & 7;
|
||||||
#elif DEPTH == 16
|
#elif DEPTH == 16
|
||||||
col = ((uint16_t *)(src1 + pattern_x))[0];
|
col = cirrus_src16(s, src1addr + pattern_x);
|
||||||
pattern_x = (pattern_x + 2) & 15;
|
pattern_x = (pattern_x + 2) & 15;
|
||||||
#elif DEPTH == 24
|
#elif DEPTH == 24
|
||||||
{
|
{
|
||||||
const uint8_t *src2 = src1 + pattern_x * 3;
|
uint32_t src2addr = src1addr + pattern_x * 3;
|
||||||
col = src2[0] | (src2[1] << 8) | (src2[2] << 16);
|
col = cirrus_src(s, src2addr) |
|
||||||
|
(cirrus_src(s, src2addr + 1) << 8) |
|
||||||
|
(cirrus_src(s, src2addr + 2) << 16);
|
||||||
pattern_x = (pattern_x + 1) & 7;
|
pattern_x = (pattern_x + 1) & 7;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
col = ((uint32_t *)(src1 + pattern_x))[0];
|
col = cirrus_src32(s, src1addr + pattern_x);
|
||||||
pattern_x = (pattern_x + 4) & 31;
|
pattern_x = (pattern_x + 4) & 31;
|
||||||
#endif
|
#endif
|
||||||
PUTPIXEL();
|
PUTPIXEL(s, addr, col);
|
||||||
d += (DEPTH / 8);
|
addr += (DEPTH / 8);
|
||||||
}
|
}
|
||||||
pattern_y = (pattern_y + 1) & 7;
|
pattern_y = (pattern_y + 1) & 7;
|
||||||
dst += dstpitch;
|
dstaddr += dstpitch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NOTE: srcpitch is ignored */
|
/* NOTE: srcpitch is ignored */
|
||||||
static void
|
static void
|
||||||
glue(glue(glue(cirrus_colorexpand_transp_, ROP_NAME), _),DEPTH)
|
glue(glue(glue(cirrus_colorexpand_transp_, ROP_NAME), _),DEPTH)
|
||||||
(CirrusVGAState * s, uint8_t * dst,
|
(CirrusVGAState *s, uint32_t dstaddr,
|
||||||
const uint8_t * src,
|
uint32_t srcaddr,
|
||||||
int dstpitch, int srcpitch,
|
int dstpitch, int srcpitch,
|
||||||
int bltwidth, int bltheight)
|
int bltwidth, int bltheight)
|
||||||
{
|
{
|
||||||
uint8_t *d;
|
uint32_t addr;
|
||||||
int x, y;
|
int x, y;
|
||||||
unsigned bits, bits_xor;
|
unsigned bits, bits_xor;
|
||||||
unsigned int col;
|
unsigned int col;
|
||||||
|
@ -122,33 +126,33 @@ glue(glue(glue(cirrus_colorexpand_transp_, ROP_NAME), _),DEPTH)
|
||||||
|
|
||||||
for(y = 0; y < bltheight; y++) {
|
for(y = 0; y < bltheight; y++) {
|
||||||
bitmask = 0x80 >> srcskipleft;
|
bitmask = 0x80 >> srcskipleft;
|
||||||
bits = *src++ ^ bits_xor;
|
bits = cirrus_src(s, srcaddr++) ^ bits_xor;
|
||||||
d = dst + dstskipleft;
|
addr = dstaddr + dstskipleft;
|
||||||
for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
|
for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
|
||||||
if ((bitmask & 0xff) == 0) {
|
if ((bitmask & 0xff) == 0) {
|
||||||
bitmask = 0x80;
|
bitmask = 0x80;
|
||||||
bits = *src++ ^ bits_xor;
|
bits = cirrus_src(s, srcaddr++) ^ bits_xor;
|
||||||
}
|
}
|
||||||
index = (bits & bitmask);
|
index = (bits & bitmask);
|
||||||
if (index) {
|
if (index) {
|
||||||
PUTPIXEL();
|
PUTPIXEL(s, addr, col);
|
||||||
}
|
}
|
||||||
d += (DEPTH / 8);
|
addr += (DEPTH / 8);
|
||||||
bitmask >>= 1;
|
bitmask >>= 1;
|
||||||
}
|
}
|
||||||
dst += dstpitch;
|
dstaddr += dstpitch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
glue(glue(glue(cirrus_colorexpand_, ROP_NAME), _),DEPTH)
|
glue(glue(glue(cirrus_colorexpand_, ROP_NAME), _),DEPTH)
|
||||||
(CirrusVGAState * s, uint8_t * dst,
|
(CirrusVGAState *s, uint32_t dstaddr,
|
||||||
const uint8_t * src,
|
uint32_t srcaddr,
|
||||||
int dstpitch, int srcpitch,
|
int dstpitch, int srcpitch,
|
||||||
int bltwidth, int bltheight)
|
int bltwidth, int bltheight)
|
||||||
{
|
{
|
||||||
uint32_t colors[2];
|
uint32_t colors[2];
|
||||||
uint8_t *d;
|
uint32_t addr;
|
||||||
int x, y;
|
int x, y;
|
||||||
unsigned bits;
|
unsigned bits;
|
||||||
unsigned int col;
|
unsigned int col;
|
||||||
|
@ -160,30 +164,30 @@ glue(glue(glue(cirrus_colorexpand_, ROP_NAME), _),DEPTH)
|
||||||
colors[1] = s->cirrus_blt_fgcol;
|
colors[1] = s->cirrus_blt_fgcol;
|
||||||
for(y = 0; y < bltheight; y++) {
|
for(y = 0; y < bltheight; y++) {
|
||||||
bitmask = 0x80 >> srcskipleft;
|
bitmask = 0x80 >> srcskipleft;
|
||||||
bits = *src++;
|
bits = cirrus_src(s, srcaddr++);
|
||||||
d = dst + dstskipleft;
|
addr = dstaddr + dstskipleft;
|
||||||
for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
|
for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
|
||||||
if ((bitmask & 0xff) == 0) {
|
if ((bitmask & 0xff) == 0) {
|
||||||
bitmask = 0x80;
|
bitmask = 0x80;
|
||||||
bits = *src++;
|
bits = cirrus_src(s, srcaddr++);
|
||||||
}
|
}
|
||||||
col = colors[!!(bits & bitmask)];
|
col = colors[!!(bits & bitmask)];
|
||||||
PUTPIXEL();
|
PUTPIXEL(s, addr, col);
|
||||||
d += (DEPTH / 8);
|
addr += (DEPTH / 8);
|
||||||
bitmask >>= 1;
|
bitmask >>= 1;
|
||||||
}
|
}
|
||||||
dst += dstpitch;
|
dstaddr += dstpitch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
glue(glue(glue(cirrus_colorexpand_pattern_transp_, ROP_NAME), _),DEPTH)
|
glue(glue(glue(cirrus_colorexpand_pattern_transp_, ROP_NAME), _),DEPTH)
|
||||||
(CirrusVGAState * s, uint8_t * dst,
|
(CirrusVGAState *s, uint32_t dstaddr,
|
||||||
const uint8_t * src,
|
uint32_t srcaddr,
|
||||||
int dstpitch, int srcpitch,
|
int dstpitch, int srcpitch,
|
||||||
int bltwidth, int bltheight)
|
int bltwidth, int bltheight)
|
||||||
{
|
{
|
||||||
uint8_t *d;
|
uint32_t addr;
|
||||||
int x, y, bitpos, pattern_y;
|
int x, y, bitpos, pattern_y;
|
||||||
unsigned int bits, bits_xor;
|
unsigned int bits, bits_xor;
|
||||||
unsigned int col;
|
unsigned int col;
|
||||||
|
@ -205,30 +209,30 @@ glue(glue(glue(cirrus_colorexpand_pattern_transp_, ROP_NAME), _),DEPTH)
|
||||||
pattern_y = s->cirrus_blt_srcaddr & 7;
|
pattern_y = s->cirrus_blt_srcaddr & 7;
|
||||||
|
|
||||||
for(y = 0; y < bltheight; y++) {
|
for(y = 0; y < bltheight; y++) {
|
||||||
bits = src[pattern_y] ^ bits_xor;
|
bits = cirrus_src(s, srcaddr + pattern_y) ^ bits_xor;
|
||||||
bitpos = 7 - srcskipleft;
|
bitpos = 7 - srcskipleft;
|
||||||
d = dst + dstskipleft;
|
addr = dstaddr + dstskipleft;
|
||||||
for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
|
for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
|
||||||
if ((bits >> bitpos) & 1) {
|
if ((bits >> bitpos) & 1) {
|
||||||
PUTPIXEL();
|
PUTPIXEL(s, addr, col);
|
||||||
}
|
}
|
||||||
d += (DEPTH / 8);
|
addr += (DEPTH / 8);
|
||||||
bitpos = (bitpos - 1) & 7;
|
bitpos = (bitpos - 1) & 7;
|
||||||
}
|
}
|
||||||
pattern_y = (pattern_y + 1) & 7;
|
pattern_y = (pattern_y + 1) & 7;
|
||||||
dst += dstpitch;
|
dstaddr += dstpitch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
glue(glue(glue(cirrus_colorexpand_pattern_, ROP_NAME), _),DEPTH)
|
glue(glue(glue(cirrus_colorexpand_pattern_, ROP_NAME), _),DEPTH)
|
||||||
(CirrusVGAState * s, uint8_t * dst,
|
(CirrusVGAState *s, uint32_t dstaddr,
|
||||||
const uint8_t * src,
|
uint32_t srcaddr,
|
||||||
int dstpitch, int srcpitch,
|
int dstpitch, int srcpitch,
|
||||||
int bltwidth, int bltheight)
|
int bltwidth, int bltheight)
|
||||||
{
|
{
|
||||||
uint32_t colors[2];
|
uint32_t colors[2];
|
||||||
uint8_t *d;
|
uint32_t addr;
|
||||||
int x, y, bitpos, pattern_y;
|
int x, y, bitpos, pattern_y;
|
||||||
unsigned int bits;
|
unsigned int bits;
|
||||||
unsigned int col;
|
unsigned int col;
|
||||||
|
@ -240,40 +244,39 @@ glue(glue(glue(cirrus_colorexpand_pattern_, ROP_NAME), _),DEPTH)
|
||||||
pattern_y = s->cirrus_blt_srcaddr & 7;
|
pattern_y = s->cirrus_blt_srcaddr & 7;
|
||||||
|
|
||||||
for(y = 0; y < bltheight; y++) {
|
for(y = 0; y < bltheight; y++) {
|
||||||
bits = src[pattern_y];
|
bits = cirrus_src(s, srcaddr + pattern_y);
|
||||||
bitpos = 7 - srcskipleft;
|
bitpos = 7 - srcskipleft;
|
||||||
d = dst + dstskipleft;
|
addr = dstaddr + dstskipleft;
|
||||||
for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
|
for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
|
||||||
col = colors[(bits >> bitpos) & 1];
|
col = colors[(bits >> bitpos) & 1];
|
||||||
PUTPIXEL();
|
PUTPIXEL(s, addr, col);
|
||||||
d += (DEPTH / 8);
|
addr += (DEPTH / 8);
|
||||||
bitpos = (bitpos - 1) & 7;
|
bitpos = (bitpos - 1) & 7;
|
||||||
}
|
}
|
||||||
pattern_y = (pattern_y + 1) & 7;
|
pattern_y = (pattern_y + 1) & 7;
|
||||||
dst += dstpitch;
|
dstaddr += dstpitch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
glue(glue(glue(cirrus_fill_, ROP_NAME), _),DEPTH)
|
glue(glue(glue(cirrus_fill_, ROP_NAME), _),DEPTH)
|
||||||
(CirrusVGAState *s,
|
(CirrusVGAState *s,
|
||||||
uint8_t *dst, int dst_pitch,
|
uint32_t dstaddr, int dst_pitch,
|
||||||
int width, int height)
|
int width, int height)
|
||||||
{
|
{
|
||||||
uint8_t *d, *d1;
|
uint32_t addr;
|
||||||
uint32_t col;
|
uint32_t col;
|
||||||
int x, y;
|
int x, y;
|
||||||
|
|
||||||
col = s->cirrus_blt_fgcol;
|
col = s->cirrus_blt_fgcol;
|
||||||
|
|
||||||
d1 = dst;
|
|
||||||
for(y = 0; y < height; y++) {
|
for(y = 0; y < height; y++) {
|
||||||
d = d1;
|
addr = dstaddr;
|
||||||
for(x = 0; x < width; x += (DEPTH / 8)) {
|
for(x = 0; x < width; x += (DEPTH / 8)) {
|
||||||
PUTPIXEL();
|
PUTPIXEL(s, addr, col);
|
||||||
d += (DEPTH / 8);
|
addr += (DEPTH / 8);
|
||||||
}
|
}
|
||||||
d1 += dst_pitch;
|
dstaddr += dst_pitch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1818,8 +1818,10 @@ static void pc_cpu_plug(HotplugHandler *hotplug_dev,
|
||||||
|
|
||||||
/* increment the number of CPUs */
|
/* increment the number of CPUs */
|
||||||
pcms->boot_cpus++;
|
pcms->boot_cpus++;
|
||||||
if (dev->hotplugged) {
|
if (pcms->rtc) {
|
||||||
rtc_set_cpus_count(pcms->rtc, pcms->boot_cpus);
|
rtc_set_cpus_count(pcms->rtc, pcms->boot_cpus);
|
||||||
|
}
|
||||||
|
if (pcms->fw_cfg) {
|
||||||
fw_cfg_modify_i16(pcms->fw_cfg, FW_CFG_NB_CPUS, pcms->boot_cpus);
|
fw_cfg_modify_i16(pcms->fw_cfg, FW_CFG_NB_CPUS, pcms->boot_cpus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -488,7 +488,7 @@ static void ahci_reg_init(AHCIState *s)
|
||||||
s->control_regs.cap = (s->ports - 1) |
|
s->control_regs.cap = (s->ports - 1) |
|
||||||
(AHCI_NUM_COMMAND_SLOTS << 8) |
|
(AHCI_NUM_COMMAND_SLOTS << 8) |
|
||||||
(AHCI_SUPPORTED_SPEED_GEN1 << AHCI_SUPPORTED_SPEED) |
|
(AHCI_SUPPORTED_SPEED_GEN1 << AHCI_SUPPORTED_SPEED) |
|
||||||
HOST_CAP_NCQ | HOST_CAP_AHCI;
|
HOST_CAP_NCQ | HOST_CAP_AHCI | HOST_CAP_64;
|
||||||
|
|
||||||
s->control_regs.impl = (1 << s->ports) - 1;
|
s->control_regs.impl = (1 << s->ports) - 1;
|
||||||
|
|
||||||
|
|
|
@ -250,6 +250,8 @@ static void apic_reset_common(DeviceState *dev)
|
||||||
s->apicbase = APIC_DEFAULT_ADDRESS | bsp | MSR_IA32_APICBASE_ENABLE;
|
s->apicbase = APIC_DEFAULT_ADDRESS | bsp | MSR_IA32_APICBASE_ENABLE;
|
||||||
s->id = s->initial_apic_id;
|
s->id = s->initial_apic_id;
|
||||||
|
|
||||||
|
apic_reset_irq_delivered();
|
||||||
|
|
||||||
s->vapic_paddr = 0;
|
s->vapic_paddr = 0;
|
||||||
info->vapic_base_update(s);
|
info->vapic_base_update(s);
|
||||||
|
|
||||||
|
|
|
@ -426,6 +426,11 @@ static void ioapic_class_init(ObjectClass *klass, void *data)
|
||||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
|
||||||
k->realize = ioapic_realize;
|
k->realize = ioapic_realize;
|
||||||
|
/*
|
||||||
|
* If APIC is in kernel, we need to update the kernel cache after
|
||||||
|
* migration, otherwise first 24 gsi routes will be invalid.
|
||||||
|
*/
|
||||||
|
k->post_load = ioapic_update_kvm_routes;
|
||||||
dc->reset = ioapic_reset_common;
|
dc->reset = ioapic_reset_common;
|
||||||
dc->props = ioapic_properties;
|
dc->props = ioapic_properties;
|
||||||
}
|
}
|
||||||
|
|
|
@ -306,7 +306,7 @@ e1000e_init_msix(E1000EState *s)
|
||||||
static void
|
static void
|
||||||
e1000e_cleanup_msix(E1000EState *s)
|
e1000e_cleanup_msix(E1000EState *s)
|
||||||
{
|
{
|
||||||
if (msix_enabled(PCI_DEVICE(s))) {
|
if (msix_present(PCI_DEVICE(s))) {
|
||||||
e1000e_unuse_msix_vectors(s, E1000E_MSIX_VEC_NUM);
|
e1000e_unuse_msix_vectors(s, E1000E_MSIX_VEC_NUM);
|
||||||
msix_uninit(PCI_DEVICE(s), &s->msix, &s->msix);
|
msix_uninit(PCI_DEVICE(s), &s->msix, &s->msix);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,13 +23,13 @@
|
||||||
|
|
||||||
struct NetRxPkt {
|
struct NetRxPkt {
|
||||||
struct virtio_net_hdr virt_hdr;
|
struct virtio_net_hdr virt_hdr;
|
||||||
uint8_t ehdr_buf[sizeof(struct eth_header)];
|
uint8_t ehdr_buf[sizeof(struct eth_header) + sizeof(struct vlan_header)];
|
||||||
struct iovec *vec;
|
struct iovec *vec;
|
||||||
uint16_t vec_len_total;
|
uint16_t vec_len_total;
|
||||||
uint16_t vec_len;
|
uint16_t vec_len;
|
||||||
uint32_t tot_len;
|
uint32_t tot_len;
|
||||||
uint16_t tci;
|
uint16_t tci;
|
||||||
bool vlan_stripped;
|
size_t ehdr_buf_len;
|
||||||
bool has_virt_hdr;
|
bool has_virt_hdr;
|
||||||
eth_pkt_types_e packet_type;
|
eth_pkt_types_e packet_type;
|
||||||
|
|
||||||
|
@ -88,17 +88,16 @@ net_rx_pkt_pull_data(struct NetRxPkt *pkt,
|
||||||
const struct iovec *iov, int iovcnt,
|
const struct iovec *iov, int iovcnt,
|
||||||
size_t ploff)
|
size_t ploff)
|
||||||
{
|
{
|
||||||
if (pkt->vlan_stripped) {
|
if (pkt->ehdr_buf_len) {
|
||||||
net_rx_pkt_iovec_realloc(pkt, iovcnt + 1);
|
net_rx_pkt_iovec_realloc(pkt, iovcnt + 1);
|
||||||
|
|
||||||
pkt->vec[0].iov_base = pkt->ehdr_buf;
|
pkt->vec[0].iov_base = pkt->ehdr_buf;
|
||||||
pkt->vec[0].iov_len = sizeof(pkt->ehdr_buf);
|
pkt->vec[0].iov_len = pkt->ehdr_buf_len;
|
||||||
|
|
||||||
pkt->tot_len =
|
|
||||||
iov_size(iov, iovcnt) - ploff + sizeof(struct eth_header);
|
|
||||||
|
|
||||||
|
pkt->tot_len = iov_size(iov, iovcnt) - ploff + pkt->ehdr_buf_len;
|
||||||
pkt->vec_len = iov_copy(pkt->vec + 1, pkt->vec_len_total - 1,
|
pkt->vec_len = iov_copy(pkt->vec + 1, pkt->vec_len_total - 1,
|
||||||
iov, iovcnt, ploff, pkt->tot_len);
|
iov, iovcnt, ploff,
|
||||||
|
pkt->tot_len - pkt->ehdr_buf_len) + 1;
|
||||||
} else {
|
} else {
|
||||||
net_rx_pkt_iovec_realloc(pkt, iovcnt);
|
net_rx_pkt_iovec_realloc(pkt, iovcnt);
|
||||||
|
|
||||||
|
@ -123,11 +122,12 @@ void net_rx_pkt_attach_iovec(struct NetRxPkt *pkt,
|
||||||
uint16_t tci = 0;
|
uint16_t tci = 0;
|
||||||
uint16_t ploff = iovoff;
|
uint16_t ploff = iovoff;
|
||||||
assert(pkt);
|
assert(pkt);
|
||||||
pkt->vlan_stripped = false;
|
|
||||||
|
|
||||||
if (strip_vlan) {
|
if (strip_vlan) {
|
||||||
pkt->vlan_stripped = eth_strip_vlan(iov, iovcnt, iovoff, pkt->ehdr_buf,
|
pkt->ehdr_buf_len = eth_strip_vlan(iov, iovcnt, iovoff, pkt->ehdr_buf,
|
||||||
&ploff, &tci);
|
&ploff, &tci);
|
||||||
|
} else {
|
||||||
|
pkt->ehdr_buf_len = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pkt->tci = tci;
|
pkt->tci = tci;
|
||||||
|
@ -143,12 +143,13 @@ void net_rx_pkt_attach_iovec_ex(struct NetRxPkt *pkt,
|
||||||
uint16_t tci = 0;
|
uint16_t tci = 0;
|
||||||
uint16_t ploff = iovoff;
|
uint16_t ploff = iovoff;
|
||||||
assert(pkt);
|
assert(pkt);
|
||||||
pkt->vlan_stripped = false;
|
|
||||||
|
|
||||||
if (strip_vlan) {
|
if (strip_vlan) {
|
||||||
pkt->vlan_stripped = eth_strip_vlan_ex(iov, iovcnt, iovoff, vet,
|
pkt->ehdr_buf_len = eth_strip_vlan_ex(iov, iovcnt, iovoff, vet,
|
||||||
pkt->ehdr_buf,
|
pkt->ehdr_buf,
|
||||||
&ploff, &tci);
|
&ploff, &tci);
|
||||||
|
} else {
|
||||||
|
pkt->ehdr_buf_len = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pkt->tci = tci;
|
pkt->tci = tci;
|
||||||
|
@ -162,8 +163,8 @@ void net_rx_pkt_dump(struct NetRxPkt *pkt)
|
||||||
NetRxPkt *pkt = (NetRxPkt *)pkt;
|
NetRxPkt *pkt = (NetRxPkt *)pkt;
|
||||||
assert(pkt);
|
assert(pkt);
|
||||||
|
|
||||||
printf("RX PKT: tot_len: %d, vlan_stripped: %d, vlan_tag: %d\n",
|
printf("RX PKT: tot_len: %d, ehdr_buf_len: %lu, vlan_tag: %d\n",
|
||||||
pkt->tot_len, pkt->vlan_stripped, pkt->tci);
|
pkt->tot_len, pkt->ehdr_buf_len, pkt->tci);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -426,7 +427,7 @@ bool net_rx_pkt_is_vlan_stripped(struct NetRxPkt *pkt)
|
||||||
{
|
{
|
||||||
assert(pkt);
|
assert(pkt);
|
||||||
|
|
||||||
return pkt->vlan_stripped;
|
return pkt->ehdr_buf_len ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool net_rx_pkt_has_virt_hdr(struct NetRxPkt *pkt)
|
bool net_rx_pkt_has_virt_hdr(struct NetRxPkt *pkt)
|
||||||
|
|
|
@ -982,8 +982,8 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
|
||||||
pci_get_function_0(pci_dev)) {
|
pci_get_function_0(pci_dev)) {
|
||||||
error_setg(errp, "PCI: slot %d function 0 already ocuppied by %s,"
|
error_setg(errp, "PCI: slot %d function 0 already ocuppied by %s,"
|
||||||
" new func %s cannot be exposed to guest.",
|
" new func %s cannot be exposed to guest.",
|
||||||
PCI_SLOT(devfn),
|
PCI_SLOT(pci_get_function_0(pci_dev)->devfn),
|
||||||
bus->devices[PCI_DEVFN(PCI_SLOT(devfn), 0)]->name,
|
pci_get_function_0(pci_dev)->name,
|
||||||
name);
|
name);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -250,5 +250,5 @@ int spapr_ovec_populate_dt(void *fdt, int fdt_offset,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return fdt_setprop(fdt, fdt_offset, name, vec, vec_len);
|
return fdt_setprop(fdt, fdt_offset, name, vec, vec_len + 1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1672,12 +1672,27 @@ void subch_device_save(SubchDev *s, QEMUFile *f)
|
||||||
|
|
||||||
int subch_device_load(SubchDev *s, QEMUFile *f)
|
int subch_device_load(SubchDev *s, QEMUFile *f)
|
||||||
{
|
{
|
||||||
|
SubchDev *old_s;
|
||||||
|
uint16_t old_schid = s->schid;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
s->cssid = qemu_get_byte(f);
|
s->cssid = qemu_get_byte(f);
|
||||||
s->ssid = qemu_get_byte(f);
|
s->ssid = qemu_get_byte(f);
|
||||||
s->schid = qemu_get_be16(f);
|
s->schid = qemu_get_be16(f);
|
||||||
s->devno = qemu_get_be16(f);
|
s->devno = qemu_get_be16(f);
|
||||||
|
/* Re-assign subch. */
|
||||||
|
if (old_schid != s->schid) {
|
||||||
|
old_s = channel_subsys.css[s->cssid]->sch_set[s->ssid]->sch[old_schid];
|
||||||
|
/*
|
||||||
|
* (old_s != s) means that some other device has its correct
|
||||||
|
* subchannel already assigned (in load).
|
||||||
|
*/
|
||||||
|
if (old_s == s) {
|
||||||
|
css_subch_assign(s->cssid, s->ssid, old_schid, s->devno, NULL);
|
||||||
|
}
|
||||||
|
/* It's OK to re-assign without a prior de-assign. */
|
||||||
|
css_subch_assign(s->cssid, s->ssid, s->schid, s->devno, s);
|
||||||
|
}
|
||||||
s->thinint_active = qemu_get_byte(f);
|
s->thinint_active = qemu_get_byte(f);
|
||||||
/* SCHIB */
|
/* SCHIB */
|
||||||
/* PMCW */
|
/* PMCW */
|
||||||
|
|
|
@ -204,8 +204,8 @@ void s390_machine_reset(void)
|
||||||
{
|
{
|
||||||
S390CPU *ipl_cpu = S390_CPU(qemu_get_cpu(0));
|
S390CPU *ipl_cpu = S390_CPU(qemu_get_cpu(0));
|
||||||
|
|
||||||
qemu_devices_reset();
|
|
||||||
s390_cmma_reset();
|
s390_cmma_reset();
|
||||||
|
qemu_devices_reset();
|
||||||
s390_crypto_reset();
|
s390_crypto_reset();
|
||||||
|
|
||||||
/* all cpus are stopped - configure and start the ipl cpu only */
|
/* all cpus are stopped - configure and start the ipl cpu only */
|
||||||
|
|
|
@ -756,7 +756,7 @@ static void mptsas_fetch_request(MPTSASState *s)
|
||||||
|
|
||||||
/* Read the message header from the guest first. */
|
/* Read the message header from the guest first. */
|
||||||
addr = s->host_mfa_high_addr | MPTSAS_FIFO_GET(s, request_post);
|
addr = s->host_mfa_high_addr | MPTSAS_FIFO_GET(s, request_post);
|
||||||
pci_dma_read(pci, addr, req, sizeof(hdr));
|
pci_dma_read(pci, addr, req, sizeof(*hdr));
|
||||||
|
|
||||||
if (hdr->Function < ARRAY_SIZE(mpi_request_sizes) &&
|
if (hdr->Function < ARRAY_SIZE(mpi_request_sizes) &&
|
||||||
mpi_request_sizes[hdr->Function]) {
|
mpi_request_sizes[hdr->Function]) {
|
||||||
|
@ -766,8 +766,8 @@ static void mptsas_fetch_request(MPTSASState *s)
|
||||||
*/
|
*/
|
||||||
size = mpi_request_sizes[hdr->Function];
|
size = mpi_request_sizes[hdr->Function];
|
||||||
assert(size <= MPTSAS_MAX_REQUEST_SIZE);
|
assert(size <= MPTSAS_MAX_REQUEST_SIZE);
|
||||||
pci_dma_read(pci, addr + sizeof(hdr), &req[sizeof(hdr)],
|
pci_dma_read(pci, addr + sizeof(*hdr), &req[sizeof(*hdr)],
|
||||||
size - sizeof(hdr));
|
size - sizeof(*hdr));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
|
if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST) {
|
||||||
|
|
|
@ -2694,7 +2694,7 @@ static bool scsi_block_is_passthrough(SCSIDiskState *s, uint8_t *buf)
|
||||||
* for the number of logical blocks specified in the length
|
* for the number of logical blocks specified in the length
|
||||||
* field). For other modes, do not use scatter/gather operation.
|
* field). For other modes, do not use scatter/gather operation.
|
||||||
*/
|
*/
|
||||||
if ((buf[1] & 6) != 2) {
|
if ((buf[1] & 6) == 2) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -536,7 +536,7 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s)
|
||||||
boundary_count -= block_size - begin;
|
boundary_count -= block_size - begin;
|
||||||
}
|
}
|
||||||
dma_memory_read(&address_space_memory, s->sdmasysad,
|
dma_memory_read(&address_space_memory, s->sdmasysad,
|
||||||
&s->fifo_buffer[begin], s->data_count);
|
&s->fifo_buffer[begin], s->data_count - begin);
|
||||||
s->sdmasysad += s->data_count - begin;
|
s->sdmasysad += s->data_count - begin;
|
||||||
if (s->data_count == block_size) {
|
if (s->data_count == block_size) {
|
||||||
for (n = 0; n < block_size; n++) {
|
for (n = 0; n < block_size; n++) {
|
||||||
|
|
|
@ -15,6 +15,8 @@ virtio_rng_pushed(void *rng, size_t len) "rng %p: %zd bytes pushed"
|
||||||
virtio_rng_request(void *rng, size_t size, unsigned quota) "rng %p: %zd bytes requested, %u bytes quota left"
|
virtio_rng_request(void *rng, size_t size, unsigned quota) "rng %p: %zd bytes requested, %u bytes quota left"
|
||||||
|
|
||||||
# hw/virtio/virtio-balloon.c
|
# hw/virtio/virtio-balloon.c
|
||||||
|
#
|
||||||
|
virtio_balloon_bad_addr(uint64_t gpa) "%"PRIx64
|
||||||
virtio_balloon_handle_output(const char *name, uint64_t gpa) "section name: %s gpa: %"PRIx64
|
virtio_balloon_handle_output(const char *name, uint64_t gpa) "section name: %s gpa: %"PRIx64
|
||||||
virtio_balloon_get_config(uint32_t num_pages, uint32_t actual) "num_pages: %d actual: %d"
|
virtio_balloon_get_config(uint32_t num_pages, uint32_t actual) "num_pages: %d actual: %d"
|
||||||
virtio_balloon_set_config(uint32_t actual, uint32_t oldactual) "actual: %d oldactual: %d"
|
virtio_balloon_set_config(uint32_t actual, uint32_t oldactual) "actual: %d oldactual: %d"
|
||||||
|
|
|
@ -228,8 +228,13 @@ static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq)
|
||||||
|
|
||||||
/* FIXME: remove get_system_memory(), but how? */
|
/* FIXME: remove get_system_memory(), but how? */
|
||||||
section = memory_region_find(get_system_memory(), pa, 1);
|
section = memory_region_find(get_system_memory(), pa, 1);
|
||||||
if (!int128_nz(section.size) || !memory_region_is_ram(section.mr))
|
if (!int128_nz(section.size) ||
|
||||||
|
!memory_region_is_ram(section.mr) ||
|
||||||
|
memory_region_is_rom(section.mr) ||
|
||||||
|
memory_region_is_romd(section.mr)) {
|
||||||
|
trace_virtio_balloon_bad_addr(pa);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
trace_virtio_balloon_handle_output(memory_region_name(section.mr),
|
trace_virtio_balloon_handle_output(memory_region_name(section.mr),
|
||||||
pa);
|
pa);
|
||||||
|
|
|
@ -416,7 +416,7 @@ virtio_crypto_sym_op_helper(VirtIODevice *vdev,
|
||||||
uint32_t hash_start_src_offset = 0, len_to_hash = 0;
|
uint32_t hash_start_src_offset = 0, len_to_hash = 0;
|
||||||
uint32_t cipher_start_src_offset = 0, len_to_cipher = 0;
|
uint32_t cipher_start_src_offset = 0, len_to_cipher = 0;
|
||||||
|
|
||||||
size_t max_len, curr_size = 0;
|
uint64_t max_len, curr_size = 0;
|
||||||
size_t s;
|
size_t s;
|
||||||
|
|
||||||
/* Plain cipher */
|
/* Plain cipher */
|
||||||
|
@ -441,7 +441,7 @@ virtio_crypto_sym_op_helper(VirtIODevice *vdev,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
max_len = iv_len + aad_len + src_len + dst_len + hash_result_len;
|
max_len = (uint64_t)iv_len + aad_len + src_len + dst_len + hash_result_len;
|
||||||
if (unlikely(max_len > vcrypto->conf.max_size)) {
|
if (unlikely(max_len > vcrypto->conf.max_size)) {
|
||||||
virtio_error(vdev, "virtio-crypto too big length");
|
virtio_error(vdev, "virtio-crypto too big length");
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -1836,6 +1836,10 @@ static void virtio_pci_reset(DeviceState *qdev)
|
||||||
|
|
||||||
for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
|
for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
|
||||||
proxy->vqs[i].enabled = 0;
|
proxy->vqs[i].enabled = 0;
|
||||||
|
proxy->vqs[i].num = 0;
|
||||||
|
proxy->vqs[i].desc[0] = proxy->vqs[i].desc[1] = 0;
|
||||||
|
proxy->vqs[i].avail[0] = proxy->vqs[i].avail[1] = 0;
|
||||||
|
proxy->vqs[i].used[0] = proxy->vqs[i].used[1] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -92,7 +92,7 @@ struct VirtQueue
|
||||||
|
|
||||||
uint16_t queue_index;
|
uint16_t queue_index;
|
||||||
|
|
||||||
int inuse;
|
unsigned int inuse;
|
||||||
|
|
||||||
uint16_t vector;
|
uint16_t vector;
|
||||||
VirtIOHandleOutput handle_output;
|
VirtIOHandleOutput handle_output;
|
||||||
|
@ -592,24 +592,12 @@ static void virtqueue_undo_map_desc(unsigned int out_num, unsigned int in_num,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void virtqueue_map_iovec(struct iovec *sg, hwaddr *addr,
|
static void virtqueue_map_iovec(struct iovec *sg, hwaddr *addr,
|
||||||
unsigned int *num_sg, unsigned int max_size,
|
unsigned int *num_sg,
|
||||||
int is_write)
|
int is_write)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
hwaddr len;
|
hwaddr len;
|
||||||
|
|
||||||
/* Note: this function MUST validate input, some callers
|
|
||||||
* are passing in num_sg values received over the network.
|
|
||||||
*/
|
|
||||||
/* TODO: teach all callers that this can fail, and return failure instead
|
|
||||||
* of asserting here.
|
|
||||||
* When we do, we might be able to re-enable NDEBUG below.
|
|
||||||
*/
|
|
||||||
#ifdef NDEBUG
|
|
||||||
#error building with NDEBUG is not supported
|
|
||||||
#endif
|
|
||||||
assert(*num_sg <= max_size);
|
|
||||||
|
|
||||||
for (i = 0; i < *num_sg; i++) {
|
for (i = 0; i < *num_sg; i++) {
|
||||||
len = sg[i].iov_len;
|
len = sg[i].iov_len;
|
||||||
sg[i].iov_base = cpu_physical_memory_map(addr[i], &len, is_write);
|
sg[i].iov_base = cpu_physical_memory_map(addr[i], &len, is_write);
|
||||||
|
@ -626,10 +614,8 @@ static void virtqueue_map_iovec(struct iovec *sg, hwaddr *addr,
|
||||||
|
|
||||||
void virtqueue_map(VirtQueueElement *elem)
|
void virtqueue_map(VirtQueueElement *elem)
|
||||||
{
|
{
|
||||||
virtqueue_map_iovec(elem->in_sg, elem->in_addr, &elem->in_num,
|
virtqueue_map_iovec(elem->in_sg, elem->in_addr, &elem->in_num, 1);
|
||||||
VIRTQUEUE_MAX_SIZE, 1);
|
virtqueue_map_iovec(elem->out_sg, elem->out_addr, &elem->out_num, 0);
|
||||||
virtqueue_map_iovec(elem->out_sg, elem->out_addr, &elem->out_num,
|
|
||||||
VIRTQUEUE_MAX_SIZE, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *virtqueue_alloc_element(size_t sz, unsigned out_num, unsigned in_num)
|
static void *virtqueue_alloc_element(size_t sz, unsigned out_num, unsigned in_num)
|
||||||
|
@ -790,6 +776,16 @@ void *qemu_get_virtqueue_element(QEMUFile *f, size_t sz)
|
||||||
|
|
||||||
qemu_get_buffer(f, (uint8_t *)&data, sizeof(VirtQueueElementOld));
|
qemu_get_buffer(f, (uint8_t *)&data, sizeof(VirtQueueElementOld));
|
||||||
|
|
||||||
|
/* TODO: teach all callers that this can fail, and return failure instead
|
||||||
|
* of asserting here.
|
||||||
|
* When we do, we might be able to re-enable NDEBUG below.
|
||||||
|
*/
|
||||||
|
#ifdef NDEBUG
|
||||||
|
#error building with NDEBUG is not supported
|
||||||
|
#endif
|
||||||
|
assert(ARRAY_SIZE(data.in_addr) >= data.in_num);
|
||||||
|
assert(ARRAY_SIZE(data.out_addr) >= data.out_num);
|
||||||
|
|
||||||
elem = virtqueue_alloc_element(sz, data.out_num, data.in_num);
|
elem = virtqueue_alloc_element(sz, data.out_num, data.in_num);
|
||||||
elem->index = data.index;
|
elem->index = data.index;
|
||||||
|
|
||||||
|
@ -1260,7 +1256,18 @@ static void virtio_queue_notify_vq(VirtQueue *vq)
|
||||||
|
|
||||||
void virtio_queue_notify(VirtIODevice *vdev, int n)
|
void virtio_queue_notify(VirtIODevice *vdev, int n)
|
||||||
{
|
{
|
||||||
virtio_queue_notify_vq(&vdev->vq[n]);
|
VirtQueue *vq = &vdev->vq[n];
|
||||||
|
|
||||||
|
if (unlikely(!vq->vring.desc || vdev->broken)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
trace_virtio_queue_notify(vdev, vq - vdev->vq, vq);
|
||||||
|
if (vq->handle_aio_output) {
|
||||||
|
event_notifier_set(&vq->host_notifier);
|
||||||
|
} else if (vq->handle_output) {
|
||||||
|
vq->handle_output(vdev, vq);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t virtio_queue_vector(VirtIODevice *vdev, int n)
|
uint16_t virtio_queue_vector(VirtIODevice *vdev, int n)
|
||||||
|
@ -1855,9 +1862,11 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
|
||||||
/*
|
/*
|
||||||
* Some devices migrate VirtQueueElements that have been popped
|
* Some devices migrate VirtQueueElements that have been popped
|
||||||
* from the avail ring but not yet returned to the used ring.
|
* from the avail ring but not yet returned to the used ring.
|
||||||
|
* Since max ring size < UINT16_MAX it's safe to use modulo
|
||||||
|
* UINT16_MAX + 1 subtraction.
|
||||||
*/
|
*/
|
||||||
vdev->vq[i].inuse = vdev->vq[i].last_avail_idx -
|
vdev->vq[i].inuse = (uint16_t)(vdev->vq[i].last_avail_idx -
|
||||||
vdev->vq[i].used_idx;
|
vdev->vq[i].used_idx);
|
||||||
if (vdev->vq[i].inuse > vdev->vq[i].vring.num) {
|
if (vdev->vq[i].inuse > vdev->vq[i].vring.num) {
|
||||||
error_report("VQ %d size 0x%x < last_avail_idx 0x%x - "
|
error_report("VQ %d size 0x%x < last_avail_idx 0x%x - "
|
||||||
"used_idx 0x%x",
|
"used_idx 0x%x",
|
||||||
|
|
|
@ -320,6 +320,7 @@ static inline void tb_set_jmp_target(TranslationBlock *tb,
|
||||||
static inline void tb_add_jump(TranslationBlock *tb, int n,
|
static inline void tb_add_jump(TranslationBlock *tb, int n,
|
||||||
TranslationBlock *tb_next)
|
TranslationBlock *tb_next)
|
||||||
{
|
{
|
||||||
|
assert(n < ARRAY_SIZE(tb->jmp_list_next));
|
||||||
if (tb->jmp_list_next[n]) {
|
if (tb->jmp_list_next[n]) {
|
||||||
/* Another thread has already done this while we were
|
/* Another thread has already done this while we were
|
||||||
* outside of the lock; nothing to do in this case */
|
* outside of the lock; nothing to do in this case */
|
||||||
|
|
|
@ -331,12 +331,12 @@ eth_get_pkt_tci(const void *p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
size_t
|
||||||
eth_strip_vlan(const struct iovec *iov, int iovcnt, size_t iovoff,
|
eth_strip_vlan(const struct iovec *iov, int iovcnt, size_t iovoff,
|
||||||
uint8_t *new_ehdr_buf,
|
uint8_t *new_ehdr_buf,
|
||||||
uint16_t *payload_offset, uint16_t *tci);
|
uint16_t *payload_offset, uint16_t *tci);
|
||||||
|
|
||||||
bool
|
size_t
|
||||||
eth_strip_vlan_ex(const struct iovec *iov, int iovcnt, size_t iovoff,
|
eth_strip_vlan_ex(const struct iovec *iov, int iovcnt, size_t iovoff,
|
||||||
uint16_t vet, uint8_t *new_ehdr_buf,
|
uint16_t vet, uint8_t *new_ehdr_buf,
|
||||||
uint16_t *payload_offset, uint16_t *tci);
|
uint16_t *payload_offset, uint16_t *tci);
|
||||||
|
|
|
@ -75,23 +75,6 @@ void user_creatable_complete(Object *obj, Error **errp);
|
||||||
*/
|
*/
|
||||||
bool user_creatable_can_be_deleted(UserCreatable *uc, Error **errp);
|
bool user_creatable_can_be_deleted(UserCreatable *uc, Error **errp);
|
||||||
|
|
||||||
/**
|
|
||||||
* user_creatable_add:
|
|
||||||
* @qdict: the object definition
|
|
||||||
* @v: the visitor
|
|
||||||
* @errp: if an error occurs, a pointer to an area to store the error
|
|
||||||
*
|
|
||||||
* Create an instance of the user creatable object whose type
|
|
||||||
* is defined in @qdict by the 'qom-type' field, placing it
|
|
||||||
* in the object composition tree with name provided by the
|
|
||||||
* 'id' field. The remaining fields in @qdict are used to
|
|
||||||
* initialize the object properties.
|
|
||||||
*
|
|
||||||
* Returns: the newly created object or NULL on error
|
|
||||||
*/
|
|
||||||
Object *user_creatable_add(const QDict *qdict,
|
|
||||||
Visitor *v, Error **errp);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* user_creatable_add_type:
|
* user_creatable_add_type:
|
||||||
* @type: the object type name
|
* @type: the object type name
|
||||||
|
|
|
@ -189,9 +189,6 @@ typedef struct DisplayChangeListenerOps {
|
||||||
int x, int y, int w, int h);
|
int x, int y, int w, int h);
|
||||||
void (*dpy_gfx_switch)(DisplayChangeListener *dcl,
|
void (*dpy_gfx_switch)(DisplayChangeListener *dcl,
|
||||||
struct DisplaySurface *new_surface);
|
struct DisplaySurface *new_surface);
|
||||||
void (*dpy_gfx_copy)(DisplayChangeListener *dcl,
|
|
||||||
int src_x, int src_y,
|
|
||||||
int dst_x, int dst_y, int w, int h);
|
|
||||||
bool (*dpy_gfx_check_format)(DisplayChangeListener *dcl,
|
bool (*dpy_gfx_check_format)(DisplayChangeListener *dcl,
|
||||||
pixman_format_code_t format);
|
pixman_format_code_t format);
|
||||||
|
|
||||||
|
@ -273,8 +270,6 @@ int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info);
|
||||||
void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h);
|
void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h);
|
||||||
void dpy_gfx_replace_surface(QemuConsole *con,
|
void dpy_gfx_replace_surface(QemuConsole *con,
|
||||||
DisplaySurface *surface);
|
DisplaySurface *surface);
|
||||||
void dpy_gfx_copy(QemuConsole *con, int src_x, int src_y,
|
|
||||||
int dst_x, int dst_y, int w, int h);
|
|
||||||
void dpy_text_cursor(QemuConsole *con, int x, int y);
|
void dpy_text_cursor(QemuConsole *con, int x, int y);
|
||||||
void dpy_text_update(QemuConsole *con, int x, int y, int w, int h);
|
void dpy_text_update(QemuConsole *con, int x, int y, int w, int h);
|
||||||
void dpy_text_resize(QemuConsole *con, int w, int h);
|
void dpy_text_resize(QemuConsole *con, int w, int h);
|
||||||
|
@ -397,8 +392,6 @@ int qemu_console_get_height(QemuConsole *con, int fallback);
|
||||||
|
|
||||||
void console_select(unsigned int index);
|
void console_select(unsigned int index);
|
||||||
void qemu_console_resize(QemuConsole *con, int width, int height);
|
void qemu_console_resize(QemuConsole *con, int width, int height);
|
||||||
void qemu_console_copy(QemuConsole *con, int src_x, int src_y,
|
|
||||||
int dst_x, int dst_y, int w, int h);
|
|
||||||
DisplaySurface *qemu_console_surface(QemuConsole *con);
|
DisplaySurface *qemu_console_surface(QemuConsole *con);
|
||||||
|
|
||||||
/* console-gl.c */
|
/* console-gl.c */
|
||||||
|
|
|
@ -18,6 +18,10 @@
|
||||||
#include <X11/XKBlib.h>
|
#include <X11/XKBlib.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef GDK_WINDOWING_WAYLAND
|
||||||
|
#include <gdk/gdkwayland.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(CONFIG_OPENGL)
|
#if defined(CONFIG_OPENGL)
|
||||||
#include "ui/egl-helpers.h"
|
#include "ui/egl-helpers.h"
|
||||||
#include "ui/egl-context.h"
|
#include "ui/egl-context.h"
|
||||||
|
|
|
@ -72,7 +72,7 @@ safe_syscall_base:
|
||||||
*/
|
*/
|
||||||
safe_syscall_start:
|
safe_syscall_start:
|
||||||
/* if signal_pending is non-zero, don't do the call */
|
/* if signal_pending is non-zero, don't do the call */
|
||||||
lt %r0,0(%r8)
|
icm %r0,15,0(%r8)
|
||||||
jne 2f
|
jne 2f
|
||||||
svc 0
|
svc 0
|
||||||
safe_syscall_end:
|
safe_syscall_end:
|
||||||
|
|
|
@ -1708,10 +1708,12 @@ void cpu_loop(CPUPPCState *env)
|
||||||
* in syscalls.
|
* in syscalls.
|
||||||
*/
|
*/
|
||||||
env->crf[0] &= ~0x1;
|
env->crf[0] &= ~0x1;
|
||||||
|
env->nip += 4;
|
||||||
ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
|
ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
|
||||||
env->gpr[5], env->gpr[6], env->gpr[7],
|
env->gpr[5], env->gpr[6], env->gpr[7],
|
||||||
env->gpr[8], 0, 0);
|
env->gpr[8], 0, 0);
|
||||||
if (ret == -TARGET_ERESTARTSYS) {
|
if (ret == -TARGET_ERESTARTSYS) {
|
||||||
|
env->nip -= 4;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (ret == (target_ulong)(-TARGET_QEMU_ESIGRETURN)) {
|
if (ret == (target_ulong)(-TARGET_QEMU_ESIGRETURN)) {
|
||||||
|
@ -1719,7 +1721,6 @@ void cpu_loop(CPUPPCState *env)
|
||||||
Avoid corrupting register state. */
|
Avoid corrupting register state. */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
env->nip += 4;
|
|
||||||
if (ret > (target_ulong)(-515)) {
|
if (ret > (target_ulong)(-515)) {
|
||||||
env->crf[0] |= 0x1;
|
env->crf[0] |= 0x1;
|
||||||
ret = -ret;
|
ret = -ret;
|
||||||
|
@ -4045,6 +4046,8 @@ int main(int argc, char **argv, char **envp)
|
||||||
# endif
|
# endif
|
||||||
#elif defined TARGET_SH4
|
#elif defined TARGET_SH4
|
||||||
cpu_model = TYPE_SH7785_CPU;
|
cpu_model = TYPE_SH7785_CPU;
|
||||||
|
#elif defined TARGET_S390X
|
||||||
|
cpu_model = "qemu";
|
||||||
#else
|
#else
|
||||||
cpu_model = "any";
|
cpu_model = "any";
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -94,7 +94,7 @@ static ssize_t drop_sync(QIOChannel *ioc, size_t size)
|
||||||
char small[1024];
|
char small[1024];
|
||||||
char *buffer;
|
char *buffer;
|
||||||
|
|
||||||
buffer = sizeof(small) < size ? small : g_malloc(MIN(65536, size));
|
buffer = sizeof(small) >= size ? small : g_malloc(MIN(65536, size));
|
||||||
while (size > 0) {
|
while (size > 0) {
|
||||||
ssize_t count = read_sync(ioc, buffer, MIN(65536, size));
|
ssize_t count = read_sync(ioc, buffer, MIN(65536, size));
|
||||||
|
|
||||||
|
|
25
net/eth.c
25
net/eth.c
|
@ -232,7 +232,7 @@ void eth_get_protocols(const struct iovec *iov, int iovcnt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
size_t
|
||||||
eth_strip_vlan(const struct iovec *iov, int iovcnt, size_t iovoff,
|
eth_strip_vlan(const struct iovec *iov, int iovcnt, size_t iovoff,
|
||||||
uint8_t *new_ehdr_buf,
|
uint8_t *new_ehdr_buf,
|
||||||
uint16_t *payload_offset, uint16_t *tci)
|
uint16_t *payload_offset, uint16_t *tci)
|
||||||
|
@ -244,7 +244,7 @@ eth_strip_vlan(const struct iovec *iov, int iovcnt, size_t iovoff,
|
||||||
new_ehdr, sizeof(*new_ehdr));
|
new_ehdr, sizeof(*new_ehdr));
|
||||||
|
|
||||||
if (copied < sizeof(*new_ehdr)) {
|
if (copied < sizeof(*new_ehdr)) {
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (be16_to_cpu(new_ehdr->h_proto)) {
|
switch (be16_to_cpu(new_ehdr->h_proto)) {
|
||||||
|
@ -254,7 +254,7 @@ eth_strip_vlan(const struct iovec *iov, int iovcnt, size_t iovoff,
|
||||||
&vlan_hdr, sizeof(vlan_hdr));
|
&vlan_hdr, sizeof(vlan_hdr));
|
||||||
|
|
||||||
if (copied < sizeof(vlan_hdr)) {
|
if (copied < sizeof(vlan_hdr)) {
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
new_ehdr->h_proto = vlan_hdr.h_proto;
|
new_ehdr->h_proto = vlan_hdr.h_proto;
|
||||||
|
@ -268,18 +268,21 @@ eth_strip_vlan(const struct iovec *iov, int iovcnt, size_t iovoff,
|
||||||
PKT_GET_VLAN_HDR(new_ehdr), sizeof(vlan_hdr));
|
PKT_GET_VLAN_HDR(new_ehdr), sizeof(vlan_hdr));
|
||||||
|
|
||||||
if (copied < sizeof(vlan_hdr)) {
|
if (copied < sizeof(vlan_hdr)) {
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
*payload_offset += sizeof(vlan_hdr);
|
*payload_offset += sizeof(vlan_hdr);
|
||||||
|
|
||||||
|
return sizeof(struct eth_header) + sizeof(struct vlan_header);
|
||||||
|
} else {
|
||||||
|
return sizeof(struct eth_header);
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
size_t
|
||||||
eth_strip_vlan_ex(const struct iovec *iov, int iovcnt, size_t iovoff,
|
eth_strip_vlan_ex(const struct iovec *iov, int iovcnt, size_t iovoff,
|
||||||
uint16_t vet, uint8_t *new_ehdr_buf,
|
uint16_t vet, uint8_t *new_ehdr_buf,
|
||||||
uint16_t *payload_offset, uint16_t *tci)
|
uint16_t *payload_offset, uint16_t *tci)
|
||||||
|
@ -291,7 +294,7 @@ eth_strip_vlan_ex(const struct iovec *iov, int iovcnt, size_t iovoff,
|
||||||
new_ehdr, sizeof(*new_ehdr));
|
new_ehdr, sizeof(*new_ehdr));
|
||||||
|
|
||||||
if (copied < sizeof(*new_ehdr)) {
|
if (copied < sizeof(*new_ehdr)) {
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (be16_to_cpu(new_ehdr->h_proto) == vet) {
|
if (be16_to_cpu(new_ehdr->h_proto) == vet) {
|
||||||
|
@ -299,17 +302,17 @@ eth_strip_vlan_ex(const struct iovec *iov, int iovcnt, size_t iovoff,
|
||||||
&vlan_hdr, sizeof(vlan_hdr));
|
&vlan_hdr, sizeof(vlan_hdr));
|
||||||
|
|
||||||
if (copied < sizeof(vlan_hdr)) {
|
if (copied < sizeof(vlan_hdr)) {
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
new_ehdr->h_proto = vlan_hdr.h_proto;
|
new_ehdr->h_proto = vlan_hdr.h_proto;
|
||||||
|
|
||||||
*tci = be16_to_cpu(vlan_hdr.h_tci);
|
*tci = be16_to_cpu(vlan_hdr.h_tci);
|
||||||
*payload_offset = iovoff + sizeof(*new_ehdr) + sizeof(vlan_hdr);
|
*payload_offset = iovoff + sizeof(*new_ehdr) + sizeof(vlan_hdr);
|
||||||
return true;
|
return sizeof(struct eth_header);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
Binary file not shown.
BIN
pc-bios/bios.bin
BIN
pc-bios/bios.bin
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -164,7 +164,7 @@ opts_check_struct(Visitor *v, Error **errp)
|
||||||
GHashTableIter iter;
|
GHashTableIter iter;
|
||||||
GQueue *any;
|
GQueue *any;
|
||||||
|
|
||||||
if (ov->depth > 0) {
|
if (ov->depth > 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
15
qemu-char.c
15
qemu-char.c
|
@ -499,7 +499,7 @@ void qemu_chr_fe_printf(CharBackend *be, const char *fmt, ...)
|
||||||
|
|
||||||
static void remove_fd_in_watch(CharDriverState *chr);
|
static void remove_fd_in_watch(CharDriverState *chr);
|
||||||
static void mux_chr_set_handlers(CharDriverState *chr, GMainContext *context);
|
static void mux_chr_set_handlers(CharDriverState *chr, GMainContext *context);
|
||||||
static void mux_set_focus(MuxDriver *d, int focus);
|
static void mux_set_focus(CharDriverState *chr, int focus);
|
||||||
|
|
||||||
static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
|
static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
|
||||||
{
|
{
|
||||||
|
@ -666,7 +666,7 @@ static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch)
|
||||||
case 'c':
|
case 'c':
|
||||||
assert(d->mux_cnt > 0); /* handler registered with first fe */
|
assert(d->mux_cnt > 0); /* handler registered with first fe */
|
||||||
/* Switch to the next registered device */
|
/* Switch to the next registered device */
|
||||||
mux_set_focus(d, (d->focus + 1) % d->mux_cnt);
|
mux_set_focus(chr, (d->focus + 1) % d->mux_cnt);
|
||||||
break;
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
d->timestamps = !d->timestamps;
|
d->timestamps = !d->timestamps;
|
||||||
|
@ -826,8 +826,10 @@ static void mux_chr_set_handlers(CharDriverState *chr, GMainContext *context)
|
||||||
context, true);
|
context, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mux_set_focus(MuxDriver *d, int focus)
|
static void mux_set_focus(CharDriverState *chr, int focus)
|
||||||
{
|
{
|
||||||
|
MuxDriver *d = chr->opaque;
|
||||||
|
|
||||||
assert(focus >= 0);
|
assert(focus >= 0);
|
||||||
assert(focus < d->mux_cnt);
|
assert(focus < d->mux_cnt);
|
||||||
|
|
||||||
|
@ -836,6 +838,7 @@ static void mux_set_focus(MuxDriver *d, int focus)
|
||||||
}
|
}
|
||||||
|
|
||||||
d->focus = focus;
|
d->focus = focus;
|
||||||
|
chr->be = d->backends[focus];
|
||||||
mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_IN);
|
mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_IN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -935,7 +938,9 @@ void qemu_chr_fe_deinit(CharBackend *b)
|
||||||
|
|
||||||
if (b->chr) {
|
if (b->chr) {
|
||||||
qemu_chr_fe_set_handlers(b, NULL, NULL, NULL, NULL, NULL, true);
|
qemu_chr_fe_set_handlers(b, NULL, NULL, NULL, NULL, NULL, true);
|
||||||
b->chr->be = NULL;
|
if (b->chr->be == b) {
|
||||||
|
b->chr->be = NULL;
|
||||||
|
}
|
||||||
if (b->chr->is_mux) {
|
if (b->chr->is_mux) {
|
||||||
MuxDriver *d = b->chr->opaque;
|
MuxDriver *d = b->chr->opaque;
|
||||||
d->backends[b->tag] = NULL;
|
d->backends[b->tag] = NULL;
|
||||||
|
@ -999,7 +1004,7 @@ void qemu_chr_fe_take_focus(CharBackend *b)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (b->chr->is_mux) {
|
if (b->chr->is_mux) {
|
||||||
mux_set_focus(b->chr->opaque, b->tag);
|
mux_set_focus(b->chr, b->tag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1243,6 +1243,9 @@ int64_t qmp_guest_fsfreeze_freeze_list(bool has_mountpoints,
|
||||||
* filesystems may not implement fsfreeze for less obvious reasons.
|
* filesystems may not implement fsfreeze for less obvious reasons.
|
||||||
* these will report EOPNOTSUPP. we simply ignore these when tallying
|
* these will report EOPNOTSUPP. we simply ignore these when tallying
|
||||||
* the number of frozen filesystems.
|
* the number of frozen filesystems.
|
||||||
|
* if a filesystem is mounted more than once (aka bind mount) a
|
||||||
|
* consecutive attempt to freeze an already frozen filesystem will
|
||||||
|
* return EBUSY.
|
||||||
*
|
*
|
||||||
* any other error means a failure to freeze a filesystem we
|
* any other error means a failure to freeze a filesystem we
|
||||||
* expect to be freezable, so return an error in those cases
|
* expect to be freezable, so return an error in those cases
|
||||||
|
@ -1250,7 +1253,7 @@ int64_t qmp_guest_fsfreeze_freeze_list(bool has_mountpoints,
|
||||||
*/
|
*/
|
||||||
ret = ioctl(fd, FIFREEZE);
|
ret = ioctl(fd, FIFREEZE);
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
if (errno != EOPNOTSUPP) {
|
if (errno != EOPNOTSUPP && errno != EBUSY) {
|
||||||
error_setg_errno(errp, errno, "failed to freeze %s",
|
error_setg_errno(errp, errno, "failed to freeze %s",
|
||||||
mount->dirname);
|
mount->dirname);
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
|
@ -35,57 +35,6 @@ bool user_creatable_can_be_deleted(UserCreatable *uc, Error **errp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Object *user_creatable_add(const QDict *qdict,
|
|
||||||
Visitor *v, Error **errp)
|
|
||||||
{
|
|
||||||
char *type = NULL;
|
|
||||||
char *id = NULL;
|
|
||||||
Object *obj = NULL;
|
|
||||||
Error *local_err = NULL;
|
|
||||||
QDict *pdict;
|
|
||||||
|
|
||||||
pdict = qdict_clone_shallow(qdict);
|
|
||||||
|
|
||||||
visit_start_struct(v, NULL, NULL, 0, &local_err);
|
|
||||||
if (local_err) {
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
qdict_del(pdict, "qom-type");
|
|
||||||
visit_type_str(v, "qom-type", &type, &local_err);
|
|
||||||
if (local_err) {
|
|
||||||
goto out_visit;
|
|
||||||
}
|
|
||||||
|
|
||||||
qdict_del(pdict, "id");
|
|
||||||
visit_type_str(v, "id", &id, &local_err);
|
|
||||||
if (local_err) {
|
|
||||||
goto out_visit;
|
|
||||||
}
|
|
||||||
visit_check_struct(v, &local_err);
|
|
||||||
if (local_err) {
|
|
||||||
goto out_visit;
|
|
||||||
}
|
|
||||||
|
|
||||||
obj = user_creatable_add_type(type, id, pdict, v, &local_err);
|
|
||||||
|
|
||||||
out_visit:
|
|
||||||
visit_end_struct(v, NULL);
|
|
||||||
|
|
||||||
out:
|
|
||||||
QDECREF(pdict);
|
|
||||||
g_free(id);
|
|
||||||
g_free(type);
|
|
||||||
if (local_err) {
|
|
||||||
error_propagate(errp, local_err);
|
|
||||||
object_unref(obj);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Object *user_creatable_add_type(const char *type, const char *id,
|
Object *user_creatable_add_type(const char *type, const char *id,
|
||||||
const QDict *qdict,
|
const QDict *qdict,
|
||||||
Visitor *v, Error **errp)
|
Visitor *v, Error **errp)
|
||||||
|
@ -158,13 +107,31 @@ Object *user_creatable_add_opts(QemuOpts *opts, Error **errp)
|
||||||
{
|
{
|
||||||
Visitor *v;
|
Visitor *v;
|
||||||
QDict *pdict;
|
QDict *pdict;
|
||||||
Object *obj = NULL;
|
Object *obj;
|
||||||
|
const char *id = qemu_opts_id(opts);
|
||||||
|
char *type = qemu_opt_get_del(opts, "qom-type");
|
||||||
|
|
||||||
v = opts_visitor_new(opts);
|
if (!type) {
|
||||||
|
error_setg(errp, QERR_MISSING_PARAMETER, "qom-type");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (!id) {
|
||||||
|
error_setg(errp, QERR_MISSING_PARAMETER, "id");
|
||||||
|
qemu_opt_set(opts, "qom-type", type, &error_abort);
|
||||||
|
g_free(type);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
qemu_opts_set_id(opts, NULL);
|
||||||
pdict = qemu_opts_to_qdict(opts, NULL);
|
pdict = qemu_opts_to_qdict(opts, NULL);
|
||||||
|
|
||||||
obj = user_creatable_add(pdict, v, errp);
|
v = opts_visitor_new(opts);
|
||||||
|
obj = user_creatable_add_type(type, id, pdict, v, errp);
|
||||||
visit_free(v);
|
visit_free(v);
|
||||||
|
|
||||||
|
qemu_opts_set_id(opts, (char *) id);
|
||||||
|
qemu_opt_set(opts, "qom-type", type, &error_abort);
|
||||||
|
g_free(type);
|
||||||
QDECREF(pdict);
|
QDECREF(pdict);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 8891697e3f7d84355420573efd98e94f14736768
|
Subproject commit 5f4c7b13cdf9c450eb55645f4362ea58fa61b79b
|
|
@ -527,7 +527,7 @@ static inline void assert_fp_access_checked(DisasContext *s)
|
||||||
static inline int vec_reg_offset(DisasContext *s, int regno,
|
static inline int vec_reg_offset(DisasContext *s, int regno,
|
||||||
int element, TCGMemOp size)
|
int element, TCGMemOp size)
|
||||||
{
|
{
|
||||||
int offs = offsetof(CPUARMState, vfp.regs[regno * 2]);
|
int offs = 0;
|
||||||
#ifdef HOST_WORDS_BIGENDIAN
|
#ifdef HOST_WORDS_BIGENDIAN
|
||||||
/* This is complicated slightly because vfp.regs[2n] is
|
/* This is complicated slightly because vfp.regs[2n] is
|
||||||
* still the low half and vfp.regs[2n+1] the high half
|
* still the low half and vfp.regs[2n+1] the high half
|
||||||
|
@ -540,6 +540,7 @@ static inline int vec_reg_offset(DisasContext *s, int regno,
|
||||||
#else
|
#else
|
||||||
offs += element * (1 << size);
|
offs += element * (1 << size);
|
||||||
#endif
|
#endif
|
||||||
|
offs += offsetof(CPUARMState, vfp.regs[regno * 2]);
|
||||||
assert_fp_access_checked(s);
|
assert_fp_access_checked(s);
|
||||||
return offs;
|
return offs;
|
||||||
}
|
}
|
||||||
|
@ -2829,9 +2830,9 @@ static void disas_ldst_single_struct(DisasContext *s, uint32_t insn)
|
||||||
} else {
|
} else {
|
||||||
/* Load/store one element per register */
|
/* Load/store one element per register */
|
||||||
if (is_load) {
|
if (is_load) {
|
||||||
do_vec_ld(s, rt, index, tcg_addr, s->be_data + scale);
|
do_vec_ld(s, rt, index, tcg_addr, scale);
|
||||||
} else {
|
} else {
|
||||||
do_vec_st(s, rt, index, tcg_addr, s->be_data + scale);
|
do_vec_st(s, rt, index, tcg_addr, scale);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tcg_gen_addi_i64(tcg_addr, tcg_addr, ebytes);
|
tcg_gen_addi_i64(tcg_addr, tcg_addr, ebytes);
|
||||||
|
|
|
@ -1610,8 +1610,9 @@ void helper_lock_init(void);
|
||||||
|
|
||||||
/* svm_helper.c */
|
/* svm_helper.c */
|
||||||
void cpu_svm_check_intercept_param(CPUX86State *env1, uint32_t type,
|
void cpu_svm_check_intercept_param(CPUX86State *env1, uint32_t type,
|
||||||
uint64_t param);
|
uint64_t param, uintptr_t retaddr);
|
||||||
void cpu_vmexit(CPUX86State *nenv, uint32_t exit_code, uint64_t exit_info_1);
|
void cpu_vmexit(CPUX86State *nenv, uint32_t exit_code, uint64_t exit_info_1,
|
||||||
|
uintptr_t retaddr);
|
||||||
|
|
||||||
/* seg_helper.c */
|
/* seg_helper.c */
|
||||||
void do_interrupt_x86_hardirq(CPUX86State *env, int intno, int is_hw);
|
void do_interrupt_x86_hardirq(CPUX86State *env, int intno, int is_hw);
|
||||||
|
|
|
@ -39,7 +39,8 @@ void helper_raise_exception(CPUX86State *env, int exception_index)
|
||||||
* needed. It should only be called, if this is not an interrupt.
|
* needed. It should only be called, if this is not an interrupt.
|
||||||
* Returns the new exception number.
|
* Returns the new exception number.
|
||||||
*/
|
*/
|
||||||
static int check_exception(CPUX86State *env, int intno, int *error_code)
|
static int check_exception(CPUX86State *env, int intno, int *error_code,
|
||||||
|
uintptr_t retaddr)
|
||||||
{
|
{
|
||||||
int first_contributory = env->old_exception == 0 ||
|
int first_contributory = env->old_exception == 0 ||
|
||||||
(env->old_exception >= 10 &&
|
(env->old_exception >= 10 &&
|
||||||
|
@ -53,7 +54,7 @@ static int check_exception(CPUX86State *env, int intno, int *error_code)
|
||||||
#if !defined(CONFIG_USER_ONLY)
|
#if !defined(CONFIG_USER_ONLY)
|
||||||
if (env->old_exception == EXCP08_DBLE) {
|
if (env->old_exception == EXCP08_DBLE) {
|
||||||
if (env->hflags & HF_SVMI_MASK) {
|
if (env->hflags & HF_SVMI_MASK) {
|
||||||
cpu_vmexit(env, SVM_EXIT_SHUTDOWN, 0); /* does not return */
|
cpu_vmexit(env, SVM_EXIT_SHUTDOWN, 0, retaddr); /* does not return */
|
||||||
}
|
}
|
||||||
|
|
||||||
qemu_log_mask(CPU_LOG_RESET, "Triple fault\n");
|
qemu_log_mask(CPU_LOG_RESET, "Triple fault\n");
|
||||||
|
@ -93,10 +94,10 @@ static void QEMU_NORETURN raise_interrupt2(CPUX86State *env, int intno,
|
||||||
|
|
||||||
if (!is_int) {
|
if (!is_int) {
|
||||||
cpu_svm_check_intercept_param(env, SVM_EXIT_EXCP_BASE + intno,
|
cpu_svm_check_intercept_param(env, SVM_EXIT_EXCP_BASE + intno,
|
||||||
error_code);
|
error_code, retaddr);
|
||||||
intno = check_exception(env, intno, &error_code);
|
intno = check_exception(env, intno, &error_code, retaddr);
|
||||||
} else {
|
} else {
|
||||||
cpu_svm_check_intercept_param(env, SVM_EXIT_SWINT, 0);
|
cpu_svm_check_intercept_param(env, SVM_EXIT_SWINT, 0, retaddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
cs->exception_index = intno;
|
cs->exception_index = intno;
|
||||||
|
|
|
@ -98,7 +98,6 @@ DEF_HELPER_2(inl, tl, env, i32)
|
||||||
DEF_HELPER_FLAGS_4(bpt_io, TCG_CALL_NO_WG, void, env, i32, i32, tl)
|
DEF_HELPER_FLAGS_4(bpt_io, TCG_CALL_NO_WG, void, env, i32, i32, tl)
|
||||||
|
|
||||||
DEF_HELPER_3(svm_check_intercept_param, void, env, i32, i64)
|
DEF_HELPER_3(svm_check_intercept_param, void, env, i32, i64)
|
||||||
DEF_HELPER_3(vmexit, void, env, i32, i64)
|
|
||||||
DEF_HELPER_4(svm_check_io, void, env, i32, i32, i32)
|
DEF_HELPER_4(svm_check_io, void, env, i32, i32, i32)
|
||||||
DEF_HELPER_3(vmrun, void, env, int, int)
|
DEF_HELPER_3(vmrun, void, env, int, int)
|
||||||
DEF_HELPER_1(vmmcall, void, env)
|
DEF_HELPER_1(vmmcall, void, env)
|
||||||
|
|
|
@ -101,7 +101,7 @@ void helper_cpuid(CPUX86State *env)
|
||||||
{
|
{
|
||||||
uint32_t eax, ebx, ecx, edx;
|
uint32_t eax, ebx, ecx, edx;
|
||||||
|
|
||||||
cpu_svm_check_intercept_param(env, SVM_EXIT_CPUID, 0);
|
cpu_svm_check_intercept_param(env, SVM_EXIT_CPUID, 0, GETPC());
|
||||||
|
|
||||||
cpu_x86_cpuid(env, (uint32_t)env->regs[R_EAX], (uint32_t)env->regs[R_ECX],
|
cpu_x86_cpuid(env, (uint32_t)env->regs[R_EAX], (uint32_t)env->regs[R_ECX],
|
||||||
&eax, &ebx, &ecx, &edx);
|
&eax, &ebx, &ecx, &edx);
|
||||||
|
@ -125,7 +125,7 @@ target_ulong helper_read_crN(CPUX86State *env, int reg)
|
||||||
{
|
{
|
||||||
target_ulong val;
|
target_ulong val;
|
||||||
|
|
||||||
cpu_svm_check_intercept_param(env, SVM_EXIT_READ_CR0 + reg, 0);
|
cpu_svm_check_intercept_param(env, SVM_EXIT_READ_CR0 + reg, 0, GETPC());
|
||||||
switch (reg) {
|
switch (reg) {
|
||||||
default:
|
default:
|
||||||
val = env->cr[reg];
|
val = env->cr[reg];
|
||||||
|
@ -143,7 +143,7 @@ target_ulong helper_read_crN(CPUX86State *env, int reg)
|
||||||
|
|
||||||
void helper_write_crN(CPUX86State *env, int reg, target_ulong t0)
|
void helper_write_crN(CPUX86State *env, int reg, target_ulong t0)
|
||||||
{
|
{
|
||||||
cpu_svm_check_intercept_param(env, SVM_EXIT_WRITE_CR0 + reg, 0);
|
cpu_svm_check_intercept_param(env, SVM_EXIT_WRITE_CR0 + reg, 0, GETPC());
|
||||||
switch (reg) {
|
switch (reg) {
|
||||||
case 0:
|
case 0:
|
||||||
cpu_x86_update_cr0(env, t0);
|
cpu_x86_update_cr0(env, t0);
|
||||||
|
@ -179,7 +179,7 @@ void helper_invlpg(CPUX86State *env, target_ulong addr)
|
||||||
{
|
{
|
||||||
X86CPU *cpu = x86_env_get_cpu(env);
|
X86CPU *cpu = x86_env_get_cpu(env);
|
||||||
|
|
||||||
cpu_svm_check_intercept_param(env, SVM_EXIT_INVLPG, 0);
|
cpu_svm_check_intercept_param(env, SVM_EXIT_INVLPG, 0, GETPC());
|
||||||
tlb_flush_page(CPU(cpu), addr);
|
tlb_flush_page(CPU(cpu), addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,7 +190,7 @@ void helper_rdtsc(CPUX86State *env)
|
||||||
if ((env->cr[4] & CR4_TSD_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) {
|
if ((env->cr[4] & CR4_TSD_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) {
|
||||||
raise_exception_ra(env, EXCP0D_GPF, GETPC());
|
raise_exception_ra(env, EXCP0D_GPF, GETPC());
|
||||||
}
|
}
|
||||||
cpu_svm_check_intercept_param(env, SVM_EXIT_RDTSC, 0);
|
cpu_svm_check_intercept_param(env, SVM_EXIT_RDTSC, 0, GETPC());
|
||||||
|
|
||||||
val = cpu_get_tsc(env) + env->tsc_offset;
|
val = cpu_get_tsc(env) + env->tsc_offset;
|
||||||
env->regs[R_EAX] = (uint32_t)(val);
|
env->regs[R_EAX] = (uint32_t)(val);
|
||||||
|
@ -208,7 +208,7 @@ void helper_rdpmc(CPUX86State *env)
|
||||||
if ((env->cr[4] & CR4_PCE_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) {
|
if ((env->cr[4] & CR4_PCE_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) {
|
||||||
raise_exception_ra(env, EXCP0D_GPF, GETPC());
|
raise_exception_ra(env, EXCP0D_GPF, GETPC());
|
||||||
}
|
}
|
||||||
cpu_svm_check_intercept_param(env, SVM_EXIT_RDPMC, 0);
|
cpu_svm_check_intercept_param(env, SVM_EXIT_RDPMC, 0, GETPC());
|
||||||
|
|
||||||
/* currently unimplemented */
|
/* currently unimplemented */
|
||||||
qemu_log_mask(LOG_UNIMP, "x86: unimplemented rdpmc\n");
|
qemu_log_mask(LOG_UNIMP, "x86: unimplemented rdpmc\n");
|
||||||
|
@ -228,7 +228,7 @@ void helper_wrmsr(CPUX86State *env)
|
||||||
{
|
{
|
||||||
uint64_t val;
|
uint64_t val;
|
||||||
|
|
||||||
cpu_svm_check_intercept_param(env, SVM_EXIT_MSR, 1);
|
cpu_svm_check_intercept_param(env, SVM_EXIT_MSR, 1, GETPC());
|
||||||
|
|
||||||
val = ((uint32_t)env->regs[R_EAX]) |
|
val = ((uint32_t)env->regs[R_EAX]) |
|
||||||
((uint64_t)((uint32_t)env->regs[R_EDX]) << 32);
|
((uint64_t)((uint32_t)env->regs[R_EDX]) << 32);
|
||||||
|
@ -388,7 +388,7 @@ void helper_rdmsr(CPUX86State *env)
|
||||||
{
|
{
|
||||||
uint64_t val;
|
uint64_t val;
|
||||||
|
|
||||||
cpu_svm_check_intercept_param(env, SVM_EXIT_MSR, 0);
|
cpu_svm_check_intercept_param(env, SVM_EXIT_MSR, 0, GETPC());
|
||||||
|
|
||||||
switch ((uint32_t)env->regs[R_ECX]) {
|
switch ((uint32_t)env->regs[R_ECX]) {
|
||||||
case MSR_IA32_SYSENTER_CS:
|
case MSR_IA32_SYSENTER_CS:
|
||||||
|
@ -557,7 +557,7 @@ void helper_hlt(CPUX86State *env, int next_eip_addend)
|
||||||
{
|
{
|
||||||
X86CPU *cpu = x86_env_get_cpu(env);
|
X86CPU *cpu = x86_env_get_cpu(env);
|
||||||
|
|
||||||
cpu_svm_check_intercept_param(env, SVM_EXIT_HLT, 0);
|
cpu_svm_check_intercept_param(env, SVM_EXIT_HLT, 0, GETPC());
|
||||||
env->eip += next_eip_addend;
|
env->eip += next_eip_addend;
|
||||||
|
|
||||||
do_hlt(cpu);
|
do_hlt(cpu);
|
||||||
|
@ -569,7 +569,7 @@ void helper_monitor(CPUX86State *env, target_ulong ptr)
|
||||||
raise_exception_ra(env, EXCP0D_GPF, GETPC());
|
raise_exception_ra(env, EXCP0D_GPF, GETPC());
|
||||||
}
|
}
|
||||||
/* XXX: store address? */
|
/* XXX: store address? */
|
||||||
cpu_svm_check_intercept_param(env, SVM_EXIT_MONITOR, 0);
|
cpu_svm_check_intercept_param(env, SVM_EXIT_MONITOR, 0, GETPC());
|
||||||
}
|
}
|
||||||
|
|
||||||
void helper_mwait(CPUX86State *env, int next_eip_addend)
|
void helper_mwait(CPUX86State *env, int next_eip_addend)
|
||||||
|
@ -580,7 +580,7 @@ void helper_mwait(CPUX86State *env, int next_eip_addend)
|
||||||
if ((uint32_t)env->regs[R_ECX] != 0) {
|
if ((uint32_t)env->regs[R_ECX] != 0) {
|
||||||
raise_exception_ra(env, EXCP0D_GPF, GETPC());
|
raise_exception_ra(env, EXCP0D_GPF, GETPC());
|
||||||
}
|
}
|
||||||
cpu_svm_check_intercept_param(env, SVM_EXIT_MWAIT, 0);
|
cpu_svm_check_intercept_param(env, SVM_EXIT_MWAIT, 0, GETPC());
|
||||||
env->eip += next_eip_addend;
|
env->eip += next_eip_addend;
|
||||||
|
|
||||||
cpu = x86_env_get_cpu(env);
|
cpu = x86_env_get_cpu(env);
|
||||||
|
@ -597,7 +597,7 @@ void helper_pause(CPUX86State *env, int next_eip_addend)
|
||||||
{
|
{
|
||||||
X86CPU *cpu = x86_env_get_cpu(env);
|
X86CPU *cpu = x86_env_get_cpu(env);
|
||||||
|
|
||||||
cpu_svm_check_intercept_param(env, SVM_EXIT_PAUSE, 0);
|
cpu_svm_check_intercept_param(env, SVM_EXIT_PAUSE, 0, GETPC());
|
||||||
env->eip += next_eip_addend;
|
env->eip += next_eip_addend;
|
||||||
|
|
||||||
do_pause(cpu);
|
do_pause(cpu);
|
||||||
|
|
|
@ -1334,7 +1334,7 @@ bool x86_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
|
||||||
} else if (env->hflags2 & HF2_GIF_MASK) {
|
} else if (env->hflags2 & HF2_GIF_MASK) {
|
||||||
if ((interrupt_request & CPU_INTERRUPT_SMI) &&
|
if ((interrupt_request & CPU_INTERRUPT_SMI) &&
|
||||||
!(env->hflags & HF_SMM_MASK)) {
|
!(env->hflags & HF_SMM_MASK)) {
|
||||||
cpu_svm_check_intercept_param(env, SVM_EXIT_SMI, 0);
|
cpu_svm_check_intercept_param(env, SVM_EXIT_SMI, 0, 0);
|
||||||
cs->interrupt_request &= ~CPU_INTERRUPT_SMI;
|
cs->interrupt_request &= ~CPU_INTERRUPT_SMI;
|
||||||
do_smm_enter(cpu);
|
do_smm_enter(cpu);
|
||||||
ret = true;
|
ret = true;
|
||||||
|
@ -1355,7 +1355,7 @@ bool x86_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
|
||||||
(env->eflags & IF_MASK &&
|
(env->eflags & IF_MASK &&
|
||||||
!(env->hflags & HF_INHIBIT_IRQ_MASK))))) {
|
!(env->hflags & HF_INHIBIT_IRQ_MASK))))) {
|
||||||
int intno;
|
int intno;
|
||||||
cpu_svm_check_intercept_param(env, SVM_EXIT_INTR, 0);
|
cpu_svm_check_intercept_param(env, SVM_EXIT_INTR, 0, 0);
|
||||||
cs->interrupt_request &= ~(CPU_INTERRUPT_HARD |
|
cs->interrupt_request &= ~(CPU_INTERRUPT_HARD |
|
||||||
CPU_INTERRUPT_VIRQ);
|
CPU_INTERRUPT_VIRQ);
|
||||||
intno = cpu_get_pic_interrupt(env);
|
intno = cpu_get_pic_interrupt(env);
|
||||||
|
@ -1371,7 +1371,7 @@ bool x86_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
|
||||||
!(env->hflags & HF_INHIBIT_IRQ_MASK)) {
|
!(env->hflags & HF_INHIBIT_IRQ_MASK)) {
|
||||||
int intno;
|
int intno;
|
||||||
/* FIXME: this should respect TPR */
|
/* FIXME: this should respect TPR */
|
||||||
cpu_svm_check_intercept_param(env, SVM_EXIT_VINTR, 0);
|
cpu_svm_check_intercept_param(env, SVM_EXIT_VINTR, 0, 0);
|
||||||
intno = x86_ldl_phys(cs, env->vm_vmcb
|
intno = x86_ldl_phys(cs, env->vm_vmcb
|
||||||
+ offsetof(struct vmcb, control.int_vector));
|
+ offsetof(struct vmcb, control.int_vector));
|
||||||
qemu_log_mask(CPU_LOG_TB_IN_ASM,
|
qemu_log_mask(CPU_LOG_TB_IN_ASM,
|
||||||
|
|
|
@ -60,11 +60,8 @@ void helper_invlpga(CPUX86State *env, int aflag)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void helper_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1)
|
void cpu_vmexit(CPUX86State *nenv, uint32_t exit_code, uint64_t exit_info_1,
|
||||||
{
|
uintptr_t retaddr)
|
||||||
}
|
|
||||||
|
|
||||||
void cpu_vmexit(CPUX86State *nenv, uint32_t exit_code, uint64_t exit_info_1)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +71,7 @@ void helper_svm_check_intercept_param(CPUX86State *env, uint32_t type,
|
||||||
}
|
}
|
||||||
|
|
||||||
void cpu_svm_check_intercept_param(CPUX86State *env, uint32_t type,
|
void cpu_svm_check_intercept_param(CPUX86State *env, uint32_t type,
|
||||||
uint64_t param)
|
uint64_t param, uintptr_t retaddr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,7 +127,7 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
|
||||||
uint32_t event_inj;
|
uint32_t event_inj;
|
||||||
uint32_t int_ctl;
|
uint32_t int_ctl;
|
||||||
|
|
||||||
cpu_svm_check_intercept_param(env, SVM_EXIT_VMRUN, 0);
|
cpu_svm_check_intercept_param(env, SVM_EXIT_VMRUN, 0, GETPC());
|
||||||
|
|
||||||
if (aflag == 2) {
|
if (aflag == 2) {
|
||||||
addr = env->regs[R_EAX];
|
addr = env->regs[R_EAX];
|
||||||
|
@ -355,7 +352,7 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
|
||||||
|
|
||||||
void helper_vmmcall(CPUX86State *env)
|
void helper_vmmcall(CPUX86State *env)
|
||||||
{
|
{
|
||||||
cpu_svm_check_intercept_param(env, SVM_EXIT_VMMCALL, 0);
|
cpu_svm_check_intercept_param(env, SVM_EXIT_VMMCALL, 0, GETPC());
|
||||||
raise_exception(env, EXCP06_ILLOP);
|
raise_exception(env, EXCP06_ILLOP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -364,7 +361,7 @@ void helper_vmload(CPUX86State *env, int aflag)
|
||||||
CPUState *cs = CPU(x86_env_get_cpu(env));
|
CPUState *cs = CPU(x86_env_get_cpu(env));
|
||||||
target_ulong addr;
|
target_ulong addr;
|
||||||
|
|
||||||
cpu_svm_check_intercept_param(env, SVM_EXIT_VMLOAD, 0);
|
cpu_svm_check_intercept_param(env, SVM_EXIT_VMLOAD, 0, GETPC());
|
||||||
|
|
||||||
if (aflag == 2) {
|
if (aflag == 2) {
|
||||||
addr = env->regs[R_EAX];
|
addr = env->regs[R_EAX];
|
||||||
|
@ -404,7 +401,7 @@ void helper_vmsave(CPUX86State *env, int aflag)
|
||||||
CPUState *cs = CPU(x86_env_get_cpu(env));
|
CPUState *cs = CPU(x86_env_get_cpu(env));
|
||||||
target_ulong addr;
|
target_ulong addr;
|
||||||
|
|
||||||
cpu_svm_check_intercept_param(env, SVM_EXIT_VMSAVE, 0);
|
cpu_svm_check_intercept_param(env, SVM_EXIT_VMSAVE, 0, GETPC());
|
||||||
|
|
||||||
if (aflag == 2) {
|
if (aflag == 2) {
|
||||||
addr = env->regs[R_EAX];
|
addr = env->regs[R_EAX];
|
||||||
|
@ -445,19 +442,19 @@ void helper_vmsave(CPUX86State *env, int aflag)
|
||||||
|
|
||||||
void helper_stgi(CPUX86State *env)
|
void helper_stgi(CPUX86State *env)
|
||||||
{
|
{
|
||||||
cpu_svm_check_intercept_param(env, SVM_EXIT_STGI, 0);
|
cpu_svm_check_intercept_param(env, SVM_EXIT_STGI, 0, GETPC());
|
||||||
env->hflags2 |= HF2_GIF_MASK;
|
env->hflags2 |= HF2_GIF_MASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void helper_clgi(CPUX86State *env)
|
void helper_clgi(CPUX86State *env)
|
||||||
{
|
{
|
||||||
cpu_svm_check_intercept_param(env, SVM_EXIT_CLGI, 0);
|
cpu_svm_check_intercept_param(env, SVM_EXIT_CLGI, 0, GETPC());
|
||||||
env->hflags2 &= ~HF2_GIF_MASK;
|
env->hflags2 &= ~HF2_GIF_MASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void helper_skinit(CPUX86State *env)
|
void helper_skinit(CPUX86State *env)
|
||||||
{
|
{
|
||||||
cpu_svm_check_intercept_param(env, SVM_EXIT_SKINIT, 0);
|
cpu_svm_check_intercept_param(env, SVM_EXIT_SKINIT, 0, GETPC());
|
||||||
/* XXX: not implemented */
|
/* XXX: not implemented */
|
||||||
raise_exception(env, EXCP06_ILLOP);
|
raise_exception(env, EXCP06_ILLOP);
|
||||||
}
|
}
|
||||||
|
@ -467,7 +464,7 @@ void helper_invlpga(CPUX86State *env, int aflag)
|
||||||
X86CPU *cpu = x86_env_get_cpu(env);
|
X86CPU *cpu = x86_env_get_cpu(env);
|
||||||
target_ulong addr;
|
target_ulong addr;
|
||||||
|
|
||||||
cpu_svm_check_intercept_param(env, SVM_EXIT_INVLPGA, 0);
|
cpu_svm_check_intercept_param(env, SVM_EXIT_INVLPGA, 0, GETPC());
|
||||||
|
|
||||||
if (aflag == 2) {
|
if (aflag == 2) {
|
||||||
addr = env->regs[R_EAX];
|
addr = env->regs[R_EAX];
|
||||||
|
@ -480,8 +477,8 @@ void helper_invlpga(CPUX86State *env, int aflag)
|
||||||
tlb_flush_page(CPU(cpu), addr);
|
tlb_flush_page(CPU(cpu), addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void helper_svm_check_intercept_param(CPUX86State *env, uint32_t type,
|
void cpu_svm_check_intercept_param(CPUX86State *env, uint32_t type,
|
||||||
uint64_t param)
|
uint64_t param, uintptr_t retaddr)
|
||||||
{
|
{
|
||||||
CPUState *cs = CPU(x86_env_get_cpu(env));
|
CPUState *cs = CPU(x86_env_get_cpu(env));
|
||||||
|
|
||||||
|
@ -491,27 +488,27 @@ void helper_svm_check_intercept_param(CPUX86State *env, uint32_t type,
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case SVM_EXIT_READ_CR0 ... SVM_EXIT_READ_CR0 + 8:
|
case SVM_EXIT_READ_CR0 ... SVM_EXIT_READ_CR0 + 8:
|
||||||
if (env->intercept_cr_read & (1 << (type - SVM_EXIT_READ_CR0))) {
|
if (env->intercept_cr_read & (1 << (type - SVM_EXIT_READ_CR0))) {
|
||||||
helper_vmexit(env, type, param);
|
cpu_vmexit(env, type, param, retaddr);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SVM_EXIT_WRITE_CR0 ... SVM_EXIT_WRITE_CR0 + 8:
|
case SVM_EXIT_WRITE_CR0 ... SVM_EXIT_WRITE_CR0 + 8:
|
||||||
if (env->intercept_cr_write & (1 << (type - SVM_EXIT_WRITE_CR0))) {
|
if (env->intercept_cr_write & (1 << (type - SVM_EXIT_WRITE_CR0))) {
|
||||||
helper_vmexit(env, type, param);
|
cpu_vmexit(env, type, param, retaddr);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SVM_EXIT_READ_DR0 ... SVM_EXIT_READ_DR0 + 7:
|
case SVM_EXIT_READ_DR0 ... SVM_EXIT_READ_DR0 + 7:
|
||||||
if (env->intercept_dr_read & (1 << (type - SVM_EXIT_READ_DR0))) {
|
if (env->intercept_dr_read & (1 << (type - SVM_EXIT_READ_DR0))) {
|
||||||
helper_vmexit(env, type, param);
|
cpu_vmexit(env, type, param, retaddr);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SVM_EXIT_WRITE_DR0 ... SVM_EXIT_WRITE_DR0 + 7:
|
case SVM_EXIT_WRITE_DR0 ... SVM_EXIT_WRITE_DR0 + 7:
|
||||||
if (env->intercept_dr_write & (1 << (type - SVM_EXIT_WRITE_DR0))) {
|
if (env->intercept_dr_write & (1 << (type - SVM_EXIT_WRITE_DR0))) {
|
||||||
helper_vmexit(env, type, param);
|
cpu_vmexit(env, type, param, retaddr);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 31:
|
case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 31:
|
||||||
if (env->intercept_exceptions & (1 << (type - SVM_EXIT_EXCP_BASE))) {
|
if (env->intercept_exceptions & (1 << (type - SVM_EXIT_EXCP_BASE))) {
|
||||||
helper_vmexit(env, type, param);
|
cpu_vmexit(env, type, param, retaddr);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SVM_EXIT_MSR:
|
case SVM_EXIT_MSR:
|
||||||
|
@ -538,28 +535,28 @@ void helper_svm_check_intercept_param(CPUX86State *env, uint32_t type,
|
||||||
t0 %= 8;
|
t0 %= 8;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
helper_vmexit(env, type, param);
|
cpu_vmexit(env, type, param, retaddr);
|
||||||
t0 = 0;
|
t0 = 0;
|
||||||
t1 = 0;
|
t1 = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (x86_ldub_phys(cs, addr + t1) & ((1 << param) << t0)) {
|
if (x86_ldub_phys(cs, addr + t1) & ((1 << param) << t0)) {
|
||||||
helper_vmexit(env, type, param);
|
cpu_vmexit(env, type, param, retaddr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (env->intercept & (1ULL << (type - SVM_EXIT_INTR))) {
|
if (env->intercept & (1ULL << (type - SVM_EXIT_INTR))) {
|
||||||
helper_vmexit(env, type, param);
|
cpu_vmexit(env, type, param, retaddr);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cpu_svm_check_intercept_param(CPUX86State *env, uint32_t type,
|
void helper_svm_check_intercept_param(CPUX86State *env, uint32_t type,
|
||||||
uint64_t param)
|
uint64_t param)
|
||||||
{
|
{
|
||||||
helper_svm_check_intercept_param(env, type, param);
|
cpu_svm_check_intercept_param(env, type, param, GETPC());
|
||||||
}
|
}
|
||||||
|
|
||||||
void helper_svm_check_io(CPUX86State *env, uint32_t port, uint32_t param,
|
void helper_svm_check_io(CPUX86State *env, uint32_t port, uint32_t param,
|
||||||
|
@ -578,17 +575,22 @@ void helper_svm_check_io(CPUX86State *env, uint32_t port, uint32_t param,
|
||||||
x86_stq_phys(cs,
|
x86_stq_phys(cs,
|
||||||
env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2),
|
env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2),
|
||||||
env->eip + next_eip_addend);
|
env->eip + next_eip_addend);
|
||||||
helper_vmexit(env, SVM_EXIT_IOIO, param | (port << 16));
|
cpu_vmexit(env, SVM_EXIT_IOIO, param | (port << 16), GETPC());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Note: currently only 32 bits of exit_code are used */
|
/* Note: currently only 32 bits of exit_code are used */
|
||||||
void helper_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1)
|
void cpu_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1,
|
||||||
|
uintptr_t retaddr)
|
||||||
{
|
{
|
||||||
CPUState *cs = CPU(x86_env_get_cpu(env));
|
CPUState *cs = CPU(x86_env_get_cpu(env));
|
||||||
uint32_t int_ctl;
|
uint32_t int_ctl;
|
||||||
|
|
||||||
|
if (retaddr) {
|
||||||
|
cpu_restore_state(cs, retaddr);
|
||||||
|
}
|
||||||
|
|
||||||
qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmexit(%08x, %016" PRIx64 ", %016"
|
qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmexit(%08x, %016" PRIx64 ", %016"
|
||||||
PRIx64 ", " TARGET_FMT_lx ")!\n",
|
PRIx64 ", " TARGET_FMT_lx ")!\n",
|
||||||
exit_code, exit_info_1,
|
exit_code, exit_info_1,
|
||||||
|
@ -766,9 +768,4 @@ void helper_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1)
|
||||||
cpu_loop_exit(cs);
|
cpu_loop_exit(cs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cpu_vmexit(CPUX86State *env, uint32_t exit_code, uint64_t exit_info_1)
|
|
||||||
{
|
|
||||||
helper_vmexit(env, exit_code, exit_info_1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -659,7 +659,6 @@ static void check_compatibility(const S390CPUModel *max_model,
|
||||||
|
|
||||||
static S390CPUModel *get_max_cpu_model(Error **errp)
|
static S390CPUModel *get_max_cpu_model(Error **errp)
|
||||||
{
|
{
|
||||||
#ifndef CONFIG_USER_ONLY
|
|
||||||
static S390CPUModel max_model;
|
static S390CPUModel max_model;
|
||||||
static bool cached;
|
static bool cached;
|
||||||
|
|
||||||
|
@ -679,7 +678,6 @@ static S390CPUModel *get_max_cpu_model(Error **errp)
|
||||||
cached = true;
|
cached = true;
|
||||||
return &max_model;
|
return &max_model;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -197,7 +197,7 @@ void kvm_s390_cmma_reset(void)
|
||||||
.attr = KVM_S390_VM_MEM_CLR_CMMA,
|
.attr = KVM_S390_VM_MEM_CLR_CMMA,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!mem_path || !kvm_s390_cmma_available()) {
|
if (mem_path || !kvm_s390_cmma_available()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2425,8 +2425,31 @@ static void gen_ldstub_asi(DisasContext *dc, TCGv dst, TCGv addr, int insn)
|
||||||
gen_ldstub(dc, dst, addr, da.mem_idx);
|
gen_ldstub(dc, dst, addr, da.mem_idx);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* ??? Should be DAE_invalid_asi. */
|
/* ??? In theory, this should be raise DAE_invalid_asi.
|
||||||
gen_exception(dc, TT_DATA_ACCESS);
|
But the SS-20 roms do ldstuba [%l0] #ASI_M_CTL, %o1. */
|
||||||
|
if (parallel_cpus) {
|
||||||
|
gen_helper_exit_atomic(cpu_env);
|
||||||
|
} else {
|
||||||
|
TCGv_i32 r_asi = tcg_const_i32(da.asi);
|
||||||
|
TCGv_i32 r_mop = tcg_const_i32(MO_UB);
|
||||||
|
TCGv_i64 s64, t64;
|
||||||
|
|
||||||
|
save_state(dc);
|
||||||
|
t64 = tcg_temp_new_i64();
|
||||||
|
gen_helper_ld_asi(t64, cpu_env, addr, r_asi, r_mop);
|
||||||
|
|
||||||
|
s64 = tcg_const_i64(0xff);
|
||||||
|
gen_helper_st_asi(cpu_env, addr, s64, r_asi, r_mop);
|
||||||
|
tcg_temp_free_i64(s64);
|
||||||
|
tcg_temp_free_i32(r_mop);
|
||||||
|
tcg_temp_free_i32(r_asi);
|
||||||
|
|
||||||
|
tcg_gen_trunc_i64_tl(dst, t64);
|
||||||
|
tcg_temp_free_i64(t64);
|
||||||
|
|
||||||
|
/* End the TB. */
|
||||||
|
dc->npc = DYNAMIC_PC;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -581,11 +581,9 @@ static void tcg_out_logicali(TCGContext *s, AArch64Insn insn, TCGType ext,
|
||||||
static void tcg_out_movi(TCGContext *s, TCGType type, TCGReg rd,
|
static void tcg_out_movi(TCGContext *s, TCGType type, TCGReg rd,
|
||||||
tcg_target_long value)
|
tcg_target_long value)
|
||||||
{
|
{
|
||||||
AArch64Insn insn;
|
|
||||||
int i, wantinv, shift;
|
int i, wantinv, shift;
|
||||||
tcg_target_long svalue = value;
|
tcg_target_long svalue = value;
|
||||||
tcg_target_long ivalue = ~value;
|
tcg_target_long ivalue = ~value;
|
||||||
tcg_target_long imask;
|
|
||||||
|
|
||||||
/* For 32-bit values, discard potential garbage in value. For 64-bit
|
/* For 32-bit values, discard potential garbage in value. For 64-bit
|
||||||
values within [2**31, 2**32-1], we can create smaller sequences by
|
values within [2**31, 2**32-1], we can create smaller sequences by
|
||||||
|
@ -631,42 +629,35 @@ static void tcg_out_movi(TCGContext *s, TCGType type, TCGReg rd,
|
||||||
|
|
||||||
/* Would it take fewer insns to begin with MOVN? For the value and its
|
/* Would it take fewer insns to begin with MOVN? For the value and its
|
||||||
inverse, count the number of 16-bit lanes that are 0. */
|
inverse, count the number of 16-bit lanes that are 0. */
|
||||||
for (i = wantinv = imask = 0; i < 64; i += 16) {
|
for (i = wantinv = 0; i < 64; i += 16) {
|
||||||
tcg_target_long mask = 0xffffull << i;
|
tcg_target_long mask = 0xffffull << i;
|
||||||
if ((value & mask) == 0) {
|
wantinv -= ((value & mask) == 0);
|
||||||
wantinv -= 1;
|
wantinv += ((ivalue & mask) == 0);
|
||||||
}
|
|
||||||
if ((ivalue & mask) == 0) {
|
|
||||||
wantinv += 1;
|
|
||||||
imask |= mask;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we had more 0xffff than 0x0000, invert VALUE and use MOVN. */
|
if (wantinv <= 0) {
|
||||||
insn = I3405_MOVZ;
|
/* Find the lowest lane that is not 0x0000. */
|
||||||
if (wantinv > 0) {
|
|
||||||
value = ivalue;
|
|
||||||
insn = I3405_MOVN;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find the lowest lane that is not 0x0000. */
|
|
||||||
shift = ctz64(value) & (63 & -16);
|
|
||||||
tcg_out_insn_3405(s, insn, type, rd, value >> shift, shift);
|
|
||||||
|
|
||||||
if (wantinv > 0) {
|
|
||||||
/* Re-invert the value, so MOVK sees non-inverted bits. */
|
|
||||||
value = ~value;
|
|
||||||
/* Clear out all the 0xffff lanes. */
|
|
||||||
value ^= imask;
|
|
||||||
}
|
|
||||||
/* Clear out the lane that we just set. */
|
|
||||||
value &= ~(0xffffUL << shift);
|
|
||||||
|
|
||||||
/* Iterate until all lanes have been set, and thus cleared from VALUE. */
|
|
||||||
while (value) {
|
|
||||||
shift = ctz64(value) & (63 & -16);
|
shift = ctz64(value) & (63 & -16);
|
||||||
tcg_out_insn(s, 3405, MOVK, type, rd, value >> shift, shift);
|
tcg_out_insn(s, 3405, MOVZ, type, rd, value >> shift, shift);
|
||||||
|
/* Clear out the lane that we just set. */
|
||||||
value &= ~(0xffffUL << shift);
|
value &= ~(0xffffUL << shift);
|
||||||
|
/* Iterate until all non-zero lanes have been processed. */
|
||||||
|
while (value) {
|
||||||
|
shift = ctz64(value) & (63 & -16);
|
||||||
|
tcg_out_insn(s, 3405, MOVK, type, rd, value >> shift, shift);
|
||||||
|
value &= ~(0xffffUL << shift);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Like above, but with the inverted value and MOVN to start. */
|
||||||
|
shift = ctz64(ivalue) & (63 & -16);
|
||||||
|
tcg_out_insn(s, 3405, MOVN, type, rd, ivalue >> shift, shift);
|
||||||
|
ivalue &= ~(0xffffUL << shift);
|
||||||
|
while (ivalue) {
|
||||||
|
shift = ctz64(ivalue) & (63 & -16);
|
||||||
|
/* Provide MOVK with the non-inverted value. */
|
||||||
|
tcg_out_insn(s, 3405, MOVK, type, rd, ~(ivalue >> shift), shift);
|
||||||
|
ivalue &= ~(0xffffUL << shift);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -965,6 +956,15 @@ static inline void tcg_out_addsub2(TCGContext *s, int ext, TCGReg rl,
|
||||||
insn = I3401_SUBSI;
|
insn = I3401_SUBSI;
|
||||||
bl = -bl;
|
bl = -bl;
|
||||||
}
|
}
|
||||||
|
if (unlikely(al == TCG_REG_XZR)) {
|
||||||
|
/* ??? We want to allow al to be zero for the benefit of
|
||||||
|
negation via subtraction. However, that leaves open the
|
||||||
|
possibility of adding 0+const in the low part, and the
|
||||||
|
immediate add instructions encode XSP not XZR. Don't try
|
||||||
|
anything more elaborate here than loading another zero. */
|
||||||
|
al = TCG_REG_TMP;
|
||||||
|
tcg_out_movi(s, ext, al, 0);
|
||||||
|
}
|
||||||
tcg_out_insn_3401(s, insn, ext, rl, al, bl);
|
tcg_out_insn_3401(s, insn, ext, rl, al, bl);
|
||||||
} else {
|
} else {
|
||||||
tcg_out_insn_3502(s, sub ? I3502_SUBS : I3502_ADDS, ext, rl, al, bl);
|
tcg_out_insn_3502(s, sub ? I3502_SUBS : I3502_ADDS, ext, rl, al, bl);
|
||||||
|
|
|
@ -172,6 +172,25 @@ expect_u64_max(OptsVisitorFixture *f, gconstpointer test_data)
|
||||||
|
|
||||||
/* test cases */
|
/* test cases */
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_opts_dict_unvisited(void)
|
||||||
|
{
|
||||||
|
Error *err = NULL;
|
||||||
|
QemuOpts *opts;
|
||||||
|
Visitor *v;
|
||||||
|
UserDefOptions *userdef;
|
||||||
|
|
||||||
|
opts = qemu_opts_parse(qemu_find_opts("userdef"), "i64x=0,bogus=1", false,
|
||||||
|
&error_abort);
|
||||||
|
|
||||||
|
v = opts_visitor_new(opts);
|
||||||
|
visit_type_UserDefOptions(v, NULL, &userdef, &err);
|
||||||
|
error_free_or_abort(&err);
|
||||||
|
visit_free(v);
|
||||||
|
qemu_opts_del(opts);
|
||||||
|
g_assert(!userdef);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
@ -263,6 +282,8 @@ main(int argc, char **argv)
|
||||||
add_test("/visitor/opts/i64/range/2big/full", &expect_fail,
|
add_test("/visitor/opts/i64/range/2big/full", &expect_fail,
|
||||||
"i64=-0x8000000000000000-0x7fffffffffffffff");
|
"i64=-0x8000000000000000-0x7fffffffffffffff");
|
||||||
|
|
||||||
|
g_test_add_func("/visitor/opts/dict/unvisited", test_opts_dict_unvisited);
|
||||||
|
|
||||||
g_test_run();
|
g_test_run();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -185,6 +185,13 @@ restart:
|
||||||
qemu_bh_schedule(pool->completion_bh);
|
qemu_bh_schedule(pool->completion_bh);
|
||||||
|
|
||||||
elem->common.cb(elem->common.opaque, elem->ret);
|
elem->common.cb(elem->common.opaque, elem->ret);
|
||||||
|
|
||||||
|
/* We can safely cancel the completion_bh here regardless of someone
|
||||||
|
* else having scheduled it meanwhile because we reenter the
|
||||||
|
* completion function anyway (goto restart).
|
||||||
|
*/
|
||||||
|
qemu_bh_cancel(pool->completion_bh);
|
||||||
|
|
||||||
qemu_aio_unref(elem);
|
qemu_aio_unref(elem);
|
||||||
goto restart;
|
goto restart;
|
||||||
} else {
|
} else {
|
||||||
|
|
28
ui/console.c
28
ui/console.c
|
@ -1562,27 +1562,6 @@ static void dpy_refresh(DisplayState *s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void dpy_gfx_copy(QemuConsole *con, int src_x, int src_y,
|
|
||||||
int dst_x, int dst_y, int w, int h)
|
|
||||||
{
|
|
||||||
DisplayState *s = con->ds;
|
|
||||||
DisplayChangeListener *dcl;
|
|
||||||
|
|
||||||
if (!qemu_console_is_visible(con)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
QLIST_FOREACH(dcl, &s->listeners, next) {
|
|
||||||
if (con != (dcl->con ? dcl->con : active_console)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (dcl->ops->dpy_gfx_copy) {
|
|
||||||
dcl->ops->dpy_gfx_copy(dcl, src_x, src_y, dst_x, dst_y, w, h);
|
|
||||||
} else { /* TODO */
|
|
||||||
dcl->ops->dpy_gfx_update(dcl, dst_x, dst_y, w, h);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void dpy_text_cursor(QemuConsole *con, int x, int y)
|
void dpy_text_cursor(QemuConsole *con, int x, int y)
|
||||||
{
|
{
|
||||||
DisplayState *s = con->ds;
|
DisplayState *s = con->ds;
|
||||||
|
@ -2120,13 +2099,6 @@ void qemu_console_resize(QemuConsole *s, int width, int height)
|
||||||
dpy_gfx_replace_surface(s, surface);
|
dpy_gfx_replace_surface(s, surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
void qemu_console_copy(QemuConsole *con, int src_x, int src_y,
|
|
||||||
int dst_x, int dst_y, int w, int h)
|
|
||||||
{
|
|
||||||
assert(con->console_type == GRAPHIC_CONSOLE);
|
|
||||||
dpy_gfx_copy(con, src_x, src_y, dst_x, dst_y, w, h);
|
|
||||||
}
|
|
||||||
|
|
||||||
DisplaySurface *qemu_console_surface(QemuConsole *console)
|
DisplaySurface *qemu_console_surface(QemuConsole *console)
|
||||||
{
|
{
|
||||||
return console->surface;
|
return console->surface;
|
||||||
|
|
13
ui/gtk.c
13
ui/gtk.c
|
@ -90,6 +90,9 @@
|
||||||
#ifndef GDK_IS_X11_DISPLAY
|
#ifndef GDK_IS_X11_DISPLAY
|
||||||
#define GDK_IS_X11_DISPLAY(dpy) (dpy == dpy)
|
#define GDK_IS_X11_DISPLAY(dpy) (dpy == dpy)
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef GDK_IS_WAYLAND_DISPLAY
|
||||||
|
#define GDK_IS_WAYLAND_DISPLAY(dpy) (dpy == dpy)
|
||||||
|
#endif
|
||||||
#ifndef GDK_IS_WIN32_DISPLAY
|
#ifndef GDK_IS_WIN32_DISPLAY
|
||||||
#define GDK_IS_WIN32_DISPLAY(dpy) (dpy == dpy)
|
#define GDK_IS_WIN32_DISPLAY(dpy) (dpy == dpy)
|
||||||
#endif
|
#endif
|
||||||
|
@ -1053,6 +1056,10 @@ static int gd_map_keycode(GtkDisplayState *s, GdkDisplay *dpy, int gdk_keycode)
|
||||||
} else {
|
} else {
|
||||||
qemu_keycode = translate_xfree86_keycode(gdk_keycode - 97);
|
qemu_keycode = translate_xfree86_keycode(gdk_keycode - 97);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef GDK_WINDOWING_WAYLAND
|
||||||
|
} else if (GDK_IS_WAYLAND_DISPLAY(dpy) && gdk_keycode < 158) {
|
||||||
|
qemu_keycode = translate_evdev_keycode(gdk_keycode - 97);
|
||||||
#endif
|
#endif
|
||||||
} else if (gdk_keycode == 208) { /* Hiragana_Katakana */
|
} else if (gdk_keycode == 208) { /* Hiragana_Katakana */
|
||||||
qemu_keycode = 0x70;
|
qemu_keycode = 0x70;
|
||||||
|
@ -2171,6 +2178,8 @@ static gboolean gtkinit;
|
||||||
|
|
||||||
void gtk_display_init(DisplayState *ds, bool full_screen, bool grab_on_hover)
|
void gtk_display_init(DisplayState *ds, bool full_screen, bool grab_on_hover)
|
||||||
{
|
{
|
||||||
|
VirtualConsole *vc;
|
||||||
|
|
||||||
GtkDisplayState *s = g_malloc0(sizeof(*s));
|
GtkDisplayState *s = g_malloc0(sizeof(*s));
|
||||||
char *filename;
|
char *filename;
|
||||||
GdkDisplay *window_display;
|
GdkDisplay *window_display;
|
||||||
|
@ -2249,9 +2258,11 @@ void gtk_display_init(DisplayState *ds, bool full_screen, bool grab_on_hover)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
vc = gd_vc_find_current(s);
|
||||||
|
gtk_widget_set_sensitive(s->view_menu, vc != NULL);
|
||||||
#ifdef CONFIG_VTE
|
#ifdef CONFIG_VTE
|
||||||
gtk_widget_set_sensitive(s->copy_item,
|
gtk_widget_set_sensitive(s->copy_item,
|
||||||
gd_vc_find_current(s)->type == GD_VC_VTE);
|
vc && vc->type == GD_VC_VTE);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (full_screen) {
|
if (full_screen) {
|
||||||
|
|
111
ui/vnc.c
111
ui/vnc.c
|
@ -872,105 +872,6 @@ int vnc_send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vnc_copy(VncState *vs, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
|
|
||||||
{
|
|
||||||
/* send bitblit op to the vnc client */
|
|
||||||
vnc_lock_output(vs);
|
|
||||||
vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE);
|
|
||||||
vnc_write_u8(vs, 0);
|
|
||||||
vnc_write_u16(vs, 1); /* number of rects */
|
|
||||||
vnc_framebuffer_update(vs, dst_x, dst_y, w, h, VNC_ENCODING_COPYRECT);
|
|
||||||
vnc_write_u16(vs, src_x);
|
|
||||||
vnc_write_u16(vs, src_y);
|
|
||||||
vnc_unlock_output(vs);
|
|
||||||
vnc_flush(vs);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void vnc_dpy_copy(DisplayChangeListener *dcl,
|
|
||||||
int src_x, int src_y,
|
|
||||||
int dst_x, int dst_y, int w, int h)
|
|
||||||
{
|
|
||||||
VncDisplay *vd = container_of(dcl, VncDisplay, dcl);
|
|
||||||
VncState *vs, *vn;
|
|
||||||
uint8_t *src_row;
|
|
||||||
uint8_t *dst_row;
|
|
||||||
int i, x, y, pitch, inc, w_lim, s;
|
|
||||||
int cmp_bytes;
|
|
||||||
|
|
||||||
if (!vd->server) {
|
|
||||||
/* no client connected */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
vnc_refresh_server_surface(vd);
|
|
||||||
QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) {
|
|
||||||
if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
|
|
||||||
vs->force_update = 1;
|
|
||||||
vnc_update_client(vs, 1, true);
|
|
||||||
/* vs might be free()ed here */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!vd->server) {
|
|
||||||
/* no client connected */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* do bitblit op on the local surface too */
|
|
||||||
pitch = vnc_server_fb_stride(vd);
|
|
||||||
src_row = vnc_server_fb_ptr(vd, src_x, src_y);
|
|
||||||
dst_row = vnc_server_fb_ptr(vd, dst_x, dst_y);
|
|
||||||
y = dst_y;
|
|
||||||
inc = 1;
|
|
||||||
if (dst_y > src_y) {
|
|
||||||
/* copy backwards */
|
|
||||||
src_row += pitch * (h-1);
|
|
||||||
dst_row += pitch * (h-1);
|
|
||||||
pitch = -pitch;
|
|
||||||
y = dst_y + h - 1;
|
|
||||||
inc = -1;
|
|
||||||
}
|
|
||||||
w_lim = w - (VNC_DIRTY_PIXELS_PER_BIT - (dst_x % VNC_DIRTY_PIXELS_PER_BIT));
|
|
||||||
if (w_lim < 0) {
|
|
||||||
w_lim = w;
|
|
||||||
} else {
|
|
||||||
w_lim = w - (w_lim % VNC_DIRTY_PIXELS_PER_BIT);
|
|
||||||
}
|
|
||||||
for (i = 0; i < h; i++) {
|
|
||||||
for (x = 0; x <= w_lim;
|
|
||||||
x += s, src_row += cmp_bytes, dst_row += cmp_bytes) {
|
|
||||||
if (x == w_lim) {
|
|
||||||
if ((s = w - w_lim) == 0)
|
|
||||||
break;
|
|
||||||
} else if (!x) {
|
|
||||||
s = (VNC_DIRTY_PIXELS_PER_BIT -
|
|
||||||
(dst_x % VNC_DIRTY_PIXELS_PER_BIT));
|
|
||||||
s = MIN(s, w_lim);
|
|
||||||
} else {
|
|
||||||
s = VNC_DIRTY_PIXELS_PER_BIT;
|
|
||||||
}
|
|
||||||
cmp_bytes = s * VNC_SERVER_FB_BYTES;
|
|
||||||
if (memcmp(src_row, dst_row, cmp_bytes) == 0)
|
|
||||||
continue;
|
|
||||||
memmove(dst_row, src_row, cmp_bytes);
|
|
||||||
QTAILQ_FOREACH(vs, &vd->clients, next) {
|
|
||||||
if (!vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
|
|
||||||
set_bit(((x + dst_x) / VNC_DIRTY_PIXELS_PER_BIT),
|
|
||||||
vs->dirty[y]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
src_row += pitch - w * VNC_SERVER_FB_BYTES;
|
|
||||||
dst_row += pitch - w * VNC_SERVER_FB_BYTES;
|
|
||||||
y += inc;
|
|
||||||
}
|
|
||||||
|
|
||||||
QTAILQ_FOREACH(vs, &vd->clients, next) {
|
|
||||||
if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
|
|
||||||
vnc_copy(vs, src_x, src_y, dst_x, dst_y, w, h);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void vnc_mouse_set(DisplayChangeListener *dcl,
|
static void vnc_mouse_set(DisplayChangeListener *dcl,
|
||||||
int x, int y, int visible)
|
int x, int y, int visible)
|
||||||
{
|
{
|
||||||
|
@ -1258,12 +1159,13 @@ ssize_t vnc_client_io_error(VncState *vs, ssize_t ret, Error **errp)
|
||||||
if (ret <= 0) {
|
if (ret <= 0) {
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
VNC_DEBUG("Closing down client sock: EOF\n");
|
VNC_DEBUG("Closing down client sock: EOF\n");
|
||||||
|
vnc_disconnect_start(vs);
|
||||||
} else if (ret != QIO_CHANNEL_ERR_BLOCK) {
|
} else if (ret != QIO_CHANNEL_ERR_BLOCK) {
|
||||||
VNC_DEBUG("Closing down client sock: ret %d (%s)\n",
|
VNC_DEBUG("Closing down client sock: ret %d (%s)\n",
|
||||||
ret, errp ? error_get_pretty(*errp) : "Unknown");
|
ret, errp ? error_get_pretty(*errp) : "Unknown");
|
||||||
|
vnc_disconnect_start(vs);
|
||||||
}
|
}
|
||||||
|
|
||||||
vnc_disconnect_start(vs);
|
|
||||||
if (errp) {
|
if (errp) {
|
||||||
error_free(*errp);
|
error_free(*errp);
|
||||||
*errp = NULL;
|
*errp = NULL;
|
||||||
|
@ -2459,10 +2361,14 @@ static int protocol_client_init(VncState *vs, uint8_t *data, size_t len)
|
||||||
|
|
||||||
pixel_format_message(vs);
|
pixel_format_message(vs);
|
||||||
|
|
||||||
if (qemu_name)
|
if (qemu_name) {
|
||||||
size = snprintf(buf, sizeof(buf), "QEMU (%s)", qemu_name);
|
size = snprintf(buf, sizeof(buf), "QEMU (%s)", qemu_name);
|
||||||
else
|
if (size > sizeof(buf)) {
|
||||||
|
size = sizeof(buf);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
size = snprintf(buf, sizeof(buf), "QEMU");
|
size = snprintf(buf, sizeof(buf), "QEMU");
|
||||||
|
}
|
||||||
|
|
||||||
vnc_write_u32(vs, size);
|
vnc_write_u32(vs, size);
|
||||||
vnc_write(vs, buf, size);
|
vnc_write(vs, buf, size);
|
||||||
|
@ -3118,7 +3024,6 @@ static gboolean vnc_listen_io(QIOChannel *ioc,
|
||||||
static const DisplayChangeListenerOps dcl_ops = {
|
static const DisplayChangeListenerOps dcl_ops = {
|
||||||
.dpy_name = "vnc",
|
.dpy_name = "vnc",
|
||||||
.dpy_refresh = vnc_refresh,
|
.dpy_refresh = vnc_refresh,
|
||||||
.dpy_gfx_copy = vnc_dpy_copy,
|
|
||||||
.dpy_gfx_update = vnc_dpy_update,
|
.dpy_gfx_update = vnc_dpy_update,
|
||||||
.dpy_gfx_switch = vnc_dpy_switch,
|
.dpy_gfx_switch = vnc_dpy_switch,
|
||||||
.dpy_gfx_check_format = qemu_pixman_check_format,
|
.dpy_gfx_check_format = qemu_pixman_check_format,
|
||||||
|
|
|
@ -481,12 +481,6 @@ void qemu_thread_create(QemuThread *thread, const char *name,
|
||||||
if (err) {
|
if (err) {
|
||||||
error_exit(err, __func__);
|
error_exit(err, __func__);
|
||||||
}
|
}
|
||||||
if (mode == QEMU_THREAD_DETACHED) {
|
|
||||||
err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
|
||||||
if (err) {
|
|
||||||
error_exit(err, __func__);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Leave signal handling to the iothread. */
|
/* Leave signal handling to the iothread. */
|
||||||
sigfillset(&set);
|
sigfillset(&set);
|
||||||
|
@ -499,6 +493,12 @@ void qemu_thread_create(QemuThread *thread, const char *name,
|
||||||
qemu_thread_set_name(thread, name);
|
qemu_thread_set_name(thread, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mode == QEMU_THREAD_DETACHED) {
|
||||||
|
err = pthread_detach(thread->thread);
|
||||||
|
if (err) {
|
||||||
|
error_exit(err, __func__);
|
||||||
|
}
|
||||||
|
}
|
||||||
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
|
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
|
||||||
|
|
||||||
pthread_attr_destroy(&attr);
|
pthread_attr_destroy(&attr);
|
||||||
|
|
Loading…
Reference in New Issue