Compare commits
157 Commits
pull-ui-20
...
pull-input
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
378af96155 | ||
|
|
ed6f72b827 | ||
|
|
ad584d37f2 | ||
|
|
65c9d60a3a | ||
|
|
7a37b59f1d | ||
|
|
f47291b7a7 | ||
|
|
c86f106b85 | ||
|
|
d187e08dc4 | ||
| d9e73d32a8 | |||
|
|
3741c2503b | ||
|
|
a721f53b8f | ||
|
|
21992cb679 | ||
|
|
1e06262da6 | ||
|
|
26920a2961 | ||
|
|
35f2fd04ce | ||
|
|
40c80b5e9e | ||
|
|
23d208ce6d | ||
|
|
3148ff8404 | ||
|
|
41eeb0e601 | ||
|
|
4515e58d60 | ||
|
|
a42cf3f3f2 | ||
|
|
209b71b60e | ||
|
|
a70fe14b7d | ||
|
|
43d70ddf9f | ||
|
|
d9ff1d35c5 | ||
|
|
544177ad1c | ||
|
|
2d76e82395 | ||
|
|
1c64fdbc81 | ||
|
|
f65e821262 | ||
|
|
b0a335e351 | ||
|
|
a3fd46152e | ||
|
|
b7a4104b73 | ||
|
|
8d5516be12 | ||
|
|
c6fcb0e201 | ||
|
|
ca5266de6c | ||
|
|
4154c7e03f | ||
|
|
81f17e0d43 | ||
|
|
a935cc3132 | ||
|
|
e514fc7e12 | ||
|
|
a2dbe1356f | ||
|
|
a1488b8661 | ||
|
|
2640077527 | ||
|
|
77c6850fd7 | ||
|
|
fea243e90a | ||
|
|
6cde51769e | ||
|
|
5fbf66e6a1 | ||
|
|
b9a0be9239 | ||
|
|
5dae13cd71 | ||
|
|
6597c28d61 | ||
|
|
a01deb36a6 | ||
|
|
24c328521b | ||
|
|
a8000cb480 | ||
|
|
762e22edcd | ||
|
|
cc5de49ebe | ||
|
|
6f7332ba71 | ||
|
|
24fc5c0feb | ||
|
|
20dc52a37c | ||
|
|
9fba702bd4 | ||
|
|
784696d119 | ||
|
|
9745807191 | ||
|
|
84775c43f3 | ||
|
|
cf2ae4428f | ||
|
|
0c53d7342b | ||
|
|
9ecaa27e71 | ||
|
|
6da544a6c4 | ||
|
|
111ece5133 | ||
|
|
930c3d0074 | ||
|
|
c56e3b8670 | ||
|
|
c40413a65e | ||
|
|
a0adc417a0 | ||
|
|
ab90233855 | ||
|
|
4a09d0bb34 | ||
|
|
ec7a9bd5bb | ||
|
|
982b78c5e3 | ||
|
|
5c379d9031 | ||
|
|
bcf4513129 | ||
|
|
b5b5c56957 | ||
|
|
a8664ba510 | ||
|
|
c937b9a6db | ||
|
|
479125d53e | ||
|
|
59046ec29a | ||
|
|
0827b9e97d | ||
|
|
ced1c6166e | ||
|
|
53f09a1076 | ||
|
|
9eb1476610 | ||
|
|
cee887d969 | ||
|
|
c77a6c8dd7 | ||
|
|
305e6c8a2f | ||
|
|
6eab3544f4 | ||
|
|
20f8a1392f | ||
|
|
df96bfab49 | ||
|
|
0b4384d0bb | ||
|
|
ed3d90df7c | ||
|
|
10d6eda192 | ||
|
|
8b3c679228 | ||
|
|
3026c4688c | ||
|
|
7061a07898 | ||
|
|
bf68bcb18e | ||
|
|
b4a2caa4bd | ||
|
|
b7aa131519 | ||
|
|
f67409a5bb | ||
|
|
8d20abe87a | ||
|
|
16e977d506 | ||
|
|
a6baa60807 | ||
|
|
20a6d768f5 | ||
|
|
256e3b6387 | ||
|
|
846a1d118e | ||
|
|
418661e032 | ||
|
|
4545d4f4af | ||
|
|
36bd422812 | ||
|
|
53b63460f6 | ||
|
|
9adceb0213 | ||
|
|
6b33f3ae8b | ||
|
|
b135233b0d | ||
|
|
e197de50c6 | ||
|
|
f23363ea44 | ||
|
|
ac2a9862b7 | ||
|
|
6311b19b5c | ||
|
|
98b2faeaee | ||
|
|
b4cc583f02 | ||
|
|
1a6d4fc27d | ||
|
|
93bf276d5f | ||
|
|
0c7209bee8 | ||
|
|
14efdb5cb3 | ||
|
|
3b5c492b1c | ||
|
|
76266d9913 | ||
|
|
054bb7b215 | ||
|
|
d6f02ce3b8 | ||
|
|
e6ec54571e | ||
|
|
fdb8665672 | ||
|
|
6b0407805d | ||
|
|
98cb5dccb1 | ||
|
|
12e97ec399 | ||
|
|
95280c31cd | ||
|
|
ec87f206d7 | ||
|
|
cf7dabeebc | ||
|
|
5e8e3c4c75 | ||
|
|
dd248ed7e2 | ||
|
|
61eedf7aec | ||
|
|
33d076ebd0 | ||
|
|
78a22af040 | ||
|
|
fed5364971 | ||
|
|
8b1897725d | ||
|
|
f073cd3a2b | ||
|
|
aecfbbc97a | ||
|
|
f5095aa380 | ||
|
|
394c8bbfb7 | ||
|
|
9bb6558a21 | ||
|
|
63f26fcfda | ||
|
|
4061200059 | ||
|
|
f7478a92dd | ||
|
|
3a062d5730 | ||
|
|
00909b5858 | ||
|
|
42922105be | ||
|
|
013befe1ca | ||
|
|
854123bf8d | ||
|
|
26d3202207 |
39
.travis.yml
39
.travis.yml
@@ -92,8 +92,8 @@ matrix:
|
||||
- env: CONFIG=""
|
||||
os: osx
|
||||
compiler: clang
|
||||
# Plain Trusty Build
|
||||
- env: CONFIG=""
|
||||
# Plain Trusty System Build
|
||||
- env: CONFIG="--disable-linux-user"
|
||||
sudo: required
|
||||
addons:
|
||||
dist: trusty
|
||||
@@ -103,16 +103,45 @@ matrix:
|
||||
- sudo apt-get build-dep -qq qemu
|
||||
- wget -O - http://people.linaro.org/~alex.bennee/qemu-submodule-git-seed.tar.xz | tar -xvJ
|
||||
- git submodule update --init --recursive
|
||||
# Trusty build with latest stable clang
|
||||
- env: CONFIG=""
|
||||
# Plain Trusty Linux User Build
|
||||
- env: CONFIG="--disable-system"
|
||||
sudo: required
|
||||
addons:
|
||||
dist: trusty
|
||||
compiler: gcc
|
||||
before_install:
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get build-dep -qq qemu
|
||||
- wget -O - http://people.linaro.org/~alex.bennee/qemu-submodule-git-seed.tar.xz | tar -xvJ
|
||||
- git submodule update --init --recursive
|
||||
# Trusty System build with latest stable clang
|
||||
- sudo: required
|
||||
addons:
|
||||
dist: trusty
|
||||
language: generic
|
||||
compiler: none
|
||||
env:
|
||||
- COMPILER_NAME=clang CXX=clang++-3.9 CC=clang-3.9
|
||||
- CONFIG="--cc=clang-3.9 --cxx=clang++-3.9"
|
||||
- CONFIG="--disable-linux-user --cc=clang-3.9 --cxx=clang++-3.9"
|
||||
before_install:
|
||||
- wget -nv -O - http://llvm.org/apt/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||
- sudo apt-add-repository -y 'deb http://llvm.org/apt/trusty llvm-toolchain-trusty-3.9 main'
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -qq -y clang-3.9
|
||||
- sudo apt-get build-dep -qq qemu
|
||||
- wget -O - http://people.linaro.org/~alex.bennee/qemu-submodule-git-seed.tar.xz | tar -xvJ
|
||||
- git submodule update --init --recursive
|
||||
before_script:
|
||||
- ./configure ${CONFIG} || cat config.log
|
||||
# Trusty Linux User build with latest stable clang
|
||||
- sudo: required
|
||||
addons:
|
||||
dist: trusty
|
||||
language: generic
|
||||
compiler: none
|
||||
env:
|
||||
- COMPILER_NAME=clang CXX=clang++-3.9 CC=clang-3.9
|
||||
- CONFIG="--disable-system --cc=clang-3.9 --cxx=clang++-3.9"
|
||||
before_install:
|
||||
- wget -nv -O - http://llvm.org/apt/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||
- sudo apt-add-repository -y 'deb http://llvm.org/apt/trusty llvm-toolchain-trusty-3.9 main'
|
||||
|
||||
@@ -1034,7 +1034,7 @@ F: hw/input/virtio-input*.c
|
||||
F: include/hw/virtio/virtio-input.h
|
||||
|
||||
virtio-serial
|
||||
M: Amit Shah <amit.shah@redhat.com>
|
||||
M: Amit Shah <amit@kernel.org>
|
||||
S: Supported
|
||||
F: hw/char/virtio-serial-bus.c
|
||||
F: hw/char/virtio-console.c
|
||||
@@ -1043,7 +1043,7 @@ F: tests/virtio-console-test.c
|
||||
F: tests/virtio-serial-test.c
|
||||
|
||||
virtio-rng
|
||||
M: Amit Shah <amit.shah@redhat.com>
|
||||
M: Amit Shah <amit@kernel.org>
|
||||
S: Supported
|
||||
F: hw/virtio/virtio-rng.c
|
||||
F: include/hw/virtio/virtio-rng.h
|
||||
@@ -1431,7 +1431,6 @@ F: scripts/checkpatch.pl
|
||||
|
||||
Migration
|
||||
M: Juan Quintela <quintela@redhat.com>
|
||||
M: Amit Shah <amit.shah@redhat.com>
|
||||
M: Dr. David Alan Gilbert <dgilbert@redhat.com>
|
||||
S: Maintained
|
||||
F: include/migration/
|
||||
|
||||
8
Makefile
8
Makefile
@@ -299,7 +299,11 @@ qemu-version.h: FORCE
|
||||
printf '""\n'; \
|
||||
fi; \
|
||||
fi) > $@.tmp)
|
||||
$(call quiet-command, cmp -s $@ $@.tmp || mv $@.tmp $@)
|
||||
$(call quiet-command, if ! cmp -s $@ $@.tmp; then \
|
||||
mv $@.tmp $@; \
|
||||
else \
|
||||
rm $@.tmp; \
|
||||
fi)
|
||||
|
||||
config-host.h: config-host.h-timestamp
|
||||
config-host.h-timestamp: config-host.mak
|
||||
@@ -589,7 +593,7 @@ endif
|
||||
endif
|
||||
|
||||
|
||||
install: all $(if $(BUILD_DOCS),install-doc) \
|
||||
install: all $(if $(BUILD_DOCS),install-doc) $(BUILD_DIR)/trace-events-all \
|
||||
install-datadir install-localstatedir
|
||||
ifneq ($(TOOLS),)
|
||||
$(call install-prog,$(subst qemu-ga,qemu-ga$(EXESUF),$(TOOLS)),$(DESTDIR)$(bindir))
|
||||
|
||||
@@ -125,6 +125,7 @@ trace-events-subdirs += crypto
|
||||
trace-events-subdirs += io
|
||||
trace-events-subdirs += migration
|
||||
trace-events-subdirs += block
|
||||
trace-events-subdirs += backends
|
||||
trace-events-subdirs += hw/block
|
||||
trace-events-subdirs += hw/block/dataplane
|
||||
trace-events-subdirs += hw/char
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
common-obj-y += rng.o rng-egd.o
|
||||
common-obj-$(CONFIG_POSIX) += rng-random.o
|
||||
|
||||
common-obj-y += msmouse.o testdev.o
|
||||
common-obj-y += msmouse.o wctablet.o testdev.o
|
||||
common-obj-$(CONFIG_BRLAPI) += baum.o
|
||||
baum.o-cflags := $(SDL_CFLAGS)
|
||||
|
||||
|
||||
10
backends/trace-events
Normal file
10
backends/trace-events
Normal file
@@ -0,0 +1,10 @@
|
||||
# See docs/tracing.txt for syntax documentation.
|
||||
|
||||
# backends/wctablet.c
|
||||
wct_init(void) ""
|
||||
wct_cmd_re(void) ""
|
||||
wct_cmd_st(void) ""
|
||||
wct_cmd_sp(void) ""
|
||||
wct_cmd_ts(int input) "0x%02x"
|
||||
wct_cmd_other(const char *cmd) "%s"
|
||||
wct_speed(int speed) "%d"
|
||||
369
backends/wctablet.c
Normal file
369
backends/wctablet.c
Normal file
@@ -0,0 +1,369 @@
|
||||
/*
|
||||
* QEMU Wacom Penpartner serial tablet emulation
|
||||
*
|
||||
* some protocol details:
|
||||
* http://linuxwacom.sourceforge.net/wiki/index.php/Serial_Protocol_IV
|
||||
*
|
||||
* Copyright (c) 2016 Anatoli Huseu1
|
||||
* Copyright (c) 2016,17 Gerd Hoffmann
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "sysemu/char.h"
|
||||
#include "ui/console.h"
|
||||
#include "ui/input.h"
|
||||
#include "trace.h"
|
||||
|
||||
|
||||
#define WC_OUTPUT_BUF_MAX_LEN 512
|
||||
#define WC_COMMAND_MAX_LEN 60
|
||||
|
||||
#define WC_L7(n) ((n) & 127)
|
||||
#define WC_M7(n) (((n) >> 7) & 127)
|
||||
#define WC_H2(n) ((n) >> 14)
|
||||
|
||||
#define WC_L4(n) ((n) & 15)
|
||||
#define WC_H4(n) (((n) >> 4) & 15)
|
||||
|
||||
/* Model string and config string */
|
||||
#define WC_MODEL_STRING_LENGTH 18
|
||||
uint8_t WC_MODEL_STRING[WC_MODEL_STRING_LENGTH + 1] = "~#CT-0045R,V1.3-5,";
|
||||
|
||||
#define WC_CONFIG_STRING_LENGTH 8
|
||||
uint8_t WC_CONFIG_STRING[WC_CONFIG_STRING_LENGTH + 1] = "96,N,8,0";
|
||||
|
||||
#define WC_FULL_CONFIG_STRING_LENGTH 61
|
||||
uint8_t WC_FULL_CONFIG_STRING[WC_FULL_CONFIG_STRING_LENGTH + 1] = {
|
||||
0x5c, 0x39, 0x36, 0x2c, 0x4e, 0x2c, 0x38, 0x2c,
|
||||
0x31, 0x28, 0x01, 0x24, 0x57, 0x41, 0x43, 0x30,
|
||||
0x30, 0x34, 0x35, 0x5c, 0x5c, 0x50, 0x45, 0x4e, 0x5c,
|
||||
0x57, 0x41, 0x43, 0x30, 0x30, 0x30, 0x30, 0x5c,
|
||||
0x54, 0x61, 0x62, 0x6c, 0x65, 0x74, 0x0d, 0x0a,
|
||||
0x43, 0x54, 0x2d, 0x30, 0x30, 0x34, 0x35, 0x52,
|
||||
0x2c, 0x56, 0x31, 0x2e, 0x33, 0x2d, 0x35, 0x0d,
|
||||
0x0a, 0x45, 0x37, 0x29
|
||||
};
|
||||
|
||||
/* This structure is used to save private info for Wacom Tablet. */
|
||||
typedef struct {
|
||||
Chardev parent;
|
||||
QemuInputHandlerState *hs;
|
||||
|
||||
/* Query string from serial */
|
||||
uint8_t query[100];
|
||||
int query_index;
|
||||
|
||||
/* Command to be sent to serial port */
|
||||
uint8_t outbuf[WC_OUTPUT_BUF_MAX_LEN];
|
||||
int outlen;
|
||||
|
||||
int line_speed;
|
||||
bool send_events;
|
||||
int axis[INPUT_AXIS__MAX];
|
||||
bool btns[INPUT_BUTTON__MAX];
|
||||
|
||||
} TabletChardev;
|
||||
|
||||
#define TYPE_CHARDEV_WCTABLET "chardev-wctablet"
|
||||
#define WCTABLET_CHARDEV(obj) \
|
||||
OBJECT_CHECK(TabletChardev, (obj), TYPE_CHARDEV_WCTABLET)
|
||||
|
||||
|
||||
static void wctablet_chr_accept_input(Chardev *chr);
|
||||
|
||||
static void wctablet_shift_input(TabletChardev *tablet, int count)
|
||||
{
|
||||
tablet->query_index -= count;
|
||||
memmove(tablet->query, tablet->query + count, tablet->query_index);
|
||||
tablet->query[tablet->query_index] = 0;
|
||||
}
|
||||
|
||||
static void wctablet_queue_output(TabletChardev *tablet, uint8_t *buf, int count)
|
||||
{
|
||||
if (tablet->outlen + count > sizeof(tablet->outbuf)) {
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(tablet->outbuf + tablet->outlen, buf, count);
|
||||
tablet->outlen += count;
|
||||
wctablet_chr_accept_input(CHARDEV(tablet));
|
||||
}
|
||||
|
||||
static void wctablet_reset(TabletChardev *tablet)
|
||||
{
|
||||
/* clear buffers */
|
||||
tablet->query_index = 0;
|
||||
tablet->outlen = 0;
|
||||
/* reset state */
|
||||
tablet->send_events = false;
|
||||
}
|
||||
|
||||
static void wctablet_queue_event(TabletChardev *tablet)
|
||||
{
|
||||
uint8_t codes[8] = { 0xe0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
if (tablet->line_speed != 9600) {
|
||||
return;
|
||||
}
|
||||
|
||||
int newX = tablet->axis[INPUT_AXIS_X] * 0.1537;
|
||||
int nexY = tablet->axis[INPUT_AXIS_Y] * 0.1152;
|
||||
|
||||
codes[0] = codes[0] | WC_H2(newX);
|
||||
codes[1] = codes[1] | WC_M7(newX);
|
||||
codes[2] = codes[2] | WC_L7(newX);
|
||||
|
||||
codes[3] = codes[3] | WC_H2(nexY);
|
||||
codes[4] = codes[4] | WC_M7(nexY);
|
||||
codes[5] = codes[5] | WC_L7(nexY);
|
||||
|
||||
if (tablet->btns[INPUT_BUTTON_LEFT]) {
|
||||
codes[0] = 0xa0;
|
||||
}
|
||||
|
||||
wctablet_queue_output(tablet, codes, 7);
|
||||
}
|
||||
|
||||
static void wctablet_input_event(DeviceState *dev, QemuConsole *src,
|
||||
InputEvent *evt)
|
||||
{
|
||||
TabletChardev *tablet = (TabletChardev *)dev;
|
||||
InputMoveEvent *move;
|
||||
InputBtnEvent *btn;
|
||||
|
||||
switch (evt->type) {
|
||||
case INPUT_EVENT_KIND_ABS:
|
||||
move = evt->u.abs.data;
|
||||
tablet->axis[move->axis] = move->value;
|
||||
break;
|
||||
|
||||
case INPUT_EVENT_KIND_BTN:
|
||||
btn = evt->u.btn.data;
|
||||
tablet->btns[btn->button] = btn->down;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* keep gcc happy */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void wctablet_input_sync(DeviceState *dev)
|
||||
{
|
||||
TabletChardev *tablet = (TabletChardev *)dev;
|
||||
|
||||
if (tablet->send_events) {
|
||||
wctablet_queue_event(tablet);
|
||||
}
|
||||
}
|
||||
|
||||
static QemuInputHandler wctablet_handler = {
|
||||
.name = "QEMU Wacome Pen Tablet",
|
||||
.mask = INPUT_EVENT_MASK_BTN | INPUT_EVENT_MASK_ABS,
|
||||
.event = wctablet_input_event,
|
||||
.sync = wctablet_input_sync,
|
||||
};
|
||||
|
||||
static void wctablet_chr_accept_input(Chardev *chr)
|
||||
{
|
||||
TabletChardev *tablet = WCTABLET_CHARDEV(chr);
|
||||
int len, canWrite;
|
||||
|
||||
canWrite = qemu_chr_be_can_write(chr);
|
||||
len = canWrite;
|
||||
if (len > tablet->outlen) {
|
||||
len = tablet->outlen;
|
||||
}
|
||||
|
||||
if (len) {
|
||||
qemu_chr_be_write(chr, tablet->outbuf, len);
|
||||
tablet->outlen -= len;
|
||||
if (tablet->outlen) {
|
||||
memmove(tablet->outbuf, tablet->outbuf + len, tablet->outlen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int wctablet_chr_write(struct Chardev *chr,
|
||||
const uint8_t *buf, int len)
|
||||
{
|
||||
TabletChardev *tablet = WCTABLET_CHARDEV(chr);
|
||||
unsigned int i, clen;
|
||||
char *pos;
|
||||
|
||||
if (tablet->line_speed != 9600) {
|
||||
return len;
|
||||
}
|
||||
for (i = 0; i < len && tablet->query_index < sizeof(tablet->query) - 1; i++) {
|
||||
tablet->query[tablet->query_index++] = buf[i];
|
||||
}
|
||||
tablet->query[tablet->query_index] = 0;
|
||||
|
||||
while (tablet->query_index > 0 && (tablet->query[0] == '@' ||
|
||||
tablet->query[0] == '\r' ||
|
||||
tablet->query[0] == '\n')) {
|
||||
wctablet_shift_input(tablet, 1);
|
||||
}
|
||||
if (!tablet->query_index) {
|
||||
return len;
|
||||
}
|
||||
|
||||
if (strncmp((char *)tablet->query, "~#", 2) == 0) {
|
||||
/* init / detect sequence */
|
||||
trace_wct_init();
|
||||
wctablet_shift_input(tablet, 2);
|
||||
wctablet_queue_output(tablet, WC_MODEL_STRING,
|
||||
WC_MODEL_STRING_LENGTH);
|
||||
return len;
|
||||
}
|
||||
|
||||
/* detect line */
|
||||
pos = strchr((char *)tablet->query, '\r');
|
||||
if (!pos) {
|
||||
pos = strchr((char *)tablet->query, '\n');
|
||||
}
|
||||
if (!pos) {
|
||||
return len;
|
||||
}
|
||||
clen = pos - (char *)tablet->query;
|
||||
|
||||
/* process commands */
|
||||
if (strncmp((char *)tablet->query, "RE", 2) == 0 &&
|
||||
clen == 2) {
|
||||
trace_wct_cmd_re();
|
||||
wctablet_shift_input(tablet, 3);
|
||||
wctablet_queue_output(tablet, WC_CONFIG_STRING,
|
||||
WC_CONFIG_STRING_LENGTH);
|
||||
|
||||
} else if (strncmp((char *)tablet->query, "ST", 2) == 0 &&
|
||||
clen == 2) {
|
||||
trace_wct_cmd_st();
|
||||
wctablet_shift_input(tablet, 3);
|
||||
tablet->send_events = true;
|
||||
wctablet_queue_event(tablet);
|
||||
|
||||
} else if (strncmp((char *)tablet->query, "SP", 2) == 0 &&
|
||||
clen == 2) {
|
||||
trace_wct_cmd_sp();
|
||||
wctablet_shift_input(tablet, 3);
|
||||
tablet->send_events = false;
|
||||
|
||||
} else if (strncmp((char *)tablet->query, "TS", 2) == 0 &&
|
||||
clen == 3) {
|
||||
unsigned int input = tablet->query[2];
|
||||
uint8_t codes[7] = {
|
||||
0xa3,
|
||||
((input & 0x80) == 0) ? 0x7e : 0x7f,
|
||||
(((WC_H4(input) & 0x7) ^ 0x5) << 4) | (WC_L4(input) ^ 0x7),
|
||||
0x03,
|
||||
0x7f,
|
||||
0x7f,
|
||||
0x00,
|
||||
};
|
||||
trace_wct_cmd_ts(input);
|
||||
wctablet_shift_input(tablet, 4);
|
||||
wctablet_queue_output(tablet, codes, 7);
|
||||
|
||||
} else {
|
||||
tablet->query[clen] = 0; /* terminate line for printing */
|
||||
trace_wct_cmd_other((char *)tablet->query);
|
||||
wctablet_shift_input(tablet, clen + 1);
|
||||
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int wctablet_chr_ioctl(Chardev *chr, int cmd, void *arg)
|
||||
{
|
||||
TabletChardev *tablet = WCTABLET_CHARDEV(chr);
|
||||
QEMUSerialSetParams *ssp;
|
||||
|
||||
switch (cmd) {
|
||||
case CHR_IOCTL_SERIAL_SET_PARAMS:
|
||||
ssp = arg;
|
||||
if (tablet->line_speed != ssp->speed) {
|
||||
trace_wct_speed(ssp->speed);
|
||||
wctablet_reset(tablet);
|
||||
tablet->line_speed = ssp->speed;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wctablet_chr_finalize(Object *obj)
|
||||
{
|
||||
TabletChardev *tablet = WCTABLET_CHARDEV(obj);
|
||||
|
||||
qemu_input_handler_unregister(tablet->hs);
|
||||
g_free(tablet);
|
||||
}
|
||||
|
||||
static void wctablet_chr_open(Chardev *chr,
|
||||
ChardevBackend *backend,
|
||||
bool *be_opened,
|
||||
Error **errp)
|
||||
{
|
||||
TabletChardev *tablet = WCTABLET_CHARDEV(chr);
|
||||
|
||||
*be_opened = true;
|
||||
|
||||
/* init state machine */
|
||||
memcpy(tablet->outbuf, WC_FULL_CONFIG_STRING, WC_FULL_CONFIG_STRING_LENGTH);
|
||||
tablet->outlen = WC_FULL_CONFIG_STRING_LENGTH;
|
||||
tablet->query_index = 0;
|
||||
|
||||
tablet->hs = qemu_input_handler_register((DeviceState *)tablet,
|
||||
&wctablet_handler);
|
||||
}
|
||||
|
||||
static void wctablet_chr_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
ChardevClass *cc = CHARDEV_CLASS(oc);
|
||||
|
||||
cc->open = wctablet_chr_open;
|
||||
cc->chr_write = wctablet_chr_write;
|
||||
cc->chr_ioctl = wctablet_chr_ioctl;
|
||||
cc->chr_accept_input = wctablet_chr_accept_input;
|
||||
}
|
||||
|
||||
static const TypeInfo wctablet_type_info = {
|
||||
.name = TYPE_CHARDEV_WCTABLET,
|
||||
.parent = TYPE_CHARDEV,
|
||||
.instance_size = sizeof(TabletChardev),
|
||||
.instance_finalize = wctablet_chr_finalize,
|
||||
.class_init = wctablet_chr_class_init,
|
||||
};
|
||||
|
||||
static void register_types(void)
|
||||
{
|
||||
type_register_static(&wctablet_type_info);
|
||||
}
|
||||
|
||||
type_init(register_types);
|
||||
24
block.c
24
block.c
@@ -3145,6 +3145,7 @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
|
||||
int is_protocol = 0;
|
||||
BlockDriverState *curr_bs = NULL;
|
||||
BlockDriverState *retval = NULL;
|
||||
Error *local_error = NULL;
|
||||
|
||||
if (!bs || !bs->drv || !backing_file) {
|
||||
return NULL;
|
||||
@@ -3165,6 +3166,18 @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
|
||||
retval = curr_bs->backing->bs;
|
||||
break;
|
||||
}
|
||||
/* Also check against the full backing filename for the image */
|
||||
bdrv_get_full_backing_filename(curr_bs, backing_file_full, PATH_MAX,
|
||||
&local_error);
|
||||
if (local_error == NULL) {
|
||||
if (strcmp(backing_file, backing_file_full) == 0) {
|
||||
retval = curr_bs->backing->bs;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
error_free(local_error);
|
||||
local_error = NULL;
|
||||
}
|
||||
} else {
|
||||
/* If not an absolute filename path, make it relative to the current
|
||||
* image's filename path */
|
||||
@@ -3235,19 +3248,18 @@ void bdrv_invalidate_cache(BlockDriverState *bs, Error **errp)
|
||||
if (!(bs->open_flags & BDRV_O_INACTIVE)) {
|
||||
return;
|
||||
}
|
||||
bs->open_flags &= ~BDRV_O_INACTIVE;
|
||||
|
||||
if (bs->drv->bdrv_invalidate_cache) {
|
||||
bs->drv->bdrv_invalidate_cache(bs, &local_err);
|
||||
QLIST_FOREACH(child, &bs->children, next) {
|
||||
bdrv_invalidate_cache(child->bs, &local_err);
|
||||
if (local_err) {
|
||||
bs->open_flags |= BDRV_O_INACTIVE;
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
QLIST_FOREACH(child, &bs->children, next) {
|
||||
bdrv_invalidate_cache(child->bs, &local_err);
|
||||
bs->open_flags &= ~BDRV_O_INACTIVE;
|
||||
if (bs->drv->bdrv_invalidate_cache) {
|
||||
bs->drv->bdrv_invalidate_cache(bs, &local_err);
|
||||
if (local_err) {
|
||||
bs->open_flags |= BDRV_O_INACTIVE;
|
||||
error_propagate(errp, local_err);
|
||||
|
||||
49
block/nfs.c
49
block/nfs.c
@@ -108,12 +108,13 @@ static int nfs_parse_uri(const char *filename, QDict *options, Error **errp)
|
||||
qdict_put(options, "path", qstring_from_str(uri->path));
|
||||
|
||||
for (i = 0; i < qp->n; i++) {
|
||||
unsigned long long val;
|
||||
if (!qp->p[i].value) {
|
||||
error_setg(errp, "Value for NFS parameter expected: %s",
|
||||
qp->p[i].name);
|
||||
goto out;
|
||||
}
|
||||
if (parse_uint_full(qp->p[i].value, NULL, 0)) {
|
||||
if (parse_uint_full(qp->p[i].value, &val, 0)) {
|
||||
error_setg(errp, "Illegal value for NFS parameter: %s",
|
||||
qp->p[i].name);
|
||||
goto out;
|
||||
@@ -358,27 +359,27 @@ static QemuOptsList runtime_opts = {
|
||||
.help = "Path of the image on the host",
|
||||
},
|
||||
{
|
||||
.name = "uid",
|
||||
.name = "user",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
.help = "UID value to use when talking to the server",
|
||||
},
|
||||
{
|
||||
.name = "gid",
|
||||
.name = "group",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
.help = "GID value to use when talking to the server",
|
||||
},
|
||||
{
|
||||
.name = "tcp-syncnt",
|
||||
.name = "tcp-syn-count",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
.help = "Number of SYNs to send during the session establish",
|
||||
},
|
||||
{
|
||||
.name = "readahead",
|
||||
.name = "readahead-size",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
.help = "Set the readahead size in bytes",
|
||||
},
|
||||
{
|
||||
.name = "pagecache",
|
||||
.name = "page-cache-size",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
.help = "Set the pagecache size in bytes",
|
||||
},
|
||||
@@ -507,29 +508,29 @@ static int64_t nfs_client_open(NFSClient *client, QDict *options,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (qemu_opt_get(opts, "uid")) {
|
||||
client->uid = qemu_opt_get_number(opts, "uid", 0);
|
||||
if (qemu_opt_get(opts, "user")) {
|
||||
client->uid = qemu_opt_get_number(opts, "user", 0);
|
||||
nfs_set_uid(client->context, client->uid);
|
||||
}
|
||||
|
||||
if (qemu_opt_get(opts, "gid")) {
|
||||
client->gid = qemu_opt_get_number(opts, "gid", 0);
|
||||
if (qemu_opt_get(opts, "group")) {
|
||||
client->gid = qemu_opt_get_number(opts, "group", 0);
|
||||
nfs_set_gid(client->context, client->gid);
|
||||
}
|
||||
|
||||
if (qemu_opt_get(opts, "tcp-syncnt")) {
|
||||
client->tcp_syncnt = qemu_opt_get_number(opts, "tcp-syncnt", 0);
|
||||
if (qemu_opt_get(opts, "tcp-syn-count")) {
|
||||
client->tcp_syncnt = qemu_opt_get_number(opts, "tcp-syn-count", 0);
|
||||
nfs_set_tcp_syncnt(client->context, client->tcp_syncnt);
|
||||
}
|
||||
|
||||
#ifdef LIBNFS_FEATURE_READAHEAD
|
||||
if (qemu_opt_get(opts, "readahead")) {
|
||||
if (qemu_opt_get(opts, "readahead-size")) {
|
||||
if (open_flags & BDRV_O_NOCACHE) {
|
||||
error_setg(errp, "Cannot enable NFS readahead "
|
||||
"if cache.direct = on");
|
||||
goto fail;
|
||||
}
|
||||
client->readahead = qemu_opt_get_number(opts, "readahead", 0);
|
||||
client->readahead = qemu_opt_get_number(opts, "readahead-size", 0);
|
||||
if (client->readahead > QEMU_NFS_MAX_READAHEAD_SIZE) {
|
||||
error_report("NFS Warning: Truncating NFS readahead "
|
||||
"size to %d", QEMU_NFS_MAX_READAHEAD_SIZE);
|
||||
@@ -544,13 +545,13 @@ static int64_t nfs_client_open(NFSClient *client, QDict *options,
|
||||
#endif
|
||||
|
||||
#ifdef LIBNFS_FEATURE_PAGECACHE
|
||||
if (qemu_opt_get(opts, "pagecache")) {
|
||||
if (qemu_opt_get(opts, "page-cache-size")) {
|
||||
if (open_flags & BDRV_O_NOCACHE) {
|
||||
error_setg(errp, "Cannot enable NFS pagecache "
|
||||
"if cache.direct = on");
|
||||
goto fail;
|
||||
}
|
||||
client->pagecache = qemu_opt_get_number(opts, "pagecache", 0);
|
||||
client->pagecache = qemu_opt_get_number(opts, "page-cache-size", 0);
|
||||
if (client->pagecache > QEMU_NFS_MAX_PAGECACHE_SIZE) {
|
||||
error_report("NFS Warning: Truncating NFS pagecache "
|
||||
"size to %d pages", QEMU_NFS_MAX_PAGECACHE_SIZE);
|
||||
@@ -803,22 +804,22 @@ static void nfs_refresh_filename(BlockDriverState *bs, QDict *options)
|
||||
qdict_put(opts, "path", qstring_from_str(client->path));
|
||||
|
||||
if (client->uid) {
|
||||
qdict_put(opts, "uid", qint_from_int(client->uid));
|
||||
qdict_put(opts, "user", qint_from_int(client->uid));
|
||||
}
|
||||
if (client->gid) {
|
||||
qdict_put(opts, "gid", qint_from_int(client->gid));
|
||||
qdict_put(opts, "group", qint_from_int(client->gid));
|
||||
}
|
||||
if (client->tcp_syncnt) {
|
||||
qdict_put(opts, "tcp-syncnt",
|
||||
qint_from_int(client->tcp_syncnt));
|
||||
qdict_put(opts, "tcp-syn-cnt",
|
||||
qint_from_int(client->tcp_syncnt));
|
||||
}
|
||||
if (client->readahead) {
|
||||
qdict_put(opts, "readahead",
|
||||
qint_from_int(client->readahead));
|
||||
qdict_put(opts, "readahead-size",
|
||||
qint_from_int(client->readahead));
|
||||
}
|
||||
if (client->pagecache) {
|
||||
qdict_put(opts, "pagecache",
|
||||
qint_from_int(client->pagecache));
|
||||
qdict_put(opts, "page-cache-size",
|
||||
qint_from_int(client->pagecache));
|
||||
}
|
||||
if (client->debug) {
|
||||
qdict_put(opts, "debug", qint_from_int(client->debug));
|
||||
|
||||
97
block/qapi.c
97
block/qapi.c
@@ -237,8 +237,8 @@ void bdrv_query_image_info(BlockDriverState *bs,
|
||||
|
||||
size = bdrv_getlength(bs);
|
||||
if (size < 0) {
|
||||
error_setg_errno(errp, -size, "Can't get size of device '%s'",
|
||||
bdrv_get_device_name(bs));
|
||||
error_setg_errno(errp, -size, "Can't get image size '%s'",
|
||||
bs->exact_filename);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -357,10 +357,6 @@ static void bdrv_query_info(BlockBackend *blk, BlockInfo **p_info,
|
||||
qapi_free_BlockInfo(info);
|
||||
}
|
||||
|
||||
static BlockStats *bdrv_query_stats(BlockBackend *blk,
|
||||
const BlockDriverState *bs,
|
||||
bool query_backing);
|
||||
|
||||
static void bdrv_query_blk_stats(BlockDeviceStats *ds, BlockBackend *blk)
|
||||
{
|
||||
BlockAcctStats *stats = blk_get_stats(blk);
|
||||
@@ -428,9 +424,18 @@ static void bdrv_query_blk_stats(BlockDeviceStats *ds, BlockBackend *blk)
|
||||
}
|
||||
}
|
||||
|
||||
static void bdrv_query_bds_stats(BlockStats *s, const BlockDriverState *bs,
|
||||
static BlockStats *bdrv_query_bds_stats(const BlockDriverState *bs,
|
||||
bool query_backing)
|
||||
{
|
||||
BlockStats *s = NULL;
|
||||
|
||||
s = g_malloc0(sizeof(*s));
|
||||
s->stats = g_malloc0(sizeof(*s->stats));
|
||||
|
||||
if (!bs) {
|
||||
return s;
|
||||
}
|
||||
|
||||
if (bdrv_get_node_name(bs)[0]) {
|
||||
s->has_node_name = true;
|
||||
s->node_name = g_strdup(bdrv_get_node_name(bs));
|
||||
@@ -440,32 +445,12 @@ static void bdrv_query_bds_stats(BlockStats *s, const BlockDriverState *bs,
|
||||
|
||||
if (bs->file) {
|
||||
s->has_parent = true;
|
||||
s->parent = bdrv_query_stats(NULL, bs->file->bs, query_backing);
|
||||
s->parent = bdrv_query_bds_stats(bs->file->bs, query_backing);
|
||||
}
|
||||
|
||||
if (query_backing && bs->backing) {
|
||||
s->has_backing = true;
|
||||
s->backing = bdrv_query_stats(NULL, bs->backing->bs, query_backing);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static BlockStats *bdrv_query_stats(BlockBackend *blk,
|
||||
const BlockDriverState *bs,
|
||||
bool query_backing)
|
||||
{
|
||||
BlockStats *s;
|
||||
|
||||
s = g_malloc0(sizeof(*s));
|
||||
s->stats = g_malloc0(sizeof(*s->stats));
|
||||
|
||||
if (blk) {
|
||||
s->has_device = true;
|
||||
s->device = g_strdup(blk_name(blk));
|
||||
bdrv_query_blk_stats(s->stats, blk);
|
||||
}
|
||||
if (bs) {
|
||||
bdrv_query_bds_stats(s, bs, query_backing);
|
||||
s->backing = bdrv_query_bds_stats(bs->backing->bs, query_backing);
|
||||
}
|
||||
|
||||
return s;
|
||||
@@ -494,42 +479,44 @@ BlockInfoList *qmp_query_block(Error **errp)
|
||||
return head;
|
||||
}
|
||||
|
||||
static bool next_query_bds(BlockBackend **blk, BlockDriverState **bs,
|
||||
bool query_nodes)
|
||||
{
|
||||
if (query_nodes) {
|
||||
*bs = bdrv_next_node(*bs);
|
||||
return !!*bs;
|
||||
}
|
||||
|
||||
*blk = blk_next(*blk);
|
||||
*bs = *blk ? blk_bs(*blk) : NULL;
|
||||
|
||||
return !!*blk;
|
||||
}
|
||||
|
||||
BlockStatsList *qmp_query_blockstats(bool has_query_nodes,
|
||||
bool query_nodes,
|
||||
Error **errp)
|
||||
{
|
||||
BlockStatsList *head = NULL, **p_next = &head;
|
||||
BlockBackend *blk = NULL;
|
||||
BlockDriverState *bs = NULL;
|
||||
BlockBackend *blk;
|
||||
BlockDriverState *bs;
|
||||
|
||||
/* Just to be safe if query_nodes is not always initialized */
|
||||
query_nodes = has_query_nodes && query_nodes;
|
||||
if (has_query_nodes && query_nodes) {
|
||||
for (bs = bdrv_next_node(NULL); bs; bs = bdrv_next_node(bs)) {
|
||||
BlockStatsList *info = g_malloc0(sizeof(*info));
|
||||
AioContext *ctx = bdrv_get_aio_context(bs);
|
||||
|
||||
while (next_query_bds(&blk, &bs, query_nodes)) {
|
||||
BlockStatsList *info = g_malloc0(sizeof(*info));
|
||||
AioContext *ctx = blk ? blk_get_aio_context(blk)
|
||||
: bdrv_get_aio_context(bs);
|
||||
aio_context_acquire(ctx);
|
||||
info->value = bdrv_query_bds_stats(bs, false);
|
||||
aio_context_release(ctx);
|
||||
|
||||
aio_context_acquire(ctx);
|
||||
info->value = bdrv_query_stats(blk, bs, !query_nodes);
|
||||
aio_context_release(ctx);
|
||||
*p_next = info;
|
||||
p_next = &info->next;
|
||||
}
|
||||
} else {
|
||||
for (blk = blk_next(NULL); blk; blk = blk_next(blk)) {
|
||||
BlockStatsList *info = g_malloc0(sizeof(*info));
|
||||
AioContext *ctx = blk_get_aio_context(blk);
|
||||
BlockStats *s;
|
||||
|
||||
*p_next = info;
|
||||
p_next = &info->next;
|
||||
aio_context_acquire(ctx);
|
||||
s = bdrv_query_bds_stats(blk_bs(blk), true);
|
||||
s->has_device = true;
|
||||
s->device = g_strdup(blk_name(blk));
|
||||
bdrv_query_blk_stats(s->stats, blk);
|
||||
aio_context_release(ctx);
|
||||
|
||||
info->value = s;
|
||||
*p_next = info;
|
||||
p_next = &info->next;
|
||||
}
|
||||
}
|
||||
|
||||
return head;
|
||||
|
||||
@@ -83,6 +83,16 @@ static Qcow2SetRefcountFunc *const set_refcount_funcs[] = {
|
||||
/*********************************************************/
|
||||
/* refcount handling */
|
||||
|
||||
static void update_max_refcount_table_index(BDRVQcow2State *s)
|
||||
{
|
||||
unsigned i = s->refcount_table_size - 1;
|
||||
while (i > 0 && (s->refcount_table[i] & REFT_OFFSET_MASK) == 0) {
|
||||
i--;
|
||||
}
|
||||
/* Set s->max_refcount_table_index to the index of the last used entry */
|
||||
s->max_refcount_table_index = i;
|
||||
}
|
||||
|
||||
int qcow2_refcount_init(BlockDriverState *bs)
|
||||
{
|
||||
BDRVQcow2State *s = bs->opaque;
|
||||
@@ -111,6 +121,7 @@ int qcow2_refcount_init(BlockDriverState *bs)
|
||||
}
|
||||
for(i = 0; i < s->refcount_table_size; i++)
|
||||
be64_to_cpus(&s->refcount_table[i]);
|
||||
update_max_refcount_table_index(s);
|
||||
}
|
||||
return 0;
|
||||
fail:
|
||||
@@ -439,6 +450,10 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
s->refcount_table[refcount_table_index] = new_block;
|
||||
/* If there's a hole in s->refcount_table then it can happen
|
||||
* that refcount_table_index < s->max_refcount_table_index */
|
||||
s->max_refcount_table_index =
|
||||
MAX(s->max_refcount_table_index, refcount_table_index);
|
||||
|
||||
/* The new refcount block may be where the caller intended to put its
|
||||
* data, so let it restart the search. */
|
||||
@@ -580,6 +595,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
||||
s->refcount_table = new_table;
|
||||
s->refcount_table_size = table_size;
|
||||
s->refcount_table_offset = table_offset;
|
||||
update_max_refcount_table_index(s);
|
||||
|
||||
/* Free old table. */
|
||||
qcow2_free_clusters(bs, old_table_offset, old_table_size * sizeof(uint64_t),
|
||||
@@ -2171,6 +2187,7 @@ write_refblocks:
|
||||
s->refcount_table = on_disk_reftable;
|
||||
s->refcount_table_offset = reftable_offset;
|
||||
s->refcount_table_size = reftable_size;
|
||||
update_max_refcount_table_index(s);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -2383,7 +2400,11 @@ int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset,
|
||||
}
|
||||
|
||||
if ((chk & QCOW2_OL_REFCOUNT_BLOCK) && s->refcount_table) {
|
||||
for (i = 0; i < s->refcount_table_size; i++) {
|
||||
unsigned last_entry = s->max_refcount_table_index;
|
||||
assert(last_entry < s->refcount_table_size);
|
||||
assert(last_entry + 1 == s->refcount_table_size ||
|
||||
(s->refcount_table[last_entry + 1] & REFT_OFFSET_MASK) == 0);
|
||||
for (i = 0; i <= last_entry; i++) {
|
||||
if ((s->refcount_table[i] & REFT_OFFSET_MASK) &&
|
||||
overlaps_with(s->refcount_table[i] & REFT_OFFSET_MASK,
|
||||
s->cluster_size)) {
|
||||
@@ -2871,6 +2892,7 @@ int qcow2_change_refcount_order(BlockDriverState *bs, int refcount_order,
|
||||
/* Now update the rest of the in-memory information */
|
||||
old_reftable = s->refcount_table;
|
||||
s->refcount_table = new_reftable;
|
||||
update_max_refcount_table_index(s);
|
||||
|
||||
s->refcount_bits = 1 << refcount_order;
|
||||
s->refcount_max = UINT64_C(1) << (s->refcount_bits - 1);
|
||||
|
||||
@@ -2743,6 +2743,7 @@ static int make_completely_empty(BlockDriverState *bs)
|
||||
|
||||
s->refcount_table_offset = s->cluster_size;
|
||||
s->refcount_table_size = s->cluster_size / sizeof(uint64_t);
|
||||
s->max_refcount_table_index = 0;
|
||||
|
||||
g_free(s->refcount_table);
|
||||
s->refcount_table = new_reftable;
|
||||
|
||||
@@ -251,6 +251,7 @@ typedef struct BDRVQcow2State {
|
||||
uint64_t *refcount_table;
|
||||
uint64_t refcount_table_offset;
|
||||
uint32_t refcount_table_size;
|
||||
uint32_t max_refcount_table_index; /* Last used entry in refcount_table */
|
||||
uint64_t free_cluster_index;
|
||||
uint64_t free_byte_offset;
|
||||
|
||||
|
||||
@@ -1361,8 +1361,8 @@ static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset,
|
||||
goto out;
|
||||
}
|
||||
|
||||
data->lba = offset >> BDRV_SECTOR_BITS;
|
||||
data->size = buf_len;
|
||||
data->lba = cpu_to_le64(offset >> BDRV_SECTOR_BITS);
|
||||
data->size = cpu_to_le32(buf_len);
|
||||
|
||||
n_bytes = buf_len + sizeof(VmdkGrainMarker);
|
||||
iov = (struct iovec) {
|
||||
|
||||
@@ -129,7 +129,7 @@ static int char_pty_chr_write(Chardev *chr, const uint8_t *buf, int len)
|
||||
/* guest sends data, check for (re-)connect */
|
||||
pty_chr_update_read_handler_locked(chr);
|
||||
if (!s->connected) {
|
||||
return 0;
|
||||
return len;
|
||||
}
|
||||
}
|
||||
return io_channel_send(s->ioc, buf, len);
|
||||
|
||||
@@ -97,6 +97,9 @@ static gboolean tcp_chr_accept(QIOChannel *chan,
|
||||
GIOCondition cond,
|
||||
void *opaque);
|
||||
|
||||
static int tcp_chr_read_poll(void *opaque);
|
||||
static void tcp_chr_disconnect(Chardev *chr);
|
||||
|
||||
/* Called with chr_write_lock held. */
|
||||
static int tcp_chr_write(Chardev *chr, const uint8_t *buf, int len)
|
||||
{
|
||||
@@ -114,6 +117,13 @@ static int tcp_chr_write(Chardev *chr, const uint8_t *buf, int len)
|
||||
s->write_msgfds_num = 0;
|
||||
}
|
||||
|
||||
if (ret < 0 && errno != EAGAIN) {
|
||||
if (tcp_chr_read_poll(chr) <= 0) {
|
||||
tcp_chr_disconnect(chr);
|
||||
return len;
|
||||
} /* else let the read handler finish it properly */
|
||||
}
|
||||
|
||||
return ret;
|
||||
} else {
|
||||
/* XXX: indicate an error ? */
|
||||
|
||||
@@ -652,6 +652,7 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename)
|
||||
if (strcmp(filename, "null") == 0 ||
|
||||
strcmp(filename, "pty") == 0 ||
|
||||
strcmp(filename, "msmouse") == 0 ||
|
||||
strcmp(filename, "wctablet") == 0 ||
|
||||
strcmp(filename, "braille") == 0 ||
|
||||
strcmp(filename, "testdev") == 0 ||
|
||||
strcmp(filename, "stdio") == 0) {
|
||||
|
||||
6
configure
vendored
6
configure
vendored
@@ -5843,7 +5843,7 @@ target_name=$(echo $target | cut -d '-' -f 1)
|
||||
target_bigendian="no"
|
||||
|
||||
case "$target_name" in
|
||||
armeb|hppa|lm32|m68k|microblaze|mips|mipsn32|mips64|moxie|or32|ppc|ppcemb|ppc64|ppc64abi32|s390x|sh4eb|sparc|sparc64|sparc32plus|xtensaeb)
|
||||
armeb|hppa|lm32|m68k|microblaze|mips|mipsn32|mips64|moxie|or1k|ppc|ppcemb|ppc64|ppc64abi32|s390x|sh4eb|sparc|sparc64|sparc32plus|xtensaeb)
|
||||
target_bigendian=yes
|
||||
;;
|
||||
esac
|
||||
@@ -5937,7 +5937,7 @@ case "$target_name" in
|
||||
;;
|
||||
nios2)
|
||||
;;
|
||||
or32)
|
||||
or1k)
|
||||
TARGET_ARCH=openrisc
|
||||
TARGET_BASE_ARCH=openrisc
|
||||
;;
|
||||
@@ -6145,7 +6145,7 @@ for i in $ARCH $TARGET_BASE_ARCH ; do
|
||||
nios2)
|
||||
disas_config "NIOS2"
|
||||
;;
|
||||
or32)
|
||||
or1k)
|
||||
disas_config "OPENRISC"
|
||||
;;
|
||||
ppc*)
|
||||
|
||||
86
cpu-exec.c
86
cpu-exec.c
@@ -461,7 +461,7 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void cpu_handle_interrupt(CPUState *cpu,
|
||||
static inline bool cpu_handle_interrupt(CPUState *cpu,
|
||||
TranslationBlock **last_tb)
|
||||
{
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
@@ -475,7 +475,7 @@ static inline void cpu_handle_interrupt(CPUState *cpu,
|
||||
if (interrupt_request & CPU_INTERRUPT_DEBUG) {
|
||||
cpu->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
|
||||
cpu->exception_index = EXCP_DEBUG;
|
||||
cpu_loop_exit(cpu);
|
||||
return true;
|
||||
}
|
||||
if (replay_mode == REPLAY_MODE_PLAY && !replay_has_interrupt()) {
|
||||
/* Do nothing */
|
||||
@@ -484,23 +484,23 @@ static inline void cpu_handle_interrupt(CPUState *cpu,
|
||||
cpu->interrupt_request &= ~CPU_INTERRUPT_HALT;
|
||||
cpu->halted = 1;
|
||||
cpu->exception_index = EXCP_HLT;
|
||||
cpu_loop_exit(cpu);
|
||||
return true;
|
||||
}
|
||||
#if defined(TARGET_I386)
|
||||
else if (interrupt_request & CPU_INTERRUPT_INIT) {
|
||||
X86CPU *x86_cpu = X86_CPU(cpu);
|
||||
CPUArchState *env = &x86_cpu->env;
|
||||
replay_interrupt();
|
||||
cpu_svm_check_intercept_param(env, SVM_EXIT_INIT, 0);
|
||||
cpu_svm_check_intercept_param(env, SVM_EXIT_INIT, 0, 0);
|
||||
do_cpu_init(x86_cpu);
|
||||
cpu->exception_index = EXCP_HALTED;
|
||||
cpu_loop_exit(cpu);
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
else if (interrupt_request & CPU_INTERRUPT_RESET) {
|
||||
replay_interrupt();
|
||||
cpu_reset(cpu);
|
||||
cpu_loop_exit(cpu);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
/* The target hook has 3 exit conditions:
|
||||
@@ -526,8 +526,10 @@ static inline void cpu_handle_interrupt(CPUState *cpu,
|
||||
if (unlikely(atomic_read(&cpu->exit_request) || replay_has_interrupt())) {
|
||||
atomic_set(&cpu->exit_request, 0);
|
||||
cpu->exception_index = EXCP_INTERRUPT;
|
||||
cpu_loop_exit(cpu);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
|
||||
@@ -542,7 +544,7 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
|
||||
|
||||
trace_exec_tb(tb, tb->pc);
|
||||
ret = cpu_tb_exec(cpu, tb);
|
||||
*last_tb = (TranslationBlock *)(ret & ~TB_EXIT_MASK);
|
||||
tb = (TranslationBlock *)(ret & ~TB_EXIT_MASK);
|
||||
*tb_exit = ret & TB_EXIT_MASK;
|
||||
switch (*tb_exit) {
|
||||
case TB_EXIT_REQUESTED:
|
||||
@@ -552,11 +554,11 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
|
||||
* have set something else (eg exit_request or
|
||||
* interrupt_request) which we will handle
|
||||
* next time around the loop. But we need to
|
||||
* ensure the tcg_exit_req read in generated code
|
||||
* ensure the zeroing of tcg_exit_req (see cpu_tb_exec)
|
||||
* comes before the next read of cpu->exit_request
|
||||
* or cpu->interrupt_request.
|
||||
*/
|
||||
smp_rmb();
|
||||
smp_mb();
|
||||
*last_tb = NULL;
|
||||
break;
|
||||
case TB_EXIT_ICOUNT_EXPIRED:
|
||||
@@ -566,6 +568,7 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
|
||||
abort();
|
||||
#else
|
||||
int insns_left = cpu->icount_decr.u32;
|
||||
*last_tb = NULL;
|
||||
if (cpu->icount_extra && insns_left >= 0) {
|
||||
/* Refill decrementer and continue execution. */
|
||||
cpu->icount_extra += insns_left;
|
||||
@@ -575,17 +578,17 @@ static inline void cpu_loop_exec_tb(CPUState *cpu, TranslationBlock *tb,
|
||||
} else {
|
||||
if (insns_left > 0) {
|
||||
/* Execute remaining instructions. */
|
||||
cpu_exec_nocache(cpu, insns_left, *last_tb, false);
|
||||
cpu_exec_nocache(cpu, insns_left, tb, false);
|
||||
align_clocks(sc, cpu);
|
||||
}
|
||||
cpu->exception_index = EXCP_INTERRUPT;
|
||||
*last_tb = NULL;
|
||||
cpu_loop_exit(cpu);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
default:
|
||||
*last_tb = tb;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -621,42 +624,37 @@ int cpu_exec(CPUState *cpu)
|
||||
*/
|
||||
init_delay_params(&sc, cpu);
|
||||
|
||||
for(;;) {
|
||||
/* prepare setjmp context for exception handling */
|
||||
if (sigsetjmp(cpu->jmp_env, 0) == 0) {
|
||||
TranslationBlock *tb, *last_tb = NULL;
|
||||
int tb_exit = 0;
|
||||
|
||||
/* if an exception is pending, we execute it here */
|
||||
if (cpu_handle_exception(cpu, &ret)) {
|
||||
break;
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
cpu_handle_interrupt(cpu, &last_tb);
|
||||
tb = tb_find(cpu, last_tb, tb_exit);
|
||||
cpu_loop_exec_tb(cpu, tb, &last_tb, &tb_exit, &sc);
|
||||
/* Try to align the host and virtual clocks
|
||||
if the guest is in advance */
|
||||
align_clocks(&sc, cpu);
|
||||
} /* for(;;) */
|
||||
} else {
|
||||
/* prepare setjmp context for exception handling */
|
||||
if (sigsetjmp(cpu->jmp_env, 0) != 0) {
|
||||
#if defined(__clang__) || !QEMU_GNUC_PREREQ(4, 6)
|
||||
/* Some compilers wrongly smash all local variables after
|
||||
* siglongjmp. There were bug reports for gcc 4.5.0 and clang.
|
||||
* Reload essential local variables here for those compilers.
|
||||
* Newer versions of gcc would complain about this code (-Wclobbered). */
|
||||
cpu = current_cpu;
|
||||
cc = CPU_GET_CLASS(cpu);
|
||||
/* Some compilers wrongly smash all local variables after
|
||||
* siglongjmp. There were bug reports for gcc 4.5.0 and clang.
|
||||
* Reload essential local variables here for those compilers.
|
||||
* Newer versions of gcc would complain about this code (-Wclobbered). */
|
||||
cpu = current_cpu;
|
||||
cc = CPU_GET_CLASS(cpu);
|
||||
#else /* buggy compiler */
|
||||
/* Assert that the compiler does not smash local variables. */
|
||||
g_assert(cpu == current_cpu);
|
||||
g_assert(cc == CPU_GET_CLASS(cpu));
|
||||
/* Assert that the compiler does not smash local variables. */
|
||||
g_assert(cpu == current_cpu);
|
||||
g_assert(cc == CPU_GET_CLASS(cpu));
|
||||
#endif /* buggy compiler */
|
||||
cpu->can_do_io = 1;
|
||||
tb_lock_reset();
|
||||
cpu->can_do_io = 1;
|
||||
tb_lock_reset();
|
||||
}
|
||||
|
||||
/* if an exception is pending, we execute it here */
|
||||
while (!cpu_handle_exception(cpu, &ret)) {
|
||||
TranslationBlock *last_tb = NULL;
|
||||
int tb_exit = 0;
|
||||
|
||||
while (!cpu_handle_interrupt(cpu, &last_tb)) {
|
||||
TranslationBlock *tb = tb_find(cpu, last_tb, tb_exit);
|
||||
cpu_loop_exec_tb(cpu, tb, &last_tb, &tb_exit, &sc);
|
||||
/* Try to align the host and virtual clocks
|
||||
if the guest is in advance */
|
||||
align_clocks(&sc, cpu);
|
||||
}
|
||||
} /* for(;;) */
|
||||
}
|
||||
|
||||
cc->cpu_exec_exit(cpu);
|
||||
rcu_read_unlock();
|
||||
|
||||
42
cpus.c
42
cpus.c
@@ -1578,6 +1578,48 @@ int vm_stop(RunState state)
|
||||
return do_vm_stop(state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare for (re)starting the VM.
|
||||
* Returns -1 if the vCPUs are not to be restarted (e.g. if they are already
|
||||
* running or in case of an error condition), 0 otherwise.
|
||||
*/
|
||||
int vm_prepare_start(void)
|
||||
{
|
||||
RunState requested;
|
||||
int res = 0;
|
||||
|
||||
qemu_vmstop_requested(&requested);
|
||||
if (runstate_is_running() && requested == RUN_STATE__MAX) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Ensure that a STOP/RESUME pair of events is emitted if a
|
||||
* vmstop request was pending. The BLOCK_IO_ERROR event, for
|
||||
* example, according to documentation is always followed by
|
||||
* the STOP event.
|
||||
*/
|
||||
if (runstate_is_running()) {
|
||||
qapi_event_send_stop(&error_abort);
|
||||
res = -1;
|
||||
} else {
|
||||
replay_enable_events();
|
||||
cpu_enable_ticks();
|
||||
runstate_set(RUN_STATE_RUNNING);
|
||||
vm_state_notify(1, RUN_STATE_RUNNING);
|
||||
}
|
||||
|
||||
/* We are sending this now, but the CPUs will be resumed shortly later */
|
||||
qapi_event_send_resume(&error_abort);
|
||||
return res;
|
||||
}
|
||||
|
||||
void vm_start(void)
|
||||
{
|
||||
if (!vm_prepare_start()) {
|
||||
resume_all_vcpus();
|
||||
}
|
||||
}
|
||||
|
||||
/* does a state transition even if the VM is already stopped,
|
||||
current state is forgotten forever */
|
||||
int vm_stop_force_state(RunState state)
|
||||
|
||||
@@ -95,6 +95,8 @@ CONFIG_VERSATILE_PCI=y
|
||||
CONFIG_VERSATILE_I2C=y
|
||||
|
||||
CONFIG_PCI_GENERIC=y
|
||||
CONFIG_VFIO_XGMAC=y
|
||||
CONFIG_VFIO_AMD_XGBE=y
|
||||
|
||||
CONFIG_SDHCI=y
|
||||
CONFIG_INTEGRATOR_DEBUG=y
|
||||
|
||||
1
default-configs/or1k-linux-user.mak
Normal file
1
default-configs/or1k-linux-user.mak
Normal file
@@ -0,0 +1 @@
|
||||
# Default configuration for or1k-linux-user
|
||||
4
default-configs/or1k-softmmu.mak
Normal file
4
default-configs/or1k-softmmu.mak
Normal file
@@ -0,0 +1,4 @@
|
||||
# Default configuration for or1k-softmmu
|
||||
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_OPENCORES_ETH=y
|
||||
@@ -1 +0,0 @@
|
||||
# Default configuration for or32-linux-user
|
||||
@@ -1,4 +0,0 @@
|
||||
# Default configuration for or32-softmmu
|
||||
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_OPENCORES_ETH=y
|
||||
1
disas.c
1
disas.c
@@ -190,6 +190,7 @@ void target_disas(FILE *out, CPUState *cpu, target_ulong code,
|
||||
|
||||
s.cpu = cpu;
|
||||
s.info.read_memory_func = target_read_memory;
|
||||
s.info.read_memory_inner_func = NULL;
|
||||
s.info.buffer_vma = code;
|
||||
s.info.buffer_length = size;
|
||||
s.info.print_address_func = generic_print_address;
|
||||
|
||||
@@ -200,7 +200,7 @@ LEGACY-CHARDEV translates to -chardev HOST-OPTS... as follows:
|
||||
|
||||
* null becomes -chardev null
|
||||
|
||||
* pty, msmouse, braille, stdio likewise
|
||||
* pty, msmouse, wctablet, braille, stdio likewise
|
||||
|
||||
* vc:WIDTHxHEIGHT becomes -chardev vc,width=WIDTH,height=HEIGHT
|
||||
|
||||
|
||||
1
exec.c
1
exec.c
@@ -2115,6 +2115,7 @@ static void check_watchpoint(int offset, int len, MemTxAttrs attrs, int flags)
|
||||
return;
|
||||
}
|
||||
vaddr = (cpu->mem_io_vaddr & TARGET_PAGE_MASK) + offset;
|
||||
vaddr = cc->adjust_watchpoint_address(cpu, vaddr, len);
|
||||
QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {
|
||||
if (cpu_watchpoint_address_matches(wp, vaddr, len)
|
||||
&& (wp->flags & flags)) {
|
||||
|
||||
207
gdbstub.c
207
gdbstub.c
@@ -387,6 +387,60 @@ static inline void gdb_continue(GDBState *s)
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Resume execution, per CPU actions. For user-mode emulation it's
|
||||
* equivalent to gdb_continue.
|
||||
*/
|
||||
static int gdb_continue_partial(GDBState *s, char *newstates)
|
||||
{
|
||||
CPUState *cpu;
|
||||
int res = 0;
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
/*
|
||||
* This is not exactly accurate, but it's an improvement compared to the
|
||||
* previous situation, where only one CPU would be single-stepped.
|
||||
*/
|
||||
CPU_FOREACH(cpu) {
|
||||
if (newstates[cpu->cpu_index] == 's') {
|
||||
cpu_single_step(cpu, sstep_flags);
|
||||
}
|
||||
}
|
||||
s->running_state = 1;
|
||||
#else
|
||||
int flag = 0;
|
||||
|
||||
if (!runstate_needs_reset()) {
|
||||
if (vm_prepare_start()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
CPU_FOREACH(cpu) {
|
||||
switch (newstates[cpu->cpu_index]) {
|
||||
case 0:
|
||||
case 1:
|
||||
break; /* nothing to do here */
|
||||
case 's':
|
||||
cpu_single_step(cpu, sstep_flags);
|
||||
cpu_resume(cpu);
|
||||
flag = 1;
|
||||
break;
|
||||
case 'c':
|
||||
cpu_resume(cpu);
|
||||
flag = 1;
|
||||
break;
|
||||
default:
|
||||
res = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flag) {
|
||||
qemu_clock_enable(QEMU_CLOCK_VIRTUAL, true);
|
||||
}
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
static void put_buffer(GDBState *s, const uint8_t *buf, int len)
|
||||
{
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
@@ -785,6 +839,107 @@ static int is_query_packet(const char *p, const char *query, char separator)
|
||||
(p[query_len] == '\0' || p[query_len] == separator);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdb_handle_vcont - Parses and handles a vCont packet.
|
||||
* returns -ENOTSUP if a command is unsupported, -EINVAL or -ERANGE if there is
|
||||
* a format error, 0 on success.
|
||||
*/
|
||||
static int gdb_handle_vcont(GDBState *s, const char *p)
|
||||
{
|
||||
int res, idx, signal = 0;
|
||||
char cur_action;
|
||||
char *newstates;
|
||||
unsigned long tmp;
|
||||
CPUState *cpu;
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
int max_cpus = 1; /* global variable max_cpus exists only in system mode */
|
||||
|
||||
CPU_FOREACH(cpu) {
|
||||
max_cpus = max_cpus <= cpu->cpu_index ? cpu->cpu_index + 1 : max_cpus;
|
||||
}
|
||||
#endif
|
||||
/* uninitialised CPUs stay 0 */
|
||||
newstates = g_new0(char, max_cpus);
|
||||
|
||||
/* mark valid CPUs with 1 */
|
||||
CPU_FOREACH(cpu) {
|
||||
newstates[cpu->cpu_index] = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* res keeps track of what error we are returning, with -ENOTSUP meaning
|
||||
* that the command is unknown or unsupported, thus returning an empty
|
||||
* packet, while -EINVAL and -ERANGE cause an E22 packet, due to invalid,
|
||||
* or incorrect parameters passed.
|
||||
*/
|
||||
res = 0;
|
||||
while (*p) {
|
||||
if (*p++ != ';') {
|
||||
res = -ENOTSUP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
cur_action = *p++;
|
||||
if (cur_action == 'C' || cur_action == 'S') {
|
||||
cur_action = tolower(cur_action);
|
||||
res = qemu_strtoul(p + 1, &p, 16, &tmp);
|
||||
if (res) {
|
||||
goto out;
|
||||
}
|
||||
signal = gdb_signal_to_target(tmp);
|
||||
} else if (cur_action != 'c' && cur_action != 's') {
|
||||
/* unknown/invalid/unsupported command */
|
||||
res = -ENOTSUP;
|
||||
goto out;
|
||||
}
|
||||
/* thread specification. special values: (none), -1 = all; 0 = any */
|
||||
if ((p[0] == ':' && p[1] == '-' && p[2] == '1') || (p[0] != ':')) {
|
||||
if (*p == ':') {
|
||||
p += 3;
|
||||
}
|
||||
for (idx = 0; idx < max_cpus; idx++) {
|
||||
if (newstates[idx] == 1) {
|
||||
newstates[idx] = cur_action;
|
||||
}
|
||||
}
|
||||
} else if (*p == ':') {
|
||||
p++;
|
||||
res = qemu_strtoul(p, &p, 16, &tmp);
|
||||
if (res) {
|
||||
goto out;
|
||||
}
|
||||
idx = tmp;
|
||||
/* 0 means any thread, so we pick the first valid CPU */
|
||||
if (!idx) {
|
||||
idx = cpu_index(first_cpu);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we are in user mode, the thread specified is actually a
|
||||
* thread id, and not an index. We need to find the actual
|
||||
* CPU first, and only then we can use its index.
|
||||
*/
|
||||
cpu = find_cpu(idx);
|
||||
/* invalid CPU/thread specified */
|
||||
if (!idx || !cpu) {
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
/* only use if no previous match occourred */
|
||||
if (newstates[cpu->cpu_index] == 1) {
|
||||
newstates[cpu->cpu_index] = cur_action;
|
||||
}
|
||||
}
|
||||
}
|
||||
s->signal = signal;
|
||||
gdb_continue_partial(s, newstates);
|
||||
|
||||
out:
|
||||
g_free(newstates);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int gdb_handle_packet(GDBState *s, const char *line_buf)
|
||||
{
|
||||
CPUState *cpu;
|
||||
@@ -830,60 +985,20 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
|
||||
return RS_IDLE;
|
||||
case 'v':
|
||||
if (strncmp(p, "Cont", 4) == 0) {
|
||||
int res_signal, res_thread;
|
||||
|
||||
p += 4;
|
||||
if (*p == '?') {
|
||||
put_packet(s, "vCont;c;C;s;S");
|
||||
break;
|
||||
}
|
||||
res = 0;
|
||||
res_signal = 0;
|
||||
res_thread = 0;
|
||||
while (*p) {
|
||||
int action, signal;
|
||||
|
||||
if (*p++ != ';') {
|
||||
res = 0;
|
||||
break;
|
||||
}
|
||||
action = *p++;
|
||||
signal = 0;
|
||||
if (action == 'C' || action == 'S') {
|
||||
signal = gdb_signal_to_target(strtoul(p, (char **)&p, 16));
|
||||
if (signal == -1) {
|
||||
signal = 0;
|
||||
}
|
||||
} else if (action != 'c' && action != 's') {
|
||||
res = 0;
|
||||
break;
|
||||
}
|
||||
thread = 0;
|
||||
if (*p == ':') {
|
||||
thread = strtoull(p+1, (char **)&p, 16);
|
||||
}
|
||||
action = tolower(action);
|
||||
if (res == 0 || (res == 'c' && action == 's')) {
|
||||
res = action;
|
||||
res_signal = signal;
|
||||
res_thread = thread;
|
||||
}
|
||||
}
|
||||
res = gdb_handle_vcont(s, p);
|
||||
|
||||
if (res) {
|
||||
if (res_thread != -1 && res_thread != 0) {
|
||||
cpu = find_cpu(res_thread);
|
||||
if (cpu == NULL) {
|
||||
put_packet(s, "E22");
|
||||
break;
|
||||
}
|
||||
s->c_cpu = cpu;
|
||||
if ((res == -EINVAL) || (res == -ERANGE)) {
|
||||
put_packet(s, "E22");
|
||||
break;
|
||||
}
|
||||
if (res == 's') {
|
||||
cpu_single_step(s->c_cpu, sstep_flags);
|
||||
}
|
||||
s->signal = res_signal;
|
||||
gdb_continue(s);
|
||||
return RS_IDLE;
|
||||
goto unknown_command;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
|
||||
@@ -113,9 +113,19 @@ static void write_boot_rom(DriveInfo *dinfo, hwaddr addr, size_t rom_size,
|
||||
{
|
||||
BlockBackend *blk = blk_by_legacy_dinfo(dinfo);
|
||||
uint8_t *storage;
|
||||
int64_t size;
|
||||
|
||||
if (rom_size > blk_getlength(blk)) {
|
||||
rom_size = blk_getlength(blk);
|
||||
/* The block backend size should have already been 'validated' by
|
||||
* the creation of the m25p80 object.
|
||||
*/
|
||||
size = blk_getlength(blk);
|
||||
if (size <= 0) {
|
||||
error_setg(errp, "failed to get flash size");
|
||||
return;
|
||||
}
|
||||
|
||||
if (rom_size > size) {
|
||||
rom_size = size;
|
||||
}
|
||||
|
||||
storage = g_new0(uint8_t, rom_size);
|
||||
@@ -138,10 +148,6 @@ static void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype,
|
||||
DriveInfo *dinfo = drive_get_next(IF_MTD);
|
||||
qemu_irq cs_line;
|
||||
|
||||
/*
|
||||
* FIXME: check that we are not using a flash module exceeding
|
||||
* the controller segment size
|
||||
*/
|
||||
fl->flash = ssi_create_slave_no_init(s->spi, flashtype);
|
||||
if (dinfo) {
|
||||
qdev_prop_set_drive(fl->flash, "drive", blk_by_legacy_dinfo(dinfo),
|
||||
@@ -200,7 +206,9 @@ static void aspeed_board_init(MachineState *machine,
|
||||
|
||||
/*
|
||||
* create a ROM region using the default mapping window size of
|
||||
* the flash module.
|
||||
* the flash module. The window size is 64MB for the AST2400
|
||||
* SoC and 128MB for the AST2500 SoC, which is twice as big as
|
||||
* needed by the flash modules of the Aspeed machines.
|
||||
*/
|
||||
memory_region_init_rom(boot_rom, OBJECT(bmc), "aspeed.boot_rom",
|
||||
fl->size, &error_abort);
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#define ASPEED_SOC_SCU_BASE 0x1E6E2000
|
||||
#define ASPEED_SOC_SRAM_BASE 0x1E720000
|
||||
#define ASPEED_SOC_TIMER_BASE 0x1E782000
|
||||
#define ASPEED_SOC_WDT_BASE 0x1E785000
|
||||
#define ASPEED_SOC_I2C_BASE 0x1E78A000
|
||||
|
||||
static const int uart_irqs[] = { 9, 32, 33, 34, 10 };
|
||||
@@ -170,6 +171,10 @@ static void aspeed_soc_init(Object *obj)
|
||||
sc->info->silicon_rev);
|
||||
object_property_add_alias(obj, "ram-size", OBJECT(&s->sdmc),
|
||||
"ram-size", &error_abort);
|
||||
|
||||
object_initialize(&s->wdt, sizeof(s->wdt), TYPE_ASPEED_WDT);
|
||||
object_property_add_child(obj, "wdt", OBJECT(&s->wdt), NULL);
|
||||
qdev_set_parent_bus(DEVICE(&s->wdt), sysbus_get_default());
|
||||
}
|
||||
|
||||
static void aspeed_soc_realize(DeviceState *dev, Error **errp)
|
||||
@@ -286,6 +291,14 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdmc), 0, ASPEED_SOC_SDMC_BASE);
|
||||
|
||||
/* Watch dog */
|
||||
object_property_set_bool(OBJECT(&s->wdt), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->wdt), 0, ASPEED_SOC_WDT_BASE);
|
||||
}
|
||||
|
||||
static void aspeed_soc_class_init(ObjectClass *oc, void *data)
|
||||
|
||||
@@ -53,6 +53,26 @@ static uint8_t integrator_spd[128] = {
|
||||
0xe, 4, 0x1c, 1, 2, 0x20, 0xc0, 0, 0, 0, 0, 0x30, 0x28, 0x30, 0x28, 0x40
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_integratorcm = {
|
||||
.name = "integratorcm",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(cm_osc, IntegratorCMState),
|
||||
VMSTATE_UINT32(cm_ctrl, IntegratorCMState),
|
||||
VMSTATE_UINT32(cm_lock, IntegratorCMState),
|
||||
VMSTATE_UINT32(cm_auxosc, IntegratorCMState),
|
||||
VMSTATE_UINT32(cm_sdram, IntegratorCMState),
|
||||
VMSTATE_UINT32(cm_init, IntegratorCMState),
|
||||
VMSTATE_UINT32(cm_flags, IntegratorCMState),
|
||||
VMSTATE_UINT32(cm_nvflags, IntegratorCMState),
|
||||
VMSTATE_UINT32(int_level, IntegratorCMState),
|
||||
VMSTATE_UINT32(irq_enabled, IntegratorCMState),
|
||||
VMSTATE_UINT32(fiq_enabled, IntegratorCMState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static uint64_t integratorcm_read(void *opaque, hwaddr offset,
|
||||
unsigned size)
|
||||
{
|
||||
@@ -309,6 +329,18 @@ typedef struct icp_pic_state {
|
||||
qemu_irq parent_fiq;
|
||||
} icp_pic_state;
|
||||
|
||||
static const VMStateDescription vmstate_icp_pic = {
|
||||
.name = "icp_pic",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(level, icp_pic_state),
|
||||
VMSTATE_UINT32(irq_enabled, icp_pic_state),
|
||||
VMSTATE_UINT32(fiq_enabled, icp_pic_state),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static void icp_pic_update(icp_pic_state *s)
|
||||
{
|
||||
uint32_t flags;
|
||||
@@ -438,6 +470,16 @@ typedef struct ICPCtrlRegsState {
|
||||
#define ICP_INTREG_WPROT (1 << 0)
|
||||
#define ICP_INTREG_CARDIN (1 << 3)
|
||||
|
||||
static const VMStateDescription vmstate_icp_control = {
|
||||
.name = "icp_control",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(intreg_state, ICPCtrlRegsState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static uint64_t icp_control_read(void *opaque, hwaddr offset,
|
||||
unsigned size)
|
||||
{
|
||||
@@ -535,27 +577,42 @@ static void integratorcp_init(MachineState *machine)
|
||||
const char *kernel_filename = machine->kernel_filename;
|
||||
const char *kernel_cmdline = machine->kernel_cmdline;
|
||||
const char *initrd_filename = machine->initrd_filename;
|
||||
char **cpustr;
|
||||
ObjectClass *cpu_oc;
|
||||
CPUClass *cc;
|
||||
Object *cpuobj;
|
||||
ARMCPU *cpu;
|
||||
const char *typename;
|
||||
MemoryRegion *address_space_mem = get_system_memory();
|
||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||
MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
|
||||
qemu_irq pic[32];
|
||||
DeviceState *dev, *sic, *icp;
|
||||
int i;
|
||||
Error *err = NULL;
|
||||
|
||||
if (!cpu_model) {
|
||||
cpu_model = "arm926";
|
||||
}
|
||||
|
||||
cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
|
||||
cpustr = g_strsplit(cpu_model, ",", 2);
|
||||
|
||||
cpu_oc = cpu_class_by_name(TYPE_ARM_CPU, cpustr[0]);
|
||||
if (!cpu_oc) {
|
||||
fprintf(stderr, "Unable to find CPU definition\n");
|
||||
exit(1);
|
||||
}
|
||||
typename = object_class_get_name(cpu_oc);
|
||||
|
||||
cpuobj = object_new(object_class_get_name(cpu_oc));
|
||||
cc = CPU_CLASS(cpu_oc);
|
||||
cc->parse_features(typename, cpustr[1], &err);
|
||||
g_strfreev(cpustr);
|
||||
if (err) {
|
||||
error_report_err(err);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
cpuobj = object_new(typename);
|
||||
|
||||
/* By default ARM1176 CPUs have EL3 enabled. This board does not
|
||||
* currently support EL3 so the CPU EL3 property is disabled before
|
||||
@@ -640,6 +697,21 @@ static void core_class_init(ObjectClass *klass, void *data)
|
||||
|
||||
dc->props = core_properties;
|
||||
dc->realize = integratorcm_realize;
|
||||
dc->vmsd = &vmstate_integratorcm;
|
||||
}
|
||||
|
||||
static void icp_pic_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->vmsd = &vmstate_icp_pic;
|
||||
}
|
||||
|
||||
static void icp_control_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->vmsd = &vmstate_icp_control;
|
||||
}
|
||||
|
||||
static const TypeInfo core_info = {
|
||||
@@ -655,6 +727,7 @@ static const TypeInfo icp_pic_info = {
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(icp_pic_state),
|
||||
.instance_init = icp_pic_init,
|
||||
.class_init = icp_pic_class_init,
|
||||
};
|
||||
|
||||
static const TypeInfo icp_ctrl_regs_info = {
|
||||
@@ -662,6 +735,7 @@ static const TypeInfo icp_ctrl_regs_info = {
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(ICPCtrlRegsState),
|
||||
.instance_init = icp_control_init,
|
||||
.class_init = icp_control_class_init,
|
||||
};
|
||||
|
||||
static void integratorcp_register_types(void)
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "exec/address-spaces.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/char/pl011.h"
|
||||
#include "hw/misc/unimp.h"
|
||||
|
||||
#define GPIO_A 0
|
||||
#define GPIO_B 1
|
||||
@@ -1220,6 +1221,40 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model,
|
||||
0x40024000, 0x40025000, 0x40026000};
|
||||
static const int gpio_irq[7] = {0, 1, 2, 3, 4, 30, 31};
|
||||
|
||||
/* Memory map of SoC devices, from
|
||||
* Stellaris LM3S6965 Microcontroller Data Sheet (rev I)
|
||||
* http://www.ti.com/lit/ds/symlink/lm3s6965.pdf
|
||||
*
|
||||
* 40000000 wdtimer (unimplemented)
|
||||
* 40002000 i2c (unimplemented)
|
||||
* 40004000 GPIO
|
||||
* 40005000 GPIO
|
||||
* 40006000 GPIO
|
||||
* 40007000 GPIO
|
||||
* 40008000 SSI
|
||||
* 4000c000 UART
|
||||
* 4000d000 UART
|
||||
* 4000e000 UART
|
||||
* 40020000 i2c
|
||||
* 40021000 i2c (unimplemented)
|
||||
* 40024000 GPIO
|
||||
* 40025000 GPIO
|
||||
* 40026000 GPIO
|
||||
* 40028000 PWM (unimplemented)
|
||||
* 4002c000 QEI (unimplemented)
|
||||
* 4002d000 QEI (unimplemented)
|
||||
* 40030000 gptimer
|
||||
* 40031000 gptimer
|
||||
* 40032000 gptimer
|
||||
* 40033000 gptimer
|
||||
* 40038000 ADC
|
||||
* 4003c000 analogue comparator (unimplemented)
|
||||
* 40048000 ethernet
|
||||
* 400fc000 hibernation module (unimplemented)
|
||||
* 400fd000 flash memory control (unimplemented)
|
||||
* 400fe000 system control
|
||||
*/
|
||||
|
||||
DeviceState *gpio_dev[7], *nvic;
|
||||
qemu_irq gpio_in[7][8];
|
||||
qemu_irq gpio_out[7][8];
|
||||
@@ -1370,6 +1405,19 @@ static void stellaris_init(const char *kernel_filename, const char *cpu_model,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Add dummy regions for the devices we don't implement yet,
|
||||
* so guest accesses don't cause unlogged crashes.
|
||||
*/
|
||||
create_unimplemented_device("wdtimer", 0x40000000, 0x1000);
|
||||
create_unimplemented_device("i2c-0", 0x40002000, 0x1000);
|
||||
create_unimplemented_device("i2c-2", 0x40021000, 0x1000);
|
||||
create_unimplemented_device("PWM", 0x40028000, 0x1000);
|
||||
create_unimplemented_device("QEI-0", 0x4002c000, 0x1000);
|
||||
create_unimplemented_device("QEI-1", 0x4002d000, 0x1000);
|
||||
create_unimplemented_device("analogue-comparator", 0x4003c000, 0x1000);
|
||||
create_unimplemented_device("hibernation", 0x400fc000, 0x1000);
|
||||
create_unimplemented_device("flash-control", 0x400fd000, 0x1000);
|
||||
}
|
||||
|
||||
/* FIXME: Figure out how to generate these from stellaris_boards. */
|
||||
|
||||
@@ -452,6 +452,7 @@ static int add_virtio_mmio_node(void *fdt, uint32_t acells, uint32_t scells,
|
||||
acells, addr, scells, size);
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "interrupt-parent", intc);
|
||||
qemu_fdt_setprop_cells(fdt, nodename, "interrupts", 0, irq, 1);
|
||||
qemu_fdt_setprop(fdt, nodename, "dma-coherent", NULL, 0);
|
||||
g_free(nodename);
|
||||
if (rc) {
|
||||
return -1;
|
||||
|
||||
@@ -90,6 +90,7 @@ static void acpi_dsdt_add_fw_cfg(Aml *scope, const MemMapEntry *fw_cfg_memmap)
|
||||
aml_append(dev, aml_name_decl("_HID", aml_string("QEMU0002")));
|
||||
/* device present, functioning, decoding, not shown in UI */
|
||||
aml_append(dev, aml_name_decl("_STA", aml_int(0xB)));
|
||||
aml_append(dev, aml_name_decl("_CCA", aml_int(1)));
|
||||
|
||||
Aml *crs = aml_resource_template();
|
||||
aml_append(crs, aml_memory32_fixed(fw_cfg_memmap->base,
|
||||
@@ -135,6 +136,7 @@ static void acpi_dsdt_add_virtio(Aml *scope,
|
||||
Aml *dev = aml_device("VR%02u", i);
|
||||
aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0005")));
|
||||
aml_append(dev, aml_name_decl("_UID", aml_int(i)));
|
||||
aml_append(dev, aml_name_decl("_CCA", aml_int(1)));
|
||||
|
||||
Aml *crs = aml_resource_template();
|
||||
aml_append(crs, aml_memory32_fixed(base, size, AML_READ_WRITE));
|
||||
|
||||
@@ -471,7 +471,7 @@ static void fdt_add_pmu_nodes(const VirtMachineState *vms)
|
||||
CPU_FOREACH(cpu) {
|
||||
armcpu = ARM_CPU(cpu);
|
||||
if (!arm_feature(&armcpu->env, ARM_FEATURE_PMU) ||
|
||||
!kvm_arm_pmu_create(cpu, PPI(VIRTUAL_PMU_IRQ))) {
|
||||
(kvm_enabled() && !kvm_arm_pmu_create(cpu, PPI(VIRTUAL_PMU_IRQ)))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -797,6 +797,7 @@ static void create_virtio_devices(const VirtMachineState *vms, qemu_irq *pic)
|
||||
qemu_fdt_setprop_cells(vms->fdt, nodename, "interrupts",
|
||||
GIC_FDT_IRQ_TYPE_SPI, irq,
|
||||
GIC_FDT_IRQ_FLAGS_EDGE_LO_HI);
|
||||
qemu_fdt_setprop(vms->fdt, nodename, "dma-coherent", NULL, 0);
|
||||
g_free(nodename);
|
||||
}
|
||||
}
|
||||
@@ -928,6 +929,7 @@ static FWCfgState *create_fw_cfg(const VirtMachineState *vms, AddressSpace *as)
|
||||
"compatible", "qemu,fw-cfg-mmio");
|
||||
qemu_fdt_setprop_sized_cells(vms->fdt, nodename, "reg",
|
||||
2, base, 2, size);
|
||||
qemu_fdt_setprop(vms->fdt, nodename, "dma-coherent", NULL, 0);
|
||||
g_free(nodename);
|
||||
return fw_cfg;
|
||||
}
|
||||
|
||||
@@ -561,7 +561,7 @@ static const VMStateDescription vmstate_exynos4210_uart_fifo = {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(sp, Exynos4210UartFIFO),
|
||||
VMSTATE_UINT32(rp, Exynos4210UartFIFO),
|
||||
VMSTATE_VBUFFER_UINT32(data, Exynos4210UartFIFO, 1, NULL, 0, size),
|
||||
VMSTATE_VBUFFER_UINT32(data, Exynos4210UartFIFO, 1, NULL, size),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
@@ -7,12 +7,15 @@
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/m68k/mcf.h"
|
||||
#include "sysemu/char.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
typedef struct {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MemoryRegion iomem;
|
||||
uint8_t mr[2];
|
||||
uint8_t sr;
|
||||
@@ -30,6 +33,9 @@ typedef struct {
|
||||
CharBackend chr;
|
||||
} mcf_uart_state;
|
||||
|
||||
#define TYPE_MCF_UART "mcf-uart"
|
||||
#define MCF_UART(obj) OBJECT_CHECK(mcf_uart_state, (obj), TYPE_MCF_UART)
|
||||
|
||||
/* UART Status Register bits. */
|
||||
#define MCF_UART_RxRDY 0x01
|
||||
#define MCF_UART_FFULL 0x02
|
||||
@@ -220,8 +226,10 @@ void mcf_uart_write(void *opaque, hwaddr addr,
|
||||
mcf_uart_update(s);
|
||||
}
|
||||
|
||||
static void mcf_uart_reset(mcf_uart_state *s)
|
||||
static void mcf_uart_reset(DeviceState *dev)
|
||||
{
|
||||
mcf_uart_state *s = MCF_UART(dev);
|
||||
|
||||
s->fifo_len = 0;
|
||||
s->mr[0] = 0;
|
||||
s->mr[1] = 0;
|
||||
@@ -275,36 +283,80 @@ static void mcf_uart_receive(void *opaque, const uint8_t *buf, int size)
|
||||
mcf_uart_push_byte(s, buf[0]);
|
||||
}
|
||||
|
||||
void *mcf_uart_init(qemu_irq irq, Chardev *chr)
|
||||
{
|
||||
mcf_uart_state *s;
|
||||
|
||||
s = g_malloc0(sizeof(mcf_uart_state));
|
||||
s->irq = irq;
|
||||
if (chr) {
|
||||
qemu_chr_fe_init(&s->chr, chr, &error_abort);
|
||||
qemu_chr_fe_set_handlers(&s->chr, mcf_uart_can_receive,
|
||||
mcf_uart_receive, mcf_uart_event,
|
||||
s, NULL, true);
|
||||
}
|
||||
mcf_uart_reset(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps mcf_uart_ops = {
|
||||
.read = mcf_uart_read,
|
||||
.write = mcf_uart_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
void mcf_uart_mm_init(MemoryRegion *sysmem,
|
||||
hwaddr base,
|
||||
qemu_irq irq,
|
||||
Chardev *chr)
|
||||
static void mcf_uart_instance_init(Object *obj)
|
||||
{
|
||||
mcf_uart_state *s;
|
||||
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
|
||||
mcf_uart_state *s = MCF_UART(dev);
|
||||
|
||||
s = mcf_uart_init(irq, chr);
|
||||
memory_region_init_io(&s->iomem, NULL, &mcf_uart_ops, s, "uart", 0x40);
|
||||
memory_region_add_subregion(sysmem, base, &s->iomem);
|
||||
memory_region_init_io(&s->iomem, obj, &mcf_uart_ops, s, "uart", 0x40);
|
||||
sysbus_init_mmio(dev, &s->iomem);
|
||||
|
||||
sysbus_init_irq(dev, &s->irq);
|
||||
}
|
||||
|
||||
static void mcf_uart_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
mcf_uart_state *s = MCF_UART(dev);
|
||||
|
||||
qemu_chr_fe_set_handlers(&s->chr, mcf_uart_can_receive, mcf_uart_receive,
|
||||
mcf_uart_event, s, NULL, true);
|
||||
}
|
||||
|
||||
static Property mcf_uart_properties[] = {
|
||||
DEFINE_PROP_CHR("chardev", mcf_uart_state, chr),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void mcf_uart_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||
|
||||
dc->realize = mcf_uart_realize;
|
||||
dc->reset = mcf_uart_reset;
|
||||
dc->props = mcf_uart_properties;
|
||||
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
|
||||
}
|
||||
|
||||
static const TypeInfo mcf_uart_info = {
|
||||
.name = TYPE_MCF_UART,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(mcf_uart_state),
|
||||
.instance_init = mcf_uart_instance_init,
|
||||
.class_init = mcf_uart_class_init,
|
||||
};
|
||||
|
||||
static void mcf_uart_register(void)
|
||||
{
|
||||
type_register_static(&mcf_uart_info);
|
||||
}
|
||||
|
||||
type_init(mcf_uart_register)
|
||||
|
||||
void *mcf_uart_init(qemu_irq irq, Chardev *chrdrv)
|
||||
{
|
||||
DeviceState *dev;
|
||||
|
||||
dev = qdev_create(NULL, TYPE_MCF_UART);
|
||||
if (chrdrv) {
|
||||
qdev_prop_set_chr(dev, "chardev", chrdrv);
|
||||
}
|
||||
qdev_init_nofail(dev);
|
||||
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
void mcf_uart_mm_init(hwaddr base, qemu_irq irq, Chardev *chrdrv)
|
||||
{
|
||||
DeviceState *dev;
|
||||
|
||||
dev = mcf_uart_init(irq, chrdrv);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "trace.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "ui/console.h"
|
||||
@@ -272,6 +273,9 @@ static void cirrus_update_memory_access(CirrusVGAState *s);
|
||||
static bool blit_region_is_unsafe(struct CirrusVGAState *s,
|
||||
int32_t pitch, int32_t addr)
|
||||
{
|
||||
if (!pitch) {
|
||||
return true;
|
||||
}
|
||||
if (pitch < 0) {
|
||||
int64_t min = addr
|
||||
+ ((int64_t)s->cirrus_blt_height - 1) * pitch
|
||||
@@ -290,11 +294,8 @@ static bool blit_region_is_unsafe(struct CirrusVGAState *s,
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool blit_is_unsafe(struct CirrusVGAState *s, bool dst_only,
|
||||
bool zero_src_pitch_ok)
|
||||
static bool blit_is_unsafe(struct CirrusVGAState *s, bool dst_only)
|
||||
{
|
||||
int32_t check_pitch;
|
||||
|
||||
/* should be the case, see cirrus_bitblt_start */
|
||||
assert(s->cirrus_blt_width > 0);
|
||||
assert(s->cirrus_blt_height > 0);
|
||||
@@ -303,10 +304,6 @@ static bool blit_is_unsafe(struct CirrusVGAState *s, bool dst_only,
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!s->cirrus_blt_dstpitch) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (blit_region_is_unsafe(s, s->cirrus_blt_dstpitch,
|
||||
s->cirrus_blt_dstaddr)) {
|
||||
return true;
|
||||
@@ -314,13 +311,7 @@ static bool blit_is_unsafe(struct CirrusVGAState *s, bool dst_only,
|
||||
if (dst_only) {
|
||||
return false;
|
||||
}
|
||||
|
||||
check_pitch = s->cirrus_blt_srcpitch;
|
||||
if (!zero_src_pitch_ok && !check_pitch) {
|
||||
check_pitch = s->cirrus_blt_width;
|
||||
}
|
||||
|
||||
if (blit_region_is_unsafe(s, check_pitch,
|
||||
if (blit_region_is_unsafe(s, s->cirrus_blt_srcpitch,
|
||||
s->cirrus_blt_srcaddr)) {
|
||||
return true;
|
||||
}
|
||||
@@ -683,14 +674,39 @@ static void cirrus_invalidate_region(CirrusVGAState * s, int off_begin,
|
||||
}
|
||||
}
|
||||
|
||||
static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s,
|
||||
const uint8_t * src)
|
||||
static int cirrus_bitblt_common_patterncopy(CirrusVGAState *s, bool videosrc)
|
||||
{
|
||||
uint32_t patternsize;
|
||||
uint8_t *dst;
|
||||
uint8_t *src;
|
||||
|
||||
dst = s->vga.vram_ptr + s->cirrus_blt_dstaddr;
|
||||
|
||||
if (blit_is_unsafe(s, false, true)) {
|
||||
if (videosrc) {
|
||||
switch (s->vga.get_bpp(&s->vga)) {
|
||||
case 8:
|
||||
patternsize = 64;
|
||||
break;
|
||||
case 15:
|
||||
case 16:
|
||||
patternsize = 128;
|
||||
break;
|
||||
case 24:
|
||||
case 32:
|
||||
default:
|
||||
patternsize = 256;
|
||||
break;
|
||||
}
|
||||
s->cirrus_blt_srcaddr &= ~(patternsize - 1);
|
||||
if (s->cirrus_blt_srcaddr + patternsize > s->vga.vram_size) {
|
||||
return 0;
|
||||
}
|
||||
src = s->vga.vram_ptr + s->cirrus_blt_srcaddr;
|
||||
} else {
|
||||
src = s->cirrus_bltbuf;
|
||||
}
|
||||
|
||||
if (blit_is_unsafe(s, true)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -709,7 +725,7 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop)
|
||||
{
|
||||
cirrus_fill_t rop_func;
|
||||
|
||||
if (blit_is_unsafe(s, true, true)) {
|
||||
if (blit_is_unsafe(s, true)) {
|
||||
return 0;
|
||||
}
|
||||
rop_func = cirrus_fill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
|
||||
@@ -731,8 +747,7 @@ static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop)
|
||||
|
||||
static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s)
|
||||
{
|
||||
return cirrus_bitblt_common_patterncopy(s, s->vga.vram_ptr +
|
||||
(s->cirrus_blt_srcaddr & ~7));
|
||||
return cirrus_bitblt_common_patterncopy(s, true);
|
||||
}
|
||||
|
||||
static int cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
|
||||
@@ -810,7 +825,7 @@ static int cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
|
||||
|
||||
static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s)
|
||||
{
|
||||
if (blit_is_unsafe(s, false, false))
|
||||
if (blit_is_unsafe(s, false))
|
||||
return 0;
|
||||
|
||||
return cirrus_do_copy(s, s->cirrus_blt_dstaddr - s->vga.start_addr,
|
||||
@@ -831,7 +846,7 @@ static void cirrus_bitblt_cputovideo_next(CirrusVGAState * s)
|
||||
|
||||
if (s->cirrus_srccounter > 0) {
|
||||
if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
|
||||
cirrus_bitblt_common_patterncopy(s, s->cirrus_bltbuf);
|
||||
cirrus_bitblt_common_patterncopy(s, false);
|
||||
the_end:
|
||||
s->cirrus_srccounter = 0;
|
||||
cirrus_bitblt_reset(s);
|
||||
@@ -1852,12 +1867,14 @@ static uint8_t cirrus_mmio_blt_read(CirrusVGAState * s, unsigned address)
|
||||
break;
|
||||
}
|
||||
|
||||
trace_vga_cirrus_write_blt(address, value);
|
||||
return (uint8_t) value;
|
||||
}
|
||||
|
||||
static void cirrus_mmio_blt_write(CirrusVGAState * s, unsigned address,
|
||||
uint8_t value)
|
||||
{
|
||||
trace_vga_cirrus_write_blt(address, value);
|
||||
switch (address) {
|
||||
case (CIRRUS_MMIO_BLTBGCOLOR + 0):
|
||||
cirrus_vga_write_gr(s, 0x00, value);
|
||||
@@ -2607,9 +2624,7 @@ static uint64_t cirrus_vga_ioport_read(void *opaque, hwaddr addr,
|
||||
break;
|
||||
}
|
||||
}
|
||||
#if defined(DEBUG_VGA)
|
||||
printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
|
||||
#endif
|
||||
trace_vga_cirrus_read_io(addr, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -2626,9 +2641,7 @@ static void cirrus_vga_ioport_write(void *opaque, hwaddr addr, uint64_t val,
|
||||
if (vga_ioport_invalid(s, addr)) {
|
||||
return;
|
||||
}
|
||||
#ifdef DEBUG_VGA
|
||||
printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
|
||||
#endif
|
||||
trace_vga_cirrus_write_io(addr, val);
|
||||
|
||||
switch (addr) {
|
||||
case 0x3c0:
|
||||
|
||||
@@ -464,7 +464,7 @@ static const VMStateDescription vmstate_g364fb = {
|
||||
.minimum_version_id = 1,
|
||||
.post_load = g364fb_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_VBUFFER_UINT32(vram, G364State, 1, NULL, 0, vram_size),
|
||||
VMSTATE_VBUFFER_UINT32(vram, G364State, 1, NULL, vram_size),
|
||||
VMSTATE_BUFFER_UNSAFE(color_palette, G364State, 0, 256 * 3),
|
||||
VMSTATE_BUFFER_UNSAFE(cursor_palette, G364State, 0, 9),
|
||||
VMSTATE_UINT16_ARRAY(cursor, G364State, 512),
|
||||
|
||||
@@ -119,3 +119,15 @@ qxl_set_client_capabilities_unsupported_by_revision(int qid, int revision) "%d r
|
||||
qxl_render_blit(int32_t stride, int32_t left, int32_t right, int32_t top, int32_t bottom) "stride=%d [%d, %d, %d, %d]"
|
||||
qxl_render_guest_primary_resized(int32_t width, int32_t height, int32_t stride, int32_t bytes_pp, int32_t bits_pp) "%dx%d, stride %d, bpp %d, depth %d"
|
||||
qxl_render_update_area_done(void *cookie) "%p"
|
||||
|
||||
# hw/display/vga.c
|
||||
vga_std_read_io(uint32_t addr, uint32_t val) "addr 0x%x, val 0x%x"
|
||||
vga_std_write_io(uint32_t addr, uint32_t val) "addr 0x%x, val 0x%x"
|
||||
vga_vbe_read(uint32_t index, uint32_t val) "index 0x%x, val 0x%x"
|
||||
vga_vbe_write(uint32_t index, uint32_t val) "index 0x%x, val 0x%x"
|
||||
|
||||
# hw/display/cirrus_vga.c
|
||||
vga_cirrus_read_io(uint32_t addr, uint32_t val) "addr 0x%x, val 0x%x"
|
||||
vga_cirrus_write_io(uint32_t addr, uint32_t val) "addr 0x%x, val 0x%x"
|
||||
vga_cirrus_read_blt(uint32_t offset, uint32_t val) "offset 0x%x, val 0x%x"
|
||||
vga_cirrus_write_blt(uint32_t offset, uint32_t val) "offset 0x%x, val 0x%x"
|
||||
|
||||
@@ -34,12 +34,9 @@
|
||||
#include "hw/xen/xen.h"
|
||||
#include "trace.h"
|
||||
|
||||
//#define DEBUG_VGA
|
||||
//#define DEBUG_VGA_MEM
|
||||
//#define DEBUG_VGA_REG
|
||||
|
||||
//#define DEBUG_BOCHS_VBE
|
||||
|
||||
/* 16 state changes per vertical frame @60 Hz */
|
||||
#define VGA_TEXT_CURSOR_PERIOD_MS (1000 * 2 * 16 / 60)
|
||||
|
||||
@@ -428,9 +425,7 @@ uint32_t vga_ioport_read(void *opaque, uint32_t addr)
|
||||
break;
|
||||
}
|
||||
}
|
||||
#if defined(DEBUG_VGA)
|
||||
printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
|
||||
#endif
|
||||
trace_vga_std_read_io(addr, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -443,9 +438,7 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
|
||||
if (vga_ioport_invalid(s, addr)) {
|
||||
return;
|
||||
}
|
||||
#ifdef DEBUG_VGA
|
||||
printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
|
||||
#endif
|
||||
trace_vga_std_write_io(addr, val);
|
||||
|
||||
switch(addr) {
|
||||
case VGA_ATT_W:
|
||||
@@ -733,9 +726,7 @@ uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
|
||||
} else {
|
||||
val = 0;
|
||||
}
|
||||
#ifdef DEBUG_BOCHS_VBE
|
||||
printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
|
||||
#endif
|
||||
trace_vga_vbe_read(s->vbe_index, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -750,9 +741,7 @@ void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
|
||||
VGACommonState *s = opaque;
|
||||
|
||||
if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
|
||||
#ifdef DEBUG_BOCHS_VBE
|
||||
printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
|
||||
#endif
|
||||
trace_vga_vbe_write(s->vbe_index, val);
|
||||
switch(s->vbe_index) {
|
||||
case VBE_DISPI_INDEX_ID:
|
||||
if (val == VBE_DISPI_ID0 ||
|
||||
@@ -1543,17 +1532,9 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
|
||||
height, format, s->line_offset,
|
||||
s->vram_ptr + (s->start_addr * 4));
|
||||
dpy_gfx_replace_surface(s->con, surface);
|
||||
#ifdef DEBUG_VGA
|
||||
printf("VGA: Using shared surface for depth=%d swap=%d\n",
|
||||
depth, byteswap);
|
||||
#endif
|
||||
} else {
|
||||
qemu_console_resize(s->con, disp_width, height);
|
||||
surface = qemu_console_surface(s->con);
|
||||
#ifdef DEBUG_VGA
|
||||
printf("VGA: Using shadow surface for depth=%d swap=%d\n",
|
||||
depth, byteswap);
|
||||
#endif
|
||||
}
|
||||
s->last_scr_width = disp_width;
|
||||
s->last_scr_height = height;
|
||||
|
||||
@@ -77,10 +77,18 @@ static void virgl_cmd_resource_unref(VirtIOGPU *g,
|
||||
struct virtio_gpu_ctrl_command *cmd)
|
||||
{
|
||||
struct virtio_gpu_resource_unref unref;
|
||||
struct iovec *res_iovs = NULL;
|
||||
int num_iovs = 0;
|
||||
|
||||
VIRTIO_GPU_FILL_CMD(unref);
|
||||
trace_virtio_gpu_cmd_res_unref(unref.resource_id);
|
||||
|
||||
virgl_renderer_resource_detach_iov(unref.resource_id,
|
||||
&res_iovs,
|
||||
&num_iovs);
|
||||
if (res_iovs != NULL && num_iovs != 0) {
|
||||
virtio_gpu_cleanup_mapping_iov(res_iovs, num_iovs);
|
||||
}
|
||||
virgl_renderer_resource_unref(unref.resource_id);
|
||||
}
|
||||
|
||||
|
||||
@@ -608,6 +608,7 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g,
|
||||
cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
|
||||
return;
|
||||
}
|
||||
pixman_image_unref(rect);
|
||||
dpy_gfx_replace_surface(g->scanout[ss.scanout_id].con, scanout->ds);
|
||||
}
|
||||
|
||||
|
||||
@@ -173,8 +173,8 @@ static const VMStateDescription vmstate_pl330_fifo = {
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_VBUFFER_UINT32(buf, PL330Fifo, 1, NULL, 0, buf_size),
|
||||
VMSTATE_VBUFFER_UINT32(tag, PL330Fifo, 1, NULL, 0, buf_size),
|
||||
VMSTATE_VBUFFER_UINT32(buf, PL330Fifo, 1, NULL, buf_size),
|
||||
VMSTATE_VBUFFER_UINT32(tag, PL330Fifo, 1, NULL, buf_size),
|
||||
VMSTATE_UINT32(head, PL330Fifo),
|
||||
VMSTATE_UINT32(num, PL330Fifo),
|
||||
VMSTATE_UINT32(buf_size, PL330Fifo),
|
||||
@@ -282,8 +282,8 @@ static const VMStateDescription vmstate_pl330 = {
|
||||
VMSTATE_STRUCT(manager, PL330State, 0, vmstate_pl330_chan, PL330Chan),
|
||||
VMSTATE_STRUCT_VARRAY_UINT32(chan, PL330State, num_chnls, 0,
|
||||
vmstate_pl330_chan, PL330Chan),
|
||||
VMSTATE_VBUFFER_UINT32(lo_seqn, PL330State, 1, NULL, 0, num_chnls),
|
||||
VMSTATE_VBUFFER_UINT32(hi_seqn, PL330State, 1, NULL, 0, num_chnls),
|
||||
VMSTATE_VBUFFER_UINT32(lo_seqn, PL330State, 1, NULL, num_chnls),
|
||||
VMSTATE_VBUFFER_UINT32(hi_seqn, PL330State, 1, NULL, num_chnls),
|
||||
VMSTATE_STRUCT(fifo, PL330State, 0, vmstate_pl330_fifo, PL330Fifo),
|
||||
VMSTATE_STRUCT(read_queue, PL330State, 0, vmstate_pl330_queue,
|
||||
PL330Queue),
|
||||
|
||||
@@ -114,11 +114,11 @@ static void kvm_ioapic_put(IOAPICCommonState *s)
|
||||
|
||||
void kvm_ioapic_dump_state(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
IOAPICCommonState s;
|
||||
IOAPICCommonState *s = IOAPIC_COMMON(object_resolve_path("ioapic", NULL));
|
||||
|
||||
kvm_ioapic_get(&s);
|
||||
|
||||
ioapic_print_redtbl(mon, &s);
|
||||
assert(s);
|
||||
kvm_ioapic_get(s);
|
||||
ioapic_print_redtbl(mon, s);
|
||||
}
|
||||
|
||||
static void kvm_ioapic_reset(DeviceState *dev)
|
||||
@@ -143,6 +143,11 @@ static void kvm_ioapic_realize(DeviceState *dev, Error **errp)
|
||||
IOAPICCommonState *s = IOAPIC_COMMON(dev);
|
||||
|
||||
memory_region_init_reservation(&s->io_memory, NULL, "kvm-ioapic", 0x1000);
|
||||
/*
|
||||
* KVM ioapic only supports 0x11 now. This will only be used when
|
||||
* we want to dump ioapic version.
|
||||
*/
|
||||
s->version = 0x11;
|
||||
|
||||
qdev_init_gpio_in(dev, kvm_ioapic_set_irq, IOAPIC_NUM_PINS);
|
||||
}
|
||||
|
||||
@@ -488,7 +488,7 @@ static void ahci_reg_init(AHCIState *s)
|
||||
s->control_regs.cap = (s->ports - 1) |
|
||||
(AHCI_NUM_COMMAND_SLOTS << 8) |
|
||||
(AHCI_SUPPORTED_SPEED_GEN1 << AHCI_SUPPORTED_SPEED) |
|
||||
HOST_CAP_NCQ | HOST_CAP_AHCI;
|
||||
HOST_CAP_NCQ | HOST_CAP_AHCI | HOST_CAP_64;
|
||||
|
||||
s->control_regs.impl = (1 << s->ports) - 1;
|
||||
|
||||
|
||||
@@ -251,6 +251,8 @@ static void apic_reset_common(DeviceState *dev)
|
||||
s->apicbase = APIC_DEFAULT_ADDRESS | bsp | MSR_IA32_APICBASE_ENABLE;
|
||||
s->id = s->initial_apic_id;
|
||||
|
||||
apic_reset_irq_delivered();
|
||||
|
||||
s->vapic_paddr = 0;
|
||||
info->vapic_base_update(s);
|
||||
|
||||
|
||||
@@ -393,7 +393,7 @@ static const VMStateDescription vmstate_exynos4210_irq_gate = {
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 2,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_VBUFFER_UINT32(level, Exynos4210IRQGateState, 1, NULL, 0, n_in),
|
||||
VMSTATE_VBUFFER_UINT32(level, Exynos4210IRQGateState, 1, NULL, n_in),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
@@ -408,13 +408,15 @@ static void ioapic_machine_done_notify(Notifier *notifier, void *data)
|
||||
#endif
|
||||
}
|
||||
|
||||
#define IOAPIC_VER_DEF 0x20
|
||||
|
||||
static void ioapic_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
IOAPICCommonState *s = IOAPIC_COMMON(dev);
|
||||
|
||||
if (s->version != 0x11 && s->version != 0x20) {
|
||||
error_report("IOAPIC only supports version 0x11 or 0x20 "
|
||||
"(default: 0x11).");
|
||||
"(default: 0x%x).", IOAPIC_VER_DEF);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -429,7 +431,7 @@ static void ioapic_realize(DeviceState *dev, Error **errp)
|
||||
}
|
||||
|
||||
static Property ioapic_properties[] = {
|
||||
DEFINE_PROP_UINT8("version", IOAPICCommonState, version, 0x20),
|
||||
DEFINE_PROP_UINT8("version", IOAPICCommonState, version, IOAPIC_VER_DEF),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
|
||||
@@ -471,10 +471,8 @@ static const VMStateDescription vmstate_ISAIPMIBTDevice = {
|
||||
VMSTATE_BOOL(bt.use_irq, ISAIPMIBTDevice),
|
||||
VMSTATE_BOOL(bt.irqs_enabled, ISAIPMIBTDevice),
|
||||
VMSTATE_UINT32(bt.outpos, ISAIPMIBTDevice),
|
||||
VMSTATE_VBUFFER_UINT32(bt.outmsg, ISAIPMIBTDevice, 1, NULL, 0,
|
||||
bt.outlen),
|
||||
VMSTATE_VBUFFER_UINT32(bt.inmsg, ISAIPMIBTDevice, 1, NULL, 0,
|
||||
bt.inlen),
|
||||
VMSTATE_VBUFFER_UINT32(bt.outmsg, ISAIPMIBTDevice, 1, NULL, bt.outlen),
|
||||
VMSTATE_VBUFFER_UINT32(bt.inmsg, ISAIPMIBTDevice, 1, NULL, bt.inlen),
|
||||
VMSTATE_UINT8(bt.control_reg, ISAIPMIBTDevice),
|
||||
VMSTATE_UINT8(bt.mask_reg, ISAIPMIBTDevice),
|
||||
VMSTATE_UINT8(bt.waiting_rsp, ISAIPMIBTDevice),
|
||||
|
||||
@@ -255,9 +255,9 @@ static void mcf5208evb_init(MachineState *machine)
|
||||
/* Internal peripherals. */
|
||||
pic = mcf_intc_init(address_space_mem, 0xfc048000, cpu);
|
||||
|
||||
mcf_uart_mm_init(address_space_mem, 0xfc060000, pic[26], serial_hds[0]);
|
||||
mcf_uart_mm_init(address_space_mem, 0xfc064000, pic[27], serial_hds[1]);
|
||||
mcf_uart_mm_init(address_space_mem, 0xfc068000, pic[28], serial_hds[2]);
|
||||
mcf_uart_mm_init(0xfc060000, pic[26], serial_hds[0]);
|
||||
mcf_uart_mm_init(0xfc064000, pic[27], serial_hds[1]);
|
||||
mcf_uart_mm_init(0xfc068000, pic[28], serial_hds[2]);
|
||||
|
||||
mcf5208_sys_init(address_space_mem, pic);
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@ common-obj-$(CONFIG_SGA) += sga.o
|
||||
common-obj-$(CONFIG_ISA_TESTDEV) += pc-testdev.o
|
||||
common-obj-$(CONFIG_PCI_TESTDEV) += pci-testdev.o
|
||||
|
||||
common-obj-y += unimp.o
|
||||
|
||||
obj-$(CONFIG_VMPORT) += vmport.o
|
||||
|
||||
# ARM devices
|
||||
|
||||
@@ -42,7 +42,7 @@ static void handle_event(int event)
|
||||
}
|
||||
|
||||
if (event & PVPANIC_PANICKED) {
|
||||
qemu_system_guest_panicked();
|
||||
qemu_system_guest_panicked(NULL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
107
hw/misc/unimp.c
Normal file
107
hw/misc/unimp.c
Normal file
@@ -0,0 +1,107 @@
|
||||
/* "Unimplemented" device
|
||||
*
|
||||
* This is a dummy device which accepts and logs all accesses.
|
||||
* It's useful for stubbing out regions of an SoC or board
|
||||
* map which correspond to devices that have not yet been
|
||||
* implemented. This is often sufficient to placate initial
|
||||
* guest device driver probing such that the system will
|
||||
* come up.
|
||||
*
|
||||
* Copyright Linaro Limited, 2017
|
||||
* Written by Peter Maydell
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/misc/unimp.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
#define UNIMPLEMENTED_DEVICE(obj) \
|
||||
OBJECT_CHECK(UnimplementedDeviceState, (obj), TYPE_UNIMPLEMENTED_DEVICE)
|
||||
|
||||
typedef struct {
|
||||
SysBusDevice parent_obj;
|
||||
MemoryRegion iomem;
|
||||
char *name;
|
||||
uint64_t size;
|
||||
} UnimplementedDeviceState;
|
||||
|
||||
static uint64_t unimp_read(void *opaque, hwaddr offset, unsigned size)
|
||||
{
|
||||
UnimplementedDeviceState *s = UNIMPLEMENTED_DEVICE(opaque);
|
||||
|
||||
qemu_log_mask(LOG_UNIMP, "%s: unimplemented device read "
|
||||
"(size %d, offset 0x%" HWADDR_PRIx ")\n",
|
||||
s->name, size, offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void unimp_write(void *opaque, hwaddr offset,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
UnimplementedDeviceState *s = UNIMPLEMENTED_DEVICE(opaque);
|
||||
|
||||
qemu_log_mask(LOG_UNIMP, "%s: unimplemented device write "
|
||||
"(size %d, value 0x%" PRIx64
|
||||
", offset 0x%" HWADDR_PRIx ")\n",
|
||||
s->name, size, value, offset);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps unimp_ops = {
|
||||
.read = unimp_read,
|
||||
.write = unimp_write,
|
||||
.impl.min_access_size = 1,
|
||||
.impl.max_access_size = 8,
|
||||
.valid.min_access_size = 1,
|
||||
.valid.max_access_size = 8,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static void unimp_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
UnimplementedDeviceState *s = UNIMPLEMENTED_DEVICE(dev);
|
||||
|
||||
if (s->size == 0) {
|
||||
error_setg(errp, "property 'size' not specified or zero");
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->name == NULL) {
|
||||
error_setg(errp, "property 'name' not specified");
|
||||
return;
|
||||
}
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &unimp_ops, s,
|
||||
s->name, s->size);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
|
||||
}
|
||||
|
||||
static Property unimp_properties[] = {
|
||||
DEFINE_PROP_UINT64("size", UnimplementedDeviceState, size, 0),
|
||||
DEFINE_PROP_STRING("name", UnimplementedDeviceState, name),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void unimp_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = unimp_realize;
|
||||
dc->props = unimp_properties;
|
||||
}
|
||||
|
||||
static const TypeInfo unimp_info = {
|
||||
.name = TYPE_UNIMPLEMENTED_DEVICE,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(UnimplementedDeviceState),
|
||||
.class_init = unimp_class_init,
|
||||
};
|
||||
|
||||
static void unimp_register_types(void)
|
||||
{
|
||||
type_register_static(&unimp_info);
|
||||
}
|
||||
|
||||
type_init(unimp_register_types)
|
||||
@@ -806,7 +806,8 @@ typedef struct E1000E_RingInfo_st {
|
||||
static inline bool
|
||||
e1000e_ring_empty(E1000ECore *core, const E1000E_RingInfo *r)
|
||||
{
|
||||
return core->mac[r->dh] == core->mac[r->dt];
|
||||
return core->mac[r->dh] == core->mac[r->dt] ||
|
||||
core->mac[r->dt] >= core->mac[r->dlen] / E1000_RING_DESC_LEN;
|
||||
}
|
||||
|
||||
static inline uint64_t
|
||||
@@ -1507,6 +1508,7 @@ e1000e_write_packet_to_guest(E1000ECore *core, struct NetRxPkt *pkt,
|
||||
const E1000E_RingInfo *rxi;
|
||||
size_t ps_hdr_len = 0;
|
||||
bool do_ps = e1000e_do_ps(core, pkt, &ps_hdr_len);
|
||||
bool is_first = true;
|
||||
|
||||
rxi = rxr->i;
|
||||
|
||||
@@ -1514,7 +1516,6 @@ e1000e_write_packet_to_guest(E1000ECore *core, struct NetRxPkt *pkt,
|
||||
hwaddr ba[MAX_PS_BUFFERS];
|
||||
e1000e_ba_state bastate = { { 0 } };
|
||||
bool is_last = false;
|
||||
bool is_first = true;
|
||||
|
||||
desc_size = total_size - desc_offset;
|
||||
|
||||
@@ -1522,6 +1523,10 @@ e1000e_write_packet_to_guest(E1000ECore *core, struct NetRxPkt *pkt,
|
||||
desc_size = core->rx_desc_buf_size;
|
||||
}
|
||||
|
||||
if (e1000e_ring_empty(core, rxi)) {
|
||||
return;
|
||||
}
|
||||
|
||||
base = e1000e_ring_head_descr(core, rxi);
|
||||
|
||||
pci_dma_read(d, base, &desc, core->rx_desc_len);
|
||||
|
||||
@@ -55,6 +55,8 @@
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define IMX_MAX_DESC 1024
|
||||
|
||||
static const char *imx_default_reg_name(IMXFECState *s, uint32_t index)
|
||||
{
|
||||
static char tmp[20];
|
||||
@@ -402,12 +404,12 @@ static void imx_eth_update(IMXFECState *s)
|
||||
|
||||
static void imx_fec_do_tx(IMXFECState *s)
|
||||
{
|
||||
int frame_size = 0;
|
||||
int frame_size = 0, descnt = 0;
|
||||
uint8_t frame[ENET_MAX_FRAME_SIZE];
|
||||
uint8_t *ptr = frame;
|
||||
uint32_t addr = s->tx_descriptor;
|
||||
|
||||
while (1) {
|
||||
while (descnt++ < IMX_MAX_DESC) {
|
||||
IMXFECBufDesc bd;
|
||||
int len;
|
||||
|
||||
@@ -453,12 +455,12 @@ static void imx_fec_do_tx(IMXFECState *s)
|
||||
|
||||
static void imx_enet_do_tx(IMXFECState *s)
|
||||
{
|
||||
int frame_size = 0;
|
||||
int frame_size = 0, descnt = 0;
|
||||
uint8_t frame[ENET_MAX_FRAME_SIZE];
|
||||
uint8_t *ptr = frame;
|
||||
uint32_t addr = s->tx_descriptor;
|
||||
|
||||
while (1) {
|
||||
while (descnt++ < IMX_MAX_DESC) {
|
||||
IMXENETBufDesc bd;
|
||||
int len;
|
||||
|
||||
|
||||
@@ -1557,119 +1557,22 @@ static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue)
|
||||
virtio_net_set_queues(n);
|
||||
}
|
||||
|
||||
static void virtio_net_save_device(VirtIODevice *vdev, QEMUFile *f)
|
||||
static int virtio_net_post_load_device(void *opaque, int version_id)
|
||||
{
|
||||
VirtIONet *n = VIRTIO_NET(vdev);
|
||||
int i;
|
||||
|
||||
qemu_put_buffer(f, n->mac, ETH_ALEN);
|
||||
qemu_put_be32(f, n->vqs[0].tx_waiting);
|
||||
qemu_put_be32(f, n->mergeable_rx_bufs);
|
||||
qemu_put_be16(f, n->status);
|
||||
qemu_put_byte(f, n->promisc);
|
||||
qemu_put_byte(f, n->allmulti);
|
||||
qemu_put_be32(f, n->mac_table.in_use);
|
||||
qemu_put_buffer(f, n->mac_table.macs, n->mac_table.in_use * ETH_ALEN);
|
||||
qemu_put_buffer(f, (uint8_t *)n->vlans, MAX_VLAN >> 3);
|
||||
qemu_put_be32(f, n->has_vnet_hdr);
|
||||
qemu_put_byte(f, n->mac_table.multi_overflow);
|
||||
qemu_put_byte(f, n->mac_table.uni_overflow);
|
||||
qemu_put_byte(f, n->alluni);
|
||||
qemu_put_byte(f, n->nomulti);
|
||||
qemu_put_byte(f, n->nouni);
|
||||
qemu_put_byte(f, n->nobcast);
|
||||
qemu_put_byte(f, n->has_ufo);
|
||||
if (n->max_queues > 1) {
|
||||
qemu_put_be16(f, n->max_queues);
|
||||
qemu_put_be16(f, n->curr_queues);
|
||||
for (i = 1; i < n->curr_queues; i++) {
|
||||
qemu_put_be32(f, n->vqs[i].tx_waiting);
|
||||
}
|
||||
}
|
||||
|
||||
if (virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) {
|
||||
qemu_put_be64(f, n->curr_guest_offloads);
|
||||
}
|
||||
}
|
||||
|
||||
static int virtio_net_load_device(VirtIODevice *vdev, QEMUFile *f,
|
||||
int version_id)
|
||||
{
|
||||
VirtIONet *n = VIRTIO_NET(vdev);
|
||||
VirtIONet *n = opaque;
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(n);
|
||||
int i, link_down;
|
||||
|
||||
qemu_get_buffer(f, n->mac, ETH_ALEN);
|
||||
n->vqs[0].tx_waiting = qemu_get_be32(f);
|
||||
|
||||
virtio_net_set_mrg_rx_bufs(n, qemu_get_be32(f),
|
||||
virtio_net_set_mrg_rx_bufs(n, n->mergeable_rx_bufs,
|
||||
virtio_vdev_has_feature(vdev,
|
||||
VIRTIO_F_VERSION_1));
|
||||
|
||||
n->status = qemu_get_be16(f);
|
||||
|
||||
n->promisc = qemu_get_byte(f);
|
||||
n->allmulti = qemu_get_byte(f);
|
||||
|
||||
n->mac_table.in_use = qemu_get_be32(f);
|
||||
/* MAC_TABLE_ENTRIES may be different from the saved image */
|
||||
if (n->mac_table.in_use <= MAC_TABLE_ENTRIES) {
|
||||
qemu_get_buffer(f, n->mac_table.macs,
|
||||
n->mac_table.in_use * ETH_ALEN);
|
||||
} else {
|
||||
int64_t i;
|
||||
|
||||
/* Overflow detected - can happen if source has a larger MAC table.
|
||||
* We simply set overflow flag so there's no need to maintain the
|
||||
* table of addresses, discard them all.
|
||||
* Note: 64 bit math to avoid integer overflow.
|
||||
*/
|
||||
for (i = 0; i < (int64_t)n->mac_table.in_use * ETH_ALEN; ++i) {
|
||||
qemu_get_byte(f);
|
||||
}
|
||||
n->mac_table.multi_overflow = n->mac_table.uni_overflow = 1;
|
||||
if (n->mac_table.in_use > MAC_TABLE_ENTRIES) {
|
||||
n->mac_table.in_use = 0;
|
||||
}
|
||||
|
||||
qemu_get_buffer(f, (uint8_t *)n->vlans, MAX_VLAN >> 3);
|
||||
|
||||
if (qemu_get_be32(f) && !peer_has_vnet_hdr(n)) {
|
||||
error_report("virtio-net: saved image requires vnet_hdr=on");
|
||||
return -1;
|
||||
}
|
||||
|
||||
n->mac_table.multi_overflow = qemu_get_byte(f);
|
||||
n->mac_table.uni_overflow = qemu_get_byte(f);
|
||||
|
||||
n->alluni = qemu_get_byte(f);
|
||||
n->nomulti = qemu_get_byte(f);
|
||||
n->nouni = qemu_get_byte(f);
|
||||
n->nobcast = qemu_get_byte(f);
|
||||
|
||||
if (qemu_get_byte(f) && !peer_has_ufo(n)) {
|
||||
error_report("virtio-net: saved image requires TUN_F_UFO support");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (n->max_queues > 1) {
|
||||
if (n->max_queues != qemu_get_be16(f)) {
|
||||
error_report("virtio-net: different max_queues ");
|
||||
return -1;
|
||||
}
|
||||
|
||||
n->curr_queues = qemu_get_be16(f);
|
||||
if (n->curr_queues > n->max_queues) {
|
||||
error_report("virtio-net: curr_queues %x > max_queues %x",
|
||||
n->curr_queues, n->max_queues);
|
||||
return -1;
|
||||
}
|
||||
for (i = 1; i < n->curr_queues; i++) {
|
||||
n->vqs[i].tx_waiting = qemu_get_be32(f);
|
||||
}
|
||||
}
|
||||
|
||||
if (virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) {
|
||||
n->curr_guest_offloads = qemu_get_be64(f);
|
||||
} else {
|
||||
if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) {
|
||||
n->curr_guest_offloads = virtio_net_supported_guest_offloads(n);
|
||||
}
|
||||
|
||||
@@ -1703,6 +1606,210 @@ static int virtio_net_load_device(VirtIODevice *vdev, QEMUFile *f,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* tx_waiting field of a VirtIONetQueue */
|
||||
static const VMStateDescription vmstate_virtio_net_queue_tx_waiting = {
|
||||
.name = "virtio-net-queue-tx_waiting",
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(tx_waiting, VirtIONetQueue),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
};
|
||||
|
||||
static bool max_queues_gt_1(void *opaque, int version_id)
|
||||
{
|
||||
return VIRTIO_NET(opaque)->max_queues > 1;
|
||||
}
|
||||
|
||||
static bool has_ctrl_guest_offloads(void *opaque, int version_id)
|
||||
{
|
||||
return virtio_vdev_has_feature(VIRTIO_DEVICE(opaque),
|
||||
VIRTIO_NET_F_CTRL_GUEST_OFFLOADS);
|
||||
}
|
||||
|
||||
static bool mac_table_fits(void *opaque, int version_id)
|
||||
{
|
||||
return VIRTIO_NET(opaque)->mac_table.in_use <= MAC_TABLE_ENTRIES;
|
||||
}
|
||||
|
||||
static bool mac_table_doesnt_fit(void *opaque, int version_id)
|
||||
{
|
||||
return !mac_table_fits(opaque, version_id);
|
||||
}
|
||||
|
||||
/* This temporary type is shared by all the WITH_TMP methods
|
||||
* although only some fields are used by each.
|
||||
*/
|
||||
struct VirtIONetMigTmp {
|
||||
VirtIONet *parent;
|
||||
VirtIONetQueue *vqs_1;
|
||||
uint16_t curr_queues_1;
|
||||
uint8_t has_ufo;
|
||||
uint32_t has_vnet_hdr;
|
||||
};
|
||||
|
||||
/* The 2nd and subsequent tx_waiting flags are loaded later than
|
||||
* the 1st entry in the queues and only if there's more than one
|
||||
* entry. We use the tmp mechanism to calculate a temporary
|
||||
* pointer and count and also validate the count.
|
||||
*/
|
||||
|
||||
static void virtio_net_tx_waiting_pre_save(void *opaque)
|
||||
{
|
||||
struct VirtIONetMigTmp *tmp = opaque;
|
||||
|
||||
tmp->vqs_1 = tmp->parent->vqs + 1;
|
||||
tmp->curr_queues_1 = tmp->parent->curr_queues - 1;
|
||||
if (tmp->parent->curr_queues == 0) {
|
||||
tmp->curr_queues_1 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int virtio_net_tx_waiting_pre_load(void *opaque)
|
||||
{
|
||||
struct VirtIONetMigTmp *tmp = opaque;
|
||||
|
||||
/* Reuse the pointer setup from save */
|
||||
virtio_net_tx_waiting_pre_save(opaque);
|
||||
|
||||
if (tmp->parent->curr_queues > tmp->parent->max_queues) {
|
||||
error_report("virtio-net: curr_queues %x > max_queues %x",
|
||||
tmp->parent->curr_queues, tmp->parent->max_queues);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0; /* all good */
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_virtio_net_tx_waiting = {
|
||||
.name = "virtio-net-tx_waiting",
|
||||
.pre_load = virtio_net_tx_waiting_pre_load,
|
||||
.pre_save = virtio_net_tx_waiting_pre_save,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_STRUCT_VARRAY_POINTER_UINT16(vqs_1, struct VirtIONetMigTmp,
|
||||
curr_queues_1,
|
||||
vmstate_virtio_net_queue_tx_waiting,
|
||||
struct VirtIONetQueue),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
};
|
||||
|
||||
/* the 'has_ufo' flag is just tested; if the incoming stream has the
|
||||
* flag set we need to check that we have it
|
||||
*/
|
||||
static int virtio_net_ufo_post_load(void *opaque, int version_id)
|
||||
{
|
||||
struct VirtIONetMigTmp *tmp = opaque;
|
||||
|
||||
if (tmp->has_ufo && !peer_has_ufo(tmp->parent)) {
|
||||
error_report("virtio-net: saved image requires TUN_F_UFO support");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void virtio_net_ufo_pre_save(void *opaque)
|
||||
{
|
||||
struct VirtIONetMigTmp *tmp = opaque;
|
||||
|
||||
tmp->has_ufo = tmp->parent->has_ufo;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_virtio_net_has_ufo = {
|
||||
.name = "virtio-net-ufo",
|
||||
.post_load = virtio_net_ufo_post_load,
|
||||
.pre_save = virtio_net_ufo_pre_save,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT8(has_ufo, struct VirtIONetMigTmp),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
};
|
||||
|
||||
/* the 'has_vnet_hdr' flag is just tested; if the incoming stream has the
|
||||
* flag set we need to check that we have it
|
||||
*/
|
||||
static int virtio_net_vnet_post_load(void *opaque, int version_id)
|
||||
{
|
||||
struct VirtIONetMigTmp *tmp = opaque;
|
||||
|
||||
if (tmp->has_vnet_hdr && !peer_has_vnet_hdr(tmp->parent)) {
|
||||
error_report("virtio-net: saved image requires vnet_hdr=on");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void virtio_net_vnet_pre_save(void *opaque)
|
||||
{
|
||||
struct VirtIONetMigTmp *tmp = opaque;
|
||||
|
||||
tmp->has_vnet_hdr = tmp->parent->has_vnet_hdr;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_virtio_net_has_vnet = {
|
||||
.name = "virtio-net-vnet",
|
||||
.post_load = virtio_net_vnet_post_load,
|
||||
.pre_save = virtio_net_vnet_pre_save,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(has_vnet_hdr, struct VirtIONetMigTmp),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_virtio_net_device = {
|
||||
.name = "virtio-net-device",
|
||||
.version_id = VIRTIO_NET_VM_VERSION,
|
||||
.minimum_version_id = VIRTIO_NET_VM_VERSION,
|
||||
.post_load = virtio_net_post_load_device,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT8_ARRAY(mac, VirtIONet, ETH_ALEN),
|
||||
VMSTATE_STRUCT_POINTER(vqs, VirtIONet,
|
||||
vmstate_virtio_net_queue_tx_waiting,
|
||||
VirtIONetQueue),
|
||||
VMSTATE_UINT32(mergeable_rx_bufs, VirtIONet),
|
||||
VMSTATE_UINT16(status, VirtIONet),
|
||||
VMSTATE_UINT8(promisc, VirtIONet),
|
||||
VMSTATE_UINT8(allmulti, VirtIONet),
|
||||
VMSTATE_UINT32(mac_table.in_use, VirtIONet),
|
||||
|
||||
/* Guarded pair: If it fits we load it, else we throw it away
|
||||
* - can happen if source has a larger MAC table.; post-load
|
||||
* sets flags in this case.
|
||||
*/
|
||||
VMSTATE_VBUFFER_MULTIPLY(mac_table.macs, VirtIONet,
|
||||
0, mac_table_fits, mac_table.in_use,
|
||||
ETH_ALEN),
|
||||
VMSTATE_UNUSED_VARRAY_UINT32(VirtIONet, mac_table_doesnt_fit, 0,
|
||||
mac_table.in_use, ETH_ALEN),
|
||||
|
||||
/* Note: This is an array of uint32's that's always been saved as a
|
||||
* buffer; hold onto your endiannesses; it's actually used as a bitmap
|
||||
* but based on the uint.
|
||||
*/
|
||||
VMSTATE_BUFFER_POINTER_UNSAFE(vlans, VirtIONet, 0, MAX_VLAN >> 3),
|
||||
VMSTATE_WITH_TMP(VirtIONet, struct VirtIONetMigTmp,
|
||||
vmstate_virtio_net_has_vnet),
|
||||
VMSTATE_UINT8(mac_table.multi_overflow, VirtIONet),
|
||||
VMSTATE_UINT8(mac_table.uni_overflow, VirtIONet),
|
||||
VMSTATE_UINT8(alluni, VirtIONet),
|
||||
VMSTATE_UINT8(nomulti, VirtIONet),
|
||||
VMSTATE_UINT8(nouni, VirtIONet),
|
||||
VMSTATE_UINT8(nobcast, VirtIONet),
|
||||
VMSTATE_WITH_TMP(VirtIONet, struct VirtIONetMigTmp,
|
||||
vmstate_virtio_net_has_ufo),
|
||||
VMSTATE_SINGLE_TEST(max_queues, VirtIONet, max_queues_gt_1, 0,
|
||||
vmstate_info_uint16_equal, uint16_t),
|
||||
VMSTATE_UINT16_TEST(curr_queues, VirtIONet, max_queues_gt_1),
|
||||
VMSTATE_WITH_TMP(VirtIONet, struct VirtIONetMigTmp,
|
||||
vmstate_virtio_net_tx_waiting),
|
||||
VMSTATE_UINT64_TEST(curr_guest_offloads, VirtIONet,
|
||||
has_ctrl_guest_offloads),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
};
|
||||
|
||||
static NetClientInfo net_virtio_info = {
|
||||
.type = NET_CLIENT_DRIVER_NIC,
|
||||
.size = sizeof(NICState),
|
||||
@@ -1989,9 +2096,8 @@ static void virtio_net_class_init(ObjectClass *klass, void *data)
|
||||
vdc->set_status = virtio_net_set_status;
|
||||
vdc->guest_notifier_mask = virtio_net_guest_notifier_mask;
|
||||
vdc->guest_notifier_pending = virtio_net_guest_notifier_pending;
|
||||
vdc->load = virtio_net_load_device;
|
||||
vdc->save = virtio_net_save_device;
|
||||
vdc->legacy_features |= (0x1 << VIRTIO_NET_F_GSO);
|
||||
vdc->vmsd = &vmstate_virtio_net_device;
|
||||
}
|
||||
|
||||
static const TypeInfo virtio_net_info = {
|
||||
|
||||
@@ -2397,7 +2397,7 @@ static const VMStateDescription vmxstate_vmxnet3_mcast_list = {
|
||||
.pre_load = vmxnet3_mcast_list_pre_load,
|
||||
.needed = vmxnet3_mc_list_needed,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_VBUFFER_UINT32(mcast_list, VMXNET3State, 0, NULL, 0,
|
||||
VMSTATE_VBUFFER_UINT32(mcast_list, VMXNET3State, 0, NULL,
|
||||
mcast_list_buff_size),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ static const VMStateDescription vmstate_macio_nvram = {
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_VBUFFER_UINT32(data, MacIONVRAMState, 0, NULL, 0, size),
|
||||
VMSTATE_VBUFFER_UINT32(data, MacIONVRAMState, 0, NULL, size),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
@@ -224,7 +224,7 @@ static const VMStateDescription vmstate_spapr_nvram = {
|
||||
.post_load = spapr_nvram_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(size, sPAPRNVRAM),
|
||||
VMSTATE_VBUFFER_ALLOC_UINT32(buf, sPAPRNVRAM, 1, NULL, 0, size),
|
||||
VMSTATE_VBUFFER_ALLOC_UINT32(buf, sPAPRNVRAM, 1, NULL, size),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
};
|
||||
|
||||
@@ -139,10 +139,10 @@ static void openrisc_sim_init(MachineState *machine)
|
||||
|
||||
static void openrisc_sim_machine_init(MachineClass *mc)
|
||||
{
|
||||
mc->desc = "or32 simulation";
|
||||
mc->desc = "or1k simulation";
|
||||
mc->init = openrisc_sim_init;
|
||||
mc->max_cpus = 1;
|
||||
mc->is_default = 1;
|
||||
}
|
||||
|
||||
DEFINE_MACHINE("or32-sim", openrisc_sim_machine_init)
|
||||
DEFINE_MACHINE("or1k-sim", openrisc_sim_machine_init)
|
||||
|
||||
@@ -334,7 +334,8 @@ static void rtas_ibm_os_term(PowerPCCPU *cpu,
|
||||
{
|
||||
target_ulong ret = 0;
|
||||
|
||||
qapi_event_send_guest_panicked(GUEST_PANIC_ACTION_PAUSE, &error_abort);
|
||||
qapi_event_send_guest_panicked(GUEST_PANIC_ACTION_PAUSE, false, NULL,
|
||||
&error_abort);
|
||||
|
||||
rtas_st(rets, 0, ret);
|
||||
}
|
||||
|
||||
@@ -536,7 +536,7 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s)
|
||||
boundary_count -= block_size - begin;
|
||||
}
|
||||
dma_memory_read(&address_space_memory, s->sdmasysad,
|
||||
&s->fifo_buffer[begin], s->data_count);
|
||||
&s->fifo_buffer[begin], s->data_count - begin);
|
||||
s->sdmasysad += s->data_count - begin;
|
||||
if (s->data_count == block_size) {
|
||||
for (n = 0; n < block_size; n++) {
|
||||
@@ -1253,7 +1253,7 @@ const VMStateDescription sdhci_vmstate = {
|
||||
VMSTATE_UINT16(data_count, SDHCIState),
|
||||
VMSTATE_UINT64(admasysaddr, SDHCIState),
|
||||
VMSTATE_UINT8(stopped_state, SDHCIState),
|
||||
VMSTATE_VBUFFER_UINT32(fifo_buffer, SDHCIState, 1, NULL, 0, buf_maxsz),
|
||||
VMSTATE_VBUFFER_UINT32(fifo_buffer, SDHCIState, 1, NULL, buf_maxsz),
|
||||
VMSTATE_TIMER_PTR(insert_timer, SDHCIState),
|
||||
VMSTATE_TIMER_PTR(transfer_timer, SDHCIState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
|
||||
@@ -475,15 +475,15 @@ static uint32_t aspeed_smc_check_segment_addr(const AspeedSMCFlash *fl,
|
||||
AspeedSegments seg;
|
||||
|
||||
aspeed_smc_reg_to_segment(s->regs[R_SEG_ADDR0 + fl->id], &seg);
|
||||
if ((addr & (seg.size - 1)) != addr) {
|
||||
if ((addr % seg.size) != addr) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: invalid address 0x%08x for CS%d segment : "
|
||||
"[ 0x%"HWADDR_PRIx" - 0x%"HWADDR_PRIx" ]\n",
|
||||
s->ctrl->name, addr, fl->id, seg.addr,
|
||||
seg.addr + seg.size);
|
||||
addr %= seg.size;
|
||||
}
|
||||
|
||||
addr &= seg.size - 1;
|
||||
return addr;
|
||||
}
|
||||
|
||||
@@ -536,10 +536,13 @@ static uint64_t aspeed_smc_flash_read(void *opaque, hwaddr addr, unsigned size)
|
||||
/*
|
||||
* Use fake transfers to model dummy bytes. The value should
|
||||
* be configured to some non-zero value in fast read mode and
|
||||
* zero in read mode.
|
||||
* zero in read mode. But, as the HW allows inconsistent
|
||||
* settings, let's check for fast read mode.
|
||||
*/
|
||||
for (i = 0; i < aspeed_smc_flash_dummies(fl); i++) {
|
||||
ssi_transfer(fl->controller->spi, 0xFF);
|
||||
if (aspeed_smc_flash_mode(fl) == CTRL_FREADMODE) {
|
||||
for (i = 0; i < aspeed_smc_flash_dummies(fl); i++) {
|
||||
ssi_transfer(fl->controller->spi, 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
|
||||
@@ -563,7 +563,7 @@ static const VMStateDescription vmstate_m48t59 = {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT8(lock, M48t59State),
|
||||
VMSTATE_UINT16(addr, M48t59State),
|
||||
VMSTATE_VBUFFER_UINT32(buffer, M48t59State, 0, NULL, 0, size),
|
||||
VMSTATE_VBUFFER_UINT32(buffer, M48t59State, 0, NULL, size),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ ifeq ($(CONFIG_LINUX), y)
|
||||
obj-$(CONFIG_SOFTMMU) += common.o
|
||||
obj-$(CONFIG_PCI) += pci.o pci-quirks.o
|
||||
obj-$(CONFIG_SOFTMMU) += platform.o
|
||||
obj-$(CONFIG_SOFTMMU) += calxeda-xgmac.o
|
||||
obj-$(CONFIG_SOFTMMU) += amd-xgbe.o
|
||||
obj-$(CONFIG_VFIO_XGMAC) += calxeda-xgmac.o
|
||||
obj-$(CONFIG_VFIO_AMD_XGBE) += amd-xgbe.o
|
||||
obj-$(CONFIG_SOFTMMU) += spapr.o
|
||||
endif
|
||||
|
||||
@@ -1041,6 +1041,7 @@ static int igd_gen(VFIOPCIDevice *vdev)
|
||||
typedef struct VFIOIGDQuirk {
|
||||
struct VFIOPCIDevice *vdev;
|
||||
uint32_t index;
|
||||
uint32_t bdsm;
|
||||
} VFIOIGDQuirk;
|
||||
|
||||
#define IGD_GMCH 0x50 /* Graphics Control Register */
|
||||
@@ -1185,6 +1186,7 @@ static void vfio_pci_igd_lpc_bridge_class_init(ObjectClass *klass, void *data)
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
||||
|
||||
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
|
||||
dc->desc = "VFIO dummy ISA/LPC bridge for IGD assignment";
|
||||
dc->hotpluggable = false;
|
||||
k->realize = vfio_pci_igd_lpc_bridge_realize;
|
||||
@@ -1304,7 +1306,7 @@ static void vfio_igd_quirk_data_write(void *opaque, hwaddr addr,
|
||||
"BIOS reserved stolen memory. Unsupported BIOS?");
|
||||
}
|
||||
|
||||
val = base | (data & ((1 << 20) - 1));
|
||||
val = data - igd->bdsm + base;
|
||||
} else {
|
||||
val = 0; /* upper 32bits of pte, we only enable below 4G PTEs */
|
||||
}
|
||||
@@ -1503,6 +1505,8 @@ static void vfio_probe_igd_bar4_quirk(VFIOPCIDevice *vdev, int nr)
|
||||
igd = quirk->data = g_malloc0(sizeof(*igd));
|
||||
igd->vdev = vdev;
|
||||
igd->index = ~0;
|
||||
igd->bdsm = vfio_pci_read_config(&vdev->pdev, IGD_BDSM, 4);
|
||||
igd->bdsm &= ~((1 << 20) - 1); /* 1MB aligned */
|
||||
|
||||
memory_region_init_io(&quirk->mem[0], OBJECT(vdev), &vfio_igd_index_quirk,
|
||||
igd, "vfio-igd-index-quirk", 4);
|
||||
|
||||
@@ -2,3 +2,4 @@ common-obj-y += watchdog.o
|
||||
common-obj-$(CONFIG_WDT_IB6300ESB) += wdt_i6300esb.o
|
||||
common-obj-$(CONFIG_WDT_IB700) += wdt_ib700.o
|
||||
common-obj-$(CONFIG_WDT_DIAG288) += wdt_diag288.o
|
||||
common-obj-$(CONFIG_ASPEED_SOC) += wdt_aspeed.o
|
||||
|
||||
225
hw/watchdog/wdt_aspeed.c
Normal file
225
hw/watchdog/wdt_aspeed.c
Normal file
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
* ASPEED Watchdog Controller
|
||||
*
|
||||
* Copyright (C) 2016-2017 IBM Corp.
|
||||
*
|
||||
* This code is licensed under the GPL version 2 or later. See the
|
||||
* COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/log.h"
|
||||
#include "sysemu/watchdog.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "hw/watchdog/wdt_aspeed.h"
|
||||
|
||||
#define WDT_STATUS (0x00 / 4)
|
||||
#define WDT_RELOAD_VALUE (0x04 / 4)
|
||||
#define WDT_RESTART (0x08 / 4)
|
||||
#define WDT_CTRL (0x0C / 4)
|
||||
#define WDT_CTRL_RESET_MODE_SOC (0x00 << 5)
|
||||
#define WDT_CTRL_RESET_MODE_FULL_CHIP (0x01 << 5)
|
||||
#define WDT_CTRL_1MHZ_CLK BIT(4)
|
||||
#define WDT_CTRL_WDT_EXT BIT(3)
|
||||
#define WDT_CTRL_WDT_INTR BIT(2)
|
||||
#define WDT_CTRL_RESET_SYSTEM BIT(1)
|
||||
#define WDT_CTRL_ENABLE BIT(0)
|
||||
|
||||
#define WDT_TIMEOUT_STATUS (0x10 / 4)
|
||||
#define WDT_TIMEOUT_CLEAR (0x14 / 4)
|
||||
#define WDT_RESET_WDITH (0x18 / 4)
|
||||
|
||||
#define WDT_RESTART_MAGIC 0x4755
|
||||
|
||||
static bool aspeed_wdt_is_enabled(const AspeedWDTState *s)
|
||||
{
|
||||
return s->regs[WDT_CTRL] & WDT_CTRL_ENABLE;
|
||||
}
|
||||
|
||||
static uint64_t aspeed_wdt_read(void *opaque, hwaddr offset, unsigned size)
|
||||
{
|
||||
AspeedWDTState *s = ASPEED_WDT(opaque);
|
||||
|
||||
offset >>= 2;
|
||||
|
||||
switch (offset) {
|
||||
case WDT_STATUS:
|
||||
return s->regs[WDT_STATUS];
|
||||
case WDT_RELOAD_VALUE:
|
||||
return s->regs[WDT_RELOAD_VALUE];
|
||||
case WDT_RESTART:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: read from write-only reg at offset 0x%"
|
||||
HWADDR_PRIx "\n", __func__, offset);
|
||||
return 0;
|
||||
case WDT_CTRL:
|
||||
return s->regs[WDT_CTRL];
|
||||
case WDT_TIMEOUT_STATUS:
|
||||
case WDT_TIMEOUT_CLEAR:
|
||||
case WDT_RESET_WDITH:
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
"%s: uninmplemented read at offset 0x%" HWADDR_PRIx "\n",
|
||||
__func__, offset);
|
||||
return 0;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
|
||||
__func__, offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void aspeed_wdt_reload(AspeedWDTState *s, bool pclk)
|
||||
{
|
||||
uint32_t reload;
|
||||
|
||||
if (pclk) {
|
||||
reload = muldiv64(s->regs[WDT_RELOAD_VALUE], NANOSECONDS_PER_SECOND,
|
||||
s->pclk_freq);
|
||||
} else {
|
||||
reload = s->regs[WDT_RELOAD_VALUE] * 1000;
|
||||
}
|
||||
|
||||
if (aspeed_wdt_is_enabled(s)) {
|
||||
timer_mod(s->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + reload);
|
||||
}
|
||||
}
|
||||
|
||||
static void aspeed_wdt_write(void *opaque, hwaddr offset, uint64_t data,
|
||||
unsigned size)
|
||||
{
|
||||
AspeedWDTState *s = ASPEED_WDT(opaque);
|
||||
bool enable = data & WDT_CTRL_ENABLE;
|
||||
|
||||
offset >>= 2;
|
||||
|
||||
switch (offset) {
|
||||
case WDT_STATUS:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: write to read-only reg at offset 0x%"
|
||||
HWADDR_PRIx "\n", __func__, offset);
|
||||
break;
|
||||
case WDT_RELOAD_VALUE:
|
||||
s->regs[WDT_RELOAD_VALUE] = data;
|
||||
break;
|
||||
case WDT_RESTART:
|
||||
if ((data & 0xFFFF) == WDT_RESTART_MAGIC) {
|
||||
s->regs[WDT_STATUS] = s->regs[WDT_RELOAD_VALUE];
|
||||
aspeed_wdt_reload(s, !(data & WDT_CTRL_1MHZ_CLK));
|
||||
}
|
||||
break;
|
||||
case WDT_CTRL:
|
||||
if (enable && !aspeed_wdt_is_enabled(s)) {
|
||||
s->regs[WDT_CTRL] = data;
|
||||
aspeed_wdt_reload(s, !(data & WDT_CTRL_1MHZ_CLK));
|
||||
} else if (!enable && aspeed_wdt_is_enabled(s)) {
|
||||
s->regs[WDT_CTRL] = data;
|
||||
timer_del(s->timer);
|
||||
}
|
||||
break;
|
||||
case WDT_TIMEOUT_STATUS:
|
||||
case WDT_TIMEOUT_CLEAR:
|
||||
case WDT_RESET_WDITH:
|
||||
qemu_log_mask(LOG_UNIMP,
|
||||
"%s: uninmplemented write at offset 0x%" HWADDR_PRIx "\n",
|
||||
__func__, offset);
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
|
||||
__func__, offset);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static WatchdogTimerModel model = {
|
||||
.wdt_name = TYPE_ASPEED_WDT,
|
||||
.wdt_description = "Aspeed watchdog device",
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_aspeed_wdt = {
|
||||
.name = "vmstate_aspeed_wdt",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_TIMER_PTR(timer, AspeedWDTState),
|
||||
VMSTATE_UINT32_ARRAY(regs, AspeedWDTState, ASPEED_WDT_REGS_MAX),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static const MemoryRegionOps aspeed_wdt_ops = {
|
||||
.read = aspeed_wdt_read,
|
||||
.write = aspeed_wdt_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.valid.min_access_size = 4,
|
||||
.valid.max_access_size = 4,
|
||||
.valid.unaligned = false,
|
||||
};
|
||||
|
||||
static void aspeed_wdt_reset(DeviceState *dev)
|
||||
{
|
||||
AspeedWDTState *s = ASPEED_WDT(dev);
|
||||
|
||||
s->regs[WDT_STATUS] = 0x3EF1480;
|
||||
s->regs[WDT_RELOAD_VALUE] = 0x03EF1480;
|
||||
s->regs[WDT_RESTART] = 0;
|
||||
s->regs[WDT_CTRL] = 0;
|
||||
|
||||
timer_del(s->timer);
|
||||
}
|
||||
|
||||
static void aspeed_wdt_timer_expired(void *dev)
|
||||
{
|
||||
AspeedWDTState *s = ASPEED_WDT(dev);
|
||||
|
||||
qemu_log_mask(CPU_LOG_RESET, "Watchdog timer expired.\n");
|
||||
watchdog_perform_action();
|
||||
timer_del(s->timer);
|
||||
}
|
||||
|
||||
#define PCLK_HZ 24000000
|
||||
|
||||
static void aspeed_wdt_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
AspeedWDTState *s = ASPEED_WDT(dev);
|
||||
|
||||
s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, aspeed_wdt_timer_expired, dev);
|
||||
|
||||
/* FIXME: This setting should be derived from the SCU hw strapping
|
||||
* register SCU70
|
||||
*/
|
||||
s->pclk_freq = PCLK_HZ;
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_wdt_ops, s,
|
||||
TYPE_ASPEED_WDT, ASPEED_WDT_REGS_MAX * 4);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
}
|
||||
|
||||
static void aspeed_wdt_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = aspeed_wdt_realize;
|
||||
dc->reset = aspeed_wdt_reset;
|
||||
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
||||
dc->vmsd = &vmstate_aspeed_wdt;
|
||||
}
|
||||
|
||||
static const TypeInfo aspeed_wdt_info = {
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.name = TYPE_ASPEED_WDT,
|
||||
.instance_size = sizeof(AspeedWDTState),
|
||||
.class_init = aspeed_wdt_class_init,
|
||||
};
|
||||
|
||||
static void wdt_aspeed_register_types(void)
|
||||
{
|
||||
watchdog_add_model(&model);
|
||||
type_register_static(&aspeed_wdt_info);
|
||||
}
|
||||
|
||||
type_init(wdt_aspeed_register_types)
|
||||
@@ -295,6 +295,7 @@ typedef struct disassemble_info {
|
||||
The bottom 16 bits are for the internal use of the disassembler. */
|
||||
unsigned long flags;
|
||||
#define INSN_HAS_RELOC 0x80000000
|
||||
#define INSN_ARM_BE32 0x00010000
|
||||
PTR private_data;
|
||||
|
||||
/* Function used to get bytes to disassemble. MEMADDR is the
|
||||
@@ -306,6 +307,12 @@ typedef struct disassemble_info {
|
||||
(bfd_vma memaddr, bfd_byte *myaddr, int length,
|
||||
struct disassemble_info *info);
|
||||
|
||||
/* A place to stash the real read_memory_func if read_memory_func wants to
|
||||
do some funky address arithmetic or similar (e.g. for ARM BE32 mode). */
|
||||
int (*read_memory_inner_func)
|
||||
(bfd_vma memaddr, bfd_byte *myaddr, int length,
|
||||
struct disassemble_info *info);
|
||||
|
||||
/* Function which should be called if we get an error that we can't
|
||||
recover from. STATUS is the errno value from read_memory_func and
|
||||
MEMADDR is the address that we were trying to read. INFO is a
|
||||
|
||||
@@ -318,6 +318,7 @@ static inline void tb_set_jmp_target(TranslationBlock *tb,
|
||||
static inline void tb_add_jump(TranslationBlock *tb, int n,
|
||||
TranslationBlock *tb_next)
|
||||
{
|
||||
assert(n < ARRAY_SIZE(tb->jmp_list_next));
|
||||
if (tb->jmp_list_next[n]) {
|
||||
/* Another thread has already done this while we were
|
||||
* outside of the lock; nothing to do in this case */
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "hw/timer/aspeed_timer.h"
|
||||
#include "hw/i2c/aspeed_i2c.h"
|
||||
#include "hw/ssi/aspeed_smc.h"
|
||||
#include "hw/watchdog/wdt_aspeed.h"
|
||||
|
||||
#define ASPEED_SPIS_NUM 2
|
||||
|
||||
@@ -37,6 +38,7 @@ typedef struct AspeedSoCState {
|
||||
AspeedSMCState fmc;
|
||||
AspeedSMCState spi[ASPEED_SPIS_NUM];
|
||||
AspeedSDMCState sdmc;
|
||||
AspeedWDTState wdt;
|
||||
} AspeedSoCState;
|
||||
|
||||
#define TYPE_ASPEED_SOC "aspeed-soc"
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
#define HW_PS2_H
|
||||
|
||||
#define PS2_MOUSE_BUTTON_LEFT 0x01
|
||||
#define PS2_MOUSE_BUTTON_MIDDLE 0x02
|
||||
#define PS2_MOUSE_BUTTON_RIGHT 0x04
|
||||
#define PS2_MOUSE_BUTTON_RIGHT 0x02
|
||||
#define PS2_MOUSE_BUTTON_MIDDLE 0x04
|
||||
#define PS2_MOUSE_BUTTON_SIDE 0x08
|
||||
#define PS2_MOUSE_BUTTON_EXTRA 0x10
|
||||
|
||||
|
||||
@@ -4,17 +4,13 @@
|
||||
|
||||
#include "target/m68k/cpu-qom.h"
|
||||
|
||||
struct MemoryRegion;
|
||||
|
||||
/* mcf_uart.c */
|
||||
uint64_t mcf_uart_read(void *opaque, hwaddr addr,
|
||||
unsigned size);
|
||||
void mcf_uart_write(void *opaque, hwaddr addr,
|
||||
uint64_t val, unsigned size);
|
||||
void *mcf_uart_init(qemu_irq irq, Chardev *chr);
|
||||
void mcf_uart_mm_init(struct MemoryRegion *sysmem,
|
||||
hwaddr base,
|
||||
qemu_irq irq, Chardev *chr);
|
||||
void mcf_uart_mm_init(hwaddr base, qemu_irq irq, Chardev *chr);
|
||||
|
||||
/* mcf_intc.c */
|
||||
qemu_irq *mcf_intc_init(struct MemoryRegion *sysmem,
|
||||
|
||||
39
include/hw/misc/unimp.h
Normal file
39
include/hw/misc/unimp.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* "Unimplemented" device
|
||||
*
|
||||
* Copyright Linaro Limited, 2017
|
||||
* Written by Peter Maydell
|
||||
*/
|
||||
|
||||
#ifndef HW_MISC_UNIMP_H
|
||||
#define HW_MISC_UNIMP_H
|
||||
|
||||
#define TYPE_UNIMPLEMENTED_DEVICE "unimplemented-device"
|
||||
|
||||
/**
|
||||
* create_unimplemented_device: create and map a dummy device
|
||||
* @name: name of the device for debug logging
|
||||
* @base: base address of the device's MMIO region
|
||||
* @size: size of the device's MMIO region
|
||||
*
|
||||
* This utility function creates and maps an instance of unimplemented-device,
|
||||
* which is a dummy device which simply logs all guest accesses to
|
||||
* it via the qemu_log LOG_UNIMP debug log.
|
||||
* The device is mapped at priority -1000, which means that you can
|
||||
* use it to cover a large region and then map other devices on top of it
|
||||
* if necessary.
|
||||
*/
|
||||
static inline void create_unimplemented_device(const char *name,
|
||||
hwaddr base,
|
||||
hwaddr size)
|
||||
{
|
||||
DeviceState *dev = qdev_create(NULL, TYPE_UNIMPLEMENTED_DEVICE);
|
||||
|
||||
qdev_prop_set_string(dev, "name", name);
|
||||
qdev_prop_set_uint64(dev, "size", size);
|
||||
qdev_init_nofail(dev);
|
||||
|
||||
sysbus_mmio_map_overlap(SYS_BUS_DEVICE(dev), 0, base, -1000);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -47,7 +47,7 @@ typedef struct VirtIONetQueue {
|
||||
VirtQueue *tx_vq;
|
||||
QEMUTimer *tx_timer;
|
||||
QEMUBH *tx_bh;
|
||||
int tx_waiting;
|
||||
uint32_t tx_waiting;
|
||||
struct {
|
||||
VirtQueueElement *elem;
|
||||
} async_tx;
|
||||
@@ -68,7 +68,7 @@ typedef struct VirtIONet {
|
||||
size_t guest_hdr_len;
|
||||
uint32_t host_features;
|
||||
uint8_t has_ufo;
|
||||
int mergeable_rx_bufs;
|
||||
uint32_t mergeable_rx_bufs;
|
||||
uint8_t promisc;
|
||||
uint8_t allmulti;
|
||||
uint8_t alluni;
|
||||
|
||||
32
include/hw/watchdog/wdt_aspeed.h
Normal file
32
include/hw/watchdog/wdt_aspeed.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* ASPEED Watchdog Controller
|
||||
*
|
||||
* Copyright (C) 2016-2017 IBM Corp.
|
||||
*
|
||||
* This code is licensed under the GPL version 2 or later. See the
|
||||
* COPYING file in the top-level directory.
|
||||
*/
|
||||
#ifndef ASPEED_WDT_H
|
||||
#define ASPEED_WDT_H
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
|
||||
#define TYPE_ASPEED_WDT "aspeed.wdt"
|
||||
#define ASPEED_WDT(obj) \
|
||||
OBJECT_CHECK(AspeedWDTState, (obj), TYPE_ASPEED_WDT)
|
||||
|
||||
#define ASPEED_WDT_REGS_MAX (0x20 / 4)
|
||||
|
||||
typedef struct AspeedWDTState {
|
||||
/*< private >*/
|
||||
SysBusDevice parent_obj;
|
||||
QEMUTimer *timer;
|
||||
|
||||
/*< public >*/
|
||||
MemoryRegion iomem;
|
||||
uint32_t regs[ASPEED_WDT_REGS_MAX];
|
||||
|
||||
uint32_t pclk_freq;
|
||||
} AspeedWDTState;
|
||||
|
||||
#endif /* ASPEED_WDT_H */
|
||||
@@ -35,4 +35,6 @@ COLOMode get_colo_mode(void);
|
||||
|
||||
/* failover */
|
||||
void colo_do_failover(MigrationState *s);
|
||||
|
||||
void colo_checkpoint_notify(void *opaque);
|
||||
#endif
|
||||
|
||||
@@ -116,6 +116,7 @@ struct MigrationIncomingState {
|
||||
QemuThread colo_incoming_thread;
|
||||
/* The coroutine we should enter (back) after failover */
|
||||
Coroutine *migration_incoming_co;
|
||||
QemuSemaphore colo_incoming_sem;
|
||||
|
||||
/* See savevm.c */
|
||||
LoadStateEntry_Head loadvm_handlers;
|
||||
@@ -187,6 +188,13 @@ struct MigrationState
|
||||
QSIMPLEQ_HEAD(src_page_requests, MigrationSrcPageRequest) src_page_requests;
|
||||
/* The RAMBlock used in the last src_page_request */
|
||||
RAMBlock *last_req_rb;
|
||||
/* The semaphore is used to notify COLO thread that failover is finished */
|
||||
QemuSemaphore colo_exit_sem;
|
||||
|
||||
/* The semaphore is used to notify COLO thread to do checkpoint */
|
||||
QemuSemaphore colo_checkpoint_sem;
|
||||
int64_t colo_checkpoint_time;
|
||||
QEMUTimer *colo_delay_timer;
|
||||
|
||||
/* The last error that occurred */
|
||||
Error *error;
|
||||
@@ -285,6 +293,7 @@ int ram_postcopy_send_discard_bitmap(MigrationState *ms);
|
||||
int ram_discard_range(MigrationIncomingState *mis, const char *block_name,
|
||||
uint64_t start, size_t length);
|
||||
int ram_postcopy_incoming_init(MigrationIncomingState *mis);
|
||||
void ram_postcopy_migrated_memory_release(MigrationState *ms);
|
||||
|
||||
/**
|
||||
* @migrate_add_blocker - prevent migration from proceeding
|
||||
@@ -304,6 +313,7 @@ int migrate_add_blocker(Error *reason, Error **errp);
|
||||
*/
|
||||
void migrate_del_blocker(Error *reason);
|
||||
|
||||
bool migrate_release_ram(void);
|
||||
bool migrate_postcopy_ram(void);
|
||||
bool migrate_zero_blocks(void);
|
||||
|
||||
|
||||
@@ -132,7 +132,8 @@ void qemu_put_byte(QEMUFile *f, int v);
|
||||
* put_buffer without copying the buffer.
|
||||
* The buffer should be available till it is sent asynchronously.
|
||||
*/
|
||||
void qemu_put_buffer_async(QEMUFile *f, const uint8_t *buf, size_t size);
|
||||
void qemu_put_buffer_async(QEMUFile *f, const uint8_t *buf, size_t size,
|
||||
bool may_free);
|
||||
bool qemu_file_mode_is_not_valid(const char *mode);
|
||||
bool qemu_file_is_writable(QEMUFile *f);
|
||||
|
||||
|
||||
@@ -259,6 +259,7 @@ extern const VMStateInfo vmstate_info_cpudouble;
|
||||
extern const VMStateInfo vmstate_info_timer;
|
||||
extern const VMStateInfo vmstate_info_buffer;
|
||||
extern const VMStateInfo vmstate_info_unused_buffer;
|
||||
extern const VMStateInfo vmstate_info_tmp;
|
||||
extern const VMStateInfo vmstate_info_bitmap;
|
||||
extern const VMStateInfo vmstate_info_qtailq;
|
||||
|
||||
@@ -587,7 +588,8 @@ extern const VMStateInfo vmstate_info_qtailq;
|
||||
.offset = vmstate_offset_buffer(_state, _field) + _start, \
|
||||
}
|
||||
|
||||
#define VMSTATE_VBUFFER_MULTIPLY(_field, _state, _version, _test, _start, _field_size, _multiply) { \
|
||||
#define VMSTATE_VBUFFER_MULTIPLY(_field, _state, _version, _test, \
|
||||
_field_size, _multiply) { \
|
||||
.name = (stringify(_field)), \
|
||||
.version_id = (_version), \
|
||||
.field_exists = (_test), \
|
||||
@@ -596,10 +598,9 @@ extern const VMStateInfo vmstate_info_qtailq;
|
||||
.info = &vmstate_info_buffer, \
|
||||
.flags = VMS_VBUFFER|VMS_POINTER|VMS_MULTIPLY, \
|
||||
.offset = offsetof(_state, _field), \
|
||||
.start = (_start), \
|
||||
}
|
||||
|
||||
#define VMSTATE_VBUFFER(_field, _state, _version, _test, _start, _field_size) { \
|
||||
#define VMSTATE_VBUFFER(_field, _state, _version, _test, _field_size) { \
|
||||
.name = (stringify(_field)), \
|
||||
.version_id = (_version), \
|
||||
.field_exists = (_test), \
|
||||
@@ -607,10 +608,9 @@ extern const VMStateInfo vmstate_info_qtailq;
|
||||
.info = &vmstate_info_buffer, \
|
||||
.flags = VMS_VBUFFER|VMS_POINTER, \
|
||||
.offset = offsetof(_state, _field), \
|
||||
.start = (_start), \
|
||||
}
|
||||
|
||||
#define VMSTATE_VBUFFER_UINT32(_field, _state, _version, _test, _start, _field_size) { \
|
||||
#define VMSTATE_VBUFFER_UINT32(_field, _state, _version, _test, _field_size) { \
|
||||
.name = (stringify(_field)), \
|
||||
.version_id = (_version), \
|
||||
.field_exists = (_test), \
|
||||
@@ -618,10 +618,10 @@ extern const VMStateInfo vmstate_info_qtailq;
|
||||
.info = &vmstate_info_buffer, \
|
||||
.flags = VMS_VBUFFER|VMS_POINTER, \
|
||||
.offset = offsetof(_state, _field), \
|
||||
.start = (_start), \
|
||||
}
|
||||
|
||||
#define VMSTATE_VBUFFER_ALLOC_UINT32(_field, _state, _version, _test, _start, _field_size) { \
|
||||
#define VMSTATE_VBUFFER_ALLOC_UINT32(_field, _state, _version, \
|
||||
_test, _field_size) { \
|
||||
.name = (stringify(_field)), \
|
||||
.version_id = (_version), \
|
||||
.field_exists = (_test), \
|
||||
@@ -629,7 +629,6 @@ extern const VMStateInfo vmstate_info_qtailq;
|
||||
.info = &vmstate_info_buffer, \
|
||||
.flags = VMS_VBUFFER|VMS_POINTER|VMS_ALLOC, \
|
||||
.offset = offsetof(_state, _field), \
|
||||
.start = (_start), \
|
||||
}
|
||||
|
||||
#define VMSTATE_BUFFER_UNSAFE_INFO_TEST(_field, _state, _test, _version, _info, _size) { \
|
||||
@@ -651,6 +650,24 @@ extern const VMStateInfo vmstate_info_qtailq;
|
||||
.offset = offsetof(_state, _field), \
|
||||
}
|
||||
|
||||
/* Allocate a temporary of type 'tmp_type', set tmp->parent to _state
|
||||
* and execute the vmsd on the temporary. Note that we're working with
|
||||
* the whole of _state here, not a field within it.
|
||||
* We compile time check that:
|
||||
* That _tmp_type contains a 'parent' member that's a pointer to the
|
||||
* '_state' type
|
||||
* That the pointer is right at the start of _tmp_type.
|
||||
*/
|
||||
#define VMSTATE_WITH_TMP(_state, _tmp_type, _vmsd) { \
|
||||
.name = "tmp", \
|
||||
.size = sizeof(_tmp_type) + \
|
||||
QEMU_BUILD_BUG_ON_ZERO(offsetof(_tmp_type, parent) != 0) + \
|
||||
type_check_pointer(_state, \
|
||||
typeof_field(_tmp_type, parent)), \
|
||||
.vmsd = &(_vmsd), \
|
||||
.info = &vmstate_info_tmp, \
|
||||
}
|
||||
|
||||
#define VMSTATE_UNUSED_BUFFER(_test, _version, _size) { \
|
||||
.name = "unused", \
|
||||
.field_exists = (_test), \
|
||||
@@ -660,6 +677,17 @@ extern const VMStateInfo vmstate_info_qtailq;
|
||||
.flags = VMS_BUFFER, \
|
||||
}
|
||||
|
||||
/* Discard size * field_num bytes, where field_num is a uint32 member */
|
||||
#define VMSTATE_UNUSED_VARRAY_UINT32(_state, _test, _version, _field_num, _size) {\
|
||||
.name = "unused", \
|
||||
.field_exists = (_test), \
|
||||
.num_offset = vmstate_offset_value(_state, _field_num, uint32_t),\
|
||||
.version_id = (_version), \
|
||||
.size = (_size), \
|
||||
.info = &vmstate_info_unused_buffer, \
|
||||
.flags = VMS_VARRAY_UINT32 | VMS_BUFFER, \
|
||||
}
|
||||
|
||||
/* _field_size should be a int32_t field in the _state struct giving the
|
||||
* size of the bitmap _field in bits.
|
||||
*/
|
||||
@@ -948,13 +976,10 @@ extern const VMStateInfo vmstate_info_qtailq;
|
||||
VMSTATE_BUFFER_START_MIDDLE_V(_f, _s, _start, 0)
|
||||
|
||||
#define VMSTATE_PARTIAL_VBUFFER(_f, _s, _size) \
|
||||
VMSTATE_VBUFFER(_f, _s, 0, NULL, 0, _size)
|
||||
VMSTATE_VBUFFER(_f, _s, 0, NULL, _size)
|
||||
|
||||
#define VMSTATE_PARTIAL_VBUFFER_UINT32(_f, _s, _size) \
|
||||
VMSTATE_VBUFFER_UINT32(_f, _s, 0, NULL, 0, _size)
|
||||
|
||||
#define VMSTATE_SUB_VBUFFER(_f, _s, _start, _size) \
|
||||
VMSTATE_VBUFFER(_f, _s, 0, NULL, _start, _size)
|
||||
VMSTATE_VBUFFER_UINT32(_f, _s, 0, NULL, _size)
|
||||
|
||||
#define VMSTATE_BUFFER_TEST(_f, _s, _test) \
|
||||
VMSTATE_STATIC_BUFFER(_f, _s, 0, _test, 0, sizeof(typeof_field(_s, _f)))
|
||||
|
||||
@@ -132,6 +132,8 @@ struct TranslationBlock;
|
||||
* @cpu_exec_exit: Callback for cpu_exec cleanup.
|
||||
* @cpu_exec_interrupt: Callback for processing interrupts in cpu_exec.
|
||||
* @disas_set_info: Setup architecture specific components of disassembly info
|
||||
* @adjust_watchpoint_address: Perform a target-specific adjustment to an
|
||||
* address before attempting to match it against watchpoints.
|
||||
*
|
||||
* Represents a CPU family or model.
|
||||
*/
|
||||
@@ -156,6 +158,7 @@ typedef struct CPUClass {
|
||||
uint8_t *buf, int len, bool is_write);
|
||||
void (*dump_state)(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
|
||||
int flags);
|
||||
GuestPanicInformation* (*get_crash_info)(CPUState *cpu);
|
||||
void (*dump_statistics)(CPUState *cpu, FILE *f,
|
||||
fprintf_function cpu_fprintf, int flags);
|
||||
int64_t (*get_arch_id)(CPUState *cpu);
|
||||
@@ -195,6 +198,7 @@ typedef struct CPUClass {
|
||||
bool (*cpu_exec_interrupt)(CPUState *cpu, int interrupt_request);
|
||||
|
||||
void (*disas_set_info)(CPUState *cpu, disassemble_info *info);
|
||||
vaddr (*adjust_watchpoint_address)(CPUState *cpu, vaddr addr, int len);
|
||||
} CPUClass;
|
||||
|
||||
#ifdef HOST_WORDS_BIGENDIAN
|
||||
@@ -468,6 +472,15 @@ int cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cpu,
|
||||
int cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cpu,
|
||||
void *opaque);
|
||||
|
||||
/**
|
||||
* cpu_get_crash_info:
|
||||
* @cpu: The CPU to get crash information for
|
||||
*
|
||||
* Gets the previously saved crash information.
|
||||
* Caller is responsible for freeing the data.
|
||||
*/
|
||||
GuestPanicInformation *cpu_get_crash_info(CPUState *cpu);
|
||||
|
||||
/**
|
||||
* CPUDumpFlags:
|
||||
* @CPU_DUMP_CODE:
|
||||
|
||||
@@ -37,6 +37,7 @@ void vm_state_notify(int running, RunState state);
|
||||
#define VMRESET_REPORT true
|
||||
|
||||
void vm_start(void);
|
||||
int vm_prepare_start(void);
|
||||
int vm_stop(RunState state);
|
||||
int vm_stop_force_state(RunState state);
|
||||
|
||||
@@ -60,11 +61,12 @@ void qemu_register_powerdown_notifier(Notifier *notifier);
|
||||
void qemu_system_debug_request(void);
|
||||
void qemu_system_vmstop_request(RunState reason);
|
||||
void qemu_system_vmstop_request_prepare(void);
|
||||
bool qemu_vmstop_requested(RunState *r);
|
||||
int qemu_shutdown_requested_get(void);
|
||||
int qemu_reset_requested_get(void);
|
||||
void qemu_system_killed(int signal, pid_t pid);
|
||||
void qemu_system_reset(bool report);
|
||||
void qemu_system_guest_panicked(void);
|
||||
void qemu_system_guest_panicked(GuestPanicInformation *info);
|
||||
size_t qemu_target_page_bits(void);
|
||||
|
||||
void qemu_add_exit_notifier(Notifier *notify);
|
||||
|
||||
@@ -2000,8 +2000,9 @@ int kvm_cpu_exec(CPUState *cpu)
|
||||
ret = EXCP_INTERRUPT;
|
||||
break;
|
||||
case KVM_SYSTEM_EVENT_CRASH:
|
||||
kvm_cpu_synchronize_state(cpu);
|
||||
qemu_mutex_lock_iothread();
|
||||
qemu_system_guest_panicked();
|
||||
qemu_system_guest_panicked(cpu_get_crash_info(cpu));
|
||||
qemu_mutex_unlock_iothread();
|
||||
ret = 0;
|
||||
break;
|
||||
|
||||
@@ -1054,9 +1054,8 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs,
|
||||
for (i = 0; i < 32; i++) {
|
||||
(*regs)[i] = tswapreg(env->gpr[i]);
|
||||
}
|
||||
|
||||
(*regs)[32] = tswapreg(env->pc);
|
||||
(*regs)[33] = tswapreg(env->sr);
|
||||
(*regs)[33] = tswapreg(cpu_get_sr(env));
|
||||
}
|
||||
#define ELF_HWCAP 0
|
||||
#define ELF_PLATFORM NULL
|
||||
@@ -2263,6 +2262,7 @@ static int symcmp(const void *s0, const void *s1)
|
||||
static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
|
||||
{
|
||||
int i, shnum, nsyms, sym_idx = 0, str_idx = 0;
|
||||
uint64_t segsz;
|
||||
struct elf_shdr *shdr;
|
||||
char *strings = NULL;
|
||||
struct syminfo *s = NULL;
|
||||
@@ -2294,19 +2294,26 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
|
||||
goto give_up;
|
||||
}
|
||||
|
||||
i = shdr[str_idx].sh_size;
|
||||
s->disas_strtab = strings = g_try_malloc(i);
|
||||
if (!strings || pread(fd, strings, i, shdr[str_idx].sh_offset) != i) {
|
||||
segsz = shdr[str_idx].sh_size;
|
||||
s->disas_strtab = strings = g_try_malloc(segsz);
|
||||
if (!strings ||
|
||||
pread(fd, strings, segsz, shdr[str_idx].sh_offset) != segsz) {
|
||||
goto give_up;
|
||||
}
|
||||
|
||||
i = shdr[sym_idx].sh_size;
|
||||
syms = g_try_malloc(i);
|
||||
if (!syms || pread(fd, syms, i, shdr[sym_idx].sh_offset) != i) {
|
||||
segsz = shdr[sym_idx].sh_size;
|
||||
syms = g_try_malloc(segsz);
|
||||
if (!syms || pread(fd, syms, segsz, shdr[sym_idx].sh_offset) != segsz) {
|
||||
goto give_up;
|
||||
}
|
||||
|
||||
nsyms = i / sizeof(struct elf_sym);
|
||||
if (segsz / sizeof(struct elf_sym) > INT_MAX) {
|
||||
/* Implausibly large symbol table: give up rather than ploughing
|
||||
* on with the number of symbols calculation overflowing
|
||||
*/
|
||||
goto give_up;
|
||||
}
|
||||
nsyms = segsz / sizeof(struct elf_sym);
|
||||
for (i = 0; i < nsyms; ) {
|
||||
bswap_sym(syms + i);
|
||||
/* Throw away entries which we do not need. */
|
||||
|
||||
@@ -72,7 +72,7 @@ safe_syscall_base:
|
||||
*/
|
||||
safe_syscall_start:
|
||||
/* if signal_pending is non-zero, don't do the call */
|
||||
lt %r0,0(%r8)
|
||||
icm %r0,15,0(%r8)
|
||||
jne 2f
|
||||
svc 0
|
||||
safe_syscall_end:
|
||||
|
||||
@@ -112,6 +112,11 @@
|
||||
#ifdef FIBMAP
|
||||
IOCTL(FIBMAP, IOC_W | IOC_R, MK_PTR(TYPE_LONG))
|
||||
#endif
|
||||
#ifdef FICLONE
|
||||
IOCTL(FICLONE, IOC_W, TYPE_INT)
|
||||
IOCTL(FICLONERANGE, IOC_W, MK_PTR(MK_STRUCT(STRUCT_file_clone_range)))
|
||||
#endif
|
||||
|
||||
#ifdef FIGETBSZ
|
||||
IOCTL(FIGETBSZ, IOC_R, MK_PTR(TYPE_LONG))
|
||||
#endif
|
||||
|
||||
@@ -376,3 +376,6 @@
|
||||
#define TARGET_NR_userfaultfd 373
|
||||
#define TARGET_NR_membarrier 374
|
||||
#define TARGET_NR_mlock2 375
|
||||
#define TARGET_NR_copy_file_range 376
|
||||
#define TARGET_NR_preadv2 377
|
||||
#define TARGET_NR_pwritev2 378
|
||||
|
||||
@@ -2574,52 +2574,17 @@ kuser_fail:
|
||||
void cpu_loop(CPUOpenRISCState *env)
|
||||
{
|
||||
CPUState *cs = CPU(openrisc_env_get_cpu(env));
|
||||
int trapnr, gdbsig;
|
||||
int trapnr;
|
||||
abi_long ret;
|
||||
target_siginfo_t info;
|
||||
|
||||
for (;;) {
|
||||
cpu_exec_start(cs);
|
||||
trapnr = cpu_exec(cs);
|
||||
cpu_exec_end(cs);
|
||||
process_queued_cpu_work(cs);
|
||||
gdbsig = 0;
|
||||
|
||||
switch (trapnr) {
|
||||
case EXCP_RESET:
|
||||
qemu_log_mask(CPU_LOG_INT, "\nReset request, exit, pc is %#x\n", env->pc);
|
||||
exit(EXIT_FAILURE);
|
||||
break;
|
||||
case EXCP_BUSERR:
|
||||
qemu_log_mask(CPU_LOG_INT, "\nBus error, exit, pc is %#x\n", env->pc);
|
||||
gdbsig = TARGET_SIGBUS;
|
||||
break;
|
||||
case EXCP_DPF:
|
||||
case EXCP_IPF:
|
||||
cpu_dump_state(cs, stderr, fprintf, 0);
|
||||
gdbsig = TARGET_SIGSEGV;
|
||||
break;
|
||||
case EXCP_TICK:
|
||||
qemu_log_mask(CPU_LOG_INT, "\nTick time interrupt pc is %#x\n", env->pc);
|
||||
break;
|
||||
case EXCP_ALIGN:
|
||||
qemu_log_mask(CPU_LOG_INT, "\nAlignment pc is %#x\n", env->pc);
|
||||
gdbsig = TARGET_SIGBUS;
|
||||
break;
|
||||
case EXCP_ILLEGAL:
|
||||
qemu_log_mask(CPU_LOG_INT, "\nIllegal instructionpc is %#x\n", env->pc);
|
||||
gdbsig = TARGET_SIGILL;
|
||||
break;
|
||||
case EXCP_INT:
|
||||
qemu_log_mask(CPU_LOG_INT, "\nExternal interruptpc is %#x\n", env->pc);
|
||||
break;
|
||||
case EXCP_DTLBMISS:
|
||||
case EXCP_ITLBMISS:
|
||||
qemu_log_mask(CPU_LOG_INT, "\nTLB miss\n");
|
||||
break;
|
||||
case EXCP_RANGE:
|
||||
qemu_log_mask(CPU_LOG_INT, "\nRange\n");
|
||||
gdbsig = TARGET_SIGSEGV;
|
||||
break;
|
||||
case EXCP_SYSCALL:
|
||||
env->pc += 4; /* 0xc00; */
|
||||
ret = do_syscall(env,
|
||||
@@ -2636,32 +2601,54 @@ void cpu_loop(CPUOpenRISCState *env)
|
||||
env->gpr[11] = ret;
|
||||
}
|
||||
break;
|
||||
case EXCP_DPF:
|
||||
case EXCP_IPF:
|
||||
case EXCP_RANGE:
|
||||
info.si_signo = TARGET_SIGSEGV;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_SEGV_MAPERR;
|
||||
info._sifields._sigfault._addr = env->pc;
|
||||
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
|
||||
break;
|
||||
case EXCP_ALIGN:
|
||||
info.si_signo = TARGET_SIGBUS;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_BUS_ADRALN;
|
||||
info._sifields._sigfault._addr = env->pc;
|
||||
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
|
||||
break;
|
||||
case EXCP_ILLEGAL:
|
||||
info.si_signo = TARGET_SIGILL;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_ILL_ILLOPC;
|
||||
info._sifields._sigfault._addr = env->pc;
|
||||
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
|
||||
break;
|
||||
case EXCP_FPE:
|
||||
qemu_log_mask(CPU_LOG_INT, "\nFloating point error\n");
|
||||
info.si_signo = TARGET_SIGFPE;
|
||||
info.si_errno = 0;
|
||||
info.si_code = 0;
|
||||
info._sifields._sigfault._addr = env->pc;
|
||||
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
|
||||
break;
|
||||
case EXCP_TRAP:
|
||||
qemu_log_mask(CPU_LOG_INT, "\nTrap\n");
|
||||
gdbsig = TARGET_SIGTRAP;
|
||||
case EXCP_INTERRUPT:
|
||||
/* We processed the pending cpu work above. */
|
||||
break;
|
||||
case EXCP_NR:
|
||||
qemu_log_mask(CPU_LOG_INT, "\nNR\n");
|
||||
case EXCP_DEBUG:
|
||||
trapnr = gdb_handlesig(cs, TARGET_SIGTRAP);
|
||||
if (trapnr) {
|
||||
info.si_signo = trapnr;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_TRAP_BRKPT;
|
||||
queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
|
||||
}
|
||||
break;
|
||||
case EXCP_ATOMIC:
|
||||
cpu_exec_step_atomic(cs);
|
||||
break;
|
||||
default:
|
||||
EXCP_DUMP(env, "\nqemu: unhandled CPU exception %#x - aborting\n",
|
||||
trapnr);
|
||||
gdbsig = TARGET_SIGILL;
|
||||
break;
|
||||
g_assert_not_reached();
|
||||
}
|
||||
if (gdbsig) {
|
||||
gdb_handlesig(cs, gdbsig);
|
||||
if (gdbsig != TARGET_SIGTRAP) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
process_pending_signals(env);
|
||||
}
|
||||
}
|
||||
@@ -4778,9 +4765,8 @@ int main(int argc, char **argv, char **envp)
|
||||
for (i = 0; i < 32; i++) {
|
||||
env->gpr[i] = regs->gpr[i];
|
||||
}
|
||||
|
||||
env->sr = regs->sr;
|
||||
env->pc = regs->pc;
|
||||
cpu_set_sr(env, regs->sr);
|
||||
}
|
||||
#elif defined(TARGET_SH4)
|
||||
{
|
||||
|
||||
@@ -193,9 +193,6 @@ static int mmap_frag(abi_ulong real_start,
|
||||
|
||||
#if HOST_LONG_BITS == 64 && TARGET_ABI_BITS == 64
|
||||
# define TASK_UNMAPPED_BASE (1ul << 38)
|
||||
#elif defined(__CYGWIN__)
|
||||
/* Cygwin doesn't have a whole lot of address space. */
|
||||
# define TASK_UNMAPPED_BASE 0x18000000
|
||||
#else
|
||||
# define TASK_UNMAPPED_BASE 0x40000000
|
||||
#endif
|
||||
@@ -429,9 +426,9 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
|
||||
may need to truncate file maps at EOF and add extra anonymous pages
|
||||
up to the targets page boundary. */
|
||||
|
||||
if ((qemu_real_host_page_size < TARGET_PAGE_SIZE)
|
||||
&& !(flags & MAP_ANONYMOUS)) {
|
||||
struct stat sb;
|
||||
if ((qemu_real_host_page_size < qemu_host_page_size) &&
|
||||
!(flags & MAP_ANONYMOUS)) {
|
||||
struct stat sb;
|
||||
|
||||
if (fstat (fd, &sb) == -1)
|
||||
goto fail;
|
||||
|
||||
@@ -30,9 +30,7 @@ static inline void cpu_clone_regs(CPUOpenRISCState *env, target_ulong newsp)
|
||||
|
||||
static inline void cpu_set_tls(CPUOpenRISCState *env, target_ulong newtls)
|
||||
{
|
||||
/* Linux kernel 3.10 does not pay any attention to CLONE_SETTLS
|
||||
* in copy_thread(), so QEMU need not do so either.
|
||||
*/
|
||||
env->gpr[10] = newtls;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -31,4 +31,6 @@ struct target_pt_regs {
|
||||
#define TARGET_MLOCKALL_MCL_CURRENT 1
|
||||
#define TARGET_MLOCKALL_MCL_FUTURE 2
|
||||
|
||||
#define MMAP_SHIFT TARGET_PAGE_BITS
|
||||
|
||||
#endif /* OPENRISC_TARGET_SYSCALL_H */
|
||||
|
||||
@@ -372,3 +372,17 @@
|
||||
#define TARGET_NR_process_vm_writev 366
|
||||
#define TARGET_NR_kcmp 367
|
||||
#define TARGET_NR_finit_module 368
|
||||
#define TARGET_NR_sched_getattr 369
|
||||
#define TARGET_NR_sched_setattr 370
|
||||
#define TARGET_NR_renameat2 371
|
||||
#define TARGET_NR_seccomp 372
|
||||
#define TARGET_NR_getrandom 373
|
||||
#define TARGET_NR_memfd_create 374
|
||||
#define TARGET_NR_bpf 375
|
||||
#define TARGET_NR_execveat 376
|
||||
#define TARGET_NR_userfaultfd 377
|
||||
#define TARGET_NR_membarrier 378
|
||||
#define TARGET_NR_mlock2 379
|
||||
#define TARGET_NR_copy_file_range 380
|
||||
#define TARGET_NR_preadv2 381
|
||||
#define TARGET_NR_pwritev2 382
|
||||
|
||||
@@ -5155,6 +5155,7 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka,
|
||||
target_ulong rt_sf_addr, newsp = 0;
|
||||
int i, err = 0;
|
||||
#if defined(TARGET_PPC64)
|
||||
struct target_sigcontext *sc = 0;
|
||||
struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
|
||||
#endif
|
||||
|
||||
@@ -5183,6 +5184,10 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka,
|
||||
#if defined(TARGET_PPC64)
|
||||
mctx = &rt_sf->uc.tuc_sigcontext.mcontext;
|
||||
trampptr = &rt_sf->trampoline[0];
|
||||
|
||||
sc = &rt_sf->uc.tuc_sigcontext;
|
||||
__put_user(h2g(mctx), &sc->regs);
|
||||
__put_user(sig, &sc->signal);
|
||||
#else
|
||||
mctx = &rt_sf->uc.tuc_mcontext;
|
||||
trampptr = (uint32_t *)&rt_sf->uc.tuc_mcontext.tramp;
|
||||
|
||||
@@ -90,10 +90,8 @@ if( cmd == val ) { \
|
||||
output_cmd( IPC_STAT );
|
||||
output_cmd( IPC_INFO );
|
||||
/* msgctl() commands */
|
||||
#ifdef __USER_MISC
|
||||
output_cmd( MSG_STAT );
|
||||
output_cmd( MSG_INFO );
|
||||
#endif
|
||||
/* shmctl() commands */
|
||||
output_cmd( SHM_LOCK );
|
||||
output_cmd( SHM_UNLOCK );
|
||||
|
||||
@@ -2326,6 +2326,8 @@ static abi_long host_to_target_data_link_rtattr(struct rtattr *rtattr)
|
||||
case QEMU_IFLA_GROUP:
|
||||
case QEMU_IFLA_MASTER:
|
||||
case QEMU_IFLA_NUM_VF:
|
||||
case QEMU_IFLA_GSO_MAX_SEGS:
|
||||
case QEMU_IFLA_GSO_MAX_SIZE:
|
||||
u32 = RTA_DATA(rtattr);
|
||||
*u32 = tswap32(*u32);
|
||||
break;
|
||||
@@ -11228,7 +11230,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
||||
arg3 = arg4;
|
||||
arg4 = arg5;
|
||||
}
|
||||
ret = get_errno(readahead(arg1, ((off64_t)arg3 << 32) | arg2, arg4));
|
||||
ret = get_errno(readahead(arg1, target_offset64(arg2, arg3) , arg4));
|
||||
#else
|
||||
ret = get_errno(readahead(arg1, arg2, arg3));
|
||||
#endif
|
||||
@@ -11561,7 +11563,8 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
||||
#ifdef CONFIG_INOTIFY1
|
||||
#if defined(TARGET_NR_inotify_init1) && defined(__NR_inotify_init1)
|
||||
case TARGET_NR_inotify_init1:
|
||||
ret = get_errno(sys_inotify_init1(arg1));
|
||||
ret = get_errno(sys_inotify_init1(target_to_host_bitmask(arg1,
|
||||
fcntl_flags_tbl)));
|
||||
break;
|
||||
#endif
|
||||
#endif
|
||||
@@ -11582,17 +11585,22 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
||||
case TARGET_NR_mq_open:
|
||||
{
|
||||
struct mq_attr posix_mq_attr;
|
||||
struct mq_attr *pposix_mq_attr;
|
||||
int host_flags;
|
||||
|
||||
host_flags = target_to_host_bitmask(arg2, fcntl_flags_tbl);
|
||||
if (copy_from_user_mq_attr(&posix_mq_attr, arg4) != 0) {
|
||||
goto efault;
|
||||
pposix_mq_attr = NULL;
|
||||
if (arg4) {
|
||||
if (copy_from_user_mq_attr(&posix_mq_attr, arg4) != 0) {
|
||||
goto efault;
|
||||
}
|
||||
pposix_mq_attr = &posix_mq_attr;
|
||||
}
|
||||
p = lock_user_string(arg1 - 1);
|
||||
if (!p) {
|
||||
goto efault;
|
||||
}
|
||||
ret = get_errno(mq_open(p, host_flags, arg3, &posix_mq_attr));
|
||||
ret = get_errno(mq_open(p, host_flags, arg3, pposix_mq_attr));
|
||||
unlock_user (p, arg1, 0);
|
||||
}
|
||||
break;
|
||||
@@ -12035,10 +12043,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
|
||||
timer_t htimer = g_posix_timers[timerid];
|
||||
struct itimerspec hspec_new = {{0},}, hspec_old = {{0},};
|
||||
|
||||
target_to_host_itimerspec(&hspec_new, arg3);
|
||||
if (target_to_host_itimerspec(&hspec_new, arg3)) {
|
||||
goto efault;
|
||||
}
|
||||
ret = get_errno(
|
||||
timer_settime(htimer, arg2, &hspec_new, &hspec_old));
|
||||
host_to_target_itimerspec(arg2, &hspec_old);
|
||||
if (arg4 && host_to_target_itimerspec(arg4, &hspec_old)) {
|
||||
goto efault;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1086,6 +1086,10 @@ struct target_pollfd {
|
||||
|
||||
#define TARGET_FIBMAP TARGET_IO(0x00,1) /* bmap access */
|
||||
#define TARGET_FIGETBSZ TARGET_IO(0x00,2) /* get the block size used for bmap */
|
||||
|
||||
#define TARGET_FICLONE TARGET_IOW(0x94, 9, int)
|
||||
#define TARGET_FICLONERANGE TARGET_IOW(0x94, 13, struct file_clone_range)
|
||||
|
||||
/* Note that the ioctl numbers claim type "long" but the actual type
|
||||
* used by the kernel is "int".
|
||||
*/
|
||||
|
||||
@@ -232,6 +232,12 @@ STRUCT(dm_target_versions,
|
||||
STRUCT(dm_target_msg,
|
||||
TYPE_ULONGLONG) /* sector */
|
||||
|
||||
STRUCT(file_clone_range,
|
||||
TYPE_LONGLONG, /* src_fd */
|
||||
TYPE_ULONGLONG, /* src_offset */
|
||||
TYPE_ULONGLONG, /* src_length */
|
||||
TYPE_ULONGLONG) /* dest_offset */
|
||||
|
||||
STRUCT(fiemap_extent,
|
||||
TYPE_ULONGLONG, /* fe_logical */
|
||||
TYPE_ULONGLONG, /* fe_physical */
|
||||
|
||||
102
migration/colo.c
102
migration/colo.c
@@ -20,6 +20,8 @@
|
||||
#include "qapi/error.h"
|
||||
#include "migration/failover.h"
|
||||
|
||||
static bool vmstate_loading;
|
||||
|
||||
#define COLO_BUFFER_BASE_SIZE (4 * 1024 * 1024)
|
||||
|
||||
bool colo_supported(void)
|
||||
@@ -51,6 +53,19 @@ static void secondary_vm_do_failover(void)
|
||||
int old_state;
|
||||
MigrationIncomingState *mis = migration_incoming_get_current();
|
||||
|
||||
/* Can not do failover during the process of VM's loading VMstate, Or
|
||||
* it will break the secondary VM.
|
||||
*/
|
||||
if (vmstate_loading) {
|
||||
old_state = failover_set_state(FAILOVER_STATUS_ACTIVE,
|
||||
FAILOVER_STATUS_RELAUNCH);
|
||||
if (old_state != FAILOVER_STATUS_ACTIVE) {
|
||||
error_report("Unknown error while do failover for secondary VM,"
|
||||
"old_state: %s", FailoverStatus_lookup[old_state]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
migrate_set_state(&mis->state, MIGRATION_STATUS_COLO,
|
||||
MIGRATION_STATUS_COMPLETED);
|
||||
|
||||
@@ -59,6 +74,18 @@ static void secondary_vm_do_failover(void)
|
||||
/* recover runstate to normal migration finish state */
|
||||
autostart = true;
|
||||
}
|
||||
/*
|
||||
* Make sure COLO incoming thread not block in recv or send,
|
||||
* If mis->from_src_file and mis->to_src_file use the same fd,
|
||||
* The second shutdown() will return -1, we ignore this value,
|
||||
* It is harmless.
|
||||
*/
|
||||
if (mis->from_src_file) {
|
||||
qemu_file_shutdown(mis->from_src_file);
|
||||
}
|
||||
if (mis->to_src_file) {
|
||||
qemu_file_shutdown(mis->to_src_file);
|
||||
}
|
||||
|
||||
old_state = failover_set_state(FAILOVER_STATUS_ACTIVE,
|
||||
FAILOVER_STATUS_COMPLETED);
|
||||
@@ -67,6 +94,8 @@ static void secondary_vm_do_failover(void)
|
||||
"secondary VM", FailoverStatus_lookup[old_state]);
|
||||
return;
|
||||
}
|
||||
/* Notify COLO incoming thread that failover work is finished */
|
||||
qemu_sem_post(&mis->colo_incoming_sem);
|
||||
/* For Secondary VM, jump to incoming co */
|
||||
if (mis->migration_incoming_co) {
|
||||
qemu_coroutine_enter(mis->migration_incoming_co);
|
||||
@@ -81,6 +110,18 @@ static void primary_vm_do_failover(void)
|
||||
migrate_set_state(&s->state, MIGRATION_STATUS_COLO,
|
||||
MIGRATION_STATUS_COMPLETED);
|
||||
|
||||
/*
|
||||
* Wake up COLO thread which may blocked in recv() or send(),
|
||||
* The s->rp_state.from_dst_file and s->to_dst_file may use the
|
||||
* same fd, but we still shutdown the fd for twice, it is harmless.
|
||||
*/
|
||||
if (s->to_dst_file) {
|
||||
qemu_file_shutdown(s->to_dst_file);
|
||||
}
|
||||
if (s->rp_state.from_dst_file) {
|
||||
qemu_file_shutdown(s->rp_state.from_dst_file);
|
||||
}
|
||||
|
||||
old_state = failover_set_state(FAILOVER_STATUS_ACTIVE,
|
||||
FAILOVER_STATUS_COMPLETED);
|
||||
if (old_state != FAILOVER_STATUS_ACTIVE) {
|
||||
@@ -88,6 +129,8 @@ static void primary_vm_do_failover(void)
|
||||
FailoverStatus_lookup[old_state]);
|
||||
return;
|
||||
}
|
||||
/* Notify COLO thread that failover work is finished */
|
||||
qemu_sem_post(&s->colo_exit_sem);
|
||||
}
|
||||
|
||||
void colo_do_failover(MigrationState *s)
|
||||
@@ -302,7 +345,7 @@ static void colo_process_checkpoint(MigrationState *s)
|
||||
{
|
||||
QIOChannelBuffer *bioc;
|
||||
QEMUFile *fb = NULL;
|
||||
int64_t current_time, checkpoint_time = qemu_clock_get_ms(QEMU_CLOCK_HOST);
|
||||
int64_t current_time = qemu_clock_get_ms(QEMU_CLOCK_HOST);
|
||||
Error *local_err = NULL;
|
||||
int ret;
|
||||
|
||||
@@ -332,26 +375,21 @@ static void colo_process_checkpoint(MigrationState *s)
|
||||
qemu_mutex_unlock_iothread();
|
||||
trace_colo_vm_state_change("stop", "run");
|
||||
|
||||
timer_mod(s->colo_delay_timer,
|
||||
current_time + s->parameters.x_checkpoint_delay);
|
||||
|
||||
while (s->state == MIGRATION_STATUS_COLO) {
|
||||
if (failover_get_state() != FAILOVER_STATUS_NONE) {
|
||||
error_report("failover request");
|
||||
goto out;
|
||||
}
|
||||
|
||||
current_time = qemu_clock_get_ms(QEMU_CLOCK_HOST);
|
||||
if (current_time - checkpoint_time <
|
||||
s->parameters.x_checkpoint_delay) {
|
||||
int64_t delay_ms;
|
||||
qemu_sem_wait(&s->colo_checkpoint_sem);
|
||||
|
||||
delay_ms = s->parameters.x_checkpoint_delay -
|
||||
(current_time - checkpoint_time);
|
||||
g_usleep(delay_ms * 1000);
|
||||
}
|
||||
ret = colo_do_checkpoint_transaction(s, bioc, fb);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
checkpoint_time = qemu_clock_get_ms(QEMU_CLOCK_HOST);
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -364,14 +402,41 @@ out:
|
||||
qemu_fclose(fb);
|
||||
}
|
||||
|
||||
timer_del(s->colo_delay_timer);
|
||||
|
||||
/* Hope this not to be too long to wait here */
|
||||
qemu_sem_wait(&s->colo_exit_sem);
|
||||
qemu_sem_destroy(&s->colo_exit_sem);
|
||||
/*
|
||||
* Must be called after failover BH is completed,
|
||||
* Or the failover BH may shutdown the wrong fd that
|
||||
* re-used by other threads after we release here.
|
||||
*/
|
||||
if (s->rp_state.from_dst_file) {
|
||||
qemu_fclose(s->rp_state.from_dst_file);
|
||||
}
|
||||
}
|
||||
|
||||
void colo_checkpoint_notify(void *opaque)
|
||||
{
|
||||
MigrationState *s = opaque;
|
||||
int64_t next_notify_time;
|
||||
|
||||
qemu_sem_post(&s->colo_checkpoint_sem);
|
||||
s->colo_checkpoint_time = qemu_clock_get_ms(QEMU_CLOCK_HOST);
|
||||
next_notify_time = s->colo_checkpoint_time +
|
||||
s->parameters.x_checkpoint_delay;
|
||||
timer_mod(s->colo_delay_timer, next_notify_time);
|
||||
}
|
||||
|
||||
void migrate_start_colo_process(MigrationState *s)
|
||||
{
|
||||
qemu_mutex_unlock_iothread();
|
||||
qemu_sem_init(&s->colo_checkpoint_sem, 0);
|
||||
s->colo_delay_timer = timer_new_ms(QEMU_CLOCK_HOST,
|
||||
colo_checkpoint_notify, s);
|
||||
|
||||
qemu_sem_init(&s->colo_exit_sem, 0);
|
||||
migrate_set_state(&s->state, MIGRATION_STATUS_ACTIVE,
|
||||
MIGRATION_STATUS_COLO);
|
||||
colo_process_checkpoint(s);
|
||||
@@ -410,6 +475,8 @@ void *colo_process_incoming_thread(void *opaque)
|
||||
uint64_t value;
|
||||
Error *local_err = NULL;
|
||||
|
||||
qemu_sem_init(&mis->colo_incoming_sem, 0);
|
||||
|
||||
migrate_set_state(&mis->state, MIGRATION_STATUS_ACTIVE,
|
||||
MIGRATION_STATUS_COLO);
|
||||
|
||||
@@ -496,13 +563,23 @@ void *colo_process_incoming_thread(void *opaque)
|
||||
|
||||
qemu_mutex_lock_iothread();
|
||||
qemu_system_reset(VMRESET_SILENT);
|
||||
vmstate_loading = true;
|
||||
if (qemu_loadvm_state(fb) < 0) {
|
||||
error_report("COLO: loadvm failed");
|
||||
qemu_mutex_unlock_iothread();
|
||||
goto out;
|
||||
}
|
||||
|
||||
vmstate_loading = false;
|
||||
qemu_mutex_unlock_iothread();
|
||||
|
||||
if (failover_get_state() == FAILOVER_STATUS_RELAUNCH) {
|
||||
failover_set_state(FAILOVER_STATUS_RELAUNCH,
|
||||
FAILOVER_STATUS_NONE);
|
||||
failover_request_active(NULL);
|
||||
goto out;
|
||||
}
|
||||
|
||||
colo_send_message(mis->to_src_file, COLO_MESSAGE_VMSTATE_LOADED,
|
||||
&local_err);
|
||||
if (local_err) {
|
||||
@@ -511,6 +588,7 @@ void *colo_process_incoming_thread(void *opaque)
|
||||
}
|
||||
|
||||
out:
|
||||
vmstate_loading = false;
|
||||
/* Throw the unreported error message after exited from loop */
|
||||
if (local_err) {
|
||||
error_report_err(local_err);
|
||||
@@ -520,6 +598,10 @@ out:
|
||||
qemu_fclose(fb);
|
||||
}
|
||||
|
||||
/* Hope this not to be too long to loop here */
|
||||
qemu_sem_wait(&mis->colo_incoming_sem);
|
||||
qemu_sem_destroy(&mis->colo_incoming_sem);
|
||||
/* Must be called after failover BH is completed */
|
||||
if (mis->to_src_file) {
|
||||
qemu_fclose(mis->to_src_file);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user