bump version to 2.11.1-1

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
Wolfgang Bumiller 2018-02-22 12:34:57 +01:00
parent db442fc8d3
commit 6838f03890
101 changed files with 5630 additions and 7178 deletions

View File

@ -1,6 +1,6 @@
# also update debian/changelog
KVMVER=2.9.1
KVMPKGREL=9
KVMVER=2.11.1
KVMPKGREL=1
KVMPACKAGE = pve-qemu-kvm
KVMSRC = qemu
@ -25,18 +25,31 @@ submodule:
.PHONY: deb kvm
deb kvm: $(DEBS)
$(DEB_DBG): $(DEB)
$(DEB): | submodule
$(DEB): keycodemapdb | submodule
rm -f *.deb
rm -rf $(BUILDSRC)
mkdir $(BUILDSRC)
cp -a $(KVMSRC)/* $(BUILDSRC)/
cp -a debian $(BUILDSRC)/debian
rm -rf $(BUILDSRC)/ui/keycodemapdb
cp -a keycodemapdb $(BUILDSRC)/ui/
echo "git clone git://git.proxmox.com/git/pve-qemu-kvm.git\\ngit checkout $(GITVERSION)" > $(BUILDSRC)/debian/SOURCE
# set package version
sed -i 's/^pkgversion="".*/pkgversion="${KVMPACKAGE}_${KVMVER}-${KVMPKGREL}"/' $(BUILDSRC)/configure
cd $(BUILDSRC); dpkg-buildpackage -b -rfakeroot -us -uc
lintian $(DEBS) || true
.PHONY: update
update:
cd $(KVMSRC) && git submodule deinit ui/keycodemapdb || true
rm -rf $(KVMSRC)/ui/keycodemapdb
mkdir $(KVMSRC)/ui/keycodemapdb
cd $(KVMSRC) && git submodule update --init ui/keycodemapdb
rm -rf keycodemapdb
mkdir keycodemapdb
cp -R $(KVMSRC)/ui/keycodemapdb/* keycodemapdb/
git add keycodemapdb
.PHONY: upload
upload: $(DEBS)
tar cf - ${DEBS} | ssh repoman@repo.proxmox.com upload --product pve --dist stretch

6
debian/changelog vendored
View File

@ -1,3 +1,9 @@
pve-qemu-kvm (2.11.1-1) stable; urgency=medium
* update to 2.11.1
-- Proxmox Support Team <support@proxmox.com> Thu, 22 Feb 2018 12:34:43 +0100
pve-qemu-kvm (2.9.1-9) stable; urgency=medium
* add EPYC and EPYC-IPBP cpu models

View File

@ -9,7 +9,7 @@ This reverts commit b8eb5512fd8a115f164edbbe897cdf8884920ccb.
1 file changed, 9 insertions(+)
diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c
index 1ef56f8d10..31fb73e9fb 100644
index 78903ea909..cdfbec5e47 100644
--- a/hw/intc/apic_common.c
+++ b/hw/intc/apic_common.c
@@ -257,6 +257,15 @@ static void apic_reset_common(DeviceState *dev)

View File

@ -13,10 +13,10 @@ Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/include/qemu/ratelimit.h b/include/qemu/ratelimit.h
index 8da1232574..324ff04fe2 100644
index 8dece483f5..1b38291823 100644
--- a/include/qemu/ratelimit.h
+++ b/include/qemu/ratelimit.h
@@ -35,7 +35,7 @@ typedef struct {
@@ -36,7 +36,7 @@ typedef struct {
static inline int64_t ratelimit_calculate_delay(RateLimit *limit, uint64_t n)
{
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
@ -25,7 +25,7 @@ index 8da1232574..324ff04fe2 100644
assert(limit->slice_quota && limit->slice_ns);
@@ -54,12 +54,11 @@ static inline int64_t ratelimit_calculate_delay(RateLimit *limit, uint64_t n)
@@ -55,12 +55,11 @@ static inline int64_t ratelimit_calculate_delay(RateLimit *limit, uint64_t n)
return 0;
}

View File

@ -1,74 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Stefan Hajnoczi <stefanha@redhat.com>
Date: Fri, 2 Jun 2017 10:54:24 +0100
Subject: [PATCH] virtio-serial: fix segfault on disconnect
Since commit d4c19cdeeb2f1e474bc426a6da261f1d7346eb5b ("virtio-serial:
add missing virtio_detach_element() call") the following commands may
cause QEMU to segfault:
$ qemu -M accel=kvm -cpu host -m 1G \
-drive if=virtio,file=test.img,format=raw \
-device virtio-serial-pci,id=virtio-serial0 \
-chardev socket,id=channel1,path=/tmp/chardev.sock,server,nowait \
-device virtserialport,chardev=channel1,bus=virtio-serial0.0,id=port1
$ nc -U /tmp/chardev.sock
^C
(guest)$ cat /dev/zero >/dev/vport0p1
The segfault is non-deterministic: if the event loop notices the socket
has been closed then there is no crash. The disconnect has to happen
right before QEMU attempts to write data to the socket.
The backtrace is as follows:
Thread 1 "qemu-system-x86" received signal SIGSEGV, Segmentation fault.
0x00005555557e0698 in do_flush_queued_data (port=0x5555582cedf0, vq=0x7fffcc854290, vdev=0x55555807b1d0) at hw/char/virtio-serial-bus.c:180
180 for (i = port->iov_idx; i < port->elem->out_num; i++) {
#1 0x000055555580d363 in virtio_queue_notify_vq (vq=0x7fffcc854290) at hw/virtio/virtio.c:1524
#2 0x000055555580d363 in virtio_queue_host_notifier_read (n=0x7fffcc8542f8) at hw/virtio/virtio.c:2430
#3 0x0000555555b3482c in aio_dispatch_handlers (ctx=ctx@entry=0x5555566b8c80) at util/aio-posix.c:399
#4 0x0000555555b350d8 in aio_dispatch (ctx=0x5555566b8c80) at util/aio-posix.c:430
#5 0x0000555555b3212e in aio_ctx_dispatch (source=<optimized out>, callback=<optimized out>, user_data=<optimized out>) at util/async.c:261
#6 0x00007fffde71de52 in g_main_context_dispatch () at /lib64/libglib-2.0.so.0
#7 0x0000555555b34353 in glib_pollfds_poll () at util/main-loop.c:213
#8 0x0000555555b34353 in os_host_main_loop_wait (timeout=<optimized out>) at util/main-loop.c:261
#9 0x0000555555b34353 in main_loop_wait (nonblocking=<optimized out>) at util/main-loop.c:517
#10 0x0000555555773207 in main_loop () at vl.c:1917
#11 0x0000555555773207 in main (argc=<optimized out>, argv=<optimized out>, envp=<optimized out>) at vl.c:4751
The do_flush_queued_data() function does not anticipate chardev close
events during vsc->have_data(). It expects port->elem to remain
non-NULL for the duration its for loop.
The fix is simply to return from do_flush_queued_data() if the port
closes because the close event already frees port->elem and drains the
virtqueue - there is nothing left for do_flush_queued_data() to do.
Reported-by: Sitong Liu <siliu@redhat.com>
Reported-by: Min Deng <mdeng@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
hw/char/virtio-serial-bus.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c
index aa9c11ae92..f5bc173844 100644
--- a/hw/char/virtio-serial-bus.c
+++ b/hw/char/virtio-serial-bus.c
@@ -186,6 +186,9 @@ static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
port->elem->out_sg[i].iov_base
+ port->iov_offset,
buf_size);
+ if (!port->elem) { /* bail if we got disconnected */
+ return;
+ }
if (port->throttled) {
port->iov_idx = i;
if (ret > 0) {
--
2.11.0

View File

@ -1,125 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Paolo Bonzini <pbonzini@redhat.com>
Date: Thu, 1 Jun 2017 17:26:14 +0200
Subject: [PATCH] megasas: always store SCSIRequest* into MegasasCmd
This ensures that the request is unref'ed properly, and avoids a
segmentation fault in the new qtest testcase that is added.
This is CVE-2017-9503.
Reported-by: Zhangyanyu <zyy4013@stu.ouc.edu.cn>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
hw/scsi/megasas.c | 31 ++++++++++++++++---------------
1 file changed, 16 insertions(+), 15 deletions(-)
diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c
index 135662df31..734fdaef90 100644
--- a/hw/scsi/megasas.c
+++ b/hw/scsi/megasas.c
@@ -609,6 +609,9 @@ static void megasas_reset_frames(MegasasState *s)
static void megasas_abort_command(MegasasCmd *cmd)
{
/* Never abort internal commands. */
+ if (cmd->dcmd_opcode != -1) {
+ return;
+ }
if (cmd->req != NULL) {
scsi_req_cancel(cmd->req);
}
@@ -1017,7 +1020,6 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun,
uint64_t pd_size;
uint16_t pd_id = ((sdev->id & 0xFF) << 8) | (lun & 0xFF);
uint8_t cmdbuf[6];
- SCSIRequest *req;
size_t len, resid;
if (!cmd->iov_buf) {
@@ -1026,8 +1028,8 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun,
info->inquiry_data[0] = 0x7f; /* Force PQual 0x3, PType 0x1f */
info->vpd_page83[0] = 0x7f;
megasas_setup_inquiry(cmdbuf, 0, sizeof(info->inquiry_data));
- req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, cmd);
- if (!req) {
+ cmd->req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, cmd);
+ if (!cmd->req) {
trace_megasas_dcmd_req_alloc_failed(cmd->index,
"PD get info std inquiry");
g_free(cmd->iov_buf);
@@ -1036,26 +1038,26 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun,
}
trace_megasas_dcmd_internal_submit(cmd->index,
"PD get info std inquiry", lun);
- len = scsi_req_enqueue(req);
+ len = scsi_req_enqueue(cmd->req);
if (len > 0) {
cmd->iov_size = len;
- scsi_req_continue(req);
+ scsi_req_continue(cmd->req);
}
return MFI_STAT_INVALID_STATUS;
} else if (info->inquiry_data[0] != 0x7f && info->vpd_page83[0] == 0x7f) {
megasas_setup_inquiry(cmdbuf, 0x83, sizeof(info->vpd_page83));
- req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, cmd);
- if (!req) {
+ cmd->req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, cmd);
+ if (!cmd->req) {
trace_megasas_dcmd_req_alloc_failed(cmd->index,
"PD get info vpd inquiry");
return MFI_STAT_FLASH_ALLOC_FAIL;
}
trace_megasas_dcmd_internal_submit(cmd->index,
"PD get info vpd inquiry", lun);
- len = scsi_req_enqueue(req);
+ len = scsi_req_enqueue(cmd->req);
if (len > 0) {
cmd->iov_size = len;
- scsi_req_continue(req);
+ scsi_req_continue(cmd->req);
}
return MFI_STAT_INVALID_STATUS;
}
@@ -1217,7 +1219,6 @@ static int megasas_ld_get_info_submit(SCSIDevice *sdev, int lun,
struct mfi_ld_info *info = cmd->iov_buf;
size_t dcmd_size = sizeof(struct mfi_ld_info);
uint8_t cdb[6];
- SCSIRequest *req;
ssize_t len, resid;
uint16_t sdev_id = ((sdev->id & 0xFF) << 8) | (lun & 0xFF);
uint64_t ld_size;
@@ -1226,8 +1227,8 @@ static int megasas_ld_get_info_submit(SCSIDevice *sdev, int lun,
cmd->iov_buf = g_malloc0(dcmd_size);
info = cmd->iov_buf;
megasas_setup_inquiry(cdb, 0x83, sizeof(info->vpd_page83));
- req = scsi_req_new(sdev, cmd->index, lun, cdb, cmd);
- if (!req) {
+ cmd->req = scsi_req_new(sdev, cmd->index, lun, cdb, cmd);
+ if (!cmd->req) {
trace_megasas_dcmd_req_alloc_failed(cmd->index,
"LD get info vpd inquiry");
g_free(cmd->iov_buf);
@@ -1236,10 +1237,10 @@ static int megasas_ld_get_info_submit(SCSIDevice *sdev, int lun,
}
trace_megasas_dcmd_internal_submit(cmd->index,
"LD get info vpd inquiry", lun);
- len = scsi_req_enqueue(req);
+ len = scsi_req_enqueue(cmd->req);
if (len > 0) {
cmd->iov_size = len;
- scsi_req_continue(req);
+ scsi_req_continue(cmd->req);
}
return MFI_STAT_INVALID_STATUS;
}
@@ -1851,7 +1852,7 @@ static void megasas_command_complete(SCSIRequest *req, uint32_t status,
return;
}
- if (cmd->req == NULL) {
+ if (cmd->dcmd_opcode != -1) {
/*
* Internal command complete
*/
--
2.11.0

View File

@ -1,35 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Prasad J Pandit <pjp@fedoraproject.org>
Date: Mon, 17 Jul 2017 17:33:26 +0530
Subject: [PATCH] slirp: check len against dhcp options array end
While parsing dhcp options string in 'dhcp_decode', if an options'
length 'len' appeared towards the end of 'bp_vend' array, ensuing
read could lead to an OOB memory access issue. Add check to avoid it.
This is CVE-2017-11434.
Reported-by: Reno Robert <renorobert@gmail.com>
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
---
slirp/bootp.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/slirp/bootp.c b/slirp/bootp.c
index 5a4646c182..5dd1a415b5 100644
--- a/slirp/bootp.c
+++ b/slirp/bootp.c
@@ -123,6 +123,9 @@ static void dhcp_decode(const struct bootp_t *bp, int *pmsg_type,
if (p >= p_end)
break;
len = *p++;
+ if (p + len > p_end) {
+ break;
+ }
DPRINTF("dhcp: tag=%d len=%d\n", tag, len);
switch(tag) {
--
2.11.0

View File

@ -1,44 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Stefan Hajnoczi <stefanha@redhat.com>
Date: Wed, 9 Aug 2017 17:02:11 +0100
Subject: [PATCH] IDE: Do not flush empty CDROM drives
The block backend changed in a way that flushing empty CDROM drives now
crashes. Amend IDE to avoid doing so until the root problem can be
addressed for 2.11.
Original patch by John Snow <jsnow@redhat.com>.
Reported-by: Kieron Shorrock <kshorrock@paloaltonetworks.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-id: 20170809160212.29976-2-stefanha@redhat.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
hw/ide/core.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 0b48b64d3a..bea39536b0 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -1063,7 +1063,15 @@ static void ide_flush_cache(IDEState *s)
s->status |= BUSY_STAT;
ide_set_retry(s);
block_acct_start(blk_get_stats(s->blk), &s->acct, 0, BLOCK_ACCT_FLUSH);
- s->pio_aiocb = blk_aio_flush(s->blk, ide_flush_cb, s);
+
+ if (blk_bs(s->blk)) {
+ s->pio_aiocb = blk_aio_flush(s->blk, ide_flush_cb, s);
+ } else {
+ /* XXX blk_aio_flush() crashes when blk_bs(blk) is NULL, remove this
+ * temporary workaround when blk_aio_*() functions handle NULL blk_bs.
+ */
+ ide_flush_cb(s, 0);
+ }
}
static void ide_cfata_metadata_inquiry(IDEState *s)
--
2.11.0

View File

@ -1,51 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Fri, 21 Apr 2017 11:16:24 +0200
Subject: [PATCH] bitmap: add bitmap_copy_and_clear_atomic
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Message-id: 20170421091632.30900-2-kraxel@redhat.com
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
include/qemu/bitmap.h | 2 ++
util/bitmap.c | 11 +++++++++++
2 files changed, 13 insertions(+)
diff --git a/include/qemu/bitmap.h b/include/qemu/bitmap.h
index 63ea2d0b1e..c318da12d7 100644
--- a/include/qemu/bitmap.h
+++ b/include/qemu/bitmap.h
@@ -220,6 +220,8 @@ void bitmap_set(unsigned long *map, long i, long len);
void bitmap_set_atomic(unsigned long *map, long i, long len);
void bitmap_clear(unsigned long *map, long start, long nr);
bool bitmap_test_and_clear_atomic(unsigned long *map, long start, long nr);
+void bitmap_copy_and_clear_atomic(unsigned long *dst, unsigned long *src,
+ long nr);
unsigned long bitmap_find_next_zero_area(unsigned long *map,
unsigned long size,
unsigned long start,
diff --git a/util/bitmap.c b/util/bitmap.c
index c1a84ca5e3..efced9a7d8 100644
--- a/util/bitmap.c
+++ b/util/bitmap.c
@@ -287,6 +287,17 @@ bool bitmap_test_and_clear_atomic(unsigned long *map, long start, long nr)
return dirty != 0;
}
+void bitmap_copy_and_clear_atomic(unsigned long *dst, unsigned long *src,
+ long nr)
+{
+ while (nr > 0) {
+ *dst = atomic_xchg(src, 0);
+ dst++;
+ src++;
+ nr -= BITS_PER_LONG;
+ }
+}
+
#define ALIGN_MASK(x,mask) (((x)+(mask))&~(mask))
/**
--
2.11.0

View File

@ -1,241 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Fri, 21 Apr 2017 11:16:25 +0200
Subject: [PATCH] memory: add support getting and using a dirty bitmap copy.
This patch adds support for getting and using a local copy of the dirty
bitmap.
memory_region_snapshot_and_clear_dirty() will create a snapshot of the
dirty bitmap for the specified range, clear the dirty bitmap and return
the copy. The returned bitmap can be a bit larger than requested, the
range is expanded so the code can copy unsigned longs from the bitmap
and avoid atomic bit update operations.
memory_region_snapshot_get_dirty() will return the dirty status of
pages, pretty much like memory_region_get_dirty(), but using the copy
returned by memory_region_copy_and_clear_dirty().
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Message-id: 20170421091632.30900-3-kraxel@redhat.com
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
exec.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++
include/exec/memory.h | 47 +++++++++++++++++++++++++++++++
include/exec/ram_addr.h | 7 +++++
include/qemu/typedefs.h | 1 +
memory.c | 17 +++++++++++
5 files changed, 147 insertions(+)
diff --git a/exec.c b/exec.c
index fcb5b16131..07c2c8ea88 100644
--- a/exec.c
+++ b/exec.c
@@ -223,6 +223,12 @@ struct CPUAddressSpace {
MemoryListener tcg_as_listener;
};
+struct DirtyBitmapSnapshot {
+ ram_addr_t start;
+ ram_addr_t end;
+ unsigned long dirty[];
+};
+
#endif
#if !defined(CONFIG_USER_ONLY)
@@ -1061,6 +1067,75 @@ bool cpu_physical_memory_test_and_clear_dirty(ram_addr_t start,
return dirty;
}
+DirtyBitmapSnapshot *cpu_physical_memory_snapshot_and_clear_dirty
+ (ram_addr_t start, ram_addr_t length, unsigned client)
+{
+ DirtyMemoryBlocks *blocks;
+ unsigned long align = 1UL << (TARGET_PAGE_BITS + BITS_PER_LEVEL);
+ ram_addr_t first = QEMU_ALIGN_DOWN(start, align);
+ ram_addr_t last = QEMU_ALIGN_UP(start + length, align);
+ DirtyBitmapSnapshot *snap;
+ unsigned long page, end, dest;
+
+ snap = g_malloc0(sizeof(*snap) +
+ ((last - first) >> (TARGET_PAGE_BITS + 3)));
+ snap->start = first;
+ snap->end = last;
+
+ page = first >> TARGET_PAGE_BITS;
+ end = last >> TARGET_PAGE_BITS;
+ dest = 0;
+
+ rcu_read_lock();
+
+ blocks = atomic_rcu_read(&ram_list.dirty_memory[client]);
+
+ while (page < end) {
+ unsigned long idx = page / DIRTY_MEMORY_BLOCK_SIZE;
+ unsigned long offset = page % DIRTY_MEMORY_BLOCK_SIZE;
+ unsigned long num = MIN(end - page, DIRTY_MEMORY_BLOCK_SIZE - offset);
+
+ assert(QEMU_IS_ALIGNED(offset, (1 << BITS_PER_LEVEL)));
+ assert(QEMU_IS_ALIGNED(num, (1 << BITS_PER_LEVEL)));
+ offset >>= BITS_PER_LEVEL;
+
+ bitmap_copy_and_clear_atomic(snap->dirty + dest,
+ blocks->blocks[idx] + offset,
+ num);
+ page += num;
+ dest += num >> BITS_PER_LEVEL;
+ }
+
+ rcu_read_unlock();
+
+ if (tcg_enabled()) {
+ tlb_reset_dirty_range_all(start, length);
+ }
+
+ return snap;
+}
+
+bool cpu_physical_memory_snapshot_get_dirty(DirtyBitmapSnapshot *snap,
+ ram_addr_t start,
+ ram_addr_t length)
+{
+ unsigned long page, end;
+
+ assert(start >= snap->start);
+ assert(start + length <= snap->end);
+
+ end = TARGET_PAGE_ALIGN(start + length - snap->start) >> TARGET_PAGE_BITS;
+ page = (start - snap->start) >> TARGET_PAGE_BITS;
+
+ while (page < end) {
+ if (test_bit(page, snap->dirty)) {
+ return true;
+ }
+ page++;
+ }
+ return false;
+}
+
/* Called from RCU critical section */
hwaddr memory_region_section_get_iotlb(CPUState *cpu,
MemoryRegionSection *section,
diff --git a/include/exec/memory.h b/include/exec/memory.h
index f20b191793..1e15e79d00 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -871,6 +871,53 @@ void memory_region_set_dirty(MemoryRegion *mr, hwaddr addr,
*/
bool memory_region_test_and_clear_dirty(MemoryRegion *mr, hwaddr addr,
hwaddr size, unsigned client);
+
+/**
+ * memory_region_snapshot_and_clear_dirty: Get a snapshot of the dirty
+ * bitmap and clear it.
+ *
+ * Creates a snapshot of the dirty bitmap, clears the dirty bitmap and
+ * returns the snapshot. The snapshot can then be used to query dirty
+ * status, using memory_region_snapshot_get_dirty. Unlike
+ * memory_region_test_and_clear_dirty this allows to query the same
+ * page multiple times, which is especially useful for display updates
+ * where the scanlines often are not page aligned.
+ *
+ * The dirty bitmap region which gets copyed into the snapshot (and
+ * cleared afterwards) can be larger than requested. The boundaries
+ * are rounded up/down so complete bitmap longs (covering 64 pages on
+ * 64bit hosts) can be copied over into the bitmap snapshot. Which
+ * isn't a problem for display updates as the extra pages are outside
+ * the visible area, and in case the visible area changes a full
+ * display redraw is due anyway. Should other use cases for this
+ * function emerge we might have to revisit this implementation
+ * detail.
+ *
+ * Use g_free to release DirtyBitmapSnapshot.
+ *
+ * @mr: the memory region being queried.
+ * @addr: the address (relative to the start of the region) being queried.
+ * @size: the size of the range being queried.
+ * @client: the user of the logging information; typically %DIRTY_MEMORY_VGA.
+ */
+DirtyBitmapSnapshot *memory_region_snapshot_and_clear_dirty(MemoryRegion *mr,
+ hwaddr addr,
+ hwaddr size,
+ unsigned client);
+
+/**
+ * memory_region_snapshot_get_dirty: Check whether a range of bytes is dirty
+ * in the specified dirty bitmap snapshot.
+ *
+ * @mr: the memory region being queried.
+ * @snap: the dirty bitmap snapshot
+ * @addr: the address (relative to the start of the region) being queried.
+ * @size: the size of the range being queried.
+ */
+bool memory_region_snapshot_get_dirty(MemoryRegion *mr,
+ DirtyBitmapSnapshot *snap,
+ hwaddr addr, hwaddr size);
+
/**
* memory_region_sync_dirty_bitmap: Synchronize a region's dirty bitmap with
* any external TLBs (e.g. kvm)
diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h
index b05dc84ab9..2b63d7f59e 100644
--- a/include/exec/ram_addr.h
+++ b/include/exec/ram_addr.h
@@ -343,6 +343,13 @@ bool cpu_physical_memory_test_and_clear_dirty(ram_addr_t start,
ram_addr_t length,
unsigned client);
+DirtyBitmapSnapshot *cpu_physical_memory_snapshot_and_clear_dirty
+ (ram_addr_t start, ram_addr_t length, unsigned client);
+
+bool cpu_physical_memory_snapshot_get_dirty(DirtyBitmapSnapshot *snap,
+ ram_addr_t start,
+ ram_addr_t length);
+
static inline void cpu_physical_memory_clear_dirty_range(ram_addr_t start,
ram_addr_t length)
{
diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
index e95f28cfec..f08d327aec 100644
--- a/include/qemu/typedefs.h
+++ b/include/qemu/typedefs.h
@@ -23,6 +23,7 @@ typedef struct CPUAddressSpace CPUAddressSpace;
typedef struct CPUState CPUState;
typedef struct DeviceListener DeviceListener;
typedef struct DeviceState DeviceState;
+typedef struct DirtyBitmapSnapshot DirtyBitmapSnapshot;
typedef struct DisplayChangeListener DisplayChangeListener;
typedef struct DisplayState DisplayState;
typedef struct DisplaySurface DisplaySurface;
diff --git a/memory.c b/memory.c
index 4c95aaf39c..8a0648551f 100644
--- a/memory.c
+++ b/memory.c
@@ -1716,6 +1716,23 @@ bool memory_region_test_and_clear_dirty(MemoryRegion *mr, hwaddr addr,
memory_region_get_ram_addr(mr) + addr, size, client);
}
+DirtyBitmapSnapshot *memory_region_snapshot_and_clear_dirty(MemoryRegion *mr,
+ hwaddr addr,
+ hwaddr size,
+ unsigned client)
+{
+ assert(mr->ram_block);
+ return cpu_physical_memory_snapshot_and_clear_dirty(
+ memory_region_get_ram_addr(mr) + addr, size, client);
+}
+
+bool memory_region_snapshot_get_dirty(MemoryRegion *mr, DirtyBitmapSnapshot *snap,
+ hwaddr addr, hwaddr size)
+{
+ assert(mr->ram_block);
+ return cpu_physical_memory_snapshot_get_dirty(snap,
+ memory_region_get_ram_addr(mr) + addr, size);
+}
void memory_region_sync_dirty_bitmap(MemoryRegion *mr)
{
--
2.11.0

View File

@ -1,63 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Fri, 21 Apr 2017 11:16:26 +0200
Subject: [PATCH] vga: add vga_scanline_invalidated helper
Add vga_scanline_invalidated helper to check whenever a scanline was
invalidated. Add a sanity check to fix OOB read access for display
heights larger than 2048.
Only cirrus uses this, for hardware cursor rendering, so having this
work properly for the first 2048 scanlines only shouldn't be a problem
as the cirrus can't handle large resolutions anyway. Also changing the
invalidated_y_table size would break live migration.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Message-id: 20170421091632.30900-4-kraxel@redhat.com
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/display/vga.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 69c3e1d674..3991b88aac 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -1434,6 +1434,14 @@ void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2)
}
}
+static bool vga_scanline_invalidated(VGACommonState *s, int y)
+{
+ if (y >= VGA_MAX_HEIGHT) {
+ return false;
+ }
+ return s->invalidated_y_table[y >> 5] & (1 << (y & 0x1f));
+}
+
void vga_sync_dirty_bitmap(VGACommonState *s)
{
memory_region_sync_dirty_bitmap(&s->vram);
@@ -1638,8 +1646,8 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
page1 = addr + bwidth - 1;
update |= memory_region_get_dirty(&s->vram, page0, page1 - page0,
DIRTY_MEMORY_VGA);
- /* explicit invalidation for the hardware cursor */
- update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
+ /* explicit invalidation for the hardware cursor (cirrus only) */
+ update |= vga_scanline_invalidated(s, y);
if (update) {
if (y_start < 0)
y_start = y;
@@ -1686,7 +1694,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
page_max - page_min,
DIRTY_MEMORY_VGA);
}
- memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
+ memset(s->invalidated_y_table, 0, sizeof(s->invalidated_y_table));
}
static void vga_draw_blank(VGACommonState *s, int full_update)
--
2.11.0

View File

@ -1,114 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Fri, 21 Apr 2017 11:16:27 +0200
Subject: [PATCH] vga: make display updates thread safe.
The vga code clears the dirty bits *after* reading the framebuffer
memory. So if the guest framebuffer updates hits the race window
between vga reading the framebuffer and vga clearing the dirty bits
vga will miss that update
Fix it by using the new memory_region_copy_and_clear_dirty()
memory_region_copy_get_dirty() functions. That way we clear the
dirty bitmap before reading the framebuffer. Any guest display
updates happening in parallel will be properly tracked in the
dirty bitmap then and the next display refresh will pick them up.
Problem triggers with mttcg only. Before mttcg was merged tcg
never ran in parallel to vga emulation. Using kvm will hide the
problem too, due to qemu operating on a userspace copy of the
kernel's dirty bitmap.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Message-id: 20170421091632.30900-5-kraxel@redhat.com
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/display/vga.c | 36 +++++++++++++++++-------------------
1 file changed, 17 insertions(+), 19 deletions(-)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 3991b88aac..b2516c8d21 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -1465,7 +1465,8 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
DisplaySurface *surface = qemu_console_surface(s->con);
int y1, y, update, linesize, y_start, double_scan, mask, depth;
int width, height, shift_control, line_offset, bwidth, bits;
- ram_addr_t page0, page1, page_min, page_max;
+ ram_addr_t page0, page1;
+ DirtyBitmapSnapshot *snap = NULL;
int disp_width, multi_scan, multi_run;
uint8_t *d;
uint32_t v, addr1, addr;
@@ -1480,9 +1481,6 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
full_update |= update_basic_params(s);
- if (!full_update)
- vga_sync_dirty_bitmap(s);
-
s->get_resolution(s, &width, &height);
disp_width = width;
@@ -1625,11 +1623,17 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
addr1 = (s->start_addr * 4);
bwidth = (width * bits + 7) / 8;
y_start = -1;
- page_min = -1;
- page_max = 0;
d = surface_data(surface);
linesize = surface_stride(surface);
y1 = 0;
+
+ if (!full_update) {
+ vga_sync_dirty_bitmap(s);
+ snap = memory_region_snapshot_and_clear_dirty(&s->vram, addr1,
+ bwidth * height,
+ DIRTY_MEMORY_VGA);
+ }
+
for(y = 0; y < height; y++) {
addr = addr1;
if (!(s->cr[VGA_CRTC_MODE] & 1)) {
@@ -1644,17 +1648,17 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
update = full_update;
page0 = addr;
page1 = addr + bwidth - 1;
- update |= memory_region_get_dirty(&s->vram, page0, page1 - page0,
- DIRTY_MEMORY_VGA);
+ if (full_update) {
+ update = 1;
+ } else {
+ update = memory_region_snapshot_get_dirty(&s->vram, snap,
+ page0, page1 - page0);
+ }
/* explicit invalidation for the hardware cursor (cirrus only) */
update |= vga_scanline_invalidated(s, y);
if (update) {
if (y_start < 0)
y_start = y;
- if (page0 < page_min)
- page_min = page0;
- if (page1 > page_max)
- page_max = page1;
if (!(is_buffer_shared(surface))) {
vga_draw_line(s, d, s->vram_ptr + addr, width);
if (s->cursor_draw_line)
@@ -1687,13 +1691,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
dpy_gfx_update(s->con, 0, y_start,
disp_width, y - y_start);
}
- /* reset modified pages */
- if (page_max >= page_min) {
- memory_region_reset_dirty(&s->vram,
- page_min,
- page_max - page_min,
- DIRTY_MEMORY_VGA);
- }
+ g_free(snap);
memset(s->invalidated_y_table, 0, sizeof(s->invalidated_y_table));
}
--
2.11.0

View File

@ -1,37 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 9 May 2017 12:48:39 +0200
Subject: [PATCH] vga: fix display update region calculation
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
vga display update mis-calculated the region for the dirty bitmap
snapshot in case the scanlines are padded. This can triggere an
assert in cpu_physical_memory_snapshot_get_dirty().
Fixes: fec5e8c92becad223df9d972770522f64aafdb72
Reported-by: Kevin Wolf <kwolf@redhat.com>
Reported-by: 李强 <liqiang6-s@360.cn>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Message-id: 20170509104839.19415-1-kraxel@redhat.com
---
hw/display/vga.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index b2516c8d21..dcc95f88e2 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -1630,7 +1630,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
if (!full_update) {
vga_sync_dirty_bitmap(s);
snap = memory_region_snapshot_and_clear_dirty(&s->vram, addr1,
- bwidth * height,
+ line_offset * height,
DIRTY_MEMORY_VGA);
}
--
2.11.0

View File

@ -1,46 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Fri, 1 Sep 2017 14:57:38 +0200
Subject: [PATCH] vga: fix display update region calculation (split screen)
vga display update mis-calculated the region for the dirty bitmap
snapshot in case split screen mode is used. This can trigger an
assert in cpu_physical_memory_snapshot_get_dirty().
Impact: DoS for privileged guest users.
Fixes: CVE-2017-13673
Fixes: fec5e8c92becad223df9d972770522f64aafdb72
Cc: P J P <ppandit@redhat.com>
Reported-by: David Buchanan <d@vidbuchanan.co.uk>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Message-id: 20170828123307.15392-1-kraxel@redhat.com
---
hw/display/vga.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index dcc95f88e2..533d8d7895 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -1628,9 +1628,15 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
y1 = 0;
if (!full_update) {
+ ram_addr_t region_start = addr1;
+ ram_addr_t region_end = addr1 + line_offset * height;
vga_sync_dirty_bitmap(s);
- snap = memory_region_snapshot_and_clear_dirty(&s->vram, addr1,
- line_offset * height,
+ if (s->line_compare < height) {
+ /* split screen mode */
+ region_start = 0;
+ }
+ snap = memory_region_snapshot_and_clear_dirty(&s->vram, region_start,
+ region_end - region_start,
DIRTY_MEMORY_VGA);
}
--
2.11.0

View File

@ -1,497 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Fri, 1 Sep 2017 14:57:39 +0200
Subject: [PATCH] vga: stop passing pointers to vga_draw_line* functions
Instead pass around the address (aka offset into vga memory).
Add vga_read_* helper functions which apply vbe_size_mask to
the address, to make sure the address stays within the valid
range, similar to the cirrus blitter fixes (commits ffaf857778
and 026aeffcb4).
Impact: DoS for privileged guest users. qemu crashes with
a segfault, when hitting the guard page after vga memory
allocation, while reading vga memory for display updates.
Fixes: CVE-2017-13672
Cc: P J P <ppandit@redhat.com>
Reported-by: David Buchanan <d@vidbuchanan.co.uk>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Message-id: 20170828122906.18993-1-kraxel@redhat.com
---
hw/display/vga-helpers.h | 202 ++++++++++++++++++++++++++---------------------
hw/display/vga.c | 5 +-
hw/display/vga_int.h | 1 +
3 files changed, 114 insertions(+), 94 deletions(-)
diff --git a/hw/display/vga-helpers.h b/hw/display/vga-helpers.h
index 94f6de2046..5a752b3f9e 100644
--- a/hw/display/vga-helpers.h
+++ b/hw/display/vga-helpers.h
@@ -95,20 +95,46 @@ static void vga_draw_glyph9(uint8_t *d, int linesize,
} while (--h);
}
+static inline uint8_t vga_read_byte(VGACommonState *vga, uint32_t addr)
+{
+ return vga->vram_ptr[addr & vga->vbe_size_mask];
+}
+
+static inline uint16_t vga_read_word_le(VGACommonState *vga, uint32_t addr)
+{
+ uint32_t offset = addr & vga->vbe_size_mask & ~1;
+ uint16_t *ptr = (uint16_t *)(vga->vram_ptr + offset);
+ return lduw_le_p(ptr);
+}
+
+static inline uint16_t vga_read_word_be(VGACommonState *vga, uint32_t addr)
+{
+ uint32_t offset = addr & vga->vbe_size_mask & ~1;
+ uint16_t *ptr = (uint16_t *)(vga->vram_ptr + offset);
+ return lduw_be_p(ptr);
+}
+
+static inline uint32_t vga_read_dword_le(VGACommonState *vga, uint32_t addr)
+{
+ uint32_t offset = addr & vga->vbe_size_mask & ~3;
+ uint32_t *ptr = (uint32_t *)(vga->vram_ptr + offset);
+ return ldl_le_p(ptr);
+}
+
/*
* 4 color mode
*/
-static void vga_draw_line2(VGACommonState *s1, uint8_t *d,
- const uint8_t *s, int width)
+static void vga_draw_line2(VGACommonState *vga, uint8_t *d,
+ uint32_t addr, int width)
{
uint32_t plane_mask, *palette, data, v;
int x;
- palette = s1->last_palette;
- plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
+ palette = vga->last_palette;
+ plane_mask = mask16[vga->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
width >>= 3;
for(x = 0; x < width; x++) {
- data = ((uint32_t *)s)[0];
+ data = vga_read_dword_le(vga, addr);
data &= plane_mask;
v = expand2[GET_PLANE(data, 0)];
v |= expand2[GET_PLANE(data, 2)] << 2;
@@ -124,7 +150,7 @@ static void vga_draw_line2(VGACommonState *s1, uint8_t *d,
((uint32_t *)d)[6] = palette[(v >> 4) & 0xf];
((uint32_t *)d)[7] = palette[(v >> 0) & 0xf];
d += 32;
- s += 4;
+ addr += 4;
}
}
@@ -134,17 +160,17 @@ static void vga_draw_line2(VGACommonState *s1, uint8_t *d,
/*
* 4 color mode, dup2 horizontal
*/
-static void vga_draw_line2d2(VGACommonState *s1, uint8_t *d,
- const uint8_t *s, int width)
+static void vga_draw_line2d2(VGACommonState *vga, uint8_t *d,
+ uint32_t addr, int width)
{
uint32_t plane_mask, *palette, data, v;
int x;
- palette = s1->last_palette;
- plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
+ palette = vga->last_palette;
+ plane_mask = mask16[vga->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
width >>= 3;
for(x = 0; x < width; x++) {
- data = ((uint32_t *)s)[0];
+ data = vga_read_dword_le(vga, addr);
data &= plane_mask;
v = expand2[GET_PLANE(data, 0)];
v |= expand2[GET_PLANE(data, 2)] << 2;
@@ -160,24 +186,24 @@ static void vga_draw_line2d2(VGACommonState *s1, uint8_t *d,
PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]);
PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]);
d += 64;
- s += 4;
+ addr += 4;
}
}
/*
* 16 color mode
*/
-static void vga_draw_line4(VGACommonState *s1, uint8_t *d,
- const uint8_t *s, int width)
+static void vga_draw_line4(VGACommonState *vga, uint8_t *d,
+ uint32_t addr, int width)
{
uint32_t plane_mask, data, v, *palette;
int x;
- palette = s1->last_palette;
- plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
+ palette = vga->last_palette;
+ plane_mask = mask16[vga->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
width >>= 3;
for(x = 0; x < width; x++) {
- data = ((uint32_t *)s)[0];
+ data = vga_read_dword_le(vga, addr);
data &= plane_mask;
v = expand4[GET_PLANE(data, 0)];
v |= expand4[GET_PLANE(data, 1)] << 1;
@@ -192,24 +218,24 @@ static void vga_draw_line4(VGACommonState *s1, uint8_t *d,
((uint32_t *)d)[6] = palette[(v >> 4) & 0xf];
((uint32_t *)d)[7] = palette[(v >> 0) & 0xf];
d += 32;
- s += 4;
+ addr += 4;
}
}
/*
* 16 color mode, dup2 horizontal
*/
-static void vga_draw_line4d2(VGACommonState *s1, uint8_t *d,
- const uint8_t *s, int width)
+static void vga_draw_line4d2(VGACommonState *vga, uint8_t *d,
+ uint32_t addr, int width)
{
uint32_t plane_mask, data, v, *palette;
int x;
- palette = s1->last_palette;
- plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
+ palette = vga->last_palette;
+ plane_mask = mask16[vga->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
width >>= 3;
for(x = 0; x < width; x++) {
- data = ((uint32_t *)s)[0];
+ data = vga_read_dword_le(vga, addr);
data &= plane_mask;
v = expand4[GET_PLANE(data, 0)];
v |= expand4[GET_PLANE(data, 1)] << 1;
@@ -224,7 +250,7 @@ static void vga_draw_line4d2(VGACommonState *s1, uint8_t *d,
PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]);
PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]);
d += 64;
- s += 4;
+ addr += 4;
}
}
@@ -233,21 +259,21 @@ static void vga_draw_line4d2(VGACommonState *s1, uint8_t *d,
*
* XXX: add plane_mask support (never used in standard VGA modes)
*/
-static void vga_draw_line8d2(VGACommonState *s1, uint8_t *d,
- const uint8_t *s, int width)
+static void vga_draw_line8d2(VGACommonState *vga, uint8_t *d,
+ uint32_t addr, int width)
{
uint32_t *palette;
int x;
- palette = s1->last_palette;
+ palette = vga->last_palette;
width >>= 3;
for(x = 0; x < width; x++) {
- PUT_PIXEL2(d, 0, palette[s[0]]);
- PUT_PIXEL2(d, 1, palette[s[1]]);
- PUT_PIXEL2(d, 2, palette[s[2]]);
- PUT_PIXEL2(d, 3, palette[s[3]]);
+ PUT_PIXEL2(d, 0, palette[vga_read_byte(vga, addr + 0)]);
+ PUT_PIXEL2(d, 1, palette[vga_read_byte(vga, addr + 1)]);
+ PUT_PIXEL2(d, 2, palette[vga_read_byte(vga, addr + 2)]);
+ PUT_PIXEL2(d, 3, palette[vga_read_byte(vga, addr + 3)]);
d += 32;
- s += 4;
+ addr += 4;
}
}
@@ -256,63 +282,63 @@ static void vga_draw_line8d2(VGACommonState *s1, uint8_t *d,
*
* XXX: add plane_mask support (never used in standard VGA modes)
*/
-static void vga_draw_line8(VGACommonState *s1, uint8_t *d,
- const uint8_t *s, int width)
+static void vga_draw_line8(VGACommonState *vga, uint8_t *d,
+ uint32_t addr, int width)
{
uint32_t *palette;
int x;
- palette = s1->last_palette;
+ palette = vga->last_palette;
width >>= 3;
for(x = 0; x < width; x++) {
- ((uint32_t *)d)[0] = palette[s[0]];
- ((uint32_t *)d)[1] = palette[s[1]];
- ((uint32_t *)d)[2] = palette[s[2]];
- ((uint32_t *)d)[3] = palette[s[3]];
- ((uint32_t *)d)[4] = palette[s[4]];
- ((uint32_t *)d)[5] = palette[s[5]];
- ((uint32_t *)d)[6] = palette[s[6]];
- ((uint32_t *)d)[7] = palette[s[7]];
+ ((uint32_t *)d)[0] = palette[vga_read_byte(vga, addr + 0)];
+ ((uint32_t *)d)[1] = palette[vga_read_byte(vga, addr + 1)];
+ ((uint32_t *)d)[2] = palette[vga_read_byte(vga, addr + 2)];
+ ((uint32_t *)d)[3] = palette[vga_read_byte(vga, addr + 3)];
+ ((uint32_t *)d)[4] = palette[vga_read_byte(vga, addr + 4)];
+ ((uint32_t *)d)[5] = palette[vga_read_byte(vga, addr + 5)];
+ ((uint32_t *)d)[6] = palette[vga_read_byte(vga, addr + 6)];
+ ((uint32_t *)d)[7] = palette[vga_read_byte(vga, addr + 7)];
d += 32;
- s += 8;
+ addr += 8;
}
}
/*
* 15 bit color
*/
-static void vga_draw_line15_le(VGACommonState *s1, uint8_t *d,
- const uint8_t *s, int width)
+static void vga_draw_line15_le(VGACommonState *vga, uint8_t *d,
+ uint32_t addr, int width)
{
int w;
uint32_t v, r, g, b;
w = width;
do {
- v = lduw_le_p((void *)s);
+ v = vga_read_word_le(vga, addr);
r = (v >> 7) & 0xf8;
g = (v >> 2) & 0xf8;
b = (v << 3) & 0xf8;
((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b);
- s += 2;
+ addr += 2;
d += 4;
} while (--w != 0);
}
-static void vga_draw_line15_be(VGACommonState *s1, uint8_t *d,
- const uint8_t *s, int width)
+static void vga_draw_line15_be(VGACommonState *vga, uint8_t *d,
+ uint32_t addr, int width)
{
int w;
uint32_t v, r, g, b;
w = width;
do {
- v = lduw_be_p((void *)s);
+ v = vga_read_word_be(vga, addr);
r = (v >> 7) & 0xf8;
g = (v >> 2) & 0xf8;
b = (v << 3) & 0xf8;
((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b);
- s += 2;
+ addr += 2;
d += 4;
} while (--w != 0);
}
@@ -320,38 +346,38 @@ static void vga_draw_line15_be(VGACommonState *s1, uint8_t *d,
/*
* 16 bit color
*/
-static void vga_draw_line16_le(VGACommonState *s1, uint8_t *d,
- const uint8_t *s, int width)
+static void vga_draw_line16_le(VGACommonState *vga, uint8_t *d,
+ uint32_t addr, int width)
{
int w;
uint32_t v, r, g, b;
w = width;
do {
- v = lduw_le_p((void *)s);
+ v = vga_read_word_le(vga, addr);
r = (v >> 8) & 0xf8;
g = (v >> 3) & 0xfc;
b = (v << 3) & 0xf8;
((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b);
- s += 2;
+ addr += 2;
d += 4;
} while (--w != 0);
}
-static void vga_draw_line16_be(VGACommonState *s1, uint8_t *d,
- const uint8_t *s, int width)
+static void vga_draw_line16_be(VGACommonState *vga, uint8_t *d,
+ uint32_t addr, int width)
{
int w;
uint32_t v, r, g, b;
w = width;
do {
- v = lduw_be_p((void *)s);
+ v = vga_read_word_be(vga, addr);
r = (v >> 8) & 0xf8;
g = (v >> 3) & 0xfc;
b = (v << 3) & 0xf8;
((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b);
- s += 2;
+ addr += 2;
d += 4;
} while (--w != 0);
}
@@ -359,36 +385,36 @@ static void vga_draw_line16_be(VGACommonState *s1, uint8_t *d,
/*
* 24 bit color
*/
-static void vga_draw_line24_le(VGACommonState *s1, uint8_t *d,
- const uint8_t *s, int width)
+static void vga_draw_line24_le(VGACommonState *vga, uint8_t *d,
+ uint32_t addr, int width)
{
int w;
uint32_t r, g, b;
w = width;
do {
- b = s[0];
- g = s[1];
- r = s[2];
+ b = vga_read_byte(vga, addr + 0);
+ g = vga_read_byte(vga, addr + 1);
+ r = vga_read_byte(vga, addr + 2);
((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b);
- s += 3;
+ addr += 3;
d += 4;
} while (--w != 0);
}
-static void vga_draw_line24_be(VGACommonState *s1, uint8_t *d,
- const uint8_t *s, int width)
+static void vga_draw_line24_be(VGACommonState *vga, uint8_t *d,
+ uint32_t addr, int width)
{
int w;
uint32_t r, g, b;
w = width;
do {
- r = s[0];
- g = s[1];
- b = s[2];
+ r = vga_read_byte(vga, addr + 0);
+ g = vga_read_byte(vga, addr + 1);
+ b = vga_read_byte(vga, addr + 2);
((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b);
- s += 3;
+ addr += 3;
d += 4;
} while (--w != 0);
}
@@ -396,44 +422,36 @@ static void vga_draw_line24_be(VGACommonState *s1, uint8_t *d,
/*
* 32 bit color
*/
-static void vga_draw_line32_le(VGACommonState *s1, uint8_t *d,
- const uint8_t *s, int width)
+static void vga_draw_line32_le(VGACommonState *vga, uint8_t *d,
+ uint32_t addr, int width)
{
-#ifndef HOST_WORDS_BIGENDIAN
- memcpy(d, s, width * 4);
-#else
int w;
uint32_t r, g, b;
w = width;
do {
- b = s[0];
- g = s[1];
- r = s[2];
+ b = vga_read_byte(vga, addr + 0);
+ g = vga_read_byte(vga, addr + 1);
+ r = vga_read_byte(vga, addr + 2);
((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b);
- s += 4;
+ addr += 4;
d += 4;
} while (--w != 0);
-#endif
}
-static void vga_draw_line32_be(VGACommonState *s1, uint8_t *d,
- const uint8_t *s, int width)
+static void vga_draw_line32_be(VGACommonState *vga, uint8_t *d,
+ uint32_t addr, int width)
{
-#ifdef HOST_WORDS_BIGENDIAN
- memcpy(d, s, width * 4);
-#else
int w;
uint32_t r, g, b;
w = width;
do {
- r = s[1];
- g = s[2];
- b = s[3];
+ r = vga_read_byte(vga, addr + 1);
+ g = vga_read_byte(vga, addr + 2);
+ b = vga_read_byte(vga, addr + 3);
((uint32_t *)d)[0] = rgb_to_pixel32(r, g, b);
- s += 4;
+ addr += 4;
d += 4;
} while (--w != 0);
-#endif
}
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 533d8d7895..13e4a5d55d 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -1005,7 +1005,7 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
}
typedef void vga_draw_line_func(VGACommonState *s1, uint8_t *d,
- const uint8_t *s, int width);
+ uint32_t srcaddr, int width);
#include "vga-helpers.h"
@@ -1666,7 +1666,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
if (y_start < 0)
y_start = y;
if (!(is_buffer_shared(surface))) {
- vga_draw_line(s, d, s->vram_ptr + addr, width);
+ vga_draw_line(s, d, addr, width);
if (s->cursor_draw_line)
s->cursor_draw_line(s, d, y);
}
@@ -2170,6 +2170,7 @@ void vga_common_init(VGACommonState *s, Object *obj, bool global_vmstate)
if (!s->vbe_size) {
s->vbe_size = s->vram_size;
}
+ s->vbe_size_mask = s->vbe_size - 1;
s->is_vbe_vmstate = 1;
memory_region_init_ram(&s->vram, obj, "vga.vram", s->vram_size,
diff --git a/hw/display/vga_int.h b/hw/display/vga_int.h
index dd6c958da3..ad34a1f048 100644
--- a/hw/display/vga_int.h
+++ b/hw/display/vga_int.h
@@ -94,6 +94,7 @@ typedef struct VGACommonState {
uint32_t vram_size;
uint32_t vram_size_mb; /* property */
uint32_t vbe_size;
+ uint32_t vbe_size_mask;
uint32_t latch;
bool has_chain4_alias;
MemoryRegion chain4_alias;
--
2.11.0

View File

@ -1,61 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Prasad J Pandit <pjp@fedoraproject.org>
Date: Thu, 7 Sep 2017 12:02:56 +0530
Subject: [PATCH] multiboot: validate multiboot header address values
While loading kernel via multiboot-v1 image, (flags & 0x00010000)
indicates that multiboot header contains valid addresses to load
the kernel image. These addresses are used to compute kernel
size and kernel text offset in the OS image. Validate these
address values to avoid an OOB access issue.
This is CVE-2017-14167.
Reported-by: Thomas Garnier <thgarnie@google.com>
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
---
hw/i386/multiboot.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/hw/i386/multiboot.c b/hw/i386/multiboot.c
index f13e23139b..22688d376d 100644
--- a/hw/i386/multiboot.c
+++ b/hw/i386/multiboot.c
@@ -221,15 +221,34 @@ int load_multiboot(FWCfgState *fw_cfg,
uint32_t mh_header_addr = ldl_p(header+i+12);
uint32_t mh_load_end_addr = ldl_p(header+i+20);
uint32_t mh_bss_end_addr = ldl_p(header+i+24);
+
mh_load_addr = ldl_p(header+i+16);
+ if (mh_header_addr < mh_load_addr) {
+ fprintf(stderr, "invalid mh_load_addr address\n");
+ exit(1);
+ }
+
uint32_t mb_kernel_text_offset = i - (mh_header_addr - mh_load_addr);
uint32_t mb_load_size = 0;
mh_entry_addr = ldl_p(header+i+28);
if (mh_load_end_addr) {
+ if (mh_bss_end_addr < mh_load_addr) {
+ fprintf(stderr, "invalid mh_bss_end_addr address\n");
+ exit(1);
+ }
mb_kernel_size = mh_bss_end_addr - mh_load_addr;
+
+ if (mh_load_end_addr < mh_load_addr) {
+ fprintf(stderr, "invalid mh_load_end_addr address\n");
+ exit(1);
+ }
mb_load_size = mh_load_end_addr - mh_load_addr;
} else {
+ if (kernel_file_size < mb_kernel_text_offset) {
+ fprintf(stderr, "invalid kernel_file_size\n");
+ exit(1);
+ }
mb_kernel_size = kernel_file_size - mb_kernel_text_offset;
mb_load_size = mb_kernel_size;
}
--
2.11.0

View File

@ -1,57 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Wed, 20 Sep 2017 08:09:33 +0200
Subject: [PATCH] virtio: fix descriptor counting in virtqueue_pop
While changing the s/g list allocation, commit 3b3b0628
also changed the descriptor counting to count iovec entries
as split by cpu_physical_memory_map(). Previously only the
actual descriptor entries were counted and the split into
the iovec happened afterwards in virtqueue_map().
Count the entries again instead to avoid erroneous
"Looped descriptor" errors.
Reported-by: Hans Middelhoek <h.middelhoek@ospito.nl>
Link: https://forum.proxmox.com/threads/vm-crash-with-memory-hotplug.35904/
Fixes: 3b3b0628217e ("virtio: slim down allocation of VirtQueueElements")
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
hw/virtio/virtio.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 890b4d7eb7..33bb770177 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -834,7 +834,7 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz)
int64_t len;
VirtIODevice *vdev = vq->vdev;
VirtQueueElement *elem = NULL;
- unsigned out_num, in_num;
+ unsigned out_num, in_num, elem_entries;
hwaddr addr[VIRTQUEUE_MAX_SIZE];
struct iovec iov[VIRTQUEUE_MAX_SIZE];
VRingDesc desc;
@@ -852,7 +852,7 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz)
smp_rmb();
/* When we start there are none of either input nor output. */
- out_num = in_num = 0;
+ out_num = in_num = elem_entries = 0;
max = vq->vring.num;
@@ -922,7 +922,7 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz)
}
/* If we've got too many, that implies a descriptor loop. */
- if ((in_num + out_num) > max) {
+ if (++elem_entries > max) {
virtio_error(vdev, "Looped descriptor");
goto err_undo_map;
}
--
2.11.0

View File

@ -1,30 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Wed, 29 Nov 2017 09:39:55 +0100
Subject: [PATCH] nbd/server: CVE-2017-15119 Reject options larger than 32M
Backported-from: fdad35ef6c58
---
nbd/server.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/nbd/server.c b/nbd/server.c
index a98bb21a0a..4d6da8ac06 100644
--- a/nbd/server.c
+++ b/nbd/server.c
@@ -489,6 +489,12 @@ static int nbd_negotiate_options(NBDClient *client)
}
length = be32_to_cpu(length);
+ if (length > NBD_MAX_BUFFER_SIZE) {
+ LOG("len (%" PRIu32" ) is larger than max len (%u)",
+ length, NBD_MAX_BUFFER_SIZE);
+ return -EINVAL;
+ }
+
TRACE("Checking option 0x%" PRIx32, clientflags);
if (client->tlscreds &&
client->ioc == (QIOChannel *)client->sioc) {
--
2.11.0

View File

@ -1,32 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
Date: Fri, 4 Aug 2017 12:33:29 +0100
Subject: [PATCH] vga/migration: Update memory map in post_load
After migration the chain4 alias mapping added by 80763888 (in 2011)
might be missing, since there's no call to vga_update_memory_access
in the post_load after the registers are updated. Add it back.
Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
Message-id: 20170804113329.13609-1-dgilbert@redhat.com
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/display/vga.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 13e4a5d55d..a99d831e04 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -2050,6 +2050,7 @@ static int vga_common_post_load(void *opaque, int version_id)
/* force refresh */
s->graphic_mode = -1;
vbe_update_vgaregs(s);
+ vga_update_memory_access(s);
return 0;
}
--
2.11.0

View File

@ -1,52 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 10 Oct 2017 16:13:21 +0200
Subject: [PATCH] vga: drop line_offset variable
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/display/vga.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index a99d831e04..77af807a51 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -1464,7 +1464,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
{
DisplaySurface *surface = qemu_console_surface(s->con);
int y1, y, update, linesize, y_start, double_scan, mask, depth;
- int width, height, shift_control, line_offset, bwidth, bits;
+ int width, height, shift_control, bwidth, bits;
ram_addr_t page0, page1;
DirtyBitmapSnapshot *snap = NULL;
int disp_width, multi_scan, multi_run;
@@ -1614,7 +1614,6 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
s->cursor_invalidate(s);
}
- line_offset = s->line_offset;
#if 0
printf("w=%d h=%d v=%d line_offset=%d cr[0x09]=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=0x%02x\n",
width, height, v, line_offset, s->cr[9], s->cr[VGA_CRTC_MODE],
@@ -1629,7 +1628,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
if (!full_update) {
ram_addr_t region_start = addr1;
- ram_addr_t region_end = addr1 + line_offset * height;
+ ram_addr_t region_end = addr1 + s->line_offset * height;
vga_sync_dirty_bitmap(s);
if (s->line_compare < height) {
/* split screen mode */
@@ -1681,7 +1680,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
if (!multi_run) {
mask = (s->cr[VGA_CRTC_MODE] & 3) ^ 3;
if ((y1 & mask) == mask)
- addr1 += line_offset;
+ addr1 += s->line_offset;
y1++;
multi_run = multi_scan;
} else {
--
2.11.0

View File

@ -1,103 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 10 Oct 2017 16:13:22 +0200
Subject: [PATCH] vga: handle cirrus vbe mode wraparounds.
Commit "3d90c62548 vga: stop passing pointers to vga_draw_line*
functions" is incomplete. It doesn't handle the case that the vga
rendering code tries to create a shared surface, i.e. a pixman image
backed by vga video memory. That can not work in case the guest display
wraps from end of video memory to the start. So force shadowing in that
case. Also adjust the snapshot region calculation.
Can trigger with cirrus only, when programming vbe modes using the bochs
api (stdvga, also qxl and virtio-vga in vga compat mode) wrap arounds
can't happen.
Fixes: CVE-2017-13672
Fixes: 3d90c6254863693a6b13d918d2b8682e08bbc681
Cc: P J P <ppandit@redhat.com>
Reported-by: David Buchanan <d@vidbuchanan.co.uk>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Message-id: 20171010141323.14049-3-kraxel@redhat.com
---
hw/display/vga.c | 28 +++++++++++++++++++++-------
1 file changed, 21 insertions(+), 7 deletions(-)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 77af807a51..7bdbf7441e 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -1465,13 +1465,13 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
DisplaySurface *surface = qemu_console_surface(s->con);
int y1, y, update, linesize, y_start, double_scan, mask, depth;
int width, height, shift_control, bwidth, bits;
- ram_addr_t page0, page1;
+ ram_addr_t page0, page1, region_start, region_end;
DirtyBitmapSnapshot *snap = NULL;
int disp_width, multi_scan, multi_run;
uint8_t *d;
uint32_t v, addr1, addr;
vga_draw_line_func *vga_draw_line = NULL;
- bool share_surface;
+ bool share_surface, force_shadow = false;
pixman_format_code_t format;
#ifdef HOST_WORDS_BIGENDIAN
bool byteswap = !s->big_endian_fb;
@@ -1484,6 +1484,15 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
s->get_resolution(s, &width, &height);
disp_width = width;
+ region_start = (s->start_addr * 4);
+ region_end = region_start + s->line_offset * height;
+ if (region_end > s->vbe_size) {
+ /* wraps around (can happen with cirrus vbe modes) */
+ region_start = 0;
+ region_end = s->vbe_size;
+ force_shadow = true;
+ }
+
shift_control = (s->gr[VGA_GFX_MODE] >> 5) & 3;
double_scan = (s->cr[VGA_CRTC_MAX_SCAN] >> 7);
if (shift_control != 1) {
@@ -1523,7 +1532,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
format = qemu_default_pixman_format(depth, !byteswap);
if (format) {
share_surface = dpy_gfx_check_format(s->con, format)
- && !s->force_shadow;
+ && !s->force_shadow && !force_shadow;
} else {
share_surface = false;
}
@@ -1627,8 +1636,6 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
y1 = 0;
if (!full_update) {
- ram_addr_t region_start = addr1;
- ram_addr_t region_end = addr1 + s->line_offset * height;
vga_sync_dirty_bitmap(s);
if (s->line_compare < height) {
/* split screen mode */
@@ -1651,10 +1658,17 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
addr = (addr & ~0x8000) | ((y1 & 2) << 14);
}
update = full_update;
- page0 = addr;
- page1 = addr + bwidth - 1;
+ page0 = addr & s->vbe_size_mask;
+ page1 = (addr + bwidth - 1) & s->vbe_size_mask;
if (full_update) {
update = 1;
+ } else if (page1 < page0) {
+ /* scanline wraps from end of video memory to the start */
+ assert(force_shadow);
+ update = memory_region_snapshot_get_dirty(&s->vram, snap,
+ page0, 0);
+ update |= memory_region_snapshot_get_dirty(&s->vram, snap,
+ page1, 0);
} else {
update = memory_region_snapshot_get_dirty(&s->vram, snap,
page0, page1 - page0);
--
2.11.0

View File

@ -1,30 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 10 Oct 2017 16:13:23 +0200
Subject: [PATCH] vga: add ram_addr_t cast
Reported by Coverity.
Fixes: CID 1381409
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Message-id: 20171010141323.14049-4-kraxel@redhat.com
---
hw/display/vga.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 7bdbf7441e..63ba404ef2 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -1485,7 +1485,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
disp_width = width;
region_start = (s->start_addr * 4);
- region_end = region_start + s->line_offset * height;
+ region_end = region_start + (ram_addr_t)s->line_offset * height;
if (region_end > s->vbe_size) {
/* wraps around (can happen with cirrus vbe modes) */
region_start = 0;
--
2.11.0

View File

@ -1,32 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Mon, 30 Oct 2017 11:28:30 +0100
Subject: [PATCH] vga: fix region checks in wraparound case
Cc: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Message-id: 20171030102830.4469-1-kraxel@redhat.com
---
hw/display/vga.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 63ba404ef2..a58d8bcd67 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -1666,9 +1666,9 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
/* scanline wraps from end of video memory to the start */
assert(force_shadow);
update = memory_region_snapshot_get_dirty(&s->vram, snap,
- page0, 0);
+ page0, s->vbe_size - page0);
update |= memory_region_snapshot_get_dirty(&s->vram, snap,
- page1, 0);
+ 0, page1);
} else {
update = memory_region_snapshot_get_dirty(&s->vram, snap,
page0, page1 - page0);
--
2.11.0

View File

@ -1,54 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: "Daniel P. Berrange" <berrange@redhat.com>
Date: Mon, 9 Oct 2017 14:43:42 +0100
Subject: [PATCH] io: monitor encoutput buffer size from websocket GSource
The websocket GSource is monitoring the size of the rawoutput
buffer to determine if the channel can accepts more writes.
The rawoutput buffer, however, is merely a temporary staging
buffer before data is copied into the encoutput buffer. Thus
its size will always be zero when the GSource runs.
This flaw causes the encoutput buffer to grow without bound
if the other end of the underlying data channel doesn't
read data being sent. This can be seen with VNC if a client
is on a slow WAN link and the guest OS is sending many screen
updates. A malicious VNC client can act like it is on a slow
link by playing a video in the guest and then reading data
very slowly, causing QEMU host memory to expand arbitrarily.
This issue is assigned CVE-2017-15268, publically reported in
https://bugs.launchpad.net/qemu/+bug/1718964
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
io/channel-websock.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/io/channel-websock.c b/io/channel-websock.c
index 8fabadea2f..882bbb4cbc 100644
--- a/io/channel-websock.c
+++ b/io/channel-websock.c
@@ -26,7 +26,7 @@
#include "trace.h"
-/* Max amount to allow in rawinput/rawoutput buffers */
+/* Max amount to allow in rawinput/encoutput buffers */
#define QIO_CHANNEL_WEBSOCK_MAX_BUFFER 8192
#define QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN 24
@@ -1006,7 +1006,7 @@ qio_channel_websock_source_prepare(GSource *source,
if (wsource->wioc->rawinput.offset) {
cond |= G_IO_IN;
}
- if (wsource->wioc->rawoutput.offset < QIO_CHANNEL_WEBSOCK_MAX_BUFFER) {
+ if (wsource->wioc->encoutput.offset < QIO_CHANNEL_WEBSOCK_MAX_BUFFER) {
cond |= G_IO_OUT;
}
--
2.11.0

View File

@ -1,43 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Prasad J Pandit <pjp@fedoraproject.org>
Date: Mon, 16 Oct 2017 14:21:59 +0200
Subject: [PATCH] 9pfs: use g_malloc0 to allocate space for xattr
9p back-end first queries the size of an extended attribute,
allocates space for it via g_malloc() and then retrieves its
value into allocated buffer. Race between querying attribute
size and retrieving its could lead to memory bytes disclosure.
Use g_malloc0() to avoid it.
Reported-by: Tuomas Tynkkynen <tuomas.tynkkynen@iki.fi>
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
Signed-off-by: Greg Kurz <groug@kaod.org>
---
hw/9pfs/9p.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
index c80ba67389..aaf9935ef4 100644
--- a/hw/9pfs/9p.c
+++ b/hw/9pfs/9p.c
@@ -3220,7 +3220,7 @@ static void coroutine_fn v9fs_xattrwalk(void *opaque)
xattr_fidp->fid_type = P9_FID_XATTR;
xattr_fidp->fs.xattr.xattrwalk_fid = true;
if (size) {
- xattr_fidp->fs.xattr.value = g_malloc(size);
+ xattr_fidp->fs.xattr.value = g_malloc0(size);
err = v9fs_co_llistxattr(pdu, &xattr_fidp->path,
xattr_fidp->fs.xattr.value,
xattr_fidp->fs.xattr.len);
@@ -3253,7 +3253,7 @@ static void coroutine_fn v9fs_xattrwalk(void *opaque)
xattr_fidp->fid_type = P9_FID_XATTR;
xattr_fidp->fs.xattr.xattrwalk_fid = true;
if (size) {
- xattr_fidp->fs.xattr.value = g_malloc(size);
+ xattr_fidp->fs.xattr.value = g_malloc0(size);
err = v9fs_co_lgetxattr(pdu, &xattr_fidp->path,
&name, xattr_fidp->fs.xattr.value,
xattr_fidp->fs.xattr.len);
--
2.11.0

View File

@ -1,58 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Wed, 11 Oct 2017 10:43:14 +0200
Subject: [PATCH] cirrus: fix oob access in mode4and5 write functions
Move dst calculation into the loop, so we apply the mask on each
interation and will not overflow vga memory.
Cc: Prasad J Pandit <pjp@fedoraproject.org>
Reported-by: Niu Guoxiang <niuguoxiang@huawei.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Message-id: 20171011084314.21752-1-kraxel@redhat.com
---
hw/display/cirrus_vga.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c
index afc290ab91..077a8cb74f 100644
--- a/hw/display/cirrus_vga.c
+++ b/hw/display/cirrus_vga.c
@@ -2038,15 +2038,14 @@ static void cirrus_mem_writeb_mode4and5_8bpp(CirrusVGAState * s,
unsigned val = mem_value;
uint8_t *dst;
- dst = s->vga.vram_ptr + (offset &= s->cirrus_addr_mask);
for (x = 0; x < 8; x++) {
+ dst = s->vga.vram_ptr + ((offset + x) & s->cirrus_addr_mask);
if (val & 0x80) {
*dst = s->cirrus_shadow_gr1;
} else if (mode == 5) {
*dst = s->cirrus_shadow_gr0;
}
val <<= 1;
- dst++;
}
memory_region_set_dirty(&s->vga.vram, offset, 8);
}
@@ -2060,8 +2059,8 @@ static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s,
unsigned val = mem_value;
uint8_t *dst;
- dst = s->vga.vram_ptr + (offset &= s->cirrus_addr_mask);
for (x = 0; x < 8; x++) {
+ dst = s->vga.vram_ptr + ((offset + 2 * x) & s->cirrus_addr_mask & ~1);
if (val & 0x80) {
*dst = s->cirrus_shadow_gr1;
*(dst + 1) = s->vga.gr[0x11];
@@ -2070,7 +2069,6 @@ static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s,
*(dst + 1) = s->vga.gr[0x10];
}
val <<= 1;
- dst += 2;
}
memory_region_set_dirty(&s->vga.vram, offset, 16);
}
--
2.11.0

View File

@ -1,68 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Prasad J Pandit <pjp@fedoraproject.org>
Date: Wed, 29 Nov 2017 23:14:27 +0530
Subject: [PATCH] virtio: check VirtQueue Vring object is set
A guest could attempt to use an uninitialised VirtQueue object
or unset Vring.align leading to a arithmetic exception. Add check
to avoid it.
Reported-by: Zhangboxian <zhangboxian@huawei.com>
Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
---
hw/virtio/virtio.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 33bb770177..76b9a9907c 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -183,7 +183,7 @@ void virtio_queue_update_rings(VirtIODevice *vdev, int n)
{
VRing *vring = &vdev->vq[n].vring;
- if (!vring->desc) {
+ if (!vring->num || !vring->desc || !vring->align) {
/* not yet setup -> nothing to do */
return;
}
@@ -1416,6 +1416,9 @@ void virtio_config_modern_writel(VirtIODevice *vdev,
void virtio_queue_set_addr(VirtIODevice *vdev, int n, hwaddr addr)
{
+ if (!vdev->vq[n].vring.num) {
+ return;
+ }
vdev->vq[n].vring.desc = addr;
virtio_queue_update_rings(vdev, n);
}
@@ -1428,6 +1431,9 @@ hwaddr virtio_queue_get_addr(VirtIODevice *vdev, int n)
void virtio_queue_set_rings(VirtIODevice *vdev, int n, hwaddr desc,
hwaddr avail, hwaddr used)
{
+ if (!vdev->vq[n].vring.num) {
+ return;
+ }
vdev->vq[n].vring.desc = desc;
vdev->vq[n].vring.avail = avail;
vdev->vq[n].vring.used = used;
@@ -1496,8 +1502,10 @@ void virtio_queue_set_align(VirtIODevice *vdev, int n, int align)
*/
assert(k->has_variable_vring_alignment);
- vdev->vq[n].vring.align = align;
- virtio_queue_update_rings(vdev, n);
+ if (align) {
+ vdev->vq[n].vring.align = align;
+ virtio_queue_update_rings(vdev, n);
+ }
}
static bool virtio_queue_notify_aio_vq(VirtQueue *vq)
--
2.11.0

View File

@ -1,107 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jeff Cody <jcody@redhat.com>
Date: Tue, 23 May 2017 13:27:50 -0400
Subject: [PATCH] block/gluster: glfs_lseek() workaround
On current released versions of glusterfs, glfs_lseek() will sometimes
return invalid values for SEEK_DATA or SEEK_HOLE. For SEEK_DATA and
SEEK_HOLE, the returned value should be >= the passed offset, or < 0 in
the case of error:
LSEEK(2):
off_t lseek(int fd, off_t offset, int whence);
[...]
SEEK_HOLE
Adjust the file offset to the next hole in the file greater
than or equal to offset. If offset points into the middle of
a hole, then the file offset is set to offset. If there is no
hole past offset, then the file offset is adjusted to the end
of the file (i.e., there is an implicit hole at the end of
any file).
[...]
RETURN VALUE
Upon successful completion, lseek() returns the resulting
offset location as measured in bytes from the beginning of the
file. On error, the value (off_t) -1 is returned and errno is
set to indicate the error
However, occasionally glfs_lseek() for SEEK_HOLE/DATA will return a
value less than the passed offset, yet greater than zero.
For instance, here are example values observed from this call:
offs = glfs_lseek(s->fd, start, SEEK_HOLE);
if (offs < 0) {
return -errno; /* D1 and (H3 or H4) */
}
start == 7608336384
offs == 7607877632
This causes QEMU to abort on the assert test. When this value is
returned, errno is also 0.
This is a reported and known bug to glusterfs:
https://bugzilla.redhat.com/show_bug.cgi?id=1425293
Although this is being fixed in gluster, we still should work around it
in QEMU, given that multiple released versions of gluster behave this
way.
This patch treats the return case of (offs < start) the same as if an
error value other than ENXIO is returned; we will assume we learned
nothing, and there are no holes in the file.
Signed-off-by: Jeff Cody <jcody@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Niels de Vos <ndevos@redhat.com>
Message-id: 87c0140e9407c08f6e74b04131b610f2e27c014c.1495560397.git.jcody@redhat.com
Signed-off-by: Jeff Cody <jcody@redhat.com>
---
block/gluster.c | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/block/gluster.c b/block/gluster.c
index 4fdf68f1fc..06421ef79d 100644
--- a/block/gluster.c
+++ b/block/gluster.c
@@ -1287,7 +1287,14 @@ static int find_allocation(BlockDriverState *bs, off_t start,
if (offs < 0) {
return -errno; /* D3 or D4 */
}
- assert(offs >= start);
+
+ if (offs < start) {
+ /* This is not a valid return by lseek(). We are safe to just return
+ * -EIO in this case, and we'll treat it like D4. Unfortunately some
+ * versions of gluster server will return offs < start, so an assert
+ * here will unnecessarily abort QEMU. */
+ return -EIO;
+ }
if (offs > start) {
/* D2: in hole, next data at offs */
@@ -1319,7 +1326,14 @@ static int find_allocation(BlockDriverState *bs, off_t start,
if (offs < 0) {
return -errno; /* D1 and (H3 or H4) */
}
- assert(offs >= start);
+
+ if (offs < start) {
+ /* This is not a valid return by lseek(). We are safe to just return
+ * -EIO in this case, and we'll treat it like H4. Unfortunately some
+ * versions of gluster server will return offs < start, so an assert
+ * here will unnecessarily abort QEMU. */
+ return -EIO;
+ }
if (offs > start) {
/*
--
2.11.0

View File

@ -1,180 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Niels de Vos <ndevos@redhat.com>
Date: Sun, 28 May 2017 12:01:14 +0530
Subject: [PATCH] gluster: add support for PREALLOC_MODE_FALLOC
Add missing support for "preallocation=falloc" to the Gluster block
driver. This change bases its logic on that of block/file-posix.c and
removed the gluster_supports_zerofill() and qemu_gluster_zerofill()
functions in favour of #ifdef checks in an easy to read
switch-statement.
Both glfs_zerofill() and glfs_fallocate() have been introduced with
GlusterFS 3.5.0 (pkg-config glusterfs-api = 6). A #define for the
availability of glfs_fallocate() has been added to ./configure.
Reported-by: Satheesaran Sundaramoorthi <sasundar@redhat.com>
Signed-off-by: Niels de Vos <ndevos@redhat.com>
Message-id: 20170528063114.28691-1-ndevos@redhat.com
URL: https://bugzilla.redhat.com/1450759
Signed-off-by: Niels de Vos <ndevos@redhat.com>
Signed-off-by: Jeff Cody <jcody@redhat.com>
---
block/gluster.c | 76 ++++++++++++++++++++++++++++++---------------------------
configure | 6 +++++
2 files changed, 46 insertions(+), 36 deletions(-)
diff --git a/block/gluster.c b/block/gluster.c
index 06421ef79d..8108c89c7f 100644
--- a/block/gluster.c
+++ b/block/gluster.c
@@ -975,29 +975,6 @@ static coroutine_fn int qemu_gluster_co_pwrite_zeroes(BlockDriverState *bs,
qemu_coroutine_yield();
return acb.ret;
}
-
-static inline bool gluster_supports_zerofill(void)
-{
- return 1;
-}
-
-static inline int qemu_gluster_zerofill(struct glfs_fd *fd, int64_t offset,
- int64_t size)
-{
- return glfs_zerofill(fd, offset, size);
-}
-
-#else
-static inline bool gluster_supports_zerofill(void)
-{
- return 0;
-}
-
-static inline int qemu_gluster_zerofill(struct glfs_fd *fd, int64_t offset,
- int64_t size)
-{
- return 0;
-}
#endif
static int qemu_gluster_create(const char *filename,
@@ -1007,9 +984,10 @@ static int qemu_gluster_create(const char *filename,
struct glfs *glfs;
struct glfs_fd *fd;
int ret = 0;
- int prealloc = 0;
+ PreallocMode prealloc;
int64_t total_size = 0;
char *tmp = NULL;
+ Error *local_err = NULL;
gconf = g_new0(BlockdevOptionsGluster, 1);
gconf->debug = qemu_opt_get_number_del(opts, GLUSTER_OPT_DEBUG,
@@ -1037,13 +1015,12 @@ static int qemu_gluster_create(const char *filename,
BDRV_SECTOR_SIZE);
tmp = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC);
- if (!tmp || !strcmp(tmp, "off")) {
- prealloc = 0;
- } else if (!strcmp(tmp, "full") && gluster_supports_zerofill()) {
- prealloc = 1;
- } else {
- error_setg(errp, "Invalid preallocation mode: '%s'"
- " or GlusterFS doesn't support zerofill API", tmp);
+ prealloc = qapi_enum_parse(PreallocMode_lookup, tmp,
+ PREALLOC_MODE__MAX, PREALLOC_MODE_OFF,
+ &local_err);
+ g_free(tmp);
+ if (local_err) {
+ error_propagate(errp, local_err);
ret = -EINVAL;
goto out;
}
@@ -1052,21 +1029,48 @@ static int qemu_gluster_create(const char *filename,
O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRUSR | S_IWUSR);
if (!fd) {
ret = -errno;
- } else {
+ goto out;
+ }
+
+ switch (prealloc) {
+#ifdef CONFIG_GLUSTERFS_FALLOCATE
+ case PREALLOC_MODE_FALLOC:
+ if (glfs_fallocate(fd, 0, 0, total_size)) {
+ error_setg(errp, "Could not preallocate data for the new file");
+ ret = -errno;
+ }
+ break;
+#endif /* CONFIG_GLUSTERFS_FALLOCATE */
+#ifdef CONFIG_GLUSTERFS_ZEROFILL
+ case PREALLOC_MODE_FULL:
if (!glfs_ftruncate(fd, total_size)) {
- if (prealloc && qemu_gluster_zerofill(fd, 0, total_size)) {
+ if (glfs_zerofill(fd, 0, total_size)) {
+ error_setg(errp, "Could not zerofill the new file");
ret = -errno;
}
} else {
+ error_setg(errp, "Could not resize file");
ret = -errno;
}
-
- if (glfs_close(fd) != 0) {
+ break;
+#endif /* CONFIG_GLUSTERFS_ZEROFILL */
+ case PREALLOC_MODE_OFF:
+ if (glfs_ftruncate(fd, total_size) != 0) {
ret = -errno;
+ error_setg(errp, "Could not resize file");
}
+ break;
+ default:
+ ret = -EINVAL;
+ error_setg(errp, "Unsupported preallocation mode: %s",
+ PreallocMode_lookup[prealloc]);
+ break;
+ }
+
+ if (glfs_close(fd) != 0) {
+ ret = -errno;
}
out:
- g_free(tmp);
qapi_free_BlockdevOptionsGluster(gconf);
glfs_clear_preopened(glfs);
return ret;
diff --git a/configure b/configure
index 841f7a8fae..3667da6f07 100755
--- a/configure
+++ b/configure
@@ -300,6 +300,7 @@ seccomp=""
glusterfs=""
glusterfs_xlator_opt="no"
glusterfs_discard="no"
+glusterfs_fallocate="no"
glusterfs_zerofill="no"
gtk=""
gtkabi=""
@@ -3537,6 +3538,7 @@ if test "$glusterfs" != "no" ; then
glusterfs_discard="yes"
fi
if $pkg_config --atleast-version=6 glusterfs-api; then
+ glusterfs_fallocate="yes"
glusterfs_zerofill="yes"
fi
else
@@ -5717,6 +5719,10 @@ if test "$glusterfs_discard" = "yes" ; then
echo "CONFIG_GLUSTERFS_DISCARD=y" >> $config_host_mak
fi
+if test "$glusterfs_fallocate" = "yes" ; then
+ echo "CONFIG_GLUSTERFS_FALLOCATE=y" >> $config_host_mak
+fi
+
if test "$glusterfs_zerofill" = "yes" ; then
echo "CONFIG_GLUSTERFS_ZEROFILL=y" >> $config_host_mak
fi
--
2.11.0

View File

@ -1,39 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Eduardo Habkost <ehabkost@redhat.com>
Date: Wed, 12 Jul 2017 13:20:56 -0300
Subject: [PATCH] target/i386: Use host_vendor_fms() in max_x86_cpu_initfn()
The existing code duplicated the logic in host_vendor_fms(), so
reuse the helper function instead.
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
Message-Id: <20170712162058.10538-3-ehabkost@redhat.com>
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
---
target/i386/cpu.c | 9 ++-------
1 file changed, 2 insertions(+), 7 deletions(-)
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 4b3bfb3802..1affd3bb5b 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -1592,13 +1592,8 @@ static void max_x86_cpu_initfn(Object *obj)
X86CPUDefinition host_cpudef = { };
uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
- host_cpuid(0x0, 0, &eax, &ebx, &ecx, &edx);
- x86_cpu_vendor_words2str(host_cpudef.vendor, ebx, edx, ecx);
-
- host_cpuid(0x1, 0, &eax, &ebx, &ecx, &edx);
- host_cpudef.family = ((eax >> 8) & 0x0F) + ((eax >> 20) & 0xFF);
- host_cpudef.model = ((eax >> 4) & 0x0F) | ((eax & 0xF0000) >> 12);
- host_cpudef.stepping = eax & 0x0F;
+ host_vendor_fms(host_cpudef.vendor, &host_cpudef.family,
+ &host_cpudef.model, &host_cpudef.stepping);
cpu_x86_fill_model_id(host_cpudef.model_id);
--
2.11.0

View File

@ -1,40 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Eduardo Habkost <ehabkost@redhat.com>
Date: Wed, 12 Jul 2017 13:20:57 -0300
Subject: [PATCH] target/i386: Define CPUID_MODEL_ID_SZ macro
Document cpu_x86_fill_model_id() and define CPUID_MODEL_ID_SZ to
help callers use the right buffer size.
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
Message-Id: <20170712162058.10538-4-ehabkost@redhat.com>
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
---
target/i386/cpu.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 1affd3bb5b..54832dd591 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -1541,6 +1541,17 @@ static bool lmce_supported(void)
return !!(mce_cap & MCG_LMCE_P);
}
+#define CPUID_MODEL_ID_SZ 48
+
+/**
+ * cpu_x86_fill_model_id:
+ * Get CPUID model ID string from host CPU.
+ *
+ * @str should have at least CPUID_MODEL_ID_SZ bytes
+ *
+ * The function does NOT add a null terminator to the string
+ * automatically.
+ */
static int cpu_x86_fill_model_id(char *str)
{
uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
--
2.11.0

View File

@ -1,92 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Eduardo Habkost <ehabkost@redhat.com>
Date: Wed, 12 Jul 2017 13:20:58 -0300
Subject: [PATCH] target/i386: Don't use x86_cpu_load_def() on "max" CPU model
When commit 0bacd8b3046f ('i386: Don't set CPUClass::cpu_def on
"max" model') removed the CPUClass::cpu_def field, we kept using
the x86_cpu_load_def() helper directly in max_x86_cpu_initfn(),
emulating the previous behavior when CPUClass::cpu_def was set.
However, x86_cpu_load_def() is intended to help initialization of
CPU models from the builtin_x86_defs table, and does lots of
other steps that are not necessary for "max".
One of the things x86_cpu_load_def() do is to set the properties
listed at tcg_default_props/kvm_default_props. We must not do
that on the "max" CPU model, otherwise under KVM we will
incorrectly report all KVM features as always available, and the
"svm" feature as always unavailable. The latter caused the bug
reported at:
https://bugzilla.redhat.com/show_bug.cgi?id=1467599
("Unable to start domain: the CPU is incompatible with host CPU:
Host CPU does not provide required features: svm")
Replace x86_cpu_load_def() with simple object_property_set*()
calls. In addition to fixing the above bug, this makes the KVM
branch in max_x86_cpu_initfn() very similar to the existing TCG
branch.
For reference, the full list of steps performed by
x86_cpu_load_def() is:
* Setting min-level and min-xlevel. Already done by
max_x86_cpu_initfn().
* Setting family/model/stepping/model-id. Done by the code added
to max_x86_cpu_initfn() in this patch.
* Copying def->features. Wrong because "-cpu max" features need to
be calculated at realize time. This was not a problem in the
current code because host_cpudef.features was all zeroes.
* x86_cpu_apply_props() calls. This causes the bug above, and
shouldn't be done.
* Setting CPUID_EXT_HYPERVISOR. Not needed because it is already
reported by x86_cpu_get_supported_feature_word(), and because
"-cpu max" features need to be calculated at realize time.
* Setting CPU vendor to host CPU vendor if on KVM mode.
Redundant, because max_x86_cpu_initfn() already sets it to the
host CPU vendor.
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
Message-Id: <20170712162058.10538-5-ehabkost@redhat.com>
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
---
target/i386/cpu.c | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 54832dd591..3d53cb4c86 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -1600,15 +1600,21 @@ static void max_x86_cpu_initfn(Object *obj)
cpu->max_features = true;
if (kvm_enabled()) {
- X86CPUDefinition host_cpudef = { };
- uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
+ char vendor[CPUID_VENDOR_SZ + 1] = { 0 };
+ char model_id[CPUID_MODEL_ID_SZ + 1] = { 0 };
+ int family, model, stepping;
- host_vendor_fms(host_cpudef.vendor, &host_cpudef.family,
- &host_cpudef.model, &host_cpudef.stepping);
+ host_vendor_fms(vendor, &family, &model, &stepping);
- cpu_x86_fill_model_id(host_cpudef.model_id);
+ cpu_x86_fill_model_id(model_id);
- x86_cpu_load_def(cpu, &host_cpudef, &error_abort);
+ object_property_set_str(OBJECT(cpu), vendor, "vendor", &error_abort);
+ object_property_set_int(OBJECT(cpu), family, "family", &error_abort);
+ object_property_set_int(OBJECT(cpu), model, "model", &error_abort);
+ object_property_set_int(OBJECT(cpu), stepping, "stepping",
+ &error_abort);
+ object_property_set_str(OBJECT(cpu), model_id, "model-id",
+ &error_abort);
env->cpuid_min_level =
kvm_arch_get_supported_cpuid(s, 0x0, 0, R_EAX);
--
2.11.0

View File

@ -1,85 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Eduardo Habkost <ehabkost@redhat.com>
Date: Tue, 9 Jan 2018 13:45:13 -0200
Subject: [PATCH] i386: Change X86CPUDefinition::model_id to const char*
It is valid to have a 48-character model ID on CPUID, however the
definition of X86CPUDefinition::model_id is char[48], which can
make the compiler drop the null terminator from the string.
If a CPU model happens to have 48 bytes on model_id, "-cpu help"
will print garbage and the object_property_set_str() call at
x86_cpu_load_def() will read data outside the model_id array.
We could increase the array size to 49, but this would mean the
compiler would not issue a warning if a 49-char string is used by
mistake for model_id.
To make things simpler, simply change model_id to be const char*,
and validate the string length using an assert() on
x86_cpu_cpudef_class_init.
Reported-by: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
---
target/i386/cpu.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 3d53cb4c86..c673521016 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -753,7 +753,7 @@ struct X86CPUDefinition {
int model;
int stepping;
FeatureWordArray features;
- char model_id[48];
+ const char *model_id;
};
static X86CPUDefinition builtin_x86_defs[] = {
@@ -922,6 +922,7 @@ static X86CPUDefinition builtin_x86_defs[] = {
.features[FEAT_1_EDX] =
I486_FEATURES,
.xlevel = 0,
+ .model_id = "",
},
{
.name = "pentium",
@@ -933,6 +934,7 @@ static X86CPUDefinition builtin_x86_defs[] = {
.features[FEAT_1_EDX] =
PENTIUM_FEATURES,
.xlevel = 0,
+ .model_id = "",
},
{
.name = "pentium2",
@@ -944,6 +946,7 @@ static X86CPUDefinition builtin_x86_defs[] = {
.features[FEAT_1_EDX] =
PENTIUM2_FEATURES,
.xlevel = 0,
+ .model_id = "",
},
{
.name = "pentium3",
@@ -955,6 +958,7 @@ static X86CPUDefinition builtin_x86_defs[] = {
.features[FEAT_1_EDX] =
PENTIUM3_FEATURES,
.xlevel = 0,
+ .model_id = "",
},
{
.name = "athlon",
@@ -2617,6 +2621,9 @@ static void x86_register_cpudef_type(X86CPUDefinition *def)
* they shouldn't be set on the CPU model table.
*/
assert(!(def->features[FEAT_8000_0001_EDX] & CPUID_EXT2_AMD_ALIASES));
+ /* catch mistakes instead of silently truncating model_id when too long */
+ assert(def->model_id && strlen(def->model_id) <= 48);
+
type_register(&ti);
g_free(typename);
--
2.11.0

View File

@ -1,135 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Paolo Bonzini <pbonzini@redhat.com>
Date: Tue, 9 Jan 2018 13:45:14 -0200
Subject: [PATCH] i386: Add support for SPEC_CTRL MSR
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
---
target/i386/cpu.h | 3 +++
target/i386/kvm.c | 15 +++++++++++++++
target/i386/machine.c | 20 ++++++++++++++++++++
3 files changed, 38 insertions(+)
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index c4602ca80d..cc322d6b39 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -333,6 +333,7 @@
#define MSR_IA32_APICBASE_BASE (0xfffffU<<12)
#define MSR_IA32_FEATURE_CONTROL 0x0000003a
#define MSR_TSC_ADJUST 0x0000003b
+#define MSR_IA32_SPEC_CTRL 0x48
#define MSR_IA32_TSCDEADLINE 0x6e0
#define FEATURE_CONTROL_LOCKED (1<<0)
@@ -1080,6 +1081,8 @@ typedef struct CPUX86State {
uint32_t pkru;
+ uint64_t spec_ctrl;
+
/* End of state preserved by INIT (dummy marker). */
struct {} end_init_save;
diff --git a/target/i386/kvm.c b/target/i386/kvm.c
index 55865dbee0..9f83c79338 100644
--- a/target/i386/kvm.c
+++ b/target/i386/kvm.c
@@ -89,6 +89,7 @@ static bool has_msr_hv_runtime;
static bool has_msr_hv_synic;
static bool has_msr_hv_stimer;
static bool has_msr_xss;
+static bool has_msr_spec_ctrl;
static bool has_msr_architectural_pmu;
static uint32_t num_architectural_pmu_counters;
@@ -1140,6 +1141,10 @@ static int kvm_get_supported_msrs(KVMState *s)
has_msr_hv_stimer = true;
continue;
}
+ if (kvm_msr_list->indices[i] == MSR_IA32_SPEC_CTRL) {
+ has_msr_spec_ctrl = true;
+ continue;
+ }
}
}
@@ -1667,6 +1672,9 @@ static int kvm_put_msrs(X86CPU *cpu, int level)
if (has_msr_xss) {
kvm_msr_entry_add(cpu, MSR_IA32_XSS, env->xss);
}
+ if (has_msr_spec_ctrl) {
+ kvm_msr_entry_add(cpu, MSR_IA32_SPEC_CTRL, env->spec_ctrl);
+ }
#ifdef TARGET_X86_64
if (lm_capable_kernel) {
kvm_msr_entry_add(cpu, MSR_CSTAR, env->cstar);
@@ -1675,6 +1683,7 @@ static int kvm_put_msrs(X86CPU *cpu, int level)
kvm_msr_entry_add(cpu, MSR_LSTAR, env->lstar);
}
#endif
+
/*
* The following MSRs have side effects on the guest or are too heavy
* for normal writeback. Limit them to reset or full state updates.
@@ -2081,6 +2090,9 @@ static int kvm_get_msrs(X86CPU *cpu)
if (has_msr_xss) {
kvm_msr_entry_add(cpu, MSR_IA32_XSS, 0);
}
+ if (has_msr_spec_ctrl) {
+ kvm_msr_entry_add(cpu, MSR_IA32_SPEC_CTRL, 0);
+ }
if (!env->tsc_valid) {
@@ -2430,6 +2442,9 @@ static int kvm_get_msrs(X86CPU *cpu)
env->mtrr_var[MSR_MTRRphysIndex(index)].base = msrs[i].data;
}
break;
+ case MSR_IA32_SPEC_CTRL:
+ env->spec_ctrl = msrs[i].data;
+ break;
}
}
diff --git a/target/i386/machine.c b/target/i386/machine.c
index 78ae2f986b..8c0d5437fa 100644
--- a/target/i386/machine.c
+++ b/target/i386/machine.c
@@ -927,6 +927,25 @@ static const VMStateDescription vmstate_mcg_ext_ctl = {
}
};
+static bool spec_ctrl_needed(void *opaque)
+{
+ X86CPU *cpu = opaque;
+ CPUX86State *env = &cpu->env;
+
+ return env->spec_ctrl != 0;
+}
+
+static const VMStateDescription vmstate_spec_ctrl = {
+ .name = "cpu/spec_ctrl",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = spec_ctrl_needed,
+ .fields = (VMStateField[]){
+ VMSTATE_UINT64(env.spec_ctrl, X86CPU),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
VMStateDescription vmstate_x86_cpu = {
.name = "cpu",
.version_id = 12,
@@ -1053,6 +1072,7 @@ VMStateDescription vmstate_x86_cpu = {
#ifdef TARGET_X86_64
&vmstate_pkru,
#endif
+ &vmstate_spec_ctrl,
&vmstate_mcg_ext_ctl,
NULL
}
--
2.11.0

View File

@ -1,41 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Eduardo Habkost <ehabkost@redhat.com>
Date: Tue, 9 Jan 2018 13:45:15 -0200
Subject: [PATCH] i386: Add spec-ctrl CPUID bit
Add the feature name and a CPUID_7_0_EDX_SPEC_CTRL macro.
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
---
target/i386/cpu.c | 2 +-
target/i386/cpu.h | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index c673521016..faf1ff6dcc 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -460,7 +460,7 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
+ NULL, NULL, "spec-ctrl", NULL,
NULL, NULL, NULL, NULL,
},
.cpuid_eax = 7,
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index cc322d6b39..71261f4819 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -640,6 +640,7 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS];
#define CPUID_7_0_EDX_AVX512_4VNNIW (1U << 2) /* AVX512 Neural Network Instructions */
#define CPUID_7_0_EDX_AVX512_4FMAPS (1U << 3) /* AVX512 Multiply Accumulation Single Precision */
+#define CPUID_7_0_EDX_SPEC_CTRL (1U << 26) /* Speculation Control */
#define CPUID_XSAVE_XSAVEOPT (1U << 0)
#define CPUID_XSAVE_XSAVEC (1U << 1)
--
2.11.0

View File

@ -1,83 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Eduardo Habkost <ehabkost@redhat.com>
Date: Tue, 9 Jan 2018 13:45:16 -0200
Subject: [PATCH] i386: Add FEAT_8000_0008_EBX CPUID feature word
Add the new feature word and the "ibpb" feature flag.
Based on a patch by Paolo Bonzini.
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
---
target/i386/cpu.c | 19 ++++++++++++++++++-
target/i386/cpu.h | 3 +++
2 files changed, 21 insertions(+), 1 deletion(-)
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index faf1ff6dcc..eee365b78d 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -484,6 +484,22 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
.tcg_features = TCG_APM_FEATURES,
.unmigratable_flags = CPUID_APM_INVTSC,
},
+ [FEAT_8000_0008_EBX] = {
+ .feat_names = {
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ "ibpb", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ },
+ .cpuid_eax = 0x80000008,
+ .cpuid_reg = R_EBX,
+ .tcg_features = 0,
+ .unmigratable_flags = 0,
+ },
[FEAT_XSAVE] = {
.feat_names = {
"xsaveopt", "xsavec", "xgetbv1", "xsaves",
@@ -2984,7 +3000,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
} else {
*eax = cpu->phys_bits;
}
- *ebx = 0;
+ *ebx = env->features[FEAT_8000_0008_EBX];
*ecx = 0;
*edx = 0;
if (cs->nr_cores * cs->nr_threads > 1) {
@@ -3440,6 +3456,7 @@ static void x86_cpu_expand_features(X86CPU *cpu, Error **errp)
x86_cpu_adjust_feat_level(cpu, FEAT_8000_0001_EDX);
x86_cpu_adjust_feat_level(cpu, FEAT_8000_0001_ECX);
x86_cpu_adjust_feat_level(cpu, FEAT_8000_0007_EDX);
+ x86_cpu_adjust_feat_level(cpu, FEAT_8000_0008_EBX);
x86_cpu_adjust_feat_level(cpu, FEAT_C000_0001_EDX);
x86_cpu_adjust_feat_level(cpu, FEAT_SVM);
x86_cpu_adjust_feat_level(cpu, FEAT_XSAVE);
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 71261f4819..1ebee91930 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -452,6 +452,7 @@ typedef enum FeatureWord {
FEAT_8000_0001_EDX, /* CPUID[8000_0001].EDX */
FEAT_8000_0001_ECX, /* CPUID[8000_0001].ECX */
FEAT_8000_0007_EDX, /* CPUID[8000_0007].EDX */
+ FEAT_8000_0008_EBX, /* CPUID[8000_0008].EBX */
FEAT_C000_0001_EDX, /* CPUID[C000_0001].EDX */
FEAT_KVM, /* CPUID[4000_0001].EAX (KVM_CPUID_FEATURES) */
FEAT_HYPERV_EAX, /* CPUID[4000_0003].EAX */
@@ -642,6 +643,8 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS];
#define CPUID_7_0_EDX_AVX512_4FMAPS (1U << 3) /* AVX512 Multiply Accumulation Single Precision */
#define CPUID_7_0_EDX_SPEC_CTRL (1U << 26) /* Speculation Control */
+#define CPUID_8000_0008_EBX_IBPB (1U << 12) /* Indirect Branch Prediction Barrier */
+
#define CPUID_XSAVE_XSAVEOPT (1U << 0)
#define CPUID_XSAVE_XSAVEC (1U << 1)
#define CPUID_XSAVE_XGETBV1 (1U << 2)
--
2.11.0

View File

@ -1,518 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Eduardo Habkost <ehabkost@redhat.com>
Date: Tue, 9 Jan 2018 13:45:17 -0200
Subject: [PATCH] i386: Add new -IBRS versions of Intel CPU models
The new MSR IA32_SPEC_CTRL MSR was introduced by a recent Intel
microcode updated and can be used by OSes to mitigate
CVE-2017-5715. Unfortunately we can't change the existing CPU
models without breaking existing setups, so users need to
explicitly update their VM configuration to use the new *-IBRS
CPU model if they want to expose IBRS to guests.
The new CPU models are simple copies of the existing CPU models,
with just CPUID_7_0_EDX_SPEC_CTRL added and model_id updated.
Cc: Jiri Denemark <jdenemar@redhat.com>
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
---
target/i386/cpu.c | 427 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 426 insertions(+), 1 deletion(-)
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index eee365b78d..e4a2d5a012 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -1085,6 +1085,31 @@ static X86CPUDefinition builtin_x86_defs[] = {
.model_id = "Intel Core i7 9xx (Nehalem Class Core i7)",
},
{
+ .name = "Nehalem-IBRS",
+ .level = 11,
+ .vendor = CPUID_VENDOR_INTEL,
+ .family = 6,
+ .model = 26,
+ .stepping = 3,
+ .features[FEAT_1_EDX] =
+ CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
+ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
+ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
+ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
+ CPUID_DE | CPUID_FP87,
+ .features[FEAT_1_ECX] =
+ CPUID_EXT_POPCNT | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 |
+ CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | CPUID_EXT_SSE3,
+ .features[FEAT_7_0_EDX] =
+ CPUID_7_0_EDX_SPEC_CTRL,
+ .features[FEAT_8000_0001_EDX] =
+ CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
+ .features[FEAT_8000_0001_ECX] =
+ CPUID_EXT3_LAHF_LM,
+ .xlevel = 0x80000008,
+ .model_id = "Intel Core i7 9xx (Nehalem Core i7, IBRS update)",
+ },
+ {
.name = "Westmere",
.level = 11,
.vendor = CPUID_VENDOR_INTEL,
@@ -1111,6 +1136,34 @@ static X86CPUDefinition builtin_x86_defs[] = {
.model_id = "Westmere E56xx/L56xx/X56xx (Nehalem-C)",
},
{
+ .name = "Westmere-IBRS",
+ .level = 11,
+ .vendor = CPUID_VENDOR_INTEL,
+ .family = 6,
+ .model = 44,
+ .stepping = 1,
+ .features[FEAT_1_EDX] =
+ CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
+ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
+ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
+ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
+ CPUID_DE | CPUID_FP87,
+ .features[FEAT_1_ECX] =
+ CPUID_EXT_AES | CPUID_EXT_POPCNT | CPUID_EXT_SSE42 |
+ CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 |
+ CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3,
+ .features[FEAT_8000_0001_EDX] =
+ CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
+ .features[FEAT_8000_0001_ECX] =
+ CPUID_EXT3_LAHF_LM,
+ .features[FEAT_7_0_EDX] =
+ CPUID_7_0_EDX_SPEC_CTRL,
+ .features[FEAT_6_EAX] =
+ CPUID_6_EAX_ARAT,
+ .xlevel = 0x80000008,
+ .model_id = "Westmere E56xx/L56xx/X56xx (IBRS update)",
+ },
+ {
.name = "SandyBridge",
.level = 0xd,
.vendor = CPUID_VENDOR_INTEL,
@@ -1142,6 +1195,39 @@ static X86CPUDefinition builtin_x86_defs[] = {
.model_id = "Intel Xeon E312xx (Sandy Bridge)",
},
{
+ .name = "SandyBridge-IBRS",
+ .level = 0xd,
+ .vendor = CPUID_VENDOR_INTEL,
+ .family = 6,
+ .model = 42,
+ .stepping = 1,
+ .features[FEAT_1_EDX] =
+ CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
+ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
+ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
+ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
+ CPUID_DE | CPUID_FP87,
+ .features[FEAT_1_ECX] =
+ CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
+ CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_POPCNT |
+ CPUID_EXT_X2APIC | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 |
+ CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | CPUID_EXT_PCLMULQDQ |
+ CPUID_EXT_SSE3,
+ .features[FEAT_8000_0001_EDX] =
+ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX |
+ CPUID_EXT2_SYSCALL,
+ .features[FEAT_8000_0001_ECX] =
+ CPUID_EXT3_LAHF_LM,
+ .features[FEAT_7_0_EDX] =
+ CPUID_7_0_EDX_SPEC_CTRL,
+ .features[FEAT_XSAVE] =
+ CPUID_XSAVE_XSAVEOPT,
+ .features[FEAT_6_EAX] =
+ CPUID_6_EAX_ARAT,
+ .xlevel = 0x80000008,
+ .model_id = "Intel Xeon E312xx (Sandy Bridge, IBRS update)",
+ },
+ {
.name = "IvyBridge",
.level = 0xd,
.vendor = CPUID_VENDOR_INTEL,
@@ -1176,6 +1262,42 @@ static X86CPUDefinition builtin_x86_defs[] = {
.model_id = "Intel Xeon E3-12xx v2 (Ivy Bridge)",
},
{
+ .name = "IvyBridge-IBRS",
+ .level = 0xd,
+ .vendor = CPUID_VENDOR_INTEL,
+ .family = 6,
+ .model = 58,
+ .stepping = 9,
+ .features[FEAT_1_EDX] =
+ CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
+ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
+ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
+ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
+ CPUID_DE | CPUID_FP87,
+ .features[FEAT_1_ECX] =
+ CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
+ CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_POPCNT |
+ CPUID_EXT_X2APIC | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 |
+ CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | CPUID_EXT_PCLMULQDQ |
+ CPUID_EXT_SSE3 | CPUID_EXT_F16C | CPUID_EXT_RDRAND,
+ .features[FEAT_7_0_EBX] =
+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_SMEP |
+ CPUID_7_0_EBX_ERMS,
+ .features[FEAT_8000_0001_EDX] =
+ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX |
+ CPUID_EXT2_SYSCALL,
+ .features[FEAT_8000_0001_ECX] =
+ CPUID_EXT3_LAHF_LM,
+ .features[FEAT_7_0_EDX] =
+ CPUID_7_0_EDX_SPEC_CTRL,
+ .features[FEAT_XSAVE] =
+ CPUID_XSAVE_XSAVEOPT,
+ .features[FEAT_6_EAX] =
+ CPUID_6_EAX_ARAT,
+ .xlevel = 0x80000008,
+ .model_id = "Intel Xeon E3-12xx v2 (Ivy Bridge, IBRS)",
+ },
+ {
.name = "Haswell-noTSX",
.level = 0xd,
.vendor = CPUID_VENDOR_INTEL,
@@ -1210,7 +1332,46 @@ static X86CPUDefinition builtin_x86_defs[] = {
CPUID_6_EAX_ARAT,
.xlevel = 0x80000008,
.model_id = "Intel Core Processor (Haswell, no TSX)",
- }, {
+ },
+ {
+ .name = "Haswell-noTSX-IBRS",
+ .level = 0xd,
+ .vendor = CPUID_VENDOR_INTEL,
+ .family = 6,
+ .model = 60,
+ .stepping = 1,
+ .features[FEAT_1_EDX] =
+ CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
+ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
+ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
+ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
+ CPUID_DE | CPUID_FP87,
+ .features[FEAT_1_ECX] =
+ CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
+ CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 |
+ CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 |
+ CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 |
+ CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE |
+ CPUID_EXT_PCID | CPUID_EXT_F16C | CPUID_EXT_RDRAND,
+ .features[FEAT_8000_0001_EDX] =
+ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX |
+ CPUID_EXT2_SYSCALL,
+ .features[FEAT_8000_0001_ECX] =
+ CPUID_EXT3_ABM | CPUID_EXT3_LAHF_LM,
+ .features[FEAT_7_0_EDX] =
+ CPUID_7_0_EDX_SPEC_CTRL,
+ .features[FEAT_7_0_EBX] =
+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 |
+ CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP |
+ CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID,
+ .features[FEAT_XSAVE] =
+ CPUID_XSAVE_XSAVEOPT,
+ .features[FEAT_6_EAX] =
+ CPUID_6_EAX_ARAT,
+ .xlevel = 0x80000008,
+ .model_id = "Intel Core Processor (Haswell, no TSX, IBRS)",
+ },
+ {
.name = "Haswell",
.level = 0xd,
.vendor = CPUID_VENDOR_INTEL,
@@ -1248,6 +1409,45 @@ static X86CPUDefinition builtin_x86_defs[] = {
.model_id = "Intel Core Processor (Haswell)",
},
{
+ .name = "Haswell-IBRS",
+ .level = 0xd,
+ .vendor = CPUID_VENDOR_INTEL,
+ .family = 6,
+ .model = 60,
+ .stepping = 4,
+ .features[FEAT_1_EDX] =
+ CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
+ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
+ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
+ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
+ CPUID_DE | CPUID_FP87,
+ .features[FEAT_1_ECX] =
+ CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
+ CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 |
+ CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 |
+ CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 |
+ CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE |
+ CPUID_EXT_PCID | CPUID_EXT_F16C | CPUID_EXT_RDRAND,
+ .features[FEAT_8000_0001_EDX] =
+ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX |
+ CPUID_EXT2_SYSCALL,
+ .features[FEAT_8000_0001_ECX] =
+ CPUID_EXT3_ABM | CPUID_EXT3_LAHF_LM,
+ .features[FEAT_7_0_EDX] =
+ CPUID_7_0_EDX_SPEC_CTRL,
+ .features[FEAT_7_0_EBX] =
+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 |
+ CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP |
+ CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID |
+ CPUID_7_0_EBX_RTM,
+ .features[FEAT_XSAVE] =
+ CPUID_XSAVE_XSAVEOPT,
+ .features[FEAT_6_EAX] =
+ CPUID_6_EAX_ARAT,
+ .xlevel = 0x80000008,
+ .model_id = "Intel Core Processor (Haswell, IBRS)",
+ },
+ {
.name = "Broadwell-noTSX",
.level = 0xd,
.vendor = CPUID_VENDOR_INTEL,
@@ -1286,6 +1486,46 @@ static X86CPUDefinition builtin_x86_defs[] = {
.model_id = "Intel Core Processor (Broadwell, no TSX)",
},
{
+ .name = "Broadwell-noTSX-IBRS",
+ .level = 0xd,
+ .vendor = CPUID_VENDOR_INTEL,
+ .family = 6,
+ .model = 61,
+ .stepping = 2,
+ .features[FEAT_1_EDX] =
+ CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
+ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
+ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
+ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
+ CPUID_DE | CPUID_FP87,
+ .features[FEAT_1_ECX] =
+ CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
+ CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 |
+ CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 |
+ CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 |
+ CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE |
+ CPUID_EXT_PCID | CPUID_EXT_F16C | CPUID_EXT_RDRAND,
+ .features[FEAT_8000_0001_EDX] =
+ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX |
+ CPUID_EXT2_SYSCALL,
+ .features[FEAT_8000_0001_ECX] =
+ CPUID_EXT3_ABM | CPUID_EXT3_LAHF_LM | CPUID_EXT3_3DNOWPREFETCH,
+ .features[FEAT_7_0_EDX] =
+ CPUID_7_0_EDX_SPEC_CTRL,
+ .features[FEAT_7_0_EBX] =
+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 |
+ CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP |
+ CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID |
+ CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX |
+ CPUID_7_0_EBX_SMAP,
+ .features[FEAT_XSAVE] =
+ CPUID_XSAVE_XSAVEOPT,
+ .features[FEAT_6_EAX] =
+ CPUID_6_EAX_ARAT,
+ .xlevel = 0x80000008,
+ .model_id = "Intel Core Processor (Broadwell, no TSX, IBRS)",
+ },
+ {
.name = "Broadwell",
.level = 0xd,
.vendor = CPUID_VENDOR_INTEL,
@@ -1324,6 +1564,46 @@ static X86CPUDefinition builtin_x86_defs[] = {
.model_id = "Intel Core Processor (Broadwell)",
},
{
+ .name = "Broadwell-IBRS",
+ .level = 0xd,
+ .vendor = CPUID_VENDOR_INTEL,
+ .family = 6,
+ .model = 61,
+ .stepping = 2,
+ .features[FEAT_1_EDX] =
+ CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
+ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
+ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
+ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
+ CPUID_DE | CPUID_FP87,
+ .features[FEAT_1_ECX] =
+ CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
+ CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 |
+ CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 |
+ CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 |
+ CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE |
+ CPUID_EXT_PCID | CPUID_EXT_F16C | CPUID_EXT_RDRAND,
+ .features[FEAT_8000_0001_EDX] =
+ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX |
+ CPUID_EXT2_SYSCALL,
+ .features[FEAT_8000_0001_ECX] =
+ CPUID_EXT3_ABM | CPUID_EXT3_LAHF_LM | CPUID_EXT3_3DNOWPREFETCH,
+ .features[FEAT_7_0_EDX] =
+ CPUID_7_0_EDX_SPEC_CTRL,
+ .features[FEAT_7_0_EBX] =
+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 |
+ CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP |
+ CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID |
+ CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX |
+ CPUID_7_0_EBX_SMAP,
+ .features[FEAT_XSAVE] =
+ CPUID_XSAVE_XSAVEOPT,
+ .features[FEAT_6_EAX] =
+ CPUID_6_EAX_ARAT,
+ .xlevel = 0x80000008,
+ .model_id = "Intel Core Processor (Broadwell, IBRS)",
+ },
+ {
.name = "Skylake-Client",
.level = 0xd,
.vendor = CPUID_VENDOR_INTEL,
@@ -1369,6 +1649,151 @@ static X86CPUDefinition builtin_x86_defs[] = {
.model_id = "Intel Core Processor (Skylake)",
},
{
+ .name = "Skylake-Client-IBRS",
+ .level = 0xd,
+ .vendor = CPUID_VENDOR_INTEL,
+ .family = 6,
+ .model = 94,
+ .stepping = 3,
+ .features[FEAT_1_EDX] =
+ CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
+ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
+ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
+ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
+ CPUID_DE | CPUID_FP87,
+ .features[FEAT_1_ECX] =
+ CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
+ CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 |
+ CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 |
+ CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 |
+ CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE |
+ CPUID_EXT_PCID | CPUID_EXT_F16C | CPUID_EXT_RDRAND,
+ .features[FEAT_8000_0001_EDX] =
+ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX |
+ CPUID_EXT2_SYSCALL,
+ .features[FEAT_8000_0001_ECX] =
+ CPUID_EXT3_ABM | CPUID_EXT3_LAHF_LM | CPUID_EXT3_3DNOWPREFETCH,
+ .features[FEAT_7_0_EDX] =
+ CPUID_7_0_EDX_SPEC_CTRL,
+ .features[FEAT_7_0_EBX] =
+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 |
+ CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP |
+ CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID |
+ CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX |
+ CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_MPX,
+ /* Missing: XSAVES (not supported by some Linux versions,
+ * including v4.1 to v4.12).
+ * KVM doesn't yet expose any XSAVES state save component,
+ * and the only one defined in Skylake (processor tracing)
+ * probably will block migration anyway.
+ */
+ .features[FEAT_XSAVE] =
+ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC |
+ CPUID_XSAVE_XGETBV1,
+ .features[FEAT_6_EAX] =
+ CPUID_6_EAX_ARAT,
+ .xlevel = 0x80000008,
+ .model_id = "Intel Core Processor (Skylake, IBRS)",
+ },
+ {
+ .name = "Skylake-Server",
+ .level = 0xd,
+ .vendor = CPUID_VENDOR_INTEL,
+ .family = 6,
+ .model = 85,
+ .stepping = 4,
+ .features[FEAT_1_EDX] =
+ CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
+ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
+ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
+ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
+ CPUID_DE | CPUID_FP87,
+ .features[FEAT_1_ECX] =
+ CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
+ CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 |
+ CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 |
+ CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 |
+ CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE |
+ CPUID_EXT_PCID | CPUID_EXT_F16C | CPUID_EXT_RDRAND,
+ .features[FEAT_8000_0001_EDX] =
+ CPUID_EXT2_LM | CPUID_EXT2_PDPE1GB | CPUID_EXT2_RDTSCP |
+ CPUID_EXT2_NX | CPUID_EXT2_SYSCALL,
+ .features[FEAT_8000_0001_ECX] =
+ CPUID_EXT3_ABM | CPUID_EXT3_LAHF_LM | CPUID_EXT3_3DNOWPREFETCH,
+ .features[FEAT_7_0_EBX] =
+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 |
+ CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP |
+ CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID |
+ CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX |
+ CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_MPX | CPUID_7_0_EBX_CLWB |
+ CPUID_7_0_EBX_AVX512F | CPUID_7_0_EBX_AVX512DQ |
+ CPUID_7_0_EBX_AVX512BW | CPUID_7_0_EBX_AVX512CD |
+ CPUID_7_0_EBX_AVX512VL,
+ /* Missing: XSAVES (not supported by some Linux versions,
+ * including v4.1 to v4.12).
+ * KVM doesn't yet expose any XSAVES state save component,
+ * and the only one defined in Skylake (processor tracing)
+ * probably will block migration anyway.
+ */
+ .features[FEAT_XSAVE] =
+ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC |
+ CPUID_XSAVE_XGETBV1,
+ .features[FEAT_6_EAX] =
+ CPUID_6_EAX_ARAT,
+ .xlevel = 0x80000008,
+ .model_id = "Intel Xeon Processor (Skylake)",
+ },
+ {
+ .name = "Skylake-Server-IBRS",
+ .level = 0xd,
+ .vendor = CPUID_VENDOR_INTEL,
+ .family = 6,
+ .model = 85,
+ .stepping = 4,
+ .features[FEAT_1_EDX] =
+ CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
+ CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
+ CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
+ CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
+ CPUID_DE | CPUID_FP87,
+ .features[FEAT_1_ECX] =
+ CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
+ CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 |
+ CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 |
+ CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 |
+ CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE |
+ CPUID_EXT_PCID | CPUID_EXT_F16C | CPUID_EXT_RDRAND,
+ .features[FEAT_8000_0001_EDX] =
+ CPUID_EXT2_LM | CPUID_EXT2_PDPE1GB | CPUID_EXT2_RDTSCP |
+ CPUID_EXT2_NX | CPUID_EXT2_SYSCALL,
+ .features[FEAT_8000_0001_ECX] =
+ CPUID_EXT3_ABM | CPUID_EXT3_LAHF_LM | CPUID_EXT3_3DNOWPREFETCH,
+ .features[FEAT_7_0_EDX] =
+ CPUID_7_0_EDX_SPEC_CTRL,
+ .features[FEAT_7_0_EBX] =
+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 |
+ CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP |
+ CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID |
+ CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX |
+ CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_MPX | CPUID_7_0_EBX_CLWB |
+ CPUID_7_0_EBX_AVX512F | CPUID_7_0_EBX_AVX512DQ |
+ CPUID_7_0_EBX_AVX512BW | CPUID_7_0_EBX_AVX512CD |
+ CPUID_7_0_EBX_AVX512VL,
+ /* Missing: XSAVES (not supported by some Linux versions,
+ * including v4.1 to v4.12).
+ * KVM doesn't yet expose any XSAVES state save component,
+ * and the only one defined in Skylake (processor tracing)
+ * probably will block migration anyway.
+ */
+ .features[FEAT_XSAVE] =
+ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC |
+ CPUID_XSAVE_XGETBV1,
+ .features[FEAT_6_EAX] =
+ CPUID_6_EAX_ARAT,
+ .xlevel = 0x80000008,
+ .model_id = "Intel Xeon Processor (Skylake, IBRS)",
+ },
+ {
.name = "Opteron_G1",
.level = 5,
.vendor = CPUID_VENDOR_AMD,
--
2.11.0

View File

@ -1,121 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Paolo Bonzini <pbonzini@redhat.com>
Date: Thu, 1 Jun 2017 12:44:56 +0200
Subject: [PATCH] nbd: make it thread-safe, fix qcow2 over nbd
NBD is not thread safe, because it accesses s->in_flight without
a CoMutex. Fixing this will be required for multiqueue.
CoQueue doesn't have spurious wakeups but, when another coroutine can
run between qemu_co_queue_next's wakeup and qemu_co_queue_wait's
re-locking of the mutex, the wait condition can become false and
a loop is necessary.
In fact, it turns out that the loop is necessary even without this
multi-threaded scenario. A particular sequence of coroutine wakeups
is happening ~80% of the time when starting a guest with qcow2 image
served over NBD (i.e. qemu-nbd --format=raw, and QEMU's -drive option
has -format=qcow2). This patch fixes that issue too.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
block/nbd-client.c | 30 +++++++++---------------------
1 file changed, 9 insertions(+), 21 deletions(-)
diff --git a/block/nbd-client.c b/block/nbd-client.c
index 56eb0e2e16..282679b4f8 100644
--- a/block/nbd-client.c
+++ b/block/nbd-client.c
@@ -114,6 +114,10 @@ static int nbd_co_send_request(BlockDriverState *bs,
int rc, ret, i;
qemu_co_mutex_lock(&s->send_mutex);
+ while (s->in_flight == MAX_NBD_REQUESTS) {
+ qemu_co_queue_wait(&s->free_sema, &s->send_mutex);
+ }
+ s->in_flight++;
for (i = 0; i < MAX_NBD_REQUESTS; i++) {
if (s->recv_coroutine[i] == NULL) {
@@ -176,20 +180,6 @@ static void nbd_co_receive_reply(NBDClientSession *s,
}
}
-static void nbd_coroutine_start(NBDClientSession *s,
- NBDRequest *request)
-{
- /* Poor man semaphore. The free_sema is locked when no other request
- * can be accepted, and unlocked after receiving one reply. */
- if (s->in_flight == MAX_NBD_REQUESTS) {
- qemu_co_queue_wait(&s->free_sema, NULL);
- assert(s->in_flight < MAX_NBD_REQUESTS);
- }
- s->in_flight++;
-
- /* s->recv_coroutine[i] is set as soon as we get the send_lock. */
-}
-
static void nbd_coroutine_end(BlockDriverState *bs,
NBDRequest *request)
{
@@ -197,13 +187,16 @@ static void nbd_coroutine_end(BlockDriverState *bs,
int i = HANDLE_TO_INDEX(s, request->handle);
s->recv_coroutine[i] = NULL;
- s->in_flight--;
- qemu_co_queue_next(&s->free_sema);
/* Kick the read_reply_co to get the next reply. */
if (s->read_reply_co) {
aio_co_wake(s->read_reply_co);
}
+
+ qemu_co_mutex_lock(&s->send_mutex);
+ s->in_flight--;
+ qemu_co_queue_next(&s->free_sema);
+ qemu_co_mutex_unlock(&s->send_mutex);
}
int nbd_client_co_preadv(BlockDriverState *bs, uint64_t offset,
@@ -221,7 +214,6 @@ int nbd_client_co_preadv(BlockDriverState *bs, uint64_t offset,
assert(bytes <= NBD_MAX_BUFFER_SIZE);
assert(!flags);
- nbd_coroutine_start(client, &request);
ret = nbd_co_send_request(bs, &request, NULL);
if (ret < 0) {
reply.error = -ret;
@@ -251,7 +243,6 @@ int nbd_client_co_pwritev(BlockDriverState *bs, uint64_t offset,
assert(bytes <= NBD_MAX_BUFFER_SIZE);
- nbd_coroutine_start(client, &request);
ret = nbd_co_send_request(bs, &request, qiov);
if (ret < 0) {
reply.error = -ret;
@@ -286,7 +277,6 @@ int nbd_client_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
request.flags |= NBD_CMD_FLAG_NO_HOLE;
}
- nbd_coroutine_start(client, &request);
ret = nbd_co_send_request(bs, &request, NULL);
if (ret < 0) {
reply.error = -ret;
@@ -311,7 +301,6 @@ int nbd_client_co_flush(BlockDriverState *bs)
request.from = 0;
request.len = 0;
- nbd_coroutine_start(client, &request);
ret = nbd_co_send_request(bs, &request, NULL);
if (ret < 0) {
reply.error = -ret;
@@ -337,7 +326,6 @@ int nbd_client_co_pdiscard(BlockDriverState *bs, int64_t offset, int count)
return 0;
}
- nbd_coroutine_start(client, &request);
ret = nbd_co_send_request(bs, &request, NULL);
if (ret < 0) {
reply.error = -ret;
--
2.11.0

View File

@ -1,52 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Date: Tue, 16 May 2017 12:45:29 +0300
Subject: [PATCH] nbd: strict nbd_wr_syncv
nbd_wr_syncv is called either from coroutine or from client negotiation
code, when socket is in blocking mode. So, -EAGAIN is impossible.
Furthermore, EAGAIN is confusing, as, what to read/write again? With
EAGAIN as a return code we don't know how much data is already
read or written by the function, so in case of EAGAIN the whole
communication is broken.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Message-Id: <20170516094533.6160-2-vsementsov@virtuozzo.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
nbd/common.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/nbd/common.c b/nbd/common.c
index dccbb8e9de..4db45b3ede 100644
--- a/nbd/common.c
+++ b/nbd/common.c
@@ -20,6 +20,10 @@
#include "qapi/error.h"
#include "nbd-internal.h"
+/* nbd_wr_syncv
+ * The function may be called from coroutine or from non-coroutine context.
+ * When called from non-coroutine context @ioc must be in blocking mode.
+ */
ssize_t nbd_wr_syncv(QIOChannel *ioc,
struct iovec *iov,
size_t niov,
@@ -42,11 +46,8 @@ ssize_t nbd_wr_syncv(QIOChannel *ioc,
len = qio_channel_writev(ioc, local_iov, nlocal_iov, &local_err);
}
if (len == QIO_CHANNEL_ERR_BLOCK) {
- if (qemu_in_coroutine()) {
- qio_channel_yield(ioc, do_read ? G_IO_IN : G_IO_OUT);
- } else {
- return -EAGAIN;
- }
+ assert(qemu_in_coroutine());
+ qio_channel_yield(ioc, do_read ? G_IO_IN : G_IO_OUT);
continue;
}
if (len < 0) {
--
2.11.0

View File

@ -1,606 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Date: Tue, 16 May 2017 12:45:30 +0300
Subject: [PATCH] nbd: read_sync and friends: return 0 on success
functions read_sync, drop_sync, write_sync, and also
nbd_negotiate_write, nbd_negotiate_read, nbd_negotiate_drop_sync
returns number of processed bytes. But what this number can be,
except requested number of bytes?
Actually, underlying nbd_wr_syncv function returns a value >= 0 and
!= requested_bytes only on eof on read operation. So, firstly, it is
impossible on write (let's add an assert) and on read it actually
means, that communication is broken (except nbd_receive_reply, see
below).
Most of callers operate like this:
if (func(..., size) != size) {
/* error path */
}
, i.e.:
1. They are not interested in partial success
2. Extra duplications in code (especially bad are duplications of
magic numbers)
3. User doesn't see actual error message, as return code is lost.
(this patch doesn't fix this point, but it makes fixing easier)
Several callers handles ret >= 0 and != requested-size separately, by
just returning EINVAL in this case. This patch makes read_sync and
friends return EINVAL in this case, so final behavior is the same.
And only one caller - nbd_receive_reply() does something not so
obvious. It returns EINVAL for ret > 0 and != requested-size, like
previous group, but for ret == 0 it returns 0. The only caller of
nbd_receive_reply() - nbd_read_reply_entry() handles ret == 0 in the
same way as ret < 0, so for now it doesn't matter. However, in
following commits error path handling will be improved and we'll need
to distinguish success from fail in this case too. So, this patch adds
separate helper for this case - read_sync_eof.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Message-Id: <20170516094533.6160-3-vsementsov@virtuozzo.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
nbd/client.c | 63 ++++++++++++++++------------------------
nbd/nbd-internal.h | 34 +++++++++++++++++++---
nbd/server.c | 84 +++++++++++++++++++++---------------------------------
3 files changed, 88 insertions(+), 93 deletions(-)
diff --git a/nbd/client.c b/nbd/client.c
index a58fb02cb4..6b74a628f1 100644
--- a/nbd/client.c
+++ b/nbd/client.c
@@ -86,9 +86,9 @@ static QTAILQ_HEAD(, NBDExport) exports = QTAILQ_HEAD_INITIALIZER(exports);
*/
-/* Discard length bytes from channel. Return -errno on failure, or
- * the amount of bytes consumed. */
-static ssize_t drop_sync(QIOChannel *ioc, size_t size)
+/* Discard length bytes from channel. Return -errno on failure and 0 on
+ * success*/
+static int drop_sync(QIOChannel *ioc, size_t size)
{
ssize_t ret = 0;
char small[1024];
@@ -96,14 +96,13 @@ static ssize_t drop_sync(QIOChannel *ioc, size_t size)
buffer = sizeof(small) >= size ? small : g_malloc(MIN(65536, size));
while (size > 0) {
- ssize_t count = read_sync(ioc, buffer, MIN(65536, size));
+ ssize_t count = MIN(65536, size);
+ ret = read_sync(ioc, buffer, MIN(65536, size));
- if (count <= 0) {
+ if (ret < 0) {
goto cleanup;
}
- assert(count <= size);
size -= count;
- ret += count;
}
cleanup:
@@ -136,12 +135,12 @@ static int nbd_send_option_request(QIOChannel *ioc, uint32_t opt,
stl_be_p(&req.option, opt);
stl_be_p(&req.length, len);
- if (write_sync(ioc, &req, sizeof(req)) != sizeof(req)) {
+ if (write_sync(ioc, &req, sizeof(req)) < 0) {
error_setg(errp, "Failed to send option request header");
return -1;
}
- if (len && write_sync(ioc, (char *) data, len) != len) {
+ if (len && write_sync(ioc, (char *) data, len) < 0) {
error_setg(errp, "Failed to send option request data");
return -1;
}
@@ -170,7 +169,7 @@ static int nbd_receive_option_reply(QIOChannel *ioc, uint32_t opt,
nbd_opt_reply *reply, Error **errp)
{
QEMU_BUILD_BUG_ON(sizeof(*reply) != 20);
- if (read_sync(ioc, reply, sizeof(*reply)) != sizeof(*reply)) {
+ if (read_sync(ioc, reply, sizeof(*reply)) < 0) {
error_setg(errp, "failed to read option reply");
nbd_send_opt_abort(ioc);
return -1;
@@ -219,7 +218,7 @@ static int nbd_handle_reply_err(QIOChannel *ioc, nbd_opt_reply *reply,
goto cleanup;
}
msg = g_malloc(reply->length + 1);
- if (read_sync(ioc, msg, reply->length) != reply->length) {
+ if (read_sync(ioc, msg, reply->length) < 0) {
error_setg(errp, "failed to read option error message");
goto cleanup;
}
@@ -321,7 +320,7 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match,
nbd_send_opt_abort(ioc);
return -1;
}
- if (read_sync(ioc, &namelen, sizeof(namelen)) != sizeof(namelen)) {
+ if (read_sync(ioc, &namelen, sizeof(namelen)) < 0) {
error_setg(errp, "failed to read option name length");
nbd_send_opt_abort(ioc);
return -1;
@@ -334,7 +333,7 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match,
return -1;
}
if (namelen != strlen(want)) {
- if (drop_sync(ioc, len) != len) {
+ if (drop_sync(ioc, len) < 0) {
error_setg(errp, "failed to skip export name with wrong length");
nbd_send_opt_abort(ioc);
return -1;
@@ -343,14 +342,14 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match,
}
assert(namelen < sizeof(name));
- if (read_sync(ioc, name, namelen) != namelen) {
+ if (read_sync(ioc, name, namelen) < 0) {
error_setg(errp, "failed to read export name");
nbd_send_opt_abort(ioc);
return -1;
}
name[namelen] = '\0';
len -= namelen;
- if (drop_sync(ioc, len) != len) {
+ if (drop_sync(ioc, len) < 0) {
error_setg(errp, "failed to read export description");
nbd_send_opt_abort(ioc);
return -1;
@@ -477,7 +476,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags,
goto fail;
}
- if (read_sync(ioc, buf, 8) != 8) {
+ if (read_sync(ioc, buf, 8) < 0) {
error_setg(errp, "Failed to read data");
goto fail;
}
@@ -503,7 +502,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags,
goto fail;
}
- if (read_sync(ioc, &magic, sizeof(magic)) != sizeof(magic)) {
+ if (read_sync(ioc, &magic, sizeof(magic)) < 0) {
error_setg(errp, "Failed to read magic");
goto fail;
}
@@ -515,8 +514,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags,
uint16_t globalflags;
bool fixedNewStyle = false;
- if (read_sync(ioc, &globalflags, sizeof(globalflags)) !=
- sizeof(globalflags)) {
+ if (read_sync(ioc, &globalflags, sizeof(globalflags)) < 0) {
error_setg(errp, "Failed to read server flags");
goto fail;
}
@@ -534,8 +532,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags,
}
/* client requested flags */
clientflags = cpu_to_be32(clientflags);
- if (write_sync(ioc, &clientflags, sizeof(clientflags)) !=
- sizeof(clientflags)) {
+ if (write_sync(ioc, &clientflags, sizeof(clientflags)) < 0) {
error_setg(errp, "Failed to send clientflags field");
goto fail;
}
@@ -573,13 +570,13 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags,
}
/* Read the response */
- if (read_sync(ioc, &s, sizeof(s)) != sizeof(s)) {
+ if (read_sync(ioc, &s, sizeof(s)) < 0) {
error_setg(errp, "Failed to read export length");
goto fail;
}
*size = be64_to_cpu(s);
- if (read_sync(ioc, flags, sizeof(*flags)) != sizeof(*flags)) {
+ if (read_sync(ioc, flags, sizeof(*flags)) < 0) {
error_setg(errp, "Failed to read export flags");
goto fail;
}
@@ -596,14 +593,14 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags,
goto fail;
}
- if (read_sync(ioc, &s, sizeof(s)) != sizeof(s)) {
+ if (read_sync(ioc, &s, sizeof(s)) < 0) {
error_setg(errp, "Failed to read export length");
goto fail;
}
*size = be64_to_cpu(s);
TRACE("Size is %" PRIu64, *size);
- if (read_sync(ioc, &oldflags, sizeof(oldflags)) != sizeof(oldflags)) {
+ if (read_sync(ioc, &oldflags, sizeof(oldflags)) < 0) {
error_setg(errp, "Failed to read export flags");
goto fail;
}
@@ -619,7 +616,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags,
}
TRACE("Size is %" PRIu64 ", export flags %" PRIx16, *size, *flags);
- if (zeroes && drop_sync(ioc, 124) != 124) {
+ if (zeroes && drop_sync(ioc, 124) < 0) {
error_setg(errp, "Failed to read reserved block");
goto fail;
}
@@ -744,7 +741,6 @@ int nbd_disconnect(int fd)
ssize_t nbd_send_request(QIOChannel *ioc, NBDRequest *request)
{
uint8_t buf[NBD_REQUEST_SIZE];
- ssize_t ret;
TRACE("Sending request to server: "
"{ .from = %" PRIu64", .len = %" PRIu32 ", .handle = %" PRIu64
@@ -759,16 +755,7 @@ ssize_t nbd_send_request(QIOChannel *ioc, NBDRequest *request)
stq_be_p(buf + 16, request->from);
stl_be_p(buf + 24, request->len);
- ret = write_sync(ioc, buf, sizeof(buf));
- if (ret < 0) {
- return ret;
- }
-
- if (ret != sizeof(buf)) {
- LOG("writing to socket failed");
- return -EINVAL;
- }
- return 0;
+ return write_sync(ioc, buf, sizeof(buf));
}
ssize_t nbd_receive_reply(QIOChannel *ioc, NBDReply *reply)
@@ -777,7 +764,7 @@ ssize_t nbd_receive_reply(QIOChannel *ioc, NBDReply *reply)
uint32_t magic;
ssize_t ret;
- ret = read_sync(ioc, buf, sizeof(buf));
+ ret = read_sync_eof(ioc, buf, sizeof(buf));
if (ret <= 0) {
return ret;
}
diff --git a/nbd/nbd-internal.h b/nbd/nbd-internal.h
index f43d990a05..e6bbc7c4b4 100644
--- a/nbd/nbd-internal.h
+++ b/nbd/nbd-internal.h
@@ -94,7 +94,13 @@
#define NBD_ENOSPC 28
#define NBD_ESHUTDOWN 108
-static inline ssize_t read_sync(QIOChannel *ioc, void *buffer, size_t size)
+/* read_sync_eof
+ * Tries to read @size bytes from @ioc. Returns number of bytes actually read.
+ * May return a value >= 0 and < size only on EOF, i.e. when iteratively called
+ * qio_channel_readv() returns 0. So, there are no needs to call read_sync_eof
+ * iteratively.
+ */
+static inline ssize_t read_sync_eof(QIOChannel *ioc, void *buffer, size_t size)
{
struct iovec iov = { .iov_base = buffer, .iov_len = size };
/* Sockets are kept in blocking mode in the negotiation phase. After
@@ -105,12 +111,32 @@ static inline ssize_t read_sync(QIOChannel *ioc, void *buffer, size_t size)
return nbd_wr_syncv(ioc, &iov, 1, size, true);
}
-static inline ssize_t write_sync(QIOChannel *ioc, const void *buffer,
- size_t size)
+/* read_sync
+ * Reads @size bytes from @ioc. Returns 0 on success.
+ */
+static inline int read_sync(QIOChannel *ioc, void *buffer, size_t size)
+{
+ ssize_t ret = read_sync_eof(ioc, buffer, size);
+
+ if (ret >= 0 && ret != size) {
+ ret = -EINVAL;
+ }
+
+ return ret < 0 ? ret : 0;
+}
+
+/* write_sync
+ * Writes @size bytes to @ioc. Returns 0 on success.
+ */
+static inline int write_sync(QIOChannel *ioc, const void *buffer, size_t size)
{
struct iovec iov = { .iov_base = (void *) buffer, .iov_len = size };
- return nbd_wr_syncv(ioc, &iov, 1, size, false);
+ ssize_t ret = nbd_wr_syncv(ioc, &iov, 1, size, false);
+
+ assert(ret < 0 || ret == size);
+
+ return ret < 0 ? ret : 0;
}
struct NBDTLSHandshakeData {
diff --git a/nbd/server.c b/nbd/server.c
index 4d6da8ac06..c2a5909ad6 100644
--- a/nbd/server.c
+++ b/nbd/server.c
@@ -112,7 +112,7 @@ static gboolean nbd_negotiate_continue(QIOChannel *ioc,
return TRUE;
}
-static ssize_t nbd_negotiate_read(QIOChannel *ioc, void *buffer, size_t size)
+static int nbd_negotiate_read(QIOChannel *ioc, void *buffer, size_t size)
{
ssize_t ret;
guint watch;
@@ -130,8 +130,7 @@ static ssize_t nbd_negotiate_read(QIOChannel *ioc, void *buffer, size_t size)
}
-static ssize_t nbd_negotiate_write(QIOChannel *ioc, const void *buffer,
- size_t size)
+static int nbd_negotiate_write(QIOChannel *ioc, const void *buffer, size_t size)
{
ssize_t ret;
guint watch;
@@ -148,24 +147,24 @@ static ssize_t nbd_negotiate_write(QIOChannel *ioc, const void *buffer,
return ret;
}
-static ssize_t nbd_negotiate_drop_sync(QIOChannel *ioc, size_t size)
+static int nbd_negotiate_drop_sync(QIOChannel *ioc, size_t size)
{
- ssize_t ret, dropped = size;
+ ssize_t ret;
uint8_t *buffer = g_malloc(MIN(65536, size));
while (size > 0) {
- ret = nbd_negotiate_read(ioc, buffer, MIN(65536, size));
+ size_t count = MIN(65536, size);
+ ret = nbd_negotiate_read(ioc, buffer, count);
if (ret < 0) {
g_free(buffer);
return ret;
}
- assert(ret <= size);
- size -= ret;
+ size -= count;
}
g_free(buffer);
- return dropped;
+ return 0;
}
/* Basic flow for negotiation
@@ -206,22 +205,22 @@ static int nbd_negotiate_send_rep_len(QIOChannel *ioc, uint32_t type,
type, opt, len);
magic = cpu_to_be64(NBD_REP_MAGIC);
- if (nbd_negotiate_write(ioc, &magic, sizeof(magic)) != sizeof(magic)) {
+ if (nbd_negotiate_write(ioc, &magic, sizeof(magic)) < 0) {
LOG("write failed (rep magic)");
return -EINVAL;
}
opt = cpu_to_be32(opt);
- if (nbd_negotiate_write(ioc, &opt, sizeof(opt)) != sizeof(opt)) {
+ if (nbd_negotiate_write(ioc, &opt, sizeof(opt)) < 0) {
LOG("write failed (rep opt)");
return -EINVAL;
}
type = cpu_to_be32(type);
- if (nbd_negotiate_write(ioc, &type, sizeof(type)) != sizeof(type)) {
+ if (nbd_negotiate_write(ioc, &type, sizeof(type)) < 0) {
LOG("write failed (rep type)");
return -EINVAL;
}
len = cpu_to_be32(len);
- if (nbd_negotiate_write(ioc, &len, sizeof(len)) != sizeof(len)) {
+ if (nbd_negotiate_write(ioc, &len, sizeof(len)) < 0) {
LOG("write failed (rep data length)");
return -EINVAL;
}
@@ -256,7 +255,7 @@ nbd_negotiate_send_rep_err(QIOChannel *ioc, uint32_t type,
if (ret < 0) {
goto out;
}
- if (nbd_negotiate_write(ioc, msg, len) != len) {
+ if (nbd_negotiate_write(ioc, msg, len) < 0) {
LOG("write failed (error message)");
ret = -EIO;
} else {
@@ -287,15 +286,15 @@ static int nbd_negotiate_send_rep_list(QIOChannel *ioc, NBDExport *exp)
}
len = cpu_to_be32(name_len);
- if (nbd_negotiate_write(ioc, &len, sizeof(len)) != sizeof(len)) {
+ if (nbd_negotiate_write(ioc, &len, sizeof(len)) < 0) {
LOG("write failed (name length)");
return -EINVAL;
}
- if (nbd_negotiate_write(ioc, name, name_len) != name_len) {
+ if (nbd_negotiate_write(ioc, name, name_len) < 0) {
LOG("write failed (name buffer)");
return -EINVAL;
}
- if (nbd_negotiate_write(ioc, desc, desc_len) != desc_len) {
+ if (nbd_negotiate_write(ioc, desc, desc_len) < 0) {
LOG("write failed (description buffer)");
return -EINVAL;
}
@@ -309,7 +308,7 @@ static int nbd_negotiate_handle_list(NBDClient *client, uint32_t length)
NBDExport *exp;
if (length) {
- if (nbd_negotiate_drop_sync(client->ioc, length) != length) {
+ if (nbd_negotiate_drop_sync(client->ioc, length) < 0) {
return -EIO;
}
return nbd_negotiate_send_rep_err(client->ioc,
@@ -340,7 +339,7 @@ static int nbd_negotiate_handle_export_name(NBDClient *client, uint32_t length)
LOG("Bad length received");
goto fail;
}
- if (nbd_negotiate_read(client->ioc, name, length) != length) {
+ if (nbd_negotiate_read(client->ioc, name, length) < 0) {
LOG("read failed");
goto fail;
}
@@ -373,7 +372,7 @@ static QIOChannel *nbd_negotiate_handle_starttls(NBDClient *client,
TRACE("Setting up TLS");
ioc = client->ioc;
if (length) {
- if (nbd_negotiate_drop_sync(ioc, length) != length) {
+ if (nbd_negotiate_drop_sync(ioc, length) < 0) {
return NULL;
}
nbd_negotiate_send_rep_err(ioc, NBD_REP_ERR_INVALID, NBD_OPT_STARTTLS,
@@ -437,8 +436,7 @@ static int nbd_negotiate_options(NBDClient *client)
... Rest of request
*/
- if (nbd_negotiate_read(client->ioc, &flags, sizeof(flags)) !=
- sizeof(flags)) {
+ if (nbd_negotiate_read(client->ioc, &flags, sizeof(flags)) < 0) {
LOG("read failed");
return -EIO;
}
@@ -464,8 +462,7 @@ static int nbd_negotiate_options(NBDClient *client)
uint32_t clientflags, length;
uint64_t magic;
- if (nbd_negotiate_read(client->ioc, &magic, sizeof(magic)) !=
- sizeof(magic)) {
+ if (nbd_negotiate_read(client->ioc, &magic, sizeof(magic)) < 0) {
LOG("read failed");
return -EINVAL;
}
@@ -476,14 +473,14 @@ static int nbd_negotiate_options(NBDClient *client)
}
if (nbd_negotiate_read(client->ioc, &clientflags,
- sizeof(clientflags)) != sizeof(clientflags)) {
+ sizeof(clientflags)) < 0)
+ {
LOG("read failed");
return -EINVAL;
}
clientflags = be32_to_cpu(clientflags);
- if (nbd_negotiate_read(client->ioc, &length, sizeof(length)) !=
- sizeof(length)) {
+ if (nbd_negotiate_read(client->ioc, &length, sizeof(length)) < 0) {
LOG("read failed");
return -EINVAL;
}
@@ -519,7 +516,7 @@ static int nbd_negotiate_options(NBDClient *client)
return -EINVAL;
default:
- if (nbd_negotiate_drop_sync(client->ioc, length) != length) {
+ if (nbd_negotiate_drop_sync(client->ioc, length) < 0) {
return -EIO;
}
ret = nbd_negotiate_send_rep_err(client->ioc,
@@ -557,7 +554,7 @@ static int nbd_negotiate_options(NBDClient *client)
return nbd_negotiate_handle_export_name(client, length);
case NBD_OPT_STARTTLS:
- if (nbd_negotiate_drop_sync(client->ioc, length) != length) {
+ if (nbd_negotiate_drop_sync(client->ioc, length) < 0) {
return -EIO;
}
if (client->tlscreds) {
@@ -576,7 +573,7 @@ static int nbd_negotiate_options(NBDClient *client)
}
break;
default:
- if (nbd_negotiate_drop_sync(client->ioc, length) != length) {
+ if (nbd_negotiate_drop_sync(client->ioc, length) < 0) {
return -EIO;
}
ret = nbd_negotiate_send_rep_err(client->ioc,
@@ -665,12 +662,12 @@ static coroutine_fn int nbd_negotiate(NBDClientNewData *data)
TRACE("TLS cannot be enabled with oldstyle protocol");
goto fail;
}
- if (nbd_negotiate_write(client->ioc, buf, sizeof(buf)) != sizeof(buf)) {
+ if (nbd_negotiate_write(client->ioc, buf, sizeof(buf)) < 0) {
LOG("write failed");
goto fail;
}
} else {
- if (nbd_negotiate_write(client->ioc, buf, 18) != 18) {
+ if (nbd_negotiate_write(client->ioc, buf, 18) < 0) {
LOG("write failed");
goto fail;
}
@@ -685,7 +682,7 @@ static coroutine_fn int nbd_negotiate(NBDClientNewData *data)
stq_be_p(buf + 18, client->exp->size);
stw_be_p(buf + 26, client->exp->nbdflags | myflags);
len = client->no_zeroes ? 10 : sizeof(buf) - 18;
- if (nbd_negotiate_write(client->ioc, buf + 18, len) != len) {
+ if (nbd_negotiate_write(client->ioc, buf + 18, len) < 0) {
LOG("write failed");
goto fail;
}
@@ -708,11 +705,6 @@ static ssize_t nbd_receive_request(QIOChannel *ioc, NBDRequest *request)
return ret;
}
- if (ret != sizeof(buf)) {
- LOG("read failed");
- return -EINVAL;
- }
-
/* Request
[ 0 .. 3] magic (NBD_REQUEST_MAGIC)
[ 4 .. 5] flags (NBD_CMD_FLAG_FUA, ...)
@@ -743,7 +735,6 @@ static ssize_t nbd_receive_request(QIOChannel *ioc, NBDRequest *request)
static ssize_t nbd_send_reply(QIOChannel *ioc, NBDReply *reply)
{
uint8_t buf[NBD_REPLY_SIZE];
- ssize_t ret;
reply->error = system_errno_to_nbd_errno(reply->error);
@@ -760,16 +751,7 @@ static ssize_t nbd_send_reply(QIOChannel *ioc, NBDReply *reply)
stl_be_p(buf + 4, reply->error);
stq_be_p(buf + 8, reply->handle);
- ret = write_sync(ioc, buf, sizeof(buf));
- if (ret < 0) {
- return ret;
- }
-
- if (ret != sizeof(buf)) {
- LOG("writing to socket failed");
- return -EINVAL;
- }
- return 0;
+ return write_sync(ioc, buf, sizeof(buf));
}
#define MAX_NBD_REQUESTS 16
@@ -1073,7 +1055,7 @@ static ssize_t nbd_co_send_reply(NBDRequestData *req, NBDReply *reply,
rc = nbd_send_reply(client->ioc, reply);
if (rc >= 0) {
ret = write_sync(client->ioc, req->data, len);
- if (ret != len) {
+ if (ret < 0) {
rc = -EIO;
}
}
@@ -1147,7 +1129,7 @@ static ssize_t nbd_co_receive_request(NBDRequestData *req,
if (request->type == NBD_CMD_WRITE) {
TRACE("Reading %" PRIu32 " byte(s)", request->len);
- if (read_sync(client->ioc, req->data, request->len) != request->len) {
+ if (read_sync(client->ioc, req->data, request->len) < 0) {
LOG("reading from socket failed");
rc = -EIO;
goto out;
--
2.11.0

View File

@ -1,151 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Eric Blake <eblake@redhat.com>
Date: Wed, 19 Jul 2017 18:02:01 +0200
Subject: [PATCH] nbd: make nbd_drop public
RH-Author: Eric Blake <eblake@redhat.com>
Message-id: <20170719180202.23329-4-eblake@redhat.com>
Patchwork-id: 75814
O-Subject: [RHEV-7.4.z qemu-kvm-rhev PATCH 3/4] nbd: make nbd_drop public
Bugzilla: 1467509
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
RH-Acked-by: Jeffrey Cody <jcody@redhat.com>
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Following commit will reuse it for nbd server too.
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Message-Id: <20170602150150.258222-3-vsementsov@virtuozzo.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 44298024d30ad36439707b89715a76333f58791b)
Conflicts:
nbd/client.c, nbd/nbd_internal.h, nbd/common.c - missing errp
addition (e44ed99) and bulk rename (d1fdf25)
Signed-off-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
---
nbd/client.c | 32 +++-----------------------------
nbd/common.c | 26 ++++++++++++++++++++++++++
nbd/nbd-internal.h | 2 ++
3 files changed, 31 insertions(+), 29 deletions(-)
diff --git a/nbd/client.c b/nbd/client.c
index 6b74a628f1..1652f28e9f 100644
--- a/nbd/client.c
+++ b/nbd/client.c
@@ -86,32 +86,6 @@ static QTAILQ_HEAD(, NBDExport) exports = QTAILQ_HEAD_INITIALIZER(exports);
*/
-/* Discard length bytes from channel. Return -errno on failure and 0 on
- * success*/
-static int drop_sync(QIOChannel *ioc, size_t size)
-{
- ssize_t ret = 0;
- char small[1024];
- char *buffer;
-
- buffer = sizeof(small) >= size ? small : g_malloc(MIN(65536, size));
- while (size > 0) {
- ssize_t count = MIN(65536, size);
- ret = read_sync(ioc, buffer, MIN(65536, size));
-
- if (ret < 0) {
- goto cleanup;
- }
- size -= count;
- }
-
- cleanup:
- if (buffer != small) {
- g_free(buffer);
- }
- return ret;
-}
-
/* Send an option request.
*
* The request is for option @opt, with @data containing @len bytes of
@@ -333,7 +307,7 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match,
return -1;
}
if (namelen != strlen(want)) {
- if (drop_sync(ioc, len) < 0) {
+ if (nbd_drop(ioc, len) < 0) {
error_setg(errp, "failed to skip export name with wrong length");
nbd_send_opt_abort(ioc);
return -1;
@@ -349,7 +323,7 @@ static int nbd_receive_list(QIOChannel *ioc, const char *want, bool *match,
}
name[namelen] = '\0';
len -= namelen;
- if (drop_sync(ioc, len) < 0) {
+ if (nbd_drop(ioc, len) < 0) {
error_setg(errp, "failed to read export description");
nbd_send_opt_abort(ioc);
return -1;
@@ -616,7 +590,7 @@ int nbd_receive_negotiate(QIOChannel *ioc, const char *name, uint16_t *flags,
}
TRACE("Size is %" PRIu64 ", export flags %" PRIx16, *size, *flags);
- if (zeroes && drop_sync(ioc, 124) < 0) {
+ if (zeroes && nbd_drop(ioc, 124) < 0) {
error_setg(errp, "Failed to read reserved block");
goto fail;
}
diff --git a/nbd/common.c b/nbd/common.c
index 4db45b3ede..9a54010c25 100644
--- a/nbd/common.c
+++ b/nbd/common.c
@@ -71,6 +71,32 @@ ssize_t nbd_wr_syncv(QIOChannel *ioc,
return done;
}
+/* Discard length bytes from channel. Return -errno on failure and 0 on
+ * success */
+int nbd_drop(QIOChannel *ioc, size_t size)
+{
+ ssize_t ret = 0;
+ char small[1024];
+ char *buffer;
+
+ buffer = sizeof(small) >= size ? small : g_malloc(MIN(65536, size));
+ while (size > 0) {
+ ssize_t count = MIN(65536, size);
+ ret = read_sync(ioc, buffer, MIN(65536, size));
+
+ if (ret < 0) {
+ goto cleanup;
+ }
+ size -= count;
+ }
+
+ cleanup:
+ if (buffer != small) {
+ g_free(buffer);
+ }
+ return ret;
+}
+
void nbd_tls_handshake(QIOTask *task,
void *opaque)
diff --git a/nbd/nbd-internal.h b/nbd/nbd-internal.h
index e6bbc7c4b4..c02378c553 100644
--- a/nbd/nbd-internal.h
+++ b/nbd/nbd-internal.h
@@ -149,4 +149,6 @@ struct NBDTLSHandshakeData {
void nbd_tls_handshake(QIOTask *task,
void *opaque);
+int nbd_drop(QIOChannel *ioc, size_t size);
+
#endif
--
2.11.0

View File

@ -1,292 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Eric Blake <eblake@redhat.com>
Date: Wed, 19 Jul 2017 18:02:02 +0200
Subject: [PATCH] nbd/server: get rid of nbd_negotiate_read and friends
RH-Author: Eric Blake <eblake@redhat.com>
Message-id: <20170719180202.23329-5-eblake@redhat.com>
Patchwork-id: 75816
O-Subject: [RHEV-7.4.z qemu-kvm-rhev PATCH 4/4] nbd/server: get rid of nbd_negotiate_read and friends
Bugzilla: 1467509
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
RH-Acked-by: Jeffrey Cody <jcody@redhat.com>
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Functions nbd_negotiate_{read,write,drop_sync} were introduced in
1a6245a5b, when nbd_rwv (was nbd_wr_sync) was working through
qemu_co_sendv_recvv (the path is nbd_wr_sync -> qemu_co_{recv/send} ->
qemu_co_send_recv -> qemu_co_sendv_recvv), which just yields, without
setting any handlers. But starting from ff82911cd nbd_rwv (was
nbd_wr_syncv) works through qio_channel_yield() which sets handlers, so
watchers are redundant in nbd_negotiate_{read,write,drop_sync}, then,
let's just use nbd_{read,write,drop} functions.
Functions nbd_{read,write,drop} has errp parameter, which is unused in
this patch. This will be fixed later.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-Id: <20170602150150.258222-4-vsementsov@virtuozzo.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
(cherry picked from commit 2b0bbc4f8809c972bad134bc1a2570dbb01dea0b)
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
Conflicts:
nbd/server.c - missing errp addition (e44ed99) and bulk
rename (d1fdf25)
Fixes CVE-2017-7539
Signed-off-by: Eric Blake <eblake@redhat.com>
---
nbd/server.c | 106 ++++++++++++-----------------------------------------------
1 file changed, 21 insertions(+), 85 deletions(-)
diff --git a/nbd/server.c b/nbd/server.c
index c2a5909ad6..ddf93d4717 100644
--- a/nbd/server.c
+++ b/nbd/server.c
@@ -104,69 +104,6 @@ struct NBDClient {
static void nbd_client_receive_next_request(NBDClient *client);
-static gboolean nbd_negotiate_continue(QIOChannel *ioc,
- GIOCondition condition,
- void *opaque)
-{
- qemu_coroutine_enter(opaque);
- return TRUE;
-}
-
-static int nbd_negotiate_read(QIOChannel *ioc, void *buffer, size_t size)
-{
- ssize_t ret;
- guint watch;
-
- assert(qemu_in_coroutine());
- /* Negotiation are always in main loop. */
- watch = qio_channel_add_watch(ioc,
- G_IO_IN,
- nbd_negotiate_continue,
- qemu_coroutine_self(),
- NULL);
- ret = read_sync(ioc, buffer, size);
- g_source_remove(watch);
- return ret;
-
-}
-
-static int nbd_negotiate_write(QIOChannel *ioc, const void *buffer, size_t size)
-{
- ssize_t ret;
- guint watch;
-
- assert(qemu_in_coroutine());
- /* Negotiation are always in main loop. */
- watch = qio_channel_add_watch(ioc,
- G_IO_OUT,
- nbd_negotiate_continue,
- qemu_coroutine_self(),
- NULL);
- ret = write_sync(ioc, buffer, size);
- g_source_remove(watch);
- return ret;
-}
-
-static int nbd_negotiate_drop_sync(QIOChannel *ioc, size_t size)
-{
- ssize_t ret;
- uint8_t *buffer = g_malloc(MIN(65536, size));
-
- while (size > 0) {
- size_t count = MIN(65536, size);
- ret = nbd_negotiate_read(ioc, buffer, count);
- if (ret < 0) {
- g_free(buffer);
- return ret;
- }
-
- size -= count;
- }
-
- g_free(buffer);
- return 0;
-}
-
/* Basic flow for negotiation
Server Client
@@ -205,22 +142,22 @@ static int nbd_negotiate_send_rep_len(QIOChannel *ioc, uint32_t type,
type, opt, len);
magic = cpu_to_be64(NBD_REP_MAGIC);
- if (nbd_negotiate_write(ioc, &magic, sizeof(magic)) < 0) {
+ if (write_sync(ioc, &magic, sizeof(magic)) < 0) {
LOG("write failed (rep magic)");
return -EINVAL;
}
opt = cpu_to_be32(opt);
- if (nbd_negotiate_write(ioc, &opt, sizeof(opt)) < 0) {
+ if (write_sync(ioc, &opt, sizeof(opt)) < 0) {
LOG("write failed (rep opt)");
return -EINVAL;
}
type = cpu_to_be32(type);
- if (nbd_negotiate_write(ioc, &type, sizeof(type)) < 0) {
+ if (write_sync(ioc, &type, sizeof(type)) < 0) {
LOG("write failed (rep type)");
return -EINVAL;
}
len = cpu_to_be32(len);
- if (nbd_negotiate_write(ioc, &len, sizeof(len)) < 0) {
+ if (write_sync(ioc, &len, sizeof(len)) < 0) {
LOG("write failed (rep data length)");
return -EINVAL;
}
@@ -255,7 +192,7 @@ nbd_negotiate_send_rep_err(QIOChannel *ioc, uint32_t type,
if (ret < 0) {
goto out;
}
- if (nbd_negotiate_write(ioc, msg, len) < 0) {
+ if (write_sync(ioc, msg, len) < 0) {
LOG("write failed (error message)");
ret = -EIO;
} else {
@@ -286,15 +223,15 @@ static int nbd_negotiate_send_rep_list(QIOChannel *ioc, NBDExport *exp)
}
len = cpu_to_be32(name_len);
- if (nbd_negotiate_write(ioc, &len, sizeof(len)) < 0) {
+ if (write_sync(ioc, &len, sizeof(len)) < 0) {
LOG("write failed (name length)");
return -EINVAL;
}
- if (nbd_negotiate_write(ioc, name, name_len) < 0) {
+ if (write_sync(ioc, name, name_len) < 0) {
LOG("write failed (name buffer)");
return -EINVAL;
}
- if (nbd_negotiate_write(ioc, desc, desc_len) < 0) {
+ if (write_sync(ioc, desc, desc_len) < 0) {
LOG("write failed (description buffer)");
return -EINVAL;
}
@@ -308,7 +245,7 @@ static int nbd_negotiate_handle_list(NBDClient *client, uint32_t length)
NBDExport *exp;
if (length) {
- if (nbd_negotiate_drop_sync(client->ioc, length) < 0) {
+ if (nbd_drop(client->ioc, length) < 0) {
return -EIO;
}
return nbd_negotiate_send_rep_err(client->ioc,
@@ -339,7 +276,7 @@ static int nbd_negotiate_handle_export_name(NBDClient *client, uint32_t length)
LOG("Bad length received");
goto fail;
}
- if (nbd_negotiate_read(client->ioc, name, length) < 0) {
+ if (read_sync(client->ioc, name, length) < 0) {
LOG("read failed");
goto fail;
}
@@ -372,7 +309,7 @@ static QIOChannel *nbd_negotiate_handle_starttls(NBDClient *client,
TRACE("Setting up TLS");
ioc = client->ioc;
if (length) {
- if (nbd_negotiate_drop_sync(ioc, length) < 0) {
+ if (nbd_drop(ioc, length) < 0) {
return NULL;
}
nbd_negotiate_send_rep_err(ioc, NBD_REP_ERR_INVALID, NBD_OPT_STARTTLS,
@@ -436,7 +373,7 @@ static int nbd_negotiate_options(NBDClient *client)
... Rest of request
*/
- if (nbd_negotiate_read(client->ioc, &flags, sizeof(flags)) < 0) {
+ if (read_sync(client->ioc, &flags, sizeof(flags)) < 0) {
LOG("read failed");
return -EIO;
}
@@ -462,7 +399,7 @@ static int nbd_negotiate_options(NBDClient *client)
uint32_t clientflags, length;
uint64_t magic;
- if (nbd_negotiate_read(client->ioc, &magic, sizeof(magic)) < 0) {
+ if (read_sync(client->ioc, &magic, sizeof(magic)) < 0) {
LOG("read failed");
return -EINVAL;
}
@@ -472,15 +409,14 @@ static int nbd_negotiate_options(NBDClient *client)
return -EINVAL;
}
- if (nbd_negotiate_read(client->ioc, &clientflags,
- sizeof(clientflags)) < 0)
+ if (read_sync(client->ioc, &clientflags, sizeof(clientflags)) < 0)
{
LOG("read failed");
return -EINVAL;
}
clientflags = be32_to_cpu(clientflags);
- if (nbd_negotiate_read(client->ioc, &length, sizeof(length)) < 0) {
+ if (read_sync(client->ioc, &length, sizeof(length)) < 0) {
LOG("read failed");
return -EINVAL;
}
@@ -516,7 +452,7 @@ static int nbd_negotiate_options(NBDClient *client)
return -EINVAL;
default:
- if (nbd_negotiate_drop_sync(client->ioc, length) < 0) {
+ if (nbd_drop(client->ioc, length) < 0) {
return -EIO;
}
ret = nbd_negotiate_send_rep_err(client->ioc,
@@ -554,7 +490,7 @@ static int nbd_negotiate_options(NBDClient *client)
return nbd_negotiate_handle_export_name(client, length);
case NBD_OPT_STARTTLS:
- if (nbd_negotiate_drop_sync(client->ioc, length) < 0) {
+ if (nbd_drop(client->ioc, length) < 0) {
return -EIO;
}
if (client->tlscreds) {
@@ -573,7 +509,7 @@ static int nbd_negotiate_options(NBDClient *client)
}
break;
default:
- if (nbd_negotiate_drop_sync(client->ioc, length) < 0) {
+ if (nbd_drop(client->ioc, length) < 0) {
return -EIO;
}
ret = nbd_negotiate_send_rep_err(client->ioc,
@@ -662,12 +598,12 @@ static coroutine_fn int nbd_negotiate(NBDClientNewData *data)
TRACE("TLS cannot be enabled with oldstyle protocol");
goto fail;
}
- if (nbd_negotiate_write(client->ioc, buf, sizeof(buf)) < 0) {
+ if (write_sync(client->ioc, buf, sizeof(buf)) < 0) {
LOG("write failed");
goto fail;
}
} else {
- if (nbd_negotiate_write(client->ioc, buf, 18) < 0) {
+ if (write_sync(client->ioc, buf, 18) < 0) {
LOG("write failed");
goto fail;
}
@@ -682,7 +618,7 @@ static coroutine_fn int nbd_negotiate(NBDClientNewData *data)
stq_be_p(buf + 18, client->exp->size);
stw_be_p(buf + 26, client->exp->nbdflags | myflags);
len = client->no_zeroes ? 10 : sizeof(buf) - 18;
- if (nbd_negotiate_write(client->ioc, buf + 18, len) < 0) {
+ if (write_sync(client->ioc, buf + 18, len) < 0) {
LOG("write failed");
goto fail;
}
--
2.11.0

View File

@ -1,153 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Eric Blake <eblake@redhat.com>
Date: Wed, 27 Sep 2017 17:57:19 +0200
Subject: [PATCH] nbd-client: Fix regression when server sends garbage
RH-Author: Eric Blake <eblake@redhat.com>
Message-id: <20170927175725.20023-2-eblake@redhat.com>
Patchwork-id: 76672
O-Subject: [RHEV-7.4.z qemu-kvm-rhev PATCH 1/7] nbd-client: Fix regression when server sends garbage
Bugzilla: 1495474
RH-Acked-by: Max Reitz <mreitz@redhat.com>
RH-Acked-by: Jeffrey Cody <jcody@redhat.com>
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
When we switched NBD to use coroutines for qemu 2.9 (in particular,
commit a12a712a), we introduced a regression: if a server sends us
garbage (such as a corrupted magic number), we quit the read loop
but do not stop sending further queued commands, resulting in the
client hanging when it never reads the response to those additional
commands. In qemu 2.8, we properly detected that the server is no
longer reliable, and cancelled all existing pending commands with
EIO, then tore down the socket so that all further command attempts
get EPIPE.
Restore the proper behavior of quitting (almost) all communication
with a broken server: Once we know we are out of sync or otherwise
can't trust the server, we must assume that any further incoming
data is unreliable and therefore end all pending commands with EIO,
and quit trying to send any further commands. As an exception, we
still (try to) send NBD_CMD_DISC to let the server know we are going
away (in part, because it is easier to do that than to further
refactor nbd_teardown_connection, and in part because it is the
only command where we do not have to wait for a reply).
Based on a patch by Vladimir Sementsov-Ogievskiy.
A malicious server can be created with the following hack,
followed by setting NBD_SERVER_DEBUG to a non-zero value in the
environment when running qemu-nbd:
| --- a/nbd/server.c
| +++ b/nbd/server.c
| @@ -919,6 +919,17 @@ static int nbd_send_reply(QIOChannel *ioc, NBDReply *reply, Error **errp)
| stl_be_p(buf + 4, reply->error);
| stq_be_p(buf + 8, reply->handle);
|
| + static int debug;
| + static int count;
| + if (!count++) {
| + const char *str = getenv("NBD_SERVER_DEBUG");
| + if (str) {
| + debug = atoi(str);
| + }
| + }
| + if (debug && !(count % debug)) {
| + buf[0] = 0;
| + }
| return nbd_write(ioc, buf, sizeof(buf), errp);
| }
Reported-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <20170814213426.24681-1-eblake@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
(cherry picked from commit 72b6ffc76653214b69a94a7b1643ff80df134486)
Signed-off-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
Conflicts:
block/nbd-client.c
---
block/nbd-client.c | 17 +++++++++++++----
block/nbd-client.h | 1 +
2 files changed, 14 insertions(+), 4 deletions(-)
diff --git a/block/nbd-client.c b/block/nbd-client.c
index 282679b4f8..701b4ce2eb 100644
--- a/block/nbd-client.c
+++ b/block/nbd-client.c
@@ -71,7 +71,7 @@ static coroutine_fn void nbd_read_reply_entry(void *opaque)
uint64_t i;
int ret;
- for (;;) {
+ while (!s->quit) {
assert(s->reply.handle == 0);
ret = nbd_receive_reply(s->ioc, &s->reply);
if (ret <= 0) {
@@ -102,6 +102,9 @@ static coroutine_fn void nbd_read_reply_entry(void *opaque)
qemu_coroutine_yield();
}
+ if (ret < 0) {
+ s->quit = true;
+ }
nbd_recv_coroutines_enter_all(s);
s->read_reply_co = NULL;
}
@@ -130,6 +133,10 @@ static int nbd_co_send_request(BlockDriverState *bs,
assert(i < MAX_NBD_REQUESTS);
request->handle = INDEX_TO_HANDLE(s, i);
+ if (s->quit) {
+ qemu_co_mutex_unlock(&s->send_mutex);
+ return -EIO;
+ }
if (!s->ioc) {
qemu_co_mutex_unlock(&s->send_mutex);
return -EPIPE;
@@ -138,7 +145,7 @@ static int nbd_co_send_request(BlockDriverState *bs,
if (qiov) {
qio_channel_set_cork(s->ioc, true);
rc = nbd_send_request(s->ioc, request);
- if (rc >= 0) {
+ if (rc >= 0 && !s->quit) {
ret = nbd_wr_syncv(s->ioc, qiov->iov, qiov->niov, request->len,
false);
if (ret != request->len) {
@@ -149,6 +156,9 @@ static int nbd_co_send_request(BlockDriverState *bs,
} else {
rc = nbd_send_request(s->ioc, request);
}
+ if (rc < 0) {
+ s->quit = true;
+ }
qemu_co_mutex_unlock(&s->send_mutex);
return rc;
}
@@ -163,8 +173,7 @@ static void nbd_co_receive_reply(NBDClientSession *s,
/* Wait until we're woken up by nbd_read_reply_entry. */
qemu_coroutine_yield();
*reply = s->reply;
- if (reply->handle != request->handle ||
- !s->ioc) {
+ if (reply->handle != request->handle || !s->ioc || s->quit) {
reply->error = EIO;
} else {
if (qiov && reply->error == 0) {
diff --git a/block/nbd-client.h b/block/nbd-client.h
index 891ba44a20..9774a8ebbb 100644
--- a/block/nbd-client.h
+++ b/block/nbd-client.h
@@ -30,6 +30,7 @@ typedef struct NBDClientSession {
Coroutine *recv_coroutine[MAX_NBD_REQUESTS];
NBDReply reply;
+ bool quit;
} NBDClientSession;
NBDClientSession *nbd_get_client_session(BlockDriverState *bs);
--
2.11.0

View File

@ -1,55 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Eric Blake <eblake@redhat.com>
Date: Wed, 27 Sep 2017 17:57:20 +0200
Subject: [PATCH] fix build failure in nbd_read_reply_entry()
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
RH-Author: Eric Blake <eblake@redhat.com>
Message-id: <20170927175725.20023-3-eblake@redhat.com>
Patchwork-id: 76668
O-Subject: [RHEV-7.4.z qemu-kvm-rhev PATCH 2/7] fix build failure in nbd_read_reply_entry()
Bugzilla: 1495474
RH-Acked-by: Max Reitz <mreitz@redhat.com>
RH-Acked-by: Jeffrey Cody <jcody@redhat.com>
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
From: Igor Mammedov <imammedo@redhat.com>
travis builds fail at HEAD at rc3 master with
block/nbd-client.c: In function nbd_read_reply_entry:
block/nbd-client.c:110:8: error: ret may be used uninitialized in this function [-Werror=uninitialized]
fix it by initializing 'ret' to 0
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit d0a180131c6655487b47ea72e7da0a909a479a3c)
Signed-off-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
Conflicts:
block/nbd-client.c - context
---
block/nbd-client.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/block/nbd-client.c b/block/nbd-client.c
index 701b4ce2eb..256dabeeef 100644
--- a/block/nbd-client.c
+++ b/block/nbd-client.c
@@ -69,7 +69,7 @@ static coroutine_fn void nbd_read_reply_entry(void *opaque)
{
NBDClientSession *s = opaque;
uint64_t i;
- int ret;
+ int ret = 0;
while (!s->quit) {
assert(s->reply.handle == 0);
--
2.11.0

View File

@ -1,184 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Eric Blake <eblake@redhat.com>
Date: Wed, 27 Sep 2017 17:57:21 +0200
Subject: [PATCH] nbd-client: avoid spurious qio_channel_yield() re-entry
RH-Author: Eric Blake <eblake@redhat.com>
Message-id: <20170927175725.20023-4-eblake@redhat.com>
Patchwork-id: 76671
O-Subject: [RHEV-7.4.z qemu-kvm-rhev PATCH 3/7] nbd-client: avoid spurious qio_channel_yield() re-entry
Bugzilla: 1495474
RH-Acked-by: Max Reitz <mreitz@redhat.com>
RH-Acked-by: Jeffrey Cody <jcody@redhat.com>
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
From: Stefan Hajnoczi <stefanha@redhat.com>
The following scenario leads to an assertion failure in
qio_channel_yield():
1. Request coroutine calls qio_channel_yield() successfully when sending
would block on the socket. It is now yielded.
2. nbd_read_reply_entry() calls nbd_recv_coroutines_enter_all() because
nbd_receive_reply() failed.
3. Request coroutine is entered and returns from qio_channel_yield().
Note that the socket fd handler has not fired yet so
ioc->write_coroutine is still set.
4. Request coroutine attempts to send the request body with nbd_rwv()
but the socket would still block. qio_channel_yield() is called
again and assert(!ioc->write_coroutine) is hit.
The problem is that nbd_read_reply_entry() does not distinguish between
request coroutines that are waiting to receive a reply and those that
are not.
This patch adds a per-request bool receiving flag so
nbd_read_reply_entry() can avoid spurious aio_wake() calls.
Reported-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Message-Id: <20170822125113.5025-1-stefanha@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Tested-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
(cherry picked from commit 40f4a21895b5a7eae4011593837069f63460d983)
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
---
block/nbd-client.c | 35 ++++++++++++++++++++++-------------
block/nbd-client.h | 7 ++++++-
2 files changed, 28 insertions(+), 14 deletions(-)
diff --git a/block/nbd-client.c b/block/nbd-client.c
index 256dabeeef..f7bca3f996 100644
--- a/block/nbd-client.c
+++ b/block/nbd-client.c
@@ -38,8 +38,10 @@ static void nbd_recv_coroutines_enter_all(NBDClientSession *s)
int i;
for (i = 0; i < MAX_NBD_REQUESTS; i++) {
- if (s->recv_coroutine[i]) {
- aio_co_wake(s->recv_coroutine[i]);
+ NBDClientRequest *req = &s->requests[i];
+
+ if (req->coroutine && req->receiving) {
+ aio_co_wake(req->coroutine);
}
}
}
@@ -83,28 +85,28 @@ static coroutine_fn void nbd_read_reply_entry(void *opaque)
* one coroutine is called until the reply finishes.
*/
i = HANDLE_TO_INDEX(s, s->reply.handle);
- if (i >= MAX_NBD_REQUESTS || !s->recv_coroutine[i]) {
+ if (i >= MAX_NBD_REQUESTS ||
+ !s->requests[i].coroutine ||
+ !s->requests[i].receiving) {
break;
}
- /* We're woken up by the recv_coroutine itself. Note that there
+ /* We're woken up again by the request itself. Note that there
* is no race between yielding and reentering read_reply_co. This
* is because:
*
- * - if recv_coroutine[i] runs on the same AioContext, it is only
+ * - if the request runs on the same AioContext, it is only
* entered after we yield
*
- * - if recv_coroutine[i] runs on a different AioContext, reentering
+ * - if the request runs on a different AioContext, reentering
* read_reply_co happens through a bottom half, which can only
* run after we yield.
*/
- aio_co_wake(s->recv_coroutine[i]);
+ aio_co_wake(s->requests[i].coroutine);
qemu_coroutine_yield();
}
- if (ret < 0) {
- s->quit = true;
- }
+ s->quit = true;
nbd_recv_coroutines_enter_all(s);
s->read_reply_co = NULL;
}
@@ -123,14 +125,17 @@ static int nbd_co_send_request(BlockDriverState *bs,
s->in_flight++;
for (i = 0; i < MAX_NBD_REQUESTS; i++) {
- if (s->recv_coroutine[i] == NULL) {
- s->recv_coroutine[i] = qemu_coroutine_self();
+ if (s->requests[i].coroutine == NULL) {
break;
}
}
g_assert(qemu_in_coroutine());
assert(i < MAX_NBD_REQUESTS);
+
+ s->requests[i].coroutine = qemu_coroutine_self();
+ s->requests[i].receiving = false;
+
request->handle = INDEX_TO_HANDLE(s, i);
if (s->quit) {
@@ -168,10 +173,13 @@ static void nbd_co_receive_reply(NBDClientSession *s,
NBDReply *reply,
QEMUIOVector *qiov)
{
+ int i = HANDLE_TO_INDEX(s, request->handle);
int ret;
/* Wait until we're woken up by nbd_read_reply_entry. */
+ s->requests[i].receiving = true;
qemu_coroutine_yield();
+ s->requests[i].receiving = false;
*reply = s->reply;
if (reply->handle != request->handle || !s->ioc || s->quit) {
reply->error = EIO;
@@ -181,6 +189,7 @@ static void nbd_co_receive_reply(NBDClientSession *s,
true);
if (ret != request->len) {
reply->error = EIO;
+ s->quit = true;
}
}
@@ -195,7 +204,7 @@ static void nbd_coroutine_end(BlockDriverState *bs,
NBDClientSession *s = nbd_get_client_session(bs);
int i = HANDLE_TO_INDEX(s, request->handle);
- s->recv_coroutine[i] = NULL;
+ s->requests[i].coroutine = NULL;
/* Kick the read_reply_co to get the next reply. */
if (s->read_reply_co) {
diff --git a/block/nbd-client.h b/block/nbd-client.h
index 9774a8ebbb..f97792ff49 100644
--- a/block/nbd-client.h
+++ b/block/nbd-client.h
@@ -17,6 +17,11 @@
#define MAX_NBD_REQUESTS 16
+typedef struct {
+ Coroutine *coroutine;
+ bool receiving; /* waiting for read_reply_co? */
+} NBDClientRequest;
+
typedef struct NBDClientSession {
QIOChannelSocket *sioc; /* The master data channel */
QIOChannel *ioc; /* The current I/O channel which may differ (eg TLS) */
@@ -28,7 +33,7 @@ typedef struct NBDClientSession {
Coroutine *read_reply_co;
int in_flight;
- Coroutine *recv_coroutine[MAX_NBD_REQUESTS];
+ NBDClientRequest requests[MAX_NBD_REQUESTS];
NBDReply reply;
bool quit;
} NBDClientSession;
--
2.11.0

View File

@ -1,160 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Eric Blake <eblake@redhat.com>
Date: Wed, 27 Sep 2017 17:57:22 +0200
Subject: [PATCH] nbd-client: avoid read_reply_co entry if send failed
RH-Author: Eric Blake <eblake@redhat.com>
Message-id: <20170927175725.20023-5-eblake@redhat.com>
Patchwork-id: 76674
O-Subject: [RHEV-7.4.z qemu-kvm-rhev PATCH 4/7] nbd-client: avoid read_reply_co entry if send failed
Bugzilla: 1495474
RH-Acked-by: Max Reitz <mreitz@redhat.com>
RH-Acked-by: Jeffrey Cody <jcody@redhat.com>
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
From: Stefan Hajnoczi <stefanha@redhat.com>
The following segfault is encountered if the NBD server closes the UNIX
domain socket immediately after negotiation:
Program terminated with signal SIGSEGV, Segmentation fault.
#0 aio_co_schedule (ctx=0x0, co=0xd3c0ff2ef0) at util/async.c:441
441 QSLIST_INSERT_HEAD_ATOMIC(&ctx->scheduled_coroutines,
(gdb) bt
#0 0x000000d3c01a50f8 in aio_co_schedule (ctx=0x0, co=0xd3c0ff2ef0) at util/async.c:441
#1 0x000000d3c012fa90 in nbd_coroutine_end (bs=bs@entry=0xd3c0fec650, request=<optimized out>) at block/nbd-client.c:207
#2 0x000000d3c012fb58 in nbd_client_co_preadv (bs=0xd3c0fec650, offset=0, bytes=<optimized out>, qiov=0x7ffc10a91b20, flags=0) at block/nbd-client.c:237
#3 0x000000d3c0128e63 in bdrv_driver_preadv (bs=bs@entry=0xd3c0fec650, offset=offset@entry=0, bytes=bytes@entry=512, qiov=qiov@entry=0x7ffc10a91b20, flags=0) at block/io.c:836
#4 0x000000d3c012c3e0 in bdrv_aligned_preadv (child=child@entry=0xd3c0ff51d0, req=req@entry=0x7f31885d6e90, offset=offset@entry=0, bytes=bytes@entry=512, align=align@entry=1, qiov=qiov@entry=0x7ffc10a91b20, f
+lags=0) at block/io.c:1086
#5 0x000000d3c012c6b8 in bdrv_co_preadv (child=0xd3c0ff51d0, offset=offset@entry=0, bytes=bytes@entry=512, qiov=qiov@entry=0x7ffc10a91b20, flags=flags@entry=0) at block/io.c:1182
#6 0x000000d3c011cc17 in blk_co_preadv (blk=0xd3c0ff4f80, offset=0, bytes=512, qiov=0x7ffc10a91b20, flags=0) at block/block-backend.c:1032
#7 0x000000d3c011ccec in blk_read_entry (opaque=0x7ffc10a91b40) at block/block-backend.c:1079
#8 0x000000d3c01bbb96 in coroutine_trampoline (i0=<optimized out>, i1=<optimized out>) at util/coroutine-ucontext.c:79
#9 0x00007f3196cb8600 in __start_context () at /lib64/libc.so.6
The problem is that nbd_client_init() uses
nbd_client_attach_aio_context() -> aio_co_schedule(new_context,
client->read_reply_co). Execution of read_reply_co is deferred to a BH
which doesn't run until later.
In the mean time blk_co_preadv() can be called and nbd_coroutine_end()
calls aio_wake() on read_reply_co. At this point in time
read_reply_co's ctx isn't set because it has never been entered yet.
This patch simplifies the nbd_co_send_request() ->
nbd_co_receive_reply() -> nbd_coroutine_end() lifecycle to just
nbd_co_send_request() -> nbd_co_receive_reply(). The request is "ended"
if an error occurs at any point. Callers no longer have to invoke
nbd_coroutine_end().
This cleanup also eliminates the segfault because we don't call
aio_co_schedule() to wake up s->read_reply_co if sending the request
failed. It is only necessary to wake up s->read_reply_co if a reply was
received.
Note this only happens with UNIX domain sockets on Linux. It doesn't
seem possible to reproduce this with TCP sockets.
Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Message-Id: <20170829122745.14309-2-stefanha@redhat.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
(cherry picked from commit 3c2d5183f9fa4eac3d17d841e26da65a0181ae7b)
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
---
block/nbd-client.c | 25 +++++++++----------------
1 file changed, 9 insertions(+), 16 deletions(-)
diff --git a/block/nbd-client.c b/block/nbd-client.c
index f7bca3f996..434acf647f 100644
--- a/block/nbd-client.c
+++ b/block/nbd-client.c
@@ -139,12 +139,12 @@ static int nbd_co_send_request(BlockDriverState *bs,
request->handle = INDEX_TO_HANDLE(s, i);
if (s->quit) {
- qemu_co_mutex_unlock(&s->send_mutex);
- return -EIO;
+ rc = -EIO;
+ goto err;
}
if (!s->ioc) {
- qemu_co_mutex_unlock(&s->send_mutex);
- return -EPIPE;
+ rc = -EPIPE;
+ goto err;
}
if (qiov) {
@@ -161,8 +161,13 @@ static int nbd_co_send_request(BlockDriverState *bs,
} else {
rc = nbd_send_request(s->ioc, request);
}
+
+err:
if (rc < 0) {
s->quit = true;
+ s->requests[i].coroutine = NULL;
+ s->in_flight--;
+ qemu_co_queue_next(&s->free_sema);
}
qemu_co_mutex_unlock(&s->send_mutex);
return rc;
@@ -196,13 +201,6 @@ static void nbd_co_receive_reply(NBDClientSession *s,
/* Tell the read handler to read another header. */
s->reply.handle = 0;
}
-}
-
-static void nbd_coroutine_end(BlockDriverState *bs,
- NBDRequest *request)
-{
- NBDClientSession *s = nbd_get_client_session(bs);
- int i = HANDLE_TO_INDEX(s, request->handle);
s->requests[i].coroutine = NULL;
@@ -238,7 +236,6 @@ int nbd_client_co_preadv(BlockDriverState *bs, uint64_t offset,
} else {
nbd_co_receive_reply(client, &request, &reply, qiov);
}
- nbd_coroutine_end(bs, &request);
return -reply.error;
}
@@ -267,7 +264,6 @@ int nbd_client_co_pwritev(BlockDriverState *bs, uint64_t offset,
} else {
nbd_co_receive_reply(client, &request, &reply, NULL);
}
- nbd_coroutine_end(bs, &request);
return -reply.error;
}
@@ -301,7 +297,6 @@ int nbd_client_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
} else {
nbd_co_receive_reply(client, &request, &reply, NULL);
}
- nbd_coroutine_end(bs, &request);
return -reply.error;
}
@@ -325,7 +320,6 @@ int nbd_client_co_flush(BlockDriverState *bs)
} else {
nbd_co_receive_reply(client, &request, &reply, NULL);
}
- nbd_coroutine_end(bs, &request);
return -reply.error;
}
@@ -350,7 +344,6 @@ int nbd_client_co_pdiscard(BlockDriverState *bs, int64_t offset, int count)
} else {
nbd_co_receive_reply(client, &request, &reply, NULL);
}
- nbd_coroutine_end(bs, &request);
return -reply.error;
}
--
2.11.0

View File

@ -1,60 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Eric Blake <eblake@redhat.com>
Date: Wed, 27 Sep 2017 17:57:23 +0200
Subject: [PATCH] qemu-iotests: improve nbd-fault-injector.py startup protocol
RH-Author: Eric Blake <eblake@redhat.com>
Message-id: <20170927175725.20023-6-eblake@redhat.com>
Patchwork-id: 76675
O-Subject: [RHEV-7.4.z qemu-kvm-rhev PATCH 5/7] qemu-iotests: improve nbd-fault-injector.py startup protocol
Bugzilla: 1495474
RH-Acked-by: Max Reitz <mreitz@redhat.com>
RH-Acked-by: Jeffrey Cody <jcody@redhat.com>
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
From: Stefan Hajnoczi <stefanha@redhat.com>
Currently 083 waits for the nbd-fault-injector.py server to start up by
looping until netstat shows the TCP listen socket.
The startup protocol can be simplified by passing a 0 port number to
nbd-fault-injector.py. The kernel will allocate a port in bind(2) and
the final port number can be printed by nbd-fault-injector.py.
This should make it slightly nicer and less TCP-specific to wait for
server startup. This patch changes nbd-fault-injector.py, the next one
will rewrite server startup in 083.
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Message-Id: <20170829122745.14309-3-stefanha@redhat.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
(cherry picked from commit 6e592fc92234a58c7156c385840633c17dedd24f)
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
---
tests/qemu-iotests/nbd-fault-injector.py | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/tests/qemu-iotests/nbd-fault-injector.py b/tests/qemu-iotests/nbd-fault-injector.py
index 6c07191a5a..1c10dcb51c 100755
--- a/tests/qemu-iotests/nbd-fault-injector.py
+++ b/tests/qemu-iotests/nbd-fault-injector.py
@@ -235,11 +235,15 @@ def open_socket(path):
sock = socket.socket()
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((host, int(port)))
+
+ # If given port was 0 the final port number is now available
+ path = '%s:%d' % sock.getsockname()
else:
sock = socket.socket(socket.AF_UNIX)
sock.bind(path)
sock.listen(0)
print 'Listening on %s' % path
+ sys.stdout.flush() # another process may be waiting, show message now
return sock
def usage(args):
--
2.11.0

View File

@ -1,454 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Eric Blake <eblake@redhat.com>
Date: Wed, 27 Sep 2017 17:57:24 +0200
Subject: [PATCH] qemu-iotests: test NBD over UNIX domain sockets in 083
RH-Author: Eric Blake <eblake@redhat.com>
Message-id: <20170927175725.20023-7-eblake@redhat.com>
Patchwork-id: 76670
O-Subject: [RHEV-7.4.z qemu-kvm-rhev PATCH 6/7] qemu-iotests: test NBD over UNIX domain sockets in 083
Bugzilla: 1495474
RH-Acked-by: Max Reitz <mreitz@redhat.com>
RH-Acked-by: Jeffrey Cody <jcody@redhat.com>
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
From: Stefan Hajnoczi <stefanha@redhat.com>
083 only tests TCP. Some failures might be specific to UNIX domain
sockets.
A few adjustments are necessary:
1. Generating a port number and waiting for server startup is
TCP-specific. Use the new nbd-fault-injector.py startup protocol to
fetch the address. This is a little more elegant because we don't
need netstat anymore.
2. The NBD filter does not work for the UNIX domain sockets URIs we
generate and must be extended.
3. Run all tests twice: once for TCP and once for UNIX domain sockets.
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Message-Id: <20170829122745.14309-4-stefanha@redhat.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
(cherry picked from commit 02d2d860d25e439f0e88658c701668ab684568fb)
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
Conflicts:
tests/qemu-iotests/083.out - error message improvements not backported
Signed-off-by: Eric Blake <eblake@redhat.com>
---
tests/qemu-iotests/083 | 136 +++++++++++++++++++++++--------------
tests/qemu-iotests/083.out | 143 ++++++++++++++++++++++++++++++++++-----
tests/qemu-iotests/common.filter | 4 +-
3 files changed, 212 insertions(+), 71 deletions(-)
diff --git a/tests/qemu-iotests/083 b/tests/qemu-iotests/083
index bff9360048..0306f112da 100755
--- a/tests/qemu-iotests/083
+++ b/tests/qemu-iotests/083
@@ -27,6 +27,14 @@ echo "QA output created by $seq"
here=`pwd`
status=1 # failure is the default!
+_cleanup()
+{
+ rm -f nbd.sock
+ rm -f nbd-fault-injector.out
+ rm -f nbd-fault-injector.conf
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
# get standard environment, filters and checks
. ./common.rc
. ./common.filter
@@ -35,81 +43,105 @@ _supported_fmt generic
_supported_proto nbd
_supported_os Linux
-# Pick a TCP port based on our pid. This way multiple instances of this test
-# can run in parallel without conflicting.
-choose_tcp_port() {
- echo $((($$ % 31744) + 1024)) # 1024 <= port < 32768
-}
-
-wait_for_tcp_port() {
- while ! (netstat --tcp --listening --numeric | \
- grep "$1.*0\\.0\\.0\\.0:\\*.*LISTEN") >/dev/null 2>&1; do
- sleep 0.1
+check_disconnect() {
+ local event export_name=foo extra_args nbd_addr nbd_url proto when
+
+ while true; do
+ case $1 in
+ --classic-negotiation)
+ shift
+ extra_args=--classic-negotiation
+ export_name=
+ ;;
+ --tcp)
+ shift
+ proto=tcp
+ ;;
+ --unix)
+ shift
+ proto=unix
+ ;;
+ *)
+ break
+ ;;
+ esac
done
-}
-check_disconnect() {
event=$1
when=$2
- negotiation=$3
echo "=== Check disconnect $when $event ==="
echo
- port=$(choose_tcp_port)
-
cat > "$TEST_DIR/nbd-fault-injector.conf" <<EOF
[inject-error]
event=$event
when=$when
EOF
- if [ "$negotiation" = "--classic-negotiation" ]; then
- extra_args=--classic-negotiation
- nbd_url="nbd:127.0.0.1:$port"
+ if [ "$proto" = "tcp" ]; then
+ nbd_addr="127.0.0.1:0"
else
- nbd_url="nbd:127.0.0.1:$port:exportname=foo"
+ nbd_addr="$TEST_DIR/nbd.sock"
+ fi
+
+ rm -f "$TEST_DIR/nbd.sock"
+
+ $PYTHON nbd-fault-injector.py $extra_args "$nbd_addr" "$TEST_DIR/nbd-fault-injector.conf" >"$TEST_DIR/nbd-fault-injector.out" 2>&1 &
+
+ # Wait for server to be ready
+ while ! grep -q 'Listening on ' "$TEST_DIR/nbd-fault-injector.out"; do
+ sleep 0.1
+ done
+
+ # Extract the final address (port number has now been assigned in tcp case)
+ nbd_addr=$(sed 's/Listening on \(.*\)$/\1/' "$TEST_DIR/nbd-fault-injector.out")
+
+ if [ "$proto" = "tcp" ]; then
+ nbd_url="nbd+tcp://$nbd_addr/$export_name"
+ else
+ nbd_url="nbd+unix:///$export_name?socket=$nbd_addr"
fi
- $PYTHON nbd-fault-injector.py $extra_args "127.0.0.1:$port" "$TEST_DIR/nbd-fault-injector.conf" >/dev/null 2>&1 &
- wait_for_tcp_port "127\\.0\\.0\\.1:$port"
$QEMU_IO -c "read 0 512" "$nbd_url" 2>&1 | _filter_qemu_io | _filter_nbd
echo
}
-for event in neg1 "export" neg2 request reply data; do
- for when in before after; do
- check_disconnect "$event" "$when"
- done
-
- # Also inject short replies from the NBD server
- case "$event" in
- neg1)
- for when in 8 16; do
- check_disconnect "$event" "$when"
- done
- ;;
- "export")
- for when in 4 12 16; do
- check_disconnect "$event" "$when"
+for proto in tcp unix; do
+ for event in neg1 "export" neg2 request reply data; do
+ for when in before after; do
+ check_disconnect "--$proto" "$event" "$when"
done
- ;;
- neg2)
- for when in 8 10; do
- check_disconnect "$event" "$when"
- done
- ;;
- reply)
- for when in 4 8; do
- check_disconnect "$event" "$when"
- done
- ;;
- esac
-done
-# Also check classic negotiation without export information
-for when in before 8 16 24 28 after; do
- check_disconnect "neg-classic" "$when" --classic-negotiation
+ # Also inject short replies from the NBD server
+ case "$event" in
+ neg1)
+ for when in 8 16; do
+ check_disconnect "--$proto" "$event" "$when"
+ done
+ ;;
+ "export")
+ for when in 4 12 16; do
+ check_disconnect "--$proto" "$event" "$when"
+ done
+ ;;
+ neg2)
+ for when in 8 10; do
+ check_disconnect "--$proto" "$event" "$when"
+ done
+ ;;
+ reply)
+ for when in 4 8; do
+ check_disconnect "--$proto" "$event" "$when"
+ done
+ ;;
+ esac
+ done
+
+ # Also check classic negotiation without export information
+ for when in before 8 16 24 28 after; do
+ check_disconnect "--$proto" --classic-negotiation "neg-classic" "$when"
+ done
done
# success, all done
diff --git a/tests/qemu-iotests/083.out b/tests/qemu-iotests/083.out
index 0c13888ba1..7419722cd7 100644
--- a/tests/qemu-iotests/083.out
+++ b/tests/qemu-iotests/083.out
@@ -1,43 +1,43 @@
QA output created by 083
=== Check disconnect before neg1 ===
-can't open device nbd:127.0.0.1:PORT:exportname=foo
+can't open device nbd+tcp://127.0.0.1:PORT/foo
=== Check disconnect after neg1 ===
-can't open device nbd:127.0.0.1:PORT:exportname=foo
+can't open device nbd+tcp://127.0.0.1:PORT/foo
=== Check disconnect 8 neg1 ===
-can't open device nbd:127.0.0.1:PORT:exportname=foo
+can't open device nbd+tcp://127.0.0.1:PORT/foo
=== Check disconnect 16 neg1 ===
-can't open device nbd:127.0.0.1:PORT:exportname=foo
+can't open device nbd+tcp://127.0.0.1:PORT/foo
=== Check disconnect before export ===
-can't open device nbd:127.0.0.1:PORT:exportname=foo
+can't open device nbd+tcp://127.0.0.1:PORT/foo
=== Check disconnect after export ===
-can't open device nbd:127.0.0.1:PORT:exportname=foo
+can't open device nbd+tcp://127.0.0.1:PORT/foo
=== Check disconnect 4 export ===
-can't open device nbd:127.0.0.1:PORT:exportname=foo
+can't open device nbd+tcp://127.0.0.1:PORT/foo
=== Check disconnect 12 export ===
-can't open device nbd:127.0.0.1:PORT:exportname=foo
+can't open device nbd+tcp://127.0.0.1:PORT/foo
=== Check disconnect 16 export ===
-can't open device nbd:127.0.0.1:PORT:exportname=foo
+can't open device nbd+tcp://127.0.0.1:PORT/foo
=== Check disconnect before neg2 ===
-can't open device nbd:127.0.0.1:PORT:exportname=foo
+can't open device nbd+tcp://127.0.0.1:PORT/foo
=== Check disconnect after neg2 ===
@@ -45,11 +45,11 @@ read failed: Input/output error
=== Check disconnect 8 neg2 ===
-can't open device nbd:127.0.0.1:PORT:exportname=foo
+can't open device nbd+tcp://127.0.0.1:PORT/foo
=== Check disconnect 10 neg2 ===
-can't open device nbd:127.0.0.1:PORT:exportname=foo
+can't open device nbd+tcp://127.0.0.1:PORT/foo
=== Check disconnect before request ===
@@ -86,23 +86,132 @@ read 512/512 bytes at offset 0
=== Check disconnect before neg-classic ===
-can't open device nbd:127.0.0.1:PORT
+can't open device nbd+tcp://127.0.0.1:PORT/
=== Check disconnect 8 neg-classic ===
-can't open device nbd:127.0.0.1:PORT
+can't open device nbd+tcp://127.0.0.1:PORT/
=== Check disconnect 16 neg-classic ===
-can't open device nbd:127.0.0.1:PORT
+can't open device nbd+tcp://127.0.0.1:PORT/
=== Check disconnect 24 neg-classic ===
-can't open device nbd:127.0.0.1:PORT
+can't open device nbd+tcp://127.0.0.1:PORT/
=== Check disconnect 28 neg-classic ===
-can't open device nbd:127.0.0.1:PORT
+can't open device nbd+tcp://127.0.0.1:PORT/
+
+=== Check disconnect after neg-classic ===
+
+read failed: Input/output error
+
+=== Check disconnect before neg1 ===
+
+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
+
+=== Check disconnect after neg1 ===
+
+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
+
+=== Check disconnect 8 neg1 ===
+
+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
+
+=== Check disconnect 16 neg1 ===
+
+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
+
+=== Check disconnect before export ===
+
+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
+
+=== Check disconnect after export ===
+
+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
+
+=== Check disconnect 4 export ===
+
+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
+
+=== Check disconnect 12 export ===
+
+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
+
+=== Check disconnect 16 export ===
+
+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
+
+=== Check disconnect before neg2 ===
+
+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
+
+=== Check disconnect after neg2 ===
+
+read failed: Input/output error
+
+=== Check disconnect 8 neg2 ===
+
+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
+
+=== Check disconnect 10 neg2 ===
+
+can't open device nbd+unix:///foo?socket=TEST_DIR/nbd.sock
+
+=== Check disconnect before request ===
+
+read failed: Input/output error
+
+=== Check disconnect after request ===
+
+read failed: Input/output error
+
+=== Check disconnect before reply ===
+
+read failed: Input/output error
+
+=== Check disconnect after reply ===
+
+read failed: Input/output error
+
+=== Check disconnect 4 reply ===
+
+read failed: Input/output error
+
+=== Check disconnect 8 reply ===
+
+read failed: Input/output error
+
+=== Check disconnect before data ===
+
+read failed: Input/output error
+
+=== Check disconnect after data ===
+
+read 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+=== Check disconnect before neg-classic ===
+
+can't open device nbd+unix:///?socket=TEST_DIR/nbd.sock
+
+=== Check disconnect 8 neg-classic ===
+
+can't open device nbd+unix:///?socket=TEST_DIR/nbd.sock
+
+=== Check disconnect 16 neg-classic ===
+
+can't open device nbd+unix:///?socket=TEST_DIR/nbd.sock
+
+=== Check disconnect 24 neg-classic ===
+
+can't open device nbd+unix:///?socket=TEST_DIR/nbd.sock
+
+=== Check disconnect 28 neg-classic ===
+
+can't open device nbd+unix:///?socket=TEST_DIR/nbd.sock
=== Check disconnect after neg-classic ===
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
index 104001358b..65ec315f25 100644
--- a/tests/qemu-iotests/common.filter
+++ b/tests/qemu-iotests/common.filter
@@ -153,9 +153,9 @@ _filter_nbd()
#
# Filter out the TCP port number since this changes between runs.
sed -e '/nbd\/.*\.c:/d' \
- -e 's#nbd:\(//\)\?127\.0\.0\.1:[0-9]*#nbd:\1127.0.0.1:PORT#g' \
+ -e 's#127\.0\.0\.1:[0-9]*#127.0.0.1:PORT#g' \
-e "s#?socket=$TEST_DIR#?socket=TEST_DIR#g" \
- -e 's#\(exportname=foo\|PORT\): Failed to .*$#\1#'
+ -e 's#\(foo\|PORT/\?\|.sock\): Failed to .*$#\1#'
}
# make sure this script returns success
--
2.11.0

View File

@ -1,45 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Eric Blake <eblake@redhat.com>
Date: Wed, 27 Sep 2017 17:57:25 +0200
Subject: [PATCH] block/nbd-client: nbd_co_send_request: fix return code
RH-Author: Eric Blake <eblake@redhat.com>
Message-id: <20170927175725.20023-8-eblake@redhat.com>
Patchwork-id: 76673
O-Subject: [RHEV-7.4.z qemu-kvm-rhev PATCH 7/7] block/nbd-client: nbd_co_send_request: fix return code
Bugzilla: 1495474
RH-Acked-by: Max Reitz <mreitz@redhat.com>
RH-Acked-by: Jeffrey Cody <jcody@redhat.com>
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
It's incorrect to return success rc >= 0 if we skip qio_channel_writev_all()
call due to s->quit.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-Id: <20170920124507.18841-4-vsementsov@virtuozzo.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
(cherry picked from commit a693437037328a95d815ad5aec37ac2f8e130e58)
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
---
block/nbd-client.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/block/nbd-client.c b/block/nbd-client.c
index 434acf647f..76789c1829 100644
--- a/block/nbd-client.c
+++ b/block/nbd-client.c
@@ -156,6 +156,8 @@ static int nbd_co_send_request(BlockDriverState *bs,
if (ret != request->len) {
rc = -EIO;
}
+ } else if (rc >= 0) {
+ rc = -EIO;
}
qio_channel_set_cork(s->ioc, false);
} else {
--
2.11.0

View File

@ -1,86 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Brijesh Singh <brijesh.singh@amd.com>
Date: Tue, 15 Aug 2017 12:00:51 -0500
Subject: [PATCH] target-i386/cpu: Add new EPYC CPU model
Add a new base CPU model called 'EPYC' to model processors from AMD EPYC
family (which includes EPYC 76xx,75xx,74xx, 73xx and 72xx).
The following features bits have been added/removed compare to Opteron_G5
Added: monitor, movbe, rdrand, mmxext, ffxsr, rdtscp, cr8legacy, osvw,
fsgsbase, bmi1, avx2, smep, bmi2, rdseed, adx, smap, clfshopt, sha
xsaveopt, xsavec, xgetbv1, arat
Removed: xop, fma4, tbm
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Richard Henderson <rth@twiddle.net>
Cc: Eduardo Habkost <ehabkost@redhat.com>
Cc: Tom Lendacky <Thomas.Lendacky@amd.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
Message-Id: <20170815170051.127257-1-brijesh.singh@amd.com>
Reviewed-by: Eduardo Habkost <ehabkost@redhat.com>
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
---
target/i386/cpu.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 44 insertions(+)
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index e4a2d5a012..e977c6c616 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -1923,6 +1923,50 @@ static X86CPUDefinition builtin_x86_defs[] = {
.xlevel = 0x8000001A,
.model_id = "AMD Opteron 63xx class CPU",
},
+ {
+ .name = "EPYC",
+ .level = 0xd,
+ .vendor = CPUID_VENDOR_AMD,
+ .family = 23,
+ .model = 1,
+ .stepping = 2,
+ .features[FEAT_1_EDX] =
+ CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | CPUID_CLFLUSH |
+ CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | CPUID_PGE |
+ CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | CPUID_MCE |
+ CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | CPUID_DE |
+ CPUID_VME | CPUID_FP87,
+ .features[FEAT_1_ECX] =
+ CPUID_EXT_RDRAND | CPUID_EXT_F16C | CPUID_EXT_AVX |
+ CPUID_EXT_XSAVE | CPUID_EXT_AES | CPUID_EXT_POPCNT |
+ CPUID_EXT_MOVBE | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 |
+ CPUID_EXT_CX16 | CPUID_EXT_FMA | CPUID_EXT_SSSE3 |
+ CPUID_EXT_MONITOR | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3,
+ .features[FEAT_8000_0001_EDX] =
+ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_PDPE1GB |
+ CPUID_EXT2_FFXSR | CPUID_EXT2_MMXEXT | CPUID_EXT2_NX |
+ CPUID_EXT2_SYSCALL,
+ .features[FEAT_8000_0001_ECX] =
+ CPUID_EXT3_OSVW | CPUID_EXT3_3DNOWPREFETCH |
+ CPUID_EXT3_MISALIGNSSE | CPUID_EXT3_SSE4A | CPUID_EXT3_ABM |
+ CPUID_EXT3_CR8LEG | CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM,
+ .features[FEAT_7_0_EBX] =
+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_AVX2 |
+ CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_RDSEED |
+ CPUID_7_0_EBX_ADX | CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_CLFLUSHOPT |
+ CPUID_7_0_EBX_SHA_NI,
+ /* Missing: XSAVES (not supported by some Linux versions,
+ * including v4.1 to v4.12).
+ * KVM doesn't yet expose any XSAVES state save component.
+ */
+ .features[FEAT_XSAVE] =
+ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC |
+ CPUID_XSAVE_XGETBV1,
+ .features[FEAT_6_EAX] =
+ CPUID_6_EAX_ARAT,
+ .xlevel = 0x8000000A,
+ .model_id = "AMD EPYC Processor",
+ },
};
typedef struct PropValue {
--
2.11.0

View File

@ -1,78 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Eduardo Habkost <ehabkost@redhat.com>
Date: Tue, 9 Jan 2018 13:45:18 -0200
Subject: [PATCH] i386: Add EPYC-IBPB CPU model
EPYC-IBPB is a copy of the EPYC CPU model with
just CPUID_8000_0008_EBX_IBPB added.
Cc: Jiri Denemark <jdenemar@redhat.com>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
Message-Id: <20180109154519.25634-7-ehabkost@redhat.com>
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
---
target/i386/cpu.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index e977c6c616..95e6a1f122 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -1967,6 +1967,52 @@ static X86CPUDefinition builtin_x86_defs[] = {
.xlevel = 0x8000000A,
.model_id = "AMD EPYC Processor",
},
+ {
+ .name = "EPYC-IBPB",
+ .level = 0xd,
+ .vendor = CPUID_VENDOR_AMD,
+ .family = 23,
+ .model = 1,
+ .stepping = 2,
+ .features[FEAT_1_EDX] =
+ CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | CPUID_CLFLUSH |
+ CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | CPUID_PGE |
+ CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | CPUID_MCE |
+ CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | CPUID_DE |
+ CPUID_VME | CPUID_FP87,
+ .features[FEAT_1_ECX] =
+ CPUID_EXT_RDRAND | CPUID_EXT_F16C | CPUID_EXT_AVX |
+ CPUID_EXT_XSAVE | CPUID_EXT_AES | CPUID_EXT_POPCNT |
+ CPUID_EXT_MOVBE | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 |
+ CPUID_EXT_CX16 | CPUID_EXT_FMA | CPUID_EXT_SSSE3 |
+ CPUID_EXT_MONITOR | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3,
+ .features[FEAT_8000_0001_EDX] =
+ CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_PDPE1GB |
+ CPUID_EXT2_FFXSR | CPUID_EXT2_MMXEXT | CPUID_EXT2_NX |
+ CPUID_EXT2_SYSCALL,
+ .features[FEAT_8000_0001_ECX] =
+ CPUID_EXT3_OSVW | CPUID_EXT3_3DNOWPREFETCH |
+ CPUID_EXT3_MISALIGNSSE | CPUID_EXT3_SSE4A | CPUID_EXT3_ABM |
+ CPUID_EXT3_CR8LEG | CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM,
+ .features[FEAT_8000_0008_EBX] =
+ CPUID_8000_0008_EBX_IBPB,
+ .features[FEAT_7_0_EBX] =
+ CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_AVX2 |
+ CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_RDSEED |
+ CPUID_7_0_EBX_ADX | CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_CLFLUSHOPT |
+ CPUID_7_0_EBX_SHA_NI,
+ /* Missing: XSAVES (not supported by some Linux versions,
+ * including v4.1 to v4.12).
+ * KVM doesn't yet expose any XSAVES state save component.
+ */
+ .features[FEAT_XSAVE] =
+ CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC |
+ CPUID_XSAVE_XGETBV1,
+ .features[FEAT_6_EAX] =
+ CPUID_6_EAX_ARAT,
+ .xlevel = 0x8000000A,
+ .model_id = "AMD EPYC Processor (with IBPB)",
+ },
};
typedef struct PropValue {
--
2.11.0

View File

@ -0,0 +1,39 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Wed, 29 Nov 2017 11:11:46 +0100
Subject: [PATCH] block/file: change locking default to off
'auto' only checks whether the system generally supports OFD
locks but not whether the storage the file resides on
supports any locking, causing issues with NFS.
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
---
block/file-posix.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/block/file-posix.c b/block/file-posix.c
index 36ee89e940..4bff572d07 100644
--- a/block/file-posix.c
+++ b/block/file-posix.c
@@ -405,7 +405,7 @@ static QemuOptsList raw_runtime_opts = {
{
.name = "locking",
.type = QEMU_OPT_STRING,
- .help = "file locking mode (on/off/auto, default: auto)",
+ .help = "file locking mode (on/off/auto, default: off)",
},
{
.name = "pr-manager",
@@ -481,7 +481,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
s->use_lock = false;
break;
case ON_OFF_AUTO_AUTO:
- s->use_lock = qemu_has_ofd_lock();
+ s->use_lock = false;
break;
default:
abort();
--
2.11.0

View File

@ -1,48 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Wed, 9 Dec 2015 14:15:49 +0100
Subject: [PATCH] fr-ca keymap corrections
---
pc-bios/keymaps/fr-ca | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/pc-bios/keymaps/fr-ca b/pc-bios/keymaps/fr-ca
index b645208e42..92912409e1 100644
--- a/pc-bios/keymaps/fr-ca
+++ b/pc-bios/keymaps/fr-ca
@@ -14,22 +14,31 @@ bar 0x29 shift
twosuperior 0x9 altgr
threesuperior 0xa altgr
onequarter 0xb altgr
+minus 0x0c
onehalf 0xc altgr
+equal 0xd
threequarters 0xd altgr
section 0x18 altgr
paragraph 0x19 altgr
bracketleft 0x1a altgr
bracketright 0x1b altgr
+semicolon 0x27
+colon 0x27 shift
asciitilde 0x27 altgr
braceleft 0x28 altgr
+numbersign 0x29
braceright 0x2b altgr
less 0x2b
greater 0x2b shift
guillemotleft 0x56
guillemotright 0x56 shift
degree 0x56 altgr
+comma 0x33
mu 0x32 altgr
+apostrophe 0x33 shift
+period 0x34 shift
eacute 0x35
+Eacute 0x35 shift
dead_acute 0x35 altgr
dead_grave 0x28
dead_circumflex 0x1a
--
2.11.0

View File

@ -8,10 +8,10 @@ Subject: [PATCH] Adjust network script path to /etc/kvm/
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/include/net/net.h b/include/net/net.h
index 99b28d5b38..40c39f00e6 100644
index 1c55a93588..13ecb9cc8c 100644
--- a/include/net/net.h
+++ b/include/net/net.h
@@ -214,8 +214,9 @@ void qmp_netdev_add(QDict *qdict, QObject **ret, Error **errp);
@@ -220,8 +220,9 @@ void qmp_netdev_add(QDict *qdict, QObject **ret, Error **errp);
int net_hub_id_for_client(NetClientState *nc, int *id);
NetClientState *net_hub_port_find(int hub_id);

View File

@ -8,12 +8,12 @@ Subject: [PATCH] qemu-img: return success on info without snapshots
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/qemu-img.c b/qemu-img.c
index e4a2686f56..c7804d63ee 100644
index 68b375f998..f8a39dd195 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -2596,7 +2596,8 @@ static int img_info(int argc, char **argv)
list = collect_image_info_list(image_opts, filename, fmt, chain);
@@ -2594,7 +2594,8 @@ static int img_info(int argc, char **argv)
list = collect_image_info_list(image_opts, filename, fmt, chain,
force_share);
if (!list) {
- return 1;
+ // return success if snapshot does not exists

View File

@ -4,24 +4,24 @@ Date: Wed, 9 Dec 2015 14:27:05 +0100
Subject: [PATCH] use kvm by default
---
accel.c | 4 ++--
accel/accel.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/accel.c b/accel.c
index 664bb88422..ddb23a3f1d 100644
--- a/accel.c
+++ b/accel.c
@@ -87,8 +87,8 @@ void configure_accelerator(MachineState *ms)
diff --git a/accel/accel.c b/accel/accel.c
index 8ae40e1e13..df21981026 100644
--- a/accel/accel.c
+++ b/accel/accel.c
@@ -79,8 +79,8 @@ void configure_accelerator(MachineState *ms)
p = qemu_opt_get(qemu_get_machine_opts(), "accel");
if (p == NULL) {
accel = qemu_opt_get(qemu_get_machine_opts(), "accel");
if (accel == NULL) {
- /* Use the default "accelerator", tcg */
- p = "tcg";
- accel = "tcg";
+ /* Use the default "accelerator", kvm */
+ p = "kvm";
+ accel = "kvm";
}
while (!accel_initialised && *p != '\0') {
p = accel;
--
2.11.0

View File

@ -8,14 +8,14 @@ command.
---
hmp.c | 30 +++++++++++++++++++++++++++++-
hw/virtio/virtio-balloon.c | 33 +++++++++++++++++++++++++++++++--
qapi-schema.json | 23 +++++++++++++++++++++--
3 files changed, 81 insertions(+), 5 deletions(-)
qapi-schema.json | 22 +++++++++++++++++++++-
3 files changed, 81 insertions(+), 4 deletions(-)
diff --git a/hmp.c b/hmp.c
index edb8970461..904542d026 100644
index 35a7041824..4e1d571003 100644
--- a/hmp.c
+++ b/hmp.c
@@ -723,7 +723,35 @@ void hmp_info_balloon(Monitor *mon, const QDict *qdict)
@@ -789,7 +789,35 @@ void hmp_info_balloon(Monitor *mon, const QDict *qdict)
return;
}
@ -53,10 +53,10 @@ index edb8970461..904542d026 100644
qapi_free_BalloonInfo(info);
}
diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
index a705e0ec55..158e13e795 100644
index 37cde38982..1feaf77223 100644
--- a/hw/virtio/virtio-balloon.c
+++ b/hw/virtio/virtio-balloon.c
@@ -379,8 +379,37 @@ static uint64_t virtio_balloon_get_features(VirtIODevice *vdev, uint64_t f,
@@ -380,8 +380,37 @@ static uint64_t virtio_balloon_get_features(VirtIODevice *vdev, uint64_t f,
static void virtio_balloon_stat(void *opaque, BalloonInfo *info)
{
VirtIOBalloon *dev = opaque;
@ -97,14 +97,13 @@ index a705e0ec55..158e13e795 100644
static void virtio_balloon_to_target(void *opaque, ram_addr_t target)
diff --git a/qapi-schema.json b/qapi-schema.json
index 250e4dc49b..f38b85bf6a 100644
index 18457954a8..ebc22fe5a6 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1900,10 +1900,29 @@
@@ -623,10 +623,30 @@
#
# @actual: the number of bytes the balloon currently contains
#
-# Since: 0.14.0
+# @last_update: time when stats got updated from guest
+#
+# @mem_swapped_in: number of pages swapped in within the guest
@ -112,7 +111,7 @@ index 250e4dc49b..f38b85bf6a 100644
+# @mem_swapped_out: number of pages swapped out within the guest
+#
+# @major_page_faults: number of major page faults within the guest
#
+#
+# @minor_page_faults: number of minor page faults within the guest
+#
+# @free_mem: amount of memory (in bytes) free in the guest
@ -121,7 +120,8 @@ index 250e4dc49b..f38b85bf6a 100644
+#
+# @max_mem: amount of memory (in bytes) assigned to the guest
+#
+# Since: 0.14.0
# Since: 0.14.0
#
##
-{ 'struct': 'BalloonInfo', 'data': {'actual': 'int' } }
+{ 'struct': 'BalloonInfo',

View File

@ -4,25 +4,25 @@ Date: Wed, 9 Dec 2015 14:30:21 +0100
Subject: [PATCH] set the CPU model to kvm64/32 instead of qemu64/32
---
hw/i386/pc.c | 4 ++--
target/i386/cpu.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 610050eb4f..e96901435a 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1151,9 +1151,9 @@ void pc_cpus_init(PCMachineState *pcms)
/* init CPUs */
if (machine->cpu_model == NULL) {
#ifdef TARGET_X86_64
- machine->cpu_model = "qemu64";
+ machine->cpu_model = "kvm64";
#else
- machine->cpu_model = "qemu32";
+ machine->cpu_model = "kvm32";
#endif
}
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index f3d0ebb673..660e42977b 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -1521,9 +1521,9 @@ uint64_t cpu_get_tsc(CPUX86State *env);
#define X86_CPU_TYPE_NAME(name) (name X86_CPU_TYPE_SUFFIX)
#ifdef TARGET_X86_64
-#define TARGET_DEFAULT_CPU_TYPE X86_CPU_TYPE_NAME("qemu64")
+#define TARGET_DEFAULT_CPU_TYPE X86_CPU_TYPE_NAME("kvm64")
#else
-#define TARGET_DEFAULT_CPU_TYPE X86_CPU_TYPE_NAME("qemu32")
+#define TARGET_DEFAULT_CPU_TYPE X86_CPU_TYPE_NAME("kvm32")
#endif
#define cpu_signal_handler cpu_x86_signal_handler
--
2.11.0

View File

@ -10,10 +10,10 @@ provide '*is-current' in MachineInfo struct
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/qapi-schema.json b/qapi-schema.json
index f38b85bf6a..51e150c6c1 100644
index ebc22fe5a6..8f436ba1f3 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -4242,6 +4242,8 @@
@@ -1914,6 +1914,8 @@
#
# @is-default: whether the machine is default
#
@ -22,7 +22,7 @@ index f38b85bf6a..51e150c6c1 100644
# @cpu-max: maximum number of CPUs supported by the machine type
# (since 1.5.0)
#
@@ -4251,7 +4253,7 @@
@@ -1923,7 +1925,7 @@
##
{ 'struct': 'MachineInfo',
'data': { 'name': 'str', '*alias': 'str',
@ -32,10 +32,10 @@ index f38b85bf6a..51e150c6c1 100644
##
diff --git a/vl.c b/vl.c
index b719cc432e..46de1b9087 100644
index 1ad1c04637..2e0fe15978 100644
--- a/vl.c
+++ b/vl.c
@@ -1518,6 +1518,11 @@ MachineInfoList *qmp_query_machines(Error **errp)
@@ -1604,6 +1604,11 @@ MachineInfoList *qmp_query_machines(Error **errp)
info->cpu_max = !mc->max_cpus ? 1 : mc->max_cpus;
info->hotpluggable_cpus = mc->has_hotpluggable_cpus;

View File

@ -5,15 +5,15 @@ Subject: [PATCH] qapi: modify spice query
Provide the last ticket in the SpiceInfo struct optionally.
---
qapi-schema.json | 3 +++
ui/spice-core.c | 5 +++++
qapi/ui.json | 3 +++
ui/spice-core.c | 5 +++++
2 files changed, 8 insertions(+)
diff --git a/qapi-schema.json b/qapi-schema.json
index 51e150c6c1..1b14ff2476 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1841,11 +1841,14 @@
diff --git a/qapi/ui.json b/qapi/ui.json
index 07b468f625..78c906ddcf 100644
--- a/qapi/ui.json
+++ b/qapi/ui.json
@@ -199,11 +199,14 @@
#
# @channels: a list of @SpiceChannel for each active spice channel
#
@ -29,10 +29,10 @@ index 51e150c6c1..1b14ff2476 100644
##
diff --git a/ui/spice-core.c b/ui/spice-core.c
index 804abc5c0f..4a417310d3 100644
index ea04dc69b5..05f5958b14 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -552,6 +552,11 @@ SpiceInfo *qmp_query_spice(Error **errp)
@@ -551,6 +551,11 @@ SpiceInfo *qmp_query_spice(Error **errp)
micro = SPICE_SERVER_VERSION & 0xff;
info->compiled_version = g_strdup_printf("%d.%d.%d", major, minor, micro);

View File

@ -8,10 +8,10 @@ Subject: [PATCH] ui/spice: default to pve certs unless otherwise specified
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/ui/spice-core.c b/ui/spice-core.c
index 4a417310d3..af1dc8c653 100644
index 05f5958b14..6e1a46d1e5 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -685,32 +685,35 @@ void qemu_spice_init(void)
@@ -684,32 +684,35 @@ void qemu_spice_init(void)
if (tls_port) {
x509_dir = qemu_opt_get(opts, "x509-dir");

View File

@ -4,37 +4,45 @@ Date: Wed, 9 Dec 2015 16:04:32 +0100
Subject: [PATCH] internal snapshot async
---
Makefile.objs | 1 +
hmp-commands-info.hx | 13 ++
hmp-commands.hx | 32 +++
hmp.c | 57 ++++++
hmp.h | 5 +
include/sysemu/sysemu.h | 5 +-
migration/savevm.c | 12 +-
qapi-schema.json | 68 +++++++
qemu-options.hx | 13 ++
savevm-async.c | 523 ++++++++++++++++++++++++++++++++++++++++++++++++
vl.c | 8 +
11 files changed, 730 insertions(+), 7 deletions(-)
Makefile.objs | 2 +-
hmp-commands-info.hx | 13 ++
hmp-commands.hx | 32 +++
hmp.c | 57 +++++
hmp.h | 5 +
include/migration/snapshot.h | 1 +
qapi-schema.json | 32 +++
qapi/migration.json | 34 +++
qemu-options.hx | 13 ++
savevm-async.c | 524 +++++++++++++++++++++++++++++++++++++++++++
vl.c | 10 +
11 files changed, 722 insertions(+), 1 deletion(-)
create mode 100644 savevm-async.c
diff --git a/Makefile.objs b/Makefile.objs
index 6167e7b17d..fbfbbb7f70 100644
index 285c6f3c15..686247b556 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -50,6 +50,7 @@ common-obj-$(CONFIG_LINUX) += fsdev/
@@ -41,6 +41,7 @@ io-obj-y = io/
ifeq ($(CONFIG_SOFTMMU),y)
common-obj-y = blockdev.o blockdev-nbd.o block/
common-obj-y += bootdevice.o iothread.o
+common-obj-y += savevm-async.o
common-obj-y += net/
common-obj-y += qdev-monitor.o device-hotplug.o
common-obj-$(CONFIG_WIN32) += os-win32.o
@@ -49,7 +50,6 @@ common-obj-$(CONFIG_POSIX) += os-posix.o
common-obj-$(CONFIG_LINUX) += fsdev/
common-obj-y += migration/
common-obj-y += page_cache.o #aio.o
+common-obj-y += savevm-async.o
common-obj-$(CONFIG_SPICE) += spice-qemu-char.o
-
common-obj-y += audio/
common-obj-y += hw/
diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx
index a53f105c52..5fc57a2210 100644
index 54c3e5eac6..3bf69a193c 100644
--- a/hmp-commands-info.hx
+++ b/hmp-commands-info.hx
@@ -560,6 +560,19 @@ Show current migration xbzrle cache size.
@@ -566,6 +566,19 @@ Show current migration xbzrle cache size.
ETEXI
{
@ -55,10 +63,10 @@ index a53f105c52..5fc57a2210 100644
.args_type = "",
.params = "",
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 88192817b2..58940a762b 100644
index 4afd57cf5f..b35bc6ab6c 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1777,3 +1777,35 @@ ETEXI
@@ -1873,3 +1873,35 @@ ETEXI
STEXI
@end table
ETEXI
@ -95,11 +103,11 @@ index 88192817b2..58940a762b 100644
+ .cmd = hmp_savevm_end,
+ },
diff --git a/hmp.c b/hmp.c
index 904542d026..f725d061e6 100644
index 4e1d571003..b9ade681f0 100644
--- a/hmp.c
+++ b/hmp.c
@@ -2207,6 +2207,63 @@ void hmp_info_memory_devices(Monitor *mon, const QDict *qdict)
qapi_free_MemoryDeviceInfoList(info_list);
@@ -2486,6 +2486,63 @@ void hmp_info_memory_devices(Monitor *mon, const QDict *qdict)
hmp_handle_error(mon, &err);
}
+void hmp_savevm_start(Monitor *mon, const QDict *qdict)
@ -163,7 +171,7 @@ index 904542d026..f725d061e6 100644
{
IOThreadInfoList *info_list = qmp_query_iothreads(NULL);
diff --git a/hmp.h b/hmp.h
index 799fd371fa..0497afbf65 100644
index a6f56b1f29..45ada581b6 100644
--- a/hmp.h
+++ b/hmp.h
@@ -26,6 +26,7 @@ void hmp_info_status(Monitor *mon, const QDict *qdict);
@ -174,7 +182,7 @@ index 799fd371fa..0497afbf65 100644
void hmp_info_migrate(Monitor *mon, const QDict *qdict);
void hmp_info_migrate_capabilities(Monitor *mon, const QDict *qdict);
void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict);
@@ -92,6 +93,10 @@ void hmp_netdev_add(Monitor *mon, const QDict *qdict);
@@ -97,6 +98,10 @@ void hmp_netdev_add(Monitor *mon, const QDict *qdict);
void hmp_netdev_del(Monitor *mon, const QDict *qdict);
void hmp_getfd(Monitor *mon, const QDict *qdict);
void hmp_closefd(Monitor *mon, const QDict *qdict);
@ -185,97 +193,65 @@ index 799fd371fa..0497afbf65 100644
void hmp_sendkey(Monitor *mon, const QDict *qdict);
void hmp_screendump(Monitor *mon, const QDict *qdict);
void hmp_nbd_server_start(Monitor *mon, const QDict *qdict);
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index 576c7ce640..74623de16c 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -78,6 +78,7 @@ void qemu_remove_machine_init_done_notifier(Notifier *notify);
void hmp_savevm(Monitor *mon, const QDict *qdict);
int save_vmstate(Monitor *mon, const char *name);
int load_vmstate(const char *name);
+int load_state_from_blockdev(const char *filename);
void hmp_delvm(Monitor *mon, const QDict *qdict);
void hmp_info_snapshots(Monitor *mon, const QDict *qdict);
diff --git a/include/migration/snapshot.h b/include/migration/snapshot.h
index c85b6ec75b..4411b7121d 100644
--- a/include/migration/snapshot.h
+++ b/include/migration/snapshot.h
@@ -17,5 +17,6 @@
@@ -105,13 +106,13 @@ enum qemu_vm_cmd {
#define MAX_VM_CMD_PACKAGED_SIZE (1ul << 24)
int save_snapshot(const char *name, Error **errp);
int load_snapshot(const char *name, Error **errp);
+int load_snapshot_from_blockdev(const char *filename, Error **errp);
bool qemu_savevm_state_blocked(Error **errp);
-void qemu_savevm_state_begin(QEMUFile *f,
+int qemu_savevm_state_begin(QEMUFile *f,
const MigrationParams *params);
void qemu_savevm_state_header(QEMUFile *f);
int qemu_savevm_state_iterate(QEMUFile *f, bool postcopy);
void qemu_savevm_state_cleanup(void);
void qemu_savevm_state_complete_postcopy(QEMUFile *f);
-void qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only);
+int qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only);
void qemu_savevm_state_pending(QEMUFile *f, uint64_t max_size,
uint64_t *res_non_postcopiable,
uint64_t *res_postcopiable);
diff --git a/migration/savevm.c b/migration/savevm.c
index 3b19a4a274..feb0dc6834 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -970,11 +970,11 @@ void qemu_savevm_state_header(QEMUFile *f)
}
-void qemu_savevm_state_begin(QEMUFile *f,
+int qemu_savevm_state_begin(QEMUFile *f,
const MigrationParams *params)
{
SaveStateEntry *se;
- int ret;
+ int ret = 0;
trace_savevm_state_begin();
QTAILQ_FOREACH(se, &savevm_state.handlers, entry) {
@@ -1002,6 +1002,7 @@ void qemu_savevm_state_begin(QEMUFile *f,
break;
}
}
+ return ret;
}
/*
@@ -1105,7 +1106,7 @@ void qemu_savevm_state_complete_postcopy(QEMUFile *f)
qemu_fflush(f);
}
-void qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only)
+int qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only)
{
QJSON *vmdesc;
int vmdesc_len;
@@ -1139,12 +1140,12 @@ void qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only)
save_section_footer(f, se);
if (ret < 0) {
qemu_file_set_error(f, ret);
- return;
+ return ret;
}
}
if (iterable_only) {
- return;
+ return ret;
}
vmdesc = qjson_new();
@@ -1191,6 +1192,7 @@ void qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only)
qjson_destroy(vmdesc);
qemu_fflush(f);
+ return qemu_file_get_error(f);
}
/* Give an estimate of the amount left to be transferred,
#endif
diff --git a/qapi-schema.json b/qapi-schema.json
index 1b14ff2476..361700d37c 100644
index 8f436ba1f3..348b527681 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -723,6 +723,40 @@
@@ -2439,6 +2439,38 @@
{ 'command': 'query-target', 'returns': 'TargetInfo' }
##
+# @savevm-start:
+#
+# Prepare for snapshot and halt VM. Save VM state to statefile.
+#
+##
+{ 'command': 'savevm-start', 'data': { '*statefile': 'str' } }
+
+##
+# @snapshot-drive:
+#
+# Create an internal drive snapshot.
+#
+##
+{ 'command': 'snapshot-drive', 'data': { 'device': 'str', 'name': 'str' } }
+
+##
+# @delete-drive-snapshot:
+#
+# Delete a drive snapshot.
+#
+##
+{ 'command': 'delete-drive-snapshot', 'data': { 'device': 'str', 'name': 'str' } }
+
+##
+# @savevm-end:
+#
+# Resume VM after a snapshot.
+#
+##
+{ 'command': 'savevm-end' }
+
+##
# @AcpiTableOptions:
#
# Specify an ACPI table on the command line to load.
diff --git a/qapi/migration.json b/qapi/migration.json
index 03f57c9616..9ae55b81a2 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -170,6 +170,40 @@
'*error-desc': 'str'} }
##
@ -316,55 +292,11 @@ index 1b14ff2476..361700d37c 100644
# @query-migrate:
#
# Returns information about current migration process. If migration
@@ -4735,9 +4769,43 @@
#
# Since: 1.2.0
##
+
{ 'command': 'query-target', 'returns': 'TargetInfo' }
##
+# @savevm-start:
+#
+# Prepare for snapshot and halt VM. Save VM state to statefile.
+#
+##
+{ 'command': 'savevm-start', 'data': { '*statefile': 'str' } }
+
+##
+# @snapshot-drive:
+#
+# Create an internal drive snapshot.
+#
+##
+{ 'command': 'snapshot-drive', 'data': { 'device': 'str', 'name': 'str' } }
+
+##
+# @delete-drive-snapshot:
+#
+# Delete a drive snapshot.
+#
+##
+{ 'command': 'delete-drive-snapshot', 'data': { 'device': 'str', 'name': 'str' } }
+
+##
+# @savevm-end:
+#
+# Resume VM after a snapshot.
+#
+##
+{ 'command': 'savevm-end' }
+
+
+##
# @QKeyCode:
#
# An enumeration of key name.
diff --git a/qemu-options.hx b/qemu-options.hx
index 48dfffd86a..cbcb27da9a 100644
index 57f2c6a75f..7c054af8f9 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -3396,6 +3396,19 @@ STEXI
@@ -3698,6 +3698,19 @@ STEXI
Start right away with a saved state (@code{loadvm} in monitor)
ETEXI
@ -386,28 +318,23 @@ index 48dfffd86a..cbcb27da9a 100644
"-daemonize daemonize QEMU after initializing\n", QEMU_ARCH_ALL)
diff --git a/savevm-async.c b/savevm-async.c
new file mode 100644
index 0000000000..5fcb56d373
index 0000000000..897134ab5a
--- /dev/null
+++ b/savevm-async.c
@@ -0,0 +1,523 @@
@@ -0,0 +1,524 @@
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "migration/migration.h"
+#include "migration/savevm.h"
+#include "migration/snapshot.h"
+#include "migration/global_state.h"
+#include "migration/ram.h"
+#include "migration/qemu-file.h"
+#include "qapi/qmp/qerror.h"
+#include "qemu/error-report.h"
+#include "sysemu/sysemu.h"
+#include "qmp-commands.h"
+#include "qemu-options.h"
+#include "migration/qemu-file.h"
+#include "qom/qom-qobject.h"
+#include "migration/migration.h"
+#include "block/snapshot.h"
+#include "block/qapi.h"
+#include "block/block.h"
+#include "qemu/timer.h"
+#include "sysemu/block-backend.h"
+#include "qapi/qmp/qstring.h"
+#include "qemu/rcu.h"
+#include "qemu/thread.h"
+#include "qemu/cutils.h"
+
+/* #define DEBUG_SAVEVM_STATE */
@ -498,7 +425,7 @@ index 0000000000..5fcb56d373
+ * note: bdrv_read() need whole blocks, so we round up
+ */
+ size_t size = (snap_state.bs_pos + BDRV_SECTOR_SIZE) & BDRV_SECTOR_MASK;
+ blk_truncate(snap_state.target, size, NULL);
+ blk_truncate(snap_state.target, size, PREALLOC_MODE_OFF, NULL);
+ blk_op_unblock_all(snap_state.target, snap_state.blocker);
+ error_free(snap_state.blocker);
+ snap_state.blocker = NULL;
@ -578,20 +505,17 @@ index 0000000000..5fcb56d373
+{
+ int ret;
+ int64_t maxlen;
+ MigrationParams params = {
+ .blk = 0,
+ .shared = 0
+ };
+
+ snap_state.state = SAVE_STATE_ACTIVE;
+
+ qemu_mutex_unlock_iothread();
+ qemu_savevm_state_header(snap_state.file);
+ ret = qemu_savevm_state_begin(snap_state.file, &params);
+ qemu_savevm_state_setup(snap_state.file);
+ ret = qemu_file_get_error(snap_state.file);
+ qemu_mutex_lock_iothread();
+
+ if (ret < 0) {
+ save_snapshot_error("qemu_savevm_state_begin failed");
+ save_snapshot_error("qemu_savevm_state_setup failed");
+ return;
+ }
+
@ -613,7 +537,16 @@ index 0000000000..5fcb56d373
+ if (store_and_stop())
+ break;
+ DPRINTF("savevm inerate finished\n");
+ qemu_savevm_state_complete_precopy(snap_state.file, false);
+ /* upstream made the return value here inconsistent
+ * (-1 instead of 'ret' in one case and 0 after flush which can
+ * still set a file error...)
+ */
+ (void)qemu_savevm_state_complete_precopy(snap_state.file, false, false);
+ ret = qemu_file_get_error(snap_state.file);
+ if (ret < 0) {
+ save_snapshot_error("qemu_savevm_state_iterate error %d", ret);
+ break;
+ }
+ DPRINTF("save complete\n");
+ save_snapshot_completed();
+ break;
@ -867,7 +800,7 @@ index 0000000000..5fcb56d373
+ .get_buffer = loadstate_get_buffer,
+};
+
+int load_state_from_blockdev(const char *filename)
+int load_snapshot_from_blockdev(const char *filename, Error **errp)
+{
+ BlockBackend *be;
+ Error *local_err = NULL;
@ -879,7 +812,7 @@ index 0000000000..5fcb56d373
+ be = blk_new_open(filename, NULL, NULL, 0, &local_err);
+
+ if (!be) {
+ error_report("Could not open VM state file");
+ error_setg(errp, "Could not open VM state file");
+ goto the_end;
+ }
+
@ -889,17 +822,17 @@ index 0000000000..5fcb56d373
+ /* restore the VM state */
+ f = qemu_fopen_ops(be, &loadstate_file_ops);
+ if (!f) {
+ error_report("Could not open VM state file");
+ error_setg(errp, "Could not open VM state file");
+ goto the_end;
+ }
+
+ qemu_system_reset(VMRESET_SILENT);
+ qemu_system_reset(SHUTDOWN_CAUSE_NONE);
+ ret = qemu_loadvm_state(f);
+
+ qemu_fclose(f);
+ migration_incoming_state_destroy();
+ if (ret < 0) {
+ error_report("Error %d while loading VM state", ret);
+ error_setg_errno(errp, -ret, "Error while loading VM state");
+ goto the_end;
+ }
+
@ -914,10 +847,10 @@ index 0000000000..5fcb56d373
+ return ret;
+}
diff --git a/vl.c b/vl.c
index 46de1b9087..2132a77129 100644
index 2e0fe15978..1bfbe95b22 100644
--- a/vl.c
+++ b/vl.c
@@ -2960,6 +2960,7 @@ int main(int argc, char **argv, char **envp)
@@ -3109,6 +3109,7 @@ int main(int argc, char **argv, char **envp)
int optind;
const char *optarg;
const char *loadvm = NULL;
@ -925,7 +858,7 @@ index 46de1b9087..2132a77129 100644
MachineClass *machine_class;
const char *cpu_model;
const char *vga_model = NULL;
@@ -3635,6 +3636,9 @@ int main(int argc, char **argv, char **envp)
@@ -3785,6 +3786,9 @@ int main(int argc, char **argv, char **envp)
case QEMU_OPTION_loadvm:
loadvm = optarg;
break;
@ -935,12 +868,14 @@ index 46de1b9087..2132a77129 100644
case QEMU_OPTION_full_screen:
full_screen = 1;
break;
@@ -4693,6 +4697,10 @@ int main(int argc, char **argv, char **envp)
if (load_vmstate(loadvm) < 0) {
@@ -4891,6 +4895,12 @@ int main(int argc, char **argv, char **envp)
error_report_err(local_err);
autostart = 0;
}
+ } else if (loadstate) {
+ if (load_state_from_blockdev(loadstate) < 0) {
+ Error *local_err = NULL;
+ if (load_snapshot_from_blockdev(loadstate, &local_err) < 0) {
+ error_report_err(local_err);
+ autostart = 0;
+ }
}

View File

@ -4,14 +4,14 @@ Date: Tue, 8 Nov 2016 11:13:06 +0100
Subject: [PATCH] convert savevm-async to threads
---
savevm-async.c | 144 +++++++++++++++++++++++++++++++++++----------------------
1 file changed, 88 insertions(+), 56 deletions(-)
savevm-async.c | 143 +++++++++++++++++++++++++++++++++++----------------------
1 file changed, 87 insertions(+), 56 deletions(-)
diff --git a/savevm-async.c b/savevm-async.c
index 5fcb56d373..97d51d3edd 100644
index 897134ab5a..96523c88ae 100644
--- a/savevm-async.c
+++ b/savevm-async.c
@@ -48,6 +48,8 @@ static struct SnapshotState {
@@ -43,6 +43,8 @@ static struct SnapshotState {
int saved_vm_running;
QEMUFile *file;
int64_t total_time;
@ -20,7 +20,7 @@ index 5fcb56d373..97d51d3edd 100644
} snap_state;
SaveVMInfo *qmp_query_savevm(Error **errp)
@@ -135,19 +137,6 @@ static void save_snapshot_error(const char *fmt, ...)
@@ -130,19 +132,6 @@ static void save_snapshot_error(const char *fmt, ...)
g_free (msg);
snap_state.state = SAVE_STATE_ERROR;
@ -40,7 +40,7 @@ index 5fcb56d373..97d51d3edd 100644
}
static int block_state_close(void *opaque)
@@ -156,51 +145,90 @@ static int block_state_close(void *opaque)
@@ -151,48 +140,86 @@ static int block_state_close(void *opaque)
return blk_flush(snap_state.target);
}
@ -125,29 +125,25 @@ index 5fcb56d373..97d51d3edd 100644
{
int ret;
int64_t maxlen;
+
MigrationParams params = {
.blk = 0,
.shared = 0
};
- snap_state.state = SAVE_STATE_ACTIVE;
+ rcu_register_thread();
- qemu_mutex_unlock_iothread();
qemu_savevm_state_header(snap_state.file);
ret = qemu_savevm_state_begin(snap_state.file, &params);
qemu_savevm_state_setup(snap_state.file);
ret = qemu_file_get_error(snap_state.file);
- qemu_mutex_lock_iothread();
if (ret < 0) {
save_snapshot_error("qemu_savevm_state_begin failed");
save_snapshot_error("qemu_savevm_state_setup failed");
- return;
+ rcu_unregister_thread();
+ return NULL;
}
while (snap_state.state == SAVE_STATE_ACTIVE) {
@@ -209,41 +237,43 @@ static void process_savevm_co(void *opaque)
@@ -201,17 +228,30 @@ static void process_savevm_co(void *opaque)
qemu_savevm_state_pending(snap_state.file, 0, &pend_nonpost, &pend_post);
pending_size = pend_post + pend_nonpost;
@ -185,7 +181,12 @@ index 5fcb56d373..97d51d3edd 100644
+ break;
+ }
DPRINTF("savevm inerate finished\n");
qemu_savevm_state_complete_precopy(snap_state.file, false);
/* upstream made the return value here inconsistent
* (-1 instead of 'ret' in one case and 0 after flush which can
@@ -223,28 +263,17 @@ static void process_savevm_co(void *opaque)
save_snapshot_error("qemu_savevm_state_iterate error %d", ret);
break;
}
+ qemu_savevm_state_cleanup();
DPRINTF("save complete\n");
- save_snapshot_completed();
@ -216,7 +217,7 @@ index 5fcb56d373..97d51d3edd 100644
}
static const QEMUFileOps block_file_ops = {
@@ -306,8 +336,10 @@ void qmp_savevm_start(bool has_statefile, const char *statefile, Error **errp)
@@ -307,8 +336,10 @@ void qmp_savevm_start(bool has_statefile, const char *statefile, Error **errp)
error_setg(&snap_state.blocker, "block device is in use by savevm");
blk_op_block_all(snap_state.target, snap_state.blocker);

View File

@ -4,15 +4,15 @@ Date: Wed, 9 Dec 2015 16:34:41 +0100
Subject: [PATCH] qmp: add get_link_status
---
net/net.c | 27 +++++++++++++++++++++++++++
qapi-schema.json | 16 ++++++++++++++++
2 files changed, 43 insertions(+)
net/net.c | 27 +++++++++++++++++++++++++++
qapi/net.json | 15 +++++++++++++++
2 files changed, 42 insertions(+)
diff --git a/net/net.c b/net/net.c
index 0ac3b9e80c..7410c1e5f3 100644
index 39ef546708..3681aa2173 100644
--- a/net/net.c
+++ b/net/net.c
@@ -1373,6 +1373,33 @@ void hmp_info_network(Monitor *mon, const QDict *qdict)
@@ -1399,6 +1399,33 @@ void hmp_info_network(Monitor *mon, const QDict *qdict)
}
}
@ -46,19 +46,11 @@ index 0ac3b9e80c..7410c1e5f3 100644
void qmp_set_link(const char *name, bool up, Error **errp)
{
NetClientState *ncs[MAX_QUEUE_NUM];
diff --git a/qapi-schema.json b/qapi-schema.json
index 361700d37c..5e82933ca1 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -56,6 +56,7 @@
{ 'pragma': {
# Commands allowed to return a non-dictionary:
'returns-whitelist': [
+ 'get_link_status',
'human-monitor-command',
'qom-get',
'query-migrate-cache-size',
@@ -2537,6 +2538,21 @@
diff --git a/qapi/net.json b/qapi/net.json
index 4beff5d582..73334c8f3c 100644
--- a/qapi/net.json
+++ b/qapi/net.json
@@ -35,6 +35,21 @@
{ 'command': 'set_link', 'data': {'name': 'str', 'up': 'bool'} }
##
@ -77,9 +69,9 @@ index 361700d37c..5e82933ca1 100644
+{ 'command': 'get_link_status', 'data': {'name': 'str'}, 'returns': 'int'}
+
+##
# @balloon:
# @netdev_add:
#
# Request the balloon driver to change its balloon size.
# Add a network backend.
--
2.11.0

View File

@ -9,10 +9,10 @@ Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index e96901435a..f049bbca9a 100644
index 186545d2a4..603a7ce6bf 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -2123,7 +2123,7 @@ bool pc_machine_is_smm_enabled(PCMachineState *pcms)
@@ -2135,7 +2135,7 @@ bool pc_machine_is_smm_enabled(PCMachineState *pcms)
if (tcg_enabled() || qtest_enabled()) {
smm_available = true;
} else if (kvm_enabled()) {

View File

@ -10,10 +10,10 @@ the version string, see PVE::QemuServer::kvm_user_version()
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/vl.c b/vl.c
index 2132a77129..5d888cd179 100644
index 1bfbe95b22..75fde82180 100644
--- a/vl.c
+++ b/vl.c
@@ -1909,7 +1909,7 @@ static void main_loop(void)
@@ -2006,7 +2006,7 @@ static void main_loop(void)
static void version(void)
{

View File

@ -8,10 +8,10 @@ Subject: [PATCH] vnc: altgr emulation
1 file changed, 25 insertions(+), 1 deletion(-)
diff --git a/ui/vnc.c b/ui/vnc.c
index b0314441c4..f30687884b 100644
index 06abe7360e..03f8f61b2e 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -1631,6 +1631,10 @@ static void kbd_leds(void *opaque, int ledstate)
@@ -1775,6 +1775,10 @@ static void kbd_leds(void *opaque, int ledstate)
static void do_key_event(VncState *vs, int down, int keycode, int sym)
{
@ -22,7 +22,7 @@ index b0314441c4..f30687884b 100644
/* QEMU console switch */
switch(keycode) {
case 0x2a: /* Left Shift */
@@ -1711,8 +1715,27 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym)
@@ -1855,8 +1859,27 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym)
}
if (qemu_console_is_graphic(NULL)) {
@ -50,7 +50,7 @@ index b0314441c4..f30687884b 100644
} else {
bool numlock = vs->modifiers_state[0x45];
bool control = (vs->modifiers_state[0x1d] ||
@@ -1852,7 +1875,8 @@ static void key_event(VncState *vs, int down, uint32_t sym)
@@ -1996,7 +2019,8 @@ static void key_event(VncState *vs, int down, uint32_t sym)
lsym = lsym - 'A' + 'a';
}

View File

@ -8,10 +8,10 @@ Subject: [PATCH] vnc: make x509 imply tls again
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/ui/vnc.c b/ui/vnc.c
index f30687884b..a345bf0d78 100644
index 03f8f61b2e..4494cb1dd4 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -3881,9 +3881,8 @@ void vnc_display_open(const char *id, Error **errp)
@@ -4034,9 +4034,8 @@ void vnc_display_open(const char *id, Error **errp)
const char *path;
bool tls = false, x509 = false, x509verify = false;
tls = qemu_opt_get_bool(opts, "tls", false);

View File

@ -4,21 +4,22 @@ Date: Mon, 11 Jan 2016 10:40:31 +0100
Subject: [PATCH] vnc: PVE VNC authentication
---
crypto/tlscreds.c | 47 +++++++++++
crypto/tlscreds.c | 47 ++++++++++++
crypto/tlscredspriv.h | 2 +
crypto/tlscredsx509.c | 13 +--
crypto/tlscredsx509.c | 13 ++--
crypto/tlssession.c | 1 +
include/crypto/tlscreds.h | 1 +
include/ui/console.h | 1 +
qapi-schema.json | 1 +
qemu-options.hx | 3 +
ui/vnc-auth-vencrypt.c | 197 ++++++++++++++++++++++++++++++++++++++--------
ui/vnc.c | 140 +++++++++++++++++++++++++++++++-
ui/vnc-auth-vencrypt.c | 182 ++++++++++++++++++++++++++++++++++++++--------
ui/vnc.c | 140 ++++++++++++++++++++++++++++++++++-
ui/vnc.h | 4 +
vl.c | 9 +++
11 files changed, 377 insertions(+), 41 deletions(-)
12 files changed, 364 insertions(+), 40 deletions(-)
diff --git a/crypto/tlscreds.c b/crypto/tlscreds.c
index a8965531b6..e9ae13ce47 100644
index 3cd41035bb..e982da3451 100644
--- a/crypto/tlscreds.c
+++ b/crypto/tlscreds.c
@@ -158,6 +158,33 @@ qcrypto_tls_creds_prop_get_verify(Object *obj,
@ -75,7 +76,7 @@ index a8965531b6..e9ae13ce47 100644
+ NULL);
+ object_property_add_enum(obj, "endpoint",
+ "QCryptoTLSCredsEndpoint",
+ QCryptoTLSCredsEndpoint_lookup,
+ &QCryptoTLSCredsEndpoint_lookup,
+ qcrypto_tls_creds_prop_get_endpoint,
+ qcrypto_tls_creds_prop_set_endpoint,
+ NULL);
@ -168,10 +169,10 @@ index ad47d88be7..f86d379f26 100644
diff --git a/include/ui/console.h b/include/ui/console.h
index d759338816..69f010e1db 100644
index 580dfc57ee..383e5c88bd 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -462,6 +462,7 @@ static inline void cocoa_display_init(DisplayState *ds, int full_screen)
@@ -466,6 +466,7 @@ static inline void cocoa_display_init(DisplayState *ds, int full_screen)
#endif
/* vnc.c */
@ -179,11 +180,23 @@ index d759338816..69f010e1db 100644
void vnc_display_init(const char *id);
void vnc_display_open(const char *id, Error **errp);
void vnc_display_add_client(const char *id, int csock, bool skipauth);
diff --git a/qapi-schema.json b/qapi-schema.json
index 348b527681..d2155cb00f 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -56,6 +56,7 @@
{ 'pragma': {
# Commands allowed to return a non-dictionary:
'returns-whitelist': [
+ 'get_link_status',
'human-monitor-command',
'qom-get',
'query-migrate-cache-size',
diff --git a/qemu-options.hx b/qemu-options.hx
index cbcb27da9a..0b1957c034 100644
index 7c054af8f9..07129d55bc 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -513,6 +513,9 @@ STEXI
@@ -583,6 +583,9 @@ STEXI
@table @option
ETEXI
@ -194,13 +207,13 @@ index cbcb27da9a..0b1957c034 100644
"-fda/-fdb file use 'file' as floppy disk 0/1 image\n", QEMU_ARCH_ALL)
DEF("fdb", HAS_ARG, QEMU_OPTION_fdb, "", QEMU_ARCH_ALL)
diff --git a/ui/vnc-auth-vencrypt.c b/ui/vnc-auth-vencrypt.c
index ffaab57550..594ca737a9 100644
index 7833631275..c42acd3714 100644
--- a/ui/vnc-auth-vencrypt.c
+++ b/ui/vnc-auth-vencrypt.c
@@ -28,6 +28,108 @@
#include "vnc.h"
@@ -29,6 +29,108 @@
#include "qapi/error.h"
#include "qemu/main-loop.h"
#include "trace.h"
+#include "io/channel-socket.h"
+
+static int protocol_client_auth_plain(VncState *vs, uint8_t *data, size_t len)
@ -228,7 +241,7 @@ index ffaab57550..594ca737a9 100644
+
+ VNC_DEBUG("AUTH PLAIN username: %s pw: %s\n", username, passwd);
+
+ if (pve_auth_verify(clientip->u.inet.data->host, username, passwd) == 0) {
+ if (pve_auth_verify(clientip->u.inet.host, username, passwd) == 0) {
+ vnc_write_u32(vs, 0); /* Accept auth completion */
+ start_client_init(vs);
+ qapi_free_SocketAddress(clientip);
@ -323,21 +336,20 @@ index ffaab57550..594ca737a9 100644
+
case VNC_AUTH_VENCRYPT_TLSVNC:
case VNC_AUTH_VENCRYPT_X509VNC:
VNC_DEBUG("Start TLS auth VNC\n");
@@ -88,45 +201,64 @@ static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len
{
start_auth_vnc(vs);
@@ -90,45 +203,51 @@ static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len
int auth = read_u32(data, 0);
trace_vnc_auth_vencrypt_subauth(vs, auth);
- if (auth != vs->subauth) {
+ if (auth != vs->subauth && auth != VNC_AUTH_VENCRYPT_PLAIN) {
VNC_DEBUG("Rejecting auth %d\n", auth);
trace_vnc_auth_fail(vs, vs->auth, "Unsupported sub-auth version", "");
vnc_write_u8(vs, 0); /* Reject auth */
vnc_flush(vs);
vnc_client_error(vs);
} else {
- Error *err = NULL;
- QIOChannelTLS *tls;
- VNC_DEBUG("Accepting auth %d, setting up TLS for handshake\n", auth);
- vnc_write_u8(vs, 1); /* Accept auth */
- vnc_flush(vs);
-
@ -352,7 +364,6 @@ index ffaab57550..594ca737a9 100644
+ {
+ Error *err = NULL;
+ QIOChannelTLS *tls;
+ VNC_DEBUG("Accepting auth %d, setting up TLS for handshake\n", auth);
+ vnc_write_u8(vs, 1); /* Accept auth */
+ vnc_flush(vs);
@ -362,7 +373,8 @@ index ffaab57550..594ca737a9 100644
- vs->vd->tlsaclname,
- &err);
- if (!tls) {
- VNC_DEBUG("Failed to setup TLS %s\n", error_get_pretty(err));
- trace_vnc_auth_fail(vs, vs->auth, "TLS setup failed",
- error_get_pretty(err));
- error_free(err);
- vnc_client_error(vs);
- return 0;
@ -371,46 +383,34 @@ index ffaab57550..594ca737a9 100644
+ g_source_remove(vs->ioc_tag);
+ vs->ioc_tag = 0;
+ }
- qio_channel_set_name(QIO_CHANNEL(tls), "vnc-server-tls");
- VNC_DEBUG("Start TLS VeNCrypt handshake process\n");
- object_unref(OBJECT(vs->ioc));
- vs->ioc = QIO_CHANNEL(tls);
- vs->tls = qio_channel_tls_get_session(tls);
+ tls = qio_channel_tls_new_server(
+ vs->ioc,
+ vs->vd->tlscreds,
+ vs->vd->tlsaclname,
+ &err);
+ if (!tls) {
+ VNC_DEBUG("Failed to setup TLS %s\n", error_get_pretty(err));
+ trace_vnc_auth_fail(vs, vs->auth, "TLS setup failed",
+ error_get_pretty(err));
+ error_free(err);
+ vnc_client_error(vs);
+ return 0;
+ vs->tls = qcrypto_tls_session_new(vs->vd->tlscreds,
+ NULL,
+ vs->vd->tlsaclname,
+ QCRYPTO_TLS_CREDS_ENDPOINT_SERVER,
+ &err);
+ if (!vs->tls) {
+ VNC_DEBUG("Failed to setup TLS %s\n",
+ error_get_pretty(err));
+ error_free(err);
+ vnc_client_error(vs);
+ return 0;
+ }
+ }
- qio_channel_set_name(QIO_CHANNEL(tls), "vnc-server-tls");
- object_unref(OBJECT(vs->ioc));
- vs->ioc = QIO_CHANNEL(tls);
- trace_vnc_client_io_wrap(vs, vs->ioc, "tls");
- vs->tls = qio_channel_tls_get_session(tls);
+ qio_channel_set_name(QIO_CHANNEL(tls), "vnc-server-tls");
+ object_unref(OBJECT(vs->ioc));
+ vs->ioc = QIO_CHANNEL(tls);
+ trace_vnc_client_io_wrap(vs, vs->ioc, "tls");
+ vs->tls = qio_channel_tls_get_session(tls);
- qio_channel_tls_handshake(tls,
- vnc_tls_handshake_done,
- vs,
- NULL);
+ VNC_DEBUG("Start TLS VeNCrypt handshake process\n");
+ object_unref(OBJECT(vs->ioc));
+ vs->ioc = QIO_CHANNEL(tls);
+ vs->tls = qio_channel_tls_get_session(tls);
+
+ qio_channel_tls_handshake(tls,
+ vnc_tls_handshake_done,
+ vs,
@ -419,12 +419,9 @@ index ffaab57550..594ca737a9 100644
}
return 0;
}
@@ -140,10 +272,11 @@ static int protocol_client_vencrypt_init(VncState *vs, uint8_t *data, size_t len
vnc_flush(vs);
@@ -144,8 +263,9 @@ static int protocol_client_vencrypt_init(VncState *vs, uint8_t *data, size_t len
vnc_client_error(vs);
} else {
- VNC_DEBUG("Sending allowed auth %d\n", vs->subauth);
+ VNC_DEBUG("Sending allowed auths %d %d\n", vs->subauth, VNC_AUTH_VENCRYPT_PLAIN);
vnc_write_u8(vs, 0); /* Accept version */
- vnc_write_u8(vs, 1); /* Number of sub-auths */
+ vnc_write_u8(vs, 2); /* Number of sub-auths */
@ -434,10 +431,10 @@ index ffaab57550..594ca737a9 100644
vnc_read_when(vs, protocol_client_vencrypt_auth, 4);
}
diff --git a/ui/vnc.c b/ui/vnc.c
index a345bf0d78..42db7e386b 100644
index 4494cb1dd4..1589cbe1b3 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -56,6 +56,125 @@ static const struct timeval VNC_REFRESH_LOSSY = { 2, 0 };
@@ -55,6 +55,125 @@ static const struct timeval VNC_REFRESH_LOSSY = { 2, 0 };
#include "vnc_keysym.h"
#include "crypto/cipher.h"
@ -563,7 +560,7 @@ index a345bf0d78..42db7e386b 100644
static QTAILQ_HEAD(, VncDisplay) vnc_displays =
QTAILQ_HEAD_INITIALIZER(vnc_displays);
@@ -3356,10 +3475,16 @@ vnc_display_setup_auth(int *auth,
@@ -3507,10 +3626,16 @@ vnc_display_setup_auth(int *auth,
if (password) {
if (is_x509) {
VNC_DEBUG("Initializing VNC server with x509 password auth\n");
@ -582,7 +579,7 @@ index a345bf0d78..42db7e386b 100644
}
} else if (sasl) {
@@ -3393,6 +3518,7 @@ vnc_display_create_creds(bool x509,
@@ -3544,6 +3669,7 @@ vnc_display_create_creds(bool x509,
bool x509verify,
const char *dir,
const char *id,
@ -590,7 +587,7 @@ index a345bf0d78..42db7e386b 100644
Error **errp)
{
gchar *credsid = g_strdup_printf("tlsvnc%s", id);
@@ -3408,6 +3534,7 @@ vnc_display_create_creds(bool x509,
@@ -3559,6 +3685,7 @@ vnc_display_create_creds(bool x509,
"endpoint", "server",
"dir", dir,
"verify-peer", x509verify ? "yes" : "no",
@ -598,7 +595,7 @@ index a345bf0d78..42db7e386b 100644
NULL);
} else {
creds = object_new_with_props(TYPE_QCRYPTO_TLS_CREDS_ANON,
@@ -3415,6 +3542,7 @@ vnc_display_create_creds(bool x509,
@@ -3566,6 +3693,7 @@ vnc_display_create_creds(bool x509,
credsid,
&err,
"endpoint", "server",
@ -606,7 +603,7 @@ index a345bf0d78..42db7e386b 100644
NULL);
}
@@ -3879,12 +4007,17 @@ void vnc_display_open(const char *id, Error **errp)
@@ -4032,12 +4160,17 @@ void vnc_display_open(const char *id, Error **errp)
}
} else {
const char *path;
@ -625,7 +622,7 @@ index a345bf0d78..42db7e386b 100644
} else {
path = qemu_opt_get(opts, "x509verify");
if (path) {
@@ -3896,6 +4029,7 @@ void vnc_display_open(const char *id, Error **errp)
@@ -4049,6 +4182,7 @@ void vnc_display_open(const char *id, Error **errp)
x509verify,
path,
vd->id,
@ -634,10 +631,10 @@ index a345bf0d78..42db7e386b 100644
if (!vd->tlscreds) {
goto fail;
diff --git a/ui/vnc.h b/ui/vnc.h
index 694cf32ca9..78d622ab84 100644
index bbda0540a7..8cc6367ed3 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -284,6 +284,8 @@ struct VncState
@@ -290,6 +290,8 @@ struct VncState
int auth;
int subauth; /* Used by VeNCrypt */
char challenge[VNC_AUTH_CHALLENGE_SIZE];
@ -646,7 +643,7 @@ index 694cf32ca9..78d622ab84 100644
QCryptoTLSSession *tls; /* Borrowed pointer from channel, don't free */
#ifdef CONFIG_VNC_SASL
VncStateSASL sasl;
@@ -577,4 +579,6 @@ int vnc_zrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
@@ -595,4 +597,6 @@ int vnc_zrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
int vnc_zywrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h);
void vnc_zrle_clear(VncState *vs);
@ -654,10 +651,10 @@ index 694cf32ca9..78d622ab84 100644
+
#endif /* QEMU_VNC_H */
diff --git a/vl.c b/vl.c
index 5d888cd179..1000a4a259 100644
index 75fde82180..255d989009 100644
--- a/vl.c
+++ b/vl.c
@@ -2947,6 +2947,7 @@ static int qemu_read_default_config_file(void)
@@ -3096,6 +3096,7 @@ static void register_global_properties(MachineState *ms)
int main(int argc, char **argv, char **envp)
{
int i;
@ -665,7 +662,7 @@ index 5d888cd179..1000a4a259 100644
int snapshot, linux_boot;
const char *initrd_filename;
const char *kernel_filename, *kernel_cmdline;
@@ -3778,6 +3779,14 @@ int main(int argc, char **argv, char **envp)
@@ -3922,6 +3923,14 @@ int main(int argc, char **argv, char **envp)
exit(1);
}
break;

View File

@ -10,10 +10,10 @@ Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
1 file changed, 4 insertions(+)
diff --git a/block/rbd.c b/block/rbd.c
index 2354ffcc64..b7700648ff 100644
index a76a5e8755..a33738a254 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -623,6 +623,10 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
@@ -642,6 +642,10 @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
rados_conf_set(s->cluster, "rbd_cache", "true");
}

View File

@ -1,25 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Thomas Lamprecht <t.lamprecht@proxmox.com>
Date: Wed, 6 Apr 2016 16:45:15 +0200
Subject: [PATCH] migrate: fix possible unitialised return value
---
migration/savevm.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/migration/savevm.c b/migration/savevm.c
index feb0dc6834..d2615f4620 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -1111,7 +1111,7 @@ int qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only)
QJSON *vmdesc;
int vmdesc_len;
SaveStateEntry *se;
- int ret;
+ int ret = -1;
bool in_postcopy = migration_in_postcopy(migrate_get_current());
trace_savevm_state_complete_precopy();
--
2.11.0

View File

@ -9,7 +9,7 @@ Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/savevm-async.c b/savevm-async.c
index 97d51d3edd..ece193a065 100644
index 96523c88ae..06dcd29fc7 100644
--- a/savevm-async.c
+++ b/savevm-async.c
@@ -377,6 +377,7 @@ void qmp_snapshot_drive(const char *device, const char *name, Error **errp)

View File

@ -11,7 +11,7 @@ Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/savevm-async.c b/savevm-async.c
index ece193a065..716dd2d7a1 100644
index 06dcd29fc7..e6f86ef865 100644
--- a/savevm-async.c
+++ b/savevm-async.c
@@ -459,6 +459,7 @@ void qmp_delete_drive_snapshot(const char *device, const char *name,

View File

@ -8,10 +8,10 @@ Subject: [PATCH] glusterfs: no default logfile if daemonized
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/block/gluster.c b/block/gluster.c
index cf29b5f9a4..bc44c50db0 100644
index 0f4265a3a4..8fab26481c 100644
--- a/block/gluster.c
+++ b/block/gluster.c
@@ -33,7 +33,7 @@
@@ -32,7 +32,7 @@
#define GLUSTER_DEBUG_DEFAULT 4
#define GLUSTER_DEBUG_MAX 9
#define GLUSTER_OPT_LOGFILE "logfile"
@ -20,15 +20,15 @@ index cf29b5f9a4..bc44c50db0 100644
#define GERR_INDEX_HINT "hint: check in 'server' array index '%d'\n"
@@ -398,6 +398,7 @@ static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf,
@@ -396,6 +396,7 @@ static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf,
int old_errno;
SocketAddressFlatList *server;
SocketAddressList *server;
unsigned long long port;
+ const char *logfile;
glfs = glfs_find_preopened(gconf->volume);
if (glfs) {
@@ -440,9 +441,15 @@ static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf,
@@ -438,9 +439,15 @@ static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf,
}
}

View File

@ -14,10 +14,10 @@ sense.
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/block/gluster.c b/block/gluster.c
index bc44c50db0..4fdf68f1fc 100644
index 8fab26481c..24296a39b3 100644
--- a/block/gluster.c
+++ b/block/gluster.c
@@ -42,6 +42,7 @@ typedef struct GlusterAIOCB {
@@ -41,6 +41,7 @@ typedef struct GlusterAIOCB {
int ret;
Coroutine *coroutine;
AioContext *aio_context;
@ -25,7 +25,7 @@ index bc44c50db0..4fdf68f1fc 100644
} GlusterAIOCB;
typedef struct BDRVGlusterState {
@@ -713,8 +714,10 @@ static void gluster_finish_aiocb(struct glfs_fd *fd, ssize_t ret, void *arg)
@@ -709,8 +710,10 @@ static void gluster_finish_aiocb(struct glfs_fd *fd, ssize_t ret, void *arg)
acb->ret = 0; /* Success */
} else if (ret < 0) {
acb->ret = -errno; /* Read/Write failed */
@ -37,7 +37,7 @@ index bc44c50db0..4fdf68f1fc 100644
}
aio_co_schedule(acb->aio_context, acb->coroutine);
@@ -962,6 +965,7 @@ static coroutine_fn int qemu_gluster_co_pwrite_zeroes(BlockDriverState *bs,
@@ -958,6 +961,7 @@ static coroutine_fn int qemu_gluster_co_pwrite_zeroes(BlockDriverState *bs,
acb.ret = 0;
acb.coroutine = qemu_coroutine_self();
acb.aio_context = bdrv_get_aio_context(bs);
@ -45,7 +45,7 @@ index bc44c50db0..4fdf68f1fc 100644
ret = glfs_zerofill_async(s->fd, offset, size, gluster_finish_aiocb, &acb);
if (ret < 0) {
@@ -1084,9 +1088,11 @@ static coroutine_fn int qemu_gluster_co_rw(BlockDriverState *bs,
@@ -1083,9 +1087,11 @@ static coroutine_fn int qemu_gluster_co_rw(BlockDriverState *bs,
acb.aio_context = bdrv_get_aio_context(bs);
if (write) {
@ -57,7 +57,7 @@ index bc44c50db0..4fdf68f1fc 100644
ret = glfs_preadv_async(s->fd, qiov->iov, qiov->niov, offset, 0,
gluster_finish_aiocb, &acb);
}
@@ -1150,6 +1156,7 @@ static coroutine_fn int qemu_gluster_co_flush_to_disk(BlockDriverState *bs)
@@ -1158,6 +1164,7 @@ static coroutine_fn int qemu_gluster_co_flush_to_disk(BlockDriverState *bs)
acb.ret = 0;
acb.coroutine = qemu_coroutine_self();
acb.aio_context = bdrv_get_aio_context(bs);
@ -65,7 +65,7 @@ index bc44c50db0..4fdf68f1fc 100644
ret = glfs_fsync_async(s->fd, gluster_finish_aiocb, &acb);
if (ret < 0) {
@@ -1196,6 +1203,7 @@ static coroutine_fn int qemu_gluster_co_pdiscard(BlockDriverState *bs,
@@ -1204,6 +1211,7 @@ static coroutine_fn int qemu_gluster_co_pdiscard(BlockDriverState *bs,
acb.ret = 0;
acb.coroutine = qemu_coroutine_self();
acb.aio_context = bdrv_get_aio_context(bs);

View File

@ -5,15 +5,15 @@ Subject: [PATCH] block: add the zeroinit block driver filter
---
block/Makefile.objs | 1 +
block/zeroinit.c | 220 ++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 221 insertions(+)
block/zeroinit.c | 202 ++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 203 insertions(+)
create mode 100644 block/zeroinit.c
diff --git a/block/Makefile.objs b/block/Makefile.objs
index de96f8ee80..8cdac08db5 100644
index 6eaf78a046..823e60cda6 100644
--- a/block/Makefile.objs
+++ b/block/Makefile.objs
@@ -4,6 +4,7 @@ block-obj-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o
@@ -4,6 +4,7 @@ block-obj-y += qed.o qed-l2-cache.o qed-table.o qed-cluster.o
block-obj-y += qed-check.o
block-obj-y += vhdx.o vhdx-endian.o vhdx-log.o
block-obj-y += quorum.o
@ -23,10 +23,10 @@ index de96f8ee80..8cdac08db5 100644
block-obj-$(CONFIG_WIN32) += file-win32.o win32-aio.o
diff --git a/block/zeroinit.c b/block/zeroinit.c
new file mode 100644
index 0000000000..305185512e
index 0000000000..37f588f75c
--- /dev/null
+++ b/block/zeroinit.c
@@ -0,0 +1,220 @@
@@ -0,0 +1,202 @@
+/*
+ * Filter to fake a zero-initialized block device.
+ *
@ -134,12 +134,10 @@ index 0000000000..305185512e
+ return bdrv_getlength(bs->file->bs);
+}
+
+static BlockAIOCB *zeroinit_aio_readv(BlockDriverState *bs,
+ int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+ BlockCompletionFunc *cb, void *opaque)
+static int coroutine_fn zeroinit_co_preadv(BlockDriverState *bs,
+ uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags)
+{
+ return bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors,
+ cb, opaque);
+ return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
+}
+
+static int coroutine_fn zeroinit_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
@ -151,23 +149,14 @@ index 0000000000..305185512e
+ return bdrv_pwrite_zeroes(bs->file, offset, count, flags);
+}
+
+static BlockAIOCB *zeroinit_aio_writev(BlockDriverState *bs,
+ int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+ BlockCompletionFunc *cb, void *opaque)
+static int coroutine_fn zeroinit_co_pwritev(BlockDriverState *bs,
+ uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags)
+{
+ BDRVZeroinitState *s = bs->opaque;
+ int64_t extents = (sector_num << BDRV_SECTOR_BITS) + ((nb_sectors + 1) << BDRV_SECTOR_BITS);
+ int64_t extents = offset + bytes;
+ if (extents > s->extents)
+ s->extents = extents;
+ return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors,
+ cb, opaque);
+}
+
+static BlockAIOCB *zeroinit_aio_flush(BlockDriverState *bs,
+ BlockCompletionFunc *cb,
+ void *opaque)
+{
+ return bdrv_aio_flush(bs->file->bs, cb, opaque);
+ return bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags);
+}
+
+static bool zeroinit_recurse_is_first_non_filter(BlockDriverState *bs,
@ -187,23 +176,16 @@ index 0000000000..305185512e
+ return s->has_zero_init;
+}
+
+static int64_t coroutine_fn zeroinit_co_get_block_status(BlockDriverState *bs,
+ int64_t sector_num,
+ int nb_sectors, int *pnum,
+ BlockDriverState **file)
+{
+ return bdrv_get_block_status(bs->file->bs, sector_num, nb_sectors, pnum, file);
+}
+
+static int coroutine_fn zeroinit_co_pdiscard(BlockDriverState *bs,
+ int64_t offset, int count)
+{
+ return bdrv_co_pdiscard(bs->file->bs, offset, count);
+}
+
+static int zeroinit_truncate(BlockDriverState *bs, int64_t offset)
+static int zeroinit_truncate(BlockDriverState *bs, int64_t offset,
+ PreallocMode prealloc, Error **errp)
+{
+ return bdrv_truncate(bs->file, offset, NULL);
+ return bdrv_truncate(bs->file, offset, prealloc, errp);
+}
+
+static int zeroinit_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
@ -224,16 +206,16 @@ index 0000000000..305185512e
+ .bdrv_co_flush_to_disk = zeroinit_co_flush,
+
+ .bdrv_co_pwrite_zeroes = zeroinit_co_pwrite_zeroes,
+ .bdrv_aio_writev = zeroinit_aio_writev,
+ .bdrv_aio_readv = zeroinit_aio_readv,
+ .bdrv_aio_flush = zeroinit_aio_flush,
+ .bdrv_co_pwritev = zeroinit_co_pwritev,
+ .bdrv_co_preadv = zeroinit_co_preadv,
+ .bdrv_co_flush = zeroinit_co_flush,
+
+ .is_filter = true,
+ .bdrv_recurse_is_first_non_filter = zeroinit_recurse_is_first_non_filter,
+
+ .bdrv_has_zero_init = zeroinit_has_zero_init,
+
+ .bdrv_co_get_block_status = zeroinit_co_get_block_status,
+ .bdrv_co_get_block_status = bdrv_co_get_block_status_from_file,
+
+ .bdrv_co_pdiscard = zeroinit_co_pdiscard,
+

View File

@ -31,30 +31,30 @@ override the output file's size.
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
---
qemu-img-cmds.hx | 4 +-
qemu-img.c | 176 +++++++++++++++++++++++++++++++++++--------------------
2 files changed, 115 insertions(+), 65 deletions(-)
qemu-img.c | 192 ++++++++++++++++++++++++++++++++++---------------------
2 files changed, 122 insertions(+), 74 deletions(-)
diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx
index 8ac78222af..16bee83987 100644
index 2fe31893cf..52042f2773 100644
--- a/qemu-img-cmds.hx
+++ b/qemu-img-cmds.hx
@@ -46,9 +46,9 @@ STEXI
@@ -53,9 +53,9 @@ STEXI
ETEXI
DEF("dd", img_dd,
- "dd [--image-opts] [-f fmt] [-O output_fmt] [bs=block_size] [count=blocks] [skip=blocks] if=input of=output")
+ "dd [--image-opts] [-f fmt] [-O output_fmt] [bs=block_size] [count=blocks] [skip=blocks] [osize=output_size] [if=input] [of=output]")
- "dd [--image-opts] [-U] [-f fmt] [-O output_fmt] [bs=block_size] [count=blocks] [skip=blocks] if=input of=output")
+ "dd [--image-opts] [-U] [-f fmt] [-O output_fmt] [bs=block_size] [count=blocks] [skip=blocks] [osize=output_size] if=input of=output")
STEXI
-@item dd [--image-opts] [-f @var{fmt}] [-O @var{output_fmt}] [bs=@var{block_size}] [count=@var{blocks}] [skip=@var{blocks}] if=@var{input} of=@var{output}
+@item dd [--image-opts] [-f @var{fmt}] [-O @var{output_fmt}] [bs=@var{block_size}] [count=@var{blocks}] [skip=@var{blocks}] [osize=output_size] [if=@var{input}] [of=@var{output}]
-@item dd [--image-opts] [-U] [-f @var{fmt}] [-O @var{output_fmt}] [bs=@var{block_size}] [count=@var{blocks}] [skip=@var{blocks}] if=@var{input} of=@var{output}
+@item dd [--image-opts] [-U] [-f @var{fmt}] [-O @var{output_fmt}] [bs=@var{block_size}] [count=@var{blocks}] [skip=@var{blocks}] [osize=output_size] if=@var{input} of=@var{output}
ETEXI
DEF("info", img_info,
diff --git a/qemu-img.c b/qemu-img.c
index c7804d63ee..ee7816e727 100644
index f8a39dd195..876a3623a7 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -4026,10 +4026,12 @@ out:
@@ -4088,10 +4088,12 @@ out:
#define C_IF 04
#define C_OF 010
#define C_SKIP 020
@ -67,7 +67,7 @@ index c7804d63ee..ee7816e727 100644
};
struct DdIo {
@@ -4108,6 +4110,20 @@ static int img_dd_skip(const char *arg,
@@ -4170,6 +4172,20 @@ static int img_dd_skip(const char *arg,
return 0;
}
@ -88,7 +88,7 @@ index c7804d63ee..ee7816e727 100644
static int img_dd(int argc, char **argv)
{
int ret = 0;
@@ -4147,6 +4163,7 @@ static int img_dd(int argc, char **argv)
@@ -4210,6 +4226,7 @@ static int img_dd(int argc, char **argv)
{ "if", img_dd_if, C_IF },
{ "of", img_dd_of, C_OF },
{ "skip", img_dd_skip, C_SKIP },
@ -96,7 +96,7 @@ index c7804d63ee..ee7816e727 100644
{ NULL, NULL, 0 }
};
const struct option long_options[] = {
@@ -4214,84 +4231,106 @@ static int img_dd(int argc, char **argv)
@@ -4288,8 +4305,13 @@ static int img_dd(int argc, char **argv)
arg = NULL;
}
@ -104,42 +104,25 @@ index c7804d63ee..ee7816e727 100644
- error_report("Must specify both input and output files");
+ if (!(dd.flags & C_IF) && (!fmt || strcmp(fmt, "raw") != 0)) {
+ error_report("Input format must be raw when readin from stdin");
ret = -1;
goto out;
}
- blk1 = img_open(image_opts, in.filename, fmt, 0, false, false);
-
- if (!blk1) {
+ ret = -1;
+ goto out;
+ }
+ if (!(dd.flags & C_OF) && strcmp(out_fmt, "raw") != 0) {
+ error_report("Output format must be raw when writing to stdout");
ret = -1;
goto out;
}
+ if (dd.flags & C_IF) {
+ blk1 = img_open(image_opts, in.filename, fmt, 0, false, false);
@@ -4301,85 +4323,101 @@ static int img_dd(int argc, char **argv)
goto out;
}
- drv = bdrv_find_format(out_fmt);
- if (!drv) {
- error_report("Unknown file format");
- ret = -1;
- goto out;
- }
- proto_drv = bdrv_find_protocol(out.filename, true, &local_err);
-
- if (!proto_drv) {
- error_report_err(local_err);
- ret = -1;
- goto out;
- }
- if (!drv->create_opts) {
- error_report("Format driver '%s' does not support image creation",
- drv->format_name);
- ret = -1;
- goto out;
- }
- if (!proto_drv->create_opts) {
- error_report("Protocol driver '%s' does not support image creation",
- proto_drv->format_name);
- blk1 = img_open(image_opts, in.filename, fmt, 0, false, false,
- force_share);
+ if (dd.flags & C_IF) {
+ blk1 = img_open(image_opts, in.filename, fmt, 0, false, false,
+ force_share);
- if (!blk1) {
- ret = -1;
- goto out;
+ if (!blk1) {
@ -147,14 +130,10 @@ index c7804d63ee..ee7816e727 100644
+ goto out;
+ }
}
- create_opts = qemu_opts_append(create_opts, drv->create_opts);
- create_opts = qemu_opts_append(create_opts, proto_drv->create_opts);
-
- opts = qemu_opts_create(create_opts, NULL, 0, &error_abort);
- size = blk_getlength(blk1);
- if (size < 0) {
- error_report("Failed to get size for '%s'", in.filename);
- drv = bdrv_find_format(out_fmt);
- if (!drv) {
- error_report("Unknown file format");
+ if (dd.flags & C_OSIZE) {
+ size = dd.osize;
+ } else if (dd.flags & C_IF) {
@ -171,30 +150,32 @@ index c7804d63ee..ee7816e727 100644
ret = -1;
goto out;
}
- proto_drv = bdrv_find_protocol(out.filename, true, &local_err);
- if (dd.flags & C_COUNT && dd.count <= INT64_MAX / in.bsz &&
+ if (!(dd.flags & C_OSIZE) && dd.flags & C_COUNT && dd.count <= INT64_MAX / in.bsz &&
dd.count * in.bsz < size) {
size = dd.count * in.bsz;
}
- /* Overflow means the specified offset is beyond input image's size */
- if (dd.flags & C_SKIP && (in.offset > INT64_MAX / in.bsz ||
- size < in.bsz * in.offset)) {
- qemu_opt_set_number(opts, BLOCK_OPT_SIZE, 0, &error_abort);
- } else {
- qemu_opt_set_number(opts, BLOCK_OPT_SIZE,
- size - in.bsz * in.offset, &error_abort);
- }
- ret = bdrv_create(drv, out.filename, opts, &local_err);
- if (ret < 0) {
- error_reportf_err(local_err,
- "%s: error while creating output image: ",
- out.filename);
- if (!proto_drv) {
- error_report_err(local_err);
- ret = -1;
- goto out;
- }
- if (!drv->create_opts) {
- error_report("Format driver '%s' does not support image creation",
- drv->format_name);
- ret = -1;
- goto out;
- }
- if (!proto_drv->create_opts) {
- error_report("Protocol driver '%s' does not support image creation",
- proto_drv->format_name);
- ret = -1;
- goto out;
+ if (!(dd.flags & C_OSIZE) && dd.flags & C_COUNT && dd.count <= INT64_MAX / in.bsz &&
+ dd.count * in.bsz < size) {
+ size = dd.count * in.bsz;
}
- create_opts = qemu_opts_append(create_opts, drv->create_opts);
- create_opts = qemu_opts_append(create_opts, proto_drv->create_opts);
- opts = qemu_opts_create(create_opts, NULL, 0, &error_abort);
+ if (dd.flags & C_OF) {
+ drv = bdrv_find_format(out_fmt);
+ if (!drv) {
@ -203,7 +184,13 @@ index c7804d63ee..ee7816e727 100644
+ goto out;
+ }
+ proto_drv = bdrv_find_protocol(out.filename, true, &local_err);
+
- size = blk_getlength(blk1);
- if (size < 0) {
- error_report("Failed to get size for '%s'", in.filename);
- ret = -1;
- goto out;
- }
+ if (!proto_drv) {
+ error_report_err(local_err);
+ ret = -1;
@ -224,24 +211,39 @@ index c7804d63ee..ee7816e727 100644
+ create_opts = qemu_opts_append(create_opts, drv->create_opts);
+ create_opts = qemu_opts_append(create_opts, proto_drv->create_opts);
- blk2 = img_open(image_opts, out.filename, out_fmt, BDRV_O_RDWR,
- false, false);
- if (dd.flags & C_COUNT && dd.count <= INT64_MAX / in.bsz &&
- dd.count * in.bsz < size) {
- size = dd.count * in.bsz;
- }
+ opts = qemu_opts_create(create_opts, NULL, 0, &error_abort);
- if (!blk2) {
- ret = -1;
- goto out;
- /* Overflow means the specified offset is beyond input image's size */
- if (dd.flags & C_SKIP && (in.offset > INT64_MAX / in.bsz ||
- size < in.bsz * in.offset)) {
- qemu_opt_set_number(opts, BLOCK_OPT_SIZE, 0, &error_abort);
- } else {
- qemu_opt_set_number(opts, BLOCK_OPT_SIZE,
- size - in.bsz * in.offset, &error_abort);
- }
+ /* Overflow means the specified offset is beyond input image's size */
+ if (dd.flags & C_OSIZE) {
+ qemu_opt_set_number(opts, BLOCK_OPT_SIZE, size, &error_abort);
+ } else if (dd.flags & C_SKIP && (in.offset > INT64_MAX / in.bsz ||
+ size < in.bsz * in.offset)) {
+ size < in.bsz * in.offset)) {
+ qemu_opt_set_number(opts, BLOCK_OPT_SIZE, 0, &error_abort);
+ } else {
+ qemu_opt_set_number(opts, BLOCK_OPT_SIZE,
+ size - in.bsz * in.offset, &error_abort);
+ }
+
- ret = bdrv_create(drv, out.filename, opts, &local_err);
- if (ret < 0) {
- error_reportf_err(local_err,
- "%s: error while creating output image: ",
- out.filename);
- ret = -1;
- goto out;
- }
+ ret = bdrv_create(drv, out.filename, opts, &local_err);
+ if (ret < 0) {
+ error_reportf_err(local_err,
@ -250,10 +252,25 @@ index c7804d63ee..ee7816e727 100644
+ ret = -1;
+ goto out;
+ }
+
+ blk2 = img_open(image_opts, out.filename, out_fmt, BDRV_O_RDWR,
+ false, false);
+
- /* TODO, we can't honour --image-opts for the target,
- * since it needs to be given in a format compatible
- * with the bdrv_create() call above which does not
- * support image-opts style.
- */
- blk2 = img_open_file(out.filename, NULL, out_fmt, BDRV_O_RDWR,
- false, false, false);
+ /* TODO, we can't honour --image-opts for the target,
+ * since it needs to be given in a format compatible
+ * with the bdrv_create() call above which does not
+ * support image-opts style.
+ */
+ blk2 = img_open_file(out.filename, NULL, out_fmt, BDRV_O_RDWR,
+ false, false, false);
- if (!blk2) {
- ret = -1;
- goto out;
+ if (!blk2) {
+ ret = -1;
+ goto out;
@ -261,14 +278,14 @@ index c7804d63ee..ee7816e727 100644
}
if (dd.flags & C_SKIP && (in.offset > INT64_MAX / in.bsz ||
@@ -4309,11 +4348,18 @@ static int img_dd(int argc, char **argv)
@@ -4397,11 +4435,17 @@ static int img_dd(int argc, char **argv)
for (out_pos = 0; in_pos < size; block_count++) {
int in_ret, out_ret;
+ size_t in_bsz = in_pos + in.bsz > size ? size - in_pos : in.bsz;
-
- if (in_pos + in.bsz > size) {
- in_ret = blk_pread(blk1, in_pos, in.buf, size - in_pos);
+ size_t in_bsz = in_pos + in.bsz > size ? size - in_pos : in.bsz;
+ if (blk1) {
+ in_ret = blk_pread(blk1, in_pos, in.buf, in_bsz);
} else {
@ -283,7 +300,7 @@ index c7804d63ee..ee7816e727 100644
}
if (in_ret < 0) {
error_report("error while reading from input image file: %s",
@@ -4323,9 +4369,13 @@ static int img_dd(int argc, char **argv)
@@ -4411,9 +4455,13 @@ static int img_dd(int argc, char **argv)
}
in_pos += in_ret;

View File

@ -16,10 +16,10 @@ having been started at the same point in time.
5 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/block/backup.c b/block/backup.c
index a4fb2884f9..1ede70c061 100644
index 99e6bcc748..8c2967a8cb 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -558,6 +558,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
@@ -539,6 +539,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
BlockdevOnError on_target_error,
int creation_flags,
BlockCompletionFunc *cb, void *opaque,
@ -27,7 +27,7 @@ index a4fb2884f9..1ede70c061 100644
BlockJobTxn *txn, Error **errp)
{
int64_t len;
@@ -682,6 +683,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
@@ -663,6 +664,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL,
&error_abort);
job->common.len = len;
@ -36,10 +36,10 @@ index a4fb2884f9..1ede70c061 100644
return &job->common;
diff --git a/block/replication.c b/block/replication.c
index bf3c395eb4..1c41d9e6bf 100644
index e41e293d2b..1b08b242eb 100644
--- a/block/replication.c
+++ b/block/replication.c
@@ -531,7 +531,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
@@ -561,7 +561,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
0, MIRROR_SYNC_MODE_NONE, NULL, false,
BLOCKDEV_ON_ERROR_REPORT,
BLOCKDEV_ON_ERROR_REPORT, BLOCK_JOB_INTERNAL,
@ -49,10 +49,10 @@ index bf3c395eb4..1c41d9e6bf 100644
error_propagate(errp, local_err);
backup_job_cleanup(bs);
diff --git a/blockdev.c b/blockdev.c
index e8a9a65167..9b6cfafd33 100644
index 56a6b24a0b..a9ed9034b5 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -3262,7 +3262,7 @@ static BlockJob *do_drive_backup(DriveBackup *backup, BlockJobTxn *txn,
@@ -3293,7 +3293,7 @@ static BlockJob *do_drive_backup(DriveBackup *backup, BlockJobTxn *txn,
job = backup_job_create(backup->job_id, bs, target_bs, backup->speed,
backup->sync, bmap, backup->compress,
backup->on_source_error, backup->on_target_error,
@ -61,7 +61,7 @@ index e8a9a65167..9b6cfafd33 100644
bdrv_unref(target_bs);
if (local_err != NULL) {
error_propagate(errp, local_err);
@@ -3341,7 +3341,7 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, BlockJobTxn *txn,
@@ -3372,7 +3372,7 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, BlockJobTxn *txn,
job = backup_job_create(backup->job_id, bs, target_bs, backup->speed,
backup->sync, NULL, backup->compress,
backup->on_source_error, backup->on_target_error,
@ -71,10 +71,10 @@ index e8a9a65167..9b6cfafd33 100644
error_propagate(errp, local_err);
}
diff --git a/blockjob.c b/blockjob.c
index 6e489327ff..764d41863e 100644
index 715c2c2680..c1b6b6a810 100644
--- a/blockjob.c
+++ b/blockjob.c
@@ -289,7 +289,7 @@ void block_job_start(BlockJob *job)
@@ -322,7 +322,7 @@ void block_job_start(BlockJob *job)
job->co = qemu_coroutine_create(block_job_co_entry, job);
job->pause_count--;
job->busy = true;
@ -84,10 +84,10 @@ index 6e489327ff..764d41863e 100644
}
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 89d7b458e7..19b84b027f 100644
index a5482775ec..1dbbdafd31 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -879,6 +879,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
@@ -985,6 +985,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
BlockdevOnError on_target_error,
int creation_flags,
BlockCompletionFunc *cb, void *opaque,

View File

@ -6,23 +6,23 @@ Subject: [PATCH] backup: introduce vma archive format
---
MAINTAINERS | 6 +
block/Makefile.objs | 3 +
block/vma.c | 424 +++++++++++++++++++++++++++++++++++++++++++
blockdev.c | 498 +++++++++++++++++++++++++++++++++++++++++++++++++++
configure | 30 ++++
block/vma.c | 424 ++++++++++++++++++++++++++++++++++++++++
blockdev.c | 536 +++++++++++++++++++++++++++++++++++++++++++++++++++
blockjob.c | 3 +-
configure | 30 +++
hmp-commands-info.hx | 13 ++
hmp-commands.hx | 31 ++++
hmp.c | 63 +++++++
hmp-commands.hx | 31 +++
hmp.c | 63 ++++++
hmp.h | 3 +
qapi-schema.json | 91 ++++++++++
qapi/block-core.json | 20 ++-
11 files changed, 1180 insertions(+), 2 deletions(-)
qapi/block-core.json | 109 ++++++++++-
11 files changed, 1219 insertions(+), 2 deletions(-)
create mode 100644 block/vma.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 430efb0ab7..6a7d338aad 100644
index 0255113470..581d80d144 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1811,6 +1811,12 @@ L: qemu-block@nongnu.org
@@ -1950,6 +1950,12 @@ L: qemu-block@nongnu.org
S: Supported
F: block/vvfat.c
@ -36,18 +36,18 @@ index 430efb0ab7..6a7d338aad 100644
M: Stefan Hajnoczi <stefanha@redhat.com>
L: qemu-block@nongnu.org
diff --git a/block/Makefile.objs b/block/Makefile.objs
index 8cdac08db5..6df5567dd3 100644
index 823e60cda6..d74140e413 100644
--- a/block/Makefile.objs
+++ b/block/Makefile.objs
@@ -21,6 +21,7 @@ block-obj-$(CONFIG_CURL) += curl.o
block-obj-$(CONFIG_RBD) += rbd.o
@@ -22,6 +22,7 @@ block-obj-$(CONFIG_RBD) += rbd.o
block-obj-$(CONFIG_GLUSTERFS) += gluster.o
block-obj-$(CONFIG_VXHS) += vxhs.o
block-obj-$(CONFIG_LIBSSH2) += ssh.o
+block-obj-$(CONFIG_VMA) += vma.o
block-obj-y += accounting.o dirty-bitmap.o
block-obj-y += write-threshold.o
block-obj-y += backup.o
@@ -45,3 +46,5 @@ block-obj-$(if $(CONFIG_BZIP2),m,n) += dmg-bz2.o
@@ -48,3 +49,5 @@ block-obj-$(if $(CONFIG_BZIP2),m,n) += dmg-bz2.o
dmg-bz2.o-libs := $(BZIP2_LIBS)
qcow.o-libs := -lz
linux-aio.o-libs := -laio
@ -484,7 +484,7 @@ index 0000000000..7151514f94
+
+block_init(bdrv_vma_init);
diff --git a/blockdev.c b/blockdev.c
index 9b6cfafd33..534c00f5da 100644
index a9ed9034b5..3ffd064c48 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -31,10 +31,12 @@
@ -500,7 +500,7 @@ index 9b6cfafd33..534c00f5da 100644
#include "block/throttle-groups.h"
#include "monitor/monitor.h"
#include "qemu/error-report.h"
@@ -2932,6 +2934,502 @@ out:
@@ -2963,6 +2965,540 @@ out:
aio_context_release(aio_context);
}
@ -521,6 +521,8 @@ index 9b6cfafd33..534c00f5da 100644
+ size_t total;
+ size_t transferred;
+ size_t zero_bytes;
+ QemuMutex backup_mutex;
+ bool backup_mutex_initialized;
+} backup_state;
+
+typedef struct PVEBackupDevInfo {
@ -536,6 +538,13 @@ index 9b6cfafd33..534c00f5da 100644
+
+static void pvebackup_cleanup(void)
+{
+ qemu_mutex_lock(&backup_state.backup_mutex);
+ // Avoid race between block jobs and backup-cancel command:
+ if (!backup_state.vmaw) {
+ qemu_mutex_unlock(&backup_state.backup_mutex);
+ return;
+ }
+
+ backup_state.end_time = time(NULL);
+
+ if (backup_state.vmaobj) {
@ -543,20 +552,15 @@ index 9b6cfafd33..534c00f5da 100644
+ backup_state.vmaobj = NULL;
+ }
+
+ if (backup_state.di_list) {
+ GList *l = backup_state.di_list;
+ while (l) {
+ PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data;
+ l = g_list_next(l);
+ g_free(di);
+ }
+ g_list_free(backup_state.di_list);
+ backup_state.di_list = NULL;
+ }
+ g_list_free(backup_state.di_list);
+ backup_state.di_list = NULL;
+ qemu_mutex_unlock(&backup_state.backup_mutex);
+}
+
+static void pvebackup_complete_cb(void *opaque, int ret)
+{
+ // This always runs in the main loop
+
+ PVEBackupDevInfo *di = opaque;
+
+ di->completed = true;
@ -574,6 +578,12 @@ index 9b6cfafd33..534c00f5da 100644
+ backup_state.vmaobj = NULL;
+ }
+
+ // remove self from job queue
+ qemu_mutex_lock(&backup_state.backup_mutex);
+ backup_state.di_list = g_list_remove(backup_state.di_list, di);
+ g_free(di);
+ qemu_mutex_unlock(&backup_state.backup_mutex);
+
+ if (!backup_state.cancel) {
+ pvebackup_run_next_job();
+ }
@ -582,6 +592,12 @@ index 9b6cfafd33..534c00f5da 100644
+static void pvebackup_cancel(void *opaque)
+{
+ backup_state.cancel = true;
+ qemu_mutex_lock(&backup_state.backup_mutex);
+ // Avoid race between block jobs and backup-cancel command:
+ if (!backup_state.vmaw) {
+ qemu_mutex_unlock(&backup_state.backup_mutex);
+ return;
+ }
+
+ if (!backup_state.error) {
+ error_setg(&backup_state.error, "backup cancelled");
@ -604,18 +620,24 @@ index 9b6cfafd33..534c00f5da 100644
+ if (!di->completed && di->bs) {
+ BlockJob *job = di->bs->job;
+ if (job) {
+ AioContext *aio_context = blk_get_aio_context(job->blk);
+ aio_context_acquire(aio_context);
+ if (!di->completed) {
+ block_job_cancel_sync(job);
+ block_job_cancel(job);
+ }
+ aio_context_release(aio_context);
+ }
+ }
+ }
+
+ qemu_mutex_unlock(&backup_state.backup_mutex);
+ pvebackup_cleanup();
+}
+
+void qmp_backup_cancel(Error **errp)
+{
+ if (!backup_state.backup_mutex_initialized)
+ return;
+ Coroutine *co = qemu_coroutine_create(pvebackup_cancel, NULL);
+ qemu_coroutine_enter(co);
+
@ -633,53 +655,61 @@ index 9b6cfafd33..534c00f5da 100644
+ const char *backup_dir,
+ Error **errp)
+{
+ char *cdata = NULL;
+ gsize clen = 0;
+ GError *err = NULL;
+ if (!g_file_get_contents(file, &cdata, &clen, &err)) {
+ error_setg(errp, "unable to read file '%s'", file);
+ char *cdata = NULL;
+ gsize clen = 0;
+ GError *err = NULL;
+ if (!g_file_get_contents(file, &cdata, &clen, &err)) {
+ error_setg(errp, "unable to read file '%s'", file);
+ return 1;
+ }
+
+ char *basename = g_path_get_basename(file);
+
+ if (format == BACKUP_FORMAT_VMA) {
+ vma_object_add_config_file(vmaobj, basename, cdata, clen, errp);
+ } else if (format == BACKUP_FORMAT_DIR) {
+ char config_path[PATH_MAX];
+ snprintf(config_path, PATH_MAX, "%s/%s", backup_dir, basename);
+ if (!g_file_set_contents(config_path, cdata, clen, &err)) {
+ error_setg(errp, "unable to write config file '%s'", config_path);
+ g_free(cdata);
+ g_free(basename);
+ return 1;
+ }
+ }
+
+ char *basename = g_path_get_basename(file);
+
+ if (format == BACKUP_FORMAT_VMA) {
+ vma_object_add_config_file(vmaobj, basename, cdata, clen, errp);
+ } else if (format == BACKUP_FORMAT_DIR) {
+ char config_path[PATH_MAX];
+ snprintf(config_path, PATH_MAX, "%s/%s", backup_dir, basename);
+ if (!g_file_set_contents(config_path, cdata, clen, &err)) {
+ error_setg(errp, "unable to write config file '%s'", config_path);
+ g_free(cdata);
+ g_free(basename);
+ return 1;
+ }
+ }
+
+ g_free(basename);
+ g_free(cdata);
+
+ return 0;
+ g_free(basename);
+ g_free(cdata);
+ return 0;
+}
+
+void block_job_resume(BlockJob *job);
+static void pvebackup_run_next_job(void)
+{
+ bool cancel = backup_state.error || backup_state.cancel;
+ qemu_mutex_lock(&backup_state.backup_mutex);
+
+ GList *next = g_list_nth(backup_state.di_list, backup_state.next_job);
+ while (next) {
+ PVEBackupDevInfo *di = (PVEBackupDevInfo *)next->data;
+ backup_state.next_job++;
+ if (!di->completed && di->bs && di->bs->job) {
+ BlockJob *job = di->bs->job;
+ if (cancel) {
+ block_job_cancel(job);
+ AioContext *aio_context = blk_get_aio_context(job->blk);
+ aio_context_acquire(aio_context);
+ qemu_mutex_unlock(&backup_state.backup_mutex);
+ if (backup_state.error || backup_state.cancel) {
+ block_job_cancel_sync(job);
+ } else {
+ block_job_resume(job);
+ }
+ aio_context_release(aio_context);
+ return;
+ }
+ next = g_list_next(next);
+ }
+ qemu_mutex_unlock(&backup_state.backup_mutex);
+
+ // no more jobs, run the cleanup
+ pvebackup_cleanup();
+}
+
@ -701,6 +731,11 @@ index 9b6cfafd33..534c00f5da 100644
+ UuidInfo *uuid_info;
+ BlockJob *job;
+
+ if (!backup_state.backup_mutex_initialized) {
+ qemu_mutex_init(&backup_state.backup_mutex);
+ backup_state.backup_mutex_initialized = true;
+ }
+
+ if (backup_state.di_list || backup_state.vmaobj) {
+ error_set(errp, ERROR_CLASS_GENERIC_ERROR,
+ "previous backup not finished");
@ -831,7 +866,7 @@ index 9b6cfafd33..534c00f5da 100644
+
+ int flags = BDRV_O_RDWR;
+ bdrv_img_create(di->targetfile, "raw", NULL, NULL, NULL,
+ di->size, flags, &local_err, false);
+ di->size, flags, false, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ goto err;
@ -844,22 +879,22 @@ index 9b6cfafd33..534c00f5da 100644
+ }
+ }
+ } else {
+ error_set(errp, ERROR_CLASS_GENERIC_ERROR, "unknown backup format");
+ goto err;
+ error_set(errp, ERROR_CLASS_GENERIC_ERROR, "unknown backup format");
+ goto err;
+ }
+
+ /* add configuration file to archive */
+ if (has_config_file) {
+ if(config_to_vma(config_file, format, backup_state.vmaobj, backup_dir, errp) != 0) {
+ goto err;
+ }
+ if(config_to_vma(config_file, format, backup_state.vmaobj, backup_dir, errp) != 0) {
+ goto err;
+ }
+ }
+
+ /* add firewall file to archive */
+ if (has_firewall_file) {
+ if(config_to_vma(firewall_file, format, backup_state.vmaobj, backup_dir, errp) != 0) {
+ goto err;
+ }
+ if(config_to_vma(firewall_file, format, backup_state.vmaobj, backup_dir, errp) != 0) {
+ goto err;
+ }
+ }
+ /* initialize global backup_state now */
+
@ -883,6 +918,7 @@ index 9b6cfafd33..534c00f5da 100644
+ memcpy(&backup_state.uuid, &uuid, sizeof(uuid));
+ qemu_uuid_unparse(&uuid, backup_state.uuid_str);
+
+ qemu_mutex_lock(&backup_state.backup_mutex);
+ backup_state.di_list = di_list;
+ backup_state.next_job = 0;
+
@ -912,6 +948,8 @@ index 9b6cfafd33..534c00f5da 100644
+ }
+ }
+
+ qemu_mutex_unlock(&backup_state.backup_mutex);
+
+ if (!backup_state.error) {
+ pvebackup_run_next_job(); // run one job
+ }
@ -1003,21 +1041,35 @@ index 9b6cfafd33..534c00f5da 100644
void qmp_block_stream(bool has_job_id, const char *job_id, const char *device,
bool has_base, const char *base,
bool has_base_node, const char *base_node,
diff --git a/blockjob.c b/blockjob.c
index c1b6b6a810..2de9f8f4dd 100644
--- a/blockjob.c
+++ b/blockjob.c
@@ -149,7 +149,8 @@ static void block_job_pause(BlockJob *job)
job->pause_count++;
}
-static void block_job_resume(BlockJob *job)
+void block_job_resume(BlockJob *job);
+void block_job_resume(BlockJob *job)
{
assert(job->pause_count > 0);
job->pause_count--;
diff --git a/configure b/configure
index be4d326ae0..841f7a8fae 100755
index 0c6e7572db..3a28a0a092 100755
--- a/configure
+++ b/configure
@@ -320,6 +320,7 @@ numa=""
tcmalloc="no"
@@ -422,6 +422,7 @@ tcmalloc="no"
jemalloc="no"
replication="yes"
vxhs=""
+vma=""
supported_cpu="no"
supported_os="no"
@@ -1183,6 +1184,10 @@ for opt do
@@ -1313,6 +1314,10 @@ for opt do
;;
--enable-replication) replication="yes"
--disable-git-update) git_update=no
;;
+ --disable-vma) vma="no"
+ ;;
@ -1026,15 +1078,15 @@ index be4d326ae0..841f7a8fae 100755
*)
echo "ERROR: unknown option $opt"
echo "Try '$0 --help' for more information"
@@ -1427,6 +1432,7 @@ disabled with --disable-FEATURE, default is enabled if available:
xfsctl xfsctl support
qom-cast-debug cast debugging support
tools build qemu-io, qemu-nbd and qemu-image tools
@@ -1561,6 +1566,7 @@ disabled with --disable-FEATURE, default is enabled if available:
crypto-afalg Linux AF_ALG crypto backend driver
vhost-user vhost-user support
capstone capstone disassembler support
+ vma VMA archive backend
NOTE: The object files are built at the place where configure is launched
EOF
@@ -3705,6 +3711,23 @@ EOF
@@ -3890,6 +3896,23 @@ EOF
fi
##########################################
@ -1058,16 +1110,16 @@ index be4d326ae0..841f7a8fae 100755
# signalfd probe
signalfd="no"
cat > $TMPC << EOF
@@ -5146,6 +5169,7 @@ echo "tcmalloc support $tcmalloc"
echo "jemalloc support $jemalloc"
echo "avx2 optimization $avx2_opt"
@@ -5555,6 +5578,7 @@ echo "avx2 optimization $avx2_opt"
echo "replication support $replication"
echo "VxHS block device $vxhs"
echo "capstone $capstone"
+echo "VMA support $vma"
if test "$sdl_too_old" = "yes"; then
echo "-> Your SDL version is too old - please upgrade to have SDL support"
@@ -5703,6 +5727,12 @@ if test "$libssh2" = "yes" ; then
echo "LIBSSH2_LIBS=$libssh2_libs" >> $config_host_mak
@@ -5998,6 +6022,12 @@ if test "$libusb" = "yes" ; then
echo "LIBUSB_LIBS=$libusb_libs" >> $config_host_mak
fi
+if test "$vma" = "yes" ; then
@ -1076,14 +1128,14 @@ index be4d326ae0..841f7a8fae 100755
+ echo "VMA_LIBS=$vma_libs" >> $config_host_mak
+fi
+
# USB host support
if test "$libusb" = "yes"; then
echo "HOST_USB=libusb legacy" >> $config_host_mak
if test "$usb_redir" = "yes" ; then
echo "CONFIG_USB_REDIR=y" >> $config_host_mak
echo "USB_REDIR_CFLAGS=$usb_redir_cflags" >> $config_host_mak
diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx
index 5fc57a2210..3b5a0f95e4 100644
index 3bf69a193c..7beeb29e99 100644
--- a/hmp-commands-info.hx
+++ b/hmp-commands-info.hx
@@ -487,6 +487,19 @@ STEXI
@@ -493,6 +493,19 @@ STEXI
Show CPU statistics.
ETEXI
@ -1104,7 +1156,7 @@ index 5fc57a2210..3b5a0f95e4 100644
{
.name = "usernet",
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 58940a762b..a2867b56f2 100644
index b35bc6ab6c..9e50947845 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -87,6 +87,37 @@ STEXI
@ -1146,10 +1198,10 @@ index 58940a762b..a2867b56f2 100644
.name = "block_job_set_speed",
.args_type = "device:B,speed:o",
diff --git a/hmp.c b/hmp.c
index f725d061e6..12f1f46125 100644
index b9ade681f0..241c2543ec 100644
--- a/hmp.c
+++ b/hmp.c
@@ -151,6 +151,44 @@ void hmp_info_mice(Monitor *mon, const QDict *qdict)
@@ -156,6 +156,44 @@ void hmp_info_mice(Monitor *mon, const QDict *qdict)
qapi_free_MouseInfoList(mice_list);
}
@ -1194,7 +1246,7 @@ index f725d061e6..12f1f46125 100644
void hmp_info_migrate(Monitor *mon, const QDict *qdict)
{
MigrationInfo *info;
@@ -1613,6 +1651,31 @@ void hmp_block_stream(Monitor *mon, const QDict *qdict)
@@ -1848,6 +1886,31 @@ void hmp_block_stream(Monitor *mon, const QDict *qdict)
hmp_handle_error(mon, &error);
}
@ -1227,7 +1279,7 @@ index f725d061e6..12f1f46125 100644
{
Error *error = NULL;
diff --git a/hmp.h b/hmp.h
index 0497afbf65..8c1b4846b3 100644
index 45ada581b6..635b9b4218 100644
--- a/hmp.h
+++ b/hmp.h
@@ -31,6 +31,7 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict);
@ -1238,7 +1290,7 @@ index 0497afbf65..8c1b4846b3 100644
void hmp_info_cpus(Monitor *mon, const QDict *qdict);
void hmp_info_block(Monitor *mon, const QDict *qdict);
void hmp_info_blockstats(Monitor *mon, const QDict *qdict);
@@ -80,6 +81,8 @@ void hmp_eject(Monitor *mon, const QDict *qdict);
@@ -85,6 +86,8 @@ void hmp_eject(Monitor *mon, const QDict *qdict);
void hmp_change(Monitor *mon, const QDict *qdict);
void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict);
void hmp_block_stream(Monitor *mon, const QDict *qdict);
@ -1247,12 +1299,12 @@ index 0497afbf65..8c1b4846b3 100644
void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict);
void hmp_block_job_cancel(Monitor *mon, const QDict *qdict);
void hmp_block_job_pause(Monitor *mon, const QDict *qdict);
diff --git a/qapi-schema.json b/qapi-schema.json
index 5e82933ca1..b20020a054 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -571,6 +571,97 @@
{ 'command': 'query-events', 'returns': ['EventInfo'] }
diff --git a/qapi/block-core.json b/qapi/block-core.json
index dd763dcf87..461fca9a3d 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -615,6 +615,97 @@
##
+# @BackupStatus:
@ -1346,24 +1398,20 @@ index 5e82933ca1..b20020a054 100644
+{ 'command': 'backup-cancel' }
+
+##
# @MigrationStats:
# @BlockDeviceTimedStats:
#
# Detailed migration status.
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 7ce90ec940..b0ffd3de4d 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -2118,7 +2118,7 @@
# Statistics of a block device during a given interval of time.
@@ -2239,7 +2330,7 @@
'host_device', 'http', 'https', 'iscsi', 'luks', 'nbd', 'nfs',
'null-aio', 'null-co', 'parallels', 'qcow', 'qcow2', 'qed',
'quorum', 'raw', 'rbd', 'replication', 'sheepdog', 'ssh',
- 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat' ] }
+ 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vma-drive' ] }
- 'throttle', 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] }
+ 'throttle', 'vdi', 'vhdx', 'vma-drive', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] }
##
# @BlockdevOptionsFile:
@@ -2895,6 +2895,21 @@
'data': { '*offset': 'int', '*size': 'int' } }
@@ -3116,6 +3207,21 @@
'*tls-creds': 'str' } }
##
+# @BlockdevOptionsVMADrive:
@ -1381,19 +1429,17 @@ index 7ce90ec940..b0ffd3de4d 100644
+ 'size': 'int' } }
+
+##
# @BlockdevOptions:
# @BlockdevOptionsThrottle:
#
# Options for creating a block device. Many options are available for all
@@ -2956,7 +2971,8 @@
# Driver specific block device options for the throttle driver
@@ -3196,6 +3302,7 @@
'throttle': 'BlockdevOptionsThrottle',
'vdi': 'BlockdevOptionsGenericFormat',
'vhdx': 'BlockdevOptionsGenericFormat',
+ 'vma-drive': 'BlockdevOptionsVMADrive',
'vmdk': 'BlockdevOptionsGenericCOWFormat',
'vpc': 'BlockdevOptionsGenericFormat',
- 'vvfat': 'BlockdevOptionsVVFAT'
+ 'vvfat': 'BlockdevOptionsVVFAT',
+ 'vma-drive': 'BlockdevOptionsVMADrive'
} }
##
'vvfat': 'BlockdevOptionsVVFAT',
--
2.11.0

View File

@ -6,35 +6,35 @@ Subject: [PATCH] adding old vma files
---
Makefile | 3 +-
Makefile.objs | 1 +
block/backup.c | 132 ++++---
block/backup.c | 130 ++++---
block/replication.c | 1 +
blockdev.c | 249 +++++++++-----
blockjob.c | 11 +-
blockdev.c | 207 +++++++----
blockjob.c | 3 +-
include/block/block_int.h | 4 +
vma-reader.c | 857 ++++++++++++++++++++++++++++++++++++++++++++++
vma-writer.c | 771 +++++++++++++++++++++++++++++++++++++++++
vma.c | 757 ++++++++++++++++++++++++++++++++++++++++
vma.h | 149 ++++++++
11 files changed, 2802 insertions(+), 133 deletions(-)
vma.c | 756 ++++++++++++++++++++++++++++++++++++++++
vma.h | 150 ++++++++
11 files changed, 2760 insertions(+), 123 deletions(-)
create mode 100644 vma-reader.c
create mode 100644 vma-writer.c
create mode 100644 vma.c
create mode 100644 vma.h
diff --git a/Makefile b/Makefile
index 6c359b2f86..edbc8b50f0 100644
index ab0354c153..ad28227b6c 100644
--- a/Makefile
+++ b/Makefile
@@ -284,7 +284,7 @@ ifneq ($(wildcard config-host.mak),)
@@ -340,7 +340,7 @@ dummy := $(call unnest-vars,, \
include $(SRC_PATH)/tests/Makefile.include
endif
-all: $(DOCS) $(TOOLS) $(HELPERS-y) recurse-all modules
+all: $(DOCS) $(TOOLS) vma$(EXESUF) $(HELPERS-y) recurse-all modules
qemu-version.h: FORCE
$(call quiet-command, \
@@ -377,6 +377,7 @@ qemu-img.o: qemu-img-cmds.h
@@ -439,6 +439,7 @@ qemu-img.o: qemu-img-cmds.h
qemu-img$(EXESUF): qemu-img.o $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
qemu-nbd$(EXESUF): qemu-nbd.o $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
qemu-io$(EXESUF): qemu-io.o $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)
@ -43,11 +43,11 @@ index 6c359b2f86..edbc8b50f0 100644
qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o $(COMMON_LDADDS)
diff --git a/Makefile.objs b/Makefile.objs
index fbfbbb7f70..f5f8dbab3b 100644
index 686247b556..34e62547d8 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -14,6 +14,7 @@ block-obj-y += block.o blockjob.o
block-obj-y += block/
block-obj-y += block/ scsi/
block-obj-y += qemu-io-cmds.o
block-obj-$(CONFIG_REPLICATION) += replication.o
+block-obj-y += vma-writer.o
@ -55,7 +55,7 @@ index fbfbbb7f70..f5f8dbab3b 100644
block-obj-m = block/
diff --git a/block/backup.c b/block/backup.c
index 1ede70c061..7c5febc434 100644
index 8c2967a8cb..0870acdae7 100644
--- a/block/backup.c
+++ b/block/backup.c
@@ -36,6 +36,7 @@ typedef struct BackupBlockJob {
@ -66,47 +66,48 @@ index 1ede70c061..7c5febc434 100644
BlockdevOnError on_source_error;
BlockdevOnError on_target_error;
CoRwlock flush_rwlock;
@@ -145,13 +146,24 @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job,
@@ -135,13 +136,24 @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job,
goto out;
}
+ int64_t start_sec = start * sectors_per_cluster;
+
if (buffer_is_zero(iov.iov_base, iov.iov_len)) {
- ret = blk_co_pwrite_zeroes(job->target, start * job->cluster_size,
- ret = blk_co_pwrite_zeroes(job->target, start,
- bounce_qiov.size, BDRV_REQ_MAY_UNMAP);
+ if (job->dump_cb) {
+ ret = job->dump_cb(job->common.opaque, job->target, start_sec, n, NULL);
+ ret = job->dump_cb(job->common.opaque, job->target, start, bounce_qiov.size, NULL);
+ }
+ if (job->target) {
+ ret = blk_co_pwrite_zeroes(job->target, start * job->cluster_size,
+ ret = blk_co_pwrite_zeroes(job->target, start,
+ bounce_qiov.size, BDRV_REQ_MAY_UNMAP);
+ }
} else {
- ret = blk_co_pwritev(job->target, start * job->cluster_size,
- ret = blk_co_pwritev(job->target, start,
- bounce_qiov.size, &bounce_qiov,
- job->compress ? BDRV_REQ_WRITE_COMPRESSED : 0);
+ if (job->dump_cb) {
+ ret = job->dump_cb(job->common.opaque, job->target, start_sec, n, bounce_buffer);
+ ret = job->dump_cb(job->common.opaque, job->target, start, bounce_qiov.size, bounce_buffer);
+ }
+ if (job->target) {
+ ret = blk_co_pwritev(job->target, start * job->cluster_size,
+ ret = blk_co_pwritev(job->target, start,
+ bounce_qiov.size, &bounce_qiov,
+ job->compress ? BDRV_REQ_WRITE_COMPRESSED : 0);
+ }
}
if (ret < 0) {
trace_backup_do_cow_write_fail(job, start, ret);
@@ -246,6 +258,9 @@ static void backup_abort(BlockJob *job)
@@ -234,7 +246,9 @@ static void backup_abort(BlockJob *job)
static void backup_clean(BlockJob *job)
{
BackupBlockJob *s = container_of(job, BackupBlockJob, common);
- assert(s->target);
+ if (!s->target) {
+ return;
+ }
assert(s->target);
blk_unref(s->target);
s->target = NULL;
@@ -255,7 +270,9 @@ static void backup_attached_aio_context(BlockJob *job, AioContext *aio_context)
}
@@ -243,7 +257,9 @@ static void backup_attached_aio_context(BlockJob *job, AioContext *aio_context)
{
BackupBlockJob *s = container_of(job, BackupBlockJob, common);
@ -117,7 +118,7 @@ index 1ede70c061..7c5febc434 100644
}
void backup_do_checkpoint(BlockJob *job, Error **errp)
@@ -330,9 +347,11 @@ static BlockErrorAction backup_error_action(BackupBlockJob *job,
@@ -315,9 +331,11 @@ static BlockErrorAction backup_error_action(BackupBlockJob *job,
if (read) {
return block_job_error_action(&job->common, job->on_source_error,
true, error);
@ -130,7 +131,7 @@ index 1ede70c061..7c5febc434 100644
}
}
@@ -557,6 +576,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
@@ -538,6 +556,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
BlockdevOnError on_source_error,
BlockdevOnError on_target_error,
int creation_flags,
@ -138,7 +139,7 @@ index 1ede70c061..7c5febc434 100644
BlockCompletionFunc *cb, void *opaque,
int pause_count,
BlockJobTxn *txn, Error **errp)
@@ -567,7 +587,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
@@ -548,7 +567,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
int ret;
assert(bs);
@ -147,7 +148,7 @@ index 1ede70c061..7c5febc434 100644
if (bs == target) {
error_setg(errp, "Source and target cannot be the same");
@@ -580,13 +600,13 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
@@ -561,13 +580,13 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
return NULL;
}
@ -163,7 +164,7 @@ index 1ede70c061..7c5febc434 100644
error_setg(errp, "Compression is not supported for this drive %s",
bdrv_get_device_name(target));
return NULL;
@@ -596,7 +616,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
@@ -577,7 +596,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
return NULL;
}
@ -172,7 +173,7 @@ index 1ede70c061..7c5febc434 100644
return NULL;
}
@@ -636,15 +656,18 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
@@ -617,15 +636,18 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
goto error;
}
@ -198,7 +199,7 @@ index 1ede70c061..7c5febc434 100644
job->on_source_error = on_source_error;
job->on_target_error = on_target_error;
job->sync_mode = sync_mode;
@@ -652,38 +675,55 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
@@ -633,36 +655,52 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
sync_bitmap : NULL;
job->compress = compress;
@ -208,12 +209,12 @@ index 1ede70c061..7c5febc434 100644
- ret = bdrv_get_info(target, &bdi);
- if (ret == -ENOTSUP && !target->backing) {
- /* Cluster size is not defined */
- error_report("WARNING: The target block device doesn't provide "
- "information about the block size and it doesn't have a "
- "backing file. The default block size of %u bytes is "
- "used. If the actual block size of the target exceeds "
- "this default, the backup may be unusable",
- BACKUP_CLUSTER_SIZE_DEFAULT);
- warn_report("The target block device doesn't provide "
- "information about the block size and it doesn't have a "
- "backing file. The default block size of %u bytes is "
- "used. If the actual block size of the target exceeds "
- "this default, the backup may be unusable",
- BACKUP_CLUSTER_SIZE_DEFAULT);
- job->cluster_size = BACKUP_CLUSTER_SIZE_DEFAULT;
- } else if (ret < 0 && !target->backing) {
- error_setg_errno(errp, -ret,
@ -232,12 +233,12 @@ index 1ede70c061..7c5febc434 100644
+ ret = bdrv_get_info(target, &bdi);
+ if (ret == -ENOTSUP && !target->backing) {
+ /* Cluster size is not defined */
+ error_report("WARNING: The target block device doesn't provide "
+ "information about the block size and it doesn't have a "
+ "backing file. The default block size of %u bytes is "
+ "used. If the actual block size of the target exceeds "
+ "this default, the backup may be unusable",
+ BACKUP_CLUSTER_SIZE_DEFAULT);
+ warn_report("The target block device doesn't provide "
+ "information about the block size and it doesn't have a "
+ "backing file. The default block size of %u bytes is "
+ "used. If the actual block size of the target exceeds "
+ "this default, the backup may be unusable",
+ BACKUP_CLUSTER_SIZE_DEFAULT);
+ job->cluster_size = BACKUP_CLUSTER_SIZE_DEFAULT;
+ } else if (ret < 0 && !target->backing) {
+ error_setg_errno(errp, -ret,
@ -274,19 +275,15 @@ index 1ede70c061..7c5febc434 100644
+ /* Required permissions are already taken with target's blk_new() */
+ block_job_add_bdrv(&job->common, "target", target, 0, BLK_PERM_ALL,
+ &error_abort);
+ } else {
+ job->common.pause_count = pause_count;
+ }
job->common.len = len;
- job->common.pause_count = pause_count;
job->common.pause_count = pause_count;
block_job_txn_add_job(txn, &job->common);
return &job->common;
diff --git a/block/replication.c b/block/replication.c
index 1c41d9e6bf..60c6524417 100644
index 1b08b242eb..3d101ce6e6 100644
--- a/block/replication.c
+++ b/block/replication.c
@@ -531,6 +531,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
@@ -561,6 +561,7 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
0, MIRROR_SYNC_MODE_NONE, NULL, false,
BLOCKDEV_ON_ERROR_REPORT,
BLOCKDEV_ON_ERROR_REPORT, BLOCK_JOB_INTERNAL,
@ -295,7 +292,7 @@ index 1c41d9e6bf..60c6524417 100644
if (local_err) {
error_propagate(errp, local_err);
diff --git a/blockdev.c b/blockdev.c
index 534c00f5da..19a82e8774 100644
index 3ffd064c48..4b6091afc6 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -31,7 +31,6 @@
@ -314,37 +311,7 @@ index 534c00f5da..19a82e8774 100644
static QTAILQ_HEAD(, BlockDriverState) monitor_bdrv_states =
QTAILQ_HEAD_INITIALIZER(monitor_bdrv_states);
@@ -2934,20 +2934,44 @@ out:
aio_context_release(aio_context);
}
+void block_job_event_cancelled(BlockJob *job);
+void block_job_event_completed(BlockJob *job, const char *msg);
+static void block_job_cb(void *opaque, int ret)
+{
+ /* Note that this function may be executed from another AioContext besides
+ * the QEMU main loop. If you need to access anything that assumes the
+ * QEMU global mutex, use a BH or introduce a mutex.
+ */
+
+ BlockDriverState *bs = opaque;
+ const char *msg = NULL;
+
+ assert(bs->job);
+
+ if (ret < 0) {
+ msg = strerror(-ret);
+ }
+
+ if (block_job_is_cancelled(bs->job)) {
+ block_job_event_cancelled(bs->job);
+ } else {
+ block_job_event_completed(bs->job, msg);
+ }
+}
+
/* PVE backup related function */
@@ -2970,15 +2970,14 @@ out:
static struct PVEBackupState {
Error *error;
bool cancel;
@ -362,45 +329,37 @@ index 534c00f5da..19a82e8774 100644
size_t total;
size_t transferred;
size_t zero_bytes;
@@ -2957,6 +2981,7 @@ typedef struct PVEBackupDevInfo {
BlockDriverState *bs;
size_t size;
uint8_t dev_id;
+ //bool started;
bool completed;
char targetfile[PATH_MAX];
BlockDriverState *target;
@@ -2964,13 +2989,79 @@ typedef struct PVEBackupDevInfo {
@@ -2997,6 +2996,71 @@ typedef struct PVEBackupDevInfo {
static void pvebackup_run_next_job(void);
+static int pvebackup_dump_cb(void *opaque, BlockBackend *target,
+ int64_t sector_num, int n_sectors,
+ unsigned char *buf)
+ uint64_t start, uint64_t bytes,
+ const void *pbuf)
+{
+ const uint64_t size = bytes;
+ const unsigned char *buf = pbuf;
+ PVEBackupDevInfo *di = opaque;
+
+ int size = n_sectors * BDRV_SECTOR_SIZE;
+ if (backup_state.cancel) {
+ return size; // return success
+ }
+
+ if (sector_num & 0x7f) {
+ uint64_t cluster_num = start / VMA_CLUSTER_SIZE;
+ if ((cluster_num * VMA_CLUSTER_SIZE) != start) {
+ if (!backup_state.error) {
+ error_setg(&backup_state.error,
+ "got unaligned write inside backup dump "
+ "callback (sector %ld)", sector_num);
+ "callback (sector %ld)", start);
+ }
+ return -1; // not aligned to cluster size
+ }
+
+ int64_t cluster_num = sector_num >> 7;
+
+ int ret = -1;
+
+ if (backup_state.vmaw) {
+ size_t zero_bytes = 0;
+ int64_t remaining = n_sectors * BDRV_SECTOR_SIZE;
+ uint64_t remaining = size;
+ while (remaining > 0) {
+ ret = vma_writer_write(backup_state.vmaw, di->dev_id, cluster_num,
+ buf, &zero_bytes);
@ -420,10 +379,11 @@ index 534c00f5da..19a82e8774 100644
+ backup_state.zero_bytes += zero_bytes;
+ if (remaining >= VMA_CLUSTER_SIZE) {
+ backup_state.transferred += VMA_CLUSTER_SIZE;
+ remaining -= VMA_CLUSTER_SIZE;
+ } else {
+ backup_state.transferred += remaining;
+ remaining = 0;
+ }
+ remaining -= VMA_CLUSTER_SIZE;
+ }
+ }
+ } else {
@ -440,6 +400,9 @@ index 534c00f5da..19a82e8774 100644
+
static void pvebackup_cleanup(void)
{
qemu_mutex_lock(&backup_state.backup_mutex);
@@ -3008,9 +3072,11 @@ static void pvebackup_cleanup(void)
backup_state.end_time = time(NULL);
- if (backup_state.vmaobj) {
@ -452,9 +415,9 @@ index 534c00f5da..19a82e8774 100644
+ backup_state.vmaw = NULL;
}
if (backup_state.di_list) {
@@ -2985,6 +3076,13 @@ static void pvebackup_cleanup(void)
}
g_list_free(backup_state.di_list);
@@ -3018,6 +3084,13 @@ static void pvebackup_cleanup(void)
qemu_mutex_unlock(&backup_state.backup_mutex);
}
+static void coroutine_fn backup_close_vma_stream(void *opaque)
@ -466,13 +429,8 @@ index 534c00f5da..19a82e8774 100644
+
static void pvebackup_complete_cb(void *opaque, int ret)
{
PVEBackupDevInfo *di = opaque;
@@ -2996,14 +3094,18 @@ static void pvebackup_complete_cb(void *opaque, int ret)
ret, strerror(-ret));
}
+ BlockDriverState *bs = di->bs;
+
// This always runs in the main loop
@@ -3034,9 +3107,9 @@ static void pvebackup_complete_cb(void *opaque, int ret)
di->bs = NULL;
di->target = NULL;
@ -484,12 +442,8 @@ index 534c00f5da..19a82e8774 100644
+ qemu_coroutine_enter(co);
}
+ block_job_cb(bs, ret);
+
if (!backup_state.cancel) {
pvebackup_run_next_job();
}
@@ -3017,14 +3119,9 @@ static void pvebackup_cancel(void *opaque)
// remove self from job queue
@@ -3064,14 +3137,9 @@ static void pvebackup_cancel(void *opaque)
error_setg(&backup_state.error, "backup cancelled");
}
@ -506,7 +460,7 @@ index 534c00f5da..19a82e8774 100644
}
GList *l = backup_state.di_list;
@@ -3049,19 +3146,15 @@ void qmp_backup_cancel(Error **errp)
@@ -3102,18 +3170,14 @@ void qmp_backup_cancel(Error **errp)
Coroutine *co = qemu_coroutine_create(pvebackup_cancel, NULL);
qemu_coroutine_enter(co);
@ -524,44 +478,33 @@ index 534c00f5da..19a82e8774 100644
static int config_to_vma(const char *file, BackupFormat format,
- Object *vmaobj,
- const char *backup_dir,
- Error **errp)
+ const char *backup_dir, VmaWriter *vmaw,
+ Error **errp)
+ const char *backup_dir, VmaWriter *vmaw,
Error **errp)
{
char *cdata = NULL;
gsize clen = 0;
@@ -3074,12 +3167,17 @@ static int config_to_vma(const char *file, BackupFormat format,
char *basename = g_path_get_basename(file);
char *cdata = NULL;
@@ -3127,7 +3191,12 @@ static int config_to_vma(const char *file, BackupFormat format,
char *basename = g_path_get_basename(file);
if (format == BACKUP_FORMAT_VMA) {
- vma_object_add_config_file(vmaobj, basename, cdata, clen, errp);
+ if (vma_writer_add_config(vmaw, basename, cdata, clen) != 0) {
+ error_setg(errp, "unable to add %s config data to vma archive", file);
+ g_free(cdata);
+ g_free(basename);
+ return 1;
+ }
} else if (format == BACKUP_FORMAT_DIR) {
char config_path[PATH_MAX];
snprintf(config_path, PATH_MAX, "%s/%s", backup_dir, basename);
if (!g_file_set_contents(config_path, cdata, clen, &err)) {
- error_setg(errp, "unable to write config file '%s'", config_path);
+ error_setg(errp, "unable to write config file '%s'", config_path);
g_free(cdata);
g_free(basename);
return 1;
@@ -3089,34 +3187,37 @@ static int config_to_vma(const char *file, BackupFormat format,
g_free(basename);
g_free(cdata);
- return 0;
+ return 0;
if (format == BACKUP_FORMAT_VMA) {
- vma_object_add_config_file(vmaobj, basename, cdata, clen, errp);
+ if (vma_writer_add_config(vmaw, basename, cdata, clen) != 0) {
+ error_setg(errp, "unable to add %s config data to vma archive", file);
+ g_free(cdata);
+ g_free(basename);
+ return 1;
+ }
} else if (format == BACKUP_FORMAT_DIR) {
char config_path[PATH_MAX];
snprintf(config_path, PATH_MAX, "%s/%s", backup_dir, basename);
@@ -3145,28 +3214,30 @@ static int config_to_vma(const char *file, BackupFormat format,
}
void block_job_resume(BlockJob *job);
+bool block_job_should_pause(BlockJob *job);
static void pvebackup_run_next_job(void)
{
- bool cancel = backup_state.error || backup_state.cancel;
qemu_mutex_lock(&backup_state.backup_mutex);
- GList *next = g_list_nth(backup_state.di_list, backup_state.next_job);
- while (next) {
- PVEBackupDevInfo *di = (PVEBackupDevInfo *)next->data;
@ -572,26 +515,28 @@ index 534c00f5da..19a82e8774 100644
+ l = g_list_next(l);
if (!di->completed && di->bs && di->bs->job) {
BlockJob *job = di->bs->job;
- if (cancel) {
- block_job_cancel(job);
AioContext *aio_context = blk_get_aio_context(job->blk);
aio_context_acquire(aio_context);
qemu_mutex_unlock(&backup_state.backup_mutex);
- if (backup_state.error || backup_state.cancel) {
- block_job_cancel_sync(job);
- } else {
- block_job_resume(job);
+ if (block_job_should_pause(job)) {
+ bool cancel = backup_state.error || backup_state.cancel;
+ if (cancel) {
+ block_job_cancel(job);
+ if (backup_state.error || backup_state.cancel) {
+ block_job_cancel_sync(job);
+ } else {
+ block_job_resume(job);
+ }
}
aio_context_release(aio_context);
return;
}
- next = g_list_next(next);
}
+
pvebackup_cleanup();
}
qemu_mutex_unlock(&backup_state.backup_mutex);
@@ -3177,7 +3248,7 @@ static void pvebackup_run_next_job(void)
UuidInfo *qmp_backup(const char *backup_file, bool has_format,
BackupFormat format,
bool has_config_file, const char *config_file,
@ -600,7 +545,7 @@ index 534c00f5da..19a82e8774 100644
bool has_devlist, const char *devlist,
bool has_speed, int64_t speed, Error **errp)
{
@@ -3124,14 +3225,15 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
@@ -3185,7 +3256,8 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
BlockDriverState *bs = NULL;
const char *backup_dir = NULL;
Error *local_err = NULL;
@ -610,15 +555,16 @@ index 534c00f5da..19a82e8774 100644
gchar **devs = NULL;
GList *di_list = NULL;
GList *l;
UuidInfo *uuid_info;
BlockJob *job;
@@ -3197,7 +3269,7 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
backup_state.backup_mutex_initialized = true;
}
- if (backup_state.di_list || backup_state.vmaobj) {
+ if (backup_state.di_list) {
error_set(errp, ERROR_CLASS_GENERIC_ERROR,
"previous backup not finished");
return NULL;
@@ -3206,40 +3308,28 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
@@ -3272,40 +3344,28 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
total += size;
}
@ -667,27 +613,24 @@ index 534c00f5da..19a82e8774 100644
goto err;
}
}
@@ -3280,15 +3370,15 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
@@ -3346,14 +3406,14 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
/* add configuration file to archive */
if (has_config_file) {
- if(config_to_vma(config_file, format, backup_state.vmaobj, backup_dir, errp) != 0) {
- goto err;
+ if(config_to_vma(config_file, format, backup_dir, vmaw, errp) != 0) {
+ goto err;
}
- if(config_to_vma(config_file, format, backup_state.vmaobj, backup_dir, errp) != 0) {
+ if (config_to_vma(config_file, format, backup_dir, vmaw, errp) != 0) {
goto err;
}
}
/* add firewall file to archive */
if (has_firewall_file) {
- if(config_to_vma(firewall_file, format, backup_state.vmaobj, backup_dir, errp) != 0) {
- goto err;
+ if(config_to_vma(firewall_file, format, backup_dir, vmaw, errp) != 0) {
+ goto err;
}
- if(config_to_vma(firewall_file, format, backup_state.vmaobj, backup_dir, errp) != 0) {
+ if (config_to_vma(firewall_file, format, backup_dir, vmaw, errp) != 0) {
goto err;
}
}
/* initialize global backup_state now */
@@ -3310,11 +3400,12 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
@@ -3376,12 +3436,13 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
}
backup_state.backup_file = g_strdup(backup_file);
@ -698,12 +641,13 @@ index 534c00f5da..19a82e8774 100644
+ uuid_copy(backup_state.uuid, uuid);
+ uuid_unparse_lower(uuid, backup_state.uuid_str);
qemu_mutex_lock(&backup_state.backup_mutex);
backup_state.di_list = di_list;
- backup_state.next_job = 0;
backup_state.total = total;
backup_state.transferred = 0;
@@ -3325,21 +3416,16 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
@@ -3392,21 +3453,16 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
while (l) {
PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data;
l = g_list_next(l);
@ -727,8 +671,8 @@ index 534c00f5da..19a82e8774 100644
+ block_job_start(job);
}
if (!backup_state.error) {
@@ -3373,9 +3459,10 @@ err:
qemu_mutex_unlock(&backup_state.backup_mutex);
@@ -3442,9 +3498,10 @@ err:
g_strfreev(devs);
}
@ -742,7 +686,7 @@ index 534c00f5da..19a82e8774 100644
}
if (backup_dir) {
@@ -3760,7 +3847,7 @@ static BlockJob *do_drive_backup(DriveBackup *backup, BlockJobTxn *txn,
@@ -3829,7 +3886,7 @@ static BlockJob *do_drive_backup(DriveBackup *backup, BlockJobTxn *txn,
job = backup_job_create(backup->job_id, bs, target_bs, backup->speed,
backup->sync, bmap, backup->compress,
backup->on_source_error, backup->on_target_error,
@ -751,7 +695,7 @@ index 534c00f5da..19a82e8774 100644
bdrv_unref(target_bs);
if (local_err != NULL) {
error_propagate(errp, local_err);
@@ -3839,7 +3926,7 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, BlockJobTxn *txn,
@@ -3908,7 +3965,7 @@ BlockJob *do_blockdev_backup(BlockdevBackup *backup, BlockJobTxn *txn,
job = backup_job_create(backup->job_id, bs, target_bs, backup->speed,
backup->sync, NULL, backup->compress,
backup->on_source_error, backup->on_target_error,
@ -761,22 +705,11 @@ index 534c00f5da..19a82e8774 100644
error_propagate(errp, local_err);
}
diff --git a/blockjob.c b/blockjob.c
index 764d41863e..cb3741f6dd 100644
index 2de9f8f4dd..1df33bd194 100644
--- a/blockjob.c
+++ b/blockjob.c
@@ -37,8 +37,8 @@
#include "qemu/timer.h"
#include "qapi-event.h"
-static void block_job_event_cancelled(BlockJob *job);
-static void block_job_event_completed(BlockJob *job, const char *msg);
+void block_job_event_cancelled(BlockJob *job);
+void block_job_event_completed(BlockJob *job, const char *msg);
/* Transactional group of block jobs */
struct BlockJobTxn {
@@ -473,7 +473,8 @@ void block_job_user_pause(BlockJob *job)
block_job_pause(job);
@@ -757,7 +757,8 @@ void block_job_completed(BlockJob *job, int ret)
}
}
-static bool block_job_should_pause(BlockJob *job)
@ -785,39 +718,21 @@ index 764d41863e..cb3741f6dd 100644
{
return job->pause_count > 0;
}
@@ -687,7 +688,7 @@ static void block_job_iostatus_set_err(BlockJob *job, int error)
}
}
-static void block_job_event_cancelled(BlockJob *job)
+void block_job_event_cancelled(BlockJob *job)
{
if (block_job_is_internal(job)) {
return;
@@ -701,7 +702,7 @@ static void block_job_event_cancelled(BlockJob *job)
&error_abort);
}
-static void block_job_event_completed(BlockJob *job, const char *msg)
+void block_job_event_completed(BlockJob *job, const char *msg)
{
if (block_job_is_internal(job)) {
return;
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 19b84b027f..fc1c53a059 100644
index 1dbbdafd31..2ed3e41437 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -59,6 +59,9 @@
@@ -60,6 +60,9 @@
#define BLOCK_PROBE_BUF_SIZE 512
+typedef int BackupDumpFunc(void *opaque, BlockBackend *be,
+ int64_t sector_num, int n_sectors, unsigned char *buf);
+ uint64_t offset, uint64_t bytes, const void *buf);
+
enum BdrvTrackedRequestType {
BDRV_TRACKED_READ,
BDRV_TRACKED_WRITE,
@@ -878,6 +881,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
@@ -984,6 +987,7 @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
BlockdevOnError on_source_error,
BlockdevOnError on_target_error,
int creation_flags,
@ -1690,7 +1605,7 @@ index 0000000000..2000889bd3
+
diff --git a/vma-writer.c b/vma-writer.c
new file mode 100644
index 0000000000..9001cbdd2b
index 0000000000..fd9567634d
--- /dev/null
+++ b/vma-writer.c
@@ -0,0 +1,771 @@
@ -2279,7 +2194,7 @@ index 0000000000..9001cbdd2b
+
+int64_t coroutine_fn
+vma_writer_write(VmaWriter *vmaw, uint8_t dev_id, int64_t cluster_num,
+ unsigned char *buf, size_t *zero_bytes)
+ const unsigned char *buf, size_t *zero_bytes)
+{
+ g_assert(vmaw != NULL);
+ g_assert(zero_bytes != NULL);
@ -2335,7 +2250,7 @@ index 0000000000..9001cbdd2b
+ int i;
+ int bit = 1;
+ for (i = 0; i < 16; i++) {
+ unsigned char *vmablock = buf + (i*VMA_BLOCK_SIZE);
+ const unsigned char *vmablock = buf + (i*VMA_BLOCK_SIZE);
+ if (!buffer_is_zero(vmablock, VMA_BLOCK_SIZE)) {
+ mask |= bit;
+ memcpy(vmaw->outbuf + vmaw->outbuf_pos, vmablock,
@ -2467,10 +2382,10 @@ index 0000000000..9001cbdd2b
+}
diff --git a/vma.c b/vma.c
new file mode 100644
index 0000000000..04915427c8
index 0000000000..1b59fd1555
--- /dev/null
+++ b/vma.c
@@ -0,0 +1,757 @@
@@ -0,0 +1,756 @@
+/*
+ * VMA: Virtual Machine Archive
+ *
@ -2492,7 +2407,6 @@ index 0000000000..04915427c8
+#include "qemu/error-report.h"
+#include "qemu/main-loop.h"
+#include "qapi/qmp/qstring.h"
+#include "sysemu/char.h" /* qstring_from_str */
+#include "sysemu/block-backend.h"
+
+static void help(void)
@ -2772,7 +2686,7 @@ index 0000000000..04915427c8
+ printf("DEVINFO %s %zd\n", devfn, di->size);
+
+ bdrv_img_create(devfn, "raw", NULL, NULL, NULL, di->size,
+ flags, &errp, 0);
+ flags, true, &errp);
+ if (errp) {
+ g_error("can't create file %s: %s", devfn,
+ error_get_pretty(errp));
@ -3230,10 +3144,10 @@ index 0000000000..04915427c8
+}
diff --git a/vma.h b/vma.h
new file mode 100644
index 0000000000..fa6f4df7e7
index 0000000000..c895c97f6d
--- /dev/null
+++ b/vma.h
@@ -0,0 +1,149 @@
@@ -0,0 +1,150 @@
+/*
+ * VMA: Virtual Machine Archive
+ *
@ -3360,7 +3274,8 @@ index 0000000000..fa6f4df7e7
+ size_t size);
+
+int64_t coroutine_fn vma_writer_write(VmaWriter *vmaw, uint8_t dev_id,
+ int64_t cluster_num, unsigned char *buf,
+ int64_t cluster_num,
+ const unsigned char *buf,
+ size_t *zero_bytes);
+
+int coroutine_fn vma_writer_close_stream(VmaWriter *vmaw, uint8_t dev_id);

View File

@ -1,253 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Tue, 5 Dec 2017 12:12:15 +0100
Subject: [PATCH] backup: fix race in backup-stop command
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
---
blockdev.c | 90 +++++++++++++++++++++++++++++++++-----------------------------
blockjob.c | 8 +++---
2 files changed, 52 insertions(+), 46 deletions(-)
diff --git a/blockdev.c b/blockdev.c
index 19a82e8774..d3490936d8 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2934,31 +2934,6 @@ out:
aio_context_release(aio_context);
}
-void block_job_event_cancelled(BlockJob *job);
-void block_job_event_completed(BlockJob *job, const char *msg);
-static void block_job_cb(void *opaque, int ret)
-{
- /* Note that this function may be executed from another AioContext besides
- * the QEMU main loop. If you need to access anything that assumes the
- * QEMU global mutex, use a BH or introduce a mutex.
- */
-
- BlockDriverState *bs = opaque;
- const char *msg = NULL;
-
- assert(bs->job);
-
- if (ret < 0) {
- msg = strerror(-ret);
- }
-
- if (block_job_is_cancelled(bs->job)) {
- block_job_event_cancelled(bs->job);
- } else {
- block_job_event_completed(bs->job, msg);
- }
-}
-
/* PVE backup related function */
static struct PVEBackupState {
@@ -2975,6 +2950,8 @@ static struct PVEBackupState {
size_t total;
size_t transferred;
size_t zero_bytes;
+ QemuMutex backup_mutex;
+ bool backup_mutex_initialized;
} backup_state;
typedef struct PVEBackupDevInfo {
@@ -3055,6 +3032,13 @@ static int pvebackup_dump_cb(void *opaque, BlockBackend *target,
static void pvebackup_cleanup(void)
{
+ qemu_mutex_lock(&backup_state.backup_mutex);
+ // Avoid race between block jobs and backup-cancel command:
+ if (!backup_state.vmaw) {
+ qemu_mutex_unlock(&backup_state.backup_mutex);
+ return;
+ }
+
backup_state.end_time = time(NULL);
if (backup_state.vmaw) {
@@ -3064,16 +3048,9 @@ static void pvebackup_cleanup(void)
backup_state.vmaw = NULL;
}
- if (backup_state.di_list) {
- GList *l = backup_state.di_list;
- while (l) {
- PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data;
- l = g_list_next(l);
- g_free(di);
- }
- g_list_free(backup_state.di_list);
- backup_state.di_list = NULL;
- }
+ g_list_free(backup_state.di_list);
+ backup_state.di_list = NULL;
+ qemu_mutex_unlock(&backup_state.backup_mutex);
}
static void coroutine_fn backup_close_vma_stream(void *opaque)
@@ -3085,6 +3062,8 @@ static void coroutine_fn backup_close_vma_stream(void *opaque)
static void pvebackup_complete_cb(void *opaque, int ret)
{
+ // This always runs in the main loop
+
PVEBackupDevInfo *di = opaque;
di->completed = true;
@@ -3094,8 +3073,6 @@ static void pvebackup_complete_cb(void *opaque, int ret)
ret, strerror(-ret));
}
- BlockDriverState *bs = di->bs;
-
di->bs = NULL;
di->target = NULL;
@@ -3104,7 +3081,11 @@ static void pvebackup_complete_cb(void *opaque, int ret)
qemu_coroutine_enter(co);
}
- block_job_cb(bs, ret);
+ // remove self from job queue
+ qemu_mutex_lock(&backup_state.backup_mutex);
+ backup_state.di_list = g_list_remove(backup_state.di_list, di);
+ g_free(di);
+ qemu_mutex_unlock(&backup_state.backup_mutex);
if (!backup_state.cancel) {
pvebackup_run_next_job();
@@ -3114,6 +3095,12 @@ static void pvebackup_complete_cb(void *opaque, int ret)
static void pvebackup_cancel(void *opaque)
{
backup_state.cancel = true;
+ qemu_mutex_lock(&backup_state.backup_mutex);
+ // Avoid race between block jobs and backup-cancel command:
+ if (!backup_state.vmaw) {
+ qemu_mutex_unlock(&backup_state.backup_mutex);
+ return;
+ }
if (!backup_state.error) {
error_setg(&backup_state.error, "backup cancelled");
@@ -3131,13 +3118,17 @@ static void pvebackup_cancel(void *opaque)
if (!di->completed && di->bs) {
BlockJob *job = di->bs->job;
if (job) {
+ AioContext *aio_context = blk_get_aio_context(job->blk);
+ aio_context_acquire(aio_context);
if (!di->completed) {
- block_job_cancel_sync(job);
+ block_job_cancel(job);
}
+ aio_context_release(aio_context);
}
}
}
+ qemu_mutex_unlock(&backup_state.backup_mutex);
pvebackup_cleanup();
}
@@ -3193,24 +3184,31 @@ static int config_to_vma(const char *file, BackupFormat format,
bool block_job_should_pause(BlockJob *job);
static void pvebackup_run_next_job(void)
{
+ qemu_mutex_lock(&backup_state.backup_mutex);
+
GList *l = backup_state.di_list;
while (l) {
PVEBackupDevInfo *di = (PVEBackupDevInfo *)l->data;
l = g_list_next(l);
if (!di->completed && di->bs && di->bs->job) {
BlockJob *job = di->bs->job;
+ AioContext *aio_context = blk_get_aio_context(job->blk);
+ aio_context_acquire(aio_context);
+ qemu_mutex_unlock(&backup_state.backup_mutex);
if (block_job_should_pause(job)) {
- bool cancel = backup_state.error || backup_state.cancel;
- if (cancel) {
- block_job_cancel(job);
+ if (backup_state.error || backup_state.cancel) {
+ block_job_cancel_sync(job);
} else {
block_job_resume(job);
}
}
+ aio_context_release(aio_context);
return;
}
}
+ qemu_mutex_unlock(&backup_state.backup_mutex);
+ // no more jobs, run the cleanup
pvebackup_cleanup();
}
@@ -3233,6 +3231,11 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
UuidInfo *uuid_info;
BlockJob *job;
+ if (!backup_state.backup_mutex_initialized) {
+ qemu_mutex_init(&backup_state.backup_mutex);
+ backup_state.backup_mutex_initialized = true;
+ }
+
if (backup_state.di_list) {
error_set(errp, ERROR_CLASS_GENERIC_ERROR,
"previous backup not finished");
@@ -3405,6 +3408,7 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
uuid_copy(backup_state.uuid, uuid);
uuid_unparse_lower(uuid, backup_state.uuid_str);
+ qemu_mutex_lock(&backup_state.backup_mutex);
backup_state.di_list = di_list;
backup_state.total = total;
@@ -3428,6 +3432,8 @@ UuidInfo *qmp_backup(const char *backup_file, bool has_format,
block_job_start(job);
}
+ qemu_mutex_unlock(&backup_state.backup_mutex);
+
if (!backup_state.error) {
pvebackup_run_next_job(); // run one job
}
diff --git a/blockjob.c b/blockjob.c
index cb3741f6dd..199d5852db 100644
--- a/blockjob.c
+++ b/blockjob.c
@@ -37,8 +37,8 @@
#include "qemu/timer.h"
#include "qapi-event.h"
-void block_job_event_cancelled(BlockJob *job);
-void block_job_event_completed(BlockJob *job, const char *msg);
+static void block_job_event_cancelled(BlockJob *job);
+static void block_job_event_completed(BlockJob *job, const char *msg);
/* Transactional group of block jobs */
struct BlockJobTxn {
@@ -688,7 +688,7 @@ static void block_job_iostatus_set_err(BlockJob *job, int error)
}
}
-void block_job_event_cancelled(BlockJob *job)
+static void block_job_event_cancelled(BlockJob *job)
{
if (block_job_is_internal(job)) {
return;
@@ -702,7 +702,7 @@ void block_job_event_cancelled(BlockJob *job)
&error_abort);
}
-void block_job_event_completed(BlockJob *job, const char *msg)
+static void block_job_event_completed(BlockJob *job, const char *msg)
{
if (block_job_is_internal(job)) {
return;
--
2.11.0

View File

@ -1,165 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Wolfgang Bumiller <w.bumiller@proxmox.com>
Date: Thu, 15 Feb 2018 11:07:56 +0100
Subject: [PATCH] vma: add throttling options to drive mapping fifo protocol
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
---
vma.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 73 insertions(+), 9 deletions(-)
diff --git a/vma.c b/vma.c
index 04915427c8..91ae14cdc3 100644
--- a/vma.c
+++ b/vma.c
@@ -18,7 +18,9 @@
#include "qemu-common.h"
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
+#include "qemu/cutils.h"
#include "qapi/qmp/qstring.h"
+#include "qapi/qmp/qint.h"
#include "sysemu/char.h" /* qstring_from_str */
#include "sysemu/block-backend.h"
@@ -133,9 +135,39 @@ typedef struct RestoreMap {
char *devname;
char *path;
char *format;
+ uint64_t throttling_bps;
+ char *throttling_group;
bool write_zero;
} RestoreMap;
+static bool try_parse_option(char **line, const char *optname, char **out, const char *inbuf) {
+ size_t optlen = strlen(optname);
+ if (strncmp(*line, optname, optlen) != 0 || (*line)[optlen] != '=') {
+ return false;
+ }
+ if (*out) {
+ g_error("read map failed - duplicate value for option '%s'", optname);
+ }
+ char *value = (*line) + optlen + 1; /* including a '=' */
+ char *colon = strchr(value, ':');
+ if (!colon) {
+ g_error("read map failed - option '%s' not terminated ('%s')",
+ optname, inbuf);
+ }
+ *line = colon+1;
+ *out = g_strndup(value, colon - value);
+ return true;
+}
+
+static uint64_t verify_u64(const char *text) {
+ uint64_t value;
+ const char *endptr = NULL;
+ if (qemu_strtou64(text, &endptr, 0, &value) != 0 || !endptr || *endptr) {
+ g_error("read map failed - not a number: %s", text);
+ }
+ return value;
+}
+
static int extract_content(int argc, char **argv)
{
int c, ret = 0;
@@ -209,6 +241,9 @@ static int extract_content(int argc, char **argv)
while (1) {
char inbuf[8192];
char *line = fgets(inbuf, sizeof(inbuf), map);
+ char *format = NULL;
+ char *bps = NULL;
+ char *group = NULL;
if (!line || line[0] == '\0' || !strcmp(line, "done\n")) {
break;
}
@@ -220,15 +255,19 @@ static int extract_content(int argc, char **argv)
}
}
- char *format = NULL;
- if (strncmp(line, "format=", sizeof("format=")-1) == 0) {
- format = line + sizeof("format=")-1;
- char *colon = strchr(format, ':');
- if (!colon) {
- g_error("read map failed - found only a format ('%s')", inbuf);
+ while (1) {
+ if (!try_parse_option(&line, "format", &format, inbuf) &&
+ !try_parse_option(&line, "throttling.bps", &bps, inbuf) &&
+ !try_parse_option(&line, "throttling.group", &group, inbuf))
+ {
+ break;
}
- format = g_strndup(format, colon - format);
- line = colon+1;
+ }
+
+ uint64_t bps_value = 0;
+ if (bps) {
+ bps_value = verify_u64(bps);
+ g_free(bps);
}
const char *path;
@@ -254,6 +293,8 @@ static int extract_content(int argc, char **argv)
map->devname = g_strdup(devname);
map->path = g_strdup(path);
map->format = format;
+ map->throttling_bps = bps_value;
+ map->throttling_group = group;
map->write_zero = write_zero;
g_hash_table_insert(devmap, map->devname, map);
@@ -281,6 +322,8 @@ static int extract_content(int argc, char **argv)
} else if (di) {
char *devfn = NULL;
const char *format = NULL;
+ uint64_t throttling_bps = 0;
+ const char *throttling_group = NULL;
int flags = BDRV_O_RDWR | BDRV_O_NO_FLUSH;
bool write_zero = true;
@@ -292,6 +335,8 @@ static int extract_content(int argc, char **argv)
}
devfn = map->path;
format = map->format;
+ throttling_bps = map->throttling_bps;
+ throttling_group = map->throttling_group;
write_zero = map->write_zero;
} else {
devfn = g_strdup_printf("%s/tmp-disk-%s.raw",
@@ -328,12 +373,31 @@ static int extract_content(int argc, char **argv)
qdict_put(options, "driver", qstring_from_str("raw"));
}
-
if (errp || !(blk = blk_new_open(devfn, NULL, options, flags, &errp))) {
g_error("can't open file %s - %s", devfn,
error_get_pretty(errp));
}
+ if (throttling_group) {
+ blk_io_limits_enable(blk, throttling_group);
+ }
+
+ if (throttling_bps) {
+ if (!throttling_group) {
+ blk_io_limits_enable(blk, devfn);
+ }
+
+ ThrottleConfig cfg;
+ throttle_config_init(&cfg);
+ cfg.buckets[THROTTLE_BPS_WRITE].avg = throttling_bps;
+ Error *err = NULL;
+ if (!throttle_is_valid(&cfg, &err)) {
+ error_report_err(err);
+ g_error("failed to apply throttling");
+ }
+ blk_set_io_limits(blk, &cfg);
+ }
+
if (vma_reader_register_bs(vmar, i, blk, write_zero, &errp) < 0) {
g_error("%s", error_get_pretty(errp));
}
--
2.11.0

74
debian/patches/series vendored
View File

@ -1,4 +1,4 @@
pve/0001-fr-ca-keymap-corrections.patch
pve/0001-block-file-change-locking-default-to-off.patch
pve/0002-Adjust-network-script-path-to-etc-kvm.patch
pve/0003-qemu-img-return-success-on-info-without-snapshots.patch
pve/0004-use-kvm-by-default.patch
@ -15,65 +15,15 @@ pve/0014-use-whitespace-between-VERSION-and-PKGVERSION.patch
pve/0015-vnc-altgr-emulation.patch
pve/0016-vnc-make-x509-imply-tls-again.patch
pve/0017-vnc-PVE-VNC-authentication.patch
pve/0018-migrate-fix-possible-unitialised-return-value.patch
pve/0019-block-rbd-disable-rbd_cache_writethrough_until_flush.patch
pve/0020-block-snapshot-qmp_snapshot_drive-add-aiocontext.patch
pve/0021-block-snapshot-qmp_delete_drive_snapshot-add-aiocont.patch
pve/0022-glusterfs-no-default-logfile-if-daemonized.patch
pve/0023-glusterfs-allow-partial-reads.patch
pve/0024-block-add-the-zeroinit-block-driver-filter.patch
pve/0025-qemu-img-dd-add-osize-and-read-from-to-stdin-stdout.patch
pve/0026-backup-modify-job-api.patch
pve/0027-backup-introduce-vma-archive-format.patch
pve/0028-adding-old-vma-files.patch
pve/0029-backup-fix-race-in-backup-stop-command.patch
pve/0030-vma-add-throttling-options-to-drive-mapping-fifo-pro.patch
pve/0018-block-rbd-disable-rbd_cache_writethrough_until_flush.patch
pve/0019-block-snapshot-qmp_snapshot_drive-add-aiocontext.patch
pve/0020-block-snapshot-qmp_delete_drive_snapshot-add-aiocont.patch
pve/0021-glusterfs-no-default-logfile-if-daemonized.patch
pve/0022-glusterfs-allow-partial-reads.patch
pve/0023-block-add-the-zeroinit-block-driver-filter.patch
pve/0024-qemu-img-dd-add-osize-and-read-from-to-stdin-stdout.patch
pve/0025-backup-modify-job-api.patch
pve/0026-backup-introduce-vma-archive-format.patch
pve/0027-adding-old-vma-files.patch
extra/0001-Revert-target-i386-disable-LINT0-after-reset.patch
extra/0002-virtio-serial-fix-segfault-on-disconnect.patch
extra/0003-megasas-always-store-SCSIRequest-into-MegasasCmd.patch
extra/0004-slirp-check-len-against-dhcp-options-array-end.patch
extra/0005-IDE-Do-not-flush-empty-CDROM-drives.patch
extra/0006-bitmap-add-bitmap_copy_and_clear_atomic.patch
extra/0007-memory-add-support-getting-and-using-a-dirty-bitmap-.patch
extra/0008-vga-add-vga_scanline_invalidated-helper.patch
extra/0009-vga-make-display-updates-thread-safe.patch
extra/0010-vga-fix-display-update-region-calculation.patch
extra/0011-vga-fix-display-update-region-calculation-split-scre.patch
extra/0012-vga-stop-passing-pointers-to-vga_draw_line-functions.patch
extra/0013-multiboot-validate-multiboot-header-address-values.patch
extra/0014-virtio-fix-descriptor-counting-in-virtqueue_pop.patch
extra/0015-nbd-server-CVE-2017-15119-Reject-options-larger-than.patch
extra/0016-vga-migration-Update-memory-map-in-post_load.patch
extra/0017-vga-drop-line_offset-variable.patch
extra/0018-vga-handle-cirrus-vbe-mode-wraparounds.patch
extra/0019-vga-add-ram_addr_t-cast.patch
extra/0020-vga-fix-region-checks-in-wraparound-case.patch
extra/0021-io-monitor-encoutput-buffer-size-from-websocket-GSou.patch
extra/0022-9pfs-use-g_malloc0-to-allocate-space-for-xattr.patch
extra/0023-cirrus-fix-oob-access-in-mode4and5-write-functions.patch
extra/0024-virtio-check-VirtQueue-Vring-object-is-set.patch
extra/0025-block-gluster-glfs_lseek-workaround.patch
extra/0026-gluster-add-support-for-PREALLOC_MODE_FALLOC.patch
extra/0027-target-i386-Use-host_vendor_fms-in-max_x86_cpu_initf.patch
extra/0028-target-i386-Define-CPUID_MODEL_ID_SZ-macro.patch
extra/0029-target-i386-Don-t-use-x86_cpu_load_def-on-max-CPU-mo.patch
extra/0030-i386-Change-X86CPUDefinition-model_id-to-const-char.patch
extra/0031-i386-Add-support-for-SPEC_CTRL-MSR.patch
extra/0032-i386-Add-spec-ctrl-CPUID-bit.patch
extra/0033-i386-Add-FEAT_8000_0008_EBX-CPUID-feature-word.patch
extra/0034-i386-Add-new-IBRS-versions-of-Intel-CPU-models.patch
extra/0035-ratelimit-don-t-align-wait-time-with-slices.patch
extra/0036-nbd-make-it-thread-safe-fix-qcow2-over-nbd.patch
extra/0037-nbd-strict-nbd_wr_syncv.patch
extra/0038-nbd-read_sync-and-friends-return-0-on-success.patch
extra/0039-nbd-make-nbd_drop-public.patch
extra/0040-nbd-server-get-rid-of-nbd_negotiate_read-and-friends.patch
extra/0041-nbd-client-Fix-regression-when-server-sends-garbage.patch
extra/0042-fix-build-failure-in-nbd_read_reply_entry.patch
extra/0043-nbd-client-avoid-spurious-qio_channel_yield-re-entry.patch
extra/0044-nbd-client-avoid-read_reply_co-entry-if-send-failed.patch
extra/0045-qemu-iotests-improve-nbd-fault-injector.py-startup-p.patch
extra/0046-qemu-iotests-test-NBD-over-UNIX-domain-sockets-in-08.patch
extra/0047-block-nbd-client-nbd_co_send_request-fix-return-code.patch
extra/0048-target-i386-cpu-Add-new-EPYC-CPU-model.patch
extra/0049-i386-Add-EPYC-IBPB-CPU-model.patch
extra/0002-ratelimit-don-t-align-wait-time-with-slices.patch

27
keycodemapdb/LICENSE.BSD Normal file
View File

@ -0,0 +1,27 @@
Copyright (c) Individual contributors.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of PyCA Cryptography nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

339
keycodemapdb/LICENSE.GPL2 Normal file
View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

114
keycodemapdb/README Normal file
View File

@ -0,0 +1,114 @@
Key code / scan code / key symbol mapping database
==================================================
This module provides a database that maps between different
key code / scan code / key symbol sets:
- Linux evdev
- OS-X
- AT Set 1
- AT Set 2
- AT Set 3
- XT
- Linux XT KBD driver
- USB HID
- Win32
- XWin XT
- XKBD XT
- Xorg Evdev
- Xorg KBD
- Xorg OS-X
- XOrg Cygwin
- RFB
Licensing
---------
The contents of this package are dual licensed under the terms of:
- GNU General Public License (version 2 or later)
- 3-clause BSD License
The output files generated by keymap-gen may be distributed & used under
the terms of either of the above licenses.
Data formats
------------
The following output formats are possible
- Code map
An array mapping between key code sets values
Indexes in the array are values from the source code set.
Entries in the array are values from the target code set
- Code table
An array listing all values in a key code set
Indexes in the array are simply a numeric counter
Entries in the array are values from the key code set
The size of the array matches the total number of entries in
the keycode database.
- Name map
An array mapping between key code sets values and names
Indexes in the array are values from the source code set
Entries in the array are names from the target code set
- Name table
An array listing all names in a key code set
Indexes in the array are simply a numeric counter
Entries in the array are values from the key code set
The size of the array matches the total number of entries in
the keycode database.
Output languages
----------------
The tool is capable of generating data tables for the following
programming languages / environments
- Standard C
- GLib2 (standard C, but with GLib2 data types)
- Python
- Perl
Usage
-----
Map values from AT Set 1 to USB HID, generating tables for the
C programming language
$ keymap-gen --lang stdc code-map data/keymaps.csv atset1 usb
Generate a tables of names for Linux key codes, OS-X key codes,
in python - equivalent array indexes map between the two sets.
A variable name override is used
$ keymap-gen --varname linux_keycodes --lang stdc \
code-table data/keymaps.csv linux
$ keymap-gen --varname osx_keycodes --lang stdc \
code-table data/keymaps.csv os-x
Generate a mapping from XOrg XWin values to Win32 names
$ keymap-gen --lang perl name-map data/keymaps.csv xorgxwin win32
Generate a table of names for Linux key codes in Perl
$ keymap-gen --lang perl name-table data/keymaps.csv linux

89
keycodemapdb/data/README Normal file
View File

@ -0,0 +1,89 @@
This directory contains the raw data for mapping between different
keyboard codes. Naming if often based on the US keyboard layout, but
does not indicate the symbol actually generated by the key.
The columns currently in this data set are:
Linux
-----
Name and value of the hardware independent keycodes used by the linux
kernel and exposed through the input subsystem.
References: linux/input.h
macOS
-----
Low level key codes as exposed by Mac OS X/macOS.
References: Carbon/HIToolbox/Events.h
PC scan code sets
-----------------
Scan codes for the three orignal PC keyboard generations:
Set 1: XT
Set 2: AT
Set 3: PS/2
The sets include codes for modern keys as well and not just the keys
present on those original keyboards.
References: linux/drivers/input/keyboard/atkbd.c
USB HID
-------
Codes as specified by the HID profile in USB.
References: linux/drivers/hid/usbhid/usbkbd.c
Windows Virtual-key codes
-------------------------
The low level, hardware independent "VKEYs" exposed by Windows.
References: mingw32/winuser.h
XWin XT
-------
X11 keycodes generated by the XWin server. Based on the XT scan code
set.
References: xorg-server/hw/xwin/{winkeybd.c,winkeynames.h}
Xfree86 KBD XT
--------------
X11 keycodes generated by the Xfree86 keyboard drivers. Based on the XT
scan code set.
References: xf86-input-keyboard/src/at_scancode.c
X11 keysyms
-----------
Corresponding X11 keysym value(s) for a US keyboard layout.
WARNING: These columns represent symbols, not physical keys, and should
be used with extreme care.
References: http://cgit.freedesktop.org/xorg/proto/x11proto/plain/keysymdef.h
HTML KeyboardEvent.code
-----------------------
Key codes seen in the KeyboardEvent.code attribute as part of the
UI Events specification.
References: https://www.w3.org/TR/uievents-code/
XKEYBOARD key names
-------------------
Hardware independent key names as used in the XKEYBOARD extension.
References: /usr/share/X11/xkb/keycodes/

View File

@ -0,0 +1,539 @@
"Linux Name","Linux Keycode","OS-X Name","OS-X Keycode","AT set1 keycode","AT set2 keycode","AT set3 keycode","USB Keycodes","Win32 Name","Win32 Keycode","Xwin XT","Xfree86 KBD XT","X11 keysym name","X11 keysym","HTML code","XKB key name","QEMU QKeyCode","Sun KBD","Apple ADB"
KEY_RESERVED,0,,0xff,,,,,,,,,,,,,unmapped,,0xff
KEY_ESC,1,Escape,0x35,0x01,0x76,0x08,41,VK_ESCAPE,0x1b,1,1,XK_Escape,0xff1b,Escape,ESC,esc,0x1d,0x35
KEY_1,2,ANSI_1,0x12,0x02,0x16,0x16,30,VK_1,0x31,2,2,XK_1,0x0031,Digit1,AE01,1,0x1e,0x12
KEY_1,2,ANSI_1,0x12,0x02,0x16,0x16,30,VK_1,0x31,2,2,XK_exclam,0x0021,Digit1,AE01,1,0x1e,0x12
KEY_2,3,ANSI_2,0x13,0x03,0x1e,0x1e,31,VK_2,0x32,3,3,XK_2,0x0032,Digit2,AE02,2,0x1f,0x13
KEY_2,3,ANSI_2,0x13,0x03,0x1e,0x1e,31,VK_2,0x32,3,3,XK_at,0x0040,Digit2,AE02,2,0x1f,0x13
KEY_3,4,ANSI_3,0x14,0x04,0x26,0x26,32,VK_3,0x33,4,4,XK_3,0x0033,Digit3,AE03,3,0x20,0x14
KEY_3,4,ANSI_3,0x14,0x04,0x26,0x26,32,VK_3,0x33,4,4,XK_numbersign,0x0023,Digit3,AE03,3,0x20,0x14
KEY_4,5,ANSI_4,0x15,0x05,0x25,0x25,33,VK_4,0x34,5,5,XK_4,0x0034,Digit4,AE04,4,0x21,0x15
KEY_4,5,ANSI_4,0x15,0x05,0x25,0x25,33,VK_4,0x34,5,5,XK_dollar,0x0024,Digit4,AE04,4,0x21,0x15
KEY_5,6,ANSI_5,0x17,0x06,0x2e,0x2e,34,VK_5,0x35,6,6,XK_5,0x0035,Digit5,AE05,5,0x22,0x17
KEY_5,6,ANSI_5,0x17,0x06,0x2e,0x2e,34,VK_5,0x35,6,6,XK_percent,0x0025,Digit5,AE05,5,0x22,0x17
KEY_6,7,ANSI_6,0x16,0x07,0x36,0x36,35,VK_6,0x36,7,7,XK_6,0x0036,Digit6,AE06,6,0x23,0x16
KEY_6,7,ANSI_6,0x16,0x07,0x36,0x36,35,VK_6,0x36,7,7,XK_asciicircum,0x005e,Digit6,AE06,6,0x23,0x16
KEY_7,8,ANSI_7,0x1a,0x08,0x3d,0x3d,36,VK_7,0x37,8,8,XK_7,0x0037,Digit7,AE07,7,0x24,0x1a
KEY_7,8,ANSI_7,0x1a,0x08,0x3d,0x3d,36,VK_7,0x37,8,8,XK_ampersand,0x0026,Digit7,AE07,7,0x24,0x1a
KEY_8,9,ANSI_8,0x1c,0x09,0x3e,0x3e,37,VK_8,0x38,9,9,XK_8,0x0038,Digit8,AE08,8,0x25,0x1c
KEY_8,9,ANSI_8,0x1c,0x09,0x3e,0x3e,37,VK_8,0x38,9,9,XK_asterisk,0x002a,Digit8,AE08,8,0x25,0x1c
KEY_9,10,ANSI_9,0x19,0x0a,0x46,0x46,38,VK_9,0x39,10,10,XK_9,0x0039,Digit9,AE09,9,0x26,0x19
KEY_9,10,ANSI_9,0x19,0x0a,0x46,0x46,38,VK_9,0x39,10,10,XK_parenleft,0x0028,Digit9,AE09,9,0x26,0x19
KEY_0,11,ANSI_0,0x1d,0x0b,0x45,0x45,39,VK_0,0x30,11,11,XK_0,0x0030,Digit0,AE10,0,0x27,0x1d
KEY_0,11,ANSI_0,0x1d,0x0b,0x45,0x45,39,VK_0,0x30,11,11,XK_parenright,0x0029,Digit0,AE10,0,0x27,0x1d
KEY_MINUS,12,ANSI_Minus,0x1b,0x0c,0x4e,0x4e,45,VK_OEM_MINUS,0xbd,12,12,XK_minus,0x002d,Minus,AE11,minus,0x28,0x1b
KEY_MINUS,12,ANSI_Minus,0x1b,0x0c,0x4e,0x4e,45,VK_OEM_MINUS,0xbd,12,12,XK_underscore,0x005f,Minus,AE11,minus,0x28,0x1b
KEY_EQUAL,13,ANSI_Equal,0x18,0x0d,0x55,0x55,46,VK_OEM_PLUS,0xbb,13,13,XK_equal,0x003d,Equal,AE12,equal,0x29,0x18
KEY_EQUAL,13,ANSI_Equal,0x18,0x0d,0x55,0x55,46,VK_OEM_PLUS,0xbb,13,13,XK_plus,0x002b,Equal,AE12,equal,0x29,0x18
KEY_BACKSPACE,14,Delete,0x33,0x0e,0x66,0x66,42,VK_BACK,0x08,14,14,XK_BackSpace,0xff08,Backspace,BKSP,backspace,0x2b,0x33
KEY_TAB,15,Tab,0x30,0x0f,0x0d,0x0d,43,VK_TAB,0x09,15,15,XK_Tab,0xff09,Tab,TAB,tab,0x35,0x30
KEY_Q,16,ANSI_Q,0xc,0x10,0x15,0x15,20,VK_Q,0x51,16,16,XK_Q,0x0051,KeyQ,AD01,q,0x36,0xc
KEY_Q,16,ANSI_Q,0xc,0x10,0x15,0x15,20,VK_Q,0x51,16,16,XK_q,0x0071,KeyQ,AD01,q,0x36,0xc
KEY_W,17,ANSI_W,0xd,0x11,0x1d,0x1d,26,VK_W,0x57,17,17,XK_W,0x0057,KeyW,AD02,w,0x37,0xd
KEY_W,17,ANSI_W,0xd,0x11,0x1d,0x1d,26,VK_W,0x57,17,17,XK_w,0x0077,KeyW,AD02,w,0x37,0xd
KEY_E,18,ANSI_E,0xe,0x12,0x24,0x24,8,VK_E,0x45,18,18,XK_E,0x0045,KeyE,AD03,e,0x38,0xe
KEY_E,18,ANSI_E,0xe,0x12,0x24,0x24,8,VK_E,0x45,18,18,XK_e,0x0065,KeyE,AD03,e,0x38,0xe
KEY_R,19,ANSI_R,0xf,0x13,0x2d,0x2d,21,VK_R,0x52,19,19,XK_R,0x0052,KeyR,AD04,r,0x39,0xf
KEY_R,19,ANSI_R,0xf,0x13,0x2d,0x2d,21,VK_R,0x52,19,19,XK_r,0x0072,KeyR,AD04,r,0x39,0xf
KEY_T,20,ANSI_T,0x11,0x14,0x2c,0x2c,23,VK_T,0x54,20,20,XK_T,0x0054,KeyT,AD05,t,0x3a,0x11
KEY_T,20,ANSI_T,0x11,0x14,0x2c,0x2c,23,VK_T,0x54,20,20,XK_t,0x0074,KeyT,AD05,t,0x3a,0x11
KEY_Y,21,ANSI_Y,0x10,0x15,0x35,0x35,28,VK_Y,0x59,21,21,XK_Y,0x0059,KeyY,AD06,y,0x3b,0x10
KEY_Y,21,ANSI_Y,0x10,0x15,0x35,0x35,28,VK_Y,0x59,21,21,XK_y,0x0079,KeyY,AD06,y,0x3b,0x10
KEY_U,22,ANSI_U,0x20,0x16,0x3c,0x3c,24,VK_U,0x55,22,22,XK_U,0x0055,KeyU,AD07,u,0x3c,0x20
KEY_U,22,ANSI_U,0x20,0x16,0x3c,0x3c,24,VK_U,0x55,22,22,XK_u,0x0075,KeyU,AD07,u,0x3c,0x20
KEY_I,23,ANSI_I,0x22,0x17,0x43,0x43,12,VK_I,0x49,23,23,XK_I,0x0049,KeyI,AD08,i,0x3d,0x22
KEY_I,23,ANSI_I,0x22,0x17,0x43,0x43,12,VK_I,0x49,23,23,XK_i,0x0069,KeyI,AD08,i,0x3d,0x22
KEY_O,24,ANSI_O,0x1f,0x18,0x44,0x44,18,VK_O,0x4f,24,24,XK_O,0x004f,KeyO,AD09,o,0x3e,0x1f
KEY_O,24,ANSI_O,0x1f,0x18,0x44,0x44,18,VK_O,0x4f,24,24,XK_o,0x006f,KeyO,AD09,o,0x3e,0x1f
KEY_P,25,ANSI_P,0x23,0x19,0x4d,0x4d,19,VK_P,0x50,25,25,XK_P,0x0050,KeyP,AD10,p,0x3f,0x23
KEY_P,25,ANSI_P,0x23,0x19,0x4d,0x4d,19,VK_P,0x50,25,25,XK_p,0x0070,KeyP,AD10,p,0x3f,0x23
KEY_LEFTBRACE,26,ANSI_LeftBracket,0x21,0x1a,0x54,0x54,47,VK_OEM_4,0xdb,26,26,XK_bracketleft,0x005b,BracketLeft,AD11,bracket_left,0x40,0x21
KEY_LEFTBRACE,26,ANSI_LeftBracket,0x21,0x1a,0x54,0x54,47,VK_OEM_4,0xdb,26,26,XK_braceleft,0x007b,BracketLeft,AD11,bracket_left,0x40,0x21
KEY_RIGHTBRACE,27,ANSI_RightBracket,0x1e,0x1b,0x5b,0x5b,48,VK_OEM_6,0xdd,27,27,XK_bracketright,0x005d,BracketRight,AD12,bracket_right,0x41,0x1e
KEY_RIGHTBRACE,27,ANSI_RightBracket,0x1e,0x1b,0x5b,0x5b,48,VK_OEM_6,0xdd,27,27,XK_braceright,0x007d,BracketRight,AD12,bracket_right,0x41,0x1e
KEY_ENTER,28,Return,0x24,0x1c,0x5a,0x5a,40,VK_RETURN,0x0d,28,28,XK_Return,0xff0d,Enter,RTRN,ret,0x59,0x24
KEY_LEFTCTRL,29,Control,0x3b,0x1d,0x14,0x11,224,VK_LCONTROL,0xa2,29,29,XK_Control_L,0xffe3,ControlLeft,LCTL,ctrl,0x4c,0x36
KEY_LEFTCTRL,29,Control,0x3b,0x1d,0x14,0x11,224,VK_CONTROL,0x11,29,29,XK_Control_L,0xffe3,ControlLeft,LCTL,ctrl,0x4c,0x36
KEY_A,30,ANSI_A,0x0,0x1e,0x1c,0x1c,4,VK_A,0x41,30,30,XK_A,0x0041,KeyA,AC01,a,0x4d,0x0
KEY_A,30,ANSI_A,0x0,0x1e,0x1c,0x1c,4,VK_A,0x41,30,30,XK_a,0x0061,KeyA,AC01,a,0x4d,0x0
KEY_S,31,ANSI_S,0x1,0x1f,0x1b,0x1b,22,VK_S,0x53,31,31,XK_S,0x0053,KeyS,AC02,s,0x4e,0x1
KEY_S,31,ANSI_S,0x1,0x1f,0x1b,0x1b,22,VK_S,0x53,31,31,XK_s,0x0073,KeyS,AC02,s,0x4e,0x1
KEY_D,32,ANSI_D,0x2,0x20,0x23,0x23,7,VK_D,0x44,32,32,XK_D,0x0044,KeyD,AC03,d,0x4f,0x2
KEY_D,32,ANSI_D,0x2,0x20,0x23,0x23,7,VK_D,0x44,32,32,XK_d,0x0064,KeyD,AC03,d,0x4f,0x2
KEY_F,33,ANSI_F,0x3,0x21,0x2b,0x2b,9,VK_F,0x46,33,33,XK_F,0x0046,KeyF,AC04,f,0x50,0x3
KEY_F,33,ANSI_F,0x3,0x21,0x2b,0x2b,9,VK_F,0x46,33,33,XK_f,0x0066,KeyF,AC04,f,0x50,0x3
KEY_G,34,ANSI_G,0x5,0x22,0x34,0x34,10,VK_G,0x47,34,34,XK_G,0x0047,KeyG,AC05,g,0x51,0x5
KEY_G,34,ANSI_G,0x5,0x22,0x34,0x34,10,VK_G,0x47,34,34,XK_g,0x0067,KeyG,AC05,g,0x51,0x5
KEY_H,35,ANSI_H,0x4,0x23,0x33,0x33,11,VK_H,0x48,35,35,XK_H,0x0048,KeyH,AC06,h,0x52,0x4
KEY_H,35,ANSI_H,0x4,0x23,0x33,0x33,11,VK_H,0x48,35,35,XK_h,0x0068,KeyH,AC06,h,0x52,0x4
KEY_J,36,ANSI_J,0x26,0x24,0x3b,0x3b,13,VK_J,0x4a,36,36,XK_J,0x004a,KeyJ,AC07,j,0x53,0x26
KEY_J,36,ANSI_J,0x26,0x24,0x3b,0x3b,13,VK_J,0x4a,36,36,XK_j,0x006a,KeyJ,AC07,j,0x53,0x26
KEY_K,37,ANSI_K,0x28,0x25,0x42,0x42,14,VK_K,0x4b,37,37,XK_K,0x004b,KeyK,AC08,k,0x54,0x28
KEY_K,37,ANSI_K,0x28,0x25,0x42,0x42,14,VK_K,0x4b,37,37,XK_k,0x006b,KeyK,AC08,k,0x54,0x28
KEY_L,38,ANSI_L,0x25,0x26,0x4b,0x4b,15,VK_L,0x4c,38,38,XK_L,0x004c,KeyL,AC09,l,0x55,0x25
KEY_L,38,ANSI_L,0x25,0x26,0x4b,0x4b,15,VK_L,0x4c,38,38,XK_l,0x006c,KeyL,AC09,l,0x55,0x25
KEY_SEMICOLON,39,ANSI_Semicolon,0x29,0x27,0x4c,0x4c,51,VK_OEM_1,0xba,39,39,XK_semicolon,0x003b,Semicolon,AC10,semicolon,0x56,0x29
KEY_SEMICOLON,39,ANSI_Semicolon,0x29,0x27,0x4c,0x4c,51,VK_OEM_1,0xba,39,39,XK_colon,0x003a,Semicolon,AC10,semicolon,0x56,0x29
KEY_APOSTROPHE,40,ANSI_Quote,0x27,0x28,0x52,0x52,52,VK_OEM_7,0xde,40,40,XK_apostrophe,0x0027,Quote,AC11,apostrophe,0x57,0x27
KEY_APOSTROPHE,40,ANSI_Quote,0x27,0x28,0x52,0x52,52,VK_OEM_7,0xde,40,40,XK_quotedbl,0x0022,Quote,AC11,apostrophe,0x57,0x27
KEY_GRAVE,41,ANSI_Grave,0x32,0x29,0x0e,0x0e,53,VK_OEM_3,0xc0,41,41,XK_grave,0x0060,Backquote,TLDE,grave_accent,0x2a,0x32
KEY_GRAVE,41,ANSI_Grave,0x32,0x29,0x0e,0x0e,53,VK_OEM_3,0xc0,41,41,XK_grave,0x0060,Backquote,AB00,grave_accent,0x2a,0x32
KEY_GRAVE,41,ANSI_Grave,0x32,0x29,0x0e,0x0e,53,VK_OEM_3,0xc0,41,41,XK_asciitilde,0x007e,Backquote,TLDE,grave_accent,0x2a,0x32
KEY_GRAVE,41,ANSI_Grave,0x32,0x29,0x0e,0x0e,53,VK_OEM_3,0xc0,41,41,XK_asciitilde,0x007e,Backquote,AB00,grave_accent,0x2a,0x32
KEY_SHIFT,42,Shift,0x38,0x2a,0x12,0x12,225,VK_SHIFT,0x10,42,42,XK_Shift_L,0xffe1,ShiftLeft,LFSH,shift,0x63,0x38
KEY_LEFTSHIFT,42,Shift,0x38,0x2a,0x12,0x12,225,VK_LSHIFT,0xa0,42,42,XK_Shift_L,0xffe1,ShiftLeft,LFSH,shift,0x63,0x38
KEY_BACKSLASH,43,ANSI_Backslash,0x2a,0x2b,0x5d,0x5c,49,VK_OEM_5,0xdc,43,43,XK_backslash,0x005c,Backslash,BKSL,backslash,0x58,0x2a
KEY_BACKSLASH,43,ANSI_Backslash,0x2a,0x2b,0x5d,0x5c,49,VK_OEM_5,0xdc,43,43,XK_backslash,0x005c,Backslash,AC12,backslash,0x58,0x2a
KEY_BACKSLASH,43,ANSI_Backslash,0x2a,0x2b,0x5d,0x5c,49,VK_OEM_5,0xdc,43,43,XK_bar,0x007c,Backslash,BKSL,backslash,0x58,0x2a
KEY_BACKSLASH,43,ANSI_Backslash,0x2a,0x2b,0x5d,0x5c,49,VK_OEM_5,0xdc,43,43,XK_bar,0x007c,Backslash,AC12,backslash,0x58,0x2a
KEY_BACKSLASH,43,ANSI_Backslash,0x2a,0x2b,0x5d,0x5c,50,VK_OEM_5,0xdc,43,43,XK_backslash,0x005c,Backslash,BKSL,backslash,0x58,0x2a
KEY_BACKSLASH,43,ANSI_Backslash,0x2a,0x2b,0x5d,0x5c,50,VK_OEM_5,0xdc,43,43,XK_backslash,0x005c,Backslash,AC12,backslash,0x58,0x2a
KEY_BACKSLASH,43,ANSI_Backslash,0x2a,0x2b,0x5d,0x5c,50,VK_OEM_5,0xdc,43,43,XK_bar,0x007c,Backslash,BKSL,backslash,0x58,0x2a
KEY_BACKSLASH,43,ANSI_Backslash,0x2a,0x2b,0x5d,0x5c,50,VK_OEM_5,0xdc,43,43,XK_bar,0x007c,Backslash,AC12,backslash,0x58,0x2a
KEY_Z,44,ANSI_Z,0x6,0x2c,0x1a,0x1a,29,VK_Z,0x5a,44,44,XK_Z,0x005a,KeyZ,AB01,z,0x64,0x6
KEY_Z,44,ANSI_Z,0x6,0x2c,0x1a,0x1a,29,VK_Z,0x5a,44,44,XK_z,0x007a,KeyZ,AB01,z,0x64,0x6
KEY_X,45,ANSI_X,0x7,0x2d,0x22,0x22,27,VK_X,0x58,45,45,XK_X,0x0058,KeyX,AB02,x,0x65,0x7
KEY_X,45,ANSI_X,0x7,0x2d,0x22,0x22,27,VK_X,0x58,45,45,XK_x,0x0078,KeyX,AB02,x,0x65,0x7
KEY_C,46,ANSI_C,0x8,0x2e,0x21,0x21,6,VK_C,0x43,46,46,XK_C,0x0043,KeyC,AB03,c,0x66,0x8
KEY_C,46,ANSI_C,0x8,0x2e,0x21,0x21,6,VK_C,0x43,46,46,XK_c,0x0063,KeyC,AB03,c,0x66,0x8
KEY_V,47,ANSI_V,0x9,0x2f,0x2a,0x2a,25,VK_V,0x56,47,47,XK_V,0x0056,KeyV,AB04,v,0x67,0x9
KEY_V,47,ANSI_V,0x9,0x2f,0x2a,0x2a,25,VK_V,0x56,47,47,XK_v,0x0076,KeyV,AB04,v,0x67,0x9
KEY_B,48,ANSI_B,0xb,0x30,0x32,0x32,5,VK_B,0x42,48,48,XK_B,0x0042,KeyB,AB05,b,0x68,0xb
KEY_B,48,ANSI_B,0xb,0x30,0x32,0x32,5,VK_B,0x42,48,48,XK_b,0x0062,KeyB,AB05,b,0x68,0xb
KEY_N,49,ANSI_N,0x2d,0x31,0x31,0x31,17,VK_N,0x4e,49,49,XK_N,0x004e,KeyN,AB06,n,0x69,0x2d
KEY_N,49,ANSI_N,0x2d,0x31,0x31,0x31,17,VK_N,0x4e,49,49,XK_n,0x006e,KeyN,AB06,n,0x69,0x2d
KEY_M,50,ANSI_M,0x2e,0x32,0x3a,0x3a,16,VK_M,0x4d,50,50,XK_M,0x004d,KeyM,AB07,m,0x6a,0x2e
KEY_M,50,ANSI_M,0x2e,0x32,0x3a,0x3a,16,VK_M,0x4d,50,50,XK_m,0x006d,KeyM,AB07,m,0x6a,0x2e
KEY_COMMA,51,ANSI_Comma,0x2b,0x33,0x41,0x41,54,VK_OEM_COMMA,0xbc,51,51,XK_comma,0x002c,Comma,AB08,comma,0x6b,0x2b
KEY_COMMA,51,ANSI_Comma,0x2b,0x33,0x41,0x41,54,VK_OEM_COMMA,0xbc,51,51,XK_less,0x003c,Comma,AB08,comma,0x6b,0x2b
KEY_DOT,52,ANSI_Period,0x2f,0x34,0x49,0x49,55,VK_OEM_PERIOD,0xbe,52,52,XK_period,0x002e,Period,AB09,dot,0x6c,0x2f
KEY_DOT,52,ANSI_Period,0x2f,0x34,0x49,0x49,55,VK_OEM_PERIOD,0xbe,52,52,XK_greater,0x003e,Period,AB09,dot,0x6c,0x2f
KEY_SLASH,53,ANSI_Slash,0x2c,0x35,0x4a,0x4a,56,VK_OEM_2,0xbf,53,53,XK_slash,0x002f,Slash,AB10,slash,0x6d,0x2c
KEY_SLASH,53,ANSI_Slash,0x2c,0x35,0x4a,0x4a,56,VK_OEM_2,0xbf,53,53,XK_question,0x003f,Slash,AB10,slash,0x6d,0x2c
KEY_RIGHTSHIFT,54,RightShift,0x3c,0x36,0x59,0x59,229,VK_RSHIFT,0xa1,54,54,XK_Shift_R,0xffe2,ShiftRight,RTSH,shift_r,0x6e,0x7b
KEY_KPASTERISK,55,ANSI_KeypadMultiply,0x43,0x37,0x7c,0x7e,85,VK_MULTIPLY,0x6a,55,55,XK_multiply,0x00d7,NumpadMultiply,KPMU,asterisk,0x2f,0x43
KEY_KPASTERISK,55,ANSI_KeypadMultiply,0x43,0x37,0x7c,0x7e,85,VK_MULTIPLY,0x6a,55,55,XK_multiply,0x00d7,NumpadMultiply,KPMU,kp_multiply,0x2f,0x43
KEY_LEFTALT,56,Option,0x3a,0x38,0x11,0x19,226,VK_LMENU,0xa4,56,56,XK_Alt_L,0xffe9,AltLeft,LALT,alt,0x13,0x3a
KEY_LEFTALT,56,Option,0x3a,0x38,0x11,0x19,226,VK_MENU,0x12,56,56,XK_Alt_L,0xffe9,AltLeft,LALT,alt,0x13,0x3a
KEY_SPACE,57,Space,0x31,0x39,0x29,0x29,44,VK_SPACE,0x20,57,57,XK_space,0x0020,Space,SPCE,spc,0x79,0x31
KEY_CAPSLOCK,58,CapsLock,0x39,0x3a,0x58,0x14,57,VK_CAPITAL,0x14,58,58,XK_Caps_Lock,0xffe5,CapsLock,CAPS,caps_lock,0x77,0x39
KEY_F1,59,F1,0x7a,0x3b,0x05,0x07,58,VK_F1,0x70,59,59,XK_F1,0xffbe,F1,FK01,f1,0x05,0x7a
KEY_F2,60,F2,0x78,0x3c,0x06,0x0f,59,VK_F2,0x71,60,60,XK_F2,0xffbf,F2,FK02,f2,0x06,0x78
KEY_F3,61,F3,0x63,0x3d,0x04,0x17,60,VK_F3,0x72,61,61,XK_F3,0xffc0,F3,FK03,f3,0x08,0x63
KEY_F4,62,F4,0x76,0x3e,0x0c,0x1f,61,VK_F4,0x73,62,62,XK_F4,0xffc1,F4,FK04,f4,0x0a,0x76
KEY_F5,63,F5,0x60,0x3f,0x03,0x27,62,VK_F5,0x74,63,63,XK_F5,0xffc2,F5,FK05,f5,0x0c,0x60
KEY_F6,64,F6,0x61,0x40,0x0b,0x2f,63,VK_F6,0x75,64,64,XK_F6,0xffc3,F6,FK06,f6,0x0e,0x61
KEY_F7,65,F7,0x62,0x41,0x83,0x37,64,VK_F7,0x76,65,65,XK_F7,0xffc4,F7,FK07,f7,0x10,0x62
KEY_F8,66,F8,0x64,0x42,0x0a,0x3f,65,VK_F8,0x77,66,66,XK_F8,0xffc5,F8,FK08,f8,0x11,0x64
KEY_F9,67,F9,0x65,0x43,0x01,0x47,66,VK_F9,0x78,67,67,XK_F9,0xffc6,F9,FK09,f9,0x12,0x65
KEY_F10,68,F10,0x6d,0x44,0x09,0x4f,67,VK_F10,0x79,68,68,XK_F10,0xffc7,F10,FK10,f10,0x07,0x6d
KEY_NUMLOCK,69,ANSI_KeypadClear,0x47,0x45,0x77,0x76,83,VK_NUMLOCK,0x90,69,69,XK_Num_Lock,0xff7f,NumLock,NMLK,num_lock,0x62,0x47
KEY_SCROLLLOCK,70,,,0x46,0x7e,0x5f,71,VK_SCROLL,0x91,70,70,XK_Scroll_Lock,0xff14,ScrollLock,SCLK,scroll_lock,0x17,0x6b
KEY_KP7,71,ANSI_Keypad7,0x59,0x47,0x6c,0x6c,95,VK_NUMPAD7,0x67,71,71,XK_KP_7,0xffb7,Numpad7,KP7,kp_7,0x44,0x59
KEY_KP8,72,ANSI_Keypad8,0x5b,0x48,0x75,0x75,96,VK_NUMPAD8,0x68,72,72,XK_KP_8,0xffb8,Numpad8,KP8,kp_8,0x45,0x5b
KEY_KP9,73,ANSI_Keypad9,0x5c,0x49,0x7d,0x7d,97,VK_NUMPAD9,0x69,73,73,XK_KP_9,0xffb9,Numpad9,KP9,kp_9,0x46,0x5c
KEY_KPMINUS,74,ANSI_KeypadMinus,0x4e,0x4a,0x7b,0x4e,86,VK_SUBTRACT,0x6d,74,74,XK_KP_Subtract,0xffad,NumpadSubtract,KPSU,kp_subtract,0x47,0x4e
KEY_KP4,75,ANSI_Keypad4,0x56,0x4b,0x6b,0x6b,92,VK_NUMPAD4,0x64,75,75,XK_KP_4,0xffb4,Numpad4,KP4,kp_4,0x5b,0x56
KEY_KP5,76,ANSI_Keypad5,0x57,0x4c,0x73,0x73,93,VK_NUMPAD5,0x65,76,76,XK_KP_5,0xffb5,Numpad5,KP5,kp_5,0x5c,0x57
KEY_KP6,77,ANSI_Keypad6,0x58,0x4d,0x74,0x74,94,VK_NUMPAD6,0x66,77,77,XK_KP_6,0xffb6,Numpad6,KP6,kp_6,0x5d,0x58
KEY_KPPLUS,78,ANSI_KeypadPlus,0x45,0x4e,0x79,0x7c,87,VK_ADD,0x6b,78,78,XK_KP_Add,0xffab,NumpadAdd,KPAD,kp_add,0x7d,0x45
KEY_KP1,79,ANSI_Keypad1,0x53,0x4f,0x69,0x69,89,VK_NUMPAD1,0x61,79,79,XK_KP_1,0xffb1,Numpad1,KP1,kp_1,0x70,0x53
KEY_KP2,80,ANSI_Keypad2,0x54,0x50,0x72,0x72,90,VK_NUMPAD2,0x62,80,80,XK_KP_2,0xffb2,Numpad2,KP2,kp_2,0x71,0x54
KEY_KP3,81,ANSI_Keypad3,0x55,0x51,0x7a,0x7a,91,VK_NUMPAD3,0x63,81,81,XK_KP_3,0xffb3,Numpad3,KP3,kp_3,0x72,0x55
KEY_KP0,82,ANSI_Keypad0,0x52,0x52,0x70,0x70,98,VK_NUMPAD0,0x60,82,82,XK_KP_0,0xffb0,Numpad0,KP0,kp_0,0x5e,0x52
KEY_KPDOT,83,ANSI_KeypadDecimal,0x41,0x53,0x71,0x71,99,VK_DECIMAL,0x6e,83,83,XK_KP_Decimal,0xffae,NumpadDecimal,KPDL,kp_decimal,0x32,0x41
KEY_KPDOT,83,ANSI_KeypadDecimal,0x41,0x53,0x71,0x71,99,VK_DECIMAL,0x6e,83,83,XK_KP_Decimal,0xffae,NumpadDecimal,KPDC,kp_decimal,0x32,0x41
,84,,,0x54,,,,,,,,,,,,,,
KEY_ZENKAKUHANKAKU,85,,,0x76,0x5f,,148,,,,,,,Lang5,HZTG,,,
KEY_102ND,86,,,0x56,0x61,0x13,100,VK_OEM_102,0xe1,86,86,,,IntlBackslash,LSGT,less,0x7c,
KEY_F11,87,F11,0x67,0x57,0x78,0x56,68,VK_F11,0x7a,87,87,XK_F11,0xffc8,F11,FK11,f11,0x09,0x67
KEY_F12,88,F12,0x6f,0x58,0x07,0x5e,69,VK_F12,0x7b,88,88,XK_F12,0xffc9,F12,FK12,f12,0x0b,0x6f
KEY_RO,89,,,0x73,0x51,,135,,,,,,,IntlRo,AB11,ro,,
KEY_KATAKANA,90,JIS_Kana,0x68,0x78,0x63,,146,VK_KANA,0x15,,,,,Katakana,KATA,,,
KEY_KATAKANA,90,JIS_Kana,0x68,0x78,0x63,,146,VK_KANA,0x15,,,,,Lang3,KATA,,,
KEY_HIRAGANA,91,,,0x77,0x62,0x87,147,,,,,,,Hiragana,HIRA,hiragana,,
KEY_HIRAGANA,91,,,0x77,0x62,0x87,147,,,,,,,Lang4,HIRA,hiragana,,
KEY_HENKAN,92,,,0x79,0x64,0x86,138,,,,,,,Convert,HENK,henkan,,
KEY_KATAKANAHIRAGANA,93,,,0x70,0x13,0x87,136,,,0xc8,0xc8,,,KanaMode,HKTG,,,
KEY_MUHENKAN,94,,,0x7b,0x67,0x85,139,,,,,,,NonConvert,NFER,,,
KEY_MUHENKAN,94,,,0x7b,0x67,0x85,139,,,,,,,NonConvert,MUHE,,,
KEY_KPJPCOMMA,95,JIS_KeypadComma,0x5f,0x5c,0x27,,140,,,,,XK_KP_Separator,0xffac,,KPSP,,,
KEY_KPJPCOMMA,95,JIS_KeypadComma,0x5f,0x5c,0x27,,140,,,,,XK_KP_Separator,0xffac,,JPCM,,,
KEY_KPENTER,96,ANSI_KeypadEnter,0x4c,0xe01c,0xe05a,0x79,88,,,0x64,0x64,XK_KP_Enter,0xff8d,NumpadEnter,KPEN,kp_enter,0x5a,0x4c
KEY_RIGHTCTRL,97,RightControl,0x3e,0xe01d,0xe014,0x58,228,VK_RCONTROL,0xa3,0x65,0x65,XK_Control_R,0xffe4,ControlRight,RCTL,ctrl_r,0x4c,0x7d
KEY_KPSLASH,98,ANSI_KeypadDivide,0x4b,0xe035,0xe04a,0x4a,84,VK_DIVIDE,0x6f,0x68,0x68,XK_KP_Divide,0xffaf,NumpadDivide,KPDV,kp_divide,0x2e,0x4b
KEY_SYSRQ,99,,,0x54,0x7f,0x57,70,VK_SNAPSHOT,0x2c,0x67,0x67,XK_Sys_Req,0xff15,PrintScreen,PRSC,print,0x16,0x69
KEY_SYSRQ,99,,,0x54,0x7f,0x57,70,VK_SNAPSHOT,0x2c,0x67,0x67,XK_Sys_Req,0xff15,PrintScreen,SYRQ,sysrq,0x16,0x69
KEY_RIGHTALT,100,RightOption,0x3d,0xe038,0xe011,0x39,230,VK_RMENU,0xa5,0x69,0x69,XK_Alt_R,0xffea,AltRight,ALGR,alt_r,0x0d,0x7c
KEY_RIGHTALT,100,RightOption,0x3d,0xe038,0xe011,0x39,230,VK_RMENU,0xa5,0x69,0x69,XK_Alt_R,0xffea,AltRight,RALT,alt_r,0x0d,0x7c
KEY_LINEFEED,101,,,0x5b,,,,,,,,,,,LNFD,lf,0x6f,
KEY_HOME,102,Home,0x73,0xe047,0xe06c,0x6e,74,VK_HOME,0x24,0x59,0x59,XK_Home,0xff50,Home,HOME,home,0x34,0x73
KEY_UP,103,UpArrow,0x7e,0xe048,0xe075,0x63,82,VK_UP,0x26,0x5a,0x5a,XK_Up,0xff52,ArrowUp,UP,up,0x14,0x3e
KEY_PAGEUP,104,PageUp,0x74,0xe049,0xe07d,0x6f,75,VK_PRIOR,0x21,0x5b,0x5b,XK_Page_Up,0xff55,PageUp,PGUP,pgup,0x60,0x74
KEY_LEFT,105,LeftArrow,0x7b,0xe04b,0xe06b,0x61,80,VK_LEFT,0x25,0x5c,0x5c,XK_Left,0xff51,ArrowLeft,LEFT,left,0x18,0x3b
KEY_RIGHT,106,RightArrow,0x7c,0xe04d,0xe074,0x6a,79,VK_RIGHT,0x27,0x5e,0x5e,XK_Right,0xff53,ArrowRight,RGHT,right,0x1c,0x3c
KEY_END,107,End,0x77,0xe04f,0xe069,0x65,77,VK_END,0x23,0x5f,0x5f,XK_End,0xff57,End,END,end,0x4a,0x77
KEY_DOWN,108,DownArrow,0x7d,0xe050,0xe072,0x60,81,VK_DOWN,0x28,0x60,0x60,XK_Down,0xff54,ArrowDown,DOWN,down,0x1b,0x3d
KEY_PAGEDOWN,109,PageDown,0x79,0xe051,0xe07a,0x6d,78,VK_NEXT,0x22,0x61,0x61,XK_Page_Down,0xff56,PageDown,PGDN,pgdn,0x7b,0x79
KEY_INSERT,110,,,0xe052,0xe070,0x67,73,VK_INSERT,0x2d,0x62,0x62,XK_Insert,0xff63,Insert,INS,insert,0x2c,0x72
KEY_DELETE,111,ForwardDelete,0x75,0xe053,0xe071,0x64,76,VK_DELETE,0x2e,0x63,0x63,XK_Delete,0xffff,Delete,DEL,delete,0x42,0x75
KEY_DELETE,111,ForwardDelete,0x75,0xe053,0xe071,0x64,76,VK_DELETE,0x2e,0x63,0x63,XK_Delete,0xffff,Delete,DELE,,0x42,0x75
KEY_MACRO,112,,,0xe06f,0xe06f,0x8e,,,,,,,,,I120,,,
KEY_MUTE,113,Mute,0x4a,0xe020,0xe023,0x9c,127,VK_VOLUME_MUTE,0xad,,,,,AudioVolumeMute,MUTE,audiomute,,
KEY_MUTE,113,Mute,0x4a,0xe020,0xe023,0x9c,239,VK_VOLUME_MUTE,0xad,,,,,AudioVolumeMute,MUTE,audiomute,,
KEY_VOLUMEDOWN,114,VolumeDown,0x49,0xe02e,0xe021,0x9d,129,VK_VOLUME_DOWN,0xae,,,,,AudioVolumeDown,VOL-,volumedown,,
KEY_VOLUMEDOWN,114,VolumeDown,0x49,0xe02e,0xe021,0x9d,238,VK_VOLUME_DOWN,0xae,,,,,AudioVolumeDown,VOL-,volumedown,,
KEY_VOLUMEUP,115,VolumeUp,0x48,0xe030,0xe032,0x95,128,VK_VOLUME_UP,0xaf,,,,,AudioVolumeUp,VOL+,volumeup,,
KEY_VOLUMEUP,115,VolumeUp,0x48,0xe030,0xe032,0x95,237,VK_VOLUME_UP,0xaf,,,,,AudioVolumeUp,VOL+,volumeup,,
KEY_POWER,116,,,0xe05e,0xe037,,102,,,,,,,Power,POWR,power,,0x7f7f
KEY_KPEQUAL,117,ANSI_KeypadEquals,0x51,0x59,0x0f,,103,,,0x76,0x76,XK_KP_Equal,0xffbd,NumpadEqual,KPEQ,kp_equals,0x2d,0x51
KEY_KPPLUSMINUS,118,,,0xe04e,0xe079,,,,,,,,,,I126,,,
KEY_PAUSE,119,,,0xe046,0xe077,0x62,72,VK_PAUSE,0x013,0x66,0x66,XK_Pause,0xff13,Pause,PAUS,pause,0x15,0x71
KEY_SCALE,120,,,0xe00b,,,,,,,,,,,I128,,,
KEY_KPCOMMA,121,,,0x7e,0x6d,,133,VK_SEPARATOR??,0x6c,,,,,NumpadComma,KPCO,kp_comma,,
KEY_KPCOMMA,121,,,0x7e,0x6d,,133,VK_SEPARATOR??,0x6c,,,,,NumpadComma,I129,,,
KEY_HANGEUL,122,,,,,,144,VK_HANGEUL,0x15,,,,,,HNGL,,,
KEY_HANJA,123,,,0xe00d,,,145,VK_HANJA,0x19,,,,,,HJCV,,,
KEY_YEN,124,JIS_Yen,0x5d,0x7d,0x6a,0x5d,137,,,0x7d,0x7d,,,IntlYen,AE13,yen,,
KEY_LEFTMETA,125,Command,0x37,0xe05b,0xe01f,0x8b,227,VK_LWIN,0x5b,0x6b,0x6b,XK_Meta_L,0xffe7,MetaLeft,LMTA,meta_l,0x78,0x37
KEY_LEFTMETA,125,Command,0x37,0xe05b,0xe01f,0x8b,227,VK_LWIN,0x5b,0x6b,0x6b,XK_Meta_L,0xffe7,MetaLeft,LWIN,meta_l,0x78,0x37
KEY_RIGHTMETA,126,RightCommand,0x36,0xe05c,0xe027,0x8c,231,VK_RWIN,0x5c,0x6c,0x6c,XK_Meta_R,0xffe8,MetaRight,RMTA,meta_r,0x7a,0x37
KEY_RIGHTMETA,126,RightCommand,0x36,0xe05c,0xe027,0x8c,231,VK_RWIN,0x5c,0x6c,0x6c,XK_Meta_R,0xffe8,MetaRight,RWIN,meta_r,0x7a,0x37
KEY_COMPOSE,127,,0x6e,0xe05d,0xe02f,0x8d,101,VK_APPS,0x5d,0x6d,0x6d,,,ContextMenu,MENU,compose,0x43,
KEY_COMPOSE,127,,0x6e,0xe05d,0xe02f,0x8d,101,VK_APPS,0x5d,0x6d,0x6d,,,ContextMenu,COMP,compose,0x43,
KEY_STOP,128,,,0xe068,0xe028,0x0a,120,VK_BROWSER_STOP,0xa9,,,,,BrowserStop,STOP,stop,0x01,
KEY_STOP,128,,,0xe068,0xe028,0x0a,243,VK_BROWSER_STOP,0xa9,,,,,BrowserStop,STOP,stop,0x01,
KEY_AGAIN,129,,,0xe005,,0x0b,121,,,,,,,Again,AGAI,again,0x03,
KEY_PROPS,130,,,0xe006,,0x0c,,,,,,,,Props,PROP,props,0x19,
KEY_UNDO,131,,,0xe007,,0x10,122,,,,,,,Undo,UNDO,undo,0x1a,
KEY_FRONT,132,,,0xe00c,,,119,,,,,,,,FRNT,front,0x31,
KEY_COPY,133,,,0xe078,,0x18,124,,,,,,,Copy,COPY,copy,0x33,
KEY_OPEN,134,,,0x64,,0x20,116,,,,,,,Open,OPEN,open,0x48,
KEY_PASTE,135,,,0x65,,0x28,125,,,,,,,Paste,PAST,paste,0x49,
KEY_FIND,136,,,0xe041,,0x30,126,,,,,,,Find,FIND,find,0x5f,
KEY_FIND,136,,,0xe041,,0x30,244,,,,,,,Find,FIND,find,0x5f,
KEY_CUT,137,,,0xe03c,,0x38,123,,,,,,,Cut,CUT,cut,0x61,
KEY_HELP,138,Help,0x72,0xe075,,0x09,117,VK_HELP,0x2f,,,XK_Help,0xff6a,Help,HELP,help,0x76,
KEY_MENU,139,,,0xe01e,,0x91,118,,,,,,,,I147,menu,,
KEY_CALC,140,,,0xe021,0xe02b,0xa3,251,,,,,,,LaunchApp2,I148,calculator,,
KEY_SETUP,141,,,0x66,,,,,,,,,,,I149,,,
KEY_SLEEP,142,,,0xe05f,0xe03f,,248,VK_SLEEP,0x5f,,,,,Sleep,I150,sleep,,
KEY_WAKEUP,143,,,0xe063,0xe05e,,,,,,,,,WakeUp,I151,wake,,
KEY_FILE,144,,,0x67,,,,,,,,,,,I152,,,
KEY_SENDFILE,145,,,0x68,,,,,,,,,,,I153,,,
KEY_DELETEFILE,146,,,0x69,,,,,,,,,,,I154,,,
KEY_XFER,147,,,0xe013,,0xa2,,,,,,,,,XFER,,,
KEY_XFER,147,,,0xe013,,0xa2,,,,,,,,,I155,,,
KEY_PROG1,148,,,0xe01f,,0xa0,,,,,,,,,I156,,,
KEY_PROG2,149,,,0xe017,,0xa1,,,,,,,,,I157,,,
KEY_WWW,150,,,0xe002,,,240,,,,,,,,I158,,,
KEY_MSDOS,151,,,0x6a,,,,,,,,,,,I159,,,
KEY_SCREENLOCK,152,,,0xe012,,0x96,249,,,,,,,,I160,,,
KEY_DIRECTION,153,,,0x6b,,,,,,,,,,,I161,,,
KEY_CYCLEWINDOWS,154,,,0xe026,,0x9b,,,,,,,,,I162,,,
KEY_MAIL,155,,,0xe06c,0xe048,,,,,,,,,LaunchMail,I163,mail,,
KEY_BOOKMARKS,156,,,0xe066,0xe018,,,,,,,,,BrowserFavorites,I164,ac_bookmarks,,
KEY_COMPUTER,157,,,0xe06b,0xe040,,,,,,,,,LaunchApp1,I165,computer,,
KEY_BACK,158,,,0xe06a,0xe038,,241,VK_BROWSER_BACK,0xa6,,,,,BrowserBack,I166,ac_back,,
KEY_FORWARD,159,,,0xe069,0xe030,,242,VK_BROWSER_FORWARD,0xa7,,,,,BrowserForward,I167,ac_forward,,
KEY_CLOSECD,160,,,0xe023,,0x9a,,,,,,,,,I168,,,
KEY_EJECTCD,161,,,0x6c,,,236,,,,,,,,I169,,,
KEY_EJECTCLOSECD,162,,,0xe07d,,,,,,,,,,Eject,I170,,,
KEY_NEXTSONG,163,,,0xe019,0xe04d,0x93,235,VK_MEDIA_NEXT_TRACK,0xb0,,,,,MediaTrackNext,I171,audionext,,
KEY_PLAYPAUSE,164,,,0xe022,0xe034,,232,VK_MEDIA_PLAY_PAUSE,0xb3,,,,,MediaPlayPause,I172,audioplay,,
KEY_PREVIOUSSONG,165,,,0xe010,0xe015,0x94,234,VK_MEDIA_PREV_TRACK,0xb1,,,,,MediaTrackPrevious,I173,audioprev,,
KEY_STOPCD,166,,,0xe024,0xe03b,0x98,233,VK_MEDIA_STOP,0xb2,,,,,MediaStop,I174,audiostop,,
KEY_RECORD,167,,,0xe031,,0x9e,,,,,,,,,I175,,,
KEY_REWIND,168,,,0xe018,,0x9f,,,,,,,,,I176,,,
KEY_PHONE,169,,,0x63,,,,,,,,,,,I177,,,
KEY_ISO,170,ISO_Section,0xa,0x70,,,,,,,,,,,I178,,,
KEY_CONFIG,171,,,0xe001,,,,,,,,,,,I179,,,
KEY_HOMEPAGE,172,,,0xe032,0xe03a,0x97,,VK_BROWSER_HOME,0xac,,,,,BrowserHome,I180,ac_home,,
KEY_REFRESH,173,,,0xe067,0xe020,,250,VK_BROWSER_REFRESH,0xa8,,,,,BrowserRefresh,I181,ac_refresh,,
KEY_EXIT,174,,,0x71,,,,,,,,,,,I182,,,
KEY_MOVE,175,,,0x72,,,,,,,,,,,I183,,,
KEY_EDIT,176,,,0xe008,,,247,,,,,,,,I184,,,
KEY_SCROLLUP,177,,,0x75,,,245,,,,,,,,I185,,,
KEY_SCROLLDOWN,178,,,0xe00f,,,246,,,,,,,,I186,,,
KEY_KPLEFTPAREN,179,,,0xe076,,,182,,,,,,,NumpadParenLeft,I187,,,
KEY_KPRIGHTPAREN,180,,,0xe07b,,,183,,,,,,,NumpadParenRight,I188,,,
KEY_NEW,181,,,0xe009,,,,,,,,,,,I189,,,
KEY_REDO,182,,,0xe00a,,,,,,,,,,,I190,,,
KEY_F13,183,F13,0x69,0x5d,0x2f,0x7f,104,VK_F13,0x7c,0x6e,0x6e,,,F13,FK13,,,0x69
KEY_F14,184,F14,0x6b,0x5e,0x37,0x80,105,VK_F14,0x7d,0x6f,0x6f,,,F14,FK14,,,0x6b
KEY_F15,185,F15,0x71,0x5f,0x3f,0x81,106,VK_F15,0x7e,0x70,0x70,,,F15,FK15,,,0x71
KEY_F16,186,F16,0x6a,0x55,,0x82,107,VK_F16,0x7f,0x71,0x71,,,F16,FK16,,,
KEY_F17,187,F17,0x40,0xe003,,0x83,108,VK_F17,0x80,0x72,0x72,,,F17,FK17,,,
KEY_F18,188,F18,0x4f,0xe077,,,109,VK_F18,0x81,,,,,F18,FK18,,,
KEY_F19,189,F19,0x50,0xe004,,,110,VK_F19,0x82,,,,,F19,FK19,,,
KEY_F20,190,F20,0x5a,0x5a,,,111,VK_F20,0x83,,,,,F20,FK20,,,
KEY_F21,191,,,0x74,,,112,VK_F21,0x84,,,,,F21,FK21,,,
KEY_F22,192,,,0xe079,,,113,VK_F22,0x85,,,,,F22,FK22,,,
KEY_F23,193,,,0x6d,,,114,VK_F23,0x86,,,,,F23,FK23,,,
KEY_F24,194,,,0x6f,,,115,VK_F24,0x87,,,,,F24,FK24,,,
,195,,,0xe015,,,,,,,,,,,,,,
,196,,,0xe016,,,,,,,,,,,,,,
,197,,,0xe01a,,,,,,,,,,,,,,
,198,,,0xe01b,,,,,,,,,,,,,,
,199,,,0xe027,,,,,,,,,,,,,,
KEY_PLAYCD,200,,,0xe028,,,,,,,,,,,I208,,,
KEY_PAUSECD,201,,,0xe029,,,,,,,,,,,I209,,,
KEY_PROG3,202,,,0xe02b,,,,,,,,,,,I210,,,
KEY_PROG4,203,,,0xe02c,,,,,,,,,,,I211,,,
KEY_DASHBOARD,204,,,0xe02d,,,,,,,,,,,I212,,,
KEY_SUSPEND,205,,,0xe025,,,,,,,,,,Suspend,I213,,,
KEY_CLOSE,206,,,0xe02f,,,,,,,,,,,I214,,,
KEY_PLAY,207,,,0xe033,,,,VK_PLAY,0xfa,,,,,,I215,,,
KEY_FASTFORWARD,208,,,0xe034,,,,,,,,,,,I216,,,
KEY_BASSBOOST,209,,,0xe036,,,,,,,,,,,I217,,,
KEY_PRINT,210,,,0xe039,,,,VK_PRINT,0x2a,,,,,,I218,,,
KEY_HP,211,,,0xe03a,,,,,,,,,,,I219,,,
KEY_CAMERA,212,,,0xe03b,,,,,,,,,,,I220,,,
KEY_SOUND,213,,,0xe03d,,,,,,,,,,,I221,,,
KEY_QUESTION,214,,,0xe03e,,,,,,,,,,,I222,,,
KEY_EMAIL,215,,,0xe03f,,,,VK_LAUNCH_MAIL,0xb4,,,,,,I223,,,
KEY_CHAT,216,,,0xe040,,,,,,,,,,,I224,,,
KEY_SEARCH,217,,,0xe065,0xe010,,,VK_BROWSER_SEARCH,0xaa,,,,,BrowserSearch,I225,,,
KEY_CONNECT,218,,,0xe042,,,,,,,,,,,I226,,,
KEY_FINANCE,219,,,0xe043,,,,,,,,,,,I227,,,
KEY_SPORT,220,,,0xe044,,,,,,,,,,,I228,,,
KEY_SHOP,221,,,0xe045,,,,,,,,,,,I229,,,
KEY_ALTERASE,222,,,0xe014,,,,,,,,,,,I230,,,
KEY_CANCEL,223,,,0xe04a,,,,,,,,,,,I231,,,
KEY_BRIGHTNESSDOWN,224,,,0xe04c,,,,,,,,,,,I232,,,
KEY_BRIGHTNESSUP,225,,,0xe054,,,,,,,,,,,I233,,,
KEY_MEDIA,226,,,0xe06d,0xe050,,,,,,,,,MediaSelect,I234,mediaselect,,
KEY_SWITCHVIDEOMODE,227,,,0xe056,,,,,,,,,,,I235,,,
KEY_KBDILLUMTOGGLE,228,,,0xe057,,,,,,,,,,,I236,,,
KEY_KBDILLUMDOWN,229,,,0xe058,,,,,,,,,,,I237,,,
KEY_KBDILLUMUP,230,,,0xe059,,,,,,,,,,,I238,,,
KEY_SEND,231,,,0xe05a,,,,,,,,,,,I239,,,
KEY_REPLY,232,,,0xe064,,,,,,,,,,,I240,,,
KEY_FORWARDMAIL,233,,,0xe00e,,,,,,,,,,,I241,,,
KEY_SAVE,234,,,0xe055,,,,,,,,,,,I242,,,
KEY_DOCUMENTS,235,,,0xe070,,,,,,,,,,,I243,,,
KEY_BATTERY,236,,,0xe071,,,,,,,,,,,I244,,,
KEY_BLUETOOTH,237,,,0xe072,,,,,,,,,,,I245,,,
KEY_WLAN,238,,,0xe073,,,,,,,,,,,I246,,,
KEY_UWB,239,,,0xe074,,,,,,,,,,,I247,,,
KEY_UNKNOWN,240,,,,,,,,,,,,,,I248,,,
KEY_VIDEO_NEXT,241,,,,,,,,,,,,,,I249,,,
KEY_VIDEO_PREV,242,,,,,,,,,,,,,,I250,,,
KEY_BRIGHTNESS_CYCLE,243,,,,,,,,,,,,,,I251,,,
KEY_BRIGHTNESS_ZERO,244,,,,,,,,,,,,,,I252,,,
KEY_DISPLAY_OFF,245,,,,,,,,,,,,,,I253,,,
KEY_WIMAX,246,,,,,,,,,,,,,,,,,
,247,,,,,,,,,,,,,,,,,
,248,,,,,,,,,,,,,,,,,
,249,,,,,,,,,,,,,,,,,
,250,,,,,,,,,,,,,,,,,
,251,,,,,,,,,,,,,,,,,
,252,,,,,,,,,,,,,,,,,
,253,,,,,,,,,,,,,,,,,
,254,,,,,,,,,,,,,,,,,
,255,,,,0xe012,,,,,,,,,,,,,
BTN_MISC,0x100,,,,,,,,,,,,,,,,,
BTN_0,0x100,,,,,,,VK_LBUTTON,0x01,,,,,,,,,
BTN_1,0x101,,,,,,,VK_RBUTTON,0x02,,,,,,,,,
BTN_2,0x102,,,,,,,VK_MBUTTON,0x04,,,,,,,,,
BTN_3,0x103,,,,,,,VK_XBUTTON1,0x05,,,,,,,,,
BTN_4,0x104,,,,,,,VK_XBUTTON2,0x06,,,,,,,,,
BTN_5,0x105,,,,,,,,,,,,,,,,,
BTN_6,0x106,,,,,,,,,,,,,,,,,
BTN_7,0x107,,,,,,,,,,,,,,,,,
BTN_8,0x108,,,,,,,,,,,,,,,,,
BTN_9,0x109,,,,,,,,,,,,,,,,,
BTN_MOUSE,0x110,,,,,,,,,,,,,,,,,
BTN_LEFT,0x110,,,,,,,,,,,,,,,,,
BTN_RIGHT,0x111,,,,,,,,,,,,,,,,,
BTN_MIDDLE,0x112,,,,,,,,,,,,,,,,,
BTN_SIDE,0x113,,,,,,,,,,,,,,,,,
BTN_EXTRA,0x114,,,,,,,,,,,,,,,,,
BTN_FORWARD,0x115,,,,,,,,,,,,,,,,,
BTN_BACK,0x116,,,,,,,,,,,,,,,,,
BTN_TASK,0x117,,,,,,,,,,,,,,,,,
BTN_JOYSTICK,0x120,,,,,,,,,,,,,,,,,
BTN_TRIGGER,0x120,,,,,,,,,,,,,,,,,
BTN_THUMB,0x121,,,,,,,,,,,,,,,,,
BTN_THUMB2,0x122,,,,,,,,,,,,,,,,,
BTN_TOP,0x123,,,,,,,,,,,,,,,,,
BTN_TOP2,0x124,,,,,,,,,,,,,,,,,
BTN_PINKIE,0x125,,,,,,,,,,,,,,,,,
BTN_BASE,0x126,,,,,,,,,,,,,,,,,
BTN_BASE2,0x127,,,,,,,,,,,,,,,,,
BTN_BASE3,0x128,,,,,,,,,,,,,,,,,
BTN_BASE4,0x129,,,,,,,,,,,,,,,,,
BTN_BASE5,0x12a,,,,,,,,,,,,,,,,,
BTN_BASE6,0x12b,,,,,,,,,,,,,,,,,
BTN_DEAD,0x12f,,,,,,,,,,,,,,,,,
BTN_GAMEPAD,0x130,,,,,,,,,,,,,,,,,
BTN_A,0x130,,,,,,,,,,,,,,,,,
BTN_B,0x131,,,,,,,,,,,,,,,,,
BTN_C,0x132,,,,,,,,,,,,,,,,,
BTN_X,0x133,,,,,,,,,,,,,,,,,
BTN_Y,0x134,,,,,,,,,,,,,,,,,
BTN_Z,0x135,,,,,,,,,,,,,,,,,
BTN_TL,0x136,,,,,,,,,,,,,,,,,
BTN_TR,0x137,,,,,,,,,,,,,,,,,
BTN_TL2,0x138,,,,,,,,,,,,,,,,,
BTN_TR2,0x139,,,,,,,,,,,,,,,,,
BTN_SELECT,0x13a,,,,,,,,,,,,,,,,,
BTN_START,0x13b,,,,,,,,,,,,,,,,,
BTN_MODE,0x13c,,,,,,,,,,,,,,,,,
BTN_THUMBL,0x13d,,,,,,,,,,,,,,,,,
BTN_THUMBR,0x13e,,,,,,,,,,,,,,,,,
BTN_DIGI,0x140,,,,,,,,,,,,,,,,,
BTN_TOOL_PEN,0x140,,,,,,,,,,,,,,,,,
BTN_TOOL_RUBBER,0x141,,,,,,,,,,,,,,,,,
BTN_TOOL_BRUSH,0x142,,,,,,,,,,,,,,,,,
BTN_TOOL_PENCIL,0x143,,,,,,,,,,,,,,,,,
BTN_TOOL_AIRBRUSH,0x144,,,,,,,,,,,,,,,,,
BTN_TOOL_FINGER,0x145,,,,,,,,,,,,,,,,,
BTN_TOOL_MOUSE,0x146,,,,,,,,,,,,,,,,,
BTN_TOOL_LENS,0x147,,,,,,,,,,,,,,,,,
BTN_TOUCH,0x14a,,,,,,,,,,,,,,,,,
BTN_STYLUS,0x14b,,,,,,,,,,,,,,,,,
BTN_STYLUS2,0x14c,,,,,,,,,,,,,,,,,
BTN_TOOL_DOUBLETAP,0x14d,,,,,,,,,,,,,,,,,
BTN_TOOL_TRIPLETAP,0x14e,,,,,,,,,,,,,,,,,
BTN_TOOL_QUADTAP,0x14f,,,,,,,,,,,,,,,,,
BTN_WHEEL,0x150,,,,,,,,,,,,,,,,,
BTN_GEAR_DOWN,0x150,,,,,,,,,,,,,,,,,
BTN_GEAR_UP,0x151,,,,,,,,,,,,,,,,,
KEY_OK,0x160,,,,,,,,,,,,,,,,,
KEY_SELECT,0x161,,,,,,,VK_SELECT,0x29,,,XK_Select,0xff60,Select,SELE,,,
KEY_GOTO,0x162,,,,,,,,,,,,,,,,,
KEY_CLEAR,0x163,,,,,,,,,,,,,NumpadClear,CLR,,,
KEY_POWER2,0x164,,,,,,,,,,,,,,,,,
KEY_OPTION,0x165,,,,,,,,,,,,,,,,,
KEY_INFO,0x166,,,,,,,,,,,,,,,,,
KEY_TIME,0x167,,,,,,,,,,,,,,,,,
KEY_VENDOR,0x168,,,,,,,,,,,,,,,,,
KEY_ARCHIVE,0x169,,,,,,,,,,,,,,,,,
KEY_PROGRAM,0x16a,,,,,,,,,,,,,,,,,
KEY_CHANNEL,0x16b,,,,,,,,,,,,,,,,,
KEY_FAVORITES,0x16c,,,,,,,VK_BROWSER_FAVOURITES,0xab,,,,,,,,,
KEY_EPG,0x16d,,,,,,,,,,,,,,,,,
KEY_PVR,0x16e,,,,,,,,,,,,,,,,,
KEY_MHP,0x16f,,,,,,,,,,,,,,,,,
KEY_LANGUAGE,0x170,,,,,,,,,,,,,,,,,
KEY_TITLE,0x171,,,,,,,,,,,,,,,,,
KEY_SUBTITLE,0x172,,,,,,,,,,,,,,,,,
KEY_ANGLE,0x173,,,,,,,,,,,,,,,,,
KEY_ZOOM,0x174,,,,,,,VK_ZOOM,0xfb,,,,,,,,,
KEY_MODE,0x175,,,,,,,,,,,,,,,,,
KEY_KEYBOARD,0x176,,,,,,,,,,,,,,,,,
KEY_SCREEN,0x177,,,,,,,,,,,,,,,,,
KEY_PC,0x178,,,,,,,,,,,,,,,,,
KEY_TV,0x179,,,,,,,,,,,,,,,,,
KEY_TV2,0x17a,,,,,,,,,,,,,,,,,
KEY_VCR,0x17b,,,,,,,,,,,,,,,,,
KEY_VCR2,0x17c,,,,,,,,,,,,,,,,,
KEY_SAT,0x17d,,,,,,,,,,,,,,,,,
KEY_SAT2,0x17e,,,,,,,,,,,,,,,,,
KEY_CD,0x17f,,,,,,,,,,,,,,,,,
KEY_TAPE,0x180,,,,,,,,,,,,,,,,,
KEY_RADIO,0x181,,,,,,,,,,,,,,,,,
KEY_TUNER,0x182,,,,,,,,,,,,,,,,,
KEY_PLAYER,0x183,,,,,,,,,,,,,,,,,
KEY_TEXT,0x184,,,,,,,,,,,,,,,,,
KEY_DVD,0x185,,,,,,,,,,,,,,,,,
KEY_AUX,0x186,,,,,,,,,,,,,,,,,
KEY_MP3,0x187,,,,,,,,,,,,,,,,,
KEY_AUDIO,0x188,,,,,,,,,,,,,,,,,
KEY_VIDEO,0x189,,,,,,,,,,,,,,,,,
KEY_DIRECTORY,0x18a,,,,,,,,,,,,,,,,,
KEY_LIST,0x18b,,,,,,,,,,,,,,,,,
KEY_MEMO,0x18c,,,,,,,,,,,,,,,,,
KEY_CALENDAR,0x18d,,,,,,,,,,,,,,,,,
KEY_RED,0x18e,,,,,,,,,,,,,,,,,
KEY_GREEN,0x18f,,,,,,,,,,,,,,,,,
KEY_YELLOW,0x190,,,,,,,,,,,,,,,,,
KEY_BLUE,0x191,,,,,,,,,,,,,,,,,
KEY_CHANNELUP,0x192,,,,,,,,,,,,,,,,,
KEY_CHANNELDOWN,0x193,,,,,,,,,,,,,,,,,
KEY_FIRST,0x194,,,,,,,,,,,,,,,,,
KEY_LAST,0x195,,,,,,,,,,,,,,,,,
KEY_AB,0x196,,,,,,,,,,,,,,,,,
KEY_NEXT,0x197,,,,,,,,,,,,,,,,,
KEY_RESTART,0x198,,,,,,,,,,,,,,,,,
KEY_SLOW,0x199,,,,,,,,,,,,,,,,,
KEY_SHUFFLE,0x19a,,,,,,,,,,,,,,,,,
KEY_BREAK,0x19b,,,,,,,,,,,,,,BREA,,,
KEY_BREAK,0x19b,,,,,,,,,,,,,,BRK,,,
KEY_PREVIOUS,0x19c,,,,,,,,,,,,,,,,,
KEY_DIGITS,0x19d,,,,,,,,,,,,,,,,,
KEY_TEEN,0x19e,,,,,,,,,,,,,,,,,
KEY_TWEN,0x19f,,,,,,,,,,,,,,,,,
KEY_VIDEOPHONE,0x1a0,,,,,,,,,,,,,,,,,
KEY_GAMES,0x1a1,,,,,,,,,,,,,,,,,
KEY_ZOOMIN,0x1a2,,,,,,,,,,,,,,,,,
KEY_ZOOMOUT,0x1a3,,,,,,,,,,,,,,,,,
KEY_ZOOMRESET,0x1a4,,,,,,,,,,,,,,,,,
KEY_WORDPROCESSOR,0x1a5,,,,,,,,,,,,,,,,,
KEY_EDITOR,0x1a6,,,,,,,,,,,,,,,,,
KEY_SPREADSHEET,0x1a7,,,,,,,,,,,,,,,,,
KEY_GRAPHICSEDITOR,0x1a8,,,,,,,,,,,,,,,,,
KEY_PRESENTATION,0x1a9,,,,,,,,,,,,,,,,,
KEY_DATABASE,0x1aa,,,,,,,,,,,,,,,,,
KEY_NEWS,0x1ab,,,,,,,,,,,,,,,,,
KEY_VOICEMAIL,0x1ac,,,,,,,,,,,,,,,,,
KEY_ADDRESSBOOK,0x1ad,,,,,,,,,,,,,,,,,
KEY_MESSENGER,0x1ae,,,,,,,,,,,,,,,,,
KEY_DISPLAYTOGGLE,0x1af,,,,,,,,,,,,,,,,,
KEY_SPELLCHECK,0x1b0,,,,,,,,,,,,,,,,,
KEY_LOGOFF,0x1b1,,,,,,,,,,,,,,,,,
KEY_DOLLAR,0x1b2,,,,,,,,,,,,,,,,,
KEY_EURO,0x1b3,,,,,,,,,,,,,,,,,
KEY_FRAMEBACK,0x1b4,,,,,,,,,,,,,,,,,
KEY_FRAMEFORWARD,0x1b5,,,,,,,,,,,,,,,,,
KEY_CONTEXT_MENU,0x1b6,,,,,,,,,,,,,,,,,
KEY_MEDIA_REPEAT,0x1b7,,,,,,,,,,,,,,,,,
KEY_DEL_EOL,0x1c0,,,,,,,,,,,,,,,,,
KEY_DEL_EOS,0x1c1,,,,,,,,,,,,,,,,,
KEY_INS_LINE,0x1c2,,,,,,,,,,,,,,,,,
KEY_DEL_LINE,0x1c3,,,,,,,,,,,,,,,,,
KEY_FN,0x1d0,Function,0x3f,,,,,,,,,,,Fn,,,,
KEY_FN_ESC,0x1d1,,,,,,,,,,,,,,,,,
KEY_FN_F1,0x1d2,,,,,,,,,,,,,,,,,
KEY_FN_F2,0x1d3,,,,,,,,,,,,,,,,,
KEY_FN_F3,0x1d4,,,,,,,,,,,,,,,,,
KEY_FN_F4,0x1d5,,,,,,,,,,,,,,,,,
KEY_FN_F5,0x1d6,,,,,,,,,,,,,,,,,
KEY_FN_F6,0x1d7,,,,,,,,,,,,,,,,,
KEY_FN_F7,0x1d8,,,,,,,,,,,,,,,,,
KEY_FN_F8,0x1d9,,,,,,,,,,,,,,,,,
KEY_FN_F9,0x1da,,,,,,,,,,,,,,,,,
KEY_FN_F10,0x1db,,,,,,,,,,,,,,,,,
KEY_FN_F11,0x1dc,,,,,,,,,,,,,,,,,
KEY_FN_F12,0x1dd,,,,,,,,,,,,,,,,,
KEY_FN_1,0x1de,,,,,,,,,,,,,,,,,
KEY_FN_2,0x1df,,,,,,,,,,,,,,,,,
KEY_FN_D,0x1e0,,,,,,,,,,,,,,,,,
KEY_FN_E,0x1e1,,,,,,,,,,,,,,,,,
KEY_FN_F,0x1e2,,,,,,,,,,,,,,,,,
KEY_FN_S,0x1e3,,,,,,,,,,,,,,,,,
KEY_FN_B,0x1e4,,,,,,,,,,,,,,,,,
KEY_BRL_DOT1,0x1f1,,,,,,,,,,,,,,,,,
KEY_BRL_DOT2,0x1f2,,,,,,,,,,,,,,,,,
KEY_BRL_DOT3,0x1f3,,,,,,,,,,,,,,,,,
KEY_BRL_DOT4,0x1f4,,,,,,,,,,,,,,,,,
KEY_BRL_DOT5,0x1f5,,,,,,,,,,,,,,,,,
KEY_BRL_DOT6,0x1f6,,,,,,,,,,,,,,,,,
KEY_BRL_DOT7,0x1f7,,,,,,,,,,,,,,,,,
KEY_BRL_DOT8,0x1f8,,,,,,,,,,,,,,,,,
KEY_BRL_DOT9,0x1f9,,,,,,,,,,,,,,,,,
KEY_BRL_DOT10,0x1fa,,,,,,,,,,,,,,,,,
KEY_NUMERIC_0,0x200,,,,,,,,,,,,,,,,,
KEY_NUMERIC_1,0x201,,,,,,,,,,,,,,,,,
KEY_NUMERIC_2,0x202,,,,,,,,,,,,,,,,,
KEY_NUMERIC_3,0x203,,,,,,,,,,,,,,,,,
KEY_NUMERIC_4,0x204,,,,,,,,,,,,,,,,,
KEY_NUMERIC_5,0x205,,,,,,,,,,,,,,,,,
KEY_NUMERIC_6,0x206,,,,,,,,,,,,,,,,,
KEY_NUMERIC_7,0x207,,,,,,,,,,,,,,,,,
KEY_NUMERIC_8,0x208,,,,,,,,,,,,,,,,,
KEY_NUMERIC_9,0x209,,,,,,,,,,,,,,,,,
KEY_NUMERIC_STAR,0x20a,,,,,,,,,,,,,NumpadStar,,,,
KEY_NUMERIC_POUND,0x20b,,,,,,,,,,,,,NumpadHash,,,,
KEY_RFKILL,0x20c,,,,,,,,,,,,,,,,,
1 Linux Name Linux Keycode OS-X Name OS-X Keycode AT set1 keycode AT set2 keycode AT set3 keycode USB Keycodes Win32 Name Win32 Keycode Xwin XT Xfree86 KBD XT X11 keysym name X11 keysym HTML code XKB key name QEMU QKeyCode Sun KBD Apple ADB
2 KEY_RESERVED 0 0xff unmapped 0xff
3 KEY_ESC 1 Escape 0x35 0x01 0x76 0x08 41 VK_ESCAPE 0x1b 1 1 XK_Escape 0xff1b Escape ESC esc 0x1d 0x35
4 KEY_1 2 ANSI_1 0x12 0x02 0x16 0x16 30 VK_1 0x31 2 2 XK_1 0x0031 Digit1 AE01 1 0x1e 0x12
5 KEY_1 2 ANSI_1 0x12 0x02 0x16 0x16 30 VK_1 0x31 2 2 XK_exclam 0x0021 Digit1 AE01 1 0x1e 0x12
6 KEY_2 3 ANSI_2 0x13 0x03 0x1e 0x1e 31 VK_2 0x32 3 3 XK_2 0x0032 Digit2 AE02 2 0x1f 0x13
7 KEY_2 3 ANSI_2 0x13 0x03 0x1e 0x1e 31 VK_2 0x32 3 3 XK_at 0x0040 Digit2 AE02 2 0x1f 0x13
8 KEY_3 4 ANSI_3 0x14 0x04 0x26 0x26 32 VK_3 0x33 4 4 XK_3 0x0033 Digit3 AE03 3 0x20 0x14
9 KEY_3 4 ANSI_3 0x14 0x04 0x26 0x26 32 VK_3 0x33 4 4 XK_numbersign 0x0023 Digit3 AE03 3 0x20 0x14
10 KEY_4 5 ANSI_4 0x15 0x05 0x25 0x25 33 VK_4 0x34 5 5 XK_4 0x0034 Digit4 AE04 4 0x21 0x15
11 KEY_4 5 ANSI_4 0x15 0x05 0x25 0x25 33 VK_4 0x34 5 5 XK_dollar 0x0024 Digit4 AE04 4 0x21 0x15
12 KEY_5 6 ANSI_5 0x17 0x06 0x2e 0x2e 34 VK_5 0x35 6 6 XK_5 0x0035 Digit5 AE05 5 0x22 0x17
13 KEY_5 6 ANSI_5 0x17 0x06 0x2e 0x2e 34 VK_5 0x35 6 6 XK_percent 0x0025 Digit5 AE05 5 0x22 0x17
14 KEY_6 7 ANSI_6 0x16 0x07 0x36 0x36 35 VK_6 0x36 7 7 XK_6 0x0036 Digit6 AE06 6 0x23 0x16
15 KEY_6 7 ANSI_6 0x16 0x07 0x36 0x36 35 VK_6 0x36 7 7 XK_asciicircum 0x005e Digit6 AE06 6 0x23 0x16
16 KEY_7 8 ANSI_7 0x1a 0x08 0x3d 0x3d 36 VK_7 0x37 8 8 XK_7 0x0037 Digit7 AE07 7 0x24 0x1a
17 KEY_7 8 ANSI_7 0x1a 0x08 0x3d 0x3d 36 VK_7 0x37 8 8 XK_ampersand 0x0026 Digit7 AE07 7 0x24 0x1a
18 KEY_8 9 ANSI_8 0x1c 0x09 0x3e 0x3e 37 VK_8 0x38 9 9 XK_8 0x0038 Digit8 AE08 8 0x25 0x1c
19 KEY_8 9 ANSI_8 0x1c 0x09 0x3e 0x3e 37 VK_8 0x38 9 9 XK_asterisk 0x002a Digit8 AE08 8 0x25 0x1c
20 KEY_9 10 ANSI_9 0x19 0x0a 0x46 0x46 38 VK_9 0x39 10 10 XK_9 0x0039 Digit9 AE09 9 0x26 0x19
21 KEY_9 10 ANSI_9 0x19 0x0a 0x46 0x46 38 VK_9 0x39 10 10 XK_parenleft 0x0028 Digit9 AE09 9 0x26 0x19
22 KEY_0 11 ANSI_0 0x1d 0x0b 0x45 0x45 39 VK_0 0x30 11 11 XK_0 0x0030 Digit0 AE10 0 0x27 0x1d
23 KEY_0 11 ANSI_0 0x1d 0x0b 0x45 0x45 39 VK_0 0x30 11 11 XK_parenright 0x0029 Digit0 AE10 0 0x27 0x1d
24 KEY_MINUS 12 ANSI_Minus 0x1b 0x0c 0x4e 0x4e 45 VK_OEM_MINUS 0xbd 12 12 XK_minus 0x002d Minus AE11 minus 0x28 0x1b
25 KEY_MINUS 12 ANSI_Minus 0x1b 0x0c 0x4e 0x4e 45 VK_OEM_MINUS 0xbd 12 12 XK_underscore 0x005f Minus AE11 minus 0x28 0x1b
26 KEY_EQUAL 13 ANSI_Equal 0x18 0x0d 0x55 0x55 46 VK_OEM_PLUS 0xbb 13 13 XK_equal 0x003d Equal AE12 equal 0x29 0x18
27 KEY_EQUAL 13 ANSI_Equal 0x18 0x0d 0x55 0x55 46 VK_OEM_PLUS 0xbb 13 13 XK_plus 0x002b Equal AE12 equal 0x29 0x18
28 KEY_BACKSPACE 14 Delete 0x33 0x0e 0x66 0x66 42 VK_BACK 0x08 14 14 XK_BackSpace 0xff08 Backspace BKSP backspace 0x2b 0x33
29 KEY_TAB 15 Tab 0x30 0x0f 0x0d 0x0d 43 VK_TAB 0x09 15 15 XK_Tab 0xff09 Tab TAB tab 0x35 0x30
30 KEY_Q 16 ANSI_Q 0xc 0x10 0x15 0x15 20 VK_Q 0x51 16 16 XK_Q 0x0051 KeyQ AD01 q 0x36 0xc
31 KEY_Q 16 ANSI_Q 0xc 0x10 0x15 0x15 20 VK_Q 0x51 16 16 XK_q 0x0071 KeyQ AD01 q 0x36 0xc
32 KEY_W 17 ANSI_W 0xd 0x11 0x1d 0x1d 26 VK_W 0x57 17 17 XK_W 0x0057 KeyW AD02 w 0x37 0xd
33 KEY_W 17 ANSI_W 0xd 0x11 0x1d 0x1d 26 VK_W 0x57 17 17 XK_w 0x0077 KeyW AD02 w 0x37 0xd
34 KEY_E 18 ANSI_E 0xe 0x12 0x24 0x24 8 VK_E 0x45 18 18 XK_E 0x0045 KeyE AD03 e 0x38 0xe
35 KEY_E 18 ANSI_E 0xe 0x12 0x24 0x24 8 VK_E 0x45 18 18 XK_e 0x0065 KeyE AD03 e 0x38 0xe
36 KEY_R 19 ANSI_R 0xf 0x13 0x2d 0x2d 21 VK_R 0x52 19 19 XK_R 0x0052 KeyR AD04 r 0x39 0xf
37 KEY_R 19 ANSI_R 0xf 0x13 0x2d 0x2d 21 VK_R 0x52 19 19 XK_r 0x0072 KeyR AD04 r 0x39 0xf
38 KEY_T 20 ANSI_T 0x11 0x14 0x2c 0x2c 23 VK_T 0x54 20 20 XK_T 0x0054 KeyT AD05 t 0x3a 0x11
39 KEY_T 20 ANSI_T 0x11 0x14 0x2c 0x2c 23 VK_T 0x54 20 20 XK_t 0x0074 KeyT AD05 t 0x3a 0x11
40 KEY_Y 21 ANSI_Y 0x10 0x15 0x35 0x35 28 VK_Y 0x59 21 21 XK_Y 0x0059 KeyY AD06 y 0x3b 0x10
41 KEY_Y 21 ANSI_Y 0x10 0x15 0x35 0x35 28 VK_Y 0x59 21 21 XK_y 0x0079 KeyY AD06 y 0x3b 0x10
42 KEY_U 22 ANSI_U 0x20 0x16 0x3c 0x3c 24 VK_U 0x55 22 22 XK_U 0x0055 KeyU AD07 u 0x3c 0x20
43 KEY_U 22 ANSI_U 0x20 0x16 0x3c 0x3c 24 VK_U 0x55 22 22 XK_u 0x0075 KeyU AD07 u 0x3c 0x20
44 KEY_I 23 ANSI_I 0x22 0x17 0x43 0x43 12 VK_I 0x49 23 23 XK_I 0x0049 KeyI AD08 i 0x3d 0x22
45 KEY_I 23 ANSI_I 0x22 0x17 0x43 0x43 12 VK_I 0x49 23 23 XK_i 0x0069 KeyI AD08 i 0x3d 0x22
46 KEY_O 24 ANSI_O 0x1f 0x18 0x44 0x44 18 VK_O 0x4f 24 24 XK_O 0x004f KeyO AD09 o 0x3e 0x1f
47 KEY_O 24 ANSI_O 0x1f 0x18 0x44 0x44 18 VK_O 0x4f 24 24 XK_o 0x006f KeyO AD09 o 0x3e 0x1f
48 KEY_P 25 ANSI_P 0x23 0x19 0x4d 0x4d 19 VK_P 0x50 25 25 XK_P 0x0050 KeyP AD10 p 0x3f 0x23
49 KEY_P 25 ANSI_P 0x23 0x19 0x4d 0x4d 19 VK_P 0x50 25 25 XK_p 0x0070 KeyP AD10 p 0x3f 0x23
50 KEY_LEFTBRACE 26 ANSI_LeftBracket 0x21 0x1a 0x54 0x54 47 VK_OEM_4 0xdb 26 26 XK_bracketleft 0x005b BracketLeft AD11 bracket_left 0x40 0x21
51 KEY_LEFTBRACE 26 ANSI_LeftBracket 0x21 0x1a 0x54 0x54 47 VK_OEM_4 0xdb 26 26 XK_braceleft 0x007b BracketLeft AD11 bracket_left 0x40 0x21
52 KEY_RIGHTBRACE 27 ANSI_RightBracket 0x1e 0x1b 0x5b 0x5b 48 VK_OEM_6 0xdd 27 27 XK_bracketright 0x005d BracketRight AD12 bracket_right 0x41 0x1e
53 KEY_RIGHTBRACE 27 ANSI_RightBracket 0x1e 0x1b 0x5b 0x5b 48 VK_OEM_6 0xdd 27 27 XK_braceright 0x007d BracketRight AD12 bracket_right 0x41 0x1e
54 KEY_ENTER 28 Return 0x24 0x1c 0x5a 0x5a 40 VK_RETURN 0x0d 28 28 XK_Return 0xff0d Enter RTRN ret 0x59 0x24
55 KEY_LEFTCTRL 29 Control 0x3b 0x1d 0x14 0x11 224 VK_LCONTROL 0xa2 29 29 XK_Control_L 0xffe3 ControlLeft LCTL ctrl 0x4c 0x36
56 KEY_LEFTCTRL 29 Control 0x3b 0x1d 0x14 0x11 224 VK_CONTROL 0x11 29 29 XK_Control_L 0xffe3 ControlLeft LCTL ctrl 0x4c 0x36
57 KEY_A 30 ANSI_A 0x0 0x1e 0x1c 0x1c 4 VK_A 0x41 30 30 XK_A 0x0041 KeyA AC01 a 0x4d 0x0
58 KEY_A 30 ANSI_A 0x0 0x1e 0x1c 0x1c 4 VK_A 0x41 30 30 XK_a 0x0061 KeyA AC01 a 0x4d 0x0
59 KEY_S 31 ANSI_S 0x1 0x1f 0x1b 0x1b 22 VK_S 0x53 31 31 XK_S 0x0053 KeyS AC02 s 0x4e 0x1
60 KEY_S 31 ANSI_S 0x1 0x1f 0x1b 0x1b 22 VK_S 0x53 31 31 XK_s 0x0073 KeyS AC02 s 0x4e 0x1
61 KEY_D 32 ANSI_D 0x2 0x20 0x23 0x23 7 VK_D 0x44 32 32 XK_D 0x0044 KeyD AC03 d 0x4f 0x2
62 KEY_D 32 ANSI_D 0x2 0x20 0x23 0x23 7 VK_D 0x44 32 32 XK_d 0x0064 KeyD AC03 d 0x4f 0x2
63 KEY_F 33 ANSI_F 0x3 0x21 0x2b 0x2b 9 VK_F 0x46 33 33 XK_F 0x0046 KeyF AC04 f 0x50 0x3
64 KEY_F 33 ANSI_F 0x3 0x21 0x2b 0x2b 9 VK_F 0x46 33 33 XK_f 0x0066 KeyF AC04 f 0x50 0x3
65 KEY_G 34 ANSI_G 0x5 0x22 0x34 0x34 10 VK_G 0x47 34 34 XK_G 0x0047 KeyG AC05 g 0x51 0x5
66 KEY_G 34 ANSI_G 0x5 0x22 0x34 0x34 10 VK_G 0x47 34 34 XK_g 0x0067 KeyG AC05 g 0x51 0x5
67 KEY_H 35 ANSI_H 0x4 0x23 0x33 0x33 11 VK_H 0x48 35 35 XK_H 0x0048 KeyH AC06 h 0x52 0x4
68 KEY_H 35 ANSI_H 0x4 0x23 0x33 0x33 11 VK_H 0x48 35 35 XK_h 0x0068 KeyH AC06 h 0x52 0x4
69 KEY_J 36 ANSI_J 0x26 0x24 0x3b 0x3b 13 VK_J 0x4a 36 36 XK_J 0x004a KeyJ AC07 j 0x53 0x26
70 KEY_J 36 ANSI_J 0x26 0x24 0x3b 0x3b 13 VK_J 0x4a 36 36 XK_j 0x006a KeyJ AC07 j 0x53 0x26
71 KEY_K 37 ANSI_K 0x28 0x25 0x42 0x42 14 VK_K 0x4b 37 37 XK_K 0x004b KeyK AC08 k 0x54 0x28
72 KEY_K 37 ANSI_K 0x28 0x25 0x42 0x42 14 VK_K 0x4b 37 37 XK_k 0x006b KeyK AC08 k 0x54 0x28
73 KEY_L 38 ANSI_L 0x25 0x26 0x4b 0x4b 15 VK_L 0x4c 38 38 XK_L 0x004c KeyL AC09 l 0x55 0x25
74 KEY_L 38 ANSI_L 0x25 0x26 0x4b 0x4b 15 VK_L 0x4c 38 38 XK_l 0x006c KeyL AC09 l 0x55 0x25
75 KEY_SEMICOLON 39 ANSI_Semicolon 0x29 0x27 0x4c 0x4c 51 VK_OEM_1 0xba 39 39 XK_semicolon 0x003b Semicolon AC10 semicolon 0x56 0x29
76 KEY_SEMICOLON 39 ANSI_Semicolon 0x29 0x27 0x4c 0x4c 51 VK_OEM_1 0xba 39 39 XK_colon 0x003a Semicolon AC10 semicolon 0x56 0x29
77 KEY_APOSTROPHE 40 ANSI_Quote 0x27 0x28 0x52 0x52 52 VK_OEM_7 0xde 40 40 XK_apostrophe 0x0027 Quote AC11 apostrophe 0x57 0x27
78 KEY_APOSTROPHE 40 ANSI_Quote 0x27 0x28 0x52 0x52 52 VK_OEM_7 0xde 40 40 XK_quotedbl 0x0022 Quote AC11 apostrophe 0x57 0x27
79 KEY_GRAVE 41 ANSI_Grave 0x32 0x29 0x0e 0x0e 53 VK_OEM_3 0xc0 41 41 XK_grave 0x0060 Backquote TLDE grave_accent 0x2a 0x32
80 KEY_GRAVE 41 ANSI_Grave 0x32 0x29 0x0e 0x0e 53 VK_OEM_3 0xc0 41 41 XK_grave 0x0060 Backquote AB00 grave_accent 0x2a 0x32
81 KEY_GRAVE 41 ANSI_Grave 0x32 0x29 0x0e 0x0e 53 VK_OEM_3 0xc0 41 41 XK_asciitilde 0x007e Backquote TLDE grave_accent 0x2a 0x32
82 KEY_GRAVE 41 ANSI_Grave 0x32 0x29 0x0e 0x0e 53 VK_OEM_3 0xc0 41 41 XK_asciitilde 0x007e Backquote AB00 grave_accent 0x2a 0x32
83 KEY_SHIFT 42 Shift 0x38 0x2a 0x12 0x12 225 VK_SHIFT 0x10 42 42 XK_Shift_L 0xffe1 ShiftLeft LFSH shift 0x63 0x38
84 KEY_LEFTSHIFT 42 Shift 0x38 0x2a 0x12 0x12 225 VK_LSHIFT 0xa0 42 42 XK_Shift_L 0xffe1 ShiftLeft LFSH shift 0x63 0x38
85 KEY_BACKSLASH 43 ANSI_Backslash 0x2a 0x2b 0x5d 0x5c 49 VK_OEM_5 0xdc 43 43 XK_backslash 0x005c Backslash BKSL backslash 0x58 0x2a
86 KEY_BACKSLASH 43 ANSI_Backslash 0x2a 0x2b 0x5d 0x5c 49 VK_OEM_5 0xdc 43 43 XK_backslash 0x005c Backslash AC12 backslash 0x58 0x2a
87 KEY_BACKSLASH 43 ANSI_Backslash 0x2a 0x2b 0x5d 0x5c 49 VK_OEM_5 0xdc 43 43 XK_bar 0x007c Backslash BKSL backslash 0x58 0x2a
88 KEY_BACKSLASH 43 ANSI_Backslash 0x2a 0x2b 0x5d 0x5c 49 VK_OEM_5 0xdc 43 43 XK_bar 0x007c Backslash AC12 backslash 0x58 0x2a
89 KEY_BACKSLASH 43 ANSI_Backslash 0x2a 0x2b 0x5d 0x5c 50 VK_OEM_5 0xdc 43 43 XK_backslash 0x005c Backslash BKSL backslash 0x58 0x2a
90 KEY_BACKSLASH 43 ANSI_Backslash 0x2a 0x2b 0x5d 0x5c 50 VK_OEM_5 0xdc 43 43 XK_backslash 0x005c Backslash AC12 backslash 0x58 0x2a
91 KEY_BACKSLASH 43 ANSI_Backslash 0x2a 0x2b 0x5d 0x5c 50 VK_OEM_5 0xdc 43 43 XK_bar 0x007c Backslash BKSL backslash 0x58 0x2a
92 KEY_BACKSLASH 43 ANSI_Backslash 0x2a 0x2b 0x5d 0x5c 50 VK_OEM_5 0xdc 43 43 XK_bar 0x007c Backslash AC12 backslash 0x58 0x2a
93 KEY_Z 44 ANSI_Z 0x6 0x2c 0x1a 0x1a 29 VK_Z 0x5a 44 44 XK_Z 0x005a KeyZ AB01 z 0x64 0x6
94 KEY_Z 44 ANSI_Z 0x6 0x2c 0x1a 0x1a 29 VK_Z 0x5a 44 44 XK_z 0x007a KeyZ AB01 z 0x64 0x6
95 KEY_X 45 ANSI_X 0x7 0x2d 0x22 0x22 27 VK_X 0x58 45 45 XK_X 0x0058 KeyX AB02 x 0x65 0x7
96 KEY_X 45 ANSI_X 0x7 0x2d 0x22 0x22 27 VK_X 0x58 45 45 XK_x 0x0078 KeyX AB02 x 0x65 0x7
97 KEY_C 46 ANSI_C 0x8 0x2e 0x21 0x21 6 VK_C 0x43 46 46 XK_C 0x0043 KeyC AB03 c 0x66 0x8
98 KEY_C 46 ANSI_C 0x8 0x2e 0x21 0x21 6 VK_C 0x43 46 46 XK_c 0x0063 KeyC AB03 c 0x66 0x8
99 KEY_V 47 ANSI_V 0x9 0x2f 0x2a 0x2a 25 VK_V 0x56 47 47 XK_V 0x0056 KeyV AB04 v 0x67 0x9
100 KEY_V 47 ANSI_V 0x9 0x2f 0x2a 0x2a 25 VK_V 0x56 47 47 XK_v 0x0076 KeyV AB04 v 0x67 0x9
101 KEY_B 48 ANSI_B 0xb 0x30 0x32 0x32 5 VK_B 0x42 48 48 XK_B 0x0042 KeyB AB05 b 0x68 0xb
102 KEY_B 48 ANSI_B 0xb 0x30 0x32 0x32 5 VK_B 0x42 48 48 XK_b 0x0062 KeyB AB05 b 0x68 0xb
103 KEY_N 49 ANSI_N 0x2d 0x31 0x31 0x31 17 VK_N 0x4e 49 49 XK_N 0x004e KeyN AB06 n 0x69 0x2d
104 KEY_N 49 ANSI_N 0x2d 0x31 0x31 0x31 17 VK_N 0x4e 49 49 XK_n 0x006e KeyN AB06 n 0x69 0x2d
105 KEY_M 50 ANSI_M 0x2e 0x32 0x3a 0x3a 16 VK_M 0x4d 50 50 XK_M 0x004d KeyM AB07 m 0x6a 0x2e
106 KEY_M 50 ANSI_M 0x2e 0x32 0x3a 0x3a 16 VK_M 0x4d 50 50 XK_m 0x006d KeyM AB07 m 0x6a 0x2e
107 KEY_COMMA 51 ANSI_Comma 0x2b 0x33 0x41 0x41 54 VK_OEM_COMMA 0xbc 51 51 XK_comma 0x002c Comma AB08 comma 0x6b 0x2b
108 KEY_COMMA 51 ANSI_Comma 0x2b 0x33 0x41 0x41 54 VK_OEM_COMMA 0xbc 51 51 XK_less 0x003c Comma AB08 comma 0x6b 0x2b
109 KEY_DOT 52 ANSI_Period 0x2f 0x34 0x49 0x49 55 VK_OEM_PERIOD 0xbe 52 52 XK_period 0x002e Period AB09 dot 0x6c 0x2f
110 KEY_DOT 52 ANSI_Period 0x2f 0x34 0x49 0x49 55 VK_OEM_PERIOD 0xbe 52 52 XK_greater 0x003e Period AB09 dot 0x6c 0x2f
111 KEY_SLASH 53 ANSI_Slash 0x2c 0x35 0x4a 0x4a 56 VK_OEM_2 0xbf 53 53 XK_slash 0x002f Slash AB10 slash 0x6d 0x2c
112 KEY_SLASH 53 ANSI_Slash 0x2c 0x35 0x4a 0x4a 56 VK_OEM_2 0xbf 53 53 XK_question 0x003f Slash AB10 slash 0x6d 0x2c
113 KEY_RIGHTSHIFT 54 RightShift 0x3c 0x36 0x59 0x59 229 VK_RSHIFT 0xa1 54 54 XK_Shift_R 0xffe2 ShiftRight RTSH shift_r 0x6e 0x7b
114 KEY_KPASTERISK 55 ANSI_KeypadMultiply 0x43 0x37 0x7c 0x7e 85 VK_MULTIPLY 0x6a 55 55 XK_multiply 0x00d7 NumpadMultiply KPMU asterisk 0x2f 0x43
115 KEY_KPASTERISK 55 ANSI_KeypadMultiply 0x43 0x37 0x7c 0x7e 85 VK_MULTIPLY 0x6a 55 55 XK_multiply 0x00d7 NumpadMultiply KPMU kp_multiply 0x2f 0x43
116 KEY_LEFTALT 56 Option 0x3a 0x38 0x11 0x19 226 VK_LMENU 0xa4 56 56 XK_Alt_L 0xffe9 AltLeft LALT alt 0x13 0x3a
117 KEY_LEFTALT 56 Option 0x3a 0x38 0x11 0x19 226 VK_MENU 0x12 56 56 XK_Alt_L 0xffe9 AltLeft LALT alt 0x13 0x3a
118 KEY_SPACE 57 Space 0x31 0x39 0x29 0x29 44 VK_SPACE 0x20 57 57 XK_space 0x0020 Space SPCE spc 0x79 0x31
119 KEY_CAPSLOCK 58 CapsLock 0x39 0x3a 0x58 0x14 57 VK_CAPITAL 0x14 58 58 XK_Caps_Lock 0xffe5 CapsLock CAPS caps_lock 0x77 0x39
120 KEY_F1 59 F1 0x7a 0x3b 0x05 0x07 58 VK_F1 0x70 59 59 XK_F1 0xffbe F1 FK01 f1 0x05 0x7a
121 KEY_F2 60 F2 0x78 0x3c 0x06 0x0f 59 VK_F2 0x71 60 60 XK_F2 0xffbf F2 FK02 f2 0x06 0x78
122 KEY_F3 61 F3 0x63 0x3d 0x04 0x17 60 VK_F3 0x72 61 61 XK_F3 0xffc0 F3 FK03 f3 0x08 0x63
123 KEY_F4 62 F4 0x76 0x3e 0x0c 0x1f 61 VK_F4 0x73 62 62 XK_F4 0xffc1 F4 FK04 f4 0x0a 0x76
124 KEY_F5 63 F5 0x60 0x3f 0x03 0x27 62 VK_F5 0x74 63 63 XK_F5 0xffc2 F5 FK05 f5 0x0c 0x60
125 KEY_F6 64 F6 0x61 0x40 0x0b 0x2f 63 VK_F6 0x75 64 64 XK_F6 0xffc3 F6 FK06 f6 0x0e 0x61
126 KEY_F7 65 F7 0x62 0x41 0x83 0x37 64 VK_F7 0x76 65 65 XK_F7 0xffc4 F7 FK07 f7 0x10 0x62
127 KEY_F8 66 F8 0x64 0x42 0x0a 0x3f 65 VK_F8 0x77 66 66 XK_F8 0xffc5 F8 FK08 f8 0x11 0x64
128 KEY_F9 67 F9 0x65 0x43 0x01 0x47 66 VK_F9 0x78 67 67 XK_F9 0xffc6 F9 FK09 f9 0x12 0x65
129 KEY_F10 68 F10 0x6d 0x44 0x09 0x4f 67 VK_F10 0x79 68 68 XK_F10 0xffc7 F10 FK10 f10 0x07 0x6d
130 KEY_NUMLOCK 69 ANSI_KeypadClear 0x47 0x45 0x77 0x76 83 VK_NUMLOCK 0x90 69 69 XK_Num_Lock 0xff7f NumLock NMLK num_lock 0x62 0x47
131 KEY_SCROLLLOCK 70 0x46 0x7e 0x5f 71 VK_SCROLL 0x91 70 70 XK_Scroll_Lock 0xff14 ScrollLock SCLK scroll_lock 0x17 0x6b
132 KEY_KP7 71 ANSI_Keypad7 0x59 0x47 0x6c 0x6c 95 VK_NUMPAD7 0x67 71 71 XK_KP_7 0xffb7 Numpad7 KP7 kp_7 0x44 0x59
133 KEY_KP8 72 ANSI_Keypad8 0x5b 0x48 0x75 0x75 96 VK_NUMPAD8 0x68 72 72 XK_KP_8 0xffb8 Numpad8 KP8 kp_8 0x45 0x5b
134 KEY_KP9 73 ANSI_Keypad9 0x5c 0x49 0x7d 0x7d 97 VK_NUMPAD9 0x69 73 73 XK_KP_9 0xffb9 Numpad9 KP9 kp_9 0x46 0x5c
135 KEY_KPMINUS 74 ANSI_KeypadMinus 0x4e 0x4a 0x7b 0x4e 86 VK_SUBTRACT 0x6d 74 74 XK_KP_Subtract 0xffad NumpadSubtract KPSU kp_subtract 0x47 0x4e
136 KEY_KP4 75 ANSI_Keypad4 0x56 0x4b 0x6b 0x6b 92 VK_NUMPAD4 0x64 75 75 XK_KP_4 0xffb4 Numpad4 KP4 kp_4 0x5b 0x56
137 KEY_KP5 76 ANSI_Keypad5 0x57 0x4c 0x73 0x73 93 VK_NUMPAD5 0x65 76 76 XK_KP_5 0xffb5 Numpad5 KP5 kp_5 0x5c 0x57
138 KEY_KP6 77 ANSI_Keypad6 0x58 0x4d 0x74 0x74 94 VK_NUMPAD6 0x66 77 77 XK_KP_6 0xffb6 Numpad6 KP6 kp_6 0x5d 0x58
139 KEY_KPPLUS 78 ANSI_KeypadPlus 0x45 0x4e 0x79 0x7c 87 VK_ADD 0x6b 78 78 XK_KP_Add 0xffab NumpadAdd KPAD kp_add 0x7d 0x45
140 KEY_KP1 79 ANSI_Keypad1 0x53 0x4f 0x69 0x69 89 VK_NUMPAD1 0x61 79 79 XK_KP_1 0xffb1 Numpad1 KP1 kp_1 0x70 0x53
141 KEY_KP2 80 ANSI_Keypad2 0x54 0x50 0x72 0x72 90 VK_NUMPAD2 0x62 80 80 XK_KP_2 0xffb2 Numpad2 KP2 kp_2 0x71 0x54
142 KEY_KP3 81 ANSI_Keypad3 0x55 0x51 0x7a 0x7a 91 VK_NUMPAD3 0x63 81 81 XK_KP_3 0xffb3 Numpad3 KP3 kp_3 0x72 0x55
143 KEY_KP0 82 ANSI_Keypad0 0x52 0x52 0x70 0x70 98 VK_NUMPAD0 0x60 82 82 XK_KP_0 0xffb0 Numpad0 KP0 kp_0 0x5e 0x52
144 KEY_KPDOT 83 ANSI_KeypadDecimal 0x41 0x53 0x71 0x71 99 VK_DECIMAL 0x6e 83 83 XK_KP_Decimal 0xffae NumpadDecimal KPDL kp_decimal 0x32 0x41
145 KEY_KPDOT 83 ANSI_KeypadDecimal 0x41 0x53 0x71 0x71 99 VK_DECIMAL 0x6e 83 83 XK_KP_Decimal 0xffae NumpadDecimal KPDC kp_decimal 0x32 0x41
146 84 0x54
147 KEY_ZENKAKUHANKAKU 85 0x76 0x5f 148 Lang5 HZTG
148 KEY_102ND 86 0x56 0x61 0x13 100 VK_OEM_102 0xe1 86 86 IntlBackslash LSGT less 0x7c
149 KEY_F11 87 F11 0x67 0x57 0x78 0x56 68 VK_F11 0x7a 87 87 XK_F11 0xffc8 F11 FK11 f11 0x09 0x67
150 KEY_F12 88 F12 0x6f 0x58 0x07 0x5e 69 VK_F12 0x7b 88 88 XK_F12 0xffc9 F12 FK12 f12 0x0b 0x6f
151 KEY_RO 89 0x73 0x51 135 IntlRo AB11 ro
152 KEY_KATAKANA 90 JIS_Kana 0x68 0x78 0x63 146 VK_KANA 0x15 Katakana KATA
153 KEY_KATAKANA 90 JIS_Kana 0x68 0x78 0x63 146 VK_KANA 0x15 Lang3 KATA
154 KEY_HIRAGANA 91 0x77 0x62 0x87 147 Hiragana HIRA hiragana
155 KEY_HIRAGANA 91 0x77 0x62 0x87 147 Lang4 HIRA hiragana
156 KEY_HENKAN 92 0x79 0x64 0x86 138 Convert HENK henkan
157 KEY_KATAKANAHIRAGANA 93 0x70 0x13 0x87 136 0xc8 0xc8 KanaMode HKTG
158 KEY_MUHENKAN 94 0x7b 0x67 0x85 139 NonConvert NFER
159 KEY_MUHENKAN 94 0x7b 0x67 0x85 139 NonConvert MUHE
160 KEY_KPJPCOMMA 95 JIS_KeypadComma 0x5f 0x5c 0x27 140 XK_KP_Separator 0xffac KPSP
161 KEY_KPJPCOMMA 95 JIS_KeypadComma 0x5f 0x5c 0x27 140 XK_KP_Separator 0xffac JPCM
162 KEY_KPENTER 96 ANSI_KeypadEnter 0x4c 0xe01c 0xe05a 0x79 88 0x64 0x64 XK_KP_Enter 0xff8d NumpadEnter KPEN kp_enter 0x5a 0x4c
163 KEY_RIGHTCTRL 97 RightControl 0x3e 0xe01d 0xe014 0x58 228 VK_RCONTROL 0xa3 0x65 0x65 XK_Control_R 0xffe4 ControlRight RCTL ctrl_r 0x4c 0x7d
164 KEY_KPSLASH 98 ANSI_KeypadDivide 0x4b 0xe035 0xe04a 0x4a 84 VK_DIVIDE 0x6f 0x68 0x68 XK_KP_Divide 0xffaf NumpadDivide KPDV kp_divide 0x2e 0x4b
165 KEY_SYSRQ 99 0x54 0x7f 0x57 70 VK_SNAPSHOT 0x2c 0x67 0x67 XK_Sys_Req 0xff15 PrintScreen PRSC print 0x16 0x69
166 KEY_SYSRQ 99 0x54 0x7f 0x57 70 VK_SNAPSHOT 0x2c 0x67 0x67 XK_Sys_Req 0xff15 PrintScreen SYRQ sysrq 0x16 0x69
167 KEY_RIGHTALT 100 RightOption 0x3d 0xe038 0xe011 0x39 230 VK_RMENU 0xa5 0x69 0x69 XK_Alt_R 0xffea AltRight ALGR alt_r 0x0d 0x7c
168 KEY_RIGHTALT 100 RightOption 0x3d 0xe038 0xe011 0x39 230 VK_RMENU 0xa5 0x69 0x69 XK_Alt_R 0xffea AltRight RALT alt_r 0x0d 0x7c
169 KEY_LINEFEED 101 0x5b LNFD lf 0x6f
170 KEY_HOME 102 Home 0x73 0xe047 0xe06c 0x6e 74 VK_HOME 0x24 0x59 0x59 XK_Home 0xff50 Home HOME home 0x34 0x73
171 KEY_UP 103 UpArrow 0x7e 0xe048 0xe075 0x63 82 VK_UP 0x26 0x5a 0x5a XK_Up 0xff52 ArrowUp UP up 0x14 0x3e
172 KEY_PAGEUP 104 PageUp 0x74 0xe049 0xe07d 0x6f 75 VK_PRIOR 0x21 0x5b 0x5b XK_Page_Up 0xff55 PageUp PGUP pgup 0x60 0x74
173 KEY_LEFT 105 LeftArrow 0x7b 0xe04b 0xe06b 0x61 80 VK_LEFT 0x25 0x5c 0x5c XK_Left 0xff51 ArrowLeft LEFT left 0x18 0x3b
174 KEY_RIGHT 106 RightArrow 0x7c 0xe04d 0xe074 0x6a 79 VK_RIGHT 0x27 0x5e 0x5e XK_Right 0xff53 ArrowRight RGHT right 0x1c 0x3c
175 KEY_END 107 End 0x77 0xe04f 0xe069 0x65 77 VK_END 0x23 0x5f 0x5f XK_End 0xff57 End END end 0x4a 0x77
176 KEY_DOWN 108 DownArrow 0x7d 0xe050 0xe072 0x60 81 VK_DOWN 0x28 0x60 0x60 XK_Down 0xff54 ArrowDown DOWN down 0x1b 0x3d
177 KEY_PAGEDOWN 109 PageDown 0x79 0xe051 0xe07a 0x6d 78 VK_NEXT 0x22 0x61 0x61 XK_Page_Down 0xff56 PageDown PGDN pgdn 0x7b 0x79
178 KEY_INSERT 110 0xe052 0xe070 0x67 73 VK_INSERT 0x2d 0x62 0x62 XK_Insert 0xff63 Insert INS insert 0x2c 0x72
179 KEY_DELETE 111 ForwardDelete 0x75 0xe053 0xe071 0x64 76 VK_DELETE 0x2e 0x63 0x63 XK_Delete 0xffff Delete DEL delete 0x42 0x75
180 KEY_DELETE 111 ForwardDelete 0x75 0xe053 0xe071 0x64 76 VK_DELETE 0x2e 0x63 0x63 XK_Delete 0xffff Delete DELE 0x42 0x75
181 KEY_MACRO 112 0xe06f 0xe06f 0x8e I120
182 KEY_MUTE 113 Mute 0x4a 0xe020 0xe023 0x9c 127 VK_VOLUME_MUTE 0xad AudioVolumeMute MUTE audiomute
183 KEY_MUTE 113 Mute 0x4a 0xe020 0xe023 0x9c 239 VK_VOLUME_MUTE 0xad AudioVolumeMute MUTE audiomute
184 KEY_VOLUMEDOWN 114 VolumeDown 0x49 0xe02e 0xe021 0x9d 129 VK_VOLUME_DOWN 0xae AudioVolumeDown VOL- volumedown
185 KEY_VOLUMEDOWN 114 VolumeDown 0x49 0xe02e 0xe021 0x9d 238 VK_VOLUME_DOWN 0xae AudioVolumeDown VOL- volumedown
186 KEY_VOLUMEUP 115 VolumeUp 0x48 0xe030 0xe032 0x95 128 VK_VOLUME_UP 0xaf AudioVolumeUp VOL+ volumeup
187 KEY_VOLUMEUP 115 VolumeUp 0x48 0xe030 0xe032 0x95 237 VK_VOLUME_UP 0xaf AudioVolumeUp VOL+ volumeup
188 KEY_POWER 116 0xe05e 0xe037 102 Power POWR power 0x7f7f
189 KEY_KPEQUAL 117 ANSI_KeypadEquals 0x51 0x59 0x0f 103 0x76 0x76 XK_KP_Equal 0xffbd NumpadEqual KPEQ kp_equals 0x2d 0x51
190 KEY_KPPLUSMINUS 118 0xe04e 0xe079 I126
191 KEY_PAUSE 119 0xe046 0xe077 0x62 72 VK_PAUSE 0x013 0x66 0x66 XK_Pause 0xff13 Pause PAUS pause 0x15 0x71
192 KEY_SCALE 120 0xe00b I128
193 KEY_KPCOMMA 121 0x7e 0x6d 133 VK_SEPARATOR?? 0x6c NumpadComma KPCO kp_comma
194 KEY_KPCOMMA 121 0x7e 0x6d 133 VK_SEPARATOR?? 0x6c NumpadComma I129
195 KEY_HANGEUL 122 144 VK_HANGEUL 0x15 HNGL
196 KEY_HANJA 123 0xe00d 145 VK_HANJA 0x19 HJCV
197 KEY_YEN 124 JIS_Yen 0x5d 0x7d 0x6a 0x5d 137 0x7d 0x7d IntlYen AE13 yen
198 KEY_LEFTMETA 125 Command 0x37 0xe05b 0xe01f 0x8b 227 VK_LWIN 0x5b 0x6b 0x6b XK_Meta_L 0xffe7 MetaLeft LMTA meta_l 0x78 0x37
199 KEY_LEFTMETA 125 Command 0x37 0xe05b 0xe01f 0x8b 227 VK_LWIN 0x5b 0x6b 0x6b XK_Meta_L 0xffe7 MetaLeft LWIN meta_l 0x78 0x37
200 KEY_RIGHTMETA 126 RightCommand 0x36 0xe05c 0xe027 0x8c 231 VK_RWIN 0x5c 0x6c 0x6c XK_Meta_R 0xffe8 MetaRight RMTA meta_r 0x7a 0x37
201 KEY_RIGHTMETA 126 RightCommand 0x36 0xe05c 0xe027 0x8c 231 VK_RWIN 0x5c 0x6c 0x6c XK_Meta_R 0xffe8 MetaRight RWIN meta_r 0x7a 0x37
202 KEY_COMPOSE 127 0x6e 0xe05d 0xe02f 0x8d 101 VK_APPS 0x5d 0x6d 0x6d ContextMenu MENU compose 0x43
203 KEY_COMPOSE 127 0x6e 0xe05d 0xe02f 0x8d 101 VK_APPS 0x5d 0x6d 0x6d ContextMenu COMP compose 0x43
204 KEY_STOP 128 0xe068 0xe028 0x0a 120 VK_BROWSER_STOP 0xa9 BrowserStop STOP stop 0x01
205 KEY_STOP 128 0xe068 0xe028 0x0a 243 VK_BROWSER_STOP 0xa9 BrowserStop STOP stop 0x01
206 KEY_AGAIN 129 0xe005 0x0b 121 Again AGAI again 0x03
207 KEY_PROPS 130 0xe006 0x0c Props PROP props 0x19
208 KEY_UNDO 131 0xe007 0x10 122 Undo UNDO undo 0x1a
209 KEY_FRONT 132 0xe00c 119 FRNT front 0x31
210 KEY_COPY 133 0xe078 0x18 124 Copy COPY copy 0x33
211 KEY_OPEN 134 0x64 0x20 116 Open OPEN open 0x48
212 KEY_PASTE 135 0x65 0x28 125 Paste PAST paste 0x49
213 KEY_FIND 136 0xe041 0x30 126 Find FIND find 0x5f
214 KEY_FIND 136 0xe041 0x30 244 Find FIND find 0x5f
215 KEY_CUT 137 0xe03c 0x38 123 Cut CUT cut 0x61
216 KEY_HELP 138 Help 0x72 0xe075 0x09 117 VK_HELP 0x2f XK_Help 0xff6a Help HELP help 0x76
217 KEY_MENU 139 0xe01e 0x91 118 I147 menu
218 KEY_CALC 140 0xe021 0xe02b 0xa3 251 LaunchApp2 I148 calculator
219 KEY_SETUP 141 0x66 I149
220 KEY_SLEEP 142 0xe05f 0xe03f 248 VK_SLEEP 0x5f Sleep I150 sleep
221 KEY_WAKEUP 143 0xe063 0xe05e WakeUp I151 wake
222 KEY_FILE 144 0x67 I152
223 KEY_SENDFILE 145 0x68 I153
224 KEY_DELETEFILE 146 0x69 I154
225 KEY_XFER 147 0xe013 0xa2 XFER
226 KEY_XFER 147 0xe013 0xa2 I155
227 KEY_PROG1 148 0xe01f 0xa0 I156
228 KEY_PROG2 149 0xe017 0xa1 I157
229 KEY_WWW 150 0xe002 240 I158
230 KEY_MSDOS 151 0x6a I159
231 KEY_SCREENLOCK 152 0xe012 0x96 249 I160
232 KEY_DIRECTION 153 0x6b I161
233 KEY_CYCLEWINDOWS 154 0xe026 0x9b I162
234 KEY_MAIL 155 0xe06c 0xe048 LaunchMail I163 mail
235 KEY_BOOKMARKS 156 0xe066 0xe018 BrowserFavorites I164 ac_bookmarks
236 KEY_COMPUTER 157 0xe06b 0xe040 LaunchApp1 I165 computer
237 KEY_BACK 158 0xe06a 0xe038 241 VK_BROWSER_BACK 0xa6 BrowserBack I166 ac_back
238 KEY_FORWARD 159 0xe069 0xe030 242 VK_BROWSER_FORWARD 0xa7 BrowserForward I167 ac_forward
239 KEY_CLOSECD 160 0xe023 0x9a I168
240 KEY_EJECTCD 161 0x6c 236 I169
241 KEY_EJECTCLOSECD 162 0xe07d Eject I170
242 KEY_NEXTSONG 163 0xe019 0xe04d 0x93 235 VK_MEDIA_NEXT_TRACK 0xb0 MediaTrackNext I171 audionext
243 KEY_PLAYPAUSE 164 0xe022 0xe034 232 VK_MEDIA_PLAY_PAUSE 0xb3 MediaPlayPause I172 audioplay
244 KEY_PREVIOUSSONG 165 0xe010 0xe015 0x94 234 VK_MEDIA_PREV_TRACK 0xb1 MediaTrackPrevious I173 audioprev
245 KEY_STOPCD 166 0xe024 0xe03b 0x98 233 VK_MEDIA_STOP 0xb2 MediaStop I174 audiostop
246 KEY_RECORD 167 0xe031 0x9e I175
247 KEY_REWIND 168 0xe018 0x9f I176
248 KEY_PHONE 169 0x63 I177
249 KEY_ISO 170 ISO_Section 0xa 0x70 I178
250 KEY_CONFIG 171 0xe001 I179
251 KEY_HOMEPAGE 172 0xe032 0xe03a 0x97 VK_BROWSER_HOME 0xac BrowserHome I180 ac_home
252 KEY_REFRESH 173 0xe067 0xe020 250 VK_BROWSER_REFRESH 0xa8 BrowserRefresh I181 ac_refresh
253 KEY_EXIT 174 0x71 I182
254 KEY_MOVE 175 0x72 I183
255 KEY_EDIT 176 0xe008 247 I184
256 KEY_SCROLLUP 177 0x75 245 I185
257 KEY_SCROLLDOWN 178 0xe00f 246 I186
258 KEY_KPLEFTPAREN 179 0xe076 182 NumpadParenLeft I187
259 KEY_KPRIGHTPAREN 180 0xe07b 183 NumpadParenRight I188
260 KEY_NEW 181 0xe009 I189
261 KEY_REDO 182 0xe00a I190
262 KEY_F13 183 F13 0x69 0x5d 0x2f 0x7f 104 VK_F13 0x7c 0x6e 0x6e F13 FK13 0x69
263 KEY_F14 184 F14 0x6b 0x5e 0x37 0x80 105 VK_F14 0x7d 0x6f 0x6f F14 FK14 0x6b
264 KEY_F15 185 F15 0x71 0x5f 0x3f 0x81 106 VK_F15 0x7e 0x70 0x70 F15 FK15 0x71
265 KEY_F16 186 F16 0x6a 0x55 0x82 107 VK_F16 0x7f 0x71 0x71 F16 FK16
266 KEY_F17 187 F17 0x40 0xe003 0x83 108 VK_F17 0x80 0x72 0x72 F17 FK17
267 KEY_F18 188 F18 0x4f 0xe077 109 VK_F18 0x81 F18 FK18
268 KEY_F19 189 F19 0x50 0xe004 110 VK_F19 0x82 F19 FK19
269 KEY_F20 190 F20 0x5a 0x5a 111 VK_F20 0x83 F20 FK20
270 KEY_F21 191 0x74 112 VK_F21 0x84 F21 FK21
271 KEY_F22 192 0xe079 113 VK_F22 0x85 F22 FK22
272 KEY_F23 193 0x6d 114 VK_F23 0x86 F23 FK23
273 KEY_F24 194 0x6f 115 VK_F24 0x87 F24 FK24
274 195 0xe015
275 196 0xe016
276 197 0xe01a
277 198 0xe01b
278 199 0xe027
279 KEY_PLAYCD 200 0xe028 I208
280 KEY_PAUSECD 201 0xe029 I209
281 KEY_PROG3 202 0xe02b I210
282 KEY_PROG4 203 0xe02c I211
283 KEY_DASHBOARD 204 0xe02d I212
284 KEY_SUSPEND 205 0xe025 Suspend I213
285 KEY_CLOSE 206 0xe02f I214
286 KEY_PLAY 207 0xe033 VK_PLAY 0xfa I215
287 KEY_FASTFORWARD 208 0xe034 I216
288 KEY_BASSBOOST 209 0xe036 I217
289 KEY_PRINT 210 0xe039 VK_PRINT 0x2a I218
290 KEY_HP 211 0xe03a I219
291 KEY_CAMERA 212 0xe03b I220
292 KEY_SOUND 213 0xe03d I221
293 KEY_QUESTION 214 0xe03e I222
294 KEY_EMAIL 215 0xe03f VK_LAUNCH_MAIL 0xb4 I223
295 KEY_CHAT 216 0xe040 I224
296 KEY_SEARCH 217 0xe065 0xe010 VK_BROWSER_SEARCH 0xaa BrowserSearch I225
297 KEY_CONNECT 218 0xe042 I226
298 KEY_FINANCE 219 0xe043 I227
299 KEY_SPORT 220 0xe044 I228
300 KEY_SHOP 221 0xe045 I229
301 KEY_ALTERASE 222 0xe014 I230
302 KEY_CANCEL 223 0xe04a I231
303 KEY_BRIGHTNESSDOWN 224 0xe04c I232
304 KEY_BRIGHTNESSUP 225 0xe054 I233
305 KEY_MEDIA 226 0xe06d 0xe050 MediaSelect I234 mediaselect
306 KEY_SWITCHVIDEOMODE 227 0xe056 I235
307 KEY_KBDILLUMTOGGLE 228 0xe057 I236
308 KEY_KBDILLUMDOWN 229 0xe058 I237
309 KEY_KBDILLUMUP 230 0xe059 I238
310 KEY_SEND 231 0xe05a I239
311 KEY_REPLY 232 0xe064 I240
312 KEY_FORWARDMAIL 233 0xe00e I241
313 KEY_SAVE 234 0xe055 I242
314 KEY_DOCUMENTS 235 0xe070 I243
315 KEY_BATTERY 236 0xe071 I244
316 KEY_BLUETOOTH 237 0xe072 I245
317 KEY_WLAN 238 0xe073 I246
318 KEY_UWB 239 0xe074 I247
319 KEY_UNKNOWN 240 I248
320 KEY_VIDEO_NEXT 241 I249
321 KEY_VIDEO_PREV 242 I250
322 KEY_BRIGHTNESS_CYCLE 243 I251
323 KEY_BRIGHTNESS_ZERO 244 I252
324 KEY_DISPLAY_OFF 245 I253
325 KEY_WIMAX 246
326 247
327 248
328 249
329 250
330 251
331 252
332 253
333 254
334 255 0xe012
335 BTN_MISC 0x100
336 BTN_0 0x100 VK_LBUTTON 0x01
337 BTN_1 0x101 VK_RBUTTON 0x02
338 BTN_2 0x102 VK_MBUTTON 0x04
339 BTN_3 0x103 VK_XBUTTON1 0x05
340 BTN_4 0x104 VK_XBUTTON2 0x06
341 BTN_5 0x105
342 BTN_6 0x106
343 BTN_7 0x107
344 BTN_8 0x108
345 BTN_9 0x109
346 BTN_MOUSE 0x110
347 BTN_LEFT 0x110
348 BTN_RIGHT 0x111
349 BTN_MIDDLE 0x112
350 BTN_SIDE 0x113
351 BTN_EXTRA 0x114
352 BTN_FORWARD 0x115
353 BTN_BACK 0x116
354 BTN_TASK 0x117
355 BTN_JOYSTICK 0x120
356 BTN_TRIGGER 0x120
357 BTN_THUMB 0x121
358 BTN_THUMB2 0x122
359 BTN_TOP 0x123
360 BTN_TOP2 0x124
361 BTN_PINKIE 0x125
362 BTN_BASE 0x126
363 BTN_BASE2 0x127
364 BTN_BASE3 0x128
365 BTN_BASE4 0x129
366 BTN_BASE5 0x12a
367 BTN_BASE6 0x12b
368 BTN_DEAD 0x12f
369 BTN_GAMEPAD 0x130
370 BTN_A 0x130
371 BTN_B 0x131
372 BTN_C 0x132
373 BTN_X 0x133
374 BTN_Y 0x134
375 BTN_Z 0x135
376 BTN_TL 0x136
377 BTN_TR 0x137
378 BTN_TL2 0x138
379 BTN_TR2 0x139
380 BTN_SELECT 0x13a
381 BTN_START 0x13b
382 BTN_MODE 0x13c
383 BTN_THUMBL 0x13d
384 BTN_THUMBR 0x13e
385 BTN_DIGI 0x140
386 BTN_TOOL_PEN 0x140
387 BTN_TOOL_RUBBER 0x141
388 BTN_TOOL_BRUSH 0x142
389 BTN_TOOL_PENCIL 0x143
390 BTN_TOOL_AIRBRUSH 0x144
391 BTN_TOOL_FINGER 0x145
392 BTN_TOOL_MOUSE 0x146
393 BTN_TOOL_LENS 0x147
394 BTN_TOUCH 0x14a
395 BTN_STYLUS 0x14b
396 BTN_STYLUS2 0x14c
397 BTN_TOOL_DOUBLETAP 0x14d
398 BTN_TOOL_TRIPLETAP 0x14e
399 BTN_TOOL_QUADTAP 0x14f
400 BTN_WHEEL 0x150
401 BTN_GEAR_DOWN 0x150
402 BTN_GEAR_UP 0x151
403 KEY_OK 0x160
404 KEY_SELECT 0x161 VK_SELECT 0x29 XK_Select 0xff60 Select SELE
405 KEY_GOTO 0x162
406 KEY_CLEAR 0x163 NumpadClear CLR
407 KEY_POWER2 0x164
408 KEY_OPTION 0x165
409 KEY_INFO 0x166
410 KEY_TIME 0x167
411 KEY_VENDOR 0x168
412 KEY_ARCHIVE 0x169
413 KEY_PROGRAM 0x16a
414 KEY_CHANNEL 0x16b
415 KEY_FAVORITES 0x16c VK_BROWSER_FAVOURITES 0xab
416 KEY_EPG 0x16d
417 KEY_PVR 0x16e
418 KEY_MHP 0x16f
419 KEY_LANGUAGE 0x170
420 KEY_TITLE 0x171
421 KEY_SUBTITLE 0x172
422 KEY_ANGLE 0x173
423 KEY_ZOOM 0x174 VK_ZOOM 0xfb
424 KEY_MODE 0x175
425 KEY_KEYBOARD 0x176
426 KEY_SCREEN 0x177
427 KEY_PC 0x178
428 KEY_TV 0x179
429 KEY_TV2 0x17a
430 KEY_VCR 0x17b
431 KEY_VCR2 0x17c
432 KEY_SAT 0x17d
433 KEY_SAT2 0x17e
434 KEY_CD 0x17f
435 KEY_TAPE 0x180
436 KEY_RADIO 0x181
437 KEY_TUNER 0x182
438 KEY_PLAYER 0x183
439 KEY_TEXT 0x184
440 KEY_DVD 0x185
441 KEY_AUX 0x186
442 KEY_MP3 0x187
443 KEY_AUDIO 0x188
444 KEY_VIDEO 0x189
445 KEY_DIRECTORY 0x18a
446 KEY_LIST 0x18b
447 KEY_MEMO 0x18c
448 KEY_CALENDAR 0x18d
449 KEY_RED 0x18e
450 KEY_GREEN 0x18f
451 KEY_YELLOW 0x190
452 KEY_BLUE 0x191
453 KEY_CHANNELUP 0x192
454 KEY_CHANNELDOWN 0x193
455 KEY_FIRST 0x194
456 KEY_LAST 0x195
457 KEY_AB 0x196
458 KEY_NEXT 0x197
459 KEY_RESTART 0x198
460 KEY_SLOW 0x199
461 KEY_SHUFFLE 0x19a
462 KEY_BREAK 0x19b BREA
463 KEY_BREAK 0x19b BRK
464 KEY_PREVIOUS 0x19c
465 KEY_DIGITS 0x19d
466 KEY_TEEN 0x19e
467 KEY_TWEN 0x19f
468 KEY_VIDEOPHONE 0x1a0
469 KEY_GAMES 0x1a1
470 KEY_ZOOMIN 0x1a2
471 KEY_ZOOMOUT 0x1a3
472 KEY_ZOOMRESET 0x1a4
473 KEY_WORDPROCESSOR 0x1a5
474 KEY_EDITOR 0x1a6
475 KEY_SPREADSHEET 0x1a7
476 KEY_GRAPHICSEDITOR 0x1a8
477 KEY_PRESENTATION 0x1a9
478 KEY_DATABASE 0x1aa
479 KEY_NEWS 0x1ab
480 KEY_VOICEMAIL 0x1ac
481 KEY_ADDRESSBOOK 0x1ad
482 KEY_MESSENGER 0x1ae
483 KEY_DISPLAYTOGGLE 0x1af
484 KEY_SPELLCHECK 0x1b0
485 KEY_LOGOFF 0x1b1
486 KEY_DOLLAR 0x1b2
487 KEY_EURO 0x1b3
488 KEY_FRAMEBACK 0x1b4
489 KEY_FRAMEFORWARD 0x1b5
490 KEY_CONTEXT_MENU 0x1b6
491 KEY_MEDIA_REPEAT 0x1b7
492 KEY_DEL_EOL 0x1c0
493 KEY_DEL_EOS 0x1c1
494 KEY_INS_LINE 0x1c2
495 KEY_DEL_LINE 0x1c3
496 KEY_FN 0x1d0 Function 0x3f Fn
497 KEY_FN_ESC 0x1d1
498 KEY_FN_F1 0x1d2
499 KEY_FN_F2 0x1d3
500 KEY_FN_F3 0x1d4
501 KEY_FN_F4 0x1d5
502 KEY_FN_F5 0x1d6
503 KEY_FN_F6 0x1d7
504 KEY_FN_F7 0x1d8
505 KEY_FN_F8 0x1d9
506 KEY_FN_F9 0x1da
507 KEY_FN_F10 0x1db
508 KEY_FN_F11 0x1dc
509 KEY_FN_F12 0x1dd
510 KEY_FN_1 0x1de
511 KEY_FN_2 0x1df
512 KEY_FN_D 0x1e0
513 KEY_FN_E 0x1e1
514 KEY_FN_F 0x1e2
515 KEY_FN_S 0x1e3
516 KEY_FN_B 0x1e4
517 KEY_BRL_DOT1 0x1f1
518 KEY_BRL_DOT2 0x1f2
519 KEY_BRL_DOT3 0x1f3
520 KEY_BRL_DOT4 0x1f4
521 KEY_BRL_DOT5 0x1f5
522 KEY_BRL_DOT6 0x1f6
523 KEY_BRL_DOT7 0x1f7
524 KEY_BRL_DOT8 0x1f8
525 KEY_BRL_DOT9 0x1f9
526 KEY_BRL_DOT10 0x1fa
527 KEY_NUMERIC_0 0x200
528 KEY_NUMERIC_1 0x201
529 KEY_NUMERIC_2 0x202
530 KEY_NUMERIC_3 0x203
531 KEY_NUMERIC_4 0x204
532 KEY_NUMERIC_5 0x205
533 KEY_NUMERIC_6 0x206
534 KEY_NUMERIC_7 0x207
535 KEY_NUMERIC_8 0x208
536 KEY_NUMERIC_9 0x209
537 KEY_NUMERIC_STAR 0x20a NumpadStar
538 KEY_NUMERIC_POUND 0x20b NumpadHash
539 KEY_RFKILL 0x20c

11
keycodemapdb/tests/.gitignore vendored Normal file
View File

@ -0,0 +1,11 @@
osx2win32.*
osx2win32_name.*
osx2xkb.*
osx2xkb_name.*
html2win32.*
html2win32_name.*
osx.*
osx_name.*
stdc
stdc++
node_modules/

118
keycodemapdb/tests/Makefile Normal file
View File

@ -0,0 +1,118 @@
TESTS := stdc stdc++ python2 python3 javascript
check: $(TESTS)
@set -e; for fn in $(TESTS); do \
./$$fn; \
echo $$fn: OK; \
done
@echo Done.
GEN := ../tools/keymap-gen
DATA := ../data/keymaps.csv
SOURCES := $(GEN) $(DATA)
.DELETE_ON_ERROR:
stdc: stdc.c osx2win32.h osx2win32_name.h \
osx2xkb.h osx2xkb_name.h \
html2win32.h html2win32_name.h \
osx.h osx_name.h
$(CC) -Wall -o $@ $^
osx2win32.h: $(SOURCES)
$(GEN) --lang stdc code-map $(DATA) osx win32 > $@
osx2win32_name.h: $(SOURCES)
$(GEN) --lang stdc name-map $(DATA) osx win32 > $@
osx2xkb.h: $(SOURCES)
$(GEN) --lang stdc code-map $(DATA) osx xkb > $@
osx2xkb_name.h: $(SOURCES)
$(GEN) --lang stdc name-map $(DATA) osx xkb > $@
html2win32.h: $(SOURCES)
$(GEN) --lang stdc code-map $(DATA) html win32 > $@
html2win32_name.h: $(SOURCES)
$(GEN) --lang stdc name-map $(DATA) html win32 > $@
osx.h: $(SOURCES)
$(GEN) --lang stdc code-table $(DATA) osx > $@
osx_name.h: $(SOURCES)
$(GEN) --lang stdc name-table $(DATA) osx > $@
stdc++: stdc++.cc osx2win32.hh osx2win32_name.hh \
osx2xkb.hh osx2xkb_name.hh \
html2win32.hh html2win32_name.hh \
osx.hh osx_name.hh
$(CXX) -Wall -std=c++11 -o $@ $^
osx2win32.hh: $(SOURCES)
$(GEN) --lang stdc++ code-map $(DATA) osx win32 > $@
osx2win32_name.hh: $(SOURCES)
$(GEN) --lang stdc++ name-map $(DATA) osx win32 > $@
osx2xkb.hh: $(SOURCES)
$(GEN) --lang stdc++ code-map $(DATA) osx xkb > $@
osx2xkb_name.hh: $(SOURCES)
$(GEN) --lang stdc++ name-map $(DATA) osx xkb > $@
html2win32.hh: $(SOURCES)
$(GEN) --lang stdc++ code-map $(DATA) html win32 > $@
html2win32_name.hh: $(SOURCES)
$(GEN) --lang stdc++ name-map $(DATA) html win32 > $@
osx.hh: $(SOURCES)
$(GEN) --lang stdc++ code-table $(DATA) osx > $@
osx_name.hh: $(SOURCES)
$(GEN) --lang stdc++ name-table $(DATA) osx > $@
python2: osx2win32.py osx2win32_name.py \
osx2xkb.py osx2xkb_name.py \
html2win32.py html2win32_name.py \
osx.py osx_name.py
osx2win32.py: $(SOURCES)
$(GEN) --lang python2 code-map $(DATA) osx win32 > $@
osx2win32_name.py: $(SOURCES)
$(GEN) --lang python2 name-map $(DATA) osx win32 > $@
osx2xkb.py: $(SOURCES)
$(GEN) --lang python2 code-map $(DATA) osx xkb > $@
osx2xkb_name.py: $(SOURCES)
$(GEN) --lang python2 name-map $(DATA) osx xkb > $@
html2win32.py: $(SOURCES)
$(GEN) --lang python2 code-map $(DATA) html win32 > $@
html2win32_name.py: $(SOURCES)
$(GEN) --lang python2 name-map $(DATA) html win32 > $@
osx.py: $(SOURCES)
$(GEN) --lang python2 code-table $(DATA) osx > $@
osx_name.py: $(SOURCES)
$(GEN) --lang python2 name-table $(DATA) osx > $@
javascript: node_modules/babel-core \
node_modules/babel-plugin-transform-es2015-modules-commonjs \
osx2win32.js osx2win32_name.js \
osx2xkb.js osx2xkb_name.js \
html2win32.js html2win32_name.js \
osx.js osx_name.js
node_modules/babel-core:
npm install babel-core
node_modules/babel-plugin-transform-es2015-modules-commonjs:
npm install babel-plugin-transform-es2015-modules-commonjs
osx2win32.js: $(SOURCES)
$(GEN) --lang js code-map $(DATA) osx win32 > $@
osx2win32_name.js: $(SOURCES)
$(GEN) --lang js name-map $(DATA) osx win32 > $@
osx2xkb.js: $(SOURCES)
$(GEN) --lang js code-map $(DATA) osx xkb > $@
osx2xkb_name.js: $(SOURCES)
$(GEN) --lang js name-map $(DATA) osx xkb > $@
html2win32.js: $(SOURCES)
$(GEN) --lang js code-map $(DATA) html win32 > $@
html2win32_name.js: $(SOURCES)
$(GEN) --lang js name-map $(DATA) html win32 > $@
osx.js: $(SOURCES)
$(GEN) --lang js code-table $(DATA) osx > $@
osx_name.js: $(SOURCES)
$(GEN) --lang js name-table $(DATA) osx > $@
clean:
rm -rf node_modules
rm -f osx2win32.*
rm -f osx2win32_name.*
rm -f osx2xkb.*
rm -f osx2xkb_name.*
rm -f html2win32.*
rm -f html2win32_name.*
rm -f osx.*
rm -f osx_name.*
rm -f stdc stdc++

53
keycodemapdb/tests/javascript Executable file
View File

@ -0,0 +1,53 @@
#!/usr/bin/env node
/*
* Keycode Map Generator JavaScript Tests
*
* Copyright 2017 Pierre Ossman for Cendio AB
*
* This file is dual license under the terms of the GPLv2 or later
* and 3-clause BSD licenses.
*/
"use strict";
var assert = require('assert');
var babel = require('babel-core');
var fs = require('fs');
function include(fn) {
var options = {
plugins: ["transform-es2015-modules-commonjs"]
};
var code = babel.transformFileSync(fn, options).code;
fs.writeFileSync("." + fn + "_nodejs.js", code);
var imp = require("./." + fn + "_nodejs.js");
fs.unlinkSync("./." + fn + "_nodejs.js");
return imp
}
var code_map_osx_to_win32 = include("osx2win32.js").default;
var name_map_osx_to_win32 = include("osx2win32_name.js").default;
var code_map_osx_to_xkb = include("osx2xkb.js").default;
var name_map_osx_to_xkb = include("osx2xkb_name.js").default;
var code_map_html_to_win32 = include("html2win32.js").default;
var name_map_html_to_win32 = include("html2win32_name.js").default;
var code_table_osx = include("osx.js").default;
var name_table_osx = include("osx_name.js").default;
assert.equal(code_map_osx_to_win32[0x1d], 0x30);
assert.equal(name_map_osx_to_win32[0x1d], "VK_0");
assert.equal(code_map_osx_to_xkb[0x1d], "AE10");
assert.equal(name_map_osx_to_xkb[0x1d], "AE10");
assert.equal(code_map_html_to_win32["ControlLeft"], 0x11);
assert.equal(name_map_html_to_win32["ControlLeft"], "VK_CONTROL");
assert.equal(code_table_osx[0x1d], 0x3b);
assert.equal(name_table_osx[0x1d], "Control");

3
keycodemapdb/tests/python2 Executable file
View File

@ -0,0 +1,3 @@
#!/bin/sh
python ./test.py

3
keycodemapdb/tests/python3 Executable file
View File

@ -0,0 +1,3 @@
#!/bin/sh
python3 ./test.py

View File

@ -0,0 +1,40 @@
/*
* Keycode Map Generator C++ Tests
*
* Copyright 2017 Pierre Ossman for Cendio AB
*
* This file is dual license under the terms of the GPLv2 or later
* and 3-clause BSD licenses.
*/
#include <assert.h>
#include <string.h>
#include "osx2win32.hh"
#include "osx2win32_name.hh"
#include "osx2xkb.hh"
#include "osx2xkb_name.hh"
#include "html2win32.hh"
#include "html2win32_name.hh"
#include "osx.hh"
#include "osx_name.hh"
int main(int argc, char** argv)
{
assert(code_map_osx_to_win32[0x1d] == 0x30);
assert(strcmp(name_map_osx_to_win32[0x1d], "VK_0") == 0);
assert(strcmp(code_map_osx_to_xkb[0x1d], "AE10") == 0);
assert(strcmp(name_map_osx_to_xkb[0x1d], "AE10") == 0);
assert(code_map_html_to_win32.at("ControlLeft") == 0x11);
assert(strcmp(name_map_html_to_win32.at("ControlLeft"), "VK_CONTROL") == 0);
assert(code_table_osx[0x1d] == 0x3b);
assert(strcmp(name_table_osx[0x1d], "Control") == 0);
return 0;
}

64
keycodemapdb/tests/stdc.c Normal file
View File

@ -0,0 +1,64 @@
/*
* Keycode Map Generator C Tests
*
* Copyright 2017 Pierre Ossman for Cendio AB
*
* This file is dual license under the terms of the GPLv2 or later
* and 3-clause BSD licenses.
*/
#include <assert.h>
#include <string.h>
#include "osx2win32.h"
#include "osx2win32_name.h"
#include "osx2xkb.h"
#include "osx2xkb_name.h"
#include "html2win32.h"
#include "html2win32_name.h"
#include "osx.h"
#include "osx_name.h"
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
int main(int argc, char** argv)
{
unsigned i;
assert(code_map_osx_to_win32_len == ARRAY_SIZE(code_map_osx_to_win32));
assert(code_map_osx_to_win32[0x1d] == 0x30);
assert(name_map_osx_to_win32_len == ARRAY_SIZE(name_map_osx_to_win32));
assert(strcmp(name_map_osx_to_win32[0x1d], "VK_0") == 0);
assert(code_map_osx_to_xkb_len == ARRAY_SIZE(code_map_osx_to_xkb));
assert(strcmp(code_map_osx_to_xkb[0x1d], "AE10") == 0);
assert(name_map_osx_to_xkb_len == ARRAY_SIZE(name_map_osx_to_xkb));
assert(strcmp(name_map_osx_to_xkb[0x1d], "AE10") == 0);
assert(code_map_html_to_win32_len == ARRAY_SIZE(code_map_html_to_win32));
for (i = 0;i < code_map_html_to_win32_len;i++) {
if (strcmp(code_map_html_to_win32[i].from, "ControlLeft") == 0) {
assert(code_map_html_to_win32[i].to == 0x11);
break;
}
}
assert(i != code_map_html_to_win32_len);
assert(name_map_html_to_win32_len == ARRAY_SIZE(name_map_html_to_win32));
for (i = 0;i < name_map_html_to_win32_len;i++) {
if (strcmp(name_map_html_to_win32[i].from, "ControlLeft") == 0) {
assert(strcmp(name_map_html_to_win32[i].to, "VK_CONTROL") == 0);
break;
}
}
assert(i != name_map_html_to_win32_len);
assert(code_table_osx_len == ARRAY_SIZE(code_table_osx));
assert(code_table_osx[0x1d] == 0x3b);
assert(name_table_osx_len == ARRAY_SIZE(name_table_osx));
assert(strcmp(name_table_osx[0x1d], "Control") == 0);
return 0;
}

View File

@ -0,0 +1,30 @@
# Keycode Map Generator Python Tests
#
# Copyright 2017 Pierre Ossman for Cendio AB
#
# This file is dual license under the terms of the GPLv2 or later
# and 3-clause BSD licenses.
import osx2win32
import osx2win32_name
import osx2xkb
import osx2xkb_name
import html2win32
import html2win32_name
import osx
import osx_name
assert osx2win32.code_map_osx_to_win32[0x1d] == 0x30
assert osx2win32_name.name_map_osx_to_win32[0x1d] == "VK_0"
assert osx2xkb.code_map_osx_to_xkb[0x1d] == "AE10"
assert osx2xkb_name.name_map_osx_to_xkb[0x1d] == "AE10"
assert html2win32.code_map_html_to_win32["ControlLeft"] == 0x11
assert html2win32_name.name_map_html_to_win32["ControlLeft"] == "VK_CONTROL"
assert osx.code_table_osx[0x1d] == 0x3b;
assert osx_name.name_table_osx[0x1d] == "Control";

View File

@ -0,0 +1,20 @@
argparse is (c) 2006-2009 Steven J. Bethard <steven.bethard@gmail.com>.
The argparse module was contributed to Python as of Python 2.7 and thus
was licensed under the Python license. Same license applies to all files in
the argparse package project.
For details about the Python License, please see doc/Python-License.txt.
History
-------
Before (and including) argparse 1.1, the argparse package was licensed under
Apache License v2.0.
After argparse 1.1, all project files from the argparse project were deleted
due to license compatibility issues between Apache License 2.0 and GNU GPL v2.
The project repository then had a clean start with some files taken from
Python 2.7.1, so definitely all files are under Python License now.

0
keycodemapdb/thirdparty/__init__.py vendored Normal file
View File

2392
keycodemapdb/thirdparty/argparse.py vendored Normal file

File diff suppressed because it is too large Load Diff

972
keycodemapdb/tools/keymap-gen Executable file
View File

@ -0,0 +1,972 @@
#!/usr/bin/python
# -*- python -*-
#
# Keycode Map Generator
#
# Copyright (C) 2009-2017 Red Hat, Inc.
#
# This file is dual license under the terms of the GPLv2 or later
# and 3-clause BSD licenses.
#
# Requires >= 2.6
from __future__ import print_function
import csv
try:
import argparse
except:
import os, sys
sys.path.append(os.path.join(os.path.dirname(__file__), "../thirdparty"))
import argparse
import hashlib
import time
import sys
class Database:
# Linux: linux/input.h
MAP_LINUX = "linux"
# OS-X: Carbon/HIToolbox/Events.h
MAP_OSX = "osx"
# AT Set 1: linux/drivers/input/keyboard/atkbd.c
# (atkbd_set2_keycode + atkbd_unxlate_table)
MAP_ATSET1 = "atset1"
# AT Set 2: linux/drivers/input/keyboard/atkbd.c
# (atkbd_set2_keycode)
MAP_ATSET2 = "atset2"
# AT Set 3: linux/drivers/input/keyboard/atkbd.c
# (atkbd_set3_keycode)
MAP_ATSET3 = "atset3"
# Linux RAW: linux/drivers/char/keyboard.c (x86_keycodes)
MAP_XTKBD = "xtkbd"
# USB HID: linux/drivers/hid/usbhid/usbkbd.c (usb_kbd_keycode)
MAP_USB = "usb"
# Win32: mingw32/winuser.h
MAP_WIN32 = "win32"
# XWin XT: xorg-server/hw/xwin/{winkeybd.c,winkeynames.h}
# (xt + manually transcribed)
MAP_XWINXT = "xwinxt"
# X11: http://cgit.freedesktop.org/xorg/proto/x11proto/plain/keysymdef.h
MAP_X11 = "x11"
# XKBD XT: xf86-input-keyboard/src/at_scancode.c
# (xt + manually transcribed)
MAP_XKBDXT = "xkbdxt"
# Xorg with evdev: linux + an offset
MAP_XORGEVDEV = "xorgevdev"
# Xorg with kbd: xkbdxt + an offset
MAP_XORGKBD = "xorgkbd"
# Xorg with OS-X: osx + an offset
MAP_XORGXQUARTZ = "xorgxquartz"
# Xorg + Cygwin: xwinxt + an offset
MAP_XORGXWIN = "xorgxwin"
# QEMU key numbers: xtkbd + special re-encoding of high bit
MAP_QNUM = "qnum"
# HTML codes
MAP_HTML = "html"
# XKB key names
MAP_XKB = "xkb"
# QEMU keycodes
MAP_QCODE = "qcode"
# Sun / Sparc scan codes
# Reference: "SPARC International Keyboard Spec 1", page 7 "US scan set"
MAP_SUN = "sun"
# Apple Desktop Bus
# Reference: http://www.archive.org/stream/apple-guide-macintosh-family-hardware/Apple_Guide_to_the_Macintosh_Family_Hardware_2e#page/n345/mode/2up
MAP_ADB = "adb"
MAP_LIST = (
MAP_LINUX,
MAP_OSX,
MAP_ATSET1,
MAP_ATSET2,
MAP_ATSET3,
MAP_USB,
MAP_WIN32,
MAP_XWINXT,
MAP_XKBDXT,
MAP_X11,
MAP_HTML,
MAP_XKB,
MAP_QCODE,
MAP_SUN,
MAP_ADB,
# These are derived from maps above
MAP_XTKBD,
MAP_XORGEVDEV,
MAP_XORGKBD,
MAP_XORGXQUARTZ,
MAP_XORGXWIN,
MAP_QNUM,
)
CODE_COLUMNS = {
MAP_LINUX: 1,
MAP_OSX: 3,
MAP_ATSET1: 4,
MAP_ATSET2: 5,
MAP_ATSET3: 6,
MAP_USB: 7,
MAP_WIN32: 9,
MAP_XWINXT: 10,
MAP_XKBDXT: 11,
MAP_X11: 13,
MAP_HTML: 14,
MAP_XKB: 15,
MAP_SUN: 17,
MAP_ADB: 18,
}
ENUM_COLUMNS = {
MAP_QCODE: 14,
}
NAME_COLUMNS = {
MAP_LINUX: 0,
MAP_OSX: 2,
MAP_WIN32: 8,
MAP_X11: 12,
MAP_HTML: 14,
MAP_XKB: 15,
MAP_QCODE: 16,
}
ENUM_BOUND = {
MAP_QCODE: "Q_KEY_CODE__MAX",
}
def __init__(self):
self.mapto = {}
self.mapfrom = {}
self.mapname = {}
self.mapchecksum = None
for name in self.MAP_LIST:
# Key is a MAP_LINUX, value is a MAP_XXX
self.mapto[name] = {}
# key is a MAP_XXX, value is a MAP_LINUX
self.mapfrom[name] = {}
for name in self.NAME_COLUMNS.keys():
# key is a MAP_LINUX, value is a string
self.mapname[name] = {}
def _generate_checksum(self, filename):
hash = hashlib.sha256()
with open(filename, "rb") as f:
for chunk in iter(lambda: f.read(4096), b""):
hash.update(chunk)
self.mapchecksum = hash.hexdigest()
def load(self, filename):
self._generate_checksum(filename)
with open(filename, 'r') as f:
reader = csv.reader(f)
first = True
for row in reader:
# Discard column headings
if first:
first = False
continue
# We special case MAP_LINUX since that is out
# master via which all other mappings are done
linux = self.load_linux(row)
# Now load all the remaining master data values
self.load_data(row, linux)
# Then load all the keycode names
self.load_names(row, linux)
# Finally calculate derived key maps
self.derive_data(row, linux)
def load_linux(self, row):
col = self.CODE_COLUMNS[self.MAP_LINUX]
linux = row[col]
if linux.startswith("0x"):
linux = int(linux, 16)
else:
linux = int(linux, 10)
self.mapto[self.MAP_LINUX][linux] = linux
self.mapfrom[self.MAP_LINUX][linux] = linux
return linux
def load_data(self, row, linux):
for mapname in self.CODE_COLUMNS:
if mapname == self.MAP_LINUX:
continue
col = self.CODE_COLUMNS[mapname]
val = row[col]
if val == "":
continue
if val.startswith("0x"):
val = int(val, 16)
elif val.isdigit():
val = int(val, 10)
self.mapto[mapname][linux] = val
self.mapfrom[mapname][val] = linux
def load_names(self, row, linux):
for mapname in self.NAME_COLUMNS:
col = self.NAME_COLUMNS[mapname]
val = row[col]
if val == "":
continue
self.mapname[mapname][linux] = val
def derive_data(self, row, linux):
# Linux RAW is XT scan codes with special encoding of the
# 0xe0 scan codes
if linux in self.mapto[self.MAP_ATSET1]:
at1 = self.mapto[self.MAP_ATSET1][linux]
if at1 > 0x7f:
assert((at1 & ~0x7f) == 0xe000)
xtkbd = 0x100 | (at1 & 0x7f)
else:
xtkbd = at1
self.mapto[self.MAP_XTKBD][linux] = xtkbd
self.mapfrom[self.MAP_XTKBD][xtkbd] = linux
# Xorg KBD is XKBD XT offset by 8
if linux in self.mapto[self.MAP_XKBDXT]:
xorgkbd = self.mapto[self.MAP_XKBDXT][linux] + 8
self.mapto[self.MAP_XORGKBD][linux] = xorgkbd
self.mapfrom[self.MAP_XORGKBD][xorgkbd] = linux
# Xorg evdev is Linux offset by 8
self.mapto[self.MAP_XORGEVDEV][linux] = linux + 8
self.mapfrom[self.MAP_XORGEVDEV][linux + 8] = linux
# Xorg XQuartx is OS-X offset by 8
if linux in self.mapto[self.MAP_OSX]:
xorgxquartz = self.mapto[self.MAP_OSX][linux] + 8
self.mapto[self.MAP_XORGXQUARTZ][linux] = xorgxquartz
self.mapfrom[self.MAP_XORGXQUARTZ][xorgxquartz] = linux
# Xorg Xwin (aka Cygwin) is XWin XT offset by 8
if linux in self.mapto[self.MAP_XWINXT]:
xorgxwin = self.mapto[self.MAP_XWINXT][linux] + 8
self.mapto[self.MAP_XORGXWIN][linux] = xorgxwin
self.mapfrom[self.MAP_XORGXWIN][xorgxwin] = linux
# QNUM keycodes are XT scan codes with a slightly
# different encoding of 0xe0 scan codes
if linux in self.mapto[self.MAP_ATSET1]:
at1 = self.mapto[self.MAP_ATSET1][linux]
if at1 > 0x7f:
assert((at1 & ~0x7f) == 0xe000)
qnum = 0x80 | (at1 & 0x7f)
else:
qnum = at1
self.mapto[self.MAP_QNUM][linux] = qnum
self.mapfrom[self.MAP_QNUM][qnum] = linux
# Hack for compatibility with previous mistakes in handling
# Print/SysRq. The preferred qnum for Print/SysRq is 0x54,
# but QEMU previously allowed 0xb7 too
if qnum == 0x54:
self.mapfrom[self.MAP_QNUM][0xb7] = self.mapfrom[self.MAP_QNUM][0x54]
if linux in self.mapname[self.MAP_QCODE]:
qcodeenum = self.mapname[self.MAP_QCODE][linux]
qcodeenum = "Q_KEY_CODE_" + qcodeenum.upper()
self.mapto[self.MAP_QCODE][linux] = qcodeenum
self.mapfrom[self.MAP_QCODE][qcodeenum] = linux
class LanguageGenerator(object):
def _boilerplate(self, lines):
raise NotImplementedError()
def generate_header(self, database, args):
today = time.strftime("%Y-%m-%d %H:%M")
self._boilerplate([
"This file is auto-generated from keymaps.csv on %s" % today,
"Database checksum sha256(%s)" % database.mapchecksum,
"To re-generate, run:",
" %s" % args,
])
class LanguageSrcGenerator(LanguageGenerator):
TYPE_INT = "integer"
TYPE_STRING = "string"
TYPE_ENUM = "enum"
def _array_start(self, varname, length, defvalue, fromtype, totype):
raise NotImplementedError()
def _array_end(self, fromtype, totype):
raise NotImplementedError()
def _array_entry(self, index, value, comment, fromtype, totype):
raise NotImplementedError()
def generate_code_map(self, varname, database, frommapname, tomapname):
if frommapname not in database.mapfrom:
raise Exception("Unknown map %s, expected one of %s" % (
frommapname, ", ".join(database.mapfrom.keys())))
if tomapname not in database.mapto:
raise Exception("Unknown map %s, expected one of %s" % (
tomapname, ", ".join(database.mapto.keys())))
tolinux = database.mapfrom[frommapname]
fromlinux = database.mapto[tomapname]
if varname is None:
varname = "code_map_%s_to_%s" % (frommapname, tomapname)
if frommapname in database.ENUM_COLUMNS:
fromtype = self.TYPE_ENUM
elif type(tolinux.keys()[0]) == str:
fromtype = self.TYPE_STRING
else:
fromtype = self.TYPE_INT
if tomapname in database.ENUM_COLUMNS:
totype = self.TYPE_ENUM
elif type(fromlinux.values()[0]) == str:
totype = self.TYPE_STRING
else:
totype = self.TYPE_INT
keys = tolinux.keys()
keys.sort()
if fromtype == self.TYPE_INT:
keys = range(keys[-1] + 1)
if fromtype == self.TYPE_ENUM:
keymax = database.ENUM_BOUND[frommapname]
else:
keymax = len(keys)
defvalue = fromlinux.get(0, None)
if fromtype == self.TYPE_ENUM:
self._array_start(varname, keymax, defvalue, fromtype, totype)
else:
self._array_start(varname, keymax, None, fromtype, totype)
for src in keys:
linux = tolinux.get(src, None)
if linux is None:
dst = None
else:
dst = fromlinux.get(linux, defvalue)
comment = "%s -> %s -> %s" % (self._label(database, frommapname, src, linux),
self._label(database, Database.MAP_LINUX, linux, linux),
self._label(database, tomapname, dst, linux))
self._array_entry(src, dst, comment, fromtype, totype)
self._array_end(fromtype, totype)
def generate_code_table(self, varname, database, mapname):
if mapname not in database.mapto:
raise Exception("Unknown map %s, expected one of %s" % (
mapname, ", ".join(database.mapto.keys())))
keys = database.mapto[Database.MAP_LINUX].keys()
keys.sort()
names = [database.mapname[Database.MAP_LINUX].get(key, "unnamed") for key in keys]
if varname is None:
varname = "code_table_%s" % mapname
if mapname in database.ENUM_COLUMNS:
totype = self.TYPE_ENUM
elif type(database.mapto[mapname].values()[0]) == str:
totype = self.TYPE_STRING
else:
totype = self.TYPE_INT
self._array_start(varname, len(keys), None, self.TYPE_INT, totype)
defvalue = database.mapto[mapname].get(0, None)
for i in range(len(keys)):
key = keys[i]
dst = database.mapto[mapname].get(key, defvalue)
self._array_entry(i, dst, names[i], self.TYPE_INT, totype)
self._array_end(self.TYPE_INT, totype)
def generate_name_map(self, varname, database, frommapname, tomapname):
if frommapname not in database.mapfrom:
raise Exception("Unknown map %s, expected one of %s" % (
frommapname, ", ".join(database.mapfrom.keys())))
if tomapname not in database.mapname:
raise Exception("Unknown map %s, expected one of %s" % (
tomapname, ", ".join(database.mapname.keys())))
tolinux = database.mapfrom[frommapname]
fromlinux = database.mapname[tomapname]
if varname is None:
varname = "name_map_%s_to_%s" % (frommapname, tomapname)
keys = tolinux.keys()
keys.sort()
if type(keys[0]) == int:
keys = range(keys[-1] + 1)
if type(keys[0]) == int:
fromtype = self.TYPE_INT
else:
fromtype = self.TYPE_STRING
self._array_start(varname, len(keys), None, fromtype, self.TYPE_STRING)
for src in keys:
linux = tolinux.get(src, None)
if linux is None:
dst = None
else:
dst = fromlinux.get(linux, None)
comment = "%s -> %s -> %s" % (self._label(database, frommapname, src, linux),
self._label(database, Database.MAP_LINUX, linux, linux),
self._label(database, tomapname, dst, linux))
self._array_entry(src, dst, comment, fromtype, self.TYPE_STRING)
self._array_end(fromtype, self.TYPE_STRING)
def generate_name_table(self, varname, database, mapname):
if mapname not in database.mapname:
raise Exception("Unknown map %s, expected one of %s" % (
mapname, ", ".join(database.mapname.keys())))
keys = database.mapto[Database.MAP_LINUX].keys()
keys.sort()
names = [database.mapname[Database.MAP_LINUX].get(key, "unnamed") for key in keys]
if varname is None:
varname = "name_table_%s" % mapname
self._array_start(varname, len(keys), None, self.TYPE_INT, self.TYPE_STRING)
for i in range(len(keys)):
key = keys[i]
dst = database.mapname[mapname].get(key, None)
self._array_entry(i, dst, names[i], self.TYPE_INT, self.TYPE_STRING)
self._array_end(self.TYPE_INT, self.TYPE_STRING)
def _label(self, database, mapname, val, linux):
if mapname in database.mapname:
return "%s:%s (%s)" % (mapname, val, database.mapname[mapname].get(linux, "unnamed"))
else:
return "%s:%s" % (mapname, val)
class LanguageDocGenerator(LanguageGenerator):
def _array_start_name_doc(self, varname, namemap):
raise NotImplementedError()
def _array_start_code_doc(self, varname, namemap, codemap):
raise NotImplementedError()
def _array_end(self):
raise NotImplementedError()
def _array_name_entry(self, value, name):
raise NotImplementedError()
def _array_code_entry(self, value, name):
raise NotImplementedError()
def generate_name_docs(self, varname, database, mapname):
if mapname not in database.mapname:
raise Exception("Unknown map %s, expected one of %s" % (
mapname, ", ".join(database.mapname.keys())))
keys = database.mapto[Database.MAP_LINUX].keys()
keys.sort()
names = [database.mapname[Database.MAP_LINUX].get(key, "unnamed") for key in keys]
if varname is None:
varname = mapname
self._array_start_name_doc(varname, mapname)
for i in range(len(keys)):
key = keys[i]
dst = database.mapname[mapname].get(key, None)
self._array_name_entry(key, dst)
self._array_end()
def generate_code_docs(self, varname, database, mapname):
if mapname not in database.mapfrom:
raise Exception("Unknown map %s, expected one of %s" % (
mapname, ", ".join(database.mapfrom.keys())))
tolinux = database.mapfrom[mapname]
keys = tolinux.keys()
keys.sort()
if mapname in database.mapname:
names = database.mapname[mapname]
namemap = mapname
else:
names = database.mapname[Database.MAP_LINUX]
namemap = Database.MAP_LINUX
if varname is None:
varname = mapname
self._array_start_code_doc(varname, mapname, namemap)
for i in range(len(keys)):
key = keys[i]
self._array_code_entry(key, names.get(tolinux[key], "unnamed"))
self._array_end()
class CLanguageGenerator(LanguageSrcGenerator):
def __init__(self, inttypename, strtypename, lentypename):
self.inttypename = inttypename
self.strtypename = strtypename
self.lentypename = lentypename
def _boilerplate(self, lines):
print("/*")
for line in lines:
print(" * %s" % line)
print("*/")
def _array_start(self, varname, length, defvalue, fromtype, totype):
self._varname = varname;
totypename = self.strtypename if totype == self.TYPE_STRING else self.inttypename
if fromtype in (self.TYPE_INT, self.TYPE_ENUM):
if type(length) == str:
print("const %s %s[%s] = {" % (totypename, varname, length))
else:
print("const %s %s[%d] = {" % (totypename, varname, length))
else:
print("const struct _%s {" % varname)
print(" const %s from;" % self.strtypename)
print(" const %s to;" % totypename)
print("} %s[] = {" % varname)
if defvalue != None:
if totype == self.TYPE_ENUM:
if type(length) == str:
print(" [0 ... %s-1] = %s," % (length, defvalue))
else:
print(" [0 ... 0x%x-1] = %s," % (length, defvalue))
else:
if type(length) == str:
print(" [0 ... %s-1] = 0x%x," % (length, defvalue))
else:
print(" [0 ... 0x%x-1] = 0x%x," % (length, defvalue))
def _array_end(self, fromtype, totype):
print("};")
print("const %s %s_len = sizeof(%s)/sizeof(%s[0]);" %
(self.lentypename, self._varname, self._varname, self._varname))
def _array_entry(self, index, value, comment, fromtype, totype):
if value is None:
return
if fromtype == self.TYPE_INT:
indexfmt = "0x%x"
elif fromtype == self.TYPE_ENUM:
indexfmt = "%s"
else:
indexfmt = "\"%s\""
if totype == self.TYPE_INT:
valuefmt = "0x%x"
elif totype == self.TYPE_ENUM:
valuefmt = "%s"
else:
valuefmt = "\"%s\""
if fromtype != self.TYPE_STRING:
print((" [" + indexfmt + "] = " + valuefmt + ", /* %s */") % (index, value, comment))
else:
print((" {" + indexfmt + ", " + valuefmt + "}, /* %s */") % (index, value, comment))
class CppLanguageGenerator(CLanguageGenerator):
def _array_start(self, varname, length, defvalue, fromtype, totype):
if fromtype == self.TYPE_ENUM:
raise NotImplementedError("Enums not supported as source in C++ generator")
totypename = "const " + self.strtypename if totype == self.TYPE_STRING else self.inttypename
if fromtype == self.TYPE_INT:
print("#include <vector>")
print("const std::vector<%s> %s = {" % (totypename, varname))
else:
print("#include <map>")
print("#include <string>")
print("const std::map<const std::string, %s> %s = {" % (totypename, varname))
def _array_end(self, fromtype, totype):
print("};")
# designated initializers not available in C++
def _array_entry(self, index, value, comment, fromtype, totype):
if fromtype == self.TYPE_STRING:
return super(CppLanguageGenerator, self)._array_entry(index, value, comment, fromtype, totype)
if value is None:
print(" 0, /* %s */" % comment)
elif totype == self.TYPE_INT:
print(" 0x%x, /* %s */" % (value, comment))
elif totype == self.TYPE_ENUM:
print(" %s, /* %s */" % (value, comment))
else:
print(" \"%s\", /* %s */" % (value, comment))
class StdCLanguageGenerator(CLanguageGenerator):
def __init__(self):
super(StdCLanguageGenerator, self).__init__("unsigned short", "char *", "unsigned int")
class StdCppLanguageGenerator(CppLanguageGenerator):
def __init__(self):
super(StdCppLanguageGenerator, self).__init__("unsigned short", "char *", "unsigned int")
class GLib2LanguageGenerator(CLanguageGenerator):
def __init__(self):
super(GLib2LanguageGenerator, self).__init__("guint16", "gchar *", "guint")
class PythonLanguageGenerator(LanguageSrcGenerator):
def _boilerplate(self, lines):
print("#")
for line in lines:
print("# %s" % line)
print("#")
def _array_start(self, varname, length, defvalue, fromtype, totype):
if fromtype == self.TYPE_ENUM:
raise NotImplementedError("Enums not supported as source in Python generator")
if fromtype != self.TYPE_STRING:
print("%s = [" % varname)
else:
print("%s = {" % varname)
def _array_end(self, fromtype, totype):
if fromtype != self.TYPE_STRING:
print("]")
else:
print("}")
def _array_entry(self, index, value, comment, fromtype, totype):
if fromtype == self.TYPE_INT:
if value is None:
print(" None, # %s" % (comment))
elif totype == self.TYPE_INT:
print(" 0x%x, # %s" % (value, comment))
elif totype == self.TYPE_ENUM:
print(" %s, # %s" % (value, comment))
else:
print(" \"%s\", # %s" % (value, comment))
else:
if value is None:
print(" \"%s\": None, # %s" % (index, comment))
elif totype == self.TYPE_INT:
print(" \"%s\": 0x%x, # %s" % (index, value, comment))
elif totype == self.TYPE_ENUM:
print(" \"%s\": %s, # %s" % (index, value, comment))
else:
print(" \"%s\": \"%s\", # %s" % (index, value, comment))
class PerlLanguageGenerator(LanguageSrcGenerator):
def _boilerplate(self, lines):
print("#")
for line in lines:
print("# %s" % line)
print("#")
def _array_start(self, varname, length, defvalue, fromtype, totype):
if fromtype == self.TYPE_ENUN:
raise NotImplementedError("Enums not supported as source in Python generator")
if fromtype == self.TYPE_INT:
print("my @%s = (" % varname)
else:
print("my %%%s = (" % varname)
def _array_end(self, fromtype, totype):
print(");")
def _array_entry(self, index, value, comment, fromtype, totype):
if fromtype == self.TYPE_INT:
if value is None:
print(" undef, # %s" % (comment))
elif totype == self.TYPE_INT:
print(" 0x%x, # %s" % (value, comment))
elif totype == self.TYPE_ENUM:
print(" %s, # %s" % (value, comment))
else:
print(" \"%s\", # %s" % (value, comment))
else:
if value is None:
print(" \"%s\", undef, # %s" % (index, comment))
elif totype == self.TYPE_INT:
print(" \"%s\", 0x%x, # %s" % (index, value, comment))
elif totype == self.TYPE_ENUM:
print(" \"%s\", 0x%x, # %s" % (index, value, comment))
else:
print(" \"%s\", \"%s\", # %s" % (index, value, comment))
class JavaScriptLanguageGenerator(LanguageSrcGenerator):
def _boilerplate(self, lines):
print("/*")
for line in lines:
print(" * %s" % line)
print("*/")
def _array_start(self, varname, length, defvalue, fromtype, totype):
print("export default {")
def _array_end(self, fromtype, totype):
print("};")
def _array_entry(self, index, value, comment, fromtype, totype):
if value is None:
return
if fromtype == self.TYPE_INT:
fromfmt = "0x%x"
elif fromtype == self.TYPE_ENUM:
fromfmt = "%s"
else:
fromfmt = "\"%s\""
if totype == self.TYPE_INT:
tofmt = "0x%x"
elif totype == self.TYPE_ENUM:
tofmt = "%s"
else:
tofmt = "\"%s\""
print((" " + fromfmt + ": " + tofmt + ", /* %s */") % (index, value, comment))
class PodLanguageGenerator(LanguageDocGenerator):
def _boilerplate(self, lines):
print("#")
for line in lines:
print("# %s" % line)
print("#")
def _array_start_name_doc(self, varname, namemap):
print("=head1 %s" % varname)
print("")
print("List of %s key code names, with corresponding key code values" % namemap)
print("")
print("=over 4")
print("")
def _array_start_code_doc(self, varname, codemap, namemap):
print("=head1 %s" % varname)
print("")
print("List of %s key code values, with corresponding %s key code names" % (codemap, namemap))
print("")
print("=over 4")
print("")
def _array_end(self):
print("=back")
print("")
def _array_name_entry(self, value, name):
print("=item %s" % name)
print("")
print("Key value %d (0x%x)" % (value, value))
print("")
def _array_code_entry(self, value, name):
print("=item %d (0x%x)" % (value, value))
print("")
print("Key name %s" % name)
print("")
SRC_GENERATORS = {
"stdc": StdCLanguageGenerator(),
"stdc++": StdCppLanguageGenerator(),
"glib2": GLib2LanguageGenerator(),
"python2": PythonLanguageGenerator(),
"python3": PythonLanguageGenerator(),
"perl": PerlLanguageGenerator(),
"js": JavaScriptLanguageGenerator(),
}
DOC_GENERATORS = {
"pod": PodLanguageGenerator(),
}
def code_map(args):
database = Database()
database.load(args.keymaps)
cliargs = ["keymap-gen", "--lang=%s" % args.lang]
if args.varname is not None:
cliargs.append("--varname=%s" % args.varname)
cliargs.extend(["code-map", "keymaps.csv", args.frommapname, args.tomapname])
SRC_GENERATORS[args.lang].generate_header(database, " ".join(cliargs))
SRC_GENERATORS[args.lang].generate_code_map(args.varname, database, args.frommapname, args.tomapname)
def code_table(args):
database = Database()
database.load(args.keymaps)
cliargs = ["keymap-gen", "--lang=%s" % args.lang]
if args.varname is not None:
cliargs.append("--varname=%s" % args.varname)
cliargs.extend(["code-table", "keymaps.csv", args.mapname])
SRC_GENERATORS[args.lang].generate_header(database, " ".join(cliargs))
SRC_GENERATORS[args.lang].generate_code_table(args.varname, database, args.mapname)
def name_map(args):
database = Database()
database.load(args.keymaps)
cliargs = ["keymap-gen", "--lang=%s" % args.lang]
if args.varname is not None:
cliargs.append("--varname=%s" % args.varname)
cliargs.extend(["name-map", "keymaps.csv", args.frommapname, args.tomapname])
SRC_GENERATORS[args.lang].generate_header(database, " ".join(cliargs))
SRC_GENERATORS[args.lang].generate_name_map(args.varname, database, args.frommapname, args.tomapname)
def name_table(args):
database = Database()
database.load(args.keymaps)
cliargs = ["keymap-gen", "--lang=%s" % args.lang]
if args.varname is not None:
cliargs.append("--varname=%s" % args.varname)
cliargs.extend(["name-table", "keymaps.csv", args.mapname])
SRC_GENERATORS[args.lang].generate_header(database, " ".join(cliargs))
SRC_GENERATORS[args.lang].generate_name_table(args.varname, database, args.mapname)
def code_docs(args):
database = Database()
database.load(args.keymaps)
cliargs = ["keymap-gen", "--lang=%s" % args.lang]
if args.varname is not None:
cliargs.append("--varname=%s" % args.varname)
cliargs.extend(["code-docs", "keymaps.csv", args.mapname])
DOC_GENERATORS[args.lang].generate_header(database, " ".join(cliargs))
DOC_GENERATORS[args.lang].generate_code_docs(args.varname, database, args.mapname)
def name_docs(args):
database = Database()
database.load(args.keymaps)
cliargs = ["keymap-gen", "--lang=%s" % args.lang]
if args.varname is not None:
cliargs.append("--varname=%s" % args.varname)
cliargs.extend(["name-docs", "keymaps.csv", args.mapname])
DOC_GENERATORS[args.lang].generate_header(database, " ".join(cliargs))
DOC_GENERATORS[args.lang].generate_name_docs(args.varname, database, args.mapname)
def usage():
print ("Please select a command:")
print (" 'code-map', 'code-table', 'name-map', 'name-table', 'docs'")
sys.exit(1)
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--lang", default="stdc",
help="Output language, (src=%s, doc=%s)" % (
",".join(SRC_GENERATORS.keys()),
",".join(DOC_GENERATORS.keys())))
parser.add_argument("--varname", default=None,
help="Data variable name")
subparsers = parser.add_subparsers(help="sub-command help")
codemapparser = subparsers.add_parser("code-map", help="Generate a mapping between code tables")
codemapparser.add_argument("keymaps", help="Path to keymap CSV data file")
codemapparser.add_argument("frommapname", help="Source code table name")
codemapparser.add_argument("tomapname", help="Target code table name")
codemapparser.set_defaults(func=code_map)
codetableparser = subparsers.add_parser("code-table", help="Generate a flat code table")
codetableparser.add_argument("keymaps", help="Path to keymap CSV data file")
codetableparser.add_argument("mapname", help="Code table name")
codetableparser.set_defaults(func=code_table)
namemapparser = subparsers.add_parser("name-map", help="Generate a mapping to names")
namemapparser.add_argument("keymaps", help="Path to keymap CSV data file")
namemapparser.add_argument("frommapname", help="Source code table name")
namemapparser.add_argument("tomapname", help="Target name table name")
namemapparser.set_defaults(func=name_map)
nametableparser = subparsers.add_parser("name-table", help="Generate a flat name table")
nametableparser.add_argument("keymaps", help="Path to keymap CSV data file")
nametableparser.add_argument("mapname", help="Name table name")
nametableparser.set_defaults(func=name_table)
codedocsparser = subparsers.add_parser("code-docs", help="Generate code documentation")
codedocsparser.add_argument("keymaps", help="Path to keymap CSV data file")
codedocsparser.add_argument("mapname", help="Code table name")
codedocsparser.set_defaults(func=code_docs)
namedocsparser = subparsers.add_parser("name-docs", help="Generate name documentation")
namedocsparser.add_argument("keymaps", help="Path to keymap CSV data file")
namedocsparser.add_argument("mapname", help="Name table name")
namedocsparser.set_defaults(func=name_docs)
args = parser.parse_args()
if hasattr(args, "func"):
args.func(args)
else:
usage()
main()

Some files were not shown because too many files have changed in this diff Show More