Compare commits
130
Commits
v2.4.0-rc2
...
v2.4.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5c79ae3615 | ||
|
|
2d697366a1 | ||
|
|
0175409df4 | ||
|
|
e94867ed5f | ||
|
|
74aae7b22b | ||
|
|
2be4f242b5 | ||
|
|
27751aabd1 | ||
|
|
426d0e7b7e | ||
|
|
b7f26e5239 | ||
|
|
060ebfef1a | ||
|
|
260425ab40 | ||
|
|
e95edefbd0 | ||
|
|
8c6dc68f4c | ||
|
|
c69adea462 | ||
|
|
f60c87154a | ||
|
|
6cd387833d | ||
|
|
2a3612ccc1 | ||
|
|
8357946b15 | ||
|
|
4240be4563 | ||
|
|
c6296ea88d | ||
|
|
03247d43c5 | ||
|
|
e1c120a9c5 | ||
|
|
d6812d60e7 | ||
|
|
39b8e7dcaf | ||
|
|
bd80b5963f | ||
|
|
ff90f84e74 | ||
|
|
c99d69694a | ||
|
|
3c8691f568 | ||
|
|
4214a8cb7c | ||
|
|
e72c4fb81d | ||
|
|
91ced51446 | ||
|
|
0e826a061a | ||
|
|
cb48f67ad8 | ||
|
|
7008d580ac | ||
|
|
46739a2d7a | ||
|
|
ca96ac44dc | ||
|
|
a076972a4d | ||
|
|
fed105e275 | ||
|
|
b83d017d88 | ||
|
|
170f209d78 | ||
|
|
8b89b3a8df | ||
|
|
5e868d2e5e | ||
|
|
9f8c5b69c2 | ||
|
|
7bba83bf80 | ||
|
|
776f878451 | ||
|
|
ff1d2ac949 | ||
|
|
52579c681c | ||
|
|
30dfa9a46c | ||
|
|
f6351288b6 | ||
|
|
84a29c7efd | ||
|
|
da52a4dfcc | ||
|
|
8bcbb834a0 | ||
|
|
325e390421 | ||
|
|
6a55c82cec | ||
|
|
52c91dac6b | ||
|
|
55875fc4ca | ||
|
|
c147b5153e | ||
|
|
8ef3ea253b | ||
|
|
226d007dbd | ||
|
|
801db5ecda | ||
|
|
786f9ce203 | ||
|
|
7e71e111e0 | ||
|
|
7155f2ca9d | ||
|
|
f6288b9c88 | ||
|
|
ab60366308 | ||
|
|
cc47a16bcb | ||
|
|
f3c30aeaa7 | ||
|
|
be66680e83 | ||
|
|
f8787f8723 | ||
|
|
edec47cfef | ||
|
|
77c102c26e | ||
|
|
b15deac795 | ||
|
|
3737129917 | ||
|
|
c9b11f971c | ||
|
|
efb8206ca7 | ||
|
|
9d5b731dd2 | ||
|
|
27462695cd | ||
|
|
bbeb82395e | ||
|
|
7df69deadf | ||
|
|
122e7dab8a | ||
|
|
f9f7492ea4 | ||
|
|
4594f93a73 | ||
|
|
1ef4a6069f | ||
|
|
1dd58ae058 | ||
|
|
3b7031e960 | ||
|
|
e813f0d881 | ||
|
|
575bafd1f3 | ||
|
|
b6cb6610c2 | ||
|
|
913440249e | ||
|
|
363db4b249 | ||
|
|
b0ba0b9b6b | ||
|
|
8c8c460c5f | ||
|
|
491a1f494e | ||
|
|
299f7bec5a | ||
|
|
3634869b27 | ||
|
|
3e230569bf | ||
|
|
e40db4c6d3 | ||
|
|
019c2ab862 | ||
|
|
6775e2c429 | ||
|
|
09999a5f7f | ||
|
|
cd4bfbb20d | ||
|
|
7882080388 | ||
|
|
5f456073aa | ||
|
|
cb72cba830 | ||
|
|
03441c3a4a | ||
|
|
d2ff858545 | ||
|
|
f793d97e45 | ||
|
|
178846bdd9 | ||
|
|
d274e07c6d | ||
|
|
c1076c3e13 | ||
|
|
deb809edb8 | ||
|
|
fb43096959 | ||
|
|
7d99f4c1b5 | ||
|
|
ab28bd2312 | ||
|
|
c170aad8b0 | ||
|
|
60928458e5 | ||
|
|
30fdfae49d | ||
|
|
f75b709853 | ||
|
|
961521261a | ||
|
|
80adb8fcad | ||
|
|
ffc6372851 | ||
|
|
6c0f0c0f12 | ||
|
|
ee8ba9e4d8 | ||
|
|
12e21eb088 | ||
|
|
4bf1cb03fb | ||
|
|
9172f428af | ||
|
|
0b8e2c1002 | ||
|
|
759b484c5d | ||
|
|
69970fcef9 | ||
|
|
6b2699672d |
No files matched your search
@@ -17,6 +17,8 @@
|
||||
/trace/generated-tcg-tracers.h
|
||||
/trace/generated-ust-provider.h
|
||||
/trace/generated-ust.c
|
||||
/ui/shader/texture-blit-frag.h
|
||||
/ui/shader/texture-blit-vert.h
|
||||
/libcacard/trace/generated-tracers.c
|
||||
*-timestamp
|
||||
/*-softmmu
|
||||
|
||||
@@ -135,7 +135,7 @@ endif
|
||||
else \
|
||||
mv $@.tmp $@; \
|
||||
cp -p $@ $@.old; \
|
||||
fi, " GEN $@");
|
||||
fi, " GEN $@");
|
||||
|
||||
defconfig:
|
||||
rm -f config-all-devices.mak $(SUBDIR_DEVICES_MAK)
|
||||
|
||||
@@ -79,8 +79,10 @@ int aio_bh_poll(AioContext *ctx)
|
||||
* aio_notify again if necessary.
|
||||
*/
|
||||
if (!bh->deleted && atomic_xchg(&bh->scheduled, 0)) {
|
||||
if (!bh->idle)
|
||||
/* Idle BHs and the notify BH don't count as progress */
|
||||
if (!bh->idle && bh != ctx->notify_dummy_bh) {
|
||||
ret = 1;
|
||||
}
|
||||
bh->idle = 0;
|
||||
bh->cb(bh->opaque);
|
||||
}
|
||||
@@ -230,7 +232,21 @@ aio_ctx_finalize(GSource *source)
|
||||
{
|
||||
AioContext *ctx = (AioContext *) source;
|
||||
|
||||
qemu_bh_delete(ctx->notify_dummy_bh);
|
||||
thread_pool_free(ctx->thread_pool);
|
||||
|
||||
qemu_mutex_lock(&ctx->bh_lock);
|
||||
while (ctx->first_bh) {
|
||||
QEMUBH *next = ctx->first_bh->next;
|
||||
|
||||
/* qemu_bh_delete() must have been called on BHs in this AioContext */
|
||||
assert(ctx->first_bh->deleted);
|
||||
|
||||
g_free(ctx->first_bh);
|
||||
ctx->first_bh = next;
|
||||
}
|
||||
qemu_mutex_unlock(&ctx->bh_lock);
|
||||
|
||||
aio_set_event_notifier(ctx, &ctx->notifier, NULL);
|
||||
event_notifier_cleanup(&ctx->notifier);
|
||||
rfifolock_destroy(&ctx->lock);
|
||||
@@ -285,8 +301,15 @@ static void aio_timerlist_notify(void *opaque)
|
||||
|
||||
static void aio_rfifolock_cb(void *opaque)
|
||||
{
|
||||
AioContext *ctx = opaque;
|
||||
|
||||
/* Kick owner thread in case they are blocked in aio_poll() */
|
||||
aio_notify(opaque);
|
||||
qemu_bh_schedule(ctx->notify_dummy_bh);
|
||||
}
|
||||
|
||||
static void notify_dummy_bh(void *opaque)
|
||||
{
|
||||
/* Do nothing, we were invoked just to force the event loop to iterate */
|
||||
}
|
||||
|
||||
static void event_notifier_dummy_cb(EventNotifier *e)
|
||||
@@ -313,6 +336,8 @@ AioContext *aio_context_new(Error **errp)
|
||||
rfifolock_init(&ctx->lock, aio_rfifolock_cb, ctx);
|
||||
timerlistgroup_init(&ctx->tlg, aio_timerlist_notify, ctx);
|
||||
|
||||
ctx->notify_dummy_bh = aio_bh_new(ctx, notify_dummy_bh, NULL);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -10,6 +10,7 @@
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
#include "sysemu/hostmem.h"
|
||||
#include "hw/boards.h"
|
||||
#include "qapi/visitor.h"
|
||||
#include "qapi-types.h"
|
||||
#include "qapi-visit.h"
|
||||
@@ -222,11 +223,10 @@ static void host_memory_backend_set_prealloc(Object *obj, bool value,
|
||||
static void host_memory_backend_init(Object *obj)
|
||||
{
|
||||
HostMemoryBackend *backend = MEMORY_BACKEND(obj);
|
||||
MachineState *machine = MACHINE(qdev_get_machine());
|
||||
|
||||
backend->merge = qemu_opt_get_bool(qemu_get_machine_opts(),
|
||||
"mem-merge", true);
|
||||
backend->dump = qemu_opt_get_bool(qemu_get_machine_opts(),
|
||||
"dump-guest-core", true);
|
||||
backend->merge = machine_mem_merge(machine);
|
||||
backend->dump = machine_dump_guest_core(machine);
|
||||
backend->prealloc = mem_prealloc;
|
||||
|
||||
object_property_add_bool(obj, "merge",
|
||||
|
||||
+4
-6
@@ -865,12 +865,6 @@ static int quorum_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
int i;
|
||||
int ret = 0;
|
||||
|
||||
if (!qcrypto_hash_supports(QCRYPTO_HASH_ALG_SHA256)) {
|
||||
error_setg(errp,
|
||||
"SHA256 hash support is required for quorum device");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
qdict_flatten(options);
|
||||
|
||||
/* count how many different children are present */
|
||||
@@ -1061,6 +1055,10 @@ static BlockDriver bdrv_quorum = {
|
||||
|
||||
static void bdrv_quorum_init(void)
|
||||
{
|
||||
if (!qcrypto_hash_supports(QCRYPTO_HASH_ALG_SHA256)) {
|
||||
/* SHA256 hash support is required for quorum device */
|
||||
return;
|
||||
}
|
||||
bdrv_register(&bdrv_quorum);
|
||||
}
|
||||
|
||||
|
||||
+71
-81
@@ -318,6 +318,10 @@ enum AIOCBState {
|
||||
AIOCB_DISCARD_OBJ,
|
||||
};
|
||||
|
||||
#define AIOCBOverwrapping(x, y) \
|
||||
(!(x->max_affect_data_idx < y->min_affect_data_idx \
|
||||
|| y->max_affect_data_idx < x->min_affect_data_idx))
|
||||
|
||||
struct SheepdogAIOCB {
|
||||
BlockAIOCB common;
|
||||
|
||||
@@ -334,6 +338,11 @@ struct SheepdogAIOCB {
|
||||
|
||||
bool cancelable;
|
||||
int nr_pending;
|
||||
|
||||
uint32_t min_affect_data_idx;
|
||||
uint32_t max_affect_data_idx;
|
||||
|
||||
QLIST_ENTRY(SheepdogAIOCB) aiocb_siblings;
|
||||
};
|
||||
|
||||
typedef struct BDRVSheepdogState {
|
||||
@@ -362,8 +371,10 @@ typedef struct BDRVSheepdogState {
|
||||
|
||||
/* Every aio request must be linked to either of these queues. */
|
||||
QLIST_HEAD(inflight_aio_head, AIOReq) inflight_aio_head;
|
||||
QLIST_HEAD(pending_aio_head, AIOReq) pending_aio_head;
|
||||
QLIST_HEAD(failed_aio_head, AIOReq) failed_aio_head;
|
||||
|
||||
CoQueue overwrapping_queue;
|
||||
QLIST_HEAD(inflight_aiocb_head, SheepdogAIOCB) inflight_aiocb_head;
|
||||
} BDRVSheepdogState;
|
||||
|
||||
static const char * sd_strerror(int err)
|
||||
@@ -498,13 +509,7 @@ static void sd_aio_cancel(BlockAIOCB *blockacb)
|
||||
AIOReq *aioreq, *next;
|
||||
|
||||
if (sd_acb_cancelable(acb)) {
|
||||
/* Remove outstanding requests from pending and failed queues. */
|
||||
QLIST_FOREACH_SAFE(aioreq, &s->pending_aio_head, aio_siblings,
|
||||
next) {
|
||||
if (aioreq->aiocb == acb) {
|
||||
free_aio_req(s, aioreq);
|
||||
}
|
||||
}
|
||||
/* Remove outstanding requests from failed queue. */
|
||||
QLIST_FOREACH_SAFE(aioreq, &s->failed_aio_head, aio_siblings,
|
||||
next) {
|
||||
if (aioreq->aiocb == acb) {
|
||||
@@ -529,6 +534,10 @@ static SheepdogAIOCB *sd_aio_setup(BlockDriverState *bs, QEMUIOVector *qiov,
|
||||
int64_t sector_num, int nb_sectors)
|
||||
{
|
||||
SheepdogAIOCB *acb;
|
||||
uint32_t object_size;
|
||||
BDRVSheepdogState *s = bs->opaque;
|
||||
|
||||
object_size = (UINT32_C(1) << s->inode.block_size_shift);
|
||||
|
||||
acb = qemu_aio_get(&sd_aiocb_info, bs, NULL, NULL);
|
||||
|
||||
@@ -542,6 +551,11 @@ static SheepdogAIOCB *sd_aio_setup(BlockDriverState *bs, QEMUIOVector *qiov,
|
||||
acb->coroutine = qemu_coroutine_self();
|
||||
acb->ret = 0;
|
||||
acb->nr_pending = 0;
|
||||
|
||||
acb->min_affect_data_idx = acb->sector_num * BDRV_SECTOR_SIZE / object_size;
|
||||
acb->max_affect_data_idx = (acb->sector_num * BDRV_SECTOR_SIZE +
|
||||
acb->nb_sectors * BDRV_SECTOR_SIZE) / object_size;
|
||||
|
||||
return acb;
|
||||
}
|
||||
|
||||
@@ -703,38 +717,6 @@ static int reload_inode(BDRVSheepdogState *s, uint32_t snapid, const char *tag);
|
||||
static int get_sheep_fd(BDRVSheepdogState *s, Error **errp);
|
||||
static void co_write_request(void *opaque);
|
||||
|
||||
static AIOReq *find_pending_req(BDRVSheepdogState *s, uint64_t oid)
|
||||
{
|
||||
AIOReq *aio_req;
|
||||
|
||||
QLIST_FOREACH(aio_req, &s->pending_aio_head, aio_siblings) {
|
||||
if (aio_req->oid == oid) {
|
||||
return aio_req;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function searchs pending requests to the object `oid', and
|
||||
* sends them.
|
||||
*/
|
||||
static void coroutine_fn send_pending_req(BDRVSheepdogState *s, uint64_t oid)
|
||||
{
|
||||
AIOReq *aio_req;
|
||||
SheepdogAIOCB *acb;
|
||||
|
||||
while ((aio_req = find_pending_req(s, oid)) != NULL) {
|
||||
acb = aio_req->aiocb;
|
||||
/* move aio_req from pending list to inflight one */
|
||||
QLIST_REMOVE(aio_req, aio_siblings);
|
||||
QLIST_INSERT_HEAD(&s->inflight_aio_head, aio_req, aio_siblings);
|
||||
add_aio_request(s, aio_req, acb->qiov->iov, acb->qiov->niov,
|
||||
acb->aiocb_type);
|
||||
}
|
||||
}
|
||||
|
||||
static coroutine_fn void reconnect_to_sdog(void *opaque)
|
||||
{
|
||||
BDRVSheepdogState *s = opaque;
|
||||
@@ -840,12 +822,6 @@ static void coroutine_fn aio_read_response(void *opaque)
|
||||
s->max_dirty_data_idx = MAX(idx, s->max_dirty_data_idx);
|
||||
s->min_dirty_data_idx = MIN(idx, s->min_dirty_data_idx);
|
||||
}
|
||||
/*
|
||||
* Some requests may be blocked because simultaneous
|
||||
* create requests are not allowed, so we search the
|
||||
* pending requests here.
|
||||
*/
|
||||
send_pending_req(s, aio_req->oid);
|
||||
}
|
||||
break;
|
||||
case AIOCB_READ_UDATA:
|
||||
@@ -1341,30 +1317,6 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Return true if the specified request is linked to the pending list. */
|
||||
static bool check_simultaneous_create(BDRVSheepdogState *s, AIOReq *aio_req)
|
||||
{
|
||||
AIOReq *areq;
|
||||
QLIST_FOREACH(areq, &s->inflight_aio_head, aio_siblings) {
|
||||
if (areq != aio_req && areq->oid == aio_req->oid) {
|
||||
/*
|
||||
* Sheepdog cannot handle simultaneous create requests to the same
|
||||
* object, so we cannot send the request until the previous request
|
||||
* finishes.
|
||||
*/
|
||||
DPRINTF("simultaneous create to %" PRIx64 "\n", aio_req->oid);
|
||||
aio_req->flags = 0;
|
||||
aio_req->base_oid = 0;
|
||||
aio_req->create = false;
|
||||
QLIST_REMOVE(aio_req, aio_siblings);
|
||||
QLIST_INSERT_HEAD(&s->pending_aio_head, aio_req, aio_siblings);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void coroutine_fn resend_aioreq(BDRVSheepdogState *s, AIOReq *aio_req)
|
||||
{
|
||||
SheepdogAIOCB *acb = aio_req->aiocb;
|
||||
@@ -1379,10 +1331,6 @@ static void coroutine_fn resend_aioreq(BDRVSheepdogState *s, AIOReq *aio_req)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (check_simultaneous_create(s, aio_req)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->inode.data_vdi_id[idx]) {
|
||||
aio_req->base_oid = vid_to_data_oid(s->inode.data_vdi_id[idx], idx);
|
||||
aio_req->flags |= SD_FLAG_CMD_COW;
|
||||
@@ -1458,8 +1406,8 @@ static int sd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
filename = qemu_opt_get(opts, "filename");
|
||||
|
||||
QLIST_INIT(&s->inflight_aio_head);
|
||||
QLIST_INIT(&s->pending_aio_head);
|
||||
QLIST_INIT(&s->failed_aio_head);
|
||||
QLIST_INIT(&s->inflight_aiocb_head);
|
||||
s->fd = -1;
|
||||
|
||||
memset(vdi, 0, sizeof(vdi));
|
||||
@@ -1524,6 +1472,7 @@ static int sd_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
bs->total_sectors = s->inode.vdi_size / BDRV_SECTOR_SIZE;
|
||||
pstrcpy(s->name, sizeof(s->name), vdi);
|
||||
qemu_co_mutex_init(&s->lock);
|
||||
qemu_co_queue_init(&s->overwrapping_queue);
|
||||
qemu_opts_del(opts);
|
||||
g_free(buf);
|
||||
return 0;
|
||||
@@ -2195,12 +2144,6 @@ static int coroutine_fn sd_co_rw_vector(void *p)
|
||||
old_oid, done);
|
||||
QLIST_INSERT_HEAD(&s->inflight_aio_head, aio_req, aio_siblings);
|
||||
|
||||
if (create) {
|
||||
if (check_simultaneous_create(s, aio_req)) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
add_aio_request(s, aio_req, acb->qiov->iov, acb->qiov->niov,
|
||||
acb->aiocb_type);
|
||||
done:
|
||||
@@ -2215,6 +2158,20 @@ out:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool check_overwrapping_aiocb(BDRVSheepdogState *s, SheepdogAIOCB *aiocb)
|
||||
{
|
||||
SheepdogAIOCB *cb;
|
||||
|
||||
QLIST_FOREACH(cb, &s->inflight_aiocb_head, aiocb_siblings) {
|
||||
if (AIOCBOverwrapping(aiocb, cb)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
QLIST_INSERT_HEAD(&s->inflight_aiocb_head, aiocb, aiocb_siblings);
|
||||
return false;
|
||||
}
|
||||
|
||||
static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors, QEMUIOVector *qiov)
|
||||
{
|
||||
@@ -2234,14 +2191,25 @@ static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num,
|
||||
acb->aio_done_func = sd_write_done;
|
||||
acb->aiocb_type = AIOCB_WRITE_UDATA;
|
||||
|
||||
retry:
|
||||
if (check_overwrapping_aiocb(s, acb)) {
|
||||
qemu_co_queue_wait(&s->overwrapping_queue);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
ret = sd_co_rw_vector(acb);
|
||||
if (ret <= 0) {
|
||||
QLIST_REMOVE(acb, aiocb_siblings);
|
||||
qemu_co_queue_restart_all(&s->overwrapping_queue);
|
||||
qemu_aio_unref(acb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
qemu_coroutine_yield();
|
||||
|
||||
QLIST_REMOVE(acb, aiocb_siblings);
|
||||
qemu_co_queue_restart_all(&s->overwrapping_queue);
|
||||
|
||||
return acb->ret;
|
||||
}
|
||||
|
||||
@@ -2250,19 +2218,30 @@ static coroutine_fn int sd_co_readv(BlockDriverState *bs, int64_t sector_num,
|
||||
{
|
||||
SheepdogAIOCB *acb;
|
||||
int ret;
|
||||
BDRVSheepdogState *s = bs->opaque;
|
||||
|
||||
acb = sd_aio_setup(bs, qiov, sector_num, nb_sectors);
|
||||
acb->aiocb_type = AIOCB_READ_UDATA;
|
||||
acb->aio_done_func = sd_finish_aiocb;
|
||||
|
||||
retry:
|
||||
if (check_overwrapping_aiocb(s, acb)) {
|
||||
qemu_co_queue_wait(&s->overwrapping_queue);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
ret = sd_co_rw_vector(acb);
|
||||
if (ret <= 0) {
|
||||
QLIST_REMOVE(acb, aiocb_siblings);
|
||||
qemu_co_queue_restart_all(&s->overwrapping_queue);
|
||||
qemu_aio_unref(acb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
qemu_coroutine_yield();
|
||||
|
||||
QLIST_REMOVE(acb, aiocb_siblings);
|
||||
qemu_co_queue_restart_all(&s->overwrapping_queue);
|
||||
return acb->ret;
|
||||
}
|
||||
|
||||
@@ -2610,14 +2589,25 @@ static coroutine_fn int sd_co_discard(BlockDriverState *bs, int64_t sector_num,
|
||||
acb->aiocb_type = AIOCB_DISCARD_OBJ;
|
||||
acb->aio_done_func = sd_finish_aiocb;
|
||||
|
||||
retry:
|
||||
if (check_overwrapping_aiocb(s, acb)) {
|
||||
qemu_co_queue_wait(&s->overwrapping_queue);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
ret = sd_co_rw_vector(acb);
|
||||
if (ret <= 0) {
|
||||
QLIST_REMOVE(acb, aiocb_siblings);
|
||||
qemu_co_queue_restart_all(&s->overwrapping_queue);
|
||||
qemu_aio_unref(acb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
qemu_coroutine_yield();
|
||||
|
||||
QLIST_REMOVE(acb, aiocb_siblings);
|
||||
qemu_co_queue_restart_all(&s->overwrapping_queue);
|
||||
|
||||
return acb->ret;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -563,7 +563,7 @@ static int connect_to_ssh(BDRVSSHState *s, QDict *options,
|
||||
/* Open the socket and connect. */
|
||||
s->sock = inet_connect(s->hostport, errp);
|
||||
if (s->sock < 0) {
|
||||
ret = -errno;
|
||||
ret = -EIO;
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
||||
+14
-4
@@ -168,6 +168,7 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
uint8_t buf[HEADER_SIZE];
|
||||
uint32_t checksum;
|
||||
uint64_t computed_size;
|
||||
uint64_t pagetable_size;
|
||||
int disk_type = VHD_DYNAMIC;
|
||||
int ret;
|
||||
|
||||
@@ -269,7 +270,17 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
s->pagetable = qemu_try_blockalign(bs->file, s->max_table_entries * 4);
|
||||
if (s->max_table_entries > SIZE_MAX / 4 ||
|
||||
s->max_table_entries > (int) INT_MAX / 4) {
|
||||
error_setg(errp, "Max Table Entries too large (%" PRId32 ")",
|
||||
s->max_table_entries);
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pagetable_size = (uint64_t) s->max_table_entries * 4;
|
||||
|
||||
s->pagetable = qemu_try_blockalign(bs->file, pagetable_size);
|
||||
if (s->pagetable == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
@@ -277,14 +288,13 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
|
||||
s->bat_offset = be64_to_cpu(dyndisk_header->table_offset);
|
||||
|
||||
ret = bdrv_pread(bs->file, s->bat_offset, s->pagetable,
|
||||
s->max_table_entries * 4);
|
||||
ret = bdrv_pread(bs->file, s->bat_offset, s->pagetable, pagetable_size);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
s->free_data_block_offset =
|
||||
(s->bat_offset + (s->max_table_entries * 4) + 511) & ~511;
|
||||
ROUND_UP(s->bat_offset + pagetable_size, 512);
|
||||
|
||||
for (i = 0; i < s->max_table_entries; i++) {
|
||||
be32_to_cpus(&s->pagetable[i]);
|
||||
|
||||
+1
-1
@@ -173,7 +173,7 @@ void cpu_loop(CPUX86State *env)
|
||||
//target_siginfo_t info;
|
||||
|
||||
for(;;) {
|
||||
trapnr = cpu_x86_exec(env);
|
||||
trapnr = cpu_x86_exec(cs);
|
||||
switch(trapnr) {
|
||||
case 0x80:
|
||||
/* syscall from int $0x80 */
|
||||
|
||||
@@ -1337,7 +1337,6 @@ disabled with --disable-FEATURE, default is enabled if available:
|
||||
vnc-sasl SASL encryption for VNC server
|
||||
vnc-jpeg JPEG lossy compression for VNC server
|
||||
vnc-png PNG compression for VNC server
|
||||
vnc-ws Websockets support for VNC server
|
||||
cocoa Cocoa UI (Mac OS X only)
|
||||
virtfs VirtFS
|
||||
xen xen backend driver support
|
||||
@@ -2116,10 +2115,26 @@ fi
|
||||
##########################################
|
||||
# GNUTLS probe
|
||||
|
||||
gnutls_works() {
|
||||
# Unfortunately some distros have bad pkg-config information for gnutls
|
||||
# such that it claims to exist but you get a compiler error if you try
|
||||
# to use the options returned by --libs. Specifically, Ubuntu for --static
|
||||
# builds doesn't work:
|
||||
# https://bugs.launchpad.net/ubuntu/+source/gnutls26/+bug/1478035
|
||||
#
|
||||
# So sanity check the cflags/libs before assuming gnutls can be used.
|
||||
if ! $pkg_config --exists "gnutls"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
write_c_skeleton
|
||||
compile_prog "$($pkg_config --cflags gnutls)" "$($pkg_config --libs gnutls)"
|
||||
}
|
||||
|
||||
gnutls_gcrypt=no
|
||||
gnutls_nettle=no
|
||||
if test "$gnutls" != "no"; then
|
||||
if $pkg_config --exists "gnutls"; then
|
||||
if gnutls_works; then
|
||||
gnutls_cflags=`$pkg_config --cflags gnutls`
|
||||
gnutls_libs=`$pkg_config --libs gnutls`
|
||||
libs_softmmu="$gnutls_libs $libs_softmmu"
|
||||
|
||||
@@ -954,6 +954,8 @@ static void *qemu_kvm_cpu_thread_fn(void *arg)
|
||||
CPUState *cpu = arg;
|
||||
int r;
|
||||
|
||||
rcu_register_thread();
|
||||
|
||||
qemu_mutex_lock_iothread();
|
||||
qemu_thread_get_self(cpu->thread);
|
||||
cpu->thread_id = qemu_get_thread_id();
|
||||
@@ -995,6 +997,8 @@ static void *qemu_dummy_cpu_thread_fn(void *arg)
|
||||
sigset_t waitset;
|
||||
int r;
|
||||
|
||||
rcu_register_thread();
|
||||
|
||||
qemu_mutex_lock_iothread();
|
||||
qemu_thread_get_self(cpu->thread);
|
||||
cpu->thread_id = qemu_get_thread_id();
|
||||
@@ -1034,6 +1038,8 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
|
||||
{
|
||||
CPUState *cpu = arg;
|
||||
|
||||
rcu_register_thread();
|
||||
|
||||
qemu_mutex_lock_iothread();
|
||||
qemu_tcg_init_cpu_signals();
|
||||
qemu_thread_get_self(cpu->thread);
|
||||
|
||||
@@ -117,7 +117,7 @@ static int qcrypto_cipher_decrypt_aes(QCryptoCipher *cipher,
|
||||
uint8_t *outptr = out;
|
||||
while (len) {
|
||||
if (len > AES_BLOCK_SIZE) {
|
||||
AES_decrypt(inptr, outptr, &ctxt->state.aes.encrypt_key);
|
||||
AES_decrypt(inptr, outptr, &ctxt->state.aes.decrypt_key);
|
||||
inptr += AES_BLOCK_SIZE;
|
||||
outptr += AES_BLOCK_SIZE;
|
||||
len -= AES_BLOCK_SIZE;
|
||||
@@ -126,15 +126,15 @@ static int qcrypto_cipher_decrypt_aes(QCryptoCipher *cipher,
|
||||
memcpy(tmp1, inptr, len);
|
||||
/* Fill with 0 to avoid valgrind uninitialized reads */
|
||||
memset(tmp1 + len, 0, sizeof(tmp1) - len);
|
||||
AES_decrypt(tmp1, tmp2, &ctxt->state.aes.encrypt_key);
|
||||
AES_decrypt(tmp1, tmp2, &ctxt->state.aes.decrypt_key);
|
||||
memcpy(outptr, tmp2, len);
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
AES_cbc_encrypt(in, out, len,
|
||||
&ctxt->state.aes.encrypt_key,
|
||||
ctxt->state.aes.iv, 1);
|
||||
&ctxt->state.aes.decrypt_key,
|
||||
ctxt->state.aes.iv, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
+1
-1
@@ -241,7 +241,7 @@ uint32_t qemu_fdt_alloc_phandle(void *fdt)
|
||||
|
||||
/*
|
||||
* We need to find out if the user gave us special instruction at
|
||||
* which phandle id to start allocting phandles.
|
||||
* which phandle id to start allocating phandles.
|
||||
*/
|
||||
if (!phandle) {
|
||||
phandle = machine_phandle_start(current_machine);
|
||||
|
||||
@@ -954,7 +954,10 @@ hwaddr memory_region_section_get_iotlb(CPUState *cpu,
|
||||
iotlb |= PHYS_SECTION_ROM;
|
||||
}
|
||||
} else {
|
||||
iotlb = section - section->address_space->dispatch->map.sections;
|
||||
AddressSpaceDispatch *d;
|
||||
|
||||
d = atomic_rcu_read(§ion->address_space->dispatch);
|
||||
iotlb = section - d->map.sections;
|
||||
iotlb += xlat;
|
||||
}
|
||||
|
||||
|
||||
@@ -1285,6 +1285,7 @@ static void gdb_vm_state_change(void *opaque, int running, RunState state)
|
||||
ret = GDB_SIGNAL_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
gdb_set_stop_cpu(cpu);
|
||||
snprintf(buf, sizeof(buf), "T%02xthread:%02x;", ret, cpu_index(cpu));
|
||||
|
||||
send_packet:
|
||||
|
||||
@@ -21,7 +21,8 @@
|
||||
#include "virtio-9p-coth.h"
|
||||
#include "hw/virtio/virtio-access.h"
|
||||
|
||||
static uint64_t virtio_9p_get_features(VirtIODevice *vdev, uint64_t features)
|
||||
static uint64_t virtio_9p_get_features(VirtIODevice *vdev, uint64_t features,
|
||||
Error **errp)
|
||||
{
|
||||
virtio_add_feature(&features, VIRTIO_9P_MOUNT_TAG);
|
||||
return features;
|
||||
|
||||
+17
-6
@@ -14,6 +14,7 @@
|
||||
#include "hw/virtio/virtio.h"
|
||||
#include "hw/i386/pc.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/iov.h"
|
||||
#include "qemu/sockets.h"
|
||||
#include "virtio-9p.h"
|
||||
#include "fsdev/qemu-fsdev.h"
|
||||
@@ -3261,16 +3262,26 @@ void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
|
||||
|
||||
while ((pdu = alloc_pdu(s)) &&
|
||||
(len = virtqueue_pop(vq, &pdu->elem)) != 0) {
|
||||
uint8_t *ptr;
|
||||
struct {
|
||||
uint32_t size_le;
|
||||
uint8_t id;
|
||||
uint16_t tag_le;
|
||||
} QEMU_PACKED out;
|
||||
int len;
|
||||
|
||||
pdu->s = s;
|
||||
BUG_ON(pdu->elem.out_num == 0 || pdu->elem.in_num == 0);
|
||||
BUG_ON(pdu->elem.out_sg[0].iov_len < 7);
|
||||
QEMU_BUILD_BUG_ON(sizeof out != 7);
|
||||
|
||||
ptr = pdu->elem.out_sg[0].iov_base;
|
||||
len = iov_to_buf(pdu->elem.out_sg, pdu->elem.out_num, 0,
|
||||
&out, sizeof out);
|
||||
BUG_ON(len != sizeof out);
|
||||
|
||||
pdu->size = le32_to_cpu(out.size_le);
|
||||
|
||||
pdu->id = out.id;
|
||||
pdu->tag = le16_to_cpu(out.tag_le);
|
||||
|
||||
pdu->size = le32_to_cpu(*(uint32_t *)ptr);
|
||||
pdu->id = ptr[4];
|
||||
pdu->tag = le16_to_cpu(*(uint16_t *)(ptr + 5));
|
||||
qemu_co_queue_init(&pdu->complete);
|
||||
submit_pdu(s, pdu);
|
||||
}
|
||||
|
||||
+2
-2
@@ -221,9 +221,9 @@ static void pm_reset(void *opaque)
|
||||
acpi_pm_tmr_reset(&pm->acpi_regs);
|
||||
acpi_gpe_reset(&pm->acpi_regs);
|
||||
|
||||
pm->smi_en = 0;
|
||||
if (!pm->smm_enabled) {
|
||||
/* Mark SMM as already inited to prevent SMM from running. KVM does not
|
||||
* support SMM mode. */
|
||||
/* Mark SMM as already inited to prevent SMM from running. */
|
||||
pm->smi_en |= ICH9_PMIO_SMI_EN_APMC_EN;
|
||||
}
|
||||
pm->smi_en_wmask = ~0;
|
||||
|
||||
@@ -223,8 +223,8 @@ void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s)
|
||||
virtio_blk_data_plane_stop(s);
|
||||
blk_op_unblock_all(s->conf->conf.blk, s->blocker);
|
||||
error_free(s->blocker);
|
||||
object_unref(OBJECT(s->iothread));
|
||||
qemu_bh_delete(s->bh);
|
||||
object_unref(OBJECT(s->iothread));
|
||||
g_free(s);
|
||||
}
|
||||
|
||||
|
||||
+11
-2
@@ -722,7 +722,8 @@ static void virtio_blk_set_config(VirtIODevice *vdev, const uint8_t *config)
|
||||
aio_context_release(blk_get_aio_context(s->blk));
|
||||
}
|
||||
|
||||
static uint64_t virtio_blk_get_features(VirtIODevice *vdev, uint64_t features)
|
||||
static uint64_t virtio_blk_get_features(VirtIODevice *vdev, uint64_t features,
|
||||
Error **errp)
|
||||
{
|
||||
VirtIOBlock *s = VIRTIO_BLK(vdev);
|
||||
|
||||
@@ -730,7 +731,15 @@ static uint64_t virtio_blk_get_features(VirtIODevice *vdev, uint64_t features)
|
||||
virtio_add_feature(&features, VIRTIO_BLK_F_GEOMETRY);
|
||||
virtio_add_feature(&features, VIRTIO_BLK_F_TOPOLOGY);
|
||||
virtio_add_feature(&features, VIRTIO_BLK_F_BLK_SIZE);
|
||||
virtio_add_feature(&features, VIRTIO_BLK_F_SCSI);
|
||||
if (__virtio_has_feature(features, VIRTIO_F_VERSION_1)) {
|
||||
if (s->conf.scsi) {
|
||||
error_setg(errp, "Please set scsi=off for virtio-blk devices in order to use virtio 1.0");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
virtio_clear_feature(&features, VIRTIO_F_ANY_LAYOUT);
|
||||
virtio_add_feature(&features, VIRTIO_BLK_F_SCSI);
|
||||
}
|
||||
|
||||
if (s->conf.config_wce) {
|
||||
virtio_add_feature(&features, VIRTIO_BLK_F_CONFIG_WCE);
|
||||
|
||||
@@ -195,7 +195,8 @@ static size_t send_control_msg(VirtIOSerial *vser, void *buf, size_t len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(elem.in_sg[0].iov_base, buf, len);
|
||||
/* TODO: detect a buffer that's too short, set NEEDS_RESET */
|
||||
iov_from_buf(elem.in_sg, elem.in_num, 0, buf, len);
|
||||
|
||||
virtqueue_push(vq, &elem, len);
|
||||
virtio_notify(VIRTIO_DEVICE(vser), vq);
|
||||
@@ -499,7 +500,8 @@ static void handle_input(VirtIODevice *vdev, VirtQueue *vq)
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t get_features(VirtIODevice *vdev, uint64_t features)
|
||||
static uint64_t get_features(VirtIODevice *vdev, uint64_t features,
|
||||
Error **errp)
|
||||
{
|
||||
VirtIOSerial *vser;
|
||||
|
||||
|
||||
+41
-34
@@ -21,12 +21,40 @@
|
||||
#include "ui/console.h"
|
||||
#include "framebuffer.h"
|
||||
|
||||
void framebuffer_update_memory_section(
|
||||
MemoryRegionSection *mem_section,
|
||||
MemoryRegion *root,
|
||||
hwaddr base,
|
||||
unsigned rows,
|
||||
unsigned src_width)
|
||||
{
|
||||
hwaddr src_len = (hwaddr)rows * src_width;
|
||||
|
||||
if (mem_section->mr) {
|
||||
memory_region_set_log(mem_section->mr, false, DIRTY_MEMORY_VGA);
|
||||
memory_region_unref(mem_section->mr);
|
||||
mem_section->mr = NULL;
|
||||
}
|
||||
|
||||
*mem_section = memory_region_find(root, base, src_len);
|
||||
if (!mem_section->mr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (int128_get64(mem_section->size) < src_len ||
|
||||
!memory_region_is_ram(mem_section->mr)) {
|
||||
memory_region_unref(mem_section->mr);
|
||||
mem_section->mr = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
memory_region_set_log(mem_section->mr, true, DIRTY_MEMORY_VGA);
|
||||
}
|
||||
|
||||
/* Render an image from a shared memory framebuffer. */
|
||||
|
||||
void framebuffer_update_display(
|
||||
DisplaySurface *ds,
|
||||
MemoryRegion *address_space,
|
||||
hwaddr base,
|
||||
MemoryRegionSection *mem_section,
|
||||
int cols, /* Width in pixels. */
|
||||
int rows, /* Height in pixels. */
|
||||
int src_width, /* Length of source line, in bytes. */
|
||||
@@ -41,51 +69,33 @@ void framebuffer_update_display(
|
||||
hwaddr src_len;
|
||||
uint8_t *dest;
|
||||
uint8_t *src;
|
||||
uint8_t *src_base;
|
||||
int first, last = 0;
|
||||
int dirty;
|
||||
int i;
|
||||
ram_addr_t addr;
|
||||
MemoryRegionSection mem_section;
|
||||
MemoryRegion *mem;
|
||||
|
||||
i = *first_row;
|
||||
*first_row = -1;
|
||||
src_len = src_width * rows;
|
||||
|
||||
mem_section = memory_region_find(address_space, base, src_len);
|
||||
mem = mem_section.mr;
|
||||
if (int128_get64(mem_section.size) != src_len ||
|
||||
!memory_region_is_ram(mem_section.mr)) {
|
||||
goto out;
|
||||
mem = mem_section->mr;
|
||||
if (!mem) {
|
||||
return;
|
||||
}
|
||||
assert(mem);
|
||||
assert(mem_section.offset_within_address_space == base);
|
||||
|
||||
memory_region_sync_dirty_bitmap(mem);
|
||||
if (!memory_region_is_logging(mem, DIRTY_MEMORY_VGA)) {
|
||||
invalidate = true;
|
||||
}
|
||||
|
||||
src_base = cpu_physical_memory_map(base, &src_len, 0);
|
||||
/* If we can't map the framebuffer then bail. We could try harder,
|
||||
but it's not really worth it as dirty flag tracking will probably
|
||||
already have failed above. */
|
||||
if (!src_base)
|
||||
goto out;
|
||||
if (src_len != src_width * rows) {
|
||||
cpu_physical_memory_unmap(src_base, src_len, 0, 0);
|
||||
goto out;
|
||||
}
|
||||
src = src_base;
|
||||
addr = mem_section->offset_within_region;
|
||||
src = memory_region_get_ram_ptr(mem) + addr;
|
||||
|
||||
dest = surface_data(ds);
|
||||
if (dest_col_pitch < 0)
|
||||
if (dest_col_pitch < 0) {
|
||||
dest -= dest_col_pitch * (cols - 1);
|
||||
}
|
||||
if (dest_row_pitch < 0) {
|
||||
dest -= dest_row_pitch * (rows - 1);
|
||||
}
|
||||
first = -1;
|
||||
addr = mem_section.offset_within_region;
|
||||
|
||||
addr += i * src_width;
|
||||
src += i * src_width;
|
||||
@@ -104,14 +114,11 @@ void framebuffer_update_display(
|
||||
src += src_width;
|
||||
dest += dest_row_pitch;
|
||||
}
|
||||
cpu_physical_memory_unmap(src_base, src_len, 0, 0);
|
||||
if (first < 0) {
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
memory_region_reset_dirty(mem, mem_section.offset_within_region, src_len,
|
||||
memory_region_reset_dirty(mem, mem_section->offset_within_region, src_len,
|
||||
DIRTY_MEMORY_VGA);
|
||||
*first_row = first;
|
||||
*last_row = last;
|
||||
out:
|
||||
memory_region_unref(mem);
|
||||
}
|
||||
@@ -7,10 +7,50 @@
|
||||
|
||||
typedef void (*drawfn)(void *, uint8_t *, const uint8_t *, int, int);
|
||||
|
||||
/* framebuffer_update_memory_section: Update framebuffer
|
||||
* #MemoryRegionSection, for example if the framebuffer is switched to
|
||||
* a different memory area.
|
||||
*
|
||||
* @mem_section: Output #MemoryRegionSection, to be passed to
|
||||
* framebuffer_update_display().
|
||||
* @root: #MemoryRegion within which the framebuffer lies
|
||||
* @base: Base address of the framebuffer within @root.
|
||||
* @rows: Height of the screen.
|
||||
* @src_width: Number of bytes in framebuffer memory between two rows.
|
||||
*/
|
||||
void framebuffer_update_memory_section(
|
||||
MemoryRegionSection *mem_section,
|
||||
MemoryRegion *root,
|
||||
hwaddr base,
|
||||
unsigned rows,
|
||||
unsigned src_width);
|
||||
|
||||
/* framebuffer_update_display: Draw the framebuffer on a surface.
|
||||
*
|
||||
* @ds: #DisplaySurface to draw to.
|
||||
* @mem_section: #MemoryRegionSection provided by
|
||||
* framebuffer_update_memory_section().
|
||||
* @cols: Width the screen.
|
||||
* @rows: Height of the screen.
|
||||
* @src_width: Number of bytes in framebuffer memory between two rows.
|
||||
* @dest_row_pitch: Number of bytes in the surface data between two rows.
|
||||
* Negative if the framebuffer is stored in the opposite order (e.g.
|
||||
* bottom-to-top) compared to the framebuffer.
|
||||
* @dest_col_pitch: Number of bytes in the surface data between two pixels.
|
||||
* Negative if the framebuffer is stored in the opposite order (e.g.
|
||||
* right-to-left) compared to the framebuffer.
|
||||
* @invalidate: True if the function should redraw the whole screen
|
||||
* without checking the DIRTY_MEMORY_VGA dirty bitmap.
|
||||
* @fn: Drawing function to be called for each row that has to be drawn.
|
||||
* @opaque: Opaque pointer passed to @fn.
|
||||
* @first_row: Pointer to an integer, receives the number of the first row
|
||||
* that was drawn (either the first dirty row, or 0 if @invalidate is true).
|
||||
* @last_row: Pointer to an integer, receives the number of the last row that
|
||||
* was drawn (either the last dirty row, or @rows-1 if @invalidate is true).
|
||||
*/
|
||||
void framebuffer_update_display(
|
||||
DisplaySurface *ds,
|
||||
MemoryRegion *address_space,
|
||||
hwaddr base,
|
||||
MemoryRegionSection *mem_section,
|
||||
int cols,
|
||||
int rows,
|
||||
int src_width,
|
||||
|
||||
@@ -71,6 +71,7 @@ struct MilkymistVgafbState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion regs_region;
|
||||
MemoryRegionSection fbsection;
|
||||
QemuConsole *con;
|
||||
|
||||
int invalidate;
|
||||
@@ -91,6 +92,7 @@ static void vgafb_update_display(void *opaque)
|
||||
MilkymistVgafbState *s = opaque;
|
||||
SysBusDevice *sbd;
|
||||
DisplaySurface *surface = qemu_console_surface(s->con);
|
||||
int src_width;
|
||||
int first = 0;
|
||||
int last = 0;
|
||||
drawfn fn;
|
||||
@@ -129,11 +131,18 @@ static void vgafb_update_display(void *opaque)
|
||||
break;
|
||||
}
|
||||
|
||||
framebuffer_update_display(surface, sysbus_address_space(sbd),
|
||||
s->regs[R_BASEADDRESS] + s->fb_offset,
|
||||
src_width = s->regs[R_HRES] * 2;
|
||||
if (s->invalidate) {
|
||||
framebuffer_update_memory_section(&s->fbsection,
|
||||
sysbus_address_space(sbd),
|
||||
s->regs[R_BASEADDRESS] + s->fb_offset,
|
||||
s->regs[R_VRES], src_width);
|
||||
}
|
||||
|
||||
framebuffer_update_display(surface, &s->fbsection,
|
||||
s->regs[R_HRES],
|
||||
s->regs[R_VRES],
|
||||
s->regs[R_HRES] * 2,
|
||||
src_width,
|
||||
dest_width,
|
||||
0,
|
||||
s->invalidate,
|
||||
|
||||
+10
-2
@@ -25,6 +25,7 @@
|
||||
struct omap_lcd_panel_s {
|
||||
MemoryRegion *sysmem;
|
||||
MemoryRegion iomem;
|
||||
MemoryRegionSection fbsection;
|
||||
qemu_irq irq;
|
||||
QemuConsole *con;
|
||||
|
||||
@@ -215,12 +216,19 @@ static void omap_update_display(void *opaque)
|
||||
|
||||
step = width * bpp >> 3;
|
||||
linesize = surface_stride(surface);
|
||||
framebuffer_update_display(surface, omap_lcd->sysmem,
|
||||
frame_base, width, height,
|
||||
if (omap_lcd->invalidate) {
|
||||
framebuffer_update_memory_section(&omap_lcd->fbsection,
|
||||
omap_lcd->sysmem, frame_base,
|
||||
height, step);
|
||||
}
|
||||
|
||||
framebuffer_update_display(surface, &omap_lcd->fbsection,
|
||||
width, height,
|
||||
step, linesize, 0,
|
||||
omap_lcd->invalidate,
|
||||
draw_line, omap_lcd->palette,
|
||||
&first, &last);
|
||||
|
||||
if (first >= 0) {
|
||||
dpy_gfx_update(omap_lcd->con, 0, first, width, last - first + 1);
|
||||
}
|
||||
|
||||
+11
-2
@@ -46,6 +46,7 @@ typedef struct PL110State {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion iomem;
|
||||
MemoryRegionSection fbsection;
|
||||
QemuConsole *con;
|
||||
|
||||
int version;
|
||||
@@ -238,12 +239,20 @@ static void pl110_update_display(void *opaque)
|
||||
}
|
||||
dest_width *= s->cols;
|
||||
first = 0;
|
||||
framebuffer_update_display(surface, sysbus_address_space(sbd),
|
||||
s->upbase, s->cols, s->rows,
|
||||
if (s->invalidate) {
|
||||
framebuffer_update_memory_section(&s->fbsection,
|
||||
sysbus_address_space(sbd),
|
||||
s->upbase,
|
||||
s->rows, src_width);
|
||||
}
|
||||
|
||||
framebuffer_update_display(surface, &s->fbsection,
|
||||
s->cols, s->rows,
|
||||
src_width, dest_width, 0,
|
||||
s->invalidate,
|
||||
fn, s->palette,
|
||||
&first, &last);
|
||||
|
||||
if (first >= 0) {
|
||||
dpy_gfx_update(s->con, 0, first, s->cols, last - first + 1);
|
||||
}
|
||||
|
||||
+21
-8
@@ -35,6 +35,7 @@ struct DMAChannel {
|
||||
struct PXA2xxLCDState {
|
||||
MemoryRegion *sysmem;
|
||||
MemoryRegion iomem;
|
||||
MemoryRegionSection fbsection;
|
||||
qemu_irq irq;
|
||||
int irqlevel;
|
||||
|
||||
@@ -687,8 +688,11 @@ static void pxa2xx_lcdc_dma0_redraw_rot0(PXA2xxLCDState *s,
|
||||
|
||||
dest_width = s->xres * s->dest_width;
|
||||
*miny = 0;
|
||||
framebuffer_update_display(surface, s->sysmem,
|
||||
addr, s->xres, s->yres,
|
||||
if (s->invalidated) {
|
||||
framebuffer_update_memory_section(&s->fbsection, s->sysmem,
|
||||
addr, s->yres, src_width);
|
||||
}
|
||||
framebuffer_update_display(surface, &s->fbsection, s->xres, s->yres,
|
||||
src_width, dest_width, s->dest_width,
|
||||
s->invalidated,
|
||||
fn, s->dma_ch[0].palette, miny, maxy);
|
||||
@@ -715,8 +719,11 @@ static void pxa2xx_lcdc_dma0_redraw_rot90(PXA2xxLCDState *s,
|
||||
|
||||
dest_width = s->yres * s->dest_width;
|
||||
*miny = 0;
|
||||
framebuffer_update_display(surface, s->sysmem,
|
||||
addr, s->xres, s->yres,
|
||||
if (s->invalidated) {
|
||||
framebuffer_update_memory_section(&s->fbsection, s->sysmem,
|
||||
addr, s->yres, src_width);
|
||||
}
|
||||
framebuffer_update_display(surface, &s->fbsection, s->xres, s->yres,
|
||||
src_width, s->dest_width, -dest_width,
|
||||
s->invalidated,
|
||||
fn, s->dma_ch[0].palette,
|
||||
@@ -747,8 +754,11 @@ static void pxa2xx_lcdc_dma0_redraw_rot180(PXA2xxLCDState *s,
|
||||
|
||||
dest_width = s->xres * s->dest_width;
|
||||
*miny = 0;
|
||||
framebuffer_update_display(surface, s->sysmem,
|
||||
addr, s->xres, s->yres,
|
||||
if (s->invalidated) {
|
||||
framebuffer_update_memory_section(&s->fbsection, s->sysmem,
|
||||
addr, s->yres, src_width);
|
||||
}
|
||||
framebuffer_update_display(surface, &s->fbsection, s->xres, s->yres,
|
||||
src_width, -dest_width, -s->dest_width,
|
||||
s->invalidated,
|
||||
fn, s->dma_ch[0].palette, miny, maxy);
|
||||
@@ -778,8 +788,11 @@ static void pxa2xx_lcdc_dma0_redraw_rot270(PXA2xxLCDState *s,
|
||||
|
||||
dest_width = s->yres * s->dest_width;
|
||||
*miny = 0;
|
||||
framebuffer_update_display(surface, s->sysmem,
|
||||
addr, s->xres, s->yres,
|
||||
if (s->invalidated) {
|
||||
framebuffer_update_memory_section(&s->fbsection, s->sysmem,
|
||||
addr, s->yres, src_width);
|
||||
}
|
||||
framebuffer_update_display(surface, &s->fbsection, s->xres, s->yres,
|
||||
src_width, -s->dest_width, dest_width,
|
||||
s->invalidated,
|
||||
fn, s->dma_ch[0].palette,
|
||||
|
||||
@@ -89,7 +89,8 @@ static void virtio_gpu_set_config(VirtIODevice *vdev, const uint8_t *config)
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t virtio_gpu_get_features(VirtIODevice *vdev, uint64_t features)
|
||||
static uint64_t virtio_gpu_get_features(VirtIODevice *vdev, uint64_t features,
|
||||
Error **errp)
|
||||
{
|
||||
return features;
|
||||
}
|
||||
|
||||
@@ -1108,8 +1108,8 @@ build_ssdt(GArray *table_data, GArray *linker,
|
||||
aml_append(field, aml_named_field("PEPT", 8));
|
||||
aml_append(dev, field);
|
||||
|
||||
/* device present, functioning, decoding, not shown in UI */
|
||||
aml_append(dev, aml_name_decl("_STA", aml_int(0xB)));
|
||||
/* device present, functioning, decoding, shown in UI */
|
||||
aml_append(dev, aml_name_decl("_STA", aml_int(0xF)));
|
||||
|
||||
method = aml_method("RDPT", 0);
|
||||
aml_append(method, aml_store(aml_name("PEPT"), aml_local(0)));
|
||||
|
||||
+1
-1
@@ -127,7 +127,7 @@
|
||||
#define PORT_CMD_SPIN_UP (1 << 1) /* Spin up device */
|
||||
#define PORT_CMD_START (1 << 0) /* Enable port DMA engine */
|
||||
|
||||
#define PORT_CMD_ICC_MASK (0xf << 28) /* i/f ICC state mask */
|
||||
#define PORT_CMD_ICC_MASK (0xfU << 28) /* i/f ICC state mask */
|
||||
#define PORT_CMD_ICC_ACTIVE (0x1 << 28) /* Put i/f in active state */
|
||||
#define PORT_CMD_ICC_PARTIAL (0x2 << 28) /* Put i/f in partial state */
|
||||
#define PORT_CMD_ICC_SLUMBER (0x6 << 28) /* Put i/f in slumber state */
|
||||
|
||||
@@ -983,6 +983,7 @@ static void cmd_start_stop_unit(IDEState *s, uint8_t* buf)
|
||||
|
||||
if (pwrcnd) {
|
||||
/* eject/load only happens for power condition == 0 */
|
||||
ide_atapi_cmd_ok(s);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+28
-4
@@ -2021,11 +2021,17 @@ void ide_data_writew(void *opaque, uint32_t addr, uint32_t val)
|
||||
}
|
||||
|
||||
p = s->data_ptr;
|
||||
if (p + 2 > s->data_end) {
|
||||
return;
|
||||
}
|
||||
|
||||
*(uint16_t *)p = le16_to_cpu(val);
|
||||
p += 2;
|
||||
s->data_ptr = p;
|
||||
if (p >= s->data_end)
|
||||
if (p >= s->data_end) {
|
||||
s->status &= ~DRQ_STAT;
|
||||
s->end_transfer_func(s);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ide_data_readw(void *opaque, uint32_t addr)
|
||||
@@ -2042,11 +2048,17 @@ uint32_t ide_data_readw(void *opaque, uint32_t addr)
|
||||
}
|
||||
|
||||
p = s->data_ptr;
|
||||
if (p + 2 > s->data_end) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = cpu_to_le16(*(uint16_t *)p);
|
||||
p += 2;
|
||||
s->data_ptr = p;
|
||||
if (p >= s->data_end)
|
||||
if (p >= s->data_end) {
|
||||
s->status &= ~DRQ_STAT;
|
||||
s->end_transfer_func(s);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2063,11 +2075,17 @@ void ide_data_writel(void *opaque, uint32_t addr, uint32_t val)
|
||||
}
|
||||
|
||||
p = s->data_ptr;
|
||||
if (p + 4 > s->data_end) {
|
||||
return;
|
||||
}
|
||||
|
||||
*(uint32_t *)p = le32_to_cpu(val);
|
||||
p += 4;
|
||||
s->data_ptr = p;
|
||||
if (p >= s->data_end)
|
||||
if (p >= s->data_end) {
|
||||
s->status &= ~DRQ_STAT;
|
||||
s->end_transfer_func(s);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ide_data_readl(void *opaque, uint32_t addr)
|
||||
@@ -2084,11 +2102,17 @@ uint32_t ide_data_readl(void *opaque, uint32_t addr)
|
||||
}
|
||||
|
||||
p = s->data_ptr;
|
||||
if (p + 4 > s->data_end) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = cpu_to_le32(*(uint32_t *)p);
|
||||
p += 4;
|
||||
s->data_ptr = p;
|
||||
if (p >= s->data_end)
|
||||
if (p >= s->data_end) {
|
||||
s->status &= ~DRQ_STAT;
|
||||
s->end_transfer_func(s);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -208,6 +208,33 @@ static void pmac_dma_write(BlockBackend *blk,
|
||||
cb, io);
|
||||
}
|
||||
|
||||
static void pmac_dma_trim(BlockBackend *blk,
|
||||
int64_t offset, int bytes,
|
||||
void (*cb)(void *opaque, int ret), void *opaque)
|
||||
{
|
||||
DBDMA_io *io = opaque;
|
||||
MACIOIDEState *m = io->opaque;
|
||||
IDEState *s = idebus_active_if(&m->bus);
|
||||
dma_addr_t dma_addr, dma_len;
|
||||
void *mem;
|
||||
|
||||
qemu_iovec_destroy(&io->iov);
|
||||
qemu_iovec_init(&io->iov, io->len / MACIO_PAGE_SIZE + 1);
|
||||
|
||||
dma_addr = io->addr;
|
||||
dma_len = io->len;
|
||||
mem = dma_memory_map(&address_space_memory, dma_addr, &dma_len,
|
||||
DMA_DIRECTION_TO_DEVICE);
|
||||
|
||||
qemu_iovec_add(&io->iov, mem, io->len);
|
||||
s->io_buffer_size -= io->len;
|
||||
s->io_buffer_index += io->len;
|
||||
io->len = 0;
|
||||
|
||||
m->aiocb = ide_issue_trim(blk, (offset >> 9), &io->iov, (bytes >> 9),
|
||||
cb, io);
|
||||
}
|
||||
|
||||
static void pmac_ide_atapi_transfer_cb(void *opaque, int ret)
|
||||
{
|
||||
DBDMA_io *io = opaque;
|
||||
@@ -313,6 +340,7 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
|
||||
pmac_dma_write(s->blk, offset, io->len, pmac_ide_transfer_cb, io);
|
||||
break;
|
||||
case IDE_DMA_TRIM:
|
||||
pmac_dma_trim(s->blk, offset, io->len, pmac_ide_transfer_cb, io);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -169,6 +169,7 @@ int pci_piix3_xen_ide_unplug(DeviceState *dev)
|
||||
PCIIDEState *pci_ide;
|
||||
DriveInfo *di;
|
||||
int i;
|
||||
IDEDevice *idedev;
|
||||
|
||||
pci_ide = PCI_IDE(dev);
|
||||
|
||||
@@ -181,6 +182,12 @@ int pci_piix3_xen_ide_unplug(DeviceState *dev)
|
||||
blk_detach_dev(blk, ds);
|
||||
}
|
||||
pci_ide->bus[di->bus].ifs[di->unit].blk = NULL;
|
||||
if (!(i % 2)) {
|
||||
idedev = pci_ide->bus[di->bus].master;
|
||||
} else {
|
||||
idedev = pci_ide->bus[di->bus].slave;
|
||||
}
|
||||
idedev->conf.blk = NULL;
|
||||
blk_unref(blk);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,7 +166,8 @@ static void virtio_input_set_config(VirtIODevice *vdev,
|
||||
virtio_notify_config(vdev);
|
||||
}
|
||||
|
||||
static uint64_t virtio_input_get_features(VirtIODevice *vdev, uint64_t f)
|
||||
static uint64_t virtio_input_get_features(VirtIODevice *vdev, uint64_t f,
|
||||
Error **errp)
|
||||
{
|
||||
return f;
|
||||
}
|
||||
|
||||
+18
-7
@@ -327,9 +327,14 @@ static void dp8393x_do_stop_timer(dp8393xState *s)
|
||||
dp8393x_update_wt_regs(s);
|
||||
}
|
||||
|
||||
static int dp8393x_can_receive(NetClientState *nc);
|
||||
|
||||
static void dp8393x_do_receiver_enable(dp8393xState *s)
|
||||
{
|
||||
s->regs[SONIC_CR] &= ~SONIC_CR_RXDIS;
|
||||
if (dp8393x_can_receive(s->nic->ncs)) {
|
||||
qemu_flush_queued_packets(qemu_get_queue(s->nic));
|
||||
}
|
||||
}
|
||||
|
||||
static void dp8393x_do_receiver_disable(dp8393xState *s)
|
||||
@@ -569,6 +574,9 @@ static void dp8393x_write(void *opaque, hwaddr addr, uint64_t data,
|
||||
dp8393x_do_read_rra(s);
|
||||
}
|
||||
dp8393x_update_irq(s);
|
||||
if (dp8393x_can_receive(s->nic->ncs)) {
|
||||
qemu_flush_queued_packets(qemu_get_queue(s->nic));
|
||||
}
|
||||
break;
|
||||
/* Ignore least significant bit */
|
||||
case SONIC_RSA:
|
||||
@@ -635,11 +643,6 @@ static int dp8393x_receive_filter(dp8393xState *s, const uint8_t * buf,
|
||||
static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
int i;
|
||||
|
||||
/* Check for runt packet (remember that checksum is not there) */
|
||||
if (size < 64 - 4) {
|
||||
return (s->regs[SONIC_RCR] & SONIC_RCR_RNT) ? 0 : -1;
|
||||
}
|
||||
|
||||
/* Check promiscuous mode */
|
||||
if ((s->regs[SONIC_RCR] & SONIC_RCR_PRO) && (buf[0] & 1) == 0) {
|
||||
return 0;
|
||||
@@ -828,6 +831,7 @@ static void dp8393x_realize(DeviceState *dev, Error **errp)
|
||||
dp8393xState *s = DP8393X(dev);
|
||||
int i, checksum;
|
||||
uint8_t *prom;
|
||||
Error *local_err = NULL;
|
||||
|
||||
address_space_init(&s->as, s->dma_mr, "dp8393x");
|
||||
memory_region_init_io(&s->mmio, OBJECT(dev), &dp8393x_ops, s,
|
||||
@@ -840,8 +844,13 @@ static void dp8393x_realize(DeviceState *dev, Error **errp)
|
||||
s->watchdog = timer_new_ns(QEMU_CLOCK_VIRTUAL, dp8393x_watchdog, s);
|
||||
s->regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux */
|
||||
|
||||
memory_region_init_rom_device(&s->prom, OBJECT(dev), NULL, NULL,
|
||||
"dp8393x-prom", SONIC_PROM_SIZE, NULL);
|
||||
memory_region_init_ram(&s->prom, OBJECT(dev),
|
||||
"dp8393x-prom", SONIC_PROM_SIZE, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
memory_region_set_readonly(&s->prom, true);
|
||||
prom = memory_region_get_ram_ptr(&s->prom);
|
||||
checksum = 0;
|
||||
for (i = 0; i < 6; i++) {
|
||||
@@ -881,6 +890,8 @@ static void dp8393x_class_init(ObjectClass *klass, void *data)
|
||||
dc->reset = dp8393x_reset;
|
||||
dc->vmsd = &vmstate_dp8393x;
|
||||
dc->props = dp8393x_properties;
|
||||
/* Reason: dma_mr property can't be set */
|
||||
dc->cannot_instantiate_with_device_add_yet = true;
|
||||
}
|
||||
|
||||
static const TypeInfo dp8393x_info = {
|
||||
|
||||
@@ -1617,16 +1617,6 @@ static const MemoryRegionOps eepro100_ops = {
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static int nic_can_receive(NetClientState *nc)
|
||||
{
|
||||
EEPRO100State *s = qemu_get_nic_opaque(nc);
|
||||
TRACE(RXTX, logout("%p\n", s));
|
||||
return get_ru_state(s) == ru_ready;
|
||||
#if 0
|
||||
return !eepro100_buffer_full(s);
|
||||
#endif
|
||||
}
|
||||
|
||||
static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size)
|
||||
{
|
||||
/* TODO:
|
||||
@@ -1844,7 +1834,6 @@ static void pci_nic_uninit(PCIDevice *pci_dev)
|
||||
static NetClientInfo net_eepro100_info = {
|
||||
.type = NET_CLIENT_OPTIONS_KIND_NIC,
|
||||
.size = sizeof(NICState),
|
||||
.can_receive = nic_can_receive,
|
||||
.receive = nic_receive,
|
||||
};
|
||||
|
||||
|
||||
+10
-10
@@ -338,25 +338,26 @@ static void etsec_reset(DeviceState *d)
|
||||
MII_SR_100X_FD_CAPS | MII_SR_100T4_CAPS;
|
||||
}
|
||||
|
||||
static int etsec_can_receive(NetClientState *nc)
|
||||
{
|
||||
eTSEC *etsec = qemu_get_nic_opaque(nc);
|
||||
|
||||
return etsec->rx_buffer_len == 0;
|
||||
}
|
||||
|
||||
static ssize_t etsec_receive(NetClientState *nc,
|
||||
const uint8_t *buf,
|
||||
size_t size)
|
||||
{
|
||||
ssize_t ret;
|
||||
eTSEC *etsec = qemu_get_nic_opaque(nc);
|
||||
|
||||
#if defined(HEX_DUMP)
|
||||
fprintf(stderr, "%s receive size:%d\n", etsec->nic->nc.name, size);
|
||||
qemu_hexdump(buf, stderr, "", size);
|
||||
#endif
|
||||
etsec_rx_ring_write(etsec, buf, size);
|
||||
return size;
|
||||
/* Flush is unnecessary as are already in receiving path */
|
||||
etsec->need_flush = false;
|
||||
ret = etsec_rx_ring_write(etsec, buf, size);
|
||||
if (ret == 0) {
|
||||
/* The packet will be queued, let's flush it when buffer is avilable
|
||||
* again. */
|
||||
etsec->need_flush = true;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -370,7 +371,6 @@ static void etsec_set_link_status(NetClientState *nc)
|
||||
static NetClientInfo net_etsec_info = {
|
||||
.type = NET_CLIENT_OPTIONS_KIND_NIC,
|
||||
.size = sizeof(NICState),
|
||||
.can_receive = etsec_can_receive,
|
||||
.receive = etsec_receive,
|
||||
.link_status_changed = etsec_set_link_status,
|
||||
};
|
||||
|
||||
@@ -144,6 +144,8 @@ typedef struct eTSEC {
|
||||
QEMUBH *bh;
|
||||
struct ptimer_state *ptimer;
|
||||
|
||||
/* Whether we should flush the rx queue when buffer becomes available. */
|
||||
bool need_flush;
|
||||
} eTSEC;
|
||||
|
||||
#define TYPE_ETSEC_COMMON "eTSEC"
|
||||
@@ -162,7 +164,7 @@ DeviceState *etsec_create(hwaddr base,
|
||||
|
||||
void etsec_walk_tx_ring(eTSEC *etsec, int ring_nbr);
|
||||
void etsec_walk_rx_ring(eTSEC *etsec, int ring_nbr);
|
||||
void etsec_rx_ring_write(eTSEC *etsec, const uint8_t *buf, size_t size);
|
||||
ssize_t etsec_rx_ring_write(eTSEC *etsec, const uint8_t *buf, size_t size);
|
||||
|
||||
void etsec_write_miim(eTSEC *etsec,
|
||||
eTSEC_Register *reg,
|
||||
|
||||
@@ -481,40 +481,42 @@ static void rx_init_frame(eTSEC *etsec, const uint8_t *buf, size_t size)
|
||||
etsec->rx_buffer_len, etsec->rx_padding);
|
||||
}
|
||||
|
||||
void etsec_rx_ring_write(eTSEC *etsec, const uint8_t *buf, size_t size)
|
||||
ssize_t etsec_rx_ring_write(eTSEC *etsec, const uint8_t *buf, size_t size)
|
||||
{
|
||||
int ring_nbr = 0; /* Always use ring0 (no filer) */
|
||||
|
||||
if (etsec->rx_buffer_len != 0) {
|
||||
RING_DEBUG("%s: We can't receive now,"
|
||||
" a buffer is already in the pipe\n", __func__);
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (etsec->regs[RSTAT].value & 1 << (23 - ring_nbr)) {
|
||||
RING_DEBUG("%s: The ring is halted\n", __func__);
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (etsec->regs[DMACTRL].value & DMACTRL_GRS) {
|
||||
RING_DEBUG("%s: Graceful receive stop\n", __func__);
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(etsec->regs[MACCFG1].value & MACCFG1_RX_EN)) {
|
||||
RING_DEBUG("%s: MAC Receive not enabled\n", __func__);
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((etsec->regs[RCTRL].value & RCTRL_RSF) && (size < 60)) {
|
||||
/* CRC is not in the packet yet, so short frame is below 60 bytes */
|
||||
RING_DEBUG("%s: Drop short frame\n", __func__);
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
|
||||
rx_init_frame(etsec, buf, size);
|
||||
|
||||
etsec_walk_rx_ring(etsec, ring_nbr);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void etsec_walk_rx_ring(eTSEC *etsec, int ring_nbr)
|
||||
@@ -644,6 +646,9 @@ void etsec_walk_rx_ring(eTSEC *etsec, int ring_nbr)
|
||||
} else {
|
||||
etsec->rx_buffer_len = 0;
|
||||
etsec->rx_buffer = NULL;
|
||||
if (etsec->need_flush) {
|
||||
qemu_flush_queued_packets(qemu_get_queue(etsec->nic));
|
||||
}
|
||||
}
|
||||
|
||||
RING_DEBUG("eTSEC End of ring_write: remaining_data:%zu\n", remaining_data);
|
||||
|
||||
@@ -94,7 +94,6 @@ static const MemoryRegionOps lance_mem_ops = {
|
||||
static NetClientInfo net_lance_info = {
|
||||
.type = NET_CLIENT_OPTIONS_KIND_NIC,
|
||||
.size = sizeof(NICState),
|
||||
.can_receive = pcnet_can_receive,
|
||||
.receive = pcnet_receive,
|
||||
.link_status_changed = pcnet_set_link_status,
|
||||
};
|
||||
|
||||
+83
-18
@@ -8,6 +8,7 @@
|
||||
#include "hw/hw.h"
|
||||
#include "net/net.h"
|
||||
#include "hw/m68k/mcf.h"
|
||||
#include "hw/net/mii.h"
|
||||
/* For crc32 */
|
||||
#include <zlib.h>
|
||||
#include "exec/address-spaces.h"
|
||||
@@ -195,12 +196,14 @@ static void mcf_fec_do_tx(mcf_fec_state *s)
|
||||
|
||||
static void mcf_fec_enable_rx(mcf_fec_state *s)
|
||||
{
|
||||
NetClientState *nc = qemu_get_queue(s->nic);
|
||||
mcf_fec_bd bd;
|
||||
|
||||
mcf_fec_read_bd(&bd, s->rx_descriptor);
|
||||
s->rx_enabled = ((bd.flags & FEC_BD_E) != 0);
|
||||
if (!s->rx_enabled)
|
||||
DPRINTF("RX buffer full\n");
|
||||
if (s->rx_enabled) {
|
||||
qemu_flush_queued_packets(nc);
|
||||
}
|
||||
}
|
||||
|
||||
static void mcf_fec_reset(mcf_fec_state *s)
|
||||
@@ -216,6 +219,51 @@ static void mcf_fec_reset(mcf_fec_state *s)
|
||||
s->rfsr = 0x500;
|
||||
}
|
||||
|
||||
#define MMFR_WRITE_OP (1 << 28)
|
||||
#define MMFR_READ_OP (2 << 28)
|
||||
#define MMFR_PHYADDR(v) (((v) >> 23) & 0x1f)
|
||||
#define MMFR_REGNUM(v) (((v) >> 18) & 0x1f)
|
||||
|
||||
static uint64_t mcf_fec_read_mdio(mcf_fec_state *s)
|
||||
{
|
||||
uint64_t v;
|
||||
|
||||
if (s->mmfr & MMFR_WRITE_OP)
|
||||
return s->mmfr;
|
||||
if (MMFR_PHYADDR(s->mmfr) != 1)
|
||||
return s->mmfr |= 0xffff;
|
||||
|
||||
switch (MMFR_REGNUM(s->mmfr)) {
|
||||
case MII_BMCR:
|
||||
v = MII_BMCR_SPEED | MII_BMCR_AUTOEN | MII_BMCR_FD;
|
||||
break;
|
||||
case MII_BMSR:
|
||||
v = MII_BMSR_100TX_FD | MII_BMSR_100TX_HD | MII_BMSR_10T_FD |
|
||||
MII_BMSR_10T_HD | MII_BMSR_MFPS | MII_BMSR_AN_COMP |
|
||||
MII_BMSR_AUTONEG | MII_BMSR_LINK_ST;
|
||||
break;
|
||||
case MII_PHYID1:
|
||||
v = DP83848_PHYID1;
|
||||
break;
|
||||
case MII_PHYID2:
|
||||
v = DP83848_PHYID2;
|
||||
break;
|
||||
case MII_ANAR:
|
||||
v = MII_ANAR_TXFD | MII_ANAR_TX | MII_ANAR_10FD |
|
||||
MII_ANAR_10 | MII_ANAR_CSMACD;
|
||||
break;
|
||||
case MII_ANLPAR:
|
||||
v = MII_ANLPAR_ACK | MII_ANLPAR_TXFD | MII_ANLPAR_TX |
|
||||
MII_ANLPAR_10FD | MII_ANLPAR_10 | MII_ANLPAR_CSMACD;
|
||||
break;
|
||||
default:
|
||||
v = 0xffff;
|
||||
break;
|
||||
}
|
||||
s->mmfr = (s->mmfr & ~0xffff) | v;
|
||||
return s->mmfr;
|
||||
}
|
||||
|
||||
static uint64_t mcf_fec_read(void *opaque, hwaddr addr,
|
||||
unsigned size)
|
||||
{
|
||||
@@ -226,7 +274,7 @@ static uint64_t mcf_fec_read(void *opaque, hwaddr addr,
|
||||
case 0x010: return s->rx_enabled ? (1 << 24) : 0; /* RDAR */
|
||||
case 0x014: return 0; /* TDAR */
|
||||
case 0x024: return s->ecr;
|
||||
case 0x040: return s->mmfr;
|
||||
case 0x040: return mcf_fec_read_mdio(s);
|
||||
case 0x044: return s->mscr;
|
||||
case 0x064: return 0; /* MIBC */
|
||||
case 0x084: return s->rcr;
|
||||
@@ -287,8 +335,8 @@ static void mcf_fec_write(void *opaque, hwaddr addr,
|
||||
}
|
||||
break;
|
||||
case 0x040:
|
||||
/* TODO: Implement MII. */
|
||||
s->mmfr = value;
|
||||
s->eir |= FEC_INT_MII;
|
||||
break;
|
||||
case 0x044:
|
||||
s->mscr = value & 0xfe;
|
||||
@@ -351,10 +399,30 @@ static void mcf_fec_write(void *opaque, hwaddr addr,
|
||||
mcf_fec_update(s);
|
||||
}
|
||||
|
||||
static int mcf_fec_can_receive(NetClientState *nc)
|
||||
static int mcf_fec_have_receive_space(mcf_fec_state *s, size_t want)
|
||||
{
|
||||
mcf_fec_state *s = qemu_get_nic_opaque(nc);
|
||||
return s->rx_enabled;
|
||||
mcf_fec_bd bd;
|
||||
uint32_t addr;
|
||||
|
||||
/* Walk descriptor list to determine if we have enough buffer */
|
||||
addr = s->rx_descriptor;
|
||||
while (want > 0) {
|
||||
mcf_fec_read_bd(&bd, addr);
|
||||
if ((bd.flags & FEC_BD_E) == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (want < s->emrbr) {
|
||||
return 1;
|
||||
}
|
||||
want -= s->emrbr;
|
||||
/* Advance to the next descriptor. */
|
||||
if ((bd.flags & FEC_BD_W) != 0) {
|
||||
addr = s->erdsr;
|
||||
} else {
|
||||
addr += 8;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t mcf_fec_receive(NetClientState *nc, const uint8_t *buf, size_t size)
|
||||
@@ -367,10 +435,11 @@ static ssize_t mcf_fec_receive(NetClientState *nc, const uint8_t *buf, size_t si
|
||||
uint32_t buf_addr;
|
||||
uint8_t *crc_ptr;
|
||||
unsigned int buf_len;
|
||||
size_t retsize;
|
||||
|
||||
DPRINTF("do_rx len %d\n", size);
|
||||
if (!s->rx_enabled) {
|
||||
fprintf(stderr, "mcf_fec_receive: Unexpected packet\n");
|
||||
return -1;
|
||||
}
|
||||
/* 4 bytes for the CRC. */
|
||||
size += 4;
|
||||
@@ -385,17 +454,14 @@ static ssize_t mcf_fec_receive(NetClientState *nc, const uint8_t *buf, size_t si
|
||||
if (size > (s->rcr >> 16)) {
|
||||
flags |= FEC_BD_LG;
|
||||
}
|
||||
/* Check if we have enough space in current descriptors */
|
||||
if (!mcf_fec_have_receive_space(s, size)) {
|
||||
return 0;
|
||||
}
|
||||
addr = s->rx_descriptor;
|
||||
retsize = size;
|
||||
while (size > 0) {
|
||||
mcf_fec_read_bd(&bd, addr);
|
||||
if ((bd.flags & FEC_BD_E) == 0) {
|
||||
/* No descriptors available. Bail out. */
|
||||
/* FIXME: This is wrong. We should probably either save the
|
||||
remainder for when more RX buffers are available, or
|
||||
flag an error. */
|
||||
fprintf(stderr, "mcf_fec: Lost end of frame\n");
|
||||
break;
|
||||
}
|
||||
buf_len = (size <= s->emrbr) ? size: s->emrbr;
|
||||
bd.length = buf_len;
|
||||
size -= buf_len;
|
||||
@@ -430,7 +496,7 @@ static ssize_t mcf_fec_receive(NetClientState *nc, const uint8_t *buf, size_t si
|
||||
s->rx_descriptor = addr;
|
||||
mcf_fec_enable_rx(s);
|
||||
mcf_fec_update(s);
|
||||
return size;
|
||||
return retsize;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps mcf_fec_ops = {
|
||||
@@ -442,7 +508,6 @@ static const MemoryRegionOps mcf_fec_ops = {
|
||||
static NetClientInfo net_mcf_fec_info = {
|
||||
.type = NET_CLIENT_OPTIONS_KIND_NIC,
|
||||
.size = sizeof(NICState),
|
||||
.can_receive = mcf_fec_can_receive,
|
||||
.receive = mcf_fec_receive,
|
||||
};
|
||||
|
||||
|
||||
+16
-17
@@ -303,8 +303,7 @@ static ssize_t minimac2_rx(NetClientState *nc, const uint8_t *buf, size_t size)
|
||||
r_state = R_STATE1;
|
||||
rx_buf = s->rx1_buf;
|
||||
} else {
|
||||
trace_milkymist_minimac2_drop_rx_frame(buf);
|
||||
return size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* assemble frame */
|
||||
@@ -354,6 +353,18 @@ minimac2_read(void *opaque, hwaddr addr, unsigned size)
|
||||
return r;
|
||||
}
|
||||
|
||||
static int minimac2_can_rx(MilkymistMinimac2State *s)
|
||||
{
|
||||
if (s->regs[R_STATE0] == STATE_LOADED) {
|
||||
return 1;
|
||||
}
|
||||
if (s->regs[R_STATE1] == STATE_LOADED) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
minimac2_write(void *opaque, hwaddr addr, uint64_t value,
|
||||
unsigned size)
|
||||
@@ -387,6 +398,9 @@ minimac2_write(void *opaque, hwaddr addr, uint64_t value,
|
||||
case R_STATE1:
|
||||
s->regs[addr] = value;
|
||||
update_rx_interrupt(s);
|
||||
if (minimac2_can_rx(s)) {
|
||||
qemu_flush_queued_packets(qemu_get_queue(s->nic));
|
||||
}
|
||||
break;
|
||||
case R_SETUP:
|
||||
case R_COUNT0:
|
||||
@@ -411,20 +425,6 @@ static const MemoryRegionOps minimac2_ops = {
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static int minimac2_can_rx(NetClientState *nc)
|
||||
{
|
||||
MilkymistMinimac2State *s = qemu_get_nic_opaque(nc);
|
||||
|
||||
if (s->regs[R_STATE0] == STATE_LOADED) {
|
||||
return 1;
|
||||
}
|
||||
if (s->regs[R_STATE1] == STATE_LOADED) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void milkymist_minimac2_reset(DeviceState *d)
|
||||
{
|
||||
MilkymistMinimac2State *s = MILKYMIST_MINIMAC2(d);
|
||||
@@ -445,7 +445,6 @@ static void milkymist_minimac2_reset(DeviceState *d)
|
||||
static NetClientInfo net_milkymist_minimac2_info = {
|
||||
.type = NET_CLIENT_OPTIONS_KIND_NIC,
|
||||
.size = sizeof(NICState),
|
||||
.can_receive = minimac2_can_rx,
|
||||
.receive = minimac2_rx,
|
||||
};
|
||||
|
||||
|
||||
+7
-2
@@ -80,7 +80,7 @@ static ssize_t mipsnet_receive(NetClientState *nc, const uint8_t *buf, size_t si
|
||||
|
||||
trace_mipsnet_receive(size);
|
||||
if (!mipsnet_can_receive(nc))
|
||||
return -1;
|
||||
return 0;
|
||||
|
||||
s->busy = 1;
|
||||
|
||||
@@ -134,6 +134,9 @@ static uint64_t mipsnet_ioport_read(void *opaque, hwaddr addr,
|
||||
if (s->rx_count) {
|
||||
s->rx_count--;
|
||||
ret = s->rx_buffer[s->rx_read++];
|
||||
if (mipsnet_can_receive(s->nic->ncs)) {
|
||||
qemu_flush_queued_packets(qemu_get_queue(s->nic));
|
||||
}
|
||||
}
|
||||
break;
|
||||
/* Reads as zero. */
|
||||
@@ -170,6 +173,9 @@ static void mipsnet_ioport_write(void *opaque, hwaddr addr,
|
||||
}
|
||||
s->busy = !!s->intctl;
|
||||
mipsnet_update_irq(s);
|
||||
if (mipsnet_can_receive(s->nic->ncs)) {
|
||||
qemu_flush_queued_packets(qemu_get_queue(s->nic));
|
||||
}
|
||||
break;
|
||||
case MIPSNET_TX_DATA_BUFFER:
|
||||
s->tx_buffer[s->tx_written++] = val;
|
||||
@@ -214,7 +220,6 @@ static const VMStateDescription vmstate_mipsnet = {
|
||||
static NetClientInfo net_mipsnet_info = {
|
||||
.type = NET_CLIENT_OPTIONS_KIND_NIC,
|
||||
.size = sizeof(NICState),
|
||||
.can_receive = mipsnet_can_receive,
|
||||
.receive = mipsnet_receive,
|
||||
};
|
||||
|
||||
|
||||
@@ -273,7 +273,6 @@ static void pci_pcnet_uninit(PCIDevice *dev)
|
||||
static NetClientInfo net_pci_pcnet_info = {
|
||||
.type = NET_CLIENT_OPTIONS_KIND_NIC,
|
||||
.size = sizeof(NICState),
|
||||
.can_receive = pcnet_can_receive,
|
||||
.receive = pcnet_receive,
|
||||
.link_status_changed = pcnet_set_link_status,
|
||||
};
|
||||
|
||||
@@ -995,15 +995,6 @@ static int pcnet_tdte_poll(PCNetState *s)
|
||||
return !!(CSR_CXST(s) & 0x8000);
|
||||
}
|
||||
|
||||
int pcnet_can_receive(NetClientState *nc)
|
||||
{
|
||||
PCNetState *s = qemu_get_nic_opaque(nc);
|
||||
if (CSR_STOP(s) || CSR_SPND(s))
|
||||
return 0;
|
||||
|
||||
return sizeof(s->buffer)-16;
|
||||
}
|
||||
|
||||
#define MIN_BUF_SIZE 60
|
||||
|
||||
ssize_t pcnet_receive(NetClientState *nc, const uint8_t *buf, size_t size_)
|
||||
|
||||
@@ -60,7 +60,6 @@ uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr);
|
||||
void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val);
|
||||
uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr);
|
||||
uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap);
|
||||
int pcnet_can_receive(NetClientState *nc);
|
||||
ssize_t pcnet_receive(NetClientState *nc, const uint8_t *buf, size_t size_);
|
||||
void pcnet_set_link_status(NetClientState *nc);
|
||||
void pcnet_common_init(DeviceState *dev, PCNetState *s, NetClientInfo *info);
|
||||
|
||||
+206
-189
@@ -2150,6 +2150,11 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
|
||||
{
|
||||
DPRINTF("+++ C+ mode offloaded task checksum\n");
|
||||
|
||||
/* Large enough for Ethernet and IP headers? */
|
||||
if (saved_size < ETH_HLEN + sizeof(ip_header)) {
|
||||
goto skip_offload;
|
||||
}
|
||||
|
||||
/* ip packet header */
|
||||
ip_header *ip = NULL;
|
||||
int hlen = 0;
|
||||
@@ -2160,223 +2165,235 @@ static int rtl8139_cplus_transmit_one(RTL8139State *s)
|
||||
size_t eth_payload_len = 0;
|
||||
|
||||
int proto = be16_to_cpu(*(uint16_t *)(saved_buffer + 12));
|
||||
if (proto == ETH_P_IP)
|
||||
if (proto != ETH_P_IP)
|
||||
{
|
||||
DPRINTF("+++ C+ mode has IP packet\n");
|
||||
|
||||
/* not aligned */
|
||||
eth_payload_data = saved_buffer + ETH_HLEN;
|
||||
eth_payload_len = saved_size - ETH_HLEN;
|
||||
|
||||
ip = (ip_header*)eth_payload_data;
|
||||
|
||||
if (IP_HEADER_VERSION(ip) != IP_HEADER_VERSION_4) {
|
||||
DPRINTF("+++ C+ mode packet has bad IP version %d "
|
||||
"expected %d\n", IP_HEADER_VERSION(ip),
|
||||
IP_HEADER_VERSION_4);
|
||||
ip = NULL;
|
||||
} else {
|
||||
hlen = IP_HEADER_LENGTH(ip);
|
||||
ip_protocol = ip->ip_p;
|
||||
ip_data_len = be16_to_cpu(ip->ip_len) - hlen;
|
||||
}
|
||||
goto skip_offload;
|
||||
}
|
||||
|
||||
if (ip)
|
||||
DPRINTF("+++ C+ mode has IP packet\n");
|
||||
|
||||
/* not aligned */
|
||||
eth_payload_data = saved_buffer + ETH_HLEN;
|
||||
eth_payload_len = saved_size - ETH_HLEN;
|
||||
|
||||
ip = (ip_header*)eth_payload_data;
|
||||
|
||||
if (IP_HEADER_VERSION(ip) != IP_HEADER_VERSION_4) {
|
||||
DPRINTF("+++ C+ mode packet has bad IP version %d "
|
||||
"expected %d\n", IP_HEADER_VERSION(ip),
|
||||
IP_HEADER_VERSION_4);
|
||||
goto skip_offload;
|
||||
}
|
||||
|
||||
hlen = IP_HEADER_LENGTH(ip);
|
||||
if (hlen < sizeof(ip_header) || hlen > eth_payload_len) {
|
||||
goto skip_offload;
|
||||
}
|
||||
|
||||
ip_protocol = ip->ip_p;
|
||||
|
||||
ip_data_len = be16_to_cpu(ip->ip_len);
|
||||
if (ip_data_len < hlen || ip_data_len > eth_payload_len) {
|
||||
goto skip_offload;
|
||||
}
|
||||
ip_data_len -= hlen;
|
||||
|
||||
if (txdw0 & CP_TX_IPCS)
|
||||
{
|
||||
if (txdw0 & CP_TX_IPCS)
|
||||
{
|
||||
DPRINTF("+++ C+ mode need IP checksum\n");
|
||||
DPRINTF("+++ C+ mode need IP checksum\n");
|
||||
|
||||
if (hlen<sizeof(ip_header) || hlen>eth_payload_len) {/* min header length */
|
||||
/* bad packet header len */
|
||||
/* or packet too short */
|
||||
}
|
||||
else
|
||||
{
|
||||
ip->ip_sum = 0;
|
||||
ip->ip_sum = ip_checksum(ip, hlen);
|
||||
DPRINTF("+++ C+ mode IP header len=%d checksum=%04x\n",
|
||||
hlen, ip->ip_sum);
|
||||
}
|
||||
ip->ip_sum = 0;
|
||||
ip->ip_sum = ip_checksum(ip, hlen);
|
||||
DPRINTF("+++ C+ mode IP header len=%d checksum=%04x\n",
|
||||
hlen, ip->ip_sum);
|
||||
}
|
||||
|
||||
if ((txdw0 & CP_TX_LGSEN) && ip_protocol == IP_PROTO_TCP)
|
||||
{
|
||||
/* Large enough for the TCP header? */
|
||||
if (ip_data_len < sizeof(tcp_header)) {
|
||||
goto skip_offload;
|
||||
}
|
||||
|
||||
if ((txdw0 & CP_TX_LGSEN) && ip_protocol == IP_PROTO_TCP)
|
||||
int large_send_mss = (txdw0 >> 16) & CP_TC_LGSEN_MSS_MASK;
|
||||
|
||||
DPRINTF("+++ C+ mode offloaded task TSO MTU=%d IP data %d "
|
||||
"frame data %d specified MSS=%d\n", ETH_MTU,
|
||||
ip_data_len, saved_size - ETH_HLEN, large_send_mss);
|
||||
|
||||
int tcp_send_offset = 0;
|
||||
int send_count = 0;
|
||||
|
||||
/* maximum IP header length is 60 bytes */
|
||||
uint8_t saved_ip_header[60];
|
||||
|
||||
/* save IP header template; data area is used in tcp checksum calculation */
|
||||
memcpy(saved_ip_header, eth_payload_data, hlen);
|
||||
|
||||
/* a placeholder for checksum calculation routine in tcp case */
|
||||
uint8_t *data_to_checksum = eth_payload_data + hlen - 12;
|
||||
// size_t data_to_checksum_len = eth_payload_len - hlen + 12;
|
||||
|
||||
/* pointer to TCP header */
|
||||
tcp_header *p_tcp_hdr = (tcp_header*)(eth_payload_data + hlen);
|
||||
|
||||
int tcp_hlen = TCP_HEADER_DATA_OFFSET(p_tcp_hdr);
|
||||
|
||||
/* Invalid TCP data offset? */
|
||||
if (tcp_hlen < sizeof(tcp_header) || tcp_hlen > ip_data_len) {
|
||||
goto skip_offload;
|
||||
}
|
||||
|
||||
/* ETH_MTU = ip header len + tcp header len + payload */
|
||||
int tcp_data_len = ip_data_len - tcp_hlen;
|
||||
int tcp_chunk_size = ETH_MTU - hlen - tcp_hlen;
|
||||
|
||||
DPRINTF("+++ C+ mode TSO IP data len %d TCP hlen %d TCP "
|
||||
"data len %d TCP chunk size %d\n", ip_data_len,
|
||||
tcp_hlen, tcp_data_len, tcp_chunk_size);
|
||||
|
||||
/* note the cycle below overwrites IP header data,
|
||||
but restores it from saved_ip_header before sending packet */
|
||||
|
||||
int is_last_frame = 0;
|
||||
|
||||
for (tcp_send_offset = 0; tcp_send_offset < tcp_data_len; tcp_send_offset += tcp_chunk_size)
|
||||
{
|
||||
int large_send_mss = (txdw0 >> 16) & CP_TC_LGSEN_MSS_MASK;
|
||||
uint16_t chunk_size = tcp_chunk_size;
|
||||
|
||||
DPRINTF("+++ C+ mode offloaded task TSO MTU=%d IP data %d "
|
||||
"frame data %d specified MSS=%d\n", ETH_MTU,
|
||||
ip_data_len, saved_size - ETH_HLEN, large_send_mss);
|
||||
|
||||
int tcp_send_offset = 0;
|
||||
int send_count = 0;
|
||||
|
||||
/* maximum IP header length is 60 bytes */
|
||||
uint8_t saved_ip_header[60];
|
||||
|
||||
/* save IP header template; data area is used in tcp checksum calculation */
|
||||
memcpy(saved_ip_header, eth_payload_data, hlen);
|
||||
|
||||
/* a placeholder for checksum calculation routine in tcp case */
|
||||
uint8_t *data_to_checksum = eth_payload_data + hlen - 12;
|
||||
// size_t data_to_checksum_len = eth_payload_len - hlen + 12;
|
||||
|
||||
/* pointer to TCP header */
|
||||
tcp_header *p_tcp_hdr = (tcp_header*)(eth_payload_data + hlen);
|
||||
|
||||
int tcp_hlen = TCP_HEADER_DATA_OFFSET(p_tcp_hdr);
|
||||
|
||||
/* ETH_MTU = ip header len + tcp header len + payload */
|
||||
int tcp_data_len = ip_data_len - tcp_hlen;
|
||||
int tcp_chunk_size = ETH_MTU - hlen - tcp_hlen;
|
||||
|
||||
DPRINTF("+++ C+ mode TSO IP data len %d TCP hlen %d TCP "
|
||||
"data len %d TCP chunk size %d\n", ip_data_len,
|
||||
tcp_hlen, tcp_data_len, tcp_chunk_size);
|
||||
|
||||
/* note the cycle below overwrites IP header data,
|
||||
but restores it from saved_ip_header before sending packet */
|
||||
|
||||
int is_last_frame = 0;
|
||||
|
||||
for (tcp_send_offset = 0; tcp_send_offset < tcp_data_len; tcp_send_offset += tcp_chunk_size)
|
||||
/* check if this is the last frame */
|
||||
if (tcp_send_offset + tcp_chunk_size >= tcp_data_len)
|
||||
{
|
||||
uint16_t chunk_size = tcp_chunk_size;
|
||||
|
||||
/* check if this is the last frame */
|
||||
if (tcp_send_offset + tcp_chunk_size >= tcp_data_len)
|
||||
{
|
||||
is_last_frame = 1;
|
||||
chunk_size = tcp_data_len - tcp_send_offset;
|
||||
}
|
||||
|
||||
DPRINTF("+++ C+ mode TSO TCP seqno %08x\n",
|
||||
be32_to_cpu(p_tcp_hdr->th_seq));
|
||||
|
||||
/* add 4 TCP pseudoheader fields */
|
||||
/* copy IP source and destination fields */
|
||||
memcpy(data_to_checksum, saved_ip_header + 12, 8);
|
||||
|
||||
DPRINTF("+++ C+ mode TSO calculating TCP checksum for "
|
||||
"packet with %d bytes data\n", tcp_hlen +
|
||||
chunk_size);
|
||||
|
||||
if (tcp_send_offset)
|
||||
{
|
||||
memcpy((uint8_t*)p_tcp_hdr + tcp_hlen, (uint8_t*)p_tcp_hdr + tcp_hlen + tcp_send_offset, chunk_size);
|
||||
}
|
||||
|
||||
/* keep PUSH and FIN flags only for the last frame */
|
||||
if (!is_last_frame)
|
||||
{
|
||||
TCP_HEADER_CLEAR_FLAGS(p_tcp_hdr, TCP_FLAG_PUSH|TCP_FLAG_FIN);
|
||||
}
|
||||
|
||||
/* recalculate TCP checksum */
|
||||
ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum;
|
||||
p_tcpip_hdr->zeros = 0;
|
||||
p_tcpip_hdr->ip_proto = IP_PROTO_TCP;
|
||||
p_tcpip_hdr->ip_payload = cpu_to_be16(tcp_hlen + chunk_size);
|
||||
|
||||
p_tcp_hdr->th_sum = 0;
|
||||
|
||||
int tcp_checksum = ip_checksum(data_to_checksum, tcp_hlen + chunk_size + 12);
|
||||
DPRINTF("+++ C+ mode TSO TCP checksum %04x\n",
|
||||
tcp_checksum);
|
||||
|
||||
p_tcp_hdr->th_sum = tcp_checksum;
|
||||
|
||||
/* restore IP header */
|
||||
memcpy(eth_payload_data, saved_ip_header, hlen);
|
||||
|
||||
/* set IP data length and recalculate IP checksum */
|
||||
ip->ip_len = cpu_to_be16(hlen + tcp_hlen + chunk_size);
|
||||
|
||||
/* increment IP id for subsequent frames */
|
||||
ip->ip_id = cpu_to_be16(tcp_send_offset/tcp_chunk_size + be16_to_cpu(ip->ip_id));
|
||||
|
||||
ip->ip_sum = 0;
|
||||
ip->ip_sum = ip_checksum(eth_payload_data, hlen);
|
||||
DPRINTF("+++ C+ mode TSO IP header len=%d "
|
||||
"checksum=%04x\n", hlen, ip->ip_sum);
|
||||
|
||||
int tso_send_size = ETH_HLEN + hlen + tcp_hlen + chunk_size;
|
||||
DPRINTF("+++ C+ mode TSO transferring packet size "
|
||||
"%d\n", tso_send_size);
|
||||
rtl8139_transfer_frame(s, saved_buffer, tso_send_size,
|
||||
0, (uint8_t *) dot1q_buffer);
|
||||
|
||||
/* add transferred count to TCP sequence number */
|
||||
p_tcp_hdr->th_seq = cpu_to_be32(chunk_size + be32_to_cpu(p_tcp_hdr->th_seq));
|
||||
++send_count;
|
||||
is_last_frame = 1;
|
||||
chunk_size = tcp_data_len - tcp_send_offset;
|
||||
}
|
||||
|
||||
/* Stop sending this frame */
|
||||
saved_size = 0;
|
||||
}
|
||||
else if (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS))
|
||||
{
|
||||
DPRINTF("+++ C+ mode need TCP or UDP checksum\n");
|
||||
|
||||
/* maximum IP header length is 60 bytes */
|
||||
uint8_t saved_ip_header[60];
|
||||
memcpy(saved_ip_header, eth_payload_data, hlen);
|
||||
|
||||
uint8_t *data_to_checksum = eth_payload_data + hlen - 12;
|
||||
// size_t data_to_checksum_len = eth_payload_len - hlen + 12;
|
||||
DPRINTF("+++ C+ mode TSO TCP seqno %08x\n",
|
||||
be32_to_cpu(p_tcp_hdr->th_seq));
|
||||
|
||||
/* add 4 TCP pseudoheader fields */
|
||||
/* copy IP source and destination fields */
|
||||
memcpy(data_to_checksum, saved_ip_header + 12, 8);
|
||||
|
||||
if ((txdw0 & CP_TX_TCPCS) && ip_protocol == IP_PROTO_TCP)
|
||||
DPRINTF("+++ C+ mode TSO calculating TCP checksum for "
|
||||
"packet with %d bytes data\n", tcp_hlen +
|
||||
chunk_size);
|
||||
|
||||
if (tcp_send_offset)
|
||||
{
|
||||
DPRINTF("+++ C+ mode calculating TCP checksum for "
|
||||
"packet with %d bytes data\n", ip_data_len);
|
||||
|
||||
ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum;
|
||||
p_tcpip_hdr->zeros = 0;
|
||||
p_tcpip_hdr->ip_proto = IP_PROTO_TCP;
|
||||
p_tcpip_hdr->ip_payload = cpu_to_be16(ip_data_len);
|
||||
|
||||
tcp_header* p_tcp_hdr = (tcp_header *) (data_to_checksum+12);
|
||||
|
||||
p_tcp_hdr->th_sum = 0;
|
||||
|
||||
int tcp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12);
|
||||
DPRINTF("+++ C+ mode TCP checksum %04x\n",
|
||||
tcp_checksum);
|
||||
|
||||
p_tcp_hdr->th_sum = tcp_checksum;
|
||||
memcpy((uint8_t*)p_tcp_hdr + tcp_hlen, (uint8_t*)p_tcp_hdr + tcp_hlen + tcp_send_offset, chunk_size);
|
||||
}
|
||||
else if ((txdw0 & CP_TX_UDPCS) && ip_protocol == IP_PROTO_UDP)
|
||||
|
||||
/* keep PUSH and FIN flags only for the last frame */
|
||||
if (!is_last_frame)
|
||||
{
|
||||
DPRINTF("+++ C+ mode calculating UDP checksum for "
|
||||
"packet with %d bytes data\n", ip_data_len);
|
||||
|
||||
ip_pseudo_header *p_udpip_hdr = (ip_pseudo_header *)data_to_checksum;
|
||||
p_udpip_hdr->zeros = 0;
|
||||
p_udpip_hdr->ip_proto = IP_PROTO_UDP;
|
||||
p_udpip_hdr->ip_payload = cpu_to_be16(ip_data_len);
|
||||
|
||||
udp_header *p_udp_hdr = (udp_header *) (data_to_checksum+12);
|
||||
|
||||
p_udp_hdr->uh_sum = 0;
|
||||
|
||||
int udp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12);
|
||||
DPRINTF("+++ C+ mode UDP checksum %04x\n",
|
||||
udp_checksum);
|
||||
|
||||
p_udp_hdr->uh_sum = udp_checksum;
|
||||
TCP_HEADER_CLEAR_FLAGS(p_tcp_hdr, TCP_FLAG_PUSH|TCP_FLAG_FIN);
|
||||
}
|
||||
|
||||
/* recalculate TCP checksum */
|
||||
ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum;
|
||||
p_tcpip_hdr->zeros = 0;
|
||||
p_tcpip_hdr->ip_proto = IP_PROTO_TCP;
|
||||
p_tcpip_hdr->ip_payload = cpu_to_be16(tcp_hlen + chunk_size);
|
||||
|
||||
p_tcp_hdr->th_sum = 0;
|
||||
|
||||
int tcp_checksum = ip_checksum(data_to_checksum, tcp_hlen + chunk_size + 12);
|
||||
DPRINTF("+++ C+ mode TSO TCP checksum %04x\n",
|
||||
tcp_checksum);
|
||||
|
||||
p_tcp_hdr->th_sum = tcp_checksum;
|
||||
|
||||
/* restore IP header */
|
||||
memcpy(eth_payload_data, saved_ip_header, hlen);
|
||||
|
||||
/* set IP data length and recalculate IP checksum */
|
||||
ip->ip_len = cpu_to_be16(hlen + tcp_hlen + chunk_size);
|
||||
|
||||
/* increment IP id for subsequent frames */
|
||||
ip->ip_id = cpu_to_be16(tcp_send_offset/tcp_chunk_size + be16_to_cpu(ip->ip_id));
|
||||
|
||||
ip->ip_sum = 0;
|
||||
ip->ip_sum = ip_checksum(eth_payload_data, hlen);
|
||||
DPRINTF("+++ C+ mode TSO IP header len=%d "
|
||||
"checksum=%04x\n", hlen, ip->ip_sum);
|
||||
|
||||
int tso_send_size = ETH_HLEN + hlen + tcp_hlen + chunk_size;
|
||||
DPRINTF("+++ C+ mode TSO transferring packet size "
|
||||
"%d\n", tso_send_size);
|
||||
rtl8139_transfer_frame(s, saved_buffer, tso_send_size,
|
||||
0, (uint8_t *) dot1q_buffer);
|
||||
|
||||
/* add transferred count to TCP sequence number */
|
||||
p_tcp_hdr->th_seq = cpu_to_be32(chunk_size + be32_to_cpu(p_tcp_hdr->th_seq));
|
||||
++send_count;
|
||||
}
|
||||
|
||||
/* Stop sending this frame */
|
||||
saved_size = 0;
|
||||
}
|
||||
else if (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS))
|
||||
{
|
||||
DPRINTF("+++ C+ mode need TCP or UDP checksum\n");
|
||||
|
||||
/* maximum IP header length is 60 bytes */
|
||||
uint8_t saved_ip_header[60];
|
||||
memcpy(saved_ip_header, eth_payload_data, hlen);
|
||||
|
||||
uint8_t *data_to_checksum = eth_payload_data + hlen - 12;
|
||||
// size_t data_to_checksum_len = eth_payload_len - hlen + 12;
|
||||
|
||||
/* add 4 TCP pseudoheader fields */
|
||||
/* copy IP source and destination fields */
|
||||
memcpy(data_to_checksum, saved_ip_header + 12, 8);
|
||||
|
||||
if ((txdw0 & CP_TX_TCPCS) && ip_protocol == IP_PROTO_TCP)
|
||||
{
|
||||
DPRINTF("+++ C+ mode calculating TCP checksum for "
|
||||
"packet with %d bytes data\n", ip_data_len);
|
||||
|
||||
ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum;
|
||||
p_tcpip_hdr->zeros = 0;
|
||||
p_tcpip_hdr->ip_proto = IP_PROTO_TCP;
|
||||
p_tcpip_hdr->ip_payload = cpu_to_be16(ip_data_len);
|
||||
|
||||
tcp_header* p_tcp_hdr = (tcp_header *) (data_to_checksum+12);
|
||||
|
||||
p_tcp_hdr->th_sum = 0;
|
||||
|
||||
int tcp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12);
|
||||
DPRINTF("+++ C+ mode TCP checksum %04x\n",
|
||||
tcp_checksum);
|
||||
|
||||
p_tcp_hdr->th_sum = tcp_checksum;
|
||||
}
|
||||
else if ((txdw0 & CP_TX_UDPCS) && ip_protocol == IP_PROTO_UDP)
|
||||
{
|
||||
DPRINTF("+++ C+ mode calculating UDP checksum for "
|
||||
"packet with %d bytes data\n", ip_data_len);
|
||||
|
||||
ip_pseudo_header *p_udpip_hdr = (ip_pseudo_header *)data_to_checksum;
|
||||
p_udpip_hdr->zeros = 0;
|
||||
p_udpip_hdr->ip_proto = IP_PROTO_UDP;
|
||||
p_udpip_hdr->ip_payload = cpu_to_be16(ip_data_len);
|
||||
|
||||
udp_header *p_udp_hdr = (udp_header *) (data_to_checksum+12);
|
||||
|
||||
p_udp_hdr->uh_sum = 0;
|
||||
|
||||
int udp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12);
|
||||
DPRINTF("+++ C+ mode UDP checksum %04x\n",
|
||||
udp_checksum);
|
||||
|
||||
p_udp_hdr->uh_sum = udp_checksum;
|
||||
}
|
||||
|
||||
/* restore IP header */
|
||||
memcpy(eth_payload_data, saved_ip_header, hlen);
|
||||
}
|
||||
}
|
||||
|
||||
skip_offload:
|
||||
/* update tally counter */
|
||||
++s->tally_counters.TxOk;
|
||||
|
||||
|
||||
@@ -228,8 +228,7 @@ static ssize_t stellaris_enet_receive(NetClientState *nc, const uint8_t *buf, si
|
||||
if ((s->rctl & SE_RCTL_RXEN) == 0)
|
||||
return -1;
|
||||
if (s->np >= 31) {
|
||||
DPRINTF("Packet dropped\n");
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
DPRINTF("Received packet len=%zu\n", size);
|
||||
@@ -260,13 +259,8 @@ static ssize_t stellaris_enet_receive(NetClientState *nc, const uint8_t *buf, si
|
||||
return size;
|
||||
}
|
||||
|
||||
static int stellaris_enet_can_receive(NetClientState *nc)
|
||||
static int stellaris_enet_can_receive(stellaris_enet_state *s)
|
||||
{
|
||||
stellaris_enet_state *s = qemu_get_nic_opaque(nc);
|
||||
|
||||
if ((s->rctl & SE_RCTL_RXEN) == 0)
|
||||
return 1;
|
||||
|
||||
return (s->np < 31);
|
||||
}
|
||||
|
||||
@@ -307,6 +301,9 @@ static uint64_t stellaris_enet_read(void *opaque, hwaddr offset,
|
||||
s->next_packet = 0;
|
||||
s->np--;
|
||||
DPRINTF("RX done np=%d\n", s->np);
|
||||
if (!s->np && stellaris_enet_can_receive(s)) {
|
||||
qemu_flush_queued_packets(qemu_get_queue(s->nic));
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
@@ -454,7 +451,6 @@ static void stellaris_enet_reset(stellaris_enet_state *s)
|
||||
static NetClientInfo net_stellaris_enet_info = {
|
||||
.type = NET_CLIENT_OPTIONS_KIND_NIC,
|
||||
.size = sizeof(NICState),
|
||||
.can_receive = stellaris_enet_can_receive,
|
||||
.receive = stellaris_enet_receive,
|
||||
};
|
||||
|
||||
|
||||
+2
-3
@@ -446,7 +446,8 @@ static void virtio_net_set_queues(VirtIONet *n)
|
||||
|
||||
static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue);
|
||||
|
||||
static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features)
|
||||
static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features,
|
||||
Error **errp)
|
||||
{
|
||||
VirtIONet *n = VIRTIO_NET(vdev);
|
||||
NetClientState *nc = qemu_get_queue(n->nic);
|
||||
@@ -1777,8 +1778,6 @@ static void virtio_net_instance_init(Object *obj)
|
||||
}
|
||||
|
||||
static Property virtio_net_properties[] = {
|
||||
DEFINE_PROP_BIT("any_layout", VirtIONet, host_features,
|
||||
VIRTIO_F_ANY_LAYOUT, true),
|
||||
DEFINE_PROP_BIT("csum", VirtIONet, host_features, VIRTIO_NET_F_CSUM, true),
|
||||
DEFINE_PROP_BIT("guest_csum", VirtIONet, host_features,
|
||||
VIRTIO_NET_F_GUEST_CSUM, true),
|
||||
|
||||
+1
-24
@@ -234,27 +234,6 @@ static void net_rx_response(struct XenNetDev *netdev,
|
||||
|
||||
#define NET_IP_ALIGN 2
|
||||
|
||||
static int net_rx_ok(NetClientState *nc)
|
||||
{
|
||||
struct XenNetDev *netdev = qemu_get_nic_opaque(nc);
|
||||
RING_IDX rc, rp;
|
||||
|
||||
if (netdev->xendev.be_state != XenbusStateConnected) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = netdev->rx_ring.req_cons;
|
||||
rp = netdev->rx_ring.sring->req_prod;
|
||||
xen_rmb();
|
||||
|
||||
if (rc == rp || RING_REQUEST_CONS_OVERFLOW(&netdev->rx_ring, rc)) {
|
||||
xen_be_printf(&netdev->xendev, 2, "%s: no rx buffers (%d/%d)\n",
|
||||
__FUNCTION__, rc, rp);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static ssize_t net_rx_packet(NetClientState *nc, const uint8_t *buf, size_t size)
|
||||
{
|
||||
struct XenNetDev *netdev = qemu_get_nic_opaque(nc);
|
||||
@@ -271,8 +250,7 @@ static ssize_t net_rx_packet(NetClientState *nc, const uint8_t *buf, size_t size
|
||||
xen_rmb(); /* Ensure we see queued requests up to 'rp'. */
|
||||
|
||||
if (rc == rp || RING_REQUEST_CONS_OVERFLOW(&netdev->rx_ring, rc)) {
|
||||
xen_be_printf(&netdev->xendev, 2, "no buffer, drop packet\n");
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
if (size > XC_PAGE_SIZE - NET_IP_ALIGN) {
|
||||
xen_be_printf(&netdev->xendev, 0, "packet too big (%lu > %ld)",
|
||||
@@ -304,7 +282,6 @@ static ssize_t net_rx_packet(NetClientState *nc, const uint8_t *buf, size_t size
|
||||
static NetClientInfo net_xen_info = {
|
||||
.type = NET_CLIENT_OPTIONS_KIND_NIC,
|
||||
.size = sizeof(NICState),
|
||||
.can_receive = net_rx_ok,
|
||||
.receive = net_rx_packet,
|
||||
};
|
||||
|
||||
|
||||
+4
-4
@@ -312,10 +312,8 @@ static const MemoryRegionOps enet_mem_ops = {
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static int eth_can_rx(NetClientState *nc)
|
||||
static int eth_can_rx(XgmacState *s)
|
||||
{
|
||||
XgmacState *s = qemu_get_nic_opaque(nc);
|
||||
|
||||
/* RX enabled? */
|
||||
return s->regs[DMA_CONTROL] & DMA_CONTROL_SR;
|
||||
}
|
||||
@@ -329,6 +327,9 @@ static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size)
|
||||
struct desc bd;
|
||||
ssize_t ret;
|
||||
|
||||
if (!eth_can_rx(s)) {
|
||||
return -1;
|
||||
}
|
||||
unicast = ~buf[0] & 0x1;
|
||||
broadcast = memcmp(buf, sa_bcast, 6) == 0;
|
||||
multicast = !unicast && !broadcast;
|
||||
@@ -371,7 +372,6 @@ out:
|
||||
static NetClientInfo net_xgmac_enet_info = {
|
||||
.type = NET_CLIENT_OPTIONS_KIND_NIC,
|
||||
.size = sizeof(NICState),
|
||||
.can_receive = eth_can_rx,
|
||||
.receive = eth_rx,
|
||||
};
|
||||
|
||||
|
||||
+13
-4
@@ -401,6 +401,9 @@ struct XilinxAXIEnet {
|
||||
|
||||
uint8_t rxapp[CONTROL_PAYLOAD_SIZE];
|
||||
uint32_t rxappsize;
|
||||
|
||||
/* Whether axienet_eth_rx_notify should flush incoming queue. */
|
||||
bool need_flush;
|
||||
};
|
||||
|
||||
static void axienet_rx_reset(XilinxAXIEnet *s)
|
||||
@@ -658,10 +661,8 @@ static const MemoryRegionOps enet_ops = {
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static int eth_can_rx(NetClientState *nc)
|
||||
static int eth_can_rx(XilinxAXIEnet *s)
|
||||
{
|
||||
XilinxAXIEnet *s = qemu_get_nic_opaque(nc);
|
||||
|
||||
/* RX enabled? */
|
||||
return !s->rxsize && !axienet_rx_resetting(s) && axienet_rx_enabled(s);
|
||||
}
|
||||
@@ -701,6 +702,10 @@ static void axienet_eth_rx_notify(void *opaque)
|
||||
s->rxpos += ret;
|
||||
if (!s->rxsize) {
|
||||
s->regs[R_IS] |= IS_RX_COMPLETE;
|
||||
if (s->need_flush) {
|
||||
s->need_flush = false;
|
||||
qemu_flush_queued_packets(qemu_get_queue(s->nic));
|
||||
}
|
||||
}
|
||||
}
|
||||
enet_update_irq(s);
|
||||
@@ -721,6 +726,11 @@ static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size)
|
||||
|
||||
DENET(qemu_log("%s: %zd bytes\n", __func__, size));
|
||||
|
||||
if (!eth_can_rx(s)) {
|
||||
s->need_flush = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
unicast = ~buf[0] & 0x1;
|
||||
broadcast = memcmp(buf, sa_bcast, 6) == 0;
|
||||
multicast = !unicast && !broadcast;
|
||||
@@ -925,7 +935,6 @@ xilinx_axienet_data_stream_push(StreamSlave *obj, uint8_t *buf, size_t size)
|
||||
static NetClientInfo net_xilinx_enet_info = {
|
||||
.type = NET_CLIENT_OPTIONS_KIND_NIC,
|
||||
.size = sizeof(NICState),
|
||||
.can_receive = eth_can_rx,
|
||||
.receive = eth_rx,
|
||||
};
|
||||
|
||||
|
||||
@@ -2202,8 +2202,15 @@ static uint64_t megasas_queue_read(void *opaque, hwaddr addr,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void megasas_queue_write(void *opaque, hwaddr addr,
|
||||
uint64_t val, unsigned size)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps megasas_queue_ops = {
|
||||
.read = megasas_queue_read,
|
||||
.write = megasas_queue_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.impl = {
|
||||
.min_access_size = 8,
|
||||
|
||||
+6
-1
@@ -1239,10 +1239,15 @@ int scsi_cdb_length(uint8_t *buf) {
|
||||
int scsi_req_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf)
|
||||
{
|
||||
int rc;
|
||||
int len;
|
||||
|
||||
cmd->lba = -1;
|
||||
cmd->len = scsi_cdb_length(buf);
|
||||
len = scsi_cdb_length(buf);
|
||||
if (len < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
cmd->len = len;
|
||||
switch (dev->type) {
|
||||
case TYPE_TAPE:
|
||||
rc = scsi_req_stream_xfer(cmd, dev, buf);
|
||||
|
||||
+15
-1
@@ -765,6 +765,9 @@ static inline bool media_is_dvd(SCSIDiskState *s)
|
||||
if (!blk_is_inserted(s->qdev.conf.blk)) {
|
||||
return false;
|
||||
}
|
||||
if (s->tray_open) {
|
||||
return false;
|
||||
}
|
||||
blk_get_geometry(s->qdev.conf.blk, &nb_sectors);
|
||||
return nb_sectors > CD_MAX_SECTORS;
|
||||
}
|
||||
@@ -778,6 +781,9 @@ static inline bool media_is_cd(SCSIDiskState *s)
|
||||
if (!blk_is_inserted(s->qdev.conf.blk)) {
|
||||
return false;
|
||||
}
|
||||
if (s->tray_open) {
|
||||
return false;
|
||||
}
|
||||
blk_get_geometry(s->qdev.conf.blk, &nb_sectors);
|
||||
return nb_sectors <= CD_MAX_SECTORS;
|
||||
}
|
||||
@@ -975,7 +981,15 @@ static int scsi_get_configuration(SCSIDiskState *s, uint8_t *outbuf)
|
||||
if (s->qdev.type != TYPE_ROM) {
|
||||
return -1;
|
||||
}
|
||||
current = media_is_dvd(s) ? MMC_PROFILE_DVD_ROM : MMC_PROFILE_CD_ROM;
|
||||
|
||||
if (media_is_dvd(s)) {
|
||||
current = MMC_PROFILE_DVD_ROM;
|
||||
} else if (media_is_cd(s)) {
|
||||
current = MMC_PROFILE_CD_ROM;
|
||||
} else {
|
||||
current = MMC_PROFILE_NONE;
|
||||
}
|
||||
|
||||
memset(outbuf, 0, 40);
|
||||
stl_be_p(&outbuf[0], 36); /* Bytes after the data length field */
|
||||
stw_be_p(&outbuf[6], current);
|
||||
|
||||
@@ -153,7 +153,8 @@ static void vhost_scsi_stop(VHostSCSI *s)
|
||||
}
|
||||
|
||||
static uint64_t vhost_scsi_get_features(VirtIODevice *vdev,
|
||||
uint64_t features)
|
||||
uint64_t features,
|
||||
Error **errp)
|
||||
{
|
||||
VHostSCSI *s = VHOST_SCSI(vdev);
|
||||
|
||||
|
||||
@@ -629,7 +629,8 @@ static void virtio_scsi_set_config(VirtIODevice *vdev,
|
||||
}
|
||||
|
||||
static uint64_t virtio_scsi_get_features(VirtIODevice *vdev,
|
||||
uint64_t requested_features)
|
||||
uint64_t requested_features,
|
||||
Error **errp)
|
||||
{
|
||||
VirtIOSCSI *s = VIRTIO_SCSI(vdev);
|
||||
|
||||
@@ -953,8 +954,6 @@ static Property virtio_scsi_properties[] = {
|
||||
0xFFFF),
|
||||
DEFINE_PROP_UINT32("cmd_per_lun", VirtIOSCSI, parent_obj.conf.cmd_per_lun,
|
||||
128),
|
||||
DEFINE_PROP_BIT("any_layout", VirtIOSCSI, host_features,
|
||||
VIRTIO_F_ANY_LAYOUT, true),
|
||||
DEFINE_PROP_BIT("hotplug", VirtIOSCSI, host_features,
|
||||
VIRTIO_SCSI_F_HOTPLUG, true),
|
||||
DEFINE_PROP_BIT("param_change", VirtIOSCSI, host_features,
|
||||
|
||||
+4
-16
@@ -1268,6 +1268,10 @@ static ssize_t usbnet_receive(NetClientState *nc, const uint8_t *buf, size_t siz
|
||||
uint8_t *in_buf = s->in_buf;
|
||||
size_t total_size = size;
|
||||
|
||||
if (!s->dev.config) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (is_rndis(s)) {
|
||||
if (s->rndis_state != RNDIS_DATA_INITIALIZED) {
|
||||
return -1;
|
||||
@@ -1309,21 +1313,6 @@ static ssize_t usbnet_receive(NetClientState *nc, const uint8_t *buf, size_t siz
|
||||
return size;
|
||||
}
|
||||
|
||||
static int usbnet_can_receive(NetClientState *nc)
|
||||
{
|
||||
USBNetState *s = qemu_get_nic_opaque(nc);
|
||||
|
||||
if (!s->dev.config) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (is_rndis(s) && s->rndis_state != RNDIS_DATA_INITIALIZED) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return !s->in_len;
|
||||
}
|
||||
|
||||
static void usbnet_cleanup(NetClientState *nc)
|
||||
{
|
||||
USBNetState *s = qemu_get_nic_opaque(nc);
|
||||
@@ -1343,7 +1332,6 @@ static void usb_net_handle_destroy(USBDevice *dev)
|
||||
static NetClientInfo net_usbnet_info = {
|
||||
.type = NET_CLIENT_OPTIONS_KIND_NIC,
|
||||
.size = sizeof(NICState),
|
||||
.can_receive = usbnet_can_receive,
|
||||
.receive = usbnet_receive,
|
||||
.cleanup = usbnet_cleanup,
|
||||
};
|
||||
|
||||
+5
-8
@@ -1517,7 +1517,7 @@ static uint64_t vfio_rtl8168_window_quirk_read(void *opaque,
|
||||
memory_region_name(&quirk->mem),
|
||||
vdev->vbasedev.name);
|
||||
|
||||
return quirk->data.address_match ^ 0x10000000U;
|
||||
return quirk->data.address_match ^ 0x80000000U;
|
||||
}
|
||||
break;
|
||||
case 0: /* data */
|
||||
@@ -1558,7 +1558,7 @@ static void vfio_rtl8168_window_quirk_write(void *opaque, hwaddr addr,
|
||||
switch (addr) {
|
||||
case 4: /* address */
|
||||
if ((data & 0x7fff0000) == 0x10000) {
|
||||
if (data & 0x10000000U &&
|
||||
if (data & 0x80000000U &&
|
||||
vdev->pdev.cap_present & QEMU_PCI_CAP_MSIX) {
|
||||
|
||||
trace_vfio_rtl8168_window_quirk_write_table(
|
||||
@@ -1566,11 +1566,9 @@ static void vfio_rtl8168_window_quirk_write(void *opaque, hwaddr addr,
|
||||
vdev->vbasedev.name);
|
||||
|
||||
memory_region_dispatch_write(&vdev->pdev.msix_table_mmio,
|
||||
(hwaddr)(quirk->data.address_match
|
||||
& 0xfff),
|
||||
data,
|
||||
size,
|
||||
MEMTXATTRS_UNSPECIFIED);
|
||||
(hwaddr)(data & 0xfff),
|
||||
(uint64_t)quirk->data.address_mask,
|
||||
size, MEMTXATTRS_UNSPECIFIED);
|
||||
}
|
||||
|
||||
quirk->data.flags = 1;
|
||||
@@ -3751,7 +3749,6 @@ static Property vfio_pci_dev_properties[] = {
|
||||
VFIO_FEATURE_ENABLE_VGA_BIT, false),
|
||||
DEFINE_PROP_BIT("x-req", VFIOPCIDevice, features,
|
||||
VFIO_FEATURE_ENABLE_REQ_BIT, true),
|
||||
DEFINE_PROP_INT32("bootindex", VFIOPCIDevice, bootindex, -1),
|
||||
DEFINE_PROP_BOOL("x-mmap", VFIOPCIDevice, vbasedev.allow_mmap, true),
|
||||
/*
|
||||
* TODO - support passed fds... is this necessary?
|
||||
|
||||
@@ -310,7 +310,8 @@ static void virtio_balloon_set_config(VirtIODevice *vdev,
|
||||
trace_virtio_balloon_set_config(dev->actual, oldactual);
|
||||
}
|
||||
|
||||
static uint64_t virtio_balloon_get_features(VirtIODevice *vdev, uint64_t f)
|
||||
static uint64_t virtio_balloon_get_features(VirtIODevice *vdev, uint64_t f,
|
||||
Error **errp)
|
||||
{
|
||||
VirtIOBalloon *dev = VIRTIO_BALLOON(vdev);
|
||||
f |= dev->host_features;
|
||||
|
||||
@@ -54,7 +54,8 @@ void virtio_bus_device_plugged(VirtIODevice *vdev, Error **errp)
|
||||
|
||||
/* Get the features of the plugged device. */
|
||||
assert(vdc->get_features != NULL);
|
||||
vdev->host_features = vdc->get_features(vdev, vdev->host_features);
|
||||
vdev->host_features = vdc->get_features(vdev, vdev->host_features,
|
||||
errp);
|
||||
}
|
||||
|
||||
/* Reset the virtio_bus */
|
||||
|
||||
+17
-1
@@ -1095,7 +1095,8 @@ static uint64_t virtio_pci_common_read(void *opaque, hwaddr addr,
|
||||
break;
|
||||
case VIRTIO_PCI_COMMON_DF:
|
||||
if (proxy->dfselect <= 1) {
|
||||
val = vdev->host_features >> (32 * proxy->dfselect);
|
||||
val = (vdev->host_features & ~VIRTIO_LEGACY_FEATURES) >>
|
||||
(32 * proxy->dfselect);
|
||||
}
|
||||
break;
|
||||
case VIRTIO_PCI_COMMON_GFSELECT:
|
||||
@@ -1413,6 +1414,13 @@ static void virtio_pci_modern_region_map(VirtIOPCIProxy *proxy,
|
||||
virtio_pci_add_mem_cap(proxy, cap);
|
||||
}
|
||||
|
||||
static void virtio_pci_modern_region_unmap(VirtIOPCIProxy *proxy,
|
||||
VirtIOPCIRegion *region)
|
||||
{
|
||||
memory_region_del_subregion(&proxy->modern_bar,
|
||||
®ion->mr);
|
||||
}
|
||||
|
||||
/* This is called by virtio-bus just after the device is plugged. */
|
||||
static void virtio_pci_device_plugged(DeviceState *d, Error **errp)
|
||||
{
|
||||
@@ -1519,8 +1527,16 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp)
|
||||
static void virtio_pci_device_unplugged(DeviceState *d)
|
||||
{
|
||||
VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
|
||||
bool modern = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_MODERN);
|
||||
|
||||
virtio_pci_stop_ioeventfd(proxy);
|
||||
|
||||
if (modern) {
|
||||
virtio_pci_modern_region_unmap(proxy, &proxy->common);
|
||||
virtio_pci_modern_region_unmap(proxy, &proxy->isr);
|
||||
virtio_pci_modern_region_unmap(proxy, &proxy->device);
|
||||
virtio_pci_modern_region_unmap(proxy, &proxy->notify);
|
||||
}
|
||||
}
|
||||
|
||||
static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp)
|
||||
|
||||
@@ -104,7 +104,7 @@ static void handle_input(VirtIODevice *vdev, VirtQueue *vq)
|
||||
virtio_rng_process(vrng);
|
||||
}
|
||||
|
||||
static uint64_t get_features(VirtIODevice *vdev, uint64_t f)
|
||||
static uint64_t get_features(VirtIODevice *vdev, uint64_t f, Error **errp)
|
||||
{
|
||||
return f;
|
||||
}
|
||||
|
||||
@@ -1049,6 +1049,61 @@ static bool virtio_64bit_features_needed(void *opaque)
|
||||
return (vdev->host_features >> 32) != 0;
|
||||
}
|
||||
|
||||
static bool virtio_virtqueue_needed(void *opaque)
|
||||
{
|
||||
VirtIODevice *vdev = opaque;
|
||||
|
||||
return virtio_host_has_feature(vdev, VIRTIO_F_VERSION_1);
|
||||
}
|
||||
|
||||
static void put_virtqueue_state(QEMUFile *f, void *pv, size_t size)
|
||||
{
|
||||
VirtIODevice *vdev = pv;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
|
||||
qemu_put_be64(f, vdev->vq[i].vring.avail);
|
||||
qemu_put_be64(f, vdev->vq[i].vring.used);
|
||||
}
|
||||
}
|
||||
|
||||
static int get_virtqueue_state(QEMUFile *f, void *pv, size_t size)
|
||||
{
|
||||
VirtIODevice *vdev = pv;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
|
||||
vdev->vq[i].vring.avail = qemu_get_be64(f);
|
||||
vdev->vq[i].vring.used = qemu_get_be64(f);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static VMStateInfo vmstate_info_virtqueue = {
|
||||
.name = "virtqueue_state",
|
||||
.get = get_virtqueue_state,
|
||||
.put = put_virtqueue_state,
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_virtio_virtqueues = {
|
||||
.name = "virtio/virtqueues",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.needed = &virtio_virtqueue_needed,
|
||||
.fields = (VMStateField[]) {
|
||||
{
|
||||
.name = "virtqueues",
|
||||
.version_id = 0,
|
||||
.field_exists = NULL,
|
||||
.size = 0,
|
||||
.info = &vmstate_info_virtqueue,
|
||||
.flags = VMS_SINGLE,
|
||||
.offset = 0,
|
||||
},
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_virtio_device_endian = {
|
||||
.name = "virtio/device_endian",
|
||||
.version_id = 1,
|
||||
@@ -1082,6 +1137,7 @@ static const VMStateDescription vmstate_virtio = {
|
||||
.subsections = (const VMStateDescription*[]) {
|
||||
&vmstate_virtio_device_endian,
|
||||
&vmstate_virtio_64bit_features,
|
||||
&vmstate_virtio_virtqueues,
|
||||
NULL
|
||||
}
|
||||
};
|
||||
|
||||
@@ -114,6 +114,9 @@ struct AioContext {
|
||||
bool notified;
|
||||
EventNotifier notifier;
|
||||
|
||||
/* Scheduling this BH forces the event loop it iterate */
|
||||
QEMUBH *notify_dummy_bh;
|
||||
|
||||
/* Thread pool for performing work and receiving completion callbacks */
|
||||
struct ThreadPool *thread_pool;
|
||||
|
||||
|
||||
@@ -180,6 +180,7 @@ struct MemoryRegion {
|
||||
bool warning_printed; /* For reservations */
|
||||
bool flush_coalesced_mmio;
|
||||
bool global_locking;
|
||||
uint8_t vga_logging_count;
|
||||
MemoryRegion *alias;
|
||||
hwaddr alias_offset;
|
||||
int32_t priority;
|
||||
|
||||
+21
-1
@@ -2,7 +2,27 @@
|
||||
#define HW_COMPAT_H
|
||||
|
||||
#define HW_COMPAT_2_3 \
|
||||
/* empty */
|
||||
{\
|
||||
.driver = "virtio-blk-pci",\
|
||||
.property = "any_layout",\
|
||||
.value = "off",\
|
||||
},{\
|
||||
.driver = "virtio-balloon-pci",\
|
||||
.property = "any_layout",\
|
||||
.value = "off",\
|
||||
},{\
|
||||
.driver = "virtio-serial-pci",\
|
||||
.property = "any_layout",\
|
||||
.value = "off",\
|
||||
},{\
|
||||
.driver = "virtio-9p-pci",\
|
||||
.property = "any_layout",\
|
||||
.value = "off",\
|
||||
},{\
|
||||
.driver = "virtio-rng-pci",\
|
||||
.property = "any_layout",\
|
||||
.value = "off",\
|
||||
},
|
||||
|
||||
#define HW_COMPAT_2_2 \
|
||||
/* empty */
|
||||
|
||||
@@ -350,6 +350,10 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
|
||||
.driver = "SandyBridge" "-" TYPE_X86_CPU,\
|
||||
.property = "xlevel",\
|
||||
.value = stringify(0x8000000a),\
|
||||
},{\
|
||||
.driver = "IvyBridge" "-" TYPE_X86_CPU,\
|
||||
.property = "xlevel",\
|
||||
.value = stringify(0x8000000a),\
|
||||
},{\
|
||||
.driver = "Haswell" "-" TYPE_X86_CPU,\
|
||||
.property = "xlevel",\
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include "net/net.h"
|
||||
#include "qemu/fifo8.h"
|
||||
#include "hw/net/mii.h"
|
||||
|
||||
#define TYPE_AW_EMAC "allwinner-emac"
|
||||
#define AW_EMAC(obj) OBJECT_CHECK(AwEmacState, (obj), TYPE_AW_EMAC)
|
||||
@@ -118,45 +119,6 @@
|
||||
#define EMAC_RX_IO_DATA_STATUS_OK (1 << 7)
|
||||
#define EMAC_UNDOCUMENTED_MAGIC 0x0143414d /* header for RX frames */
|
||||
|
||||
/* PHY registers */
|
||||
#define MII_BMCR 0
|
||||
#define MII_BMSR 1
|
||||
#define MII_PHYID1 2
|
||||
#define MII_PHYID2 3
|
||||
#define MII_ANAR 4
|
||||
#define MII_ANLPAR 5
|
||||
#define MII_ANER 6
|
||||
#define MII_NSR 16
|
||||
#define MII_LBREMR 17
|
||||
#define MII_REC 18
|
||||
#define MII_SNRDR 19
|
||||
#define MII_TEST 25
|
||||
|
||||
/* PHY registers fields */
|
||||
#define MII_BMCR_RESET (1 << 15)
|
||||
#define MII_BMCR_LOOPBACK (1 << 14)
|
||||
#define MII_BMCR_SPEED (1 << 13)
|
||||
#define MII_BMCR_AUTOEN (1 << 12)
|
||||
#define MII_BMCR_FD (1 << 8)
|
||||
|
||||
#define MII_BMSR_100TX_FD (1 << 14)
|
||||
#define MII_BMSR_100TX_HD (1 << 13)
|
||||
#define MII_BMSR_10T_FD (1 << 12)
|
||||
#define MII_BMSR_10T_HD (1 << 11)
|
||||
#define MII_BMSR_MFPS (1 << 6)
|
||||
#define MII_BMSR_AN_COMP (1 << 5)
|
||||
#define MII_BMSR_AUTONEG (1 << 3)
|
||||
#define MII_BMSR_LINK_ST (1 << 2)
|
||||
|
||||
#define MII_ANAR_TXFD (1 << 8)
|
||||
#define MII_ANAR_TX (1 << 7)
|
||||
#define MII_ANAR_10FD (1 << 6)
|
||||
#define MII_ANAR_10 (1 << 5)
|
||||
#define MII_ANAR_CSMACD (1 << 0)
|
||||
|
||||
#define RTL8201CP_PHYID1 0x0000
|
||||
#define RTL8201CP_PHYID2 0x8201
|
||||
|
||||
/* INT CTL and INT STA registers fields */
|
||||
#define EMAC_INT_TX_CHAN(x) (1 << (x))
|
||||
#define EMAC_INT_RX (1 << 8)
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Common network MII address and register definitions.
|
||||
*
|
||||
* Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
|
||||
*
|
||||
* Allwinner EMAC register definitions from Linux kernel are:
|
||||
* Copyright 2012 Stefan Roese <sr@denx.de>
|
||||
* Copyright 2013 Maxime Ripard <maxime.ripard@free-electrons.com>
|
||||
* Copyright 1997 Sten Wang
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#ifndef MII_H
|
||||
#define MII_H
|
||||
|
||||
/* PHY registers */
|
||||
#define MII_BMCR 0
|
||||
#define MII_BMSR 1
|
||||
#define MII_PHYID1 2
|
||||
#define MII_PHYID2 3
|
||||
#define MII_ANAR 4
|
||||
#define MII_ANLPAR 5
|
||||
#define MII_ANER 6
|
||||
#define MII_NSR 16
|
||||
#define MII_LBREMR 17
|
||||
#define MII_REC 18
|
||||
#define MII_SNRDR 19
|
||||
#define MII_TEST 25
|
||||
|
||||
/* PHY registers fields */
|
||||
#define MII_BMCR_RESET (1 << 15)
|
||||
#define MII_BMCR_LOOPBACK (1 << 14)
|
||||
#define MII_BMCR_SPEED (1 << 13)
|
||||
#define MII_BMCR_AUTOEN (1 << 12)
|
||||
#define MII_BMCR_FD (1 << 8)
|
||||
|
||||
#define MII_BMSR_100TX_FD (1 << 14)
|
||||
#define MII_BMSR_100TX_HD (1 << 13)
|
||||
#define MII_BMSR_10T_FD (1 << 12)
|
||||
#define MII_BMSR_10T_HD (1 << 11)
|
||||
#define MII_BMSR_MFPS (1 << 6)
|
||||
#define MII_BMSR_AN_COMP (1 << 5)
|
||||
#define MII_BMSR_AUTONEG (1 << 3)
|
||||
#define MII_BMSR_LINK_ST (1 << 2)
|
||||
|
||||
#define MII_ANAR_TXFD (1 << 8)
|
||||
#define MII_ANAR_TX (1 << 7)
|
||||
#define MII_ANAR_10FD (1 << 6)
|
||||
#define MII_ANAR_10 (1 << 5)
|
||||
#define MII_ANAR_CSMACD (1 << 0)
|
||||
|
||||
#define MII_ANLPAR_ACK (1 << 14)
|
||||
#define MII_ANLPAR_TXFD (1 << 8)
|
||||
#define MII_ANLPAR_TX (1 << 7)
|
||||
#define MII_ANLPAR_10FD (1 << 6)
|
||||
#define MII_ANLPAR_10 (1 << 5)
|
||||
#define MII_ANLPAR_CSMACD (1 << 0)
|
||||
|
||||
/* List of vendor identifiers */
|
||||
/* RealTek 8201 */
|
||||
#define RTL8201CP_PHYID1 0x0000
|
||||
#define RTL8201CP_PHYID2 0x8201
|
||||
|
||||
/* National Semiconductor DP83848 */
|
||||
#define DP83848_PHYID1 0x2000
|
||||
#define DP83848_PHYID2 0x5c90
|
||||
|
||||
#endif /* MII_H */
|
||||
@@ -37,7 +37,7 @@
|
||||
#define R_CONTROL_TIMER_ENABLE (1 << 0)
|
||||
#define R_CONTROL_COMP_ENABLE (1 << 1)
|
||||
#define R_CONTROL_IRQ_ENABLE (1 << 2)
|
||||
#define R_CONTROL_AUTO_INCREMENT (1 << 2)
|
||||
#define R_CONTROL_AUTO_INCREMENT (1 << 3)
|
||||
#define R_CONTROL_PRESCALER_SHIFT 8
|
||||
#define R_CONTROL_PRESCALER_LEN 8
|
||||
#define R_CONTROL_PRESCALER_MASK (((1 << R_CONTROL_PRESCALER_LEN) - 1) << \
|
||||
|
||||
@@ -25,6 +25,10 @@
|
||||
/* A guest should never accept this. It implies negotiation is broken. */
|
||||
#define VIRTIO_F_BAD_FEATURE 30
|
||||
|
||||
#define VIRTIO_LEGACY_FEATURES ((0x1ULL << VIRTIO_F_BAD_FEATURE) | \
|
||||
(0x1ULL << VIRTIO_F_NOTIFY_ON_EMPTY) | \
|
||||
(0x1ULL << VIRTIO_F_ANY_LAYOUT))
|
||||
|
||||
struct VirtQueue;
|
||||
|
||||
static inline hwaddr vring_align(hwaddr addr,
|
||||
@@ -97,7 +101,9 @@ typedef struct VirtioDeviceClass {
|
||||
/* This is what a VirtioDevice must implement */
|
||||
DeviceRealize realize;
|
||||
DeviceUnrealize unrealize;
|
||||
uint64_t (*get_features)(VirtIODevice *vdev, uint64_t requested_features);
|
||||
uint64_t (*get_features)(VirtIODevice *vdev,
|
||||
uint64_t requested_features,
|
||||
Error **errp);
|
||||
uint64_t (*bad_features)(VirtIODevice *vdev);
|
||||
void (*set_features)(VirtIODevice *vdev, uint64_t val);
|
||||
int (*validate_features)(VirtIODevice *vdev);
|
||||
@@ -214,7 +220,9 @@ typedef struct VirtIORNGConf VirtIORNGConf;
|
||||
DEFINE_PROP_BIT64("event_idx", _state, _field, \
|
||||
VIRTIO_RING_F_EVENT_IDX, true), \
|
||||
DEFINE_PROP_BIT64("notify_on_empty", _state, _field, \
|
||||
VIRTIO_F_NOTIFY_ON_EMPTY, true)
|
||||
VIRTIO_F_NOTIFY_ON_EMPTY, true), \
|
||||
DEFINE_PROP_BIT64("any_layout", _state, _field, \
|
||||
VIRTIO_F_ANY_LAYOUT, true)
|
||||
|
||||
hwaddr virtio_queue_get_desc_addr(VirtIODevice *vdev, int n);
|
||||
hwaddr virtio_queue_get_avail_addr(VirtIODevice *vdev, int n);
|
||||
@@ -264,6 +272,12 @@ static inline bool virtio_has_feature(VirtIODevice *vdev, unsigned int fbit)
|
||||
return __virtio_has_feature(vdev->guest_features, fbit);
|
||||
}
|
||||
|
||||
static inline bool virtio_host_has_feature(VirtIODevice *vdev,
|
||||
unsigned int fbit)
|
||||
{
|
||||
return __virtio_has_feature(vdev->host_features, fbit);
|
||||
}
|
||||
|
||||
static inline bool virtio_is_big_endian(VirtIODevice *vdev)
|
||||
{
|
||||
if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) {
|
||||
|
||||
@@ -203,4 +203,5 @@ void register_global_state(void);
|
||||
void global_state_set_optional(void);
|
||||
void savevm_skip_configuration(void);
|
||||
int global_state_store(void);
|
||||
void global_state_store_running(void);
|
||||
#endif
|
||||
@@ -75,9 +75,6 @@ int register_savevm_live(DeviceState *dev,
|
||||
void *opaque);
|
||||
|
||||
void unregister_savevm(DeviceState *dev, const char *idstr, void *opaque);
|
||||
void register_device_unmigratable(DeviceState *dev, const char *idstr,
|
||||
void *opaque);
|
||||
|
||||
|
||||
typedef struct VMStateInfo VMStateInfo;
|
||||
typedef struct VMStateDescription VMStateDescription;
|
||||
|
||||
+113
-1
@@ -148,13 +148,125 @@ static inline bool is_help_option(const char *s)
|
||||
return !strcmp(s, "?") || !strcmp(s, "help");
|
||||
}
|
||||
|
||||
/* cutils.c */
|
||||
/* util/cutils.c */
|
||||
/**
|
||||
* pstrcpy:
|
||||
* @buf: buffer to copy string into
|
||||
* @buf_size: size of @buf in bytes
|
||||
* @str: string to copy
|
||||
*
|
||||
* Copy @str into @buf, including the trailing NUL, but do not
|
||||
* write more than @buf_size bytes. The resulting buffer is
|
||||
* always NUL terminated (even if the source string was too long).
|
||||
* If @buf_size is zero or negative then no bytes are copied.
|
||||
*
|
||||
* This function is similar to strncpy(), but avoids two of that
|
||||
* function's problems:
|
||||
* * if @str fits in the buffer, pstrcpy() does not zero-fill the
|
||||
* remaining space at the end of @buf
|
||||
* * if @str is too long, pstrcpy() will copy the first @buf_size-1
|
||||
* bytes and then add a NUL
|
||||
*/
|
||||
void pstrcpy(char *buf, int buf_size, const char *str);
|
||||
/**
|
||||
* strpadcpy:
|
||||
* @buf: buffer to copy string into
|
||||
* @buf_size: size of @buf in bytes
|
||||
* @str: string to copy
|
||||
* @pad: character to pad the remainder of @buf with
|
||||
*
|
||||
* Copy @str into @buf (but *not* its trailing NUL!), and then pad the
|
||||
* rest of the buffer with the @pad character. If @str is too large
|
||||
* for the buffer then it is truncated, so that @buf contains the
|
||||
* first @buf_size characters of @str, with no terminator.
|
||||
*/
|
||||
void strpadcpy(char *buf, int buf_size, const char *str, char pad);
|
||||
/**
|
||||
* pstrcat:
|
||||
* @buf: buffer containing existing string
|
||||
* @buf_size: size of @buf in bytes
|
||||
* @s: string to concatenate to @buf
|
||||
*
|
||||
* Append a copy of @s to the string already in @buf, but do not
|
||||
* allow the buffer to overflow. If the existing contents of @buf
|
||||
* plus @str would total more than @buf_size bytes, then write
|
||||
* as much of @str as will fit followed by a NUL terminator.
|
||||
*
|
||||
* @buf must already contain a NUL-terminated string, or the
|
||||
* behaviour is undefined.
|
||||
*
|
||||
* Returns: @buf.
|
||||
*/
|
||||
char *pstrcat(char *buf, int buf_size, const char *s);
|
||||
/**
|
||||
* strstart:
|
||||
* @str: string to test
|
||||
* @val: prefix string to look for
|
||||
* @ptr: NULL, or pointer to be written to indicate start of
|
||||
* the remainder of the string
|
||||
*
|
||||
* Test whether @str starts with the prefix @val.
|
||||
* If it does (including the degenerate case where @str and @val
|
||||
* are equal) then return true. If @ptr is not NULL then a
|
||||
* pointer to the first character following the prefix is written
|
||||
* to it. If @val is not a prefix of @str then return false (and
|
||||
* @ptr is not written to).
|
||||
*
|
||||
* Returns: true if @str starts with prefix @val, false otherwise.
|
||||
*/
|
||||
int strstart(const char *str, const char *val, const char **ptr);
|
||||
/**
|
||||
* stristart:
|
||||
* @str: string to test
|
||||
* @val: prefix string to look for
|
||||
* @ptr: NULL, or pointer to be written to indicate start of
|
||||
* the remainder of the string
|
||||
*
|
||||
* Test whether @str starts with the case-insensitive prefix @val.
|
||||
* This function behaves identically to strstart(), except that the
|
||||
* comparison is made after calling qemu_toupper() on each pair of
|
||||
* characters.
|
||||
*
|
||||
* Returns: true if @str starts with case-insensitive prefix @val,
|
||||
* false otherwise.
|
||||
*/
|
||||
int stristart(const char *str, const char *val, const char **ptr);
|
||||
/**
|
||||
* qemu_strnlen:
|
||||
* @s: string
|
||||
* @max_len: maximum number of bytes in @s to scan
|
||||
*
|
||||
* Return the length of the string @s, like strlen(), but do not
|
||||
* examine more than @max_len bytes of the memory pointed to by @s.
|
||||
* If no NUL terminator is found within @max_len bytes, then return
|
||||
* @max_len instead.
|
||||
*
|
||||
* This function has the same behaviour as the POSIX strnlen()
|
||||
* function.
|
||||
*
|
||||
* Returns: length of @s in bytes, or @max_len, whichever is smaller.
|
||||
*/
|
||||
int qemu_strnlen(const char *s, int max_len);
|
||||
/**
|
||||
* qemu_strsep:
|
||||
* @input: pointer to string to parse
|
||||
* @delim: string containing delimiter characters to search for
|
||||
*
|
||||
* Locate the first occurrence of any character in @delim within
|
||||
* the string referenced by @input, and replace it with a NUL.
|
||||
* The location of the next character after the delimiter character
|
||||
* is stored into @input.
|
||||
* If the end of the string was reached without finding a delimiter
|
||||
* character, then NULL is stored into @input.
|
||||
* If @input points to a NULL pointer on entry, return NULL.
|
||||
* The return value is always the original value of *@input (and
|
||||
* so now points to a NUL-terminated string corresponding to the
|
||||
* part of the input up to the first delimiter).
|
||||
*
|
||||
* This function has the same behaviour as the BSD strsep() function.
|
||||
*
|
||||
* Returns: the pointer originally in @input.
|
||||
*/
|
||||
char *qemu_strsep(char **input, const char *delim);
|
||||
time_t mktimegm(struct tm *tm);
|
||||
int qemu_fls(int i);
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "sysemu/iothread.h"
|
||||
#include "qmp-commands.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/rcu.h"
|
||||
|
||||
typedef ObjectClass IOThreadClass;
|
||||
|
||||
@@ -31,6 +32,8 @@ static void *iothread_run(void *opaque)
|
||||
IOThread *iothread = opaque;
|
||||
bool blocking;
|
||||
|
||||
rcu_register_thread();
|
||||
|
||||
qemu_mutex_lock(&iothread->init_done_lock);
|
||||
iothread->thread_id = qemu_get_thread_id();
|
||||
qemu_cond_signal(&iothread->init_done_cond);
|
||||
@@ -45,6 +48,8 @@ static void *iothread_run(void *opaque)
|
||||
}
|
||||
aio_context_release(iothread->ctx);
|
||||
}
|
||||
|
||||
rcu_unregister_thread();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
+10
-1
@@ -114,6 +114,14 @@ static int qemu_signal_init(void)
|
||||
#endif
|
||||
|
||||
static AioContext *qemu_aio_context;
|
||||
static QEMUBH *qemu_notify_bh;
|
||||
|
||||
static void notify_event_cb(void *opaque)
|
||||
{
|
||||
/* No need to do anything; this bottom half is only used to
|
||||
* kick the kernel out of ppoll/poll/WaitForMultipleObjects.
|
||||
*/
|
||||
}
|
||||
|
||||
AioContext *qemu_get_aio_context(void)
|
||||
{
|
||||
@@ -125,7 +133,7 @@ void qemu_notify_event(void)
|
||||
if (!qemu_aio_context) {
|
||||
return;
|
||||
}
|
||||
aio_notify(qemu_aio_context);
|
||||
qemu_bh_schedule(qemu_notify_bh);
|
||||
}
|
||||
|
||||
static GArray *gpollfds;
|
||||
@@ -144,6 +152,7 @@ int qemu_init_main_loop(Error **errp)
|
||||
}
|
||||
|
||||
qemu_aio_context = aio_context_new(&local_error);
|
||||
qemu_notify_bh = qemu_bh_new(notify_event_cb, NULL);
|
||||
if (!qemu_aio_context) {
|
||||
error_propagate(errp, local_error);
|
||||
return -EMFILE;
|
||||
|
||||
@@ -859,11 +859,6 @@ static void memory_region_destructor_ram(MemoryRegion *mr)
|
||||
qemu_ram_free(mr->ram_addr);
|
||||
}
|
||||
|
||||
static void memory_region_destructor_alias(MemoryRegion *mr)
|
||||
{
|
||||
memory_region_unref(mr->alias);
|
||||
}
|
||||
|
||||
static void memory_region_destructor_ram_from_ptr(MemoryRegion *mr)
|
||||
{
|
||||
qemu_ram_free_from_ptr(mr->ram_addr);
|
||||
@@ -1272,8 +1267,6 @@ void memory_region_init_alias(MemoryRegion *mr,
|
||||
uint64_t size)
|
||||
{
|
||||
memory_region_init(mr, owner, name, size);
|
||||
memory_region_ref(orig);
|
||||
mr->destructor = memory_region_destructor_alias;
|
||||
mr->alias = orig;
|
||||
mr->alias_offset = offset;
|
||||
}
|
||||
@@ -1433,8 +1426,15 @@ void memory_region_notify_iommu(MemoryRegion *mr,
|
||||
void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client)
|
||||
{
|
||||
uint8_t mask = 1 << client;
|
||||
uint8_t old_logging;
|
||||
|
||||
assert(client == DIRTY_MEMORY_VGA);
|
||||
old_logging = mr->vga_logging_count;
|
||||
mr->vga_logging_count += log ? 1 : -1;
|
||||
if (!!old_logging == !!mr->vga_logging_count) {
|
||||
return;
|
||||
}
|
||||
|
||||
memory_region_transaction_begin();
|
||||
mr->dirty_log_mask = (mr->dirty_log_mask & ~mask) | (log * mask);
|
||||
memory_region_update_pending |= mr->enabled;
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "block/block.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "qemu/sockets.h"
|
||||
#include "qemu/rcu.h"
|
||||
#include "migration/block.h"
|
||||
#include "qemu/thread.h"
|
||||
#include "qmp-commands.h"
|
||||
@@ -121,6 +122,13 @@ int global_state_store(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void global_state_store_running(void)
|
||||
{
|
||||
const char *state = RunState_lookup[RUN_STATE_RUNNING];
|
||||
strncpy((char *)global_state.runstate,
|
||||
state, sizeof(global_state.runstate));
|
||||
}
|
||||
|
||||
static bool global_state_received(void)
|
||||
{
|
||||
return global_state.received;
|
||||
@@ -917,6 +925,8 @@ static void *migration_thread(void *opaque)
|
||||
int64_t start_time = initial_time;
|
||||
bool old_vm_running = false;
|
||||
|
||||
rcu_register_thread();
|
||||
|
||||
qemu_savevm_state_header(s->file);
|
||||
qemu_savevm_state_begin(s->file, &s->params);
|
||||
|
||||
@@ -1016,6 +1026,7 @@ static void *migration_thread(void *opaque)
|
||||
qemu_bh_schedule(s->cleanup_bh);
|
||||
qemu_mutex_unlock_iothread();
|
||||
|
||||
rcu_unregister_thread();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -1394,6 +1394,7 @@ void qmp_xen_save_devices_state(const char *filename, Error **errp)
|
||||
|
||||
saved_vm_running = runstate_is_running();
|
||||
vm_stop(RUN_STATE_SAVE_VM);
|
||||
global_state_store_running();
|
||||
|
||||
f = qemu_fopen(filename, "wb");
|
||||
if (!f) {
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
{ 'include': 'qapi/trace.json' }
|
||||
|
||||
##
|
||||
# LostTickPolicy:
|
||||
# @LostTickPolicy:
|
||||
#
|
||||
# Policy for handling lost ticks in timer devices.
|
||||
#
|
||||
|
||||
+16
-10
@@ -807,7 +807,8 @@ static gboolean io_watch_poll_prepare(GSource *source, gint *timeout_)
|
||||
}
|
||||
|
||||
if (now_active) {
|
||||
iwp->src = g_io_create_watch(iwp->channel, G_IO_IN | G_IO_ERR | G_IO_HUP);
|
||||
iwp->src = g_io_create_watch(iwp->channel,
|
||||
G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL);
|
||||
g_source_set_callback(iwp->src, iwp->fd_read, iwp->opaque, NULL);
|
||||
g_source_attach(iwp->src, NULL);
|
||||
} else {
|
||||
@@ -2797,7 +2798,10 @@ static ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len)
|
||||
#ifdef MSG_CMSG_CLOEXEC
|
||||
flags |= MSG_CMSG_CLOEXEC;
|
||||
#endif
|
||||
ret = recvmsg(s->fd, &msg, flags);
|
||||
do {
|
||||
ret = recvmsg(s->fd, &msg, flags);
|
||||
} while (ret == -1 && errno == EINTR);
|
||||
|
||||
if (ret > 0 && s->is_unix) {
|
||||
unix_process_msgfd(chr, &msg);
|
||||
}
|
||||
@@ -2808,7 +2812,13 @@ static ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len)
|
||||
static ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len)
|
||||
{
|
||||
TCPCharDriver *s = chr->opaque;
|
||||
return qemu_recv(s->fd, buf, len, 0);
|
||||
ssize_t ret;
|
||||
|
||||
do {
|
||||
ret = qemu_recv(s->fd, buf, len, 0);
|
||||
} while (ret == -1 && socket_error() == EINTR);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2847,12 +2857,6 @@ static gboolean tcp_chr_read(GIOChannel *chan, GIOCondition cond, void *opaque)
|
||||
uint8_t buf[READ_BUF_LEN];
|
||||
int len, size;
|
||||
|
||||
if (cond & G_IO_HUP) {
|
||||
/* connection closed */
|
||||
tcp_chr_disconnect(chr);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (!s->connected || s->max_size <= 0) {
|
||||
return TRUE;
|
||||
}
|
||||
@@ -2860,7 +2864,9 @@ static gboolean tcp_chr_read(GIOChannel *chan, GIOCondition cond, void *opaque)
|
||||
if (len > s->max_size)
|
||||
len = s->max_size;
|
||||
size = tcp_chr_recv(chr, (void *)buf, len);
|
||||
if (size == 0) {
|
||||
if (size == 0 ||
|
||||
(size < 0 &&
|
||||
socket_error() != EAGAIN && socket_error() != EWOULDBLOCK)) {
|
||||
/* connection closed */
|
||||
tcp_chr_disconnect(chr);
|
||||
} else if (size > 0) {
|
||||
|
||||
+1
-1
@@ -1061,7 +1061,7 @@ type is assumed.
|
||||
@var{server} specifies the server where the volume file specification for
|
||||
the given volume resides. This can be either hostname, ipv4 address
|
||||
or ipv6 address. ipv6 address needs to be within square brackets [ ].
|
||||
If transport type is unix, then @var{server} field should not be specifed.
|
||||
If transport type is unix, then @var{server} field should not be specified.
|
||||
Instead @var{socket} field needs to be populated with the path to unix domain
|
||||
socket.
|
||||
|
||||
|
||||
+1
-1
@@ -206,7 +206,7 @@ STEXI
|
||||
@item -boot [order=@var{drives}][,once=@var{drives}][,menu=on|off][,splash=@var{sp_name}][,splash-time=@var{sp_time}][,reboot-timeout=@var{rb_timeout}][,strict=on|off]
|
||||
@findex -boot
|
||||
Specify boot order @var{drives} as a string of drive letters. Valid
|
||||
drive letters depend on the target achitecture. The x86 PC uses: a, b
|
||||
drive letters depend on the target architecture. The x86 PC uses: a, b
|
||||
(floppy 1 and 2), c (first hard disk), d (first CD-ROM), n-p (Etherboot
|
||||
from network adapter 1-4), hard disk boot is the default. To apply a
|
||||
particular boot order only on the first startup, specify it via
|
||||
|
||||
+1
-1
@@ -440,7 +440,7 @@ translator cannot deduce statically).
|
||||
@section Direct block chaining
|
||||
|
||||
After each translated basic block is executed, QEMU uses the simulated
|
||||
Program Counter (PC) and other cpu state informations (such as the CS
|
||||
Program Counter (PC) and other cpu state information (such as the CS
|
||||
segment base value) to find the next basic block.
|
||||
|
||||
In order to accelerate the most common cases where the new simulated PC
|
||||
|
||||
@@ -272,7 +272,7 @@ int64_t helper_fistll_ST0(CPUX86State *env)
|
||||
old_exp_flags = get_float_exception_flags(&env->fp_status);
|
||||
set_float_exception_flags(0, &env->fp_status);
|
||||
|
||||
val = floatx80_to_int32(ST0, &env->fp_status);
|
||||
val = floatx80_to_int64(ST0, &env->fp_status);
|
||||
if (get_float_exception_flags(&env->fp_status) & float_flag_invalid) {
|
||||
val = 0x8000000000000000ULL;
|
||||
}
|
||||
|
||||
+19
-23
@@ -565,34 +565,30 @@ void mips_cpu_do_interrupt(CPUState *cs)
|
||||
break;
|
||||
case EXCP_EXT_INTERRUPT:
|
||||
cause = 0;
|
||||
if (env->CP0_Cause & (1 << CP0Ca_IV))
|
||||
offset = 0x200;
|
||||
if (env->CP0_Cause & (1 << CP0Ca_IV)) {
|
||||
uint32_t spacing = (env->CP0_IntCtl >> CP0IntCtl_VS) & 0x1f;
|
||||
|
||||
if (env->CP0_Config3 & ((1 << CP0C3_VInt) | (1 << CP0C3_VEIC))) {
|
||||
/* Vectored Interrupts. */
|
||||
unsigned int spacing;
|
||||
unsigned int vector;
|
||||
unsigned int pending = (env->CP0_Cause & CP0Ca_IP_mask) >> 8;
|
||||
if ((env->CP0_Status & (1 << CP0St_BEV)) || spacing == 0) {
|
||||
offset = 0x200;
|
||||
} else {
|
||||
uint32_t vector = 0;
|
||||
uint32_t pending = (env->CP0_Cause & CP0Ca_IP_mask) >> CP0Ca_IP;
|
||||
|
||||
pending &= env->CP0_Status >> 8;
|
||||
/* Compute the Vector Spacing. */
|
||||
spacing = (env->CP0_IntCtl >> CP0IntCtl_VS) & ((1 << 6) - 1);
|
||||
spacing <<= 5;
|
||||
|
||||
if (env->CP0_Config3 & (1 << CP0C3_VInt)) {
|
||||
/* For VInt mode, the MIPS computes the vector internally. */
|
||||
for (vector = 7; vector > 0; vector--) {
|
||||
if (pending & (1 << vector)) {
|
||||
/* Found it. */
|
||||
break;
|
||||
if (env->CP0_Config3 & (1 << CP0C3_VEIC)) {
|
||||
/* For VEIC mode, the external interrupt controller feeds
|
||||
* the vector through the CP0Cause IP lines. */
|
||||
vector = pending;
|
||||
} else {
|
||||
/* Vectored Interrupts
|
||||
* Mask with Status.IM7-IM0 to get enabled interrupts. */
|
||||
pending &= (env->CP0_Status >> CP0St_IM) & 0xff;
|
||||
/* Find the highest-priority interrupt. */
|
||||
while (pending >>= 1) {
|
||||
vector++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* For VEIC mode, the external interrupt controller feeds the
|
||||
vector through the CP0Cause IP lines. */
|
||||
vector = pending;
|
||||
offset = 0x200 + (vector * (spacing << 5));
|
||||
}
|
||||
offset = 0x200 + vector * spacing;
|
||||
}
|
||||
goto set_EPC;
|
||||
case EXCP_LTLBL:
|
||||
|
||||
@@ -153,6 +153,7 @@ static void put_tlb(QEMUFile *f, void *pv, size_t size)
|
||||
{
|
||||
r4k_tlb_t *v = pv;
|
||||
|
||||
uint8_t asid = v->ASID;
|
||||
uint16_t flags = ((v->EHINV << 15) |
|
||||
(v->RI1 << 14) |
|
||||
(v->RI0 << 13) |
|
||||
@@ -168,7 +169,7 @@ static void put_tlb(QEMUFile *f, void *pv, size_t size)
|
||||
|
||||
qemu_put_betls(f, &v->VPN);
|
||||
qemu_put_be32s(f, &v->PageMask);
|
||||
qemu_put_8s(f, &v->ASID);
|
||||
qemu_put_8s(f, &asid);
|
||||
qemu_put_be16s(f, &flags);
|
||||
qemu_put_be64s(f, &v->PFN[0]);
|
||||
qemu_put_be64s(f, &v->PFN[1]);
|
||||
|
||||
@@ -1432,7 +1432,6 @@ void helper_mttc0_status(CPUMIPSState *env, target_ulong arg1)
|
||||
|
||||
void helper_mtc0_intctl(CPUMIPSState *env, target_ulong arg1)
|
||||
{
|
||||
/* vectored interrupts not implemented, no performance counters. */
|
||||
env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000003e0) | (arg1 & 0x000003e0);
|
||||
}
|
||||
|
||||
@@ -1473,7 +1472,6 @@ target_ulong helper_mftc0_ebase(CPUMIPSState *env)
|
||||
|
||||
void helper_mtc0_ebase(CPUMIPSState *env, target_ulong arg1)
|
||||
{
|
||||
/* vectored interrupts not implemented */
|
||||
env->CP0_EBase = (env->CP0_EBase & ~0x3FFFF000) | (arg1 & 0x3FFFF000);
|
||||
}
|
||||
|
||||
|
||||
+32
-23
@@ -4750,48 +4750,53 @@ static void gen_bitops (DisasContext *ctx, uint32_t opc, int rt,
|
||||
gen_load_gpr(t1, rs);
|
||||
switch (opc) {
|
||||
case OPC_EXT:
|
||||
if (lsb + msb > 31)
|
||||
if (lsb + msb > 31) {
|
||||
goto fail;
|
||||
}
|
||||
tcg_gen_shri_tl(t0, t1, lsb);
|
||||
if (msb != 31) {
|
||||
tcg_gen_andi_tl(t0, t0, (1 << (msb + 1)) - 1);
|
||||
tcg_gen_andi_tl(t0, t0, (1U << (msb + 1)) - 1);
|
||||
} else {
|
||||
tcg_gen_ext32s_tl(t0, t0);
|
||||
}
|
||||
break;
|
||||
#if defined(TARGET_MIPS64)
|
||||
case OPC_DEXTM:
|
||||
tcg_gen_shri_tl(t0, t1, lsb);
|
||||
if (msb != 31) {
|
||||
tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1 + 32)) - 1);
|
||||
}
|
||||
break;
|
||||
case OPC_DEXTU:
|
||||
tcg_gen_shri_tl(t0, t1, lsb + 32);
|
||||
tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1)) - 1);
|
||||
break;
|
||||
lsb += 32;
|
||||
goto do_dext;
|
||||
case OPC_DEXTM:
|
||||
msb += 32;
|
||||
goto do_dext;
|
||||
case OPC_DEXT:
|
||||
do_dext:
|
||||
if (lsb + msb > 63) {
|
||||
goto fail;
|
||||
}
|
||||
tcg_gen_shri_tl(t0, t1, lsb);
|
||||
tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1)) - 1);
|
||||
if (msb != 63) {
|
||||
tcg_gen_andi_tl(t0, t0, (1ULL << (msb + 1)) - 1);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case OPC_INS:
|
||||
if (lsb > msb)
|
||||
if (lsb > msb) {
|
||||
goto fail;
|
||||
}
|
||||
gen_load_gpr(t0, rt);
|
||||
tcg_gen_deposit_tl(t0, t0, t1, lsb, msb - lsb + 1);
|
||||
tcg_gen_ext32s_tl(t0, t0);
|
||||
break;
|
||||
#if defined(TARGET_MIPS64)
|
||||
case OPC_DINSM:
|
||||
gen_load_gpr(t0, rt);
|
||||
tcg_gen_deposit_tl(t0, t0, t1, lsb, msb + 32 - lsb + 1);
|
||||
break;
|
||||
case OPC_DINSU:
|
||||
gen_load_gpr(t0, rt);
|
||||
tcg_gen_deposit_tl(t0, t0, t1, lsb + 32, msb - lsb + 1);
|
||||
break;
|
||||
lsb += 32;
|
||||
/* FALLTHRU */
|
||||
case OPC_DINSM:
|
||||
msb += 32;
|
||||
/* FALLTHRU */
|
||||
case OPC_DINS:
|
||||
if (lsb > msb) {
|
||||
goto fail;
|
||||
}
|
||||
gen_load_gpr(t0, rt);
|
||||
tcg_gen_deposit_tl(t0, t0, t1, lsb, msb - lsb + 1);
|
||||
break;
|
||||
@@ -13278,10 +13283,14 @@ static void gen_pool16c_r6_insn(DisasContext *ctx)
|
||||
break;
|
||||
case R6_SDBBP16:
|
||||
/* SDBBP16 */
|
||||
if (ctx->hflags & MIPS_HFLAG_SBRI) {
|
||||
generate_exception(ctx, EXCP_RI);
|
||||
if (is_uhi(extract32(ctx->opcode, 6, 4))) {
|
||||
gen_helper_do_semihosting(cpu_env);
|
||||
} else {
|
||||
generate_exception(ctx, EXCP_DBp);
|
||||
if (ctx->hflags & MIPS_HFLAG_SBRI) {
|
||||
generate_exception(ctx, EXCP_RI);
|
||||
} else {
|
||||
generate_exception(ctx, EXCP_DBp);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
+36
-27
@@ -280,7 +280,7 @@ typedef enum {
|
||||
I3312_LDRSHX = 0x38000000 | LDST_LD_S_X << 22 | MO_16 << 30,
|
||||
I3312_LDRSWX = 0x38000000 | LDST_LD_S_X << 22 | MO_32 << 30,
|
||||
|
||||
I3312_TO_I3310 = 0x00206800,
|
||||
I3312_TO_I3310 = 0x00200800,
|
||||
I3312_TO_I3313 = 0x01000000,
|
||||
|
||||
/* Load/store register pair instructions. */
|
||||
@@ -496,13 +496,14 @@ static void tcg_out_insn_3509(TCGContext *s, AArch64Insn insn, TCGType ext,
|
||||
}
|
||||
|
||||
static void tcg_out_insn_3310(TCGContext *s, AArch64Insn insn,
|
||||
TCGReg rd, TCGReg base, TCGReg regoff)
|
||||
TCGReg rd, TCGReg base, TCGType ext,
|
||||
TCGReg regoff)
|
||||
{
|
||||
/* Note the AArch64Insn constants above are for C3.3.12. Adjust. */
|
||||
tcg_out32(s, insn | I3312_TO_I3310 | regoff << 16 | base << 5 | rd);
|
||||
tcg_out32(s, insn | I3312_TO_I3310 | regoff << 16 |
|
||||
0x4000 | ext << 13 | base << 5 | rd);
|
||||
}
|
||||
|
||||
|
||||
static void tcg_out_insn_3312(TCGContext *s, AArch64Insn insn,
|
||||
TCGReg rd, TCGReg rn, intptr_t offset)
|
||||
{
|
||||
@@ -677,7 +678,7 @@ static void tcg_out_ldst(TCGContext *s, AArch64Insn insn,
|
||||
|
||||
/* Worst-case scenario, move offset to temp register, use reg offset. */
|
||||
tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, offset);
|
||||
tcg_out_ldst_r(s, insn, rd, rn, TCG_REG_TMP);
|
||||
tcg_out_ldst_r(s, insn, rd, rn, TCG_TYPE_I64, TCG_REG_TMP);
|
||||
}
|
||||
|
||||
static inline void tcg_out_mov(TCGContext *s,
|
||||
@@ -1108,51 +1109,52 @@ static void tcg_out_tlb_read(TCGContext *s, TCGReg addr_reg, TCGMemOp s_bits,
|
||||
#endif /* CONFIG_SOFTMMU */
|
||||
|
||||
static void tcg_out_qemu_ld_direct(TCGContext *s, TCGMemOp memop, TCGType ext,
|
||||
TCGReg data_r, TCGReg addr_r, TCGReg off_r)
|
||||
TCGReg data_r, TCGReg addr_r,
|
||||
TCGType otype, TCGReg off_r)
|
||||
{
|
||||
const TCGMemOp bswap = memop & MO_BSWAP;
|
||||
|
||||
switch (memop & MO_SSIZE) {
|
||||
case MO_UB:
|
||||
tcg_out_ldst_r(s, I3312_LDRB, data_r, addr_r, off_r);
|
||||
tcg_out_ldst_r(s, I3312_LDRB, data_r, addr_r, otype, off_r);
|
||||
break;
|
||||
case MO_SB:
|
||||
tcg_out_ldst_r(s, ext ? I3312_LDRSBX : I3312_LDRSBW,
|
||||
data_r, addr_r, off_r);
|
||||
data_r, addr_r, otype, off_r);
|
||||
break;
|
||||
case MO_UW:
|
||||
tcg_out_ldst_r(s, I3312_LDRH, data_r, addr_r, off_r);
|
||||
tcg_out_ldst_r(s, I3312_LDRH, data_r, addr_r, otype, off_r);
|
||||
if (bswap) {
|
||||
tcg_out_rev16(s, data_r, data_r);
|
||||
}
|
||||
break;
|
||||
case MO_SW:
|
||||
if (bswap) {
|
||||
tcg_out_ldst_r(s, I3312_LDRH, data_r, addr_r, off_r);
|
||||
tcg_out_ldst_r(s, I3312_LDRH, data_r, addr_r, otype, off_r);
|
||||
tcg_out_rev16(s, data_r, data_r);
|
||||
tcg_out_sxt(s, ext, MO_16, data_r, data_r);
|
||||
} else {
|
||||
tcg_out_ldst_r(s, ext ? I3312_LDRSHX : I3312_LDRSHW,
|
||||
data_r, addr_r, off_r);
|
||||
tcg_out_ldst_r(s, (ext ? I3312_LDRSHX : I3312_LDRSHW),
|
||||
data_r, addr_r, otype, off_r);
|
||||
}
|
||||
break;
|
||||
case MO_UL:
|
||||
tcg_out_ldst_r(s, I3312_LDRW, data_r, addr_r, off_r);
|
||||
tcg_out_ldst_r(s, I3312_LDRW, data_r, addr_r, otype, off_r);
|
||||
if (bswap) {
|
||||
tcg_out_rev32(s, data_r, data_r);
|
||||
}
|
||||
break;
|
||||
case MO_SL:
|
||||
if (bswap) {
|
||||
tcg_out_ldst_r(s, I3312_LDRW, data_r, addr_r, off_r);
|
||||
tcg_out_ldst_r(s, I3312_LDRW, data_r, addr_r, otype, off_r);
|
||||
tcg_out_rev32(s, data_r, data_r);
|
||||
tcg_out_sxt(s, TCG_TYPE_I64, MO_32, data_r, data_r);
|
||||
} else {
|
||||
tcg_out_ldst_r(s, I3312_LDRSWX, data_r, addr_r, off_r);
|
||||
tcg_out_ldst_r(s, I3312_LDRSWX, data_r, addr_r, otype, off_r);
|
||||
}
|
||||
break;
|
||||
case MO_Q:
|
||||
tcg_out_ldst_r(s, I3312_LDRX, data_r, addr_r, off_r);
|
||||
tcg_out_ldst_r(s, I3312_LDRX, data_r, addr_r, otype, off_r);
|
||||
if (bswap) {
|
||||
tcg_out_rev64(s, data_r, data_r);
|
||||
}
|
||||
@@ -1163,34 +1165,35 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, TCGMemOp memop, TCGType ext,
|
||||
}
|
||||
|
||||
static void tcg_out_qemu_st_direct(TCGContext *s, TCGMemOp memop,
|
||||
TCGReg data_r, TCGReg addr_r, TCGReg off_r)
|
||||
TCGReg data_r, TCGReg addr_r,
|
||||
TCGType otype, TCGReg off_r)
|
||||
{
|
||||
const TCGMemOp bswap = memop & MO_BSWAP;
|
||||
|
||||
switch (memop & MO_SIZE) {
|
||||
case MO_8:
|
||||
tcg_out_ldst_r(s, I3312_STRB, data_r, addr_r, off_r);
|
||||
tcg_out_ldst_r(s, I3312_STRB, data_r, addr_r, otype, off_r);
|
||||
break;
|
||||
case MO_16:
|
||||
if (bswap && data_r != TCG_REG_XZR) {
|
||||
tcg_out_rev16(s, TCG_REG_TMP, data_r);
|
||||
data_r = TCG_REG_TMP;
|
||||
}
|
||||
tcg_out_ldst_r(s, I3312_STRH, data_r, addr_r, off_r);
|
||||
tcg_out_ldst_r(s, I3312_STRH, data_r, addr_r, otype, off_r);
|
||||
break;
|
||||
case MO_32:
|
||||
if (bswap && data_r != TCG_REG_XZR) {
|
||||
tcg_out_rev32(s, TCG_REG_TMP, data_r);
|
||||
data_r = TCG_REG_TMP;
|
||||
}
|
||||
tcg_out_ldst_r(s, I3312_STRW, data_r, addr_r, off_r);
|
||||
tcg_out_ldst_r(s, I3312_STRW, data_r, addr_r, otype, off_r);
|
||||
break;
|
||||
case MO_64:
|
||||
if (bswap && data_r != TCG_REG_XZR) {
|
||||
tcg_out_rev64(s, TCG_REG_TMP, data_r);
|
||||
data_r = TCG_REG_TMP;
|
||||
}
|
||||
tcg_out_ldst_r(s, I3312_STRX, data_r, addr_r, off_r);
|
||||
tcg_out_ldst_r(s, I3312_STRX, data_r, addr_r, otype, off_r);
|
||||
break;
|
||||
default:
|
||||
tcg_abort();
|
||||
@@ -1201,18 +1204,21 @@ static void tcg_out_qemu_ld(TCGContext *s, TCGReg data_reg, TCGReg addr_reg,
|
||||
TCGMemOpIdx oi, TCGType ext)
|
||||
{
|
||||
TCGMemOp memop = get_memop(oi);
|
||||
const TCGType otype = TARGET_LONG_BITS == 64 ? TCG_TYPE_I64 : TCG_TYPE_I32;
|
||||
#ifdef CONFIG_SOFTMMU
|
||||
unsigned mem_index = get_mmuidx(oi);
|
||||
TCGMemOp s_bits = memop & MO_SIZE;
|
||||
tcg_insn_unit *label_ptr;
|
||||
|
||||
tcg_out_tlb_read(s, addr_reg, s_bits, &label_ptr, mem_index, 1);
|
||||
tcg_out_qemu_ld_direct(s, memop, ext, data_reg, addr_reg, TCG_REG_X1);
|
||||
tcg_out_qemu_ld_direct(s, memop, ext, data_reg,
|
||||
TCG_REG_X1, otype, addr_reg);
|
||||
add_qemu_ldst_label(s, true, oi, ext, data_reg, addr_reg,
|
||||
s->code_ptr, label_ptr);
|
||||
#else /* !CONFIG_SOFTMMU */
|
||||
tcg_out_qemu_ld_direct(s, memop, ext, data_reg, addr_reg,
|
||||
GUEST_BASE ? TCG_REG_GUEST_BASE : TCG_REG_XZR);
|
||||
tcg_out_qemu_ld_direct(s, memop, ext, data_reg,
|
||||
GUEST_BASE ? TCG_REG_GUEST_BASE : TCG_REG_XZR,
|
||||
otype, addr_reg);
|
||||
#endif /* CONFIG_SOFTMMU */
|
||||
}
|
||||
|
||||
@@ -1220,18 +1226,21 @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg data_reg, TCGReg addr_reg,
|
||||
TCGMemOpIdx oi)
|
||||
{
|
||||
TCGMemOp memop = get_memop(oi);
|
||||
const TCGType otype = TARGET_LONG_BITS == 64 ? TCG_TYPE_I64 : TCG_TYPE_I32;
|
||||
#ifdef CONFIG_SOFTMMU
|
||||
unsigned mem_index = get_mmuidx(oi);
|
||||
TCGMemOp s_bits = memop & MO_SIZE;
|
||||
tcg_insn_unit *label_ptr;
|
||||
|
||||
tcg_out_tlb_read(s, addr_reg, s_bits, &label_ptr, mem_index, 0);
|
||||
tcg_out_qemu_st_direct(s, memop, data_reg, addr_reg, TCG_REG_X1);
|
||||
tcg_out_qemu_st_direct(s, memop, data_reg,
|
||||
TCG_REG_X1, otype, addr_reg);
|
||||
add_qemu_ldst_label(s, false, oi, s_bits == MO_64, data_reg, addr_reg,
|
||||
s->code_ptr, label_ptr);
|
||||
#else /* !CONFIG_SOFTMMU */
|
||||
tcg_out_qemu_st_direct(s, memop, data_reg, addr_reg,
|
||||
GUEST_BASE ? TCG_REG_GUEST_BASE : TCG_REG_XZR);
|
||||
tcg_out_qemu_st_direct(s, memop, data_reg,
|
||||
GUEST_BASE ? TCG_REG_GUEST_BASE : TCG_REG_XZR,
|
||||
otype, addr_reg);
|
||||
#endif /* CONFIG_SOFTMMU */
|
||||
}
|
||||
|
||||
|
||||
+72
-42
@@ -1434,8 +1434,8 @@ static inline void setup_guest_base_seg(void) { }
|
||||
#endif /* SOFTMMU */
|
||||
|
||||
static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg datalo, TCGReg datahi,
|
||||
TCGReg base, intptr_t ofs, int seg,
|
||||
TCGMemOp memop)
|
||||
TCGReg base, int index, intptr_t ofs,
|
||||
int seg, TCGMemOp memop)
|
||||
{
|
||||
const TCGMemOp real_bswap = memop & MO_BSWAP;
|
||||
TCGMemOp bswap = real_bswap;
|
||||
@@ -1448,13 +1448,16 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg datalo, TCGReg datahi,
|
||||
|
||||
switch (memop & MO_SSIZE) {
|
||||
case MO_UB:
|
||||
tcg_out_modrm_offset(s, OPC_MOVZBL + seg, datalo, base, ofs);
|
||||
tcg_out_modrm_sib_offset(s, OPC_MOVZBL + seg, datalo,
|
||||
base, index, 0, ofs);
|
||||
break;
|
||||
case MO_SB:
|
||||
tcg_out_modrm_offset(s, OPC_MOVSBL + P_REXW + seg, datalo, base, ofs);
|
||||
tcg_out_modrm_sib_offset(s, OPC_MOVSBL + P_REXW + seg, datalo,
|
||||
base, index, 0, ofs);
|
||||
break;
|
||||
case MO_UW:
|
||||
tcg_out_modrm_offset(s, OPC_MOVZWL + seg, datalo, base, ofs);
|
||||
tcg_out_modrm_sib_offset(s, OPC_MOVZWL + seg, datalo,
|
||||
base, index, 0, ofs);
|
||||
if (real_bswap) {
|
||||
tcg_out_rolw_8(s, datalo);
|
||||
}
|
||||
@@ -1462,20 +1465,21 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg datalo, TCGReg datahi,
|
||||
case MO_SW:
|
||||
if (real_bswap) {
|
||||
if (have_movbe) {
|
||||
tcg_out_modrm_offset(s, OPC_MOVBE_GyMy + P_DATA16 + seg,
|
||||
datalo, base, ofs);
|
||||
tcg_out_modrm_sib_offset(s, OPC_MOVBE_GyMy + P_DATA16 + seg,
|
||||
datalo, base, index, 0, ofs);
|
||||
} else {
|
||||
tcg_out_modrm_offset(s, OPC_MOVZWL + seg, datalo, base, ofs);
|
||||
tcg_out_modrm_sib_offset(s, OPC_MOVZWL + seg, datalo,
|
||||
base, index, 0, ofs);
|
||||
tcg_out_rolw_8(s, datalo);
|
||||
}
|
||||
tcg_out_modrm(s, OPC_MOVSWL + P_REXW, datalo, datalo);
|
||||
} else {
|
||||
tcg_out_modrm_offset(s, OPC_MOVSWL + P_REXW + seg,
|
||||
datalo, base, ofs);
|
||||
tcg_out_modrm_sib_offset(s, OPC_MOVSWL + P_REXW + seg,
|
||||
datalo, base, index, 0, ofs);
|
||||
}
|
||||
break;
|
||||
case MO_UL:
|
||||
tcg_out_modrm_offset(s, movop + seg, datalo, base, ofs);
|
||||
tcg_out_modrm_sib_offset(s, movop + seg, datalo, base, index, 0, ofs);
|
||||
if (bswap) {
|
||||
tcg_out_bswap32(s, datalo);
|
||||
}
|
||||
@@ -1483,19 +1487,22 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg datalo, TCGReg datahi,
|
||||
#if TCG_TARGET_REG_BITS == 64
|
||||
case MO_SL:
|
||||
if (real_bswap) {
|
||||
tcg_out_modrm_offset(s, movop + seg, datalo, base, ofs);
|
||||
tcg_out_modrm_sib_offset(s, movop + seg, datalo,
|
||||
base, index, 0, ofs);
|
||||
if (bswap) {
|
||||
tcg_out_bswap32(s, datalo);
|
||||
}
|
||||
tcg_out_ext32s(s, datalo, datalo);
|
||||
} else {
|
||||
tcg_out_modrm_offset(s, OPC_MOVSLQ + seg, datalo, base, ofs);
|
||||
tcg_out_modrm_sib_offset(s, OPC_MOVSLQ + seg, datalo,
|
||||
base, index, 0, ofs);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case MO_Q:
|
||||
if (TCG_TARGET_REG_BITS == 64) {
|
||||
tcg_out_modrm_offset(s, movop + P_REXW + seg, datalo, base, ofs);
|
||||
tcg_out_modrm_sib_offset(s, movop + P_REXW + seg, datalo,
|
||||
base, index, 0, ofs);
|
||||
if (bswap) {
|
||||
tcg_out_bswap64(s, datalo);
|
||||
}
|
||||
@@ -1506,11 +1513,15 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg datalo, TCGReg datahi,
|
||||
datahi = t;
|
||||
}
|
||||
if (base != datalo) {
|
||||
tcg_out_modrm_offset(s, movop + seg, datalo, base, ofs);
|
||||
tcg_out_modrm_offset(s, movop + seg, datahi, base, ofs + 4);
|
||||
tcg_out_modrm_sib_offset(s, movop + seg, datalo,
|
||||
base, index, 0, ofs);
|
||||
tcg_out_modrm_sib_offset(s, movop + seg, datahi,
|
||||
base, index, 0, ofs + 4);
|
||||
} else {
|
||||
tcg_out_modrm_offset(s, movop + seg, datahi, base, ofs + 4);
|
||||
tcg_out_modrm_offset(s, movop + seg, datalo, base, ofs);
|
||||
tcg_out_modrm_sib_offset(s, movop + seg, datahi,
|
||||
base, index, 0, ofs + 4);
|
||||
tcg_out_modrm_sib_offset(s, movop + seg, datalo,
|
||||
base, index, 0, ofs);
|
||||
}
|
||||
if (bswap) {
|
||||
tcg_out_bswap32(s, datalo);
|
||||
@@ -1553,7 +1564,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is64)
|
||||
label_ptr, offsetof(CPUTLBEntry, addr_read));
|
||||
|
||||
/* TLB Hit. */
|
||||
tcg_out_qemu_ld_direct(s, datalo, datahi, TCG_REG_L1, 0, 0, opc);
|
||||
tcg_out_qemu_ld_direct(s, datalo, datahi, TCG_REG_L1, -1, 0, 0, opc);
|
||||
|
||||
/* Record the current context of a load into ldst label */
|
||||
add_qemu_ldst_label(s, true, oi, datalo, datahi, addrlo, addrhi,
|
||||
@@ -1562,24 +1573,33 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is64)
|
||||
{
|
||||
int32_t offset = GUEST_BASE;
|
||||
TCGReg base = addrlo;
|
||||
int index = -1;
|
||||
int seg = 0;
|
||||
|
||||
/* ??? We assume all operations have left us with register contents
|
||||
that are zero extended. So far this appears to be true. If we
|
||||
want to enforce this, we can either do an explicit zero-extension
|
||||
here, or (if GUEST_BASE == 0, or a segment register is in use)
|
||||
use the ADDR32 prefix. For now, do nothing. */
|
||||
if (GUEST_BASE && guest_base_flags) {
|
||||
/* For a 32-bit guest, the high 32 bits may contain garbage.
|
||||
We can do this with the ADDR32 prefix if we're not using
|
||||
a guest base, or when using segmentation. Otherwise we
|
||||
need to zero-extend manually. */
|
||||
if (GUEST_BASE == 0 || guest_base_flags) {
|
||||
seg = guest_base_flags;
|
||||
offset = 0;
|
||||
} else if (TCG_TARGET_REG_BITS == 64 && offset != GUEST_BASE) {
|
||||
tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_L1, GUEST_BASE);
|
||||
tgen_arithr(s, ARITH_ADD + P_REXW, TCG_REG_L1, base);
|
||||
base = TCG_REG_L1;
|
||||
offset = 0;
|
||||
if (TCG_TARGET_REG_BITS > TARGET_LONG_BITS) {
|
||||
seg |= P_ADDR32;
|
||||
}
|
||||
} else if (TCG_TARGET_REG_BITS == 64) {
|
||||
if (TARGET_LONG_BITS == 32) {
|
||||
tcg_out_ext32u(s, TCG_REG_L0, base);
|
||||
base = TCG_REG_L0;
|
||||
}
|
||||
if (offset != GUEST_BASE) {
|
||||
tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_L1, GUEST_BASE);
|
||||
index = TCG_REG_L1;
|
||||
offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
tcg_out_qemu_ld_direct(s, datalo, datahi, base, offset, seg, opc);
|
||||
tcg_out_qemu_ld_direct(s, datalo, datahi,
|
||||
base, index, offset, seg, opc);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1697,19 +1717,29 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is64)
|
||||
TCGReg base = addrlo;
|
||||
int seg = 0;
|
||||
|
||||
/* ??? We assume all operations have left us with register contents
|
||||
that are zero extended. So far this appears to be true. If we
|
||||
want to enforce this, we can either do an explicit zero-extension
|
||||
here, or (if GUEST_BASE == 0, or a segment register is in use)
|
||||
use the ADDR32 prefix. For now, do nothing. */
|
||||
if (GUEST_BASE && guest_base_flags) {
|
||||
/* See comment in tcg_out_qemu_ld re zero-extension of addrlo. */
|
||||
if (GUEST_BASE == 0 || guest_base_flags) {
|
||||
seg = guest_base_flags;
|
||||
offset = 0;
|
||||
} else if (TCG_TARGET_REG_BITS == 64 && offset != GUEST_BASE) {
|
||||
tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_L1, GUEST_BASE);
|
||||
tgen_arithr(s, ARITH_ADD + P_REXW, TCG_REG_L1, base);
|
||||
base = TCG_REG_L1;
|
||||
offset = 0;
|
||||
if (TCG_TARGET_REG_BITS > TARGET_LONG_BITS) {
|
||||
seg |= P_ADDR32;
|
||||
}
|
||||
} else if (TCG_TARGET_REG_BITS == 64) {
|
||||
/* ??? Note that we can't use the same SIB addressing scheme
|
||||
as for loads, since we require L0 free for bswap. */
|
||||
if (offset != GUEST_BASE) {
|
||||
if (TARGET_LONG_BITS == 32) {
|
||||
tcg_out_ext32u(s, TCG_REG_L0, base);
|
||||
base = TCG_REG_L0;
|
||||
}
|
||||
tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_L1, GUEST_BASE);
|
||||
tgen_arithr(s, ARITH_ADD + P_REXW, TCG_REG_L1, base);
|
||||
base = TCG_REG_L1;
|
||||
offset = 0;
|
||||
} else if (TARGET_LONG_BITS == 32) {
|
||||
tcg_out_ext32u(s, TCG_REG_L1, base);
|
||||
base = TCG_REG_L1;
|
||||
}
|
||||
}
|
||||
|
||||
tcg_out_qemu_st_direct(s, datalo, datahi, base, offset, seg, opc);
|
||||
|
||||
@@ -963,9 +963,11 @@ static void tcg_out_tlb_load(TCGContext *s, TCGReg base, TCGReg addrl,
|
||||
}
|
||||
|
||||
/* Load the tlb comparator. */
|
||||
tcg_out_opc_imm(s, OPC_LW, TCG_TMP0, TCG_REG_A0, cmp_off + LO_OFF);
|
||||
if (TARGET_LONG_BITS == 64) {
|
||||
tcg_out_opc_imm(s, OPC_LW, TCG_TMP0, TCG_REG_A0, cmp_off + LO_OFF);
|
||||
tcg_out_opc_imm(s, OPC_LW, base, TCG_REG_A0, cmp_off + HI_OFF);
|
||||
} else {
|
||||
tcg_out_opc_imm(s, OPC_LW, TCG_TMP0, TCG_REG_A0, cmp_off);
|
||||
}
|
||||
|
||||
/* Mask the page bits, keeping the alignment bits to compare against.
|
||||
@@ -1103,7 +1105,7 @@ static void tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
|
||||
static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg datalo, TCGReg datahi,
|
||||
TCGReg base, TCGMemOp opc)
|
||||
{
|
||||
switch (opc) {
|
||||
switch (opc & (MO_SSIZE | MO_BSWAP)) {
|
||||
case MO_UB:
|
||||
tcg_out_opc_imm(s, OPC_LBU, datalo, base, 0);
|
||||
break;
|
||||
@@ -1193,7 +1195,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is_64)
|
||||
static void tcg_out_qemu_st_direct(TCGContext *s, TCGReg datalo, TCGReg datahi,
|
||||
TCGReg base, TCGMemOp opc)
|
||||
{
|
||||
switch (opc) {
|
||||
switch (opc & (MO_SIZE | MO_BSWAP)) {
|
||||
case MO_8:
|
||||
tcg_out_opc_imm(s, OPC_SB, datalo, base, 0);
|
||||
break;
|
||||
@@ -1269,6 +1271,9 @@ static void tcg_out_addsub2(TCGContext *s, TCGReg rl, TCGReg rh, TCGReg al,
|
||||
if (cbl) {
|
||||
tcg_out_opc_imm(s, OPC_ADDIU, rl, al, bl);
|
||||
tcg_out_opc_imm(s, OPC_SLTIU, TCG_TMP0, rl, bl);
|
||||
} else if (rl == al && rl == bl) {
|
||||
tcg_out_opc_sa(s, OPC_SRL, TCG_TMP0, al, 31);
|
||||
tcg_out_opc_reg(s, OPC_ADDU, rl, al, bl);
|
||||
} else {
|
||||
tcg_out_opc_reg(s, OPC_ADDU, rl, al, bl);
|
||||
tcg_out_opc_reg(s, OPC_SLTU, TCG_TMP0, rl, (rl == bl ? al : bl));
|
||||
|
||||
+1
-1
@@ -205,7 +205,7 @@ static void tcg_opt_gen_movi(TCGContext *s, TCGOp *op, TCGArg *args,
|
||||
temps[dst].state = TCG_TEMP_CONST;
|
||||
temps[dst].val = val;
|
||||
mask = val;
|
||||
if (TCG_TARGET_REG_BITS > 32 && new_op == INDEX_op_mov_i32) {
|
||||
if (TCG_TARGET_REG_BITS > 32 && new_op == INDEX_op_movi_i32) {
|
||||
/* High bits of the destination are now garbage. */
|
||||
mask |= ~0xffffffffull;
|
||||
}
|
||||
|
||||
@@ -1390,7 +1390,7 @@ static void tcg_out_call(TCGContext *s, tcg_insn_unit *dest)
|
||||
static void tcg_out_qemu_ld_direct(TCGContext *s, TCGMemOp opc, TCGReg data,
|
||||
TCGReg base, TCGReg index, int disp)
|
||||
{
|
||||
switch (opc) {
|
||||
switch (opc & (MO_SSIZE | MO_BSWAP)) {
|
||||
case MO_UB:
|
||||
tcg_out_insn(s, RXY, LLGC, data, base, index, disp);
|
||||
break;
|
||||
@@ -1449,7 +1449,7 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, TCGMemOp opc, TCGReg data,
|
||||
static void tcg_out_qemu_st_direct(TCGContext *s, TCGMemOp opc, TCGReg data,
|
||||
TCGReg base, TCGReg index, int disp)
|
||||
{
|
||||
switch (opc) {
|
||||
switch (opc & (MO_SIZE | MO_BSWAP)) {
|
||||
case MO_UB:
|
||||
if (disp >= 0 && disp < 0x1000) {
|
||||
tcg_out_insn(s, RX, STC, data, base, index, disp);
|
||||
|
||||
@@ -1894,6 +1894,7 @@ static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def,
|
||||
ts->mem_coherent = 1;
|
||||
} else if (ts->val_type == TEMP_VAL_CONST) {
|
||||
tcg_out_movi(s, itype, ts->reg, ts->val);
|
||||
ts->mem_coherent = 0;
|
||||
}
|
||||
s->reg_to_temp[ts->reg] = args[1];
|
||||
ts->val_type = TEMP_VAL_REG;
|
||||
@@ -1920,6 +1921,9 @@ static void tcg_reg_alloc_mov(TCGContext *s, const TCGOpDef *def,
|
||||
}
|
||||
ots->val_type = TEMP_VAL_CONST;
|
||||
ots->val = ts->val;
|
||||
if (IS_DEAD_ARG(1)) {
|
||||
temp_dead(s, args[1]);
|
||||
}
|
||||
} else {
|
||||
/* The code in the first if block should have moved the
|
||||
temp to a register. */
|
||||
|
||||
+2
-2
@@ -487,10 +487,10 @@ check-report-unit.xml: $(check-unit-y)
|
||||
# Reports and overall runs
|
||||
|
||||
check-report.xml: $(patsubst %,check-report-qtest-%.xml, $(QTEST_TARGETS)) check-report-unit.xml
|
||||
$(call quiet-command,$(SRC_PATH)/scripts/gtester-cat $^ > $@, " GEN $@")
|
||||
$(call quiet-command,$(SRC_PATH)/scripts/gtester-cat $^ > $@, " GEN $@")
|
||||
|
||||
check-report.html: check-report.xml
|
||||
$(call quiet-command,gtester-report $< > $@, " GEN $@")
|
||||
$(call quiet-command,gtester-report $< > $@, " GEN $@")
|
||||
|
||||
|
||||
# Other tests
|
||||
|
||||
Executable
+54
@@ -0,0 +1,54 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Test VPC open of image with large Max Table Entries value.
|
||||
#
|
||||
# Copyright (C) 2015 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=jcody@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 vpc
|
||||
_supported_proto generic
|
||||
_supported_os Linux
|
||||
|
||||
_use_sample_img afl5.img.bz2
|
||||
|
||||
echo
|
||||
echo "=== Verify image open and failure ===="
|
||||
$QEMU_IMG info "$TEST_IMG" 2>&1| _filter_testdir
|
||||
|
||||
# success, all done
|
||||
echo "*** done"
|
||||
rm -f $seq.full
|
||||
status=0
|
||||
Loaded 100 of 110 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user