Compare commits
166 Commits
pull-roms-
...
pull-input
Author | SHA1 | Date | |
---|---|---|---|
|
8977bd111f | ||
|
f85d28316a | ||
|
ee8c0b622c | ||
|
6f5943cf45 | ||
|
8b84286f4c | ||
|
1ff5eedd1d | ||
|
86846bfe64 | ||
|
2386a90730 | ||
|
11c7fa7fa6 | ||
|
f5c0ab1312 | ||
|
178ac111bc | ||
|
6054d883d6 | ||
|
5118dc5975 | ||
|
45e66b7beb | ||
|
65903a8b08 | ||
|
fc13d93726 | ||
|
3478881130 | ||
|
d2e064a73e | ||
|
3894c78764 | ||
|
0aff637e92 | ||
|
5f758366c0 | ||
|
3f9286b721 | ||
|
3b69595068 | ||
|
5a7733b0b7 | ||
|
770a63792b | ||
|
b30f4dfbda | ||
|
8e4e86afa5 | ||
|
76eb98d51c | ||
|
d426d9fba8 | ||
|
7bca3892cb | ||
|
03cf077ac9 | ||
|
7b35d0c44c | ||
|
61c7bbd236 | ||
|
ca8c0fab95 | ||
|
f2564d88fe | ||
|
b1fe60cd35 | ||
|
a2554a334a | ||
|
c5fa6c86d0 | ||
|
5bc8f026dd | ||
|
465bee1da8 | ||
|
6a23082b4e | ||
|
82a402e99f | ||
|
43f35cb5e0 | ||
|
d66e5cee00 | ||
|
46485de0cb | ||
|
42eb58179b | ||
|
7159a45b2b | ||
|
ea54feff58 | ||
|
0a86cb7317 | ||
|
97a3ea5719 | ||
|
e3542c67af | ||
|
9aedd5a5d6 | ||
|
b5e51dd714 | ||
|
d530e34232 | ||
|
4ad303369c | ||
|
4993f7ea7e | ||
|
8a5eb36a1c | ||
|
9c52681277 | ||
|
26e2da7279 | ||
|
6906046169 | ||
|
395071a763 | ||
|
e88ae2264d | ||
|
91e7fcca47 | ||
|
c4ce4c4b1f | ||
|
24fd848950 | ||
|
59e7a13005 | ||
|
97256073b1 | ||
|
2ada510698 | ||
|
65e7545ea3 | ||
|
2a766d294a | ||
|
66e6536e0c | ||
|
ce53f2f98f | ||
|
528728fd93 | ||
|
02aa76c2ba | ||
|
2858ab09e6 | ||
|
11b389f21e | ||
|
b162b49adc | ||
|
40d19394b7 | ||
|
13e315dada | ||
|
6297d9a279 | ||
|
29136cd8a4 | ||
|
87a560c455 | ||
|
297a3646c2 | ||
|
cdaec3808e | ||
|
2ddb16a95f | ||
|
f9f3a5ecde | ||
|
be3c771796 | ||
|
192cca60ae | ||
|
4fa953f20d | ||
|
468866b816 | ||
|
e2cd0f4fb4 | ||
|
cbc95538ed | ||
|
f9bee751be | ||
|
6e2bb3ec70 | ||
|
1a381811b4 | ||
|
16a9189921 | ||
|
ba43bc25c9 | ||
|
895527eea5 | ||
|
a10c64e0df | ||
|
061cdd8182 | ||
|
50cb70d185 | ||
|
6b7aa99eb4 | ||
|
ef3cb5ca82 | ||
|
06e33c1c3c | ||
|
7d983531c6 | ||
|
7b7066b1db | ||
|
ad19b35808 | ||
|
f167dc37da | ||
|
547ec12141 | ||
|
fb5964152d | ||
|
f24efee41e | ||
|
b8dd88b85c | ||
|
a5a04f2830 | ||
|
a175689654 | ||
|
450445d543 | ||
|
719ffe1f5f | ||
|
d6ed7312d1 | ||
|
35d08458a9 | ||
|
6e3d652ab2 | ||
|
14bcfdc7f1 | ||
|
fb626663da | ||
|
89f26e6b7b | ||
|
1a7917210b | ||
|
c3a699be3c | ||
|
2a41c92854 | ||
|
7e7e5858f8 | ||
|
c94239fe56 | ||
|
654039b42a | ||
|
2f0d8631b7 | ||
|
2e11986727 | ||
|
889ac2a32f | ||
|
eacd606ca7 | ||
|
a9171c4fb5 | ||
|
c6fa443b3d | ||
|
7fd5f064d1 | ||
|
5c10495ab1 | ||
|
8f1e884b38 | ||
|
09319b3041 | ||
|
4700a316df | ||
|
4a92a558f4 | ||
|
7b4d915e11 | ||
|
43175fa96a | ||
|
05e7e819d7 | ||
|
e0723c4510 | ||
|
50a2c6e55f | ||
|
7848c8d19f | ||
|
fd460606fd | ||
|
010e639a8d | ||
|
304520291a | ||
|
639973a474 | ||
|
ee11f7a822 | ||
|
ada4135f84 | ||
|
8e03c100a7 | ||
|
dc1823ce26 | ||
|
9372514080 | ||
|
6a86dec619 | ||
|
3d2acaa308 | ||
|
5917af812e | ||
|
b03c38057b | ||
|
dbe5c58f2a | ||
|
d383c625e2 | ||
|
4522b69c6c | ||
|
23335f6273 | ||
|
34bb4d02e0 | ||
|
6ee143a0a4 | ||
|
4bbeb8b173 |
@@ -659,6 +659,12 @@ S: Supported
|
||||
F: hw/block/nvme*
|
||||
F: tests/nvme-test.c
|
||||
|
||||
megasas
|
||||
M: Hannes Reinecke <hare@suse.de>
|
||||
S: Supported
|
||||
F: hw/scsi/megasas.c
|
||||
F: hw/scsi/mfi.h
|
||||
|
||||
Xilinx EDK
|
||||
M: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
|
||||
M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
|
||||
|
155
arch_init.c
155
arch_init.c
@@ -560,20 +560,93 @@ static void migration_bitmap_sync(void)
|
||||
}
|
||||
|
||||
/*
|
||||
* ram_save_block: Writes a page of memory to the stream f
|
||||
* ram_save_page: Send the given page to the stream
|
||||
*
|
||||
* Returns: Number of bytes written.
|
||||
*/
|
||||
static int ram_save_page(QEMUFile *f, RAMBlock* block, ram_addr_t offset,
|
||||
bool last_stage)
|
||||
{
|
||||
int bytes_sent;
|
||||
int cont;
|
||||
ram_addr_t current_addr;
|
||||
MemoryRegion *mr = block->mr;
|
||||
uint8_t *p;
|
||||
int ret;
|
||||
bool send_async = true;
|
||||
|
||||
cont = (block == last_sent_block) ? RAM_SAVE_FLAG_CONTINUE : 0;
|
||||
|
||||
p = memory_region_get_ram_ptr(mr) + offset;
|
||||
|
||||
/* In doubt sent page as normal */
|
||||
bytes_sent = -1;
|
||||
ret = ram_control_save_page(f, block->offset,
|
||||
offset, TARGET_PAGE_SIZE, &bytes_sent);
|
||||
|
||||
XBZRLE_cache_lock();
|
||||
|
||||
current_addr = block->offset + offset;
|
||||
if (ret != RAM_SAVE_CONTROL_NOT_SUPP) {
|
||||
if (ret != RAM_SAVE_CONTROL_DELAYED) {
|
||||
if (bytes_sent > 0) {
|
||||
acct_info.norm_pages++;
|
||||
} else if (bytes_sent == 0) {
|
||||
acct_info.dup_pages++;
|
||||
}
|
||||
}
|
||||
} else if (is_zero_range(p, TARGET_PAGE_SIZE)) {
|
||||
acct_info.dup_pages++;
|
||||
bytes_sent = save_block_hdr(f, block, offset, cont,
|
||||
RAM_SAVE_FLAG_COMPRESS);
|
||||
qemu_put_byte(f, 0);
|
||||
bytes_sent++;
|
||||
/* Must let xbzrle know, otherwise a previous (now 0'd) cached
|
||||
* page would be stale
|
||||
*/
|
||||
xbzrle_cache_zero_page(current_addr);
|
||||
} else if (!ram_bulk_stage && migrate_use_xbzrle()) {
|
||||
bytes_sent = save_xbzrle_page(f, &p, current_addr, block,
|
||||
offset, cont, last_stage);
|
||||
if (!last_stage) {
|
||||
/* Can't send this cached data async, since the cache page
|
||||
* might get updated before it gets to the wire
|
||||
*/
|
||||
send_async = false;
|
||||
}
|
||||
}
|
||||
|
||||
/* XBZRLE overflow or normal page */
|
||||
if (bytes_sent == -1) {
|
||||
bytes_sent = save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_PAGE);
|
||||
if (send_async) {
|
||||
qemu_put_buffer_async(f, p, TARGET_PAGE_SIZE);
|
||||
} else {
|
||||
qemu_put_buffer(f, p, TARGET_PAGE_SIZE);
|
||||
}
|
||||
bytes_sent += TARGET_PAGE_SIZE;
|
||||
acct_info.norm_pages++;
|
||||
}
|
||||
|
||||
XBZRLE_cache_unlock();
|
||||
|
||||
return bytes_sent;
|
||||
}
|
||||
|
||||
/*
|
||||
* ram_find_and_save_block: Finds a page to send and sends it to f
|
||||
*
|
||||
* Returns: The number of bytes written.
|
||||
* 0 means no dirty pages
|
||||
*/
|
||||
|
||||
static int ram_save_block(QEMUFile *f, bool last_stage)
|
||||
static int ram_find_and_save_block(QEMUFile *f, bool last_stage)
|
||||
{
|
||||
RAMBlock *block = last_seen_block;
|
||||
ram_addr_t offset = last_offset;
|
||||
bool complete_round = false;
|
||||
int bytes_sent = 0;
|
||||
MemoryRegion *mr;
|
||||
ram_addr_t current_addr;
|
||||
|
||||
if (!block)
|
||||
block = QTAILQ_FIRST(&ram_list.blocks);
|
||||
@@ -594,64 +667,8 @@ static int ram_save_block(QEMUFile *f, bool last_stage)
|
||||
ram_bulk_stage = false;
|
||||
}
|
||||
} else {
|
||||
int ret;
|
||||
uint8_t *p;
|
||||
bool send_async = true;
|
||||
int cont = (block == last_sent_block) ?
|
||||
RAM_SAVE_FLAG_CONTINUE : 0;
|
||||
bytes_sent = ram_save_page(f, block, offset, last_stage);
|
||||
|
||||
p = memory_region_get_ram_ptr(mr) + offset;
|
||||
|
||||
/* In doubt sent page as normal */
|
||||
bytes_sent = -1;
|
||||
ret = ram_control_save_page(f, block->offset,
|
||||
offset, TARGET_PAGE_SIZE, &bytes_sent);
|
||||
|
||||
XBZRLE_cache_lock();
|
||||
|
||||
current_addr = block->offset + offset;
|
||||
if (ret != RAM_SAVE_CONTROL_NOT_SUPP) {
|
||||
if (ret != RAM_SAVE_CONTROL_DELAYED) {
|
||||
if (bytes_sent > 0) {
|
||||
acct_info.norm_pages++;
|
||||
} else if (bytes_sent == 0) {
|
||||
acct_info.dup_pages++;
|
||||
}
|
||||
}
|
||||
} else if (is_zero_range(p, TARGET_PAGE_SIZE)) {
|
||||
acct_info.dup_pages++;
|
||||
bytes_sent = save_block_hdr(f, block, offset, cont,
|
||||
RAM_SAVE_FLAG_COMPRESS);
|
||||
qemu_put_byte(f, 0);
|
||||
bytes_sent++;
|
||||
/* Must let xbzrle know, otherwise a previous (now 0'd) cached
|
||||
* page would be stale
|
||||
*/
|
||||
xbzrle_cache_zero_page(current_addr);
|
||||
} else if (!ram_bulk_stage && migrate_use_xbzrle()) {
|
||||
bytes_sent = save_xbzrle_page(f, &p, current_addr, block,
|
||||
offset, cont, last_stage);
|
||||
if (!last_stage) {
|
||||
/* Can't send this cached data async, since the cache page
|
||||
* might get updated before it gets to the wire
|
||||
*/
|
||||
send_async = false;
|
||||
}
|
||||
}
|
||||
|
||||
/* XBZRLE overflow or normal page */
|
||||
if (bytes_sent == -1) {
|
||||
bytes_sent = save_block_hdr(f, block, offset, cont, RAM_SAVE_FLAG_PAGE);
|
||||
if (send_async) {
|
||||
qemu_put_buffer_async(f, p, TARGET_PAGE_SIZE);
|
||||
} else {
|
||||
qemu_put_buffer(f, p, TARGET_PAGE_SIZE);
|
||||
}
|
||||
bytes_sent += TARGET_PAGE_SIZE;
|
||||
acct_info.norm_pages++;
|
||||
}
|
||||
|
||||
XBZRLE_cache_unlock();
|
||||
/* if page is unmodified, continue to the next */
|
||||
if (bytes_sent > 0) {
|
||||
last_sent_block = block;
|
||||
@@ -850,7 +867,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque)
|
||||
while ((ret = qemu_file_rate_limit(f)) == 0) {
|
||||
int bytes_sent;
|
||||
|
||||
bytes_sent = ram_save_block(f, false);
|
||||
bytes_sent = ram_find_and_save_block(f, false);
|
||||
/* no more blocks to sent */
|
||||
if (bytes_sent == 0) {
|
||||
break;
|
||||
@@ -912,7 +929,7 @@ static int ram_save_complete(QEMUFile *f, void *opaque)
|
||||
while (true) {
|
||||
int bytes_sent;
|
||||
|
||||
bytes_sent = ram_save_block(f, true);
|
||||
bytes_sent = ram_find_and_save_block(f, true);
|
||||
/* no more blocks to sent */
|
||||
if (bytes_sent == 0) {
|
||||
break;
|
||||
@@ -946,7 +963,6 @@ static uint64_t ram_save_pending(QEMUFile *f, void *opaque, uint64_t max_size)
|
||||
|
||||
static int load_xbzrle(QEMUFile *f, ram_addr_t addr, void *host)
|
||||
{
|
||||
int ret, rc = 0;
|
||||
unsigned int xh_len;
|
||||
int xh_flags;
|
||||
|
||||
@@ -971,18 +987,13 @@ static int load_xbzrle(QEMUFile *f, ram_addr_t addr, void *host)
|
||||
qemu_get_buffer(f, xbzrle_decoded_buf, xh_len);
|
||||
|
||||
/* decode RLE */
|
||||
ret = xbzrle_decode_buffer(xbzrle_decoded_buf, xh_len, host,
|
||||
TARGET_PAGE_SIZE);
|
||||
if (ret == -1) {
|
||||
if (xbzrle_decode_buffer(xbzrle_decoded_buf, xh_len, host,
|
||||
TARGET_PAGE_SIZE) == -1) {
|
||||
fprintf(stderr, "Failed to load XBZRLE page - decode error!\n");
|
||||
rc = -1;
|
||||
} else if (ret > TARGET_PAGE_SIZE) {
|
||||
fprintf(stderr, "Failed to load XBZRLE page - size %d exceeds %d!\n",
|
||||
ret, TARGET_PAGE_SIZE);
|
||||
abort();
|
||||
return -1;
|
||||
}
|
||||
|
||||
return rc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void *host_from_stream_offset(QEMUFile *f,
|
||||
|
@@ -1812,8 +1812,7 @@ static const VMStateDescription vmstate_audio = {
|
||||
.name = "audio",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField []) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
60
block.c
60
block.c
@@ -1274,6 +1274,33 @@ out:
|
||||
g_free(tmp_filename);
|
||||
}
|
||||
|
||||
static QDict *parse_json_filename(const char *filename, Error **errp)
|
||||
{
|
||||
QObject *options_obj;
|
||||
QDict *options;
|
||||
int ret;
|
||||
|
||||
ret = strstart(filename, "json:", &filename);
|
||||
assert(ret);
|
||||
|
||||
options_obj = qobject_from_json(filename);
|
||||
if (!options_obj) {
|
||||
error_setg(errp, "Could not parse the JSON options");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (qobject_type(options_obj) != QTYPE_QDICT) {
|
||||
qobject_decref(options_obj);
|
||||
error_setg(errp, "Invalid JSON object given");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
options = qobject_to_qdict(options_obj);
|
||||
qdict_flatten(options);
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
/*
|
||||
* Opens a disk image (raw, qcow2, vmdk, ...)
|
||||
*
|
||||
@@ -1337,6 +1364,20 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
|
||||
options = qdict_new();
|
||||
}
|
||||
|
||||
if (filename && g_str_has_prefix(filename, "json:")) {
|
||||
QDict *json_options = parse_json_filename(filename, &local_err);
|
||||
if (local_err) {
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Options given in the filename have lower priority than options
|
||||
* specified directly */
|
||||
qdict_join(options, json_options, false);
|
||||
QDECREF(json_options);
|
||||
filename = NULL;
|
||||
}
|
||||
|
||||
bs->options = options;
|
||||
options = qdict_clone_shallow(options);
|
||||
|
||||
@@ -3248,6 +3289,15 @@ static int coroutine_fn bdrv_aligned_pwritev(BlockDriverState *bs,
|
||||
|
||||
ret = notifier_with_return_list_notify(&bs->before_write_notifiers, req);
|
||||
|
||||
if (!ret && bs->detect_zeroes != BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF &&
|
||||
!(flags & BDRV_REQ_ZERO_WRITE) && drv->bdrv_co_write_zeroes &&
|
||||
qemu_iovec_is_zero(qiov)) {
|
||||
flags |= BDRV_REQ_ZERO_WRITE;
|
||||
if (bs->detect_zeroes == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP) {
|
||||
flags |= BDRV_REQ_MAY_UNMAP;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
/* Do nothing, write notifier decided to fail this request */
|
||||
} else if (flags & BDRV_REQ_ZERO_WRITE) {
|
||||
@@ -3864,7 +3914,7 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
|
||||
|
||||
if (!bs->drv->bdrv_co_get_block_status) {
|
||||
*pnum = nb_sectors;
|
||||
ret = BDRV_BLOCK_DATA;
|
||||
ret = BDRV_BLOCK_DATA | BDRV_BLOCK_ALLOCATED;
|
||||
if (bs->drv->protocol_name) {
|
||||
ret |= BDRV_BLOCK_OFFSET_VALID | (sector_num * BDRV_SECTOR_SIZE);
|
||||
}
|
||||
@@ -3883,6 +3933,10 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
|
||||
*pnum, pnum);
|
||||
}
|
||||
|
||||
if (ret & (BDRV_BLOCK_DATA | BDRV_BLOCK_ZERO)) {
|
||||
ret |= BDRV_BLOCK_ALLOCATED;
|
||||
}
|
||||
|
||||
if (!(ret & BDRV_BLOCK_DATA) && !(ret & BDRV_BLOCK_ZERO)) {
|
||||
if (bdrv_unallocated_blocks_are_zero(bs)) {
|
||||
ret |= BDRV_BLOCK_ZERO;
|
||||
@@ -3959,9 +4013,7 @@ int coroutine_fn bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num,
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
return
|
||||
(ret & BDRV_BLOCK_DATA) ||
|
||||
((ret & BDRV_BLOCK_ZERO) && !bdrv_has_zero_init(bs));
|
||||
return (ret & BDRV_BLOCK_ALLOCATED);
|
||||
}
|
||||
|
||||
/*
|
||||
|
79
block/curl.c
79
block/curl.c
@@ -23,6 +23,7 @@
|
||||
*/
|
||||
#include "qemu-common.h"
|
||||
#include "block/block_int.h"
|
||||
#include "qapi/qmp/qbool.h"
|
||||
#include <curl/curl.h>
|
||||
|
||||
// #define DEBUG
|
||||
@@ -37,6 +38,21 @@
|
||||
#if LIBCURL_VERSION_NUM >= 0x071000
|
||||
/* The multi interface timer callback was introduced in 7.16.0 */
|
||||
#define NEED_CURL_TIMER_CALLBACK
|
||||
#define HAVE_SOCKET_ACTION
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_SOCKET_ACTION
|
||||
/* If curl_multi_socket_action isn't available, define it statically here in
|
||||
* terms of curl_multi_socket. Note that ev_bitmask will be ignored, which is
|
||||
* less efficient but still safe. */
|
||||
static CURLMcode __curl_multi_socket_action(CURLM *multi_handle,
|
||||
curl_socket_t sockfd,
|
||||
int ev_bitmask,
|
||||
int *running_handles)
|
||||
{
|
||||
return curl_multi_socket(multi_handle, sockfd, running_handles);
|
||||
}
|
||||
#define curl_multi_socket_action __curl_multi_socket_action
|
||||
#endif
|
||||
|
||||
#define PROTOCOLS (CURLPROTO_HTTP | CURLPROTO_HTTPS | \
|
||||
@@ -46,12 +62,16 @@
|
||||
#define CURL_NUM_STATES 8
|
||||
#define CURL_NUM_ACB 8
|
||||
#define SECTOR_SIZE 512
|
||||
#define READ_AHEAD_SIZE (256 * 1024)
|
||||
#define READ_AHEAD_DEFAULT (256 * 1024)
|
||||
|
||||
#define FIND_RET_NONE 0
|
||||
#define FIND_RET_OK 1
|
||||
#define FIND_RET_WAIT 2
|
||||
|
||||
#define CURL_BLOCK_OPT_URL "url"
|
||||
#define CURL_BLOCK_OPT_READAHEAD "readahead"
|
||||
#define CURL_BLOCK_OPT_SSLVERIFY "sslverify"
|
||||
|
||||
struct BDRVCURLState;
|
||||
|
||||
typedef struct CURLAIOCB {
|
||||
@@ -88,6 +108,7 @@ typedef struct BDRVCURLState {
|
||||
CURLState states[CURL_NUM_STATES];
|
||||
char *url;
|
||||
size_t readahead_size;
|
||||
bool sslverify;
|
||||
bool accept_range;
|
||||
} BDRVCURLState;
|
||||
|
||||
@@ -354,6 +375,8 @@ static CURLState *curl_init_state(BDRVCURLState *s)
|
||||
return NULL;
|
||||
}
|
||||
curl_easy_setopt(state->curl, CURLOPT_URL, s->url);
|
||||
curl_easy_setopt(state->curl, CURLOPT_SSL_VERIFYPEER,
|
||||
(long) s->sslverify);
|
||||
curl_easy_setopt(state->curl, CURLOPT_TIMEOUT, 5);
|
||||
curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION,
|
||||
(void *)curl_read_cb);
|
||||
@@ -396,43 +419,7 @@ static void curl_clean_state(CURLState *s)
|
||||
static void curl_parse_filename(const char *filename, QDict *options,
|
||||
Error **errp)
|
||||
{
|
||||
|
||||
#define RA_OPTSTR ":readahead="
|
||||
char *file;
|
||||
char *ra;
|
||||
const char *ra_val;
|
||||
int parse_state = 0;
|
||||
|
||||
file = g_strdup(filename);
|
||||
|
||||
/* Parse a trailing ":readahead=#:" param, if present. */
|
||||
ra = file + strlen(file) - 1;
|
||||
while (ra >= file) {
|
||||
if (parse_state == 0) {
|
||||
if (*ra == ':') {
|
||||
parse_state++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else if (parse_state == 1) {
|
||||
if (*ra > '9' || *ra < '0') {
|
||||
char *opt_start = ra - strlen(RA_OPTSTR) + 1;
|
||||
if (opt_start > file &&
|
||||
strncmp(opt_start, RA_OPTSTR, strlen(RA_OPTSTR)) == 0) {
|
||||
ra_val = ra + 1;
|
||||
ra -= strlen(RA_OPTSTR) - 1;
|
||||
*ra = '\0';
|
||||
qdict_put(options, "readahead", qstring_from_str(ra_val));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
ra--;
|
||||
}
|
||||
|
||||
qdict_put(options, "url", qstring_from_str(file));
|
||||
|
||||
g_free(file);
|
||||
qdict_put(options, CURL_BLOCK_OPT_URL, qstring_from_str(filename));
|
||||
}
|
||||
|
||||
static QemuOptsList runtime_opts = {
|
||||
@@ -440,15 +427,20 @@ static QemuOptsList runtime_opts = {
|
||||
.head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
|
||||
.desc = {
|
||||
{
|
||||
.name = "url",
|
||||
.name = CURL_BLOCK_OPT_URL,
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "URL to open",
|
||||
},
|
||||
{
|
||||
.name = "readahead",
|
||||
.name = CURL_BLOCK_OPT_READAHEAD,
|
||||
.type = QEMU_OPT_SIZE,
|
||||
.help = "Readahead size",
|
||||
},
|
||||
{
|
||||
.name = CURL_BLOCK_OPT_SSLVERIFY,
|
||||
.type = QEMU_OPT_BOOL,
|
||||
.help = "Verify SSL certificate"
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
@@ -477,14 +469,17 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
goto out_noclean;
|
||||
}
|
||||
|
||||
s->readahead_size = qemu_opt_get_size(opts, "readahead", READ_AHEAD_SIZE);
|
||||
s->readahead_size = qemu_opt_get_size(opts, CURL_BLOCK_OPT_READAHEAD,
|
||||
READ_AHEAD_DEFAULT);
|
||||
if ((s->readahead_size & 0x1ff) != 0) {
|
||||
error_setg(errp, "HTTP_READAHEAD_SIZE %zd is not a multiple of 512",
|
||||
s->readahead_size);
|
||||
goto out_noclean;
|
||||
}
|
||||
|
||||
file = qemu_opt_get(opts, "url");
|
||||
s->sslverify = qemu_opt_get_bool(opts, CURL_BLOCK_OPT_SSLVERIFY, true);
|
||||
|
||||
file = qemu_opt_get(opts, CURL_BLOCK_OPT_URL);
|
||||
if (file == NULL) {
|
||||
error_setg(errp, "curl block driver requires an 'url' option");
|
||||
goto out_noclean;
|
||||
|
317
block/iscsi.c
317
block/iscsi.c
@@ -30,6 +30,8 @@
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/config-file.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/bitops.h"
|
||||
#include "qemu/bitmap.h"
|
||||
#include "block/block_int.h"
|
||||
#include "trace.h"
|
||||
#include "block/scsi.h"
|
||||
@@ -59,6 +61,8 @@ typedef struct IscsiLun {
|
||||
struct scsi_inquiry_logical_block_provisioning lbp;
|
||||
struct scsi_inquiry_block_limits bl;
|
||||
unsigned char *zeroblock;
|
||||
unsigned long *allocationmap;
|
||||
int cluster_sectors;
|
||||
} IscsiLun;
|
||||
|
||||
typedef struct IscsiTask {
|
||||
@@ -92,6 +96,15 @@ typedef struct IscsiAIOCB {
|
||||
#define MAX_NOP_FAILURES 3
|
||||
#define ISCSI_CMD_RETRIES 5
|
||||
|
||||
/* this threshhold is a trade-off knob to choose between
|
||||
* the potential additional overhead of an extra GET_LBA_STATUS request
|
||||
* vs. unnecessarily reading a lot of zero sectors over the wire.
|
||||
* If a read request is greater or equal than ISCSI_CHECKALLOC_THRES
|
||||
* sectors we check the allocation status of the area covered by the
|
||||
* request first if the allocationmap indicates that the area might be
|
||||
* unallocated. */
|
||||
#define ISCSI_CHECKALLOC_THRES 64
|
||||
|
||||
static void
|
||||
iscsi_bh_cb(void *p)
|
||||
{
|
||||
@@ -273,6 +286,32 @@ static bool is_request_lun_aligned(int64_t sector_num, int nb_sectors,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void iscsi_allocationmap_set(IscsiLun *iscsilun, int64_t sector_num,
|
||||
int nb_sectors)
|
||||
{
|
||||
if (iscsilun->allocationmap == NULL) {
|
||||
return;
|
||||
}
|
||||
bitmap_set(iscsilun->allocationmap,
|
||||
sector_num / iscsilun->cluster_sectors,
|
||||
DIV_ROUND_UP(nb_sectors, iscsilun->cluster_sectors));
|
||||
}
|
||||
|
||||
static void iscsi_allocationmap_clear(IscsiLun *iscsilun, int64_t sector_num,
|
||||
int nb_sectors)
|
||||
{
|
||||
int64_t cluster_num, nb_clusters;
|
||||
if (iscsilun->allocationmap == NULL) {
|
||||
return;
|
||||
}
|
||||
cluster_num = DIV_ROUND_UP(sector_num, iscsilun->cluster_sectors);
|
||||
nb_clusters = (sector_num + nb_sectors) / iscsilun->cluster_sectors
|
||||
- cluster_num;
|
||||
if (nb_clusters > 0) {
|
||||
bitmap_clear(iscsilun->allocationmap, cluster_num, nb_clusters);
|
||||
}
|
||||
}
|
||||
|
||||
static int coroutine_fn iscsi_co_writev(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors,
|
||||
QEMUIOVector *iov)
|
||||
@@ -336,9 +375,125 @@ retry:
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
iscsi_allocationmap_set(iscsilun, sector_num, nb_sectors);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#if defined(LIBISCSI_FEATURE_IOVECTOR)
|
||||
static bool iscsi_allocationmap_is_allocated(IscsiLun *iscsilun,
|
||||
int64_t sector_num, int nb_sectors)
|
||||
{
|
||||
unsigned long size;
|
||||
if (iscsilun->allocationmap == NULL) {
|
||||
return true;
|
||||
}
|
||||
size = DIV_ROUND_UP(sector_num + nb_sectors, iscsilun->cluster_sectors);
|
||||
return !(find_next_bit(iscsilun->allocationmap, size,
|
||||
sector_num / iscsilun->cluster_sectors) == size);
|
||||
}
|
||||
|
||||
static int64_t coroutine_fn iscsi_co_get_block_status(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
int nb_sectors, int *pnum)
|
||||
{
|
||||
IscsiLun *iscsilun = bs->opaque;
|
||||
struct scsi_get_lba_status *lbas = NULL;
|
||||
struct scsi_lba_status_descriptor *lbasd = NULL;
|
||||
struct IscsiTask iTask;
|
||||
int64_t ret;
|
||||
|
||||
iscsi_co_init_iscsitask(iscsilun, &iTask);
|
||||
|
||||
if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* default to all sectors allocated */
|
||||
ret = BDRV_BLOCK_DATA;
|
||||
ret |= (sector_num << BDRV_SECTOR_BITS) | BDRV_BLOCK_OFFSET_VALID;
|
||||
*pnum = nb_sectors;
|
||||
|
||||
/* LUN does not support logical block provisioning */
|
||||
if (iscsilun->lbpme == 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
retry:
|
||||
if (iscsi_get_lba_status_task(iscsilun->iscsi, iscsilun->lun,
|
||||
sector_qemu2lun(sector_num, iscsilun),
|
||||
8 + 16, iscsi_co_generic_cb,
|
||||
&iTask) == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (!iTask.complete) {
|
||||
iscsi_set_events(iscsilun);
|
||||
qemu_coroutine_yield();
|
||||
}
|
||||
|
||||
if (iTask.do_retry) {
|
||||
if (iTask.task != NULL) {
|
||||
scsi_free_scsi_task(iTask.task);
|
||||
iTask.task = NULL;
|
||||
}
|
||||
iTask.complete = 0;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (iTask.status != SCSI_STATUS_GOOD) {
|
||||
/* in case the get_lba_status_callout fails (i.e.
|
||||
* because the device is busy or the cmd is not
|
||||
* supported) we pretend all blocks are allocated
|
||||
* for backwards compatibility */
|
||||
goto out;
|
||||
}
|
||||
|
||||
lbas = scsi_datain_unmarshall(iTask.task);
|
||||
if (lbas == NULL) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
lbasd = &lbas->descriptors[0];
|
||||
|
||||
if (sector_qemu2lun(sector_num, iscsilun) != lbasd->lba) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*pnum = sector_lun2qemu(lbasd->num_blocks, iscsilun);
|
||||
|
||||
if (lbasd->provisioning == SCSI_PROVISIONING_TYPE_DEALLOCATED ||
|
||||
lbasd->provisioning == SCSI_PROVISIONING_TYPE_ANCHORED) {
|
||||
ret &= ~BDRV_BLOCK_DATA;
|
||||
if (iscsilun->lbprz) {
|
||||
ret |= BDRV_BLOCK_ZERO;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret & BDRV_BLOCK_ZERO) {
|
||||
iscsi_allocationmap_clear(iscsilun, sector_num, *pnum);
|
||||
} else {
|
||||
iscsi_allocationmap_set(iscsilun, sector_num, *pnum);
|
||||
}
|
||||
|
||||
if (*pnum > nb_sectors) {
|
||||
*pnum = nb_sectors;
|
||||
}
|
||||
out:
|
||||
if (iTask.task != NULL) {
|
||||
scsi_free_scsi_task(iTask.task);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* LIBISCSI_FEATURE_IOVECTOR */
|
||||
|
||||
|
||||
static int coroutine_fn iscsi_co_readv(BlockDriverState *bs,
|
||||
int64_t sector_num, int nb_sectors,
|
||||
QEMUIOVector *iov)
|
||||
@@ -355,6 +510,22 @@ static int coroutine_fn iscsi_co_readv(BlockDriverState *bs,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#if defined(LIBISCSI_FEATURE_IOVECTOR)
|
||||
if (iscsilun->lbprz && nb_sectors >= ISCSI_CHECKALLOC_THRES &&
|
||||
!iscsi_allocationmap_is_allocated(iscsilun, sector_num, nb_sectors)) {
|
||||
int64_t ret;
|
||||
int pnum;
|
||||
ret = iscsi_co_get_block_status(bs, sector_num, INT_MAX, &pnum);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
if (ret & BDRV_BLOCK_ZERO && pnum >= nb_sectors) {
|
||||
qemu_iovec_memset(iov, 0, 0x00, iov->size);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
lba = sector_qemu2lun(sector_num, iscsilun);
|
||||
num_sectors = sector_qemu2lun(nb_sectors, iscsilun);
|
||||
|
||||
@@ -643,101 +814,6 @@ iscsi_getlength(BlockDriverState *bs)
|
||||
return len;
|
||||
}
|
||||
|
||||
#if defined(LIBISCSI_FEATURE_IOVECTOR)
|
||||
|
||||
static int64_t coroutine_fn iscsi_co_get_block_status(BlockDriverState *bs,
|
||||
int64_t sector_num,
|
||||
int nb_sectors, int *pnum)
|
||||
{
|
||||
IscsiLun *iscsilun = bs->opaque;
|
||||
struct scsi_get_lba_status *lbas = NULL;
|
||||
struct scsi_lba_status_descriptor *lbasd = NULL;
|
||||
struct IscsiTask iTask;
|
||||
int64_t ret;
|
||||
|
||||
iscsi_co_init_iscsitask(iscsilun, &iTask);
|
||||
|
||||
if (!is_request_lun_aligned(sector_num, nb_sectors, iscsilun)) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* default to all sectors allocated */
|
||||
ret = BDRV_BLOCK_DATA;
|
||||
ret |= (sector_num << BDRV_SECTOR_BITS) | BDRV_BLOCK_OFFSET_VALID;
|
||||
*pnum = nb_sectors;
|
||||
|
||||
/* LUN does not support logical block provisioning */
|
||||
if (iscsilun->lbpme == 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
retry:
|
||||
if (iscsi_get_lba_status_task(iscsilun->iscsi, iscsilun->lun,
|
||||
sector_qemu2lun(sector_num, iscsilun),
|
||||
8 + 16, iscsi_co_generic_cb,
|
||||
&iTask) == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (!iTask.complete) {
|
||||
iscsi_set_events(iscsilun);
|
||||
qemu_coroutine_yield();
|
||||
}
|
||||
|
||||
if (iTask.do_retry) {
|
||||
if (iTask.task != NULL) {
|
||||
scsi_free_scsi_task(iTask.task);
|
||||
iTask.task = NULL;
|
||||
}
|
||||
iTask.complete = 0;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (iTask.status != SCSI_STATUS_GOOD) {
|
||||
/* in case the get_lba_status_callout fails (i.e.
|
||||
* because the device is busy or the cmd is not
|
||||
* supported) we pretend all blocks are allocated
|
||||
* for backwards compatibility */
|
||||
goto out;
|
||||
}
|
||||
|
||||
lbas = scsi_datain_unmarshall(iTask.task);
|
||||
if (lbas == NULL) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
lbasd = &lbas->descriptors[0];
|
||||
|
||||
if (sector_qemu2lun(sector_num, iscsilun) != lbasd->lba) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*pnum = sector_lun2qemu(lbasd->num_blocks, iscsilun);
|
||||
if (*pnum > nb_sectors) {
|
||||
*pnum = nb_sectors;
|
||||
}
|
||||
|
||||
if (lbasd->provisioning == SCSI_PROVISIONING_TYPE_DEALLOCATED ||
|
||||
lbasd->provisioning == SCSI_PROVISIONING_TYPE_ANCHORED) {
|
||||
ret &= ~BDRV_BLOCK_DATA;
|
||||
if (iscsilun->lbprz) {
|
||||
ret |= BDRV_BLOCK_ZERO;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (iTask.task != NULL) {
|
||||
scsi_free_scsi_task(iTask.task);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* LIBISCSI_FEATURE_IOVECTOR */
|
||||
|
||||
static int
|
||||
coroutine_fn iscsi_co_discard(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors)
|
||||
@@ -791,6 +867,8 @@ retry:
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
iscsi_allocationmap_clear(iscsilun, sector_num, nb_sectors);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -809,13 +887,14 @@ coroutine_fn iscsi_co_write_zeroes(BlockDriverState *bs, int64_t sector_num,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!(flags & BDRV_REQ_MAY_UNMAP) && !iscsilun->has_write_same) {
|
||||
/* WRITE SAME without UNMAP is not supported by the target */
|
||||
return -ENOTSUP;
|
||||
if ((flags & BDRV_REQ_MAY_UNMAP) && !iscsilun->lbp.lbpws) {
|
||||
/* WRITE SAME with UNMAP is not supported by the target,
|
||||
* fall back and try WRITE SAME without UNMAP */
|
||||
flags &= ~BDRV_REQ_MAY_UNMAP;
|
||||
}
|
||||
|
||||
if ((flags & BDRV_REQ_MAY_UNMAP) && !iscsilun->lbp.lbpws) {
|
||||
/* WRITE SAME with UNMAP is not supported by the target */
|
||||
if (!(flags & BDRV_REQ_MAY_UNMAP) && !iscsilun->has_write_same) {
|
||||
/* WRITE SAME without UNMAP is not supported by the target */
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
@@ -864,6 +943,12 @@ retry:
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (flags & BDRV_REQ_MAY_UNMAP) {
|
||||
iscsi_allocationmap_clear(iscsilun, sector_num, nb_sectors);
|
||||
} else {
|
||||
iscsi_allocationmap_set(iscsilun, sector_num, nb_sectors);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1295,6 +1380,22 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
timer_mod(iscsilun->nop_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + NOP_INTERVAL);
|
||||
#endif
|
||||
|
||||
/* Guess the internal cluster (page) size of the iscsi target by the means
|
||||
* of opt_unmap_gran. Transfer the unmap granularity only if it has a
|
||||
* reasonable size */
|
||||
if (iscsilun->bl.opt_unmap_gran * iscsilun->block_size >= 4 * 1024 &&
|
||||
iscsilun->bl.opt_unmap_gran * iscsilun->block_size <= 16 * 1024 * 1024) {
|
||||
iscsilun->cluster_sectors = (iscsilun->bl.opt_unmap_gran *
|
||||
iscsilun->block_size) >> BDRV_SECTOR_BITS;
|
||||
#if defined(LIBISCSI_FEATURE_IOVECTOR)
|
||||
if (iscsilun->lbprz && !(bs->open_flags & BDRV_O_NOCACHE)) {
|
||||
iscsilun->allocationmap =
|
||||
bitmap_new(DIV_ROUND_UP(bs->total_sectors,
|
||||
iscsilun->cluster_sectors));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
out:
|
||||
qemu_opts_del(opts);
|
||||
if (initiator_name != NULL) {
|
||||
@@ -1328,6 +1429,7 @@ static void iscsi_close(BlockDriverState *bs)
|
||||
qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), NULL, NULL, NULL);
|
||||
iscsi_destroy_context(iscsi);
|
||||
g_free(iscsilun->zeroblock);
|
||||
g_free(iscsilun->allocationmap);
|
||||
memset(iscsilun, 0, sizeof(IscsiLun));
|
||||
}
|
||||
|
||||
@@ -1388,6 +1490,13 @@ static int iscsi_truncate(BlockDriverState *bs, int64_t offset)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (iscsilun->allocationmap != NULL) {
|
||||
g_free(iscsilun->allocationmap);
|
||||
iscsilun->allocationmap =
|
||||
bitmap_new(DIV_ROUND_UP(bs->total_sectors,
|
||||
iscsilun->cluster_sectors));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1450,13 +1559,7 @@ static int iscsi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
|
||||
IscsiLun *iscsilun = bs->opaque;
|
||||
bdi->unallocated_blocks_are_zero = !!iscsilun->lbprz;
|
||||
bdi->can_write_zeroes_with_unmap = iscsilun->lbprz && iscsilun->lbp.lbpws;
|
||||
/* Guess the internal cluster (page) size of the iscsi target by the means
|
||||
* of opt_unmap_gran. Transfer the unmap granularity only if it has a
|
||||
* reasonable size for bdi->cluster_size */
|
||||
if (iscsilun->bl.opt_unmap_gran * iscsilun->block_size >= 64 * 1024 &&
|
||||
iscsilun->bl.opt_unmap_gran * iscsilun->block_size <= 16 * 1024 * 1024) {
|
||||
bdi->cluster_size = iscsilun->bl.opt_unmap_gran * iscsilun->block_size;
|
||||
}
|
||||
bdi->cluster_size = iscsilun->cluster_sectors * BDRV_SECTOR_SIZE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -50,6 +50,7 @@ BlockDeviceInfo *bdrv_block_device_info(BlockDriverState *bs)
|
||||
}
|
||||
|
||||
info->backing_file_depth = bdrv_get_backing_file_depth(bs);
|
||||
info->detect_zeroes = bs->detect_zeroes;
|
||||
|
||||
if (bs->io_limits_enabled) {
|
||||
ThrottleConfig cfg;
|
||||
|
44
block/qcow.c
44
block/qcow.c
@@ -48,9 +48,10 @@ typedef struct QCowHeader {
|
||||
uint64_t size; /* in bytes */
|
||||
uint8_t cluster_bits;
|
||||
uint8_t l2_bits;
|
||||
uint16_t padding;
|
||||
uint32_t crypt_method;
|
||||
uint64_t l1_table_offset;
|
||||
} QCowHeader;
|
||||
} QEMU_PACKED QCowHeader;
|
||||
|
||||
#define L2_CACHE_SIZE 16
|
||||
|
||||
@@ -60,7 +61,7 @@ typedef struct BDRVQcowState {
|
||||
int cluster_sectors;
|
||||
int l2_bits;
|
||||
int l2_size;
|
||||
int l1_size;
|
||||
unsigned int l1_size;
|
||||
uint64_t cluster_offset_mask;
|
||||
uint64_t l1_table_offset;
|
||||
uint64_t *l1_table;
|
||||
@@ -96,7 +97,8 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
Error **errp)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int len, i, shift, ret;
|
||||
unsigned int len, i, shift;
|
||||
int ret;
|
||||
QCowHeader header;
|
||||
|
||||
ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
|
||||
@@ -127,11 +129,25 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (header.size <= 1 || header.cluster_bits < 9) {
|
||||
error_setg(errp, "invalid value in qcow header");
|
||||
if (header.size <= 1) {
|
||||
error_setg(errp, "Image size is too small (must be at least 2 bytes)");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
if (header.cluster_bits < 9 || header.cluster_bits > 16) {
|
||||
error_setg(errp, "Cluster size must be between 512 and 64k");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* l2_bits specifies number of entries; storing a uint64_t in each entry,
|
||||
* so bytes = num_entries << 3. */
|
||||
if (header.l2_bits < 9 - 3 || header.l2_bits > 16 - 3) {
|
||||
error_setg(errp, "L2 table size must be between 512 and 64k");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (header.crypt_method > QCOW_CRYPT_AES) {
|
||||
error_setg(errp, "invalid encryption method in qcow header");
|
||||
ret = -EINVAL;
|
||||
@@ -151,7 +167,19 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
|
||||
/* read the level 1 table */
|
||||
shift = s->cluster_bits + s->l2_bits;
|
||||
s->l1_size = (header.size + (1LL << shift) - 1) >> shift;
|
||||
if (header.size > UINT64_MAX - (1LL << shift)) {
|
||||
error_setg(errp, "Image too large");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
} else {
|
||||
uint64_t l1_size = (header.size + (1LL << shift) - 1) >> shift;
|
||||
if (l1_size > INT_MAX / sizeof(uint64_t)) {
|
||||
error_setg(errp, "Image too large");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
s->l1_size = l1_size;
|
||||
}
|
||||
|
||||
s->l1_table_offset = header.l1_table_offset;
|
||||
s->l1_table = g_malloc(s->l1_size * sizeof(uint64_t));
|
||||
@@ -175,7 +203,9 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
if (header.backing_file_offset != 0) {
|
||||
len = header.backing_file_size;
|
||||
if (len > 1023) {
|
||||
len = 1023;
|
||||
error_setg(errp, "Backing file name too long");
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
ret = bdrv_pread(bs->file, header.backing_file_offset,
|
||||
bs->backing_file, len);
|
||||
|
@@ -473,7 +473,14 @@ static void vhdx_parse_header(BlockDriverState *bs, BDRVVHDXState *s,
|
||||
} else if (h2_seq > h1_seq) {
|
||||
s->curr_header = 1;
|
||||
} else {
|
||||
goto fail;
|
||||
/* The Microsoft Disk2VHD tool will create 2 identical
|
||||
* headers, with identical sequence numbers. If the headers are
|
||||
* identical, don't consider the file corrupt */
|
||||
if (!memcmp(header1, header2, sizeof(VHDXHeader))) {
|
||||
s->curr_header = 0;
|
||||
} else {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
43
blockdev.c
43
blockdev.c
@@ -288,6 +288,25 @@ static int parse_block_error_action(const char *buf, bool is_read, Error **errp)
|
||||
}
|
||||
}
|
||||
|
||||
static inline int parse_enum_option(const char *lookup[], const char *buf,
|
||||
int max, int def, Error **errp)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!buf) {
|
||||
return def;
|
||||
}
|
||||
|
||||
for (i = 0; i < max; i++) {
|
||||
if (!strcmp(buf, lookup[i])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
error_setg(errp, "invalid parameter value: %s", buf);
|
||||
return def;
|
||||
}
|
||||
|
||||
static bool check_throttle_config(ThrottleConfig *cfg, Error **errp)
|
||||
{
|
||||
if (throttle_conflicting(cfg)) {
|
||||
@@ -324,6 +343,7 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
|
||||
QemuOpts *opts;
|
||||
const char *id;
|
||||
bool has_driver_specific_opts;
|
||||
BlockdevDetectZeroesOptions detect_zeroes;
|
||||
BlockDriver *drv = NULL;
|
||||
|
||||
/* Check common options by copying from bs_opts to opts, all other options
|
||||
@@ -452,6 +472,24 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
|
||||
}
|
||||
}
|
||||
|
||||
detect_zeroes =
|
||||
parse_enum_option(BlockdevDetectZeroesOptions_lookup,
|
||||
qemu_opt_get(opts, "detect-zeroes"),
|
||||
BLOCKDEV_DETECT_ZEROES_OPTIONS_MAX,
|
||||
BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF,
|
||||
&error);
|
||||
if (error) {
|
||||
error_propagate(errp, error);
|
||||
goto early_err;
|
||||
}
|
||||
|
||||
if (detect_zeroes == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP &&
|
||||
!(bdrv_flags & BDRV_O_UNMAP)) {
|
||||
error_setg(errp, "setting detect-zeroes to unmap is not allowed "
|
||||
"without setting discard operation to unmap");
|
||||
goto early_err;
|
||||
}
|
||||
|
||||
/* init */
|
||||
dinfo = g_malloc0(sizeof(*dinfo));
|
||||
dinfo->id = g_strdup(qemu_opts_id(opts));
|
||||
@@ -462,6 +500,7 @@ static DriveInfo *blockdev_init(const char *file, QDict *bs_opts,
|
||||
}
|
||||
dinfo->bdrv->open_flags = snapshot ? BDRV_O_SNAPSHOT : 0;
|
||||
dinfo->bdrv->read_only = ro;
|
||||
dinfo->bdrv->detect_zeroes = detect_zeroes;
|
||||
dinfo->refcount = 1;
|
||||
if (serial != NULL) {
|
||||
dinfo->serial = g_strdup(serial);
|
||||
@@ -2455,6 +2494,10 @@ QemuOptsList qemu_common_drive_opts = {
|
||||
.name = "copy-on-read",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
.help = "copy read data from backing file into image file",
|
||||
},{
|
||||
.name = "detect-zeroes",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "try to optimize zero writes (off, on, unmap)",
|
||||
},
|
||||
{ /* end of list */ }
|
||||
},
|
||||
|
@@ -1003,8 +1003,6 @@ int main(int argc, char **argv)
|
||||
cpu->opaque = ts;
|
||||
|
||||
#if defined(TARGET_I386)
|
||||
cpu_x86_set_cpl(env, 3);
|
||||
|
||||
env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
|
||||
env->hflags |= HF_PE_MASK;
|
||||
if (env->features[FEAT_1_EDX] & CPUID_SSE) {
|
||||
|
10
configure
vendored
10
configure
vendored
@@ -1137,11 +1137,11 @@ case "$cpu" in
|
||||
CPU_CFLAGS="-m64 -mcpu=ultrasparc"
|
||||
;;
|
||||
s390)
|
||||
CPU_CFLAGS="-m31 -march=z990"
|
||||
CPU_CFLAGS="-m31"
|
||||
LDFLAGS="-m31 $LDFLAGS"
|
||||
;;
|
||||
s390x)
|
||||
CPU_CFLAGS="-m64 -march=z990"
|
||||
CPU_CFLAGS="-m64"
|
||||
LDFLAGS="-m64 $LDFLAGS"
|
||||
;;
|
||||
i386)
|
||||
@@ -4768,12 +4768,6 @@ if test "$gcov" = "yes" ; then
|
||||
echo "GCOV=$gcov_tool" >> $config_host_mak
|
||||
fi
|
||||
|
||||
iotests_common_env="tests/qemu-iotests/common.env"
|
||||
|
||||
echo "# Automatically generated by configure - do not modify" > $iotests_common_env
|
||||
echo >> $iotests_common_env
|
||||
echo "PYTHON='$python'" >> $iotests_common_env
|
||||
|
||||
# use included Linux headers
|
||||
if test "$linux" = "yes" ; then
|
||||
mkdir -p linux-headers
|
||||
|
23
cpu-exec.c
23
cpu-exec.c
@@ -335,6 +335,18 @@ int cpu_exec(CPUArchState *env)
|
||||
cpu_loop_exit(cpu);
|
||||
}
|
||||
#endif
|
||||
#if defined(TARGET_I386)
|
||||
if (interrupt_request & CPU_INTERRUPT_INIT) {
|
||||
cpu_svm_check_intercept_param(env, SVM_EXIT_INIT, 0);
|
||||
do_cpu_init(x86_cpu);
|
||||
cpu->exception_index = EXCP_HALTED;
|
||||
cpu_loop_exit(cpu);
|
||||
}
|
||||
#else
|
||||
if (interrupt_request & CPU_INTERRUPT_RESET) {
|
||||
cpu_reset(cpu);
|
||||
}
|
||||
#endif
|
||||
#if defined(TARGET_I386)
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
if (interrupt_request & CPU_INTERRUPT_POLL) {
|
||||
@@ -342,13 +354,7 @@ int cpu_exec(CPUArchState *env)
|
||||
apic_poll_irq(x86_cpu->apic_state);
|
||||
}
|
||||
#endif
|
||||
if (interrupt_request & CPU_INTERRUPT_INIT) {
|
||||
cpu_svm_check_intercept_param(env, SVM_EXIT_INIT,
|
||||
0);
|
||||
do_cpu_init(x86_cpu);
|
||||
cpu->exception_index = EXCP_HALTED;
|
||||
cpu_loop_exit(cpu);
|
||||
} else if (interrupt_request & CPU_INTERRUPT_SIPI) {
|
||||
if (interrupt_request & CPU_INTERRUPT_SIPI) {
|
||||
do_cpu_sipi(x86_cpu);
|
||||
} else if (env->hflags2 & HF2_GIF_MASK) {
|
||||
if ((interrupt_request & CPU_INTERRUPT_SMI) &&
|
||||
@@ -405,9 +411,6 @@ int cpu_exec(CPUArchState *env)
|
||||
}
|
||||
}
|
||||
#elif defined(TARGET_PPC)
|
||||
if ((interrupt_request & CPU_INTERRUPT_RESET)) {
|
||||
cpu_reset(cpu);
|
||||
}
|
||||
if (interrupt_request & CPU_INTERRUPT_HARD) {
|
||||
ppc_hw_interrupt(env);
|
||||
if (env->pending_interrupts == 0) {
|
||||
|
3
cpus.c
3
cpus.c
@@ -430,8 +430,7 @@ static const VMStateDescription vmstate_timers = {
|
||||
.name = "timer",
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_INT64(cpu_ticks_offset, TimersState),
|
||||
VMSTATE_INT64(dummy, TimersState),
|
||||
VMSTATE_INT64_V(cpu_clock_offset, TimersState, 2),
|
||||
|
@@ -1,3 +1,4 @@
|
||||
CONFIG_VIRTIO=y
|
||||
CONFIG_SCLPCONSOLE=y
|
||||
CONFIG_S390_FLIC=$(CONFIG_KVM)
|
||||
CONFIG_S390_FLIC=y
|
||||
CONFIG_S390_FLIC_KVM=$(CONFIG_KVM)
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -116,6 +116,8 @@ V_(ImmCmpBranch, 23, 5, SignedBits) \
|
||||
V_(ImmLLiteral, 23, 5, SignedBits) \
|
||||
V_(ImmException, 20, 5, Bits) \
|
||||
V_(ImmHint, 11, 5, Bits) \
|
||||
V_(ImmBarrierDomain, 11, 10, Bits) \
|
||||
V_(ImmBarrierType, 9, 8, Bits) \
|
||||
\
|
||||
/* System (MRS, MSR) */ \
|
||||
V_(ImmSystemRegister, 19, 5, Bits) \
|
||||
@@ -181,7 +183,7 @@ enum Condition {
|
||||
inline Condition InvertCondition(Condition cond) {
|
||||
// Conditions al and nv behave identically, as "always true". They can't be
|
||||
// inverted, because there is no "always false" condition.
|
||||
ASSERT((cond != al) && (cond != nv));
|
||||
VIXL_ASSERT((cond != al) && (cond != nv));
|
||||
return static_cast<Condition>(cond ^ 1);
|
||||
}
|
||||
|
||||
@@ -246,6 +248,20 @@ enum SystemHint {
|
||||
SEVL = 5
|
||||
};
|
||||
|
||||
enum BarrierDomain {
|
||||
OuterShareable = 0,
|
||||
NonShareable = 1,
|
||||
InnerShareable = 2,
|
||||
FullSystem = 3
|
||||
};
|
||||
|
||||
enum BarrierType {
|
||||
BarrierOther = 0,
|
||||
BarrierReads = 1,
|
||||
BarrierWrites = 2,
|
||||
BarrierAll = 3
|
||||
};
|
||||
|
||||
// System/special register names.
|
||||
// This information is not encoded as one field but as the concatenation of
|
||||
// multiple fields (Op0<0>, Op1, Crn, Crm, Op2).
|
||||
@@ -274,7 +290,7 @@ enum SystemRegister {
|
||||
//
|
||||
// The enumerations can be used like this:
|
||||
//
|
||||
// ASSERT(instr->Mask(PCRelAddressingFMask) == PCRelAddressingFixed);
|
||||
// VIXL_ASSERT(instr->Mask(PCRelAddressingFMask) == PCRelAddressingFixed);
|
||||
// switch(instr->Mask(PCRelAddressingMask)) {
|
||||
// case ADR: Format("adr 'Xd, 'AddrPCRelByte"); break;
|
||||
// case ADRP: Format("adrp 'Xd, 'AddrPCRelPage"); break;
|
||||
@@ -560,6 +576,15 @@ enum ExceptionOp {
|
||||
DCPS3 = ExceptionFixed | 0x00A00003
|
||||
};
|
||||
|
||||
enum MemBarrierOp {
|
||||
MemBarrierFixed = 0xD503309F,
|
||||
MemBarrierFMask = 0xFFFFF09F,
|
||||
MemBarrierMask = 0xFFFFF0FF,
|
||||
DSB = MemBarrierFixed | 0x00000000,
|
||||
DMB = MemBarrierFixed | 0x00000020,
|
||||
ISB = MemBarrierFixed | 0x00000040
|
||||
};
|
||||
|
||||
// Any load or store.
|
||||
enum LoadStoreAnyOp {
|
||||
LoadStoreAnyFMask = 0x0a000000,
|
||||
@@ -927,17 +952,22 @@ enum FPDataProcessing1SourceOp {
|
||||
FRINTN = FRINTN_s,
|
||||
FRINTP_s = FPDataProcessing1SourceFixed | 0x00048000,
|
||||
FRINTP_d = FPDataProcessing1SourceFixed | FP64 | 0x00048000,
|
||||
FRINTP = FRINTP_s,
|
||||
FRINTM_s = FPDataProcessing1SourceFixed | 0x00050000,
|
||||
FRINTM_d = FPDataProcessing1SourceFixed | FP64 | 0x00050000,
|
||||
FRINTM = FRINTM_s,
|
||||
FRINTZ_s = FPDataProcessing1SourceFixed | 0x00058000,
|
||||
FRINTZ_d = FPDataProcessing1SourceFixed | FP64 | 0x00058000,
|
||||
FRINTZ = FRINTZ_s,
|
||||
FRINTA_s = FPDataProcessing1SourceFixed | 0x00060000,
|
||||
FRINTA_d = FPDataProcessing1SourceFixed | FP64 | 0x00060000,
|
||||
FRINTA = FRINTA_s,
|
||||
FRINTX_s = FPDataProcessing1SourceFixed | 0x00070000,
|
||||
FRINTX_d = FPDataProcessing1SourceFixed | FP64 | 0x00070000,
|
||||
FRINTX = FRINTX_s,
|
||||
FRINTI_s = FPDataProcessing1SourceFixed | 0x00078000,
|
||||
FRINTI_d = FPDataProcessing1SourceFixed | FP64 | 0x00078000
|
||||
FRINTI_d = FPDataProcessing1SourceFixed | FP64 | 0x00078000,
|
||||
FRINTI = FRINTI_s
|
||||
};
|
||||
|
||||
// Floating point data processing 2 source.
|
||||
|
@@ -132,7 +132,7 @@ void Decoder::InsertVisitorBefore(DecoderVisitor* new_visitor,
|
||||
}
|
||||
// We reached the end of the list. The last element must be
|
||||
// registered_visitor.
|
||||
ASSERT(*it == registered_visitor);
|
||||
VIXL_ASSERT(*it == registered_visitor);
|
||||
visitors_.insert(it, new_visitor);
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ void Decoder::InsertVisitorAfter(DecoderVisitor* new_visitor,
|
||||
}
|
||||
// We reached the end of the list. The last element must be
|
||||
// registered_visitor.
|
||||
ASSERT(*it == registered_visitor);
|
||||
VIXL_ASSERT(*it == registered_visitor);
|
||||
visitors_.push_back(new_visitor);
|
||||
}
|
||||
|
||||
@@ -161,16 +161,16 @@ void Decoder::RemoveVisitor(DecoderVisitor* visitor) {
|
||||
|
||||
|
||||
void Decoder::DecodePCRelAddressing(Instruction* instr) {
|
||||
ASSERT(instr->Bits(27, 24) == 0x0);
|
||||
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.
|
||||
ASSERT(instr->Bit(28) == 0x1);
|
||||
VIXL_ASSERT(instr->Bit(28) == 0x1);
|
||||
VisitPCRelAddressing(instr);
|
||||
}
|
||||
|
||||
|
||||
void Decoder::DecodeBranchSystemException(Instruction* instr) {
|
||||
ASSERT((instr->Bits(27, 24) == 0x4) ||
|
||||
VIXL_ASSERT((instr->Bits(27, 24) == 0x4) ||
|
||||
(instr->Bits(27, 24) == 0x5) ||
|
||||
(instr->Bits(27, 24) == 0x6) ||
|
||||
(instr->Bits(27, 24) == 0x7) );
|
||||
@@ -271,7 +271,7 @@ void Decoder::DecodeBranchSystemException(Instruction* instr) {
|
||||
|
||||
|
||||
void Decoder::DecodeLoadStore(Instruction* instr) {
|
||||
ASSERT((instr->Bits(27, 24) == 0x8) ||
|
||||
VIXL_ASSERT((instr->Bits(27, 24) == 0x8) ||
|
||||
(instr->Bits(27, 24) == 0x9) ||
|
||||
(instr->Bits(27, 24) == 0xC) ||
|
||||
(instr->Bits(27, 24) == 0xD) );
|
||||
@@ -390,7 +390,7 @@ void Decoder::DecodeLoadStore(Instruction* instr) {
|
||||
|
||||
|
||||
void Decoder::DecodeLogical(Instruction* instr) {
|
||||
ASSERT(instr->Bits(27, 24) == 0x2);
|
||||
VIXL_ASSERT(instr->Bits(27, 24) == 0x2);
|
||||
|
||||
if (instr->Mask(0x80400000) == 0x00400000) {
|
||||
VisitUnallocated(instr);
|
||||
@@ -409,7 +409,7 @@ void Decoder::DecodeLogical(Instruction* instr) {
|
||||
|
||||
|
||||
void Decoder::DecodeBitfieldExtract(Instruction* instr) {
|
||||
ASSERT(instr->Bits(27, 24) == 0x3);
|
||||
VIXL_ASSERT(instr->Bits(27, 24) == 0x3);
|
||||
|
||||
if ((instr->Mask(0x80400000) == 0x80000000) ||
|
||||
(instr->Mask(0x80400000) == 0x00400000) ||
|
||||
@@ -434,7 +434,7 @@ void Decoder::DecodeBitfieldExtract(Instruction* instr) {
|
||||
|
||||
|
||||
void Decoder::DecodeAddSubImmediate(Instruction* instr) {
|
||||
ASSERT(instr->Bits(27, 24) == 0x1);
|
||||
VIXL_ASSERT(instr->Bits(27, 24) == 0x1);
|
||||
if (instr->Bit(23) == 1) {
|
||||
VisitUnallocated(instr);
|
||||
} else {
|
||||
@@ -444,8 +444,8 @@ void Decoder::DecodeAddSubImmediate(Instruction* instr) {
|
||||
|
||||
|
||||
void Decoder::DecodeDataProcessing(Instruction* instr) {
|
||||
ASSERT((instr->Bits(27, 24) == 0xA) ||
|
||||
(instr->Bits(27, 24) == 0xB) );
|
||||
VIXL_ASSERT((instr->Bits(27, 24) == 0xA) ||
|
||||
(instr->Bits(27, 24) == 0xB));
|
||||
|
||||
if (instr->Bit(24) == 0) {
|
||||
if (instr->Bit(28) == 0) {
|
||||
@@ -559,8 +559,8 @@ void Decoder::DecodeDataProcessing(Instruction* instr) {
|
||||
|
||||
|
||||
void Decoder::DecodeFP(Instruction* instr) {
|
||||
ASSERT((instr->Bits(27, 24) == 0xE) ||
|
||||
(instr->Bits(27, 24) == 0xF) );
|
||||
VIXL_ASSERT((instr->Bits(27, 24) == 0xE) ||
|
||||
(instr->Bits(27, 24) == 0xF));
|
||||
|
||||
if (instr->Bit(28) == 0) {
|
||||
DecodeAdvSIMDDataProcessing(instr);
|
||||
@@ -665,14 +665,14 @@ void Decoder::DecodeFP(Instruction* instr) {
|
||||
VisitFPConditionalSelect(instr);
|
||||
break;
|
||||
}
|
||||
default: UNREACHABLE();
|
||||
default: VIXL_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Bit 30 == 1 has been handled earlier.
|
||||
ASSERT(instr->Bit(30) == 0);
|
||||
VIXL_ASSERT(instr->Bit(30) == 0);
|
||||
if (instr->Mask(0xA0800000) != 0) {
|
||||
VisitUnallocated(instr);
|
||||
} else {
|
||||
@@ -687,21 +687,21 @@ void Decoder::DecodeFP(Instruction* instr) {
|
||||
|
||||
void Decoder::DecodeAdvSIMDLoadStore(Instruction* instr) {
|
||||
// TODO: Implement Advanced SIMD load/store instruction decode.
|
||||
ASSERT(instr->Bits(29, 25) == 0x6);
|
||||
VIXL_ASSERT(instr->Bits(29, 25) == 0x6);
|
||||
VisitUnimplemented(instr);
|
||||
}
|
||||
|
||||
|
||||
void Decoder::DecodeAdvSIMDDataProcessing(Instruction* instr) {
|
||||
// TODO: Implement Advanced SIMD data processing instruction decode.
|
||||
ASSERT(instr->Bits(27, 25) == 0x7);
|
||||
VIXL_ASSERT(instr->Bits(27, 25) == 0x7);
|
||||
VisitUnimplemented(instr);
|
||||
}
|
||||
|
||||
|
||||
#define DEFINE_VISITOR_CALLERS(A) \
|
||||
void Decoder::Visit##A(Instruction *instr) { \
|
||||
ASSERT(instr->Mask(A##FMask) == A##Fixed); \
|
||||
VIXL_ASSERT(instr->Mask(A##FMask) == A##Fixed); \
|
||||
std::list<DecoderVisitor*>::iterator it; \
|
||||
for (it = visitors_.begin(); it != visitors_.end(); it++) { \
|
||||
(*it)->Visit##A(instr); \
|
||||
|
@@ -95,7 +95,7 @@ void Disassembler::VisitAddSubImmediate(Instruction* instr) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: UNREACHABLE();
|
||||
default: VIXL_UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
@@ -142,7 +142,7 @@ void Disassembler::VisitAddSubShifted(Instruction* instr) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: UNREACHABLE();
|
||||
default: VIXL_UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
@@ -180,7 +180,7 @@ void Disassembler::VisitAddSubExtended(Instruction* instr) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: UNREACHABLE();
|
||||
default: VIXL_UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
@@ -215,7 +215,7 @@ void Disassembler::VisitAddSubWithCarry(Instruction* instr) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: UNREACHABLE();
|
||||
default: VIXL_UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
@@ -258,30 +258,30 @@ void Disassembler::VisitLogicalImmediate(Instruction* instr) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: UNREACHABLE();
|
||||
default: VIXL_UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
|
||||
|
||||
bool Disassembler::IsMovzMovnImm(unsigned reg_size, uint64_t value) {
|
||||
ASSERT((reg_size == kXRegSize) ||
|
||||
((reg_size == kWRegSize) && (value <= 0xffffffff)));
|
||||
VIXL_ASSERT((reg_size == kXRegSize) ||
|
||||
((reg_size == kWRegSize) && (value <= 0xffffffff)));
|
||||
|
||||
// Test for movz: 16 bits set at positions 0, 16, 32 or 48.
|
||||
if (((value & 0xffffffffffff0000ULL) == 0ULL) ||
|
||||
((value & 0xffffffff0000ffffULL) == 0ULL) ||
|
||||
((value & 0xffff0000ffffffffULL) == 0ULL) ||
|
||||
((value & 0x0000ffffffffffffULL) == 0ULL)) {
|
||||
if (((value & UINT64_C(0xffffffffffff0000)) == 0) ||
|
||||
((value & UINT64_C(0xffffffff0000ffff)) == 0) ||
|
||||
((value & UINT64_C(0xffff0000ffffffff)) == 0) ||
|
||||
((value & UINT64_C(0x0000ffffffffffff)) == 0)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Test for movn: NOT(16 bits set at positions 0, 16, 32 or 48).
|
||||
if ((reg_size == kXRegSize) &&
|
||||
(((value & 0xffffffffffff0000ULL) == 0xffffffffffff0000ULL) ||
|
||||
((value & 0xffffffff0000ffffULL) == 0xffffffff0000ffffULL) ||
|
||||
((value & 0xffff0000ffffffffULL) == 0xffff0000ffffffffULL) ||
|
||||
((value & 0x0000ffffffffffffULL) == 0x0000ffffffffffffULL))) {
|
||||
(((~value & UINT64_C(0xffffffffffff0000)) == 0) ||
|
||||
((~value & UINT64_C(0xffffffff0000ffff)) == 0) ||
|
||||
((~value & UINT64_C(0xffff0000ffffffff)) == 0) ||
|
||||
((~value & UINT64_C(0x0000ffffffffffff)) == 0))) {
|
||||
return true;
|
||||
}
|
||||
if ((reg_size == kWRegSize) &&
|
||||
@@ -337,7 +337,7 @@ void Disassembler::VisitLogicalShifted(Instruction* instr) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: UNREACHABLE();
|
||||
default: VIXL_UNREACHABLE();
|
||||
}
|
||||
|
||||
Format(instr, mnemonic, form);
|
||||
@@ -353,7 +353,7 @@ void Disassembler::VisitConditionalCompareRegister(Instruction* instr) {
|
||||
case CCMN_x: mnemonic = "ccmn"; break;
|
||||
case CCMP_w:
|
||||
case CCMP_x: mnemonic = "ccmp"; break;
|
||||
default: UNREACHABLE();
|
||||
default: VIXL_UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
@@ -368,7 +368,7 @@ void Disassembler::VisitConditionalCompareImmediate(Instruction* instr) {
|
||||
case CCMN_x_imm: mnemonic = "ccmn"; break;
|
||||
case CCMP_w_imm:
|
||||
case CCMP_x_imm: mnemonic = "ccmp"; break;
|
||||
default: UNREACHABLE();
|
||||
default: VIXL_UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
@@ -421,7 +421,7 @@ void Disassembler::VisitConditionalSelect(Instruction* instr) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: UNREACHABLE();
|
||||
default: VIXL_UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
@@ -520,7 +520,7 @@ void Disassembler::VisitExtract(Instruction* instr) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: UNREACHABLE();
|
||||
default: VIXL_UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
@@ -538,7 +538,7 @@ void Disassembler::VisitPCRelAddressing(Instruction* instr) {
|
||||
void Disassembler::VisitConditionalBranch(Instruction* instr) {
|
||||
switch (instr->Mask(ConditionalBranchMask)) {
|
||||
case B_cond: Format(instr, "b.'CBrn", "'BImmCond"); break;
|
||||
default: UNREACHABLE();
|
||||
default: VIXL_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -570,7 +570,7 @@ void Disassembler::VisitUnconditionalBranch(Instruction* instr) {
|
||||
switch (instr->Mask(UnconditionalBranchMask)) {
|
||||
case B: mnemonic = "b"; break;
|
||||
case BL: mnemonic = "bl"; break;
|
||||
default: UNREACHABLE();
|
||||
default: VIXL_UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
@@ -591,7 +591,7 @@ void Disassembler::VisitDataProcessing1Source(Instruction* instr) {
|
||||
FORMAT(CLS, "cls");
|
||||
#undef FORMAT
|
||||
case REV32_x: mnemonic = "rev32"; break;
|
||||
default: UNREACHABLE();
|
||||
default: VIXL_UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
@@ -690,7 +690,7 @@ void Disassembler::VisitDataProcessing3Source(Instruction* instr) {
|
||||
form = form_xxx;
|
||||
break;
|
||||
}
|
||||
default: UNREACHABLE();
|
||||
default: VIXL_UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
@@ -705,7 +705,7 @@ void Disassembler::VisitCompareBranch(Instruction* instr) {
|
||||
case CBZ_x: mnemonic = "cbz"; break;
|
||||
case CBNZ_w:
|
||||
case CBNZ_x: mnemonic = "cbnz"; break;
|
||||
default: UNREACHABLE();
|
||||
default: VIXL_UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
@@ -722,7 +722,7 @@ void Disassembler::VisitTestBranch(Instruction* instr) {
|
||||
switch (instr->Mask(TestBranchMask)) {
|
||||
case TBZ: mnemonic = "tbz"; break;
|
||||
case TBNZ: mnemonic = "tbnz"; break;
|
||||
default: UNREACHABLE();
|
||||
default: VIXL_UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
@@ -742,7 +742,7 @@ void Disassembler::VisitMoveWideImmediate(Instruction* instr) {
|
||||
case MOVZ_x: mnemonic = "movz"; break;
|
||||
case MOVK_w:
|
||||
case MOVK_x: mnemonic = "movk"; form = "'Rd, 'IMoveLSL"; break;
|
||||
default: UNREACHABLE();
|
||||
default: VIXL_UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
@@ -981,7 +981,7 @@ void Disassembler::VisitFPConditionalSelect(Instruction* instr) {
|
||||
switch (instr->Mask(FPConditionalSelectMask)) {
|
||||
case FCSEL_s:
|
||||
case FCSEL_d: mnemonic = "fcsel"; break;
|
||||
default: UNREACHABLE();
|
||||
default: VIXL_UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
@@ -1033,7 +1033,7 @@ void Disassembler::VisitFPDataProcessing2Source(Instruction* instr) {
|
||||
FORMAT(FMINNM, "fminnm");
|
||||
FORMAT(FNMUL, "fnmul");
|
||||
#undef FORMAT
|
||||
default: UNREACHABLE();
|
||||
default: VIXL_UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
@@ -1052,7 +1052,7 @@ void Disassembler::VisitFPDataProcessing3Source(Instruction* instr) {
|
||||
FORMAT(FNMADD, "fnmadd");
|
||||
FORMAT(FNMSUB, "fnmsub");
|
||||
#undef FORMAT
|
||||
default: UNREACHABLE();
|
||||
default: VIXL_UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
@@ -1065,7 +1065,7 @@ void Disassembler::VisitFPImmediate(Instruction* instr) {
|
||||
switch (instr->Mask(FPImmediateMask)) {
|
||||
case FMOV_s_imm: mnemonic = "fmov"; form = "'Sd, 'IFPSingle"; break;
|
||||
case FMOV_d_imm: mnemonic = "fmov"; form = "'Dd, 'IFPDouble"; break;
|
||||
default: UNREACHABLE();
|
||||
default: VIXL_UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
@@ -1082,6 +1082,14 @@ void Disassembler::VisitFPIntegerConvert(Instruction* instr) {
|
||||
case FMOV_xd: mnemonic = "fmov"; form = form_rf; break;
|
||||
case FMOV_sw:
|
||||
case FMOV_dx: mnemonic = "fmov"; form = form_fr; break;
|
||||
case FCVTAS_ws:
|
||||
case FCVTAS_xs:
|
||||
case FCVTAS_wd:
|
||||
case FCVTAS_xd: mnemonic = "fcvtas"; form = form_rf; break;
|
||||
case FCVTAU_ws:
|
||||
case FCVTAU_xs:
|
||||
case FCVTAU_wd:
|
||||
case FCVTAU_xd: mnemonic = "fcvtau"; form = form_rf; break;
|
||||
case FCVTMS_ws:
|
||||
case FCVTMS_xs:
|
||||
case FCVTMS_wd:
|
||||
@@ -1141,7 +1149,7 @@ void Disassembler::VisitFPFixedPointConvert(Instruction* instr) {
|
||||
case UCVTF_sx_fixed:
|
||||
case UCVTF_dw_fixed:
|
||||
case UCVTF_dx_fixed: mnemonic = "ucvtf"; form = form_fr; break;
|
||||
default: UNREACHABLE();
|
||||
default: VIXL_UNREACHABLE();
|
||||
}
|
||||
Format(instr, mnemonic, form);
|
||||
}
|
||||
@@ -1176,7 +1184,7 @@ void Disassembler::VisitSystem(Instruction* instr) {
|
||||
}
|
||||
}
|
||||
} else if (instr->Mask(SystemHintFMask) == SystemHintFixed) {
|
||||
ASSERT(instr->Mask(SystemHintMask) == HINT);
|
||||
VIXL_ASSERT(instr->Mask(SystemHintMask) == HINT);
|
||||
switch (instr->ImmHint()) {
|
||||
case NOP: {
|
||||
mnemonic = "nop";
|
||||
@@ -1184,6 +1192,24 @@ void Disassembler::VisitSystem(Instruction* instr) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (instr->Mask(MemBarrierFMask) == MemBarrierFixed) {
|
||||
switch (instr->Mask(MemBarrierMask)) {
|
||||
case DMB: {
|
||||
mnemonic = "dmb";
|
||||
form = "'M";
|
||||
break;
|
||||
}
|
||||
case DSB: {
|
||||
mnemonic = "dsb";
|
||||
form = "'M";
|
||||
break;
|
||||
}
|
||||
case ISB: {
|
||||
mnemonic = "isb";
|
||||
form = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Format(instr, mnemonic, form);
|
||||
@@ -1226,7 +1252,7 @@ void Disassembler::ProcessOutput(Instruction* /*instr*/) {
|
||||
|
||||
void Disassembler::Format(Instruction* instr, const char* mnemonic,
|
||||
const char* format) {
|
||||
ASSERT(mnemonic != NULL);
|
||||
VIXL_ASSERT(mnemonic != NULL);
|
||||
ResetOutput();
|
||||
Substitute(instr, mnemonic);
|
||||
if (format != NULL) {
|
||||
@@ -1268,8 +1294,9 @@ int Disassembler::SubstituteField(Instruction* instr, const char* format) {
|
||||
case 'A': return SubstitutePCRelAddressField(instr, format);
|
||||
case 'B': return SubstituteBranchTargetField(instr, format);
|
||||
case 'O': return SubstituteLSRegOffsetField(instr, format);
|
||||
case 'M': return SubstituteBarrierField(instr, format);
|
||||
default: {
|
||||
UNREACHABLE();
|
||||
VIXL_UNREACHABLE();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -1294,7 +1321,7 @@ int Disassembler::SubstituteRegisterField(Instruction* instr,
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: UNREACHABLE();
|
||||
default: VIXL_UNREACHABLE();
|
||||
}
|
||||
|
||||
// Increase field length for registers tagged as stack.
|
||||
@@ -1331,7 +1358,7 @@ int Disassembler::SubstituteRegisterField(Instruction* instr,
|
||||
|
||||
int Disassembler::SubstituteImmediateField(Instruction* instr,
|
||||
const char* format) {
|
||||
ASSERT(format[0] == 'I');
|
||||
VIXL_ASSERT(format[0] == 'I');
|
||||
|
||||
switch (format[1]) {
|
||||
case 'M': { // IMoveImm or IMoveLSL.
|
||||
@@ -1339,10 +1366,10 @@ int Disassembler::SubstituteImmediateField(Instruction* instr,
|
||||
uint64_t imm = instr->ImmMoveWide() << (16 * instr->ShiftMoveWide());
|
||||
AppendToOutput("#0x%" PRIx64, imm);
|
||||
} else {
|
||||
ASSERT(format[5] == 'L');
|
||||
VIXL_ASSERT(format[5] == 'L');
|
||||
AppendToOutput("#0x%" PRIx64, instr->ImmMoveWide());
|
||||
if (instr->ShiftMoveWide() > 0) {
|
||||
AppendToOutput(", lsl #%" PRId64, 16 * instr->ShiftMoveWide());
|
||||
AppendToOutput(", lsl #%d", 16 * instr->ShiftMoveWide());
|
||||
}
|
||||
}
|
||||
return 8;
|
||||
@@ -1384,14 +1411,14 @@ int Disassembler::SubstituteImmediateField(Instruction* instr,
|
||||
return 6;
|
||||
}
|
||||
case 'A': { // IAddSub.
|
||||
ASSERT(instr->ShiftAddSub() <= 1);
|
||||
VIXL_ASSERT(instr->ShiftAddSub() <= 1);
|
||||
int64_t imm = instr->ImmAddSub() << (12 * instr->ShiftAddSub());
|
||||
AppendToOutput("#0x%" PRIx64 " (%" PRId64 ")", imm, imm);
|
||||
return 7;
|
||||
}
|
||||
case 'F': { // IFPSingle, IFPDouble or IFPFBits.
|
||||
if (format[3] == 'F') { // IFPFbits.
|
||||
AppendToOutput("#%" PRId64, 64 - instr->FPScale());
|
||||
AppendToOutput("#%d", 64 - instr->FPScale());
|
||||
return 8;
|
||||
} else {
|
||||
AppendToOutput("#0x%" PRIx64 " (%.4f)", instr->ImmFP(),
|
||||
@@ -1412,27 +1439,27 @@ int Disassembler::SubstituteImmediateField(Instruction* instr,
|
||||
return 5;
|
||||
}
|
||||
case 'P': { // IP - Conditional compare.
|
||||
AppendToOutput("#%" PRId64, instr->ImmCondCmp());
|
||||
AppendToOutput("#%d", instr->ImmCondCmp());
|
||||
return 2;
|
||||
}
|
||||
case 'B': { // Bitfields.
|
||||
return SubstituteBitfieldImmediateField(instr, format);
|
||||
}
|
||||
case 'E': { // IExtract.
|
||||
AppendToOutput("#%" PRId64, instr->ImmS());
|
||||
AppendToOutput("#%d", instr->ImmS());
|
||||
return 8;
|
||||
}
|
||||
case 'S': { // IS - Test and branch bit.
|
||||
AppendToOutput("#%" PRId64, (instr->ImmTestBranchBit5() << 5) |
|
||||
instr->ImmTestBranchBit40());
|
||||
AppendToOutput("#%d", (instr->ImmTestBranchBit5() << 5) |
|
||||
instr->ImmTestBranchBit40());
|
||||
return 2;
|
||||
}
|
||||
case 'D': { // IDebug - HLT and BRK instructions.
|
||||
AppendToOutput("#0x%" PRIx64, instr->ImmException());
|
||||
AppendToOutput("#0x%x", instr->ImmException());
|
||||
return 6;
|
||||
}
|
||||
default: {
|
||||
UNIMPLEMENTED();
|
||||
VIXL_UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1441,7 +1468,7 @@ int Disassembler::SubstituteImmediateField(Instruction* instr,
|
||||
|
||||
int Disassembler::SubstituteBitfieldImmediateField(Instruction* instr,
|
||||
const char* format) {
|
||||
ASSERT((format[0] == 'I') && (format[1] == 'B'));
|
||||
VIXL_ASSERT((format[0] == 'I') && (format[1] == 'B'));
|
||||
unsigned r = instr->ImmR();
|
||||
unsigned s = instr->ImmS();
|
||||
|
||||
@@ -1455,19 +1482,19 @@ int Disassembler::SubstituteBitfieldImmediateField(Instruction* instr,
|
||||
AppendToOutput("#%d", s + 1);
|
||||
return 5;
|
||||
} else {
|
||||
ASSERT(format[3] == '-');
|
||||
VIXL_ASSERT(format[3] == '-');
|
||||
AppendToOutput("#%d", s - r + 1);
|
||||
return 7;
|
||||
}
|
||||
}
|
||||
case 'Z': { // IBZ-r.
|
||||
ASSERT((format[3] == '-') && (format[4] == 'r'));
|
||||
VIXL_ASSERT((format[3] == '-') && (format[4] == 'r'));
|
||||
unsigned reg_size = (instr->SixtyFourBits() == 1) ? kXRegSize : kWRegSize;
|
||||
AppendToOutput("#%d", reg_size - r);
|
||||
return 5;
|
||||
}
|
||||
default: {
|
||||
UNREACHABLE();
|
||||
VIXL_UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1476,7 +1503,7 @@ int Disassembler::SubstituteBitfieldImmediateField(Instruction* instr,
|
||||
|
||||
int Disassembler::SubstituteLiteralField(Instruction* instr,
|
||||
const char* format) {
|
||||
ASSERT(strncmp(format, "LValue", 6) == 0);
|
||||
VIXL_ASSERT(strncmp(format, "LValue", 6) == 0);
|
||||
USE(format);
|
||||
|
||||
switch (instr->Mask(LoadLiteralMask)) {
|
||||
@@ -1484,7 +1511,7 @@ int Disassembler::SubstituteLiteralField(Instruction* instr,
|
||||
case LDR_x_lit:
|
||||
case LDR_s_lit:
|
||||
case LDR_d_lit: AppendToOutput("(addr %p)", instr->LiteralAddress()); break;
|
||||
default: UNREACHABLE();
|
||||
default: VIXL_UNREACHABLE();
|
||||
}
|
||||
|
||||
return 6;
|
||||
@@ -1492,12 +1519,12 @@ int Disassembler::SubstituteLiteralField(Instruction* instr,
|
||||
|
||||
|
||||
int Disassembler::SubstituteShiftField(Instruction* instr, const char* format) {
|
||||
ASSERT(format[0] == 'H');
|
||||
ASSERT(instr->ShiftDP() <= 0x3);
|
||||
VIXL_ASSERT(format[0] == 'H');
|
||||
VIXL_ASSERT(instr->ShiftDP() <= 0x3);
|
||||
|
||||
switch (format[1]) {
|
||||
case 'D': { // HDP.
|
||||
ASSERT(instr->ShiftDP() != ROR);
|
||||
VIXL_ASSERT(instr->ShiftDP() != ROR);
|
||||
} // Fall through.
|
||||
case 'L': { // HLo.
|
||||
if (instr->ImmDPShift() != 0) {
|
||||
@@ -1508,7 +1535,7 @@ int Disassembler::SubstituteShiftField(Instruction* instr, const char* format) {
|
||||
return 3;
|
||||
}
|
||||
default:
|
||||
UNIMPLEMENTED();
|
||||
VIXL_UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1516,7 +1543,7 @@ int Disassembler::SubstituteShiftField(Instruction* instr, const char* format) {
|
||||
|
||||
int Disassembler::SubstituteConditionField(Instruction* instr,
|
||||
const char* format) {
|
||||
ASSERT(format[0] == 'C');
|
||||
VIXL_ASSERT(format[0] == 'C');
|
||||
const char* condition_code[] = { "eq", "ne", "hs", "lo",
|
||||
"mi", "pl", "vs", "vc",
|
||||
"hi", "ls", "ge", "lt",
|
||||
@@ -1538,27 +1565,27 @@ int Disassembler::SubstituteConditionField(Instruction* instr,
|
||||
int Disassembler::SubstitutePCRelAddressField(Instruction* instr,
|
||||
const char* format) {
|
||||
USE(format);
|
||||
ASSERT(strncmp(format, "AddrPCRel", 9) == 0);
|
||||
VIXL_ASSERT(strncmp(format, "AddrPCRel", 9) == 0);
|
||||
|
||||
int offset = instr->ImmPCRel();
|
||||
|
||||
// Only ADR (AddrPCRelByte) is supported.
|
||||
ASSERT(strcmp(format, "AddrPCRelByte") == 0);
|
||||
VIXL_ASSERT(strcmp(format, "AddrPCRelByte") == 0);
|
||||
|
||||
char sign = '+';
|
||||
if (offset < 0) {
|
||||
offset = -offset;
|
||||
sign = '-';
|
||||
}
|
||||
// TODO: Extend this to support printing the target address.
|
||||
AppendToOutput("#%c0x%x", sign, offset);
|
||||
VIXL_STATIC_ASSERT(sizeof(*instr) == 1);
|
||||
AppendToOutput("#%c0x%x (addr %p)", sign, offset, instr + offset);
|
||||
return 13;
|
||||
}
|
||||
|
||||
|
||||
int Disassembler::SubstituteBranchTargetField(Instruction* instr,
|
||||
const char* format) {
|
||||
ASSERT(strncmp(format, "BImm", 4) == 0);
|
||||
VIXL_ASSERT(strncmp(format, "BImm", 4) == 0);
|
||||
|
||||
int64_t offset = 0;
|
||||
switch (format[5]) {
|
||||
@@ -1570,7 +1597,7 @@ int Disassembler::SubstituteBranchTargetField(Instruction* instr,
|
||||
case 'm': offset = instr->ImmCmpBranch(); break;
|
||||
// BImmTest - test and branch immediate.
|
||||
case 'e': offset = instr->ImmTestBranch(); break;
|
||||
default: UNIMPLEMENTED();
|
||||
default: VIXL_UNIMPLEMENTED();
|
||||
}
|
||||
offset <<= kInstructionSizeLog2;
|
||||
char sign = '+';
|
||||
@@ -1578,15 +1605,16 @@ int Disassembler::SubstituteBranchTargetField(Instruction* instr,
|
||||
offset = -offset;
|
||||
sign = '-';
|
||||
}
|
||||
AppendToOutput("#%c0x%" PRIx64, sign, offset);
|
||||
VIXL_STATIC_ASSERT(sizeof(*instr) == 1);
|
||||
AppendToOutput("#%c0x%" PRIx64 " (addr %p)", sign, offset, instr + offset);
|
||||
return 8;
|
||||
}
|
||||
|
||||
|
||||
int Disassembler::SubstituteExtendField(Instruction* instr,
|
||||
const char* format) {
|
||||
ASSERT(strncmp(format, "Ext", 3) == 0);
|
||||
ASSERT(instr->ExtendMode() <= 7);
|
||||
VIXL_ASSERT(strncmp(format, "Ext", 3) == 0);
|
||||
VIXL_ASSERT(instr->ExtendMode() <= 7);
|
||||
USE(format);
|
||||
|
||||
const char* extend_mode[] = { "uxtb", "uxth", "uxtw", "uxtx",
|
||||
@@ -1598,12 +1626,12 @@ int Disassembler::SubstituteExtendField(Instruction* instr,
|
||||
(((instr->ExtendMode() == UXTW) && (instr->SixtyFourBits() == 0)) ||
|
||||
(instr->ExtendMode() == UXTX))) {
|
||||
if (instr->ImmExtendShift() > 0) {
|
||||
AppendToOutput(", lsl #%" PRId64, instr->ImmExtendShift());
|
||||
AppendToOutput(", lsl #%d", instr->ImmExtendShift());
|
||||
}
|
||||
} else {
|
||||
AppendToOutput(", %s", extend_mode[instr->ExtendMode()]);
|
||||
if (instr->ImmExtendShift() > 0) {
|
||||
AppendToOutput(" #%" PRId64, instr->ImmExtendShift());
|
||||
AppendToOutput(" #%d", instr->ImmExtendShift());
|
||||
}
|
||||
}
|
||||
return 3;
|
||||
@@ -1612,7 +1640,7 @@ int Disassembler::SubstituteExtendField(Instruction* instr,
|
||||
|
||||
int Disassembler::SubstituteLSRegOffsetField(Instruction* instr,
|
||||
const char* format) {
|
||||
ASSERT(strncmp(format, "Offsetreg", 9) == 0);
|
||||
VIXL_ASSERT(strncmp(format, "Offsetreg", 9) == 0);
|
||||
const char* extend_mode[] = { "undefined", "undefined", "uxtw", "lsl",
|
||||
"undefined", "undefined", "sxtw", "sxtx" };
|
||||
USE(format);
|
||||
@@ -1632,7 +1660,7 @@ int Disassembler::SubstituteLSRegOffsetField(Instruction* instr,
|
||||
if (!((ext == UXTX) && (shift == 0))) {
|
||||
AppendToOutput(", %s", extend_mode[ext]);
|
||||
if (shift != 0) {
|
||||
AppendToOutput(" #%" PRId64, instr->SizeLS());
|
||||
AppendToOutput(" #%d", instr->SizeLS());
|
||||
}
|
||||
}
|
||||
return 9;
|
||||
@@ -1641,7 +1669,7 @@ int Disassembler::SubstituteLSRegOffsetField(Instruction* instr,
|
||||
|
||||
int Disassembler::SubstitutePrefetchField(Instruction* instr,
|
||||
const char* format) {
|
||||
ASSERT(format[0] == 'P');
|
||||
VIXL_ASSERT(format[0] == 'P');
|
||||
USE(format);
|
||||
|
||||
int prefetch_mode = instr->PrefetchMode();
|
||||
@@ -1654,6 +1682,23 @@ int Disassembler::SubstitutePrefetchField(Instruction* instr,
|
||||
return 6;
|
||||
}
|
||||
|
||||
int Disassembler::SubstituteBarrierField(Instruction* instr,
|
||||
const char* format) {
|
||||
VIXL_ASSERT(format[0] == 'M');
|
||||
USE(format);
|
||||
|
||||
static const char* options[4][4] = {
|
||||
{ "sy (0b0000)", "oshld", "oshst", "osh" },
|
||||
{ "sy (0b0100)", "nshld", "nshst", "nsh" },
|
||||
{ "sy (0b1000)", "ishld", "ishst", "ish" },
|
||||
{ "sy (0b1100)", "ld", "st", "sy" }
|
||||
};
|
||||
int domain = instr->ImmBarrierDomain();
|
||||
int type = instr->ImmBarrierType();
|
||||
|
||||
AppendToOutput("%s", options[domain][type]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Disassembler::ResetOutput() {
|
||||
buffer_pos_ = 0;
|
||||
|
@@ -64,6 +64,7 @@ class Disassembler: public DecoderVisitor {
|
||||
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);
|
||||
|
||||
inline bool RdIsZROrSP(Instruction* instr) const {
|
||||
return (instr->Rd() == kZeroRegCode);
|
||||
|
@@ -33,20 +33,20 @@ namespace vixl {
|
||||
static uint64_t RotateRight(uint64_t value,
|
||||
unsigned int rotate,
|
||||
unsigned int width) {
|
||||
ASSERT(width <= 64);
|
||||
VIXL_ASSERT(width <= 64);
|
||||
rotate &= 63;
|
||||
return ((value & ((1UL << rotate) - 1UL)) << (width - rotate)) |
|
||||
(value >> rotate);
|
||||
return ((value & ((UINT64_C(1) << rotate) - 1)) <<
|
||||
(width - rotate)) | (value >> rotate);
|
||||
}
|
||||
|
||||
|
||||
static uint64_t RepeatBitsAcrossReg(unsigned reg_size,
|
||||
uint64_t value,
|
||||
unsigned width) {
|
||||
ASSERT((width == 2) || (width == 4) || (width == 8) || (width == 16) ||
|
||||
(width == 32));
|
||||
ASSERT((reg_size == kWRegSize) || (reg_size == kXRegSize));
|
||||
uint64_t result = value & ((1UL << width) - 1UL);
|
||||
VIXL_ASSERT((width == 2) || (width == 4) || (width == 8) || (width == 16) ||
|
||||
(width == 32));
|
||||
VIXL_ASSERT((reg_size == kWRegSize) || (reg_size == kXRegSize));
|
||||
uint64_t result = value & ((UINT64_C(1) << width) - 1);
|
||||
for (unsigned i = width; i < reg_size; i *= 2) {
|
||||
result |= (result << i);
|
||||
}
|
||||
@@ -84,7 +84,7 @@ uint64_t Instruction::ImmLogical() {
|
||||
if (imm_s == 0x3F) {
|
||||
return 0;
|
||||
}
|
||||
uint64_t bits = (1UL << (imm_s + 1)) - 1;
|
||||
uint64_t bits = (UINT64_C(1) << (imm_s + 1)) - 1;
|
||||
return RotateRight(bits, imm_r, 64);
|
||||
} else {
|
||||
if ((imm_s >> 1) == 0x1F) {
|
||||
@@ -96,14 +96,14 @@ uint64_t Instruction::ImmLogical() {
|
||||
if ((imm_s & mask) == mask) {
|
||||
return 0;
|
||||
}
|
||||
uint64_t bits = (1UL << ((imm_s & mask) + 1)) - 1;
|
||||
uint64_t bits = (UINT64_C(1) << ((imm_s & mask) + 1)) - 1;
|
||||
return RepeatBitsAcrossReg(reg_size,
|
||||
RotateRight(bits, imm_r & mask, width),
|
||||
width);
|
||||
}
|
||||
}
|
||||
}
|
||||
UNREACHABLE();
|
||||
VIXL_UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -155,7 +155,7 @@ Instruction* Instruction::ImmPCOffsetTarget() {
|
||||
offset = ImmPCRel();
|
||||
} else {
|
||||
// All PC-relative branches.
|
||||
ASSERT(BranchType() != UnknownBranchType);
|
||||
VIXL_ASSERT(BranchType() != UnknownBranchType);
|
||||
// Relative branch offsets are instruction-size-aligned.
|
||||
offset = ImmBranch() << kInstructionSizeLog2;
|
||||
}
|
||||
@@ -169,7 +169,7 @@ inline int Instruction::ImmBranch() const {
|
||||
case UncondBranchType: return ImmUncondBranch();
|
||||
case CompareBranchType: return ImmCmpBranch();
|
||||
case TestBranchType: return ImmTestBranch();
|
||||
default: UNREACHABLE();
|
||||
default: VIXL_UNREACHABLE();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -186,7 +186,7 @@ void Instruction::SetImmPCOffsetTarget(Instruction* target) {
|
||||
|
||||
void Instruction::SetPCRelImmTarget(Instruction* target) {
|
||||
// ADRP is not supported, so 'this' must point to an ADR instruction.
|
||||
ASSERT(Mask(PCRelAddressingMask) == ADR);
|
||||
VIXL_ASSERT(Mask(PCRelAddressingMask) == ADR);
|
||||
|
||||
Instr imm = Assembler::ImmPCRelAddress(target - this);
|
||||
|
||||
@@ -195,7 +195,7 @@ void Instruction::SetPCRelImmTarget(Instruction* target) {
|
||||
|
||||
|
||||
void Instruction::SetBranchImmTarget(Instruction* target) {
|
||||
ASSERT(((target - this) & 3) == 0);
|
||||
VIXL_ASSERT(((target - this) & 3) == 0);
|
||||
Instr branch_imm = 0;
|
||||
uint32_t imm_mask = 0;
|
||||
int offset = (target - this) >> kInstructionSizeLog2;
|
||||
@@ -220,14 +220,14 @@ void Instruction::SetBranchImmTarget(Instruction* target) {
|
||||
imm_mask = ImmTestBranch_mask;
|
||||
break;
|
||||
}
|
||||
default: UNREACHABLE();
|
||||
default: VIXL_UNREACHABLE();
|
||||
}
|
||||
SetInstructionBits(Mask(~imm_mask) | branch_imm);
|
||||
}
|
||||
|
||||
|
||||
void Instruction::SetImmLLiteral(Instruction* source) {
|
||||
ASSERT(((source - this) & 3) == 0);
|
||||
VIXL_ASSERT(((source - this) & 3) == 0);
|
||||
int offset = (source - this) >> kLiteralEntrySizeLog2;
|
||||
Instr imm = Assembler::ImmLLiteral(offset);
|
||||
Instr mask = ImmLLiteral_mask;
|
||||
|
@@ -44,30 +44,36 @@ const unsigned kMaxLoadLiteralRange = 1 * MBytes;
|
||||
const unsigned kWRegSize = 32;
|
||||
const unsigned kWRegSizeLog2 = 5;
|
||||
const unsigned kWRegSizeInBytes = kWRegSize / 8;
|
||||
const unsigned kWRegSizeInBytesLog2 = kWRegSizeLog2 - 3;
|
||||
const unsigned kXRegSize = 64;
|
||||
const unsigned kXRegSizeLog2 = 6;
|
||||
const unsigned kXRegSizeInBytes = kXRegSize / 8;
|
||||
const unsigned kXRegSizeInBytesLog2 = kXRegSizeLog2 - 3;
|
||||
const unsigned kSRegSize = 32;
|
||||
const unsigned kSRegSizeLog2 = 5;
|
||||
const unsigned kSRegSizeInBytes = kSRegSize / 8;
|
||||
const unsigned kSRegSizeInBytesLog2 = kSRegSizeLog2 - 3;
|
||||
const unsigned kDRegSize = 64;
|
||||
const unsigned kDRegSizeLog2 = 6;
|
||||
const unsigned kDRegSizeInBytes = kDRegSize / 8;
|
||||
const int64_t kWRegMask = 0x00000000ffffffffLL;
|
||||
const int64_t kXRegMask = 0xffffffffffffffffLL;
|
||||
const int64_t kSRegMask = 0x00000000ffffffffLL;
|
||||
const int64_t kDRegMask = 0xffffffffffffffffLL;
|
||||
const int64_t kXSignMask = 0x1LL << 63;
|
||||
const int64_t kWSignMask = 0x1LL << 31;
|
||||
const int64_t kByteMask = 0xffL;
|
||||
const int64_t kHalfWordMask = 0xffffL;
|
||||
const int64_t kWordMask = 0xffffffffLL;
|
||||
const uint64_t kXMaxUInt = 0xffffffffffffffffULL;
|
||||
const uint64_t kWMaxUInt = 0xffffffffULL;
|
||||
const int64_t kXMaxInt = 0x7fffffffffffffffLL;
|
||||
const int64_t kXMinInt = 0x8000000000000000LL;
|
||||
const int32_t kWMaxInt = 0x7fffffff;
|
||||
const int32_t kWMinInt = 0x80000000;
|
||||
const unsigned kDRegSizeInBytesLog2 = kDRegSizeLog2 - 3;
|
||||
const uint64_t kWRegMask = UINT64_C(0xffffffff);
|
||||
const uint64_t kXRegMask = UINT64_C(0xffffffffffffffff);
|
||||
const uint64_t kSRegMask = UINT64_C(0xffffffff);
|
||||
const uint64_t kDRegMask = UINT64_C(0xffffffffffffffff);
|
||||
const uint64_t kSSignMask = UINT64_C(0x80000000);
|
||||
const uint64_t kDSignMask = UINT64_C(0x8000000000000000);
|
||||
const uint64_t kWSignMask = UINT64_C(0x80000000);
|
||||
const uint64_t kXSignMask = UINT64_C(0x8000000000000000);
|
||||
const uint64_t kByteMask = UINT64_C(0xff);
|
||||
const uint64_t kHalfWordMask = UINT64_C(0xffff);
|
||||
const uint64_t kWordMask = UINT64_C(0xffffffff);
|
||||
const uint64_t kXMaxUInt = UINT64_C(0xffffffffffffffff);
|
||||
const uint64_t kWMaxUInt = UINT64_C(0xffffffff);
|
||||
const int64_t kXMaxInt = INT64_C(0x7fffffffffffffff);
|
||||
const int64_t kXMinInt = INT64_C(0x8000000000000000);
|
||||
const int32_t kWMaxInt = INT32_C(0x7fffffff);
|
||||
const int32_t kWMinInt = INT32_C(0x80000000);
|
||||
const unsigned kLinkRegCode = 30;
|
||||
const unsigned kZeroRegCode = 31;
|
||||
const unsigned kSPRegInternalCode = 63;
|
||||
@@ -81,18 +87,28 @@ const unsigned kFloatExponentBits = 8;
|
||||
|
||||
const float kFP32PositiveInfinity = rawbits_to_float(0x7f800000);
|
||||
const float kFP32NegativeInfinity = rawbits_to_float(0xff800000);
|
||||
const double kFP64PositiveInfinity = rawbits_to_double(0x7ff0000000000000ULL);
|
||||
const double kFP64NegativeInfinity = rawbits_to_double(0xfff0000000000000ULL);
|
||||
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(0x7ff000007f800001ULL);
|
||||
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(0x7ff800007fc00001ULL);
|
||||
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,
|
||||
@@ -325,7 +341,7 @@ class Instruction {
|
||||
}
|
||||
|
||||
inline Instruction* InstructionAtOffset(int64_t offset) {
|
||||
ASSERT(IsWordAligned(this + offset));
|
||||
VIXL_ASSERT(IsWordAligned(this + offset));
|
||||
return this + offset;
|
||||
}
|
||||
|
||||
|
@@ -27,8 +27,20 @@
|
||||
#ifndef VIXL_GLOBALS_H
|
||||
#define VIXL_GLOBALS_H
|
||||
|
||||
// Get the standard printf format macros for C99 stdint types.
|
||||
// Get standard C99 macros for integer types.
|
||||
#ifndef __STDC_CONSTANT_MACROS
|
||||
#define __STDC_CONSTANT_MACROS
|
||||
#endif
|
||||
|
||||
#ifndef __STDC_LIMIT_MACROS
|
||||
#define __STDC_LIMIT_MACROS
|
||||
#endif
|
||||
|
||||
#ifndef __STDC_FORMAT_MACROS
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <assert.h>
|
||||
@@ -45,21 +57,29 @@ typedef uint8_t byte;
|
||||
const int KBytes = 1024;
|
||||
const int MBytes = 1024 * KBytes;
|
||||
|
||||
#define ABORT() printf("in %s, line %i", __FILE__, __LINE__); abort()
|
||||
#define VIXL_ABORT() printf("in %s, line %i", __FILE__, __LINE__); abort()
|
||||
#ifdef DEBUG
|
||||
#define ASSERT(condition) assert(condition)
|
||||
#define CHECK(condition) ASSERT(condition)
|
||||
#define UNIMPLEMENTED() printf("UNIMPLEMENTED\t"); ABORT()
|
||||
#define UNREACHABLE() printf("UNREACHABLE\t"); ABORT()
|
||||
#define VIXL_ASSERT(condition) assert(condition)
|
||||
#define VIXL_CHECK(condition) VIXL_ASSERT(condition)
|
||||
#define VIXL_UNIMPLEMENTED() printf("UNIMPLEMENTED\t"); VIXL_ABORT()
|
||||
#define VIXL_UNREACHABLE() printf("UNREACHABLE\t"); VIXL_ABORT()
|
||||
#else
|
||||
#define ASSERT(condition) ((void) 0)
|
||||
#define CHECK(condition) assert(condition)
|
||||
#define UNIMPLEMENTED() ((void) 0)
|
||||
#define UNREACHABLE() ((void) 0)
|
||||
#define VIXL_ASSERT(condition) ((void) 0)
|
||||
#define VIXL_CHECK(condition) assert(condition)
|
||||
#define VIXL_UNIMPLEMENTED() ((void) 0)
|
||||
#define VIXL_UNREACHABLE() ((void) 0)
|
||||
#endif
|
||||
// This is not as powerful as template based assertions, but it is simple.
|
||||
// It assumes that the descriptions are unique. If this starts being a problem,
|
||||
// we can switch to a different implemention.
|
||||
#define VIXL_CONCAT(a, b) a##b
|
||||
#define VIXL_STATIC_ASSERT_LINE(line, condition) \
|
||||
typedef char VIXL_CONCAT(STATIC_ASSERT_LINE_, line)[(condition) ? 1 : -1] \
|
||||
__attribute__((unused))
|
||||
#define VIXL_STATIC_ASSERT(condition) VIXL_STATIC_ASSERT_LINE(__LINE__, condition) //NOLINT
|
||||
|
||||
template <typename T> inline void USE(T) {}
|
||||
|
||||
#define ALIGNMENT_EXCEPTION() printf("ALIGNMENT EXCEPTION\t"); ABORT()
|
||||
#define VIXL_ALIGNMENT_EXCEPTION() printf("ALIGNMENT EXCEPTION\t"); VIXL_ABORT()
|
||||
|
||||
#endif // VIXL_GLOBALS_H
|
||||
|
@@ -34,9 +34,7 @@ namespace vixl {
|
||||
// Currently we assume running the simulator implies running on x86 hardware.
|
||||
inline void HostBreakpoint() { asm("int3"); }
|
||||
#else
|
||||
inline void HostBreakpoint() {
|
||||
// TODO: Implement HostBreakpoint on a64.
|
||||
}
|
||||
inline void HostBreakpoint() { asm("brk"); }
|
||||
#endif
|
||||
} // namespace vixl
|
||||
|
||||
|
@@ -58,9 +58,9 @@ double rawbits_to_double(uint64_t bits) {
|
||||
|
||||
|
||||
int CountLeadingZeros(uint64_t value, int width) {
|
||||
ASSERT((width == 32) || (width == 64));
|
||||
VIXL_ASSERT((width == 32) || (width == 64));
|
||||
int count = 0;
|
||||
uint64_t bit_test = 1UL << (width - 1);
|
||||
uint64_t bit_test = UINT64_C(1) << (width - 1);
|
||||
while ((count < width) && ((bit_test & value) == 0)) {
|
||||
count++;
|
||||
bit_test >>= 1;
|
||||
@@ -70,7 +70,7 @@ int CountLeadingZeros(uint64_t value, int width) {
|
||||
|
||||
|
||||
int CountLeadingSignBits(int64_t value, int width) {
|
||||
ASSERT((width == 32) || (width == 64));
|
||||
VIXL_ASSERT((width == 32) || (width == 64));
|
||||
if (value >= 0) {
|
||||
return CountLeadingZeros(value, width) - 1;
|
||||
} else {
|
||||
@@ -80,7 +80,7 @@ int CountLeadingSignBits(int64_t value, int width) {
|
||||
|
||||
|
||||
int CountTrailingZeros(uint64_t value, int width) {
|
||||
ASSERT((width == 32) || (width == 64));
|
||||
VIXL_ASSERT((width == 32) || (width == 64));
|
||||
int count = 0;
|
||||
while ((count < width) && (((value >> count) & 1) == 0)) {
|
||||
count++;
|
||||
@@ -92,10 +92,10 @@ int CountTrailingZeros(uint64_t value, int width) {
|
||||
int CountSetBits(uint64_t value, int width) {
|
||||
// TODO: Other widths could be added here, as the implementation already
|
||||
// supports them.
|
||||
ASSERT((width == 32) || (width == 64));
|
||||
VIXL_ASSERT((width == 32) || (width == 64));
|
||||
|
||||
// Mask out unused bits to ensure that they are not counted.
|
||||
value &= (0xffffffffffffffffULL >> (64-width));
|
||||
value &= (UINT64_C(0xffffffffffffffff) >> (64-width));
|
||||
|
||||
// Add up the set bits.
|
||||
// The algorithm works by adding pairs of bit fields together iteratively,
|
||||
@@ -108,18 +108,19 @@ int CountSetBits(uint64_t value, int width) {
|
||||
// value = h+g+f+e d+c+b+a
|
||||
// \ |
|
||||
// value = h+g+f+e+d+c+b+a
|
||||
value = ((value >> 1) & 0x5555555555555555ULL) +
|
||||
(value & 0x5555555555555555ULL);
|
||||
value = ((value >> 2) & 0x3333333333333333ULL) +
|
||||
(value & 0x3333333333333333ULL);
|
||||
value = ((value >> 4) & 0x0f0f0f0f0f0f0f0fULL) +
|
||||
(value & 0x0f0f0f0f0f0f0f0fULL);
|
||||
value = ((value >> 8) & 0x00ff00ff00ff00ffULL) +
|
||||
(value & 0x00ff00ff00ff00ffULL);
|
||||
value = ((value >> 16) & 0x0000ffff0000ffffULL) +
|
||||
(value & 0x0000ffff0000ffffULL);
|
||||
value = ((value >> 32) & 0x00000000ffffffffULL) +
|
||||
(value & 0x00000000ffffffffULL);
|
||||
const uint64_t kMasks[] = {
|
||||
UINT64_C(0x5555555555555555),
|
||||
UINT64_C(0x3333333333333333),
|
||||
UINT64_C(0x0f0f0f0f0f0f0f0f),
|
||||
UINT64_C(0x00ff00ff00ff00ff),
|
||||
UINT64_C(0x0000ffff0000ffff),
|
||||
UINT64_C(0x00000000ffffffff),
|
||||
};
|
||||
|
||||
for (unsigned i = 0; i < (sizeof(kMasks) / sizeof(kMasks[0])); i++) {
|
||||
int shift = 1 << i;
|
||||
value = ((value >> shift) & kMasks[i]) + (value & kMasks[i]);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
@@ -27,7 +27,7 @@
|
||||
#ifndef VIXL_UTILS_H
|
||||
#define VIXL_UTILS_H
|
||||
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include "globals.h"
|
||||
|
||||
@@ -35,19 +35,19 @@ namespace vixl {
|
||||
|
||||
// Check number width.
|
||||
inline bool is_intn(unsigned n, int64_t x) {
|
||||
ASSERT((0 < n) && (n < 64));
|
||||
int64_t limit = 1ULL << (n - 1);
|
||||
VIXL_ASSERT((0 < n) && (n < 64));
|
||||
int64_t limit = INT64_C(1) << (n - 1);
|
||||
return (-limit <= x) && (x < limit);
|
||||
}
|
||||
|
||||
inline bool is_uintn(unsigned n, int64_t x) {
|
||||
ASSERT((0 < n) && (n < 64));
|
||||
VIXL_ASSERT((0 < n) && (n < 64));
|
||||
return !(x >> n);
|
||||
}
|
||||
|
||||
inline unsigned truncate_to_intn(unsigned n, int64_t x) {
|
||||
ASSERT((0 < n) && (n < 64));
|
||||
return (x & ((1ULL << n) - 1));
|
||||
VIXL_ASSERT((0 < n) && (n < 64));
|
||||
return (x & ((INT64_C(1) << n) - 1));
|
||||
}
|
||||
|
||||
#define INT_1_TO_63_LIST(V) \
|
||||
@@ -90,13 +90,67 @@ inline int64_t signed_bitextract_64(int msb, int lsb, int64_t x) {
|
||||
return (x << (63 - msb)) >> (lsb + 63 - msb);
|
||||
}
|
||||
|
||||
// floating point representation
|
||||
// Floating point representation.
|
||||
uint32_t float_to_rawbits(float value);
|
||||
uint64_t double_to_rawbits(double value);
|
||||
float rawbits_to_float(uint32_t bits);
|
||||
double rawbits_to_double(uint64_t bits);
|
||||
|
||||
// Bits counting.
|
||||
|
||||
// NaN tests.
|
||||
inline bool IsSignallingNaN(double num) {
|
||||
const uint64_t kFP64QuietNaNMask = UINT64_C(0x0008000000000000);
|
||||
uint64_t raw = double_to_rawbits(num);
|
||||
if (isnan(num) && ((raw & kFP64QuietNaNMask) == 0)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
inline bool IsSignallingNaN(float num) {
|
||||
const uint32_t kFP32QuietNaNMask = 0x00400000;
|
||||
uint32_t raw = float_to_rawbits(num);
|
||||
if (isnan(num) && ((raw & kFP32QuietNaNMask) == 0)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
inline bool IsQuietNaN(T num) {
|
||||
return isnan(num) && !IsSignallingNaN(num);
|
||||
}
|
||||
|
||||
|
||||
// Convert the NaN in 'num' to a quiet NaN.
|
||||
inline double ToQuietNaN(double num) {
|
||||
const uint64_t kFP64QuietNaNMask = UINT64_C(0x0008000000000000);
|
||||
VIXL_ASSERT(isnan(num));
|
||||
return rawbits_to_double(double_to_rawbits(num) | kFP64QuietNaNMask);
|
||||
}
|
||||
|
||||
|
||||
inline float ToQuietNaN(float num) {
|
||||
const uint32_t kFP32QuietNaNMask = 0x00400000;
|
||||
VIXL_ASSERT(isnan(num));
|
||||
return rawbits_to_float(float_to_rawbits(num) | kFP32QuietNaNMask);
|
||||
}
|
||||
|
||||
|
||||
// Fused multiply-add.
|
||||
inline double FusedMultiplyAdd(double op1, double op2, double a) {
|
||||
return fma(op1, op2, a);
|
||||
}
|
||||
|
||||
|
||||
inline float FusedMultiplyAdd(float op1, float op2, float a) {
|
||||
return fmaf(op1, op2, a);
|
||||
}
|
||||
|
||||
|
||||
// Bit counting.
|
||||
int CountLeadingZeros(uint64_t value, int width);
|
||||
int CountLeadingSignBits(int64_t value, int width);
|
||||
int CountTrailingZeros(uint64_t value, int width);
|
||||
@@ -106,20 +160,30 @@ int CountSetBits(uint64_t value, int width);
|
||||
// TODO: rename/refactor to make it specific to instructions.
|
||||
template<typename T>
|
||||
bool IsWordAligned(T pointer) {
|
||||
ASSERT(sizeof(pointer) == sizeof(intptr_t)); // NOLINT(runtime/sizeof)
|
||||
VIXL_ASSERT(sizeof(pointer) == sizeof(intptr_t)); // NOLINT(runtime/sizeof)
|
||||
return (reinterpret_cast<intptr_t>(pointer) & 3) == 0;
|
||||
}
|
||||
|
||||
// Increment a pointer until it has the specified alignment.
|
||||
template<class T>
|
||||
T AlignUp(T pointer, size_t alignment) {
|
||||
ASSERT(sizeof(pointer) == sizeof(uintptr_t));
|
||||
VIXL_STATIC_ASSERT(sizeof(pointer) == sizeof(uintptr_t));
|
||||
uintptr_t pointer_raw = reinterpret_cast<uintptr_t>(pointer);
|
||||
size_t align_step = (alignment - pointer_raw) % alignment;
|
||||
ASSERT((pointer_raw + align_step) % alignment == 0);
|
||||
VIXL_ASSERT((pointer_raw + align_step) % alignment == 0);
|
||||
return reinterpret_cast<T>(pointer_raw + align_step);
|
||||
}
|
||||
|
||||
// Decrement a pointer until it has the specified alignment.
|
||||
template<class T>
|
||||
T AlignDown(T pointer, size_t alignment) {
|
||||
VIXL_STATIC_ASSERT(sizeof(pointer) == sizeof(uintptr_t));
|
||||
uintptr_t pointer_raw = reinterpret_cast<uintptr_t>(pointer);
|
||||
size_t align_step = pointer_raw % alignment;
|
||||
VIXL_ASSERT((pointer_raw - align_step) % alignment == 0);
|
||||
return reinterpret_cast<T>(pointer_raw - align_step);
|
||||
}
|
||||
|
||||
|
||||
} // namespace vixl
|
||||
|
||||
|
@@ -139,7 +139,7 @@ static const VMStateDescription vmstate_kbd = {
|
||||
.name = "pckbd",
|
||||
.version_id = 3,
|
||||
.minimum_version_id = 3,
|
||||
.fields = (VMStateField []) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT8(write_cmd, KBDState),
|
||||
VMSTATE_UINT8(status, KBDState),
|
||||
VMSTATE_UINT8(mode, KBDState),
|
||||
@@ -257,7 +257,7 @@ const VMStateDescription vmstate_ide_drive_pio_state = {
|
||||
.minimum_version_id = 1,
|
||||
.pre_save = ide_drive_pio_pre_save,
|
||||
.post_load = ide_drive_pio_post_load,
|
||||
.fields = (VMStateField []) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_INT32(req_nb_sectors, IDEState),
|
||||
VMSTATE_VARRAY_INT32(io_buffer, IDEState, io_buffer_total_len, 1,
|
||||
vmstate_info_uint8, uint8_t),
|
||||
@@ -275,7 +275,7 @@ const VMStateDescription vmstate_ide_drive = {
|
||||
.version_id = 3,
|
||||
.minimum_version_id = 0,
|
||||
.post_load = ide_drive_post_load,
|
||||
.fields = (VMStateField []) {
|
||||
.fields = (VMStateField[]) {
|
||||
.... several fields ....
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
|
76
docs/multiseat.txt
Normal file
76
docs/multiseat.txt
Normal file
@@ -0,0 +1,76 @@
|
||||
|
||||
multiseat howto (with some multihead coverage)
|
||||
==============================================
|
||||
|
||||
host side
|
||||
---------
|
||||
|
||||
First you must compile qemu with a user interface supporting
|
||||
multihead/multiseat and input event routing. Right now this list is
|
||||
pretty short: sdl2.
|
||||
|
||||
./configure --enable-sdl --with-sdlabi=2.0
|
||||
|
||||
|
||||
Next put together the qemu command line:
|
||||
|
||||
qemu -enable-kvm -usb $memory $disk $whatever \
|
||||
-display sdl \
|
||||
-vga std \
|
||||
-device usb-tablet
|
||||
|
||||
That is it for the first head, which will use the standard vga, the
|
||||
standard ps/2 keyboard (implicitly there) and the usb-tablet. Now the
|
||||
additional switches for the second head:
|
||||
|
||||
-device pci-bridge,addr=12.0,chassis_nr=2,id=head.2 \
|
||||
-device secondary-vga,bus=head.2,addr=02.0,id=video.2 \
|
||||
-device nec-usb-xhci,bus=head.2,addr=0f.0,id=usb.2 \
|
||||
-device usb-kbd,bus=usb.2.0,port=1,display=video.2 \
|
||||
-device usb-tablet,bus=usb.2.0,port=2,display=video.2
|
||||
|
||||
This places a pci bridge in slot 12, connects a display adapter and
|
||||
xhci (usb) controller to the bridge. Then it adds a usb keyboard and
|
||||
usb mouse, both connected to the xhci and linked to the display.
|
||||
|
||||
The "display=video2" sets up the input routing. Any input coming from
|
||||
the window which belongs to the video.2 display adapter will be routed
|
||||
to these input devices.
|
||||
|
||||
|
||||
guest side
|
||||
----------
|
||||
|
||||
You need a pretty recent linux guest. systemd with loginctl. kernel
|
||||
3.14+ with CONFIG_DRM_BOCHS enabled. Fedora 20 will do. Must be
|
||||
fully updated for the new kernel though, i.e. the live iso doesn't cut
|
||||
it.
|
||||
|
||||
Now we'll have to configure the guest. Boot and login. By default
|
||||
all devices belong to seat0. You can use "loginctl seat-status seat0"
|
||||
to list them all (and to get the sysfs paths for cut+paste). Now
|
||||
we'll go assign all pci devices connected the pci bridge in slot 12 to
|
||||
a new head:
|
||||
|
||||
loginctl attach seat-qemu \
|
||||
/sys/devices/pci0000:00/0000:00:12.0/0000:01:02.0/drm/card1
|
||||
loginctl attach seat-qemu \
|
||||
/sys/devices/pci0000:00/0000:00:12.0/0000:01:02.0/graphics/fb1
|
||||
loginctl attach seat-qemu \
|
||||
/sys/devices/pci0000:00/0000:00:12.0/0000:01:0f.0/usb2
|
||||
|
||||
Use "loginctl seat-status seat-qemu" to check the result. It isn't
|
||||
needed to assign the usb devices to the head individually, assigning a
|
||||
usb (root) hub will automatically assign all usb devices connected to
|
||||
it too.
|
||||
|
||||
BTW: loginctl writes udev rules to /etc/udev/rules.d to make these
|
||||
device assignments permanent, so you need to do this only once.
|
||||
|
||||
Now simply restart gdm (rebooting will do too), and a login screen
|
||||
should show up on the second head.
|
||||
|
||||
Enjoy!
|
||||
|
||||
--
|
||||
Gerd Hoffmann <kraxel@redhat.com>
|
@@ -48,7 +48,7 @@ The QAPI schema definitions can be modularized using the 'include' directive:
|
||||
{ 'include': 'path/to/file.json'}
|
||||
|
||||
The directive is evaluated recursively, and include paths are relative to the
|
||||
file using the directive.
|
||||
file using the directive. Multiple includes of the same file are safe.
|
||||
|
||||
|
||||
=== Complex types ===
|
||||
@@ -230,14 +230,13 @@ node structure that can be used to chain together a list of such types in
|
||||
case we want to accept/return a list of this type with a command), and a
|
||||
command which takes that type as a parameter and returns the same type:
|
||||
|
||||
mdroth@illuin:~/w/qemu2.git$ cat example-schema.json
|
||||
$ cat example-schema.json
|
||||
{ 'type': 'UserDefOne',
|
||||
'data': { 'integer': 'int', 'string': 'str' } }
|
||||
|
||||
{ 'command': 'my-command',
|
||||
'data': {'arg1': 'UserDefOne'},
|
||||
'returns': 'UserDefOne' }
|
||||
mdroth@illuin:~/w/qemu2.git$
|
||||
|
||||
=== scripts/qapi-types.py ===
|
||||
|
||||
@@ -255,14 +254,25 @@ created code.
|
||||
|
||||
Example:
|
||||
|
||||
mdroth@illuin:~/w/qemu2.git$ python scripts/qapi-types.py \
|
||||
--output-dir="qapi-generated" --prefix="example-" --input-file=example-schema.json
|
||||
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-types.c
|
||||
/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
||||
$ python scripts/qapi-types.py --output-dir="qapi-generated" \
|
||||
--prefix="example-" --input-file=example-schema.json
|
||||
$ cat qapi-generated/example-qapi-types.c
|
||||
[Uninteresting stuff omitted...]
|
||||
|
||||
#include "qapi/qapi-dealloc-visitor.h"
|
||||
#include "example-qapi-types.h"
|
||||
#include "example-qapi-visit.h"
|
||||
void qapi_free_UserDefOneList(UserDefOneList * obj)
|
||||
{
|
||||
QapiDeallocVisitor *md;
|
||||
Visitor *v;
|
||||
|
||||
if (!obj) {
|
||||
return;
|
||||
}
|
||||
|
||||
md = qapi_dealloc_visitor_new();
|
||||
v = qapi_dealloc_get_visitor(md);
|
||||
visit_type_UserDefOneList(v, &obj, NULL, NULL);
|
||||
qapi_dealloc_visitor_cleanup(md);
|
||||
}
|
||||
|
||||
void qapi_free_UserDefOne(UserDefOne * obj)
|
||||
{
|
||||
@@ -279,32 +289,38 @@ Example:
|
||||
qapi_dealloc_visitor_cleanup(md);
|
||||
}
|
||||
|
||||
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-types.h
|
||||
/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
||||
#ifndef QAPI_GENERATED_EXAMPLE_QAPI_TYPES
|
||||
#define QAPI_GENERATED_EXAMPLE_QAPI_TYPES
|
||||
$ cat qapi-generated/example-qapi-types.h
|
||||
[Uninteresting stuff omitted...]
|
||||
|
||||
#include "qapi/qapi-types-core.h"
|
||||
#ifndef EXAMPLE_QAPI_TYPES_H
|
||||
#define EXAMPLE_QAPI_TYPES_H
|
||||
|
||||
[Builtin types omitted...]
|
||||
|
||||
typedef struct UserDefOne UserDefOne;
|
||||
|
||||
typedef struct UserDefOneList
|
||||
{
|
||||
UserDefOne *value;
|
||||
union {
|
||||
UserDefOne *value;
|
||||
uint64_t padding;
|
||||
};
|
||||
struct UserDefOneList *next;
|
||||
} UserDefOneList;
|
||||
|
||||
[Functions on builtin types omitted...]
|
||||
|
||||
struct UserDefOne
|
||||
{
|
||||
int64_t integer;
|
||||
char * string;
|
||||
};
|
||||
|
||||
void qapi_free_UserDefOneList(UserDefOneList * obj);
|
||||
void qapi_free_UserDefOne(UserDefOne * obj);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
=== scripts/qapi-visit.py ===
|
||||
|
||||
Used to generate the visitor functions used to walk through and convert
|
||||
@@ -325,51 +341,78 @@ $(prefix)qapi-visit.h: declarations for previously mentioned visitor
|
||||
|
||||
Example:
|
||||
|
||||
mdroth@illuin:~/w/qemu2.git$ python scripts/qapi-visit.py \
|
||||
--output-dir="qapi-generated" --prefix="example-" --input-file=example-schema.json
|
||||
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-visit.c
|
||||
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
||||
$ python scripts/qapi-visit.py --output-dir="qapi-generated"
|
||||
--prefix="example-" --input-file=example-schema.json
|
||||
$ cat qapi-generated/example-qapi-visit.c
|
||||
[Uninteresting stuff omitted...]
|
||||
|
||||
#include "example-qapi-visit.h"
|
||||
static void visit_type_UserDefOne_fields(Visitor *m, UserDefOne ** obj, Error **errp)
|
||||
{
|
||||
Error *err = NULL;
|
||||
visit_type_int(m, &(*obj)->integer, "integer", &err);
|
||||
if (err) {
|
||||
goto out;
|
||||
}
|
||||
visit_type_str(m, &(*obj)->string, "string", &err);
|
||||
if (err) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
error_propagate(errp, err);
|
||||
}
|
||||
|
||||
void visit_type_UserDefOne(Visitor *m, UserDefOne ** obj, const char *name, Error **errp)
|
||||
{
|
||||
visit_start_struct(m, (void **)obj, "UserDefOne", name, sizeof(UserDefOne), errp);
|
||||
visit_type_int(m, (obj && *obj) ? &(*obj)->integer : NULL, "integer", errp);
|
||||
visit_type_str(m, (obj && *obj) ? &(*obj)->string : NULL, "string", errp);
|
||||
visit_end_struct(m, errp);
|
||||
Error *err = NULL;
|
||||
|
||||
visit_start_struct(m, (void **)obj, "UserDefOne", name, sizeof(UserDefOne), &err);
|
||||
if (!err) {
|
||||
if (*obj) {
|
||||
visit_type_UserDefOne_fields(m, obj, errp);
|
||||
}
|
||||
visit_end_struct(m, &err);
|
||||
}
|
||||
error_propagate(errp, err);
|
||||
}
|
||||
|
||||
void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp)
|
||||
{
|
||||
GenericList *i, **prev = (GenericList **)obj;
|
||||
Error *err = NULL;
|
||||
GenericList *i, **prev;
|
||||
|
||||
visit_start_list(m, name, errp);
|
||||
|
||||
for (; (i = visit_next_list(m, prev, errp)) != NULL; prev = &i) {
|
||||
UserDefOneList *native_i = (UserDefOneList *)i;
|
||||
visit_type_UserDefOne(m, &native_i->value, NULL, errp);
|
||||
visit_start_list(m, name, &err);
|
||||
if (err) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
visit_end_list(m, errp);
|
||||
for (prev = (GenericList **)obj;
|
||||
!err && (i = visit_next_list(m, prev, &err)) != NULL;
|
||||
prev = &i) {
|
||||
UserDefOneList *native_i = (UserDefOneList *)i;
|
||||
visit_type_UserDefOne(m, &native_i->value, NULL, &err);
|
||||
}
|
||||
|
||||
error_propagate(errp, err);
|
||||
err = NULL;
|
||||
visit_end_list(m, &err);
|
||||
out:
|
||||
error_propagate(errp, err);
|
||||
}
|
||||
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qapi-visit.h
|
||||
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
||||
$ python scripts/qapi-commands.py --output-dir="qapi-generated" \
|
||||
--prefix="example-" --input-file=example-schema.json
|
||||
$ cat qapi-generated/example-qapi-visit.h
|
||||
[Uninteresting stuff omitted...]
|
||||
|
||||
#ifndef QAPI_GENERATED_EXAMPLE_QAPI_VISIT
|
||||
#define QAPI_GENERATED_EXAMPLE_QAPI_VISIT
|
||||
#ifndef EXAMPLE_QAPI_VISIT_H
|
||||
#define EXAMPLE_QAPI_VISIT_H
|
||||
|
||||
#include "qapi/qapi-visit-core.h"
|
||||
#include "example-qapi-types.h"
|
||||
[Visitors for builtin types omitted...]
|
||||
|
||||
void visit_type_UserDefOne(Visitor *m, UserDefOne ** obj, const char *name, Error **errp);
|
||||
void visit_type_UserDefOneList(Visitor *m, UserDefOneList ** obj, const char *name, Error **errp);
|
||||
|
||||
#endif
|
||||
mdroth@illuin:~/w/qemu2.git$
|
||||
|
||||
(The actual structure of the visit_type_* functions is a bit more complex
|
||||
in order to propagate errors correctly and avoid leaking memory).
|
||||
|
||||
=== scripts/qapi-commands.py ===
|
||||
|
||||
@@ -390,77 +433,80 @@ $(prefix)qmp-commands.h: Function prototypes for the QMP commands
|
||||
|
||||
Example:
|
||||
|
||||
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qmp-marshal.c
|
||||
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
||||
$ cat qapi-generated/example-qmp-marshal.c
|
||||
[Uninteresting stuff omitted...]
|
||||
|
||||
#include "qemu-objects.h"
|
||||
#include "qapi/qmp-core.h"
|
||||
#include "qapi/qapi-visit-core.h"
|
||||
#include "qapi/qmp-output-visitor.h"
|
||||
#include "qapi/qmp-input-visitor.h"
|
||||
#include "qapi/qapi-dealloc-visitor.h"
|
||||
#include "example-qapi-types.h"
|
||||
#include "example-qapi-visit.h"
|
||||
|
||||
#include "example-qmp-commands.h"
|
||||
static void qmp_marshal_output_my_command(UserDefOne * ret_in, QObject **ret_out, Error **errp)
|
||||
{
|
||||
QapiDeallocVisitor *md = qapi_dealloc_visitor_new();
|
||||
Error *local_err = NULL;
|
||||
QmpOutputVisitor *mo = qmp_output_visitor_new();
|
||||
QapiDeallocVisitor *md;
|
||||
Visitor *v;
|
||||
|
||||
v = qmp_output_get_visitor(mo);
|
||||
visit_type_UserDefOne(v, &ret_in, "unused", errp);
|
||||
v = qapi_dealloc_get_visitor(md);
|
||||
visit_type_UserDefOne(v, &ret_in, "unused", errp);
|
||||
qapi_dealloc_visitor_cleanup(md);
|
||||
|
||||
|
||||
visit_type_UserDefOne(v, &ret_in, "unused", &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
*ret_out = qmp_output_get_qobject(mo);
|
||||
|
||||
out:
|
||||
error_propagate(errp, local_err);
|
||||
qmp_output_visitor_cleanup(mo);
|
||||
md = qapi_dealloc_visitor_new();
|
||||
v = qapi_dealloc_get_visitor(md);
|
||||
visit_type_UserDefOne(v, &ret_in, "unused", NULL);
|
||||
qapi_dealloc_visitor_cleanup(md);
|
||||
}
|
||||
|
||||
static void qmp_marshal_input_my_command(QmpState *qmp__sess, QDict *args, QObject **ret, Error **errp)
|
||||
static void qmp_marshal_input_my_command(QDict *args, QObject **ret, Error **errp)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
UserDefOne * retval = NULL;
|
||||
QmpInputVisitor *mi;
|
||||
QmpInputVisitor *mi = qmp_input_visitor_new_strict(QOBJECT(args));
|
||||
QapiDeallocVisitor *md;
|
||||
Visitor *v;
|
||||
UserDefOne * arg1 = NULL;
|
||||
|
||||
mi = qmp_input_visitor_new(QOBJECT(args));
|
||||
v = qmp_input_get_visitor(mi);
|
||||
visit_type_UserDefOne(v, &arg1, "arg1", errp);
|
||||
|
||||
if (error_is_set(errp)) {
|
||||
visit_type_UserDefOne(v, &arg1, "arg1", &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
retval = qmp_my_command(arg1, errp);
|
||||
qmp_marshal_output_my_command(retval, ret, errp);
|
||||
|
||||
retval = qmp_my_command(arg1, &local_err);
|
||||
if (local_err) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
qmp_marshal_output_my_command(retval, ret, &local_err);
|
||||
|
||||
out:
|
||||
error_propagate(errp, local_err);
|
||||
qmp_input_visitor_cleanup(mi);
|
||||
md = qapi_dealloc_visitor_new();
|
||||
v = qapi_dealloc_get_visitor(md);
|
||||
visit_type_UserDefOne(v, &arg1, "arg1", errp);
|
||||
visit_type_UserDefOne(v, &arg1, "arg1", NULL);
|
||||
qapi_dealloc_visitor_cleanup(md);
|
||||
return;
|
||||
}
|
||||
|
||||
static void qmp_init_marshal(void)
|
||||
{
|
||||
qmp_register_command("my-command", qmp_marshal_input_my_command);
|
||||
qmp_register_command("my-command", qmp_marshal_input_my_command, QCO_NO_OPTIONS);
|
||||
}
|
||||
|
||||
qapi_init(qmp_init_marshal);
|
||||
mdroth@illuin:~/w/qemu2.git$ cat qapi-generated/example-qmp-commands.h
|
||||
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
||||
$ cat qapi-generated/example-qmp-commands.h
|
||||
[Uninteresting stuff omitted...]
|
||||
|
||||
#ifndef QAPI_GENERATED_EXAMPLE_QMP_COMMANDS
|
||||
#define QAPI_GENERATED_EXAMPLE_QMP_COMMANDS
|
||||
#ifndef EXAMPLE_QMP_COMMANDS_H
|
||||
#define EXAMPLE_QMP_COMMANDS_H
|
||||
|
||||
#include "example-qapi-types.h"
|
||||
#include "error.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
UserDefOne * qmp_my_command(UserDefOne * arg1, Error **errp);
|
||||
|
||||
#endif
|
||||
mdroth@illuin:~/w/qemu2.git$
|
||||
|
3
exec.c
3
exec.c
@@ -429,9 +429,8 @@ const VMStateDescription vmstate_cpu_common = {
|
||||
.name = "cpu_common",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.post_load = cpu_common_post_load,
|
||||
.fields = (VMStateField []) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(halted, CPUState),
|
||||
VMSTATE_UINT32(interrupt_request, CPUState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
|
@@ -556,6 +556,7 @@ ETEXI
|
||||
.params = "keys [hold_ms]",
|
||||
.help = "send keys to the VM (e.g. 'sendkey ctrl-alt-f1', default hold time=100 ms)",
|
||||
.mhandler.cmd = hmp_send_key,
|
||||
.command_completion = sendkey_completion,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1233,9 +1234,10 @@ ETEXI
|
||||
{
|
||||
.name = "netdev_add",
|
||||
.args_type = "netdev:O",
|
||||
.params = "[user|tap|socket|hubport|netmap],id=str[,prop=value][,...]",
|
||||
.params = "[user|tap|socket|vde|bridge|hubport|netmap],id=str[,prop=value][,...]",
|
||||
.help = "add host network device",
|
||||
.mhandler.cmd = hmp_netdev_add,
|
||||
.command_completion = netdev_add_completion,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1250,6 +1252,7 @@ ETEXI
|
||||
.params = "id",
|
||||
.help = "remove host network device",
|
||||
.mhandler.cmd = hmp_netdev_del,
|
||||
.command_completion = netdev_del_completion,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1339,6 +1342,7 @@ ETEXI
|
||||
.params = "name on|off",
|
||||
.help = "change the link status of a network adapter",
|
||||
.mhandler.cmd = hmp_set_link,
|
||||
.command_completion = set_link_completion,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1622,6 +1626,7 @@ ETEXI
|
||||
.params = "args",
|
||||
.help = "add chardev",
|
||||
.mhandler.cmd = hmp_chardev_add,
|
||||
.command_completion = chardev_add_completion,
|
||||
},
|
||||
|
||||
STEXI
|
||||
@@ -1638,6 +1643,7 @@ ETEXI
|
||||
.params = "id",
|
||||
.help = "remove chardev",
|
||||
.mhandler.cmd = hmp_chardev_remove,
|
||||
.command_completion = chardev_remove_completion,
|
||||
},
|
||||
|
||||
STEXI
|
||||
|
21
hmp.c
21
hmp.c
@@ -341,6 +341,11 @@ void hmp_info_block(Monitor *mon, const QDict *qdict)
|
||||
info->value->inserted->backing_file_depth);
|
||||
}
|
||||
|
||||
if (info->value->inserted->detect_zeroes != BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF) {
|
||||
monitor_printf(mon, " Detect zeroes: %s\n",
|
||||
BlockdevDetectZeroesOptions_lookup[info->value->inserted->detect_zeroes]);
|
||||
}
|
||||
|
||||
if (info->value->inserted->bps
|
||||
|| info->value->inserted->bps_rd
|
||||
|| info->value->inserted->bps_wr
|
||||
@@ -1388,6 +1393,7 @@ void hmp_netdev_del(Monitor *mon, const QDict *qdict)
|
||||
void hmp_object_add(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
Error *err = NULL;
|
||||
Error *err_end = NULL;
|
||||
QemuOpts *opts;
|
||||
char *type = NULL;
|
||||
char *id = NULL;
|
||||
@@ -1411,24 +1417,23 @@ void hmp_object_add(Monitor *mon, const QDict *qdict)
|
||||
qdict_del(pdict, "qom-type");
|
||||
visit_type_str(opts_get_visitor(ov), &type, "qom-type", &err);
|
||||
if (err) {
|
||||
goto out_clean;
|
||||
goto out_end;
|
||||
}
|
||||
|
||||
qdict_del(pdict, "id");
|
||||
visit_type_str(opts_get_visitor(ov), &id, "id", &err);
|
||||
if (err) {
|
||||
goto out_clean;
|
||||
goto out_end;
|
||||
}
|
||||
|
||||
object_add(type, id, pdict, opts_get_visitor(ov), &err);
|
||||
if (err) {
|
||||
goto out_clean;
|
||||
}
|
||||
visit_end_struct(opts_get_visitor(ov), &err);
|
||||
if (err) {
|
||||
|
||||
out_end:
|
||||
visit_end_struct(opts_get_visitor(ov), &err_end);
|
||||
if (!err && err_end) {
|
||||
qmp_object_del(id, NULL);
|
||||
}
|
||||
|
||||
error_propagate(&err, err_end);
|
||||
out_clean:
|
||||
opts_visitor_cleanup(ov);
|
||||
|
||||
|
6
hmp.h
6
hmp.h
@@ -97,5 +97,11 @@ void object_add_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||
void object_del_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||
void device_add_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||
void device_del_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||
void sendkey_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||
void chardev_remove_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||
void chardev_add_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||
void set_link_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||
void netdev_add_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||
void netdev_del_completion(ReadLineState *rs, int nb_args, const char *str);
|
||||
|
||||
#endif
|
||||
|
@@ -134,7 +134,6 @@ static VMStateDescription vmstate_highbank_regs = {
|
||||
.name = "highbank-regs",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.minimum_version_id_old = 0,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(regs, HighbankRegsState, NUM_REGS),
|
||||
VMSTATE_END_OF_LIST(),
|
||||
|
@@ -405,7 +405,6 @@ static const VMStateDescription mv88w8618_eth_vmsd = {
|
||||
.name = "mv88w8618_eth",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(smir, mv88w8618_eth_state),
|
||||
VMSTATE_UINT32(icr, mv88w8618_eth_state),
|
||||
@@ -642,7 +641,6 @@ static const VMStateDescription musicpal_lcd_vmsd = {
|
||||
.name = "musicpal_lcd",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(brightness, musicpal_lcd_state),
|
||||
VMSTATE_UINT32(mode, musicpal_lcd_state),
|
||||
@@ -769,7 +767,6 @@ static const VMStateDescription mv88w8618_pic_vmsd = {
|
||||
.name = "mv88w8618_pic",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(level, mv88w8618_pic_state),
|
||||
VMSTATE_UINT32(enabled, mv88w8618_pic_state),
|
||||
@@ -940,7 +937,6 @@ static const VMStateDescription mv88w8618_timer_vmsd = {
|
||||
.name = "timer",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_PTIMER(ptimer, mv88w8618_timer_state),
|
||||
VMSTATE_UINT32(limit, mv88w8618_timer_state),
|
||||
@@ -952,7 +948,6 @@ static const VMStateDescription mv88w8618_pit_vmsd = {
|
||||
.name = "mv88w8618_pit",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_STRUCT_ARRAY(timer, mv88w8618_pit_state, 4, 1,
|
||||
mv88w8618_timer_vmsd, mv88w8618_timer_state),
|
||||
@@ -1041,7 +1036,6 @@ static const VMStateDescription mv88w8618_flashcfg_vmsd = {
|
||||
.name = "mv88w8618_flashcfg",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(cfgr0, mv88w8618_flashcfg_state),
|
||||
VMSTATE_END_OF_LIST()
|
||||
@@ -1381,7 +1375,6 @@ static const VMStateDescription musicpal_gpio_vmsd = {
|
||||
.name = "musicpal_gpio",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(lcd_brightness, musicpal_gpio_state),
|
||||
VMSTATE_UINT32(out_state, musicpal_gpio_state),
|
||||
@@ -1548,7 +1541,6 @@ static const VMStateDescription musicpal_key_vmsd = {
|
||||
.name = "musicpal_key",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(kbd_extended, musicpal_key_state),
|
||||
VMSTATE_UINT32(pressed_keys, musicpal_key_state),
|
||||
|
@@ -2709,8 +2709,8 @@ static void omap_rtc_write(void *opaque, hwaddr addr,
|
||||
s->ti += ti[1];
|
||||
} else {
|
||||
/* A less accurate version */
|
||||
s->ti -= (s->current_tm.tm_year % 100) * 31536000;
|
||||
s->ti += from_bcd(value) * 31536000;
|
||||
s->ti -= (time_t)(s->current_tm.tm_year % 100) * 31536000;
|
||||
s->ti += (time_t)from_bcd(value) * 31536000;
|
||||
}
|
||||
return;
|
||||
|
||||
|
@@ -148,8 +148,7 @@ static const VMStateDescription vmstate_pxa2xx_pm = {
|
||||
.name = "pxa2xx_pm",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.minimum_version_id_old = 0,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(pm_regs, PXA2xxState, 0x40),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
@@ -215,8 +214,7 @@ static const VMStateDescription vmstate_pxa2xx_cm = {
|
||||
.name = "pxa2xx_cm",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.minimum_version_id_old = 0,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(cm_regs, PXA2xxState, 4),
|
||||
VMSTATE_UINT32(clkcfg, PXA2xxState),
|
||||
VMSTATE_UINT32(pmnc, PXA2xxState),
|
||||
@@ -440,8 +438,7 @@ static const VMStateDescription vmstate_pxa2xx_mm = {
|
||||
.name = "pxa2xx_mm",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.minimum_version_id_old = 0,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(mm_regs, PXA2xxState, 0x1a),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
@@ -1172,7 +1169,6 @@ static const VMStateDescription vmstate_pxa2xx_rtc_regs = {
|
||||
.name = "pxa2xx_rtc",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.minimum_version_id_old = 0,
|
||||
.pre_save = pxa2xx_rtc_pre_save,
|
||||
.post_load = pxa2xx_rtc_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
@@ -1436,8 +1432,7 @@ static const VMStateDescription vmstate_pxa2xx_i2c_slave = {
|
||||
.name = "pxa2xx_i2c_slave",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField []) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_I2C_SLAVE(parent_obj, PXA2xxI2CSlaveState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
@@ -1447,8 +1442,7 @@ static const VMStateDescription vmstate_pxa2xx_i2c = {
|
||||
.name = "pxa2xx_i2c",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField []) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT16(control, PXA2xxI2CState),
|
||||
VMSTATE_UINT16(status, PXA2xxI2CState),
|
||||
VMSTATE_UINT8(ibmr, PXA2xxI2CState),
|
||||
@@ -1705,8 +1699,7 @@ static const VMStateDescription vmstate_pxa2xx_i2s = {
|
||||
.name = "pxa2xx_i2s",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.minimum_version_id_old = 0,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(control, PXA2xxI2SState, 2),
|
||||
VMSTATE_UINT32(status, PXA2xxI2SState),
|
||||
VMSTATE_UINT32(mask, PXA2xxI2SState),
|
||||
|
@@ -313,8 +313,7 @@ static const VMStateDescription vmstate_pxa2xx_gpio_regs = {
|
||||
.name = "pxa2xx-gpio",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField []) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_INT32(lines, PXA2xxGPIOInfo),
|
||||
VMSTATE_UINT32_ARRAY(ilevel, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
|
||||
VMSTATE_UINT32_ARRAY(olevel, PXA2xxGPIOInfo, PXA2XX_GPIO_BANKS),
|
||||
|
@@ -296,7 +296,6 @@ static VMStateDescription vmstate_pxa2xx_pic_regs = {
|
||||
.name = "pxa2xx_pic",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.minimum_version_id_old = 0,
|
||||
.post_load = pxa2xx_pic_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(int_enabled, PXA2xxPICState, 2),
|
||||
|
@@ -1006,8 +1006,7 @@ static VMStateDescription vmstate_sl_nand_info = {
|
||||
.name = "sl-nand",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.minimum_version_id_old = 0,
|
||||
.fields = (VMStateField []) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT8(ctl, SLNANDState),
|
||||
VMSTATE_STRUCT(ecc, SLNANDState, 0, vmstate_ecc_state, ECCState),
|
||||
VMSTATE_END_OF_LIST(),
|
||||
@@ -1041,9 +1040,8 @@ static VMStateDescription vmstate_spitz_kbd = {
|
||||
.name = "spitz-keyboard",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 0,
|
||||
.minimum_version_id_old = 0,
|
||||
.post_load = spitz_keyboard_post_load,
|
||||
.fields = (VMStateField []) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT16(sense_state, SpitzKeyboardState),
|
||||
VMSTATE_UINT16(strobe_state, SpitzKeyboardState),
|
||||
VMSTATE_UNUSED_TEST(is_version_0, 5),
|
||||
@@ -1076,8 +1074,7 @@ static const VMStateDescription vmstate_corgi_ssp_regs = {
|
||||
.name = "corgi-ssp",
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 2,
|
||||
.minimum_version_id_old = 2,
|
||||
.fields = (VMStateField []) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_SSI_SLAVE(ssidev, CorgiSSPState),
|
||||
VMSTATE_UINT32_ARRAY(enable, CorgiSSPState, 3),
|
||||
VMSTATE_END_OF_LIST(),
|
||||
@@ -1105,8 +1102,7 @@ static const VMStateDescription vmstate_spitz_lcdtg_regs = {
|
||||
.name = "spitz-lcdtg",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField []) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_SSI_SLAVE(ssidev, SpitzLCDTG),
|
||||
VMSTATE_UINT32(bl_intensity, SpitzLCDTG),
|
||||
VMSTATE_UINT32(bl_power, SpitzLCDTG),
|
||||
|
@@ -185,12 +185,19 @@ static uint64_t gptm_read(void *opaque, hwaddr offset,
|
||||
case 0x44: /* TBPMR */
|
||||
return s->match_prescale[1];
|
||||
case 0x48: /* TAR */
|
||||
if (s->control == 1)
|
||||
if (s->config == 1) {
|
||||
return s->rtc;
|
||||
}
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
"GPTM: read of TAR but timer read not supported");
|
||||
return 0;
|
||||
case 0x4c: /* TBR */
|
||||
hw_error("TODO: Timer value read\n");
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
"GPTM: read of TBR but timer read not supported");
|
||||
return 0;
|
||||
default:
|
||||
hw_error("gptm_read: Bad offset 0x%x\n", (int)offset);
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"GPTM: read at bad offset 0x%x\n", (int)offset);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -286,8 +293,7 @@ static const VMStateDescription vmstate_stellaris_gptm = {
|
||||
.name = "stellaris_gptm",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(config, gptm_state),
|
||||
VMSTATE_UINT32_ARRAY(mode, gptm_state, 2),
|
||||
VMSTATE_UINT32(control, gptm_state),
|
||||
@@ -643,9 +649,8 @@ static const VMStateDescription vmstate_stellaris_sys = {
|
||||
.name = "stellaris_sys",
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.post_load = stellaris_sys_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(pborctl, ssys_state),
|
||||
VMSTATE_UINT32(ldopctl, ssys_state),
|
||||
VMSTATE_UINT32(int_mask, ssys_state),
|
||||
@@ -851,8 +856,7 @@ static const VMStateDescription vmstate_stellaris_i2c = {
|
||||
.name = "stellaris_i2c",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(msa, stellaris_i2c_state),
|
||||
VMSTATE_UINT32(mcs, stellaris_i2c_state),
|
||||
VMSTATE_UINT32(mdr, stellaris_i2c_state),
|
||||
@@ -1121,8 +1125,7 @@ static const VMStateDescription vmstate_stellaris_adc = {
|
||||
.name = "stellaris_adc",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(actss, stellaris_adc_state),
|
||||
VMSTATE_UINT32(ris, stellaris_adc_state),
|
||||
VMSTATE_UINT32(im, stellaris_adc_state),
|
||||
|
@@ -199,7 +199,6 @@ static VMStateDescription vmstate_strongarm_pic_regs = {
|
||||
.name = "strongarm_pic",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.minimum_version_id_old = 0,
|
||||
.post_load = strongarm_pic_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(pending, StrongARMPICState),
|
||||
@@ -424,7 +423,6 @@ static const VMStateDescription vmstate_strongarm_rtc_regs = {
|
||||
.name = "strongarm-rtc",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.minimum_version_id_old = 0,
|
||||
.pre_save = strongarm_rtc_pre_save,
|
||||
.post_load = strongarm_rtc_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
@@ -670,7 +668,6 @@ static const VMStateDescription vmstate_strongarm_gpio_regs = {
|
||||
.name = "strongarm-gpio",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.minimum_version_id_old = 0,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(ilevel, StrongARMGPIOInfo),
|
||||
VMSTATE_UINT32(olevel, StrongARMGPIOInfo),
|
||||
@@ -842,7 +839,6 @@ static const VMStateDescription vmstate_strongarm_ppc_regs = {
|
||||
.name = "strongarm-ppc",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.minimum_version_id_old = 0,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(ilevel, StrongARMPPCInfo),
|
||||
VMSTATE_UINT32(olevel, StrongARMPPCInfo),
|
||||
@@ -1293,7 +1289,6 @@ static const VMStateDescription vmstate_strongarm_uart_regs = {
|
||||
.name = "strongarm-uart",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.minimum_version_id_old = 0,
|
||||
.post_load = strongarm_uart_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT8(utcr0, StrongARMUARTState),
|
||||
@@ -1553,7 +1548,6 @@ static const VMStateDescription vmstate_strongarm_ssp_regs = {
|
||||
.name = "strongarm-ssp",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.minimum_version_id_old = 0,
|
||||
.post_load = strongarm_ssp_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT16_ARRAY(sscr, StrongARMSSPState, 2),
|
||||
|
@@ -164,7 +164,6 @@ static VMStateDescription vmstate_zipit_lcd_state = {
|
||||
.name = "zipit-lcd",
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 2,
|
||||
.minimum_version_id_old = 2,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_SSI_SLAVE(ssidev, ZipitLCD),
|
||||
VMSTATE_INT32(selected, ZipitLCD),
|
||||
@@ -275,7 +274,6 @@ static VMStateDescription vmstate_aer915_state = {
|
||||
.name = "aer915",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_INT32(len, AER915State),
|
||||
VMSTATE_BUFFER(buf, AER915State),
|
||||
|
@@ -245,7 +245,7 @@ static void intel_hda_update_int_sts(IntelHDAState *d)
|
||||
|
||||
/* update global status */
|
||||
if (sts & d->int_ctl) {
|
||||
sts |= (1 << 31);
|
||||
sts |= (1U << 31);
|
||||
}
|
||||
|
||||
d->int_sts = sts;
|
||||
@@ -257,7 +257,7 @@ static void intel_hda_update_irq(IntelHDAState *d)
|
||||
int level;
|
||||
|
||||
intel_hda_update_int_sts(d);
|
||||
if (d->int_sts & (1 << 31) && d->int_ctl & (1 << 31)) {
|
||||
if (d->int_sts & (1U << 31) && d->int_ctl & (1U << 31)) {
|
||||
level = 1;
|
||||
} else {
|
||||
level = 0;
|
||||
@@ -574,7 +574,7 @@ static void intel_hda_set_st_ctl(IntelHDAState *d, const IntelHDAReg *reg, uint3
|
||||
if (st->ctl & 0x01) {
|
||||
/* reset */
|
||||
dprint(d, 1, "st #%d: reset\n", reg->stream);
|
||||
st->ctl = 0;
|
||||
st->ctl = SD_STS_FIFO_READY << 24;
|
||||
}
|
||||
if ((st->ctl & 0x02) != (old & 0x02)) {
|
||||
uint32_t stnr = (st->ctl >> 20) & 0x0f;
|
||||
@@ -829,6 +829,7 @@ static const struct IntelHDAReg regtab[] = {
|
||||
.wclear = 0x1c000000, \
|
||||
.offset = offsetof(IntelHDAState, st[_i].ctl), \
|
||||
.whandler = intel_hda_set_st_ctl, \
|
||||
.reset = SD_STS_FIFO_READY << 24 \
|
||||
}, \
|
||||
[ ST_REG(_i, ICH6_REG_SD_LPIB) ] = { \
|
||||
.stream = _i, \
|
||||
|
@@ -324,9 +324,8 @@ const VMStateDescription vmstate_lm4549_state = {
|
||||
.name = "lm4549_state",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.post_load = &lm4549_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
.post_load = lm4549_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(voice_is_active, lm4549_state),
|
||||
VMSTATE_UINT16_ARRAY(regfile, lm4549_state, 128),
|
||||
VMSTATE_UINT16_ARRAY(buffer, lm4549_state, LM4549_BUFFER_SIZE),
|
||||
|
@@ -259,7 +259,6 @@ static const VMStateDescription mv88w8618_audio_vmsd = {
|
||||
.name = "mv88w8618_audio",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(playback_mode, mv88w8618_audio_state),
|
||||
VMSTATE_UINT32(status, mv88w8618_audio_state),
|
||||
|
@@ -316,9 +316,8 @@ static const VMStateDescription vmstate_milkymist_ac97 = {
|
||||
.name = "milkymist-ac97",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.post_load = ac97_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(regs, MilkymistAC97State, R_MAX),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
|
@@ -561,8 +561,7 @@ static const VMStateDescription vmstate_pl041_regfile = {
|
||||
.name = "pl041_regfile",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField[]) {
|
||||
#define REGISTER(name, offset) VMSTATE_UINT32(name, pl041_regfile),
|
||||
#include "pl041.hx"
|
||||
#undef REGISTER
|
||||
@@ -574,8 +573,7 @@ static const VMStateDescription vmstate_pl041_fifo = {
|
||||
.name = "pl041_fifo",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(level, pl041_fifo),
|
||||
VMSTATE_UINT32_ARRAY(data, pl041_fifo, MAX_FIFO_DEPTH),
|
||||
VMSTATE_END_OF_LIST()
|
||||
@@ -586,8 +584,7 @@ static const VMStateDescription vmstate_pl041_channel = {
|
||||
.name = "pl041_channel",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_STRUCT(tx_fifo, pl041_channel, 0,
|
||||
vmstate_pl041_fifo, pl041_fifo),
|
||||
VMSTATE_UINT8(tx_enabled, pl041_channel),
|
||||
|
@@ -583,10 +583,9 @@ static const VMStateDescription vmstate_wm8750 = {
|
||||
.name = CODEC,
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.minimum_version_id_old = 0,
|
||||
.pre_save = wm8750_pre_save,
|
||||
.post_load = wm8750_post_load,
|
||||
.fields = (VMStateField []) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT8_ARRAY(i2c_data, WM8750State, 2),
|
||||
VMSTATE_INT32(i2c_len, WM8750State),
|
||||
VMSTATE_INT32(enable, WM8750State),
|
||||
|
@@ -81,8 +81,7 @@ VMStateDescription vmstate_ecc_state = {
|
||||
.name = "ecc-state",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.minimum_version_id_old = 0,
|
||||
.fields = (VMStateField []) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT8(cp, ECCState),
|
||||
VMSTATE_UINT16_ARRAY(lp, ECCState, 2),
|
||||
VMSTATE_UINT16(count, ECCState),
|
||||
|
@@ -653,7 +653,6 @@ static const VMStateDescription vmstate_m25p80 = {
|
||||
.name = "xilinx_spi",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.pre_save = m25p80_pre_save,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT8(state, Flash),
|
||||
|
@@ -346,10 +346,9 @@ static const VMStateDescription vmstate_nand = {
|
||||
.name = "nand",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.pre_save = nand_pre_save,
|
||||
.post_load = nand_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT8(cle, NANDFlashState),
|
||||
VMSTATE_UINT8(ale, NANDFlashState),
|
||||
VMSTATE_UINT8(ce, NANDFlashState),
|
||||
|
@@ -169,7 +169,6 @@ static const VMStateDescription vmstate_onenand = {
|
||||
.name = "onenand",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.pre_save = onenand_pre_save,
|
||||
.post_load = onenand_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
|
@@ -504,7 +504,6 @@ static const VMStateDescription vmstate_cadence_uart = {
|
||||
.name = "cadence_uart",
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 2,
|
||||
.minimum_version_id_old = 2,
|
||||
.post_load = cadence_uart_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(r, UartState, R_MAX),
|
||||
|
@@ -162,7 +162,6 @@ static const VMStateDescription vmstate_digic_uart = {
|
||||
.name = "digic-uart",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(reg_rx, DigicUartState),
|
||||
VMSTATE_UINT32(reg_st, DigicUartState),
|
||||
|
231
hw/char/escc.c
231
hw/char/escc.c
@@ -27,6 +27,7 @@
|
||||
#include "hw/char/escc.h"
|
||||
#include "sysemu/char.h"
|
||||
#include "ui/console.h"
|
||||
#include "ui/input.h"
|
||||
#include "trace.h"
|
||||
|
||||
/*
|
||||
@@ -94,6 +95,7 @@ typedef struct ChannelState {
|
||||
ChnID chn; // this channel, A (base+4) or B (base+0)
|
||||
ChnType type;
|
||||
uint8_t rx, tx;
|
||||
QemuInputHandlerState *hs;
|
||||
} ChannelState;
|
||||
|
||||
#define ESCC(obj) OBJECT_CHECK(ESCCState, (obj), TYPE_ESCC)
|
||||
@@ -714,71 +716,181 @@ MemoryRegion *escc_init(hwaddr base, qemu_irq irqA, qemu_irq irqB,
|
||||
return &d->mmio;
|
||||
}
|
||||
|
||||
static const uint8_t keycodes[128] = {
|
||||
127, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 53,
|
||||
54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 89, 76, 77, 78,
|
||||
79, 80, 81, 82, 83, 84, 85, 86, 87, 42, 99, 88, 100, 101, 102, 103,
|
||||
104, 105, 106, 107, 108, 109, 110, 47, 19, 121, 119, 5, 6, 8, 10, 12,
|
||||
14, 16, 17, 18, 7, 98, 23, 68, 69, 70, 71, 91, 92, 93, 125, 112,
|
||||
113, 114, 94, 50, 0, 0, 124, 9, 11, 0, 0, 0, 0, 0, 0, 0,
|
||||
90, 0, 46, 22, 13, 111, 52, 20, 96, 24, 28, 74, 27, 123, 44, 66,
|
||||
0, 45, 2, 4, 48, 0, 0, 21, 0, 0, 0, 0, 0, 120, 122, 67,
|
||||
static const uint8_t qcode_to_keycode[Q_KEY_CODE_MAX] = {
|
||||
[Q_KEY_CODE_SHIFT] = 99,
|
||||
[Q_KEY_CODE_SHIFT_R] = 110,
|
||||
[Q_KEY_CODE_ALT] = 19,
|
||||
[Q_KEY_CODE_ALT_R] = 13,
|
||||
[Q_KEY_CODE_ALTGR] = 13,
|
||||
[Q_KEY_CODE_CTRL] = 76,
|
||||
[Q_KEY_CODE_CTRL_R] = 76,
|
||||
[Q_KEY_CODE_ESC] = 29,
|
||||
[Q_KEY_CODE_1] = 30,
|
||||
[Q_KEY_CODE_2] = 31,
|
||||
[Q_KEY_CODE_3] = 32,
|
||||
[Q_KEY_CODE_4] = 33,
|
||||
[Q_KEY_CODE_5] = 34,
|
||||
[Q_KEY_CODE_6] = 35,
|
||||
[Q_KEY_CODE_7] = 36,
|
||||
[Q_KEY_CODE_8] = 37,
|
||||
[Q_KEY_CODE_9] = 38,
|
||||
[Q_KEY_CODE_0] = 39,
|
||||
[Q_KEY_CODE_MINUS] = 40,
|
||||
[Q_KEY_CODE_EQUAL] = 41,
|
||||
[Q_KEY_CODE_BACKSPACE] = 43,
|
||||
[Q_KEY_CODE_TAB] = 53,
|
||||
[Q_KEY_CODE_Q] = 54,
|
||||
[Q_KEY_CODE_W] = 55,
|
||||
[Q_KEY_CODE_E] = 56,
|
||||
[Q_KEY_CODE_R] = 57,
|
||||
[Q_KEY_CODE_T] = 58,
|
||||
[Q_KEY_CODE_Y] = 59,
|
||||
[Q_KEY_CODE_U] = 60,
|
||||
[Q_KEY_CODE_I] = 61,
|
||||
[Q_KEY_CODE_O] = 62,
|
||||
[Q_KEY_CODE_P] = 63,
|
||||
[Q_KEY_CODE_BRACKET_LEFT] = 64,
|
||||
[Q_KEY_CODE_BRACKET_RIGHT] = 65,
|
||||
[Q_KEY_CODE_RET] = 89,
|
||||
[Q_KEY_CODE_A] = 77,
|
||||
[Q_KEY_CODE_S] = 78,
|
||||
[Q_KEY_CODE_D] = 79,
|
||||
[Q_KEY_CODE_F] = 80,
|
||||
[Q_KEY_CODE_G] = 81,
|
||||
[Q_KEY_CODE_H] = 82,
|
||||
[Q_KEY_CODE_J] = 83,
|
||||
[Q_KEY_CODE_K] = 84,
|
||||
[Q_KEY_CODE_L] = 85,
|
||||
[Q_KEY_CODE_SEMICOLON] = 86,
|
||||
[Q_KEY_CODE_APOSTROPHE] = 87,
|
||||
[Q_KEY_CODE_GRAVE_ACCENT] = 42,
|
||||
[Q_KEY_CODE_BACKSLASH] = 88,
|
||||
[Q_KEY_CODE_Z] = 100,
|
||||
[Q_KEY_CODE_X] = 101,
|
||||
[Q_KEY_CODE_C] = 102,
|
||||
[Q_KEY_CODE_V] = 103,
|
||||
[Q_KEY_CODE_B] = 104,
|
||||
[Q_KEY_CODE_N] = 105,
|
||||
[Q_KEY_CODE_M] = 106,
|
||||
[Q_KEY_CODE_COMMA] = 107,
|
||||
[Q_KEY_CODE_DOT] = 108,
|
||||
[Q_KEY_CODE_SLASH] = 109,
|
||||
[Q_KEY_CODE_ASTERISK] = 47,
|
||||
[Q_KEY_CODE_SPC] = 121,
|
||||
[Q_KEY_CODE_CAPS_LOCK] = 119,
|
||||
[Q_KEY_CODE_F1] = 5,
|
||||
[Q_KEY_CODE_F2] = 6,
|
||||
[Q_KEY_CODE_F3] = 8,
|
||||
[Q_KEY_CODE_F4] = 10,
|
||||
[Q_KEY_CODE_F5] = 12,
|
||||
[Q_KEY_CODE_F6] = 14,
|
||||
[Q_KEY_CODE_F7] = 16,
|
||||
[Q_KEY_CODE_F8] = 17,
|
||||
[Q_KEY_CODE_F9] = 18,
|
||||
[Q_KEY_CODE_F10] = 7,
|
||||
[Q_KEY_CODE_NUM_LOCK] = 98,
|
||||
[Q_KEY_CODE_SCROLL_LOCK] = 23,
|
||||
[Q_KEY_CODE_KP_DIVIDE] = 46,
|
||||
[Q_KEY_CODE_KP_MULTIPLY] = 47,
|
||||
[Q_KEY_CODE_KP_SUBTRACT] = 71,
|
||||
[Q_KEY_CODE_KP_ADD] = 125,
|
||||
[Q_KEY_CODE_KP_ENTER] = 90,
|
||||
[Q_KEY_CODE_KP_DECIMAL] = 50,
|
||||
[Q_KEY_CODE_KP_0] = 94,
|
||||
[Q_KEY_CODE_KP_1] = 112,
|
||||
[Q_KEY_CODE_KP_2] = 113,
|
||||
[Q_KEY_CODE_KP_3] = 114,
|
||||
[Q_KEY_CODE_KP_4] = 91,
|
||||
[Q_KEY_CODE_KP_5] = 92,
|
||||
[Q_KEY_CODE_KP_6] = 93,
|
||||
[Q_KEY_CODE_KP_7] = 68,
|
||||
[Q_KEY_CODE_KP_8] = 69,
|
||||
[Q_KEY_CODE_KP_9] = 70,
|
||||
[Q_KEY_CODE_LESS] = 124,
|
||||
[Q_KEY_CODE_F11] = 9,
|
||||
[Q_KEY_CODE_F12] = 11,
|
||||
[Q_KEY_CODE_HOME] = 52,
|
||||
[Q_KEY_CODE_PGUP] = 96,
|
||||
[Q_KEY_CODE_PGDN] = 123,
|
||||
[Q_KEY_CODE_END] = 74,
|
||||
[Q_KEY_CODE_LEFT] = 24,
|
||||
[Q_KEY_CODE_UP] = 20,
|
||||
[Q_KEY_CODE_DOWN] = 27,
|
||||
[Q_KEY_CODE_RIGHT] = 28,
|
||||
[Q_KEY_CODE_INSERT] = 44,
|
||||
[Q_KEY_CODE_DELETE] = 66,
|
||||
[Q_KEY_CODE_STOP] = 1,
|
||||
[Q_KEY_CODE_AGAIN] = 3,
|
||||
[Q_KEY_CODE_PROPS] = 25,
|
||||
[Q_KEY_CODE_UNDO] = 26,
|
||||
[Q_KEY_CODE_FRONT] = 49,
|
||||
[Q_KEY_CODE_COPY] = 51,
|
||||
[Q_KEY_CODE_OPEN] = 72,
|
||||
[Q_KEY_CODE_PASTE] = 73,
|
||||
[Q_KEY_CODE_FIND] = 95,
|
||||
[Q_KEY_CODE_CUT] = 97,
|
||||
[Q_KEY_CODE_LF] = 111,
|
||||
[Q_KEY_CODE_HELP] = 118,
|
||||
[Q_KEY_CODE_META_L] = 120,
|
||||
[Q_KEY_CODE_META_R] = 122,
|
||||
[Q_KEY_CODE_COMPOSE] = 67,
|
||||
[Q_KEY_CODE_PRINT] = 22,
|
||||
[Q_KEY_CODE_SYSRQ] = 21,
|
||||
};
|
||||
|
||||
static const uint8_t e0_keycodes[128] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 76, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 109, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 68, 69, 70, 0, 91, 0, 93, 0, 112,
|
||||
113, 114, 94, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 3, 25, 26, 49, 52, 72, 73, 97, 99, 111, 118, 120, 122, 67, 0,
|
||||
};
|
||||
|
||||
static void sunkbd_event(void *opaque, int ch)
|
||||
static void sunkbd_handle_event(DeviceState *dev, QemuConsole *src,
|
||||
InputEvent *evt)
|
||||
{
|
||||
ChannelState *s = opaque;
|
||||
int release = ch & 0x80;
|
||||
ChannelState *s = (ChannelState *)dev;
|
||||
int qcode, keycode;
|
||||
|
||||
trace_escc_sunkbd_event_in(ch);
|
||||
switch (ch) {
|
||||
case 58: // Caps lock press
|
||||
s->caps_lock_mode ^= 1;
|
||||
if (s->caps_lock_mode == 2)
|
||||
return; // Drop second press
|
||||
break;
|
||||
case 69: // Num lock press
|
||||
s->num_lock_mode ^= 1;
|
||||
if (s->num_lock_mode == 2)
|
||||
return; // Drop second press
|
||||
break;
|
||||
case 186: // Caps lock release
|
||||
s->caps_lock_mode ^= 2;
|
||||
if (s->caps_lock_mode == 3)
|
||||
return; // Drop first release
|
||||
break;
|
||||
case 197: // Num lock release
|
||||
s->num_lock_mode ^= 2;
|
||||
if (s->num_lock_mode == 3)
|
||||
return; // Drop first release
|
||||
break;
|
||||
case 0xe0:
|
||||
s->e0_mode = 1;
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
assert(evt->kind == INPUT_EVENT_KIND_KEY);
|
||||
qcode = qemu_input_key_value_to_qcode(evt->key->key);
|
||||
trace_escc_sunkbd_event_in(qcode, QKeyCode_lookup[qcode],
|
||||
evt->key->down);
|
||||
|
||||
if (qcode == Q_KEY_CODE_CAPS_LOCK) {
|
||||
if (evt->key->down) {
|
||||
s->caps_lock_mode ^= 1;
|
||||
if (s->caps_lock_mode == 2) {
|
||||
return; /* Drop second press */
|
||||
}
|
||||
} else {
|
||||
s->caps_lock_mode ^= 2;
|
||||
if (s->caps_lock_mode == 3) {
|
||||
return; /* Drop first release */
|
||||
}
|
||||
}
|
||||
}
|
||||
if (s->e0_mode) {
|
||||
s->e0_mode = 0;
|
||||
ch = e0_keycodes[ch & 0x7f];
|
||||
} else {
|
||||
ch = keycodes[ch & 0x7f];
|
||||
|
||||
if (qcode == Q_KEY_CODE_NUM_LOCK) {
|
||||
if (evt->key->down) {
|
||||
s->num_lock_mode ^= 1;
|
||||
if (s->num_lock_mode == 2) {
|
||||
return; /* Drop second press */
|
||||
}
|
||||
} else {
|
||||
s->num_lock_mode ^= 2;
|
||||
if (s->num_lock_mode == 3) {
|
||||
return; /* Drop first release */
|
||||
}
|
||||
}
|
||||
}
|
||||
trace_escc_sunkbd_event_out(ch);
|
||||
put_queue(s, ch | release);
|
||||
|
||||
keycode = qcode_to_keycode[qcode];
|
||||
if (!evt->key->down) {
|
||||
keycode |= 0x80;
|
||||
}
|
||||
trace_escc_sunkbd_event_out(keycode);
|
||||
put_queue(s, keycode);
|
||||
}
|
||||
|
||||
static QemuInputHandler sunkbd_handler = {
|
||||
.name = "sun keyboard",
|
||||
.mask = INPUT_EVENT_MASK_KEY,
|
||||
.event = sunkbd_handle_event,
|
||||
};
|
||||
|
||||
static void handle_kbd_command(ChannelState *s, int val)
|
||||
{
|
||||
trace_escc_kbd_command(val);
|
||||
@@ -800,7 +912,7 @@ static void handle_kbd_command(ChannelState *s, int val)
|
||||
case 0xf:
|
||||
clear_queue(s);
|
||||
put_queue(s, 0xfe);
|
||||
put_queue(s, 0); // XXX, layout?
|
||||
put_queue(s, 0x21); /* en-us layout */
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -898,7 +1010,8 @@ static int escc_init1(SysBusDevice *dev)
|
||||
"QEMU Sun Mouse");
|
||||
}
|
||||
if (s->chn[1].type == kbd) {
|
||||
qemu_add_kbd_event_handler(sunkbd_event, &s->chn[1]);
|
||||
s->chn[1].hs = qemu_input_handler_register((DeviceState *)(&s->chn[1]),
|
||||
&sunkbd_handler);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@@ -560,7 +560,6 @@ static const VMStateDescription vmstate_exynos4210_uart_fifo = {
|
||||
.name = "exynos4210.uart.fifo",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(sp, Exynos4210UartFIFO),
|
||||
VMSTATE_UINT32(rp, Exynos4210UartFIFO),
|
||||
@@ -573,7 +572,6 @@ static const VMStateDescription vmstate_exynos4210_uart = {
|
||||
.name = "exynos4210.uart",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_STRUCT(rx, Exynos4210UartState, 1,
|
||||
vmstate_exynos4210_uart_fifo, Exynos4210UartFIFO),
|
||||
|
@@ -76,7 +76,6 @@ static const VMStateDescription vmstate_imx_serial = {
|
||||
.name = "imx-serial",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_INT32(readbuff, IMXSerialState),
|
||||
VMSTATE_UINT32(usr1, IMXSerialState),
|
||||
|
@@ -124,8 +124,7 @@ static const VMStateDescription vmstate_scc2698_channel = {
|
||||
.name = "scc2698_channel",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_BOOL(rx_enabled, SCC2698Channel),
|
||||
VMSTATE_UINT8_ARRAY(mr, SCC2698Channel, 2),
|
||||
VMSTATE_UINT8(mr_idx, SCC2698Channel),
|
||||
@@ -141,8 +140,7 @@ static const VMStateDescription vmstate_scc2698_block = {
|
||||
.name = "scc2698_block",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT8(imr, SCC2698Block),
|
||||
VMSTATE_UINT8(isr, SCC2698Block),
|
||||
VMSTATE_END_OF_LIST()
|
||||
@@ -153,8 +151,7 @@ static const VMStateDescription vmstate_ipoctal = {
|
||||
.name = "ipoctal232",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_IPACK_DEVICE(parent_obj, IPOctalState),
|
||||
VMSTATE_STRUCT_ARRAY(ch, IPOctalState, N_CHANNELS, 1,
|
||||
vmstate_scc2698_channel, SCC2698Channel),
|
||||
|
@@ -129,8 +129,7 @@ static const VMStateDescription vmstate_lm32_juart = {
|
||||
.name = "lm32-juart",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(jtx, LM32JuartState),
|
||||
VMSTATE_UINT32(jrx, LM32JuartState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
|
@@ -270,8 +270,7 @@ static const VMStateDescription vmstate_lm32_uart = {
|
||||
.name = "lm32-uart",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(regs, LM32UartState, R_MAX),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
|
@@ -221,8 +221,7 @@ static const VMStateDescription vmstate_milkymist_uart = {
|
||||
.name = "milkymist-uart",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(regs, MilkymistUartState, R_MAX),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
|
@@ -251,8 +251,7 @@ static const VMStateDescription vmstate_pl011 = {
|
||||
.name = "pl011",
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 2,
|
||||
.minimum_version_id_old = 2,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(readbuff, PL011State),
|
||||
VMSTATE_UINT32(flags, PL011State),
|
||||
VMSTATE_UINT32(lcr, PL011State),
|
||||
|
@@ -291,8 +291,7 @@ static const VMStateDescription vmstate_sclplmconsole = {
|
||||
.name = "sclplmconsole",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.minimum_version_id_old = 0,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_BOOL(event.event_pending, SCLPConsoleLM),
|
||||
VMSTATE_UINT32(write_errors, SCLPConsoleLM),
|
||||
VMSTATE_UINT32(length, SCLPConsoleLM),
|
||||
|
@@ -185,8 +185,7 @@ static const VMStateDescription vmstate_sclpconsole = {
|
||||
.name = "sclpconsole",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.minimum_version_id_old = 0,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_BOOL(event.event_pending, SCLPConsole),
|
||||
VMSTATE_UINT8_ARRAY(iov, SCLPConsole, SIZE_BUFFER_VT220),
|
||||
VMSTATE_UINT32(iov_sclp, SCLPConsole),
|
||||
|
@@ -206,8 +206,7 @@ const VMStateDescription vmstate_ptimer = {
|
||||
.name = "ptimer",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT8(enabled, ptimer_state),
|
||||
VMSTATE_UINT64(limit, ptimer_state),
|
||||
VMSTATE_UINT64(delta, ptimer_state),
|
||||
|
@@ -121,9 +121,8 @@ static const VMStateDescription vmstate_ads7846 = {
|
||||
.name = "ads7846",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.post_load = ads7856_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_SSI_SLAVE(ssidev, ADS7846State),
|
||||
VMSTATE_INT32_ARRAY(input, ADS7846State, 8),
|
||||
VMSTATE_INT32(noise, ADS7846State),
|
||||
|
@@ -324,7 +324,7 @@ static const VMStateDescription vmstate_cg3 = {
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.post_load = vmstate_cg3_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT16(height, CG3State),
|
||||
VMSTATE_UINT16(width, CG3State),
|
||||
VMSTATE_UINT16(depth, CG3State),
|
||||
|
@@ -1845,7 +1845,7 @@ static const VMStateDescription exynos4210_fimd_window_vmstate = {
|
||||
.name = "exynos4210.fimd_window",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(wincon, Exynos4210fimdWindow),
|
||||
VMSTATE_UINT32_ARRAY(buf_start, Exynos4210fimdWindow, 3),
|
||||
VMSTATE_UINT32_ARRAY(buf_end, Exynos4210fimdWindow, 3),
|
||||
@@ -1875,7 +1875,7 @@ static const VMStateDescription exynos4210_fimd_vmstate = {
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.post_load = exynos4210_fimd_load,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(vidcon, Exynos4210fimdState, 4),
|
||||
VMSTATE_UINT32_ARRAY(vidtcon, Exynos4210fimdState, 4),
|
||||
VMSTATE_UINT32(shadowcon, Exynos4210fimdState),
|
||||
|
@@ -459,7 +459,6 @@ static const VMStateDescription vmstate_g364fb = {
|
||||
.name = "g364fb",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.post_load = g364fb_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_VBUFFER_UINT32(vram, G364State, 1, NULL, 0, vram_size),
|
||||
|
@@ -250,7 +250,6 @@ static const VMStateDescription vmstate_jazz_led = {
|
||||
.name = "jazz-led",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.minimum_version_id_old = 0,
|
||||
.post_load = jazz_led_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT8(segments, LedState),
|
||||
|
@@ -463,8 +463,7 @@ static const VMStateDescription vmstate_milkymist_tmu2 = {
|
||||
.name = "milkymist-tmu2",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(regs, MilkymistTMU2State, R_MAX),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
|
@@ -305,9 +305,8 @@ static const VMStateDescription vmstate_milkymist_vgafb = {
|
||||
.name = "milkymist-vgafb",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.post_load = vgafb_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(regs, MilkymistVgafbState, R_MAX),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
|
@@ -932,8 +932,7 @@ static const VMStateDescription vmstate_dma_channel = {
|
||||
.name = "dma_channel",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.minimum_version_id_old = 0,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(branch, struct DMAChannel),
|
||||
VMSTATE_UINT8(up, struct DMAChannel),
|
||||
VMSTATE_BUFFER(pbuffer, struct DMAChannel),
|
||||
@@ -959,9 +958,8 @@ static const VMStateDescription vmstate_pxa2xx_lcdc = {
|
||||
.name = "pxa2xx_lcdc",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.minimum_version_id_old = 0,
|
||||
.post_load = pxa2xx_lcdc_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_INT32(irqlevel, PXA2xxLCDState),
|
||||
VMSTATE_INT32(transp, PXA2xxLCDState),
|
||||
VMSTATE_UINT32_ARRAY(control, PXA2xxLCDState, 6),
|
||||
|
@@ -272,8 +272,7 @@ static const VMStateDescription vmstate_ssd0303 = {
|
||||
.name = "ssd0303_oled",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField []) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_INT32(row, ssd0303_state),
|
||||
VMSTATE_INT32(col, ssd0303_state),
|
||||
VMSTATE_INT32(start_line, ssd0303_state),
|
||||
|
@@ -416,9 +416,8 @@ static const VMStateDescription vmstate_tcx = {
|
||||
.name ="tcx",
|
||||
.version_id = 4,
|
||||
.minimum_version_id = 4,
|
||||
.minimum_version_id_old = 4,
|
||||
.post_load = vmstate_tcx_post_load,
|
||||
.fields = (VMStateField []) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT16(height, TCXState),
|
||||
VMSTATE_UINT16(width, TCXState),
|
||||
VMSTATE_UINT16(depth, TCXState),
|
||||
|
@@ -973,7 +973,7 @@ static int omap_dma_ch_reg_write(struct omap_dma_s *s,
|
||||
|
||||
case 0x22: /* DMA_COLOR_U */
|
||||
ch->color &= 0xffff;
|
||||
ch->color |= value << 16;
|
||||
ch->color |= (uint32_t)value << 16;
|
||||
break;
|
||||
|
||||
case 0x24: /* DMA_CCR2 */
|
||||
@@ -1043,7 +1043,7 @@ static int omap_dma_3_2_lcd_write(struct omap_dma_lcd_channel_s *s, int offset,
|
||||
|
||||
case 0xbca: /* TOP_B1_U */
|
||||
s->src_f1_top &= 0x0000ffff;
|
||||
s->src_f1_top |= value << 16;
|
||||
s->src_f1_top |= (uint32_t)value << 16;
|
||||
break;
|
||||
|
||||
case 0xbcc: /* BOT_B1_L */
|
||||
@@ -1265,7 +1265,7 @@ static int omap_dma_3_1_lcd_write(struct omap_dma_lcd_channel_s *s, int offset,
|
||||
|
||||
case 0x304: /* SYS_DMA_LCD_TOP_F1_U */
|
||||
s->src_f1_top &= 0x0000ffff;
|
||||
s->src_f1_top |= value << 16;
|
||||
s->src_f1_top |= (uint32_t)value << 16;
|
||||
break;
|
||||
|
||||
case 0x306: /* SYS_DMA_LCD_BOT_F1_L */
|
||||
@@ -1275,7 +1275,7 @@ static int omap_dma_3_1_lcd_write(struct omap_dma_lcd_channel_s *s, int offset,
|
||||
|
||||
case 0x308: /* SYS_DMA_LCD_BOT_F1_U */
|
||||
s->src_f1_bottom &= 0x0000ffff;
|
||||
s->src_f1_bottom |= value << 16;
|
||||
s->src_f1_bottom |= (uint32_t)value << 16;
|
||||
break;
|
||||
|
||||
case 0x30a: /* SYS_DMA_LCD_TOP_F2_L */
|
||||
@@ -1285,7 +1285,7 @@ static int omap_dma_3_1_lcd_write(struct omap_dma_lcd_channel_s *s, int offset,
|
||||
|
||||
case 0x30c: /* SYS_DMA_LCD_TOP_F2_U */
|
||||
s->src_f2_top &= 0x0000ffff;
|
||||
s->src_f2_top |= value << 16;
|
||||
s->src_f2_top |= (uint32_t)value << 16;
|
||||
break;
|
||||
|
||||
case 0x30e: /* SYS_DMA_LCD_BOT_F2_L */
|
||||
@@ -1295,7 +1295,7 @@ static int omap_dma_3_1_lcd_write(struct omap_dma_lcd_channel_s *s, int offset,
|
||||
|
||||
case 0x310: /* SYS_DMA_LCD_BOT_F2_U */
|
||||
s->src_f2_bottom &= 0x0000ffff;
|
||||
s->src_f2_bottom |= value << 16;
|
||||
s->src_f2_bottom |= (uint32_t)value << 16;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@@ -138,7 +138,6 @@ static const VMStateDescription vmstate_pl330_chan = {
|
||||
.name = "pl330_chan",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(src, PL330Chan),
|
||||
VMSTATE_UINT32(dst, PL330Chan),
|
||||
@@ -170,7 +169,6 @@ static const VMStateDescription vmstate_pl330_fifo = {
|
||||
.name = "pl330_chan",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_VBUFFER_UINT32(buf, PL330Fifo, 1, NULL, 0, buf_size),
|
||||
VMSTATE_VBUFFER_UINT32(tag, PL330Fifo, 1, NULL, 0, buf_size),
|
||||
@@ -195,7 +193,6 @@ static const VMStateDescription vmstate_pl330_queue_entry = {
|
||||
.name = "pl330_queue_entry",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(addr, PL330QueueEntry),
|
||||
VMSTATE_UINT32(len, PL330QueueEntry),
|
||||
@@ -218,7 +215,6 @@ static const VMStateDescription vmstate_pl330_queue = {
|
||||
.name = "pl330_queue",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_STRUCT_VARRAY_UINT32(queue, PL330Queue, queue_size, 1,
|
||||
vmstate_pl330_queue_entry, PL330QueueEntry),
|
||||
@@ -279,7 +275,6 @@ static const VMStateDescription vmstate_pl330 = {
|
||||
.name = "pl330",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_STRUCT(manager, PL330State, 0, vmstate_pl330_chan, PL330Chan),
|
||||
VMSTATE_STRUCT_VARRAY_UINT32(chan, PL330State, num_chnls, 0,
|
||||
|
@@ -514,7 +514,6 @@ static VMStateDescription vmstate_pxa2xx_dma_chan = {
|
||||
.name = "pxa2xx_dma_chan",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(descr, PXA2xxDMAChannel),
|
||||
VMSTATE_UINT32(src, PXA2xxDMAChannel),
|
||||
@@ -530,7 +529,6 @@ static VMStateDescription vmstate_pxa2xx_dma = {
|
||||
.name = "pxa2xx_dma",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 0,
|
||||
.minimum_version_id_old = 0,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UNUSED_TEST(is_version_0, 4),
|
||||
VMSTATE_UINT32(stopintr, PXA2xxDMAState),
|
||||
|
@@ -263,8 +263,7 @@ static const VMStateDescription vmstate_dma = {
|
||||
.name ="sparc32_dma",
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 2,
|
||||
.minimum_version_id_old = 2,
|
||||
.fields = (VMStateField []) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(dmaregs, DMAState, DMA_REGS),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
|
@@ -327,8 +327,7 @@ static const VMStateDescription vmstate_iommu = {
|
||||
.name ="iommu",
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 2,
|
||||
.minimum_version_id_old = 2,
|
||||
.fields = (VMStateField []) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(regs, IOMMUState, IOMMU_NREGS),
|
||||
VMSTATE_UINT64(iostart, IOMMUState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
|
@@ -152,8 +152,7 @@ static const VMStateDescription vmstate_max7310 = {
|
||||
.name = "max7310",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.minimum_version_id_old = 0,
|
||||
.fields = (VMStateField []) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_INT32(i2c_command_byte, MAX7310State),
|
||||
VMSTATE_INT32(len, MAX7310State),
|
||||
VMSTATE_UINT8(level, MAX7310State),
|
||||
|
@@ -216,9 +216,8 @@ static const VMStateDescription vmstate_scoop_regs = {
|
||||
.name = "scoop",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 0,
|
||||
.minimum_version_id_old = 0,
|
||||
.post_load = scoop_post_load,
|
||||
.fields = (VMStateField []) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT16(status, ScoopInfo),
|
||||
VMSTATE_UINT16(power, ScoopInfo),
|
||||
VMSTATE_UINT32(gpio_level, ScoopInfo),
|
||||
|
@@ -52,10 +52,9 @@ static const VMStateDescription vmstate_i2c_bus = {
|
||||
.name = "i2c_bus",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.pre_save = i2c_bus_pre_save,
|
||||
.post_load = i2c_bus_post_load,
|
||||
.fields = (VMStateField []) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT8(saved_address, I2CBus),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
@@ -194,9 +193,8 @@ const VMStateDescription vmstate_i2c_slave = {
|
||||
.name = "I2CSlave",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.post_load = i2c_slave_post_load,
|
||||
.fields = (VMStateField []) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT8(address, I2CSlave),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
|
@@ -48,7 +48,6 @@ static const VMStateDescription vmstate_ich9_smbus = {
|
||||
.name = "ich9_smb",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_PCI_DEVICE(dev, struct ICH9SMBState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
|
@@ -1300,6 +1300,7 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev, Error **errp)
|
||||
if (pos != 0 && kvm_device_msix_supported(kvm_state)) {
|
||||
int bar_nr;
|
||||
uint32_t msix_table_entry;
|
||||
uint16_t msix_max;
|
||||
|
||||
verify_irqchip_in_kernel(&local_err);
|
||||
if (local_err) {
|
||||
@@ -1315,9 +1316,10 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev, Error **errp)
|
||||
}
|
||||
pci_dev->msix_cap = pos;
|
||||
|
||||
pci_set_word(pci_dev->config + pos + PCI_MSIX_FLAGS,
|
||||
pci_get_word(pci_dev->config + pos + PCI_MSIX_FLAGS) &
|
||||
PCI_MSIX_FLAGS_QSIZE);
|
||||
msix_max = (pci_get_word(pci_dev->config + pos + PCI_MSIX_FLAGS) &
|
||||
PCI_MSIX_FLAGS_QSIZE) + 1;
|
||||
msix_max = MIN(msix_max, KVM_MAX_MSIX_PER_DEV);
|
||||
pci_set_word(pci_dev->config + pos + PCI_MSIX_FLAGS, msix_max - 1);
|
||||
|
||||
/* Only enable and function mask bits are writable */
|
||||
pci_set_word(pci_dev->wmask + pos + PCI_MSIX_FLAGS,
|
||||
@@ -1327,9 +1329,7 @@ static int assigned_device_pci_cap_init(PCIDevice *pci_dev, Error **errp)
|
||||
bar_nr = msix_table_entry & PCI_MSIX_FLAGS_BIRMASK;
|
||||
msix_table_entry &= ~PCI_MSIX_FLAGS_BIRMASK;
|
||||
dev->msix_table_addr = pci_region[bar_nr].base_addr + msix_table_entry;
|
||||
dev->msix_max = pci_get_word(pci_dev->config + pos + PCI_MSIX_FLAGS);
|
||||
dev->msix_max &= PCI_MSIX_FLAGS_QSIZE;
|
||||
dev->msix_max += 1;
|
||||
dev->msix_max = msix_max;
|
||||
}
|
||||
|
||||
/* Minimal PM support, nothing writable, device appears to NAK changes */
|
||||
@@ -1664,6 +1664,7 @@ static void assigned_dev_register_msix_mmio(AssignedDevice *dev, Error **errp)
|
||||
MAP_ANONYMOUS|MAP_PRIVATE, 0, 0);
|
||||
if (dev->msix_table == MAP_FAILED) {
|
||||
error_setg_errno(errp, errno, "failed to allocate msix_table");
|
||||
dev->msix_table = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -471,11 +471,12 @@ static void port92_write(void *opaque, hwaddr addr, uint64_t val,
|
||||
unsigned size)
|
||||
{
|
||||
Port92State *s = opaque;
|
||||
int oldval = s->outport;
|
||||
|
||||
DPRINTF("port92: write 0x%02x\n", val);
|
||||
s->outport = val;
|
||||
qemu_set_irq(*s->a20_out, (val >> 1) & 1);
|
||||
if (val & 1) {
|
||||
if ((val & 1) && !(oldval & 1)) {
|
||||
qemu_system_reset_request();
|
||||
}
|
||||
}
|
||||
|
@@ -2342,8 +2342,7 @@ static const VMStateDescription vmstate_ide_atapi_gesn_state = {
|
||||
.name ="ide_drive/atapi/gesn_state",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField []) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_BOOL(events.new_media, IDEState),
|
||||
VMSTATE_BOOL(events.eject_request, IDEState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
@@ -2354,7 +2353,6 @@ static const VMStateDescription vmstate_ide_tray_state = {
|
||||
.name = "ide_drive/tray_state",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_BOOL(tray_open, IDEState),
|
||||
VMSTATE_BOOL(tray_locked, IDEState),
|
||||
@@ -2366,10 +2364,9 @@ static const VMStateDescription vmstate_ide_drive_pio_state = {
|
||||
.name = "ide_drive/pio_state",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.pre_save = ide_drive_pio_pre_save,
|
||||
.post_load = ide_drive_pio_post_load,
|
||||
.fields = (VMStateField []) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_INT32(req_nb_sectors, IDEState),
|
||||
VMSTATE_VARRAY_INT32(io_buffer, IDEState, io_buffer_total_len, 1,
|
||||
vmstate_info_uint8, uint8_t),
|
||||
@@ -2386,9 +2383,8 @@ const VMStateDescription vmstate_ide_drive = {
|
||||
.name = "ide_drive",
|
||||
.version_id = 3,
|
||||
.minimum_version_id = 0,
|
||||
.minimum_version_id_old = 0,
|
||||
.post_load = ide_drive_post_load,
|
||||
.fields = (VMStateField []) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_INT32(mult_sectors, IDEState),
|
||||
VMSTATE_INT32(identify_set, IDEState),
|
||||
VMSTATE_BUFFER_TEST(identify_data, IDEState, is_identify_set),
|
||||
@@ -2431,8 +2427,7 @@ static const VMStateDescription vmstate_ide_error_status = {
|
||||
.name ="ide_bus/error",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField []) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_INT32(error_status, IDEBus),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
@@ -2442,8 +2437,7 @@ const VMStateDescription vmstate_ide_bus = {
|
||||
.name = "ide_bus",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField []) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT8(cmd, IDEBus),
|
||||
VMSTATE_UINT8(unit, IDEBus),
|
||||
VMSTATE_END_OF_LIST()
|
||||
|
@@ -480,8 +480,7 @@ static const VMStateDescription vmstate_pmac = {
|
||||
.name = "ide",
|
||||
.version_id = 3,
|
||||
.minimum_version_id = 0,
|
||||
.minimum_version_id_old = 0,
|
||||
.fields = (VMStateField []) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_IDE_BUS(bus, MACIOIDEState),
|
||||
VMSTATE_IDE_DRIVES(bus.ifs, MACIOIDEState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
|
@@ -332,8 +332,7 @@ static const VMStateDescription vmstate_microdrive = {
|
||||
.name = "microdrive",
|
||||
.version_id = 3,
|
||||
.minimum_version_id = 0,
|
||||
.minimum_version_id_old = 0,
|
||||
.fields = (VMStateField []) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT8(opt, MicroDriveState),
|
||||
VMSTATE_UINT8(stat, MicroDriveState),
|
||||
VMSTATE_UINT8(pins, MicroDriveState),
|
||||
|
@@ -109,8 +109,7 @@ static const VMStateDescription vmstate_ide_mmio = {
|
||||
.name = "mmio-ide",
|
||||
.version_id = 3,
|
||||
.minimum_version_id = 0,
|
||||
.minimum_version_id_old = 0,
|
||||
.fields = (VMStateField []) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_IDE_BUS(bus, MMIOState),
|
||||
VMSTATE_IDE_DRIVES(bus.ifs, MMIOState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
|
@@ -303,8 +303,7 @@ static const VMStateDescription vmstate_adb_kbd = {
|
||||
.name = "adb_kbd",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_BUFFER(data, KBDState),
|
||||
VMSTATE_INT32(rptr, KBDState),
|
||||
VMSTATE_INT32(wptr, KBDState),
|
||||
@@ -518,8 +517,7 @@ static const VMStateDescription vmstate_adb_mouse = {
|
||||
.name = "adb_mouse",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_INT32(buttons_state, MouseState),
|
||||
VMSTATE_INT32(last_buttons_state, MouseState),
|
||||
VMSTATE_INT32(dx, MouseState),
|
||||
|
222
hw/input/hid.c
222
hw/input/hid.c
@@ -105,70 +105,135 @@ void hid_set_next_idle(HIDState *hs)
|
||||
}
|
||||
}
|
||||
|
||||
static void hid_pointer_event_clear(HIDPointerEvent *e, int buttons)
|
||||
static void hid_pointer_event(DeviceState *dev, QemuConsole *src,
|
||||
InputEvent *evt)
|
||||
{
|
||||
e->xdx = e->ydy = e->dz = 0;
|
||||
e->buttons_state = buttons;
|
||||
static const int bmap[INPUT_BUTTON_MAX] = {
|
||||
[INPUT_BUTTON_LEFT] = 0x01,
|
||||
[INPUT_BUTTON_RIGHT] = 0x02,
|
||||
[INPUT_BUTTON_MIDDLE] = 0x04,
|
||||
};
|
||||
HIDState *hs = (HIDState *)dev;
|
||||
HIDPointerEvent *e;
|
||||
|
||||
assert(hs->n < QUEUE_LENGTH);
|
||||
e = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK];
|
||||
|
||||
switch (evt->kind) {
|
||||
case INPUT_EVENT_KIND_REL:
|
||||
if (evt->rel->axis == INPUT_AXIS_X) {
|
||||
e->xdx += evt->rel->value;
|
||||
} else if (evt->rel->axis == INPUT_AXIS_Y) {
|
||||
e->ydy -= evt->rel->value;
|
||||
}
|
||||
break;
|
||||
|
||||
case INPUT_EVENT_KIND_ABS:
|
||||
if (evt->rel->axis == INPUT_AXIS_X) {
|
||||
e->xdx = evt->rel->value;
|
||||
} else if (evt->rel->axis == INPUT_AXIS_Y) {
|
||||
e->ydy = evt->rel->value;
|
||||
}
|
||||
break;
|
||||
|
||||
case INPUT_EVENT_KIND_BTN:
|
||||
if (evt->btn->down) {
|
||||
e->buttons_state |= bmap[evt->btn->button];
|
||||
if (evt->btn->button == INPUT_BUTTON_WHEEL_UP) {
|
||||
e->dz--;
|
||||
} else if (evt->btn->button == INPUT_BUTTON_WHEEL_DOWN) {
|
||||
e->dz++;
|
||||
}
|
||||
} else {
|
||||
e->buttons_state &= ~bmap[evt->btn->button];
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* keep gcc happy */
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void hid_pointer_event_combine(HIDPointerEvent *e, int xyrel,
|
||||
int x1, int y1, int z1) {
|
||||
if (xyrel) {
|
||||
e->xdx += x1;
|
||||
e->ydy += y1;
|
||||
} else {
|
||||
e->xdx = x1;
|
||||
e->ydy = y1;
|
||||
/* Windows drivers do not like the 0/0 position and ignore such
|
||||
* events. */
|
||||
if (!(x1 | y1)) {
|
||||
e->xdx = 1;
|
||||
static void hid_pointer_sync(DeviceState *dev)
|
||||
{
|
||||
HIDState *hs = (HIDState *)dev;
|
||||
HIDPointerEvent *prev, *curr, *next;
|
||||
bool event_compression = false;
|
||||
|
||||
if (hs->n == QUEUE_LENGTH-1) {
|
||||
/*
|
||||
* Queue full. We are loosing information, but we at least
|
||||
* keep track of most recent button state.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
prev = &hs->ptr.queue[(hs->head + hs->n - 1) & QUEUE_MASK];
|
||||
curr = &hs->ptr.queue[(hs->head + hs->n) & QUEUE_MASK];
|
||||
next = &hs->ptr.queue[(hs->head + hs->n + 1) & QUEUE_MASK];
|
||||
|
||||
if (hs->n > 0) {
|
||||
/*
|
||||
* No button state change between previous and current event
|
||||
* (and previous wasn't seen by the guest yet), so there is
|
||||
* motion information only and we can combine the two event
|
||||
* into one.
|
||||
*/
|
||||
if (curr->buttons_state == prev->buttons_state) {
|
||||
event_compression = true;
|
||||
}
|
||||
}
|
||||
e->dz += z1;
|
||||
}
|
||||
|
||||
static void hid_pointer_event(void *opaque,
|
||||
int x1, int y1, int z1, int buttons_state)
|
||||
{
|
||||
HIDState *hs = opaque;
|
||||
unsigned use_slot = (hs->head + hs->n - 1) & QUEUE_MASK;
|
||||
unsigned previous_slot = (use_slot - 1) & QUEUE_MASK;
|
||||
|
||||
/* We combine events where feasible to keep the queue small. We shouldn't
|
||||
* combine anything with the first event of a particular button state, as
|
||||
* that would change the location of the button state change. When the
|
||||
* queue is empty, a second event is needed because we don't know if
|
||||
* the first event changed the button state. */
|
||||
if (hs->n == QUEUE_LENGTH) {
|
||||
/* Queue full. Discard old button state, combine motion normally. */
|
||||
hs->ptr.queue[use_slot].buttons_state = buttons_state;
|
||||
} else if (hs->n < 2 ||
|
||||
hs->ptr.queue[use_slot].buttons_state != buttons_state ||
|
||||
hs->ptr.queue[previous_slot].buttons_state !=
|
||||
hs->ptr.queue[use_slot].buttons_state) {
|
||||
/* Cannot or should not combine, so add an empty item to the queue. */
|
||||
QUEUE_INCR(use_slot);
|
||||
if (event_compression) {
|
||||
/* add current motion to previous, clear current */
|
||||
if (hs->kind == HID_MOUSE) {
|
||||
prev->xdx += curr->xdx;
|
||||
curr->xdx = 0;
|
||||
prev->ydy -= curr->ydy;
|
||||
curr->ydy = 0;
|
||||
} else {
|
||||
prev->xdx = curr->xdx;
|
||||
prev->ydy = curr->ydy;
|
||||
}
|
||||
prev->dz += curr->dz;
|
||||
curr->dz = 0;
|
||||
} else {
|
||||
/* prepate next (clear rel, copy abs + btns) */
|
||||
if (hs->kind == HID_MOUSE) {
|
||||
next->xdx = 0;
|
||||
next->ydy = 0;
|
||||
} else {
|
||||
next->xdx = curr->xdx;
|
||||
next->ydy = curr->ydy;
|
||||
}
|
||||
next->dz = 0;
|
||||
next->buttons_state = curr->buttons_state;
|
||||
/* make current guest visible, notify guest */
|
||||
hs->n++;
|
||||
hid_pointer_event_clear(&hs->ptr.queue[use_slot], buttons_state);
|
||||
hs->event(hs);
|
||||
}
|
||||
hid_pointer_event_combine(&hs->ptr.queue[use_slot],
|
||||
hs->kind == HID_MOUSE,
|
||||
x1, y1, z1);
|
||||
hs->event(hs);
|
||||
}
|
||||
|
||||
static void hid_keyboard_event(void *opaque, int keycode)
|
||||
static void hid_keyboard_event(DeviceState *dev, QemuConsole *src,
|
||||
InputEvent *evt)
|
||||
{
|
||||
HIDState *hs = opaque;
|
||||
HIDState *hs = (HIDState *)dev;
|
||||
int scancodes[3], i, count;
|
||||
int slot;
|
||||
|
||||
if (hs->n == QUEUE_LENGTH) {
|
||||
count = qemu_input_key_value_to_scancode(evt->key->key,
|
||||
evt->key->down,
|
||||
scancodes);
|
||||
if (hs->n + count > QUEUE_LENGTH) {
|
||||
fprintf(stderr, "usb-kbd: warning: key event queue full\n");
|
||||
return;
|
||||
}
|
||||
slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++;
|
||||
hs->kbd.keycodes[slot] = keycode;
|
||||
for (i = 0; i < count; i++) {
|
||||
slot = (hs->head + hs->n) & QUEUE_MASK; hs->n++;
|
||||
hs->kbd.keycodes[slot] = scancodes[i];
|
||||
}
|
||||
hs->event(hs);
|
||||
}
|
||||
|
||||
@@ -247,14 +312,14 @@ static inline int int_clamp(int val, int vmin, int vmax)
|
||||
void hid_pointer_activate(HIDState *hs)
|
||||
{
|
||||
if (!hs->ptr.mouse_grabbed) {
|
||||
qemu_activate_mouse_event_handler(hs->ptr.eh_entry);
|
||||
qemu_input_handler_activate(hs->s);
|
||||
hs->ptr.mouse_grabbed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
|
||||
{
|
||||
int dx, dy, dz, b, l;
|
||||
int dx, dy, dz, l;
|
||||
int index;
|
||||
HIDPointerEvent *e;
|
||||
|
||||
@@ -279,17 +344,6 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
|
||||
dz = int_clamp(e->dz, -127, 127);
|
||||
e->dz -= dz;
|
||||
|
||||
b = 0;
|
||||
if (e->buttons_state & MOUSE_EVENT_LBUTTON) {
|
||||
b |= 0x01;
|
||||
}
|
||||
if (e->buttons_state & MOUSE_EVENT_RBUTTON) {
|
||||
b |= 0x02;
|
||||
}
|
||||
if (e->buttons_state & MOUSE_EVENT_MBUTTON) {
|
||||
b |= 0x04;
|
||||
}
|
||||
|
||||
if (hs->n &&
|
||||
!e->dz &&
|
||||
(hs->kind == HID_TABLET || (!e->xdx && !e->ydy))) {
|
||||
@@ -304,7 +358,7 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
|
||||
switch (hs->kind) {
|
||||
case HID_MOUSE:
|
||||
if (len > l) {
|
||||
buf[l++] = b;
|
||||
buf[l++] = e->buttons_state;
|
||||
}
|
||||
if (len > l) {
|
||||
buf[l++] = dx;
|
||||
@@ -319,7 +373,7 @@ int hid_pointer_poll(HIDState *hs, uint8_t *buf, int len)
|
||||
|
||||
case HID_TABLET:
|
||||
if (len > l) {
|
||||
buf[l++] = b;
|
||||
buf[l++] = e->buttons_state;
|
||||
}
|
||||
if (len > l) {
|
||||
buf[l++] = dx & 0xff;
|
||||
@@ -413,31 +467,45 @@ void hid_reset(HIDState *hs)
|
||||
|
||||
void hid_free(HIDState *hs)
|
||||
{
|
||||
switch (hs->kind) {
|
||||
case HID_KEYBOARD:
|
||||
qemu_remove_kbd_event_handler(hs->kbd.eh_entry);
|
||||
break;
|
||||
case HID_MOUSE:
|
||||
case HID_TABLET:
|
||||
qemu_remove_mouse_event_handler(hs->ptr.eh_entry);
|
||||
break;
|
||||
}
|
||||
qemu_input_handler_unregister(hs->s);
|
||||
hid_del_idle_timer(hs);
|
||||
}
|
||||
|
||||
static QemuInputHandler hid_keyboard_handler = {
|
||||
.name = "QEMU HID Keyboard",
|
||||
.mask = INPUT_EVENT_MASK_KEY,
|
||||
.event = hid_keyboard_event,
|
||||
};
|
||||
|
||||
static QemuInputHandler hid_mouse_handler = {
|
||||
.name = "QEMU HID Mouse",
|
||||
.mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
|
||||
.event = hid_pointer_event,
|
||||
.sync = hid_pointer_sync,
|
||||
};
|
||||
|
||||
static QemuInputHandler hid_tablet_handler = {
|
||||
.name = "QEMU HID Tablet",
|
||||
.mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS,
|
||||
.event = hid_pointer_event,
|
||||
.sync = hid_pointer_sync,
|
||||
};
|
||||
|
||||
void hid_init(HIDState *hs, int kind, HIDEventFunc event)
|
||||
{
|
||||
hs->kind = kind;
|
||||
hs->event = event;
|
||||
|
||||
if (hs->kind == HID_KEYBOARD) {
|
||||
hs->kbd.eh_entry = qemu_add_kbd_event_handler(hid_keyboard_event, hs);
|
||||
hs->s = qemu_input_handler_register((DeviceState *)hs,
|
||||
&hid_keyboard_handler);
|
||||
qemu_input_handler_activate(hs->s);
|
||||
} else if (hs->kind == HID_MOUSE) {
|
||||
hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs,
|
||||
0, "QEMU HID Mouse");
|
||||
hs->s = qemu_input_handler_register((DeviceState *)hs,
|
||||
&hid_mouse_handler);
|
||||
} else if (hs->kind == HID_TABLET) {
|
||||
hs->ptr.eh_entry = qemu_add_mouse_event_handler(hid_pointer_event, hs,
|
||||
1, "QEMU HID Tablet");
|
||||
hs->s = qemu_input_handler_register((DeviceState *)hs,
|
||||
&hid_tablet_handler);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -432,9 +432,8 @@ static const VMStateDescription vmstate_lm_kbd = {
|
||||
.name = "LM8323",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.minimum_version_id_old = 0,
|
||||
.post_load = lm_kbd_post_load,
|
||||
.fields = (VMStateField []) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_I2C_SLAVE(parent_obj, LM823KbdState),
|
||||
VMSTATE_UINT8(i2c_dir, LM823KbdState),
|
||||
VMSTATE_UINT8(i2c_cycle, LM823KbdState),
|
||||
|
@@ -295,8 +295,7 @@ static const VMStateDescription vmstate_milkymist_softusb = {
|
||||
.name = "milkymist-softusb",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(regs, MilkymistSoftUsbState, R_MAX),
|
||||
VMSTATE_HID_KEYBOARD_DEVICE(hid_kbd, MilkymistSoftUsbState),
|
||||
VMSTATE_HID_POINTER_DEVICE(hid_mouse, MilkymistSoftUsbState),
|
||||
|
166
hw/input/ps2.c
166
hw/input/ps2.c
@@ -24,6 +24,7 @@
|
||||
#include "hw/hw.h"
|
||||
#include "hw/input/ps2.h"
|
||||
#include "ui/console.h"
|
||||
#include "ui/input.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
|
||||
/* debug PC keyboard */
|
||||
@@ -71,10 +72,12 @@
|
||||
#define MOUSE_STATUS_ENABLED 0x20
|
||||
#define MOUSE_STATUS_SCALE21 0x10
|
||||
|
||||
#define PS2_QUEUE_SIZE 256
|
||||
#define PS2_QUEUE_SIZE 16 /* Buffer size required by PS/2 protocol */
|
||||
|
||||
typedef struct {
|
||||
uint8_t data[PS2_QUEUE_SIZE];
|
||||
/* Keep the data array 256 bytes long, which compatibility
|
||||
with older qemu versions. */
|
||||
uint8_t data[256];
|
||||
int rptr, wptr, count;
|
||||
} PS2Queue;
|
||||
|
||||
@@ -137,7 +140,7 @@ void ps2_queue(void *opaque, int b)
|
||||
PS2State *s = (PS2State *)opaque;
|
||||
PS2Queue *q = &s->queue;
|
||||
|
||||
if (q->count >= PS2_QUEUE_SIZE)
|
||||
if (q->count >= PS2_QUEUE_SIZE - 1)
|
||||
return;
|
||||
q->data[q->wptr] = b;
|
||||
if (++q->wptr == PS2_QUEUE_SIZE)
|
||||
@@ -170,6 +173,21 @@ static void ps2_put_keycode(void *opaque, int keycode)
|
||||
ps2_queue(&s->common, keycode);
|
||||
}
|
||||
|
||||
static void ps2_keyboard_event(DeviceState *dev, QemuConsole *src,
|
||||
InputEvent *evt)
|
||||
{
|
||||
PS2KbdState *s = (PS2KbdState *)dev;
|
||||
int scancodes[3], i, count;
|
||||
|
||||
qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
|
||||
count = qemu_input_key_value_to_scancode(evt->key->key,
|
||||
evt->key->down,
|
||||
scancodes);
|
||||
for (i = 0; i < count; i++) {
|
||||
ps2_put_keycode(s, scancodes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ps2_read_data(void *opaque)
|
||||
{
|
||||
PS2State *s = (PS2State *)opaque;
|
||||
@@ -352,31 +370,57 @@ static void ps2_mouse_send_packet(PS2MouseState *s)
|
||||
s->mouse_dz -= dz1;
|
||||
}
|
||||
|
||||
static void ps2_mouse_event(void *opaque,
|
||||
int dx, int dy, int dz, int buttons_state)
|
||||
static void ps2_mouse_event(DeviceState *dev, QemuConsole *src,
|
||||
InputEvent *evt)
|
||||
{
|
||||
PS2MouseState *s = opaque;
|
||||
static const int bmap[INPUT_BUTTON_MAX] = {
|
||||
[INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON,
|
||||
[INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON,
|
||||
[INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON,
|
||||
};
|
||||
PS2MouseState *s = (PS2MouseState *)dev;
|
||||
|
||||
/* check if deltas are recorded when disabled */
|
||||
if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
|
||||
return;
|
||||
|
||||
s->mouse_dx += dx;
|
||||
s->mouse_dy -= dy;
|
||||
s->mouse_dz += dz;
|
||||
/* XXX: SDL sometimes generates nul events: we delete them */
|
||||
if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 &&
|
||||
s->mouse_buttons == buttons_state)
|
||||
return;
|
||||
s->mouse_buttons = buttons_state;
|
||||
switch (evt->kind) {
|
||||
case INPUT_EVENT_KIND_REL:
|
||||
if (evt->rel->axis == INPUT_AXIS_X) {
|
||||
s->mouse_dx += evt->rel->value;
|
||||
} else if (evt->rel->axis == INPUT_AXIS_Y) {
|
||||
s->mouse_dy -= evt->rel->value;
|
||||
}
|
||||
break;
|
||||
|
||||
if (buttons_state) {
|
||||
case INPUT_EVENT_KIND_BTN:
|
||||
if (evt->btn->down) {
|
||||
s->mouse_buttons |= bmap[evt->btn->button];
|
||||
if (evt->btn->button == INPUT_BUTTON_WHEEL_UP) {
|
||||
s->mouse_dz--;
|
||||
} else if (evt->btn->button == INPUT_BUTTON_WHEEL_DOWN) {
|
||||
s->mouse_dz++;
|
||||
}
|
||||
} else {
|
||||
s->mouse_buttons &= ~bmap[evt->btn->button];
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* keep gcc happy */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void ps2_mouse_sync(DeviceState *dev)
|
||||
{
|
||||
PS2MouseState *s = (PS2MouseState *)dev;
|
||||
|
||||
if (s->mouse_buttons) {
|
||||
qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
|
||||
}
|
||||
|
||||
if (!(s->mouse_status & MOUSE_STATUS_REMOTE) &&
|
||||
(s->common.queue.count < (PS2_QUEUE_SIZE - 16))) {
|
||||
for(;;) {
|
||||
if (!(s->mouse_status & MOUSE_STATUS_REMOTE)) {
|
||||
while (s->common.queue.count < PS2_QUEUE_SIZE - 4) {
|
||||
/* if not remote, send event. Multiple events are sent if
|
||||
too big deltas */
|
||||
ps2_mouse_send_packet(s);
|
||||
@@ -388,7 +432,9 @@ static void ps2_mouse_event(void *opaque,
|
||||
|
||||
void ps2_mouse_fake_event(void *opaque)
|
||||
{
|
||||
ps2_mouse_event(opaque, 1, 0, 0, 0);
|
||||
PS2MouseState *s = opaque;
|
||||
s->mouse_dx++;
|
||||
ps2_mouse_sync(opaque);
|
||||
}
|
||||
|
||||
void ps2_write_mouse(void *opaque, int val)
|
||||
@@ -528,6 +574,34 @@ static void ps2_common_reset(PS2State *s)
|
||||
s->update_irq(s->update_arg, 0);
|
||||
}
|
||||
|
||||
static void ps2_common_post_load(PS2State *s)
|
||||
{
|
||||
PS2Queue *q = &s->queue;
|
||||
int size;
|
||||
int i;
|
||||
int tmp_data[PS2_QUEUE_SIZE];
|
||||
|
||||
/* set the useful data buffer queue size, < PS2_QUEUE_SIZE */
|
||||
size = q->count > PS2_QUEUE_SIZE ? 0 : q->count;
|
||||
|
||||
/* move the queue elements to the start of data array */
|
||||
if (size > 0) {
|
||||
for (i = 0; i < size; i++) {
|
||||
/* move the queue elements to the temporary buffer */
|
||||
tmp_data[i] = q->data[q->rptr];
|
||||
if (++q->rptr == 256) {
|
||||
q->rptr = 0;
|
||||
}
|
||||
}
|
||||
memcpy(q->data, tmp_data, size);
|
||||
}
|
||||
/* reset rptr/wptr/count */
|
||||
q->rptr = 0;
|
||||
q->wptr = size;
|
||||
q->count = size;
|
||||
s->update_irq(s->update_arg, q->count != 0);
|
||||
}
|
||||
|
||||
static void ps2_kbd_reset(void *opaque)
|
||||
{
|
||||
PS2KbdState *s = (PS2KbdState *) opaque;
|
||||
@@ -600,18 +674,31 @@ static const VMStateDescription vmstate_ps2_keyboard_ledstate = {
|
||||
static int ps2_kbd_post_load(void* opaque, int version_id)
|
||||
{
|
||||
PS2KbdState *s = (PS2KbdState*)opaque;
|
||||
PS2State *ps2 = &s->common;
|
||||
|
||||
if (version_id == 2)
|
||||
s->scancode_set=2;
|
||||
|
||||
ps2_common_post_load(ps2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ps2_kbd_pre_save(void *opaque)
|
||||
{
|
||||
PS2KbdState *s = (PS2KbdState *)opaque;
|
||||
PS2State *ps2 = &s->common;
|
||||
|
||||
ps2_common_post_load(ps2);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_ps2_keyboard = {
|
||||
.name = "ps2kbd",
|
||||
.version_id = 3,
|
||||
.minimum_version_id = 2,
|
||||
.minimum_version_id_old = 2,
|
||||
.post_load = ps2_kbd_post_load,
|
||||
.pre_save = ps2_kbd_pre_save,
|
||||
.fields = (VMStateField []) {
|
||||
VMSTATE_STRUCT(common, PS2KbdState, 0, vmstate_ps2_common, PS2State),
|
||||
VMSTATE_INT32(scan_enabled, PS2KbdState),
|
||||
@@ -629,11 +716,31 @@ static const VMStateDescription vmstate_ps2_keyboard = {
|
||||
}
|
||||
};
|
||||
|
||||
static int ps2_mouse_post_load(void *opaque, int version_id)
|
||||
{
|
||||
PS2MouseState *s = (PS2MouseState *)opaque;
|
||||
PS2State *ps2 = &s->common;
|
||||
|
||||
ps2_common_post_load(ps2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ps2_mouse_pre_save(void *opaque)
|
||||
{
|
||||
PS2MouseState *s = (PS2MouseState *)opaque;
|
||||
PS2State *ps2 = &s->common;
|
||||
|
||||
ps2_common_post_load(ps2);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_ps2_mouse = {
|
||||
.name = "ps2mouse",
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 2,
|
||||
.minimum_version_id_old = 2,
|
||||
.post_load = ps2_mouse_post_load,
|
||||
.pre_save = ps2_mouse_pre_save,
|
||||
.fields = (VMStateField []) {
|
||||
VMSTATE_STRUCT(common, PS2MouseState, 0, vmstate_ps2_common, PS2State),
|
||||
VMSTATE_UINT8(mouse_status, PS2MouseState),
|
||||
@@ -650,6 +757,12 @@ static const VMStateDescription vmstate_ps2_mouse = {
|
||||
}
|
||||
};
|
||||
|
||||
static QemuInputHandler ps2_keyboard_handler = {
|
||||
.name = "QEMU PS/2 Keyboard",
|
||||
.mask = INPUT_EVENT_MASK_KEY,
|
||||
.event = ps2_keyboard_event,
|
||||
};
|
||||
|
||||
void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg)
|
||||
{
|
||||
PS2KbdState *s = (PS2KbdState *)g_malloc0(sizeof(PS2KbdState));
|
||||
@@ -658,11 +771,19 @@ void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg)
|
||||
s->common.update_arg = update_arg;
|
||||
s->scancode_set = 2;
|
||||
vmstate_register(NULL, 0, &vmstate_ps2_keyboard, s);
|
||||
qemu_add_kbd_event_handler(ps2_put_keycode, s);
|
||||
qemu_input_handler_register((DeviceState *)s,
|
||||
&ps2_keyboard_handler);
|
||||
qemu_register_reset(ps2_kbd_reset, s);
|
||||
return s;
|
||||
}
|
||||
|
||||
static QemuInputHandler ps2_mouse_handler = {
|
||||
.name = "QEMU PS/2 Mouse",
|
||||
.mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_REL,
|
||||
.event = ps2_mouse_event,
|
||||
.sync = ps2_mouse_sync,
|
||||
};
|
||||
|
||||
void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg)
|
||||
{
|
||||
PS2MouseState *s = (PS2MouseState *)g_malloc0(sizeof(PS2MouseState));
|
||||
@@ -670,7 +791,8 @@ void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg)
|
||||
s->common.update_irq = update_irq;
|
||||
s->common.update_arg = update_arg;
|
||||
vmstate_register(NULL, 0, &vmstate_ps2_mouse, s);
|
||||
qemu_add_mouse_event_handler(ps2_mouse_event, s, 0, "QEMU PS/2 Mouse");
|
||||
qemu_input_handler_register((DeviceState *)s,
|
||||
&ps2_mouse_handler);
|
||||
qemu_register_reset(ps2_mouse_reset, s);
|
||||
return s;
|
||||
}
|
||||
|
@@ -291,8 +291,7 @@ static const VMStateDescription vmstate_pxa2xx_keypad = {
|
||||
.name = "pxa2xx_keypad",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.minimum_version_id_old = 0,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(kpc, PXA2xxKeyPadState),
|
||||
VMSTATE_UINT32(kpdk, PXA2xxKeyPadState),
|
||||
VMSTATE_UINT32(kprec, PXA2xxKeyPadState),
|
||||
|
@@ -51,8 +51,7 @@ static const VMStateDescription vmstate_stellaris_button = {
|
||||
.name = "stellaris_button",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.minimum_version_id_old = 0,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT8(pressed, gamepad_button),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
@@ -62,8 +61,7 @@ static const VMStateDescription vmstate_stellaris_gamepad = {
|
||||
.name = "stellaris_gamepad",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_INT32(extension, gamepad_state),
|
||||
VMSTATE_STRUCT_VARRAY_INT32(buttons, gamepad_state, num_buttons, 0,
|
||||
vmstate_stellaris_button, gamepad_button),
|
||||
|
@@ -26,3 +26,4 @@ obj-$(CONFIG_XICS) += xics.o
|
||||
obj-$(CONFIG_XICS_KVM) += xics_kvm.o
|
||||
obj-$(CONFIG_ALLWINNER_A10_PIC) += allwinner-a10-pic.o
|
||||
obj-$(CONFIG_S390_FLIC) += s390_flic.o
|
||||
obj-$(CONFIG_S390_FLIC_KVM) += s390_flic_kvm.o
|
||||
|
@@ -97,6 +97,7 @@ static void aw_a10_pic_write(void *opaque, hwaddr offset, uint64_t value,
|
||||
switch (offset) {
|
||||
case AW_A10_PIC_BASE_ADDR:
|
||||
s->base_addr = value & ~0x3;
|
||||
break;
|
||||
case AW_A10_PIC_PROTECT:
|
||||
s->protect = value;
|
||||
break;
|
||||
@@ -141,7 +142,6 @@ static const VMStateDescription vmstate_aw_a10_pic = {
|
||||
.name = "a10.pic",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.minimum_version_id_old = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(vector, AwA10PICState),
|
||||
VMSTATE_UINT32(base_addr, AwA10PICState),
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user