Compare commits
219 Commits
pull-booti
...
pull-gtk-2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
316cb068bd | ||
|
|
987fec54e1 | ||
|
|
3e9418e160 | ||
|
|
817ef04db2 | ||
|
|
ff0d48768b | ||
|
|
6f64091786 | ||
|
|
74dda9876b | ||
|
|
71b7f54fdf | ||
|
|
dbe9d16367 | ||
|
|
592125f83a | ||
|
|
dcbff19bd0 | ||
|
|
027fc52704 | ||
|
|
19e0fefa6f | ||
|
|
0b7d409d42 | ||
|
|
23adb8618c | ||
|
|
0e7b176ae0 | ||
|
|
14e5f10607 | ||
|
|
211b016915 | ||
|
|
98128601ac | ||
|
|
37e6456ef5 | ||
|
|
3940433843 | ||
|
|
3df53cdf56 | ||
|
|
0adf7d3cc3 | ||
|
|
543486db35 | ||
|
|
635117e71f | ||
|
|
94cc44a9e5 | ||
|
|
7b95a50858 | ||
|
|
6aea44fc2b | ||
|
|
c6faa758e3 | ||
|
|
b32a950910 | ||
|
|
7797a73947 | ||
|
|
8b135a288a | ||
|
|
d4db399b8b | ||
|
|
832390a5ed | ||
|
|
1430500bb8 | ||
|
|
3cad83075c | ||
|
|
1b2dd0bee6 | ||
|
|
a1391444fe | ||
|
|
925bb3238d | ||
|
|
4b25bbc4c2 | ||
|
|
59c9a95fd2 | ||
|
|
7f75a07d50 | ||
|
|
4b318d6ca6 | ||
|
|
17bd5f4727 | ||
|
|
234764eed1 | ||
|
|
d26e6ec052 | ||
|
|
791230d8bb | ||
|
|
c7c0681bc8 | ||
|
|
f307b2558f | ||
|
|
001c158def | ||
|
|
9696df219a | ||
|
|
641bb63cd6 | ||
|
|
fef4d3d564 | ||
|
|
ad27390c85 | ||
|
|
713d9675e0 | ||
|
|
057a3fe57e | ||
|
|
78fb328e85 | ||
|
|
6ca56bf5e9 | ||
|
|
5b84106bd9 | ||
|
|
1d13d65466 | ||
|
|
9ebd844805 | ||
|
|
c5f7c0af47 | ||
|
|
e9082e4736 | ||
|
|
8113fb5292 | ||
|
|
292420918d | ||
|
|
558939c6c7 | ||
|
|
e799157c76 | ||
|
|
6a1fa9f5a6 | ||
|
|
66e56b13ad | ||
|
|
f3582ba41c | ||
|
|
4c7e251ae6 | ||
|
|
37917da2d0 | ||
|
|
22644cd2c6 | ||
|
|
e40830afa1 | ||
|
|
6de4e7fdf6 | ||
|
|
60b6381ffb | ||
|
|
8f4699d873 | ||
|
|
895b810c12 | ||
|
|
19f3772995 | ||
|
|
4b4ce6c2b8 | ||
|
|
e668d1b854 | ||
|
|
ad089894a8 | ||
|
|
31cc9514a5 | ||
|
|
01a2050fa5 | ||
|
|
4277af19d9 | ||
|
|
84ebe3755f | ||
|
|
a7f53e26a6 | ||
|
|
6007cdd448 | ||
|
|
d829a2115f | ||
|
|
26f8b3a847 | ||
|
|
d3aeb1b7da | ||
|
|
b8864be5f3 | ||
|
|
a987ee1f1b | ||
|
|
4be746345f | ||
|
|
2a30307f70 | ||
|
|
f75167313c | ||
|
|
097310b53e | ||
|
|
7c84b1b831 | ||
|
|
fa1d36df74 | ||
|
|
7f06d47eff | ||
|
|
bfb197e0d9 | ||
|
|
fea68bb6e9 | ||
|
|
b9fe8a7a12 | ||
|
|
9ba10c95a4 | ||
|
|
8fb3c76c94 | ||
|
|
18e46a033d | ||
|
|
7e7d56d9e0 | ||
|
|
26f54e9a3c | ||
|
|
e4e9986b1c | ||
|
|
ec0de76874 | ||
|
|
7c15903789 | ||
|
|
38c4d0aea3 | ||
|
|
d8bb71b622 | ||
|
|
3a16ecb063 | ||
|
|
b74f2b5bb3 | ||
|
|
f718b0bbfa | ||
|
|
59543d4ee1 | ||
|
|
030c58dfb7 | ||
|
|
5f77ef69a1 | ||
|
|
8a2c263624 | ||
|
|
605c690b1b | ||
|
|
89b516d8b9 | ||
|
|
ac20e1bb0e | ||
|
|
b13ce07688 | ||
|
|
58e4fee24a | ||
|
|
32d9c5613e | ||
|
|
50e1206069 | ||
|
|
9879232543 | ||
|
|
b5682aa4ca | ||
|
|
9e5a25f1c2 | ||
|
|
ff326ffaeb | ||
|
|
5c960521b8 | ||
|
|
84961407a5 | ||
|
|
88e6599669 | ||
|
|
18b91a3e08 | ||
|
|
07d09c58db | ||
|
|
b8c9cd5c8c | ||
|
|
8074264203 | ||
|
|
51b2e8c331 | ||
|
|
b6cc36abb2 | ||
|
|
7716b8ca74 | ||
|
|
2d9a982f37 | ||
|
|
5f4d917376 | ||
|
|
138d587afb | ||
|
|
77de4a09c6 | ||
|
|
af01492755 | ||
|
|
e9fd12aa0d | ||
|
|
10bdcd5659 | ||
|
|
02206e5275 | ||
|
|
91c8daad4b | ||
|
|
bddd763a4e | ||
|
|
277bc95ed3 | ||
|
|
e98f8c3622 | ||
|
|
492bcf8f71 | ||
|
|
2f4f603517 | ||
|
|
0ddef15b04 | ||
|
|
7f17a91715 | ||
|
|
c32e36f6ab | ||
|
|
e378acb404 | ||
|
|
431bbb26cb | ||
|
|
014176f914 | ||
|
|
181a2c6323 | ||
|
|
14d5a28fb6 | ||
|
|
ce9835e00d | ||
|
|
39b888bd88 | ||
|
|
49cec38591 | ||
|
|
b6ca82feed | ||
|
|
b393768314 | ||
|
|
fbd942c993 | ||
|
|
b0354ec596 | ||
|
|
aaf3607051 | ||
|
|
9224709b7b | ||
|
|
d1f3fc24f8 | ||
|
|
2f8b276720 | ||
|
|
823a9987c9 | ||
|
|
ac2c4946cc | ||
|
|
8ae9a9ef4e | ||
|
|
3a53009fa0 | ||
|
|
340fff722d | ||
|
|
31efecccce | ||
|
|
c7986fd6cd | ||
|
|
b808a1a812 | ||
|
|
3414e93eb7 | ||
|
|
b231c103af | ||
|
|
a83bddd60d | ||
|
|
a773cc7970 | ||
|
|
9fba150042 | ||
|
|
0aefa33318 | ||
|
|
ddc584bdb5 | ||
|
|
3f4938833c | ||
|
|
e7f16abbc5 | ||
|
|
2d31e0607d | ||
|
|
d4ea6acdf6 | ||
|
|
5b0e9dd46f | ||
|
|
c54d1c0670 | ||
|
|
bee223ba27 | ||
|
|
532bc727c3 | ||
|
|
e68dd36596 | ||
|
|
9a4ac51f72 | ||
|
|
94ed706d53 | ||
|
|
7ea2d269cb | ||
|
|
9935baca9b | ||
|
|
deb22f9a44 | ||
|
|
688b057aec | ||
|
|
a69bef1cf1 | ||
|
|
b235a71f52 | ||
|
|
31837be3ee | ||
|
|
15eacb9b52 | ||
|
|
01f7288579 | ||
|
|
4267d3e6e0 | ||
|
|
b42ee5e1d9 | ||
|
|
bf7910c6b1 | ||
|
|
fac5a07330 | ||
|
|
10dc65dbb8 | ||
|
|
099e5b4d9f | ||
|
|
4368b29a26 | ||
|
|
b691d9d2a0 | ||
|
|
fecd264695 | ||
|
|
fa0d2f69e7 |
20
MAINTAINERS
20
MAINTAINERS
@@ -51,6 +51,7 @@ Descriptions of section entries:
|
||||
General Project Administration
|
||||
------------------------------
|
||||
M: Anthony Liguori <aliguori@amazon.com>
|
||||
M: Peter Maydell <peter.maydell@linaro.org>
|
||||
|
||||
Responsible Disclosure, Reporting Security Issues
|
||||
------------------------------
|
||||
@@ -100,7 +101,8 @@ F: hw/microblaze/
|
||||
|
||||
MIPS
|
||||
M: Aurelien Jarno <aurelien@aurel32.net>
|
||||
S: Odd Fixes
|
||||
M: Leon Alrae <leon.alrae@imgtec.com>
|
||||
S: Maintained
|
||||
F: target-mips/
|
||||
F: hw/mips/
|
||||
|
||||
@@ -198,7 +200,9 @@ M: Cornelia Huck <cornelia.huck@de.ibm.com>
|
||||
M: Alexander Graf <agraf@suse.de>
|
||||
S: Maintained
|
||||
F: target-s390x/kvm.c
|
||||
F: hw/intc/s390_flic.[hc]
|
||||
F: hw/intc/s390_flic.c
|
||||
F: hw/intc/s390_flic_kvm.c
|
||||
F: include/hw/s390x/s390_flic.h
|
||||
|
||||
X86
|
||||
M: Marcelo Tosatti <mtosatti@redhat.com>
|
||||
@@ -521,6 +525,8 @@ F: hw/s390x/s390-virtio-ccw.c
|
||||
F: hw/s390x/css.[hc]
|
||||
F: hw/s390x/sclp*.[hc]
|
||||
F: hw/s390x/ipl*.[hc]
|
||||
F: include/hw/s390x/
|
||||
F: pc-bios/s390-ccw/
|
||||
T: git git://github.com/cohuck/qemu virtio-ccw-upstr
|
||||
|
||||
UniCore32 Machines
|
||||
@@ -706,11 +712,15 @@ Block
|
||||
M: Kevin Wolf <kwolf@redhat.com>
|
||||
M: Stefan Hajnoczi <stefanha@redhat.com>
|
||||
S: Supported
|
||||
F: async.c
|
||||
F: aio-*.c
|
||||
F: block*
|
||||
F: block/
|
||||
F: hw/block/
|
||||
F: qemu-img*
|
||||
F: qemu-io*
|
||||
F: tests/image-fuzzer/
|
||||
F: tests/qemu-iotests/
|
||||
T: git git://repo.or.cz/qemu/kevin.git block
|
||||
T: git git://github.com/stefanha/qemu.git block
|
||||
|
||||
@@ -825,6 +835,12 @@ S: Supported
|
||||
F: qapi-schema.json
|
||||
T: git git://repo.or.cz/qemu/qmp-unstable.git queue/qmp
|
||||
|
||||
QObject
|
||||
M: Luiz Capitulino <lcapitulino@redhat.com>
|
||||
S: Maintained
|
||||
F: qobject/
|
||||
T: git git://repo.or.cz/qemu/qmp-unstable.git queue/qmp
|
||||
|
||||
QOM
|
||||
M: Anthony Liguori <aliguori@amazon.com>
|
||||
M: Andreas Färber <afaerber@suse.de>
|
||||
|
||||
@@ -50,7 +50,7 @@ common-obj-$(CONFIG_LINUX) += fsdev/
|
||||
|
||||
common-obj-y += migration.o migration-tcp.o
|
||||
common-obj-y += vmstate.o
|
||||
common-obj-y += qemu-file.o
|
||||
common-obj-y += qemu-file.o qemu-file-unix.o qemu-file-stdio.o
|
||||
common-obj-$(CONFIG_RDMA) += migration-rdma.o
|
||||
common-obj-y += qemu-char.o #aio.o
|
||||
common-obj-y += block-migration.o
|
||||
|
||||
62
arch_init.c
62
arch_init.c
@@ -1040,8 +1040,7 @@ void ram_handle_compressed(void *host, uint8_t ch, uint64_t size)
|
||||
|
||||
static int ram_load(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
ram_addr_t addr;
|
||||
int flags, ret = 0;
|
||||
int flags = 0, ret = 0;
|
||||
static uint64_t seq_iter;
|
||||
|
||||
seq_iter++;
|
||||
@@ -1050,21 +1049,24 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
while (!ret) {
|
||||
addr = qemu_get_be64(f);
|
||||
while (!ret && !(flags & RAM_SAVE_FLAG_EOS)) {
|
||||
ram_addr_t addr, total_ram_bytes;
|
||||
void *host;
|
||||
uint8_t ch;
|
||||
|
||||
addr = qemu_get_be64(f);
|
||||
flags = addr & ~TARGET_PAGE_MASK;
|
||||
addr &= TARGET_PAGE_MASK;
|
||||
|
||||
if (flags & RAM_SAVE_FLAG_MEM_SIZE) {
|
||||
switch (flags & ~RAM_SAVE_FLAG_CONTINUE) {
|
||||
case RAM_SAVE_FLAG_MEM_SIZE:
|
||||
/* Synchronize RAM block list */
|
||||
char id[256];
|
||||
ram_addr_t length;
|
||||
ram_addr_t total_ram_bytes = addr;
|
||||
|
||||
while (total_ram_bytes) {
|
||||
total_ram_bytes = addr;
|
||||
while (!ret && total_ram_bytes) {
|
||||
RAMBlock *block;
|
||||
uint8_t len;
|
||||
char id[256];
|
||||
ram_addr_t length;
|
||||
|
||||
len = qemu_get_byte(f);
|
||||
qemu_get_buffer(f, (uint8_t *)id, len);
|
||||
@@ -1088,16 +1090,11 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
|
||||
"accept migration", id);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
if (ret) {
|
||||
break;
|
||||
}
|
||||
|
||||
total_ram_bytes -= length;
|
||||
}
|
||||
} else if (flags & RAM_SAVE_FLAG_COMPRESS) {
|
||||
void *host;
|
||||
uint8_t ch;
|
||||
|
||||
break;
|
||||
case RAM_SAVE_FLAG_COMPRESS:
|
||||
host = host_from_stream_offset(f, addr, flags);
|
||||
if (!host) {
|
||||
error_report("Illegal RAM offset " RAM_ADDR_FMT, addr);
|
||||
@@ -1107,9 +1104,8 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
|
||||
|
||||
ch = qemu_get_byte(f);
|
||||
ram_handle_compressed(host, ch, TARGET_PAGE_SIZE);
|
||||
} else if (flags & RAM_SAVE_FLAG_PAGE) {
|
||||
void *host;
|
||||
|
||||
break;
|
||||
case RAM_SAVE_FLAG_PAGE:
|
||||
host = host_from_stream_offset(f, addr, flags);
|
||||
if (!host) {
|
||||
error_report("Illegal RAM offset " RAM_ADDR_FMT, addr);
|
||||
@@ -1118,8 +1114,9 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
|
||||
}
|
||||
|
||||
qemu_get_buffer(f, host, TARGET_PAGE_SIZE);
|
||||
} else if (flags & RAM_SAVE_FLAG_XBZRLE) {
|
||||
void *host = host_from_stream_offset(f, addr, flags);
|
||||
break;
|
||||
case RAM_SAVE_FLAG_XBZRLE:
|
||||
host = host_from_stream_offset(f, addr, flags);
|
||||
if (!host) {
|
||||
error_report("Illegal RAM offset " RAM_ADDR_FMT, addr);
|
||||
ret = -EINVAL;
|
||||
@@ -1132,17 +1129,22 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
} else if (flags & RAM_SAVE_FLAG_HOOK) {
|
||||
ram_control_load_hook(f, flags);
|
||||
} else if (flags & RAM_SAVE_FLAG_EOS) {
|
||||
break;
|
||||
case RAM_SAVE_FLAG_EOS:
|
||||
/* normal exit */
|
||||
break;
|
||||
} else {
|
||||
error_report("Unknown migration flags: %#x", flags);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
default:
|
||||
if (flags & RAM_SAVE_FLAG_HOOK) {
|
||||
ram_control_load_hook(f, flags);
|
||||
} else {
|
||||
error_report("Unknown combination of migration flags: %#x",
|
||||
flags);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
}
|
||||
if (!ret) {
|
||||
ret = qemu_file_get_error(f);
|
||||
}
|
||||
ret = qemu_file_get_error(f);
|
||||
}
|
||||
|
||||
DPRINTF("Completed load of VM with exit code %d seq iteration "
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
*/
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "block/block_int.h"
|
||||
#include "block/block.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "hw/hw.h"
|
||||
#include "qemu/queue.h"
|
||||
#include "qemu/timer.h"
|
||||
@@ -70,7 +72,7 @@ typedef struct BlkMigBlock {
|
||||
int nr_sectors;
|
||||
struct iovec iov;
|
||||
QEMUIOVector qiov;
|
||||
BlockDriverAIOCB *aiocb;
|
||||
BlockAIOCB *aiocb;
|
||||
|
||||
/* Protected by block migration lock. */
|
||||
int ret;
|
||||
@@ -130,9 +132,9 @@ static void blk_send(QEMUFile *f, BlkMigBlock * blk)
|
||||
| flags);
|
||||
|
||||
/* device name */
|
||||
len = strlen(blk->bmds->bs->device_name);
|
||||
len = strlen(bdrv_get_device_name(blk->bmds->bs));
|
||||
qemu_put_byte(f, len);
|
||||
qemu_put_buffer(f, (uint8_t *)blk->bmds->bs->device_name, len);
|
||||
qemu_put_buffer(f, (uint8_t *)bdrv_get_device_name(blk->bmds->bs), len);
|
||||
|
||||
/* if a block is zero we need to flush here since the network
|
||||
* bandwidth is now a lot higher than the storage device bandwidth.
|
||||
@@ -343,12 +345,25 @@ static void unset_dirty_tracking(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void init_blk_migration_it(void *opaque, BlockDriverState *bs)
|
||||
static void init_blk_migration(QEMUFile *f)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
BlkMigDevState *bmds;
|
||||
int64_t sectors;
|
||||
|
||||
if (!bdrv_is_read_only(bs)) {
|
||||
block_mig_state.submitted = 0;
|
||||
block_mig_state.read_done = 0;
|
||||
block_mig_state.transferred = 0;
|
||||
block_mig_state.total_sector_sum = 0;
|
||||
block_mig_state.prev_progress = -1;
|
||||
block_mig_state.bulk_completed = 0;
|
||||
block_mig_state.zero_blocks = migrate_zero_blocks();
|
||||
|
||||
for (bs = bdrv_next(NULL); bs; bs = bdrv_next(bs)) {
|
||||
if (bdrv_is_read_only(bs)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
sectors = bdrv_nb_sectors(bs);
|
||||
if (sectors <= 0) {
|
||||
return;
|
||||
@@ -369,28 +384,15 @@ static void init_blk_migration_it(void *opaque, BlockDriverState *bs)
|
||||
|
||||
if (bmds->shared_base) {
|
||||
DPRINTF("Start migration for %s with shared base image\n",
|
||||
bs->device_name);
|
||||
bdrv_get_device_name(bs));
|
||||
} else {
|
||||
DPRINTF("Start full migration for %s\n", bs->device_name);
|
||||
DPRINTF("Start full migration for %s\n", bdrv_get_device_name(bs));
|
||||
}
|
||||
|
||||
QSIMPLEQ_INSERT_TAIL(&block_mig_state.bmds_list, bmds, entry);
|
||||
}
|
||||
}
|
||||
|
||||
static void init_blk_migration(QEMUFile *f)
|
||||
{
|
||||
block_mig_state.submitted = 0;
|
||||
block_mig_state.read_done = 0;
|
||||
block_mig_state.transferred = 0;
|
||||
block_mig_state.total_sector_sum = 0;
|
||||
block_mig_state.prev_progress = -1;
|
||||
block_mig_state.bulk_completed = 0;
|
||||
block_mig_state.zero_blocks = migrate_zero_blocks();
|
||||
|
||||
bdrv_iterate(init_blk_migration_it, NULL);
|
||||
}
|
||||
|
||||
/* Called with no lock taken. */
|
||||
|
||||
static int blk_mig_save_bulked_block(QEMUFile *f)
|
||||
|
||||
439
block.c
439
block.c
@@ -28,8 +28,8 @@
|
||||
#include "block/blockjob.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qapi/qmp/qjson.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/blockdev.h" /* FIXME layering violation */
|
||||
#include "qemu/notify.h"
|
||||
#include "block/coroutine.h"
|
||||
#include "block/qapi.h"
|
||||
@@ -58,15 +58,12 @@ struct BdrvDirtyBitmap {
|
||||
|
||||
#define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */
|
||||
|
||||
#define COROUTINE_POOL_RESERVATION 64 /* number of coroutines to reserve */
|
||||
|
||||
static void bdrv_dev_change_media_cb(BlockDriverState *bs, bool load);
|
||||
static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
|
||||
static BlockAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque);
|
||||
static BlockDriverAIOCB *bdrv_aio_writev_em(BlockDriverState *bs,
|
||||
BlockCompletionFunc *cb, void *opaque);
|
||||
static BlockAIOCB *bdrv_aio_writev_em(BlockDriverState *bs,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque);
|
||||
BlockCompletionFunc *cb, void *opaque);
|
||||
static int coroutine_fn bdrv_co_readv_em(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors,
|
||||
QEMUIOVector *iov);
|
||||
@@ -79,14 +76,14 @@ static int coroutine_fn bdrv_co_do_preadv(BlockDriverState *bs,
|
||||
static int coroutine_fn bdrv_co_do_pwritev(BlockDriverState *bs,
|
||||
int64_t offset, unsigned int bytes, QEMUIOVector *qiov,
|
||||
BdrvRequestFlags flags);
|
||||
static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
QEMUIOVector *qiov,
|
||||
int nb_sectors,
|
||||
BdrvRequestFlags flags,
|
||||
BlockDriverCompletionFunc *cb,
|
||||
void *opaque,
|
||||
bool is_write);
|
||||
static BlockAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
QEMUIOVector *qiov,
|
||||
int nb_sectors,
|
||||
BdrvRequestFlags flags,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque,
|
||||
bool is_write);
|
||||
static void coroutine_fn bdrv_co_do_rw(void *opaque);
|
||||
static int coroutine_fn bdrv_co_do_write_zeroes(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors, BdrvRequestFlags flags);
|
||||
@@ -335,35 +332,21 @@ void bdrv_register(BlockDriver *bdrv)
|
||||
QLIST_INSERT_HEAD(&bdrv_drivers, bdrv, list);
|
||||
}
|
||||
|
||||
/* create a new block device (by default it is empty) */
|
||||
BlockDriverState *bdrv_new(const char *device_name, Error **errp)
|
||||
BlockDriverState *bdrv_new_root(void)
|
||||
{
|
||||
BlockDriverState *bs = bdrv_new();
|
||||
|
||||
QTAILQ_INSERT_TAIL(&bdrv_states, bs, device_list);
|
||||
return bs;
|
||||
}
|
||||
|
||||
BlockDriverState *bdrv_new(void)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
int i;
|
||||
|
||||
if (*device_name && !id_wellformed(device_name)) {
|
||||
error_setg(errp, "Invalid device name");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (bdrv_find(device_name)) {
|
||||
error_setg(errp, "Device with id '%s' already exists",
|
||||
device_name);
|
||||
return NULL;
|
||||
}
|
||||
if (bdrv_find_node(device_name)) {
|
||||
error_setg(errp,
|
||||
"Device name '%s' conflicts with an existing node name",
|
||||
device_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bs = g_new0(BlockDriverState, 1);
|
||||
QLIST_INIT(&bs->dirty_bitmaps);
|
||||
pstrcpy(bs->device_name, sizeof(bs->device_name), device_name);
|
||||
if (device_name[0] != '\0') {
|
||||
QTAILQ_INSERT_TAIL(&bdrv_states, bs, device_list);
|
||||
}
|
||||
for (i = 0; i < BLOCK_OP_TYPE_MAX; i++) {
|
||||
QLIST_INIT(&bs->op_blockers[i]);
|
||||
}
|
||||
@@ -875,7 +858,7 @@ static void bdrv_assign_node_name(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
/* takes care of avoiding namespaces collisions */
|
||||
if (bdrv_find(node_name)) {
|
||||
if (blk_by_name(node_name)) {
|
||||
error_setg(errp, "node-name=%s is conflicting with a device id",
|
||||
node_name);
|
||||
return;
|
||||
@@ -1159,7 +1142,7 @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd)
|
||||
} else if (backing_hd) {
|
||||
error_setg(&bs->backing_blocker,
|
||||
"device is used as backing hd of '%s'",
|
||||
bs->device_name);
|
||||
bdrv_get_device_name(bs));
|
||||
}
|
||||
|
||||
bs->backing_hd = backing_hd;
|
||||
@@ -1224,7 +1207,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
|
||||
goto free_exit;
|
||||
}
|
||||
|
||||
backing_hd = bdrv_new("", errp);
|
||||
backing_hd = bdrv_new();
|
||||
|
||||
if (bs->backing_format[0] != '\0') {
|
||||
back_drv = bdrv_find_format(bs->backing_format);
|
||||
@@ -1353,7 +1336,7 @@ int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp)
|
||||
qdict_put(snapshot_options, "file.filename",
|
||||
qstring_from_str(tmp_filename));
|
||||
|
||||
bs_snapshot = bdrv_new("", &error_abort);
|
||||
bs_snapshot = bdrv_new();
|
||||
|
||||
ret = bdrv_open(&bs_snapshot, NULL, NULL, snapshot_options,
|
||||
flags, bdrv_qcow2, &local_err);
|
||||
@@ -1424,7 +1407,7 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
|
||||
if (*pbs) {
|
||||
bs = *pbs;
|
||||
} else {
|
||||
bs = bdrv_new("", &error_abort);
|
||||
bs = bdrv_new();
|
||||
}
|
||||
|
||||
/* NULL means an empty set of options */
|
||||
@@ -1533,7 +1516,7 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
|
||||
} else {
|
||||
error_setg(errp, "Block format '%s' used by device '%s' doesn't "
|
||||
"support the option '%s'", drv->format_name,
|
||||
bs->device_name, entry->key);
|
||||
bdrv_get_device_name(bs), entry->key);
|
||||
}
|
||||
|
||||
ret = -EINVAL;
|
||||
@@ -1541,7 +1524,9 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
|
||||
}
|
||||
|
||||
if (!bdrv_key_required(bs)) {
|
||||
bdrv_dev_change_media_cb(bs, true);
|
||||
if (bs->blk) {
|
||||
blk_dev_change_media_cb(bs->blk, true);
|
||||
}
|
||||
} else if (!runstate_check(RUN_STATE_PRELAUNCH)
|
||||
&& !runstate_check(RUN_STATE_INMIGRATE)
|
||||
&& !runstate_check(RUN_STATE_PAUSED)) { /* HACK */
|
||||
@@ -1740,7 +1725,7 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
|
||||
if (!(reopen_state->bs->open_flags & BDRV_O_ALLOW_RDWR) &&
|
||||
reopen_state->flags & BDRV_O_RDWR) {
|
||||
error_set(errp, QERR_DEVICE_IS_READ_ONLY,
|
||||
reopen_state->bs->device_name);
|
||||
bdrv_get_device_name(reopen_state->bs));
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -1767,7 +1752,7 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
|
||||
/* It is currently mandatory to have a bdrv_reopen_prepare()
|
||||
* handler for each supported drv. */
|
||||
error_set(errp, QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
|
||||
drv->format_name, reopen_state->bs->device_name,
|
||||
drv->format_name, bdrv_get_device_name(reopen_state->bs),
|
||||
"reopening of file");
|
||||
ret = -1;
|
||||
goto error;
|
||||
@@ -1866,7 +1851,9 @@ void bdrv_close(BlockDriverState *bs)
|
||||
}
|
||||
}
|
||||
|
||||
bdrv_dev_change_media_cb(bs, false);
|
||||
if (bs->blk) {
|
||||
blk_dev_change_media_cb(bs->blk, false);
|
||||
}
|
||||
|
||||
/*throttling disk I/O limits*/
|
||||
if (bs->io_limits_enabled) {
|
||||
@@ -1955,10 +1942,17 @@ void bdrv_drain_all(void)
|
||||
Also, NULL terminate the device_name to prevent double remove */
|
||||
void bdrv_make_anon(BlockDriverState *bs)
|
||||
{
|
||||
if (bs->device_name[0] != '\0') {
|
||||
/*
|
||||
* Take care to remove bs from bdrv_states only when it's actually
|
||||
* in it. Note that bs->device_list.tqe_prev is initially null,
|
||||
* and gets set to non-null by QTAILQ_INSERT_TAIL(). Establish
|
||||
* the useful invariant "bs in bdrv_states iff bs->tqe_prev" by
|
||||
* resetting it to null on remove.
|
||||
*/
|
||||
if (bs->device_list.tqe_prev) {
|
||||
QTAILQ_REMOVE(&bdrv_states, bs, device_list);
|
||||
bs->device_list.tqe_prev = NULL;
|
||||
}
|
||||
bs->device_name[0] = '\0';
|
||||
if (bs->node_name[0] != '\0') {
|
||||
QTAILQ_REMOVE(&graph_bdrv_states, bs, node_list);
|
||||
}
|
||||
@@ -1978,9 +1972,6 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest,
|
||||
/* move some fields that need to stay attached to the device */
|
||||
|
||||
/* dev info */
|
||||
bs_dest->dev_ops = bs_src->dev_ops;
|
||||
bs_dest->dev_opaque = bs_src->dev_opaque;
|
||||
bs_dest->dev = bs_src->dev;
|
||||
bs_dest->guest_block_size = bs_src->guest_block_size;
|
||||
bs_dest->copy_on_read = bs_src->copy_on_read;
|
||||
|
||||
@@ -2012,9 +2003,9 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest,
|
||||
bs_dest->job = bs_src->job;
|
||||
|
||||
/* keep the same entry in bdrv_states */
|
||||
pstrcpy(bs_dest->device_name, sizeof(bs_dest->device_name),
|
||||
bs_src->device_name);
|
||||
bs_dest->device_list = bs_src->device_list;
|
||||
bs_dest->blk = bs_src->blk;
|
||||
|
||||
memcpy(bs_dest->op_blockers, bs_src->op_blockers,
|
||||
sizeof(bs_dest->op_blockers));
|
||||
}
|
||||
@@ -2027,7 +2018,7 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest,
|
||||
* This will modify the BlockDriverState fields, and swap contents
|
||||
* between bs_new and bs_old. Both bs_new and bs_old are modified.
|
||||
*
|
||||
* bs_new is required to be anonymous.
|
||||
* bs_new must not be attached to a BlockBackend.
|
||||
*
|
||||
* This function does not create any image files.
|
||||
*/
|
||||
@@ -2046,11 +2037,10 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old)
|
||||
QTAILQ_REMOVE(&graph_bdrv_states, bs_old, node_list);
|
||||
}
|
||||
|
||||
/* bs_new must be anonymous and shouldn't have anything fancy enabled */
|
||||
assert(bs_new->device_name[0] == '\0');
|
||||
/* bs_new must be unattached and shouldn't have anything fancy enabled */
|
||||
assert(!bs_new->blk);
|
||||
assert(QLIST_EMPTY(&bs_new->dirty_bitmaps));
|
||||
assert(bs_new->job == NULL);
|
||||
assert(bs_new->dev == NULL);
|
||||
assert(bs_new->io_limits_enabled == false);
|
||||
assert(!throttle_have_timer(&bs_new->throttle_state));
|
||||
|
||||
@@ -2063,11 +2053,10 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old)
|
||||
bdrv_move_feature_fields(bs_old, bs_new);
|
||||
bdrv_move_feature_fields(bs_new, &tmp);
|
||||
|
||||
/* bs_new shouldn't be in bdrv_states even after the swap! */
|
||||
assert(bs_new->device_name[0] == '\0');
|
||||
/* bs_new must remain unattached */
|
||||
assert(!bs_new->blk);
|
||||
|
||||
/* Check a few fields that should remain attached to the device */
|
||||
assert(bs_new->dev == NULL);
|
||||
assert(bs_new->job == NULL);
|
||||
assert(bs_new->io_limits_enabled == false);
|
||||
assert(!throttle_have_timer(&bs_new->throttle_state));
|
||||
@@ -2091,7 +2080,7 @@ void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old)
|
||||
* This will modify the BlockDriverState fields, and swap contents
|
||||
* between bs_new and bs_top. Both bs_new and bs_top are modified.
|
||||
*
|
||||
* bs_new is required to be anonymous.
|
||||
* bs_new must not be attached to a BlockBackend.
|
||||
*
|
||||
* This function does not create any image files.
|
||||
*/
|
||||
@@ -2106,7 +2095,6 @@ void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top)
|
||||
|
||||
static void bdrv_delete(BlockDriverState *bs)
|
||||
{
|
||||
assert(!bs->dev);
|
||||
assert(!bs->job);
|
||||
assert(bdrv_op_blocker_is_empty(bs));
|
||||
assert(!bs->refcnt);
|
||||
@@ -2117,109 +2105,9 @@ static void bdrv_delete(BlockDriverState *bs)
|
||||
/* remove from list, if necessary */
|
||||
bdrv_make_anon(bs);
|
||||
|
||||
drive_info_del(drive_get_by_blockdev(bs));
|
||||
g_free(bs);
|
||||
}
|
||||
|
||||
int bdrv_attach_dev(BlockDriverState *bs, void *dev)
|
||||
/* TODO change to DeviceState *dev when all users are qdevified */
|
||||
{
|
||||
if (bs->dev) {
|
||||
return -EBUSY;
|
||||
}
|
||||
bs->dev = dev;
|
||||
bdrv_iostatus_reset(bs);
|
||||
|
||||
/* We're expecting I/O from the device so bump up coroutine pool size */
|
||||
qemu_coroutine_adjust_pool_size(COROUTINE_POOL_RESERVATION);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TODO qdevified devices don't use this, remove when devices are qdevified */
|
||||
void bdrv_attach_dev_nofail(BlockDriverState *bs, void *dev)
|
||||
{
|
||||
if (bdrv_attach_dev(bs, dev) < 0) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void bdrv_detach_dev(BlockDriverState *bs, void *dev)
|
||||
/* TODO change to DeviceState *dev when all users are qdevified */
|
||||
{
|
||||
assert(bs->dev == dev);
|
||||
bs->dev = NULL;
|
||||
bs->dev_ops = NULL;
|
||||
bs->dev_opaque = NULL;
|
||||
bs->guest_block_size = 512;
|
||||
qemu_coroutine_adjust_pool_size(-COROUTINE_POOL_RESERVATION);
|
||||
}
|
||||
|
||||
/* TODO change to return DeviceState * when all users are qdevified */
|
||||
void *bdrv_get_attached_dev(BlockDriverState *bs)
|
||||
{
|
||||
return bs->dev;
|
||||
}
|
||||
|
||||
void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops,
|
||||
void *opaque)
|
||||
{
|
||||
bs->dev_ops = ops;
|
||||
bs->dev_opaque = opaque;
|
||||
}
|
||||
|
||||
static void bdrv_dev_change_media_cb(BlockDriverState *bs, bool load)
|
||||
{
|
||||
if (bs->dev_ops && bs->dev_ops->change_media_cb) {
|
||||
bool tray_was_closed = !bdrv_dev_is_tray_open(bs);
|
||||
bs->dev_ops->change_media_cb(bs->dev_opaque, load);
|
||||
if (tray_was_closed) {
|
||||
/* tray open */
|
||||
qapi_event_send_device_tray_moved(bdrv_get_device_name(bs),
|
||||
true, &error_abort);
|
||||
}
|
||||
if (load) {
|
||||
/* tray close */
|
||||
qapi_event_send_device_tray_moved(bdrv_get_device_name(bs),
|
||||
false, &error_abort);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool bdrv_dev_has_removable_media(BlockDriverState *bs)
|
||||
{
|
||||
return !bs->dev || (bs->dev_ops && bs->dev_ops->change_media_cb);
|
||||
}
|
||||
|
||||
void bdrv_dev_eject_request(BlockDriverState *bs, bool force)
|
||||
{
|
||||
if (bs->dev_ops && bs->dev_ops->eject_request_cb) {
|
||||
bs->dev_ops->eject_request_cb(bs->dev_opaque, force);
|
||||
}
|
||||
}
|
||||
|
||||
bool bdrv_dev_is_tray_open(BlockDriverState *bs)
|
||||
{
|
||||
if (bs->dev_ops && bs->dev_ops->is_tray_open) {
|
||||
return bs->dev_ops->is_tray_open(bs->dev_opaque);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void bdrv_dev_resize_cb(BlockDriverState *bs)
|
||||
{
|
||||
if (bs->dev_ops && bs->dev_ops->resize_cb) {
|
||||
bs->dev_ops->resize_cb(bs->dev_opaque);
|
||||
}
|
||||
}
|
||||
|
||||
bool bdrv_dev_is_medium_locked(BlockDriverState *bs)
|
||||
{
|
||||
if (bs->dev_ops && bs->dev_ops->is_medium_locked) {
|
||||
return bs->dev_ops->is_medium_locked(bs->dev_opaque);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Run consistency checks on an image
|
||||
*
|
||||
@@ -3553,7 +3441,9 @@ int bdrv_truncate(BlockDriverState *bs, int64_t offset)
|
||||
ret = drv->bdrv_truncate(bs, offset);
|
||||
if (ret == 0) {
|
||||
ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
|
||||
bdrv_dev_resize_cb(bs);
|
||||
if (bs->blk) {
|
||||
blk_dev_resize_cb(bs->blk);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -3754,8 +3644,10 @@ int bdrv_set_key(BlockDriverState *bs, const char *key)
|
||||
bs->valid_key = 0;
|
||||
} else if (!bs->valid_key) {
|
||||
bs->valid_key = 1;
|
||||
/* call the change callback now, we skipped it on open */
|
||||
bdrv_dev_change_media_cb(bs, true);
|
||||
if (bs->blk) {
|
||||
/* call the change callback now, we skipped it on open */
|
||||
blk_dev_change_media_cb(bs->blk, true);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -3803,16 +3695,12 @@ void bdrv_iterate_format(void (*it)(void *opaque, const char *name),
|
||||
}
|
||||
|
||||
/* This function is to find block backend bs */
|
||||
/* TODO convert callers to blk_by_name(), then remove */
|
||||
BlockDriverState *bdrv_find(const char *name)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
BlockBackend *blk = blk_by_name(name);
|
||||
|
||||
QTAILQ_FOREACH(bs, &bdrv_states, device_list) {
|
||||
if (!strcmp(name, bs->device_name)) {
|
||||
return bs;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
return blk ? blk_bs(blk) : NULL;
|
||||
}
|
||||
|
||||
/* This function is to find a node in the bs graph */
|
||||
@@ -3851,13 +3739,14 @@ BlockDriverState *bdrv_lookup_bs(const char *device,
|
||||
const char *node_name,
|
||||
Error **errp)
|
||||
{
|
||||
BlockDriverState *bs = NULL;
|
||||
BlockBackend *blk;
|
||||
BlockDriverState *bs;
|
||||
|
||||
if (device) {
|
||||
bs = bdrv_find(device);
|
||||
blk = blk_by_name(device);
|
||||
|
||||
if (bs) {
|
||||
return bs;
|
||||
if (blk) {
|
||||
return blk_bs(blk);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3894,18 +3783,10 @@ BlockDriverState *bdrv_next(BlockDriverState *bs)
|
||||
return QTAILQ_NEXT(bs, device_list);
|
||||
}
|
||||
|
||||
void bdrv_iterate(void (*it)(void *opaque, BlockDriverState *bs), void *opaque)
|
||||
/* TODO check what callers really want: bs->node_name or blk_name() */
|
||||
const char *bdrv_get_device_name(const BlockDriverState *bs)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
|
||||
QTAILQ_FOREACH(bs, &bdrv_states, device_list) {
|
||||
it(opaque, bs);
|
||||
}
|
||||
}
|
||||
|
||||
const char *bdrv_get_device_name(BlockDriverState *bs)
|
||||
{
|
||||
return bs->device_name;
|
||||
return bs->blk ? blk_name(bs->blk) : "";
|
||||
}
|
||||
|
||||
int bdrv_get_flags(BlockDriverState *bs)
|
||||
@@ -4073,13 +3954,24 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
|
||||
if (bs->file &&
|
||||
(ret & BDRV_BLOCK_DATA) && !(ret & BDRV_BLOCK_ZERO) &&
|
||||
(ret & BDRV_BLOCK_OFFSET_VALID)) {
|
||||
int file_pnum;
|
||||
|
||||
ret2 = bdrv_co_get_block_status(bs->file, ret >> BDRV_SECTOR_BITS,
|
||||
*pnum, pnum);
|
||||
*pnum, &file_pnum);
|
||||
if (ret2 >= 0) {
|
||||
/* Ignore errors. This is just providing extra information, it
|
||||
* is useful but not necessary.
|
||||
*/
|
||||
ret |= (ret2 & BDRV_BLOCK_ZERO);
|
||||
if (!file_pnum) {
|
||||
/* !file_pnum indicates an offset at or beyond the EOF; it is
|
||||
* perfectly valid for the format block driver to point to such
|
||||
* offsets, so catch it and mark everything as zero */
|
||||
ret |= BDRV_BLOCK_ZERO;
|
||||
} else {
|
||||
/* Limit request to the range reported by the protocol driver */
|
||||
*pnum = file_pnum;
|
||||
ret |= (ret2 & BDRV_BLOCK_ZERO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4432,9 +4324,9 @@ int bdrv_get_backing_file_depth(BlockDriverState *bs)
|
||||
/**************************************************************/
|
||||
/* async I/Os */
|
||||
|
||||
BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
|
||||
QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
BlockAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
|
||||
QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
trace_bdrv_aio_readv(bs, sector_num, nb_sectors, opaque);
|
||||
|
||||
@@ -4442,9 +4334,9 @@ BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,
|
||||
cb, opaque, false);
|
||||
}
|
||||
|
||||
BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
|
||||
QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
BlockAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
|
||||
QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
trace_bdrv_aio_writev(bs, sector_num, nb_sectors, opaque);
|
||||
|
||||
@@ -4452,9 +4344,9 @@ BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num,
|
||||
cb, opaque, true);
|
||||
}
|
||||
|
||||
BlockDriverAIOCB *bdrv_aio_write_zeroes(BlockDriverState *bs,
|
||||
BlockAIOCB *bdrv_aio_write_zeroes(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors, BdrvRequestFlags flags,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
trace_bdrv_aio_write_zeroes(bs, sector_num, nb_sectors, flags, opaque);
|
||||
|
||||
@@ -4469,7 +4361,7 @@ typedef struct MultiwriteCB {
|
||||
int num_requests;
|
||||
int num_callbacks;
|
||||
struct {
|
||||
BlockDriverCompletionFunc *cb;
|
||||
BlockCompletionFunc *cb;
|
||||
void *opaque;
|
||||
QEMUIOVector *free_qiov;
|
||||
} callbacks[];
|
||||
@@ -4646,7 +4538,7 @@ int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs, int num_reqs)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void bdrv_aio_cancel(BlockDriverAIOCB *acb)
|
||||
void bdrv_aio_cancel(BlockAIOCB *acb)
|
||||
{
|
||||
qemu_aio_ref(acb);
|
||||
bdrv_aio_cancel_async(acb);
|
||||
@@ -4665,7 +4557,7 @@ void bdrv_aio_cancel(BlockDriverAIOCB *acb)
|
||||
/* Async version of aio cancel. The caller is not blocked if the acb implements
|
||||
* cancel_async, otherwise we do nothing and let the request normally complete.
|
||||
* In either case the completion callback must be called. */
|
||||
void bdrv_aio_cancel_async(BlockDriverAIOCB *acb)
|
||||
void bdrv_aio_cancel_async(BlockAIOCB *acb)
|
||||
{
|
||||
if (acb->aiocb_info->cancel_async) {
|
||||
acb->aiocb_info->cancel_async(acb);
|
||||
@@ -4675,23 +4567,23 @@ void bdrv_aio_cancel_async(BlockDriverAIOCB *acb)
|
||||
/**************************************************************/
|
||||
/* async block device emulation */
|
||||
|
||||
typedef struct BlockDriverAIOCBSync {
|
||||
BlockDriverAIOCB common;
|
||||
typedef struct BlockAIOCBSync {
|
||||
BlockAIOCB common;
|
||||
QEMUBH *bh;
|
||||
int ret;
|
||||
/* vector translation state */
|
||||
QEMUIOVector *qiov;
|
||||
uint8_t *bounce;
|
||||
int is_write;
|
||||
} BlockDriverAIOCBSync;
|
||||
} BlockAIOCBSync;
|
||||
|
||||
static const AIOCBInfo bdrv_em_aiocb_info = {
|
||||
.aiocb_size = sizeof(BlockDriverAIOCBSync),
|
||||
.aiocb_size = sizeof(BlockAIOCBSync),
|
||||
};
|
||||
|
||||
static void bdrv_aio_bh_cb(void *opaque)
|
||||
{
|
||||
BlockDriverAIOCBSync *acb = opaque;
|
||||
BlockAIOCBSync *acb = opaque;
|
||||
|
||||
if (!acb->is_write && acb->ret >= 0) {
|
||||
qemu_iovec_from_buf(acb->qiov, 0, acb->bounce, acb->qiov->size);
|
||||
@@ -4703,16 +4595,16 @@ static void bdrv_aio_bh_cb(void *opaque)
|
||||
qemu_aio_unref(acb);
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *bdrv_aio_rw_vector(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
QEMUIOVector *qiov,
|
||||
int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb,
|
||||
void *opaque,
|
||||
int is_write)
|
||||
static BlockAIOCB *bdrv_aio_rw_vector(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
QEMUIOVector *qiov,
|
||||
int nb_sectors,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque,
|
||||
int is_write)
|
||||
|
||||
{
|
||||
BlockDriverAIOCBSync *acb;
|
||||
BlockAIOCBSync *acb;
|
||||
|
||||
acb = qemu_aio_get(&bdrv_em_aiocb_info, bs, cb, opaque);
|
||||
acb->is_write = is_write;
|
||||
@@ -4734,36 +4626,36 @@ static BlockDriverAIOCB *bdrv_aio_rw_vector(BlockDriverState *bs,
|
||||
return &acb->common;
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
|
||||
static BlockAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
return bdrv_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *bdrv_aio_writev_em(BlockDriverState *bs,
|
||||
static BlockAIOCB *bdrv_aio_writev_em(BlockDriverState *bs,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
return bdrv_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
|
||||
}
|
||||
|
||||
|
||||
typedef struct BlockDriverAIOCBCoroutine {
|
||||
BlockDriverAIOCB common;
|
||||
typedef struct BlockAIOCBCoroutine {
|
||||
BlockAIOCB common;
|
||||
BlockRequest req;
|
||||
bool is_write;
|
||||
bool *done;
|
||||
QEMUBH* bh;
|
||||
} BlockDriverAIOCBCoroutine;
|
||||
} BlockAIOCBCoroutine;
|
||||
|
||||
static const AIOCBInfo bdrv_em_co_aiocb_info = {
|
||||
.aiocb_size = sizeof(BlockDriverAIOCBCoroutine),
|
||||
.aiocb_size = sizeof(BlockAIOCBCoroutine),
|
||||
};
|
||||
|
||||
static void bdrv_co_em_bh(void *opaque)
|
||||
{
|
||||
BlockDriverAIOCBCoroutine *acb = opaque;
|
||||
BlockAIOCBCoroutine *acb = opaque;
|
||||
|
||||
acb->common.cb(acb->common.opaque, acb->req.error);
|
||||
|
||||
@@ -4774,7 +4666,7 @@ static void bdrv_co_em_bh(void *opaque)
|
||||
/* Invoke bdrv_co_do_readv/bdrv_co_do_writev */
|
||||
static void coroutine_fn bdrv_co_do_rw(void *opaque)
|
||||
{
|
||||
BlockDriverAIOCBCoroutine *acb = opaque;
|
||||
BlockAIOCBCoroutine *acb = opaque;
|
||||
BlockDriverState *bs = acb->common.bs;
|
||||
|
||||
if (!acb->is_write) {
|
||||
@@ -4789,17 +4681,17 @@ static void coroutine_fn bdrv_co_do_rw(void *opaque)
|
||||
qemu_bh_schedule(acb->bh);
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
QEMUIOVector *qiov,
|
||||
int nb_sectors,
|
||||
BdrvRequestFlags flags,
|
||||
BlockDriverCompletionFunc *cb,
|
||||
void *opaque,
|
||||
bool is_write)
|
||||
static BlockAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
QEMUIOVector *qiov,
|
||||
int nb_sectors,
|
||||
BdrvRequestFlags flags,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque,
|
||||
bool is_write)
|
||||
{
|
||||
Coroutine *co;
|
||||
BlockDriverAIOCBCoroutine *acb;
|
||||
BlockAIOCBCoroutine *acb;
|
||||
|
||||
acb = qemu_aio_get(&bdrv_em_co_aiocb_info, bs, cb, opaque);
|
||||
acb->req.sector = sector_num;
|
||||
@@ -4816,7 +4708,7 @@ static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
|
||||
|
||||
static void coroutine_fn bdrv_aio_flush_co_entry(void *opaque)
|
||||
{
|
||||
BlockDriverAIOCBCoroutine *acb = opaque;
|
||||
BlockAIOCBCoroutine *acb = opaque;
|
||||
BlockDriverState *bs = acb->common.bs;
|
||||
|
||||
acb->req.error = bdrv_co_flush(bs);
|
||||
@@ -4824,13 +4716,13 @@ static void coroutine_fn bdrv_aio_flush_co_entry(void *opaque)
|
||||
qemu_bh_schedule(acb->bh);
|
||||
}
|
||||
|
||||
BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
BlockAIOCB *bdrv_aio_flush(BlockDriverState *bs,
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
trace_bdrv_aio_flush(bs, opaque);
|
||||
|
||||
Coroutine *co;
|
||||
BlockDriverAIOCBCoroutine *acb;
|
||||
BlockAIOCBCoroutine *acb;
|
||||
|
||||
acb = qemu_aio_get(&bdrv_em_co_aiocb_info, bs, cb, opaque);
|
||||
|
||||
@@ -4842,7 +4734,7 @@ BlockDriverAIOCB *bdrv_aio_flush(BlockDriverState *bs,
|
||||
|
||||
static void coroutine_fn bdrv_aio_discard_co_entry(void *opaque)
|
||||
{
|
||||
BlockDriverAIOCBCoroutine *acb = opaque;
|
||||
BlockAIOCBCoroutine *acb = opaque;
|
||||
BlockDriverState *bs = acb->common.bs;
|
||||
|
||||
acb->req.error = bdrv_co_discard(bs, acb->req.sector, acb->req.nb_sectors);
|
||||
@@ -4850,12 +4742,12 @@ static void coroutine_fn bdrv_aio_discard_co_entry(void *opaque)
|
||||
qemu_bh_schedule(acb->bh);
|
||||
}
|
||||
|
||||
BlockDriverAIOCB *bdrv_aio_discard(BlockDriverState *bs,
|
||||
BlockAIOCB *bdrv_aio_discard(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
Coroutine *co;
|
||||
BlockDriverAIOCBCoroutine *acb;
|
||||
BlockAIOCBCoroutine *acb;
|
||||
|
||||
trace_bdrv_aio_discard(bs, sector_num, nb_sectors, opaque);
|
||||
|
||||
@@ -4880,9 +4772,9 @@ void bdrv_init_with_whitelist(void)
|
||||
}
|
||||
|
||||
void *qemu_aio_get(const AIOCBInfo *aiocb_info, BlockDriverState *bs,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
BlockDriverAIOCB *acb;
|
||||
BlockAIOCB *acb;
|
||||
|
||||
acb = g_slice_alloc(aiocb_info->aiocb_size);
|
||||
acb->aiocb_info = aiocb_info;
|
||||
@@ -4895,13 +4787,13 @@ void *qemu_aio_get(const AIOCBInfo *aiocb_info, BlockDriverState *bs,
|
||||
|
||||
void qemu_aio_ref(void *p)
|
||||
{
|
||||
BlockDriverAIOCB *acb = p;
|
||||
BlockAIOCB *acb = p;
|
||||
acb->refcnt++;
|
||||
}
|
||||
|
||||
void qemu_aio_unref(void *p)
|
||||
{
|
||||
BlockDriverAIOCB *acb = p;
|
||||
BlockAIOCB *acb = p;
|
||||
assert(acb->refcnt > 0);
|
||||
if (--acb->refcnt == 0) {
|
||||
g_slice_free1(acb->aiocb_info->aiocb_size, acb);
|
||||
@@ -4931,7 +4823,7 @@ static int coroutine_fn bdrv_co_io_em(BlockDriverState *bs, int64_t sector_num,
|
||||
CoroutineIOCompletion co = {
|
||||
.coroutine = qemu_coroutine_self(),
|
||||
};
|
||||
BlockDriverAIOCB *acb;
|
||||
BlockAIOCB *acb;
|
||||
|
||||
if (is_write) {
|
||||
acb = bs->drv->bdrv_aio_writev(bs, sector_num, iov, nb_sectors,
|
||||
@@ -4997,7 +4889,7 @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
|
||||
if (bs->drv->bdrv_co_flush_to_disk) {
|
||||
ret = bs->drv->bdrv_co_flush_to_disk(bs);
|
||||
} else if (bs->drv->bdrv_aio_flush) {
|
||||
BlockDriverAIOCB *acb;
|
||||
BlockAIOCB *acb;
|
||||
CoroutineIOCompletion co = {
|
||||
.coroutine = qemu_coroutine_self(),
|
||||
};
|
||||
@@ -5043,6 +4935,11 @@ void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(bs->open_flags & BDRV_O_INCOMING)) {
|
||||
return;
|
||||
}
|
||||
bs->open_flags &= ~BDRV_O_INCOMING;
|
||||
|
||||
if (bs->drv->bdrv_invalidate_cache) {
|
||||
bs->drv->bdrv_invalidate_cache(bs, &local_err);
|
||||
} else if (bs->file) {
|
||||
@@ -5078,19 +4975,6 @@ void bdrv_invalidate_cache_all(Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
void bdrv_clear_incoming_migration_all(void)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
|
||||
QTAILQ_FOREACH(bs, &bdrv_states, device_list) {
|
||||
AioContext *aio_context = bdrv_get_aio_context(bs);
|
||||
|
||||
aio_context_acquire(aio_context);
|
||||
bs->open_flags = bs->open_flags & ~(BDRV_O_INCOMING);
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
}
|
||||
|
||||
int bdrv_flush(BlockDriverState *bs)
|
||||
{
|
||||
Coroutine *co;
|
||||
@@ -5180,7 +5064,7 @@ int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num,
|
||||
if (bs->drv->bdrv_co_discard) {
|
||||
ret = bs->drv->bdrv_co_discard(bs, sector_num, num);
|
||||
} else {
|
||||
BlockDriverAIOCB *acb;
|
||||
BlockAIOCB *acb;
|
||||
CoroutineIOCompletion co = {
|
||||
.coroutine = qemu_coroutine_self(),
|
||||
};
|
||||
@@ -5267,13 +5151,15 @@ int bdrv_media_changed(BlockDriverState *bs)
|
||||
void bdrv_eject(BlockDriverState *bs, bool eject_flag)
|
||||
{
|
||||
BlockDriver *drv = bs->drv;
|
||||
const char *device_name;
|
||||
|
||||
if (drv && drv->bdrv_eject) {
|
||||
drv->bdrv_eject(bs, eject_flag);
|
||||
}
|
||||
|
||||
if (bs->device_name[0] != '\0') {
|
||||
qapi_event_send_device_tray_moved(bdrv_get_device_name(bs),
|
||||
device_name = bdrv_get_device_name(bs);
|
||||
if (device_name[0] != '\0') {
|
||||
qapi_event_send_device_tray_moved(device_name,
|
||||
eject_flag, &error_abort);
|
||||
}
|
||||
}
|
||||
@@ -5304,9 +5190,9 @@ int bdrv_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
|
||||
BlockAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
|
||||
unsigned long int req, void *buf,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
BlockDriver *drv = bs->drv;
|
||||
|
||||
@@ -5325,6 +5211,11 @@ void *qemu_blockalign(BlockDriverState *bs, size_t size)
|
||||
return qemu_memalign(bdrv_opt_mem_align(bs), size);
|
||||
}
|
||||
|
||||
void *qemu_blockalign0(BlockDriverState *bs, size_t size)
|
||||
{
|
||||
return memset(qemu_blockalign(bs, size), 0, size);
|
||||
}
|
||||
|
||||
void *qemu_try_blockalign(BlockDriverState *bs, size_t size)
|
||||
{
|
||||
size_t align = bdrv_opt_mem_align(bs);
|
||||
@@ -5338,6 +5229,17 @@ void *qemu_try_blockalign(BlockDriverState *bs, size_t size)
|
||||
return qemu_try_memalign(align, size);
|
||||
}
|
||||
|
||||
void *qemu_try_blockalign0(BlockDriverState *bs, size_t size)
|
||||
{
|
||||
void *mem = qemu_try_blockalign(bs, size);
|
||||
|
||||
if (mem) {
|
||||
memset(mem, 0, size);
|
||||
}
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if all memory in this vector is sector aligned.
|
||||
*/
|
||||
@@ -5483,7 +5385,8 @@ bool bdrv_op_is_blocked(BlockDriverState *bs, BlockOpType op, Error **errp)
|
||||
blocker = QLIST_FIRST(&bs->op_blockers[op]);
|
||||
if (errp) {
|
||||
error_setg(errp, "Device '%s' is busy: %s",
|
||||
bs->device_name, error_get_pretty(blocker->reason));
|
||||
bdrv_get_device_name(bs),
|
||||
error_get_pretty(blocker->reason));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ block-obj-y += qed-check.o
|
||||
block-obj-$(CONFIG_VHDX) += vhdx.o vhdx-endian.o vhdx-log.o
|
||||
block-obj-$(CONFIG_QUORUM) += quorum.o
|
||||
block-obj-y += parallels.o blkdebug.o blkverify.o
|
||||
block-obj-y += snapshot.o qapi.o
|
||||
block-obj-y += block-backend.o snapshot.o qapi.o
|
||||
block-obj-$(CONFIG_WIN32) += raw-win32.o win32-aio.o
|
||||
block-obj-$(CONFIG_POSIX) += raw-posix.o
|
||||
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
|
||||
|
||||
@@ -86,7 +86,7 @@ typedef enum {
|
||||
} ARCHIPCmd;
|
||||
|
||||
typedef struct ArchipelagoAIOCB {
|
||||
BlockDriverAIOCB common;
|
||||
BlockAIOCB common;
|
||||
QEMUBH *bh;
|
||||
struct BDRVArchipelagoState *s;
|
||||
QEMUIOVector *qiov;
|
||||
@@ -856,13 +856,13 @@ err_exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *qemu_archipelago_aio_rw(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
QEMUIOVector *qiov,
|
||||
int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb,
|
||||
void *opaque,
|
||||
int op)
|
||||
static BlockAIOCB *qemu_archipelago_aio_rw(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
QEMUIOVector *qiov,
|
||||
int nb_sectors,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque,
|
||||
int op)
|
||||
{
|
||||
ArchipelagoAIOCB *aio_cb;
|
||||
BDRVArchipelagoState *s = bs->opaque;
|
||||
@@ -894,17 +894,17 @@ err_exit:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *qemu_archipelago_aio_readv(BlockDriverState *bs,
|
||||
static BlockAIOCB *qemu_archipelago_aio_readv(BlockDriverState *bs,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
return qemu_archipelago_aio_rw(bs, sector_num, qiov, nb_sectors, cb,
|
||||
opaque, ARCHIP_OP_READ);
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *qemu_archipelago_aio_writev(BlockDriverState *bs,
|
||||
static BlockAIOCB *qemu_archipelago_aio_writev(BlockDriverState *bs,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
return qemu_archipelago_aio_rw(bs, sector_num, qiov, nb_sectors, cb,
|
||||
opaque, ARCHIP_OP_WRITE);
|
||||
@@ -1052,8 +1052,8 @@ static QemuOptsList qemu_archipelago_create_opts = {
|
||||
}
|
||||
};
|
||||
|
||||
static BlockDriverAIOCB *qemu_archipelago_aio_flush(BlockDriverState *bs,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
static BlockAIOCB *qemu_archipelago_aio_flush(BlockDriverState *bs,
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
return qemu_archipelago_aio_rw(bs, 0, NULL, 0, cb, opaque,
|
||||
ARCHIP_OP_FLUSH);
|
||||
|
||||
@@ -353,7 +353,7 @@ void backup_start(BlockDriverState *bs, BlockDriverState *target,
|
||||
int64_t speed, MirrorSyncMode sync_mode,
|
||||
BlockdevOnError on_source_error,
|
||||
BlockdevOnError on_target_error,
|
||||
BlockDriverCompletionFunc *cb, void *opaque,
|
||||
BlockCompletionFunc *cb, void *opaque,
|
||||
Error **errp)
|
||||
{
|
||||
int64_t len;
|
||||
|
||||
@@ -41,7 +41,7 @@ typedef struct BDRVBlkdebugState {
|
||||
} BDRVBlkdebugState;
|
||||
|
||||
typedef struct BlkdebugAIOCB {
|
||||
BlockDriverAIOCB common;
|
||||
BlockAIOCB common;
|
||||
QEMUBH *bh;
|
||||
int ret;
|
||||
} BlkdebugAIOCB;
|
||||
@@ -463,8 +463,8 @@ static void error_callback_bh(void *opaque)
|
||||
qemu_aio_unref(acb);
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *inject_error(BlockDriverState *bs,
|
||||
BlockDriverCompletionFunc *cb, void *opaque, BlkdebugRule *rule)
|
||||
static BlockAIOCB *inject_error(BlockDriverState *bs,
|
||||
BlockCompletionFunc *cb, void *opaque, BlkdebugRule *rule)
|
||||
{
|
||||
BDRVBlkdebugState *s = bs->opaque;
|
||||
int error = rule->options.inject.error;
|
||||
@@ -489,9 +489,9 @@ static BlockDriverAIOCB *inject_error(BlockDriverState *bs,
|
||||
return &acb->common;
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *blkdebug_aio_readv(BlockDriverState *bs,
|
||||
static BlockAIOCB *blkdebug_aio_readv(BlockDriverState *bs,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
BDRVBlkdebugState *s = bs->opaque;
|
||||
BlkdebugRule *rule = NULL;
|
||||
@@ -511,9 +511,9 @@ static BlockDriverAIOCB *blkdebug_aio_readv(BlockDriverState *bs,
|
||||
return bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
|
||||
static BlockAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
BDRVBlkdebugState *s = bs->opaque;
|
||||
BlkdebugRule *rule = NULL;
|
||||
@@ -533,8 +533,8 @@ static BlockDriverAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
|
||||
return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *blkdebug_aio_flush(BlockDriverState *bs,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
static BlockAIOCB *blkdebug_aio_flush(BlockDriverState *bs,
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
BDRVBlkdebugState *s = bs->opaque;
|
||||
BlkdebugRule *rule = NULL;
|
||||
|
||||
@@ -19,7 +19,7 @@ typedef struct {
|
||||
|
||||
typedef struct BlkverifyAIOCB BlkverifyAIOCB;
|
||||
struct BlkverifyAIOCB {
|
||||
BlockDriverAIOCB common;
|
||||
BlockAIOCB common;
|
||||
QEMUBH *bh;
|
||||
|
||||
/* Request metadata */
|
||||
@@ -165,7 +165,7 @@ static int64_t blkverify_getlength(BlockDriverState *bs)
|
||||
static BlkverifyAIOCB *blkverify_aio_get(BlockDriverState *bs, bool is_write,
|
||||
int64_t sector_num, QEMUIOVector *qiov,
|
||||
int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque)
|
||||
{
|
||||
BlkverifyAIOCB *acb = qemu_aio_get(&blkverify_aiocb_info, bs, cb, opaque);
|
||||
@@ -229,9 +229,9 @@ static void blkverify_verify_readv(BlkverifyAIOCB *acb)
|
||||
}
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *blkverify_aio_readv(BlockDriverState *bs,
|
||||
static BlockAIOCB *blkverify_aio_readv(BlockDriverState *bs,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
BDRVBlkverifyState *s = bs->opaque;
|
||||
BlkverifyAIOCB *acb = blkverify_aio_get(bs, false, sector_num, qiov,
|
||||
@@ -249,9 +249,9 @@ static BlockDriverAIOCB *blkverify_aio_readv(BlockDriverState *bs,
|
||||
return &acb->common;
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *blkverify_aio_writev(BlockDriverState *bs,
|
||||
static BlockAIOCB *blkverify_aio_writev(BlockDriverState *bs,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
BDRVBlkverifyState *s = bs->opaque;
|
||||
BlkverifyAIOCB *acb = blkverify_aio_get(bs, true, sector_num, qiov,
|
||||
@@ -264,9 +264,9 @@ static BlockDriverAIOCB *blkverify_aio_writev(BlockDriverState *bs,
|
||||
return &acb->common;
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *blkverify_aio_flush(BlockDriverState *bs,
|
||||
BlockDriverCompletionFunc *cb,
|
||||
void *opaque)
|
||||
static BlockAIOCB *blkverify_aio_flush(BlockDriverState *bs,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque)
|
||||
{
|
||||
BDRVBlkverifyState *s = bs->opaque;
|
||||
|
||||
|
||||
631
block/block-backend.c
Normal file
631
block/block-backend.c
Normal file
@@ -0,0 +1,631 @@
|
||||
/*
|
||||
* QEMU Block backends
|
||||
*
|
||||
* Copyright (C) 2014 Red Hat, Inc.
|
||||
*
|
||||
* Authors:
|
||||
* Markus Armbruster <armbru@redhat.com>,
|
||||
*
|
||||
* This work is licensed under the terms of the GNU LGPL, version 2.1
|
||||
* or later. See the COPYING.LIB file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "block/block_int.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "qapi-event.h"
|
||||
|
||||
/* Number of coroutines to reserve per attached device model */
|
||||
#define COROUTINE_POOL_RESERVATION 64
|
||||
|
||||
struct BlockBackend {
|
||||
char *name;
|
||||
int refcnt;
|
||||
BlockDriverState *bs;
|
||||
DriveInfo *legacy_dinfo; /* null unless created by drive_new() */
|
||||
QTAILQ_ENTRY(BlockBackend) link; /* for blk_backends */
|
||||
|
||||
void *dev; /* attached device model, if any */
|
||||
/* TODO change to DeviceState when all users are qdevified */
|
||||
const BlockDevOps *dev_ops;
|
||||
void *dev_opaque;
|
||||
};
|
||||
|
||||
static void drive_info_del(DriveInfo *dinfo);
|
||||
|
||||
/* All the BlockBackends (except for hidden ones) */
|
||||
static QTAILQ_HEAD(, BlockBackend) blk_backends =
|
||||
QTAILQ_HEAD_INITIALIZER(blk_backends);
|
||||
|
||||
/*
|
||||
* Create a new BlockBackend with @name, with a reference count of one.
|
||||
* @name must not be null or empty.
|
||||
* Fail if a BlockBackend with this name already exists.
|
||||
* Store an error through @errp on failure, unless it's null.
|
||||
* Return the new BlockBackend on success, null on failure.
|
||||
*/
|
||||
BlockBackend *blk_new(const char *name, Error **errp)
|
||||
{
|
||||
BlockBackend *blk;
|
||||
|
||||
assert(name && name[0]);
|
||||
if (!id_wellformed(name)) {
|
||||
error_setg(errp, "Invalid device name");
|
||||
return NULL;
|
||||
}
|
||||
if (blk_by_name(name)) {
|
||||
error_setg(errp, "Device with id '%s' already exists", name);
|
||||
return NULL;
|
||||
}
|
||||
if (bdrv_find_node(name)) {
|
||||
error_setg(errp,
|
||||
"Device name '%s' conflicts with an existing node name",
|
||||
name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
blk = g_new0(BlockBackend, 1);
|
||||
blk->name = g_strdup(name);
|
||||
blk->refcnt = 1;
|
||||
QTAILQ_INSERT_TAIL(&blk_backends, blk, link);
|
||||
return blk;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new BlockBackend with a new BlockDriverState attached.
|
||||
* Otherwise just like blk_new(), which see.
|
||||
*/
|
||||
BlockBackend *blk_new_with_bs(const char *name, Error **errp)
|
||||
{
|
||||
BlockBackend *blk;
|
||||
BlockDriverState *bs;
|
||||
|
||||
blk = blk_new(name, errp);
|
||||
if (!blk) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bs = bdrv_new_root();
|
||||
blk->bs = bs;
|
||||
bs->blk = blk;
|
||||
return blk;
|
||||
}
|
||||
|
||||
static void blk_delete(BlockBackend *blk)
|
||||
{
|
||||
assert(!blk->refcnt);
|
||||
assert(!blk->dev);
|
||||
if (blk->bs) {
|
||||
assert(blk->bs->blk == blk);
|
||||
blk->bs->blk = NULL;
|
||||
bdrv_unref(blk->bs);
|
||||
blk->bs = NULL;
|
||||
}
|
||||
/* Avoid double-remove after blk_hide_on_behalf_of_do_drive_del() */
|
||||
if (blk->name[0]) {
|
||||
QTAILQ_REMOVE(&blk_backends, blk, link);
|
||||
}
|
||||
g_free(blk->name);
|
||||
drive_info_del(blk->legacy_dinfo);
|
||||
g_free(blk);
|
||||
}
|
||||
|
||||
static void drive_info_del(DriveInfo *dinfo)
|
||||
{
|
||||
if (!dinfo) {
|
||||
return;
|
||||
}
|
||||
qemu_opts_del(dinfo->opts);
|
||||
g_free(dinfo->serial);
|
||||
g_free(dinfo);
|
||||
}
|
||||
|
||||
/*
|
||||
* Increment @blk's reference count.
|
||||
* @blk must not be null.
|
||||
*/
|
||||
void blk_ref(BlockBackend *blk)
|
||||
{
|
||||
blk->refcnt++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decrement @blk's reference count.
|
||||
* If this drops it to zero, destroy @blk.
|
||||
* For convenience, do nothing if @blk is null.
|
||||
*/
|
||||
void blk_unref(BlockBackend *blk)
|
||||
{
|
||||
if (blk) {
|
||||
assert(blk->refcnt > 0);
|
||||
if (!--blk->refcnt) {
|
||||
blk_delete(blk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the BlockBackend after @blk.
|
||||
* If @blk is null, return the first one.
|
||||
* Else, return @blk's next sibling, which may be null.
|
||||
*
|
||||
* To iterate over all BlockBackends, do
|
||||
* for (blk = blk_next(NULL); blk; blk = blk_next(blk)) {
|
||||
* ...
|
||||
* }
|
||||
*/
|
||||
BlockBackend *blk_next(BlockBackend *blk)
|
||||
{
|
||||
return blk ? QTAILQ_NEXT(blk, link) : QTAILQ_FIRST(&blk_backends);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return @blk's name, a non-null string.
|
||||
* Wart: the name is empty iff @blk has been hidden with
|
||||
* blk_hide_on_behalf_of_do_drive_del().
|
||||
*/
|
||||
const char *blk_name(BlockBackend *blk)
|
||||
{
|
||||
return blk->name;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the BlockBackend with name @name if it exists, else null.
|
||||
* @name must not be null.
|
||||
*/
|
||||
BlockBackend *blk_by_name(const char *name)
|
||||
{
|
||||
BlockBackend *blk;
|
||||
|
||||
assert(name);
|
||||
QTAILQ_FOREACH(blk, &blk_backends, link) {
|
||||
if (!strcmp(name, blk->name)) {
|
||||
return blk;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the BlockDriverState attached to @blk if any, else null.
|
||||
*/
|
||||
BlockDriverState *blk_bs(BlockBackend *blk)
|
||||
{
|
||||
return blk->bs;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return @blk's DriveInfo if any, else null.
|
||||
*/
|
||||
DriveInfo *blk_legacy_dinfo(BlockBackend *blk)
|
||||
{
|
||||
return blk->legacy_dinfo;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set @blk's DriveInfo to @dinfo, and return it.
|
||||
* @blk must not have a DriveInfo set already.
|
||||
* No other BlockBackend may have the same DriveInfo set.
|
||||
*/
|
||||
DriveInfo *blk_set_legacy_dinfo(BlockBackend *blk, DriveInfo *dinfo)
|
||||
{
|
||||
assert(!blk->legacy_dinfo);
|
||||
return blk->legacy_dinfo = dinfo;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the BlockBackend with DriveInfo @dinfo.
|
||||
* It must exist.
|
||||
*/
|
||||
BlockBackend *blk_by_legacy_dinfo(DriveInfo *dinfo)
|
||||
{
|
||||
BlockBackend *blk;
|
||||
|
||||
QTAILQ_FOREACH(blk, &blk_backends, link) {
|
||||
if (blk->legacy_dinfo == dinfo) {
|
||||
return blk;
|
||||
}
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
||||
/*
|
||||
* Hide @blk.
|
||||
* @blk must not have been hidden already.
|
||||
* Make attached BlockDriverState, if any, anonymous.
|
||||
* Once hidden, @blk is invisible to all functions that don't receive
|
||||
* it as argument. For example, blk_by_name() won't return it.
|
||||
* Strictly for use by do_drive_del().
|
||||
* TODO get rid of it!
|
||||
*/
|
||||
void blk_hide_on_behalf_of_do_drive_del(BlockBackend *blk)
|
||||
{
|
||||
QTAILQ_REMOVE(&blk_backends, blk, link);
|
||||
blk->name[0] = 0;
|
||||
if (blk->bs) {
|
||||
bdrv_make_anon(blk->bs);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Attach device model @dev to @blk.
|
||||
* Return 0 on success, -EBUSY when a device model is attached already.
|
||||
*/
|
||||
int blk_attach_dev(BlockBackend *blk, void *dev)
|
||||
/* TODO change to DeviceState *dev when all users are qdevified */
|
||||
{
|
||||
if (blk->dev) {
|
||||
return -EBUSY;
|
||||
}
|
||||
blk_ref(blk);
|
||||
blk->dev = dev;
|
||||
bdrv_iostatus_reset(blk->bs);
|
||||
|
||||
/* We're expecting I/O from the device so bump up coroutine pool size */
|
||||
qemu_coroutine_adjust_pool_size(COROUTINE_POOL_RESERVATION);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Attach device model @dev to @blk.
|
||||
* @blk must not have a device model attached already.
|
||||
* TODO qdevified devices don't use this, remove when devices are qdevified
|
||||
*/
|
||||
void blk_attach_dev_nofail(BlockBackend *blk, void *dev)
|
||||
{
|
||||
if (blk_attach_dev(blk, dev) < 0) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Detach device model @dev from @blk.
|
||||
* @dev must be currently attached to @blk.
|
||||
*/
|
||||
void blk_detach_dev(BlockBackend *blk, void *dev)
|
||||
/* TODO change to DeviceState *dev when all users are qdevified */
|
||||
{
|
||||
assert(blk->dev == dev);
|
||||
blk->dev = NULL;
|
||||
blk->dev_ops = NULL;
|
||||
blk->dev_opaque = NULL;
|
||||
bdrv_set_guest_block_size(blk->bs, 512);
|
||||
qemu_coroutine_adjust_pool_size(-COROUTINE_POOL_RESERVATION);
|
||||
blk_unref(blk);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the device model attached to @blk if any, else null.
|
||||
*/
|
||||
void *blk_get_attached_dev(BlockBackend *blk)
|
||||
/* TODO change to return DeviceState * when all users are qdevified */
|
||||
{
|
||||
return blk->dev;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set @blk's device model callbacks to @ops.
|
||||
* @opaque is the opaque argument to pass to the callbacks.
|
||||
* This is for use by device models.
|
||||
*/
|
||||
void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops,
|
||||
void *opaque)
|
||||
{
|
||||
blk->dev_ops = ops;
|
||||
blk->dev_opaque = opaque;
|
||||
}
|
||||
|
||||
/*
|
||||
* Notify @blk's attached device model of media change.
|
||||
* If @load is true, notify of media load.
|
||||
* Else, notify of media eject.
|
||||
* Also send DEVICE_TRAY_MOVED events as appropriate.
|
||||
*/
|
||||
void blk_dev_change_media_cb(BlockBackend *blk, bool load)
|
||||
{
|
||||
if (blk->dev_ops && blk->dev_ops->change_media_cb) {
|
||||
bool tray_was_closed = !blk_dev_is_tray_open(blk);
|
||||
|
||||
blk->dev_ops->change_media_cb(blk->dev_opaque, load);
|
||||
if (tray_was_closed) {
|
||||
/* tray open */
|
||||
qapi_event_send_device_tray_moved(blk_name(blk),
|
||||
true, &error_abort);
|
||||
}
|
||||
if (load) {
|
||||
/* tray close */
|
||||
qapi_event_send_device_tray_moved(blk_name(blk),
|
||||
false, &error_abort);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Does @blk's attached device model have removable media?
|
||||
* %true if no device model is attached.
|
||||
*/
|
||||
bool blk_dev_has_removable_media(BlockBackend *blk)
|
||||
{
|
||||
return !blk->dev || (blk->dev_ops && blk->dev_ops->change_media_cb);
|
||||
}
|
||||
|
||||
/*
|
||||
* Notify @blk's attached device model of a media eject request.
|
||||
* If @force is true, the medium is about to be yanked out forcefully.
|
||||
*/
|
||||
void blk_dev_eject_request(BlockBackend *blk, bool force)
|
||||
{
|
||||
if (blk->dev_ops && blk->dev_ops->eject_request_cb) {
|
||||
blk->dev_ops->eject_request_cb(blk->dev_opaque, force);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Does @blk's attached device model have a tray, and is it open?
|
||||
*/
|
||||
bool blk_dev_is_tray_open(BlockBackend *blk)
|
||||
{
|
||||
if (blk->dev_ops && blk->dev_ops->is_tray_open) {
|
||||
return blk->dev_ops->is_tray_open(blk->dev_opaque);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Does @blk's attached device model have the medium locked?
|
||||
* %false if the device model has no such lock.
|
||||
*/
|
||||
bool blk_dev_is_medium_locked(BlockBackend *blk)
|
||||
{
|
||||
if (blk->dev_ops && blk->dev_ops->is_medium_locked) {
|
||||
return blk->dev_ops->is_medium_locked(blk->dev_opaque);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Notify @blk's attached device model of a backend size change.
|
||||
*/
|
||||
void blk_dev_resize_cb(BlockBackend *blk)
|
||||
{
|
||||
if (blk->dev_ops && blk->dev_ops->resize_cb) {
|
||||
blk->dev_ops->resize_cb(blk->dev_opaque);
|
||||
}
|
||||
}
|
||||
|
||||
void blk_iostatus_enable(BlockBackend *blk)
|
||||
{
|
||||
bdrv_iostatus_enable(blk->bs);
|
||||
}
|
||||
|
||||
int blk_read(BlockBackend *blk, int64_t sector_num, uint8_t *buf,
|
||||
int nb_sectors)
|
||||
{
|
||||
return bdrv_read(blk->bs, sector_num, buf, nb_sectors);
|
||||
}
|
||||
|
||||
int blk_read_unthrottled(BlockBackend *blk, int64_t sector_num, uint8_t *buf,
|
||||
int nb_sectors)
|
||||
{
|
||||
return bdrv_read_unthrottled(blk->bs, sector_num, buf, nb_sectors);
|
||||
}
|
||||
|
||||
int blk_write(BlockBackend *blk, int64_t sector_num, const uint8_t *buf,
|
||||
int nb_sectors)
|
||||
{
|
||||
return bdrv_write(blk->bs, sector_num, buf, nb_sectors);
|
||||
}
|
||||
|
||||
BlockAIOCB *blk_aio_write_zeroes(BlockBackend *blk, int64_t sector_num,
|
||||
int nb_sectors, BdrvRequestFlags flags,
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
return bdrv_aio_write_zeroes(blk->bs, sector_num, nb_sectors, flags,
|
||||
cb, opaque);
|
||||
}
|
||||
|
||||
int blk_pread(BlockBackend *blk, int64_t offset, void *buf, int count)
|
||||
{
|
||||
return bdrv_pread(blk->bs, offset, buf, count);
|
||||
}
|
||||
|
||||
int blk_pwrite(BlockBackend *blk, int64_t offset, const void *buf, int count)
|
||||
{
|
||||
return bdrv_pwrite(blk->bs, offset, buf, count);
|
||||
}
|
||||
|
||||
int64_t blk_getlength(BlockBackend *blk)
|
||||
{
|
||||
return bdrv_getlength(blk->bs);
|
||||
}
|
||||
|
||||
void blk_get_geometry(BlockBackend *blk, uint64_t *nb_sectors_ptr)
|
||||
{
|
||||
bdrv_get_geometry(blk->bs, nb_sectors_ptr);
|
||||
}
|
||||
|
||||
BlockAIOCB *blk_aio_readv(BlockBackend *blk, int64_t sector_num,
|
||||
QEMUIOVector *iov, int nb_sectors,
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
return bdrv_aio_readv(blk->bs, sector_num, iov, nb_sectors, cb, opaque);
|
||||
}
|
||||
|
||||
BlockAIOCB *blk_aio_writev(BlockBackend *blk, int64_t sector_num,
|
||||
QEMUIOVector *iov, int nb_sectors,
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
return bdrv_aio_writev(blk->bs, sector_num, iov, nb_sectors, cb, opaque);
|
||||
}
|
||||
|
||||
BlockAIOCB *blk_aio_flush(BlockBackend *blk,
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
return bdrv_aio_flush(blk->bs, cb, opaque);
|
||||
}
|
||||
|
||||
BlockAIOCB *blk_aio_discard(BlockBackend *blk,
|
||||
int64_t sector_num, int nb_sectors,
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
return bdrv_aio_discard(blk->bs, sector_num, nb_sectors, cb, opaque);
|
||||
}
|
||||
|
||||
void blk_aio_cancel(BlockAIOCB *acb)
|
||||
{
|
||||
bdrv_aio_cancel(acb);
|
||||
}
|
||||
|
||||
void blk_aio_cancel_async(BlockAIOCB *acb)
|
||||
{
|
||||
bdrv_aio_cancel_async(acb);
|
||||
}
|
||||
|
||||
int blk_aio_multiwrite(BlockBackend *blk, BlockRequest *reqs, int num_reqs)
|
||||
{
|
||||
return bdrv_aio_multiwrite(blk->bs, reqs, num_reqs);
|
||||
}
|
||||
|
||||
int blk_ioctl(BlockBackend *blk, unsigned long int req, void *buf)
|
||||
{
|
||||
return bdrv_ioctl(blk->bs, req, buf);
|
||||
}
|
||||
|
||||
BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned long int req, void *buf,
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
return bdrv_aio_ioctl(blk->bs, req, buf, cb, opaque);
|
||||
}
|
||||
|
||||
int blk_flush(BlockBackend *blk)
|
||||
{
|
||||
return bdrv_flush(blk->bs);
|
||||
}
|
||||
|
||||
int blk_flush_all(void)
|
||||
{
|
||||
return bdrv_flush_all();
|
||||
}
|
||||
|
||||
void blk_drain_all(void)
|
||||
{
|
||||
bdrv_drain_all();
|
||||
}
|
||||
|
||||
BlockdevOnError blk_get_on_error(BlockBackend *blk, bool is_read)
|
||||
{
|
||||
return bdrv_get_on_error(blk->bs, is_read);
|
||||
}
|
||||
|
||||
BlockErrorAction blk_get_error_action(BlockBackend *blk, bool is_read,
|
||||
int error)
|
||||
{
|
||||
return bdrv_get_error_action(blk->bs, is_read, error);
|
||||
}
|
||||
|
||||
void blk_error_action(BlockBackend *blk, BlockErrorAction action,
|
||||
bool is_read, int error)
|
||||
{
|
||||
bdrv_error_action(blk->bs, action, is_read, error);
|
||||
}
|
||||
|
||||
int blk_is_read_only(BlockBackend *blk)
|
||||
{
|
||||
return bdrv_is_read_only(blk->bs);
|
||||
}
|
||||
|
||||
int blk_is_sg(BlockBackend *blk)
|
||||
{
|
||||
return bdrv_is_sg(blk->bs);
|
||||
}
|
||||
|
||||
int blk_enable_write_cache(BlockBackend *blk)
|
||||
{
|
||||
return bdrv_enable_write_cache(blk->bs);
|
||||
}
|
||||
|
||||
void blk_set_enable_write_cache(BlockBackend *blk, bool wce)
|
||||
{
|
||||
bdrv_set_enable_write_cache(blk->bs, wce);
|
||||
}
|
||||
|
||||
int blk_is_inserted(BlockBackend *blk)
|
||||
{
|
||||
return bdrv_is_inserted(blk->bs);
|
||||
}
|
||||
|
||||
void blk_lock_medium(BlockBackend *blk, bool locked)
|
||||
{
|
||||
bdrv_lock_medium(blk->bs, locked);
|
||||
}
|
||||
|
||||
void blk_eject(BlockBackend *blk, bool eject_flag)
|
||||
{
|
||||
bdrv_eject(blk->bs, eject_flag);
|
||||
}
|
||||
|
||||
int blk_get_flags(BlockBackend *blk)
|
||||
{
|
||||
return bdrv_get_flags(blk->bs);
|
||||
}
|
||||
|
||||
void blk_set_guest_block_size(BlockBackend *blk, int align)
|
||||
{
|
||||
bdrv_set_guest_block_size(blk->bs, align);
|
||||
}
|
||||
|
||||
void *blk_blockalign(BlockBackend *blk, size_t size)
|
||||
{
|
||||
return qemu_blockalign(blk ? blk->bs : NULL, size);
|
||||
}
|
||||
|
||||
bool blk_op_is_blocked(BlockBackend *blk, BlockOpType op, Error **errp)
|
||||
{
|
||||
return bdrv_op_is_blocked(blk->bs, op, errp);
|
||||
}
|
||||
|
||||
void blk_op_unblock(BlockBackend *blk, BlockOpType op, Error *reason)
|
||||
{
|
||||
bdrv_op_unblock(blk->bs, op, reason);
|
||||
}
|
||||
|
||||
void blk_op_block_all(BlockBackend *blk, Error *reason)
|
||||
{
|
||||
bdrv_op_block_all(blk->bs, reason);
|
||||
}
|
||||
|
||||
void blk_op_unblock_all(BlockBackend *blk, Error *reason)
|
||||
{
|
||||
bdrv_op_unblock_all(blk->bs, reason);
|
||||
}
|
||||
|
||||
AioContext *blk_get_aio_context(BlockBackend *blk)
|
||||
{
|
||||
return bdrv_get_aio_context(blk->bs);
|
||||
}
|
||||
|
||||
void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
|
||||
{
|
||||
bdrv_set_aio_context(blk->bs, new_context);
|
||||
}
|
||||
|
||||
void blk_io_plug(BlockBackend *blk)
|
||||
{
|
||||
bdrv_io_plug(blk->bs);
|
||||
}
|
||||
|
||||
void blk_io_unplug(BlockBackend *blk)
|
||||
{
|
||||
bdrv_io_unplug(blk->bs);
|
||||
}
|
||||
|
||||
BlockAcctStats *blk_get_stats(BlockBackend *blk)
|
||||
{
|
||||
return bdrv_get_stats(blk->bs);
|
||||
}
|
||||
|
||||
void *blk_aio_get(const AIOCBInfo *aiocb_info, BlockBackend *blk,
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
return qemu_aio_get(aiocb_info, blk_bs(blk), cb, opaque);
|
||||
}
|
||||
@@ -182,7 +182,7 @@ static const BlockJobDriver commit_job_driver = {
|
||||
|
||||
void commit_start(BlockDriverState *bs, BlockDriverState *base,
|
||||
BlockDriverState *top, int64_t speed,
|
||||
BlockdevOnError on_error, BlockDriverCompletionFunc *cb,
|
||||
BlockdevOnError on_error, BlockCompletionFunc *cb,
|
||||
void *opaque, const char *backing_file_str, Error **errp)
|
||||
{
|
||||
CommitBlockJob *s;
|
||||
|
||||
@@ -78,7 +78,7 @@ static CURLMcode __curl_multi_socket_action(CURLM *multi_handle,
|
||||
struct BDRVCURLState;
|
||||
|
||||
typedef struct CURLAIOCB {
|
||||
BlockDriverAIOCB common;
|
||||
BlockAIOCB common;
|
||||
QEMUBH *bh;
|
||||
QEMUIOVector *qiov;
|
||||
|
||||
@@ -680,9 +680,9 @@ static void curl_readv_bh_cb(void *p)
|
||||
curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running);
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs,
|
||||
static BlockAIOCB *curl_aio_readv(BlockDriverState *bs,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
CURLAIOCB *acb;
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ typedef struct IscsiTask {
|
||||
} IscsiTask;
|
||||
|
||||
typedef struct IscsiAIOCB {
|
||||
BlockDriverAIOCB common;
|
||||
BlockAIOCB common;
|
||||
QEMUIOVector *qiov;
|
||||
QEMUBH *bh;
|
||||
IscsiLun *iscsilun;
|
||||
@@ -227,7 +227,7 @@ iscsi_abort_task_cb(struct iscsi_context *iscsi, int status, void *command_data,
|
||||
}
|
||||
|
||||
static void
|
||||
iscsi_aio_cancel(BlockDriverAIOCB *blockacb)
|
||||
iscsi_aio_cancel(BlockAIOCB *blockacb)
|
||||
{
|
||||
IscsiAIOCB *acb = (IscsiAIOCB *)blockacb;
|
||||
IscsiLun *iscsilun = acb->iscsilun;
|
||||
@@ -663,9 +663,9 @@ iscsi_aio_ioctl_cb(struct iscsi_context *iscsi, int status,
|
||||
iscsi_schedule_bh(acb);
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *iscsi_aio_ioctl(BlockDriverState *bs,
|
||||
static BlockAIOCB *iscsi_aio_ioctl(BlockDriverState *bs,
|
||||
unsigned long int req, void *buf,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
IscsiLun *iscsilun = bs->opaque;
|
||||
struct iscsi_context *iscsi = iscsilun->iscsi;
|
||||
@@ -1519,7 +1519,7 @@ static int iscsi_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
IscsiLun *iscsilun = NULL;
|
||||
QDict *bs_options;
|
||||
|
||||
bs = bdrv_new("", &error_abort);
|
||||
bs = bdrv_new();
|
||||
|
||||
/* Read out options */
|
||||
total_size = DIV_ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#define MAX_QUEUED_IO 128
|
||||
|
||||
struct qemu_laiocb {
|
||||
BlockDriverAIOCB common;
|
||||
BlockAIOCB common;
|
||||
struct qemu_laio_state *ctx;
|
||||
struct iocb iocb;
|
||||
ssize_t ret;
|
||||
@@ -146,7 +146,7 @@ static void qemu_laio_completion_cb(EventNotifier *e)
|
||||
}
|
||||
}
|
||||
|
||||
static void laio_cancel(BlockDriverAIOCB *blockacb)
|
||||
static void laio_cancel(BlockAIOCB *blockacb)
|
||||
{
|
||||
struct qemu_laiocb *laiocb = (struct qemu_laiocb *)blockacb;
|
||||
struct io_event event;
|
||||
@@ -243,9 +243,9 @@ int laio_io_unplug(BlockDriverState *bs, void *aio_ctx, bool unplug)
|
||||
return ret;
|
||||
}
|
||||
|
||||
BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
|
||||
BlockAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque, int type)
|
||||
BlockCompletionFunc *cb, void *opaque, int type)
|
||||
{
|
||||
struct qemu_laio_state *s = aio_ctx;
|
||||
struct qemu_laiocb *laiocb;
|
||||
|
||||
@@ -567,7 +567,8 @@ static void mirror_complete(BlockJob *job, Error **errp)
|
||||
return;
|
||||
}
|
||||
if (!s->synced) {
|
||||
error_set(errp, QERR_BLOCK_JOB_NOT_READY, job->bs->device_name);
|
||||
error_set(errp, QERR_BLOCK_JOB_NOT_READY,
|
||||
bdrv_get_device_name(job->bs));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -612,7 +613,7 @@ static void mirror_start_job(BlockDriverState *bs, BlockDriverState *target,
|
||||
int64_t buf_size,
|
||||
BlockdevOnError on_source_error,
|
||||
BlockdevOnError on_target_error,
|
||||
BlockDriverCompletionFunc *cb,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque, Error **errp,
|
||||
const BlockJobDriver *driver,
|
||||
bool is_none_mode, BlockDriverState *base)
|
||||
@@ -672,7 +673,7 @@ void mirror_start(BlockDriverState *bs, BlockDriverState *target,
|
||||
int64_t speed, int64_t granularity, int64_t buf_size,
|
||||
MirrorSyncMode mode, BlockdevOnError on_source_error,
|
||||
BlockdevOnError on_target_error,
|
||||
BlockDriverCompletionFunc *cb,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
bool is_none_mode;
|
||||
@@ -689,7 +690,7 @@ void mirror_start(BlockDriverState *bs, BlockDriverState *target,
|
||||
void commit_active_start(BlockDriverState *bs, BlockDriverState *base,
|
||||
int64_t speed,
|
||||
BlockdevOnError on_error,
|
||||
BlockDriverCompletionFunc *cb,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
int64_t length, base_length;
|
||||
|
||||
46
block/nbd.c
46
block/nbd.c
@@ -342,30 +342,44 @@ static void nbd_attach_aio_context(BlockDriverState *bs,
|
||||
|
||||
static void nbd_refresh_filename(BlockDriverState *bs)
|
||||
{
|
||||
BDRVNBDState *s = bs->opaque;
|
||||
QDict *opts = qdict_new();
|
||||
const char *path = qemu_opt_get(s->socket_opts, "path");
|
||||
const char *host = qemu_opt_get(s->socket_opts, "host");
|
||||
const char *port = qemu_opt_get(s->socket_opts, "port");
|
||||
const char *export = qemu_opt_get(s->socket_opts, "export");
|
||||
const char *path = qdict_get_try_str(bs->options, "path");
|
||||
const char *host = qdict_get_try_str(bs->options, "host");
|
||||
const char *port = qdict_get_try_str(bs->options, "port");
|
||||
const char *export = qdict_get_try_str(bs->options, "export");
|
||||
|
||||
qdict_put_obj(opts, "driver", QOBJECT(qstring_from_str("nbd")));
|
||||
|
||||
if (path && export) {
|
||||
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
|
||||
"nbd+unix:///%s?socket=%s", export, path);
|
||||
} else if (path && !export) {
|
||||
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
|
||||
"nbd+unix://?socket=%s", path);
|
||||
} else if (!path && export && port) {
|
||||
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
|
||||
"nbd://%s:%s/%s", host, port, export);
|
||||
} else if (!path && export && !port) {
|
||||
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
|
||||
"nbd://%s/%s", host, export);
|
||||
} else if (!path && !export && port) {
|
||||
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
|
||||
"nbd://%s:%s", host, port);
|
||||
} else if (!path && !export && !port) {
|
||||
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
|
||||
"nbd://%s", host);
|
||||
}
|
||||
|
||||
if (path) {
|
||||
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
|
||||
"nbd+unix:%s", path);
|
||||
qdict_put_obj(opts, "path", QOBJECT(qstring_from_str(path)));
|
||||
} else if (export) {
|
||||
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
|
||||
"nbd:%s:%s/%s", host, port, export);
|
||||
qdict_put_obj(opts, "host", QOBJECT(qstring_from_str(host)));
|
||||
qdict_put_obj(opts, "port", QOBJECT(qstring_from_str(port)));
|
||||
qdict_put_obj(opts, "export", QOBJECT(qstring_from_str(export)));
|
||||
} else {
|
||||
snprintf(bs->exact_filename, sizeof(bs->exact_filename),
|
||||
"nbd:%s:%s", host, port);
|
||||
} else if (port) {
|
||||
qdict_put_obj(opts, "host", QOBJECT(qstring_from_str(host)));
|
||||
qdict_put_obj(opts, "port", QOBJECT(qstring_from_str(port)));
|
||||
} else {
|
||||
qdict_put_obj(opts, "host", QOBJECT(qstring_from_str(host)));
|
||||
}
|
||||
if (export) {
|
||||
qdict_put_obj(opts, "export", QOBJECT(qstring_from_str(export)));
|
||||
}
|
||||
|
||||
bs->full_open_options = opts;
|
||||
|
||||
34
block/null.c
34
block/null.c
@@ -78,7 +78,7 @@ static coroutine_fn int null_co_flush(BlockDriverState *bs)
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
BlockDriverAIOCB common;
|
||||
BlockAIOCB common;
|
||||
QEMUBH *bh;
|
||||
} NullAIOCB;
|
||||
|
||||
@@ -94,9 +94,9 @@ static void null_bh_cb(void *opaque)
|
||||
qemu_aio_unref(acb);
|
||||
}
|
||||
|
||||
static inline BlockDriverAIOCB *null_aio_common(BlockDriverState *bs,
|
||||
BlockDriverCompletionFunc *cb,
|
||||
void *opaque)
|
||||
static inline BlockAIOCB *null_aio_common(BlockDriverState *bs,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque)
|
||||
{
|
||||
NullAIOCB *acb;
|
||||
|
||||
@@ -106,27 +106,27 @@ static inline BlockDriverAIOCB *null_aio_common(BlockDriverState *bs,
|
||||
return &acb->common;
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *null_aio_readv(BlockDriverState *bs,
|
||||
int64_t sector_num, QEMUIOVector *qiov,
|
||||
int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb,
|
||||
void *opaque)
|
||||
static BlockAIOCB *null_aio_readv(BlockDriverState *bs,
|
||||
int64_t sector_num, QEMUIOVector *qiov,
|
||||
int nb_sectors,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque)
|
||||
{
|
||||
return null_aio_common(bs, cb, opaque);
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *null_aio_writev(BlockDriverState *bs,
|
||||
int64_t sector_num, QEMUIOVector *qiov,
|
||||
int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb,
|
||||
void *opaque)
|
||||
static BlockAIOCB *null_aio_writev(BlockDriverState *bs,
|
||||
int64_t sector_num, QEMUIOVector *qiov,
|
||||
int nb_sectors,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque)
|
||||
{
|
||||
return null_aio_common(bs, cb, opaque);
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *null_aio_flush(BlockDriverState *bs,
|
||||
BlockDriverCompletionFunc *cb,
|
||||
void *opaque)
|
||||
static BlockAIOCB *null_aio_flush(BlockDriverState *bs,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque)
|
||||
{
|
||||
return null_aio_common(bs, cb, opaque);
|
||||
}
|
||||
|
||||
27
block/qapi.c
27
block/qapi.c
@@ -28,6 +28,7 @@
|
||||
#include "qapi-visit.h"
|
||||
#include "qapi/qmp-output-visitor.h"
|
||||
#include "qapi/qmp/types.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#ifdef __linux__
|
||||
#include <linux/fs.h>
|
||||
#include <sys/ioctl.h>
|
||||
@@ -264,22 +265,22 @@ void bdrv_query_image_info(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
/* @p_info will be set only on success. */
|
||||
void bdrv_query_info(BlockDriverState *bs,
|
||||
BlockInfo **p_info,
|
||||
Error **errp)
|
||||
static void bdrv_query_info(BlockBackend *blk, BlockInfo **p_info,
|
||||
Error **errp)
|
||||
{
|
||||
BlockInfo *info = g_malloc0(sizeof(*info));
|
||||
BlockDriverState *bs = blk_bs(blk);
|
||||
BlockDriverState *bs0;
|
||||
ImageInfo **p_image_info;
|
||||
Error *local_err = NULL;
|
||||
info->device = g_strdup(bs->device_name);
|
||||
info->device = g_strdup(blk_name(blk));
|
||||
info->type = g_strdup("unknown");
|
||||
info->locked = bdrv_dev_is_medium_locked(bs);
|
||||
info->removable = bdrv_dev_has_removable_media(bs);
|
||||
info->locked = blk_dev_is_medium_locked(blk);
|
||||
info->removable = blk_dev_has_removable_media(blk);
|
||||
|
||||
if (bdrv_dev_has_removable_media(bs)) {
|
||||
if (blk_dev_has_removable_media(blk)) {
|
||||
info->has_tray_open = true;
|
||||
info->tray_open = bdrv_dev_is_tray_open(bs);
|
||||
info->tray_open = blk_dev_is_tray_open(blk);
|
||||
}
|
||||
|
||||
if (bdrv_iostatus_is_enabled(bs)) {
|
||||
@@ -327,9 +328,9 @@ static BlockStats *bdrv_query_stats(const BlockDriverState *bs)
|
||||
|
||||
s = g_malloc0(sizeof(*s));
|
||||
|
||||
if (bs->device_name[0]) {
|
||||
if (bdrv_get_device_name(bs)[0]) {
|
||||
s->has_device = true;
|
||||
s->device = g_strdup(bs->device_name);
|
||||
s->device = g_strdup(bdrv_get_device_name(bs));
|
||||
}
|
||||
|
||||
s->stats = g_malloc0(sizeof(*s->stats));
|
||||
@@ -360,12 +361,12 @@ static BlockStats *bdrv_query_stats(const BlockDriverState *bs)
|
||||
BlockInfoList *qmp_query_block(Error **errp)
|
||||
{
|
||||
BlockInfoList *head = NULL, **p_next = &head;
|
||||
BlockDriverState *bs = NULL;
|
||||
BlockBackend *blk;
|
||||
Error *local_err = NULL;
|
||||
|
||||
while ((bs = bdrv_next(bs))) {
|
||||
for (blk = blk_next(NULL); blk; blk = blk_next(blk)) {
|
||||
BlockInfoList *info = g_malloc0(sizeof(*info));
|
||||
bdrv_query_info(bs, &info->value, &local_err);
|
||||
bdrv_query_info(blk, &info->value, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
goto err;
|
||||
|
||||
@@ -124,7 +124,7 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
snprintf(version, sizeof(version), "QCOW version %" PRIu32,
|
||||
header.version);
|
||||
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
||||
bs->device_name, "qcow", version);
|
||||
bdrv_get_device_name(bs), "qcow", version);
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
}
|
||||
@@ -231,7 +231,7 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
/* Disable migration when qcow images are used */
|
||||
error_set(&s->migration_blocker,
|
||||
QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
|
||||
"qcow", bs->device_name, "live migration");
|
||||
"qcow", bdrv_get_device_name(bs), "live migration");
|
||||
migrate_add_blocker(s->migration_blocker);
|
||||
|
||||
qemu_co_mutex_init(&s->lock);
|
||||
|
||||
@@ -164,12 +164,14 @@ static int l2_load(BlockDriverState *bs, uint64_t l2_offset,
|
||||
int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
uint64_t buf[L1_ENTRIES_PER_SECTOR];
|
||||
uint64_t buf[L1_ENTRIES_PER_SECTOR] = { 0 };
|
||||
int l1_start_index;
|
||||
int i, ret;
|
||||
|
||||
l1_start_index = l1_index & ~(L1_ENTRIES_PER_SECTOR - 1);
|
||||
for (i = 0; i < L1_ENTRIES_PER_SECTOR; i++) {
|
||||
for (i = 0; i < L1_ENTRIES_PER_SECTOR && l1_start_index + i < s->l1_size;
|
||||
i++)
|
||||
{
|
||||
buf[i] = cpu_to_be64(s->l1_table[l1_start_index + i]);
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -206,8 +206,8 @@ static void GCC_FMT_ATTR(3, 4) report_unsupported(BlockDriverState *bs,
|
||||
vsnprintf(msg, sizeof(msg), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE, bs->device_name, "qcow2",
|
||||
msg);
|
||||
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
||||
bdrv_get_device_name(bs), "qcow2", msg);
|
||||
}
|
||||
|
||||
static void report_unsupported_feature(BlockDriverState *bs,
|
||||
@@ -698,6 +698,9 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
|
||||
s->l2_bits = s->cluster_bits - 3; /* L2 is always one cluster */
|
||||
s->l2_size = 1 << s->l2_bits;
|
||||
/* 2^(s->refcount_order - 3) is the refcount width in bytes */
|
||||
s->refcount_block_bits = s->cluster_bits - (s->refcount_order - 3);
|
||||
s->refcount_block_size = 1 << s->refcount_block_bits;
|
||||
bs->total_sectors = header.size / 512;
|
||||
s->csize_shift = (62 - (s->cluster_bits - 8));
|
||||
s->csize_mask = (1 << (s->cluster_bits - 8)) - 1;
|
||||
@@ -907,7 +910,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
(s->incompatible_features & QCOW2_INCOMPAT_DIRTY)) {
|
||||
BdrvCheckResult result = {0};
|
||||
|
||||
ret = qcow2_check(bs, &result, BDRV_FIX_ERRORS);
|
||||
ret = qcow2_check(bs, &result, BDRV_FIX_ERRORS | BDRV_FIX_LEAKS);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "Could not repair dirty image");
|
||||
goto fail;
|
||||
@@ -1871,7 +1874,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
|
||||
.l1_size = cpu_to_be32(0),
|
||||
.refcount_table_offset = cpu_to_be64(cluster_size),
|
||||
.refcount_table_clusters = cpu_to_be32(1),
|
||||
.refcount_order = cpu_to_be32(3 + REFCOUNT_SHIFT),
|
||||
.refcount_order = cpu_to_be32(4),
|
||||
.header_length = cpu_to_be32(sizeof(*header)),
|
||||
};
|
||||
|
||||
|
||||
@@ -59,8 +59,6 @@
|
||||
/* The cluster reads as all zeros */
|
||||
#define QCOW_OFLAG_ZERO (1ULL << 0)
|
||||
|
||||
#define REFCOUNT_SHIFT 1 /* refcount size is 2 bytes */
|
||||
|
||||
#define MIN_CLUSTER_BITS 9
|
||||
#define MAX_CLUSTER_BITS 21
|
||||
|
||||
@@ -223,6 +221,8 @@ typedef struct BDRVQcowState {
|
||||
int l2_size;
|
||||
int l1_size;
|
||||
int l1_vm_state_index;
|
||||
int refcount_block_bits;
|
||||
int refcount_block_size;
|
||||
int csize_shift;
|
||||
int csize_mask;
|
||||
uint64_t cluster_offset_mask;
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
#include "qed.h"
|
||||
|
||||
void *gencb_alloc(size_t len, BlockDriverCompletionFunc *cb, void *opaque)
|
||||
void *gencb_alloc(size_t len, BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
GenericCB *gencb = g_malloc(len);
|
||||
gencb->cb = cb;
|
||||
@@ -24,7 +24,7 @@ void *gencb_alloc(size_t len, BlockDriverCompletionFunc *cb, void *opaque)
|
||||
void gencb_complete(void *opaque, int ret)
|
||||
{
|
||||
GenericCB *gencb = opaque;
|
||||
BlockDriverCompletionFunc *cb = gencb->cb;
|
||||
BlockCompletionFunc *cb = gencb->cb;
|
||||
void *user_opaque = gencb->opaque;
|
||||
|
||||
g_free(gencb);
|
||||
|
||||
@@ -49,7 +49,7 @@ out:
|
||||
}
|
||||
|
||||
static void qed_read_table(BDRVQEDState *s, uint64_t offset, QEDTable *table,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
QEDReadTableCB *read_table_cb = gencb_alloc(sizeof(*read_table_cb),
|
||||
cb, opaque);
|
||||
@@ -119,7 +119,7 @@ out:
|
||||
*/
|
||||
static void qed_write_table(BDRVQEDState *s, uint64_t offset, QEDTable *table,
|
||||
unsigned int index, unsigned int n, bool flush,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
QEDWriteTableCB *write_table_cb;
|
||||
unsigned int sector_mask = BDRV_SECTOR_SIZE / sizeof(uint64_t) - 1;
|
||||
@@ -180,7 +180,7 @@ int qed_read_l1_table_sync(BDRVQEDState *s)
|
||||
}
|
||||
|
||||
void qed_write_l1_table(BDRVQEDState *s, unsigned int index, unsigned int n,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
BLKDBG_EVENT(s->bs->file, BLKDBG_L1_UPDATE);
|
||||
qed_write_table(s, s->header.l1_table_offset,
|
||||
@@ -235,7 +235,7 @@ static void qed_read_l2_table_cb(void *opaque, int ret)
|
||||
}
|
||||
|
||||
void qed_read_l2_table(BDRVQEDState *s, QEDRequest *request, uint64_t offset,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
QEDReadL2TableCB *read_l2_table_cb;
|
||||
|
||||
@@ -275,7 +275,7 @@ int qed_read_l2_table_sync(BDRVQEDState *s, QEDRequest *request, uint64_t offset
|
||||
|
||||
void qed_write_l2_table(BDRVQEDState *s, QEDRequest *request,
|
||||
unsigned int index, unsigned int n, bool flush,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
BLKDBG_EVENT(s->bs->file, BLKDBG_L2_UPDATE);
|
||||
qed_write_table(s, request->l2_table->offset,
|
||||
|
||||
46
block/qed.c
46
block/qed.c
@@ -130,7 +130,7 @@ static void qed_write_header_read_cb(void *opaque, int ret)
|
||||
* This function only updates known header fields in-place and does not affect
|
||||
* extra data after the QED header.
|
||||
*/
|
||||
static void qed_write_header(BDRVQEDState *s, BlockDriverCompletionFunc cb,
|
||||
static void qed_write_header(BDRVQEDState *s, BlockCompletionFunc cb,
|
||||
void *opaque)
|
||||
{
|
||||
/* We must write full sectors for O_DIRECT but cannot necessarily generate
|
||||
@@ -408,7 +408,7 @@ static int bdrv_qed_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
snprintf(buf, sizeof(buf), "%" PRIx64,
|
||||
s->header.features & ~QED_FEATURE_MASK);
|
||||
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
||||
bs->device_name, "QED", buf);
|
||||
bdrv_get_device_name(bs), "QED", buf);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
if (!qed_is_cluster_size_valid(s->header.cluster_size)) {
|
||||
@@ -759,7 +759,7 @@ static BDRVQEDState *acb_to_s(QEDAIOCB *acb)
|
||||
static void qed_read_backing_file(BDRVQEDState *s, uint64_t pos,
|
||||
QEMUIOVector *qiov,
|
||||
QEMUIOVector **backing_qiov,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
uint64_t backing_length = 0;
|
||||
size_t size;
|
||||
@@ -851,7 +851,7 @@ static void qed_copy_from_backing_file_write(void *opaque, int ret)
|
||||
*/
|
||||
static void qed_copy_from_backing_file(BDRVQEDState *s, uint64_t pos,
|
||||
uint64_t len, uint64_t offset,
|
||||
BlockDriverCompletionFunc *cb,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque)
|
||||
{
|
||||
CopyFromBackingFileCB *copy_cb;
|
||||
@@ -902,7 +902,7 @@ static void qed_update_l2_table(BDRVQEDState *s, QEDTable *table, int index,
|
||||
static void qed_aio_complete_bh(void *opaque)
|
||||
{
|
||||
QEDAIOCB *acb = opaque;
|
||||
BlockDriverCompletionFunc *cb = acb->common.cb;
|
||||
BlockCompletionFunc *cb = acb->common.cb;
|
||||
void *user_opaque = acb->common.opaque;
|
||||
int ret = acb->bh_ret;
|
||||
|
||||
@@ -1064,7 +1064,7 @@ static void qed_aio_write_main(void *opaque, int ret)
|
||||
BDRVQEDState *s = acb_to_s(acb);
|
||||
uint64_t offset = acb->cur_cluster +
|
||||
qed_offset_into_cluster(s, acb->cur_pos);
|
||||
BlockDriverCompletionFunc *next_fn;
|
||||
BlockCompletionFunc *next_fn;
|
||||
|
||||
trace_qed_aio_write_main(s, acb, ret, offset, acb->cur_qiov.size);
|
||||
|
||||
@@ -1164,7 +1164,7 @@ static void qed_aio_write_zero_cluster(void *opaque, int ret)
|
||||
static void qed_aio_write_alloc(QEDAIOCB *acb, size_t len)
|
||||
{
|
||||
BDRVQEDState *s = acb_to_s(acb);
|
||||
BlockDriverCompletionFunc *cb;
|
||||
BlockCompletionFunc *cb;
|
||||
|
||||
/* Cancel timer when the first allocating request comes in */
|
||||
if (QSIMPLEQ_EMPTY(&s->allocating_write_reqs)) {
|
||||
@@ -1365,11 +1365,11 @@ static void qed_aio_next_io(void *opaque, int ret)
|
||||
io_fn, acb);
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *qed_aio_setup(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb,
|
||||
void *opaque, int flags)
|
||||
static BlockAIOCB *qed_aio_setup(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque, int flags)
|
||||
{
|
||||
QEDAIOCB *acb = qemu_aio_get(&qed_aiocb_info, bs, cb, opaque);
|
||||
|
||||
@@ -1390,20 +1390,20 @@ static BlockDriverAIOCB *qed_aio_setup(BlockDriverState *bs,
|
||||
return &acb->common;
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *bdrv_qed_aio_readv(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb,
|
||||
void *opaque)
|
||||
static BlockAIOCB *bdrv_qed_aio_readv(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque)
|
||||
{
|
||||
return qed_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *bdrv_qed_aio_writev(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb,
|
||||
void *opaque)
|
||||
static BlockAIOCB *bdrv_qed_aio_writev(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque)
|
||||
{
|
||||
return qed_aio_setup(bs, sector_num, qiov, nb_sectors, cb,
|
||||
opaque, QED_AIOCB_WRITE);
|
||||
@@ -1431,7 +1431,7 @@ static int coroutine_fn bdrv_qed_co_write_zeroes(BlockDriverState *bs,
|
||||
int nb_sectors,
|
||||
BdrvRequestFlags flags)
|
||||
{
|
||||
BlockDriverAIOCB *blockacb;
|
||||
BlockAIOCB *blockacb;
|
||||
BDRVQEDState *s = bs->opaque;
|
||||
QEDWriteZeroesCB cb = { .done = false };
|
||||
QEMUIOVector qiov;
|
||||
|
||||
12
block/qed.h
12
block/qed.h
@@ -128,7 +128,7 @@ enum {
|
||||
};
|
||||
|
||||
typedef struct QEDAIOCB {
|
||||
BlockDriverAIOCB common;
|
||||
BlockAIOCB common;
|
||||
QEMUBH *bh;
|
||||
int bh_ret; /* final return status for completion bh */
|
||||
QSIMPLEQ_ENTRY(QEDAIOCB) next; /* next request */
|
||||
@@ -203,11 +203,11 @@ typedef void QEDFindClusterFunc(void *opaque, int ret, uint64_t offset, size_t l
|
||||
* Generic callback for chaining async callbacks
|
||||
*/
|
||||
typedef struct {
|
||||
BlockDriverCompletionFunc *cb;
|
||||
BlockCompletionFunc *cb;
|
||||
void *opaque;
|
||||
} GenericCB;
|
||||
|
||||
void *gencb_alloc(size_t len, BlockDriverCompletionFunc *cb, void *opaque);
|
||||
void *gencb_alloc(size_t len, BlockCompletionFunc *cb, void *opaque);
|
||||
void gencb_complete(void *opaque, int ret);
|
||||
|
||||
/**
|
||||
@@ -230,16 +230,16 @@ void qed_commit_l2_cache_entry(L2TableCache *l2_cache, CachedL2Table *l2_table);
|
||||
*/
|
||||
int qed_read_l1_table_sync(BDRVQEDState *s);
|
||||
void qed_write_l1_table(BDRVQEDState *s, unsigned int index, unsigned int n,
|
||||
BlockDriverCompletionFunc *cb, void *opaque);
|
||||
BlockCompletionFunc *cb, void *opaque);
|
||||
int qed_write_l1_table_sync(BDRVQEDState *s, unsigned int index,
|
||||
unsigned int n);
|
||||
int qed_read_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
|
||||
uint64_t offset);
|
||||
void qed_read_l2_table(BDRVQEDState *s, QEDRequest *request, uint64_t offset,
|
||||
BlockDriverCompletionFunc *cb, void *opaque);
|
||||
BlockCompletionFunc *cb, void *opaque);
|
||||
void qed_write_l2_table(BDRVQEDState *s, QEDRequest *request,
|
||||
unsigned int index, unsigned int n, bool flush,
|
||||
BlockDriverCompletionFunc *cb, void *opaque);
|
||||
BlockCompletionFunc *cb, void *opaque);
|
||||
int qed_write_l2_table_sync(BDRVQEDState *s, QEDRequest *request,
|
||||
unsigned int index, unsigned int n, bool flush);
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ typedef struct QuorumAIOCB QuorumAIOCB;
|
||||
* $children_count QuorumChildRequest.
|
||||
*/
|
||||
typedef struct QuorumChildRequest {
|
||||
BlockDriverAIOCB *aiocb;
|
||||
BlockAIOCB *aiocb;
|
||||
QEMUIOVector qiov;
|
||||
uint8_t *buf;
|
||||
int ret;
|
||||
@@ -105,7 +105,7 @@ typedef struct QuorumChildRequest {
|
||||
* used to do operations on each children and track overall progress.
|
||||
*/
|
||||
struct QuorumAIOCB {
|
||||
BlockDriverAIOCB common;
|
||||
BlockAIOCB common;
|
||||
|
||||
/* Request metadata */
|
||||
uint64_t sector_num;
|
||||
@@ -130,7 +130,7 @@ struct QuorumAIOCB {
|
||||
|
||||
static bool quorum_vote(QuorumAIOCB *acb);
|
||||
|
||||
static void quorum_aio_cancel(BlockDriverAIOCB *blockacb)
|
||||
static void quorum_aio_cancel(BlockAIOCB *blockacb)
|
||||
{
|
||||
QuorumAIOCB *acb = container_of(blockacb, QuorumAIOCB, common);
|
||||
BDRVQuorumState *s = acb->common.bs->opaque;
|
||||
@@ -186,7 +186,7 @@ static QuorumAIOCB *quorum_aio_get(BDRVQuorumState *s,
|
||||
QEMUIOVector *qiov,
|
||||
uint64_t sector_num,
|
||||
int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque)
|
||||
{
|
||||
QuorumAIOCB *acb = qemu_aio_get(&quorum_aiocb_info, bs, cb, opaque);
|
||||
@@ -226,8 +226,8 @@ static void quorum_report_bad(QuorumAIOCB *acb, char *node_name, int ret)
|
||||
|
||||
static void quorum_report_failure(QuorumAIOCB *acb)
|
||||
{
|
||||
const char *reference = acb->common.bs->device_name[0] ?
|
||||
acb->common.bs->device_name :
|
||||
const char *reference = bdrv_get_device_name(acb->common.bs)[0] ?
|
||||
bdrv_get_device_name(acb->common.bs) :
|
||||
acb->common.bs->node_name;
|
||||
|
||||
qapi_event_send_quorum_failure(reference, acb->sector_num,
|
||||
@@ -264,7 +264,7 @@ static void quorum_rewrite_aio_cb(void *opaque, int ret)
|
||||
quorum_aio_finalize(acb);
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *read_fifo_child(QuorumAIOCB *acb);
|
||||
static BlockAIOCB *read_fifo_child(QuorumAIOCB *acb);
|
||||
|
||||
static void quorum_copy_qiov(QEMUIOVector *dest, QEMUIOVector *source)
|
||||
{
|
||||
@@ -640,7 +640,7 @@ free_exit:
|
||||
return rewrite;
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *read_quorum_children(QuorumAIOCB *acb)
|
||||
static BlockAIOCB *read_quorum_children(QuorumAIOCB *acb)
|
||||
{
|
||||
BDRVQuorumState *s = acb->common.bs->opaque;
|
||||
int i;
|
||||
@@ -659,7 +659,7 @@ static BlockDriverAIOCB *read_quorum_children(QuorumAIOCB *acb)
|
||||
return &acb->common;
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *read_fifo_child(QuorumAIOCB *acb)
|
||||
static BlockAIOCB *read_fifo_child(QuorumAIOCB *acb)
|
||||
{
|
||||
BDRVQuorumState *s = acb->common.bs->opaque;
|
||||
|
||||
@@ -675,12 +675,12 @@ static BlockDriverAIOCB *read_fifo_child(QuorumAIOCB *acb)
|
||||
return &acb->common;
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *quorum_aio_readv(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
QEMUIOVector *qiov,
|
||||
int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb,
|
||||
void *opaque)
|
||||
static BlockAIOCB *quorum_aio_readv(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
QEMUIOVector *qiov,
|
||||
int nb_sectors,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque)
|
||||
{
|
||||
BDRVQuorumState *s = bs->opaque;
|
||||
QuorumAIOCB *acb = quorum_aio_get(s, bs, qiov, sector_num,
|
||||
@@ -696,12 +696,12 @@ static BlockDriverAIOCB *quorum_aio_readv(BlockDriverState *bs,
|
||||
return read_fifo_child(acb);
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *quorum_aio_writev(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
QEMUIOVector *qiov,
|
||||
int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb,
|
||||
void *opaque)
|
||||
static BlockAIOCB *quorum_aio_writev(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
QEMUIOVector *qiov,
|
||||
int nb_sectors,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque)
|
||||
{
|
||||
BDRVQuorumState *s = bs->opaque;
|
||||
QuorumAIOCB *acb = quorum_aio_get(s, bs, qiov, sector_num, nb_sectors,
|
||||
|
||||
@@ -35,9 +35,9 @@
|
||||
#ifdef CONFIG_LINUX_AIO
|
||||
void *laio_init(void);
|
||||
void laio_cleanup(void *s);
|
||||
BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
|
||||
BlockAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque, int type);
|
||||
BlockCompletionFunc *cb, void *opaque, int type);
|
||||
void laio_detach_aio_context(void *s, AioContext *old_context);
|
||||
void laio_attach_aio_context(void *s, AioContext *new_context);
|
||||
void laio_io_plug(BlockDriverState *bs, void *aio_ctx);
|
||||
@@ -49,10 +49,10 @@ typedef struct QEMUWin32AIOState QEMUWin32AIOState;
|
||||
QEMUWin32AIOState *win32_aio_init(void);
|
||||
void win32_aio_cleanup(QEMUWin32AIOState *aio);
|
||||
int win32_aio_attach(QEMUWin32AIOState *aio, HANDLE hfile);
|
||||
BlockDriverAIOCB *win32_aio_submit(BlockDriverState *bs,
|
||||
BlockAIOCB *win32_aio_submit(BlockDriverState *bs,
|
||||
QEMUWin32AIOState *aio, HANDLE hfile,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque, int type);
|
||||
BlockCompletionFunc *cb, void *opaque, int type);
|
||||
void win32_aio_detach_aio_context(QEMUWin32AIOState *aio,
|
||||
AioContext *old_context);
|
||||
void win32_aio_attach_aio_context(QEMUWin32AIOState *aio,
|
||||
|
||||
@@ -150,6 +150,7 @@ typedef struct BDRVRawState {
|
||||
bool has_discard:1;
|
||||
bool has_write_zeroes:1;
|
||||
bool discard_zeroes:1;
|
||||
bool needs_alignment;
|
||||
#ifdef CONFIG_FIEMAP
|
||||
bool skip_fiemap;
|
||||
#endif
|
||||
@@ -230,7 +231,7 @@ static void raw_probe_alignment(BlockDriverState *bs, int fd, Error **errp)
|
||||
|
||||
/* For /dev/sg devices the alignment is not really used.
|
||||
With buffered I/O, we don't have any restrictions. */
|
||||
if (bs->sg || !(s->open_flags & O_DIRECT)) {
|
||||
if (bs->sg || !s->needs_alignment) {
|
||||
bs->request_alignment = 1;
|
||||
s->buf_align = 1;
|
||||
return;
|
||||
@@ -446,6 +447,9 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
||||
|
||||
s->has_discard = true;
|
||||
s->has_write_zeroes = true;
|
||||
if ((bs->open_flags & BDRV_O_NOCACHE) != 0) {
|
||||
s->needs_alignment = true;
|
||||
}
|
||||
|
||||
if (fstat(s->fd, &st) < 0) {
|
||||
error_setg_errno(errp, errno, "Could not stat file");
|
||||
@@ -472,6 +476,17 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef __FreeBSD__
|
||||
if (S_ISCHR(st.st_mode)) {
|
||||
/*
|
||||
* The file is a char device (disk), which on FreeBSD isn't behind
|
||||
* a pager, so force all requests to be aligned. This is needed
|
||||
* so QEMU makes sure all IO operations on the device are aligned
|
||||
* to sector size, or else FreeBSD will reject them with EINVAL.
|
||||
*/
|
||||
s->needs_alignment = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_XFS
|
||||
if (platform_test_xfs_fd(s->fd)) {
|
||||
@@ -1041,9 +1056,9 @@ static int paio_submit_co(BlockDriverState *bs, int fd,
|
||||
return thread_pool_submit_co(pool, aio_worker, acb);
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *paio_submit(BlockDriverState *bs, int fd,
|
||||
static BlockAIOCB *paio_submit(BlockDriverState *bs, int fd,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque, int type)
|
||||
BlockCompletionFunc *cb, void *opaque, int type)
|
||||
{
|
||||
RawPosixAIOData *acb = g_slice_new(RawPosixAIOData);
|
||||
ThreadPool *pool;
|
||||
@@ -1066,9 +1081,9 @@ static BlockDriverAIOCB *paio_submit(BlockDriverState *bs, int fd,
|
||||
return thread_pool_submit_aio(pool, aio_worker, acb, cb, opaque);
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *raw_aio_submit(BlockDriverState *bs,
|
||||
static BlockAIOCB *raw_aio_submit(BlockDriverState *bs,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque, int type)
|
||||
BlockCompletionFunc *cb, void *opaque, int type)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
|
||||
@@ -1076,11 +1091,12 @@ static BlockDriverAIOCB *raw_aio_submit(BlockDriverState *bs,
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* If O_DIRECT is used the buffer needs to be aligned on a sector
|
||||
* boundary. Check if this is the case or tell the low-level
|
||||
* driver that it needs to copy the buffer.
|
||||
* Check if the underlying device requires requests to be aligned,
|
||||
* and if the request we are trying to submit is aligned or not.
|
||||
* If this is the case tell the low-level driver that it needs
|
||||
* to copy the buffer.
|
||||
*/
|
||||
if ((bs->open_flags & BDRV_O_NOCACHE)) {
|
||||
if (s->needs_alignment) {
|
||||
if (!bdrv_qiov_is_aligned(bs, qiov)) {
|
||||
type |= QEMU_AIO_MISALIGNED;
|
||||
#ifdef CONFIG_LINUX_AIO
|
||||
@@ -1125,24 +1141,24 @@ static void raw_aio_flush_io_queue(BlockDriverState *bs)
|
||||
#endif
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *raw_aio_readv(BlockDriverState *bs,
|
||||
static BlockAIOCB *raw_aio_readv(BlockDriverState *bs,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
return raw_aio_submit(bs, sector_num, qiov, nb_sectors,
|
||||
cb, opaque, QEMU_AIO_READ);
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *raw_aio_writev(BlockDriverState *bs,
|
||||
static BlockAIOCB *raw_aio_writev(BlockDriverState *bs,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
return raw_aio_submit(bs, sector_num, qiov, nb_sectors,
|
||||
cb, opaque, QEMU_AIO_WRITE);
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *raw_aio_flush(BlockDriverState *bs,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
static BlockAIOCB *raw_aio_flush(BlockDriverState *bs,
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
|
||||
@@ -1482,7 +1498,7 @@ static int64_t try_fiemap(BlockDriverState *bs, off_t start, off_t *data,
|
||||
|
||||
f.fm.fm_start = start;
|
||||
f.fm.fm_length = (int64_t)nb_sectors * BDRV_SECTOR_SIZE;
|
||||
f.fm.fm_flags = 0;
|
||||
f.fm.fm_flags = FIEMAP_FLAG_SYNC;
|
||||
f.fm.fm_extent_count = 1;
|
||||
f.fm.fm_reserved = 0;
|
||||
if (ioctl(s->fd, FS_IOC_FIEMAP, &f) == -1) {
|
||||
@@ -1571,9 +1587,9 @@ static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs,
|
||||
|
||||
start = sector_num * BDRV_SECTOR_SIZE;
|
||||
|
||||
ret = try_fiemap(bs, start, &data, &hole, nb_sectors, pnum);
|
||||
ret = try_seek_hole(bs, start, &data, &hole, pnum);
|
||||
if (ret < 0) {
|
||||
ret = try_seek_hole(bs, start, &data, &hole, pnum);
|
||||
ret = try_fiemap(bs, start, &data, &hole, nb_sectors, pnum);
|
||||
if (ret < 0) {
|
||||
/* Assume everything is allocated. */
|
||||
data = 0;
|
||||
@@ -1595,9 +1611,9 @@ static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static coroutine_fn BlockDriverAIOCB *raw_aio_discard(BlockDriverState *bs,
|
||||
static coroutine_fn BlockAIOCB *raw_aio_discard(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
|
||||
@@ -1935,9 +1951,9 @@ static int hdev_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
|
||||
return ioctl(s->fd, req, buf);
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *hdev_aio_ioctl(BlockDriverState *bs,
|
||||
static BlockAIOCB *hdev_aio_ioctl(BlockDriverState *bs,
|
||||
unsigned long int req, void *buf,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
RawPosixAIOData *acb;
|
||||
@@ -1976,9 +1992,9 @@ static int fd_open(BlockDriverState *bs)
|
||||
|
||||
#endif /* !linux && !FreeBSD */
|
||||
|
||||
static coroutine_fn BlockDriverAIOCB *hdev_aio_discard(BlockDriverState *bs,
|
||||
static coroutine_fn BlockAIOCB *hdev_aio_discard(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
|
||||
|
||||
@@ -138,9 +138,9 @@ static int aio_worker(void *arg)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *paio_submit(BlockDriverState *bs, HANDLE hfile,
|
||||
static BlockAIOCB *paio_submit(BlockDriverState *bs, HANDLE hfile,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque, int type)
|
||||
BlockCompletionFunc *cb, void *opaque, int type)
|
||||
{
|
||||
RawWin32AIOData *acb = g_slice_new(RawWin32AIOData);
|
||||
ThreadPool *pool;
|
||||
@@ -369,9 +369,9 @@ fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *raw_aio_readv(BlockDriverState *bs,
|
||||
static BlockAIOCB *raw_aio_readv(BlockDriverState *bs,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
if (s->aio) {
|
||||
@@ -383,9 +383,9 @@ static BlockDriverAIOCB *raw_aio_readv(BlockDriverState *bs,
|
||||
}
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *raw_aio_writev(BlockDriverState *bs,
|
||||
static BlockAIOCB *raw_aio_writev(BlockDriverState *bs,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
if (s->aio) {
|
||||
@@ -397,8 +397,8 @@ static BlockDriverAIOCB *raw_aio_writev(BlockDriverState *bs,
|
||||
}
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *raw_aio_flush(BlockDriverState *bs,
|
||||
BlockDriverCompletionFunc *cb, void *opaque)
|
||||
static BlockAIOCB *raw_aio_flush(BlockDriverState *bs,
|
||||
BlockCompletionFunc *cb, void *opaque)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
return paio_submit(bs, s->hfile, 0, NULL, 0, cb, opaque, QEMU_AIO_FLUSH);
|
||||
|
||||
@@ -129,10 +129,10 @@ static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
|
||||
return bdrv_ioctl(bs->file, req, buf);
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *raw_aio_ioctl(BlockDriverState *bs,
|
||||
unsigned long int req, void *buf,
|
||||
BlockDriverCompletionFunc *cb,
|
||||
void *opaque)
|
||||
static BlockAIOCB *raw_aio_ioctl(BlockDriverState *bs,
|
||||
unsigned long int req, void *buf,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque)
|
||||
{
|
||||
return bdrv_aio_ioctl(bs->file, req, buf, cb, opaque);
|
||||
}
|
||||
|
||||
56
block/rbd.c
56
block/rbd.c
@@ -68,7 +68,7 @@ typedef enum {
|
||||
} RBDAIOCmd;
|
||||
|
||||
typedef struct RBDAIOCB {
|
||||
BlockDriverAIOCB common;
|
||||
BlockAIOCB common;
|
||||
QEMUBH *bh;
|
||||
int64_t ret;
|
||||
QEMUIOVector *qiov;
|
||||
@@ -589,13 +589,13 @@ static int rbd_aio_flush_wrapper(rbd_image_t image,
|
||||
#endif
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *rbd_start_aio(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
QEMUIOVector *qiov,
|
||||
int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb,
|
||||
void *opaque,
|
||||
RBDAIOCmd cmd)
|
||||
static BlockAIOCB *rbd_start_aio(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
QEMUIOVector *qiov,
|
||||
int nb_sectors,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque,
|
||||
RBDAIOCmd cmd)
|
||||
{
|
||||
RBDAIOCB *acb;
|
||||
RADOSCB *rcb = NULL;
|
||||
@@ -675,32 +675,32 @@ failed:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *qemu_rbd_aio_readv(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
QEMUIOVector *qiov,
|
||||
int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb,
|
||||
void *opaque)
|
||||
static BlockAIOCB *qemu_rbd_aio_readv(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
QEMUIOVector *qiov,
|
||||
int nb_sectors,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque)
|
||||
{
|
||||
return rbd_start_aio(bs, sector_num, qiov, nb_sectors, cb, opaque,
|
||||
RBD_AIO_READ);
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *qemu_rbd_aio_writev(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
QEMUIOVector *qiov,
|
||||
int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb,
|
||||
void *opaque)
|
||||
static BlockAIOCB *qemu_rbd_aio_writev(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
QEMUIOVector *qiov,
|
||||
int nb_sectors,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque)
|
||||
{
|
||||
return rbd_start_aio(bs, sector_num, qiov, nb_sectors, cb, opaque,
|
||||
RBD_AIO_WRITE);
|
||||
}
|
||||
|
||||
#ifdef LIBRBD_SUPPORTS_AIO_FLUSH
|
||||
static BlockDriverAIOCB *qemu_rbd_aio_flush(BlockDriverState *bs,
|
||||
BlockDriverCompletionFunc *cb,
|
||||
void *opaque)
|
||||
static BlockAIOCB *qemu_rbd_aio_flush(BlockDriverState *bs,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque)
|
||||
{
|
||||
return rbd_start_aio(bs, 0, NULL, 0, cb, opaque, RBD_AIO_FLUSH);
|
||||
}
|
||||
@@ -876,11 +876,11 @@ static int qemu_rbd_snap_list(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
#ifdef LIBRBD_SUPPORTS_DISCARD
|
||||
static BlockDriverAIOCB* qemu_rbd_aio_discard(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb,
|
||||
void *opaque)
|
||||
static BlockAIOCB* qemu_rbd_aio_discard(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
int nb_sectors,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque)
|
||||
{
|
||||
return rbd_start_aio(bs, sector_num, NULL, nb_sectors, cb, opaque,
|
||||
RBD_AIO_DISCARD);
|
||||
|
||||
@@ -301,7 +301,7 @@ enum AIOCBState {
|
||||
};
|
||||
|
||||
struct SheepdogAIOCB {
|
||||
BlockDriverAIOCB common;
|
||||
BlockAIOCB common;
|
||||
|
||||
QEMUIOVector *qiov;
|
||||
|
||||
@@ -473,7 +473,7 @@ static bool sd_acb_cancelable(const SheepdogAIOCB *acb)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void sd_aio_cancel(BlockDriverAIOCB *blockacb)
|
||||
static void sd_aio_cancel(BlockAIOCB *blockacb)
|
||||
{
|
||||
SheepdogAIOCB *acb = (SheepdogAIOCB *)blockacb;
|
||||
BDRVSheepdogState *s = acb->common.bs->opaque;
|
||||
|
||||
@@ -220,7 +220,7 @@ static const BlockJobDriver stream_job_driver = {
|
||||
void stream_start(BlockDriverState *bs, BlockDriverState *base,
|
||||
const char *backing_file_str, int64_t speed,
|
||||
BlockdevOnError on_error,
|
||||
BlockDriverCompletionFunc *cb,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
StreamBlockJob *s;
|
||||
|
||||
11
block/vdi.c
11
block/vdi.c
@@ -407,8 +407,7 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
We accept them but round the disk size to the next multiple of
|
||||
SECTOR_SIZE. */
|
||||
logout("odd disk size %" PRIu64 " B, round up\n", header.disk_size);
|
||||
header.disk_size += SECTOR_SIZE - 1;
|
||||
header.disk_size &= ~(SECTOR_SIZE - 1);
|
||||
header.disk_size = ROUND_UP(header.disk_size, SECTOR_SIZE);
|
||||
}
|
||||
|
||||
if (header.signature != VDI_SIGNATURE) {
|
||||
@@ -475,7 +474,7 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
s->header = header;
|
||||
|
||||
bmap_size = header.blocks_in_image * sizeof(uint32_t);
|
||||
bmap_size = (bmap_size + SECTOR_SIZE - 1) / SECTOR_SIZE;
|
||||
bmap_size = DIV_ROUND_UP(bmap_size, SECTOR_SIZE);
|
||||
s->bmap = qemu_try_blockalign(bs->file, bmap_size * SECTOR_SIZE);
|
||||
if (s->bmap == NULL) {
|
||||
ret = -ENOMEM;
|
||||
@@ -490,7 +489,7 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
/* Disable migration when vdi images are used */
|
||||
error_set(&s->migration_blocker,
|
||||
QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
|
||||
"vdi", bs->device_name, "live migration");
|
||||
"vdi", bdrv_get_device_name(bs), "live migration");
|
||||
migrate_add_blocker(s->migration_blocker);
|
||||
|
||||
return 0;
|
||||
@@ -736,10 +735,10 @@ static int vdi_create(const char *filename, QemuOpts *opts, Error **errp)
|
||||
|
||||
/* We need enough blocks to store the given disk size,
|
||||
so always round up. */
|
||||
blocks = (bytes + block_size - 1) / block_size;
|
||||
blocks = DIV_ROUND_UP(bytes, block_size);
|
||||
|
||||
bmap_size = blocks * sizeof(uint32_t);
|
||||
bmap_size = ((bmap_size + SECTOR_SIZE - 1) & ~(SECTOR_SIZE -1));
|
||||
bmap_size = ROUND_UP(bmap_size, SECTOR_SIZE);
|
||||
|
||||
memset(&header, 0, sizeof(header));
|
||||
pstrcpy(header.text, sizeof(header.text), VDI_TEXT);
|
||||
|
||||
@@ -1004,7 +1004,7 @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
/* Disable migration when VHDX images are used */
|
||||
error_set(&s->migration_blocker,
|
||||
QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
|
||||
"vhdx", bs->device_name, "live migration");
|
||||
"vhdx", bdrv_get_device_name(bs), "live migration");
|
||||
migrate_add_blocker(s->migration_blocker);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -657,7 +657,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
|
||||
snprintf(buf, sizeof(buf), "VMDK version %" PRId32,
|
||||
le32_to_cpu(header.version));
|
||||
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
||||
bs->device_name, "vmdk", buf);
|
||||
bdrv_get_device_name(bs), "vmdk", buf);
|
||||
return -ENOTSUP;
|
||||
} else if (le32_to_cpu(header.version) == 3 && (flags & BDRV_O_RDWR)) {
|
||||
/* VMware KB 2064959 explains that version 3 added support for
|
||||
@@ -939,7 +939,7 @@ static int vmdk_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
/* Disable migration when VMDK images are used */
|
||||
error_set(&s->migration_blocker,
|
||||
QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
|
||||
"vmdk", bs->device_name, "live migration");
|
||||
"vmdk", bdrv_get_device_name(bs), "live migration");
|
||||
migrate_add_blocker(s->migration_blocker);
|
||||
g_free(buf);
|
||||
return 0;
|
||||
|
||||
@@ -320,7 +320,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
/* Disable migration when VHD images are used */
|
||||
error_set(&s->migration_blocker,
|
||||
QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
|
||||
"vpc", bs->device_name, "live migration");
|
||||
"vpc", bdrv_get_device_name(bs), "live migration");
|
||||
migrate_add_blocker(s->migration_blocker);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -1182,7 +1182,7 @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
if (s->qcow) {
|
||||
error_set(&s->migration_blocker,
|
||||
QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
|
||||
"vvfat (rw)", bs->device_name, "live migration");
|
||||
"vvfat (rw)", bdrv_get_device_name(bs), "live migration");
|
||||
migrate_add_blocker(s->migration_blocker);
|
||||
}
|
||||
|
||||
@@ -2939,7 +2939,7 @@ static int enable_write_target(BDRVVVFATState *s, Error **errp)
|
||||
unlink(s->qcow_filename);
|
||||
#endif
|
||||
|
||||
bdrv_set_backing_hd(s->bs, bdrv_new("", &error_abort));
|
||||
bdrv_set_backing_hd(s->bs, bdrv_new());
|
||||
s->bs->backing_hd->drv = &vvfat_write_target;
|
||||
s->bs->backing_hd->opaque = g_new(void *, 1);
|
||||
*(void**)s->bs->backing_hd->opaque = s;
|
||||
|
||||
@@ -44,7 +44,7 @@ struct QEMUWin32AIOState {
|
||||
};
|
||||
|
||||
typedef struct QEMUWin32AIOCB {
|
||||
BlockDriverAIOCB common;
|
||||
BlockAIOCB common;
|
||||
struct QEMUWin32AIOState *ctx;
|
||||
int nbytes;
|
||||
OVERLAPPED ov;
|
||||
@@ -110,10 +110,10 @@ static const AIOCBInfo win32_aiocb_info = {
|
||||
.aiocb_size = sizeof(QEMUWin32AIOCB),
|
||||
};
|
||||
|
||||
BlockDriverAIOCB *win32_aio_submit(BlockDriverState *bs,
|
||||
BlockAIOCB *win32_aio_submit(BlockDriverState *bs,
|
||||
QEMUWin32AIOState *aio, HANDLE hfile,
|
||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||
BlockDriverCompletionFunc *cb, void *opaque, int type)
|
||||
BlockCompletionFunc *cb, void *opaque, int type)
|
||||
{
|
||||
struct QEMUWin32AIOCB *waiocb;
|
||||
uint64_t offset = sector_num * 512;
|
||||
|
||||
201
blockdev.c
201
blockdev.c
@@ -30,6 +30,7 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "hw/block/block.h"
|
||||
#include "block/blockjob.h"
|
||||
@@ -46,8 +47,6 @@
|
||||
#include "trace.h"
|
||||
#include "sysemu/arch_init.h"
|
||||
|
||||
static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives);
|
||||
|
||||
static const char *const if_name[IF_COUNT] = {
|
||||
[IF_NONE] = "none",
|
||||
[IF_IDE] = "ide",
|
||||
@@ -85,13 +84,15 @@ static int if_max_devs[IF_COUNT] = {
|
||||
*/
|
||||
void override_max_devs(BlockInterfaceType type, int max_devs)
|
||||
{
|
||||
BlockBackend *blk;
|
||||
DriveInfo *dinfo;
|
||||
|
||||
if (max_devs <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
QTAILQ_FOREACH(dinfo, &drives, next) {
|
||||
for (blk = blk_next(NULL); blk; blk = blk_next(blk)) {
|
||||
dinfo = blk_legacy_dinfo(blk);
|
||||
if (dinfo->type == type) {
|
||||
fprintf(stderr, "Cannot override units-per-bus property of"
|
||||
" the %s interface, because a drive of that type has"
|
||||
@@ -110,28 +111,27 @@ void override_max_devs(BlockInterfaceType type, int max_devs)
|
||||
* automatic deletion, and generic qdev code calls blockdev_auto_del()
|
||||
* when deletion is actually safe.
|
||||
*/
|
||||
void blockdev_mark_auto_del(BlockDriverState *bs)
|
||||
void blockdev_mark_auto_del(BlockBackend *blk)
|
||||
{
|
||||
DriveInfo *dinfo = drive_get_by_blockdev(bs);
|
||||
DriveInfo *dinfo = blk_legacy_dinfo(blk);
|
||||
BlockDriverState *bs = blk_bs(blk);
|
||||
|
||||
if (dinfo && !dinfo->enable_auto_del) {
|
||||
if (!dinfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (bs->job) {
|
||||
block_job_cancel(bs->job);
|
||||
}
|
||||
if (dinfo) {
|
||||
dinfo->auto_del = 1;
|
||||
}
|
||||
dinfo->auto_del = 1;
|
||||
}
|
||||
|
||||
void blockdev_auto_del(BlockDriverState *bs)
|
||||
void blockdev_auto_del(BlockBackend *blk)
|
||||
{
|
||||
DriveInfo *dinfo = drive_get_by_blockdev(bs);
|
||||
DriveInfo *dinfo = blk_legacy_dinfo(blk);
|
||||
|
||||
if (dinfo && dinfo->auto_del) {
|
||||
drive_del(dinfo);
|
||||
blk_unref(blk);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,15 +193,15 @@ QemuOpts *drive_add(BlockInterfaceType type, int index, const char *file,
|
||||
|
||||
DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit)
|
||||
{
|
||||
BlockBackend *blk;
|
||||
DriveInfo *dinfo;
|
||||
|
||||
/* seek interface, bus and unit */
|
||||
|
||||
QTAILQ_FOREACH(dinfo, &drives, next) {
|
||||
if (dinfo->type == type &&
|
||||
dinfo->bus == bus &&
|
||||
dinfo->unit == unit)
|
||||
for (blk = blk_next(NULL); blk; blk = blk_next(blk)) {
|
||||
dinfo = blk_legacy_dinfo(blk);
|
||||
if (dinfo && dinfo->type == type
|
||||
&& dinfo->bus == bus && dinfo->unit == unit) {
|
||||
return dinfo;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -209,17 +209,19 @@ DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit)
|
||||
|
||||
bool drive_check_orphaned(void)
|
||||
{
|
||||
BlockBackend *blk;
|
||||
DriveInfo *dinfo;
|
||||
bool rs = false;
|
||||
|
||||
QTAILQ_FOREACH(dinfo, &drives, next) {
|
||||
for (blk = blk_next(NULL); blk; blk = blk_next(blk)) {
|
||||
dinfo = blk_legacy_dinfo(blk);
|
||||
/* If dinfo->bdrv->dev is NULL, it has no device attached. */
|
||||
/* Unless this is a default drive, this may be an oversight. */
|
||||
if (!dinfo->bdrv->dev && !dinfo->is_default &&
|
||||
if (!blk_get_attached_dev(blk) && !dinfo->is_default &&
|
||||
dinfo->type != IF_NONE) {
|
||||
fprintf(stderr, "Warning: Orphaned drive without device: "
|
||||
"id=%s,file=%s,if=%s,bus=%d,unit=%d\n",
|
||||
dinfo->id, dinfo->bdrv->filename, if_name[dinfo->type],
|
||||
blk_name(blk), blk_bs(blk)->filename, if_name[dinfo->type],
|
||||
dinfo->bus, dinfo->unit);
|
||||
rs = true;
|
||||
}
|
||||
@@ -238,13 +240,15 @@ DriveInfo *drive_get_by_index(BlockInterfaceType type, int index)
|
||||
int drive_get_max_bus(BlockInterfaceType type)
|
||||
{
|
||||
int max_bus;
|
||||
BlockBackend *blk;
|
||||
DriveInfo *dinfo;
|
||||
|
||||
max_bus = -1;
|
||||
QTAILQ_FOREACH(dinfo, &drives, next) {
|
||||
if(dinfo->type == type &&
|
||||
dinfo->bus > max_bus)
|
||||
for (blk = blk_next(NULL); blk; blk = blk_next(blk)) {
|
||||
dinfo = blk_legacy_dinfo(blk);
|
||||
if (dinfo && dinfo->type == type && dinfo->bus > max_bus) {
|
||||
max_bus = dinfo->bus;
|
||||
}
|
||||
}
|
||||
return max_bus;
|
||||
}
|
||||
@@ -259,40 +263,11 @@ DriveInfo *drive_get_next(BlockInterfaceType type)
|
||||
return drive_get(type, 0, next_block_unit[type]++);
|
||||
}
|
||||
|
||||
DriveInfo *drive_get_by_blockdev(BlockDriverState *bs)
|
||||
{
|
||||
DriveInfo *dinfo;
|
||||
|
||||
QTAILQ_FOREACH(dinfo, &drives, next) {
|
||||
if (dinfo->bdrv == bs) {
|
||||
return dinfo;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void bdrv_format_print(void *opaque, const char *name)
|
||||
{
|
||||
error_printf(" %s", name);
|
||||
}
|
||||
|
||||
void drive_del(DriveInfo *dinfo)
|
||||
{
|
||||
bdrv_unref(dinfo->bdrv);
|
||||
}
|
||||
|
||||
void drive_info_del(DriveInfo *dinfo)
|
||||
{
|
||||
if (!dinfo) {
|
||||
return;
|
||||
}
|
||||
qemu_opts_del(dinfo->opts);
|
||||
g_free(dinfo->id);
|
||||
QTAILQ_REMOVE(&drives, dinfo, next);
|
||||
g_free(dinfo->serial);
|
||||
g_free(dinfo);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
QEMUBH *bh;
|
||||
BlockDriverState *bs;
|
||||
@@ -360,15 +335,15 @@ static bool check_throttle_config(ThrottleConfig *cfg, Error **errp)
|
||||
typedef enum { MEDIA_DISK, MEDIA_CDROM } DriveMediaType;
|
||||
|
||||
/* Takes the ownership of bs_opts */
|
||||
static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
|
||||
Error **errp)
|
||||
static BlockBackend *blockdev_init(const char *file, QDict *bs_opts,
|
||||
Error **errp)
|
||||
{
|
||||
const char *buf;
|
||||
int ro = 0;
|
||||
int bdrv_flags = 0;
|
||||
int on_read_error, on_write_error;
|
||||
BlockBackend *blk;
|
||||
BlockDriverState *bs;
|
||||
DriveInfo *dinfo;
|
||||
ThrottleConfig cfg;
|
||||
int snapshot = 0;
|
||||
bool copy_on_read;
|
||||
@@ -523,10 +498,11 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
|
||||
}
|
||||
|
||||
/* init */
|
||||
bs = bdrv_new(qemu_opts_id(opts), errp);
|
||||
if (!bs) {
|
||||
blk = blk_new_with_bs(qemu_opts_id(opts), errp);
|
||||
if (!blk) {
|
||||
goto early_err;
|
||||
}
|
||||
bs = blk_bs(blk);
|
||||
bs->open_flags = snapshot ? BDRV_O_SNAPSHOT : 0;
|
||||
bs->read_only = ro;
|
||||
bs->detect_zeroes = detect_zeroes;
|
||||
@@ -539,18 +515,13 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
|
||||
bdrv_set_io_limits(bs, &cfg);
|
||||
}
|
||||
|
||||
dinfo = g_malloc0(sizeof(*dinfo));
|
||||
dinfo->id = g_strdup(qemu_opts_id(opts));
|
||||
dinfo->bdrv = bs;
|
||||
QTAILQ_INSERT_TAIL(&drives, dinfo, next);
|
||||
|
||||
if (!file || !*file) {
|
||||
if (has_driver_specific_opts) {
|
||||
file = NULL;
|
||||
} else {
|
||||
QDECREF(bs_opts);
|
||||
qemu_opts_del(opts);
|
||||
return dinfo;
|
||||
return blk;
|
||||
}
|
||||
}
|
||||
if (snapshot) {
|
||||
@@ -571,11 +542,11 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
|
||||
|
||||
QINCREF(bs_opts);
|
||||
ret = bdrv_open(&bs, file, NULL, bs_opts, bdrv_flags, drv, &error);
|
||||
assert(bs == dinfo->bdrv);
|
||||
assert(bs == blk_bs(blk));
|
||||
|
||||
if (ret < 0) {
|
||||
error_setg(errp, "could not open disk image %s: %s",
|
||||
file ?: dinfo->id, error_get_pretty(error));
|
||||
file ?: blk_name(blk), error_get_pretty(error));
|
||||
error_free(error);
|
||||
goto err;
|
||||
}
|
||||
@@ -587,10 +558,10 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
|
||||
QDECREF(bs_opts);
|
||||
qemu_opts_del(opts);
|
||||
|
||||
return dinfo;
|
||||
return blk;
|
||||
|
||||
err:
|
||||
bdrv_unref(bs);
|
||||
blk_unref(blk);
|
||||
early_err:
|
||||
qemu_opts_del(opts);
|
||||
err_no_opts:
|
||||
@@ -703,6 +674,7 @@ QemuOptsList qemu_legacy_drive_opts = {
|
||||
DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
|
||||
{
|
||||
const char *value;
|
||||
BlockBackend *blk;
|
||||
DriveInfo *dinfo = NULL;
|
||||
QDict *bs_opts;
|
||||
QemuOpts *legacy_opts;
|
||||
@@ -1000,9 +972,9 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
|
||||
}
|
||||
|
||||
/* Actual block device init: Functionality shared with blockdev-add */
|
||||
dinfo = blockdev_init(filename, bs_opts, &local_err);
|
||||
blk = blockdev_init(filename, bs_opts, &local_err);
|
||||
bs_opts = NULL;
|
||||
if (dinfo == NULL) {
|
||||
if (!blk) {
|
||||
if (local_err) {
|
||||
error_report("%s", error_get_pretty(local_err));
|
||||
error_free(local_err);
|
||||
@@ -1012,8 +984,8 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
|
||||
assert(!local_err);
|
||||
}
|
||||
|
||||
/* Set legacy DriveInfo fields */
|
||||
dinfo->enable_auto_del = true;
|
||||
/* Create legacy DriveInfo */
|
||||
dinfo = g_malloc0(sizeof(*dinfo));
|
||||
dinfo->opts = all_opts;
|
||||
|
||||
dinfo->cyls = cyls;
|
||||
@@ -1025,9 +997,10 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
|
||||
dinfo->bus = bus_id;
|
||||
dinfo->unit = unit_id;
|
||||
dinfo->devaddr = devaddr;
|
||||
|
||||
dinfo->serial = g_strdup(serial);
|
||||
|
||||
blk_set_legacy_dinfo(blk, dinfo);
|
||||
|
||||
switch(type) {
|
||||
case IF_IDE:
|
||||
case IF_SCSI:
|
||||
@@ -1620,19 +1593,21 @@ exit:
|
||||
}
|
||||
|
||||
|
||||
static void eject_device(BlockDriverState *bs, int force, Error **errp)
|
||||
static void eject_device(BlockBackend *blk, int force, Error **errp)
|
||||
{
|
||||
BlockDriverState *bs = blk_bs(blk);
|
||||
|
||||
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) {
|
||||
return;
|
||||
}
|
||||
if (!bdrv_dev_has_removable_media(bs)) {
|
||||
if (!blk_dev_has_removable_media(blk)) {
|
||||
error_setg(errp, "Device '%s' is not removable",
|
||||
bdrv_get_device_name(bs));
|
||||
return;
|
||||
}
|
||||
|
||||
if (bdrv_dev_is_medium_locked(bs) && !bdrv_dev_is_tray_open(bs)) {
|
||||
bdrv_dev_eject_request(bs, force);
|
||||
if (blk_dev_is_medium_locked(blk) && !blk_dev_is_tray_open(blk)) {
|
||||
blk_dev_eject_request(blk, force);
|
||||
if (!force) {
|
||||
error_setg(errp, "Device '%s' is locked",
|
||||
bdrv_get_device_name(bs));
|
||||
@@ -1645,15 +1620,15 @@ static void eject_device(BlockDriverState *bs, int force, Error **errp)
|
||||
|
||||
void qmp_eject(const char *device, bool has_force, bool force, Error **errp)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
BlockBackend *blk;
|
||||
|
||||
bs = bdrv_find(device);
|
||||
if (!bs) {
|
||||
blk = blk_by_name(device);
|
||||
if (!blk) {
|
||||
error_set(errp, QERR_DEVICE_NOT_FOUND, device);
|
||||
return;
|
||||
}
|
||||
|
||||
eject_device(bs, force, errp);
|
||||
eject_device(blk, force, errp);
|
||||
}
|
||||
|
||||
void qmp_block_passwd(bool has_device, const char *device,
|
||||
@@ -1712,16 +1687,18 @@ static void qmp_bdrv_open_encrypted(BlockDriverState *bs, const char *filename,
|
||||
void qmp_change_blockdev(const char *device, const char *filename,
|
||||
const char *format, Error **errp)
|
||||
{
|
||||
BlockBackend *blk;
|
||||
BlockDriverState *bs;
|
||||
BlockDriver *drv = NULL;
|
||||
int bdrv_flags;
|
||||
Error *err = NULL;
|
||||
|
||||
bs = bdrv_find(device);
|
||||
if (!bs) {
|
||||
blk = blk_by_name(device);
|
||||
if (!blk) {
|
||||
error_set(errp, QERR_DEVICE_NOT_FOUND, device);
|
||||
return;
|
||||
}
|
||||
bs = blk_bs(blk);
|
||||
|
||||
if (format) {
|
||||
drv = bdrv_find_whitelisted_format(format, bs->read_only);
|
||||
@@ -1731,7 +1708,7 @@ void qmp_change_blockdev(const char *device, const char *filename,
|
||||
}
|
||||
}
|
||||
|
||||
eject_device(bs, 0, &err);
|
||||
eject_device(blk, 0, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
@@ -1829,19 +1806,19 @@ void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
|
||||
int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
||||
{
|
||||
const char *id = qdict_get_str(qdict, "id");
|
||||
BlockBackend *blk;
|
||||
BlockDriverState *bs;
|
||||
DriveInfo *dinfo;
|
||||
AioContext *aio_context;
|
||||
Error *local_err = NULL;
|
||||
|
||||
bs = bdrv_find(id);
|
||||
if (!bs) {
|
||||
blk = blk_by_name(id);
|
||||
if (!blk) {
|
||||
error_report("Device '%s' not found", id);
|
||||
return -1;
|
||||
}
|
||||
bs = blk_bs(blk);
|
||||
|
||||
dinfo = drive_get_by_blockdev(bs);
|
||||
if (dinfo && !dinfo->enable_auto_del) {
|
||||
if (!blk_legacy_dinfo(blk)) {
|
||||
error_report("Deleting device added with blockdev-add"
|
||||
" is not supported");
|
||||
return -1;
|
||||
@@ -1867,14 +1844,13 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
|
||||
* can be removed. If this is a drive with no device backing
|
||||
* then we can just get rid of the block driver state right here.
|
||||
*/
|
||||
if (bdrv_get_attached_dev(bs)) {
|
||||
bdrv_make_anon(bs);
|
||||
|
||||
if (blk_get_attached_dev(blk)) {
|
||||
blk_hide_on_behalf_of_do_drive_del(blk);
|
||||
/* Further I/O must not pause the guest */
|
||||
bdrv_set_on_error(bs, BLOCKDEV_ON_ERROR_REPORT,
|
||||
BLOCKDEV_ON_ERROR_REPORT);
|
||||
} else {
|
||||
drive_del(dinfo);
|
||||
blk_unref(blk);
|
||||
}
|
||||
|
||||
aio_context_release(aio_context);
|
||||
@@ -2566,7 +2542,7 @@ void qmp_change_backing_file(const char *device,
|
||||
void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
|
||||
{
|
||||
QmpOutputVisitor *ov = qmp_output_visitor_new();
|
||||
DriveInfo *dinfo;
|
||||
BlockBackend *blk;
|
||||
QObject *obj;
|
||||
QDict *qdict;
|
||||
Error *local_err = NULL;
|
||||
@@ -2604,14 +2580,14 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
|
||||
|
||||
qdict_flatten(qdict);
|
||||
|
||||
dinfo = blockdev_init(NULL, qdict, &local_err);
|
||||
blk = blockdev_init(NULL, qdict, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (bdrv_key_required(dinfo->bdrv)) {
|
||||
drive_del(dinfo);
|
||||
if (bdrv_key_required(blk_bs(blk))) {
|
||||
blk_unref(blk);
|
||||
error_setg(errp, "blockdev-add doesn't support encrypted devices");
|
||||
goto fail;
|
||||
}
|
||||
@@ -2620,26 +2596,21 @@ fail:
|
||||
qmp_output_visitor_cleanup(ov);
|
||||
}
|
||||
|
||||
static void do_qmp_query_block_jobs_one(void *opaque, BlockDriverState *bs)
|
||||
{
|
||||
BlockJobInfoList **prev = opaque;
|
||||
BlockJob *job = bs->job;
|
||||
|
||||
if (job) {
|
||||
BlockJobInfoList *elem = g_new0(BlockJobInfoList, 1);
|
||||
elem->value = block_job_query(bs->job);
|
||||
(*prev)->next = elem;
|
||||
*prev = elem;
|
||||
}
|
||||
}
|
||||
|
||||
BlockJobInfoList *qmp_query_block_jobs(Error **errp)
|
||||
{
|
||||
/* Dummy is a fake list element for holding the head pointer */
|
||||
BlockJobInfoList dummy = {};
|
||||
BlockJobInfoList *prev = &dummy;
|
||||
bdrv_iterate(do_qmp_query_block_jobs_one, &prev);
|
||||
return dummy.next;
|
||||
BlockJobInfoList *head = NULL, **p_next = &head;
|
||||
BlockDriverState *bs;
|
||||
|
||||
for (bs = bdrv_next(NULL); bs; bs = bdrv_next(bs)) {
|
||||
if (bs->job) {
|
||||
BlockJobInfoList *elem = g_new0(BlockJobInfoList, 1);
|
||||
elem->value = block_job_query(bs->job);
|
||||
*p_next = elem;
|
||||
p_next = &elem->next;
|
||||
}
|
||||
}
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
QemuOptsList qemu_common_drive_opts = {
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
#include "qapi-event.h"
|
||||
|
||||
void *block_job_create(const BlockJobDriver *driver, BlockDriverState *bs,
|
||||
int64_t speed, BlockDriverCompletionFunc *cb,
|
||||
int64_t speed, BlockCompletionFunc *cb,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
BlockJob *job;
|
||||
@@ -107,7 +107,8 @@ void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
|
||||
void block_job_complete(BlockJob *job, Error **errp)
|
||||
{
|
||||
if (job->paused || job->cancelled || !job->driver->complete) {
|
||||
error_set(errp, QERR_BLOCK_JOB_NOT_READY, job->bs->device_name);
|
||||
error_set(errp, QERR_BLOCK_JOB_NOT_READY,
|
||||
bdrv_get_device_name(job->bs));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -154,7 +155,7 @@ void block_job_iostatus_reset(BlockJob *job)
|
||||
|
||||
struct BlockCancelData {
|
||||
BlockJob *job;
|
||||
BlockDriverCompletionFunc *cb;
|
||||
BlockCompletionFunc *cb;
|
||||
void *opaque;
|
||||
bool cancelled;
|
||||
int ret;
|
||||
|
||||
6
configure
vendored
6
configure
vendored
@@ -4211,9 +4211,9 @@ EOF
|
||||
fi
|
||||
fi
|
||||
|
||||
# add pixman flags after all config tests are done
|
||||
QEMU_CFLAGS="$QEMU_CFLAGS $pixman_cflags $fdt_cflags"
|
||||
libs_softmmu="$libs_softmmu $pixman_libs"
|
||||
# prepend pixman and ftd flags after all config tests are done
|
||||
QEMU_CFLAGS="$pixman_cflags $fdt_cflags $QEMU_CFLAGS"
|
||||
libs_softmmu="$pixman_libs $libs_softmmu"
|
||||
|
||||
echo "Install prefix $prefix"
|
||||
echo "BIOS directory `eval echo $qemu_datadir`"
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include "hw/hw.h"
|
||||
#include "hw/boards.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "qemu/config-file.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
@@ -76,6 +77,6 @@ void drive_hot_add(Monitor *mon, const QDict *qdict)
|
||||
|
||||
err:
|
||||
if (dinfo) {
|
||||
drive_del(dinfo);
|
||||
blk_unref(blk_by_legacy_dinfo(dinfo));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ public:
|
||||
~QEMUDisassembler() { }
|
||||
|
||||
protected:
|
||||
void ProcessOutput(Instruction *instr) {
|
||||
virtual void ProcessOutput(const Instruction *instr) {
|
||||
fprintf(stream_, "%08" PRIx32 " %s",
|
||||
instr->InstructionBits(), GetOutput());
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
The code in this directory is a subset of libvixl:
|
||||
https://github.com/armvixl/vixl
|
||||
(specifically, it is the set of files needed for disassembly only,
|
||||
taken from libvixl 1.5).
|
||||
taken from libvixl 1.6).
|
||||
Bugfixes should preferably be sent upstream initially.
|
||||
|
||||
The disassembler does not currently support the entire A64 instruction
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
#include "globals.h"
|
||||
#include "utils.h"
|
||||
#include "code-buffer.h"
|
||||
#include "a64/instructions-a64.h"
|
||||
|
||||
namespace vixl {
|
||||
@@ -168,6 +169,11 @@ class CPURegister {
|
||||
return type_ == kFPRegister;
|
||||
}
|
||||
|
||||
bool IsW() const { return IsValidRegister() && Is32Bits(); }
|
||||
bool IsX() const { return IsValidRegister() && Is64Bits(); }
|
||||
bool IsS() const { return IsValidFPRegister() && Is32Bits(); }
|
||||
bool IsD() const { return IsValidFPRegister() && Is64Bits(); }
|
||||
|
||||
const Register& W() const;
|
||||
const Register& X() const;
|
||||
const FPRegister& S() const;
|
||||
@@ -191,12 +197,12 @@ class CPURegister {
|
||||
|
||||
class Register : public CPURegister {
|
||||
public:
|
||||
explicit Register() : CPURegister() {}
|
||||
Register() : CPURegister() {}
|
||||
inline explicit Register(const CPURegister& other)
|
||||
: CPURegister(other.code(), other.size(), other.type()) {
|
||||
VIXL_ASSERT(IsValidRegister());
|
||||
}
|
||||
explicit Register(unsigned code, unsigned size)
|
||||
Register(unsigned code, unsigned size)
|
||||
: CPURegister(code, size, kRegister) {}
|
||||
|
||||
bool IsValid() const {
|
||||
@@ -536,7 +542,7 @@ class Operand {
|
||||
class MemOperand {
|
||||
public:
|
||||
explicit MemOperand(Register base,
|
||||
ptrdiff_t offset = 0,
|
||||
int64_t offset = 0,
|
||||
AddrMode addrmode = Offset);
|
||||
explicit MemOperand(Register base,
|
||||
Register regoffset,
|
||||
@@ -552,7 +558,7 @@ class MemOperand {
|
||||
|
||||
const Register& base() const { return base_; }
|
||||
const Register& regoffset() const { return regoffset_; }
|
||||
ptrdiff_t offset() const { return offset_; }
|
||||
int64_t offset() const { return offset_; }
|
||||
AddrMode addrmode() const { return addrmode_; }
|
||||
Shift shift() const { return shift_; }
|
||||
Extend extend() const { return extend_; }
|
||||
@@ -565,7 +571,7 @@ class MemOperand {
|
||||
private:
|
||||
Register base_;
|
||||
Register regoffset_;
|
||||
ptrdiff_t offset_;
|
||||
int64_t offset_;
|
||||
AddrMode addrmode_;
|
||||
Shift shift_;
|
||||
Extend extend_;
|
||||
@@ -680,32 +686,80 @@ class Label {
|
||||
};
|
||||
|
||||
|
||||
// TODO: Obtain better values for these, based on real-world data.
|
||||
const int kLiteralPoolCheckInterval = 4 * KBytes;
|
||||
const int kRecommendedLiteralPoolRange = 2 * kLiteralPoolCheckInterval;
|
||||
// A literal is a 32-bit or 64-bit piece of data stored in the instruction
|
||||
// stream and loaded through a pc relative load. The same literal can be
|
||||
// referred to by multiple instructions but a literal can only reside at one
|
||||
// place in memory. A literal can be used by a load before or after being
|
||||
// placed in memory.
|
||||
//
|
||||
// Internally an offset of 0 is associated with a literal which has been
|
||||
// neither used nor placed. Then two possibilities arise:
|
||||
// 1) the label is placed, the offset (stored as offset + 1) is used to
|
||||
// resolve any subsequent load using the label.
|
||||
// 2) the label is not placed and offset is the offset of the last load using
|
||||
// the literal (stored as -offset -1). If multiple loads refer to this
|
||||
// literal then the last load holds the offset of the preceding load and
|
||||
// all loads form a chain. Once the offset is placed all the loads in the
|
||||
// chain are resolved and future loads fall back to possibility 1.
|
||||
class RawLiteral {
|
||||
public:
|
||||
RawLiteral() : size_(0), offset_(0), raw_value_(0) {}
|
||||
|
||||
size_t size() {
|
||||
VIXL_STATIC_ASSERT(kDRegSizeInBytes == kXRegSizeInBytes);
|
||||
VIXL_STATIC_ASSERT(kSRegSizeInBytes == kWRegSizeInBytes);
|
||||
VIXL_ASSERT((size_ == kXRegSizeInBytes) || (size_ == kWRegSizeInBytes));
|
||||
return size_;
|
||||
}
|
||||
uint64_t raw_value64() {
|
||||
VIXL_ASSERT(size_ == kXRegSizeInBytes);
|
||||
return raw_value_;
|
||||
}
|
||||
uint32_t raw_value32() {
|
||||
VIXL_ASSERT(size_ == kWRegSizeInBytes);
|
||||
VIXL_ASSERT(is_uint32(raw_value_) || is_int32(raw_value_));
|
||||
return static_cast<uint32_t>(raw_value_);
|
||||
}
|
||||
bool IsUsed() { return offset_ < 0; }
|
||||
bool IsPlaced() { return offset_ > 0; }
|
||||
|
||||
// Control whether a branch over the literal pool should also be emitted. This
|
||||
// is needed if the literal pool has to be emitted in the middle of the JITted
|
||||
// code.
|
||||
enum LiteralPoolEmitOption {
|
||||
JumpRequired,
|
||||
NoJumpRequired
|
||||
protected:
|
||||
ptrdiff_t offset() {
|
||||
VIXL_ASSERT(IsPlaced());
|
||||
return offset_ - 1;
|
||||
}
|
||||
void set_offset(ptrdiff_t offset) {
|
||||
VIXL_ASSERT(offset >= 0);
|
||||
VIXL_ASSERT(IsWordAligned(offset));
|
||||
VIXL_ASSERT(!IsPlaced());
|
||||
offset_ = offset + 1;
|
||||
}
|
||||
ptrdiff_t last_use() {
|
||||
VIXL_ASSERT(IsUsed());
|
||||
return -offset_ - 1;
|
||||
}
|
||||
void set_last_use(ptrdiff_t offset) {
|
||||
VIXL_ASSERT(offset >= 0);
|
||||
VIXL_ASSERT(IsWordAligned(offset));
|
||||
VIXL_ASSERT(!IsPlaced());
|
||||
offset_ = -offset - 1;
|
||||
}
|
||||
|
||||
size_t size_;
|
||||
ptrdiff_t offset_;
|
||||
uint64_t raw_value_;
|
||||
|
||||
friend class Assembler;
|
||||
};
|
||||
|
||||
|
||||
// Literal pool entry.
|
||||
class Literal {
|
||||
template <typename T>
|
||||
class Literal : public RawLiteral {
|
||||
public:
|
||||
Literal(Instruction* pc, uint64_t imm, unsigned size)
|
||||
: pc_(pc), value_(imm), size_(size) {}
|
||||
|
||||
private:
|
||||
Instruction* pc_;
|
||||
int64_t value_;
|
||||
unsigned size_;
|
||||
|
||||
friend class Assembler;
|
||||
explicit Literal(T value) {
|
||||
size_ = sizeof(value);
|
||||
memcpy(&raw_value_, &value, sizeof(value));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -750,7 +804,9 @@ enum LoadStoreScalingOption {
|
||||
// Assembler.
|
||||
class Assembler {
|
||||
public:
|
||||
Assembler(byte* buffer, unsigned buffer_size,
|
||||
Assembler(size_t capacity,
|
||||
PositionIndependentCodeOption pic = PositionIndependentCode);
|
||||
Assembler(byte* buffer, size_t capacity,
|
||||
PositionIndependentCodeOption pic = PositionIndependentCode);
|
||||
|
||||
// The destructor asserts that one of the following is true:
|
||||
@@ -763,9 +819,6 @@ class Assembler {
|
||||
|
||||
// Start generating code from the beginning of the buffer, discarding any code
|
||||
// and data that has already been emitted into the buffer.
|
||||
//
|
||||
// In order to avoid any accidental transfer of state, Reset ASSERTs that the
|
||||
// constant pool is not blocked.
|
||||
void Reset();
|
||||
|
||||
// Finalize a code buffer of generated instructions. This function must be
|
||||
@@ -776,13 +829,47 @@ class Assembler {
|
||||
// Bind a label to the current PC.
|
||||
void bind(Label* label);
|
||||
|
||||
// Bind a label to a specified offset from the start of the buffer.
|
||||
void BindToOffset(Label* label, ptrdiff_t offset);
|
||||
|
||||
// Place a literal at the current PC.
|
||||
void place(RawLiteral* literal);
|
||||
|
||||
ptrdiff_t CursorOffset() const {
|
||||
return buffer_->CursorOffset();
|
||||
}
|
||||
|
||||
ptrdiff_t BufferEndOffset() const {
|
||||
return static_cast<ptrdiff_t>(buffer_->capacity());
|
||||
}
|
||||
|
||||
// Return the address of an offset in the buffer.
|
||||
template <typename T>
|
||||
inline T GetOffsetAddress(ptrdiff_t offset) {
|
||||
VIXL_STATIC_ASSERT(sizeof(T) >= sizeof(uintptr_t));
|
||||
return buffer_->GetOffsetAddress<T>(offset);
|
||||
}
|
||||
|
||||
// Return the address of a bound label.
|
||||
template <typename T>
|
||||
inline T GetLabelAddress(const Label * label) {
|
||||
VIXL_ASSERT(label->IsBound());
|
||||
VIXL_STATIC_ASSERT(sizeof(T) >= sizeof(uintptr_t));
|
||||
VIXL_STATIC_ASSERT(sizeof(*buffer_) == 1);
|
||||
return reinterpret_cast<T>(buffer_ + label->location());
|
||||
return GetOffsetAddress<T>(label->location());
|
||||
}
|
||||
|
||||
// Return the address of the cursor.
|
||||
template <typename T>
|
||||
inline T GetCursorAddress() {
|
||||
VIXL_STATIC_ASSERT(sizeof(T) >= sizeof(uintptr_t));
|
||||
return GetOffsetAddress<T>(CursorOffset());
|
||||
}
|
||||
|
||||
// Return the address of the start of the buffer.
|
||||
template <typename T>
|
||||
inline T GetStartAddress() {
|
||||
VIXL_STATIC_ASSERT(sizeof(T) >= sizeof(uintptr_t));
|
||||
return GetOffsetAddress<T>(0);
|
||||
}
|
||||
|
||||
// Instruction set functions.
|
||||
@@ -1324,14 +1411,17 @@ class Assembler {
|
||||
void stnp(const CPURegister& rt, const CPURegister& rt2,
|
||||
const MemOperand& dst);
|
||||
|
||||
// Load literal to register.
|
||||
void ldr(const Register& rt, uint64_t imm);
|
||||
// Load integer or FP register from literal pool.
|
||||
void ldr(const CPURegister& rt, RawLiteral* literal);
|
||||
|
||||
// Load double precision floating point literal to FP register.
|
||||
void ldr(const FPRegister& ft, double imm);
|
||||
// Load word with sign extension from literal pool.
|
||||
void ldrsw(const Register& rt, RawLiteral* literal);
|
||||
|
||||
// Load single precision floating point literal to FP register.
|
||||
void ldr(const FPRegister& ft, float imm);
|
||||
// Load integer or FP register from pc + imm19 << 2.
|
||||
void ldr(const CPURegister& rt, int imm19);
|
||||
|
||||
// Load word with sign extension from pc + imm19 << 2.
|
||||
void ldrsw(const Register& rt, int imm19);
|
||||
|
||||
// Store exclusive byte.
|
||||
void stxrb(const Register& rs, const Register& rt, const MemOperand& dst);
|
||||
@@ -1618,25 +1708,26 @@ class Assembler {
|
||||
inline void dci(Instr raw_inst) { Emit(raw_inst); }
|
||||
|
||||
// Emit 32 bits of data into the instruction stream.
|
||||
inline void dc32(uint32_t data) { EmitData(&data, sizeof(data)); }
|
||||
inline void dc32(uint32_t data) {
|
||||
VIXL_ASSERT(buffer_monitor_ > 0);
|
||||
buffer_->Emit32(data);
|
||||
}
|
||||
|
||||
// Emit 64 bits of data into the instruction stream.
|
||||
inline void dc64(uint64_t data) { EmitData(&data, sizeof(data)); }
|
||||
inline void dc64(uint64_t data) {
|
||||
VIXL_ASSERT(buffer_monitor_ > 0);
|
||||
buffer_->Emit64(data);
|
||||
}
|
||||
|
||||
// Copy a string into the instruction stream, including the terminating NULL
|
||||
// character. The instruction pointer (pc_) is then aligned correctly for
|
||||
// character. The instruction pointer is then aligned correctly for
|
||||
// subsequent instructions.
|
||||
void EmitStringData(const char * string) {
|
||||
void EmitString(const char * string) {
|
||||
VIXL_ASSERT(string != NULL);
|
||||
VIXL_ASSERT(buffer_monitor_ > 0);
|
||||
|
||||
size_t len = strlen(string) + 1;
|
||||
EmitData(string, len);
|
||||
|
||||
// Pad with NULL characters until pc_ is aligned.
|
||||
const char pad[] = {'\0', '\0', '\0', '\0'};
|
||||
VIXL_STATIC_ASSERT(sizeof(pad) == kInstructionSize);
|
||||
Instruction* next_pc = AlignUp(pc_, kInstructionSize);
|
||||
EmitData(&pad, next_pc - pc_);
|
||||
buffer_->EmitString(string);
|
||||
buffer_->Align();
|
||||
}
|
||||
|
||||
// Code generation helpers.
|
||||
@@ -1912,43 +2003,39 @@ class Assembler {
|
||||
return scale << FPScale_offset;
|
||||
}
|
||||
|
||||
// Size of the code generated in bytes
|
||||
size_t SizeOfCodeGenerated() const {
|
||||
VIXL_ASSERT((pc_ >= buffer_) && (pc_ < (buffer_ + buffer_size_)));
|
||||
return pc_ - buffer_;
|
||||
}
|
||||
|
||||
// Size of the code generated since label to the current position.
|
||||
size_t SizeOfCodeGeneratedSince(Label* label) const {
|
||||
size_t pc_offset = SizeOfCodeGenerated();
|
||||
|
||||
VIXL_ASSERT(label->IsBound());
|
||||
VIXL_ASSERT(pc_offset >= static_cast<size_t>(label->location()));
|
||||
VIXL_ASSERT(pc_offset < buffer_size_);
|
||||
|
||||
return pc_offset - label->location();
|
||||
return buffer_->OffsetFrom(label->location());
|
||||
}
|
||||
|
||||
size_t BufferCapacity() const { return buffer_->capacity(); }
|
||||
|
||||
inline void BlockLiteralPool() {
|
||||
literal_pool_monitor_++;
|
||||
}
|
||||
size_t RemainingBufferSpace() const { return buffer_->RemainingBytes(); }
|
||||
|
||||
inline void ReleaseLiteralPool() {
|
||||
if (--literal_pool_monitor_ == 0) {
|
||||
// Has the literal pool been blocked for too long?
|
||||
VIXL_ASSERT(literals_.empty() ||
|
||||
(pc_ < (literals_.back()->pc_ + kMaxLoadLiteralRange)));
|
||||
void EnsureSpaceFor(size_t amount) {
|
||||
if (buffer_->RemainingBytes() < amount) {
|
||||
size_t capacity = buffer_->capacity();
|
||||
size_t size = buffer_->CursorOffset();
|
||||
do {
|
||||
// TODO(all): refine.
|
||||
capacity *= 2;
|
||||
} while ((capacity - size) < amount);
|
||||
buffer_->Grow(capacity);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool IsLiteralPoolBlocked() {
|
||||
return literal_pool_monitor_ != 0;
|
||||
#ifdef DEBUG
|
||||
void AcquireBuffer() {
|
||||
VIXL_ASSERT(buffer_monitor_ >= 0);
|
||||
buffer_monitor_++;
|
||||
}
|
||||
|
||||
void CheckLiteralPool(LiteralPoolEmitOption option = JumpRequired);
|
||||
void EmitLiteralPool(LiteralPoolEmitOption option = NoJumpRequired);
|
||||
size_t LiteralPoolSize();
|
||||
void ReleaseBuffer() {
|
||||
buffer_monitor_--;
|
||||
VIXL_ASSERT(buffer_monitor_ >= 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
inline PositionIndependentCodeOption pic() {
|
||||
return pic_;
|
||||
@@ -1959,22 +2046,30 @@ class Assembler {
|
||||
(pic() == PositionDependentCode);
|
||||
}
|
||||
|
||||
protected:
|
||||
inline const Register& AppropriateZeroRegFor(const CPURegister& reg) const {
|
||||
static inline const Register& AppropriateZeroRegFor(const CPURegister& reg) {
|
||||
return reg.Is64Bits() ? xzr : wzr;
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
void LoadStore(const CPURegister& rt,
|
||||
const MemOperand& addr,
|
||||
LoadStoreOp op,
|
||||
LoadStoreScalingOption option = PreferScaledOffset);
|
||||
static bool IsImmLSUnscaled(ptrdiff_t offset);
|
||||
static bool IsImmLSScaled(ptrdiff_t offset, LSDataSize size);
|
||||
static bool IsImmLSUnscaled(int64_t offset);
|
||||
static bool IsImmLSScaled(int64_t offset, LSDataSize size);
|
||||
|
||||
void LoadStorePair(const CPURegister& rt,
|
||||
const CPURegister& rt2,
|
||||
const MemOperand& addr,
|
||||
LoadStorePairOp op);
|
||||
static bool IsImmLSPair(int64_t offset, LSDataSize size);
|
||||
|
||||
// TODO(all): The third parameter should be passed by reference but gcc 4.8.2
|
||||
// reports a bogus uninitialised warning then.
|
||||
void Logical(const Register& rd,
|
||||
const Register& rn,
|
||||
const Operand& operand,
|
||||
const Operand operand,
|
||||
LogicalOp op);
|
||||
void LogicalImmediate(const Register& rd,
|
||||
const Register& rn,
|
||||
@@ -2035,6 +2130,7 @@ class Assembler {
|
||||
const CPURegister& rt, const CPURegister& rt2);
|
||||
static LoadStorePairNonTemporalOp StorePairNonTemporalOpFor(
|
||||
const CPURegister& rt, const CPURegister& rt2);
|
||||
static LoadLiteralOp LoadLiteralOpFor(const CPURegister& rt);
|
||||
|
||||
|
||||
private:
|
||||
@@ -2053,10 +2149,6 @@ class Assembler {
|
||||
const Operand& operand,
|
||||
FlagsUpdate S,
|
||||
Instr op);
|
||||
void LoadStorePair(const CPURegister& rt,
|
||||
const CPURegister& rt2,
|
||||
const MemOperand& addr,
|
||||
LoadStorePairOp op);
|
||||
void LoadStorePairNonTemporal(const CPURegister& rt,
|
||||
const CPURegister& rt2,
|
||||
const MemOperand& addr,
|
||||
@@ -2088,8 +2180,6 @@ class Assembler {
|
||||
const FPRegister& fa,
|
||||
FPDataProcessing3SourceOp op);
|
||||
|
||||
void RecordLiteral(int64_t imm, unsigned size);
|
||||
|
||||
// Link the current (not-yet-emitted) instruction to the specified label, then
|
||||
// return an offset to be encoded in the instruction. If the label is not yet
|
||||
// bound, an offset of 0 is returned.
|
||||
@@ -2098,79 +2188,102 @@ class Assembler {
|
||||
ptrdiff_t LinkAndGetPageOffsetTo(Label * label);
|
||||
|
||||
// A common implementation for the LinkAndGet<Type>OffsetTo helpers.
|
||||
template <int element_size>
|
||||
template <int element_shift>
|
||||
ptrdiff_t LinkAndGetOffsetTo(Label* label);
|
||||
|
||||
// Emit the instruction at pc_.
|
||||
// Literal load offset are in words (32-bit).
|
||||
ptrdiff_t LinkAndGetWordOffsetTo(RawLiteral* literal);
|
||||
|
||||
// Emit the instruction in buffer_.
|
||||
void Emit(Instr instruction) {
|
||||
VIXL_STATIC_ASSERT(sizeof(*pc_) == 1);
|
||||
VIXL_STATIC_ASSERT(sizeof(instruction) == kInstructionSize);
|
||||
VIXL_ASSERT((pc_ + sizeof(instruction)) <= (buffer_ + buffer_size_));
|
||||
|
||||
#ifdef DEBUG
|
||||
finalized_ = false;
|
||||
#endif
|
||||
|
||||
memcpy(pc_, &instruction, sizeof(instruction));
|
||||
pc_ += sizeof(instruction);
|
||||
CheckBufferSpace();
|
||||
VIXL_ASSERT(buffer_monitor_ > 0);
|
||||
buffer_->Emit32(instruction);
|
||||
}
|
||||
|
||||
// Emit data inline in the instruction stream.
|
||||
void EmitData(void const * data, unsigned size) {
|
||||
VIXL_STATIC_ASSERT(sizeof(*pc_) == 1);
|
||||
VIXL_ASSERT((pc_ + size) <= (buffer_ + buffer_size_));
|
||||
|
||||
#ifdef DEBUG
|
||||
finalized_ = false;
|
||||
#endif
|
||||
|
||||
// TODO: Record this 'instruction' as data, so that it can be disassembled
|
||||
// correctly.
|
||||
memcpy(pc_, data, size);
|
||||
pc_ += size;
|
||||
CheckBufferSpace();
|
||||
}
|
||||
|
||||
inline void CheckBufferSpace() {
|
||||
VIXL_ASSERT(pc_ < (buffer_ + buffer_size_));
|
||||
if (pc_ > next_literal_pool_check_) {
|
||||
CheckLiteralPool();
|
||||
}
|
||||
}
|
||||
|
||||
// The buffer into which code and relocation info are generated.
|
||||
Instruction* buffer_;
|
||||
// Buffer size, in bytes.
|
||||
size_t buffer_size_;
|
||||
Instruction* pc_;
|
||||
std::list<Literal*> literals_;
|
||||
Instruction* next_literal_pool_check_;
|
||||
unsigned literal_pool_monitor_;
|
||||
|
||||
// Buffer where the code is emitted.
|
||||
CodeBuffer* buffer_;
|
||||
PositionIndependentCodeOption pic_;
|
||||
|
||||
friend class Label;
|
||||
friend class BlockLiteralPoolScope;
|
||||
|
||||
#ifdef DEBUG
|
||||
bool finalized_;
|
||||
int64_t buffer_monitor_;
|
||||
#endif
|
||||
};
|
||||
|
||||
class BlockLiteralPoolScope {
|
||||
|
||||
// All Assembler emits MUST acquire/release the underlying code buffer. The
|
||||
// helper scope below will do so and optionally ensure the buffer is big enough
|
||||
// to receive the emit. It is possible to request the scope not to perform any
|
||||
// checks (kNoCheck) if for example it is known in advance the buffer size is
|
||||
// adequate or there is some other size checking mechanism in place.
|
||||
class CodeBufferCheckScope {
|
||||
public:
|
||||
explicit BlockLiteralPoolScope(Assembler* assm) : assm_(assm) {
|
||||
assm_->BlockLiteralPool();
|
||||
// Tell whether or not the scope needs to ensure the associated CodeBuffer
|
||||
// has enough space for the requested size.
|
||||
enum CheckPolicy {
|
||||
kNoCheck,
|
||||
kCheck
|
||||
};
|
||||
|
||||
// Tell whether or not the scope should assert the amount of code emitted
|
||||
// within the scope is consistent with the requested amount.
|
||||
enum AssertPolicy {
|
||||
kNoAssert, // No assert required.
|
||||
kExactSize, // The code emitted must be exactly size bytes.
|
||||
kMaximumSize // The code emitted must be at most size bytes.
|
||||
};
|
||||
|
||||
CodeBufferCheckScope(Assembler* assm,
|
||||
size_t size,
|
||||
CheckPolicy check_policy = kCheck,
|
||||
AssertPolicy assert_policy = kMaximumSize)
|
||||
: assm_(assm) {
|
||||
if (check_policy == kCheck) assm->EnsureSpaceFor(size);
|
||||
#ifdef DEBUG
|
||||
assm->bind(&start_);
|
||||
size_ = size;
|
||||
assert_policy_ = assert_policy;
|
||||
assm->AcquireBuffer();
|
||||
#else
|
||||
USE(assert_policy);
|
||||
#endif
|
||||
}
|
||||
|
||||
~BlockLiteralPoolScope() {
|
||||
assm_->ReleaseLiteralPool();
|
||||
// This is a shortcut for CodeBufferCheckScope(assm, 0, kNoCheck, kNoAssert).
|
||||
explicit CodeBufferCheckScope(Assembler* assm) : assm_(assm) {
|
||||
#ifdef DEBUG
|
||||
size_ = 0;
|
||||
assert_policy_ = kNoAssert;
|
||||
assm->AcquireBuffer();
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
~CodeBufferCheckScope() {
|
||||
#ifdef DEBUG
|
||||
assm_->ReleaseBuffer();
|
||||
switch (assert_policy_) {
|
||||
case kNoAssert: break;
|
||||
case kExactSize:
|
||||
VIXL_ASSERT(assm_->SizeOfCodeGeneratedSince(&start_) == size_);
|
||||
break;
|
||||
case kMaximumSize:
|
||||
VIXL_ASSERT(assm_->SizeOfCodeGeneratedSince(&start_) <= size_);
|
||||
break;
|
||||
default:
|
||||
VIXL_UNREACHABLE();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
protected:
|
||||
Assembler* assm_;
|
||||
#ifdef DEBUG
|
||||
Label start_;
|
||||
size_t size_;
|
||||
AssertPolicy assert_policy_;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace vixl
|
||||
|
||||
#endif // VIXL_A64_ASSEMBLER_A64_H_
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
#include "a64/decoder-a64.h"
|
||||
|
||||
namespace vixl {
|
||||
// Top-level instruction decode function.
|
||||
void Decoder::Decode(Instruction *instr) {
|
||||
|
||||
void Decoder::DecodeInstruction(const Instruction *instr) {
|
||||
if (instr->Bits(28, 27) == 0) {
|
||||
VisitUnallocated(instr);
|
||||
} else {
|
||||
@@ -109,20 +109,17 @@ void Decoder::Decode(Instruction *instr) {
|
||||
}
|
||||
|
||||
void Decoder::AppendVisitor(DecoderVisitor* new_visitor) {
|
||||
visitors_.remove(new_visitor);
|
||||
visitors_.push_front(new_visitor);
|
||||
visitors_.push_back(new_visitor);
|
||||
}
|
||||
|
||||
|
||||
void Decoder::PrependVisitor(DecoderVisitor* new_visitor) {
|
||||
visitors_.remove(new_visitor);
|
||||
visitors_.push_back(new_visitor);
|
||||
visitors_.push_front(new_visitor);
|
||||
}
|
||||
|
||||
|
||||
void Decoder::InsertVisitorBefore(DecoderVisitor* new_visitor,
|
||||
DecoderVisitor* registered_visitor) {
|
||||
visitors_.remove(new_visitor);
|
||||
std::list<DecoderVisitor*>::iterator it;
|
||||
for (it = visitors_.begin(); it != visitors_.end(); it++) {
|
||||
if (*it == registered_visitor) {
|
||||
@@ -139,7 +136,6 @@ void Decoder::InsertVisitorBefore(DecoderVisitor* new_visitor,
|
||||
|
||||
void Decoder::InsertVisitorAfter(DecoderVisitor* new_visitor,
|
||||
DecoderVisitor* registered_visitor) {
|
||||
visitors_.remove(new_visitor);
|
||||
std::list<DecoderVisitor*>::iterator it;
|
||||
for (it = visitors_.begin(); it != visitors_.end(); it++) {
|
||||
if (*it == registered_visitor) {
|
||||
@@ -160,7 +156,7 @@ void Decoder::RemoveVisitor(DecoderVisitor* visitor) {
|
||||
}
|
||||
|
||||
|
||||
void Decoder::DecodePCRelAddressing(Instruction* instr) {
|
||||
void Decoder::DecodePCRelAddressing(const Instruction* instr) {
|
||||
VIXL_ASSERT(instr->Bits(27, 24) == 0x0);
|
||||
// We know bit 28 is set, as <b28:b27> = 0 is filtered out at the top level
|
||||
// decode.
|
||||
@@ -169,7 +165,7 @@ void Decoder::DecodePCRelAddressing(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Decoder::DecodeBranchSystemException(Instruction* instr) {
|
||||
void Decoder::DecodeBranchSystemException(const Instruction* instr) {
|
||||
VIXL_ASSERT((instr->Bits(27, 24) == 0x4) ||
|
||||
(instr->Bits(27, 24) == 0x5) ||
|
||||
(instr->Bits(27, 24) == 0x6) ||
|
||||
@@ -270,7 +266,7 @@ void Decoder::DecodeBranchSystemException(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Decoder::DecodeLoadStore(Instruction* instr) {
|
||||
void Decoder::DecodeLoadStore(const Instruction* instr) {
|
||||
VIXL_ASSERT((instr->Bits(27, 24) == 0x8) ||
|
||||
(instr->Bits(27, 24) == 0x9) ||
|
||||
(instr->Bits(27, 24) == 0xC) ||
|
||||
@@ -388,7 +384,7 @@ void Decoder::DecodeLoadStore(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Decoder::DecodeLogical(Instruction* instr) {
|
||||
void Decoder::DecodeLogical(const Instruction* instr) {
|
||||
VIXL_ASSERT(instr->Bits(27, 24) == 0x2);
|
||||
|
||||
if (instr->Mask(0x80400000) == 0x00400000) {
|
||||
@@ -407,7 +403,7 @@ void Decoder::DecodeLogical(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Decoder::DecodeBitfieldExtract(Instruction* instr) {
|
||||
void Decoder::DecodeBitfieldExtract(const Instruction* instr) {
|
||||
VIXL_ASSERT(instr->Bits(27, 24) == 0x3);
|
||||
|
||||
if ((instr->Mask(0x80400000) == 0x80000000) ||
|
||||
@@ -432,7 +428,7 @@ void Decoder::DecodeBitfieldExtract(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Decoder::DecodeAddSubImmediate(Instruction* instr) {
|
||||
void Decoder::DecodeAddSubImmediate(const Instruction* instr) {
|
||||
VIXL_ASSERT(instr->Bits(27, 24) == 0x1);
|
||||
if (instr->Bit(23) == 1) {
|
||||
VisitUnallocated(instr);
|
||||
@@ -442,7 +438,7 @@ void Decoder::DecodeAddSubImmediate(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Decoder::DecodeDataProcessing(Instruction* instr) {
|
||||
void Decoder::DecodeDataProcessing(const Instruction* instr) {
|
||||
VIXL_ASSERT((instr->Bits(27, 24) == 0xA) ||
|
||||
(instr->Bits(27, 24) == 0xB));
|
||||
|
||||
@@ -557,7 +553,7 @@ void Decoder::DecodeDataProcessing(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Decoder::DecodeFP(Instruction* instr) {
|
||||
void Decoder::DecodeFP(const Instruction* instr) {
|
||||
VIXL_ASSERT((instr->Bits(27, 24) == 0xE) ||
|
||||
(instr->Bits(27, 24) == 0xF));
|
||||
|
||||
@@ -684,14 +680,14 @@ void Decoder::DecodeFP(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Decoder::DecodeAdvSIMDLoadStore(Instruction* instr) {
|
||||
void Decoder::DecodeAdvSIMDLoadStore(const Instruction* instr) {
|
||||
// TODO: Implement Advanced SIMD load/store instruction decode.
|
||||
VIXL_ASSERT(instr->Bits(29, 25) == 0x6);
|
||||
VisitUnimplemented(instr);
|
||||
}
|
||||
|
||||
|
||||
void Decoder::DecodeAdvSIMDDataProcessing(Instruction* instr) {
|
||||
void Decoder::DecodeAdvSIMDDataProcessing(const Instruction* instr) {
|
||||
// TODO: Implement Advanced SIMD data processing instruction decode.
|
||||
VIXL_ASSERT(instr->Bits(27, 25) == 0x7);
|
||||
VisitUnimplemented(instr);
|
||||
@@ -699,7 +695,7 @@ void Decoder::DecodeAdvSIMDDataProcessing(Instruction* instr) {
|
||||
|
||||
|
||||
#define DEFINE_VISITOR_CALLERS(A) \
|
||||
void Decoder::Visit##A(Instruction *instr) { \
|
||||
void Decoder::Visit##A(const Instruction *instr) { \
|
||||
VIXL_ASSERT(instr->Mask(A##FMask) == A##Fixed); \
|
||||
std::list<DecoderVisitor*>::iterator it; \
|
||||
for (it = visitors_.begin(); it != visitors_.end(); it++) { \
|
||||
|
||||
@@ -88,112 +88,152 @@ namespace vixl {
|
||||
// must provide implementations for all of these functions.
|
||||
class DecoderVisitor {
|
||||
public:
|
||||
#define DECLARE(A) virtual void Visit##A(Instruction* instr) = 0;
|
||||
VISITOR_LIST(DECLARE)
|
||||
#undef DECLARE
|
||||
enum VisitorConstness {
|
||||
kConstVisitor,
|
||||
kNonConstVisitor
|
||||
};
|
||||
explicit DecoderVisitor(VisitorConstness constness = kConstVisitor)
|
||||
: constness_(constness) {}
|
||||
|
||||
virtual ~DecoderVisitor() {}
|
||||
|
||||
private:
|
||||
// Visitors are registered in a list.
|
||||
std::list<DecoderVisitor*> visitors_;
|
||||
#define DECLARE(A) virtual void Visit##A(const Instruction* instr) = 0;
|
||||
VISITOR_LIST(DECLARE)
|
||||
#undef DECLARE
|
||||
|
||||
friend class Decoder;
|
||||
bool IsConstVisitor() const { return constness_ == kConstVisitor; }
|
||||
Instruction* MutableInstruction(const Instruction* instr) {
|
||||
VIXL_ASSERT(!IsConstVisitor());
|
||||
return const_cast<Instruction*>(instr);
|
||||
}
|
||||
|
||||
private:
|
||||
VisitorConstness constness_;
|
||||
};
|
||||
|
||||
|
||||
class Decoder: public DecoderVisitor {
|
||||
class Decoder {
|
||||
public:
|
||||
Decoder() {}
|
||||
|
||||
// Top-level instruction decoder function. Decodes an instruction and calls
|
||||
// the visitor functions registered with the Decoder class.
|
||||
void Decode(Instruction *instr);
|
||||
// Top-level wrappers around the actual decoding function.
|
||||
void Decode(const Instruction* instr) {
|
||||
std::list<DecoderVisitor*>::iterator it;
|
||||
for (it = visitors_.begin(); it != visitors_.end(); it++) {
|
||||
VIXL_ASSERT((*it)->IsConstVisitor());
|
||||
}
|
||||
DecodeInstruction(instr);
|
||||
}
|
||||
void Decode(Instruction* instr) {
|
||||
DecodeInstruction(const_cast<const Instruction*>(instr));
|
||||
}
|
||||
|
||||
// Register a new visitor class with the decoder.
|
||||
// Decode() will call the corresponding visitor method from all registered
|
||||
// visitor classes when decoding reaches the leaf node of the instruction
|
||||
// decode tree.
|
||||
// Visitors are called in the order.
|
||||
// A visitor can only be registered once.
|
||||
// Registering an already registered visitor will update its position.
|
||||
// Visitors are called in order.
|
||||
// A visitor can be registered multiple times.
|
||||
//
|
||||
// d.AppendVisitor(V1);
|
||||
// d.AppendVisitor(V2);
|
||||
// d.PrependVisitor(V2); // Move V2 at the start of the list.
|
||||
// d.InsertVisitorBefore(V3, V2);
|
||||
// d.AppendVisitor(V4);
|
||||
// d.AppendVisitor(V4); // No effect.
|
||||
// d.PrependVisitor(V2);
|
||||
// d.AppendVisitor(V3);
|
||||
//
|
||||
// d.Decode(i);
|
||||
//
|
||||
// will call in order visitor methods in V3, V2, V1, V4.
|
||||
// will call in order visitor methods in V2, V1, V2, V3.
|
||||
void AppendVisitor(DecoderVisitor* visitor);
|
||||
void PrependVisitor(DecoderVisitor* visitor);
|
||||
// These helpers register `new_visitor` before or after the first instance of
|
||||
// `registered_visiter` in the list.
|
||||
// So if
|
||||
// V1, V2, V1, V2
|
||||
// are registered in this order in the decoder, calls to
|
||||
// d.InsertVisitorAfter(V3, V1);
|
||||
// d.InsertVisitorBefore(V4, V2);
|
||||
// will yield the order
|
||||
// V1, V3, V4, V2, V1, V2
|
||||
//
|
||||
// For more complex modifications of the order of registered visitors, one can
|
||||
// directly access and modify the list of visitors via the `visitors()'
|
||||
// accessor.
|
||||
void InsertVisitorBefore(DecoderVisitor* new_visitor,
|
||||
DecoderVisitor* registered_visitor);
|
||||
void InsertVisitorAfter(DecoderVisitor* new_visitor,
|
||||
DecoderVisitor* registered_visitor);
|
||||
|
||||
// Remove a previously registered visitor class from the list of visitors
|
||||
// stored by the decoder.
|
||||
// Remove all instances of a previously registered visitor class from the list
|
||||
// of visitors stored by the decoder.
|
||||
void RemoveVisitor(DecoderVisitor* visitor);
|
||||
|
||||
#define DECLARE(A) void Visit##A(Instruction* instr);
|
||||
#define DECLARE(A) void Visit##A(const Instruction* instr);
|
||||
VISITOR_LIST(DECLARE)
|
||||
#undef DECLARE
|
||||
|
||||
|
||||
std::list<DecoderVisitor*>* visitors() { return &visitors_; }
|
||||
|
||||
private:
|
||||
// Decodes an instruction and calls the visitor functions registered with the
|
||||
// Decoder class.
|
||||
void DecodeInstruction(const Instruction* instr);
|
||||
|
||||
// Decode the PC relative addressing instruction, and call the corresponding
|
||||
// visitors.
|
||||
// On entry, instruction bits 27:24 = 0x0.
|
||||
void DecodePCRelAddressing(Instruction* instr);
|
||||
void DecodePCRelAddressing(const Instruction* instr);
|
||||
|
||||
// Decode the add/subtract immediate instruction, and call the correspoding
|
||||
// visitors.
|
||||
// On entry, instruction bits 27:24 = 0x1.
|
||||
void DecodeAddSubImmediate(Instruction* instr);
|
||||
void DecodeAddSubImmediate(const Instruction* instr);
|
||||
|
||||
// Decode the branch, system command, and exception generation parts of
|
||||
// the instruction tree, and call the corresponding visitors.
|
||||
// On entry, instruction bits 27:24 = {0x4, 0x5, 0x6, 0x7}.
|
||||
void DecodeBranchSystemException(Instruction* instr);
|
||||
void DecodeBranchSystemException(const Instruction* instr);
|
||||
|
||||
// Decode the load and store parts of the instruction tree, and call
|
||||
// the corresponding visitors.
|
||||
// On entry, instruction bits 27:24 = {0x8, 0x9, 0xC, 0xD}.
|
||||
void DecodeLoadStore(Instruction* instr);
|
||||
void DecodeLoadStore(const Instruction* instr);
|
||||
|
||||
// Decode the logical immediate and move wide immediate parts of the
|
||||
// instruction tree, and call the corresponding visitors.
|
||||
// On entry, instruction bits 27:24 = 0x2.
|
||||
void DecodeLogical(Instruction* instr);
|
||||
void DecodeLogical(const Instruction* instr);
|
||||
|
||||
// Decode the bitfield and extraction parts of the instruction tree,
|
||||
// and call the corresponding visitors.
|
||||
// On entry, instruction bits 27:24 = 0x3.
|
||||
void DecodeBitfieldExtract(Instruction* instr);
|
||||
void DecodeBitfieldExtract(const Instruction* instr);
|
||||
|
||||
// Decode the data processing parts of the instruction tree, and call the
|
||||
// corresponding visitors.
|
||||
// On entry, instruction bits 27:24 = {0x1, 0xA, 0xB}.
|
||||
void DecodeDataProcessing(Instruction* instr);
|
||||
void DecodeDataProcessing(const Instruction* instr);
|
||||
|
||||
// Decode the floating point parts of the instruction tree, and call the
|
||||
// corresponding visitors.
|
||||
// On entry, instruction bits 27:24 = {0xE, 0xF}.
|
||||
void DecodeFP(Instruction* instr);
|
||||
void DecodeFP(const Instruction* instr);
|
||||
|
||||
// Decode the Advanced SIMD (NEON) load/store part of the instruction tree,
|
||||
// and call the corresponding visitors.
|
||||
// On entry, instruction bits 29:25 = 0x6.
|
||||
void DecodeAdvSIMDLoadStore(Instruction* instr);
|
||||
void DecodeAdvSIMDLoadStore(const Instruction* instr);
|
||||
|
||||
// Decode the Advanced SIMD (NEON) data processing part of the instruction
|
||||
// tree, and call the corresponding visitors.
|
||||
// On entry, instruction bits 27:25 = 0x7.
|
||||
void DecodeAdvSIMDDataProcessing(Instruction* instr);
|
||||
void DecodeAdvSIMDDataProcessing(const Instruction* instr);
|
||||
|
||||
private:
|
||||
// Visitors are registered in a list.
|
||||
std::list<DecoderVisitor*> visitors_;
|
||||
};
|
||||
|
||||
} // namespace vixl
|
||||
|
||||
#endif // VIXL_A64_DECODER_A64_H_
|
||||
|
||||
@@ -57,7 +57,7 @@ char* Disassembler::GetOutput() {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitAddSubImmediate(Instruction* instr) {
|
||||
void Disassembler::VisitAddSubImmediate(const Instruction* instr) {
|
||||
bool rd_is_zr = RdIsZROrSP(instr);
|
||||
bool stack_op = (rd_is_zr || RnIsZROrSP(instr)) &&
|
||||
(instr->ImmAddSub() == 0) ? true : false;
|
||||
@@ -102,7 +102,7 @@ void Disassembler::VisitAddSubImmediate(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitAddSubShifted(Instruction* instr) {
|
||||
void Disassembler::VisitAddSubShifted(const Instruction* instr) {
|
||||
bool rd_is_zr = RdIsZROrSP(instr);
|
||||
bool rn_is_zr = RnIsZROrSP(instr);
|
||||
const char *mnemonic = "";
|
||||
@@ -149,7 +149,7 @@ void Disassembler::VisitAddSubShifted(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitAddSubExtended(Instruction* instr) {
|
||||
void Disassembler::VisitAddSubExtended(const Instruction* instr) {
|
||||
bool rd_is_zr = RdIsZROrSP(instr);
|
||||
const char *mnemonic = "";
|
||||
Extend mode = static_cast<Extend>(instr->ExtendMode());
|
||||
@@ -187,7 +187,7 @@ void Disassembler::VisitAddSubExtended(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitAddSubWithCarry(Instruction* instr) {
|
||||
void Disassembler::VisitAddSubWithCarry(const Instruction* instr) {
|
||||
bool rn_is_zr = RnIsZROrSP(instr);
|
||||
const char *mnemonic = "";
|
||||
const char *form = "'Rd, 'Rn, 'Rm";
|
||||
@@ -222,7 +222,7 @@ void Disassembler::VisitAddSubWithCarry(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitLogicalImmediate(Instruction* instr) {
|
||||
void Disassembler::VisitLogicalImmediate(const Instruction* instr) {
|
||||
bool rd_is_zr = RdIsZROrSP(instr);
|
||||
bool rn_is_zr = RnIsZROrSP(instr);
|
||||
const char *mnemonic = "";
|
||||
@@ -294,7 +294,7 @@ bool Disassembler::IsMovzMovnImm(unsigned reg_size, uint64_t value) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitLogicalShifted(Instruction* instr) {
|
||||
void Disassembler::VisitLogicalShifted(const Instruction* instr) {
|
||||
bool rd_is_zr = RdIsZROrSP(instr);
|
||||
bool rn_is_zr = RnIsZROrSP(instr);
|
||||
const char *mnemonic = "";
|
||||
@@ -345,7 +345,7 @@ void Disassembler::VisitLogicalShifted(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitConditionalCompareRegister(Instruction* instr) {
|
||||
void Disassembler::VisitConditionalCompareRegister(const Instruction* instr) {
|
||||
const char *mnemonic = "";
|
||||
const char *form = "'Rn, 'Rm, 'INzcv, 'Cond";
|
||||
|
||||
@@ -360,7 +360,7 @@ void Disassembler::VisitConditionalCompareRegister(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitConditionalCompareImmediate(Instruction* instr) {
|
||||
void Disassembler::VisitConditionalCompareImmediate(const Instruction* instr) {
|
||||
const char *mnemonic = "";
|
||||
const char *form = "'Rn, 'IP, 'INzcv, 'Cond";
|
||||
|
||||
@@ -375,7 +375,7 @@ void Disassembler::VisitConditionalCompareImmediate(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitConditionalSelect(Instruction* instr) {
|
||||
void Disassembler::VisitConditionalSelect(const Instruction* instr) {
|
||||
bool rnm_is_zr = (RnIsZROrSP(instr) && RmIsZROrSP(instr));
|
||||
bool rn_is_rm = (instr->Rn() == instr->Rm());
|
||||
const char *mnemonic = "";
|
||||
@@ -428,7 +428,7 @@ void Disassembler::VisitConditionalSelect(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitBitfield(Instruction* instr) {
|
||||
void Disassembler::VisitBitfield(const Instruction* instr) {
|
||||
unsigned s = instr->ImmS();
|
||||
unsigned r = instr->ImmR();
|
||||
unsigned rd_size_minus_1 =
|
||||
@@ -506,7 +506,7 @@ void Disassembler::VisitBitfield(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitExtract(Instruction* instr) {
|
||||
void Disassembler::VisitExtract(const Instruction* instr) {
|
||||
const char *mnemonic = "";
|
||||
const char *form = "'Rd, 'Rn, 'Rm, 'IExtract";
|
||||
|
||||
@@ -527,7 +527,7 @@ void Disassembler::VisitExtract(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitPCRelAddressing(Instruction* instr) {
|
||||
void Disassembler::VisitPCRelAddressing(const Instruction* instr) {
|
||||
switch (instr->Mask(PCRelAddressingMask)) {
|
||||
case ADR: Format(instr, "adr", "'Xd, 'AddrPCRelByte"); break;
|
||||
case ADRP: Format(instr, "adrp", "'Xd, 'AddrPCRelPage"); break;
|
||||
@@ -536,7 +536,7 @@ void Disassembler::VisitPCRelAddressing(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitConditionalBranch(Instruction* instr) {
|
||||
void Disassembler::VisitConditionalBranch(const Instruction* instr) {
|
||||
switch (instr->Mask(ConditionalBranchMask)) {
|
||||
case B_cond: Format(instr, "b.'CBrn", "'BImmCond"); break;
|
||||
default: VIXL_UNREACHABLE();
|
||||
@@ -544,7 +544,8 @@ void Disassembler::VisitConditionalBranch(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitUnconditionalBranchToRegister(Instruction* instr) {
|
||||
void Disassembler::VisitUnconditionalBranchToRegister(
|
||||
const Instruction* instr) {
|
||||
const char *mnemonic = "unimplemented";
|
||||
const char *form = "'Xn";
|
||||
|
||||
@@ -564,7 +565,7 @@ void Disassembler::VisitUnconditionalBranchToRegister(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitUnconditionalBranch(Instruction* instr) {
|
||||
void Disassembler::VisitUnconditionalBranch(const Instruction* instr) {
|
||||
const char *mnemonic = "";
|
||||
const char *form = "'BImmUncn";
|
||||
|
||||
@@ -577,7 +578,7 @@ void Disassembler::VisitUnconditionalBranch(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitDataProcessing1Source(Instruction* instr) {
|
||||
void Disassembler::VisitDataProcessing1Source(const Instruction* instr) {
|
||||
const char *mnemonic = "";
|
||||
const char *form = "'Rd, 'Rn";
|
||||
|
||||
@@ -598,7 +599,7 @@ void Disassembler::VisitDataProcessing1Source(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitDataProcessing2Source(Instruction* instr) {
|
||||
void Disassembler::VisitDataProcessing2Source(const Instruction* instr) {
|
||||
const char *mnemonic = "unimplemented";
|
||||
const char *form = "'Rd, 'Rn, 'Rm";
|
||||
|
||||
@@ -619,7 +620,7 @@ void Disassembler::VisitDataProcessing2Source(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitDataProcessing3Source(Instruction* instr) {
|
||||
void Disassembler::VisitDataProcessing3Source(const Instruction* instr) {
|
||||
bool ra_is_zr = RaIsZROrSP(instr);
|
||||
const char *mnemonic = "";
|
||||
const char *form = "'Xd, 'Wn, 'Wm, 'Xa";
|
||||
@@ -697,7 +698,7 @@ void Disassembler::VisitDataProcessing3Source(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitCompareBranch(Instruction* instr) {
|
||||
void Disassembler::VisitCompareBranch(const Instruction* instr) {
|
||||
const char *mnemonic = "";
|
||||
const char *form = "'Rt, 'BImmCmpa";
|
||||
|
||||
@@ -712,7 +713,7 @@ void Disassembler::VisitCompareBranch(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitTestBranch(Instruction* instr) {
|
||||
void Disassembler::VisitTestBranch(const Instruction* instr) {
|
||||
const char *mnemonic = "";
|
||||
// If the top bit of the immediate is clear, the tested register is
|
||||
// disassembled as Wt, otherwise Xt. As the top bit of the immediate is
|
||||
@@ -729,7 +730,7 @@ void Disassembler::VisitTestBranch(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitMoveWideImmediate(Instruction* instr) {
|
||||
void Disassembler::VisitMoveWideImmediate(const Instruction* instr) {
|
||||
const char *mnemonic = "";
|
||||
const char *form = "'Rd, 'IMoveImm";
|
||||
|
||||
@@ -768,7 +769,7 @@ void Disassembler::VisitMoveWideImmediate(Instruction* instr) {
|
||||
V(LDR_s, "ldr", "'St") \
|
||||
V(LDR_d, "ldr", "'Dt")
|
||||
|
||||
void Disassembler::VisitLoadStorePreIndex(Instruction* instr) {
|
||||
void Disassembler::VisitLoadStorePreIndex(const Instruction* instr) {
|
||||
const char *mnemonic = "unimplemented";
|
||||
const char *form = "(LoadStorePreIndex)";
|
||||
|
||||
@@ -782,7 +783,7 @@ void Disassembler::VisitLoadStorePreIndex(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitLoadStorePostIndex(Instruction* instr) {
|
||||
void Disassembler::VisitLoadStorePostIndex(const Instruction* instr) {
|
||||
const char *mnemonic = "unimplemented";
|
||||
const char *form = "(LoadStorePostIndex)";
|
||||
|
||||
@@ -796,7 +797,7 @@ void Disassembler::VisitLoadStorePostIndex(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitLoadStoreUnsignedOffset(Instruction* instr) {
|
||||
void Disassembler::VisitLoadStoreUnsignedOffset(const Instruction* instr) {
|
||||
const char *mnemonic = "unimplemented";
|
||||
const char *form = "(LoadStoreUnsignedOffset)";
|
||||
|
||||
@@ -811,7 +812,7 @@ void Disassembler::VisitLoadStoreUnsignedOffset(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitLoadStoreRegisterOffset(Instruction* instr) {
|
||||
void Disassembler::VisitLoadStoreRegisterOffset(const Instruction* instr) {
|
||||
const char *mnemonic = "unimplemented";
|
||||
const char *form = "(LoadStoreRegisterOffset)";
|
||||
|
||||
@@ -826,7 +827,7 @@ void Disassembler::VisitLoadStoreRegisterOffset(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitLoadStoreUnscaledOffset(Instruction* instr) {
|
||||
void Disassembler::VisitLoadStoreUnscaledOffset(const Instruction* instr) {
|
||||
const char *mnemonic = "unimplemented";
|
||||
const char *form = "'Wt, ['Xns'ILS]";
|
||||
const char *form_x = "'Xt, ['Xns'ILS]";
|
||||
@@ -857,7 +858,7 @@ void Disassembler::VisitLoadStoreUnscaledOffset(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitLoadLiteral(Instruction* instr) {
|
||||
void Disassembler::VisitLoadLiteral(const Instruction* instr) {
|
||||
const char *mnemonic = "ldr";
|
||||
const char *form = "(LoadLiteral)";
|
||||
|
||||
@@ -866,6 +867,11 @@ void Disassembler::VisitLoadLiteral(Instruction* instr) {
|
||||
case LDR_x_lit: form = "'Xt, 'ILLiteral 'LValue"; break;
|
||||
case LDR_s_lit: form = "'St, 'ILLiteral 'LValue"; break;
|
||||
case LDR_d_lit: form = "'Dt, 'ILLiteral 'LValue"; break;
|
||||
case LDRSW_x_lit: {
|
||||
mnemonic = "ldrsw";
|
||||
form = "'Xt, 'ILLiteral 'LValue";
|
||||
break;
|
||||
}
|
||||
default: mnemonic = "unimplemented";
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
@@ -883,7 +889,7 @@ void Disassembler::VisitLoadLiteral(Instruction* instr) {
|
||||
V(STP_d, "stp", "'Dt, 'Dt2", "8") \
|
||||
V(LDP_d, "ldp", "'Dt, 'Dt2", "8")
|
||||
|
||||
void Disassembler::VisitLoadStorePairPostIndex(Instruction* instr) {
|
||||
void Disassembler::VisitLoadStorePairPostIndex(const Instruction* instr) {
|
||||
const char *mnemonic = "unimplemented";
|
||||
const char *form = "(LoadStorePairPostIndex)";
|
||||
|
||||
@@ -897,7 +903,7 @@ void Disassembler::VisitLoadStorePairPostIndex(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitLoadStorePairPreIndex(Instruction* instr) {
|
||||
void Disassembler::VisitLoadStorePairPreIndex(const Instruction* instr) {
|
||||
const char *mnemonic = "unimplemented";
|
||||
const char *form = "(LoadStorePairPreIndex)";
|
||||
|
||||
@@ -911,7 +917,7 @@ void Disassembler::VisitLoadStorePairPreIndex(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitLoadStorePairOffset(Instruction* instr) {
|
||||
void Disassembler::VisitLoadStorePairOffset(const Instruction* instr) {
|
||||
const char *mnemonic = "unimplemented";
|
||||
const char *form = "(LoadStorePairOffset)";
|
||||
|
||||
@@ -925,7 +931,7 @@ void Disassembler::VisitLoadStorePairOffset(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitLoadStorePairNonTemporal(Instruction* instr) {
|
||||
void Disassembler::VisitLoadStorePairNonTemporal(const Instruction* instr) {
|
||||
const char *mnemonic = "unimplemented";
|
||||
const char *form;
|
||||
|
||||
@@ -944,7 +950,7 @@ void Disassembler::VisitLoadStorePairNonTemporal(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitLoadStoreExclusive(Instruction* instr) {
|
||||
void Disassembler::VisitLoadStoreExclusive(const Instruction* instr) {
|
||||
const char *mnemonic = "unimplemented";
|
||||
const char *form;
|
||||
|
||||
@@ -987,7 +993,7 @@ void Disassembler::VisitLoadStoreExclusive(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitFPCompare(Instruction* instr) {
|
||||
void Disassembler::VisitFPCompare(const Instruction* instr) {
|
||||
const char *mnemonic = "unimplemented";
|
||||
const char *form = "'Fn, 'Fm";
|
||||
const char *form_zero = "'Fn, #0.0";
|
||||
@@ -1003,7 +1009,7 @@ void Disassembler::VisitFPCompare(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitFPConditionalCompare(Instruction* instr) {
|
||||
void Disassembler::VisitFPConditionalCompare(const Instruction* instr) {
|
||||
const char *mnemonic = "unmplemented";
|
||||
const char *form = "'Fn, 'Fm, 'INzcv, 'Cond";
|
||||
|
||||
@@ -1018,7 +1024,7 @@ void Disassembler::VisitFPConditionalCompare(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitFPConditionalSelect(Instruction* instr) {
|
||||
void Disassembler::VisitFPConditionalSelect(const Instruction* instr) {
|
||||
const char *mnemonic = "";
|
||||
const char *form = "'Fd, 'Fn, 'Fm, 'Cond";
|
||||
|
||||
@@ -1031,7 +1037,7 @@ void Disassembler::VisitFPConditionalSelect(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitFPDataProcessing1Source(Instruction* instr) {
|
||||
void Disassembler::VisitFPDataProcessing1Source(const Instruction* instr) {
|
||||
const char *mnemonic = "unimplemented";
|
||||
const char *form = "'Fd, 'Fn";
|
||||
|
||||
@@ -1059,7 +1065,7 @@ void Disassembler::VisitFPDataProcessing1Source(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitFPDataProcessing2Source(Instruction* instr) {
|
||||
void Disassembler::VisitFPDataProcessing2Source(const Instruction* instr) {
|
||||
const char *mnemonic = "";
|
||||
const char *form = "'Fd, 'Fn, 'Fm";
|
||||
|
||||
@@ -1083,7 +1089,7 @@ void Disassembler::VisitFPDataProcessing2Source(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitFPDataProcessing3Source(Instruction* instr) {
|
||||
void Disassembler::VisitFPDataProcessing3Source(const Instruction* instr) {
|
||||
const char *mnemonic = "";
|
||||
const char *form = "'Fd, 'Fn, 'Fm, 'Fa";
|
||||
|
||||
@@ -1102,7 +1108,7 @@ void Disassembler::VisitFPDataProcessing3Source(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitFPImmediate(Instruction* instr) {
|
||||
void Disassembler::VisitFPImmediate(const Instruction* instr) {
|
||||
const char *mnemonic = "";
|
||||
const char *form = "(FPImmediate)";
|
||||
|
||||
@@ -1115,7 +1121,7 @@ void Disassembler::VisitFPImmediate(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitFPIntegerConvert(Instruction* instr) {
|
||||
void Disassembler::VisitFPIntegerConvert(const Instruction* instr) {
|
||||
const char *mnemonic = "unimplemented";
|
||||
const char *form = "(FPIntegerConvert)";
|
||||
const char *form_rf = "'Rd, 'Fn";
|
||||
@@ -1171,7 +1177,7 @@ void Disassembler::VisitFPIntegerConvert(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitFPFixedPointConvert(Instruction* instr) {
|
||||
void Disassembler::VisitFPFixedPointConvert(const Instruction* instr) {
|
||||
const char *mnemonic = "";
|
||||
const char *form = "'Rd, 'Fn, 'IFPFBits";
|
||||
const char *form_fr = "'Fd, 'Rn, 'IFPFBits";
|
||||
@@ -1199,7 +1205,7 @@ void Disassembler::VisitFPFixedPointConvert(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitSystem(Instruction* instr) {
|
||||
void Disassembler::VisitSystem(const Instruction* instr) {
|
||||
// Some system instructions hijack their Op and Cp fields to represent a
|
||||
// range of immediates instead of indicating a different instruction. This
|
||||
// makes the decoding tricky.
|
||||
@@ -1267,7 +1273,7 @@ void Disassembler::VisitSystem(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitException(Instruction* instr) {
|
||||
void Disassembler::VisitException(const Instruction* instr) {
|
||||
const char *mnemonic = "unimplemented";
|
||||
const char *form = "'IDebug";
|
||||
|
||||
@@ -1286,22 +1292,75 @@ void Disassembler::VisitException(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitUnimplemented(Instruction* instr) {
|
||||
void Disassembler::VisitUnimplemented(const Instruction* instr) {
|
||||
Format(instr, "unimplemented", "(Unimplemented)");
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::VisitUnallocated(Instruction* instr) {
|
||||
void Disassembler::VisitUnallocated(const Instruction* instr) {
|
||||
Format(instr, "unallocated", "(Unallocated)");
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::ProcessOutput(Instruction* /*instr*/) {
|
||||
void Disassembler::ProcessOutput(const Instruction* /*instr*/) {
|
||||
// The base disasm does nothing more than disassembling into a buffer.
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::Format(Instruction* instr, const char* mnemonic,
|
||||
void Disassembler::AppendRegisterNameToOutput(const Instruction* instr,
|
||||
const CPURegister& reg) {
|
||||
USE(instr);
|
||||
VIXL_ASSERT(reg.IsValid());
|
||||
char reg_char;
|
||||
|
||||
if (reg.IsRegister()) {
|
||||
reg_char = reg.Is64Bits() ? 'x' : 'w';
|
||||
} else {
|
||||
VIXL_ASSERT(reg.IsFPRegister());
|
||||
reg_char = reg.Is64Bits() ? 'd' : 's';
|
||||
}
|
||||
|
||||
if (reg.IsFPRegister() || !(reg.Aliases(sp) || reg.Aliases(xzr))) {
|
||||
// A normal register: w0 - w30, x0 - x30, s0 - s31, d0 - d31.
|
||||
AppendToOutput("%c%d", reg_char, reg.code());
|
||||
} else if (reg.Aliases(sp)) {
|
||||
// Disassemble w31/x31 as stack pointer wsp/sp.
|
||||
AppendToOutput("%s", reg.Is64Bits() ? "sp" : "wsp");
|
||||
} else {
|
||||
// Disassemble w31/x31 as zero register wzr/xzr.
|
||||
AppendToOutput("%czr", reg_char);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::AppendPCRelativeOffsetToOutput(const Instruction* instr,
|
||||
int64_t offset) {
|
||||
USE(instr);
|
||||
char sign = (offset < 0) ? '-' : '+';
|
||||
AppendToOutput("#%c0x%" PRIx64, sign, std::abs(offset));
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::AppendAddressToOutput(const Instruction* instr,
|
||||
const void* addr) {
|
||||
USE(instr);
|
||||
AppendToOutput("(addr %p)", addr);
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::AppendCodeAddressToOutput(const Instruction* instr,
|
||||
const void* addr) {
|
||||
AppendAddressToOutput(instr, addr);
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::AppendDataAddressToOutput(const Instruction* instr,
|
||||
const void* addr) {
|
||||
AppendAddressToOutput(instr, addr);
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::Format(const Instruction* instr, const char* mnemonic,
|
||||
const char* format) {
|
||||
VIXL_ASSERT(mnemonic != NULL);
|
||||
ResetOutput();
|
||||
@@ -1315,7 +1374,7 @@ void Disassembler::Format(Instruction* instr, const char* mnemonic,
|
||||
}
|
||||
|
||||
|
||||
void Disassembler::Substitute(Instruction* instr, const char* string) {
|
||||
void Disassembler::Substitute(const Instruction* instr, const char* string) {
|
||||
char chr = *string++;
|
||||
while (chr != '\0') {
|
||||
if (chr == '\'') {
|
||||
@@ -1328,7 +1387,8 @@ void Disassembler::Substitute(Instruction* instr, const char* string) {
|
||||
}
|
||||
|
||||
|
||||
int Disassembler::SubstituteField(Instruction* instr, const char* format) {
|
||||
int Disassembler::SubstituteField(const Instruction* instr,
|
||||
const char* format) {
|
||||
switch (format[0]) {
|
||||
case 'R': // Register. X or W, selected by sf bit.
|
||||
case 'F': // FP Register. S or D, selected by type field.
|
||||
@@ -1354,7 +1414,7 @@ int Disassembler::SubstituteField(Instruction* instr, const char* format) {
|
||||
}
|
||||
|
||||
|
||||
int Disassembler::SubstituteRegisterField(Instruction* instr,
|
||||
int Disassembler::SubstituteRegisterField(const Instruction* instr,
|
||||
const char* format) {
|
||||
unsigned reg_num = 0;
|
||||
unsigned field_len = 2;
|
||||
@@ -1381,34 +1441,47 @@ int Disassembler::SubstituteRegisterField(Instruction* instr,
|
||||
field_len = 3;
|
||||
}
|
||||
|
||||
char reg_type;
|
||||
CPURegister::RegisterType reg_type;
|
||||
unsigned reg_size;
|
||||
|
||||
if (format[0] == 'R') {
|
||||
// Register type is R: use sf bit to choose X and W.
|
||||
reg_type = instr->SixtyFourBits() ? 'x' : 'w';
|
||||
reg_type = CPURegister::kRegister;
|
||||
reg_size = instr->SixtyFourBits() ? kXRegSize : kWRegSize;
|
||||
} else if (format[0] == 'F') {
|
||||
// Floating-point register: use type field to choose S or D.
|
||||
reg_type = ((instr->FPType() & 1) == 0) ? 's' : 'd';
|
||||
reg_type = CPURegister::kFPRegister;
|
||||
reg_size = ((instr->FPType() & 1) == 0) ? kSRegSize : kDRegSize;
|
||||
} else {
|
||||
// Register type is specified. Make it lower case.
|
||||
reg_type = format[0] + 0x20;
|
||||
// The register type is specified.
|
||||
switch (format[0]) {
|
||||
case 'W':
|
||||
reg_type = CPURegister::kRegister; reg_size = kWRegSize; break;
|
||||
case 'X':
|
||||
reg_type = CPURegister::kRegister; reg_size = kXRegSize; break;
|
||||
case 'S':
|
||||
reg_type = CPURegister::kFPRegister; reg_size = kSRegSize; break;
|
||||
case 'D':
|
||||
reg_type = CPURegister::kFPRegister; reg_size = kDRegSize; break;
|
||||
default:
|
||||
VIXL_UNREACHABLE();
|
||||
reg_type = CPURegister::kRegister;
|
||||
reg_size = kXRegSize;
|
||||
}
|
||||
}
|
||||
|
||||
if ((reg_num != kZeroRegCode) || (reg_type == 's') || (reg_type == 'd')) {
|
||||
// A normal register: w0 - w30, x0 - x30, s0 - s31, d0 - d31.
|
||||
AppendToOutput("%c%d", reg_type, reg_num);
|
||||
} else if (format[2] == 's') {
|
||||
// Disassemble w31/x31 as stack pointer wsp/sp.
|
||||
AppendToOutput("%s", (reg_type == 'w') ? "wsp" : "sp");
|
||||
} else {
|
||||
// Disassemble w31/x31 as zero register wzr/xzr.
|
||||
AppendToOutput("%czr", reg_type);
|
||||
if ((reg_type == CPURegister::kRegister) &&
|
||||
(reg_num == kZeroRegCode) && (format[2] == 's')) {
|
||||
reg_num = kSPRegInternalCode;
|
||||
}
|
||||
|
||||
AppendRegisterNameToOutput(instr, CPURegister(reg_num, reg_size, reg_type));
|
||||
|
||||
return field_len;
|
||||
}
|
||||
|
||||
|
||||
int Disassembler::SubstituteImmediateField(Instruction* instr,
|
||||
int Disassembler::SubstituteImmediateField(const Instruction* instr,
|
||||
const char* format) {
|
||||
VIXL_ASSERT(format[0] == 'I');
|
||||
|
||||
@@ -1458,8 +1531,7 @@ int Disassembler::SubstituteImmediateField(Instruction* instr,
|
||||
}
|
||||
case 'C': { // ICondB - Immediate Conditional Branch.
|
||||
int64_t offset = instr->ImmCondBranch() << 2;
|
||||
char sign = (offset >= 0) ? '+' : '-';
|
||||
AppendToOutput("#%c0x%" PRIx64, sign, offset);
|
||||
AppendPCRelativeOffsetToOutput(instr, offset);
|
||||
return 6;
|
||||
}
|
||||
case 'A': { // IAddSub.
|
||||
@@ -1522,7 +1594,7 @@ int Disassembler::SubstituteImmediateField(Instruction* instr,
|
||||
}
|
||||
|
||||
|
||||
int Disassembler::SubstituteBitfieldImmediateField(Instruction* instr,
|
||||
int Disassembler::SubstituteBitfieldImmediateField(const Instruction* instr,
|
||||
const char* format) {
|
||||
VIXL_ASSERT((format[0] == 'I') && (format[1] == 'B'));
|
||||
unsigned r = instr->ImmR();
|
||||
@@ -1557,7 +1629,7 @@ int Disassembler::SubstituteBitfieldImmediateField(Instruction* instr,
|
||||
}
|
||||
|
||||
|
||||
int Disassembler::SubstituteLiteralField(Instruction* instr,
|
||||
int Disassembler::SubstituteLiteralField(const Instruction* instr,
|
||||
const char* format) {
|
||||
VIXL_ASSERT(strncmp(format, "LValue", 6) == 0);
|
||||
USE(format);
|
||||
@@ -1565,16 +1637,21 @@ int Disassembler::SubstituteLiteralField(Instruction* instr,
|
||||
switch (instr->Mask(LoadLiteralMask)) {
|
||||
case LDR_w_lit:
|
||||
case LDR_x_lit:
|
||||
case LDRSW_x_lit:
|
||||
case LDR_s_lit:
|
||||
case LDR_d_lit: AppendToOutput("(addr %p)", instr->LiteralAddress()); break;
|
||||
default: VIXL_UNREACHABLE();
|
||||
case LDR_d_lit:
|
||||
AppendDataAddressToOutput(instr, instr->LiteralAddress());
|
||||
break;
|
||||
default:
|
||||
VIXL_UNREACHABLE();
|
||||
}
|
||||
|
||||
return 6;
|
||||
}
|
||||
|
||||
|
||||
int Disassembler::SubstituteShiftField(Instruction* instr, const char* format) {
|
||||
int Disassembler::SubstituteShiftField(const Instruction* instr,
|
||||
const char* format) {
|
||||
VIXL_ASSERT(format[0] == 'H');
|
||||
VIXL_ASSERT(instr->ShiftDP() <= 0x3);
|
||||
|
||||
@@ -1597,7 +1674,7 @@ int Disassembler::SubstituteShiftField(Instruction* instr, const char* format) {
|
||||
}
|
||||
|
||||
|
||||
int Disassembler::SubstituteConditionField(Instruction* instr,
|
||||
int Disassembler::SubstituteConditionField(const Instruction* instr,
|
||||
const char* format) {
|
||||
VIXL_ASSERT(format[0] == 'C');
|
||||
const char* condition_code[] = { "eq", "ne", "hs", "lo",
|
||||
@@ -1618,27 +1695,28 @@ int Disassembler::SubstituteConditionField(Instruction* instr,
|
||||
}
|
||||
|
||||
|
||||
int Disassembler::SubstitutePCRelAddressField(Instruction* instr,
|
||||
int Disassembler::SubstitutePCRelAddressField(const Instruction* instr,
|
||||
const char* format) {
|
||||
VIXL_ASSERT((strcmp(format, "AddrPCRelByte") == 0) || // Used by `adr`.
|
||||
(strcmp(format, "AddrPCRelPage") == 0)); // Used by `adrp`.
|
||||
|
||||
int64_t offset = instr->ImmPCRel();
|
||||
Instruction * base = instr;
|
||||
const Instruction * base = instr;
|
||||
|
||||
if (format[9] == 'P') {
|
||||
offset *= kPageSize;
|
||||
base = AlignDown(base, kPageSize);
|
||||
}
|
||||
|
||||
char sign = (offset < 0) ? '-' : '+';
|
||||
void * target = reinterpret_cast<void *>(base + offset);
|
||||
AppendToOutput("#%c0x%" PRIx64 " (addr %p)", sign, std::abs(offset), target);
|
||||
const void* target = reinterpret_cast<const void*>(base + offset);
|
||||
AppendPCRelativeOffsetToOutput(instr, offset);
|
||||
AppendToOutput(" ");
|
||||
AppendAddressToOutput(instr, target);
|
||||
return 13;
|
||||
}
|
||||
|
||||
|
||||
int Disassembler::SubstituteBranchTargetField(Instruction* instr,
|
||||
int Disassembler::SubstituteBranchTargetField(const Instruction* instr,
|
||||
const char* format) {
|
||||
VIXL_ASSERT(strncmp(format, "BImm", 4) == 0);
|
||||
|
||||
@@ -1655,19 +1733,18 @@ int Disassembler::SubstituteBranchTargetField(Instruction* instr,
|
||||
default: VIXL_UNIMPLEMENTED();
|
||||
}
|
||||
offset <<= kInstructionSizeLog2;
|
||||
char sign = '+';
|
||||
if (offset < 0) {
|
||||
offset = -offset;
|
||||
sign = '-';
|
||||
}
|
||||
const void* target_address = reinterpret_cast<const void*>(instr + offset);
|
||||
VIXL_STATIC_ASSERT(sizeof(*instr) == 1);
|
||||
void * address = reinterpret_cast<void *>(instr + offset);
|
||||
AppendToOutput("#%c0x%" PRIx64 " (addr %p)", sign, offset, address);
|
||||
|
||||
AppendPCRelativeOffsetToOutput(instr, offset);
|
||||
AppendToOutput(" ");
|
||||
AppendCodeAddressToOutput(instr, target_address);
|
||||
|
||||
return 8;
|
||||
}
|
||||
|
||||
|
||||
int Disassembler::SubstituteExtendField(Instruction* instr,
|
||||
int Disassembler::SubstituteExtendField(const Instruction* instr,
|
||||
const char* format) {
|
||||
VIXL_ASSERT(strncmp(format, "Ext", 3) == 0);
|
||||
VIXL_ASSERT(instr->ExtendMode() <= 7);
|
||||
@@ -1694,7 +1771,7 @@ int Disassembler::SubstituteExtendField(Instruction* instr,
|
||||
}
|
||||
|
||||
|
||||
int Disassembler::SubstituteLSRegOffsetField(Instruction* instr,
|
||||
int Disassembler::SubstituteLSRegOffsetField(const Instruction* instr,
|
||||
const char* format) {
|
||||
VIXL_ASSERT(strncmp(format, "Offsetreg", 9) == 0);
|
||||
const char* extend_mode[] = { "undefined", "undefined", "uxtw", "lsl",
|
||||
@@ -1723,7 +1800,7 @@ int Disassembler::SubstituteLSRegOffsetField(Instruction* instr,
|
||||
}
|
||||
|
||||
|
||||
int Disassembler::SubstitutePrefetchField(Instruction* instr,
|
||||
int Disassembler::SubstitutePrefetchField(const Instruction* instr,
|
||||
const char* format) {
|
||||
VIXL_ASSERT(format[0] == 'P');
|
||||
USE(format);
|
||||
@@ -1738,7 +1815,7 @@ int Disassembler::SubstitutePrefetchField(Instruction* instr,
|
||||
return 6;
|
||||
}
|
||||
|
||||
int Disassembler::SubstituteBarrierField(Instruction* instr,
|
||||
int Disassembler::SubstituteBarrierField(const Instruction* instr,
|
||||
const char* format) {
|
||||
VIXL_ASSERT(format[0] == 'M');
|
||||
USE(format);
|
||||
@@ -1770,7 +1847,7 @@ void Disassembler::AppendToOutput(const char* format, ...) {
|
||||
}
|
||||
|
||||
|
||||
void PrintDisassembler::ProcessOutput(Instruction* instr) {
|
||||
void PrintDisassembler::ProcessOutput(const Instruction* instr) {
|
||||
fprintf(stream_, "0x%016" PRIx64 " %08" PRIx32 "\t\t%s\n",
|
||||
reinterpret_cast<uint64_t>(instr),
|
||||
instr->InstructionBits(),
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "utils.h"
|
||||
#include "instructions-a64.h"
|
||||
#include "decoder-a64.h"
|
||||
#include "assembler-a64.h"
|
||||
|
||||
namespace vixl {
|
||||
|
||||
@@ -42,48 +43,83 @@ class Disassembler: public DecoderVisitor {
|
||||
char* GetOutput();
|
||||
|
||||
// Declare all Visitor functions.
|
||||
#define DECLARE(A) void Visit##A(Instruction* instr);
|
||||
#define DECLARE(A) void Visit##A(const Instruction* instr);
|
||||
VISITOR_LIST(DECLARE)
|
||||
#undef DECLARE
|
||||
|
||||
protected:
|
||||
virtual void ProcessOutput(Instruction* instr);
|
||||
virtual void ProcessOutput(const Instruction* instr);
|
||||
|
||||
// Default output functions. The functions below implement a default way of
|
||||
// printing elements in the disassembly. A sub-class can override these to
|
||||
// customize the disassembly output.
|
||||
|
||||
// Prints the name of a register.
|
||||
virtual void AppendRegisterNameToOutput(const Instruction* instr,
|
||||
const CPURegister& reg);
|
||||
|
||||
// Prints a PC-relative offset. This is used for example when disassembling
|
||||
// branches to immediate offsets.
|
||||
virtual void AppendPCRelativeOffsetToOutput(const Instruction* instr,
|
||||
int64_t offset);
|
||||
|
||||
// Prints an address, in the general case. It can be code or data. This is
|
||||
// used for example to print the target address of an ADR instruction.
|
||||
virtual void AppendAddressToOutput(const Instruction* instr,
|
||||
const void* addr);
|
||||
|
||||
// Prints the address of some code.
|
||||
// This is used for example to print the target address of a branch to an
|
||||
// immediate offset.
|
||||
// A sub-class can for example override this method to lookup the address and
|
||||
// print an appropriate name.
|
||||
virtual void AppendCodeAddressToOutput(const Instruction* instr,
|
||||
const void* addr);
|
||||
|
||||
// Prints the address of some data.
|
||||
// This is used for example to print the source address of a load literal
|
||||
// instruction.
|
||||
virtual void AppendDataAddressToOutput(const Instruction* instr,
|
||||
const void* addr);
|
||||
|
||||
private:
|
||||
void Format(Instruction* instr, const char* mnemonic, const char* format);
|
||||
void Substitute(Instruction* instr, const char* string);
|
||||
int SubstituteField(Instruction* instr, const char* format);
|
||||
int SubstituteRegisterField(Instruction* instr, const char* format);
|
||||
int SubstituteImmediateField(Instruction* instr, const char* format);
|
||||
int SubstituteLiteralField(Instruction* instr, const char* format);
|
||||
int SubstituteBitfieldImmediateField(Instruction* instr, const char* format);
|
||||
int SubstituteShiftField(Instruction* instr, const char* format);
|
||||
int SubstituteExtendField(Instruction* instr, const char* format);
|
||||
int SubstituteConditionField(Instruction* instr, const char* format);
|
||||
int SubstitutePCRelAddressField(Instruction* instr, const char* format);
|
||||
int SubstituteBranchTargetField(Instruction* instr, const char* format);
|
||||
int SubstituteLSRegOffsetField(Instruction* instr, const char* format);
|
||||
int SubstitutePrefetchField(Instruction* instr, const char* format);
|
||||
int SubstituteBarrierField(Instruction* instr, const char* format);
|
||||
void Format(
|
||||
const Instruction* instr, const char* mnemonic, const char* format);
|
||||
void Substitute(const Instruction* instr, const char* string);
|
||||
int SubstituteField(const Instruction* instr, const char* format);
|
||||
int SubstituteRegisterField(const Instruction* instr, const char* format);
|
||||
int SubstituteImmediateField(const Instruction* instr, const char* format);
|
||||
int SubstituteLiteralField(const Instruction* instr, const char* format);
|
||||
int SubstituteBitfieldImmediateField(
|
||||
const Instruction* instr, const char* format);
|
||||
int SubstituteShiftField(const Instruction* instr, const char* format);
|
||||
int SubstituteExtendField(const Instruction* instr, const char* format);
|
||||
int SubstituteConditionField(const Instruction* instr, const char* format);
|
||||
int SubstitutePCRelAddressField(const Instruction* instr, const char* format);
|
||||
int SubstituteBranchTargetField(const Instruction* instr, const char* format);
|
||||
int SubstituteLSRegOffsetField(const Instruction* instr, const char* format);
|
||||
int SubstitutePrefetchField(const Instruction* instr, const char* format);
|
||||
int SubstituteBarrierField(const Instruction* instr, const char* format);
|
||||
|
||||
inline bool RdIsZROrSP(Instruction* instr) const {
|
||||
inline bool RdIsZROrSP(const Instruction* instr) const {
|
||||
return (instr->Rd() == kZeroRegCode);
|
||||
}
|
||||
|
||||
inline bool RnIsZROrSP(Instruction* instr) const {
|
||||
inline bool RnIsZROrSP(const Instruction* instr) const {
|
||||
return (instr->Rn() == kZeroRegCode);
|
||||
}
|
||||
|
||||
inline bool RmIsZROrSP(Instruction* instr) const {
|
||||
inline bool RmIsZROrSP(const Instruction* instr) const {
|
||||
return (instr->Rm() == kZeroRegCode);
|
||||
}
|
||||
|
||||
inline bool RaIsZROrSP(Instruction* instr) const {
|
||||
inline bool RaIsZROrSP(const Instruction* instr) const {
|
||||
return (instr->Ra() == kZeroRegCode);
|
||||
}
|
||||
|
||||
bool IsMovzMovnImm(unsigned reg_size, uint64_t value);
|
||||
|
||||
protected:
|
||||
void ResetOutput();
|
||||
void AppendToOutput(const char* string, ...) PRINTF_CHECK(2, 3);
|
||||
|
||||
@@ -97,10 +133,10 @@ class Disassembler: public DecoderVisitor {
|
||||
class PrintDisassembler: public Disassembler {
|
||||
public:
|
||||
explicit PrintDisassembler(FILE* stream) : stream_(stream) { }
|
||||
~PrintDisassembler() { }
|
||||
virtual ~PrintDisassembler() { }
|
||||
|
||||
protected:
|
||||
virtual void ProcessOutput(Instruction* instr);
|
||||
virtual void ProcessOutput(const Instruction* instr);
|
||||
|
||||
private:
|
||||
FILE *stream_;
|
||||
|
||||
@@ -57,7 +57,7 @@ static uint64_t RepeatBitsAcrossReg(unsigned reg_size,
|
||||
// Logical immediates can't encode zero, so a return value of zero is used to
|
||||
// indicate a failure case. Specifically, where the constraints on imm_s are
|
||||
// not met.
|
||||
uint64_t Instruction::ImmLogical() {
|
||||
uint64_t Instruction::ImmLogical() const {
|
||||
unsigned reg_size = SixtyFourBits() ? kXRegSize : kWRegSize;
|
||||
int64_t n = BitN();
|
||||
int64_t imm_s = ImmSetBits();
|
||||
@@ -108,7 +108,7 @@ uint64_t Instruction::ImmLogical() {
|
||||
}
|
||||
|
||||
|
||||
float Instruction::ImmFP32() {
|
||||
float Instruction::ImmFP32() const {
|
||||
// ImmFP: abcdefgh (8 bits)
|
||||
// Single: aBbb.bbbc.defg.h000.0000.0000.0000.0000 (32 bits)
|
||||
// where B is b ^ 1
|
||||
@@ -122,7 +122,7 @@ float Instruction::ImmFP32() {
|
||||
}
|
||||
|
||||
|
||||
double Instruction::ImmFP64() {
|
||||
double Instruction::ImmFP64() const {
|
||||
// ImmFP: abcdefgh (8 bits)
|
||||
// Double: aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000
|
||||
// 0000.0000.0000.0000.0000.0000.0000.0000 (64 bits)
|
||||
@@ -148,8 +148,8 @@ LSDataSize CalcLSPairDataSize(LoadStorePairOp op) {
|
||||
}
|
||||
|
||||
|
||||
Instruction* Instruction::ImmPCOffsetTarget() {
|
||||
Instruction * base = this;
|
||||
const Instruction* Instruction::ImmPCOffsetTarget() const {
|
||||
const Instruction * base = this;
|
||||
ptrdiff_t offset;
|
||||
if (IsPCRelAddressing()) {
|
||||
// ADR and ADRP.
|
||||
@@ -182,7 +182,7 @@ inline int Instruction::ImmBranch() const {
|
||||
}
|
||||
|
||||
|
||||
void Instruction::SetImmPCOffsetTarget(Instruction* target) {
|
||||
void Instruction::SetImmPCOffsetTarget(const Instruction* target) {
|
||||
if (IsPCRelAddressing()) {
|
||||
SetPCRelImmTarget(target);
|
||||
} else {
|
||||
@@ -191,7 +191,7 @@ void Instruction::SetImmPCOffsetTarget(Instruction* target) {
|
||||
}
|
||||
|
||||
|
||||
void Instruction::SetPCRelImmTarget(Instruction* target) {
|
||||
void Instruction::SetPCRelImmTarget(const Instruction* target) {
|
||||
int32_t imm21;
|
||||
if ((Mask(PCRelAddressingMask) == ADR)) {
|
||||
imm21 = target - this;
|
||||
@@ -207,7 +207,7 @@ void Instruction::SetPCRelImmTarget(Instruction* target) {
|
||||
}
|
||||
|
||||
|
||||
void Instruction::SetBranchImmTarget(Instruction* target) {
|
||||
void Instruction::SetBranchImmTarget(const Instruction* target) {
|
||||
VIXL_ASSERT(((target - this) & 3) == 0);
|
||||
Instr branch_imm = 0;
|
||||
uint32_t imm_mask = 0;
|
||||
@@ -239,9 +239,9 @@ void Instruction::SetBranchImmTarget(Instruction* target) {
|
||||
}
|
||||
|
||||
|
||||
void Instruction::SetImmLLiteral(Instruction* source) {
|
||||
VIXL_ASSERT(((source - this) & 3) == 0);
|
||||
int offset = (source - this) >> kLiteralEntrySizeLog2;
|
||||
void Instruction::SetImmLLiteral(const Instruction* source) {
|
||||
VIXL_ASSERT(IsWordAligned(source));
|
||||
ptrdiff_t offset = (source - this) >> kLiteralEntrySizeLog2;
|
||||
Instr imm = Assembler::ImmLLiteral(offset);
|
||||
Instr mask = ImmLLiteral_mask;
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ const unsigned kMaxLoadLiteralRange = 1 * MBytes;
|
||||
// This is the nominal page size (as used by the adrp instruction); the actual
|
||||
// size of the memory pages allocated by the kernel is likely to differ.
|
||||
const unsigned kPageSize = 4 * KBytes;
|
||||
const unsigned kPageSizeLog2 = 12;
|
||||
|
||||
const unsigned kWRegSize = 32;
|
||||
const unsigned kWRegSizeLog2 = 5;
|
||||
@@ -95,30 +96,6 @@ const unsigned kDoubleExponentBits = 11;
|
||||
const unsigned kFloatMantissaBits = 23;
|
||||
const unsigned kFloatExponentBits = 8;
|
||||
|
||||
const float kFP32PositiveInfinity = rawbits_to_float(0x7f800000);
|
||||
const float kFP32NegativeInfinity = rawbits_to_float(0xff800000);
|
||||
const double kFP64PositiveInfinity =
|
||||
rawbits_to_double(UINT64_C(0x7ff0000000000000));
|
||||
const double kFP64NegativeInfinity =
|
||||
rawbits_to_double(UINT64_C(0xfff0000000000000));
|
||||
|
||||
// This value is a signalling NaN as both a double and as a float (taking the
|
||||
// least-significant word).
|
||||
static const double kFP64SignallingNaN =
|
||||
rawbits_to_double(UINT64_C(0x7ff000007f800001));
|
||||
static const float kFP32SignallingNaN = rawbits_to_float(0x7f800001);
|
||||
|
||||
// A similar value, but as a quiet NaN.
|
||||
static const double kFP64QuietNaN =
|
||||
rawbits_to_double(UINT64_C(0x7ff800007fc00001));
|
||||
static const float kFP32QuietNaN = rawbits_to_float(0x7fc00001);
|
||||
|
||||
// The default NaN values (for FPCR.DN=1).
|
||||
static const double kFP64DefaultNaN =
|
||||
rawbits_to_double(UINT64_C(0x7ff8000000000000));
|
||||
static const float kFP32DefaultNaN = rawbits_to_float(0x7fc00000);
|
||||
|
||||
|
||||
enum LSDataSize {
|
||||
LSByte = 0,
|
||||
LSHalfword = 1,
|
||||
@@ -201,9 +178,9 @@ class Instruction {
|
||||
return signed_bitextract_32(width-1, 0, offset);
|
||||
}
|
||||
|
||||
uint64_t ImmLogical();
|
||||
float ImmFP32();
|
||||
double ImmFP64();
|
||||
uint64_t ImmLogical() const;
|
||||
float ImmFP32() const;
|
||||
double ImmFP64() const;
|
||||
|
||||
inline LSDataSize SizeLSPair() const {
|
||||
return CalcLSPairDataSize(
|
||||
@@ -311,46 +288,49 @@ class Instruction {
|
||||
|
||||
// Find the target of this instruction. 'this' may be a branch or a
|
||||
// PC-relative addressing instruction.
|
||||
Instruction* ImmPCOffsetTarget();
|
||||
const Instruction* ImmPCOffsetTarget() const;
|
||||
|
||||
// Patch a PC-relative offset to refer to 'target'. 'this' may be a branch or
|
||||
// a PC-relative addressing instruction.
|
||||
void SetImmPCOffsetTarget(Instruction* target);
|
||||
void SetImmPCOffsetTarget(const Instruction* target);
|
||||
// Patch a literal load instruction to load from 'source'.
|
||||
void SetImmLLiteral(Instruction* source);
|
||||
void SetImmLLiteral(const Instruction* source);
|
||||
|
||||
inline uint8_t* LiteralAddress() {
|
||||
inline uint8_t* LiteralAddress() const {
|
||||
int offset = ImmLLiteral() << kLiteralEntrySizeLog2;
|
||||
return reinterpret_cast<uint8_t*>(this) + offset;
|
||||
const uint8_t* address = reinterpret_cast<const uint8_t*>(this) + offset;
|
||||
// Note that the result is safely mutable only if the backing buffer is
|
||||
// safely mutable.
|
||||
return const_cast<uint8_t*>(address);
|
||||
}
|
||||
|
||||
inline uint32_t Literal32() {
|
||||
inline uint32_t Literal32() const {
|
||||
uint32_t literal;
|
||||
memcpy(&literal, LiteralAddress(), sizeof(literal));
|
||||
|
||||
return literal;
|
||||
}
|
||||
|
||||
inline uint64_t Literal64() {
|
||||
inline uint64_t Literal64() const {
|
||||
uint64_t literal;
|
||||
memcpy(&literal, LiteralAddress(), sizeof(literal));
|
||||
|
||||
return literal;
|
||||
}
|
||||
|
||||
inline float LiteralFP32() {
|
||||
inline float LiteralFP32() const {
|
||||
return rawbits_to_float(Literal32());
|
||||
}
|
||||
|
||||
inline double LiteralFP64() {
|
||||
inline double LiteralFP64() const {
|
||||
return rawbits_to_double(Literal64());
|
||||
}
|
||||
|
||||
inline Instruction* NextInstruction() {
|
||||
inline const Instruction* NextInstruction() const {
|
||||
return this + kInstructionSize;
|
||||
}
|
||||
|
||||
inline Instruction* InstructionAtOffset(int64_t offset) {
|
||||
inline const Instruction* InstructionAtOffset(int64_t offset) const {
|
||||
VIXL_ASSERT(IsWordAligned(this + offset));
|
||||
return this + offset;
|
||||
}
|
||||
@@ -359,11 +339,15 @@ class Instruction {
|
||||
return reinterpret_cast<Instruction*>(src);
|
||||
}
|
||||
|
||||
template<typename T> static inline const Instruction* CastConst(T src) {
|
||||
return reinterpret_cast<const Instruction*>(src);
|
||||
}
|
||||
|
||||
private:
|
||||
inline int ImmBranch() const;
|
||||
|
||||
void SetPCRelImmTarget(Instruction* target);
|
||||
void SetBranchImmTarget(Instruction* target);
|
||||
void SetPCRelImmTarget(const Instruction* target);
|
||||
void SetBranchImmTarget(const Instruction* target);
|
||||
};
|
||||
} // namespace vixl
|
||||
|
||||
|
||||
113
disas/libvixl/code-buffer.h
Normal file
113
disas/libvixl/code-buffer.h
Normal file
@@ -0,0 +1,113 @@
|
||||
// Copyright 2014, ARM Limited
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * 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.
|
||||
// * Neither the name of ARM Limited 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 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.
|
||||
|
||||
#ifndef VIXL_CODE_BUFFER_H
|
||||
#define VIXL_CODE_BUFFER_H
|
||||
|
||||
#include <string.h>
|
||||
#include "globals.h"
|
||||
|
||||
namespace vixl {
|
||||
|
||||
class CodeBuffer {
|
||||
public:
|
||||
explicit CodeBuffer(size_t capacity = 4 * KBytes);
|
||||
CodeBuffer(void* buffer, size_t capacity);
|
||||
~CodeBuffer();
|
||||
|
||||
void Reset();
|
||||
|
||||
ptrdiff_t OffsetFrom(ptrdiff_t offset) const {
|
||||
ptrdiff_t cursor_offset = cursor_ - buffer_;
|
||||
VIXL_ASSERT((offset >= 0) && (offset <= cursor_offset));
|
||||
return cursor_offset - offset;
|
||||
}
|
||||
|
||||
ptrdiff_t CursorOffset() const {
|
||||
return OffsetFrom(0);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T GetOffsetAddress(ptrdiff_t offset) const {
|
||||
VIXL_ASSERT((offset >= 0) && (offset <= (cursor_ - buffer_)));
|
||||
return reinterpret_cast<T>(buffer_ + offset);
|
||||
}
|
||||
|
||||
size_t RemainingBytes() const {
|
||||
VIXL_ASSERT((cursor_ >= buffer_) && (cursor_ <= (buffer_ + capacity_)));
|
||||
return (buffer_ + capacity_) - cursor_;
|
||||
}
|
||||
|
||||
// A code buffer can emit:
|
||||
// * 32-bit data: instruction and constant.
|
||||
// * 64-bit data: constant.
|
||||
// * string: debug info.
|
||||
void Emit32(uint32_t data) { Emit(data); }
|
||||
|
||||
void Emit64(uint64_t data) { Emit(data); }
|
||||
|
||||
void EmitString(const char* string);
|
||||
|
||||
// Align to kInstructionSize.
|
||||
void Align();
|
||||
|
||||
size_t capacity() const { return capacity_; }
|
||||
|
||||
bool IsManaged() const { return managed_; }
|
||||
|
||||
void Grow(size_t new_capacity);
|
||||
|
||||
bool IsDirty() const { return dirty_; }
|
||||
|
||||
void SetClean() { dirty_ = false; }
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
void Emit(T value) {
|
||||
VIXL_ASSERT(RemainingBytes() >= sizeof(value));
|
||||
dirty_ = true;
|
||||
memcpy(cursor_, &value, sizeof(value));
|
||||
cursor_ += sizeof(value);
|
||||
}
|
||||
|
||||
// Backing store of the buffer.
|
||||
byte* buffer_;
|
||||
// If true the backing store is allocated and deallocated by the buffer. The
|
||||
// backing store can then grow on demand. If false the backing store is
|
||||
// provided by the user and cannot be resized internally.
|
||||
bool managed_;
|
||||
// Pointer to the next location to be written.
|
||||
byte* cursor_;
|
||||
// True if there has been any write since the buffer was created or cleaned.
|
||||
bool dirty_;
|
||||
// Capacity in bytes of the backing store.
|
||||
size_t capacity_;
|
||||
};
|
||||
|
||||
} // namespace vixl
|
||||
|
||||
#endif // VIXL_CODE_BUFFER_H
|
||||
|
||||
@@ -134,4 +134,5 @@ uint64_t LowestSetBit(uint64_t value) {
|
||||
bool IsPowerOf2(int64_t value) {
|
||||
return (value != 0) && ((value & (value - 1)) == 0);
|
||||
}
|
||||
|
||||
} // namespace vixl
|
||||
|
||||
@@ -171,7 +171,7 @@ bool IsPowerOf2(int64_t value);
|
||||
template<typename T>
|
||||
bool IsWordAligned(T pointer) {
|
||||
VIXL_ASSERT(sizeof(pointer) == sizeof(intptr_t)); // NOLINT(runtime/sizeof)
|
||||
return (reinterpret_cast<intptr_t>(pointer) & 3) == 0;
|
||||
return ((intptr_t)(pointer) & 3) == 0;
|
||||
}
|
||||
|
||||
// Increment a pointer until it has the specified alignment.
|
||||
@@ -204,7 +204,6 @@ T AlignDown(T pointer, size_t alignment) {
|
||||
return (T)(pointer_raw - align_step);
|
||||
}
|
||||
|
||||
|
||||
} // namespace vixl
|
||||
|
||||
#endif // VIXL_UTILS_H
|
||||
|
||||
211
disas/mips.c
211
disas/mips.c
@@ -119,6 +119,8 @@ see <http://www.gnu.org/licenses/>. */
|
||||
#define OP_SH_IMMEDIATE 0
|
||||
#define OP_MASK_DELTA 0xffff
|
||||
#define OP_SH_DELTA 0
|
||||
#define OP_MASK_DELTA_R6 0x1ff
|
||||
#define OP_SH_DELTA_R6 7
|
||||
#define OP_MASK_FUNCT 0x3f
|
||||
#define OP_SH_FUNCT 0
|
||||
#define OP_MASK_SPEC 0x3f
|
||||
@@ -405,6 +407,12 @@ struct mips_opcode
|
||||
"+3" UDI immediate bits 6-20
|
||||
"+4" UDI immediate bits 6-25
|
||||
|
||||
R6 immediates/displacements :
|
||||
(adding suffix to 'o' to avoid adding new characters)
|
||||
"+o" 9 bits immediate/displacement (shift = 7)
|
||||
"+o1" 18 bits immediate/displacement (shift = 0)
|
||||
"+o2" 19 bits immediate/displacement (shift = 0)
|
||||
|
||||
Other:
|
||||
"()" parens surrounding optional value
|
||||
"," separates operands
|
||||
@@ -521,6 +529,8 @@ struct mips_opcode
|
||||
#define INSN_ISA64 0x00000040
|
||||
#define INSN_ISA32R2 0x00000080
|
||||
#define INSN_ISA64R2 0x00000100
|
||||
#define INSN_ISA32R6 0x00000200
|
||||
#define INSN_ISA64R6 0x00000400
|
||||
|
||||
/* Masks used for MIPS-defined ASEs. */
|
||||
#define INSN_ASE_MASK 0x0000f000
|
||||
@@ -585,6 +595,8 @@ struct mips_opcode
|
||||
#define ISA_MIPS32R2 (ISA_MIPS32 | INSN_ISA32R2)
|
||||
#define ISA_MIPS64R2 (ISA_MIPS64 | INSN_ISA32R2 | INSN_ISA64R2)
|
||||
|
||||
#define ISA_MIPS32R6 (ISA_MIPS32R2 | INSN_ISA32R6)
|
||||
#define ISA_MIPS64R6 (ISA_MIPS64R2 | INSN_ISA32R6 | INSN_ISA64R6)
|
||||
|
||||
/* CPU defines, use instead of hardcoding processor number. Keep this
|
||||
in sync with bfd/archures.c in order for machine selection to work. */
|
||||
@@ -1121,6 +1133,8 @@ extern const int bfd_mips16_num_opcodes;
|
||||
#define I64 INSN_ISA64
|
||||
#define I33 INSN_ISA32R2
|
||||
#define I65 INSN_ISA64R2
|
||||
#define I32R6 INSN_ISA32R6
|
||||
#define I64R6 INSN_ISA64R6
|
||||
|
||||
/* MIPS64 MIPS-3D ASE support. */
|
||||
#define I16 INSN_MIPS16
|
||||
@@ -1209,6 +1223,146 @@ const struct mips_opcode mips_builtin_opcodes[] =
|
||||
them first. The assemblers uses a hash table based on the
|
||||
instruction name anyhow. */
|
||||
/* name, args, match, mask, pinfo, membership */
|
||||
{"lwpc", "s,+o2", 0xec080000, 0xfc180000, WR_d, 0, I32R6},
|
||||
{"lwupc", "s,+o2", 0xec100000, 0xfc180000, WR_d, 0, I64R6},
|
||||
{"ldpc", "s,+o1", 0xec180000, 0xfc1c0000, WR_d, 0, I64R6},
|
||||
{"addiupc", "s,+o2", 0xec000000, 0xfc180000, WR_d, 0, I32R6},
|
||||
{"auipc", "s,u", 0xec1e0000, 0xfc1f0000, WR_d, 0, I32R6},
|
||||
{"aluipc", "s,u", 0xec1f0000, 0xfc1f0000, WR_d, 0, I32R6},
|
||||
{"daui", "s,t,u", 0x74000000, 0xfc000000, RD_s|WR_t, 0, I64R6},
|
||||
{"dahi", "s,u", 0x04060000, 0xfc1f0000, RD_s, 0, I64R6},
|
||||
{"dati", "s,u", 0x041e0000, 0xfc1f0000, RD_s, 0, I64R6},
|
||||
{"lsa", "d,s,t", 0x00000005, 0xfc00073f, WR_d|RD_s|RD_t, 0, I32R6},
|
||||
{"dlsa", "d,s,t", 0x00000015, 0xfc00073f, WR_d|RD_s|RD_t, 0, I64R6},
|
||||
{"clz", "U,s", 0x00000050, 0xfc1f07ff, WR_d|RD_s, 0, I32R6},
|
||||
{"clo", "U,s", 0x00000051, 0xfc1f07ff, WR_d|RD_s, 0, I32R6},
|
||||
{"dclz", "U,s", 0x00000052, 0xfc1f07ff, WR_d|RD_s, 0, I64R6},
|
||||
{"dclo", "U,s", 0x00000053, 0xfc1f07ff, WR_d|RD_s, 0, I64R6},
|
||||
{"sdbbp", "B", 0x0000000e, 0xfc00003f, TRAP, 0, I32R6},
|
||||
{"mul", "d,s,t", 0x00000098, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6},
|
||||
{"muh", "d,s,t", 0x000000d8, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6},
|
||||
{"mulu", "d,s,t", 0x00000099, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6},
|
||||
{"muhu", "d,s,t", 0x000000d9, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6},
|
||||
{"div", "d,s,t", 0x0000009a, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6},
|
||||
{"mod", "d,s,t", 0x000000da, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6},
|
||||
{"divu", "d,s,t", 0x0000009b, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6},
|
||||
{"modu", "d,s,t", 0x000000db, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6},
|
||||
{"dmul", "d,s,t", 0x0000009c, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I64R6},
|
||||
{"dmuh", "d,s,t", 0x000000dc, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I64R6},
|
||||
{"dmulu", "d,s,t", 0x0000009d, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I64R6},
|
||||
{"dmuhu", "d,s,t", 0x000000dd, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I64R6},
|
||||
{"ddiv", "d,s,t", 0x0000009e, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I64R6},
|
||||
{"dmod", "d,s,t", 0x000000de, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I64R6},
|
||||
{"ddivu", "d,s,t", 0x0000009f, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I64R6},
|
||||
{"dmodu", "d,s,t", 0x000000df, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I64R6},
|
||||
{"ll", "t,o(b)", 0x7c000036, 0xfc00007f, LDD|RD_b|WR_t, 0, I32R6},
|
||||
{"sc", "t,o(b)", 0x7c000026, 0xfc00007f, LDD|RD_b|WR_t, 0, I32R6},
|
||||
{"lld", "t,o(b)", 0x7c000037, 0xfc00007f, LDD|RD_b|WR_t, 0, I64R6},
|
||||
{"scd", "t,o(b)", 0x7c000027, 0xfc00007f, LDD|RD_b|WR_t, 0, I64R6},
|
||||
{"pref", "h,o(b)", 0x7c000035, 0xfc00007f, RD_b, 0, I32R6},
|
||||
{"cache", "k,o(b)", 0x7c000025, 0xfc00007f, RD_b, 0, I32R6},
|
||||
{"seleqz", "d,v,t", 0x00000035, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6},
|
||||
{"selnez", "d,v,t", 0x00000037, 0xfc0007ff, WR_d|RD_s|RD_t, 0, I32R6},
|
||||
{"maddf.s", "D,S,T", 0x46000018, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6},
|
||||
{"maddf.d", "D,S,T", 0x46200018, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6},
|
||||
{"msubf.s", "D,S,T", 0x46000019, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6},
|
||||
{"msubf.d", "D,S,T", 0x46200019, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6},
|
||||
{"max.s", "D,S,T", 0x4600001e, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6},
|
||||
{"max.d", "D,S,T", 0x4620001e, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6},
|
||||
{"maxa.s", "D,S,T", 0x4600001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6},
|
||||
{"maxa.d", "D,S,T", 0x4620001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6},
|
||||
{"rint.s", "D,S", 0x4600001a, 0xffff003f, WR_D|RD_S|FP_S, 0, I32R6},
|
||||
{"rint.d", "D,S", 0x4620001a, 0xffff003f, WR_D|RD_S|FP_D, 0, I32R6},
|
||||
{"class.s", "D,S", 0x4600001b, 0xffff003f, WR_D|RD_S|FP_S, 0, I32R6},
|
||||
{"class.d", "D,S", 0x4620001b, 0xffff003f, WR_D|RD_S|FP_D, 0, I32R6},
|
||||
{"min.s", "D,S,T", 0x4600001c, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6},
|
||||
{"min.d", "D,S,T", 0x4620001c, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6},
|
||||
{"mina.s", "D,S,T", 0x4600001d, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6},
|
||||
{"mina.d", "D,S,T", 0x4620001d, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6},
|
||||
{"sel.s", "D,S,T", 0x46000010, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6},
|
||||
{"sel.d", "D,S,T", 0x46200010, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6},
|
||||
{"seleqz.s", "D,S,T", 0x46000014, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6},
|
||||
{"seleqz.d", "D,S,T", 0x46200014, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6},
|
||||
{"selnez.s", "D,S,T", 0x46000017, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, 0, I32R6},
|
||||
{"selnez.d", "D,S,T", 0x46200017, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, 0, I32R6},
|
||||
{"align", "d,v,t", 0x7c000220, 0xfc00073f, WR_d|RD_s|RD_t, 0, I32R6},
|
||||
{"dalign", "d,v,t", 0x7c000224, 0xfc00063f, WR_d|RD_s|RD_t, 0, I64R6},
|
||||
{"bitswap", "d,w", 0x7c000020, 0xffe007ff, WR_d|RD_t, 0, I32R6},
|
||||
{"dbitswap","d,w", 0x7c000024, 0xffe007ff, WR_d|RD_t, 0, I64R6},
|
||||
{"balc", "+p", 0xe8000000, 0xfc000000, UBD|WR_31, 0, I32R6},
|
||||
{"bc", "+p", 0xc8000000, 0xfc000000, UBD|WR_31, 0, I32R6},
|
||||
{"jic", "t,o", 0xd8000000, 0xffe00000, UBD|RD_t, 0, I32R6},
|
||||
{"beqzc", "s,+p", 0xd8000000, 0xfc000000, CBD|RD_s, 0, I32R6},
|
||||
{"jialc", "t,o", 0xf8000000, 0xffe00000, UBD|RD_t, 0, I32R6},
|
||||
{"bnezc", "s,+p", 0xf8000000, 0xfc000000, CBD|RD_s, 0, I32R6},
|
||||
{"beqzalc", "s,t,p", 0x20000000, 0xffe00000, CBD|RD_s|RD_t, 0, I32R6},
|
||||
{"bovc", "s,t,p", 0x20000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6},
|
||||
{"beqc", "s,t,p", 0x20000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6},
|
||||
{"bnezalc", "s,t,p", 0x60000000, 0xffe00000, CBD|RD_s|RD_t, 0, I32R6},
|
||||
{"bnvc", "s,t,p", 0x60000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6},
|
||||
{"bnec", "s,t,p", 0x60000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6},
|
||||
{"blezc", "s,t,p", 0x58000000, 0xffe00000, CBD|RD_s|RD_t, 0, I32R6},
|
||||
{"bgezc", "s,t,p", 0x58000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6},
|
||||
{"bgec", "s,t,p", 0x58000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6},
|
||||
{"bgtzc", "s,t,p", 0x5c000000, 0xffe00000, CBD|RD_s|RD_t, 0, I32R6},
|
||||
{"bltzc", "s,t,p", 0x5c000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6},
|
||||
{"bltc", "s,t,p", 0x5c000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6},
|
||||
{"blezalc", "s,t,p", 0x18000000, 0xffe00000, CBD|RD_s|RD_t, 0, I32R6},
|
||||
{"bgezalc", "s,t,p", 0x18000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6},
|
||||
{"bgeuc", "s,t,p", 0x18000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6},
|
||||
{"bgtzalc", "s,t,p", 0x1c000000, 0xffe00000, CBD|RD_s|RD_t, 0, I32R6},
|
||||
{"bltzalc", "s,t,p", 0x1c000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6},
|
||||
{"bltuc", "s,t,p", 0x1c000000, 0xfc000000, CBD|RD_s|RD_t, 0, I32R6},
|
||||
{"nal", "p", 0x04100000, 0xffff0000, WR_31, 0, I32R6},
|
||||
{"bal", "p", 0x04110000, 0xffff0000, UBD|WR_31, 0, I32R6},
|
||||
{"bc1eqz", "T,p", 0x45200000, 0xffe00000, CBD|RD_T|FP_S|FP_D, 0, I32R6},
|
||||
{"bc1nez", "T,p", 0x45a00000, 0xffe00000, CBD|RD_T|FP_S|FP_D, 0, I32R6},
|
||||
{"bc2eqz", "E,p", 0x49200000, 0xffe00000, CBD|RD_C2, 0, I32R6},
|
||||
{"bc2nez", "E,p", 0x49a00000, 0xffe00000, CBD|RD_C2, 0, I32R6},
|
||||
{"cmp.af.s", "D,S,T", 0x46800000, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
|
||||
{"cmp.un.s", "D,S,T", 0x46800001, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
|
||||
{"cmp.eq.s", "D,S,T", 0x46800002, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
|
||||
{"cmp.ueq.s", "D,S,T", 0x46800003, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
|
||||
{"cmp.lt.s", "D,S,T", 0x46800004, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
|
||||
{"cmp.ult.s", "D,S,T", 0x46800005, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
|
||||
{"cmp.le.s", "D,S,T", 0x46800006, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
|
||||
{"cmp.ule.s", "D,S,T", 0x46800007, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
|
||||
{"cmp.saf.s", "D,S,T", 0x46800008, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
|
||||
{"cmp.sun.s", "D,S,T", 0x46800009, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
|
||||
{"cmp.seq.s", "D,S,T", 0x4680000a, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
|
||||
{"cmp.sueq.s", "D,S,T", 0x4680000b, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
|
||||
{"cmp.slt.s", "D,S,T", 0x4680000c, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
|
||||
{"cmp.sult.s", "D,S,T", 0x4680000d, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
|
||||
{"cmp.sle.s", "D,S,T", 0x4680000e, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
|
||||
{"cmp.sule.s", "D,S,T", 0x4680000f, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
|
||||
{"cmp.or.s", "D,S,T", 0x46800011, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
|
||||
{"cmp.une.s", "D,S,T", 0x46800012, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
|
||||
{"cmp.ne.s", "D,S,T", 0x46800013, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
|
||||
{"cmp.sor.s", "D,S,T", 0x46800019, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
|
||||
{"cmp.sune.s", "D,S,T", 0x4680001a, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
|
||||
{"cmp.sne.s", "D,S,T", 0x4680001b, 0xffe0003f, RD_S|RD_T|WR_D|FP_S, 0, I32R6},
|
||||
{"cmp.af.d", "D,S,T", 0x46a00000, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
|
||||
{"cmp.un.d", "D,S,T", 0x46a00001, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
|
||||
{"cmp.eq.d", "D,S,T", 0x46a00002, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
|
||||
{"cmp.ueq.d", "D,S,T", 0x46a00003, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
|
||||
{"cmp.lt.d", "D,S,T", 0x46a00004, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
|
||||
{"cmp.ult.d", "D,S,T", 0x46a00005, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
|
||||
{"cmp.le.d", "D,S,T", 0x46a00006, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
|
||||
{"cmp.ule.d", "D,S,T", 0x46a00007, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
|
||||
{"cmp.saf.d", "D,S,T", 0x46a00008, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
|
||||
{"cmp.sun.d", "D,S,T", 0x46a00009, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
|
||||
{"cmp.seq.d", "D,S,T", 0x46a0000a, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
|
||||
{"cmp.sueq.d", "D,S,T", 0x46a0000b, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
|
||||
{"cmp.slt.d", "D,S,T", 0x46a0000c, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
|
||||
{"cmp.sult.d", "D,S,T", 0x46a0000d, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
|
||||
{"cmp.sle.d", "D,S,T", 0x46a0000e, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
|
||||
{"cmp.sule.d", "D,S,T", 0x46a0000f, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
|
||||
{"cmp.or.d", "D,S,T", 0x46a00011, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
|
||||
{"cmp.une.d", "D,S,T", 0x46a00012, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
|
||||
{"cmp.ne.d", "D,S,T", 0x46a00013, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
|
||||
{"cmp.sor.d", "D,S,T", 0x46a00019, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
|
||||
{"cmp.sune.d", "D,S,T", 0x46a0001a, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
|
||||
{"cmp.sne.d", "D,S,T", 0x46a0001b, 0xffe0003f, RD_S|RD_T|WR_D|FP_D, 0, I32R6},
|
||||
{"pref", "k,o(b)", 0xcc000000, 0xfc000000, RD_b, 0, I4|I32|G3 },
|
||||
{"prefx", "h,t(b)", 0x4c00000f, 0xfc0007ff, RD_b|RD_t, 0, I4|I33 },
|
||||
{"nop", "", 0x00000000, 0xffffffff, 0, INSN2_ALIAS, I1 }, /* sll */
|
||||
@@ -1753,6 +1907,7 @@ const struct mips_opcode mips_builtin_opcodes[] =
|
||||
{"lld", "t,o(b)", 0xd0000000, 0xfc000000, LDD|RD_b|WR_t, 0, I3 },
|
||||
{"lld", "t,A(b)", 0, (int) M_LLD_AB, INSN_MACRO, 0, I3 },
|
||||
{"lui", "t,u", 0x3c000000, 0xffe00000, WR_t, 0, I1 },
|
||||
{"aui", "s,t,u", 0x3c000000, 0xfc000000, RD_s|WR_t, 0, I32R6},
|
||||
{"luxc1", "D,t(b)", 0x4c000005, 0xfc00f83f, LDD|WR_D|RD_t|RD_b|FP_D, 0, I5|I33|N55},
|
||||
{"lw", "t,o(b)", 0x8c000000, 0xfc000000, LDD|RD_b|WR_t, 0, I1 },
|
||||
{"lw", "t,A(b)", 0, (int) M_LW_AB, INSN_MACRO, 0, I1 },
|
||||
@@ -3575,6 +3730,42 @@ print_insn_args (const char *d,
|
||||
(*info->fprintf_func) (info->stream, "0x%x", msbd + 1);
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
switch (*(d+1)) {
|
||||
case '1':
|
||||
d++;
|
||||
delta = l & ((1 << 18) - 1);
|
||||
if (delta & 0x20000) {
|
||||
delta |= ~0x1ffff;
|
||||
}
|
||||
break;
|
||||
case '2':
|
||||
d++;
|
||||
delta = l & ((1 << 19) - 1);
|
||||
if (delta & 0x40000) {
|
||||
delta |= ~0x3ffff;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
delta = (l >> OP_SH_DELTA_R6) & OP_MASK_DELTA_R6;
|
||||
if (delta & 0x8000) {
|
||||
delta |= ~0xffff;
|
||||
}
|
||||
}
|
||||
|
||||
(*info->fprintf_func) (info->stream, "%d", delta);
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
/* Sign extend the displacement with 26 bits. */
|
||||
delta = (l >> OP_SH_DELTA) & OP_MASK_TARGET;
|
||||
if (delta & 0x2000000) {
|
||||
delta |= ~0x3FFFFFF;
|
||||
}
|
||||
info->target = (delta << 2) + pc + INSNLEN;
|
||||
(*info->print_address_func) (info->target, info);
|
||||
break;
|
||||
|
||||
case 't': /* Coprocessor 0 reg name */
|
||||
(*info->fprintf_func) (info->stream, "%s",
|
||||
mips_cp0_names[(l >> OP_SH_RT) &
|
||||
@@ -3726,7 +3917,8 @@ print_insn_args (const char *d,
|
||||
|
||||
case 'j': /* Same as i, but sign-extended. */
|
||||
case 'o':
|
||||
delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA;
|
||||
delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA;
|
||||
|
||||
if (delta & 0x8000)
|
||||
delta |= ~0xffff;
|
||||
(*info->fprintf_func) (info->stream, "%d",
|
||||
@@ -4052,6 +4244,23 @@ print_insn_mips (bfd_vma memaddr,
|
||||
&& strcmp (op->name, "jalx"))
|
||||
continue;
|
||||
|
||||
if (strcmp(op->name, "bovc") == 0
|
||||
|| strcmp(op->name, "bnvc") == 0) {
|
||||
if (((word >> OP_SH_RS) & OP_MASK_RS) <
|
||||
((word >> OP_SH_RT) & OP_MASK_RT)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (strcmp(op->name, "bgezc") == 0
|
||||
|| strcmp(op->name, "bltzc") == 0
|
||||
|| strcmp(op->name, "bgezalc") == 0
|
||||
|| strcmp(op->name, "bltzalc") == 0) {
|
||||
if (((word >> OP_SH_RS) & OP_MASK_RS) !=
|
||||
((word >> OP_SH_RT) & OP_MASK_RT)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Figure out instruction type and branch delay information. */
|
||||
if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0)
|
||||
{
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
* (GNU GPL), version 2 or later.
|
||||
*/
|
||||
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/dma.h"
|
||||
#include "trace.h"
|
||||
#include "qemu/range.h"
|
||||
@@ -67,9 +68,9 @@ void qemu_sglist_destroy(QEMUSGList *qsg)
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
BlockDriverAIOCB common;
|
||||
BlockDriverState *bs;
|
||||
BlockDriverAIOCB *acb;
|
||||
BlockAIOCB common;
|
||||
BlockBackend *blk;
|
||||
BlockAIOCB *acb;
|
||||
QEMUSGList *sg;
|
||||
uint64_t sector_num;
|
||||
DMADirection dir;
|
||||
@@ -80,7 +81,7 @@ typedef struct {
|
||||
DMAIOFunc *io_func;
|
||||
} DMAAIOCB;
|
||||
|
||||
static void dma_bdrv_cb(void *opaque, int ret);
|
||||
static void dma_blk_cb(void *opaque, int ret);
|
||||
|
||||
static void reschedule_dma(void *opaque)
|
||||
{
|
||||
@@ -88,7 +89,7 @@ static void reschedule_dma(void *opaque)
|
||||
|
||||
qemu_bh_delete(dbs->bh);
|
||||
dbs->bh = NULL;
|
||||
dma_bdrv_cb(dbs, 0);
|
||||
dma_blk_cb(dbs, 0);
|
||||
}
|
||||
|
||||
static void continue_after_map_failure(void *opaque)
|
||||
@@ -99,7 +100,7 @@ static void continue_after_map_failure(void *opaque)
|
||||
qemu_bh_schedule(dbs->bh);
|
||||
}
|
||||
|
||||
static void dma_bdrv_unmap(DMAAIOCB *dbs)
|
||||
static void dma_blk_unmap(DMAAIOCB *dbs)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -115,7 +116,7 @@ static void dma_complete(DMAAIOCB *dbs, int ret)
|
||||
{
|
||||
trace_dma_complete(dbs, ret, dbs->common.cb);
|
||||
|
||||
dma_bdrv_unmap(dbs);
|
||||
dma_blk_unmap(dbs);
|
||||
if (dbs->common.cb) {
|
||||
dbs->common.cb(dbs->common.opaque, ret);
|
||||
}
|
||||
@@ -127,13 +128,13 @@ static void dma_complete(DMAAIOCB *dbs, int ret)
|
||||
qemu_aio_unref(dbs);
|
||||
}
|
||||
|
||||
static void dma_bdrv_cb(void *opaque, int ret)
|
||||
static void dma_blk_cb(void *opaque, int ret)
|
||||
{
|
||||
DMAAIOCB *dbs = (DMAAIOCB *)opaque;
|
||||
dma_addr_t cur_addr, cur_len;
|
||||
void *mem;
|
||||
|
||||
trace_dma_bdrv_cb(dbs, ret);
|
||||
trace_dma_blk_cb(dbs, ret);
|
||||
|
||||
dbs->acb = NULL;
|
||||
dbs->sector_num += dbs->iov.size / 512;
|
||||
@@ -142,7 +143,7 @@ static void dma_bdrv_cb(void *opaque, int ret)
|
||||
dma_complete(dbs, ret);
|
||||
return;
|
||||
}
|
||||
dma_bdrv_unmap(dbs);
|
||||
dma_blk_unmap(dbs);
|
||||
|
||||
while (dbs->sg_cur_index < dbs->sg->nsg) {
|
||||
cur_addr = dbs->sg->sg[dbs->sg_cur_index].base + dbs->sg_cur_byte;
|
||||
@@ -168,19 +169,19 @@ static void dma_bdrv_cb(void *opaque, int ret)
|
||||
qemu_iovec_discard_back(&dbs->iov, dbs->iov.size & ~BDRV_SECTOR_MASK);
|
||||
}
|
||||
|
||||
dbs->acb = dbs->io_func(dbs->bs, dbs->sector_num, &dbs->iov,
|
||||
dbs->iov.size / 512, dma_bdrv_cb, dbs);
|
||||
dbs->acb = dbs->io_func(dbs->blk, dbs->sector_num, &dbs->iov,
|
||||
dbs->iov.size / 512, dma_blk_cb, dbs);
|
||||
assert(dbs->acb);
|
||||
}
|
||||
|
||||
static void dma_aio_cancel(BlockDriverAIOCB *acb)
|
||||
static void dma_aio_cancel(BlockAIOCB *acb)
|
||||
{
|
||||
DMAAIOCB *dbs = container_of(acb, DMAAIOCB, common);
|
||||
|
||||
trace_dma_aio_cancel(dbs);
|
||||
|
||||
if (dbs->acb) {
|
||||
bdrv_aio_cancel_async(dbs->acb);
|
||||
blk_aio_cancel_async(dbs->acb);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,17 +191,17 @@ static const AIOCBInfo dma_aiocb_info = {
|
||||
.cancel_async = dma_aio_cancel,
|
||||
};
|
||||
|
||||
BlockDriverAIOCB *dma_bdrv_io(
|
||||
BlockDriverState *bs, QEMUSGList *sg, uint64_t sector_num,
|
||||
DMAIOFunc *io_func, BlockDriverCompletionFunc *cb,
|
||||
BlockAIOCB *dma_blk_io(
|
||||
BlockBackend *blk, QEMUSGList *sg, uint64_t sector_num,
|
||||
DMAIOFunc *io_func, BlockCompletionFunc *cb,
|
||||
void *opaque, DMADirection dir)
|
||||
{
|
||||
DMAAIOCB *dbs = qemu_aio_get(&dma_aiocb_info, bs, cb, opaque);
|
||||
DMAAIOCB *dbs = blk_aio_get(&dma_aiocb_info, blk, cb, opaque);
|
||||
|
||||
trace_dma_bdrv_io(dbs, bs, sector_num, (dir == DMA_DIRECTION_TO_DEVICE));
|
||||
trace_dma_blk_io(dbs, blk, sector_num, (dir == DMA_DIRECTION_TO_DEVICE));
|
||||
|
||||
dbs->acb = NULL;
|
||||
dbs->bs = bs;
|
||||
dbs->blk = blk;
|
||||
dbs->sg = sg;
|
||||
dbs->sector_num = sector_num;
|
||||
dbs->sg_cur_index = 0;
|
||||
@@ -209,25 +210,25 @@ BlockDriverAIOCB *dma_bdrv_io(
|
||||
dbs->io_func = io_func;
|
||||
dbs->bh = NULL;
|
||||
qemu_iovec_init(&dbs->iov, sg->nsg);
|
||||
dma_bdrv_cb(dbs, 0);
|
||||
dma_blk_cb(dbs, 0);
|
||||
return &dbs->common;
|
||||
}
|
||||
|
||||
|
||||
BlockDriverAIOCB *dma_bdrv_read(BlockDriverState *bs,
|
||||
QEMUSGList *sg, uint64_t sector,
|
||||
void (*cb)(void *opaque, int ret), void *opaque)
|
||||
BlockAIOCB *dma_blk_read(BlockBackend *blk,
|
||||
QEMUSGList *sg, uint64_t sector,
|
||||
void (*cb)(void *opaque, int ret), void *opaque)
|
||||
{
|
||||
return dma_bdrv_io(bs, sg, sector, bdrv_aio_readv, cb, opaque,
|
||||
DMA_DIRECTION_FROM_DEVICE);
|
||||
return dma_blk_io(blk, sg, sector, blk_aio_readv, cb, opaque,
|
||||
DMA_DIRECTION_FROM_DEVICE);
|
||||
}
|
||||
|
||||
BlockDriverAIOCB *dma_bdrv_write(BlockDriverState *bs,
|
||||
QEMUSGList *sg, uint64_t sector,
|
||||
void (*cb)(void *opaque, int ret), void *opaque)
|
||||
BlockAIOCB *dma_blk_write(BlockBackend *blk,
|
||||
QEMUSGList *sg, uint64_t sector,
|
||||
void (*cb)(void *opaque, int ret), void *opaque)
|
||||
{
|
||||
return dma_bdrv_io(bs, sg, sector, bdrv_aio_writev, cb, opaque,
|
||||
DMA_DIRECTION_TO_DEVICE);
|
||||
return dma_blk_io(blk, sg, sector, blk_aio_writev, cb, opaque,
|
||||
DMA_DIRECTION_TO_DEVICE);
|
||||
}
|
||||
|
||||
|
||||
@@ -262,8 +263,8 @@ uint64_t dma_buf_write(uint8_t *ptr, int32_t len, QEMUSGList *sg)
|
||||
return dma_buf_rw(ptr, len, sg, DMA_DIRECTION_TO_DEVICE);
|
||||
}
|
||||
|
||||
void dma_acct_start(BlockDriverState *bs, BlockAcctCookie *cookie,
|
||||
void dma_acct_start(BlockBackend *blk, BlockAcctCookie *cookie,
|
||||
QEMUSGList *sg, enum BlockAcctType type)
|
||||
{
|
||||
block_acct_start(bdrv_get_stats(bs), cookie, sg->size, type);
|
||||
block_acct_start(blk_get_stats(blk), cookie, sg->size, type);
|
||||
}
|
||||
|
||||
@@ -70,10 +70,10 @@ Rules support the following attributes:
|
||||
once - (optional, default "off") only execute this action on the first
|
||||
matching request
|
||||
|
||||
immediately - (optional, default "off") return a NULL BlockDriverAIOCB
|
||||
pointer and fail without an errno instead. This exercises the
|
||||
code path where BlockDriverAIOCB fails and the caller's
|
||||
BlockDriverCompletionFunc is not invoked.
|
||||
immediately - (optional, default "off") return a NULL BlockAIOCB
|
||||
pointer and fail without an errno instead. This
|
||||
exercises the code path where BlockAIOCB fails and the
|
||||
caller's BlockCompletionFunc is not invoked.
|
||||
|
||||
Events
|
||||
------
|
||||
|
||||
@@ -110,6 +110,7 @@ in the description of a field.
|
||||
in bits: refcount_bits = 1 << refcount_order). For version 2
|
||||
images, the order is always assumed to be 4
|
||||
(i.e. refcount_bits = 16).
|
||||
This value may not exceed 6 (i.e. refcount_bits = 64).
|
||||
|
||||
100 - 103: header_length
|
||||
Length of the header structure in bytes. For version 2
|
||||
@@ -183,7 +184,7 @@ blocks and are exactly one cluster in size.
|
||||
Given a offset into the image file, the refcount of its cluster can be obtained
|
||||
as follows:
|
||||
|
||||
refcount_block_entries = (cluster_size / sizeof(uint16_t))
|
||||
refcount_block_entries = (cluster_size * 8 / refcount_bits)
|
||||
|
||||
refcount_block_index = (offset / cluster_size) % refcount_block_entries
|
||||
refcount_table_index = (offset / cluster_size) / refcount_block_entries
|
||||
|
||||
@@ -70,3 +70,12 @@ Likewise applies to the pci variant only for obvious reasons.
|
||||
0500 - 0515 : bochs dispi interface registers, mapped flat
|
||||
without index/data ports. Use (index << 1)
|
||||
as offset for (16bit) register access.
|
||||
|
||||
0600 - 0607 : qemu extended registers. qemu 2.2+ only.
|
||||
The pci revision is 2 (or greater) when
|
||||
these registers are present. The registers
|
||||
are 32bit.
|
||||
0600 : qemu extended register region size, in bytes.
|
||||
0604 : framebuffer endianness register.
|
||||
- 0xbebebebe indicates big endian.
|
||||
- 0x1e1e1e1e indicates little endian.
|
||||
|
||||
383
dump.c
383
dump.c
@@ -81,9 +81,10 @@ static int dump_cleanup(DumpState *s)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dump_error(DumpState *s, const char *reason)
|
||||
static void dump_error(DumpState *s, const char *reason, Error **errp)
|
||||
{
|
||||
dump_cleanup(s);
|
||||
error_setg(errp, "%s", reason);
|
||||
}
|
||||
|
||||
static int fd_write_vmcore(const void *buf, size_t size, void *opaque)
|
||||
@@ -99,7 +100,7 @@ static int fd_write_vmcore(const void *buf, size_t size, void *opaque)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_elf64_header(DumpState *s)
|
||||
static void write_elf64_header(DumpState *s, Error **errp)
|
||||
{
|
||||
Elf64_Ehdr elf_header;
|
||||
int ret;
|
||||
@@ -126,14 +127,11 @@ static int write_elf64_header(DumpState *s)
|
||||
|
||||
ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write elf header.\n");
|
||||
return -1;
|
||||
dump_error(s, "dump: failed to write elf header", errp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_elf32_header(DumpState *s)
|
||||
static void write_elf32_header(DumpState *s, Error **errp)
|
||||
{
|
||||
Elf32_Ehdr elf_header;
|
||||
int ret;
|
||||
@@ -160,16 +158,13 @@ static int write_elf32_header(DumpState *s)
|
||||
|
||||
ret = fd_write_vmcore(&elf_header, sizeof(elf_header), s);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write elf header.\n");
|
||||
return -1;
|
||||
dump_error(s, "dump: failed to write elf header", errp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_elf64_load(DumpState *s, MemoryMapping *memory_mapping,
|
||||
int phdr_index, hwaddr offset,
|
||||
hwaddr filesz)
|
||||
static void write_elf64_load(DumpState *s, MemoryMapping *memory_mapping,
|
||||
int phdr_index, hwaddr offset,
|
||||
hwaddr filesz, Error **errp)
|
||||
{
|
||||
Elf64_Phdr phdr;
|
||||
int ret;
|
||||
@@ -186,16 +181,13 @@ static int write_elf64_load(DumpState *s, MemoryMapping *memory_mapping,
|
||||
|
||||
ret = fd_write_vmcore(&phdr, sizeof(Elf64_Phdr), s);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write program header table.\n");
|
||||
return -1;
|
||||
dump_error(s, "dump: failed to write program header table", errp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_elf32_load(DumpState *s, MemoryMapping *memory_mapping,
|
||||
int phdr_index, hwaddr offset,
|
||||
hwaddr filesz)
|
||||
static void write_elf32_load(DumpState *s, MemoryMapping *memory_mapping,
|
||||
int phdr_index, hwaddr offset,
|
||||
hwaddr filesz, Error **errp)
|
||||
{
|
||||
Elf32_Phdr phdr;
|
||||
int ret;
|
||||
@@ -212,14 +204,11 @@ static int write_elf32_load(DumpState *s, MemoryMapping *memory_mapping,
|
||||
|
||||
ret = fd_write_vmcore(&phdr, sizeof(Elf32_Phdr), s);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write program header table.\n");
|
||||
return -1;
|
||||
dump_error(s, "dump: failed to write program header table", errp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_elf64_note(DumpState *s)
|
||||
static void write_elf64_note(DumpState *s, Error **errp)
|
||||
{
|
||||
Elf64_Phdr phdr;
|
||||
hwaddr begin = s->memory_offset - s->note_size;
|
||||
@@ -235,11 +224,8 @@ static int write_elf64_note(DumpState *s)
|
||||
|
||||
ret = fd_write_vmcore(&phdr, sizeof(Elf64_Phdr), s);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write program header table.\n");
|
||||
return -1;
|
||||
dump_error(s, "dump: failed to write program header table", errp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int cpu_index(CPUState *cpu)
|
||||
@@ -247,7 +233,8 @@ static inline int cpu_index(CPUState *cpu)
|
||||
return cpu->cpu_index + 1;
|
||||
}
|
||||
|
||||
static int write_elf64_notes(WriteCoreDumpFunction f, DumpState *s)
|
||||
static void write_elf64_notes(WriteCoreDumpFunction f, DumpState *s,
|
||||
Error **errp)
|
||||
{
|
||||
CPUState *cpu;
|
||||
int ret;
|
||||
@@ -257,23 +244,21 @@ static int write_elf64_notes(WriteCoreDumpFunction f, DumpState *s)
|
||||
id = cpu_index(cpu);
|
||||
ret = cpu_write_elf64_note(f, cpu, id, s);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write elf notes.\n");
|
||||
return -1;
|
||||
dump_error(s, "dump: failed to write elf notes", errp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
CPU_FOREACH(cpu) {
|
||||
ret = cpu_write_elf64_qemunote(f, cpu, s);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write CPU status.\n");
|
||||
return -1;
|
||||
dump_error(s, "dump: failed to write CPU status", errp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_elf32_note(DumpState *s)
|
||||
static void write_elf32_note(DumpState *s, Error **errp)
|
||||
{
|
||||
hwaddr begin = s->memory_offset - s->note_size;
|
||||
Elf32_Phdr phdr;
|
||||
@@ -289,14 +274,12 @@ static int write_elf32_note(DumpState *s)
|
||||
|
||||
ret = fd_write_vmcore(&phdr, sizeof(Elf32_Phdr), s);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write program header table.\n");
|
||||
return -1;
|
||||
dump_error(s, "dump: failed to write program header table", errp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_elf32_notes(WriteCoreDumpFunction f, DumpState *s)
|
||||
static void write_elf32_notes(WriteCoreDumpFunction f, DumpState *s,
|
||||
Error **errp)
|
||||
{
|
||||
CPUState *cpu;
|
||||
int ret;
|
||||
@@ -306,23 +289,21 @@ static int write_elf32_notes(WriteCoreDumpFunction f, DumpState *s)
|
||||
id = cpu_index(cpu);
|
||||
ret = cpu_write_elf32_note(f, cpu, id, s);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write elf notes.\n");
|
||||
return -1;
|
||||
dump_error(s, "dump: failed to write elf notes", errp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
CPU_FOREACH(cpu) {
|
||||
ret = cpu_write_elf32_qemunote(f, cpu, s);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write CPU status.\n");
|
||||
return -1;
|
||||
dump_error(s, "dump: failed to write CPU status", errp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_elf_section(DumpState *s, int type)
|
||||
static void write_elf_section(DumpState *s, int type, Error **errp)
|
||||
{
|
||||
Elf32_Shdr shdr32;
|
||||
Elf64_Shdr shdr64;
|
||||
@@ -344,50 +325,44 @@ static int write_elf_section(DumpState *s, int type)
|
||||
|
||||
ret = fd_write_vmcore(&shdr, shdr_size, s);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write section header table.\n");
|
||||
return -1;
|
||||
dump_error(s, "dump: failed to write section header table", errp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_data(DumpState *s, void *buf, int length)
|
||||
static void write_data(DumpState *s, void *buf, int length, Error **errp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = fd_write_vmcore(buf, length, s);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to save memory.\n");
|
||||
return -1;
|
||||
dump_error(s, "dump: failed to save memory", errp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* write the memroy to vmcore. 1 page per I/O. */
|
||||
static int write_memory(DumpState *s, GuestPhysBlock *block, ram_addr_t start,
|
||||
int64_t size)
|
||||
/* write the memory to vmcore. 1 page per I/O. */
|
||||
static void write_memory(DumpState *s, GuestPhysBlock *block, ram_addr_t start,
|
||||
int64_t size, Error **errp)
|
||||
{
|
||||
int64_t i;
|
||||
int ret;
|
||||
Error *local_err = NULL;
|
||||
|
||||
for (i = 0; i < size / TARGET_PAGE_SIZE; i++) {
|
||||
ret = write_data(s, block->host_addr + start + i * TARGET_PAGE_SIZE,
|
||||
TARGET_PAGE_SIZE);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
write_data(s, block->host_addr + start + i * TARGET_PAGE_SIZE,
|
||||
TARGET_PAGE_SIZE, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ((size % TARGET_PAGE_SIZE) != 0) {
|
||||
ret = write_data(s, block->host_addr + start + i * TARGET_PAGE_SIZE,
|
||||
size % TARGET_PAGE_SIZE);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
write_data(s, block->host_addr + start + i * TARGET_PAGE_SIZE,
|
||||
size % TARGET_PAGE_SIZE, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* get the memory's offset and size in the vmcore */
|
||||
@@ -452,13 +427,13 @@ static void get_offset_range(hwaddr phys_addr,
|
||||
}
|
||||
}
|
||||
|
||||
static int write_elf_loads(DumpState *s)
|
||||
static void write_elf_loads(DumpState *s, Error **errp)
|
||||
{
|
||||
hwaddr offset, filesz;
|
||||
MemoryMapping *memory_mapping;
|
||||
uint32_t phdr_index = 1;
|
||||
int ret;
|
||||
uint32_t max_index;
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (s->have_section) {
|
||||
max_index = s->sh_info;
|
||||
@@ -471,29 +446,28 @@ static int write_elf_loads(DumpState *s)
|
||||
memory_mapping->length,
|
||||
s, &offset, &filesz);
|
||||
if (s->dump_info.d_class == ELFCLASS64) {
|
||||
ret = write_elf64_load(s, memory_mapping, phdr_index++, offset,
|
||||
filesz);
|
||||
write_elf64_load(s, memory_mapping, phdr_index++, offset,
|
||||
filesz, &local_err);
|
||||
} else {
|
||||
ret = write_elf32_load(s, memory_mapping, phdr_index++, offset,
|
||||
filesz);
|
||||
write_elf32_load(s, memory_mapping, phdr_index++, offset,
|
||||
filesz, &local_err);
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (phdr_index >= max_index) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* write elf header, PT_NOTE and elf note to vmcore. */
|
||||
static int dump_begin(DumpState *s)
|
||||
static void dump_begin(DumpState *s, Error **errp)
|
||||
{
|
||||
int ret;
|
||||
Error *local_err = NULL;
|
||||
|
||||
/*
|
||||
* the vmcore's format is:
|
||||
@@ -521,69 +495,81 @@ static int dump_begin(DumpState *s)
|
||||
|
||||
/* write elf header to vmcore */
|
||||
if (s->dump_info.d_class == ELFCLASS64) {
|
||||
ret = write_elf64_header(s);
|
||||
write_elf64_header(s, &local_err);
|
||||
} else {
|
||||
ret = write_elf32_header(s);
|
||||
write_elf32_header(s, &local_err);
|
||||
}
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->dump_info.d_class == ELFCLASS64) {
|
||||
/* write PT_NOTE to vmcore */
|
||||
if (write_elf64_note(s) < 0) {
|
||||
return -1;
|
||||
write_elf64_note(s, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* write all PT_LOAD to vmcore */
|
||||
if (write_elf_loads(s) < 0) {
|
||||
return -1;
|
||||
write_elf_loads(s, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* write section to vmcore */
|
||||
if (s->have_section) {
|
||||
if (write_elf_section(s, 1) < 0) {
|
||||
return -1;
|
||||
write_elf_section(s, 1, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* write notes to vmcore */
|
||||
if (write_elf64_notes(fd_write_vmcore, s) < 0) {
|
||||
return -1;
|
||||
write_elf64_notes(fd_write_vmcore, s, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* write PT_NOTE to vmcore */
|
||||
if (write_elf32_note(s) < 0) {
|
||||
return -1;
|
||||
write_elf32_note(s, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* write all PT_LOAD to vmcore */
|
||||
if (write_elf_loads(s) < 0) {
|
||||
return -1;
|
||||
write_elf_loads(s, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* write section to vmcore */
|
||||
if (s->have_section) {
|
||||
if (write_elf_section(s, 0) < 0) {
|
||||
return -1;
|
||||
write_elf_section(s, 0, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* write notes to vmcore */
|
||||
if (write_elf32_notes(fd_write_vmcore, s) < 0) {
|
||||
return -1;
|
||||
write_elf32_notes(fd_write_vmcore, s, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* write PT_LOAD to vmcore */
|
||||
static int dump_completed(DumpState *s)
|
||||
static void dump_completed(DumpState *s)
|
||||
{
|
||||
dump_cleanup(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_next_block(DumpState *s, GuestPhysBlock *block)
|
||||
@@ -614,11 +600,12 @@ static int get_next_block(DumpState *s, GuestPhysBlock *block)
|
||||
}
|
||||
|
||||
/* write all memory to vmcore */
|
||||
static int dump_iterate(DumpState *s)
|
||||
static void dump_iterate(DumpState *s, Error **errp)
|
||||
{
|
||||
GuestPhysBlock *block;
|
||||
int64_t size;
|
||||
int ret;
|
||||
Error *local_err = NULL;
|
||||
|
||||
while (1) {
|
||||
block = s->next_block;
|
||||
@@ -630,34 +617,30 @@ static int dump_iterate(DumpState *s)
|
||||
size -= block->target_end - (s->begin + s->length);
|
||||
}
|
||||
}
|
||||
ret = write_memory(s, block, s->start, size);
|
||||
if (ret == -1) {
|
||||
return ret;
|
||||
write_memory(s, block, s->start, size, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = get_next_block(s, block);
|
||||
if (ret == 1) {
|
||||
dump_completed(s);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int create_vmcore(DumpState *s)
|
||||
static void create_vmcore(DumpState *s, Error **errp)
|
||||
{
|
||||
int ret;
|
||||
Error *local_err = NULL;
|
||||
|
||||
ret = dump_begin(s);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
dump_begin(s, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = dump_iterate(s);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
dump_iterate(s, errp);
|
||||
}
|
||||
|
||||
static int write_start_flat_header(int fd)
|
||||
@@ -738,9 +721,8 @@ static int buf_write_note(const void *buf, size_t size, void *opaque)
|
||||
}
|
||||
|
||||
/* write common header, sub header and elf note to vmcore */
|
||||
static int create_header32(DumpState *s)
|
||||
static void create_header32(DumpState *s, Error **errp)
|
||||
{
|
||||
int ret = 0;
|
||||
DiskDumpHeader32 *dh = NULL;
|
||||
KdumpSubHeader32 *kh = NULL;
|
||||
size_t size;
|
||||
@@ -749,6 +731,7 @@ static int create_header32(DumpState *s)
|
||||
uint32_t bitmap_blocks;
|
||||
uint32_t status = 0;
|
||||
uint64_t offset_note;
|
||||
Error *local_err = NULL;
|
||||
|
||||
/* write common header, the version of kdump-compressed format is 6th */
|
||||
size = sizeof(DiskDumpHeader32);
|
||||
@@ -784,8 +767,7 @@ static int create_header32(DumpState *s)
|
||||
dh->status = cpu_to_dump32(s, status);
|
||||
|
||||
if (write_buffer(s->fd, 0, dh, size) < 0) {
|
||||
dump_error(s, "dump: failed to write disk dump header.\n");
|
||||
ret = -1;
|
||||
dump_error(s, "dump: failed to write disk dump header", errp);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -804,8 +786,7 @@ static int create_header32(DumpState *s)
|
||||
|
||||
if (write_buffer(s->fd, DISKDUMP_HEADER_BLOCKS *
|
||||
block_size, kh, size) < 0) {
|
||||
dump_error(s, "dump: failed to write kdump sub header.\n");
|
||||
ret = -1;
|
||||
dump_error(s, "dump: failed to write kdump sub header", errp);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -814,15 +795,14 @@ static int create_header32(DumpState *s)
|
||||
s->note_buf_offset = 0;
|
||||
|
||||
/* use s->note_buf to store notes temporarily */
|
||||
if (write_elf32_notes(buf_write_note, s) < 0) {
|
||||
ret = -1;
|
||||
write_elf32_notes(buf_write_note, s, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (write_buffer(s->fd, offset_note, s->note_buf,
|
||||
s->note_size) < 0) {
|
||||
dump_error(s, "dump: failed to write notes");
|
||||
ret = -1;
|
||||
dump_error(s, "dump: failed to write notes", errp);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -838,14 +818,11 @@ out:
|
||||
g_free(dh);
|
||||
g_free(kh);
|
||||
g_free(s->note_buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* write common header, sub header and elf note to vmcore */
|
||||
static int create_header64(DumpState *s)
|
||||
static void create_header64(DumpState *s, Error **errp)
|
||||
{
|
||||
int ret = 0;
|
||||
DiskDumpHeader64 *dh = NULL;
|
||||
KdumpSubHeader64 *kh = NULL;
|
||||
size_t size;
|
||||
@@ -854,6 +831,7 @@ static int create_header64(DumpState *s)
|
||||
uint32_t bitmap_blocks;
|
||||
uint32_t status = 0;
|
||||
uint64_t offset_note;
|
||||
Error *local_err = NULL;
|
||||
|
||||
/* write common header, the version of kdump-compressed format is 6th */
|
||||
size = sizeof(DiskDumpHeader64);
|
||||
@@ -889,8 +867,7 @@ static int create_header64(DumpState *s)
|
||||
dh->status = cpu_to_dump32(s, status);
|
||||
|
||||
if (write_buffer(s->fd, 0, dh, size) < 0) {
|
||||
dump_error(s, "dump: failed to write disk dump header.\n");
|
||||
ret = -1;
|
||||
dump_error(s, "dump: failed to write disk dump header", errp);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -909,8 +886,7 @@ static int create_header64(DumpState *s)
|
||||
|
||||
if (write_buffer(s->fd, DISKDUMP_HEADER_BLOCKS *
|
||||
block_size, kh, size) < 0) {
|
||||
dump_error(s, "dump: failed to write kdump sub header.\n");
|
||||
ret = -1;
|
||||
dump_error(s, "dump: failed to write kdump sub header", errp);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -919,15 +895,15 @@ static int create_header64(DumpState *s)
|
||||
s->note_buf_offset = 0;
|
||||
|
||||
/* use s->note_buf to store notes temporarily */
|
||||
if (write_elf64_notes(buf_write_note, s) < 0) {
|
||||
ret = -1;
|
||||
write_elf64_notes(buf_write_note, s, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (write_buffer(s->fd, offset_note, s->note_buf,
|
||||
s->note_size) < 0) {
|
||||
dump_error(s, "dump: failed to write notes");
|
||||
ret = -1;
|
||||
dump_error(s, "dump: failed to write notes", errp);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -943,16 +919,19 @@ out:
|
||||
g_free(dh);
|
||||
g_free(kh);
|
||||
g_free(s->note_buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int write_dump_header(DumpState *s)
|
||||
static void write_dump_header(DumpState *s, Error **errp)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (s->dump_info.d_class == ELFCLASS32) {
|
||||
return create_header32(s);
|
||||
create_header32(s, &local_err);
|
||||
} else {
|
||||
return create_header64(s);
|
||||
create_header64(s, &local_err);
|
||||
}
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1066,7 +1045,7 @@ static bool get_next_page(GuestPhysBlock **blockptr, uint64_t *pfnptr,
|
||||
return true;
|
||||
}
|
||||
|
||||
static int write_dump_bitmap(DumpState *s)
|
||||
static void write_dump_bitmap(DumpState *s, Error **errp)
|
||||
{
|
||||
int ret = 0;
|
||||
uint64_t last_pfn, pfn;
|
||||
@@ -1087,8 +1066,7 @@ static int write_dump_bitmap(DumpState *s)
|
||||
while (get_next_page(&block_iter, &pfn, NULL, s)) {
|
||||
ret = set_dump_bitmap(last_pfn, pfn, true, dump_bitmap_buf, s);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to set dump_bitmap.\n");
|
||||
ret = -1;
|
||||
dump_error(s, "dump: failed to set dump_bitmap", errp);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1105,8 +1083,7 @@ static int write_dump_bitmap(DumpState *s)
|
||||
ret = set_dump_bitmap(last_pfn, last_pfn + PFN_BUFBITMAP, false,
|
||||
dump_bitmap_buf, s);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to sync dump_bitmap.\n");
|
||||
ret = -1;
|
||||
dump_error(s, "dump: failed to sync dump_bitmap", errp);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@@ -1116,8 +1093,6 @@ static int write_dump_bitmap(DumpState *s)
|
||||
|
||||
out:
|
||||
g_free(dump_bitmap_buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void prepare_data_cache(DataCache *data_cache, DumpState *s,
|
||||
@@ -1197,7 +1172,7 @@ static inline bool is_zero_page(const uint8_t *buf, size_t page_size)
|
||||
return buffer_is_zero(buf, page_size);
|
||||
}
|
||||
|
||||
static int write_dump_pages(DumpState *s)
|
||||
static void write_dump_pages(DumpState *s, Error **errp)
|
||||
{
|
||||
int ret = 0;
|
||||
DataCache page_desc, page_data;
|
||||
@@ -1241,7 +1216,7 @@ static int write_dump_pages(DumpState *s)
|
||||
ret = write_cache(&page_data, buf, TARGET_PAGE_SIZE, false);
|
||||
g_free(buf);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write page data(zero page).\n");
|
||||
dump_error(s, "dump: failed to write page data (zero page)", errp);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1257,7 +1232,7 @@ static int write_dump_pages(DumpState *s)
|
||||
ret = write_cache(&page_desc, &pd_zero, sizeof(PageDescriptor),
|
||||
false);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write page desc.\n");
|
||||
dump_error(s, "dump: failed to write page desc", errp);
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
@@ -1282,7 +1257,7 @@ static int write_dump_pages(DumpState *s)
|
||||
|
||||
ret = write_cache(&page_data, buf_out, size_out, false);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write page data.\n");
|
||||
dump_error(s, "dump: failed to write page data", errp);
|
||||
goto out;
|
||||
}
|
||||
#ifdef CONFIG_LZO
|
||||
@@ -1295,7 +1270,7 @@ static int write_dump_pages(DumpState *s)
|
||||
|
||||
ret = write_cache(&page_data, buf_out, size_out, false);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write page data.\n");
|
||||
dump_error(s, "dump: failed to write page data", errp);
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
@@ -1309,7 +1284,7 @@ static int write_dump_pages(DumpState *s)
|
||||
|
||||
ret = write_cache(&page_data, buf_out, size_out, false);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write page data.\n");
|
||||
dump_error(s, "dump: failed to write page data", errp);
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
@@ -1324,7 +1299,7 @@ static int write_dump_pages(DumpState *s)
|
||||
|
||||
ret = write_cache(&page_data, buf, TARGET_PAGE_SIZE, false);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write page data.\n");
|
||||
dump_error(s, "dump: failed to write page data", errp);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@@ -1336,7 +1311,7 @@ static int write_dump_pages(DumpState *s)
|
||||
|
||||
ret = write_cache(&page_desc, &pd, sizeof(PageDescriptor), false);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write page desc.\n");
|
||||
dump_error(s, "dump: failed to write page desc", errp);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@@ -1344,12 +1319,12 @@ static int write_dump_pages(DumpState *s)
|
||||
|
||||
ret = write_cache(&page_desc, NULL, 0, true);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to sync cache for page_desc.\n");
|
||||
dump_error(s, "dump: failed to sync cache for page_desc", errp);
|
||||
goto out;
|
||||
}
|
||||
ret = write_cache(&page_data, NULL, 0, true);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to sync cache for page_data.\n");
|
||||
dump_error(s, "dump: failed to sync cache for page_data", errp);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1362,13 +1337,12 @@ out:
|
||||
#endif
|
||||
|
||||
g_free(buf_out);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int create_kdump_vmcore(DumpState *s)
|
||||
static void create_kdump_vmcore(DumpState *s, Error **errp)
|
||||
{
|
||||
int ret;
|
||||
Error *local_err = NULL;
|
||||
|
||||
/*
|
||||
* the kdump-compressed format is:
|
||||
@@ -1394,34 +1368,35 @@ static int create_kdump_vmcore(DumpState *s)
|
||||
|
||||
ret = write_start_flat_header(s->fd);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write start flat header.\n");
|
||||
return -1;
|
||||
dump_error(s, "dump: failed to write start flat header", errp);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = write_dump_header(s);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
write_dump_header(s, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = write_dump_bitmap(s);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
write_dump_bitmap(s, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = write_dump_pages(s);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
write_dump_pages(s, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = write_end_flat_header(s->fd);
|
||||
if (ret < 0) {
|
||||
dump_error(s, "dump: failed to write end flat header.\n");
|
||||
return -1;
|
||||
dump_error(s, "dump: failed to write end flat header", errp);
|
||||
return;
|
||||
}
|
||||
|
||||
dump_completed(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ram_addr_t get_start_block(DumpState *s)
|
||||
@@ -1460,9 +1435,9 @@ static void get_max_mapnr(DumpState *s)
|
||||
s->max_mapnr = paddr_to_pfn(last_block->target_end);
|
||||
}
|
||||
|
||||
static int dump_init(DumpState *s, int fd, bool has_format,
|
||||
DumpGuestMemoryFormat format, bool paging, bool has_filter,
|
||||
int64_t begin, int64_t length, Error **errp)
|
||||
static void dump_init(DumpState *s, int fd, bool has_format,
|
||||
DumpGuestMemoryFormat format, bool paging, bool has_filter,
|
||||
int64_t begin, int64_t length, Error **errp)
|
||||
{
|
||||
CPUState *cpu;
|
||||
int nr_cpus;
|
||||
@@ -1567,7 +1542,7 @@ static int dump_init(DumpState *s, int fd, bool has_format,
|
||||
s->flag_compress = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->has_filter) {
|
||||
@@ -1616,11 +1591,10 @@ static int dump_init(DumpState *s, int fd, bool has_format,
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return;
|
||||
|
||||
cleanup:
|
||||
dump_cleanup(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin,
|
||||
@@ -1631,7 +1605,7 @@ void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin,
|
||||
const char *p;
|
||||
int fd = -1;
|
||||
DumpState *s;
|
||||
int ret;
|
||||
Error *local_err = NULL;
|
||||
|
||||
/*
|
||||
* kdump-compressed format need the whole memory dumped, so paging or
|
||||
@@ -1691,21 +1665,18 @@ void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin,
|
||||
|
||||
s = g_malloc0(sizeof(DumpState));
|
||||
|
||||
ret = dump_init(s, fd, has_format, format, paging, has_begin,
|
||||
begin, length, errp);
|
||||
if (ret < 0) {
|
||||
dump_init(s, fd, has_format, format, paging, has_begin,
|
||||
begin, length, &local_err);
|
||||
if (local_err) {
|
||||
g_free(s);
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (has_format && format != DUMP_GUEST_MEMORY_FORMAT_ELF) {
|
||||
if (create_kdump_vmcore(s) < 0) {
|
||||
error_set(errp, QERR_IO_ERROR);
|
||||
}
|
||||
create_kdump_vmcore(s, errp);
|
||||
} else {
|
||||
if (create_vmcore(s) < 0) {
|
||||
error_set(errp, QERR_IO_ERROR);
|
||||
}
|
||||
create_vmcore(s, errp);
|
||||
}
|
||||
|
||||
g_free(s);
|
||||
|
||||
@@ -7240,13 +7240,17 @@ int float128_compare_quiet( float128 a, float128 b STATUS_PARAM )
|
||||
* minnum() and maxnum correspond to the IEEE 754-2008 minNum()
|
||||
* and maxNum() operations. min() and max() are the typical min/max
|
||||
* semantics provided by many CPUs which predate that specification.
|
||||
*
|
||||
* minnummag() and maxnummag() functions correspond to minNumMag()
|
||||
* and minNumMag() from the IEEE-754 2008.
|
||||
*/
|
||||
#define MINMAX(s) \
|
||||
static inline float ## s float ## s ## _minmax(float ## s a, float ## s b, \
|
||||
int ismin, int isieee STATUS_PARAM) \
|
||||
int ismin, int isieee, \
|
||||
int ismag STATUS_PARAM) \
|
||||
{ \
|
||||
flag aSign, bSign; \
|
||||
uint ## s ## _t av, bv; \
|
||||
uint ## s ## _t av, bv, aav, abv; \
|
||||
a = float ## s ## _squash_input_denormal(a STATUS_VAR); \
|
||||
b = float ## s ## _squash_input_denormal(b STATUS_VAR); \
|
||||
if (float ## s ## _is_any_nan(a) || \
|
||||
@@ -7266,6 +7270,17 @@ static inline float ## s float ## s ## _minmax(float ## s a, float ## s b, \
|
||||
bSign = extractFloat ## s ## Sign(b); \
|
||||
av = float ## s ## _val(a); \
|
||||
bv = float ## s ## _val(b); \
|
||||
if (ismag) { \
|
||||
aav = float ## s ## _abs(av); \
|
||||
abv = float ## s ## _abs(bv); \
|
||||
if (aav != abv) { \
|
||||
if (ismin) { \
|
||||
return (aav < abv) ? a : b; \
|
||||
} else { \
|
||||
return (aav < abv) ? b : a; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
if (aSign != bSign) { \
|
||||
if (ismin) { \
|
||||
return aSign ? a : b; \
|
||||
@@ -7283,22 +7298,32 @@ static inline float ## s float ## s ## _minmax(float ## s a, float ## s b, \
|
||||
\
|
||||
float ## s float ## s ## _min(float ## s a, float ## s b STATUS_PARAM) \
|
||||
{ \
|
||||
return float ## s ## _minmax(a, b, 1, 0 STATUS_VAR); \
|
||||
return float ## s ## _minmax(a, b, 1, 0, 0 STATUS_VAR); \
|
||||
} \
|
||||
\
|
||||
float ## s float ## s ## _max(float ## s a, float ## s b STATUS_PARAM) \
|
||||
{ \
|
||||
return float ## s ## _minmax(a, b, 0, 0 STATUS_VAR); \
|
||||
return float ## s ## _minmax(a, b, 0, 0, 0 STATUS_VAR); \
|
||||
} \
|
||||
\
|
||||
float ## s float ## s ## _minnum(float ## s a, float ## s b STATUS_PARAM) \
|
||||
{ \
|
||||
return float ## s ## _minmax(a, b, 1, 1 STATUS_VAR); \
|
||||
return float ## s ## _minmax(a, b, 1, 1, 0 STATUS_VAR); \
|
||||
} \
|
||||
\
|
||||
float ## s float ## s ## _maxnum(float ## s a, float ## s b STATUS_PARAM) \
|
||||
{ \
|
||||
return float ## s ## _minmax(a, b, 0, 1 STATUS_VAR); \
|
||||
return float ## s ## _minmax(a, b, 0, 1, 0 STATUS_VAR); \
|
||||
} \
|
||||
\
|
||||
float ## s float ## s ## _minnummag(float ## s a, float ## s b STATUS_PARAM) \
|
||||
{ \
|
||||
return float ## s ## _minmax(a, b, 1, 1, 1 STATUS_VAR); \
|
||||
} \
|
||||
\
|
||||
float ## s float ## s ## _maxnummag(float ## s a, float ## s b STATUS_PARAM) \
|
||||
{ \
|
||||
return float ## s ## _minmax(a, b, 0, 1, 1 STATUS_VAR); \
|
||||
}
|
||||
|
||||
MINMAX(32)
|
||||
|
||||
@@ -1748,8 +1748,6 @@ show information about active capturing
|
||||
show list of VM snapshots
|
||||
@item info status
|
||||
show the current VM status (running|paused)
|
||||
@item info pcmcia
|
||||
show guest PCMCIA status
|
||||
@item info mice
|
||||
show which guest mouse is receiving events
|
||||
@item info vnc
|
||||
|
||||
@@ -354,8 +354,8 @@ static void piix4_device_plug_cb(HotplugHandler *hotplug_dev,
|
||||
}
|
||||
}
|
||||
|
||||
static void piix4_device_unplug_cb(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
static void piix4_device_unplug_request_cb(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
PIIX4PMState *s = PIIX4_PM(hotplug_dev);
|
||||
|
||||
@@ -615,7 +615,7 @@ static void piix4_pm_class_init(ObjectClass *klass, void *data)
|
||||
dc->cannot_instantiate_with_device_add_yet = true;
|
||||
dc->hotpluggable = false;
|
||||
hc->plug = piix4_device_plug_cb;
|
||||
hc->unplug = piix4_device_unplug_cb;
|
||||
hc->unplug_request = piix4_device_unplug_request_cb;
|
||||
adevc->ospm_status = piix4_ospm_status;
|
||||
}
|
||||
|
||||
|
||||
@@ -478,7 +478,7 @@ static void do_cpu_reset(void *opaque)
|
||||
|
||||
void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
|
||||
{
|
||||
CPUState *cs = CPU(cpu);
|
||||
CPUState *cs;
|
||||
int kernel_size;
|
||||
int initrd_size;
|
||||
int is_linux = 0;
|
||||
@@ -488,6 +488,15 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
|
||||
int big_endian;
|
||||
static const ARMInsnFixup *primary_loader;
|
||||
|
||||
/* CPU objects (unlike devices) are not automatically reset on system
|
||||
* reset, so we must always register a handler to do so. If we're
|
||||
* actually loading a kernel, the handler is also responsible for
|
||||
* arranging that we start it correctly.
|
||||
*/
|
||||
for (cs = CPU(cpu); cs; cs = CPU_NEXT(cs)) {
|
||||
qemu_register_reset(do_cpu_reset, ARM_CPU(cs));
|
||||
}
|
||||
|
||||
/* Load the kernel. */
|
||||
if (!info->kernel_filename) {
|
||||
|
||||
@@ -652,9 +661,7 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info)
|
||||
}
|
||||
info->is_linux = is_linux;
|
||||
|
||||
for (; cs; cs = CPU_NEXT(cs)) {
|
||||
cpu = ARM_CPU(cs);
|
||||
cpu->env.boot_info = info;
|
||||
qemu_register_reset(do_cpu_reset, cpu);
|
||||
for (cs = CPU(cpu); cs; cs = CPU_NEXT(cs)) {
|
||||
ARM_CPU(cs)->env.boot_info = info;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include "strongarm.h"
|
||||
#include "hw/arm/arm.h"
|
||||
#include "hw/block/flash.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "exec/address-spaces.h"
|
||||
|
||||
static struct arm_boot_info collie_binfo = {
|
||||
@@ -41,13 +41,13 @@ static void collie_init(MachineState *machine)
|
||||
|
||||
dinfo = drive_get(IF_PFLASH, 0, 0);
|
||||
pflash_cfi01_register(SA_CS0, NULL, "collie.fl1", 0x02000000,
|
||||
dinfo ? dinfo->bdrv : NULL, (64 * 1024),
|
||||
512, 4, 0x00, 0x00, 0x00, 0x00, 0);
|
||||
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
|
||||
(64 * 1024), 512, 4, 0x00, 0x00, 0x00, 0x00, 0);
|
||||
|
||||
dinfo = drive_get(IF_PFLASH, 0, 1);
|
||||
pflash_cfi01_register(SA_CS1, NULL, "collie.fl2", 0x02000000,
|
||||
dinfo ? dinfo->bdrv : NULL, (64 * 1024),
|
||||
512, 4, 0x00, 0x00, 0x00, 0x00, 0);
|
||||
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
|
||||
(64 * 1024), 512, 4, 0x00, 0x00, 0x00, 0x00, 0);
|
||||
|
||||
sysbus_create_simple("scoop", 0x40800000, NULL);
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
#include "hw/block/flash.h"
|
||||
#include "hw/devices.h"
|
||||
#include "hw/boards.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "sysemu/qtest.h"
|
||||
|
||||
@@ -71,7 +71,7 @@ static void connex_init(MachineState *machine)
|
||||
be = 0;
|
||||
#endif
|
||||
if (!pflash_cfi01_register(0x00000000, NULL, "connext.rom", connex_rom,
|
||||
dinfo ? dinfo->bdrv : NULL,
|
||||
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
|
||||
sector_len, connex_rom / sector_len,
|
||||
2, 0, 0, 0, 0, be)) {
|
||||
fprintf(stderr, "qemu: Error registering flash memory.\n");
|
||||
@@ -109,7 +109,7 @@ static void verdex_init(MachineState *machine)
|
||||
be = 0;
|
||||
#endif
|
||||
if (!pflash_cfi01_register(0x00000000, NULL, "verdex.rom", verdex_rom,
|
||||
dinfo ? dinfo->bdrv : NULL,
|
||||
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
|
||||
sector_len, verdex_rom / sector_len,
|
||||
2, 0, 0, 0, 0, be)) {
|
||||
fprintf(stderr, "qemu: Error registering flash memory.\n");
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include "net/net.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/boards.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include "hw/devices.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/block/flash.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "sysemu/qtest.h"
|
||||
@@ -149,9 +149,9 @@ static void mainstone_common_init(MemoryRegion *address_space_mem,
|
||||
if (!pflash_cfi01_register(mainstone_flash_base[i], NULL,
|
||||
i ? "mainstone.flash1" : "mainstone.flash0",
|
||||
MAINSTONE_FLASH,
|
||||
dinfo->bdrv, sector_len,
|
||||
MAINSTONE_FLASH / sector_len, 4, 0, 0, 0, 0,
|
||||
be)) {
|
||||
blk_by_legacy_dinfo(dinfo),
|
||||
sector_len, MAINSTONE_FLASH / sector_len,
|
||||
4, 0, 0, 0, 0, be)) {
|
||||
fprintf(stderr, "qemu: Error registering flash memory.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -18,11 +18,10 @@
|
||||
#include "hw/char/serial.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "hw/ptimer.h"
|
||||
#include "block/block.h"
|
||||
#include "hw/block/flash.h"
|
||||
#include "ui/console.h"
|
||||
#include "hw/i2c/i2c.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "ui/pixel_ops.h"
|
||||
|
||||
@@ -1632,7 +1631,9 @@ static void musicpal_init(MachineState *machine)
|
||||
/* Register flash */
|
||||
dinfo = drive_get(IF_PFLASH, 0, 0);
|
||||
if (dinfo) {
|
||||
flash_size = bdrv_getlength(dinfo->bdrv);
|
||||
BlockBackend *blk = blk_by_legacy_dinfo(dinfo);
|
||||
|
||||
flash_size = blk_getlength(blk);
|
||||
if (flash_size != 8*1024*1024 && flash_size != 16*1024*1024 &&
|
||||
flash_size != 32*1024*1024) {
|
||||
fprintf(stderr, "Invalid flash image size\n");
|
||||
@@ -1647,16 +1648,14 @@ static void musicpal_init(MachineState *machine)
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
pflash_cfi02_register(0x100000000ULL-MP_FLASH_SIZE_MAX, NULL,
|
||||
"musicpal.flash", flash_size,
|
||||
dinfo->bdrv, 0x10000,
|
||||
(flash_size + 0xffff) >> 16,
|
||||
blk, 0x10000, (flash_size + 0xffff) >> 16,
|
||||
MP_FLASH_SIZE_MAX / flash_size,
|
||||
2, 0x00BF, 0x236D, 0x0000, 0x0000,
|
||||
0x5555, 0x2AAA, 1);
|
||||
#else
|
||||
pflash_cfi02_register(0x100000000ULL-MP_FLASH_SIZE_MAX, NULL,
|
||||
"musicpal.flash", flash_size,
|
||||
dinfo->bdrv, 0x10000,
|
||||
(flash_size + 0xffff) >> 16,
|
||||
blk, 0x10000, (flash_size + 0xffff) >> 16,
|
||||
MP_FLASH_SIZE_MAX / flash_size,
|
||||
2, 0x00BF, 0x236D, 0x0000, 0x0000,
|
||||
0x5555, 0x2AAA, 0);
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
#include "hw/hw.h"
|
||||
#include "hw/bt.h"
|
||||
#include "hw/loader.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "exec/address-spaces.h"
|
||||
|
||||
@@ -172,8 +172,9 @@ static void n8x0_nand_setup(struct n800_s *s)
|
||||
qdev_prop_set_uint16(s->nand, "version_id", 0);
|
||||
qdev_prop_set_int32(s->nand, "shift", 1);
|
||||
dinfo = drive_get(IF_MTD, 0, 0);
|
||||
if (dinfo && dinfo->bdrv) {
|
||||
qdev_prop_set_drive_nofail(s->nand, "drive", dinfo->bdrv);
|
||||
if (dinfo) {
|
||||
qdev_prop_set_drive_nofail(s->nand, "drive",
|
||||
blk_by_legacy_dinfo(dinfo));
|
||||
}
|
||||
qdev_init_nofail(s->nand);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(s->nand), 0,
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "hw/arm/omap.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/arm/soc_dma.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "qemu/range.h"
|
||||
#include "hw/sysbus.h"
|
||||
@@ -3978,7 +3979,8 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *system_memory,
|
||||
fprintf(stderr, "qemu: missing SecureDigital device\n");
|
||||
exit(1);
|
||||
}
|
||||
s->mmc = omap_mmc_init(0xfffb7800, system_memory, dinfo->bdrv,
|
||||
s->mmc = omap_mmc_init(0xfffb7800, system_memory,
|
||||
blk_by_legacy_dinfo(dinfo),
|
||||
qdev_get_gpio_in(s->ih[1], OMAP_INT_OQN),
|
||||
&s->drq[OMAP_DMA_MMC_TX],
|
||||
omap_findclk(s, "mmc_ck"));
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/arm/arm.h"
|
||||
@@ -2461,7 +2462,8 @@ struct omap_mpu_state_s *omap2420_mpu_init(MemoryRegion *sysmem,
|
||||
fprintf(stderr, "qemu: missing SecureDigital device\n");
|
||||
exit(1);
|
||||
}
|
||||
s->mmc = omap2_mmc_init(omap_l4tao(s->l4, 9), dinfo->bdrv,
|
||||
s->mmc = omap2_mmc_init(omap_l4tao(s->l4, 9),
|
||||
blk_by_legacy_dinfo(dinfo),
|
||||
qdev_get_gpio_in(s->ih[0], OMAP_INT_24XX_MMC_IRQ),
|
||||
&s->drq[OMAP24XX_DMA_MMC1_TX],
|
||||
omap_findclk(s, "mmc_fclk"), omap_findclk(s, "mmc_iclk"));
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
#include "hw/boards.h"
|
||||
#include "hw/arm/arm.h"
|
||||
#include "hw/block/flash.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/qtest.h"
|
||||
#include "exec/address-spaces.h"
|
||||
|
||||
@@ -154,8 +154,8 @@ static void sx1_init(MachineState *machine, const int version)
|
||||
if ((dinfo = drive_get(IF_PFLASH, 0, fl_idx)) != NULL) {
|
||||
if (!pflash_cfi01_register(OMAP_CS0_BASE, NULL,
|
||||
"omap_sx1.flash0-1", flash_size,
|
||||
dinfo->bdrv, sector_size,
|
||||
flash_size / sector_size,
|
||||
blk_by_legacy_dinfo(dinfo),
|
||||
sector_size, flash_size / sector_size,
|
||||
4, 0, 0, 0, 0, be)) {
|
||||
fprintf(stderr, "qemu: Error registering flash memory %d.\n",
|
||||
fl_idx);
|
||||
@@ -178,8 +178,8 @@ static void sx1_init(MachineState *machine, const int version)
|
||||
|
||||
if (!pflash_cfi01_register(OMAP_CS1_BASE, NULL,
|
||||
"omap_sx1.flash1-1", flash1_size,
|
||||
dinfo->bdrv, sector_size,
|
||||
flash1_size / sector_size,
|
||||
blk_by_legacy_dinfo(dinfo),
|
||||
sector_size, flash1_size / sector_size,
|
||||
4, 0, 0, 0, 0, be)) {
|
||||
fprintf(stderr, "qemu: Error registering flash memory %d.\n",
|
||||
fl_idx);
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "hw/i2c/i2c.h"
|
||||
#include "hw/ssi.h"
|
||||
#include "sysemu/char.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
|
||||
static struct {
|
||||
@@ -2085,7 +2086,8 @@ PXA2xxState *pxa270_init(MemoryRegion *address_space,
|
||||
fprintf(stderr, "qemu: missing SecureDigital device\n");
|
||||
exit(1);
|
||||
}
|
||||
s->mmc = pxa2xx_mmci_init(address_space, 0x41100000, dinfo->bdrv,
|
||||
s->mmc = pxa2xx_mmci_init(address_space, 0x41100000,
|
||||
blk_by_legacy_dinfo(dinfo),
|
||||
qdev_get_gpio_in(s->pic, PXA2XX_PIC_MMC),
|
||||
qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_MMCI),
|
||||
qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_MMCI));
|
||||
@@ -2217,7 +2219,8 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size)
|
||||
fprintf(stderr, "qemu: missing SecureDigital device\n");
|
||||
exit(1);
|
||||
}
|
||||
s->mmc = pxa2xx_mmci_init(address_space, 0x41100000, dinfo->bdrv,
|
||||
s->mmc = pxa2xx_mmci_init(address_space, 0x41100000,
|
||||
blk_by_legacy_dinfo(dinfo),
|
||||
qdev_get_gpio_in(s->pic, PXA2XX_PIC_MMC),
|
||||
qdev_get_gpio_in(s->dma, PXA2XX_RX_RQ_MMCI),
|
||||
qdev_get_gpio_in(s->dma, PXA2XX_TX_RQ_MMCI));
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/i2c/i2c.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
|
||||
@@ -22,10 +22,9 @@
|
||||
#include "hw/devices.h"
|
||||
#include "hw/arm/sharpsl.h"
|
||||
#include "ui/console.h"
|
||||
#include "block/block.h"
|
||||
#include "audio/audio.h"
|
||||
#include "hw/boards.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "exec/address-spaces.h"
|
||||
|
||||
@@ -170,7 +169,8 @@ static int sl_nand_init(SysBusDevice *dev)
|
||||
|
||||
s->ctl = 0;
|
||||
nand = drive_get(IF_MTD, 0, 0);
|
||||
s->nand = nand_init(nand ? nand->bdrv : NULL, s->manf_id, s->chip_id);
|
||||
s->nand = nand_init(nand ? blk_by_legacy_dinfo(nand) : NULL,
|
||||
s->manf_id, s->chip_id);
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &sl_ops, s, "sl", 0x40);
|
||||
sysbus_init_mmio(dev, &s->iomem);
|
||||
|
||||
@@ -17,11 +17,10 @@
|
||||
#include "hw/devices.h"
|
||||
#include "hw/arm/sharpsl.h"
|
||||
#include "hw/pcmcia.h"
|
||||
#include "block/block.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/i2c/i2c.h"
|
||||
#include "hw/ssi.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "exec/address-spaces.h"
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/i2c/i2c.h"
|
||||
#include "hw/boards.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "hw/block/flash.h"
|
||||
|
||||
@@ -338,7 +338,8 @@ static void versatile_init(MachineState *machine, int board_id)
|
||||
|
||||
dinfo = drive_get(IF_PFLASH, 0, 0);
|
||||
if (!pflash_cfi01_register(VERSATILE_FLASH_ADDR, NULL, "versatile.flash",
|
||||
VERSATILE_FLASH_SIZE, dinfo ? dinfo->bdrv : NULL,
|
||||
VERSATILE_FLASH_SIZE,
|
||||
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
|
||||
VERSATILE_FLASH_SECT_SIZE,
|
||||
VERSATILE_FLASH_SIZE / VERSATILE_FLASH_SECT_SIZE,
|
||||
4, 0x0089, 0x0018, 0x0000, 0x0, 0)) {
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
#include "hw/boards.h"
|
||||
#include "hw/loader.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "hw/block/flash.h"
|
||||
#include "sysemu/device_tree.h"
|
||||
#include "qemu/error-report.h"
|
||||
@@ -491,7 +491,8 @@ static pflash_t *ve_pflash_cfi01_register(hwaddr base, const char *name,
|
||||
{
|
||||
DeviceState *dev = qdev_create(NULL, "cfi.pflash01");
|
||||
|
||||
if (di && qdev_prop_set_drive(dev, "drive", di->bdrv)) {
|
||||
if (di && qdev_prop_set_drive(dev, "drive",
|
||||
blk_by_legacy_dinfo(di))) {
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "hw/arm/primecell.h"
|
||||
#include "hw/devices.h"
|
||||
#include "net/net.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/device_tree.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/kvm.h"
|
||||
@@ -190,47 +191,48 @@ static void create_fdt(VirtBoardInfo *vbi)
|
||||
|
||||
static void fdt_add_psci_node(const VirtBoardInfo *vbi)
|
||||
{
|
||||
uint32_t cpu_suspend_fn;
|
||||
uint32_t cpu_off_fn;
|
||||
uint32_t cpu_on_fn;
|
||||
uint32_t migrate_fn;
|
||||
void *fdt = vbi->fdt;
|
||||
ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(0));
|
||||
|
||||
/* No PSCI for TCG yet */
|
||||
if (kvm_enabled()) {
|
||||
uint32_t cpu_suspend_fn;
|
||||
uint32_t cpu_off_fn;
|
||||
uint32_t cpu_on_fn;
|
||||
uint32_t migrate_fn;
|
||||
qemu_fdt_add_subnode(fdt, "/psci");
|
||||
if (armcpu->psci_version == 2) {
|
||||
const char comp[] = "arm,psci-0.2\0arm,psci";
|
||||
qemu_fdt_setprop(fdt, "/psci", "compatible", comp, sizeof(comp));
|
||||
|
||||
qemu_fdt_add_subnode(fdt, "/psci");
|
||||
if (armcpu->psci_version == 2) {
|
||||
const char comp[] = "arm,psci-0.2\0arm,psci";
|
||||
qemu_fdt_setprop(fdt, "/psci", "compatible", comp, sizeof(comp));
|
||||
|
||||
cpu_off_fn = QEMU_PSCI_0_2_FN_CPU_OFF;
|
||||
if (arm_feature(&armcpu->env, ARM_FEATURE_AARCH64)) {
|
||||
cpu_suspend_fn = QEMU_PSCI_0_2_FN64_CPU_SUSPEND;
|
||||
cpu_on_fn = QEMU_PSCI_0_2_FN64_CPU_ON;
|
||||
migrate_fn = QEMU_PSCI_0_2_FN64_MIGRATE;
|
||||
} else {
|
||||
cpu_suspend_fn = QEMU_PSCI_0_2_FN_CPU_SUSPEND;
|
||||
cpu_on_fn = QEMU_PSCI_0_2_FN_CPU_ON;
|
||||
migrate_fn = QEMU_PSCI_0_2_FN_MIGRATE;
|
||||
}
|
||||
cpu_off_fn = QEMU_PSCI_0_2_FN_CPU_OFF;
|
||||
if (arm_feature(&armcpu->env, ARM_FEATURE_AARCH64)) {
|
||||
cpu_suspend_fn = QEMU_PSCI_0_2_FN64_CPU_SUSPEND;
|
||||
cpu_on_fn = QEMU_PSCI_0_2_FN64_CPU_ON;
|
||||
migrate_fn = QEMU_PSCI_0_2_FN64_MIGRATE;
|
||||
} else {
|
||||
qemu_fdt_setprop_string(fdt, "/psci", "compatible", "arm,psci");
|
||||
|
||||
cpu_suspend_fn = QEMU_PSCI_0_1_FN_CPU_SUSPEND;
|
||||
cpu_off_fn = QEMU_PSCI_0_1_FN_CPU_OFF;
|
||||
cpu_on_fn = QEMU_PSCI_0_1_FN_CPU_ON;
|
||||
migrate_fn = QEMU_PSCI_0_1_FN_MIGRATE;
|
||||
cpu_suspend_fn = QEMU_PSCI_0_2_FN_CPU_SUSPEND;
|
||||
cpu_on_fn = QEMU_PSCI_0_2_FN_CPU_ON;
|
||||
migrate_fn = QEMU_PSCI_0_2_FN_MIGRATE;
|
||||
}
|
||||
} else {
|
||||
qemu_fdt_setprop_string(fdt, "/psci", "compatible", "arm,psci");
|
||||
|
||||
qemu_fdt_setprop_string(fdt, "/psci", "method", "hvc");
|
||||
|
||||
qemu_fdt_setprop_cell(fdt, "/psci", "cpu_suspend", cpu_suspend_fn);
|
||||
qemu_fdt_setprop_cell(fdt, "/psci", "cpu_off", cpu_off_fn);
|
||||
qemu_fdt_setprop_cell(fdt, "/psci", "cpu_on", cpu_on_fn);
|
||||
qemu_fdt_setprop_cell(fdt, "/psci", "migrate", migrate_fn);
|
||||
cpu_suspend_fn = QEMU_PSCI_0_1_FN_CPU_SUSPEND;
|
||||
cpu_off_fn = QEMU_PSCI_0_1_FN_CPU_OFF;
|
||||
cpu_on_fn = QEMU_PSCI_0_1_FN_CPU_ON;
|
||||
migrate_fn = QEMU_PSCI_0_1_FN_MIGRATE;
|
||||
}
|
||||
|
||||
/* We adopt the PSCI spec's nomenclature, and use 'conduit' to refer
|
||||
* to the instruction that should be used to invoke PSCI functions.
|
||||
* However, the device tree binding uses 'method' instead, so that is
|
||||
* what we should use here.
|
||||
*/
|
||||
qemu_fdt_setprop_string(fdt, "/psci", "method", "hvc");
|
||||
|
||||
qemu_fdt_setprop_cell(fdt, "/psci", "cpu_suspend", cpu_suspend_fn);
|
||||
qemu_fdt_setprop_cell(fdt, "/psci", "cpu_off", cpu_off_fn);
|
||||
qemu_fdt_setprop_cell(fdt, "/psci", "cpu_on", cpu_on_fn);
|
||||
qemu_fdt_setprop_cell(fdt, "/psci", "migrate", migrate_fn);
|
||||
}
|
||||
|
||||
static void fdt_add_timer_nodes(const VirtBoardInfo *vbi)
|
||||
@@ -239,14 +241,23 @@ static void fdt_add_timer_nodes(const VirtBoardInfo *vbi)
|
||||
* but for the GIC implementation provided by both QEMU and KVM
|
||||
* they are edge-triggered.
|
||||
*/
|
||||
ARMCPU *armcpu;
|
||||
uint32_t irqflags = GIC_FDT_IRQ_FLAGS_EDGE_LO_HI;
|
||||
|
||||
irqflags = deposit32(irqflags, GIC_FDT_IRQ_PPI_CPU_START,
|
||||
GIC_FDT_IRQ_PPI_CPU_WIDTH, (1 << vbi->smp_cpus) - 1);
|
||||
|
||||
qemu_fdt_add_subnode(vbi->fdt, "/timer");
|
||||
qemu_fdt_setprop_string(vbi->fdt, "/timer",
|
||||
"compatible", "arm,armv7-timer");
|
||||
|
||||
armcpu = ARM_CPU(qemu_get_cpu(0));
|
||||
if (arm_feature(&armcpu->env, ARM_FEATURE_V8)) {
|
||||
const char compat[] = "arm,armv8-timer\0arm,armv7-timer";
|
||||
qemu_fdt_setprop(vbi->fdt, "/timer", "compatible",
|
||||
compat, sizeof(compat));
|
||||
} else {
|
||||
qemu_fdt_setprop_string(vbi->fdt, "/timer", "compatible",
|
||||
"arm,armv7-timer");
|
||||
}
|
||||
qemu_fdt_setprop_cells(vbi->fdt, "/timer", "interrupts",
|
||||
GIC_FDT_IRQ_TYPE_PPI, 13, irqflags,
|
||||
GIC_FDT_IRQ_TYPE_PPI, 14, irqflags,
|
||||
@@ -450,7 +461,8 @@ static void create_one_flash(const char *name, hwaddr flashbase,
|
||||
DeviceState *dev = qdev_create(NULL, "cfi.pflash01");
|
||||
const uint64_t sectorlength = 256 * 1024;
|
||||
|
||||
if (dinfo && qdev_prop_set_drive(dev, "drive", dinfo->bdrv)) {
|
||||
if (dinfo && qdev_prop_set_drive(dev, "drive",
|
||||
blk_by_legacy_dinfo(dinfo))) {
|
||||
abort();
|
||||
}
|
||||
|
||||
@@ -537,23 +549,12 @@ static void machvirt_init(MachineState *machine)
|
||||
|
||||
vbi->smp_cpus = smp_cpus;
|
||||
|
||||
/*
|
||||
* Only supported method of starting secondary CPUs is PSCI and
|
||||
* PSCI is not yet supported with TCG, so limit smp_cpus to 1
|
||||
* if we're not using KVM.
|
||||
*/
|
||||
if (!kvm_enabled() && smp_cpus > 1) {
|
||||
error_report("mach-virt: must enable KVM to use multiple CPUs");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (machine->ram_size > vbi->memmap[VIRT_MEM].size) {
|
||||
error_report("mach-virt: cannot model more than 30GB RAM");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
create_fdt(vbi);
|
||||
fdt_add_timer_nodes(vbi);
|
||||
|
||||
for (n = 0; n < smp_cpus; n++) {
|
||||
ObjectClass *oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
|
||||
@@ -565,6 +566,9 @@ static void machvirt_init(MachineState *machine)
|
||||
}
|
||||
cpuobj = object_new(object_class_get_name(oc));
|
||||
|
||||
object_property_set_int(cpuobj, QEMU_PSCI_CONDUIT_HVC, "psci-conduit",
|
||||
NULL);
|
||||
|
||||
/* Secondary CPUs start in PSCI powered-down state */
|
||||
if (n > 0) {
|
||||
object_property_set_bool(cpuobj, true, "start-powered-off", NULL);
|
||||
@@ -577,6 +581,7 @@ static void machvirt_init(MachineState *machine)
|
||||
|
||||
object_property_set_bool(cpuobj, true, "realized", NULL);
|
||||
}
|
||||
fdt_add_timer_nodes(vbi);
|
||||
fdt_add_cpu_nodes(vbi);
|
||||
fdt_add_psci_node(vbi);
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/block/flash.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "hw/loader.h"
|
||||
#include "hw/ssi.h"
|
||||
#include "qemu/error-report.h"
|
||||
@@ -164,7 +164,8 @@ static void zynq_init(MachineState *machine)
|
||||
|
||||
/* AMD */
|
||||
pflash_cfi02_register(0xe2000000, NULL, "zynq.pflash", FLASH_SIZE,
|
||||
dinfo ? dinfo->bdrv : NULL, FLASH_SECTOR_SIZE,
|
||||
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
|
||||
FLASH_SECTOR_SIZE,
|
||||
FLASH_SIZE/FLASH_SECTOR_SIZE, 1,
|
||||
1, 0x0066, 0x0022, 0x0000, 0x0000, 0x0555, 0x2aa,
|
||||
0);
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include "hw/boards.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/block/flash.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "ui/console.h"
|
||||
#include "audio/audio.h"
|
||||
#include "exec/address-spaces.h"
|
||||
@@ -336,9 +336,9 @@ static void z2_init(MachineState *machine)
|
||||
|
||||
if (!pflash_cfi01_register(Z2_FLASH_BASE,
|
||||
NULL, "z2.flash0", Z2_FLASH_SIZE,
|
||||
dinfo ? dinfo->bdrv : NULL, sector_len,
|
||||
Z2_FLASH_SIZE / sector_len, 4, 0, 0, 0, 0,
|
||||
be)) {
|
||||
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
|
||||
sector_len, Z2_FLASH_SIZE / sector_len,
|
||||
4, 0, 0, 0, 0, be)) {
|
||||
fprintf(stderr, "qemu: Error registering flash memory.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
*/
|
||||
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "hw/block/block.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
@@ -17,8 +18,10 @@ void blkconf_serial(BlockConf *conf, char **serial)
|
||||
|
||||
if (!*serial) {
|
||||
/* try to fall back to value set with legacy -drive serial=... */
|
||||
dinfo = drive_get_by_blockdev(conf->bs);
|
||||
*serial = g_strdup(dinfo->serial);
|
||||
dinfo = blk_legacy_dinfo(conf->blk);
|
||||
if (dinfo) {
|
||||
*serial = g_strdup(dinfo->serial);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,16 +33,18 @@ void blkconf_geometry(BlockConf *conf, int *ptrans,
|
||||
|
||||
if (!conf->cyls && !conf->heads && !conf->secs) {
|
||||
/* try to fall back to value set with legacy -drive cyls=... */
|
||||
dinfo = drive_get_by_blockdev(conf->bs);
|
||||
conf->cyls = dinfo->cyls;
|
||||
conf->heads = dinfo->heads;
|
||||
conf->secs = dinfo->secs;
|
||||
if (ptrans) {
|
||||
*ptrans = dinfo->trans;
|
||||
dinfo = blk_legacy_dinfo(conf->blk);
|
||||
if (dinfo) {
|
||||
conf->cyls = dinfo->cyls;
|
||||
conf->heads = dinfo->heads;
|
||||
conf->secs = dinfo->secs;
|
||||
if (ptrans) {
|
||||
*ptrans = dinfo->trans;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!conf->cyls && !conf->heads && !conf->secs) {
|
||||
hd_geometry_guess(conf->bs,
|
||||
hd_geometry_guess(conf->blk,
|
||||
&conf->cyls, &conf->heads, &conf->secs,
|
||||
ptrans);
|
||||
} else if (ptrans && *ptrans == BIOS_ATA_TRANSLATION_AUTO) {
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#include "qemu/thread.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "hw/virtio/dataplane/vring.h"
|
||||
#include "block/block.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "hw/virtio/virtio-blk.h"
|
||||
#include "virtio-blk.h"
|
||||
#include "block/aio.h"
|
||||
@@ -30,7 +30,7 @@ struct VirtIOBlockDataPlane {
|
||||
bool stopping;
|
||||
bool disabled;
|
||||
|
||||
VirtIOBlkConf *blk;
|
||||
VirtIOBlkConf *conf;
|
||||
|
||||
VirtIODevice *vdev;
|
||||
Vring vring; /* virtqueue vring */
|
||||
@@ -94,7 +94,7 @@ static void handle_notify(EventNotifier *e)
|
||||
VirtIOBlock *vblk = VIRTIO_BLK(s->vdev);
|
||||
|
||||
event_notifier_test_and_clear(&s->host_notifier);
|
||||
bdrv_io_plug(s->blk->conf.bs);
|
||||
blk_io_plug(s->conf->conf.blk);
|
||||
for (;;) {
|
||||
MultiReqBuffer mrb = {
|
||||
.num_writes = 0,
|
||||
@@ -120,7 +120,7 @@ static void handle_notify(EventNotifier *e)
|
||||
virtio_blk_handle_request(req, &mrb);
|
||||
}
|
||||
|
||||
virtio_submit_multiwrite(s->blk->conf.bs, &mrb);
|
||||
virtio_submit_multiwrite(s->conf->conf.blk, &mrb);
|
||||
|
||||
if (likely(ret == -EAGAIN)) { /* vring emptied */
|
||||
/* Re-enable guest->host notifies and stop processing the vring.
|
||||
@@ -133,11 +133,11 @@ static void handle_notify(EventNotifier *e)
|
||||
break;
|
||||
}
|
||||
}
|
||||
bdrv_io_unplug(s->blk->conf.bs);
|
||||
blk_io_unplug(s->conf->conf.blk);
|
||||
}
|
||||
|
||||
/* Context: QEMU global mutex held */
|
||||
void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
|
||||
void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf,
|
||||
VirtIOBlockDataPlane **dataplane,
|
||||
Error **errp)
|
||||
{
|
||||
@@ -148,7 +148,7 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
|
||||
|
||||
*dataplane = NULL;
|
||||
|
||||
if (!blk->data_plane && !blk->iothread) {
|
||||
if (!conf->data_plane && !conf->iothread) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -163,7 +163,8 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
|
||||
/* If dataplane is (re-)enabled while the guest is running there could be
|
||||
* block jobs that can conflict.
|
||||
*/
|
||||
if (bdrv_op_is_blocked(blk->conf.bs, BLOCK_OP_TYPE_DATAPLANE, &local_err)) {
|
||||
if (blk_op_is_blocked(conf->conf.blk, BLOCK_OP_TYPE_DATAPLANE,
|
||||
&local_err)) {
|
||||
error_setg(errp, "cannot start dataplane thread: %s",
|
||||
error_get_pretty(local_err));
|
||||
error_free(local_err);
|
||||
@@ -172,10 +173,10 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
|
||||
|
||||
s = g_new0(VirtIOBlockDataPlane, 1);
|
||||
s->vdev = vdev;
|
||||
s->blk = blk;
|
||||
s->conf = conf;
|
||||
|
||||
if (blk->iothread) {
|
||||
s->iothread = blk->iothread;
|
||||
if (conf->iothread) {
|
||||
s->iothread = conf->iothread;
|
||||
object_ref(OBJECT(s->iothread));
|
||||
} else {
|
||||
/* Create per-device IOThread if none specified. This is for
|
||||
@@ -192,9 +193,9 @@ void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
|
||||
s->bh = aio_bh_new(s->ctx, notify_guest_bh, s);
|
||||
|
||||
error_setg(&s->blocker, "block device is in use by data plane");
|
||||
bdrv_op_block_all(blk->conf.bs, s->blocker);
|
||||
bdrv_op_unblock(blk->conf.bs, BLOCK_OP_TYPE_RESIZE, s->blocker);
|
||||
bdrv_op_unblock(blk->conf.bs, BLOCK_OP_TYPE_DRIVE_DEL, s->blocker);
|
||||
blk_op_block_all(conf->conf.blk, s->blocker);
|
||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_RESIZE, s->blocker);
|
||||
blk_op_unblock(conf->conf.blk, BLOCK_OP_TYPE_DRIVE_DEL, s->blocker);
|
||||
|
||||
*dataplane = s;
|
||||
}
|
||||
@@ -207,7 +208,7 @@ void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s)
|
||||
}
|
||||
|
||||
virtio_blk_data_plane_stop(s);
|
||||
bdrv_op_unblock_all(s->blk->conf.bs, s->blocker);
|
||||
blk_op_unblock_all(s->conf->conf.blk, s->blocker);
|
||||
error_free(s->blocker);
|
||||
object_unref(OBJECT(s->iothread));
|
||||
qemu_bh_delete(s->bh);
|
||||
@@ -262,7 +263,7 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s)
|
||||
s->started = true;
|
||||
trace_virtio_blk_data_plane_start(s);
|
||||
|
||||
bdrv_set_aio_context(s->blk->conf.bs, s->ctx);
|
||||
blk_set_aio_context(s->conf->conf.blk, s->ctx);
|
||||
|
||||
/* Kick right away to begin processing requests already in vring */
|
||||
event_notifier_set(virtio_queue_get_host_notifier(vq));
|
||||
@@ -308,7 +309,7 @@ void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s)
|
||||
aio_set_event_notifier(s->ctx, &s->host_notifier, NULL);
|
||||
|
||||
/* Drain and switch bs back to the QEMU main loop */
|
||||
bdrv_set_aio_context(s->blk->conf.bs, qemu_get_aio_context());
|
||||
blk_set_aio_context(s->conf->conf.blk, qemu_get_aio_context());
|
||||
|
||||
aio_context_release(s->ctx);
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
typedef struct VirtIOBlockDataPlane VirtIOBlockDataPlane;
|
||||
|
||||
void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk,
|
||||
void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *conf,
|
||||
VirtIOBlockDataPlane **dataplane,
|
||||
Error **errp);
|
||||
void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s);
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "qemu/timer.h"
|
||||
#include "hw/isa/isa.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "qemu/log.h"
|
||||
@@ -113,7 +114,7 @@ static const FDFormat fd_formats[] = {
|
||||
{ FDRIVE_DRV_NONE, -1, -1, 0, 0, },
|
||||
};
|
||||
|
||||
static void pick_geometry(BlockDriverState *bs, int *nb_heads,
|
||||
static void pick_geometry(BlockBackend *blk, int *nb_heads,
|
||||
int *max_track, int *last_sect,
|
||||
FDriveType drive_in, FDriveType *drive,
|
||||
FDriveRate *rate)
|
||||
@@ -122,7 +123,7 @@ static void pick_geometry(BlockDriverState *bs, int *nb_heads,
|
||||
uint64_t nb_sectors, size;
|
||||
int i, first_match, match;
|
||||
|
||||
bdrv_get_geometry(bs, &nb_sectors);
|
||||
blk_get_geometry(blk, &nb_sectors);
|
||||
match = -1;
|
||||
first_match = -1;
|
||||
for (i = 0; ; i++) {
|
||||
@@ -175,7 +176,7 @@ typedef enum FDiskFlags {
|
||||
|
||||
typedef struct FDrive {
|
||||
FDCtrl *fdctrl;
|
||||
BlockDriverState *bs;
|
||||
BlockBackend *blk;
|
||||
/* Drive status */
|
||||
FDriveType drive;
|
||||
uint8_t perpendicular; /* 2.88 MB access mode */
|
||||
@@ -260,7 +261,7 @@ static int fd_seek(FDrive *drv, uint8_t head, uint8_t track, uint8_t sect,
|
||||
#endif
|
||||
drv->head = head;
|
||||
if (drv->track != track) {
|
||||
if (drv->bs != NULL && bdrv_is_inserted(drv->bs)) {
|
||||
if (drv->blk != NULL && blk_is_inserted(drv->blk)) {
|
||||
drv->media_changed = 0;
|
||||
}
|
||||
ret = 1;
|
||||
@@ -269,7 +270,7 @@ static int fd_seek(FDrive *drv, uint8_t head, uint8_t track, uint8_t sect,
|
||||
drv->sect = sect;
|
||||
}
|
||||
|
||||
if (drv->bs == NULL || !bdrv_is_inserted(drv->bs)) {
|
||||
if (drv->blk == NULL || !blk_is_inserted(drv->blk)) {
|
||||
ret = 2;
|
||||
}
|
||||
|
||||
@@ -291,11 +292,11 @@ static void fd_revalidate(FDrive *drv)
|
||||
FDriveRate rate;
|
||||
|
||||
FLOPPY_DPRINTF("revalidate\n");
|
||||
if (drv->bs != NULL) {
|
||||
ro = bdrv_is_read_only(drv->bs);
|
||||
pick_geometry(drv->bs, &nb_heads, &max_track,
|
||||
if (drv->blk != NULL) {
|
||||
ro = blk_is_read_only(drv->blk);
|
||||
pick_geometry(drv->blk, &nb_heads, &max_track,
|
||||
&last_sect, drv->drive, &drive, &rate);
|
||||
if (!bdrv_is_inserted(drv->bs)) {
|
||||
if (!blk_is_inserted(drv->blk)) {
|
||||
FLOPPY_DPRINTF("No disk in drive\n");
|
||||
} else {
|
||||
FLOPPY_DPRINTF("Floppy disk (%d h %d t %d s) %s\n", nb_heads,
|
||||
@@ -665,7 +666,7 @@ static bool fdrive_media_changed_needed(void *opaque)
|
||||
{
|
||||
FDrive *drive = opaque;
|
||||
|
||||
return (drive->bs != NULL && drive->media_changed != 1);
|
||||
return (drive->blk != NULL && drive->media_changed != 1);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_fdrive_media_changed = {
|
||||
@@ -910,8 +911,9 @@ static void fdctrl_reset(FDCtrl *fdctrl, int do_irq)
|
||||
/* Initialise controller */
|
||||
fdctrl->sra = 0;
|
||||
fdctrl->srb = 0xc0;
|
||||
if (!fdctrl->drives[1].bs)
|
||||
if (!fdctrl->drives[1].blk) {
|
||||
fdctrl->sra |= FD_SRA_nDRV2;
|
||||
}
|
||||
fdctrl->cur_drv = 0;
|
||||
fdctrl->dor = FD_DOR_nRESET;
|
||||
fdctrl->dor |= (fdctrl->dma_chann != -1) ? FD_DOR_DMAEN : 0;
|
||||
@@ -1403,7 +1405,7 @@ static int fdctrl_transfer_handler (void *opaque, int nchan,
|
||||
status2 = FD_SR2_SNS;
|
||||
if (dma_len > fdctrl->data_len)
|
||||
dma_len = fdctrl->data_len;
|
||||
if (cur_drv->bs == NULL) {
|
||||
if (cur_drv->blk == NULL) {
|
||||
if (fdctrl->data_dir == FD_DIR_WRITE)
|
||||
fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
|
||||
else
|
||||
@@ -1424,8 +1426,8 @@ static int fdctrl_transfer_handler (void *opaque, int nchan,
|
||||
if (fdctrl->data_dir != FD_DIR_WRITE ||
|
||||
len < FD_SECTOR_LEN || rel_pos != 0) {
|
||||
/* READ & SCAN commands and realign to a sector for WRITE */
|
||||
if (bdrv_read(cur_drv->bs, fd_sector(cur_drv),
|
||||
fdctrl->fifo, 1) < 0) {
|
||||
if (blk_read(cur_drv->blk, fd_sector(cur_drv),
|
||||
fdctrl->fifo, 1) < 0) {
|
||||
FLOPPY_DPRINTF("Floppy: error getting sector %d\n",
|
||||
fd_sector(cur_drv));
|
||||
/* Sure, image size is too small... */
|
||||
@@ -1452,8 +1454,8 @@ static int fdctrl_transfer_handler (void *opaque, int nchan,
|
||||
|
||||
DMA_read_memory (nchan, fdctrl->fifo + rel_pos,
|
||||
fdctrl->data_pos, len);
|
||||
if (bdrv_write(cur_drv->bs, fd_sector(cur_drv),
|
||||
fdctrl->fifo, 1) < 0) {
|
||||
if (blk_write(cur_drv->blk, fd_sector(cur_drv),
|
||||
fdctrl->fifo, 1) < 0) {
|
||||
FLOPPY_DPRINTF("error writing sector %d\n",
|
||||
fd_sector(cur_drv));
|
||||
fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
|
||||
@@ -1528,7 +1530,8 @@ static uint32_t fdctrl_read_data(FDCtrl *fdctrl)
|
||||
fd_sector(cur_drv));
|
||||
return 0;
|
||||
}
|
||||
if (bdrv_read(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {
|
||||
if (blk_read(cur_drv->blk, fd_sector(cur_drv), fdctrl->fifo, 1)
|
||||
< 0) {
|
||||
FLOPPY_DPRINTF("error getting sector %d\n",
|
||||
fd_sector(cur_drv));
|
||||
/* Sure, image size is too small... */
|
||||
@@ -1597,8 +1600,8 @@ static void fdctrl_format_sector(FDCtrl *fdctrl)
|
||||
break;
|
||||
}
|
||||
memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
|
||||
if (cur_drv->bs == NULL ||
|
||||
bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {
|
||||
if (cur_drv->blk == NULL ||
|
||||
blk_write(cur_drv->blk, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {
|
||||
FLOPPY_DPRINTF("error formatting sector %d\n", fd_sector(cur_drv));
|
||||
fdctrl_stop_transfer(fdctrl, FD_SR0_ABNTERM | FD_SR0_SEEK, 0x00, 0x00);
|
||||
} else {
|
||||
@@ -1988,7 +1991,8 @@ static void fdctrl_write_data(FDCtrl *fdctrl, uint32_t value)
|
||||
if (pos == FD_SECTOR_LEN - 1 ||
|
||||
fdctrl->data_pos == fdctrl->data_len) {
|
||||
cur_drv = get_cur_drv(fdctrl);
|
||||
if (bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {
|
||||
if (blk_write(cur_drv->blk, fd_sector(cur_drv), fdctrl->fifo, 1)
|
||||
< 0) {
|
||||
FLOPPY_DPRINTF("error writing sector %d\n",
|
||||
fd_sector(cur_drv));
|
||||
return;
|
||||
@@ -2076,12 +2080,12 @@ static void fdctrl_connect_drives(FDCtrl *fdctrl, Error **errp)
|
||||
drive = &fdctrl->drives[i];
|
||||
drive->fdctrl = fdctrl;
|
||||
|
||||
if (drive->bs) {
|
||||
if (bdrv_get_on_error(drive->bs, 0) != BLOCKDEV_ON_ERROR_ENOSPC) {
|
||||
if (drive->blk) {
|
||||
if (blk_get_on_error(drive->blk, 0) != BLOCKDEV_ON_ERROR_ENOSPC) {
|
||||
error_setg(errp, "fdc doesn't support drive option werror");
|
||||
return;
|
||||
}
|
||||
if (bdrv_get_on_error(drive->bs, 1) != BLOCKDEV_ON_ERROR_REPORT) {
|
||||
if (blk_get_on_error(drive->blk, 1) != BLOCKDEV_ON_ERROR_REPORT) {
|
||||
error_setg(errp, "fdc doesn't support drive option rerror");
|
||||
return;
|
||||
}
|
||||
@@ -2089,8 +2093,8 @@ static void fdctrl_connect_drives(FDCtrl *fdctrl, Error **errp)
|
||||
|
||||
fd_init(drive);
|
||||
fdctrl_change_cb(drive, 0);
|
||||
if (drive->bs) {
|
||||
bdrv_set_dev_ops(drive->bs, &fdctrl_block_ops, drive);
|
||||
if (drive->blk) {
|
||||
blk_set_dev_ops(drive->blk, &fdctrl_block_ops, drive);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2107,10 +2111,10 @@ ISADevice *fdctrl_init_isa(ISABus *bus, DriveInfo **fds)
|
||||
dev = DEVICE(isadev);
|
||||
|
||||
if (fds[0]) {
|
||||
qdev_prop_set_drive_nofail(dev, "driveA", fds[0]->bdrv);
|
||||
qdev_prop_set_drive_nofail(dev, "driveA", blk_by_legacy_dinfo(fds[0]));
|
||||
}
|
||||
if (fds[1]) {
|
||||
qdev_prop_set_drive_nofail(dev, "driveB", fds[1]->bdrv);
|
||||
qdev_prop_set_drive_nofail(dev, "driveB", blk_by_legacy_dinfo(fds[1]));
|
||||
}
|
||||
qdev_init_nofail(dev);
|
||||
|
||||
@@ -2130,10 +2134,10 @@ void fdctrl_init_sysbus(qemu_irq irq, int dma_chann,
|
||||
fdctrl = &sys->state;
|
||||
fdctrl->dma_chann = dma_chann; /* FIXME */
|
||||
if (fds[0]) {
|
||||
qdev_prop_set_drive_nofail(dev, "driveA", fds[0]->bdrv);
|
||||
qdev_prop_set_drive_nofail(dev, "driveA", blk_by_legacy_dinfo(fds[0]));
|
||||
}
|
||||
if (fds[1]) {
|
||||
qdev_prop_set_drive_nofail(dev, "driveB", fds[1]->bdrv);
|
||||
qdev_prop_set_drive_nofail(dev, "driveB", blk_by_legacy_dinfo(fds[1]));
|
||||
}
|
||||
qdev_init_nofail(dev);
|
||||
sbd = SYS_BUS_DEVICE(dev);
|
||||
@@ -2149,7 +2153,7 @@ void sun4m_fdctrl_init(qemu_irq irq, hwaddr io_base,
|
||||
|
||||
dev = qdev_create(NULL, "SUNW,fdtwo");
|
||||
if (fds[0]) {
|
||||
qdev_prop_set_drive_nofail(dev, "drive", fds[0]->bdrv);
|
||||
qdev_prop_set_drive_nofail(dev, "drive", blk_by_legacy_dinfo(fds[0]));
|
||||
}
|
||||
qdev_init_nofail(dev);
|
||||
sys = SYSBUS_FDC(dev);
|
||||
@@ -2286,8 +2290,8 @@ static Property isa_fdc_properties[] = {
|
||||
DEFINE_PROP_UINT32("iobase", FDCtrlISABus, iobase, 0x3f0),
|
||||
DEFINE_PROP_UINT32("irq", FDCtrlISABus, irq, 6),
|
||||
DEFINE_PROP_UINT32("dma", FDCtrlISABus, dma, 2),
|
||||
DEFINE_PROP_DRIVE("driveA", FDCtrlISABus, state.drives[0].bs),
|
||||
DEFINE_PROP_DRIVE("driveB", FDCtrlISABus, state.drives[1].bs),
|
||||
DEFINE_PROP_DRIVE("driveA", FDCtrlISABus, state.drives[0].blk),
|
||||
DEFINE_PROP_DRIVE("driveB", FDCtrlISABus, state.drives[1].blk),
|
||||
DEFINE_PROP_BIT("check_media_rate", FDCtrlISABus, state.check_media_rate,
|
||||
0, true),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
@@ -2336,8 +2340,8 @@ static const VMStateDescription vmstate_sysbus_fdc ={
|
||||
};
|
||||
|
||||
static Property sysbus_fdc_properties[] = {
|
||||
DEFINE_PROP_DRIVE("driveA", FDCtrlSysBus, state.drives[0].bs),
|
||||
DEFINE_PROP_DRIVE("driveB", FDCtrlSysBus, state.drives[1].bs),
|
||||
DEFINE_PROP_DRIVE("driveA", FDCtrlSysBus, state.drives[0].blk),
|
||||
DEFINE_PROP_DRIVE("driveB", FDCtrlSysBus, state.drives[1].blk),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
@@ -2357,7 +2361,7 @@ static const TypeInfo sysbus_fdc_info = {
|
||||
};
|
||||
|
||||
static Property sun4m_fdc_properties[] = {
|
||||
DEFINE_PROP_DRIVE("drive", FDCtrlSysBus, state.drives[0].bs),
|
||||
DEFINE_PROP_DRIVE("drive", FDCtrlSysBus, state.drives[0].blk),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "block/block.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "hw/block/block.h"
|
||||
#include "trace.h"
|
||||
|
||||
@@ -49,7 +49,7 @@ struct partition {
|
||||
|
||||
/* try to guess the disk logical geometry from the MSDOS partition table.
|
||||
Return 0 if OK, -1 if could not guess */
|
||||
static int guess_disk_lchs(BlockDriverState *bs,
|
||||
static int guess_disk_lchs(BlockBackend *blk,
|
||||
int *pcylinders, int *pheads, int *psectors)
|
||||
{
|
||||
uint8_t buf[BDRV_SECTOR_SIZE];
|
||||
@@ -58,14 +58,14 @@ static int guess_disk_lchs(BlockDriverState *bs,
|
||||
uint32_t nr_sects;
|
||||
uint64_t nb_sectors;
|
||||
|
||||
bdrv_get_geometry(bs, &nb_sectors);
|
||||
blk_get_geometry(blk, &nb_sectors);
|
||||
|
||||
/**
|
||||
* The function will be invoked during startup not only in sync I/O mode,
|
||||
* but also in async I/O mode. So the I/O throttling function has to
|
||||
* be disabled temporarily here, not permanently.
|
||||
*/
|
||||
if (bdrv_read_unthrottled(bs, 0, buf, 1) < 0) {
|
||||
if (blk_read_unthrottled(blk, 0, buf, 1) < 0) {
|
||||
return -1;
|
||||
}
|
||||
/* test msdos magic */
|
||||
@@ -90,20 +90,20 @@ static int guess_disk_lchs(BlockDriverState *bs,
|
||||
*pheads = heads;
|
||||
*psectors = sectors;
|
||||
*pcylinders = cylinders;
|
||||
trace_hd_geometry_lchs_guess(bs, cylinders, heads, sectors);
|
||||
trace_hd_geometry_lchs_guess(blk, cylinders, heads, sectors);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void guess_chs_for_size(BlockDriverState *bs,
|
||||
static void guess_chs_for_size(BlockBackend *blk,
|
||||
uint32_t *pcyls, uint32_t *pheads, uint32_t *psecs)
|
||||
{
|
||||
uint64_t nb_sectors;
|
||||
int cylinders;
|
||||
|
||||
bdrv_get_geometry(bs, &nb_sectors);
|
||||
blk_get_geometry(blk, &nb_sectors);
|
||||
|
||||
cylinders = nb_sectors / (16 * 63);
|
||||
if (cylinders > 16383) {
|
||||
@@ -116,21 +116,21 @@ static void guess_chs_for_size(BlockDriverState *bs,
|
||||
*psecs = 63;
|
||||
}
|
||||
|
||||
void hd_geometry_guess(BlockDriverState *bs,
|
||||
void hd_geometry_guess(BlockBackend *blk,
|
||||
uint32_t *pcyls, uint32_t *pheads, uint32_t *psecs,
|
||||
int *ptrans)
|
||||
{
|
||||
int cylinders, heads, secs, translation;
|
||||
|
||||
if (guess_disk_lchs(bs, &cylinders, &heads, &secs) < 0) {
|
||||
if (guess_disk_lchs(blk, &cylinders, &heads, &secs) < 0) {
|
||||
/* no LCHS guess: use a standard physical disk geometry */
|
||||
guess_chs_for_size(bs, pcyls, pheads, psecs);
|
||||
guess_chs_for_size(blk, pcyls, pheads, psecs);
|
||||
translation = hd_bios_chs_auto_trans(*pcyls, *pheads, *psecs);
|
||||
} else if (heads > 16) {
|
||||
/* LCHS guess with heads > 16 means that a BIOS LBA
|
||||
translation was active, so a standard physical disk
|
||||
geometry is OK */
|
||||
guess_chs_for_size(bs, pcyls, pheads, psecs);
|
||||
guess_chs_for_size(blk, pcyls, pheads, psecs);
|
||||
translation = *pcyls * *pheads <= 131072
|
||||
? BIOS_ATA_TRANSLATION_LARGE
|
||||
: BIOS_ATA_TRANSLATION_LBA;
|
||||
@@ -146,7 +146,7 @@ void hd_geometry_guess(BlockDriverState *bs,
|
||||
if (ptrans) {
|
||||
*ptrans = translation;
|
||||
}
|
||||
trace_hd_geometry_guess(bs, *pcyls, *pheads, *psecs, translation);
|
||||
trace_hd_geometry_guess(blk, *pcyls, *pheads, *psecs, translation);
|
||||
}
|
||||
|
||||
int hd_bios_chs_auto_trans(uint32_t cyls, uint32_t heads, uint32_t secs)
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
*/
|
||||
|
||||
#include "hw/hw.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "hw/ssi.h"
|
||||
|
||||
@@ -245,7 +246,7 @@ typedef struct Flash {
|
||||
|
||||
uint32_t r;
|
||||
|
||||
BlockDriverState *bdrv;
|
||||
BlockBackend *blk;
|
||||
|
||||
uint8_t *storage;
|
||||
uint32_t size;
|
||||
@@ -279,7 +280,7 @@ typedef struct M25P80Class {
|
||||
#define M25P80_GET_CLASS(obj) \
|
||||
OBJECT_GET_CLASS(M25P80Class, (obj), TYPE_M25P80)
|
||||
|
||||
static void bdrv_sync_complete(void *opaque, int ret)
|
||||
static void blk_sync_complete(void *opaque, int ret)
|
||||
{
|
||||
/* do nothing. Masters do not directly interact with the backing store,
|
||||
* only the working copy so no mutexing required.
|
||||
@@ -288,20 +289,20 @@ static void bdrv_sync_complete(void *opaque, int ret)
|
||||
|
||||
static void flash_sync_page(Flash *s, int page)
|
||||
{
|
||||
int bdrv_sector, nb_sectors;
|
||||
int blk_sector, nb_sectors;
|
||||
QEMUIOVector iov;
|
||||
|
||||
if (!s->bdrv || bdrv_is_read_only(s->bdrv)) {
|
||||
if (!s->blk || blk_is_read_only(s->blk)) {
|
||||
return;
|
||||
}
|
||||
|
||||
bdrv_sector = (page * s->pi->page_size) / BDRV_SECTOR_SIZE;
|
||||
blk_sector = (page * s->pi->page_size) / BDRV_SECTOR_SIZE;
|
||||
nb_sectors = DIV_ROUND_UP(s->pi->page_size, BDRV_SECTOR_SIZE);
|
||||
qemu_iovec_init(&iov, 1);
|
||||
qemu_iovec_add(&iov, s->storage + bdrv_sector * BDRV_SECTOR_SIZE,
|
||||
qemu_iovec_add(&iov, s->storage + blk_sector * BDRV_SECTOR_SIZE,
|
||||
nb_sectors * BDRV_SECTOR_SIZE);
|
||||
bdrv_aio_writev(s->bdrv, bdrv_sector, &iov, nb_sectors, bdrv_sync_complete,
|
||||
NULL);
|
||||
blk_aio_writev(s->blk, blk_sector, &iov, nb_sectors, blk_sync_complete,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static inline void flash_sync_area(Flash *s, int64_t off, int64_t len)
|
||||
@@ -309,7 +310,7 @@ static inline void flash_sync_area(Flash *s, int64_t off, int64_t len)
|
||||
int64_t start, end, nb_sectors;
|
||||
QEMUIOVector iov;
|
||||
|
||||
if (!s->bdrv || bdrv_is_read_only(s->bdrv)) {
|
||||
if (!s->blk || blk_is_read_only(s->blk)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -320,7 +321,7 @@ static inline void flash_sync_area(Flash *s, int64_t off, int64_t len)
|
||||
qemu_iovec_init(&iov, 1);
|
||||
qemu_iovec_add(&iov, s->storage + (start * BDRV_SECTOR_SIZE),
|
||||
nb_sectors * BDRV_SECTOR_SIZE);
|
||||
bdrv_aio_writev(s->bdrv, start, &iov, nb_sectors, bdrv_sync_complete, NULL);
|
||||
blk_aio_writev(s->blk, start, &iov, nb_sectors, blk_sync_complete, NULL);
|
||||
}
|
||||
|
||||
static void flash_erase(Flash *s, int offset, FlashCMD cmd)
|
||||
@@ -620,17 +621,17 @@ static int m25p80_init(SSISlave *ss)
|
||||
|
||||
s->size = s->pi->sector_size * s->pi->n_sectors;
|
||||
s->dirty_page = -1;
|
||||
s->storage = qemu_blockalign(s->bdrv, s->size);
|
||||
s->storage = blk_blockalign(s->blk, s->size);
|
||||
|
||||
dinfo = drive_get_next(IF_MTD);
|
||||
|
||||
if (dinfo && dinfo->bdrv) {
|
||||
if (dinfo) {
|
||||
DB_PRINT_L(0, "Binding to IF_MTD drive\n");
|
||||
s->bdrv = dinfo->bdrv;
|
||||
s->blk = blk_by_legacy_dinfo(dinfo);
|
||||
|
||||
/* FIXME: Move to late init */
|
||||
if (bdrv_read(s->bdrv, 0, s->storage, DIV_ROUND_UP(s->size,
|
||||
BDRV_SECTOR_SIZE))) {
|
||||
if (blk_read(s->blk, 0, s->storage,
|
||||
DIV_ROUND_UP(s->size, BDRV_SECTOR_SIZE))) {
|
||||
fprintf(stderr, "Failed to initialize SPI flash!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
# include "hw/hw.h"
|
||||
# include "hw/block/flash.h"
|
||||
# include "sysemu/blockdev.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "hw/qdev.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
@@ -61,7 +61,7 @@ struct NANDFlashState {
|
||||
int size, pages;
|
||||
int page_shift, oob_shift, erase_shift, addr_shift;
|
||||
uint8_t *storage;
|
||||
BlockDriverState *bdrv;
|
||||
BlockBackend *blk;
|
||||
int mem_oob;
|
||||
|
||||
uint8_t cle, ale, ce, wp, gnd;
|
||||
@@ -400,12 +400,12 @@ static void nand_realize(DeviceState *dev, Error **errp)
|
||||
|
||||
pagesize = 1 << s->oob_shift;
|
||||
s->mem_oob = 1;
|
||||
if (s->bdrv) {
|
||||
if (bdrv_is_read_only(s->bdrv)) {
|
||||
if (s->blk) {
|
||||
if (blk_is_read_only(s->blk)) {
|
||||
error_setg(errp, "Can't use a read-only drive");
|
||||
return;
|
||||
}
|
||||
if (bdrv_getlength(s->bdrv) >=
|
||||
if (blk_getlength(s->blk) >=
|
||||
(s->pages << s->page_shift) + (s->pages << s->oob_shift)) {
|
||||
pagesize = 0;
|
||||
s->mem_oob = 0;
|
||||
@@ -424,7 +424,7 @@ static void nand_realize(DeviceState *dev, Error **errp)
|
||||
static Property nand_properties[] = {
|
||||
DEFINE_PROP_UINT8("manufacturer_id", NANDFlashState, manf_id, 0),
|
||||
DEFINE_PROP_UINT8("chip_id", NANDFlashState, chip_id, 0),
|
||||
DEFINE_PROP_DRIVE("drive", NANDFlashState, bdrv),
|
||||
DEFINE_PROP_DRIVE("drive", NANDFlashState, blk),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
@@ -624,7 +624,7 @@ uint32_t nand_getbuswidth(DeviceState *dev)
|
||||
return s->buswidth << 3;
|
||||
}
|
||||
|
||||
DeviceState *nand_init(BlockDriverState *bdrv, int manf_id, int chip_id)
|
||||
DeviceState *nand_init(BlockBackend *blk, int manf_id, int chip_id)
|
||||
{
|
||||
DeviceState *dev;
|
||||
|
||||
@@ -634,8 +634,8 @@ DeviceState *nand_init(BlockDriverState *bdrv, int manf_id, int chip_id)
|
||||
dev = DEVICE(object_new(TYPE_NAND));
|
||||
qdev_prop_set_uint8(dev, "manufacturer_id", manf_id);
|
||||
qdev_prop_set_uint8(dev, "chip_id", chip_id);
|
||||
if (bdrv) {
|
||||
qdev_prop_set_drive_nofail(dev, "drive", bdrv);
|
||||
if (blk) {
|
||||
qdev_prop_set_drive_nofail(dev, "drive", blk);
|
||||
}
|
||||
|
||||
qdev_init_nofail(dev);
|
||||
@@ -654,14 +654,14 @@ static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s)
|
||||
if (PAGE(s->addr) >= s->pages)
|
||||
return;
|
||||
|
||||
if (!s->bdrv) {
|
||||
if (!s->blk) {
|
||||
mem_and(s->storage + PAGE_START(s->addr) + (s->addr & PAGE_MASK) +
|
||||
s->offset, s->io, s->iolen);
|
||||
} else if (s->mem_oob) {
|
||||
sector = SECTOR(s->addr);
|
||||
off = (s->addr & PAGE_MASK) + s->offset;
|
||||
soff = SECTOR_OFFSET(s->addr);
|
||||
if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS) < 0) {
|
||||
if (blk_read(s->blk, sector, iobuf, PAGE_SECTORS) < 0) {
|
||||
printf("%s: read error in sector %" PRIu64 "\n", __func__, sector);
|
||||
return;
|
||||
}
|
||||
@@ -673,21 +673,21 @@ static void glue(nand_blk_write_, PAGE_SIZE)(NANDFlashState *s)
|
||||
MIN(OOB_SIZE, off + s->iolen - PAGE_SIZE));
|
||||
}
|
||||
|
||||
if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS) < 0) {
|
||||
if (blk_write(s->blk, sector, iobuf, PAGE_SECTORS) < 0) {
|
||||
printf("%s: write error in sector %" PRIu64 "\n", __func__, sector);
|
||||
}
|
||||
} else {
|
||||
off = PAGE_START(s->addr) + (s->addr & PAGE_MASK) + s->offset;
|
||||
sector = off >> 9;
|
||||
soff = off & 0x1ff;
|
||||
if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) < 0) {
|
||||
if (blk_read(s->blk, sector, iobuf, PAGE_SECTORS + 2) < 0) {
|
||||
printf("%s: read error in sector %" PRIu64 "\n", __func__, sector);
|
||||
return;
|
||||
}
|
||||
|
||||
mem_and(iobuf + soff, s->io, s->iolen);
|
||||
|
||||
if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) < 0) {
|
||||
if (blk_write(s->blk, sector, iobuf, PAGE_SECTORS + 2) < 0) {
|
||||
printf("%s: write error in sector %" PRIu64 "\n", __func__, sector);
|
||||
}
|
||||
}
|
||||
@@ -705,7 +705,7 @@ static void glue(nand_blk_erase_, PAGE_SIZE)(NANDFlashState *s)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!s->bdrv) {
|
||||
if (!s->blk) {
|
||||
memset(s->storage + PAGE_START(addr),
|
||||
0xff, (PAGE_SIZE + OOB_SIZE) << s->erase_shift);
|
||||
} else if (s->mem_oob) {
|
||||
@@ -714,17 +714,17 @@ static void glue(nand_blk_erase_, PAGE_SIZE)(NANDFlashState *s)
|
||||
i = SECTOR(addr);
|
||||
page = SECTOR(addr + (ADDR_SHIFT + s->erase_shift));
|
||||
for (; i < page; i ++)
|
||||
if (bdrv_write(s->bdrv, i, iobuf, 1) < 0) {
|
||||
if (blk_write(s->blk, i, iobuf, 1) < 0) {
|
||||
printf("%s: write error in sector %" PRIu64 "\n", __func__, i);
|
||||
}
|
||||
} else {
|
||||
addr = PAGE_START(addr);
|
||||
page = addr >> 9;
|
||||
if (bdrv_read(s->bdrv, page, iobuf, 1) < 0) {
|
||||
if (blk_read(s->blk, page, iobuf, 1) < 0) {
|
||||
printf("%s: read error in sector %" PRIu64 "\n", __func__, page);
|
||||
}
|
||||
memset(iobuf + (addr & 0x1ff), 0xff, (~addr & 0x1ff) + 1);
|
||||
if (bdrv_write(s->bdrv, page, iobuf, 1) < 0) {
|
||||
if (blk_write(s->blk, page, iobuf, 1) < 0) {
|
||||
printf("%s: write error in sector %" PRIu64 "\n", __func__, page);
|
||||
}
|
||||
|
||||
@@ -732,18 +732,18 @@ static void glue(nand_blk_erase_, PAGE_SIZE)(NANDFlashState *s)
|
||||
i = (addr & ~0x1ff) + 0x200;
|
||||
for (addr += ((PAGE_SIZE + OOB_SIZE) << s->erase_shift) - 0x200;
|
||||
i < addr; i += 0x200) {
|
||||
if (bdrv_write(s->bdrv, i >> 9, iobuf, 1) < 0) {
|
||||
if (blk_write(s->blk, i >> 9, iobuf, 1) < 0) {
|
||||
printf("%s: write error in sector %" PRIu64 "\n",
|
||||
__func__, i >> 9);
|
||||
}
|
||||
}
|
||||
|
||||
page = i >> 9;
|
||||
if (bdrv_read(s->bdrv, page, iobuf, 1) < 0) {
|
||||
if (blk_read(s->blk, page, iobuf, 1) < 0) {
|
||||
printf("%s: read error in sector %" PRIu64 "\n", __func__, page);
|
||||
}
|
||||
memset(iobuf, 0xff, ((addr - 1) & 0x1ff) + 1);
|
||||
if (bdrv_write(s->bdrv, page, iobuf, 1) < 0) {
|
||||
if (blk_write(s->blk, page, iobuf, 1) < 0) {
|
||||
printf("%s: write error in sector %" PRIu64 "\n", __func__, page);
|
||||
}
|
||||
}
|
||||
@@ -756,9 +756,9 @@ static void glue(nand_blk_load_, PAGE_SIZE)(NANDFlashState *s,
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->bdrv) {
|
||||
if (s->blk) {
|
||||
if (s->mem_oob) {
|
||||
if (bdrv_read(s->bdrv, SECTOR(addr), s->io, PAGE_SECTORS) < 0) {
|
||||
if (blk_read(s->blk, SECTOR(addr), s->io, PAGE_SECTORS) < 0) {
|
||||
printf("%s: read error in sector %" PRIu64 "\n",
|
||||
__func__, SECTOR(addr));
|
||||
}
|
||||
@@ -767,8 +767,8 @@ static void glue(nand_blk_load_, PAGE_SIZE)(NANDFlashState *s,
|
||||
OOB_SIZE);
|
||||
s->ioaddr = s->io + SECTOR_OFFSET(s->addr) + offset;
|
||||
} else {
|
||||
if (bdrv_read(s->bdrv, PAGE_START(addr) >> 9,
|
||||
s->io, (PAGE_SECTORS + 2)) < 0) {
|
||||
if (blk_read(s->blk, PAGE_START(addr) >> 9,
|
||||
s->io, (PAGE_SECTORS + 2)) < 0) {
|
||||
printf("%s: read error in sector %" PRIu64 "\n",
|
||||
__func__, PAGE_START(addr) >> 9);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <hw/pci/pci.h>
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "qapi/visitor.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
|
||||
#include "nvme.h"
|
||||
|
||||
@@ -199,7 +200,7 @@ static void nvme_rw_cb(void *opaque, int ret)
|
||||
NvmeCtrl *n = sq->ctrl;
|
||||
NvmeCQueue *cq = n->cq[sq->cqid];
|
||||
|
||||
block_acct_done(bdrv_get_stats(n->conf.bs), &req->acct);
|
||||
block_acct_done(blk_get_stats(n->conf.blk), &req->acct);
|
||||
if (!ret) {
|
||||
req->status = NVME_SUCCESS;
|
||||
} else {
|
||||
@@ -233,11 +234,11 @@ static uint16_t nvme_rw(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
|
||||
}
|
||||
assert((nlb << data_shift) == req->qsg.size);
|
||||
|
||||
dma_acct_start(n->conf.bs, &req->acct, &req->qsg, is_write ?
|
||||
BLOCK_ACCT_WRITE : BLOCK_ACCT_READ);
|
||||
dma_acct_start(n->conf.blk, &req->acct, &req->qsg,
|
||||
is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ);
|
||||
req->aiocb = is_write ?
|
||||
dma_bdrv_write(n->conf.bs, &req->qsg, aio_slba, nvme_rw_cb, req) :
|
||||
dma_bdrv_read(n->conf.bs, &req->qsg, aio_slba, nvme_rw_cb, req);
|
||||
dma_blk_write(n->conf.blk, &req->qsg, aio_slba, nvme_rw_cb, req) :
|
||||
dma_blk_read(n->conf.blk, &req->qsg, aio_slba, nvme_rw_cb, req);
|
||||
|
||||
return NVME_NO_COMPLETE;
|
||||
}
|
||||
@@ -290,7 +291,7 @@ static uint16_t nvme_del_sq(NvmeCtrl *n, NvmeCmd *cmd)
|
||||
while (!QTAILQ_EMPTY(&sq->out_req_list)) {
|
||||
req = QTAILQ_FIRST(&sq->out_req_list);
|
||||
assert(req->aiocb);
|
||||
bdrv_aio_cancel(req->aiocb);
|
||||
blk_aio_cancel(req->aiocb);
|
||||
}
|
||||
if (!nvme_check_cqid(n, sq->cqid)) {
|
||||
cq = n->cq[sq->cqid];
|
||||
@@ -565,7 +566,7 @@ static void nvme_clear_ctrl(NvmeCtrl *n)
|
||||
}
|
||||
}
|
||||
|
||||
bdrv_flush(n->conf.bs);
|
||||
blk_flush(n->conf.blk);
|
||||
n->bar.cc = 0;
|
||||
}
|
||||
|
||||
@@ -750,11 +751,11 @@ static int nvme_init(PCIDevice *pci_dev)
|
||||
int64_t bs_size;
|
||||
uint8_t *pci_conf;
|
||||
|
||||
if (!(n->conf.bs)) {
|
||||
if (!n->conf.blk) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
bs_size = bdrv_getlength(n->conf.bs);
|
||||
bs_size = blk_getlength(n->conf.blk);
|
||||
if (bs_size < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -636,7 +636,7 @@ typedef struct NvmeAsyncEvent {
|
||||
|
||||
typedef struct NvmeRequest {
|
||||
struct NvmeSQueue *sq;
|
||||
BlockDriverAIOCB *aiocb;
|
||||
BlockAIOCB *aiocb;
|
||||
uint16_t status;
|
||||
NvmeCqe cqe;
|
||||
BlockAcctCookie acct;
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "hw/hw.h"
|
||||
#include "hw/block/flash.h"
|
||||
#include "hw/irq.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "exec/memory.h"
|
||||
#include "exec/address-spaces.h"
|
||||
@@ -49,8 +50,8 @@ typedef struct OneNANDState {
|
||||
hwaddr base;
|
||||
qemu_irq intr;
|
||||
qemu_irq rdy;
|
||||
BlockDriverState *bdrv;
|
||||
BlockDriverState *bdrv_cur;
|
||||
BlockBackend *blk;
|
||||
BlockBackend *blk_cur;
|
||||
uint8_t *image;
|
||||
uint8_t *otp;
|
||||
uint8_t *current;
|
||||
@@ -213,7 +214,7 @@ static void onenand_reset(OneNANDState *s, int cold)
|
||||
s->wpstatus = 0x0002;
|
||||
s->cycle = 0;
|
||||
s->otpmode = 0;
|
||||
s->bdrv_cur = s->bdrv;
|
||||
s->blk_cur = s->blk;
|
||||
s->current = s->image;
|
||||
s->secs_cur = s->secs;
|
||||
|
||||
@@ -221,7 +222,7 @@ static void onenand_reset(OneNANDState *s, int cold)
|
||||
/* Lock the whole flash */
|
||||
memset(s->blockwp, ONEN_LOCK_LOCKED, s->blocks);
|
||||
|
||||
if (s->bdrv_cur && bdrv_read(s->bdrv_cur, 0, s->boot[0], 8) < 0) {
|
||||
if (s->blk_cur && blk_read(s->blk_cur, 0, s->boot[0], 8) < 0) {
|
||||
hw_error("%s: Loading the BootRAM failed.\n", __func__);
|
||||
}
|
||||
}
|
||||
@@ -237,10 +238,11 @@ static void onenand_system_reset(DeviceState *dev)
|
||||
static inline int onenand_load_main(OneNANDState *s, int sec, int secn,
|
||||
void *dest)
|
||||
{
|
||||
if (s->bdrv_cur)
|
||||
return bdrv_read(s->bdrv_cur, sec, dest, secn) < 0;
|
||||
else if (sec + secn > s->secs_cur)
|
||||
if (s->blk_cur) {
|
||||
return blk_read(s->blk_cur, sec, dest, secn) < 0;
|
||||
} else if (sec + secn > s->secs_cur) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
memcpy(dest, s->current + (sec << 9), secn << 9);
|
||||
|
||||
@@ -256,9 +258,9 @@ static inline int onenand_prog_main(OneNANDState *s, int sec, int secn,
|
||||
uint32_t size = (uint32_t)secn * 512;
|
||||
const uint8_t *sp = (const uint8_t *)src;
|
||||
uint8_t *dp = 0;
|
||||
if (s->bdrv_cur) {
|
||||
if (s->blk_cur) {
|
||||
dp = g_malloc(size);
|
||||
if (!dp || bdrv_read(s->bdrv_cur, sec, dp, secn) < 0) {
|
||||
if (!dp || blk_read(s->blk_cur, sec, dp, secn) < 0) {
|
||||
result = 1;
|
||||
}
|
||||
} else {
|
||||
@@ -273,11 +275,11 @@ static inline int onenand_prog_main(OneNANDState *s, int sec, int secn,
|
||||
for (i = 0; i < size; i++) {
|
||||
dp[i] &= sp[i];
|
||||
}
|
||||
if (s->bdrv_cur) {
|
||||
result = bdrv_write(s->bdrv_cur, sec, dp, secn) < 0;
|
||||
if (s->blk_cur) {
|
||||
result = blk_write(s->blk_cur, sec, dp, secn) < 0;
|
||||
}
|
||||
}
|
||||
if (dp && s->bdrv_cur) {
|
||||
if (dp && s->blk_cur) {
|
||||
g_free(dp);
|
||||
}
|
||||
}
|
||||
@@ -290,14 +292,16 @@ static inline int onenand_load_spare(OneNANDState *s, int sec, int secn,
|
||||
{
|
||||
uint8_t buf[512];
|
||||
|
||||
if (s->bdrv_cur) {
|
||||
if (bdrv_read(s->bdrv_cur, s->secs_cur + (sec >> 5), buf, 1) < 0)
|
||||
if (s->blk_cur) {
|
||||
if (blk_read(s->blk_cur, s->secs_cur + (sec >> 5), buf, 1) < 0) {
|
||||
return 1;
|
||||
}
|
||||
memcpy(dest, buf + ((sec & 31) << 4), secn << 4);
|
||||
} else if (sec + secn > s->secs_cur)
|
||||
} else if (sec + secn > s->secs_cur) {
|
||||
return 1;
|
||||
else
|
||||
} else {
|
||||
memcpy(dest, s->current + (s->secs_cur << 9) + (sec << 4), secn << 4);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -309,11 +313,10 @@ static inline int onenand_prog_spare(OneNANDState *s, int sec, int secn,
|
||||
if (secn > 0) {
|
||||
const uint8_t *sp = (const uint8_t *)src;
|
||||
uint8_t *dp = 0, *dpp = 0;
|
||||
if (s->bdrv_cur) {
|
||||
if (s->blk_cur) {
|
||||
dp = g_malloc(512);
|
||||
if (!dp || bdrv_read(s->bdrv_cur,
|
||||
s->secs_cur + (sec >> 5),
|
||||
dp, 1) < 0) {
|
||||
if (!dp
|
||||
|| blk_read(s->blk_cur, s->secs_cur + (sec >> 5), dp, 1) < 0) {
|
||||
result = 1;
|
||||
} else {
|
||||
dpp = dp + ((sec & 31) << 4);
|
||||
@@ -330,9 +333,9 @@ static inline int onenand_prog_spare(OneNANDState *s, int sec, int secn,
|
||||
for (i = 0; i < (secn << 4); i++) {
|
||||
dpp[i] &= sp[i];
|
||||
}
|
||||
if (s->bdrv_cur) {
|
||||
result = bdrv_write(s->bdrv_cur, s->secs_cur + (sec >> 5),
|
||||
dp, 1) < 0;
|
||||
if (s->blk_cur) {
|
||||
result = blk_write(s->blk_cur, s->secs_cur + (sec >> 5),
|
||||
dp, 1) < 0;
|
||||
}
|
||||
}
|
||||
g_free(dp);
|
||||
@@ -354,16 +357,16 @@ static inline int onenand_erase(OneNANDState *s, int sec, int num)
|
||||
}
|
||||
memset(blankbuf, 0xff, 512);
|
||||
for (; num > 0; num--, sec++) {
|
||||
if (s->bdrv_cur) {
|
||||
if (s->blk_cur) {
|
||||
int erasesec = s->secs_cur + (sec >> 5);
|
||||
if (bdrv_write(s->bdrv_cur, sec, blankbuf, 1) < 0) {
|
||||
if (blk_write(s->blk_cur, sec, blankbuf, 1) < 0) {
|
||||
goto fail;
|
||||
}
|
||||
if (bdrv_read(s->bdrv_cur, erasesec, tmpbuf, 1) < 0) {
|
||||
if (blk_read(s->blk_cur, erasesec, tmpbuf, 1) < 0) {
|
||||
goto fail;
|
||||
}
|
||||
memcpy(tmpbuf + ((sec & 31) << 4), blankbuf, 1 << 4);
|
||||
if (bdrv_write(s->bdrv_cur, erasesec, tmpbuf, 1) < 0) {
|
||||
if (blk_write(s->blk_cur, erasesec, tmpbuf, 1) < 0) {
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
@@ -576,7 +579,7 @@ static void onenand_command(OneNANDState *s)
|
||||
|
||||
case 0x65: /* OTP Access */
|
||||
s->intstatus |= ONEN_INT;
|
||||
s->bdrv_cur = NULL;
|
||||
s->blk_cur = NULL;
|
||||
s->current = s->otp;
|
||||
s->secs_cur = 1 << (BLOCK_SHIFT - 9);
|
||||
s->addr[ONEN_BUF_BLOCK] = 0;
|
||||
@@ -776,15 +779,15 @@ static int onenand_initfn(SysBusDevice *sbd)
|
||||
? (1 << (6 + ((s->id.dev >> 4) & 7))) : 0;
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &onenand_ops, s, "onenand",
|
||||
0x10000 << s->shift);
|
||||
if (!s->bdrv) {
|
||||
if (!s->blk) {
|
||||
s->image = memset(g_malloc(size + (size >> 5)),
|
||||
0xff, size + (size >> 5));
|
||||
} else {
|
||||
if (bdrv_is_read_only(s->bdrv)) {
|
||||
if (blk_is_read_only(s->blk)) {
|
||||
error_report("Can't use a read-only drive");
|
||||
return -1;
|
||||
}
|
||||
s->bdrv_cur = s->bdrv;
|
||||
s->blk_cur = s->blk;
|
||||
}
|
||||
s->otp = memset(g_malloc((64 + 2) << PAGE_SHIFT),
|
||||
0xff, (64 + 2) << PAGE_SHIFT);
|
||||
@@ -815,7 +818,7 @@ static Property onenand_properties[] = {
|
||||
DEFINE_PROP_UINT16("device_id", OneNANDState, id.dev, 0),
|
||||
DEFINE_PROP_UINT16("version_id", OneNANDState, id.ver, 0),
|
||||
DEFINE_PROP_INT32("shift", OneNANDState, shift, 0),
|
||||
DEFINE_PROP_DRIVE("drive", OneNANDState, bdrv),
|
||||
DEFINE_PROP_DRIVE("drive", OneNANDState, blk),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
#include "hw/hw.h"
|
||||
#include "hw/block/flash.h"
|
||||
#include "block/block.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "qemu/bitops.h"
|
||||
#include "exec/address-spaces.h"
|
||||
@@ -69,7 +69,7 @@ struct pflash_t {
|
||||
SysBusDevice parent_obj;
|
||||
/*< public >*/
|
||||
|
||||
BlockDriverState *bs;
|
||||
BlockBackend *blk;
|
||||
uint32_t nb_blocs;
|
||||
uint64_t sector_len;
|
||||
uint8_t bank_width;
|
||||
@@ -395,13 +395,13 @@ static void pflash_update(pflash_t *pfl, int offset,
|
||||
int size)
|
||||
{
|
||||
int offset_end;
|
||||
if (pfl->bs) {
|
||||
if (pfl->blk) {
|
||||
offset_end = offset + size;
|
||||
/* round to sectors */
|
||||
offset = offset >> 9;
|
||||
offset_end = (offset_end + 511) >> 9;
|
||||
bdrv_write(pfl->bs, offset, pfl->storage + (offset << 9),
|
||||
offset_end - offset);
|
||||
blk_write(pfl->blk, offset, pfl->storage + (offset << 9),
|
||||
offset_end - offset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -784,9 +784,9 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp)
|
||||
pfl->storage = memory_region_get_ram_ptr(&pfl->mem);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->mem);
|
||||
|
||||
if (pfl->bs) {
|
||||
if (pfl->blk) {
|
||||
/* read the initial flash content */
|
||||
ret = bdrv_read(pfl->bs, 0, pfl->storage, total_len >> 9);
|
||||
ret = blk_read(pfl->blk, 0, pfl->storage, total_len >> 9);
|
||||
|
||||
if (ret < 0) {
|
||||
vmstate_unregister_ram(&pfl->mem, DEVICE(pfl));
|
||||
@@ -795,8 +795,8 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
if (pfl->bs) {
|
||||
pfl->ro = bdrv_is_read_only(pfl->bs);
|
||||
if (pfl->blk) {
|
||||
pfl->ro = blk_is_read_only(pfl->blk);
|
||||
} else {
|
||||
pfl->ro = 0;
|
||||
}
|
||||
@@ -898,7 +898,7 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp)
|
||||
}
|
||||
|
||||
static Property pflash_cfi01_properties[] = {
|
||||
DEFINE_PROP_DRIVE("drive", struct pflash_t, bs),
|
||||
DEFINE_PROP_DRIVE("drive", struct pflash_t, blk),
|
||||
/* num-blocks is the number of blocks actually visible to the guest,
|
||||
* ie the total size of the device divided by the sector length.
|
||||
* If we're emulating flash devices wired in parallel the actual
|
||||
@@ -962,14 +962,14 @@ type_init(pflash_cfi01_register_types)
|
||||
pflash_t *pflash_cfi01_register(hwaddr base,
|
||||
DeviceState *qdev, const char *name,
|
||||
hwaddr size,
|
||||
BlockDriverState *bs,
|
||||
BlockBackend *blk,
|
||||
uint32_t sector_len, int nb_blocs,
|
||||
int bank_width, uint16_t id0, uint16_t id1,
|
||||
uint16_t id2, uint16_t id3, int be)
|
||||
{
|
||||
DeviceState *dev = qdev_create(NULL, TYPE_CFI_PFLASH01);
|
||||
|
||||
if (bs && qdev_prop_set_drive(dev, "drive", bs)) {
|
||||
if (blk && qdev_prop_set_drive(dev, "drive", blk)) {
|
||||
abort();
|
||||
}
|
||||
qdev_prop_set_uint32(dev, "num-blocks", nb_blocs);
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
#include "hw/hw.h"
|
||||
#include "hw/block/flash.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "block/block.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "qemu/host-utils.h"
|
||||
#include "hw/sysbus.h"
|
||||
@@ -63,7 +63,7 @@ struct pflash_t {
|
||||
SysBusDevice parent_obj;
|
||||
/*< public >*/
|
||||
|
||||
BlockDriverState *bs;
|
||||
BlockBackend *blk;
|
||||
uint32_t sector_len;
|
||||
uint32_t nb_blocs;
|
||||
uint32_t chip_len;
|
||||
@@ -249,13 +249,13 @@ static void pflash_update(pflash_t *pfl, int offset,
|
||||
int size)
|
||||
{
|
||||
int offset_end;
|
||||
if (pfl->bs) {
|
||||
if (pfl->blk) {
|
||||
offset_end = offset + size;
|
||||
/* round to sectors */
|
||||
offset = offset >> 9;
|
||||
offset_end = (offset_end + 511) >> 9;
|
||||
bdrv_write(pfl->bs, offset, pfl->storage + (offset << 9),
|
||||
offset_end - offset);
|
||||
blk_write(pfl->blk, offset, pfl->storage + (offset << 9),
|
||||
offset_end - offset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -618,9 +618,9 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
|
||||
vmstate_register_ram(&pfl->orig_mem, DEVICE(pfl));
|
||||
pfl->storage = memory_region_get_ram_ptr(&pfl->orig_mem);
|
||||
pfl->chip_len = chip_len;
|
||||
if (pfl->bs) {
|
||||
if (pfl->blk) {
|
||||
/* read the initial flash content */
|
||||
ret = bdrv_read(pfl->bs, 0, pfl->storage, chip_len >> 9);
|
||||
ret = blk_read(pfl->blk, 0, pfl->storage, chip_len >> 9);
|
||||
if (ret < 0) {
|
||||
vmstate_unregister_ram(&pfl->orig_mem, DEVICE(pfl));
|
||||
error_setg(errp, "failed to read the initial flash content");
|
||||
@@ -632,8 +632,8 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
|
||||
pfl->rom_mode = 1;
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->mem);
|
||||
|
||||
if (pfl->bs) {
|
||||
pfl->ro = bdrv_is_read_only(pfl->bs);
|
||||
if (pfl->blk) {
|
||||
pfl->ro = blk_is_read_only(pfl->blk);
|
||||
} else {
|
||||
pfl->ro = 0;
|
||||
}
|
||||
@@ -722,7 +722,7 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
|
||||
}
|
||||
|
||||
static Property pflash_cfi02_properties[] = {
|
||||
DEFINE_PROP_DRIVE("drive", struct pflash_t, bs),
|
||||
DEFINE_PROP_DRIVE("drive", struct pflash_t, blk),
|
||||
DEFINE_PROP_UINT32("num-blocks", struct pflash_t, nb_blocs, 0),
|
||||
DEFINE_PROP_UINT32("sector-length", struct pflash_t, sector_len, 0),
|
||||
DEFINE_PROP_UINT8("width", struct pflash_t, width, 0),
|
||||
@@ -763,7 +763,7 @@ type_init(pflash_cfi02_register_types)
|
||||
pflash_t *pflash_cfi02_register(hwaddr base,
|
||||
DeviceState *qdev, const char *name,
|
||||
hwaddr size,
|
||||
BlockDriverState *bs, uint32_t sector_len,
|
||||
BlockBackend *blk, uint32_t sector_len,
|
||||
int nb_blocs, int nb_mappings, int width,
|
||||
uint16_t id0, uint16_t id1,
|
||||
uint16_t id2, uint16_t id3,
|
||||
@@ -772,7 +772,7 @@ pflash_t *pflash_cfi02_register(hwaddr base,
|
||||
{
|
||||
DeviceState *dev = qdev_create(NULL, TYPE_CFI_PFLASH02);
|
||||
|
||||
if (bs && qdev_prop_set_drive(dev, "drive", bs)) {
|
||||
if (blk && qdev_prop_set_drive(dev, "drive", blk)) {
|
||||
abort();
|
||||
}
|
||||
qdev_prop_set_uint32(dev, "num-blocks", nb_blocs);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "qemu/error-report.h"
|
||||
#include "trace.h"
|
||||
#include "hw/block/block.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "hw/virtio/virtio-blk.h"
|
||||
#include "dataplane/virtio-blk.h"
|
||||
@@ -64,7 +65,8 @@ static void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status)
|
||||
static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error,
|
||||
bool is_read)
|
||||
{
|
||||
BlockErrorAction action = bdrv_get_error_action(req->dev->bs, is_read, error);
|
||||
BlockErrorAction action = blk_get_error_action(req->dev->blk,
|
||||
is_read, error);
|
||||
VirtIOBlock *s = req->dev;
|
||||
|
||||
if (action == BLOCK_ERROR_ACTION_STOP) {
|
||||
@@ -72,11 +74,11 @@ static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error,
|
||||
s->rq = req;
|
||||
} else if (action == BLOCK_ERROR_ACTION_REPORT) {
|
||||
virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
|
||||
block_acct_done(bdrv_get_stats(s->bs), &req->acct);
|
||||
block_acct_done(blk_get_stats(s->blk), &req->acct);
|
||||
virtio_blk_free_request(req);
|
||||
}
|
||||
|
||||
bdrv_error_action(s->bs, action, is_read, error);
|
||||
blk_error_action(s->blk, action, is_read, error);
|
||||
return action != BLOCK_ERROR_ACTION_IGNORE;
|
||||
}
|
||||
|
||||
@@ -94,7 +96,7 @@ static void virtio_blk_rw_complete(void *opaque, int ret)
|
||||
}
|
||||
|
||||
virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
|
||||
block_acct_done(bdrv_get_stats(req->dev->bs), &req->acct);
|
||||
block_acct_done(blk_get_stats(req->dev->blk), &req->acct);
|
||||
virtio_blk_free_request(req);
|
||||
}
|
||||
|
||||
@@ -109,7 +111,7 @@ static void virtio_blk_flush_complete(void *opaque, int ret)
|
||||
}
|
||||
|
||||
virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
|
||||
block_acct_done(bdrv_get_stats(req->dev->bs), &req->acct);
|
||||
block_acct_done(blk_get_stats(req->dev->blk), &req->acct);
|
||||
virtio_blk_free_request(req);
|
||||
}
|
||||
|
||||
@@ -155,7 +157,7 @@ int virtio_blk_handle_scsi_req(VirtIOBlock *blk,
|
||||
*/
|
||||
scsi = (void *)elem->in_sg[elem->in_num - 2].iov_base;
|
||||
|
||||
if (!blk->blk.scsi) {
|
||||
if (!blk->conf.scsi) {
|
||||
status = VIRTIO_BLK_S_UNSUPP;
|
||||
goto fail;
|
||||
}
|
||||
@@ -209,7 +211,7 @@ int virtio_blk_handle_scsi_req(VirtIOBlock *blk,
|
||||
hdr.sbp = elem->in_sg[elem->in_num - 3].iov_base;
|
||||
hdr.mx_sb_len = elem->in_sg[elem->in_num - 3].iov_len;
|
||||
|
||||
status = bdrv_ioctl(blk->bs, SG_IO, &hdr);
|
||||
status = blk_ioctl(blk->blk, SG_IO, &hdr);
|
||||
if (status) {
|
||||
status = VIRTIO_BLK_S_UNSUPP;
|
||||
goto fail;
|
||||
@@ -255,7 +257,7 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
|
||||
virtio_blk_free_request(req);
|
||||
}
|
||||
|
||||
void virtio_submit_multiwrite(BlockDriverState *bs, MultiReqBuffer *mrb)
|
||||
void virtio_submit_multiwrite(BlockBackend *blk, MultiReqBuffer *mrb)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
@@ -263,7 +265,7 @@ void virtio_submit_multiwrite(BlockDriverState *bs, MultiReqBuffer *mrb)
|
||||
return;
|
||||
}
|
||||
|
||||
ret = bdrv_aio_multiwrite(bs, mrb->blkreq, mrb->num_writes);
|
||||
ret = blk_aio_multiwrite(blk, mrb->blkreq, mrb->num_writes);
|
||||
if (ret != 0) {
|
||||
for (i = 0; i < mrb->num_writes; i++) {
|
||||
if (mrb->blkreq[i].error) {
|
||||
@@ -277,14 +279,14 @@ void virtio_submit_multiwrite(BlockDriverState *bs, MultiReqBuffer *mrb)
|
||||
|
||||
static void virtio_blk_handle_flush(VirtIOBlockReq *req, MultiReqBuffer *mrb)
|
||||
{
|
||||
block_acct_start(bdrv_get_stats(req->dev->bs), &req->acct, 0,
|
||||
block_acct_start(blk_get_stats(req->dev->blk), &req->acct, 0,
|
||||
BLOCK_ACCT_FLUSH);
|
||||
|
||||
/*
|
||||
* Make sure all outstanding writes are posted to the backing device.
|
||||
*/
|
||||
virtio_submit_multiwrite(req->dev->bs, mrb);
|
||||
bdrv_aio_flush(req->dev->bs, virtio_blk_flush_complete, req);
|
||||
virtio_submit_multiwrite(req->dev->blk, mrb);
|
||||
blk_aio_flush(req->dev->blk, virtio_blk_flush_complete, req);
|
||||
}
|
||||
|
||||
static bool virtio_blk_sect_range_ok(VirtIOBlock *dev,
|
||||
@@ -296,10 +298,10 @@ static bool virtio_blk_sect_range_ok(VirtIOBlock *dev,
|
||||
if (sector & dev->sector_mask) {
|
||||
return false;
|
||||
}
|
||||
if (size % dev->conf->logical_block_size) {
|
||||
if (size % dev->conf.conf.logical_block_size) {
|
||||
return false;
|
||||
}
|
||||
bdrv_get_geometry(dev->bs, &total_sectors);
|
||||
blk_get_geometry(dev->blk, &total_sectors);
|
||||
if (sector > total_sectors || nb_sectors > total_sectors - sector) {
|
||||
return false;
|
||||
}
|
||||
@@ -321,11 +323,11 @@ static void virtio_blk_handle_write(VirtIOBlockReq *req, MultiReqBuffer *mrb)
|
||||
return;
|
||||
}
|
||||
|
||||
block_acct_start(bdrv_get_stats(req->dev->bs), &req->acct, req->qiov.size,
|
||||
block_acct_start(blk_get_stats(req->dev->blk), &req->acct, req->qiov.size,
|
||||
BLOCK_ACCT_WRITE);
|
||||
|
||||
if (mrb->num_writes == 32) {
|
||||
virtio_submit_multiwrite(req->dev->bs, mrb);
|
||||
virtio_submit_multiwrite(req->dev->blk, mrb);
|
||||
}
|
||||
|
||||
blkreq = &mrb->blkreq[mrb->num_writes];
|
||||
@@ -353,11 +355,11 @@ static void virtio_blk_handle_read(VirtIOBlockReq *req)
|
||||
return;
|
||||
}
|
||||
|
||||
block_acct_start(bdrv_get_stats(req->dev->bs), &req->acct, req->qiov.size,
|
||||
block_acct_start(blk_get_stats(req->dev->blk), &req->acct, req->qiov.size,
|
||||
BLOCK_ACCT_READ);
|
||||
bdrv_aio_readv(req->dev->bs, sector, &req->qiov,
|
||||
req->qiov.size / BDRV_SECTOR_SIZE,
|
||||
virtio_blk_rw_complete, req);
|
||||
blk_aio_readv(req->dev->blk, sector, &req->qiov,
|
||||
req->qiov.size / BDRV_SECTOR_SIZE,
|
||||
virtio_blk_rw_complete, req);
|
||||
}
|
||||
|
||||
void virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
|
||||
@@ -405,7 +407,7 @@ void virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
|
||||
* NB: per existing s/n string convention the string is
|
||||
* terminated by '\0' only when shorter than buffer.
|
||||
*/
|
||||
const char *serial = s->blk.serial ? s->blk.serial : "";
|
||||
const char *serial = s->conf.serial ? s->conf.serial : "";
|
||||
size_t size = MIN(strlen(serial) + 1,
|
||||
MIN(iov_size(in_iov, in_num),
|
||||
VIRTIO_BLK_ID_BYTES));
|
||||
@@ -445,7 +447,7 @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
|
||||
virtio_blk_handle_request(req, &mrb);
|
||||
}
|
||||
|
||||
virtio_submit_multiwrite(s->bs, &mrb);
|
||||
virtio_submit_multiwrite(s->blk, &mrb);
|
||||
|
||||
/*
|
||||
* FIXME: Want to check for completions before returning to guest mode,
|
||||
@@ -473,7 +475,7 @@ static void virtio_blk_dma_restart_bh(void *opaque)
|
||||
req = next;
|
||||
}
|
||||
|
||||
virtio_submit_multiwrite(s->bs, &mrb);
|
||||
virtio_submit_multiwrite(s->blk, &mrb);
|
||||
}
|
||||
|
||||
static void virtio_blk_dma_restart_cb(void *opaque, int running,
|
||||
@@ -486,7 +488,7 @@ static void virtio_blk_dma_restart_cb(void *opaque, int running,
|
||||
}
|
||||
|
||||
if (!s->bh) {
|
||||
s->bh = aio_bh_new(bdrv_get_aio_context(s->blk.conf.bs),
|
||||
s->bh = aio_bh_new(blk_get_aio_context(s->conf.conf.blk),
|
||||
virtio_blk_dma_restart_bh, s);
|
||||
qemu_bh_schedule(s->bh);
|
||||
}
|
||||
@@ -504,8 +506,8 @@ static void virtio_blk_reset(VirtIODevice *vdev)
|
||||
* This should cancel pending requests, but can't do nicely until there
|
||||
* are per-device request lists.
|
||||
*/
|
||||
bdrv_drain_all();
|
||||
bdrv_set_enable_write_cache(s->bs, s->original_wce);
|
||||
blk_drain_all();
|
||||
blk_set_enable_write_cache(s->blk, s->original_wce);
|
||||
}
|
||||
|
||||
/* coalesce internal state, copy to pci i/o region 0
|
||||
@@ -513,19 +515,20 @@ static void virtio_blk_reset(VirtIODevice *vdev)
|
||||
static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
|
||||
{
|
||||
VirtIOBlock *s = VIRTIO_BLK(vdev);
|
||||
BlockConf *conf = &s->conf.conf;
|
||||
struct virtio_blk_config blkcfg;
|
||||
uint64_t capacity;
|
||||
int blk_size = s->conf->logical_block_size;
|
||||
int blk_size = conf->logical_block_size;
|
||||
|
||||
bdrv_get_geometry(s->bs, &capacity);
|
||||
blk_get_geometry(s->blk, &capacity);
|
||||
memset(&blkcfg, 0, sizeof(blkcfg));
|
||||
virtio_stq_p(vdev, &blkcfg.capacity, capacity);
|
||||
virtio_stl_p(vdev, &blkcfg.seg_max, 128 - 2);
|
||||
virtio_stw_p(vdev, &blkcfg.cylinders, s->conf->cyls);
|
||||
virtio_stw_p(vdev, &blkcfg.cylinders, conf->cyls);
|
||||
virtio_stl_p(vdev, &blkcfg.blk_size, blk_size);
|
||||
virtio_stw_p(vdev, &blkcfg.min_io_size, s->conf->min_io_size / blk_size);
|
||||
virtio_stw_p(vdev, &blkcfg.opt_io_size, s->conf->opt_io_size / blk_size);
|
||||
blkcfg.heads = s->conf->heads;
|
||||
virtio_stw_p(vdev, &blkcfg.min_io_size, conf->min_io_size / blk_size);
|
||||
virtio_stw_p(vdev, &blkcfg.opt_io_size, conf->opt_io_size / blk_size);
|
||||
blkcfg.heads = conf->heads;
|
||||
/*
|
||||
* We must ensure that the block device capacity is a multiple of
|
||||
* the logical block size. If that is not the case, let's use
|
||||
@@ -537,15 +540,15 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
|
||||
* divided by 512 - instead it is the amount of blk_size blocks
|
||||
* per track (cylinder).
|
||||
*/
|
||||
if (bdrv_getlength(s->bs) / s->conf->heads / s->conf->secs % blk_size) {
|
||||
blkcfg.sectors = s->conf->secs & ~s->sector_mask;
|
||||
if (blk_getlength(s->blk) / conf->heads / conf->secs % blk_size) {
|
||||
blkcfg.sectors = conf->secs & ~s->sector_mask;
|
||||
} else {
|
||||
blkcfg.sectors = s->conf->secs;
|
||||
blkcfg.sectors = conf->secs;
|
||||
}
|
||||
blkcfg.size_max = 0;
|
||||
blkcfg.physical_block_exp = get_physical_block_exp(s->conf);
|
||||
blkcfg.physical_block_exp = get_physical_block_exp(conf);
|
||||
blkcfg.alignment_offset = 0;
|
||||
blkcfg.wce = bdrv_enable_write_cache(s->bs);
|
||||
blkcfg.wce = blk_enable_write_cache(s->blk);
|
||||
memcpy(config, &blkcfg, sizeof(struct virtio_blk_config));
|
||||
}
|
||||
|
||||
@@ -556,9 +559,9 @@ static void virtio_blk_set_config(VirtIODevice *vdev, const uint8_t *config)
|
||||
|
||||
memcpy(&blkcfg, config, sizeof(blkcfg));
|
||||
|
||||
aio_context_acquire(bdrv_get_aio_context(s->bs));
|
||||
bdrv_set_enable_write_cache(s->bs, blkcfg.wce != 0);
|
||||
aio_context_release(bdrv_get_aio_context(s->bs));
|
||||
aio_context_acquire(blk_get_aio_context(s->blk));
|
||||
blk_set_enable_write_cache(s->blk, blkcfg.wce != 0);
|
||||
aio_context_release(blk_get_aio_context(s->blk));
|
||||
}
|
||||
|
||||
static uint32_t virtio_blk_get_features(VirtIODevice *vdev, uint32_t features)
|
||||
@@ -571,14 +574,15 @@ static uint32_t virtio_blk_get_features(VirtIODevice *vdev, uint32_t features)
|
||||
features |= (1 << VIRTIO_BLK_F_BLK_SIZE);
|
||||
features |= (1 << VIRTIO_BLK_F_SCSI);
|
||||
|
||||
if (s->blk.config_wce) {
|
||||
if (s->conf.config_wce) {
|
||||
features |= (1 << VIRTIO_BLK_F_CONFIG_WCE);
|
||||
}
|
||||
if (bdrv_enable_write_cache(s->bs))
|
||||
if (blk_enable_write_cache(s->blk)) {
|
||||
features |= (1 << VIRTIO_BLK_F_WCE);
|
||||
|
||||
if (bdrv_is_read_only(s->bs))
|
||||
}
|
||||
if (blk_is_read_only(s->blk)) {
|
||||
features |= 1 << VIRTIO_BLK_F_RO;
|
||||
}
|
||||
|
||||
return features;
|
||||
}
|
||||
@@ -612,13 +616,13 @@ static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status)
|
||||
* Guest writes 1 to the WCE configuration field (writeback mode)
|
||||
* Guest sets DRIVER_OK bit in status field
|
||||
*
|
||||
* s->bs would erroneously be placed in writethrough mode.
|
||||
* s->blk would erroneously be placed in writethrough mode.
|
||||
*/
|
||||
if (!(features & (1 << VIRTIO_BLK_F_CONFIG_WCE))) {
|
||||
aio_context_acquire(bdrv_get_aio_context(s->bs));
|
||||
bdrv_set_enable_write_cache(s->bs,
|
||||
!!(features & (1 << VIRTIO_BLK_F_WCE)));
|
||||
aio_context_release(bdrv_get_aio_context(s->bs));
|
||||
aio_context_acquire(blk_get_aio_context(s->blk));
|
||||
blk_set_enable_write_cache(s->blk,
|
||||
!!(features & (1 << VIRTIO_BLK_F_WCE)));
|
||||
aio_context_release(blk_get_aio_context(s->blk));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -707,8 +711,8 @@ static void virtio_blk_migration_state_changed(Notifier *notifier, void *data)
|
||||
if (s->dataplane) {
|
||||
return;
|
||||
}
|
||||
bdrv_drain_all(); /* complete in-flight non-dataplane requests */
|
||||
virtio_blk_data_plane_create(VIRTIO_DEVICE(s), &s->blk,
|
||||
blk_drain_all(); /* complete in-flight non-dataplane requests */
|
||||
virtio_blk_data_plane_create(VIRTIO_DEVICE(s), &s->conf,
|
||||
&s->dataplane, &err);
|
||||
if (err != NULL) {
|
||||
error_report("%s", error_get_pretty(err));
|
||||
@@ -721,22 +725,22 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
||||
VirtIOBlock *s = VIRTIO_BLK(dev);
|
||||
VirtIOBlkConf *blk = &(s->blk);
|
||||
VirtIOBlkConf *conf = &s->conf;
|
||||
Error *err = NULL;
|
||||
static int virtio_blk_id;
|
||||
|
||||
if (!blk->conf.bs) {
|
||||
if (!conf->conf.blk) {
|
||||
error_setg(errp, "drive property not set");
|
||||
return;
|
||||
}
|
||||
if (!bdrv_is_inserted(blk->conf.bs)) {
|
||||
if (!blk_is_inserted(conf->conf.blk)) {
|
||||
error_setg(errp, "Device needs media, but drive is empty");
|
||||
return;
|
||||
}
|
||||
|
||||
blkconf_serial(&blk->conf, &blk->serial);
|
||||
s->original_wce = bdrv_enable_write_cache(blk->conf.bs);
|
||||
blkconf_geometry(&blk->conf, NULL, 65535, 255, 255, &err);
|
||||
blkconf_serial(&conf->conf, &conf->serial);
|
||||
s->original_wce = blk_enable_write_cache(conf->conf.blk);
|
||||
blkconf_geometry(&conf->conf, NULL, 65535, 255, 255, &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
@@ -745,14 +749,13 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
|
||||
virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK,
|
||||
sizeof(struct virtio_blk_config));
|
||||
|
||||
s->bs = blk->conf.bs;
|
||||
s->conf = &blk->conf;
|
||||
s->blk = conf->conf.blk;
|
||||
s->rq = NULL;
|
||||
s->sector_mask = (s->conf->logical_block_size / BDRV_SECTOR_SIZE) - 1;
|
||||
s->sector_mask = (s->conf.conf.logical_block_size / BDRV_SECTOR_SIZE) - 1;
|
||||
|
||||
s->vq = virtio_add_queue(vdev, 128, virtio_blk_handle_output);
|
||||
s->complete_request = virtio_blk_complete_request;
|
||||
virtio_blk_data_plane_create(vdev, blk, &s->dataplane, &err);
|
||||
virtio_blk_data_plane_create(vdev, conf, &s->dataplane, &err);
|
||||
if (err != NULL) {
|
||||
error_propagate(errp, err);
|
||||
virtio_cleanup(vdev);
|
||||
@@ -764,10 +767,10 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
|
||||
s->change = qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s);
|
||||
register_savevm(dev, "virtio-blk", virtio_blk_id++, 2,
|
||||
virtio_blk_save, virtio_blk_load, s);
|
||||
bdrv_set_dev_ops(s->bs, &virtio_block_ops, s);
|
||||
bdrv_set_guest_block_size(s->bs, s->conf->logical_block_size);
|
||||
blk_set_dev_ops(s->blk, &virtio_block_ops, s);
|
||||
blk_set_guest_block_size(s->blk, s->conf.conf.logical_block_size);
|
||||
|
||||
bdrv_iostatus_enable(s->bs);
|
||||
blk_iostatus_enable(s->blk);
|
||||
}
|
||||
|
||||
static void virtio_blk_device_unrealize(DeviceState *dev, Error **errp)
|
||||
@@ -780,7 +783,7 @@ static void virtio_blk_device_unrealize(DeviceState *dev, Error **errp)
|
||||
s->dataplane = NULL;
|
||||
qemu_del_vm_change_state_handler(s->change);
|
||||
unregister_savevm(dev, "virtio-blk", s);
|
||||
blockdev_mark_auto_del(s->bs);
|
||||
blockdev_mark_auto_del(s->blk);
|
||||
virtio_cleanup(vdev);
|
||||
}
|
||||
|
||||
@@ -789,23 +792,23 @@ static void virtio_blk_instance_init(Object *obj)
|
||||
VirtIOBlock *s = VIRTIO_BLK(obj);
|
||||
|
||||
object_property_add_link(obj, "iothread", TYPE_IOTHREAD,
|
||||
(Object **)&s->blk.iothread,
|
||||
(Object **)&s->conf.iothread,
|
||||
qdev_prop_allow_set_link_before_realize,
|
||||
OBJ_PROP_LINK_UNREF_ON_RELEASE, NULL);
|
||||
device_add_bootindex_property(obj, &s->blk.conf.bootindex,
|
||||
device_add_bootindex_property(obj, &s->conf.conf.bootindex,
|
||||
"bootindex", "/disk@0,0",
|
||||
DEVICE(obj), NULL);
|
||||
}
|
||||
|
||||
static Property virtio_blk_properties[] = {
|
||||
DEFINE_BLOCK_PROPERTIES(VirtIOBlock, blk.conf),
|
||||
DEFINE_BLOCK_CHS_PROPERTIES(VirtIOBlock, blk.conf),
|
||||
DEFINE_PROP_STRING("serial", VirtIOBlock, blk.serial),
|
||||
DEFINE_PROP_BIT("config-wce", VirtIOBlock, blk.config_wce, 0, true),
|
||||
DEFINE_BLOCK_PROPERTIES(VirtIOBlock, conf.conf),
|
||||
DEFINE_BLOCK_CHS_PROPERTIES(VirtIOBlock, conf.conf),
|
||||
DEFINE_PROP_STRING("serial", VirtIOBlock, conf.serial),
|
||||
DEFINE_PROP_BIT("config-wce", VirtIOBlock, conf.config_wce, 0, true),
|
||||
#ifdef __linux__
|
||||
DEFINE_PROP_BIT("scsi", VirtIOBlock, blk.scsi, 0, true),
|
||||
DEFINE_PROP_BIT("scsi", VirtIOBlock, conf.scsi, 0, true),
|
||||
#endif
|
||||
DEFINE_PROP_BIT("x-data-plane", VirtIOBlock, blk.data_plane, 0, false),
|
||||
DEFINE_PROP_BIT("x-data-plane", VirtIOBlock, conf.data_plane, 0, false),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "hw/xen/xen_backend.h"
|
||||
#include "xen_blkif.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
|
||||
@@ -122,7 +123,7 @@ struct XenBlkDev {
|
||||
|
||||
/* qemu block driver */
|
||||
DriveInfo *dinfo;
|
||||
BlockDriverState *bs;
|
||||
BlockBackend *blk;
|
||||
QEMUBH *bh;
|
||||
};
|
||||
|
||||
@@ -479,7 +480,7 @@ static void qemu_aio_complete(void *opaque, int ret)
|
||||
if (ioreq->postsync) {
|
||||
ioreq->postsync = 0;
|
||||
ioreq->aio_inflight++;
|
||||
bdrv_aio_flush(ioreq->blkdev->bs, qemu_aio_complete, ioreq);
|
||||
blk_aio_flush(ioreq->blkdev->blk, qemu_aio_complete, ioreq);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -493,7 +494,7 @@ static void qemu_aio_complete(void *opaque, int ret)
|
||||
break;
|
||||
}
|
||||
case BLKIF_OP_READ:
|
||||
block_acct_done(bdrv_get_stats(ioreq->blkdev->bs), &ioreq->acct);
|
||||
block_acct_done(blk_get_stats(ioreq->blkdev->blk), &ioreq->acct);
|
||||
break;
|
||||
case BLKIF_OP_DISCARD:
|
||||
default:
|
||||
@@ -512,18 +513,18 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
|
||||
|
||||
ioreq->aio_inflight++;
|
||||
if (ioreq->presync) {
|
||||
bdrv_aio_flush(ioreq->blkdev->bs, qemu_aio_complete, ioreq);
|
||||
blk_aio_flush(ioreq->blkdev->blk, qemu_aio_complete, ioreq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (ioreq->req.operation) {
|
||||
case BLKIF_OP_READ:
|
||||
block_acct_start(bdrv_get_stats(blkdev->bs), &ioreq->acct,
|
||||
block_acct_start(blk_get_stats(blkdev->blk), &ioreq->acct,
|
||||
ioreq->v.size, BLOCK_ACCT_READ);
|
||||
ioreq->aio_inflight++;
|
||||
bdrv_aio_readv(blkdev->bs, ioreq->start / BLOCK_SIZE,
|
||||
&ioreq->v, ioreq->v.size / BLOCK_SIZE,
|
||||
qemu_aio_complete, ioreq);
|
||||
blk_aio_readv(blkdev->blk, ioreq->start / BLOCK_SIZE,
|
||||
&ioreq->v, ioreq->v.size / BLOCK_SIZE,
|
||||
qemu_aio_complete, ioreq);
|
||||
break;
|
||||
case BLKIF_OP_WRITE:
|
||||
case BLKIF_OP_FLUSH_DISKCACHE:
|
||||
@@ -531,18 +532,18 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
|
||||
break;
|
||||
}
|
||||
|
||||
block_acct_start(bdrv_get_stats(blkdev->bs), &ioreq->acct,
|
||||
block_acct_start(blk_get_stats(blkdev->blk), &ioreq->acct,
|
||||
ioreq->v.size, BLOCK_ACCT_WRITE);
|
||||
ioreq->aio_inflight++;
|
||||
bdrv_aio_writev(blkdev->bs, ioreq->start / BLOCK_SIZE,
|
||||
&ioreq->v, ioreq->v.size / BLOCK_SIZE,
|
||||
qemu_aio_complete, ioreq);
|
||||
blk_aio_writev(blkdev->blk, ioreq->start / BLOCK_SIZE,
|
||||
&ioreq->v, ioreq->v.size / BLOCK_SIZE,
|
||||
qemu_aio_complete, ioreq);
|
||||
break;
|
||||
case BLKIF_OP_DISCARD:
|
||||
{
|
||||
struct blkif_request_discard *discard_req = (void *)&ioreq->req;
|
||||
ioreq->aio_inflight++;
|
||||
bdrv_aio_discard(blkdev->bs,
|
||||
blk_aio_discard(blkdev->blk,
|
||||
discard_req->sector_number, discard_req->nr_sectors,
|
||||
qemu_aio_complete, ioreq);
|
||||
break;
|
||||
@@ -854,44 +855,49 @@ static int blk_connect(struct XenDevice *xendev)
|
||||
blkdev->dinfo = drive_get(IF_XEN, 0, index);
|
||||
if (!blkdev->dinfo) {
|
||||
Error *local_err = NULL;
|
||||
BlockBackend *blk;
|
||||
BlockDriver *drv;
|
||||
BlockDriverState *bs;
|
||||
|
||||
/* setup via xenbus -> create new block driver instance */
|
||||
xen_be_printf(&blkdev->xendev, 2, "create new bdrv (xenbus setup)\n");
|
||||
blkdev->bs = bdrv_new(blkdev->dev, NULL);
|
||||
if (!blkdev->bs) {
|
||||
blk = blk_new_with_bs(blkdev->dev, NULL);
|
||||
if (!blk) {
|
||||
return -1;
|
||||
}
|
||||
blkdev->blk = blk;
|
||||
|
||||
bs = blk_bs(blk);
|
||||
drv = bdrv_find_whitelisted_format(blkdev->fileproto, readonly);
|
||||
if (bdrv_open(&blkdev->bs, blkdev->filename, NULL, NULL, qflags,
|
||||
if (bdrv_open(&bs, blkdev->filename, NULL, NULL, qflags,
|
||||
drv, &local_err) != 0) {
|
||||
xen_be_printf(&blkdev->xendev, 0, "error: %s\n",
|
||||
error_get_pretty(local_err));
|
||||
error_free(local_err);
|
||||
bdrv_unref(blkdev->bs);
|
||||
blkdev->bs = NULL;
|
||||
blk_unref(blk);
|
||||
blkdev->blk = NULL;
|
||||
return -1;
|
||||
}
|
||||
assert(bs == blk_bs(blk));
|
||||
} else {
|
||||
/* setup via qemu cmdline -> already setup for us */
|
||||
xen_be_printf(&blkdev->xendev, 2, "get configured bdrv (cmdline setup)\n");
|
||||
blkdev->bs = blkdev->dinfo->bdrv;
|
||||
if (bdrv_is_read_only(blkdev->bs) && !readonly) {
|
||||
blkdev->blk = blk_by_legacy_dinfo(blkdev->dinfo);
|
||||
if (blk_is_read_only(blkdev->blk) && !readonly) {
|
||||
xen_be_printf(&blkdev->xendev, 0, "Unexpected read-only drive");
|
||||
blkdev->bs = NULL;
|
||||
blkdev->blk = NULL;
|
||||
return -1;
|
||||
}
|
||||
/* blkdev->bs is not create by us, we get a reference
|
||||
* so we can bdrv_unref() unconditionally */
|
||||
bdrv_ref(blkdev->bs);
|
||||
/* blkdev->blk is not create by us, we get a reference
|
||||
* so we can blk_unref() unconditionally */
|
||||
blk_ref(blkdev->blk);
|
||||
}
|
||||
bdrv_attach_dev_nofail(blkdev->bs, blkdev);
|
||||
blkdev->file_size = bdrv_getlength(blkdev->bs);
|
||||
blk_attach_dev_nofail(blkdev->blk, blkdev);
|
||||
blkdev->file_size = blk_getlength(blkdev->blk);
|
||||
if (blkdev->file_size < 0) {
|
||||
xen_be_printf(&blkdev->xendev, 1, "bdrv_getlength: %d (%s) | drv %s\n",
|
||||
xen_be_printf(&blkdev->xendev, 1, "blk_getlength: %d (%s) | drv %s\n",
|
||||
(int)blkdev->file_size, strerror(-blkdev->file_size),
|
||||
bdrv_get_format_name(blkdev->bs) ?: "-");
|
||||
bdrv_get_format_name(blk_bs(blkdev->blk)) ?: "-");
|
||||
blkdev->file_size = 0;
|
||||
}
|
||||
|
||||
@@ -982,10 +988,10 @@ static void blk_disconnect(struct XenDevice *xendev)
|
||||
{
|
||||
struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
|
||||
|
||||
if (blkdev->bs) {
|
||||
bdrv_detach_dev(blkdev->bs, blkdev);
|
||||
bdrv_unref(blkdev->bs);
|
||||
blkdev->bs = NULL;
|
||||
if (blkdev->blk) {
|
||||
blk_detach_dev(blkdev->blk, blkdev);
|
||||
blk_unref(blkdev->blk);
|
||||
blkdev->blk = NULL;
|
||||
}
|
||||
xen_be_unbind_evtchn(&blkdev->xendev);
|
||||
|
||||
@@ -1001,7 +1007,7 @@ static int blk_free(struct XenDevice *xendev)
|
||||
struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
|
||||
struct ioreq *ioreq;
|
||||
|
||||
if (blkdev->bs || blkdev->sring) {
|
||||
if (blkdev->blk || blkdev->sring) {
|
||||
blk_disconnect(xendev);
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user