Compare commits
79 Commits
pull-gtk-6
...
pull-smbio
Author | SHA1 | Date | |
---|---|---|---|
|
c97294ec1b | ||
|
2e6e8d7a25 | ||
|
cb36acb672 | ||
|
e41fca3da7 | ||
|
e6667f719c | ||
|
7bf8ef196e | ||
|
3458b2b075 | ||
|
fdaad4715a | ||
|
e50bf23438 | ||
|
c090c10dc4 | ||
|
87f6ede9bb | ||
|
f42c5c8ec8 | ||
|
3078e848fa | ||
|
6420474384 | ||
|
37f0806ed9 | ||
|
6ab9f49934 | ||
|
1b505f93bc | ||
|
fed3ffb9f1 | ||
|
252ec40576 | ||
|
e3da9921eb | ||
|
3b77157964 | ||
|
051b9980b9 | ||
|
52b08670e2 | ||
|
61e5b75c17 | ||
|
b7079df410 | ||
|
1f2cead324 | ||
|
838ef60249 | ||
|
b69cdef876 | ||
|
e466183718 | ||
|
38bbc0a580 | ||
|
9e550b3260 | ||
|
f6246509be | ||
|
0549ea8b6d | ||
|
e1b42f456f | ||
|
b93f995081 | ||
|
a49139af77 | ||
|
521b2b5df0 | ||
|
91f827dcff | ||
|
48add816cf | ||
|
e080f0fdff | ||
|
40f1ee27aa | ||
|
35d0d40a03 | ||
|
f1f25a2e2e | ||
|
7e3d98dd31 | ||
|
8bfea15dda | ||
|
5669b44de5 | ||
|
317fc44ef2 | ||
|
0b50cc8853 | ||
|
cffb12051a | ||
|
c883db0df9 | ||
|
cc8a7e560c | ||
|
c557527455 | ||
|
b006f8162e | ||
|
c3cc95bd15 | ||
|
373df5b135 | ||
|
e855e4fb7b | ||
|
3f2fde2a00 | ||
|
8b15d9f1d2 | ||
|
4843877e5d | ||
|
5f6979cba9 | ||
|
ebd0c614d7 | ||
|
035b239826 | ||
|
35e2da1556 | ||
|
b357f902bf | ||
|
98b90bab3f | ||
|
425532d71d | ||
|
f4c166619e | ||
|
8b66eefe0d | ||
|
34b1a49cb1 | ||
|
a24fba935a | ||
|
9f44adc573 | ||
|
4bb7a41ed6 | ||
|
71b926992e | ||
|
f0e9736012 | ||
|
7db1689c35 | ||
|
a889bc2bb2 | ||
|
0850fd583f | ||
|
63e3e24db2 | ||
|
e2bbfc8ee2 |
106
block.c
106
block.c
@@ -774,6 +774,45 @@ void bdrv_disable_copy_on_read(BlockDriverState *bs)
|
||||
bs->copy_on_read--;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the flags that bs->file should get, based on the given flags for
|
||||
* the parent BDS
|
||||
*/
|
||||
static int bdrv_inherited_flags(int flags)
|
||||
{
|
||||
/* Enable protocol handling, disable format probing for bs->file */
|
||||
flags |= BDRV_O_PROTOCOL;
|
||||
|
||||
/* Our block drivers take care to send flushes and respect unmap policy,
|
||||
* so we can enable both unconditionally on lower layers. */
|
||||
flags |= BDRV_O_CACHE_WB | BDRV_O_UNMAP;
|
||||
|
||||
/* The backing file of a temporary snapshot is read-only */
|
||||
if (flags & BDRV_O_SNAPSHOT) {
|
||||
flags &= ~BDRV_O_RDWR;
|
||||
}
|
||||
|
||||
/* Clear flags that only apply to the top layer */
|
||||
flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | BDRV_O_COPY_ON_READ);
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the flags that bs->backing_hd should get, based on the given flags
|
||||
* for the parent BDS
|
||||
*/
|
||||
static int bdrv_backing_flags(int flags)
|
||||
{
|
||||
/* backing files always opened read-only */
|
||||
flags &= ~(BDRV_O_RDWR | BDRV_O_COPY_ON_READ);
|
||||
|
||||
/* snapshot=on is handled on the top layer */
|
||||
flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_TEMPORARY);
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static int bdrv_open_flags(BlockDriverState *bs, int flags)
|
||||
{
|
||||
int open_flags = flags | BDRV_O_CACHE_WB;
|
||||
@@ -792,7 +831,7 @@ static int bdrv_open_flags(BlockDriverState *bs, int flags)
|
||||
/*
|
||||
* Snapshots should be writable.
|
||||
*/
|
||||
if (bs->is_temporary) {
|
||||
if (flags & BDRV_O_TEMPORARY) {
|
||||
open_flags |= BDRV_O_RDWR;
|
||||
}
|
||||
|
||||
@@ -951,13 +990,6 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
|
||||
bdrv_refresh_limits(bs);
|
||||
assert(bdrv_opt_mem_align(bs) != 0);
|
||||
assert((bs->request_alignment != 0) || bs->sg);
|
||||
|
||||
#ifndef _WIN32
|
||||
if (bs->is_temporary) {
|
||||
assert(bs->filename[0] != '\0');
|
||||
unlink(bs->filename);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
free_and_fail:
|
||||
@@ -1069,7 +1101,7 @@ fail:
|
||||
int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
|
||||
{
|
||||
char *backing_filename = g_malloc0(PATH_MAX);
|
||||
int back_flags, ret = 0;
|
||||
int ret = 0;
|
||||
BlockDriver *back_drv = NULL;
|
||||
Error *local_err = NULL;
|
||||
|
||||
@@ -1097,14 +1129,10 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
|
||||
back_drv = bdrv_find_format(bs->backing_format);
|
||||
}
|
||||
|
||||
/* backing files always opened read-only */
|
||||
back_flags = bs->open_flags & ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT |
|
||||
BDRV_O_COPY_ON_READ);
|
||||
|
||||
assert(bs->backing_hd == NULL);
|
||||
ret = bdrv_open(&bs->backing_hd,
|
||||
*backing_filename ? backing_filename : NULL, NULL, options,
|
||||
back_flags, back_drv, &local_err);
|
||||
bdrv_backing_flags(bs->open_flags), back_drv, &local_err);
|
||||
if (ret < 0) {
|
||||
bs->backing_hd = NULL;
|
||||
bs->open_flags |= BDRV_O_NO_BACKING;
|
||||
@@ -1232,10 +1260,10 @@ void bdrv_append_temp_snapshot(BlockDriverState *bs, Error **errp)
|
||||
qstring_from_str(tmp_filename));
|
||||
|
||||
bs_snapshot = bdrv_new("", &error_abort);
|
||||
bs_snapshot->is_temporary = 1;
|
||||
|
||||
ret = bdrv_open(&bs_snapshot, NULL, NULL, snapshot_options,
|
||||
bs->open_flags & ~BDRV_O_SNAPSHOT, bdrv_qcow2, &local_err);
|
||||
(bs->open_flags & ~BDRV_O_SNAPSHOT) | BDRV_O_TEMPORARY,
|
||||
bdrv_qcow2, &local_err);
|
||||
if (ret < 0) {
|
||||
error_propagate(errp, local_err);
|
||||
goto out;
|
||||
@@ -1333,10 +1361,10 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
|
||||
|
||||
assert(file == NULL);
|
||||
ret = bdrv_open_image(&file, filename, options, "file",
|
||||
bdrv_open_flags(bs, flags | BDRV_O_UNMAP) |
|
||||
BDRV_O_PROTOCOL, true, &local_err);
|
||||
bdrv_inherited_flags(flags),
|
||||
true, &local_err);
|
||||
if (ret < 0) {
|
||||
goto unlink_and_fail;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Find the right image format driver */
|
||||
@@ -1347,7 +1375,7 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
|
||||
if (!drv) {
|
||||
error_setg(errp, "Invalid driver: '%s'", drvname);
|
||||
ret = -EINVAL;
|
||||
goto unlink_and_fail;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1357,18 +1385,18 @@ int bdrv_open(BlockDriverState **pbs, const char *filename,
|
||||
} else {
|
||||
error_setg(errp, "Must specify either driver or file");
|
||||
ret = -EINVAL;
|
||||
goto unlink_and_fail;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (!drv) {
|
||||
goto unlink_and_fail;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Open the image */
|
||||
ret = bdrv_open_common(bs, file, options, flags, drv, &local_err);
|
||||
if (ret < 0) {
|
||||
goto unlink_and_fail;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (file && (bs->file != file)) {
|
||||
@@ -1430,14 +1458,10 @@ done:
|
||||
*pbs = bs;
|
||||
return 0;
|
||||
|
||||
unlink_and_fail:
|
||||
fail:
|
||||
if (file != NULL) {
|
||||
bdrv_unref(file);
|
||||
}
|
||||
if (bs->is_temporary) {
|
||||
unlink(filename);
|
||||
}
|
||||
fail:
|
||||
QDECREF(bs->options);
|
||||
QDECREF(options);
|
||||
bs->options = NULL;
|
||||
@@ -1501,8 +1525,11 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
|
||||
QSIMPLEQ_INIT(bs_queue);
|
||||
}
|
||||
|
||||
/* bdrv_open() masks this flag out */
|
||||
flags &= ~BDRV_O_PROTOCOL;
|
||||
|
||||
if (bs->file) {
|
||||
bdrv_reopen_queue(bs_queue, bs->file, flags);
|
||||
bdrv_reopen_queue(bs_queue, bs->file, bdrv_inherited_flags(flags));
|
||||
}
|
||||
|
||||
bs_entry = g_new0(BlockReopenQueueEntry, 1);
|
||||
@@ -1717,11 +1744,6 @@ void bdrv_close(BlockDriverState *bs)
|
||||
}
|
||||
bs->drv->bdrv_close(bs);
|
||||
g_free(bs->opaque);
|
||||
#ifdef _WIN32
|
||||
if (bs->is_temporary) {
|
||||
unlink(bs->filename);
|
||||
}
|
||||
#endif
|
||||
bs->opaque = NULL;
|
||||
bs->drv = NULL;
|
||||
bs->copy_on_read = 0;
|
||||
@@ -1845,7 +1867,6 @@ static void bdrv_move_feature_fields(BlockDriverState *bs_dest,
|
||||
BlockDriverState *bs_src)
|
||||
{
|
||||
/* move some fields that need to stay attached to the device */
|
||||
bs_dest->open_flags = bs_src->open_flags;
|
||||
|
||||
/* dev info */
|
||||
bs_dest->dev_ops = bs_src->dev_ops;
|
||||
@@ -3601,11 +3622,26 @@ void bdrv_iterate_format(void (*it)(void *opaque, const char *name),
|
||||
void *opaque)
|
||||
{
|
||||
BlockDriver *drv;
|
||||
int count = 0;
|
||||
const char **formats = NULL;
|
||||
|
||||
QLIST_FOREACH(drv, &bdrv_drivers, list) {
|
||||
if (drv->format_name) {
|
||||
bool found = false;
|
||||
int i = count;
|
||||
while (formats && i && !found) {
|
||||
found = !strcmp(formats[--i], drv->format_name);
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
formats = g_realloc(formats, (count + 1) * sizeof(char *));
|
||||
formats[count++] = drv->format_name;
|
||||
it(opaque, drv->format_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
g_free(formats);
|
||||
}
|
||||
|
||||
/* This function is to find block backend bs */
|
||||
BlockDriverState *bdrv_find(const char *name)
|
||||
|
@@ -187,13 +187,14 @@ static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
|
||||
uint64_t offset = sector_num * 512;
|
||||
uint64_t extent_index, extent_offset, bitmap_offset;
|
||||
char bitmap_entry;
|
||||
int ret;
|
||||
|
||||
// seek to sector
|
||||
extent_index = offset / s->extent_size;
|
||||
extent_offset = (offset % s->extent_size) / 512;
|
||||
|
||||
if (s->catalog_bitmap[extent_index] == 0xffffffff) {
|
||||
return -1; /* not allocated */
|
||||
return 0; /* not allocated */
|
||||
}
|
||||
|
||||
bitmap_offset = s->data_offset +
|
||||
@@ -201,13 +202,14 @@ static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
|
||||
(s->extent_blocks + s->bitmap_blocks));
|
||||
|
||||
/* read in bitmap for current extent */
|
||||
if (bdrv_pread(bs->file, bitmap_offset + (extent_offset / 8),
|
||||
&bitmap_entry, 1) != 1) {
|
||||
return -1;
|
||||
ret = bdrv_pread(bs->file, bitmap_offset + (extent_offset / 8),
|
||||
&bitmap_entry, 1);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!((bitmap_entry >> (extent_offset % 8)) & 1)) {
|
||||
return -1; /* not allocated */
|
||||
return 0; /* not allocated */
|
||||
}
|
||||
|
||||
return bitmap_offset + (512 * (s->bitmap_blocks + extent_offset));
|
||||
@@ -220,13 +222,16 @@ static int bochs_read(BlockDriverState *bs, int64_t sector_num,
|
||||
|
||||
while (nb_sectors > 0) {
|
||||
int64_t block_offset = seek_to_sector(bs, sector_num);
|
||||
if (block_offset >= 0) {
|
||||
if (block_offset < 0) {
|
||||
return block_offset;
|
||||
} else if (block_offset > 0) {
|
||||
ret = bdrv_pread(bs->file, block_offset, buf, 512);
|
||||
if (ret != 512) {
|
||||
return -1;
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
memset(buf, 0, 512);
|
||||
}
|
||||
nb_sectors--;
|
||||
sector_num++;
|
||||
buf += 512;
|
||||
|
@@ -82,7 +82,7 @@ static int cow_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
if (be32_to_cpu(cow_header.version) != COW_VERSION) {
|
||||
char version[64];
|
||||
snprintf(version, sizeof(version),
|
||||
"COW version %d", cow_header.version);
|
||||
"COW version %" PRIu32, cow_header.version);
|
||||
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
||||
bs->device_name, "cow", version);
|
||||
ret = -ENOTSUP;
|
||||
|
75
block/curl.c
75
block/curl.c
@@ -71,6 +71,7 @@ typedef struct CURLState
|
||||
struct BDRVCURLState *s;
|
||||
CURLAIOCB *acb[CURL_NUM_ACB];
|
||||
CURL *curl;
|
||||
curl_socket_t sock_fd;
|
||||
char *orig_buf;
|
||||
size_t buf_start;
|
||||
size_t buf_off;
|
||||
@@ -92,6 +93,7 @@ typedef struct BDRVCURLState {
|
||||
|
||||
static void curl_clean_state(CURLState *s);
|
||||
static void curl_multi_do(void *arg);
|
||||
static void curl_multi_read(void *arg);
|
||||
|
||||
#ifdef NEED_CURL_TIMER_CALLBACK
|
||||
static int curl_timer_cb(CURLM *multi, long timeout_ms, void *opaque)
|
||||
@@ -113,16 +115,20 @@ static int curl_timer_cb(CURLM *multi, long timeout_ms, void *opaque)
|
||||
static int curl_sock_cb(CURL *curl, curl_socket_t fd, int action,
|
||||
void *s, void *sp)
|
||||
{
|
||||
CURLState *state = NULL;
|
||||
curl_easy_getinfo(curl, CURLINFO_PRIVATE, (char **)&state);
|
||||
state->sock_fd = fd;
|
||||
|
||||
DPRINTF("CURL (AIO): Sock action %d on fd %d\n", action, fd);
|
||||
switch (action) {
|
||||
case CURL_POLL_IN:
|
||||
qemu_aio_set_fd_handler(fd, curl_multi_do, NULL, s);
|
||||
qemu_aio_set_fd_handler(fd, curl_multi_read, NULL, state);
|
||||
break;
|
||||
case CURL_POLL_OUT:
|
||||
qemu_aio_set_fd_handler(fd, NULL, curl_multi_do, s);
|
||||
qemu_aio_set_fd_handler(fd, NULL, curl_multi_do, state);
|
||||
break;
|
||||
case CURL_POLL_INOUT:
|
||||
qemu_aio_set_fd_handler(fd, curl_multi_do, curl_multi_do, s);
|
||||
qemu_aio_set_fd_handler(fd, curl_multi_read, curl_multi_do, state);
|
||||
break;
|
||||
case CURL_POLL_REMOVE:
|
||||
qemu_aio_set_fd_handler(fd, NULL, NULL, NULL);
|
||||
@@ -155,7 +161,7 @@ static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
|
||||
DPRINTF("CURL: Just reading %zd bytes\n", realsize);
|
||||
|
||||
if (!s || !s->orig_buf)
|
||||
goto read_end;
|
||||
return 0;
|
||||
|
||||
if (s->buf_off >= s->buf_len) {
|
||||
/* buffer full, read nothing */
|
||||
@@ -180,7 +186,6 @@ static size_t curl_read_cb(void *ptr, size_t size, size_t nmemb, void *opaque)
|
||||
}
|
||||
}
|
||||
|
||||
read_end:
|
||||
return realsize;
|
||||
}
|
||||
|
||||
@@ -215,7 +220,8 @@ static int curl_find_buf(BDRVCURLState *s, size_t start, size_t len,
|
||||
}
|
||||
|
||||
// Wait for unfinished chunks
|
||||
if ((start >= state->buf_start) &&
|
||||
if (state->in_use &&
|
||||
(start >= state->buf_start) &&
|
||||
(start <= buf_fend) &&
|
||||
(end >= state->buf_start) &&
|
||||
(end <= buf_fend))
|
||||
@@ -237,26 +243,24 @@ static int curl_find_buf(BDRVCURLState *s, size_t start, size_t len,
|
||||
return FIND_RET_NONE;
|
||||
}
|
||||
|
||||
static void curl_multi_read(BDRVCURLState *s)
|
||||
static void curl_multi_check_completion(BDRVCURLState *s)
|
||||
{
|
||||
int msgs_in_queue;
|
||||
|
||||
/* Try to find done transfers, so we can free the easy
|
||||
* handle again. */
|
||||
do {
|
||||
for (;;) {
|
||||
CURLMsg *msg;
|
||||
msg = curl_multi_info_read(s->multi, &msgs_in_queue);
|
||||
|
||||
/* Quit when there are no more completions */
|
||||
if (!msg)
|
||||
break;
|
||||
if (msg->msg == CURLMSG_NONE)
|
||||
break;
|
||||
|
||||
switch (msg->msg) {
|
||||
case CURLMSG_DONE:
|
||||
{
|
||||
if (msg->msg == CURLMSG_DONE) {
|
||||
CURLState *state = NULL;
|
||||
curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, (char**)&state);
|
||||
curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE,
|
||||
(char **)&state);
|
||||
|
||||
/* ACBs for successful messages get completed in curl_read_cb */
|
||||
if (msg->data.result != CURLE_OK) {
|
||||
@@ -277,28 +281,31 @@ static void curl_multi_read(BDRVCURLState *s)
|
||||
curl_clean_state(state);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
msgs_in_queue = 0;
|
||||
break;
|
||||
}
|
||||
} while(msgs_in_queue);
|
||||
}
|
||||
|
||||
static void curl_multi_do(void *arg)
|
||||
{
|
||||
BDRVCURLState *s = (BDRVCURLState *)arg;
|
||||
CURLState *s = (CURLState *)arg;
|
||||
int running;
|
||||
int r;
|
||||
|
||||
if (!s->multi) {
|
||||
if (!s->s->multi) {
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
r = curl_multi_socket_all(s->multi, &running);
|
||||
r = curl_multi_socket_action(s->s->multi, s->sock_fd, 0, &running);
|
||||
} while(r == CURLM_CALL_MULTI_PERFORM);
|
||||
|
||||
curl_multi_read(s);
|
||||
}
|
||||
|
||||
static void curl_multi_read(void *arg)
|
||||
{
|
||||
CURLState *s = (CURLState *)arg;
|
||||
|
||||
curl_multi_do(arg);
|
||||
curl_multi_check_completion(s->s);
|
||||
}
|
||||
|
||||
static void curl_multi_timeout_do(void *arg)
|
||||
@@ -313,7 +320,7 @@ static void curl_multi_timeout_do(void *arg)
|
||||
|
||||
curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running);
|
||||
|
||||
curl_multi_read(s);
|
||||
curl_multi_check_completion(s);
|
||||
#else
|
||||
abort();
|
||||
#endif
|
||||
@@ -337,20 +344,19 @@ static CURLState *curl_init_state(BDRVCURLState *s)
|
||||
break;
|
||||
}
|
||||
if (!state) {
|
||||
g_usleep(100);
|
||||
curl_multi_do(s);
|
||||
qemu_aio_wait();
|
||||
}
|
||||
} while(!state);
|
||||
|
||||
if (state->curl)
|
||||
goto has_curl;
|
||||
|
||||
if (!state->curl) {
|
||||
state->curl = curl_easy_init();
|
||||
if (!state->curl)
|
||||
if (!state->curl) {
|
||||
return NULL;
|
||||
}
|
||||
curl_easy_setopt(state->curl, CURLOPT_URL, s->url);
|
||||
curl_easy_setopt(state->curl, CURLOPT_TIMEOUT, 5);
|
||||
curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION, (void *)curl_read_cb);
|
||||
curl_easy_setopt(state->curl, CURLOPT_WRITEFUNCTION,
|
||||
(void *)curl_read_cb);
|
||||
curl_easy_setopt(state->curl, CURLOPT_WRITEDATA, (void *)state);
|
||||
curl_easy_setopt(state->curl, CURLOPT_PRIVATE, (void *)state);
|
||||
curl_easy_setopt(state->curl, CURLOPT_AUTOREFERER, 1);
|
||||
@@ -373,8 +379,7 @@ static CURLState *curl_init_state(BDRVCURLState *s)
|
||||
#ifdef DEBUG_VERBOSE
|
||||
curl_easy_setopt(state->curl, CURLOPT_VERBOSE, 1);
|
||||
#endif
|
||||
|
||||
has_curl:
|
||||
}
|
||||
|
||||
state->s = s;
|
||||
|
||||
@@ -531,13 +536,11 @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
// initialize the multi interface!
|
||||
|
||||
s->multi = curl_multi_init();
|
||||
curl_multi_setopt(s->multi, CURLMOPT_SOCKETDATA, s);
|
||||
curl_multi_setopt(s->multi, CURLMOPT_SOCKETFUNCTION, curl_sock_cb);
|
||||
#ifdef NEED_CURL_TIMER_CALLBACK
|
||||
curl_multi_setopt(s->multi, CURLMOPT_TIMERDATA, s);
|
||||
curl_multi_setopt(s->multi, CURLMOPT_TIMERFUNCTION, curl_timer_cb);
|
||||
#endif
|
||||
curl_multi_do(s);
|
||||
|
||||
qemu_opts_del(opts);
|
||||
return 0;
|
||||
@@ -566,6 +569,7 @@ static const AIOCBInfo curl_aiocb_info = {
|
||||
static void curl_readv_bh_cb(void *p)
|
||||
{
|
||||
CURLState *state;
|
||||
int running;
|
||||
|
||||
CURLAIOCB *acb = p;
|
||||
BDRVCURLState *s = acb->common.bs->opaque;
|
||||
@@ -614,8 +618,9 @@ static void curl_readv_bh_cb(void *p)
|
||||
curl_easy_setopt(state->curl, CURLOPT_RANGE, state->range);
|
||||
|
||||
curl_multi_add_handle(s->multi, state->curl);
|
||||
curl_multi_do(s);
|
||||
|
||||
/* Tell curl it needs to kick things off */
|
||||
curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running);
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *curl_aio_readv(BlockDriverState *bs,
|
||||
|
@@ -248,8 +248,8 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
offset += 8;
|
||||
|
||||
if (s->sectorcounts[i] > DMG_SECTORCOUNTS_MAX) {
|
||||
error_report("sector count %" PRIu64 " for chunk %u is "
|
||||
"larger than max (%u)",
|
||||
error_report("sector count %" PRIu64 " for chunk %" PRIu32
|
||||
" is larger than max (%u)",
|
||||
s->sectorcounts[i], i, DMG_SECTORCOUNTS_MAX);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
@@ -269,8 +269,8 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
offset += 8;
|
||||
|
||||
if (s->lengths[i] > DMG_LENGTHS_MAX) {
|
||||
error_report("length %" PRIu64 " for chunk %u is larger "
|
||||
"than max (%u)",
|
||||
error_report("length %" PRIu64 " for chunk %" PRIu32
|
||||
" is larger than max (%u)",
|
||||
s->lengths[i], i, DMG_LENGTHS_MAX);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
|
@@ -325,11 +325,11 @@ static void coroutine_fn mirror_run(void *opaque)
|
||||
|
||||
s->common.len = bdrv_getlength(bs);
|
||||
if (s->common.len <= 0) {
|
||||
block_job_completed(&s->common, s->common.len);
|
||||
return;
|
||||
ret = s->common.len;
|
||||
goto immediate_exit;
|
||||
}
|
||||
|
||||
length = (bdrv_getlength(bs) + s->granularity - 1) / s->granularity;
|
||||
length = DIV_ROUND_UP(s->common.len, s->granularity);
|
||||
s->in_flight_bitmap = bitmap_new(length);
|
||||
|
||||
/* If we have no backing file yet in the destination, we cannot let
|
||||
@@ -339,7 +339,10 @@ static void coroutine_fn mirror_run(void *opaque)
|
||||
bdrv_get_backing_filename(s->target, backing_filename,
|
||||
sizeof(backing_filename));
|
||||
if (backing_filename[0] && !s->target->backing_hd) {
|
||||
bdrv_get_info(s->target, &bdi);
|
||||
ret = bdrv_get_info(s->target, &bdi);
|
||||
if (ret < 0) {
|
||||
goto immediate_exit;
|
||||
}
|
||||
if (s->granularity < bdi.cluster_size) {
|
||||
s->buf_size = MAX(s->buf_size, bdi.cluster_size);
|
||||
s->cow_bitmap = bitmap_new(length);
|
||||
|
@@ -532,12 +532,11 @@ static void dump_qdict(fprintf_function func_fprintf, void *f, int indentation,
|
||||
void bdrv_image_info_specific_dump(fprintf_function func_fprintf, void *f,
|
||||
ImageInfoSpecific *info_spec)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
QmpOutputVisitor *ov = qmp_output_visitor_new();
|
||||
QObject *obj, *data;
|
||||
|
||||
visit_type_ImageInfoSpecific(qmp_output_get_visitor(ov), &info_spec, NULL,
|
||||
&local_err);
|
||||
&error_abort);
|
||||
obj = qmp_output_get_qobject(ov);
|
||||
assert(qobject_type(obj) == QTYPE_QDICT);
|
||||
data = qdict_get(qobject_to_qdict(obj), "data");
|
||||
|
@@ -119,7 +119,8 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
if (header.version != QCOW_VERSION) {
|
||||
char version[64];
|
||||
snprintf(version, sizeof(version), "QCOW version %d", header.version);
|
||||
snprintf(version, sizeof(version), "QCOW version %" PRIu32,
|
||||
header.version);
|
||||
error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
|
||||
bs->device_name, "qcow", version);
|
||||
ret = -ENOTSUP;
|
||||
|
@@ -42,6 +42,13 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
|
||||
if (min_size <= s->l1_size)
|
||||
return 0;
|
||||
|
||||
/* Do a sanity check on min_size before trying to calculate new_l1_size
|
||||
* (this prevents overflows during the while loop for the calculation of
|
||||
* new_l1_size) */
|
||||
if (min_size > INT_MAX / sizeof(uint64_t)) {
|
||||
return -EFBIG;
|
||||
}
|
||||
|
||||
if (exact_size) {
|
||||
new_l1_size = min_size;
|
||||
} else {
|
||||
@@ -1360,9 +1367,9 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
|
||||
nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
|
||||
|
||||
for (i = 0; i < nb_clusters; i++) {
|
||||
uint64_t old_offset;
|
||||
uint64_t old_l2_entry;
|
||||
|
||||
old_offset = be64_to_cpu(l2_table[l2_index + i]);
|
||||
old_l2_entry = be64_to_cpu(l2_table[l2_index + i]);
|
||||
|
||||
/*
|
||||
* Make sure that a discarded area reads back as zeroes for v3 images
|
||||
@@ -1373,12 +1380,22 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
|
||||
* TODO We might want to use bdrv_get_block_status(bs) here, but we're
|
||||
* holding s->lock, so that doesn't work today.
|
||||
*/
|
||||
if (old_offset & QCOW_OFLAG_ZERO) {
|
||||
switch (qcow2_get_cluster_type(old_l2_entry)) {
|
||||
case QCOW2_CLUSTER_UNALLOCATED:
|
||||
if (!bs->backing_hd) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
if ((old_offset & L2E_OFFSET_MASK) == 0 && !bs->backing_hd) {
|
||||
case QCOW2_CLUSTER_ZERO:
|
||||
continue;
|
||||
|
||||
case QCOW2_CLUSTER_NORMAL:
|
||||
case QCOW2_CLUSTER_COMPRESSED:
|
||||
break;
|
||||
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
/* First remove L2 entries */
|
||||
@@ -1390,7 +1407,7 @@ static int discard_single_l2(BlockDriverState *bs, uint64_t offset,
|
||||
}
|
||||
|
||||
/* Then decrease the refcount */
|
||||
qcow2_free_any_clusters(bs, old_offset, 1, type);
|
||||
qcow2_free_any_clusters(bs, old_l2_entry, 1, type);
|
||||
}
|
||||
|
||||
ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
|
||||
|
@@ -653,6 +653,13 @@ retry:
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure that all offsets in the "allocated" range are representable
|
||||
* in an int64_t */
|
||||
if (s->free_cluster_index - 1 > (INT64_MAX >> s->cluster_bits)) {
|
||||
return -EFBIG;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_ALLOC2
|
||||
fprintf(stderr, "alloc_clusters: size=%" PRId64 " -> %" PRId64 "\n",
|
||||
size,
|
||||
@@ -1480,6 +1487,11 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
|
||||
int ret;
|
||||
|
||||
size = bdrv_getlength(bs->file);
|
||||
if (size < 0) {
|
||||
res->check_errors++;
|
||||
return size;
|
||||
}
|
||||
|
||||
nb_clusters = size_to_clusters(s, size);
|
||||
if (nb_clusters > INT_MAX) {
|
||||
res->check_errors++;
|
||||
|
@@ -124,8 +124,9 @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
|
||||
|
||||
case QCOW2_EXT_MAGIC_BACKING_FORMAT:
|
||||
if (ext.len >= sizeof(bs->backing_format)) {
|
||||
error_setg(errp, "ERROR: ext_backing_format: len=%u too large"
|
||||
" (>=%zu)", ext.len, sizeof(bs->backing_format));
|
||||
error_setg(errp, "ERROR: ext_backing_format: len=%" PRIu32
|
||||
" too large (>=%zu)", ext.len,
|
||||
sizeof(bs->backing_format));
|
||||
return 2;
|
||||
}
|
||||
ret = bdrv_pread(bs->file, offset, bs->backing_format, ext.len);
|
||||
@@ -483,7 +484,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
goto fail;
|
||||
}
|
||||
if (header.version < 2 || header.version > 3) {
|
||||
report_unsupported(bs, errp, "QCOW version %d", header.version);
|
||||
report_unsupported(bs, errp, "QCOW version %" PRIu32, header.version);
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
}
|
||||
@@ -493,7 +494,8 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
/* Initialise cluster size */
|
||||
if (header.cluster_bits < MIN_CLUSTER_BITS ||
|
||||
header.cluster_bits > MAX_CLUSTER_BITS) {
|
||||
error_setg(errp, "Unsupported cluster size: 2^%i", header.cluster_bits);
|
||||
error_setg(errp, "Unsupported cluster size: 2^%" PRIu32,
|
||||
header.cluster_bits);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
@@ -591,7 +593,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
s->refcount_order = header.refcount_order;
|
||||
|
||||
if (header.crypt_method > QCOW_CRYPT_AES) {
|
||||
error_setg(errp, "Unsupported encryption method: %i",
|
||||
error_setg(errp, "Unsupported encryption method: %" PRIu32,
|
||||
header.crypt_method);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
|
@@ -366,7 +366,7 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
||||
BDRVRawState *s = bs->opaque;
|
||||
QemuOpts *opts;
|
||||
Error *local_err = NULL;
|
||||
const char *filename;
|
||||
const char *filename = NULL;
|
||||
int fd, ret;
|
||||
struct stat st;
|
||||
|
||||
@@ -446,6 +446,9 @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
|
||||
|
||||
ret = 0;
|
||||
fail:
|
||||
if (filename && (bdrv_flags & BDRV_O_TEMPORARY)) {
|
||||
unlink(filename);
|
||||
}
|
||||
qemu_opts_del(opts);
|
||||
return ret;
|
||||
}
|
||||
|
@@ -390,6 +390,9 @@ static void raw_close(BlockDriverState *bs)
|
||||
{
|
||||
BDRVRawState *s = bs->opaque;
|
||||
CloseHandle(s->hfile);
|
||||
if (bs->open_flags & BDRV_O_TEMPORARY) {
|
||||
unlink(bs->filename);
|
||||
}
|
||||
}
|
||||
|
||||
static int raw_truncate(BlockDriverState *bs, int64_t offset)
|
||||
|
@@ -1099,7 +1099,7 @@ static int find_vdi_name(BDRVSheepdogState *s, const char *filename,
|
||||
}
|
||||
|
||||
if (rsp->result != SD_RES_SUCCESS) {
|
||||
error_report("cannot get vdi info, %s, %s %d %s",
|
||||
error_report("cannot get vdi info, %s, %s %" PRIu32 " %s",
|
||||
sd_strerror(rsp->result), filename, snapid, tag);
|
||||
if (rsp->result == SD_RES_NO_VDI) {
|
||||
ret = -ENOENT;
|
||||
@@ -2316,8 +2316,8 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
|
||||
sn_tab[found].vm_state_size = inode.vm_state_size;
|
||||
sn_tab[found].vm_clock_nsec = inode.vm_clock_nsec;
|
||||
|
||||
snprintf(sn_tab[found].id_str, sizeof(sn_tab[found].id_str), "%u",
|
||||
inode.snap_id);
|
||||
snprintf(sn_tab[found].id_str, sizeof(sn_tab[found].id_str),
|
||||
"%" PRIu32, inode.snap_id);
|
||||
pstrcpy(sn_tab[found].name,
|
||||
MIN(sizeof(sn_tab[found].name), sizeof(inode.tag)),
|
||||
inode.tag);
|
||||
|
28
block/vdi.c
28
block/vdi.c
@@ -408,34 +408,35 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
}
|
||||
|
||||
if (header.signature != VDI_SIGNATURE) {
|
||||
error_setg(errp, "Image not in VDI format (bad signature %08x)", header.signature);
|
||||
error_setg(errp, "Image not in VDI format (bad signature %08" PRIx32
|
||||
")", header.signature);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
} else if (header.version != VDI_VERSION_1_1) {
|
||||
error_setg(errp, "unsupported VDI image (version %u.%u)",
|
||||
header.version >> 16, header.version & 0xffff);
|
||||
error_setg(errp, "unsupported VDI image (version %" PRIu32 ".%" PRIu32
|
||||
")", header.version >> 16, header.version & 0xffff);
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
} else if (header.offset_bmap % SECTOR_SIZE != 0) {
|
||||
/* We only support block maps which start on a sector boundary. */
|
||||
error_setg(errp, "unsupported VDI image (unaligned block map offset "
|
||||
"0x%x)", header.offset_bmap);
|
||||
"0x%" PRIx32 ")", header.offset_bmap);
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
} else if (header.offset_data % SECTOR_SIZE != 0) {
|
||||
/* We only support data blocks which start on a sector boundary. */
|
||||
error_setg(errp, "unsupported VDI image (unaligned data offset 0x%x)",
|
||||
header.offset_data);
|
||||
error_setg(errp, "unsupported VDI image (unaligned data offset 0x%"
|
||||
PRIx32 ")", header.offset_data);
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
} else if (header.sector_size != SECTOR_SIZE) {
|
||||
error_setg(errp, "unsupported VDI image (sector size %u is not %u)",
|
||||
header.sector_size, SECTOR_SIZE);
|
||||
error_setg(errp, "unsupported VDI image (sector size %" PRIu32
|
||||
" is not %u)", header.sector_size, SECTOR_SIZE);
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
} else if (header.block_size != DEFAULT_CLUSTER_SIZE) {
|
||||
error_setg(errp, "unsupported VDI image (block size %u is not %u)",
|
||||
header.block_size, DEFAULT_CLUSTER_SIZE);
|
||||
error_setg(errp, "unsupported VDI image (block size %" PRIu32
|
||||
" is not %u)", header.block_size, DEFAULT_CLUSTER_SIZE);
|
||||
ret = -ENOTSUP;
|
||||
goto fail;
|
||||
} else if (header.disk_size >
|
||||
@@ -755,6 +756,7 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options,
|
||||
vdi_header_to_le(&header);
|
||||
if (write(fd, &header, sizeof(header)) < 0) {
|
||||
result = -errno;
|
||||
goto close_and_exit;
|
||||
}
|
||||
|
||||
if (bmap_size > 0) {
|
||||
@@ -768,6 +770,8 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options,
|
||||
}
|
||||
if (write(fd, bmap, bmap_size) < 0) {
|
||||
result = -errno;
|
||||
g_free(bmap);
|
||||
goto close_and_exit;
|
||||
}
|
||||
g_free(bmap);
|
||||
}
|
||||
@@ -775,10 +779,12 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options,
|
||||
if (image_type == VDI_TYPE_STATIC) {
|
||||
if (ftruncate(fd, sizeof(header) + bmap_size + blocks * block_size)) {
|
||||
result = -errno;
|
||||
goto close_and_exit;
|
||||
}
|
||||
}
|
||||
|
||||
if (close(fd) < 0) {
|
||||
close_and_exit:
|
||||
if ((close(fd) < 0) && !result) {
|
||||
result = -errno;
|
||||
}
|
||||
|
||||
|
@@ -8,6 +8,7 @@ command line switches:
|
||||
-vga std [ picks isa for -M isapc, otherwise pci ]
|
||||
-device VGA [ pci variant ]
|
||||
-device isa-vga [ isa variant ]
|
||||
-device secondary-vga [ legacy-free pci variant ]
|
||||
|
||||
|
||||
PCI spec
|
||||
@@ -31,9 +32,15 @@ PCI ROM Region:
|
||||
Holds the vgabios (qemu 0.14+).
|
||||
|
||||
|
||||
The legacy-free variant has no ROM and has PCI_CLASS_DISPLAY_OTHER
|
||||
instead of PCI_CLASS_DISPLAY_VGA.
|
||||
|
||||
|
||||
IO ports used
|
||||
-------------
|
||||
|
||||
Doesn't apply to the legacy-free pci variant, use the MMIO bar instead.
|
||||
|
||||
03c0 - 03df : standard vga ports
|
||||
01ce : bochs vbe interface index port
|
||||
01cf : bochs vbe interface data port (x86 only)
|
||||
|
@@ -75,8 +75,6 @@ typedef struct MemMapEntry {
|
||||
typedef struct VirtBoardInfo {
|
||||
struct arm_boot_info bootinfo;
|
||||
const char *cpu_model;
|
||||
const char *qdevname;
|
||||
const char *gic_compatible;
|
||||
const MemMapEntry *memmap;
|
||||
const int *irqmap;
|
||||
int smp_cpus;
|
||||
@@ -98,10 +96,10 @@ typedef struct VirtBoardInfo {
|
||||
static const MemMapEntry a15memmap[] = {
|
||||
/* Space up to 0x8000000 is reserved for a boot ROM */
|
||||
[VIRT_FLASH] = { 0, 0x8000000 },
|
||||
[VIRT_CPUPERIPHS] = { 0x8000000, 0x8000 },
|
||||
[VIRT_CPUPERIPHS] = { 0x8000000, 0x20000 },
|
||||
/* GIC distributor and CPU interfaces sit inside the CPU peripheral space */
|
||||
[VIRT_GIC_DIST] = { 0x8001000, 0x1000 },
|
||||
[VIRT_GIC_CPU] = { 0x8002000, 0x1000 },
|
||||
[VIRT_GIC_DIST] = { 0x8000000, 0x10000 },
|
||||
[VIRT_GIC_CPU] = { 0x8010000, 0x10000 },
|
||||
[VIRT_UART] = { 0x9000000, 0x1000 },
|
||||
[VIRT_MMIO] = { 0xa000000, 0x200 },
|
||||
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
|
||||
@@ -117,16 +115,16 @@ static const int a15irqmap[] = {
|
||||
static VirtBoardInfo machines[] = {
|
||||
{
|
||||
.cpu_model = "cortex-a15",
|
||||
.qdevname = "a15mpcore_priv",
|
||||
.gic_compatible = "arm,cortex-a15-gic",
|
||||
.memmap = a15memmap,
|
||||
.irqmap = a15irqmap,
|
||||
},
|
||||
{
|
||||
.cpu_model = "cortex-a57",
|
||||
.memmap = a15memmap,
|
||||
.irqmap = a15irqmap,
|
||||
},
|
||||
{
|
||||
.cpu_model = "host",
|
||||
/* We use the A15 private peripheral model to get a V2 GIC */
|
||||
.qdevname = "a15mpcore_priv",
|
||||
.gic_compatible = "arm,cortex-a15-gic",
|
||||
.memmap = a15memmap,
|
||||
.irqmap = a15irqmap,
|
||||
},
|
||||
@@ -251,8 +249,9 @@ static void fdt_add_gic_node(const VirtBoardInfo *vbi)
|
||||
qemu_fdt_setprop_cell(vbi->fdt, "/", "interrupt-parent", gic_phandle);
|
||||
|
||||
qemu_fdt_add_subnode(vbi->fdt, "/intc");
|
||||
/* 'cortex-a15-gic' means 'GIC v2' */
|
||||
qemu_fdt_setprop_string(vbi->fdt, "/intc", "compatible",
|
||||
vbi->gic_compatible);
|
||||
"arm,cortex-a15-gic");
|
||||
qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#interrupt-cells", 3);
|
||||
qemu_fdt_setprop(vbi->fdt, "/intc", "interrupt-controller", NULL, 0);
|
||||
qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc", "reg",
|
||||
@@ -263,6 +262,56 @@ static void fdt_add_gic_node(const VirtBoardInfo *vbi)
|
||||
qemu_fdt_setprop_cell(vbi->fdt, "/intc", "phandle", gic_phandle);
|
||||
}
|
||||
|
||||
static void create_gic(const VirtBoardInfo *vbi, qemu_irq *pic)
|
||||
{
|
||||
/* We create a standalone GIC v2 */
|
||||
DeviceState *gicdev;
|
||||
SysBusDevice *gicbusdev;
|
||||
const char *gictype = "arm_gic";
|
||||
int i;
|
||||
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
gictype = "kvm-arm-gic";
|
||||
}
|
||||
|
||||
gicdev = qdev_create(NULL, gictype);
|
||||
qdev_prop_set_uint32(gicdev, "revision", 2);
|
||||
qdev_prop_set_uint32(gicdev, "num-cpu", smp_cpus);
|
||||
/* Note that the num-irq property counts both internal and external
|
||||
* interrupts; there are always 32 of the former (mandated by GIC spec).
|
||||
*/
|
||||
qdev_prop_set_uint32(gicdev, "num-irq", NUM_IRQS + 32);
|
||||
qdev_init_nofail(gicdev);
|
||||
gicbusdev = SYS_BUS_DEVICE(gicdev);
|
||||
sysbus_mmio_map(gicbusdev, 0, vbi->memmap[VIRT_GIC_DIST].base);
|
||||
sysbus_mmio_map(gicbusdev, 1, vbi->memmap[VIRT_GIC_CPU].base);
|
||||
|
||||
/* Wire the outputs from each CPU's generic timer to the
|
||||
* appropriate GIC PPI inputs, and the GIC's IRQ output to
|
||||
* the CPU's IRQ input.
|
||||
*/
|
||||
for (i = 0; i < smp_cpus; i++) {
|
||||
DeviceState *cpudev = DEVICE(qemu_get_cpu(i));
|
||||
int ppibase = NUM_IRQS + i * 32;
|
||||
/* physical timer; we wire it up to the non-secure timer's ID,
|
||||
* since a real A15 always has TrustZone but QEMU doesn't.
|
||||
*/
|
||||
qdev_connect_gpio_out(cpudev, 0,
|
||||
qdev_get_gpio_in(gicdev, ppibase + 30));
|
||||
/* virtual timer */
|
||||
qdev_connect_gpio_out(cpudev, 1,
|
||||
qdev_get_gpio_in(gicdev, ppibase + 27));
|
||||
|
||||
sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
|
||||
}
|
||||
|
||||
for (i = 0; i < NUM_IRQS; i++) {
|
||||
pic[i] = qdev_get_gpio_in(gicdev, i);
|
||||
}
|
||||
|
||||
fdt_add_gic_node(vbi);
|
||||
}
|
||||
|
||||
static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic)
|
||||
{
|
||||
char *nodename;
|
||||
@@ -340,8 +389,6 @@ static void machvirt_init(QEMUMachineInitArgs *args)
|
||||
MemoryRegion *sysmem = get_system_memory();
|
||||
int n;
|
||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||
DeviceState *dev;
|
||||
SysBusDevice *busdev;
|
||||
const char *cpu_model = args->cpu_model;
|
||||
VirtBoardInfo *vbi;
|
||||
|
||||
@@ -404,25 +451,7 @@ static void machvirt_init(QEMUMachineInitArgs *args)
|
||||
vmstate_register_ram_global(ram);
|
||||
memory_region_add_subregion(sysmem, vbi->memmap[VIRT_MEM].base, ram);
|
||||
|
||||
dev = qdev_create(NULL, vbi->qdevname);
|
||||
qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
|
||||
/* Note that the num-irq property counts both internal and external
|
||||
* interrupts; there are always 32 of the former (mandated by GIC spec).
|
||||
*/
|
||||
qdev_prop_set_uint32(dev, "num-irq", NUM_IRQS + 32);
|
||||
qdev_init_nofail(dev);
|
||||
busdev = SYS_BUS_DEVICE(dev);
|
||||
sysbus_mmio_map(busdev, 0, vbi->memmap[VIRT_CPUPERIPHS].base);
|
||||
fdt_add_gic_node(vbi);
|
||||
for (n = 0; n < smp_cpus; n++) {
|
||||
DeviceState *cpudev = DEVICE(qemu_get_cpu(n));
|
||||
|
||||
sysbus_connect_irq(busdev, n, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
|
||||
}
|
||||
|
||||
for (n = 0; n < NUM_IRQS; n++) {
|
||||
pic[n] = qdev_get_gpio_in(dev, n);
|
||||
}
|
||||
create_gic(vbi, pic);
|
||||
|
||||
create_uart(vbi, pic);
|
||||
|
||||
|
@@ -261,6 +261,9 @@ static void hda_audio_set_amp(HDAAudioStream *st)
|
||||
left = left * 255 / QEMU_HDA_AMP_STEPS;
|
||||
right = right * 255 / QEMU_HDA_AMP_STEPS;
|
||||
|
||||
if (!st->state->mixer) {
|
||||
return;
|
||||
}
|
||||
if (st->output) {
|
||||
AUD_set_volume_out(st->voice.out, muted, left, right);
|
||||
} else {
|
||||
|
@@ -2913,7 +2913,7 @@ static void isa_cirrus_vga_realizefn(DeviceState *dev, Error **errp)
|
||||
ISACirrusVGAState *d = ISA_CIRRUS_VGA(dev);
|
||||
VGACommonState *s = &d->cirrus_vga.vga;
|
||||
|
||||
vga_common_init(s, OBJECT(dev));
|
||||
vga_common_init(s, OBJECT(dev), true);
|
||||
cirrus_init_common(&d->cirrus_vga, OBJECT(dev), CIRRUS_ID_CLGD5430, 0,
|
||||
isa_address_space(isadev),
|
||||
isa_address_space_io(isadev));
|
||||
@@ -2960,7 +2960,7 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev)
|
||||
int16_t device_id = pc->device_id;
|
||||
|
||||
/* setup VGA */
|
||||
vga_common_init(&s->vga, OBJECT(dev));
|
||||
vga_common_init(&s->vga, OBJECT(dev), true);
|
||||
cirrus_init_common(s, OBJECT(dev), device_id, 1, pci_address_space(dev),
|
||||
pci_address_space_io(dev));
|
||||
s->vga.con = graphic_console_init(DEVICE(dev), 0, s->vga.hw_ops, &s->vga);
|
||||
|
@@ -2061,7 +2061,7 @@ static int qxl_init_primary(PCIDevice *dev)
|
||||
qxl->id = 0;
|
||||
qxl_init_ramsize(qxl);
|
||||
vga->vram_size_mb = qxl->vga.vram_size >> 20;
|
||||
vga_common_init(vga, OBJECT(dev));
|
||||
vga_common_init(vga, OBJECT(dev), true);
|
||||
vga_init(vga, OBJECT(dev),
|
||||
pci_address_space(dev), pci_address_space_io(dev), false);
|
||||
portio_list_init(qxl_vga_port_list, OBJECT(dev), qxl_vga_portio_list,
|
||||
|
@@ -132,7 +132,7 @@ int isa_vga_mm_init(hwaddr vram_base,
|
||||
s = g_malloc0(sizeof(*s));
|
||||
|
||||
s->vga.vram_size_mb = VGA_RAM_SIZE >> 20;
|
||||
vga_common_init(&s->vga, NULL);
|
||||
vga_common_init(&s->vga, NULL, true);
|
||||
vga_mm_init(s, vram_base, ctrl_base, it_shift, address_space);
|
||||
|
||||
s->vga.con = graphic_console_init(NULL, 0, s->vga.hw_ops, s);
|
||||
|
@@ -56,7 +56,7 @@ static void vga_isa_realizefn(DeviceState *dev, Error **errp)
|
||||
MemoryRegion *vga_io_memory;
|
||||
const MemoryRegionPortio *vga_ports, *vbe_ports;
|
||||
|
||||
vga_common_init(s, OBJECT(dev));
|
||||
vga_common_init(s, OBJECT(dev), true);
|
||||
s->legacy_address_space = isa_address_space(isadev);
|
||||
vga_io_memory = vga_init_io(s, OBJECT(dev), &vga_ports, &vbe_ports);
|
||||
isa_register_portio_list(isadev, 0x3b0, vga_ports, s, "vga");
|
||||
|
@@ -147,7 +147,7 @@ static int pci_std_vga_initfn(PCIDevice *dev)
|
||||
VGACommonState *s = &d->vga;
|
||||
|
||||
/* vga + console init */
|
||||
vga_common_init(s, OBJECT(dev));
|
||||
vga_common_init(s, OBJECT(dev), true);
|
||||
vga_init(s, OBJECT(dev), pci_address_space(dev), pci_address_space_io(dev),
|
||||
true);
|
||||
|
||||
@@ -179,12 +179,51 @@ static int pci_std_vga_initfn(PCIDevice *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pci_secondary_vga_initfn(PCIDevice *dev)
|
||||
{
|
||||
PCIVGAState *d = DO_UPCAST(PCIVGAState, dev, dev);
|
||||
VGACommonState *s = &d->vga;
|
||||
|
||||
/* vga + console init */
|
||||
vga_common_init(s, OBJECT(dev), false);
|
||||
s->con = graphic_console_init(DEVICE(dev), 0, s->hw_ops, s);
|
||||
|
||||
/* mmio bar */
|
||||
memory_region_init(&d->mmio, OBJECT(dev), "vga.mmio", 4096);
|
||||
memory_region_init_io(&d->ioport, OBJECT(dev), &pci_vga_ioport_ops, d,
|
||||
"vga ioports remapped", PCI_VGA_IOPORT_SIZE);
|
||||
memory_region_init_io(&d->bochs, OBJECT(dev), &pci_vga_bochs_ops, d,
|
||||
"bochs dispi interface", PCI_VGA_BOCHS_SIZE);
|
||||
|
||||
memory_region_add_subregion(&d->mmio, PCI_VGA_IOPORT_OFFSET,
|
||||
&d->ioport);
|
||||
memory_region_add_subregion(&d->mmio, PCI_VGA_BOCHS_OFFSET,
|
||||
&d->bochs);
|
||||
|
||||
pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram);
|
||||
pci_register_bar(&d->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pci_secondary_vga_reset(DeviceState *dev)
|
||||
{
|
||||
PCIVGAState *d = DO_UPCAST(PCIVGAState, dev.qdev, dev);
|
||||
|
||||
vga_common_reset(&d->vga);
|
||||
}
|
||||
|
||||
static Property vga_pci_properties[] = {
|
||||
DEFINE_PROP_UINT32("vgamem_mb", PCIVGAState, vga.vram_size_mb, 16),
|
||||
DEFINE_PROP_BIT("mmio", PCIVGAState, flags, PCI_VGA_FLAG_ENABLE_MMIO, true),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static Property secondary_pci_properties[] = {
|
||||
DEFINE_PROP_UINT32("vgamem_mb", PCIVGAState, vga.vram_size_mb, 16),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void vga_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
@@ -201,6 +240,20 @@ static void vga_class_init(ObjectClass *klass, void *data)
|
||||
set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
|
||||
}
|
||||
|
||||
static void secondary_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = pci_secondary_vga_initfn;
|
||||
k->vendor_id = PCI_VENDOR_ID_QEMU;
|
||||
k->device_id = PCI_DEVICE_ID_QEMU_VGA;
|
||||
k->class_id = PCI_CLASS_DISPLAY_OTHER;
|
||||
dc->vmsd = &vmstate_vga_pci;
|
||||
dc->props = secondary_pci_properties;
|
||||
dc->reset = pci_secondary_vga_reset;
|
||||
}
|
||||
|
||||
static const TypeInfo vga_info = {
|
||||
.name = "VGA",
|
||||
.parent = TYPE_PCI_DEVICE,
|
||||
@@ -208,9 +261,17 @@ static const TypeInfo vga_info = {
|
||||
.class_init = vga_class_init,
|
||||
};
|
||||
|
||||
static const TypeInfo secondary_info = {
|
||||
.name = "secondary-vga",
|
||||
.parent = TYPE_PCI_DEVICE,
|
||||
.instance_size = sizeof(PCIVGAState),
|
||||
.class_init = secondary_class_init,
|
||||
};
|
||||
|
||||
static void vga_register_types(void)
|
||||
{
|
||||
type_register_static(&vga_info);
|
||||
type_register_static(&secondary_info);
|
||||
}
|
||||
|
||||
type_init(vga_register_types)
|
||||
|
@@ -171,6 +171,10 @@ static void vga_update_memory_access(VGACommonState *s)
|
||||
MemoryRegion *region, *old_region = s->chain4_alias;
|
||||
hwaddr base, offset, size;
|
||||
|
||||
if (s->legacy_address_space == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
s->chain4_alias = NULL;
|
||||
|
||||
if ((s->sr[VGA_SEQ_PLANE_WRITE] & VGA_SR02_ALL_PLANES) ==
|
||||
@@ -2252,7 +2256,7 @@ static const GraphicHwOps vga_ops = {
|
||||
.text_update = vga_update_text,
|
||||
};
|
||||
|
||||
void vga_common_init(VGACommonState *s, Object *obj)
|
||||
void vga_common_init(VGACommonState *s, Object *obj, bool global_vmstate)
|
||||
{
|
||||
int i, j, v, b;
|
||||
|
||||
@@ -2289,7 +2293,7 @@ void vga_common_init(VGACommonState *s, Object *obj)
|
||||
|
||||
s->is_vbe_vmstate = 1;
|
||||
memory_region_init_ram(&s->vram, obj, "vga.vram", s->vram_size);
|
||||
vmstate_register_ram_global(&s->vram);
|
||||
vmstate_register_ram(&s->vram, global_vmstate ? NULL : DEVICE(obj));
|
||||
xen_register_framebuffer(&s->vram);
|
||||
s->vram_ptr = memory_region_get_ram_ptr(&s->vram);
|
||||
s->get_bpp = vga_get_bpp;
|
||||
|
@@ -177,7 +177,7 @@ static inline int c6_to_8(int v)
|
||||
return (v << 2) | (b << 1) | b;
|
||||
}
|
||||
|
||||
void vga_common_init(VGACommonState *s, Object *obj);
|
||||
void vga_common_init(VGACommonState *s, Object *obj, bool global_vmstate);
|
||||
void vga_init(VGACommonState *s, Object *obj, MemoryRegion *address_space,
|
||||
MemoryRegion *address_space_io, bool init_vga_ports);
|
||||
MemoryRegion *vga_init_io(VGACommonState *s, Object *obj,
|
||||
|
@@ -1207,7 +1207,7 @@ static void vmsvga_init(DeviceState *dev, struct vmsvga_state_s *s,
|
||||
vmstate_register_ram_global(&s->fifo_ram);
|
||||
s->fifo_ptr = memory_region_get_ram_ptr(&s->fifo_ram);
|
||||
|
||||
vga_common_init(&s->vga, OBJECT(dev));
|
||||
vga_common_init(&s->vga, OBJECT(dev), true);
|
||||
vga_init(&s->vga, OBJECT(dev), address_space, io, true);
|
||||
vmstate_register(NULL, 0, &vmstate_vga_common, &s->vga);
|
||||
s->new_depth = 32;
|
||||
|
39
hw/i386/pc.c
39
hw/i386/pc.c
@@ -612,6 +612,21 @@ int e820_add_entry(uint64_t address, uint64_t length, uint32_t type)
|
||||
return e820_entries;
|
||||
}
|
||||
|
||||
int e820_get_num_entries(void)
|
||||
{
|
||||
return e820_entries;
|
||||
}
|
||||
|
||||
bool e820_get_entry(int idx, uint32_t type, uint64_t *address, uint64_t *length)
|
||||
{
|
||||
if (idx < e820_entries && e820_table[idx].type == cpu_to_le32(type)) {
|
||||
*address = le64_to_cpu(e820_table[idx].address);
|
||||
*length = le64_to_cpu(e820_table[idx].length);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Calculates the limit to CPU APIC ID values
|
||||
*
|
||||
* This function returns the limit for the APIC ID value, so that all
|
||||
@@ -627,8 +642,8 @@ static unsigned int pc_apic_id_limit(unsigned int max_cpus)
|
||||
static FWCfgState *bochs_bios_init(void)
|
||||
{
|
||||
FWCfgState *fw_cfg;
|
||||
uint8_t *smbios_table;
|
||||
size_t smbios_len;
|
||||
uint8_t *smbios_tables, *smbios_anchor;
|
||||
size_t smbios_tables_len, smbios_anchor_len;
|
||||
uint64_t *numa_fw_cfg;
|
||||
int i, j;
|
||||
unsigned int apic_id_limit = pc_apic_id_limit(max_cpus);
|
||||
@@ -655,10 +670,21 @@ static FWCfgState *bochs_bios_init(void)
|
||||
acpi_tables, acpi_tables_len);
|
||||
fw_cfg_add_i32(fw_cfg, FW_CFG_IRQ0_OVERRIDE, kvm_allows_irq0_override());
|
||||
|
||||
smbios_table = smbios_get_table(&smbios_len);
|
||||
if (smbios_table)
|
||||
smbios_tables = smbios_get_table_legacy(&smbios_tables_len);
|
||||
if (smbios_tables) {
|
||||
fw_cfg_add_bytes(fw_cfg, FW_CFG_SMBIOS_ENTRIES,
|
||||
smbios_table, smbios_len);
|
||||
smbios_tables, smbios_tables_len);
|
||||
}
|
||||
|
||||
smbios_get_tables(&smbios_tables, &smbios_tables_len,
|
||||
&smbios_anchor, &smbios_anchor_len);
|
||||
if (smbios_anchor) {
|
||||
fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-tables",
|
||||
smbios_tables, smbios_tables_len);
|
||||
fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-anchor",
|
||||
smbios_anchor, smbios_anchor_len);
|
||||
}
|
||||
|
||||
fw_cfg_add_bytes(fw_cfg, FW_CFG_E820_TABLE,
|
||||
&e820_reserve, sizeof(e820_reserve));
|
||||
fw_cfg_add_file(fw_cfg, "etc/e820", e820_table,
|
||||
@@ -1027,6 +1053,9 @@ void pc_cpus_init(const char *cpu_model, DeviceState *icc_bridge)
|
||||
sysbus_mmio_map_overlap(SYS_BUS_DEVICE(icc_bridge), 0,
|
||||
APIC_DEFAULT_ADDRESS, 0x1000);
|
||||
}
|
||||
|
||||
/* tell smbios about cpuid version and features */
|
||||
smbios_set_cpuid(cpu->env.cpuid_version, cpu->env.features[FEAT_1_EDX]);
|
||||
}
|
||||
|
||||
/* pci-info ROM file. Little endian format */
|
||||
|
@@ -60,7 +60,8 @@ static const int ide_irq[MAX_IDE_BUS] = { 14, 15 };
|
||||
|
||||
static bool has_pci_info;
|
||||
static bool has_acpi_build = true;
|
||||
static bool smbios_type1_defaults = true;
|
||||
static bool smbios_defaults = true;
|
||||
static bool smbios_legacy_mode;
|
||||
/* Make sure that guest addresses aligned at 1Gbyte boundaries get mapped to
|
||||
* host addresses aligned at 1Gbyte boundaries. This way we can use 1GByte
|
||||
* pages in the host.
|
||||
@@ -143,10 +144,10 @@ static void pc_init1(QEMUMachineInitArgs *args,
|
||||
guest_info->has_pci_info = has_pci_info;
|
||||
guest_info->isapc_ram_fw = !pci_enabled;
|
||||
|
||||
if (smbios_type1_defaults) {
|
||||
if (smbios_defaults) {
|
||||
/* These values are guest ABI, do not change */
|
||||
smbios_set_type1_defaults("QEMU", "Standard PC (i440FX + PIIX, 1996)",
|
||||
args->machine->name);
|
||||
smbios_set_defaults("QEMU", "Standard PC (i440FX + PIIX, 1996)",
|
||||
args->machine->name, smbios_legacy_mode);
|
||||
}
|
||||
|
||||
/* allocate ram and load rom/bios */
|
||||
@@ -262,9 +263,15 @@ static void pc_init_pci(QEMUMachineInitArgs *args)
|
||||
pc_init1(args, 1, 1);
|
||||
}
|
||||
|
||||
static void pc_compat_2_0(QEMUMachineInitArgs *args)
|
||||
{
|
||||
smbios_legacy_mode = true;
|
||||
}
|
||||
|
||||
static void pc_compat_1_7(QEMUMachineInitArgs *args)
|
||||
{
|
||||
smbios_type1_defaults = false;
|
||||
pc_compat_2_0(args);
|
||||
smbios_defaults = false;
|
||||
gigabyte_align = false;
|
||||
option_rom_has_mr = true;
|
||||
x86_cpu_compat_disable_kvm_features(FEAT_1_ECX, CPUID_EXT_X2APIC);
|
||||
@@ -303,6 +310,12 @@ static void pc_compat_1_2(QEMUMachineInitArgs *args)
|
||||
x86_cpu_compat_disable_kvm_features(FEAT_KVM, KVM_FEATURE_PV_EOI);
|
||||
}
|
||||
|
||||
static void pc_init_pci_2_0(QEMUMachineInitArgs *args)
|
||||
{
|
||||
pc_compat_2_0(args);
|
||||
pc_init_pci(args);
|
||||
}
|
||||
|
||||
static void pc_init_pci_1_7(QEMUMachineInitArgs *args)
|
||||
{
|
||||
pc_compat_1_7(args);
|
||||
@@ -345,7 +358,7 @@ static void pc_init_pci_no_kvmclock(QEMUMachineInitArgs *args)
|
||||
{
|
||||
has_pci_info = false;
|
||||
has_acpi_build = false;
|
||||
smbios_type1_defaults = false;
|
||||
smbios_defaults = false;
|
||||
x86_cpu_compat_disable_kvm_features(FEAT_KVM, KVM_FEATURE_PV_EOI);
|
||||
enable_compat_apic_id_mode();
|
||||
pc_init1(args, 1, 0);
|
||||
@@ -355,7 +368,7 @@ static void pc_init_isa(QEMUMachineInitArgs *args)
|
||||
{
|
||||
has_pci_info = false;
|
||||
has_acpi_build = false;
|
||||
smbios_type1_defaults = false;
|
||||
smbios_defaults = false;
|
||||
if (!args->cpu_model) {
|
||||
args->cpu_model = "486";
|
||||
}
|
||||
@@ -383,16 +396,24 @@ static void pc_xen_hvm_init(QEMUMachineInitArgs *args)
|
||||
.desc = "Standard PC (i440FX + PIIX, 1996)", \
|
||||
.hot_add_cpu = pc_hot_add_cpu
|
||||
|
||||
#define PC_I440FX_2_0_MACHINE_OPTIONS \
|
||||
#define PC_I440FX_2_1_MACHINE_OPTIONS \
|
||||
PC_I440FX_MACHINE_OPTIONS, \
|
||||
.default_machine_opts = "firmware=bios-256k.bin"
|
||||
|
||||
static QEMUMachine pc_i440fx_machine_v2_1 = {
|
||||
PC_I440FX_2_1_MACHINE_OPTIONS,
|
||||
.name = "pc-i440fx-2.1",
|
||||
.alias = "pc",
|
||||
.init = pc_init_pci,
|
||||
.is_default = 1,
|
||||
};
|
||||
|
||||
#define PC_I440FX_2_0_MACHINE_OPTIONS PC_I440FX_2_1_MACHINE_OPTIONS
|
||||
|
||||
static QEMUMachine pc_i440fx_machine_v2_0 = {
|
||||
PC_I440FX_2_0_MACHINE_OPTIONS,
|
||||
.name = "pc-i440fx-2.0",
|
||||
.alias = "pc",
|
||||
.init = pc_init_pci,
|
||||
.is_default = 1,
|
||||
.init = pc_init_pci_2_0,
|
||||
};
|
||||
|
||||
#define PC_I440FX_1_7_MACHINE_OPTIONS PC_I440FX_MACHINE_OPTIONS
|
||||
@@ -817,6 +838,7 @@ static QEMUMachine xenfv_machine = {
|
||||
|
||||
static void pc_machine_init(void)
|
||||
{
|
||||
qemu_register_machine(&pc_i440fx_machine_v2_1);
|
||||
qemu_register_machine(&pc_i440fx_machine_v2_0);
|
||||
qemu_register_machine(&pc_i440fx_machine_v1_7);
|
||||
qemu_register_machine(&pc_i440fx_machine_v1_6);
|
||||
|
@@ -50,7 +50,8 @@
|
||||
|
||||
static bool has_pci_info;
|
||||
static bool has_acpi_build = true;
|
||||
static bool smbios_type1_defaults = true;
|
||||
static bool smbios_defaults = true;
|
||||
static bool smbios_legacy_mode;
|
||||
/* Make sure that guest addresses aligned at 1Gbyte boundaries get mapped to
|
||||
* host addresses aligned at 1Gbyte boundaries. This way we can use 1GByte
|
||||
* pages in the host.
|
||||
@@ -130,10 +131,10 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
|
||||
guest_info->isapc_ram_fw = false;
|
||||
guest_info->has_acpi_build = has_acpi_build;
|
||||
|
||||
if (smbios_type1_defaults) {
|
||||
if (smbios_defaults) {
|
||||
/* These values are guest ABI, do not change */
|
||||
smbios_set_type1_defaults("QEMU", "Standard PC (Q35 + ICH9, 2009)",
|
||||
args->machine->name);
|
||||
smbios_set_defaults("QEMU", "Standard PC (Q35 + ICH9, 2009)",
|
||||
args->machine->name, smbios_legacy_mode);
|
||||
}
|
||||
|
||||
/* allocate ram and load rom/bios */
|
||||
@@ -240,9 +241,15 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
|
||||
}
|
||||
}
|
||||
|
||||
static void pc_compat_2_0(QEMUMachineInitArgs *args)
|
||||
{
|
||||
smbios_legacy_mode = true;
|
||||
}
|
||||
|
||||
static void pc_compat_1_7(QEMUMachineInitArgs *args)
|
||||
{
|
||||
smbios_type1_defaults = false;
|
||||
pc_compat_2_0(args);
|
||||
smbios_defaults = false;
|
||||
gigabyte_align = false;
|
||||
option_rom_has_mr = true;
|
||||
x86_cpu_compat_disable_kvm_features(FEAT_1_ECX, CPUID_EXT_X2APIC);
|
||||
@@ -268,6 +275,12 @@ static void pc_compat_1_4(QEMUMachineInitArgs *args)
|
||||
x86_cpu_compat_set_features("Westmere", FEAT_1_ECX, 0, CPUID_EXT_PCLMULQDQ);
|
||||
}
|
||||
|
||||
static void pc_q35_init_2_0(QEMUMachineInitArgs *args)
|
||||
{
|
||||
pc_compat_2_0(args);
|
||||
pc_q35_init(args);
|
||||
}
|
||||
|
||||
static void pc_q35_init_1_7(QEMUMachineInitArgs *args)
|
||||
{
|
||||
pc_compat_1_7(args);
|
||||
@@ -297,15 +310,23 @@ static void pc_q35_init_1_4(QEMUMachineInitArgs *args)
|
||||
.desc = "Standard PC (Q35 + ICH9, 2009)", \
|
||||
.hot_add_cpu = pc_hot_add_cpu
|
||||
|
||||
#define PC_Q35_2_0_MACHINE_OPTIONS \
|
||||
#define PC_Q35_2_1_MACHINE_OPTIONS \
|
||||
PC_Q35_MACHINE_OPTIONS, \
|
||||
.default_machine_opts = "firmware=bios-256k.bin"
|
||||
|
||||
static QEMUMachine pc_q35_machine_v2_1 = {
|
||||
PC_Q35_2_1_MACHINE_OPTIONS,
|
||||
.name = "pc-q35-2.1",
|
||||
.alias = "q35",
|
||||
.init = pc_q35_init,
|
||||
};
|
||||
|
||||
#define PC_Q35_2_0_MACHINE_OPTIONS PC_Q35_2_1_MACHINE_OPTIONS
|
||||
|
||||
static QEMUMachine pc_q35_machine_v2_0 = {
|
||||
PC_Q35_2_0_MACHINE_OPTIONS,
|
||||
.name = "pc-q35-2.0",
|
||||
.alias = "q35",
|
||||
.init = pc_q35_init,
|
||||
.init = pc_q35_init_2_0,
|
||||
};
|
||||
|
||||
#define PC_Q35_1_7_MACHINE_OPTIONS PC_Q35_MACHINE_OPTIONS
|
||||
@@ -358,6 +379,7 @@ static QEMUMachine pc_q35_machine_v1_4 = {
|
||||
|
||||
static void pc_q35_machine_init(void)
|
||||
{
|
||||
qemu_register_machine(&pc_q35_machine_v2_1);
|
||||
qemu_register_machine(&pc_q35_machine_v2_0);
|
||||
qemu_register_machine(&pc_q35_machine_v1_7);
|
||||
qemu_register_machine(&pc_q35_machine_v1_6);
|
||||
|
789
hw/i386/smbios.c
789
hw/i386/smbios.c
@@ -18,12 +18,13 @@
|
||||
#include "qemu/config-file.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/cpus.h"
|
||||
#include "hw/i386/pc.h"
|
||||
#include "hw/i386/smbios.h"
|
||||
#include "hw/loader.h"
|
||||
|
||||
/*
|
||||
* Structures shared with the BIOS
|
||||
*/
|
||||
|
||||
/* legacy structures and constants for <= 2.0 machines */
|
||||
struct smbios_header {
|
||||
uint16_t length;
|
||||
uint8_t type;
|
||||
@@ -46,14 +47,23 @@ struct smbios_table {
|
||||
|
||||
static uint8_t *smbios_entries;
|
||||
static size_t smbios_entries_len;
|
||||
static bool smbios_legacy = true;
|
||||
/* end: legacy structures & constants for <= 2.0 machines */
|
||||
|
||||
|
||||
static uint8_t *smbios_tables;
|
||||
static size_t smbios_tables_len;
|
||||
static unsigned smbios_table_max;
|
||||
static unsigned smbios_table_cnt;
|
||||
static struct smbios_entry_point ep;
|
||||
|
||||
static int smbios_type4_count = 0;
|
||||
static bool smbios_immutable;
|
||||
static bool smbios_have_defaults;
|
||||
static uint32_t smbios_cpuid_version, smbios_cpuid_features, smbios_smp_sockets;
|
||||
|
||||
static struct {
|
||||
bool seen;
|
||||
int headertype;
|
||||
Location loc;
|
||||
} first_opt[2];
|
||||
static DECLARE_BITMAP(have_binfile_bitmap, SMBIOS_MAX_TYPE+1);
|
||||
static DECLARE_BITMAP(have_fields_bitmap, SMBIOS_MAX_TYPE+1);
|
||||
|
||||
static struct {
|
||||
const char *vendor, *version, *date;
|
||||
@@ -66,6 +76,22 @@ static struct {
|
||||
/* uuid is in qemu_uuid[] */
|
||||
} type1;
|
||||
|
||||
static struct {
|
||||
const char *manufacturer, *product, *version, *serial, *asset, *location;
|
||||
} type2;
|
||||
|
||||
static struct {
|
||||
const char *manufacturer, *version, *serial, *asset, *sku;
|
||||
} type3;
|
||||
|
||||
static struct {
|
||||
const char *sock_pfx, *manufacturer, *version, *serial, *asset, *part;
|
||||
} type4;
|
||||
|
||||
static struct {
|
||||
const char *loc_pfx, *bank, *manufacturer, *serial, *asset, *part;
|
||||
} type17;
|
||||
|
||||
static QemuOptsList qemu_smbios_opts = {
|
||||
.name = "smbios",
|
||||
.head = QTAILQ_HEAD_INITIALIZER(qemu_smbios_opts.head),
|
||||
@@ -149,6 +175,134 @@ static const QemuOptDesc qemu_smbios_type1_opts[] = {
|
||||
{ /* end of list */ }
|
||||
};
|
||||
|
||||
static const QemuOptDesc qemu_smbios_type2_opts[] = {
|
||||
{
|
||||
.name = "type",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
.help = "SMBIOS element type",
|
||||
},{
|
||||
.name = "manufacturer",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "manufacturer name",
|
||||
},{
|
||||
.name = "product",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "product name",
|
||||
},{
|
||||
.name = "version",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "version number",
|
||||
},{
|
||||
.name = "serial",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "serial number",
|
||||
},{
|
||||
.name = "asset",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "asset tag number",
|
||||
},{
|
||||
.name = "location",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "location in chassis",
|
||||
},
|
||||
{ /* end of list */ }
|
||||
};
|
||||
|
||||
static const QemuOptDesc qemu_smbios_type3_opts[] = {
|
||||
{
|
||||
.name = "type",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
.help = "SMBIOS element type",
|
||||
},{
|
||||
.name = "manufacturer",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "manufacturer name",
|
||||
},{
|
||||
.name = "version",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "version number",
|
||||
},{
|
||||
.name = "serial",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "serial number",
|
||||
},{
|
||||
.name = "asset",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "asset tag number",
|
||||
},{
|
||||
.name = "sku",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "SKU number",
|
||||
},
|
||||
{ /* end of list */ }
|
||||
};
|
||||
|
||||
static const QemuOptDesc qemu_smbios_type4_opts[] = {
|
||||
{
|
||||
.name = "type",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
.help = "SMBIOS element type",
|
||||
},{
|
||||
.name = "sock_pfx",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "socket designation string prefix",
|
||||
},{
|
||||
.name = "manufacturer",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "manufacturer name",
|
||||
},{
|
||||
.name = "version",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "version number",
|
||||
},{
|
||||
.name = "serial",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "serial number",
|
||||
},{
|
||||
.name = "asset",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "asset tag number",
|
||||
},{
|
||||
.name = "part",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "part number",
|
||||
},
|
||||
{ /* end of list */ }
|
||||
};
|
||||
|
||||
static const QemuOptDesc qemu_smbios_type17_opts[] = {
|
||||
{
|
||||
.name = "type",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
.help = "SMBIOS element type",
|
||||
},{
|
||||
.name = "loc_pfx",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "device locator string prefix",
|
||||
},{
|
||||
.name = "bank",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "bank locator string",
|
||||
},{
|
||||
.name = "manufacturer",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "manufacturer name",
|
||||
},{
|
||||
.name = "serial",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "serial number",
|
||||
},{
|
||||
.name = "asset",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "asset tag number",
|
||||
},{
|
||||
.name = "part",
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "part number",
|
||||
},
|
||||
{ /* end of list */ }
|
||||
};
|
||||
|
||||
static void smbios_register_config(void)
|
||||
{
|
||||
qemu_add_opts(&qemu_smbios_opts);
|
||||
@@ -158,35 +312,17 @@ machine_init(smbios_register_config);
|
||||
|
||||
static void smbios_validate_table(void)
|
||||
{
|
||||
if (smbios_type4_count && smbios_type4_count != smp_cpus) {
|
||||
error_report("Number of SMBIOS Type 4 tables must match cpu count");
|
||||
uint32_t expect_t4_count = smbios_legacy ? smp_cpus : smbios_smp_sockets;
|
||||
|
||||
if (smbios_type4_count && smbios_type4_count != expect_t4_count) {
|
||||
error_report("Expected %d SMBIOS Type 4 tables, got %d instead",
|
||||
expect_t4_count, smbios_type4_count);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* To avoid unresolvable overlaps in data, don't allow both
|
||||
* tables and fields for the same smbios type.
|
||||
*/
|
||||
static void smbios_check_collision(int type, int entry)
|
||||
{
|
||||
if (type < ARRAY_SIZE(first_opt)) {
|
||||
if (first_opt[type].seen) {
|
||||
if (first_opt[type].headertype != entry) {
|
||||
error_report("Can't mix file= and type= for same type");
|
||||
loc_push_restore(&first_opt[type].loc);
|
||||
error_report("This is the conflicting setting");
|
||||
loc_pop(&first_opt[type].loc);
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
first_opt[type].seen = true;
|
||||
first_opt[type].headertype = entry;
|
||||
loc_save(&first_opt[type].loc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* legacy setup functions for <= 2.0 machines */
|
||||
static void smbios_add_field(int type, int offset, const void *data, size_t len)
|
||||
{
|
||||
struct smbios_field *field;
|
||||
@@ -256,22 +392,13 @@ static void smbios_build_type_1_fields(void)
|
||||
}
|
||||
}
|
||||
|
||||
void smbios_set_type1_defaults(const char *manufacturer,
|
||||
const char *product, const char *version)
|
||||
uint8_t *smbios_get_table_legacy(size_t *length)
|
||||
{
|
||||
if (!type1.manufacturer) {
|
||||
type1.manufacturer = manufacturer;
|
||||
}
|
||||
if (!type1.product) {
|
||||
type1.product = product;
|
||||
}
|
||||
if (!type1.version) {
|
||||
type1.version = version;
|
||||
}
|
||||
if (!smbios_legacy) {
|
||||
*length = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8_t *smbios_get_table(size_t *length)
|
||||
{
|
||||
if (!smbios_immutable) {
|
||||
smbios_build_type_0_fields();
|
||||
smbios_build_type_1_fields();
|
||||
@@ -281,6 +408,458 @@ uint8_t *smbios_get_table(size_t *length)
|
||||
*length = smbios_entries_len;
|
||||
return smbios_entries;
|
||||
}
|
||||
/* end: legacy setup functions for <= 2.0 machines */
|
||||
|
||||
|
||||
static bool smbios_skip_table(uint8_t type, bool required_table)
|
||||
{
|
||||
if (test_bit(type, have_binfile_bitmap)) {
|
||||
return true; /* user provided their own binary blob(s) */
|
||||
}
|
||||
if (test_bit(type, have_fields_bitmap)) {
|
||||
return false; /* user provided fields via command line */
|
||||
}
|
||||
if (smbios_have_defaults && required_table) {
|
||||
return false; /* we're building tables, and this one's required */
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#define SMBIOS_BUILD_TABLE_PRE(tbl_type, tbl_handle, tbl_required) \
|
||||
struct smbios_type_##tbl_type *t; \
|
||||
size_t t_off; /* table offset into smbios_tables */ \
|
||||
int str_index = 0; \
|
||||
do { \
|
||||
/* should we skip building this table ? */ \
|
||||
if (smbios_skip_table(tbl_type, tbl_required)) { \
|
||||
return; \
|
||||
} \
|
||||
\
|
||||
/* use offset of table t within smbios_tables */ \
|
||||
/* (pointer must be updated after each realloc) */ \
|
||||
t_off = smbios_tables_len; \
|
||||
smbios_tables_len += sizeof(*t); \
|
||||
smbios_tables = g_realloc(smbios_tables, smbios_tables_len); \
|
||||
t = (struct smbios_type_##tbl_type *)(smbios_tables + t_off); \
|
||||
\
|
||||
t->header.type = tbl_type; \
|
||||
t->header.length = sizeof(*t); \
|
||||
t->header.handle = tbl_handle; \
|
||||
} while (0)
|
||||
|
||||
#define SMBIOS_TABLE_SET_STR(tbl_type, field, value) \
|
||||
do { \
|
||||
int len = (value != NULL) ? strlen(value) + 1 : 0; \
|
||||
if (len > 1) { \
|
||||
smbios_tables = g_realloc(smbios_tables, \
|
||||
smbios_tables_len + len); \
|
||||
memcpy(smbios_tables + smbios_tables_len, value, len); \
|
||||
smbios_tables_len += len; \
|
||||
/* update pointer post-realloc */ \
|
||||
t = (struct smbios_type_##tbl_type *)(smbios_tables + t_off); \
|
||||
t->field = ++str_index; \
|
||||
} else { \
|
||||
t->field = 0; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define SMBIOS_BUILD_TABLE_POST \
|
||||
do { \
|
||||
size_t term_cnt, t_size; \
|
||||
\
|
||||
/* add '\0' terminator (add two if no strings defined) */ \
|
||||
term_cnt = (str_index == 0) ? 2 : 1; \
|
||||
smbios_tables = g_realloc(smbios_tables, \
|
||||
smbios_tables_len + term_cnt); \
|
||||
memset(smbios_tables + smbios_tables_len, 0, term_cnt); \
|
||||
smbios_tables_len += term_cnt; \
|
||||
\
|
||||
/* update smbios max. element size */ \
|
||||
t_size = smbios_tables_len - t_off; \
|
||||
if (t_size > smbios_table_max) { \
|
||||
smbios_table_max = t_size; \
|
||||
} \
|
||||
\
|
||||
/* update smbios element count */ \
|
||||
smbios_table_cnt++; \
|
||||
} while (0)
|
||||
|
||||
static void smbios_build_type_0_table(void)
|
||||
{
|
||||
SMBIOS_BUILD_TABLE_PRE(0, 0x000, false); /* optional, leave up to BIOS */
|
||||
|
||||
SMBIOS_TABLE_SET_STR(0, vendor_str, type0.vendor);
|
||||
SMBIOS_TABLE_SET_STR(0, bios_version_str, type0.version);
|
||||
|
||||
t->bios_starting_address_segment = 0xE800; /* hardcoded in SeaBIOS */
|
||||
|
||||
SMBIOS_TABLE_SET_STR(0, bios_release_date_str, type0.date);
|
||||
|
||||
t->bios_rom_size = 0; /* hardcoded in SeaBIOS with FIXME comment */
|
||||
|
||||
/* BIOS characteristics not supported */
|
||||
memset(t->bios_characteristics, 0, 8);
|
||||
t->bios_characteristics[0] = 0x08;
|
||||
|
||||
/* Enable targeted content distribution (needed for SVVP, per SeaBIOS) */
|
||||
t->bios_characteristics_extension_bytes[0] = 0;
|
||||
t->bios_characteristics_extension_bytes[1] = 4;
|
||||
|
||||
if (type0.have_major_minor) {
|
||||
t->system_bios_major_release = type0.major;
|
||||
t->system_bios_minor_release = type0.minor;
|
||||
} else {
|
||||
t->system_bios_major_release = 0;
|
||||
t->system_bios_minor_release = 0;
|
||||
}
|
||||
|
||||
/* hardcoded in SeaBIOS */
|
||||
t->embedded_controller_major_release = 0xFF;
|
||||
t->embedded_controller_minor_release = 0xFF;
|
||||
|
||||
SMBIOS_BUILD_TABLE_POST;
|
||||
}
|
||||
|
||||
static void smbios_build_type_1_table(void)
|
||||
{
|
||||
SMBIOS_BUILD_TABLE_PRE(1, 0x100, true); /* required */
|
||||
|
||||
SMBIOS_TABLE_SET_STR(1, manufacturer_str, type1.manufacturer);
|
||||
SMBIOS_TABLE_SET_STR(1, product_name_str, type1.product);
|
||||
SMBIOS_TABLE_SET_STR(1, version_str, type1.version);
|
||||
SMBIOS_TABLE_SET_STR(1, serial_number_str, type1.serial);
|
||||
if (qemu_uuid_set) {
|
||||
memcpy(t->uuid, qemu_uuid, 16);
|
||||
} else {
|
||||
memset(t->uuid, 0, 16);
|
||||
}
|
||||
t->wake_up_type = 0x06; /* power switch */
|
||||
SMBIOS_TABLE_SET_STR(1, sku_number_str, type1.sku);
|
||||
SMBIOS_TABLE_SET_STR(1, family_str, type1.family);
|
||||
|
||||
SMBIOS_BUILD_TABLE_POST;
|
||||
}
|
||||
|
||||
static void smbios_build_type_2_table(void)
|
||||
{
|
||||
SMBIOS_BUILD_TABLE_PRE(2, 0x200, false); /* optional */
|
||||
|
||||
SMBIOS_TABLE_SET_STR(2, manufacturer_str, type2.manufacturer);
|
||||
SMBIOS_TABLE_SET_STR(2, product_str, type2.product);
|
||||
SMBIOS_TABLE_SET_STR(2, version_str, type2.version);
|
||||
SMBIOS_TABLE_SET_STR(2, serial_number_str, type2.serial);
|
||||
SMBIOS_TABLE_SET_STR(2, asset_tag_number_str, type2.asset);
|
||||
t->feature_flags = 0x01; /* Motherboard */
|
||||
SMBIOS_TABLE_SET_STR(2, location_str, type2.location);
|
||||
t->chassis_handle = 0x300; /* Type 3 (System enclosure) */
|
||||
t->board_type = 0x0A; /* Motherboard */
|
||||
t->contained_element_count = 0;
|
||||
|
||||
SMBIOS_BUILD_TABLE_POST;
|
||||
}
|
||||
|
||||
static void smbios_build_type_3_table(void)
|
||||
{
|
||||
SMBIOS_BUILD_TABLE_PRE(3, 0x300, true); /* required */
|
||||
|
||||
SMBIOS_TABLE_SET_STR(3, manufacturer_str, type3.manufacturer);
|
||||
t->type = 0x01; /* Other */
|
||||
SMBIOS_TABLE_SET_STR(3, version_str, type3.version);
|
||||
SMBIOS_TABLE_SET_STR(3, serial_number_str, type3.serial);
|
||||
SMBIOS_TABLE_SET_STR(3, asset_tag_number_str, type3.asset);
|
||||
t->boot_up_state = 0x03; /* Safe */
|
||||
t->power_supply_state = 0x03; /* Safe */
|
||||
t->thermal_state = 0x03; /* Safe */
|
||||
t->security_status = 0x02; /* Unknown */
|
||||
t->oem_defined = 0;
|
||||
t->height = 0;
|
||||
t->number_of_power_cords = 0;
|
||||
t->contained_element_count = 0;
|
||||
SMBIOS_TABLE_SET_STR(3, sku_number_str, type3.sku);
|
||||
|
||||
SMBIOS_BUILD_TABLE_POST;
|
||||
}
|
||||
|
||||
static void smbios_build_type_4_table(unsigned instance)
|
||||
{
|
||||
char sock_str[128];
|
||||
|
||||
SMBIOS_BUILD_TABLE_PRE(4, 0x400 + instance, true); /* required */
|
||||
|
||||
snprintf(sock_str, sizeof(sock_str), "%s%2x", type4.sock_pfx, instance);
|
||||
SMBIOS_TABLE_SET_STR(4, socket_designation_str, sock_str);
|
||||
t->processor_type = 0x03; /* CPU */
|
||||
SMBIOS_TABLE_SET_STR(4, processor_manufacturer_str, type4.manufacturer);
|
||||
t->processor_id[0] = smbios_cpuid_version;
|
||||
t->processor_id[1] = smbios_cpuid_features;
|
||||
SMBIOS_TABLE_SET_STR(4, processor_version_str, type4.version);
|
||||
t->voltage = 0;
|
||||
t->external_clock = 0; /* Unknown */
|
||||
t->max_speed = 0; /* Unknown */
|
||||
t->current_speed = 0; /* Unknown */
|
||||
t->status = 0x41; /* Socket populated, CPU enabled */
|
||||
t->processor_upgrade = 0x01; /* Other */
|
||||
t->l1_cache_handle = 0xFFFF; /* N/A */
|
||||
t->l2_cache_handle = 0xFFFF; /* N/A */
|
||||
t->l3_cache_handle = 0xFFFF; /* N/A */
|
||||
SMBIOS_TABLE_SET_STR(4, serial_number_str, type4.serial);
|
||||
SMBIOS_TABLE_SET_STR(4, asset_tag_number_str, type4.asset);
|
||||
SMBIOS_TABLE_SET_STR(4, part_number_str, type4.part);
|
||||
t->core_count = t->core_enabled = smp_cores;
|
||||
t->thread_count = smp_threads;
|
||||
t->processor_characteristics = 0x02; /* Unknown */
|
||||
t->processor_family = t->processor_family2 = 0x01; /* Other */
|
||||
|
||||
SMBIOS_BUILD_TABLE_POST;
|
||||
smbios_type4_count++;
|
||||
}
|
||||
|
||||
#define ONE_KB ((ram_addr_t)1 << 10)
|
||||
#define ONE_MB ((ram_addr_t)1 << 20)
|
||||
#define ONE_GB ((ram_addr_t)1 << 30)
|
||||
|
||||
#define MAX_T16_STD_SZ 0x80000000 /* 2T in Kilobytes */
|
||||
|
||||
static void smbios_build_type_16_table(unsigned dimm_cnt)
|
||||
{
|
||||
ram_addr_t size_kb;
|
||||
|
||||
SMBIOS_BUILD_TABLE_PRE(16, 0x1000, true); /* required */
|
||||
|
||||
t->location = 0x01; /* Other */
|
||||
t->use = 0x03; /* System memory */
|
||||
t->error_correction = 0x06; /* Multi-bit ECC (for Microsoft, per SeaBIOS) */
|
||||
size_kb = QEMU_ALIGN_UP(ram_size, ONE_KB) / ONE_KB;
|
||||
if (size_kb < MAX_T16_STD_SZ) {
|
||||
t->maximum_capacity = size_kb;
|
||||
t->extended_maximum_capacity = 0;
|
||||
} else {
|
||||
t->maximum_capacity = MAX_T16_STD_SZ;
|
||||
t->extended_maximum_capacity = ram_size;
|
||||
}
|
||||
t->memory_error_information_handle = 0xFFFE; /* Not provided */
|
||||
t->number_of_memory_devices = dimm_cnt;
|
||||
|
||||
SMBIOS_BUILD_TABLE_POST;
|
||||
}
|
||||
|
||||
#define MAX_T17_STD_SZ 0x7FFF /* (32G - 1M), in Megabytes */
|
||||
#define MAX_T17_EXT_SZ 0x80000000 /* 2P, in Megabytes */
|
||||
|
||||
static void smbios_build_type_17_table(unsigned instance, ram_addr_t size)
|
||||
{
|
||||
char loc_str[128];
|
||||
ram_addr_t size_mb;
|
||||
|
||||
SMBIOS_BUILD_TABLE_PRE(17, 0x1100 + instance, true); /* required */
|
||||
|
||||
t->physical_memory_array_handle = 0x1000; /* Type 16 (Phys. Mem. Array) */
|
||||
t->memory_error_information_handle = 0xFFFE; /* Not provided */
|
||||
t->total_width = 0xFFFF; /* Unknown */
|
||||
t->data_width = 0xFFFF; /* Unknown */
|
||||
size_mb = QEMU_ALIGN_UP(size, ONE_MB) / ONE_MB;
|
||||
if (size_mb < MAX_T17_STD_SZ) {
|
||||
t->size = size_mb;
|
||||
t->extended_size = 0;
|
||||
} else {
|
||||
assert(size_mb < MAX_T17_EXT_SZ);
|
||||
t->size = MAX_T17_STD_SZ;
|
||||
t->extended_size = size_mb;
|
||||
}
|
||||
t->form_factor = 0x09; /* DIMM */
|
||||
t->device_set = 0; /* Not in a set */
|
||||
snprintf(loc_str, sizeof(loc_str), "%s %d", type17.loc_pfx, instance);
|
||||
SMBIOS_TABLE_SET_STR(17, device_locator_str, loc_str);
|
||||
SMBIOS_TABLE_SET_STR(17, bank_locator_str, type17.bank);
|
||||
t->memory_type = 0x07; /* RAM */
|
||||
t->type_detail = 0x02; /* Other */
|
||||
t->speed = 0; /* Unknown */
|
||||
SMBIOS_TABLE_SET_STR(17, manufacturer_str, type17.manufacturer);
|
||||
SMBIOS_TABLE_SET_STR(17, serial_number_str, type17.serial);
|
||||
SMBIOS_TABLE_SET_STR(17, asset_tag_number_str, type17.asset);
|
||||
SMBIOS_TABLE_SET_STR(17, part_number_str, type17.part);
|
||||
t->attributes = 0; /* Unknown */
|
||||
t->configured_clock_speed = 0; /* Unknown */
|
||||
t->minimum_voltage = 0; /* Unknown */
|
||||
t->maximum_voltage = 0; /* Unknown */
|
||||
t->configured_voltage = 0; /* Unknown */
|
||||
|
||||
SMBIOS_BUILD_TABLE_POST;
|
||||
}
|
||||
|
||||
static void smbios_build_type_19_table(unsigned instance,
|
||||
ram_addr_t start, ram_addr_t size)
|
||||
{
|
||||
ram_addr_t end, start_kb, end_kb;
|
||||
|
||||
SMBIOS_BUILD_TABLE_PRE(19, 0x1300 + instance, true); /* required */
|
||||
|
||||
end = start + size - 1;
|
||||
assert(end > start);
|
||||
start_kb = start / ONE_KB;
|
||||
end_kb = end / ONE_KB;
|
||||
if (start_kb < UINT32_MAX && end_kb < UINT32_MAX) {
|
||||
t->starting_address = start_kb;
|
||||
t->ending_address = end_kb;
|
||||
t->extended_starting_address = t->extended_ending_address = 0;
|
||||
} else {
|
||||
t->starting_address = t->ending_address = UINT32_MAX;
|
||||
t->extended_starting_address = start;
|
||||
t->extended_ending_address = end;
|
||||
}
|
||||
t->memory_array_handle = 0x1000; /* Type 16 (Phys. Mem. Array) */
|
||||
t->partition_width = 1; /* One device per row */
|
||||
|
||||
SMBIOS_BUILD_TABLE_POST;
|
||||
}
|
||||
|
||||
static void smbios_build_type_32_table(void)
|
||||
{
|
||||
SMBIOS_BUILD_TABLE_PRE(32, 0x2000, true); /* required */
|
||||
|
||||
memset(t->reserved, 0, 6);
|
||||
t->boot_status = 0; /* No errors detected */
|
||||
|
||||
SMBIOS_BUILD_TABLE_POST;
|
||||
}
|
||||
|
||||
static void smbios_build_type_127_table(void)
|
||||
{
|
||||
SMBIOS_BUILD_TABLE_PRE(127, 0x7F00, true); /* required */
|
||||
SMBIOS_BUILD_TABLE_POST;
|
||||
}
|
||||
|
||||
void smbios_set_cpuid(uint32_t version, uint32_t features)
|
||||
{
|
||||
smbios_cpuid_version = version;
|
||||
smbios_cpuid_features = features;
|
||||
}
|
||||
|
||||
#define SMBIOS_SET_DEFAULT(field, value) \
|
||||
if (!field) { \
|
||||
field = value; \
|
||||
}
|
||||
|
||||
#define G_FREE_UNLESS_NULL(ptr) \
|
||||
if (ptr != NULL) { \
|
||||
g_free(ptr); \
|
||||
}
|
||||
|
||||
void smbios_set_defaults(const char *manufacturer, const char *product,
|
||||
const char *version, bool legacy_mode)
|
||||
{
|
||||
smbios_have_defaults = true;
|
||||
smbios_legacy = legacy_mode;
|
||||
|
||||
/* drop unwanted version of command-line file blob(s) */
|
||||
if (smbios_legacy) {
|
||||
G_FREE_UNLESS_NULL(smbios_tables);
|
||||
/* in legacy mode, also complain if fields were given for types > 1 */
|
||||
if (find_next_bit(have_fields_bitmap,
|
||||
SMBIOS_MAX_TYPE+1, 2) < SMBIOS_MAX_TYPE+1) {
|
||||
error_report("can't process fields for smbios "
|
||||
"types > 1 on machine versions < 2.1!");
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
G_FREE_UNLESS_NULL(smbios_entries);
|
||||
}
|
||||
|
||||
SMBIOS_SET_DEFAULT(type1.manufacturer, manufacturer);
|
||||
SMBIOS_SET_DEFAULT(type1.product, product);
|
||||
SMBIOS_SET_DEFAULT(type1.version, version);
|
||||
SMBIOS_SET_DEFAULT(type2.manufacturer, manufacturer);
|
||||
SMBIOS_SET_DEFAULT(type2.product, product);
|
||||
SMBIOS_SET_DEFAULT(type2.version, version);
|
||||
SMBIOS_SET_DEFAULT(type3.manufacturer, manufacturer);
|
||||
SMBIOS_SET_DEFAULT(type3.version, version);
|
||||
SMBIOS_SET_DEFAULT(type4.sock_pfx, "CPU");
|
||||
SMBIOS_SET_DEFAULT(type4.manufacturer, manufacturer);
|
||||
SMBIOS_SET_DEFAULT(type4.version, version);
|
||||
SMBIOS_SET_DEFAULT(type17.loc_pfx, "DIMM");
|
||||
SMBIOS_SET_DEFAULT(type17.manufacturer, manufacturer);
|
||||
}
|
||||
|
||||
static void smbios_entry_point_setup(void)
|
||||
{
|
||||
memcpy(ep.anchor_string, "_SM_", 4);
|
||||
memcpy(ep.intermediate_anchor_string, "_DMI_", 5);
|
||||
ep.length = sizeof(struct smbios_entry_point);
|
||||
ep.entry_point_revision = 0; /* formatted_area reserved, per spec v2.1+ */
|
||||
memset(ep.formatted_area, 0, 5);
|
||||
|
||||
/* compliant with smbios spec v2.8 */
|
||||
ep.smbios_major_version = 2;
|
||||
ep.smbios_minor_version = 8;
|
||||
ep.smbios_bcd_revision = 0x28;
|
||||
|
||||
/* set during table construction, but BIOS may override: */
|
||||
ep.structure_table_length = smbios_tables_len;
|
||||
ep.max_structure_size = smbios_table_max;
|
||||
ep.number_of_structures = smbios_table_cnt;
|
||||
|
||||
/* BIOS must recalculate: */
|
||||
ep.checksum = 0;
|
||||
ep.intermediate_checksum = 0;
|
||||
ep.structure_table_address = 0; /* where BIOS has copied smbios_tables */
|
||||
}
|
||||
|
||||
void smbios_get_tables(uint8_t **tables, size_t *tables_len,
|
||||
uint8_t **anchor, size_t *anchor_len)
|
||||
{
|
||||
unsigned i, dimm_cnt, instance;
|
||||
|
||||
if (smbios_legacy) {
|
||||
*tables = *anchor = NULL;
|
||||
*tables_len = *anchor_len = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!smbios_immutable) {
|
||||
smbios_build_type_0_table();
|
||||
smbios_build_type_1_table();
|
||||
smbios_build_type_2_table();
|
||||
smbios_build_type_3_table();
|
||||
|
||||
smbios_smp_sockets = smp_cpus / (smp_cores * smp_threads);
|
||||
assert(smbios_smp_sockets >= 1);
|
||||
|
||||
for (i = 0; i < smbios_smp_sockets; i++) {
|
||||
smbios_build_type_4_table(i);
|
||||
}
|
||||
|
||||
#define MAX_DIMM_SZ (16ll * ONE_GB)
|
||||
#define GET_DIMM_SZ ((i < dimm_cnt - 1) ? MAX_DIMM_SZ : ram_size % MAX_DIMM_SZ)
|
||||
|
||||
dimm_cnt = QEMU_ALIGN_UP(ram_size, MAX_DIMM_SZ) / MAX_DIMM_SZ;
|
||||
|
||||
smbios_build_type_16_table(dimm_cnt);
|
||||
|
||||
for (i = 0; i < dimm_cnt; i++) {
|
||||
smbios_build_type_17_table(i, GET_DIMM_SZ);
|
||||
}
|
||||
|
||||
for (i = 0, instance = 0; i < e820_get_num_entries(); i++) {
|
||||
uint64_t address, length;
|
||||
if (e820_get_entry(i, E820_RAM, &address, &length)) {
|
||||
smbios_build_type_19_table(instance++, address, length);
|
||||
}
|
||||
}
|
||||
|
||||
smbios_build_type_32_table();
|
||||
smbios_build_type_127_table();
|
||||
|
||||
smbios_validate_table();
|
||||
smbios_entry_point_setup();
|
||||
smbios_immutable = true;
|
||||
}
|
||||
|
||||
/* return tables blob and entry point (anchor), and their sizes */
|
||||
*tables = smbios_tables;
|
||||
*tables_len = smbios_tables_len;
|
||||
*anchor = (uint8_t *)&ep;
|
||||
*anchor_len = sizeof(struct smbios_entry_point);
|
||||
}
|
||||
|
||||
static void save_opt(const char **dest, QemuOpts *opts, const char *name)
|
||||
{
|
||||
@@ -297,11 +876,12 @@ void smbios_entry_add(QemuOpts *opts)
|
||||
const char *val;
|
||||
|
||||
assert(!smbios_immutable);
|
||||
|
||||
val = qemu_opt_get(opts, "file");
|
||||
if (val) {
|
||||
struct smbios_structure_header *header;
|
||||
struct smbios_table *table;
|
||||
int size;
|
||||
struct smbios_table *table; /* legacy mode only */
|
||||
|
||||
qemu_opts_validate(opts, qemu_smbios_file_opts, &local_err);
|
||||
if (local_err) {
|
||||
@@ -315,31 +895,60 @@ void smbios_entry_add(QemuOpts *opts)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!smbios_entries) {
|
||||
smbios_entries_len = sizeof(uint16_t);
|
||||
smbios_entries = g_malloc0(smbios_entries_len);
|
||||
}
|
||||
/*
|
||||
* NOTE: standard double '\0' terminator expected, per smbios spec.
|
||||
* (except in legacy mode, where the second '\0' is implicit and
|
||||
* will be inserted by the BIOS).
|
||||
*/
|
||||
smbios_tables = g_realloc(smbios_tables, smbios_tables_len + size);
|
||||
header = (struct smbios_structure_header *)(smbios_tables +
|
||||
smbios_tables_len);
|
||||
|
||||
smbios_entries = g_realloc(smbios_entries, smbios_entries_len +
|
||||
sizeof(*table) + size);
|
||||
table = (struct smbios_table *)(smbios_entries + smbios_entries_len);
|
||||
table->header.type = SMBIOS_TABLE_ENTRY;
|
||||
table->header.length = cpu_to_le16(sizeof(*table) + size);
|
||||
|
||||
if (load_image(val, table->data) != size) {
|
||||
if (load_image(val, (uint8_t *)header) != size) {
|
||||
error_report("Failed to load SMBIOS file %s", val);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
header = (struct smbios_structure_header *)(table->data);
|
||||
smbios_check_collision(header->type, SMBIOS_TABLE_ENTRY);
|
||||
if (test_bit(header->type, have_fields_bitmap)) {
|
||||
error_report("can't load type %d struct, fields already specified!",
|
||||
header->type);
|
||||
exit(1);
|
||||
}
|
||||
set_bit(header->type, have_binfile_bitmap);
|
||||
|
||||
if (header->type == 4) {
|
||||
smbios_type4_count++;
|
||||
}
|
||||
|
||||
smbios_tables_len += size;
|
||||
if (size > smbios_table_max) {
|
||||
smbios_table_max = size;
|
||||
}
|
||||
smbios_table_cnt++;
|
||||
|
||||
/* add a copy of the newly loaded blob to legacy smbios_entries */
|
||||
/* NOTE: This code runs before smbios_set_defaults(), so we don't
|
||||
* yet know which mode (legacy vs. aggregate-table) will be
|
||||
* required. We therefore add the binary blob to both legacy
|
||||
* (smbios_entries) and aggregate (smbios_tables) tables, and
|
||||
* delete the one we don't need from smbios_set_defaults(),
|
||||
* once we know which machine version has been requested.
|
||||
*/
|
||||
if (!smbios_entries) {
|
||||
smbios_entries_len = sizeof(uint16_t);
|
||||
smbios_entries = g_malloc0(smbios_entries_len);
|
||||
}
|
||||
smbios_entries = g_realloc(smbios_entries, smbios_entries_len +
|
||||
size + sizeof(*table));
|
||||
table = (struct smbios_table *)(smbios_entries + smbios_entries_len);
|
||||
table->header.type = SMBIOS_TABLE_ENTRY;
|
||||
table->header.length = cpu_to_le16(sizeof(*table) + size);
|
||||
memcpy(table->data, header, size);
|
||||
smbios_entries_len += sizeof(*table) + size;
|
||||
(*(uint16_t *)smbios_entries) =
|
||||
cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1);
|
||||
/* end: add a copy of the newly loaded blob to legacy smbios_entries */
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -347,7 +956,16 @@ void smbios_entry_add(QemuOpts *opts)
|
||||
if (val) {
|
||||
unsigned long type = strtoul(val, NULL, 0);
|
||||
|
||||
smbios_check_collision(type, SMBIOS_FIELD_ENTRY);
|
||||
if (type > SMBIOS_MAX_TYPE) {
|
||||
error_report("out of range!");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (test_bit(type, have_binfile_bitmap)) {
|
||||
error_report("can't add fields, binary file already loaded!");
|
||||
exit(1);
|
||||
}
|
||||
set_bit(type, have_fields_bitmap);
|
||||
|
||||
switch (type) {
|
||||
case 0:
|
||||
@@ -391,6 +1009,57 @@ void smbios_entry_add(QemuOpts *opts)
|
||||
qemu_uuid_set = true;
|
||||
}
|
||||
return;
|
||||
case 2:
|
||||
qemu_opts_validate(opts, qemu_smbios_type2_opts, &local_err);
|
||||
if (local_err) {
|
||||
error_report("%s", error_get_pretty(local_err));
|
||||
exit(1);
|
||||
}
|
||||
save_opt(&type2.manufacturer, opts, "manufacturer");
|
||||
save_opt(&type2.product, opts, "product");
|
||||
save_opt(&type2.version, opts, "version");
|
||||
save_opt(&type2.serial, opts, "serial");
|
||||
save_opt(&type2.asset, opts, "asset");
|
||||
save_opt(&type2.location, opts, "location");
|
||||
return;
|
||||
case 3:
|
||||
qemu_opts_validate(opts, qemu_smbios_type3_opts, &local_err);
|
||||
if (local_err) {
|
||||
error_report("%s", error_get_pretty(local_err));
|
||||
exit(1);
|
||||
}
|
||||
save_opt(&type3.manufacturer, opts, "manufacturer");
|
||||
save_opt(&type3.version, opts, "version");
|
||||
save_opt(&type3.serial, opts, "serial");
|
||||
save_opt(&type3.asset, opts, "asset");
|
||||
save_opt(&type3.sku, opts, "sku");
|
||||
return;
|
||||
case 4:
|
||||
qemu_opts_validate(opts, qemu_smbios_type4_opts, &local_err);
|
||||
if (local_err) {
|
||||
error_report("%s", error_get_pretty(local_err));
|
||||
exit(1);
|
||||
}
|
||||
save_opt(&type4.sock_pfx, opts, "sock_pfx");
|
||||
save_opt(&type4.manufacturer, opts, "manufacturer");
|
||||
save_opt(&type4.version, opts, "version");
|
||||
save_opt(&type4.serial, opts, "serial");
|
||||
save_opt(&type4.asset, opts, "asset");
|
||||
save_opt(&type4.part, opts, "part");
|
||||
return;
|
||||
case 17:
|
||||
qemu_opts_validate(opts, qemu_smbios_type17_opts, &local_err);
|
||||
if (local_err) {
|
||||
error_report("%s", error_get_pretty(local_err));
|
||||
exit(1);
|
||||
}
|
||||
save_opt(&type17.loc_pfx, opts, "loc_pfx");
|
||||
save_opt(&type17.bank, opts, "bank");
|
||||
save_opt(&type17.manufacturer, opts, "manufacturer");
|
||||
save_opt(&type17.serial, opts, "serial");
|
||||
save_opt(&type17.asset, opts, "asset");
|
||||
save_opt(&type17.part, opts, "part");
|
||||
return;
|
||||
default:
|
||||
error_report("Don't know how to build fields for SMBIOS type %ld",
|
||||
type);
|
||||
|
@@ -173,7 +173,7 @@ static uint32_t nvic_readl(nvic_state *s, uint32_t offset)
|
||||
return 10000;
|
||||
case 0xd00: /* CPUID Base. */
|
||||
cpu = ARM_CPU(current_cpu);
|
||||
return cpu->env.cp15.c0_cpuid;
|
||||
return cpu->midr;
|
||||
case 0xd04: /* Interrupt Control State. */
|
||||
/* VECTACTIVE */
|
||||
val = s->gic.running_irq[0];
|
||||
|
@@ -234,13 +234,9 @@ static void kvm_openpic_realize(DeviceState *dev, Error **errp)
|
||||
int kvm_openpic_connect_vcpu(DeviceState *d, CPUState *cs)
|
||||
{
|
||||
KVMOpenPICState *opp = KVM_OPENPIC(d);
|
||||
struct kvm_enable_cap encap = {};
|
||||
|
||||
encap.cap = KVM_CAP_IRQ_MPIC;
|
||||
encap.args[0] = opp->fd;
|
||||
encap.args[1] = kvm_arch_vcpu_id(cs);
|
||||
|
||||
return kvm_vcpu_ioctl(cs, KVM_ENABLE_CAP, &encap);
|
||||
return kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_MPIC, 0, opp->fd,
|
||||
kvm_arch_vcpu_id(cs));
|
||||
}
|
||||
|
||||
static Property kvm_openpic_properties[] = {
|
||||
|
@@ -331,15 +331,11 @@ static void xics_kvm_cpu_setup(XICSState *icp, PowerPCCPU *cpu)
|
||||
|
||||
if (icpkvm->kernel_xics_fd != -1) {
|
||||
int ret;
|
||||
struct kvm_enable_cap xics_enable_cap = {
|
||||
.cap = KVM_CAP_IRQ_XICS,
|
||||
.flags = 0,
|
||||
.args = {icpkvm->kernel_xics_fd, kvm_arch_vcpu_id(cs), 0, 0},
|
||||
};
|
||||
|
||||
ss->cs = cs;
|
||||
|
||||
ret = kvm_vcpu_ioctl(ss->cs, KVM_ENABLE_CAP, &xics_enable_cap);
|
||||
ret = kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_XICS, 0,
|
||||
icpkvm->kernel_xics_fd, kvm_arch_vcpu_id(cs));
|
||||
if (ret < 0) {
|
||||
error_report("Unable to connect CPU%ld to kernel XICS: %s",
|
||||
kvm_arch_vcpu_id(cs), strerror(errno));
|
||||
|
@@ -92,6 +92,7 @@ typedef enum {
|
||||
|
||||
#define BDRV_O_RDWR 0x0002
|
||||
#define BDRV_O_SNAPSHOT 0x0008 /* open the file read only and save writes in a snapshot */
|
||||
#define BDRV_O_TEMPORARY 0x0010 /* delete the file after use */
|
||||
#define BDRV_O_NOCACHE 0x0020 /* do not use the host page cache */
|
||||
#define BDRV_O_CACHE_WB 0x0040 /* use write-back caching */
|
||||
#define BDRV_O_NATIVE_AIO 0x0080 /* use native AIO instead of the thread pool */
|
||||
|
@@ -299,7 +299,6 @@ struct BlockDriverState {
|
||||
char backing_file[1024]; /* if non zero, the image is a diff of
|
||||
this file image */
|
||||
char backing_format[16]; /* if non-zero and backing_file exists */
|
||||
int is_temporary;
|
||||
|
||||
BlockDriverState *backing_hd;
|
||||
BlockDriverState *file;
|
||||
|
@@ -84,7 +84,7 @@
|
||||
#define dh_is_64bit_noreturn 0
|
||||
#define dh_is_64bit_i32 0
|
||||
#define dh_is_64bit_i64 1
|
||||
#define dh_is_64bit_ptr (TCG_TARGET_REG_BITS == 64)
|
||||
#define dh_is_64bit_ptr (sizeof(void *) == 8)
|
||||
#define dh_is_64bit(t) glue(dh_is_64bit_, dh_alias(t))
|
||||
|
||||
#define dh_is_signed_void 0
|
||||
|
@@ -239,6 +239,8 @@ uint16_t pvpanic_port(void);
|
||||
#define E820_UNUSABLE 5
|
||||
|
||||
int e820_add_entry(uint64_t, uint64_t, uint32_t);
|
||||
int e820_get_num_entries(void);
|
||||
bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
|
||||
|
||||
#define PC_Q35_COMPAT_1_7 \
|
||||
PC_COMPAT_1_7, \
|
||||
|
@@ -15,15 +15,40 @@
|
||||
|
||||
#include "qemu/option.h"
|
||||
|
||||
#define SMBIOS_MAX_TYPE 127
|
||||
|
||||
void smbios_entry_add(QemuOpts *opts);
|
||||
void smbios_set_type1_defaults(const char *manufacturer,
|
||||
const char *product, const char *version);
|
||||
uint8_t *smbios_get_table(size_t *length);
|
||||
void smbios_set_cpuid(uint32_t version, uint32_t features);
|
||||
void smbios_set_defaults(const char *manufacturer, const char *product,
|
||||
const char *version, bool legacy_mode);
|
||||
uint8_t *smbios_get_table_legacy(size_t *length);
|
||||
void smbios_get_tables(uint8_t **tables, size_t *tables_len,
|
||||
uint8_t **anchor, size_t *anchor_len);
|
||||
|
||||
/*
|
||||
* SMBIOS spec defined tables
|
||||
*/
|
||||
|
||||
/* SMBIOS entry point (anchor).
|
||||
* BIOS must place this at a 16-bit-aligned address between 0xf0000 and 0xfffff.
|
||||
*/
|
||||
struct smbios_entry_point {
|
||||
uint8_t anchor_string[4];
|
||||
uint8_t checksum;
|
||||
uint8_t length;
|
||||
uint8_t smbios_major_version;
|
||||
uint8_t smbios_minor_version;
|
||||
uint16_t max_structure_size;
|
||||
uint8_t entry_point_revision;
|
||||
uint8_t formatted_area[5];
|
||||
uint8_t intermediate_anchor_string[5];
|
||||
uint8_t intermediate_checksum;
|
||||
uint16_t structure_table_length;
|
||||
uint32_t structure_table_address;
|
||||
uint16_t number_of_structures;
|
||||
uint8_t smbios_bcd_revision;
|
||||
} QEMU_PACKED;
|
||||
|
||||
/* This goes at the beginning of every SMBIOS structure. */
|
||||
struct smbios_structure_header {
|
||||
uint8_t type;
|
||||
@@ -60,7 +85,23 @@ struct smbios_type_1 {
|
||||
uint8_t family_str;
|
||||
} QEMU_PACKED;
|
||||
|
||||
/* SMBIOS type 3 - System Enclosure (v2.3) */
|
||||
/* SMBIOS type 2 - Base Board */
|
||||
struct smbios_type_2 {
|
||||
struct smbios_structure_header header;
|
||||
uint8_t manufacturer_str;
|
||||
uint8_t product_str;
|
||||
uint8_t version_str;
|
||||
uint8_t serial_number_str;
|
||||
uint8_t asset_tag_number_str;
|
||||
uint8_t feature_flags;
|
||||
uint8_t location_str;
|
||||
uint16_t chassis_handle;
|
||||
uint8_t board_type;
|
||||
uint8_t contained_element_count;
|
||||
/* contained elements follow */
|
||||
} QEMU_PACKED;
|
||||
|
||||
/* SMBIOS type 3 - System Enclosure (v2.7) */
|
||||
struct smbios_type_3 {
|
||||
struct smbios_structure_header header;
|
||||
uint8_t manufacturer_str;
|
||||
@@ -76,10 +117,11 @@ struct smbios_type_3 {
|
||||
uint8_t height;
|
||||
uint8_t number_of_power_cords;
|
||||
uint8_t contained_element_count;
|
||||
// contained elements follow
|
||||
uint8_t sku_number_str;
|
||||
/* contained elements follow */
|
||||
} QEMU_PACKED;
|
||||
|
||||
/* SMBIOS type 4 - Processor Information (v2.0) */
|
||||
/* SMBIOS type 4 - Processor Information (v2.6) */
|
||||
struct smbios_type_4 {
|
||||
struct smbios_structure_header header;
|
||||
uint8_t socket_designation_str;
|
||||
@@ -97,11 +139,17 @@ struct smbios_type_4 {
|
||||
uint16_t l1_cache_handle;
|
||||
uint16_t l2_cache_handle;
|
||||
uint16_t l3_cache_handle;
|
||||
uint8_t serial_number_str;
|
||||
uint8_t asset_tag_number_str;
|
||||
uint8_t part_number_str;
|
||||
uint8_t core_count;
|
||||
uint8_t core_enabled;
|
||||
uint8_t thread_count;
|
||||
uint16_t processor_characteristics;
|
||||
uint16_t processor_family2;
|
||||
} QEMU_PACKED;
|
||||
|
||||
/* SMBIOS type 16 - Physical Memory Array
|
||||
* Associated with one type 17 (Memory Device).
|
||||
*/
|
||||
/* SMBIOS type 16 - Physical Memory Array (v2.7) */
|
||||
struct smbios_type_16 {
|
||||
struct smbios_structure_header header;
|
||||
uint8_t location;
|
||||
@@ -110,10 +158,10 @@ struct smbios_type_16 {
|
||||
uint32_t maximum_capacity;
|
||||
uint16_t memory_error_information_handle;
|
||||
uint16_t number_of_memory_devices;
|
||||
uint64_t extended_maximum_capacity;
|
||||
} QEMU_PACKED;
|
||||
/* SMBIOS type 17 - Memory Device
|
||||
* Associated with one type 19
|
||||
*/
|
||||
|
||||
/* SMBIOS type 17 - Memory Device (v2.8) */
|
||||
struct smbios_type_17 {
|
||||
struct smbios_structure_header header;
|
||||
uint16_t physical_memory_array_handle;
|
||||
@@ -127,27 +175,28 @@ struct smbios_type_17 {
|
||||
uint8_t bank_locator_str;
|
||||
uint8_t memory_type;
|
||||
uint16_t type_detail;
|
||||
uint16_t speed;
|
||||
uint8_t manufacturer_str;
|
||||
uint8_t serial_number_str;
|
||||
uint8_t asset_tag_number_str;
|
||||
uint8_t part_number_str;
|
||||
uint8_t attributes;
|
||||
uint32_t extended_size;
|
||||
uint32_t configured_clock_speed;
|
||||
uint32_t minimum_voltage;
|
||||
uint32_t maximum_voltage;
|
||||
uint32_t configured_voltage;
|
||||
} QEMU_PACKED;
|
||||
|
||||
/* SMBIOS type 19 - Memory Array Mapped Address */
|
||||
/* SMBIOS type 19 - Memory Array Mapped Address (v2.7) */
|
||||
struct smbios_type_19 {
|
||||
struct smbios_structure_header header;
|
||||
uint32_t starting_address;
|
||||
uint32_t ending_address;
|
||||
uint16_t memory_array_handle;
|
||||
uint8_t partition_width;
|
||||
} QEMU_PACKED;
|
||||
|
||||
/* SMBIOS type 20 - Memory Device Mapped Address */
|
||||
struct smbios_type_20 {
|
||||
struct smbios_structure_header header;
|
||||
uint32_t starting_address;
|
||||
uint32_t ending_address;
|
||||
uint16_t memory_device_handle;
|
||||
uint16_t memory_array_mapped_address_handle;
|
||||
uint8_t partition_row_position;
|
||||
uint8_t interleave_position;
|
||||
uint8_t interleaved_data_depth;
|
||||
uint64_t extended_starting_address;
|
||||
uint64_t extended_ending_address;
|
||||
} QEMU_PACKED;
|
||||
|
||||
/* SMBIOS type 32 - System Boot Information */
|
||||
|
@@ -294,6 +294,36 @@ bool kvm_arch_stop_on_emulation_error(CPUState *cpu);
|
||||
|
||||
int kvm_check_extension(KVMState *s, unsigned int extension);
|
||||
|
||||
#define kvm_vm_enable_cap(s, capability, cap_flags, ...) \
|
||||
({ \
|
||||
struct kvm_enable_cap cap = { \
|
||||
.cap = capability, \
|
||||
.flags = cap_flags, \
|
||||
}; \
|
||||
uint64_t args_tmp[] = { __VA_ARGS__ }; \
|
||||
int i; \
|
||||
for (i = 0; i < ARRAY_SIZE(args_tmp) && \
|
||||
i < ARRAY_SIZE(cap.args); i++) { \
|
||||
cap.args[i] = args_tmp[i]; \
|
||||
} \
|
||||
kvm_vm_ioctl(s, KVM_ENABLE_CAP, &cap); \
|
||||
})
|
||||
|
||||
#define kvm_vcpu_enable_cap(cpu, capability, cap_flags, ...) \
|
||||
({ \
|
||||
struct kvm_enable_cap cap = { \
|
||||
.cap = capability, \
|
||||
.flags = cap_flags, \
|
||||
}; \
|
||||
uint64_t args_tmp[] = { __VA_ARGS__ }; \
|
||||
int i; \
|
||||
for (i = 0; i < ARRAY_SIZE(args_tmp) && \
|
||||
i < ARRAY_SIZE(cap.args); i++) { \
|
||||
cap.args[i] = args_tmp[i]; \
|
||||
} \
|
||||
kvm_vcpu_ioctl(cpu, KVM_ENABLE_CAP, &cap); \
|
||||
})
|
||||
|
||||
uint32_t kvm_arch_get_supported_cpuid(KVMState *env, uint32_t function,
|
||||
uint32_t index, int reg);
|
||||
|
||||
|
24
qemu-img.c
24
qemu-img.c
@@ -33,6 +33,9 @@
|
||||
#include "block/qapi.h"
|
||||
#include <getopt.h>
|
||||
|
||||
#define QEMU_IMG_VERSION "qemu-img version " QEMU_VERSION \
|
||||
", Copyright (c) 2004-2008 Fabrice Bellard\n"
|
||||
|
||||
typedef struct img_cmd_t {
|
||||
const char *name;
|
||||
int (*handler)(int argc, char **argv);
|
||||
@@ -75,7 +78,7 @@ static void QEMU_NORETURN GCC_FMT_ATTR(1, 2) error_exit(const char *fmt, ...)
|
||||
static void QEMU_NORETURN help(void)
|
||||
{
|
||||
const char *help_msg =
|
||||
"qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2008 Fabrice Bellard\n"
|
||||
QEMU_IMG_VERSION
|
||||
"usage: qemu-img command [command options]\n"
|
||||
"QEMU disk image utility\n"
|
||||
"\n"
|
||||
@@ -2789,6 +2792,12 @@ int main(int argc, char **argv)
|
||||
{
|
||||
const img_cmd_t *cmd;
|
||||
const char *cmdname;
|
||||
int c;
|
||||
static const struct option long_options[] = {
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"version", no_argument, 0, 'v'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
#ifdef CONFIG_POSIX
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
@@ -2803,15 +2812,24 @@ int main(int argc, char **argv)
|
||||
error_exit("Not enough arguments");
|
||||
}
|
||||
cmdname = argv[1];
|
||||
argc--; argv++;
|
||||
|
||||
/* find the command */
|
||||
for (cmd = img_cmds; cmd->name != NULL; cmd++) {
|
||||
if (!strcmp(cmdname, cmd->name)) {
|
||||
return cmd->handler(argc, argv);
|
||||
return cmd->handler(argc - 1, argv + 1);
|
||||
}
|
||||
}
|
||||
|
||||
c = getopt_long(argc, argv, "h", long_options, NULL);
|
||||
|
||||
if (c == 'h') {
|
||||
help();
|
||||
}
|
||||
if (c == 'v') {
|
||||
printf(QEMU_IMG_VERSION);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* not found */
|
||||
error_exit("Command not found: %s", cmdname);
|
||||
}
|
||||
|
@@ -657,7 +657,7 @@ static void vbar_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||
* contexts. (ARMv8 would permit us to do no masking at all, but ARMv7
|
||||
* requires the bottom five bits to be RAZ/WI because they're UNK/SBZP.)
|
||||
*/
|
||||
env->cp15.c12_vbar = value & ~0x1Ful;
|
||||
env->cp15.c12_vbar = value & ~0x1FULL;
|
||||
}
|
||||
|
||||
static uint64_t ccsidr_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||
@@ -1578,6 +1578,21 @@ static const ARMCPRegInfo xscale_cp_reginfo[] = {
|
||||
.cp = 15, .crn = 1, .crm = 0, .opc1 = 0, .opc2 = 1, .access = PL1_RW,
|
||||
.fieldoffset = offsetof(CPUARMState, cp15.c1_xscaleauxcr),
|
||||
.resetvalue = 0, },
|
||||
/* XScale specific cache-lockdown: since we have no cache we NOP these
|
||||
* and hope the guest does not really rely on cache behaviour.
|
||||
*/
|
||||
{ .name = "XSCALE_LOCK_ICACHE_LINE",
|
||||
.cp = 15, .opc1 = 0, .crn = 9, .crm = 1, .opc2 = 0,
|
||||
.access = PL1_W, .type = ARM_CP_NOP },
|
||||
{ .name = "XSCALE_UNLOCK_ICACHE",
|
||||
.cp = 15, .opc1 = 0, .crn = 9, .crm = 1, .opc2 = 1,
|
||||
.access = PL1_W, .type = ARM_CP_NOP },
|
||||
{ .name = "XSCALE_DCACHE_LOCK",
|
||||
.cp = 15, .opc1 = 0, .crn = 9, .crm = 2, .opc2 = 0,
|
||||
.access = PL1_RW, .type = ARM_CP_NOP },
|
||||
{ .name = "XSCALE_UNLOCK_DCACHE",
|
||||
.cp = 15, .opc1 = 0, .crn = 9, .crm = 2, .opc2 = 1,
|
||||
.access = PL1_W, .type = ARM_CP_NOP },
|
||||
REGINFO_SENTINEL
|
||||
};
|
||||
|
||||
@@ -1893,51 +1908,51 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
|
||||
.access = PL1_W, .type = ARM_CP_NOP },
|
||||
/* TLBI operations */
|
||||
{ .name = "TLBI_VMALLE1IS", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc2 = 0, .crn = 8, .crm = 3, .opc2 = 0,
|
||||
.opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 0,
|
||||
.access = PL1_W, .type = ARM_CP_NO_MIGRATE,
|
||||
.writefn = tlbiall_write },
|
||||
{ .name = "TLBI_VAE1IS", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc2 = 0, .crn = 8, .crm = 3, .opc2 = 1,
|
||||
.opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 1,
|
||||
.access = PL1_W, .type = ARM_CP_NO_MIGRATE,
|
||||
.writefn = tlbi_aa64_va_write },
|
||||
{ .name = "TLBI_ASIDE1IS", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc2 = 0, .crn = 8, .crm = 3, .opc2 = 2,
|
||||
.opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 2,
|
||||
.access = PL1_W, .type = ARM_CP_NO_MIGRATE,
|
||||
.writefn = tlbi_aa64_asid_write },
|
||||
{ .name = "TLBI_VAAE1IS", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc2 = 0, .crn = 8, .crm = 3, .opc2 = 3,
|
||||
.opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 3,
|
||||
.access = PL1_W, .type = ARM_CP_NO_MIGRATE,
|
||||
.writefn = tlbi_aa64_vaa_write },
|
||||
{ .name = "TLBI_VALE1IS", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc2 = 0, .crn = 8, .crm = 3, .opc2 = 5,
|
||||
.opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 5,
|
||||
.access = PL1_W, .type = ARM_CP_NO_MIGRATE,
|
||||
.writefn = tlbi_aa64_va_write },
|
||||
{ .name = "TLBI_VAALE1IS", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc2 = 0, .crn = 8, .crm = 3, .opc2 = 7,
|
||||
.opc0 = 1, .opc1 = 0, .crn = 8, .crm = 3, .opc2 = 7,
|
||||
.access = PL1_W, .type = ARM_CP_NO_MIGRATE,
|
||||
.writefn = tlbi_aa64_vaa_write },
|
||||
{ .name = "TLBI_VMALLE1", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc2 = 0, .crn = 8, .crm = 7, .opc2 = 0,
|
||||
.opc0 = 1, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 0,
|
||||
.access = PL1_W, .type = ARM_CP_NO_MIGRATE,
|
||||
.writefn = tlbiall_write },
|
||||
{ .name = "TLBI_VAE1", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc2 = 0, .crn = 8, .crm = 7, .opc2 = 1,
|
||||
.opc0 = 1, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 1,
|
||||
.access = PL1_W, .type = ARM_CP_NO_MIGRATE,
|
||||
.writefn = tlbi_aa64_va_write },
|
||||
{ .name = "TLBI_ASIDE1", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc2 = 0, .crn = 8, .crm = 7, .opc2 = 2,
|
||||
.opc0 = 1, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 2,
|
||||
.access = PL1_W, .type = ARM_CP_NO_MIGRATE,
|
||||
.writefn = tlbi_aa64_asid_write },
|
||||
{ .name = "TLBI_VAAE1", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc2 = 0, .crn = 8, .crm = 7, .opc2 = 3,
|
||||
.opc0 = 1, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 3,
|
||||
.access = PL1_W, .type = ARM_CP_NO_MIGRATE,
|
||||
.writefn = tlbi_aa64_vaa_write },
|
||||
{ .name = "TLBI_VALE1", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc2 = 0, .crn = 8, .crm = 7, .opc2 = 5,
|
||||
.opc0 = 1, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 5,
|
||||
.access = PL1_W, .type = ARM_CP_NO_MIGRATE,
|
||||
.writefn = tlbi_aa64_va_write },
|
||||
{ .name = "TLBI_VAALE1", .state = ARM_CP_STATE_AA64,
|
||||
.opc0 = 1, .opc2 = 0, .crn = 8, .crm = 7, .opc2 = 7,
|
||||
.opc0 = 1, .opc1 = 0, .crn = 8, .crm = 7, .opc2 = 7,
|
||||
.access = PL1_W, .type = ARM_CP_NO_MIGRATE,
|
||||
.writefn = tlbi_aa64_vaa_write },
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
|
@@ -418,7 +418,7 @@ void HELPER(exception_return)(CPUARMState *env)
|
||||
goto illegal_return;
|
||||
}
|
||||
if (new_el == 0 && (spsr & PSTATE_SP)) {
|
||||
/* Return to EL1 with M[0] bit set */
|
||||
/* Return to EL0 with M[0] bit set */
|
||||
goto illegal_return;
|
||||
}
|
||||
env->aarch64 = 1;
|
||||
|
@@ -1151,6 +1151,8 @@ static void handle_hint(DisasContext *s, uint32_t insn,
|
||||
return;
|
||||
case 1: /* YIELD */
|
||||
case 2: /* WFE */
|
||||
s->is_jmp = DISAS_WFE;
|
||||
return;
|
||||
case 4: /* SEV */
|
||||
case 5: /* SEVL */
|
||||
/* we treat all as NOP at least for now */
|
||||
@@ -1507,8 +1509,10 @@ static void disas_uncond_b_reg(DisasContext *s, uint32_t insn)
|
||||
switch (opc) {
|
||||
case 0: /* BR */
|
||||
case 2: /* RET */
|
||||
tcg_gen_mov_i64(cpu_pc, cpu_reg(s, rn));
|
||||
break;
|
||||
case 1: /* BLR */
|
||||
tcg_gen_mov_i64(cpu_pc, cpu_reg(s, rn));
|
||||
tcg_gen_movi_i64(cpu_reg(s, 30), s->pc);
|
||||
break;
|
||||
case 4: /* ERET */
|
||||
@@ -1527,7 +1531,6 @@ static void disas_uncond_b_reg(DisasContext *s, uint32_t insn)
|
||||
return;
|
||||
}
|
||||
|
||||
tcg_gen_mov_i64(cpu_pc, cpu_reg(s, rn));
|
||||
s->is_jmp = DISAS_JUMP;
|
||||
}
|
||||
|
||||
@@ -10765,6 +10768,10 @@ void gen_intermediate_code_internal_a64(ARMCPU *cpu,
|
||||
case DISAS_EXC:
|
||||
case DISAS_SWI:
|
||||
break;
|
||||
case DISAS_WFE:
|
||||
gen_a64_set_pc_im(dc->pc);
|
||||
gen_helper_wfe(cpu_env);
|
||||
break;
|
||||
case DISAS_WFI:
|
||||
/* This is a special case because we don't want to just halt the CPU
|
||||
* if trying to debug across a WFI.
|
||||
|
@@ -151,7 +151,6 @@ static int kvm_booke206_tlb_init(PowerPCCPU *cpu)
|
||||
CPUState *cs = CPU(cpu);
|
||||
struct kvm_book3e_206_tlb_params params = {};
|
||||
struct kvm_config_tlb cfg = {};
|
||||
struct kvm_enable_cap encap = {};
|
||||
unsigned int entries = 0;
|
||||
int ret, i;
|
||||
|
||||
@@ -178,10 +177,7 @@ static int kvm_booke206_tlb_init(PowerPCCPU *cpu)
|
||||
cfg.params = (uintptr_t)¶ms;
|
||||
cfg.mmu_type = KVM_MMU_FSL_BOOKE_NOHV;
|
||||
|
||||
encap.cap = KVM_CAP_SW_TLB;
|
||||
encap.args[0] = (uintptr_t)&cfg;
|
||||
|
||||
ret = kvm_vcpu_ioctl(cs, KVM_ENABLE_CAP, &encap);
|
||||
ret = kvm_vcpu_enable_cap(cs, KVM_CAP_SW_TLB, 0, (uintptr_t)&cfg);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "%s: couldn't enable KVM_CAP_SW_TLB: %s\n",
|
||||
__func__, strerror(-ret));
|
||||
@@ -1292,7 +1288,6 @@ int kvmppc_set_tcr(PowerPCCPU *cpu)
|
||||
int kvmppc_booke_watchdog_enable(PowerPCCPU *cpu)
|
||||
{
|
||||
CPUState *cs = CPU(cpu);
|
||||
struct kvm_enable_cap encap = {};
|
||||
int ret;
|
||||
|
||||
if (!kvm_enabled()) {
|
||||
@@ -1304,8 +1299,7 @@ int kvmppc_booke_watchdog_enable(PowerPCCPU *cpu)
|
||||
return -1;
|
||||
}
|
||||
|
||||
encap.cap = KVM_CAP_PPC_BOOKE_WATCHDOG;
|
||||
ret = kvm_vcpu_ioctl(cs, KVM_ENABLE_CAP, &encap);
|
||||
ret = kvm_vcpu_enable_cap(cs, KVM_CAP_PPC_BOOKE_WATCHDOG, 0);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "%s: couldn't enable KVM_CAP_PPC_BOOKE_WATCHDOG: %s\n",
|
||||
__func__, strerror(-ret));
|
||||
@@ -1505,12 +1499,9 @@ int kvmppc_get_hypercall(CPUPPCState *env, uint8_t *buf, int buf_len)
|
||||
void kvmppc_set_papr(PowerPCCPU *cpu)
|
||||
{
|
||||
CPUState *cs = CPU(cpu);
|
||||
struct kvm_enable_cap cap = {};
|
||||
int ret;
|
||||
|
||||
cap.cap = KVM_CAP_PPC_PAPR;
|
||||
ret = kvm_vcpu_ioctl(cs, KVM_ENABLE_CAP, &cap);
|
||||
|
||||
ret = kvm_vcpu_enable_cap(cs, KVM_CAP_PPC_PAPR, 0);
|
||||
if (ret) {
|
||||
cpu_abort(cs, "This KVM version does not support PAPR\n");
|
||||
}
|
||||
@@ -1523,13 +1514,9 @@ void kvmppc_set_papr(PowerPCCPU *cpu)
|
||||
void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy)
|
||||
{
|
||||
CPUState *cs = CPU(cpu);
|
||||
struct kvm_enable_cap cap = {};
|
||||
int ret;
|
||||
|
||||
cap.cap = KVM_CAP_PPC_EPR;
|
||||
cap.args[0] = mpic_proxy;
|
||||
ret = kvm_vcpu_ioctl(cs, KVM_ENABLE_CAP, &cap);
|
||||
|
||||
ret = kvm_vcpu_enable_cap(cs, KVM_CAP_PPC_EPR, 0, mpic_proxy);
|
||||
if (ret && mpic_proxy) {
|
||||
cpu_abort(cs, "This KVM version does not support EPR\n");
|
||||
}
|
||||
|
@@ -929,12 +929,10 @@ void kvm_s390_crw_mchk(S390CPU *cpu)
|
||||
|
||||
void kvm_s390_enable_css_support(S390CPU *cpu)
|
||||
{
|
||||
struct kvm_enable_cap cap = {};
|
||||
int r;
|
||||
|
||||
/* Activate host kernel channel subsystem support. */
|
||||
cap.cap = KVM_CAP_S390_CSS_SUPPORT;
|
||||
r = kvm_vcpu_ioctl(CPU(cpu), KVM_ENABLE_CAP, &cap);
|
||||
r = kvm_vcpu_enable_cap(CPU(cpu), KVM_CAP_S390_CSS_SUPPORT, 0);
|
||||
assert(r == 0);
|
||||
}
|
||||
|
||||
|
@@ -314,6 +314,11 @@ This operation would be equivalent to
|
||||
|
||||
dest = (t1 & ~0x0f00) | ((t2 << 8) & 0x0f00)
|
||||
|
||||
* trunc_shr_i32 t0, t1, pos
|
||||
|
||||
For 64-bit hosts only, right shift the 64-bit input T1 by POS and
|
||||
truncate to 32-bit output T0. Depending on the host, this may be
|
||||
a simple mov/shift, or may require additional canonicalization.
|
||||
|
||||
********* Conditional moves
|
||||
|
||||
|
@@ -68,6 +68,7 @@ typedef enum {
|
||||
#define TCG_TARGET_HAS_muls2_i32 0
|
||||
#define TCG_TARGET_HAS_muluh_i32 0
|
||||
#define TCG_TARGET_HAS_mulsh_i32 0
|
||||
#define TCG_TARGET_HAS_trunc_shr_i32 0
|
||||
|
||||
#define TCG_TARGET_HAS_div_i64 1
|
||||
#define TCG_TARGET_HAS_rem_i64 1
|
||||
|
@@ -99,6 +99,7 @@ extern bool have_bmi1;
|
||||
#define TCG_TARGET_HAS_mulsh_i32 0
|
||||
|
||||
#if TCG_TARGET_REG_BITS == 64
|
||||
#define TCG_TARGET_HAS_trunc_shr_i32 0
|
||||
#define TCG_TARGET_HAS_div2_i64 1
|
||||
#define TCG_TARGET_HAS_rot_i64 1
|
||||
#define TCG_TARGET_HAS_ext8s_i64 1
|
||||
|
@@ -152,6 +152,7 @@ typedef enum {
|
||||
#define TCG_TARGET_HAS_muluh_i64 0
|
||||
#define TCG_TARGET_HAS_mulsh_i32 0
|
||||
#define TCG_TARGET_HAS_mulsh_i64 0
|
||||
#define TCG_TARGET_HAS_trunc_shr_i32 0
|
||||
|
||||
#define TCG_TARGET_HAS_new_ldst 1
|
||||
|
||||
|
@@ -228,6 +228,7 @@ static TCGArg do_constant_folding_2(TCGOpcode op, TCGArg x, TCGArg y)
|
||||
case INDEX_op_shr_i32:
|
||||
return (uint32_t)x >> (y & 31);
|
||||
|
||||
case INDEX_op_trunc_shr_i32:
|
||||
case INDEX_op_shr_i64:
|
||||
return (uint64_t)x >> (y & 63);
|
||||
|
||||
@@ -830,6 +831,10 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
|
||||
}
|
||||
break;
|
||||
|
||||
case INDEX_op_trunc_shr_i32:
|
||||
mask = (uint64_t)temps[args[1]].mask >> args[2];
|
||||
break;
|
||||
|
||||
CASE_OP_32_64(shl):
|
||||
if (temps[args[2]].state == TCG_TEMP_CONST) {
|
||||
tmp = temps[args[2]].val & (TCG_TARGET_REG_BITS - 1);
|
||||
@@ -1021,6 +1026,17 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr,
|
||||
}
|
||||
goto do_default;
|
||||
|
||||
case INDEX_op_trunc_shr_i32:
|
||||
if (temps[args[1]].state == TCG_TEMP_CONST) {
|
||||
s->gen_opc_buf[op_index] = op_to_movi(op);
|
||||
tmp = do_constant_folding(op, temps[args[1]].val, args[2]);
|
||||
tcg_opt_gen_movi(gen_args, args[0], tmp);
|
||||
gen_args += 2;
|
||||
args += 3;
|
||||
break;
|
||||
}
|
||||
goto do_default;
|
||||
|
||||
CASE_OP_32_64(add):
|
||||
CASE_OP_32_64(sub):
|
||||
CASE_OP_32_64(mul):
|
||||
|
@@ -96,6 +96,7 @@ typedef enum {
|
||||
#define TCG_TARGET_HAS_muls2_i32 0
|
||||
#define TCG_TARGET_HAS_muluh_i32 0
|
||||
#define TCG_TARGET_HAS_mulsh_i32 0
|
||||
#define TCG_TARGET_HAS_trunc_shr_i32 0
|
||||
|
||||
#define TCG_TARGET_HAS_div_i64 1
|
||||
#define TCG_TARGET_HAS_rem_i64 0
|
||||
|
@@ -69,6 +69,7 @@ typedef enum TCGReg {
|
||||
#define TCG_TARGET_HAS_muls2_i32 0
|
||||
#define TCG_TARGET_HAS_muluh_i32 0
|
||||
#define TCG_TARGET_HAS_mulsh_i32 0
|
||||
#define TCG_TARGET_HAS_trunc_shr_i32 0
|
||||
|
||||
#define TCG_TARGET_HAS_div2_i64 1
|
||||
#define TCG_TARGET_HAS_rot_i64 1
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -24,13 +24,7 @@
|
||||
#ifndef TCG_TARGET_SPARC
|
||||
#define TCG_TARGET_SPARC 1
|
||||
|
||||
#if UINTPTR_MAX == UINT32_MAX
|
||||
# define TCG_TARGET_REG_BITS 32
|
||||
#elif UINTPTR_MAX == UINT64_MAX
|
||||
#define TCG_TARGET_REG_BITS 64
|
||||
#else
|
||||
# error Unknown pointer size for tcg target
|
||||
#endif
|
||||
|
||||
#define TCG_TARGET_NB_REGS 32
|
||||
|
||||
@@ -76,7 +70,7 @@ typedef enum {
|
||||
/* used for function call generation */
|
||||
#define TCG_REG_CALL_STACK TCG_REG_O6
|
||||
|
||||
#if TCG_TARGET_REG_BITS == 64
|
||||
#ifdef __arch64__
|
||||
#define TCG_TARGET_STACK_BIAS 2047
|
||||
#define TCG_TARGET_STACK_ALIGN 16
|
||||
#define TCG_TARGET_CALL_STACK_OFFSET (128 + 6*8 + TCG_TARGET_STACK_BIAS)
|
||||
@@ -86,7 +80,7 @@ typedef enum {
|
||||
#define TCG_TARGET_CALL_STACK_OFFSET (64 + 4 + 6*4)
|
||||
#endif
|
||||
|
||||
#if TCG_TARGET_REG_BITS == 64
|
||||
#ifdef __arch64__
|
||||
#define TCG_TARGET_EXTEND_ARGS 1
|
||||
#endif
|
||||
|
||||
@@ -112,11 +106,11 @@ typedef enum {
|
||||
#define TCG_TARGET_HAS_add2_i32 1
|
||||
#define TCG_TARGET_HAS_sub2_i32 1
|
||||
#define TCG_TARGET_HAS_mulu2_i32 1
|
||||
#define TCG_TARGET_HAS_muls2_i32 0
|
||||
#define TCG_TARGET_HAS_muls2_i32 1
|
||||
#define TCG_TARGET_HAS_muluh_i32 0
|
||||
#define TCG_TARGET_HAS_mulsh_i32 0
|
||||
|
||||
#if TCG_TARGET_REG_BITS == 64
|
||||
#define TCG_TARGET_HAS_trunc_shr_i32 1
|
||||
#define TCG_TARGET_HAS_div_i64 1
|
||||
#define TCG_TARGET_HAS_rem_i64 0
|
||||
#define TCG_TARGET_HAS_rot_i64 0
|
||||
@@ -144,7 +138,6 @@ typedef enum {
|
||||
#define TCG_TARGET_HAS_muls2_i64 0
|
||||
#define TCG_TARGET_HAS_muluh_i64 0
|
||||
#define TCG_TARGET_HAS_mulsh_i64 0
|
||||
#endif
|
||||
|
||||
#define TCG_TARGET_HAS_new_ldst 1
|
||||
|
||||
|
50
tcg/tcg-op.h
50
tcg/tcg-op.h
@@ -1624,9 +1624,20 @@ static inline void tcg_gen_ext32u_i64(TCGv_i64 ret, TCGv_i64 arg)
|
||||
tcg_gen_movi_i32(TCGV_HIGH(ret), 0);
|
||||
}
|
||||
|
||||
static inline void tcg_gen_trunc_i64_i32(TCGv_i32 ret, TCGv_i64 arg)
|
||||
static inline void tcg_gen_trunc_shr_i64_i32(TCGv_i32 ret, TCGv_i64 arg,
|
||||
unsigned int count)
|
||||
{
|
||||
tcg_debug_assert(count < 64);
|
||||
if (count >= 32) {
|
||||
tcg_gen_shri_i32(ret, TCGV_HIGH(arg), count - 32);
|
||||
} else if (count == 0) {
|
||||
tcg_gen_mov_i32(ret, TCGV_LOW(arg));
|
||||
} else {
|
||||
TCGv_i64 t = tcg_temp_new_i64();
|
||||
tcg_gen_shri_i64(t, arg, count);
|
||||
tcg_gen_mov_i32(ret, TCGV_LOW(t));
|
||||
tcg_temp_free_i64(t);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void tcg_gen_extu_i32_i64(TCGv_i64 ret, TCGv_i32 arg)
|
||||
@@ -1727,11 +1738,21 @@ static inline void tcg_gen_ext32u_i64(TCGv_i64 ret, TCGv_i64 arg)
|
||||
}
|
||||
}
|
||||
|
||||
/* Note: we assume the target supports move between 32 and 64 bit
|
||||
registers. This will probably break MIPS64 targets. */
|
||||
static inline void tcg_gen_trunc_i64_i32(TCGv_i32 ret, TCGv_i64 arg)
|
||||
static inline void tcg_gen_trunc_shr_i64_i32(TCGv_i32 ret, TCGv_i64 arg,
|
||||
unsigned int count)
|
||||
{
|
||||
tcg_debug_assert(count < 64);
|
||||
if (TCG_TARGET_HAS_trunc_shr_i32) {
|
||||
tcg_gen_op3i_i32(INDEX_op_trunc_shr_i32, ret,
|
||||
MAKE_TCGV_I32(GET_TCGV_I64(arg)), count);
|
||||
} else if (count == 0) {
|
||||
tcg_gen_mov_i32(ret, MAKE_TCGV_I32(GET_TCGV_I64(arg)));
|
||||
} else {
|
||||
TCGv_i64 t = tcg_temp_new_i64();
|
||||
tcg_gen_shri_i64(t, arg, count);
|
||||
tcg_gen_mov_i32(ret, MAKE_TCGV_I32(GET_TCGV_I64(t)));
|
||||
tcg_temp_free_i64(t);
|
||||
}
|
||||
}
|
||||
|
||||
/* Note: we assume the target supports move between 32 and 64 bit
|
||||
@@ -2275,18 +2296,15 @@ static inline void tcg_gen_concat32_i64(TCGv_i64 dest, TCGv_i64 low,
|
||||
tcg_gen_deposit_i64(dest, low, high, 32, 32);
|
||||
}
|
||||
|
||||
static inline void tcg_gen_trunc_i64_i32(TCGv_i32 ret, TCGv_i64 arg)
|
||||
{
|
||||
tcg_gen_trunc_shr_i64_i32(ret, arg, 0);
|
||||
}
|
||||
|
||||
static inline void tcg_gen_extr_i64_i32(TCGv_i32 lo, TCGv_i32 hi, TCGv_i64 arg)
|
||||
{
|
||||
#if TCG_TARGET_REG_BITS == 32
|
||||
tcg_gen_mov_i32(lo, TCGV_LOW(arg));
|
||||
tcg_gen_mov_i32(hi, TCGV_HIGH(arg));
|
||||
#else
|
||||
TCGv_i64 t0 = tcg_temp_new_i64();
|
||||
tcg_gen_trunc_i64_i32(lo, arg);
|
||||
tcg_gen_shri_i64(t0, arg, 32);
|
||||
tcg_gen_trunc_i64_i32(hi, t0);
|
||||
tcg_temp_free_i64(t0);
|
||||
#endif
|
||||
tcg_gen_trunc_shr_i64_i32(lo, arg, 0);
|
||||
tcg_gen_trunc_shr_i64_i32(hi, arg, 32);
|
||||
}
|
||||
|
||||
static inline void tcg_gen_extr32_i64(TCGv_i64 lo, TCGv_i64 hi, TCGv_i64 arg)
|
||||
@@ -2861,7 +2879,7 @@ static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index)
|
||||
#define tcg_gen_muls2_tl tcg_gen_muls2_i32
|
||||
#endif
|
||||
|
||||
#if TCG_TARGET_REG_BITS == 32
|
||||
#if UINTPTR_MAX == UINT32_MAX
|
||||
# define tcg_gen_ld_ptr(R, A, O) \
|
||||
tcg_gen_ld_i32(TCGV_PTR_TO_NAT(R), (A), (O))
|
||||
# define tcg_gen_discard_ptr(A) \
|
||||
@@ -2883,4 +2901,4 @@ static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index)
|
||||
tcg_gen_addi_i64(TCGV_PTR_TO_NAT(R), TCGV_PTR_TO_NAT(A), (B))
|
||||
# define tcg_gen_ext_i32_ptr(R, A) \
|
||||
tcg_gen_ext_i32_i64(TCGV_PTR_TO_NAT(R), (A))
|
||||
#endif /* TCG_TARGET_REG_BITS == 32 */
|
||||
#endif /* UINTPTR_MAX == UINT32_MAX */
|
||||
|
@@ -147,6 +147,10 @@ DEF(rotl_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_rot_i64))
|
||||
DEF(rotr_i64, 1, 2, 0, IMPL64 | IMPL(TCG_TARGET_HAS_rot_i64))
|
||||
DEF(deposit_i64, 1, 2, 2, IMPL64 | IMPL(TCG_TARGET_HAS_deposit_i64))
|
||||
|
||||
DEF(trunc_shr_i32, 1, 1, 1,
|
||||
IMPL(TCG_TARGET_HAS_trunc_shr_i32)
|
||||
| (TCG_TARGET_REG_BITS == 32 ? TCG_OPF_NOT_PRESENT : 0))
|
||||
|
||||
DEF(brcond_i64, 0, 2, 2, TCG_OPF_BB_END | IMPL64)
|
||||
DEF(ext8s_i64, 1, 1, 0, IMPL64 | IMPL(TCG_TARGET_HAS_ext8s_i64))
|
||||
DEF(ext16s_i64, 1, 1, 0, IMPL64 | IMPL(TCG_TARGET_HAS_ext16s_i64))
|
||||
|
80
tcg/tcg.c
80
tcg/tcg.c
@@ -664,7 +664,36 @@ void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags,
|
||||
int nb_rets;
|
||||
TCGArg *nparam;
|
||||
|
||||
#if defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
|
||||
#if defined(__sparc__) && !defined(__arch64__) \
|
||||
&& !defined(CONFIG_TCG_INTERPRETER)
|
||||
/* We have 64-bit values in one register, but need to pass as two
|
||||
separate parameters. Split them. */
|
||||
int orig_sizemask = sizemask;
|
||||
int orig_nargs = nargs;
|
||||
TCGv_i64 retl, reth;
|
||||
|
||||
TCGV_UNUSED_I64(retl);
|
||||
TCGV_UNUSED_I64(reth);
|
||||
if (sizemask != 0) {
|
||||
TCGArg *split_args = __builtin_alloca(sizeof(TCGArg) * nargs * 2);
|
||||
for (i = real_args = 0; i < nargs; ++i) {
|
||||
int is_64bit = sizemask & (1 << (i+1)*2);
|
||||
if (is_64bit) {
|
||||
TCGv_i64 orig = MAKE_TCGV_I64(args[i]);
|
||||
TCGv_i32 h = tcg_temp_new_i32();
|
||||
TCGv_i32 l = tcg_temp_new_i32();
|
||||
tcg_gen_extr_i64_i32(l, h, orig);
|
||||
split_args[real_args++] = GET_TCGV_I32(h);
|
||||
split_args[real_args++] = GET_TCGV_I32(l);
|
||||
} else {
|
||||
split_args[real_args++] = args[i];
|
||||
}
|
||||
}
|
||||
nargs = real_args;
|
||||
args = split_args;
|
||||
sizemask = 0;
|
||||
}
|
||||
#elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
|
||||
for (i = 0; i < nargs; ++i) {
|
||||
int is_64bit = sizemask & (1 << (i+1)*2);
|
||||
int is_signed = sizemask & (2 << (i+1)*2);
|
||||
@@ -684,8 +713,23 @@ void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags,
|
||||
*s->gen_opc_ptr++ = INDEX_op_call;
|
||||
nparam = s->gen_opparam_ptr++;
|
||||
if (ret != TCG_CALL_DUMMY_ARG) {
|
||||
#if TCG_TARGET_REG_BITS < 64
|
||||
if (sizemask & 1) {
|
||||
#if defined(__sparc__) && !defined(__arch64__) \
|
||||
&& !defined(CONFIG_TCG_INTERPRETER)
|
||||
if (orig_sizemask & 1) {
|
||||
/* The 32-bit ABI is going to return the 64-bit value in
|
||||
the %o0/%o1 register pair. Prepare for this by using
|
||||
two return temporaries, and reassemble below. */
|
||||
retl = tcg_temp_new_i64();
|
||||
reth = tcg_temp_new_i64();
|
||||
*s->gen_opparam_ptr++ = GET_TCGV_I64(reth);
|
||||
*s->gen_opparam_ptr++ = GET_TCGV_I64(retl);
|
||||
nb_rets = 2;
|
||||
} else {
|
||||
*s->gen_opparam_ptr++ = ret;
|
||||
nb_rets = 1;
|
||||
}
|
||||
#else
|
||||
if (TCG_TARGET_REG_BITS < 64 && (sizemask & 1)) {
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
*s->gen_opparam_ptr++ = ret + 1;
|
||||
*s->gen_opparam_ptr++ = ret;
|
||||
@@ -694,12 +738,11 @@ void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags,
|
||||
*s->gen_opparam_ptr++ = ret + 1;
|
||||
#endif
|
||||
nb_rets = 2;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
} else {
|
||||
*s->gen_opparam_ptr++ = ret;
|
||||
nb_rets = 1;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
nb_rets = 0;
|
||||
}
|
||||
@@ -749,7 +792,29 @@ void tcg_gen_callN(TCGContext *s, TCGv_ptr func, unsigned int flags,
|
||||
/* total parameters, needed to go backward in the instruction stream */
|
||||
*s->gen_opparam_ptr++ = 1 + nb_rets + real_args + 3;
|
||||
|
||||
#if defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
|
||||
#if defined(__sparc__) && !defined(__arch64__) \
|
||||
&& !defined(CONFIG_TCG_INTERPRETER)
|
||||
/* Free all of the parts we allocated above. */
|
||||
for (i = real_args = 0; i < orig_nargs; ++i) {
|
||||
int is_64bit = orig_sizemask & (1 << (i+1)*2);
|
||||
if (is_64bit) {
|
||||
TCGv_i32 h = MAKE_TCGV_I32(args[real_args++]);
|
||||
TCGv_i32 l = MAKE_TCGV_I32(args[real_args++]);
|
||||
tcg_temp_free_i32(h);
|
||||
tcg_temp_free_i32(l);
|
||||
} else {
|
||||
real_args++;
|
||||
}
|
||||
}
|
||||
if (orig_sizemask & 1) {
|
||||
/* The 32-bit ABI returned two 32-bit pieces. Re-assemble them.
|
||||
Note that describing these as TCGv_i64 eliminates an unnecessary
|
||||
zero-extension that tcg_gen_concat_i32_i64 would create. */
|
||||
tcg_gen_concat32_i64(MAKE_TCGV_I64(ret), retl, reth);
|
||||
tcg_temp_free_i64(retl);
|
||||
tcg_temp_free_i64(reth);
|
||||
}
|
||||
#elif defined(TCG_TARGET_EXTEND_ARGS) && TCG_TARGET_REG_BITS == 64
|
||||
for (i = 0; i < nargs; ++i) {
|
||||
int is_64bit = sizemask & (1 << (i+1)*2);
|
||||
if (!is_64bit) {
|
||||
@@ -2411,6 +2476,7 @@ static int tcg_reg_alloc_call(TCGContext *s, const TCGOpDef *def,
|
||||
ts = &s->temps[arg];
|
||||
reg = tcg_target_call_oarg_regs[i];
|
||||
assert(s->reg_to_temp[reg] == -1);
|
||||
|
||||
if (ts->fixed_reg) {
|
||||
if (ts->reg != reg) {
|
||||
tcg_out_mov(s, ts->type, ts->reg, reg);
|
||||
|
@@ -66,6 +66,7 @@ typedef uint64_t TCGRegSet;
|
||||
|
||||
#if TCG_TARGET_REG_BITS == 32
|
||||
/* Turn some undef macros into false macros. */
|
||||
#define TCG_TARGET_HAS_trunc_shr_i32 0
|
||||
#define TCG_TARGET_HAS_div_i64 0
|
||||
#define TCG_TARGET_HAS_rem_i64 0
|
||||
#define TCG_TARGET_HAS_div2_i64 0
|
||||
|
@@ -82,6 +82,7 @@
|
||||
#define TCG_TARGET_HAS_mulsh_i32 0
|
||||
|
||||
#if TCG_TARGET_REG_BITS == 64
|
||||
#define TCG_TARGET_HAS_trunc_shr_i32 0
|
||||
#define TCG_TARGET_HAS_bswap16_i64 1
|
||||
#define TCG_TARGET_HAS_bswap32_i64 1
|
||||
#define TCG_TARGET_HAS_bswap64_i64 1
|
||||
|
@@ -113,6 +113,10 @@ check-qtest-pci-y += tests/tpci200-test$(EXESUF)
|
||||
gcov-files-pci-y += hw/ipack/tpci200.c
|
||||
check-qtest-pci-y += $(check-qtest-ipack-y)
|
||||
gcov-files-pci-y += $(gcov-files-ipack-y)
|
||||
check-qtest-pci-y += tests/display-vga-test$(EXESUF)
|
||||
gcov-files-pci-y += hw/display/vga.c
|
||||
gcov-files-pci-y += hw/display/cirrus_vga.c
|
||||
gcov-files-pci-y += hw/display/vga-pci.c
|
||||
|
||||
check-qtest-i386-y = tests/endianness-test$(EXESUF)
|
||||
check-qtest-i386-y += tests/fdc-test$(EXESUF)
|
||||
@@ -280,6 +284,7 @@ tests/virtio-9p-test$(EXESUF): tests/virtio-9p-test.o
|
||||
tests/virtio-serial-test$(EXESUF): tests/virtio-serial-test.o
|
||||
tests/virtio-console-test$(EXESUF): tests/virtio-console-test.o
|
||||
tests/tpci200-test$(EXESUF): tests/tpci200-test.o
|
||||
tests/display-vga-test$(EXESUF): tests/display-vga-test.o
|
||||
tests/ipoctal232-test$(EXESUF): tests/ipoctal232-test.o
|
||||
tests/qom-test$(EXESUF): tests/qom-test.o
|
||||
tests/blockdev-test$(EXESUF): tests/blockdev-test.o $(libqos-pc-obj-y)
|
||||
|
52
tests/display-vga-test.c
Normal file
52
tests/display-vga-test.c
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* QTest testcase for vga cards
|
||||
*
|
||||
* Copyright (c) 2014 Red Hat, Inc
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include <glib.h>
|
||||
#include <string.h>
|
||||
#include "libqtest.h"
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
static void pci_cirrus(void)
|
||||
{
|
||||
qtest_start("-vga none -device cirrus-vga");
|
||||
qtest_end();
|
||||
}
|
||||
|
||||
static void pci_stdvga(void)
|
||||
{
|
||||
qtest_start("-vga none -device VGA");
|
||||
qtest_end();
|
||||
}
|
||||
|
||||
static void pci_secondary(void)
|
||||
{
|
||||
qtest_start("-vga none -device secondary-vga");
|
||||
qtest_end();
|
||||
}
|
||||
|
||||
static void pci_multihead(void)
|
||||
{
|
||||
qtest_start("-vga none -device VGA -device secondary-vga");
|
||||
qtest_end();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
qtest_add_func("/display/pci/cirrus", pci_cirrus);
|
||||
qtest_add_func("/display/pci/stdvga", pci_stdvga);
|
||||
qtest_add_func("/display/pci/secondary", pci_secondary);
|
||||
qtest_add_func("/display/pci/multihead", pci_multihead);
|
||||
ret = g_test_run();
|
||||
|
||||
return ret;
|
||||
}
|
@@ -96,7 +96,7 @@ mv "$TEST_IMG" "$TEST_IMG.orig"
|
||||
for backing_option in "-B " "-o backing_file="; do
|
||||
|
||||
echo
|
||||
echo Testing conversion with $backing_option$TEST_IMG.base | _filter_testdir | _filter_imgfmt
|
||||
echo Testing conversion with $backing_option"$TEST_IMG.base" | _filter_testdir | _filter_imgfmt
|
||||
echo
|
||||
$QEMU_IMG convert -O $IMGFMT $backing_option"$TEST_IMG.base" "$TEST_IMG.orig" "$TEST_IMG"
|
||||
|
||||
|
@@ -51,10 +51,10 @@ function run_qemu_img()
|
||||
size=128M
|
||||
|
||||
_make_test_img $size
|
||||
$QEMU_IO -c 'write 0 1M' $TEST_IMG | _filter_qemu_io
|
||||
$QEMU_IO -c 'write 2M 1M' $TEST_IMG | _filter_qemu_io
|
||||
$QEMU_IO -c 'write 4M 1M' $TEST_IMG | _filter_qemu_io
|
||||
$QEMU_IO -c 'write 32M 1M' $TEST_IMG | _filter_qemu_io
|
||||
$QEMU_IO -c 'write 0 1M' "$TEST_IMG" | _filter_qemu_io
|
||||
$QEMU_IO -c 'write 2M 1M' "$TEST_IMG" | _filter_qemu_io
|
||||
$QEMU_IO -c 'write 4M 1M' "$TEST_IMG" | _filter_qemu_io
|
||||
$QEMU_IO -c 'write 32M 1M' "$TEST_IMG" | _filter_qemu_io
|
||||
|
||||
$QEMU_IMG convert -p -O $IMGFMT -f $IMGFMT "$TEST_IMG" "$TEST_IMG".base 2>&1 |\
|
||||
_filter_testdir | sed -e 's/\r/\n/g'
|
||||
|
61
tests/qemu-iotests/090
Executable file
61
tests/qemu-iotests/090
Executable file
@@ -0,0 +1,61 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Test for discarding compressed clusters on qcow2 images
|
||||
#
|
||||
# Copyright (C) 2014 Red Hat, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# creator
|
||||
owner=mreitz@redhat.com
|
||||
|
||||
seq="$(basename $0)"
|
||||
echo "QA output created by $seq"
|
||||
|
||||
here="$PWD"
|
||||
tmp=/tmp/$$
|
||||
status=1 # failure is the default!
|
||||
|
||||
_cleanup()
|
||||
{
|
||||
_cleanup_test_img
|
||||
}
|
||||
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||
|
||||
# get standard environment, filters and checks
|
||||
. ./common.rc
|
||||
. ./common.filter
|
||||
|
||||
_supported_fmt qcow2
|
||||
_supported_proto file
|
||||
_supported_os Linux
|
||||
|
||||
IMG_SIZE=128K
|
||||
|
||||
_make_test_img $IMG_SIZE
|
||||
|
||||
$QEMU_IO -c 'write -c -P 42 0 64k' \
|
||||
-c 'write -c -P 23 64k 64k' \
|
||||
-c 'discard 64k 64k' \
|
||||
"$TEST_IMG" | _filter_qemu_io
|
||||
|
||||
$QEMU_IO -c 'read -P 0 64k 64k' "$TEST_IMG" | _filter_qemu_io
|
||||
|
||||
_check_test_img
|
||||
|
||||
# success, all done
|
||||
echo "*** done"
|
||||
rm -f $seq.full
|
||||
status=0
|
12
tests/qemu-iotests/090.out
Normal file
12
tests/qemu-iotests/090.out
Normal file
@@ -0,0 +1,12 @@
|
||||
QA output created by 090
|
||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072
|
||||
wrote 65536/65536 bytes at offset 0
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
wrote 65536/65536 bytes at offset 65536
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
discard 65536/65536 bytes at offset 65536
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
read 65536/65536 bytes at offset 65536
|
||||
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
||||
No errors were found on the image.
|
||||
*** done
|
@@ -178,10 +178,10 @@ _rm_test_img()
|
||||
local img=$1
|
||||
if [ "$IMGFMT" = "vmdk" ]; then
|
||||
# Remove all the extents for vmdk
|
||||
$QEMU_IMG info $img 2>/dev/null | grep 'filename:' | cut -f 2 -d: \
|
||||
"$QEMU_IMG" info "$img" 2>/dev/null | grep 'filename:' | cut -f 2 -d: \
|
||||
| xargs -I {} rm -f "{}"
|
||||
fi
|
||||
rm -f $img
|
||||
rm -f "$img"
|
||||
}
|
||||
|
||||
_cleanup_test_img()
|
||||
|
@@ -95,3 +95,4 @@
|
||||
086 rw auto quick
|
||||
087 rw auto
|
||||
088 rw auto
|
||||
090 rw auto quick
|
||||
|
49
ui/sdl2.c
49
ui/sdl2.c
@@ -359,16 +359,12 @@ static void sdl_mouse_mode_change(Notifier *notify, void *data)
|
||||
}
|
||||
|
||||
static void sdl_send_mouse_event(struct sdl2_state *scon, int dx, int dy,
|
||||
int dz, int x, int y, int state)
|
||||
int x, int y, int state)
|
||||
{
|
||||
static uint32_t bmap[INPUT_BUTTON_MAX] = {
|
||||
[INPUT_BUTTON_LEFT] = SDL_BUTTON(SDL_BUTTON_LEFT),
|
||||
[INPUT_BUTTON_MIDDLE] = SDL_BUTTON(SDL_BUTTON_MIDDLE),
|
||||
[INPUT_BUTTON_RIGHT] = SDL_BUTTON(SDL_BUTTON_RIGHT),
|
||||
#if 0
|
||||
[INPUT_BUTTON_WHEEL_UP] = SDL_BUTTON(SDL_BUTTON_WHEELUP),
|
||||
[INPUT_BUTTON_WHEEL_DOWN] = SDL_BUTTON(SDL_BUTTON_WHEELDOWN),
|
||||
#endif
|
||||
};
|
||||
static uint32_t prev_state;
|
||||
|
||||
@@ -566,7 +562,7 @@ static void handle_mousemotion(SDL_Event *ev)
|
||||
}
|
||||
}
|
||||
if (gui_grab || qemu_input_is_absolute() || absolute_enabled) {
|
||||
sdl_send_mouse_event(scon, ev->motion.xrel, ev->motion.yrel, 0,
|
||||
sdl_send_mouse_event(scon, ev->motion.xrel, ev->motion.yrel,
|
||||
ev->motion.x, ev->motion.y, ev->motion.state);
|
||||
}
|
||||
}
|
||||
@@ -576,7 +572,6 @@ static void handle_mousebutton(SDL_Event *ev)
|
||||
int buttonstate = SDL_GetMouseState(NULL, NULL);
|
||||
SDL_MouseButtonEvent *bev;
|
||||
struct sdl2_state *scon = get_scon_from_window(ev->key.windowID);
|
||||
int dz;
|
||||
|
||||
bev = &ev->button;
|
||||
if (!gui_grab && !qemu_input_is_absolute()) {
|
||||
@@ -585,23 +580,33 @@ static void handle_mousebutton(SDL_Event *ev)
|
||||
sdl_grab_start(scon);
|
||||
}
|
||||
} else {
|
||||
dz = 0;
|
||||
if (ev->type == SDL_MOUSEBUTTONDOWN) {
|
||||
buttonstate |= SDL_BUTTON(bev->button);
|
||||
} else {
|
||||
buttonstate &= ~SDL_BUTTON(bev->button);
|
||||
}
|
||||
#ifdef SDL_BUTTON_WHEELUP
|
||||
if (bev->button == SDL_BUTTON_WHEELUP &&
|
||||
ev->type == SDL_MOUSEBUTTONDOWN) {
|
||||
dz = -1;
|
||||
} else if (bev->button == SDL_BUTTON_WHEELDOWN &&
|
||||
ev->type == SDL_MOUSEBUTTONDOWN) {
|
||||
dz = 1;
|
||||
sdl_send_mouse_event(scon, 0, 0, bev->x, bev->y, buttonstate);
|
||||
}
|
||||
#endif
|
||||
sdl_send_mouse_event(scon, 0, 0, dz, bev->x, bev->y, buttonstate);
|
||||
}
|
||||
|
||||
static void handle_mousewheel(SDL_Event *ev)
|
||||
{
|
||||
struct sdl2_state *scon = get_scon_from_window(ev->key.windowID);
|
||||
SDL_MouseWheelEvent *wev = &ev->wheel;
|
||||
InputButton btn;
|
||||
|
||||
if (wev->y > 0) {
|
||||
btn = INPUT_BUTTON_WHEEL_UP;
|
||||
} else if (wev->y < 0) {
|
||||
btn = INPUT_BUTTON_WHEEL_DOWN;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
qemu_input_queue_btn(scon->dcl.con, btn, true);
|
||||
qemu_input_event_sync();
|
||||
qemu_input_queue_btn(scon->dcl.con, btn, false);
|
||||
qemu_input_event_sync();
|
||||
}
|
||||
|
||||
static void handle_windowevent(DisplayChangeListener *dcl, SDL_Event *ev)
|
||||
@@ -612,6 +617,13 @@ static void handle_windowevent(DisplayChangeListener *dcl, SDL_Event *ev)
|
||||
switch (ev->window.event) {
|
||||
case SDL_WINDOWEVENT_RESIZED:
|
||||
sdl_scale(scon, ev->window.data1, ev->window.data2);
|
||||
{
|
||||
QemuUIInfo info;
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.width = ev->window.data1;
|
||||
info.height = ev->window.data2;
|
||||
dpy_set_ui_info(scon->dcl.con, &info);
|
||||
}
|
||||
graphic_hw_invalidate(scon->dcl.con);
|
||||
graphic_hw_update(scon->dcl.con);
|
||||
break;
|
||||
@@ -678,6 +690,9 @@ static void sdl_refresh(DisplayChangeListener *dcl)
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
handle_mousebutton(ev);
|
||||
break;
|
||||
case SDL_MOUSEWHEEL:
|
||||
handle_mousewheel(ev);
|
||||
break;
|
||||
case SDL_WINDOWEVENT:
|
||||
handle_windowevent(dcl, ev);
|
||||
break;
|
||||
|
Reference in New Issue
Block a user