Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4ce5bc2dd1 | ||
|
|
113f4cd9e9 | ||
|
|
f965d237b5 | ||
|
|
5a16dd9bc8 | ||
|
|
c7580c1034 | ||
|
|
a8cd6f7ddf | ||
|
|
ce4fc986e5 | ||
|
|
219a7482ab | ||
|
|
28846ad3b5 | ||
|
|
cccb5446a6 | ||
|
|
25c0807e3c | ||
|
|
57fa9fb4ef | ||
|
|
450ead742a | ||
|
|
69c67eca97 | ||
|
|
256c899432 | ||
|
|
849c865155 | ||
|
|
57708c532f | ||
|
|
8d45ae8352 | ||
|
|
2f0f684cce | ||
|
|
bc4321e754 | ||
|
|
9a32fb2824 | ||
|
|
50462f2ca8 | ||
|
|
ec16f35e4e | ||
|
|
0ba3d50242 | ||
|
|
0214b6b4de | ||
|
|
63f7166a80 | ||
|
|
1d34dff02f | ||
|
|
5330a894ed | ||
|
|
cdcf2aa41c | ||
|
|
5ea33884f6 | ||
|
|
50d0184cb7 | ||
|
|
c068d37020 | ||
|
|
cc5caf7df4 | ||
|
|
b68e45c686 | ||
|
|
df60f451b3 | ||
|
|
1bc6332461 | ||
|
|
07548727b3 | ||
|
|
c7e6d6b115 | ||
|
|
886c62a3ff | ||
|
|
b598cb2214 | ||
|
|
799c27e124 | ||
|
|
b90d717b64 | ||
|
|
a410be59b5 | ||
|
|
f946f010f5 | ||
|
|
d438650fa5 | ||
|
|
07ab4fc1ef | ||
|
|
fd21cc14f5 | ||
|
|
cfeb9958c8 | ||
|
|
ffc7565c81 | ||
|
|
393d4c9214 | ||
|
|
5ae1c7ca0a | ||
|
|
c094d3d818 | ||
|
|
a473439574 | ||
|
|
2a93a89400 | ||
|
|
c337db8cc9 | ||
|
|
44a42fd2b6 | ||
|
|
1a933e4801 | ||
|
|
55e64b6ddd | ||
|
|
b83883e2db | ||
|
|
9c7e3b98aa | ||
|
|
8a869baa08 | ||
|
|
dbeb6c22d7 | ||
|
|
b00201d402 | ||
|
|
a1a17b1d5a | ||
|
|
f49853a4bd | ||
|
|
b10daa61f9 | ||
|
|
34b41ed15d | ||
|
|
3b38972743 | ||
|
|
36ed337845 | ||
|
|
5a1800cf1c | ||
|
|
97ac3b1af5 | ||
|
|
08e642c00e | ||
|
|
7940c766d4 | ||
|
|
f408f49165 | ||
|
|
785adb09b9 | ||
|
|
f52d0d639e | ||
|
|
4082e889ee | ||
|
|
b7093f294c | ||
|
|
cd63a77e99 | ||
|
|
8456852657 | ||
|
|
7d440f20bd | ||
|
|
feba8ae20b | ||
|
|
c9c2479289 | ||
|
|
4c45bf61d3 | ||
|
|
70d582074f | ||
|
|
0da4c07322 | ||
|
|
ee7735fa63 | ||
|
|
02fe741375 | ||
|
|
dbe4ac16bb | ||
|
|
f63e60327b | ||
|
|
0ec3907571 | ||
|
|
1658e3cd89 | ||
|
|
065436479b | ||
|
|
f6db26e4f8 | ||
|
|
c49dd1bf64 | ||
|
|
b4fcb4b499 | ||
|
|
7672b714b2 | ||
|
|
ca09717e8e | ||
|
|
0cc21de484 | ||
|
|
08375616a0 | ||
|
|
b993b863e7 | ||
|
|
07ff37597b | ||
|
|
e77326d99c | ||
|
|
8b3ac66120 | ||
|
|
2eb4d314ce | ||
|
|
adda59173c | ||
|
|
b696aeab6a | ||
|
|
6514fe5047 | ||
|
|
c63c453889 | ||
|
|
78260a5f08 | ||
|
|
b3dbb9546a | ||
|
|
272d28ecf2 | ||
|
|
6f12926142 | ||
|
|
d6111501c1 | ||
|
|
eba25057b9 | ||
|
|
e78bd5ab07 | ||
|
|
1643f2b232 | ||
|
|
1352672860 | ||
|
|
9e2fa418fb | ||
|
|
eecae14724 | ||
|
|
a6de8ed80e | ||
|
|
9c3a596a03 | ||
|
|
8294a64d7f | ||
|
|
1c4ad9d2b4 | ||
|
|
60b46aa2f3 | ||
|
|
f283edc482 | ||
|
|
dd86df756e | ||
|
|
422831fc81 | ||
|
|
306761537f | ||
|
|
7943df571a | ||
|
|
d501f8478a | ||
|
|
917cfc1f26 | ||
|
|
9b24d8e987 | ||
|
|
f4dfa67f04 | ||
|
|
6bcd1346bb | ||
|
|
dbfff6d776 | ||
|
|
c7b4a95202 | ||
|
|
c9b9f6824f | ||
|
|
e20e48a802 | ||
|
|
24f50d7ea5 | ||
|
|
7cd331617a | ||
|
|
cfb08fbafc | ||
|
|
9ecd394753 | ||
|
|
b84762e245 | ||
|
|
df02179189 | ||
|
|
b6fc8245e9 | ||
|
|
cb595887cc | ||
|
|
622b6057be | ||
|
|
9fda6ab1d9 | ||
|
|
b6c147622d | ||
|
|
12badfc238 | ||
|
|
2c02cbf6e9 | ||
|
|
8ab1bf120d | ||
|
|
aeb29b6459 | ||
|
|
f8687bab91 | ||
|
|
c48b0c80fc | ||
|
|
4accd107d0 | ||
|
|
a340046614 | ||
|
|
2a633c461e | ||
|
|
a6c5c84ae2 | ||
|
|
12c5674b84 | ||
|
|
0e47931b88 | ||
|
|
f34e73cd69 | ||
|
|
80a2ba3d3c | ||
|
|
b4f1a7ca72 | ||
|
|
fba0c40bb7 | ||
|
|
fd4567d9a6 | ||
|
|
d7f66b52de | ||
|
|
77a8f1a512 | ||
|
|
4636b9d146 | ||
|
|
5f2bf0fe55 | ||
|
|
a28853871d | ||
|
|
ace2e4dad7 | ||
|
|
180640ea07 | ||
|
|
a4f1a7589a | ||
|
|
ed54776643 | ||
|
|
c6961b7d38 | ||
|
|
ba1dffed63 | ||
|
|
95d5d75ede | ||
|
|
c2d8d311c1 | ||
|
|
8efacc43ae | ||
|
|
6c615ec57e | ||
|
|
3674838cd0 | ||
|
|
d5dd3498eb | ||
|
|
dc8764f061 | ||
|
|
226a48949c | ||
|
|
04b4e75f33 | ||
|
|
d9fcd2a1c8 | ||
|
|
432d29db0d | ||
|
|
c6fcc10ab3 | ||
|
|
8926817219 | ||
|
|
ce8c8b7bd8 | ||
|
|
d34b867d81 |
No files matched your search
@@ -271,6 +271,7 @@ endif
|
||||
install-doc: $(DOCS)
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)"
|
||||
$(INSTALL_DATA) qemu-doc.html qemu-tech.html "$(DESTDIR)$(qemu_docdir)"
|
||||
$(INSTALL_DATA) QMP/qmp-commands.txt "$(DESTDIR)$(qemu_docdir)"
|
||||
ifdef CONFIG_POSIX
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
|
||||
$(INSTALL_DATA) qemu.1 qemu-img.1 "$(DESTDIR)$(mandir)/man1"
|
||||
|
||||
@@ -100,6 +100,10 @@ const uint32_t arch_type = QEMU_ARCH;
|
||||
#define VECTYPE vector unsigned char
|
||||
#define SPLAT(p) vec_splat(vec_ld(0, p), 0)
|
||||
#define ALL_EQ(v1, v2) vec_all_eq(v1, v2)
|
||||
/* altivec.h may redefine the bool macro as vector type.
|
||||
* Reset it to POSIX semantics. */
|
||||
#undef bool
|
||||
#define bool _Bool
|
||||
#elif defined __SSE2__
|
||||
#include <emmintrin.h>
|
||||
#define VECTYPE __m128i
|
||||
|
||||
+7
-6
@@ -194,18 +194,19 @@ uint32_t do_arm_semihosting(CPUARMState *env)
|
||||
if (!(s = lock_user_string(ARG(0))))
|
||||
/* FIXME - should this error code be -TARGET_EFAULT ? */
|
||||
return (uint32_t)-1;
|
||||
if (ARG(1) >= 12)
|
||||
if (ARG(1) >= 12) {
|
||||
unlock_user(s, ARG(0), 0);
|
||||
return (uint32_t)-1;
|
||||
}
|
||||
if (strcmp(s, ":tt") == 0) {
|
||||
if (ARG(1) < 4)
|
||||
return STDIN_FILENO;
|
||||
else
|
||||
return STDOUT_FILENO;
|
||||
int result_fileno = ARG(1) < 4 ? STDIN_FILENO : STDOUT_FILENO;
|
||||
unlock_user(s, ARG(0), 0);
|
||||
return result_fileno;
|
||||
}
|
||||
if (use_gdb_syscalls()) {
|
||||
gdb_do_syscall(arm_semi_cb, "open,%s,%x,1a4", ARG(0),
|
||||
(int)ARG(2)+1, gdb_open_modeflags[ARG(1)]);
|
||||
return env->regs[0];
|
||||
ret = env->regs[0];
|
||||
} else {
|
||||
ret = set_swi_errno(ts, open(s, open_modeflags[ARG(1)], 0644));
|
||||
}
|
||||
|
||||
+8
-4
@@ -1775,10 +1775,12 @@ static void audio_atexit (void)
|
||||
HWVoiceOut *hwo = NULL;
|
||||
HWVoiceIn *hwi = NULL;
|
||||
|
||||
while ((hwo = audio_pcm_hw_find_any_enabled_out (hwo))) {
|
||||
while ((hwo = audio_pcm_hw_find_any_out (hwo))) {
|
||||
SWVoiceCap *sc;
|
||||
|
||||
hwo->pcm_ops->ctl_out (hwo, VOICE_DISABLE);
|
||||
if (hwo->enabled) {
|
||||
hwo->pcm_ops->ctl_out (hwo, VOICE_DISABLE);
|
||||
}
|
||||
hwo->pcm_ops->fini_out (hwo);
|
||||
|
||||
for (sc = hwo->cap_head.lh_first; sc; sc = sc->entries.le_next) {
|
||||
@@ -1791,8 +1793,10 @@ static void audio_atexit (void)
|
||||
}
|
||||
}
|
||||
|
||||
while ((hwi = audio_pcm_hw_find_any_enabled_in (hwi))) {
|
||||
hwi->pcm_ops->ctl_in (hwi, VOICE_DISABLE);
|
||||
while ((hwi = audio_pcm_hw_find_any_in (hwi))) {
|
||||
if (hwi->enabled) {
|
||||
hwi->pcm_ops->ctl_in (hwi, VOICE_DISABLE);
|
||||
}
|
||||
hwi->pcm_ops->fini_in (hwi);
|
||||
}
|
||||
|
||||
|
||||
+24
-12
@@ -33,7 +33,8 @@
|
||||
#define ENDIAN_CONVERT(v) (v)
|
||||
|
||||
/* Signed 8 bit */
|
||||
#define IN_T int8_t
|
||||
#define BSIZE 8
|
||||
#define ITYPE int
|
||||
#define IN_MIN SCHAR_MIN
|
||||
#define IN_MAX SCHAR_MAX
|
||||
#define SIGNED
|
||||
@@ -42,25 +43,29 @@
|
||||
#undef SIGNED
|
||||
#undef IN_MAX
|
||||
#undef IN_MIN
|
||||
#undef IN_T
|
||||
#undef BSIZE
|
||||
#undef ITYPE
|
||||
#undef SHIFT
|
||||
|
||||
/* Unsigned 8 bit */
|
||||
#define IN_T uint8_t
|
||||
#define BSIZE 8
|
||||
#define ITYPE uint
|
||||
#define IN_MIN 0
|
||||
#define IN_MAX UCHAR_MAX
|
||||
#define SHIFT 8
|
||||
#include "mixeng_template.h"
|
||||
#undef IN_MAX
|
||||
#undef IN_MIN
|
||||
#undef IN_T
|
||||
#undef BSIZE
|
||||
#undef ITYPE
|
||||
#undef SHIFT
|
||||
|
||||
#undef ENDIAN_CONVERT
|
||||
#undef ENDIAN_CONVERSION
|
||||
|
||||
/* Signed 16 bit */
|
||||
#define IN_T int16_t
|
||||
#define BSIZE 16
|
||||
#define ITYPE int
|
||||
#define IN_MIN SHRT_MIN
|
||||
#define IN_MAX SHRT_MAX
|
||||
#define SIGNED
|
||||
@@ -78,11 +83,13 @@
|
||||
#undef SIGNED
|
||||
#undef IN_MAX
|
||||
#undef IN_MIN
|
||||
#undef IN_T
|
||||
#undef BSIZE
|
||||
#undef ITYPE
|
||||
#undef SHIFT
|
||||
|
||||
/* Unsigned 16 bit */
|
||||
#define IN_T uint16_t
|
||||
#define BSIZE 16
|
||||
#define ITYPE uint
|
||||
#define IN_MIN 0
|
||||
#define IN_MAX USHRT_MAX
|
||||
#define SHIFT 16
|
||||
@@ -98,11 +105,13 @@
|
||||
#undef ENDIAN_CONVERSION
|
||||
#undef IN_MAX
|
||||
#undef IN_MIN
|
||||
#undef IN_T
|
||||
#undef BSIZE
|
||||
#undef ITYPE
|
||||
#undef SHIFT
|
||||
|
||||
/* Signed 32 bit */
|
||||
#define IN_T int32_t
|
||||
#define BSIZE 32
|
||||
#define ITYPE int
|
||||
#define IN_MIN INT32_MIN
|
||||
#define IN_MAX INT32_MAX
|
||||
#define SIGNED
|
||||
@@ -120,11 +129,13 @@
|
||||
#undef SIGNED
|
||||
#undef IN_MAX
|
||||
#undef IN_MIN
|
||||
#undef IN_T
|
||||
#undef BSIZE
|
||||
#undef ITYPE
|
||||
#undef SHIFT
|
||||
|
||||
/* Unsigned 32 bit */
|
||||
#define IN_T uint32_t
|
||||
#define BSIZE 32
|
||||
#define ITYPE uint
|
||||
#define IN_MIN 0
|
||||
#define IN_MAX UINT32_MAX
|
||||
#define SHIFT 32
|
||||
@@ -140,7 +151,8 @@
|
||||
#undef ENDIAN_CONVERSION
|
||||
#undef IN_MAX
|
||||
#undef IN_MIN
|
||||
#undef IN_T
|
||||
#undef BSIZE
|
||||
#undef ITYPE
|
||||
#undef SHIFT
|
||||
|
||||
t_sample *mixeng_conv[2][2][2][3] = {
|
||||
|
||||
@@ -31,7 +31,8 @@
|
||||
#define HALF (IN_MAX >> 1)
|
||||
#endif
|
||||
|
||||
#define ET glue (ENDIAN_CONVERSION, glue (_, IN_T))
|
||||
#define ET glue (ENDIAN_CONVERSION, glue (glue (glue (_, ITYPE), BSIZE), _t))
|
||||
#define IN_T glue (glue (ITYPE, BSIZE), _t)
|
||||
|
||||
#ifdef FLOAT_MIXENG
|
||||
static mixeng_real inline glue (conv_, ET) (IN_T v)
|
||||
@@ -150,3 +151,4 @@ static void glue (glue (clip_, ET), _from_mono)
|
||||
|
||||
#undef ET
|
||||
#undef HALF
|
||||
#undef IN_T
|
||||
@@ -349,21 +349,15 @@ static int winwave_ctl_out (HWVoiceOut *hw, int cmd, ...)
|
||||
else {
|
||||
hw->poll_mode = 0;
|
||||
}
|
||||
if (wave->paused) {
|
||||
mr = waveOutRestart (wave->hwo);
|
||||
if (mr != MMSYSERR_NOERROR) {
|
||||
winwave_logerr (mr, "waveOutRestart");
|
||||
}
|
||||
wave->paused = 0;
|
||||
}
|
||||
wave->paused = 0;
|
||||
}
|
||||
return 0;
|
||||
|
||||
case VOICE_DISABLE:
|
||||
if (!wave->paused) {
|
||||
mr = waveOutPause (wave->hwo);
|
||||
mr = waveOutReset (wave->hwo);
|
||||
if (mr != MMSYSERR_NOERROR) {
|
||||
winwave_logerr (mr, "waveOutPause");
|
||||
winwave_logerr (mr, "waveOutReset");
|
||||
}
|
||||
else {
|
||||
wave->paused = 1;
|
||||
|
||||
@@ -409,28 +409,36 @@ int bdrv_create_file(const char* filename, QEMUOptionParameter *options)
|
||||
return bdrv_create(drv, filename, options);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a uniquely-named empty temporary file.
|
||||
* Return 0 upon success, otherwise a negative errno value.
|
||||
*/
|
||||
int get_tmp_filename(char *filename, int size)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
void get_tmp_filename(char *filename, int size)
|
||||
{
|
||||
char temp_dir[MAX_PATH];
|
||||
|
||||
GetTempPath(MAX_PATH, temp_dir);
|
||||
GetTempFileName(temp_dir, "qem", 0, filename);
|
||||
}
|
||||
/* GetTempFileName requires that its output buffer (4th param)
|
||||
have length MAX_PATH or greater. */
|
||||
assert(size >= MAX_PATH);
|
||||
return (GetTempPath(MAX_PATH, temp_dir)
|
||||
&& GetTempFileName(temp_dir, "qem", 0, filename)
|
||||
? 0 : -GetLastError());
|
||||
#else
|
||||
void get_tmp_filename(char *filename, int size)
|
||||
{
|
||||
int fd;
|
||||
const char *tmpdir;
|
||||
/* XXX: race condition possible */
|
||||
tmpdir = getenv("TMPDIR");
|
||||
if (!tmpdir)
|
||||
tmpdir = "/tmp";
|
||||
snprintf(filename, size, "%s/vl.XXXXXX", tmpdir);
|
||||
if (snprintf(filename, size, "%s/vl.XXXXXX", tmpdir) >= size) {
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
fd = mkstemp(filename);
|
||||
close(fd);
|
||||
}
|
||||
if (fd < 0 || close(fd)) {
|
||||
return -errno;
|
||||
}
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Detect host devices. By convention, /dev/cdrom[N] is always
|
||||
@@ -753,7 +761,10 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
|
||||
|
||||
bdrv_delete(bs1);
|
||||
|
||||
get_tmp_filename(tmp_filename, sizeof(tmp_filename));
|
||||
ret = get_tmp_filename(tmp_filename, sizeof(tmp_filename));
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Real path is meaningless for protocols */
|
||||
if (is_protocol)
|
||||
|
||||
+257
-93
@@ -25,10 +25,12 @@
|
||||
#include "config-host.h"
|
||||
|
||||
#include <poll.h>
|
||||
#include <arpa/inet.h>
|
||||
#include "qemu-common.h"
|
||||
#include "qemu-error.h"
|
||||
#include "block_int.h"
|
||||
#include "trace.h"
|
||||
#include "hw/scsi-defs.h"
|
||||
|
||||
#include <iscsi/iscsi.h>
|
||||
#include <iscsi/scsi-lowlevel.h>
|
||||
@@ -37,8 +39,10 @@
|
||||
typedef struct IscsiLun {
|
||||
struct iscsi_context *iscsi;
|
||||
int lun;
|
||||
enum scsi_inquiry_peripheral_device_type type;
|
||||
int block_size;
|
||||
unsigned long num_blocks;
|
||||
uint64_t num_blocks;
|
||||
int events;
|
||||
} IscsiLun;
|
||||
|
||||
typedef struct IscsiAIOCB {
|
||||
@@ -61,10 +65,44 @@ struct IscsiTask {
|
||||
int complete;
|
||||
};
|
||||
|
||||
static void
|
||||
iscsi_bh_cb(void *p)
|
||||
{
|
||||
IscsiAIOCB *acb = p;
|
||||
|
||||
qemu_bh_delete(acb->bh);
|
||||
|
||||
if (acb->canceled == 0) {
|
||||
acb->common.cb(acb->common.opaque, acb->status);
|
||||
}
|
||||
|
||||
if (acb->task != NULL) {
|
||||
scsi_free_scsi_task(acb->task);
|
||||
acb->task = NULL;
|
||||
}
|
||||
|
||||
qemu_aio_release(acb);
|
||||
}
|
||||
|
||||
static void
|
||||
iscsi_schedule_bh(IscsiAIOCB *acb)
|
||||
{
|
||||
if (acb->bh) {
|
||||
return;
|
||||
}
|
||||
acb->bh = qemu_bh_new(iscsi_bh_cb, acb);
|
||||
qemu_bh_schedule(acb->bh);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
iscsi_abort_task_cb(struct iscsi_context *iscsi, int status, void *command_data,
|
||||
void *private_data)
|
||||
{
|
||||
IscsiAIOCB *acb = private_data;
|
||||
|
||||
acb->status = -ECANCELED;
|
||||
iscsi_schedule_bh(acb);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -73,15 +111,19 @@ iscsi_aio_cancel(BlockDriverAIOCB *blockacb)
|
||||
IscsiAIOCB *acb = (IscsiAIOCB *)blockacb;
|
||||
IscsiLun *iscsilun = acb->iscsilun;
|
||||
|
||||
acb->common.cb(acb->common.opaque, -ECANCELED);
|
||||
if (acb->status != -EINPROGRESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
acb->canceled = 1;
|
||||
|
||||
/* send a task mgmt call to the target to cancel the task on the target */
|
||||
iscsi_task_mgmt_abort_task_async(iscsilun->iscsi, acb->task,
|
||||
iscsi_abort_task_cb, NULL);
|
||||
iscsi_abort_task_cb, acb);
|
||||
|
||||
/* then also cancel the task locally in libiscsi */
|
||||
iscsi_scsi_task_cancel(iscsilun->iscsi, acb->task);
|
||||
while (acb->status == -EINPROGRESS) {
|
||||
qemu_aio_wait();
|
||||
}
|
||||
}
|
||||
|
||||
static AIOPool iscsi_aio_pool = {
|
||||
@@ -104,11 +146,27 @@ static void
|
||||
iscsi_set_events(IscsiLun *iscsilun)
|
||||
{
|
||||
struct iscsi_context *iscsi = iscsilun->iscsi;
|
||||
int ev;
|
||||
|
||||
qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), iscsi_process_read,
|
||||
(iscsi_which_events(iscsi) & POLLOUT)
|
||||
? iscsi_process_write : NULL,
|
||||
iscsi_process_flush, iscsilun);
|
||||
/* We always register a read handler. */
|
||||
ev = POLLIN;
|
||||
ev |= iscsi_which_events(iscsi);
|
||||
if (ev != iscsilun->events) {
|
||||
qemu_aio_set_fd_handler(iscsi_get_fd(iscsi),
|
||||
iscsi_process_read,
|
||||
(ev & POLLOUT) ? iscsi_process_write : NULL,
|
||||
iscsi_process_flush,
|
||||
iscsilun);
|
||||
|
||||
}
|
||||
|
||||
/* If we just added an event, the callback might be delayed
|
||||
* unless we call qemu_notify_event().
|
||||
*/
|
||||
if (ev & ~iscsilun->events) {
|
||||
qemu_notify_event();
|
||||
}
|
||||
iscsilun->events = ev;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -132,61 +190,28 @@ iscsi_process_write(void *arg)
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
iscsi_schedule_bh(QEMUBHFunc *cb, IscsiAIOCB *acb)
|
||||
{
|
||||
acb->bh = qemu_bh_new(cb, acb);
|
||||
if (!acb->bh) {
|
||||
error_report("oom: could not create iscsi bh");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
qemu_bh_schedule(acb->bh);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
iscsi_readv_writev_bh_cb(void *p)
|
||||
{
|
||||
IscsiAIOCB *acb = p;
|
||||
|
||||
qemu_bh_delete(acb->bh);
|
||||
|
||||
if (acb->canceled == 0) {
|
||||
acb->common.cb(acb->common.opaque, acb->status);
|
||||
}
|
||||
|
||||
qemu_aio_release(acb);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
iscsi_aio_write10_cb(struct iscsi_context *iscsi, int status,
|
||||
iscsi_aio_write16_cb(struct iscsi_context *iscsi, int status,
|
||||
void *command_data, void *opaque)
|
||||
{
|
||||
IscsiAIOCB *acb = opaque;
|
||||
|
||||
trace_iscsi_aio_write10_cb(iscsi, status, acb, acb->canceled);
|
||||
trace_iscsi_aio_write16_cb(iscsi, status, acb, acb->canceled);
|
||||
|
||||
g_free(acb->buf);
|
||||
|
||||
if (acb->canceled != 0) {
|
||||
qemu_aio_release(acb);
|
||||
scsi_free_scsi_task(acb->task);
|
||||
acb->task = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
acb->status = 0;
|
||||
if (status < 0) {
|
||||
error_report("Failed to write10 data to iSCSI lun. %s",
|
||||
error_report("Failed to write16 data to iSCSI lun. %s",
|
||||
iscsi_get_error(iscsi));
|
||||
acb->status = -EIO;
|
||||
}
|
||||
|
||||
iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb);
|
||||
scsi_free_scsi_task(acb->task);
|
||||
acb->task = NULL;
|
||||
iscsi_schedule_bh(acb);
|
||||
}
|
||||
|
||||
static int64_t sector_qemu2lun(int64_t sector, IscsiLun *iscsilun)
|
||||
@@ -204,12 +229,9 @@ iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num,
|
||||
struct iscsi_context *iscsi = iscsilun->iscsi;
|
||||
IscsiAIOCB *acb;
|
||||
size_t size;
|
||||
int fua = 0;
|
||||
|
||||
/* set FUA on writes when cache mode is write through */
|
||||
if (!(bs->open_flags & BDRV_O_CACHE_WB)) {
|
||||
fua = 1;
|
||||
}
|
||||
uint32_t num_sectors;
|
||||
uint64_t lba;
|
||||
struct iscsi_data data;
|
||||
|
||||
acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
|
||||
trace_iscsi_aio_writev(iscsi, sector_num, nb_sectors, opaque, acb);
|
||||
@@ -218,19 +240,47 @@ iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num,
|
||||
acb->qiov = qiov;
|
||||
|
||||
acb->canceled = 0;
|
||||
acb->bh = NULL;
|
||||
acb->status = -EINPROGRESS;
|
||||
|
||||
/* XXX we should pass the iovec to write10 to avoid the extra copy */
|
||||
/* XXX we should pass the iovec to write16 to avoid the extra copy */
|
||||
/* this will allow us to get rid of 'buf' completely */
|
||||
size = nb_sectors * BDRV_SECTOR_SIZE;
|
||||
acb->buf = g_malloc(size);
|
||||
qemu_iovec_to_buffer(acb->qiov, acb->buf);
|
||||
acb->task = iscsi_write10_task(iscsi, iscsilun->lun, acb->buf, size,
|
||||
sector_qemu2lun(sector_num, iscsilun),
|
||||
fua, 0, iscsilun->block_size,
|
||||
iscsi_aio_write10_cb, acb);
|
||||
|
||||
|
||||
acb->task = malloc(sizeof(struct scsi_task));
|
||||
if (acb->task == NULL) {
|
||||
error_report("iSCSI: Failed to send write10 command. %s",
|
||||
iscsi_get_error(iscsi));
|
||||
error_report("iSCSI: Failed to allocate task for scsi WRITE16 "
|
||||
"command. %s", iscsi_get_error(iscsi));
|
||||
qemu_aio_release(acb);
|
||||
return NULL;
|
||||
}
|
||||
memset(acb->task, 0, sizeof(struct scsi_task));
|
||||
|
||||
acb->task->xfer_dir = SCSI_XFER_WRITE;
|
||||
acb->task->cdb_size = 16;
|
||||
acb->task->cdb[0] = 0x8a;
|
||||
if (!(bs->open_flags & BDRV_O_CACHE_WB)) {
|
||||
/* set FUA on writes when cache mode is write through */
|
||||
acb->task->cdb[1] |= 0x04;
|
||||
}
|
||||
lba = sector_qemu2lun(sector_num, iscsilun);
|
||||
*(uint32_t *)&acb->task->cdb[2] = htonl(lba >> 32);
|
||||
*(uint32_t *)&acb->task->cdb[6] = htonl(lba & 0xffffffff);
|
||||
num_sectors = size / iscsilun->block_size;
|
||||
*(uint32_t *)&acb->task->cdb[10] = htonl(num_sectors);
|
||||
acb->task->expxferlen = size;
|
||||
|
||||
data.data = acb->buf;
|
||||
data.size = size;
|
||||
|
||||
if (iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task,
|
||||
iscsi_aio_write16_cb,
|
||||
&data,
|
||||
acb) != 0) {
|
||||
scsi_free_scsi_task(acb->task);
|
||||
g_free(acb->buf);
|
||||
qemu_aio_release(acb);
|
||||
return NULL;
|
||||
@@ -242,30 +292,25 @@ iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num,
|
||||
}
|
||||
|
||||
static void
|
||||
iscsi_aio_read10_cb(struct iscsi_context *iscsi, int status,
|
||||
iscsi_aio_read16_cb(struct iscsi_context *iscsi, int status,
|
||||
void *command_data, void *opaque)
|
||||
{
|
||||
IscsiAIOCB *acb = opaque;
|
||||
|
||||
trace_iscsi_aio_read10_cb(iscsi, status, acb, acb->canceled);
|
||||
trace_iscsi_aio_read16_cb(iscsi, status, acb, acb->canceled);
|
||||
|
||||
if (acb->canceled != 0) {
|
||||
qemu_aio_release(acb);
|
||||
scsi_free_scsi_task(acb->task);
|
||||
acb->task = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
acb->status = 0;
|
||||
if (status != 0) {
|
||||
error_report("Failed to read10 data from iSCSI lun. %s",
|
||||
error_report("Failed to read16 data from iSCSI lun. %s",
|
||||
iscsi_get_error(iscsi));
|
||||
acb->status = -EIO;
|
||||
}
|
||||
|
||||
iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb);
|
||||
scsi_free_scsi_task(acb->task);
|
||||
acb->task = NULL;
|
||||
iscsi_schedule_bh(acb);
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *
|
||||
@@ -277,8 +322,10 @@ iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num,
|
||||
IscsiLun *iscsilun = bs->opaque;
|
||||
struct iscsi_context *iscsi = iscsilun->iscsi;
|
||||
IscsiAIOCB *acb;
|
||||
size_t qemu_read_size, lun_read_size;
|
||||
size_t qemu_read_size;
|
||||
int i;
|
||||
uint64_t lba;
|
||||
uint32_t num_sectors;
|
||||
|
||||
qemu_read_size = BDRV_SECTOR_SIZE * (size_t)nb_sectors;
|
||||
|
||||
@@ -289,6 +336,8 @@ iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num,
|
||||
acb->qiov = qiov;
|
||||
|
||||
acb->canceled = 0;
|
||||
acb->bh = NULL;
|
||||
acb->status = -EINPROGRESS;
|
||||
acb->read_size = qemu_read_size;
|
||||
acb->buf = NULL;
|
||||
|
||||
@@ -303,16 +352,44 @@ iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num,
|
||||
acb->read_offset = bdrv_offset % iscsilun->block_size;
|
||||
}
|
||||
|
||||
lun_read_size = (qemu_read_size + iscsilun->block_size
|
||||
+ acb->read_offset - 1)
|
||||
/ iscsilun->block_size * iscsilun->block_size;
|
||||
acb->task = iscsi_read10_task(iscsi, iscsilun->lun,
|
||||
sector_qemu2lun(sector_num, iscsilun),
|
||||
lun_read_size, iscsilun->block_size,
|
||||
iscsi_aio_read10_cb, acb);
|
||||
num_sectors = (qemu_read_size + iscsilun->block_size
|
||||
+ acb->read_offset - 1)
|
||||
/ iscsilun->block_size;
|
||||
|
||||
acb->task = malloc(sizeof(struct scsi_task));
|
||||
if (acb->task == NULL) {
|
||||
error_report("iSCSI: Failed to send read10 command. %s",
|
||||
iscsi_get_error(iscsi));
|
||||
error_report("iSCSI: Failed to allocate task for scsi READ16 "
|
||||
"command. %s", iscsi_get_error(iscsi));
|
||||
qemu_aio_release(acb);
|
||||
return NULL;
|
||||
}
|
||||
memset(acb->task, 0, sizeof(struct scsi_task));
|
||||
|
||||
acb->task->xfer_dir = SCSI_XFER_READ;
|
||||
lba = sector_qemu2lun(sector_num, iscsilun);
|
||||
acb->task->expxferlen = qemu_read_size;
|
||||
|
||||
switch (iscsilun->type) {
|
||||
case TYPE_DISK:
|
||||
acb->task->cdb_size = 16;
|
||||
acb->task->cdb[0] = 0x88;
|
||||
*(uint32_t *)&acb->task->cdb[2] = htonl(lba >> 32);
|
||||
*(uint32_t *)&acb->task->cdb[6] = htonl(lba & 0xffffffff);
|
||||
*(uint32_t *)&acb->task->cdb[10] = htonl(num_sectors);
|
||||
break;
|
||||
default:
|
||||
acb->task->cdb_size = 10;
|
||||
acb->task->cdb[0] = 0x28;
|
||||
*(uint32_t *)&acb->task->cdb[2] = htonl(lba);
|
||||
*(uint16_t *)&acb->task->cdb[7] = htons(num_sectors);
|
||||
break;
|
||||
}
|
||||
|
||||
if (iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task,
|
||||
iscsi_aio_read16_cb,
|
||||
NULL,
|
||||
acb) != 0) {
|
||||
scsi_free_scsi_task(acb->task);
|
||||
qemu_aio_release(acb);
|
||||
return NULL;
|
||||
}
|
||||
@@ -336,9 +413,6 @@ iscsi_synccache10_cb(struct iscsi_context *iscsi, int status,
|
||||
IscsiAIOCB *acb = opaque;
|
||||
|
||||
if (acb->canceled != 0) {
|
||||
qemu_aio_release(acb);
|
||||
scsi_free_scsi_task(acb->task);
|
||||
acb->task = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -349,9 +423,7 @@ iscsi_synccache10_cb(struct iscsi_context *iscsi, int status,
|
||||
acb->status = -EIO;
|
||||
}
|
||||
|
||||
iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb);
|
||||
scsi_free_scsi_task(acb->task);
|
||||
acb->task = NULL;
|
||||
iscsi_schedule_bh(acb);
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *
|
||||
@@ -366,6 +438,8 @@ iscsi_aio_flush(BlockDriverState *bs,
|
||||
|
||||
acb->iscsilun = iscsilun;
|
||||
acb->canceled = 0;
|
||||
acb->bh = NULL;
|
||||
acb->status = -EINPROGRESS;
|
||||
|
||||
acb->task = iscsi_synchronizecache10_task(iscsi, iscsilun->lun,
|
||||
0, 0, 0, 0,
|
||||
@@ -390,9 +464,6 @@ iscsi_unmap_cb(struct iscsi_context *iscsi, int status,
|
||||
IscsiAIOCB *acb = opaque;
|
||||
|
||||
if (acb->canceled != 0) {
|
||||
qemu_aio_release(acb);
|
||||
scsi_free_scsi_task(acb->task);
|
||||
acb->task = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -403,9 +474,7 @@ iscsi_unmap_cb(struct iscsi_context *iscsi, int status,
|
||||
acb->status = -EIO;
|
||||
}
|
||||
|
||||
iscsi_schedule_bh(iscsi_readv_writev_bh_cb, acb);
|
||||
scsi_free_scsi_task(acb->task);
|
||||
acb->task = NULL;
|
||||
iscsi_schedule_bh(acb);
|
||||
}
|
||||
|
||||
static BlockDriverAIOCB *
|
||||
@@ -422,6 +491,8 @@ iscsi_aio_discard(BlockDriverState *bs,
|
||||
|
||||
acb->iscsilun = iscsilun;
|
||||
acb->canceled = 0;
|
||||
acb->bh = NULL;
|
||||
acb->status = -EINPROGRESS;
|
||||
|
||||
list[0].lba = sector_qemu2lun(sector_num, iscsilun);
|
||||
list[0].num = nb_sectors * BDRV_SECTOR_SIZE / iscsilun->block_size;
|
||||
@@ -490,6 +561,98 @@ iscsi_readcapacity16_cb(struct iscsi_context *iscsi, int status,
|
||||
scsi_free_scsi_task(task);
|
||||
}
|
||||
|
||||
static void
|
||||
iscsi_readcapacity10_cb(struct iscsi_context *iscsi, int status,
|
||||
void *command_data, void *opaque)
|
||||
{
|
||||
struct IscsiTask *itask = opaque;
|
||||
struct scsi_readcapacity10 *rc10;
|
||||
struct scsi_task *task = command_data;
|
||||
|
||||
if (status != 0) {
|
||||
error_report("iSCSI: Failed to read capacity of iSCSI lun. %s",
|
||||
iscsi_get_error(iscsi));
|
||||
itask->status = 1;
|
||||
itask->complete = 1;
|
||||
scsi_free_scsi_task(task);
|
||||
return;
|
||||
}
|
||||
|
||||
rc10 = scsi_datain_unmarshall(task);
|
||||
if (rc10 == NULL) {
|
||||
error_report("iSCSI: Failed to unmarshall readcapacity10 data.");
|
||||
itask->status = 1;
|
||||
itask->complete = 1;
|
||||
scsi_free_scsi_task(task);
|
||||
return;
|
||||
}
|
||||
|
||||
itask->iscsilun->block_size = rc10->block_size;
|
||||
itask->iscsilun->num_blocks = rc10->lba + 1;
|
||||
itask->bs->total_sectors = itask->iscsilun->num_blocks *
|
||||
itask->iscsilun->block_size / BDRV_SECTOR_SIZE ;
|
||||
|
||||
itask->status = 0;
|
||||
itask->complete = 1;
|
||||
scsi_free_scsi_task(task);
|
||||
}
|
||||
|
||||
static void
|
||||
iscsi_inquiry_cb(struct iscsi_context *iscsi, int status, void *command_data,
|
||||
void *opaque)
|
||||
{
|
||||
struct IscsiTask *itask = opaque;
|
||||
struct scsi_task *task = command_data;
|
||||
struct scsi_inquiry_standard *inq;
|
||||
|
||||
if (status != 0) {
|
||||
itask->status = 1;
|
||||
itask->complete = 1;
|
||||
scsi_free_scsi_task(task);
|
||||
return;
|
||||
}
|
||||
|
||||
inq = scsi_datain_unmarshall(task);
|
||||
if (inq == NULL) {
|
||||
error_report("iSCSI: Failed to unmarshall inquiry data.");
|
||||
itask->status = 1;
|
||||
itask->complete = 1;
|
||||
scsi_free_scsi_task(task);
|
||||
return;
|
||||
}
|
||||
|
||||
itask->iscsilun->type = inq->periperal_device_type;
|
||||
|
||||
scsi_free_scsi_task(task);
|
||||
|
||||
switch (itask->iscsilun->type) {
|
||||
case TYPE_DISK:
|
||||
task = iscsi_readcapacity16_task(iscsi, itask->iscsilun->lun,
|
||||
iscsi_readcapacity16_cb, opaque);
|
||||
if (task == NULL) {
|
||||
error_report("iSCSI: failed to send readcapacity16 command.");
|
||||
itask->status = 1;
|
||||
itask->complete = 1;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case TYPE_ROM:
|
||||
task = iscsi_readcapacity10_task(iscsi, itask->iscsilun->lun,
|
||||
0, 0,
|
||||
iscsi_readcapacity10_cb, opaque);
|
||||
if (task == NULL) {
|
||||
error_report("iSCSI: failed to send readcapacity16 command.");
|
||||
itask->status = 1;
|
||||
itask->complete = 1;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
itask->status = 0;
|
||||
itask->complete = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
iscsi_connect_cb(struct iscsi_context *iscsi, int status, void *command_data,
|
||||
void *opaque)
|
||||
@@ -503,10 +666,11 @@ iscsi_connect_cb(struct iscsi_context *iscsi, int status, void *command_data,
|
||||
return;
|
||||
}
|
||||
|
||||
task = iscsi_readcapacity16_task(iscsi, itask->iscsilun->lun,
|
||||
iscsi_readcapacity16_cb, opaque);
|
||||
task = iscsi_inquiry_task(iscsi, itask->iscsilun->lun,
|
||||
0, 0, 36,
|
||||
iscsi_inquiry_cb, opaque);
|
||||
if (task == NULL) {
|
||||
error_report("iSCSI: failed to send readcapacity16 command.");
|
||||
error_report("iSCSI: failed to send inquiry command.");
|
||||
itask->status = 1;
|
||||
itask->complete = 1;
|
||||
return;
|
||||
|
||||
+15
-10
@@ -471,6 +471,8 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
|
||||
QCOW_OFLAG_COMPRESSED | QCOW_OFLAG_ZERO);
|
||||
*cluster_offset &= L2E_OFFSET_MASK;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
|
||||
@@ -762,7 +764,6 @@ static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset,
|
||||
uint64_t *host_offset, unsigned int *nb_clusters)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int64_t cluster_offset;
|
||||
QCowL2Meta *old_alloc;
|
||||
|
||||
trace_qcow2_do_alloc_clusters_offset(qemu_coroutine_self(), guest_offset,
|
||||
@@ -808,17 +809,21 @@ static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset,
|
||||
/* Allocate new clusters */
|
||||
trace_qcow2_cluster_alloc_phys(qemu_coroutine_self());
|
||||
if (*host_offset == 0) {
|
||||
cluster_offset = qcow2_alloc_clusters(bs, *nb_clusters * s->cluster_size);
|
||||
int64_t cluster_offset =
|
||||
qcow2_alloc_clusters(bs, *nb_clusters * s->cluster_size);
|
||||
if (cluster_offset < 0) {
|
||||
return cluster_offset;
|
||||
}
|
||||
*host_offset = cluster_offset;
|
||||
return 0;
|
||||
} else {
|
||||
cluster_offset = *host_offset;
|
||||
*nb_clusters = qcow2_alloc_clusters_at(bs, cluster_offset, *nb_clusters);
|
||||
int ret = qcow2_alloc_clusters_at(bs, *host_offset, *nb_clusters);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
*nb_clusters = ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cluster_offset < 0) {
|
||||
return cluster_offset;
|
||||
}
|
||||
*host_offset = cluster_offset;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -367,7 +367,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
|
||||
}
|
||||
|
||||
for(i = 0; i < table_size; i++) {
|
||||
cpu_to_be64s(&new_table[i]);
|
||||
be64_to_cpus(&new_table[i]);
|
||||
}
|
||||
|
||||
/* Hook up the new refcount table in the qcow2 header */
|
||||
|
||||
+11
-9
@@ -298,14 +298,6 @@ static int qcow2_open(BlockDriverState *bs, int flags)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!bs->read_only && s->autoclear_features != 0) {
|
||||
s->autoclear_features = 0;
|
||||
ret = qcow2_update_header(bs);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check support for various header values */
|
||||
if (header.refcount_order != 4) {
|
||||
report_unsupported(bs, "%d bit reference counts",
|
||||
@@ -411,6 +403,15 @@ static int qcow2_open(BlockDriverState *bs, int flags)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Clear unknown autoclear feature bits */
|
||||
if (!bs->read_only && s->autoclear_features != 0) {
|
||||
s->autoclear_features = 0;
|
||||
ret = qcow2_update_header(bs);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialise locks */
|
||||
qemu_co_mutex_init(&s->lock);
|
||||
|
||||
@@ -919,7 +920,8 @@ int qcow2_update_header(BlockDriverState *bs)
|
||||
ret = sizeof(*header);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
buf += ret;
|
||||
|
||||
+74
-50
@@ -468,7 +468,7 @@ static int connect_to_sdog(const char *addr, const char *port)
|
||||
if (ret) {
|
||||
error_report("unable to get address info %s, %s",
|
||||
addr, strerror(errno));
|
||||
return -1;
|
||||
return -errno;
|
||||
}
|
||||
|
||||
for (res = res0; res; res = res->ai_next) {
|
||||
@@ -489,13 +489,14 @@ static int connect_to_sdog(const char *addr, const char *port)
|
||||
if (errno == EINTR) {
|
||||
goto reconnect;
|
||||
}
|
||||
close(fd);
|
||||
break;
|
||||
}
|
||||
|
||||
dprintf("connected to %s:%s\n", addr, port);
|
||||
goto success;
|
||||
}
|
||||
fd = -1;
|
||||
fd = -errno;
|
||||
error_report("failed connect to %s:%s", addr, port);
|
||||
success:
|
||||
freeaddrinfo(res0);
|
||||
@@ -510,12 +511,13 @@ static int send_req(int sockfd, SheepdogReq *hdr, void *data,
|
||||
ret = qemu_send_full(sockfd, hdr, sizeof(*hdr), 0);
|
||||
if (ret < sizeof(*hdr)) {
|
||||
error_report("failed to send a req, %s", strerror(errno));
|
||||
return ret;
|
||||
return -errno;
|
||||
}
|
||||
|
||||
ret = qemu_send_full(sockfd, data, *wlen, 0);
|
||||
if (ret < *wlen) {
|
||||
error_report("failed to send a req, %s", strerror(errno));
|
||||
ret = -errno;
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -553,6 +555,7 @@ static int do_req(int sockfd, SheepdogReq *hdr, void *data,
|
||||
ret = qemu_recv_full(sockfd, hdr, sizeof(*hdr), 0);
|
||||
if (ret < sizeof(*hdr)) {
|
||||
error_report("failed to get a rsp, %s", strerror(errno));
|
||||
ret = -errno;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -564,6 +567,7 @@ static int do_req(int sockfd, SheepdogReq *hdr, void *data,
|
||||
ret = qemu_recv_full(sockfd, data, *rlen, 0);
|
||||
if (ret < *rlen) {
|
||||
error_report("failed to get the data, %s", strerror(errno));
|
||||
ret = -errno;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@@ -587,6 +591,7 @@ static int do_co_req(int sockfd, SheepdogReq *hdr, void *data,
|
||||
ret = qemu_co_recv(sockfd, hdr, sizeof(*hdr));
|
||||
if (ret < sizeof(*hdr)) {
|
||||
error_report("failed to get a rsp, %s", strerror(errno));
|
||||
ret = -errno;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -598,6 +603,7 @@ static int do_co_req(int sockfd, SheepdogReq *hdr, void *data,
|
||||
ret = qemu_co_recv(sockfd, data, *rlen);
|
||||
if (ret < *rlen) {
|
||||
error_report("failed to get the data, %s", strerror(errno));
|
||||
ret = -errno;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@@ -787,7 +793,7 @@ static int get_sheep_fd(BDRVSheepdogState *s)
|
||||
fd = connect_to_sdog(s->addr, s->port);
|
||||
if (fd < 0) {
|
||||
error_report("%s", strerror(errno));
|
||||
return -1;
|
||||
return fd;
|
||||
}
|
||||
|
||||
socket_set_nonblock(fd);
|
||||
@@ -796,7 +802,7 @@ static int get_sheep_fd(BDRVSheepdogState *s)
|
||||
if (ret) {
|
||||
error_report("%s", strerror(errno));
|
||||
closesocket(fd);
|
||||
return -1;
|
||||
return -errno;
|
||||
}
|
||||
|
||||
qemu_aio_set_fd_handler(fd, co_read_response, NULL, aio_flush_request, s);
|
||||
@@ -883,7 +889,7 @@ static int find_vdi_name(BDRVSheepdogState *s, char *filename, uint32_t snapid,
|
||||
|
||||
fd = connect_to_sdog(s->addr, s->port);
|
||||
if (fd < 0) {
|
||||
return -1;
|
||||
return fd;
|
||||
}
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
@@ -904,14 +910,17 @@ static int find_vdi_name(BDRVSheepdogState *s, char *filename, uint32_t snapid,
|
||||
|
||||
ret = do_req(fd, (SheepdogReq *)&hdr, buf, &wlen, &rlen);
|
||||
if (ret) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (rsp->result != SD_RES_SUCCESS) {
|
||||
error_report("cannot get vdi info, %s, %s %d %s",
|
||||
sd_strerror(rsp->result), filename, snapid, tag);
|
||||
ret = -1;
|
||||
if (rsp->result == SD_RES_NO_VDI) {
|
||||
ret = -ENOENT;
|
||||
} else {
|
||||
ret = -EIO;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
*vid = rsp->vdi_id;
|
||||
@@ -980,7 +989,7 @@ static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
|
||||
if (ret < 0) {
|
||||
qemu_co_mutex_unlock(&s->lock);
|
||||
error_report("failed to send a req, %s", strerror(errno));
|
||||
return -EIO;
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (wlen) {
|
||||
@@ -988,7 +997,7 @@ static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
|
||||
if (ret < 0) {
|
||||
qemu_co_mutex_unlock(&s->lock);
|
||||
error_report("failed to send a data, %s", strerror(errno));
|
||||
return -EIO;
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1038,7 +1047,7 @@ static int read_write_object(int fd, char *buf, uint64_t oid, int copies,
|
||||
ret = do_req(fd, (SheepdogReq *)&hdr, buf, &wlen, &rlen);
|
||||
if (ret) {
|
||||
error_report("failed to send a request to the sheep");
|
||||
return -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (rsp->result) {
|
||||
@@ -1046,7 +1055,7 @@ static int read_write_object(int fd, char *buf, uint64_t oid, int copies,
|
||||
return 0;
|
||||
default:
|
||||
error_report("%s", sd_strerror(rsp->result));
|
||||
return -1;
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1082,10 +1091,12 @@ static int sd_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
memset(vdi, 0, sizeof(vdi));
|
||||
memset(tag, 0, sizeof(tag));
|
||||
if (parse_vdiname(s, filename, vdi, &snapid, tag) < 0) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
s->fd = get_sheep_fd(s);
|
||||
if (s->fd < 0) {
|
||||
ret = s->fd;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1099,11 +1110,12 @@ static int sd_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
s->flush_fd = connect_to_sdog(s->addr, s->port);
|
||||
if (s->flush_fd < 0) {
|
||||
error_report("failed to connect");
|
||||
ret = s->flush_fd;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (snapid) {
|
||||
if (snapid || tag[0] != '\0') {
|
||||
dprintf("%" PRIx32 " snapshot inode was open.\n", vid);
|
||||
s->is_snapshot = 1;
|
||||
}
|
||||
@@ -1111,6 +1123,7 @@ static int sd_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
fd = connect_to_sdog(s->addr, s->port);
|
||||
if (fd < 0) {
|
||||
error_report("failed to connect");
|
||||
ret = fd;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1139,7 +1152,7 @@ out:
|
||||
closesocket(s->fd);
|
||||
}
|
||||
g_free(buf);
|
||||
return -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int do_sd_create(char *filename, int64_t vdi_size,
|
||||
@@ -1154,7 +1167,7 @@ static int do_sd_create(char *filename, int64_t vdi_size,
|
||||
|
||||
fd = connect_to_sdog(addr, port);
|
||||
if (fd < 0) {
|
||||
return -EIO;
|
||||
return fd;
|
||||
}
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
@@ -1177,7 +1190,7 @@ static int do_sd_create(char *filename, int64_t vdi_size,
|
||||
closesocket(fd);
|
||||
|
||||
if (ret) {
|
||||
return -EIO;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (rsp->result != SD_RES_SUCCESS) {
|
||||
@@ -1237,24 +1250,26 @@ out:
|
||||
|
||||
static int sd_create(const char *filename, QEMUOptionParameter *options)
|
||||
{
|
||||
int ret;
|
||||
int ret = 0;
|
||||
uint32_t vid = 0, base_vid = 0;
|
||||
int64_t vdi_size = 0;
|
||||
char *backing_file = NULL;
|
||||
BDRVSheepdogState s;
|
||||
BDRVSheepdogState *s;
|
||||
char vdi[SD_MAX_VDI_LEN], tag[SD_MAX_VDI_TAG_LEN];
|
||||
uint32_t snapid;
|
||||
int prealloc = 0;
|
||||
const char *vdiname;
|
||||
|
||||
s = g_malloc0(sizeof(BDRVSheepdogState));
|
||||
|
||||
strstart(filename, "sheepdog:", &vdiname);
|
||||
|
||||
memset(&s, 0, sizeof(s));
|
||||
memset(vdi, 0, sizeof(vdi));
|
||||
memset(tag, 0, sizeof(tag));
|
||||
if (parse_vdiname(&s, vdiname, vdi, &snapid, tag) < 0) {
|
||||
if (parse_vdiname(s, vdiname, vdi, &snapid, tag) < 0) {
|
||||
error_report("invalid filename");
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (options && options->name) {
|
||||
@@ -1270,7 +1285,8 @@ static int sd_create(const char *filename, QEMUOptionParameter *options)
|
||||
} else {
|
||||
error_report("Invalid preallocation mode: '%s'",
|
||||
options->value.s);
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
options++;
|
||||
@@ -1278,7 +1294,8 @@ static int sd_create(const char *filename, QEMUOptionParameter *options)
|
||||
|
||||
if (vdi_size > SD_MAX_VDI_SIZE) {
|
||||
error_report("too big image size");
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (backing_file) {
|
||||
@@ -1290,31 +1307,37 @@ static int sd_create(const char *filename, QEMUOptionParameter *options)
|
||||
drv = bdrv_find_protocol(backing_file);
|
||||
if (!drv || strcmp(drv->protocol_name, "sheepdog") != 0) {
|
||||
error_report("backing_file must be a sheepdog image");
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = bdrv_file_open(&bs, backing_file, 0);
|
||||
if (ret < 0)
|
||||
return -EIO;
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
s = bs->opaque;
|
||||
|
||||
if (!is_snapshot(&s->inode)) {
|
||||
error_report("cannot clone from a non snapshot vdi");
|
||||
bdrv_delete(bs);
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
base_vid = s->inode.vdi_id;
|
||||
bdrv_delete(bs);
|
||||
}
|
||||
|
||||
ret = do_sd_create(vdi, vdi_size, base_vid, &vid, 0, s.addr, s.port);
|
||||
ret = do_sd_create(vdi, vdi_size, base_vid, &vid, 0, s->addr, s->port);
|
||||
if (!prealloc || ret) {
|
||||
return ret;
|
||||
goto out;
|
||||
}
|
||||
|
||||
return sd_prealloc(filename);
|
||||
ret = sd_prealloc(filename);
|
||||
out:
|
||||
g_free(s);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void sd_close(BlockDriverState *bs)
|
||||
@@ -1379,7 +1402,7 @@ static int sd_truncate(BlockDriverState *bs, int64_t offset)
|
||||
|
||||
fd = connect_to_sdog(s->addr, s->port);
|
||||
if (fd < 0) {
|
||||
return -EIO;
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* we don't need to update entire object */
|
||||
@@ -1391,10 +1414,9 @@ static int sd_truncate(BlockDriverState *bs, int64_t offset)
|
||||
|
||||
if (ret < 0) {
|
||||
error_report("failed to update an inode.");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1464,6 +1486,7 @@ static int sd_create_branch(BDRVSheepdogState *s)
|
||||
fd = connect_to_sdog(s->addr, s->port);
|
||||
if (fd < 0) {
|
||||
error_report("failed to connect");
|
||||
ret = fd;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1606,8 +1629,9 @@ static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num,
|
||||
|
||||
if (bs->growable && sector_num + nb_sectors > bs->total_sectors) {
|
||||
/* TODO: shouldn't block here */
|
||||
if (sd_truncate(bs, (sector_num + nb_sectors) * SECTOR_SIZE) < 0) {
|
||||
return -EIO;
|
||||
ret = sd_truncate(bs, (sector_num + nb_sectors) * SECTOR_SIZE);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
bs->total_sectors = sector_num + nb_sectors;
|
||||
}
|
||||
@@ -1724,7 +1748,7 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
|
||||
/* refresh inode. */
|
||||
fd = connect_to_sdog(s->addr, s->port);
|
||||
if (fd < 0) {
|
||||
ret = -EIO;
|
||||
ret = fd;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@@ -1732,7 +1756,6 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
|
||||
s->inode.nr_copies, datalen, 0, 0, s->cache_enabled);
|
||||
if (ret < 0) {
|
||||
error_report("failed to write snapshot's inode.");
|
||||
ret = -EIO;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@@ -1741,7 +1764,6 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
|
||||
if (ret < 0) {
|
||||
error_report("failed to create inode for snapshot. %s",
|
||||
strerror(errno));
|
||||
ret = -EIO;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@@ -1752,7 +1774,6 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
|
||||
|
||||
if (ret < 0) {
|
||||
error_report("failed to read new inode info. %s", strerror(errno));
|
||||
ret = -EIO;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@@ -1773,7 +1794,7 @@ static int sd_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
|
||||
char *buf = NULL;
|
||||
uint32_t vid;
|
||||
uint32_t snapid = 0;
|
||||
int ret = -ENOENT, fd;
|
||||
int ret = 0, fd;
|
||||
|
||||
old_s = g_malloc(sizeof(BDRVSheepdogState));
|
||||
|
||||
@@ -1791,13 +1812,13 @@ static int sd_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
|
||||
ret = find_vdi_name(s, vdi, snapid, tag, &vid, 1);
|
||||
if (ret) {
|
||||
error_report("Failed to find_vdi_name");
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
fd = connect_to_sdog(s->addr, s->port);
|
||||
if (fd < 0) {
|
||||
error_report("failed to connect");
|
||||
ret = fd;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1808,7 +1829,6 @@ static int sd_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
|
||||
closesocket(fd);
|
||||
|
||||
if (ret) {
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1861,6 +1881,7 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
|
||||
|
||||
fd = connect_to_sdog(s->addr, s->port);
|
||||
if (fd < 0) {
|
||||
ret = fd;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1888,6 +1909,7 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
|
||||
fd = connect_to_sdog(s->addr, s->port);
|
||||
if (fd < 0) {
|
||||
error_report("failed to connect");
|
||||
ret = fd;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1925,6 +1947,10 @@ out:
|
||||
|
||||
g_free(vdi_inuse);
|
||||
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
@@ -1932,7 +1958,7 @@ static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data,
|
||||
int64_t pos, int size, int load)
|
||||
{
|
||||
int fd, create;
|
||||
int ret = 0;
|
||||
int ret = 0, remaining = size;
|
||||
unsigned int data_len;
|
||||
uint64_t vmstate_oid;
|
||||
uint32_t vdi_index;
|
||||
@@ -1940,15 +1966,14 @@ static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data,
|
||||
|
||||
fd = connect_to_sdog(s->addr, s->port);
|
||||
if (fd < 0) {
|
||||
ret = -EIO;
|
||||
goto cleanup;
|
||||
return fd;
|
||||
}
|
||||
|
||||
while (size) {
|
||||
while (remaining) {
|
||||
vdi_index = pos / SD_DATA_OBJ_SIZE;
|
||||
offset = pos % SD_DATA_OBJ_SIZE;
|
||||
|
||||
data_len = MIN(size, SD_DATA_OBJ_SIZE);
|
||||
data_len = MIN(remaining, SD_DATA_OBJ_SIZE);
|
||||
|
||||
vmstate_oid = vid_to_vmstate_oid(s->inode.vdi_id, vdi_index);
|
||||
|
||||
@@ -1965,14 +1990,13 @@ static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data,
|
||||
|
||||
if (ret < 0) {
|
||||
error_report("failed to save vmstate %s", strerror(errno));
|
||||
ret = -EIO;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
pos += data_len;
|
||||
size -= data_len;
|
||||
ret += data_len;
|
||||
remaining -= data_len;
|
||||
}
|
||||
ret = size;
|
||||
cleanup:
|
||||
closesocket(fd);
|
||||
return ret;
|
||||
|
||||
+57
-1
@@ -35,6 +35,7 @@
|
||||
#define VMDK4_FLAG_RGD (1 << 1)
|
||||
#define VMDK4_FLAG_COMPRESS (1 << 16)
|
||||
#define VMDK4_FLAG_MARKER (1 << 17)
|
||||
#define VMDK4_GD_AT_END 0xffffffffffffffffULL
|
||||
|
||||
typedef struct {
|
||||
uint32_t version;
|
||||
@@ -57,8 +58,8 @@ typedef struct {
|
||||
int64_t desc_offset;
|
||||
int64_t desc_size;
|
||||
int32_t num_gtes_per_gte;
|
||||
int64_t gd_offset;
|
||||
int64_t rgd_offset;
|
||||
int64_t gd_offset;
|
||||
int64_t grain_offset;
|
||||
char filler[1];
|
||||
char check_bytes[4];
|
||||
@@ -115,6 +116,13 @@ typedef struct VmdkGrainMarker {
|
||||
uint8_t data[0];
|
||||
} VmdkGrainMarker;
|
||||
|
||||
enum {
|
||||
MARKER_END_OF_STREAM = 0,
|
||||
MARKER_GRAIN_TABLE = 1,
|
||||
MARKER_GRAIN_DIRECTORY = 2,
|
||||
MARKER_FOOTER = 3,
|
||||
};
|
||||
|
||||
static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
{
|
||||
uint32_t magic;
|
||||
@@ -451,6 +459,54 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
|
||||
if (header.capacity == 0 && header.desc_offset) {
|
||||
return vmdk_open_desc_file(bs, flags, header.desc_offset << 9);
|
||||
}
|
||||
|
||||
if (le64_to_cpu(header.gd_offset) == VMDK4_GD_AT_END) {
|
||||
/*
|
||||
* The footer takes precedence over the header, so read it in. The
|
||||
* footer starts at offset -1024 from the end: One sector for the
|
||||
* footer, and another one for the end-of-stream marker.
|
||||
*/
|
||||
struct {
|
||||
struct {
|
||||
uint64_t val;
|
||||
uint32_t size;
|
||||
uint32_t type;
|
||||
uint8_t pad[512 - 16];
|
||||
} QEMU_PACKED footer_marker;
|
||||
|
||||
uint32_t magic;
|
||||
VMDK4Header header;
|
||||
uint8_t pad[512 - 4 - sizeof(VMDK4Header)];
|
||||
|
||||
struct {
|
||||
uint64_t val;
|
||||
uint32_t size;
|
||||
uint32_t type;
|
||||
uint8_t pad[512 - 16];
|
||||
} QEMU_PACKED eos_marker;
|
||||
} QEMU_PACKED footer;
|
||||
|
||||
ret = bdrv_pread(file,
|
||||
bs->file->total_sectors * 512 - 1536,
|
||||
&footer, sizeof(footer));
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Some sanity checks for the footer */
|
||||
if (be32_to_cpu(footer.magic) != VMDK4_MAGIC ||
|
||||
le32_to_cpu(footer.footer_marker.size) != 0 ||
|
||||
le32_to_cpu(footer.footer_marker.type) != MARKER_FOOTER ||
|
||||
le64_to_cpu(footer.eos_marker.val) != 0 ||
|
||||
le32_to_cpu(footer.eos_marker.size) != 0 ||
|
||||
le32_to_cpu(footer.eos_marker.type) != MARKER_END_OF_STREAM)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
header = footer.header;
|
||||
}
|
||||
|
||||
l1_entry_sectors = le32_to_cpu(header.num_gtes_per_gte)
|
||||
* le64_to_cpu(header.granularity);
|
||||
if (l1_entry_sectors == 0) {
|
||||
|
||||
+6
-1
@@ -2808,7 +2808,12 @@ static int enable_write_target(BDRVVVFATState *s)
|
||||
array_init(&(s->commits), sizeof(commit_t));
|
||||
|
||||
s->qcow_filename = g_malloc(1024);
|
||||
get_tmp_filename(s->qcow_filename, 1024);
|
||||
ret = get_tmp_filename(s->qcow_filename, 1024);
|
||||
if (ret < 0) {
|
||||
g_free(s->qcow_filename);
|
||||
s->qcow_filename = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bdrv_qcow = bdrv_find_format("qcow");
|
||||
options = parse_option_parameters("", bdrv_qcow->create_options, NULL);
|
||||
|
||||
+1
-1
@@ -335,7 +335,7 @@ struct BlockDriverState {
|
||||
BlockJob *job;
|
||||
};
|
||||
|
||||
void get_tmp_filename(char *filename, int size);
|
||||
int get_tmp_filename(char *filename, int size);
|
||||
|
||||
void bdrv_set_io_limits(BlockDriverState *bs,
|
||||
BlockIOLimit *io_limits);
|
||||
|
||||
@@ -275,6 +275,41 @@ EOF
|
||||
compile_object
|
||||
}
|
||||
|
||||
if check_define __linux__ ; then
|
||||
targetos="Linux"
|
||||
elif check_define _WIN32 ; then
|
||||
targetos='MINGW32'
|
||||
elif check_define __OpenBSD__ ; then
|
||||
targetos='OpenBSD'
|
||||
elif check_define __sun__ ; then
|
||||
targetos='SunOS'
|
||||
elif check_define __HAIKU__ ; then
|
||||
targetos='Haiku'
|
||||
else
|
||||
targetos=`uname -s`
|
||||
fi
|
||||
|
||||
# Some host OSes need non-standard checks for which CPU to use.
|
||||
# Note that these checks are broken for cross-compilation: if you're
|
||||
# cross-compiling to one of these OSes then you'll need to specify
|
||||
# the correct CPU with the --cpu option.
|
||||
case $targetos in
|
||||
Darwin)
|
||||
# on Leopard most of the system is 32-bit, so we have to ask the kernel if we can
|
||||
# run 64-bit userspace code.
|
||||
# If the user didn't specify a CPU explicitly and the kernel says this is
|
||||
# 64 bit hw, then assume x86_64. Otherwise fall through to the usual detection code.
|
||||
if test -z "$cpu" && test "$(sysctl -n hw.optional.x86_64)" = "1"; then
|
||||
cpu="x86_64"
|
||||
fi
|
||||
;;
|
||||
SunOS)
|
||||
# `uname -m` returns i86pc even on an x86_64 box, so default based on isainfo
|
||||
if test -z "$cpu" && test "$(isainfo -k)" = "amd64"; then
|
||||
cpu="x86_64"
|
||||
fi
|
||||
esac
|
||||
|
||||
if test ! -z "$cpu" ; then
|
||||
# command line argument
|
||||
:
|
||||
@@ -349,19 +384,6 @@ if test -z "$ARCH"; then
|
||||
fi
|
||||
|
||||
# OS specific
|
||||
if check_define __linux__ ; then
|
||||
targetos="Linux"
|
||||
elif check_define _WIN32 ; then
|
||||
targetos='MINGW32'
|
||||
elif check_define __OpenBSD__ ; then
|
||||
targetos='OpenBSD'
|
||||
elif check_define __sun__ ; then
|
||||
targetos='SunOS'
|
||||
elif check_define __HAIKU__ ; then
|
||||
targetos='Haiku'
|
||||
else
|
||||
targetos=`uname -s`
|
||||
fi
|
||||
|
||||
case $targetos in
|
||||
CYGWIN*)
|
||||
@@ -411,12 +433,6 @@ OpenBSD)
|
||||
Darwin)
|
||||
bsd="yes"
|
||||
darwin="yes"
|
||||
# on Leopard most of the system is 32-bit, so we have to ask the kernel it if we can
|
||||
# run 64-bit userspace code
|
||||
if [ "$cpu" = "i386" ] ; then
|
||||
is_x86_64=`sysctl -n hw.optional.x86_64`
|
||||
[ "$is_x86_64" = "1" ] && cpu=x86_64
|
||||
fi
|
||||
if [ "$cpu" = "x86_64" ] ; then
|
||||
QEMU_CFLAGS="-arch x86_64 $QEMU_CFLAGS"
|
||||
LDFLAGS="-arch x86_64 $LDFLAGS"
|
||||
@@ -437,12 +453,6 @@ SunOS)
|
||||
smbd="${SMBD-/usr/sfw/sbin/smbd}"
|
||||
needs_libsunmath="no"
|
||||
solarisrev=`uname -r | cut -f2 -d.`
|
||||
# have to select again, because `uname -m` returns i86pc
|
||||
# even on an x86_64 box.
|
||||
solariscpu=`isainfo -k`
|
||||
if test "${solariscpu}" = "amd64" ; then
|
||||
cpu="x86_64"
|
||||
fi
|
||||
if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
|
||||
if test "$solarisrev" -le 9 ; then
|
||||
if test -f /opt/SUNWspro/prod/lib/libsunmath.so.1; then
|
||||
@@ -2811,7 +2821,11 @@ fi
|
||||
open_by_hande_at=no
|
||||
cat > $TMPC << EOF
|
||||
#include <fcntl.h>
|
||||
#if !defined(AT_EMPTY_PATH)
|
||||
# error missing definition
|
||||
#else
|
||||
int main(void) { struct file_handle fh; return open_by_handle_at(0, &fh, 0); }
|
||||
#endif
|
||||
EOF
|
||||
if compile_prog "" "" ; then
|
||||
open_by_handle_at=yes
|
||||
@@ -2831,6 +2845,21 @@ if compile_prog "" "" ; then
|
||||
linux_magic_h=yes
|
||||
fi
|
||||
|
||||
########################################
|
||||
# check if environ is declared
|
||||
|
||||
has_environ=no
|
||||
cat > $TMPC << EOF
|
||||
#include <unistd.h>
|
||||
int main(void) {
|
||||
environ = environ;
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
if compile_prog "" "" ; then
|
||||
has_environ=yes
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# End of CC checks
|
||||
# After here, no more $cc or $ld runs
|
||||
@@ -2900,7 +2929,8 @@ if test "$softmmu" = yes ; then
|
||||
tools="$tools fsdev/virtfs-proxy-helper\$(EXESUF)"
|
||||
else
|
||||
if test "$virtfs" = yes; then
|
||||
feature_not_found "virtfs"
|
||||
echo "VirtFS is supported only on Linux and requires libcap-devel and libattr-devel"
|
||||
exit 1
|
||||
fi
|
||||
virtfs=no
|
||||
fi
|
||||
@@ -3342,6 +3372,10 @@ if test "$linux_magic_h" = "yes" ; then
|
||||
echo "CONFIG_LINUX_MAGIC_H=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
if test "$has_environ" = "yes" ; then
|
||||
echo "CONFIG_HAS_ENVIRON=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
# USB host support
|
||||
case "$usb" in
|
||||
linux)
|
||||
|
||||
@@ -847,6 +847,26 @@ static void console_clear_xy(TextConsole *s, int x, int y)
|
||||
update_xy(s, x, y);
|
||||
}
|
||||
|
||||
/* set cursor, checking bounds */
|
||||
static void set_cursor(TextConsole *s, int x, int y)
|
||||
{
|
||||
if (x < 0) {
|
||||
x = 0;
|
||||
}
|
||||
if (y < 0) {
|
||||
y = 0;
|
||||
}
|
||||
if (y >= s->height) {
|
||||
y = s->height - 1;
|
||||
}
|
||||
if (x >= s->width) {
|
||||
x = s->width - 1;
|
||||
}
|
||||
|
||||
s->x = x;
|
||||
s->y = y;
|
||||
}
|
||||
|
||||
static void console_putchar(TextConsole *s, int ch)
|
||||
{
|
||||
TextCell *c;
|
||||
@@ -918,7 +938,8 @@ static void console_putchar(TextConsole *s, int ch)
|
||||
s->esc_params[s->nb_esc_params] * 10 + ch - '0';
|
||||
}
|
||||
} else {
|
||||
s->nb_esc_params++;
|
||||
if (s->nb_esc_params < MAX_ESC_PARAMS)
|
||||
s->nb_esc_params++;
|
||||
if (ch == ';')
|
||||
break;
|
||||
#ifdef DEBUG_CONSOLE
|
||||
@@ -932,59 +953,37 @@ static void console_putchar(TextConsole *s, int ch)
|
||||
if (s->esc_params[0] == 0) {
|
||||
s->esc_params[0] = 1;
|
||||
}
|
||||
s->y -= s->esc_params[0];
|
||||
if (s->y < 0) {
|
||||
s->y = 0;
|
||||
}
|
||||
set_cursor(s, s->x, s->y - s->esc_params[0]);
|
||||
break;
|
||||
case 'B':
|
||||
/* move cursor down */
|
||||
if (s->esc_params[0] == 0) {
|
||||
s->esc_params[0] = 1;
|
||||
}
|
||||
s->y += s->esc_params[0];
|
||||
if (s->y >= s->height) {
|
||||
s->y = s->height - 1;
|
||||
}
|
||||
set_cursor(s, s->x, s->y + s->esc_params[0]);
|
||||
break;
|
||||
case 'C':
|
||||
/* move cursor right */
|
||||
if (s->esc_params[0] == 0) {
|
||||
s->esc_params[0] = 1;
|
||||
}
|
||||
s->x += s->esc_params[0];
|
||||
if (s->x >= s->width) {
|
||||
s->x = s->width - 1;
|
||||
}
|
||||
set_cursor(s, s->x + s->esc_params[0], s->y);
|
||||
break;
|
||||
case 'D':
|
||||
/* move cursor left */
|
||||
if (s->esc_params[0] == 0) {
|
||||
s->esc_params[0] = 1;
|
||||
}
|
||||
s->x -= s->esc_params[0];
|
||||
if (s->x < 0) {
|
||||
s->x = 0;
|
||||
}
|
||||
set_cursor(s, s->x - s->esc_params[0], s->y);
|
||||
break;
|
||||
case 'G':
|
||||
/* move cursor to column */
|
||||
s->x = s->esc_params[0] - 1;
|
||||
if (s->x < 0) {
|
||||
s->x = 0;
|
||||
}
|
||||
set_cursor(s, s->esc_params[0] - 1, s->y);
|
||||
break;
|
||||
case 'f':
|
||||
case 'H':
|
||||
/* move cursor to row, column */
|
||||
s->x = s->esc_params[1] - 1;
|
||||
if (s->x < 0) {
|
||||
s->x = 0;
|
||||
}
|
||||
s->y = s->esc_params[0] - 1;
|
||||
if (s->y < 0) {
|
||||
s->y = 0;
|
||||
}
|
||||
set_cursor(s, s->esc_params[1] - 1, s->esc_params[0] - 1);
|
||||
break;
|
||||
case 'J':
|
||||
switch (s->esc_params[0]) {
|
||||
|
||||
@@ -285,6 +285,12 @@ int cpu_exec(CPUArchState *env)
|
||||
}
|
||||
#endif
|
||||
#if defined(TARGET_I386)
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
if (interrupt_request & CPU_INTERRUPT_POLL) {
|
||||
env->interrupt_request &= ~CPU_INTERRUPT_POLL;
|
||||
apic_poll_irq(env->apic_state);
|
||||
}
|
||||
#endif
|
||||
if (interrupt_request & CPU_INTERRUPT_INIT) {
|
||||
svm_check_intercept(env, SVM_EXIT_INIT);
|
||||
do_cpu_init(env);
|
||||
|
||||
@@ -33,6 +33,7 @@ void qemu_sglist_add(QEMUSGList *qsg, dma_addr_t base, dma_addr_t len)
|
||||
void qemu_sglist_destroy(QEMUSGList *qsg)
|
||||
{
|
||||
g_free(qsg->sg);
|
||||
memset(qsg, 0, sizeof(*qsg));
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -55,6 +55,21 @@ try ...
|
||||
... then use "bus=ehci.0" to assign your usb devices to that bus.
|
||||
|
||||
|
||||
xhci controller support
|
||||
-----------------------
|
||||
|
||||
There also is xhci host controller support available. It got alot
|
||||
less testing than ehci and there are a bunch of known limitations, so
|
||||
ehci may work better for you. On the other hand the xhci hardware
|
||||
design is much more virtualization-friendly, thus xhci emulation uses
|
||||
less ressources (especially cpu). If you wanna give xhci a try
|
||||
use this to add the host controller ...
|
||||
|
||||
qemu -device nec-usb-xhci,id=xhci
|
||||
|
||||
... then use "bus=xhci.0" when assigning usb devices.
|
||||
|
||||
|
||||
More USB tips & tricks
|
||||
======================
|
||||
|
||||
|
||||
@@ -96,6 +96,8 @@ void QEMU_NORETURN cpu_loop_exit(CPUArchState *env1);
|
||||
int page_unprotect(target_ulong address, uintptr_t pc, void *puc);
|
||||
void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end,
|
||||
int is_cpu_write_access);
|
||||
void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end,
|
||||
int is_cpu_write_access);
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
/* cputlb.c */
|
||||
void tlb_flush_page(CPUArchState *env, target_ulong addr);
|
||||
|
||||
@@ -1075,6 +1075,23 @@ TranslationBlock *tb_gen_code(CPUArchState *env,
|
||||
return tb;
|
||||
}
|
||||
|
||||
/*
|
||||
* invalidate all TBs which intersect with the target physical pages
|
||||
* starting in range [start;end[. NOTE: start and end may refer to
|
||||
* different physical pages. 'is_cpu_write_access' should be true if called
|
||||
* from a real cpu write access: the virtual CPU will exit the current
|
||||
* TB if code is modified inside this TB.
|
||||
*/
|
||||
void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end,
|
||||
int is_cpu_write_access)
|
||||
{
|
||||
while (start < end) {
|
||||
tb_invalidate_phys_page_range(start, end, is_cpu_write_access);
|
||||
start &= TARGET_PAGE_MASK;
|
||||
start += TARGET_PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
/* invalidate all TBs which intersect with the target physical page
|
||||
starting in range [start;end[. NOTE: start and end must refer to
|
||||
the same physical page. 'is_cpu_write_access' should be true if called
|
||||
@@ -1475,7 +1492,8 @@ void tb_invalidate_phys_addr(target_phys_addr_t addr)
|
||||
|
||||
static void breakpoint_invalidate(CPUArchState *env, target_ulong pc)
|
||||
{
|
||||
tb_invalidate_phys_addr(cpu_get_phys_page_debug(env, pc));
|
||||
tb_invalidate_phys_addr(cpu_get_phys_page_debug(env, pc) |
|
||||
(pc & ~TARGET_PAGE_MASK));
|
||||
}
|
||||
#endif
|
||||
#endif /* TARGET_HAS_ICE */
|
||||
|
||||
+3
-2
@@ -345,6 +345,9 @@ static void piix4_reset(void *opaque)
|
||||
pci_conf[0x5a] = 0;
|
||||
pci_conf[0x5b] = 0;
|
||||
|
||||
pci_conf[0x40] = 0x01; /* PM io base read only bit */
|
||||
pci_conf[0x80] = 0;
|
||||
|
||||
if (s->kvm_enabled) {
|
||||
/* Mark SMM as already inited (until KVM supports SMM). */
|
||||
pci_conf[0x5B] = 0x02;
|
||||
@@ -384,8 +387,6 @@ static int piix4_pm_initfn(PCIDevice *dev)
|
||||
pci_conf[0x09] = 0x00;
|
||||
pci_conf[0x3d] = 0x01; // interrupt pin 1
|
||||
|
||||
pci_conf[0x40] = 0x01; /* PM io base read only bit */
|
||||
|
||||
/* APM */
|
||||
apm_init(&s->apm, apm_ctrl_changed, s);
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
#include "qemu-thread.h"
|
||||
#include "apic_internal.h"
|
||||
#include "apic.h"
|
||||
#include "ioapic.h"
|
||||
@@ -369,11 +370,10 @@ static void apic_update_irq(APICCommonState *s)
|
||||
if (!(s->spurious_vec & APIC_SV_ENABLE)) {
|
||||
return;
|
||||
}
|
||||
if (apic_irq_pending(s) > 0) {
|
||||
if (!qemu_cpu_is_self(s->cpu_env)) {
|
||||
cpu_interrupt(s->cpu_env, CPU_INTERRUPT_POLL);
|
||||
} else if (apic_irq_pending(s) > 0) {
|
||||
cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
|
||||
} else if (apic_accept_pic_intr(&s->busdev.qdev) &&
|
||||
pic_get_output(isa_pic)) {
|
||||
apic_deliver_pic_intr(&s->busdev.qdev, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -543,6 +543,15 @@ static void apic_deliver(DeviceState *d, uint8_t dest, uint8_t dest_mode,
|
||||
apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, trigger_mode);
|
||||
}
|
||||
|
||||
static bool apic_check_pic(APICCommonState *s)
|
||||
{
|
||||
if (!apic_accept_pic_intr(&s->busdev.qdev) || !pic_get_output(isa_pic)) {
|
||||
return false;
|
||||
}
|
||||
apic_deliver_pic_intr(&s->busdev.qdev, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
int apic_get_interrupt(DeviceState *d)
|
||||
{
|
||||
APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
|
||||
@@ -568,7 +577,12 @@ int apic_get_interrupt(DeviceState *d)
|
||||
reset_bit(s->irr, intno);
|
||||
set_bit(s->isr, intno);
|
||||
apic_sync_vapic(s, SYNC_TO_VAPIC);
|
||||
|
||||
/* re-inject if there is still a pending PIC interrupt */
|
||||
apic_check_pic(s);
|
||||
|
||||
apic_update_irq(s);
|
||||
|
||||
return intno;
|
||||
}
|
||||
|
||||
@@ -808,8 +822,11 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
int n = index - 0x32;
|
||||
s->lvt[n] = val;
|
||||
if (n == APIC_LVT_TIMER)
|
||||
if (n == APIC_LVT_TIMER) {
|
||||
apic_timer_update(s, qemu_get_clock_ns(vm_clock));
|
||||
} else if (n == APIC_LVT_LINT0 && apic_check_pic(s)) {
|
||||
apic_update_irq(s);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x38:
|
||||
|
||||
@@ -20,6 +20,7 @@ void apic_init_reset(DeviceState *s);
|
||||
void apic_sipi(DeviceState *s);
|
||||
void apic_handle_tpr_access_report(DeviceState *d, target_ulong ip,
|
||||
TPRAccess access);
|
||||
void apic_poll_irq(DeviceState *d);
|
||||
|
||||
/* pc.c */
|
||||
int cpu_is_bsp(CPUX86State *env);
|
||||
|
||||
+3
-1
@@ -289,7 +289,9 @@ static int apic_init_common(SysBusDevice *dev)
|
||||
|
||||
sysbus_init_mmio(dev, &s->io_memory);
|
||||
|
||||
if (!vapic && s->vapic_control & VAPIC_ENABLE_MASK) {
|
||||
/* Note: We need at least 1M to map the VAPIC option ROM */
|
||||
if (!vapic && s->vapic_control & VAPIC_ENABLE_MASK &&
|
||||
ram_size >= 1024 * 1024) {
|
||||
vapic = sysbus_create_simple("kvmvapic", -1, NULL);
|
||||
}
|
||||
s->vapic = vapic;
|
||||
|
||||
@@ -141,7 +141,6 @@ void apic_report_irq_delivered(int delivered);
|
||||
bool apic_next_timer(APICCommonState *s, int64_t current_time);
|
||||
void apic_enable_tpr_access_reporting(DeviceState *d, bool enable);
|
||||
void apic_enable_vapic(DeviceState *d, target_phys_addr_t paddr);
|
||||
void apic_poll_irq(DeviceState *d);
|
||||
|
||||
void vapic_report_tpr_access(DeviceState *dev, void *cpu, target_ulong ip,
|
||||
TPRAccess access);
|
||||
|
||||
@@ -955,6 +955,7 @@ static TypeInfo arm_gic_info = {
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(gic_state),
|
||||
.class_init = arm_gic_class_init,
|
||||
.class_size = sizeof(SysBusDeviceClass),
|
||||
};
|
||||
|
||||
static void arm_gic_register_types(void)
|
||||
|
||||
+6
-5
@@ -410,7 +410,7 @@ static void es1370_update_voices (ES1370State *s, uint32_t ctl, uint32_t sctl)
|
||||
|
||||
if ((old_fmt != new_fmt) || (old_freq != new_freq)) {
|
||||
d->shift = (new_fmt & 1) + (new_fmt >> 1);
|
||||
ldebug ("channel %d, freq = %d, nchannels %d, fmt %d, shift %d\n",
|
||||
ldebug ("channel %zu, freq = %d, nchannels %d, fmt %d, shift %d\n",
|
||||
i,
|
||||
new_freq,
|
||||
1 << (new_fmt & 1),
|
||||
@@ -578,7 +578,7 @@ IO_WRITE_PROTO (es1370_writel)
|
||||
d++;
|
||||
case ES1370_REG_DAC1_SCOUNT:
|
||||
d->scount = (val & 0xffff) | (d->scount & ~0xffff);
|
||||
ldebug ("chan %d CURR_SAMP_CT %d, SAMP_CT %d\n",
|
||||
ldebug ("chan %td CURR_SAMP_CT %d, SAMP_CT %d\n",
|
||||
d - &s->chan[0], val >> 16, (val & 0xffff));
|
||||
break;
|
||||
|
||||
@@ -588,7 +588,7 @@ IO_WRITE_PROTO (es1370_writel)
|
||||
d++;
|
||||
case ES1370_REG_DAC1_FRAMEADR:
|
||||
d->frame_addr = val;
|
||||
ldebug ("chan %d frame address %#x\n", d - &s->chan[0], val);
|
||||
ldebug ("chan %td frame address %#x\n", d - &s->chan[0], val);
|
||||
break;
|
||||
|
||||
case ES1370_REG_PHANTOM_FRAMECNT:
|
||||
@@ -605,7 +605,7 @@ IO_WRITE_PROTO (es1370_writel)
|
||||
case ES1370_REG_DAC1_FRAMECNT:
|
||||
d->frame_cnt = val;
|
||||
d->leftover = 0;
|
||||
ldebug ("chan %d frame count %d, buffer size %d\n",
|
||||
ldebug ("chan %td frame count %d, buffer size %d\n",
|
||||
d - &s->chan[0], val >> 16, val & 0xffff);
|
||||
break;
|
||||
|
||||
@@ -745,9 +745,10 @@ IO_READ_PROTO (es1370_readl)
|
||||
{
|
||||
uint32_t size = ((d->frame_cnt & 0xffff) + 1) << 2;
|
||||
uint32_t curr = ((d->frame_cnt >> 16) + 1) << 2;
|
||||
if (curr > size)
|
||||
if (curr > size) {
|
||||
dolog ("read framecnt curr %d, size %d %d\n", curr, size,
|
||||
curr > size);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
||||
@@ -159,6 +159,10 @@ static int fd_seek(FDrive *drv, uint8_t head, uint8_t track, uint8_t sect,
|
||||
drv->sect = sect;
|
||||
}
|
||||
|
||||
if (drv->bs == NULL || !bdrv_is_inserted(drv->bs)) {
|
||||
ret = 2;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -179,12 +183,14 @@ static void fd_revalidate(FDrive *drv)
|
||||
FDriveRate rate;
|
||||
|
||||
FLOPPY_DPRINTF("revalidate\n");
|
||||
if (drv->bs != NULL && bdrv_is_inserted(drv->bs)) {
|
||||
if (drv->bs != NULL) {
|
||||
ro = bdrv_is_read_only(drv->bs);
|
||||
bdrv_get_floppy_geometry_hint(drv->bs, &nb_heads, &max_track,
|
||||
&last_sect, drv->drive, &drive, &rate);
|
||||
if (nb_heads != 0 && max_track != 0 && last_sect != 0) {
|
||||
FLOPPY_DPRINTF("User defined disk (%d %d %d)",
|
||||
if (!bdrv_is_inserted(drv->bs)) {
|
||||
FLOPPY_DPRINTF("No disk in drive\n");
|
||||
} else if (nb_heads != 0 && max_track != 0 && last_sect != 0) {
|
||||
FLOPPY_DPRINTF("User defined disk (%d %d %d)\n",
|
||||
nb_heads - 1, max_track, last_sect);
|
||||
} else {
|
||||
FLOPPY_DPRINTF("Floppy disk (%d h %d t %d s) %s\n", nb_heads,
|
||||
@@ -201,7 +207,7 @@ static void fd_revalidate(FDrive *drv)
|
||||
drv->drive = drive;
|
||||
drv->media_rate = rate;
|
||||
} else {
|
||||
FLOPPY_DPRINTF("No disk in drive\n");
|
||||
FLOPPY_DPRINTF("No drive connected\n");
|
||||
drv->last_sect = 0;
|
||||
drv->max_track = 0;
|
||||
drv->flags &= ~FDISK_DBL_SIDES;
|
||||
@@ -709,7 +715,7 @@ static void fdctrl_raise_irq(FDCtrl *fdctrl, uint8_t status0)
|
||||
FDrive *cur_drv;
|
||||
/* A seek clears the disk change line (if a disk is inserted) */
|
||||
cur_drv = get_cur_drv(fdctrl);
|
||||
if (cur_drv->max_track) {
|
||||
if (cur_drv->bs != NULL && bdrv_is_inserted(cur_drv->bs)) {
|
||||
cur_drv->media_changed = 0;
|
||||
}
|
||||
}
|
||||
@@ -1878,7 +1884,7 @@ static int fdctrl_connect_drives(FDCtrl *fdctrl)
|
||||
}
|
||||
|
||||
fd_init(drive);
|
||||
fd_revalidate(drive);
|
||||
fdctrl_change_cb(drive, 0);
|
||||
if (drive->bs) {
|
||||
bdrv_set_dev_ops(drive->bs, &fdctrl_block_ops, drive);
|
||||
}
|
||||
|
||||
@@ -225,7 +225,6 @@ static int pci_i82378_init(PCIDevice *dev)
|
||||
pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->io);
|
||||
|
||||
memory_region_init_io(&s->mem, &i82378_mem_ops, s, "i82378-mem", 0x01000000);
|
||||
memory_region_set_coalescing(&s->mem);
|
||||
pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem);
|
||||
|
||||
/* Make I/O address read only */
|
||||
|
||||
+39
-9
@@ -462,7 +462,7 @@ static void ahci_check_cmd_bh(void *opaque)
|
||||
|
||||
static void ahci_init_d2h(AHCIDevice *ad)
|
||||
{
|
||||
uint8_t init_fis[0x20];
|
||||
uint8_t init_fis[20];
|
||||
IDEState *ide_state = &ad->port.ifs[0];
|
||||
|
||||
memset(init_fis, 0, sizeof(init_fis));
|
||||
@@ -619,7 +619,7 @@ static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis)
|
||||
d2h_fis[11] = cmd_fis[11];
|
||||
d2h_fis[12] = cmd_fis[12];
|
||||
d2h_fis[13] = cmd_fis[13];
|
||||
for (i = 14; i < 0x20; i++) {
|
||||
for (i = 14; i < 20; i++) {
|
||||
d2h_fis[i] = 0;
|
||||
}
|
||||
|
||||
@@ -634,7 +634,7 @@ static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis)
|
||||
}
|
||||
}
|
||||
|
||||
static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist)
|
||||
static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist, int offset)
|
||||
{
|
||||
AHCICmdHdr *cmd = ad->cur_cmd;
|
||||
uint32_t opts = le32_to_cpu(cmd->opts);
|
||||
@@ -645,6 +645,10 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist)
|
||||
uint8_t *prdt;
|
||||
int i;
|
||||
int r = 0;
|
||||
int sum = 0;
|
||||
int off_idx = -1;
|
||||
int off_pos = -1;
|
||||
int tbl_entry_size;
|
||||
|
||||
if (!sglist_alloc_hint) {
|
||||
DPRINTF(ad->port_no, "no sg list given by guest: 0x%08x\n", opts);
|
||||
@@ -666,9 +670,30 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist)
|
||||
/* Get entries in the PRDT, init a qemu sglist accordingly */
|
||||
if (sglist_alloc_hint > 0) {
|
||||
AHCI_SG *tbl = (AHCI_SG *)prdt;
|
||||
|
||||
qemu_sglist_init(sglist, sglist_alloc_hint);
|
||||
sum = 0;
|
||||
for (i = 0; i < sglist_alloc_hint; i++) {
|
||||
/* flags_size is zero-based */
|
||||
tbl_entry_size = (le32_to_cpu(tbl[i].flags_size) + 1);
|
||||
if (offset <= (sum + tbl_entry_size)) {
|
||||
off_idx = i;
|
||||
off_pos = offset - sum;
|
||||
break;
|
||||
}
|
||||
sum += tbl_entry_size;
|
||||
}
|
||||
if ((off_idx == -1) || (off_pos < 0) || (off_pos > tbl_entry_size)) {
|
||||
DPRINTF(ad->port_no, "%s: Incorrect offset! "
|
||||
"off_idx: %d, off_pos: %d\n",
|
||||
__func__, off_idx, off_pos);
|
||||
r = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
qemu_sglist_init(sglist, (sglist_alloc_hint - off_idx));
|
||||
qemu_sglist_add(sglist, le64_to_cpu(tbl[off_idx].addr + off_pos),
|
||||
le32_to_cpu(tbl[off_idx].flags_size) + 1 - off_pos);
|
||||
|
||||
for (i = off_idx + 1; i < sglist_alloc_hint; i++) {
|
||||
/* flags_size is zero-based */
|
||||
qemu_sglist_add(sglist, le64_to_cpu(tbl[i].addr),
|
||||
le32_to_cpu(tbl[i].flags_size) + 1);
|
||||
@@ -741,7 +766,7 @@ static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis,
|
||||
ncq_tfs->lba, ncq_tfs->lba + ncq_tfs->sector_count - 2,
|
||||
s->dev[port].port.ifs[0].nb_sectors - 1);
|
||||
|
||||
ahci_populate_sglist(&s->dev[port], &ncq_tfs->sglist);
|
||||
ahci_populate_sglist(&s->dev[port], &ncq_tfs->sglist, 0);
|
||||
ncq_tfs->tag = tag;
|
||||
|
||||
switch(ncq_fis->command) {
|
||||
@@ -964,7 +989,7 @@ static int ahci_start_transfer(IDEDMA *dma)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!ahci_populate_sglist(ad, &s->sg)) {
|
||||
if (!ahci_populate_sglist(ad, &s->sg, 0)) {
|
||||
has_sglist = 1;
|
||||
}
|
||||
|
||||
@@ -1009,6 +1034,7 @@ static void ahci_start_dma(IDEDMA *dma, IDEState *s,
|
||||
DPRINTF(ad->port_no, "\n");
|
||||
ad->dma_cb = dma_cb;
|
||||
ad->dma_status |= BM_STATUS_DMAING;
|
||||
s->io_buffer_offset = 0;
|
||||
dma_cb(s, 0);
|
||||
}
|
||||
|
||||
@@ -1017,7 +1043,7 @@ static int ahci_dma_prepare_buf(IDEDMA *dma, int is_write)
|
||||
AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
|
||||
IDEState *s = &ad->port.ifs[0];
|
||||
|
||||
ahci_populate_sglist(ad, &s->sg);
|
||||
ahci_populate_sglist(ad, &s->sg, 0);
|
||||
s->io_buffer_size = s->sg.size;
|
||||
|
||||
DPRINTF(ad->port_no, "len=%#x\n", s->io_buffer_size);
|
||||
@@ -1031,7 +1057,7 @@ static int ahci_dma_rw_buf(IDEDMA *dma, int is_write)
|
||||
uint8_t *p = s->io_buffer + s->io_buffer_index;
|
||||
int l = s->io_buffer_size - s->io_buffer_index;
|
||||
|
||||
if (ahci_populate_sglist(ad, &s->sg)) {
|
||||
if (ahci_populate_sglist(ad, &s->sg, s->io_buffer_offset)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1041,9 +1067,13 @@ static int ahci_dma_rw_buf(IDEDMA *dma, int is_write)
|
||||
dma_buf_write(p, l, &s->sg);
|
||||
}
|
||||
|
||||
/* free sglist that was created in ahci_populate_sglist() */
|
||||
qemu_sglist_destroy(&s->sg);
|
||||
|
||||
/* update number of transferred bytes */
|
||||
ad->cur_cmd->status = cpu_to_le32(le32_to_cpu(ad->cur_cmd->status) + l);
|
||||
s->io_buffer_index += l;
|
||||
s->io_buffer_offset += l;
|
||||
|
||||
DPRINTF(ad->port_no, "len=%#x\n", l);
|
||||
|
||||
|
||||
+10
-2
@@ -84,6 +84,14 @@ static const VMStateDescription vmstate_ahci = {
|
||||
.unmigratable = 1,
|
||||
};
|
||||
|
||||
static void pci_ich9_reset(void *opaque)
|
||||
{
|
||||
struct AHCIPCIState *d = opaque;
|
||||
|
||||
msi_reset(&d->card);
|
||||
ahci_reset(opaque);
|
||||
}
|
||||
|
||||
static int pci_ich9_ahci_init(PCIDevice *dev)
|
||||
{
|
||||
struct AHCIPCIState *d;
|
||||
@@ -102,7 +110,7 @@ static int pci_ich9_ahci_init(PCIDevice *dev)
|
||||
/* XXX Software should program this register */
|
||||
d->card.config[0x90] = 1 << 6; /* Address Map Register - AHCI mode */
|
||||
|
||||
qemu_register_reset(ahci_reset, d);
|
||||
qemu_register_reset(pci_ich9_reset, d);
|
||||
|
||||
msi_init(dev, 0x50, 1, true, false);
|
||||
d->ahci.irq = d->card.irq[0];
|
||||
@@ -133,7 +141,7 @@ static int pci_ich9_uninit(PCIDevice *dev)
|
||||
d = DO_UPCAST(struct AHCIPCIState, card, dev);
|
||||
|
||||
msi_uninit(dev);
|
||||
qemu_unregister_reset(ahci_reset, d);
|
||||
qemu_unregister_reset(pci_ich9_reset, d);
|
||||
ahci_uninit(&d->ahci);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -389,6 +389,7 @@ struct IDEState {
|
||||
struct iovec iov;
|
||||
QEMUIOVector qiov;
|
||||
/* ATA DMA state */
|
||||
int io_buffer_offset;
|
||||
int io_buffer_size;
|
||||
QEMUSGList sg;
|
||||
/* PIO transfer handling */
|
||||
|
||||
@@ -1107,6 +1107,9 @@ static void intel_hda_reset(DeviceState *dev)
|
||||
DeviceState *qdev;
|
||||
HDACodecDevice *cdev;
|
||||
|
||||
if (d->msi) {
|
||||
msi_reset(&d->pci);
|
||||
}
|
||||
intel_hda_regs_reset(d);
|
||||
d->wall_base_ns = qemu_get_clock_ns(vm_clock);
|
||||
|
||||
|
||||
+4
-20
@@ -351,6 +351,10 @@ static void close_guest_eventfds(IVShmemState *s, int posn)
|
||||
{
|
||||
int i, guest_curr_max;
|
||||
|
||||
if (!ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
|
||||
return;
|
||||
}
|
||||
|
||||
guest_curr_max = s->peers[posn].nb_eventfds;
|
||||
|
||||
for (i = 0; i < guest_curr_max; i++) {
|
||||
@@ -363,22 +367,6 @@ static void close_guest_eventfds(IVShmemState *s, int posn)
|
||||
s->peers[posn].nb_eventfds = 0;
|
||||
}
|
||||
|
||||
static void setup_ioeventfds(IVShmemState *s) {
|
||||
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i <= s->max_peer; i++) {
|
||||
for (j = 0; j < s->peers[i].nb_eventfds; j++) {
|
||||
memory_region_add_eventfd(&s->ivshmem_mmio,
|
||||
DOORBELL,
|
||||
4,
|
||||
true,
|
||||
(i << 16) | j,
|
||||
s->peers[i].eventfds[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* this function increase the dynamic storage need to store data about other
|
||||
* guests */
|
||||
static void increase_dynamic_storage(IVShmemState *s, int new_min_size) {
|
||||
@@ -685,10 +673,6 @@ static int pci_ivshmem_init(PCIDevice *dev)
|
||||
memory_region_init_io(&s->ivshmem_mmio, &ivshmem_mmio_ops, s,
|
||||
"ivshmem-mmio", IVSHMEM_REG_BAR_SIZE);
|
||||
|
||||
if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
|
||||
setup_ioeventfds(s);
|
||||
}
|
||||
|
||||
/* region for registers*/
|
||||
pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY,
|
||||
&s->ivshmem_mmio);
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ void kvm_put_apic_state(DeviceState *d, struct kvm_lapic_state *kapic)
|
||||
APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
|
||||
int i;
|
||||
|
||||
memset(kapic, 0, sizeof(kapic));
|
||||
memset(kapic, 0, sizeof(*kapic));
|
||||
kvm_apic_set_reg(kapic, 0x2, s->id << 24);
|
||||
kvm_apic_set_reg(kapic, 0x8, s->tpr);
|
||||
kvm_apic_set_reg(kapic, 0xd, s->log_dest << 24);
|
||||
|
||||
+72
-9
@@ -23,31 +23,71 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "qemu-timer.h"
|
||||
#include "sysemu.h"
|
||||
#include "hw/i8254.h"
|
||||
#include "hw/i8254_internal.h"
|
||||
#include "kvm.h"
|
||||
|
||||
#define KVM_PIT_REINJECT_BIT 0
|
||||
|
||||
#define CALIBRATION_ROUNDS 3
|
||||
|
||||
typedef struct KVMPITState {
|
||||
PITCommonState pit;
|
||||
LostTickPolicy lost_tick_policy;
|
||||
bool vm_stopped;
|
||||
int64_t kernel_clock_offset;
|
||||
} KVMPITState;
|
||||
|
||||
static void kvm_pit_get(PITCommonState *s)
|
||||
static int64_t abs64(int64_t v)
|
||||
{
|
||||
return v < 0 ? -v : v;
|
||||
}
|
||||
|
||||
static void kvm_pit_update_clock_offset(KVMPITState *s)
|
||||
{
|
||||
int64_t offset, clock_offset;
|
||||
struct timespec ts;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Measure the delta between CLOCK_MONOTONIC, the base used for
|
||||
* kvm_pit_channel_state::count_load_time, and vm_clock. Take the
|
||||
* minimum of several samples to filter out scheduling noise.
|
||||
*/
|
||||
clock_offset = INT64_MAX;
|
||||
for (i = 0; i < CALIBRATION_ROUNDS; i++) {
|
||||
offset = qemu_get_clock_ns(vm_clock);
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
offset -= ts.tv_nsec;
|
||||
offset -= (int64_t)ts.tv_sec * 1000000000;
|
||||
if (abs64(offset) < abs64(clock_offset)) {
|
||||
clock_offset = offset;
|
||||
}
|
||||
}
|
||||
s->kernel_clock_offset = clock_offset;
|
||||
}
|
||||
|
||||
static void kvm_pit_get(PITCommonState *pit)
|
||||
{
|
||||
KVMPITState *s = DO_UPCAST(KVMPITState, pit, pit);
|
||||
struct kvm_pit_state2 kpit;
|
||||
struct kvm_pit_channel_state *kchan;
|
||||
struct PITChannelState *sc;
|
||||
int i, ret;
|
||||
|
||||
/* No need to re-read the state if VM is stopped. */
|
||||
if (s->vm_stopped) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (kvm_has_pit_state2()) {
|
||||
ret = kvm_vm_ioctl(kvm_state, KVM_GET_PIT2, &kpit);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "KVM_GET_PIT2 failed: %s\n", strerror(ret));
|
||||
abort();
|
||||
}
|
||||
s->channels[0].irq_disabled = kpit.flags & KVM_PIT_FLAGS_HPET_LEGACY;
|
||||
pit->channels[0].irq_disabled = kpit.flags & KVM_PIT_FLAGS_HPET_LEGACY;
|
||||
} else {
|
||||
/*
|
||||
* kvm_pit_state2 is superset of kvm_pit_state struct,
|
||||
@@ -61,7 +101,7 @@ static void kvm_pit_get(PITCommonState *s)
|
||||
}
|
||||
for (i = 0; i < 3; i++) {
|
||||
kchan = &kpit.channels[i];
|
||||
sc = &s->channels[i];
|
||||
sc = &pit->channels[i];
|
||||
sc->count = kchan->count;
|
||||
sc->latched_count = kchan->latched_count;
|
||||
sc->count_latched = kchan->count_latched;
|
||||
@@ -74,25 +114,31 @@ static void kvm_pit_get(PITCommonState *s)
|
||||
sc->mode = kchan->mode;
|
||||
sc->bcd = kchan->bcd;
|
||||
sc->gate = kchan->gate;
|
||||
sc->count_load_time = kchan->count_load_time;
|
||||
sc->count_load_time = kchan->count_load_time + s->kernel_clock_offset;
|
||||
}
|
||||
|
||||
sc = &s->channels[0];
|
||||
sc = &pit->channels[0];
|
||||
sc->next_transition_time =
|
||||
pit_get_next_transition_time(sc, sc->count_load_time);
|
||||
}
|
||||
|
||||
static void kvm_pit_put(PITCommonState *s)
|
||||
static void kvm_pit_put(PITCommonState *pit)
|
||||
{
|
||||
KVMPITState *s = DO_UPCAST(KVMPITState, pit, pit);
|
||||
struct kvm_pit_state2 kpit;
|
||||
struct kvm_pit_channel_state *kchan;
|
||||
struct PITChannelState *sc;
|
||||
int i, ret;
|
||||
|
||||
kpit.flags = s->channels[0].irq_disabled ? KVM_PIT_FLAGS_HPET_LEGACY : 0;
|
||||
/* The offset keeps changing as long as the VM is stopped. */
|
||||
if (s->vm_stopped) {
|
||||
kvm_pit_update_clock_offset(s);
|
||||
}
|
||||
|
||||
kpit.flags = pit->channels[0].irq_disabled ? KVM_PIT_FLAGS_HPET_LEGACY : 0;
|
||||
for (i = 0; i < 3; i++) {
|
||||
kchan = &kpit.channels[i];
|
||||
sc = &s->channels[i];
|
||||
sc = &pit->channels[i];
|
||||
kchan->count = sc->count;
|
||||
kchan->latched_count = sc->latched_count;
|
||||
kchan->count_latched = sc->count_latched;
|
||||
@@ -105,7 +151,7 @@ static void kvm_pit_put(PITCommonState *s)
|
||||
kchan->mode = sc->mode;
|
||||
kchan->bcd = sc->bcd;
|
||||
kchan->gate = sc->gate;
|
||||
kchan->count_load_time = sc->count_load_time;
|
||||
kchan->count_load_time = sc->count_load_time - s->kernel_clock_offset;
|
||||
}
|
||||
|
||||
ret = kvm_vm_ioctl(kvm_state,
|
||||
@@ -173,6 +219,21 @@ static void kvm_pit_irq_control(void *opaque, int n, int enable)
|
||||
kvm_pit_put(pit);
|
||||
}
|
||||
|
||||
static void kvm_pit_vm_state_change(void *opaque, int running,
|
||||
RunState state)
|
||||
{
|
||||
KVMPITState *s = opaque;
|
||||
|
||||
if (running) {
|
||||
kvm_pit_update_clock_offset(s);
|
||||
s->vm_stopped = false;
|
||||
} else {
|
||||
kvm_pit_update_clock_offset(s);
|
||||
kvm_pit_get(&s->pit);
|
||||
s->vm_stopped = true;
|
||||
}
|
||||
}
|
||||
|
||||
static int kvm_pit_initfn(PITCommonState *pit)
|
||||
{
|
||||
KVMPITState *s = DO_UPCAST(KVMPITState, pit, pit);
|
||||
@@ -215,6 +276,8 @@ static int kvm_pit_initfn(PITCommonState *pit)
|
||||
|
||||
qdev_init_gpio_in(&pit->dev.qdev, kvm_pit_irq_control, 1);
|
||||
|
||||
qemu_add_vm_change_state_handler(kvm_pit_vm_state_change, s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -103,7 +103,7 @@ ssize_t read_targphys(const char *name,
|
||||
|
||||
/* return the size or -1 if error */
|
||||
int load_image_targphys(const char *filename,
|
||||
target_phys_addr_t addr, int max_sz)
|
||||
target_phys_addr_t addr, uint64_t max_sz)
|
||||
{
|
||||
int size;
|
||||
|
||||
|
||||
+2
-1
@@ -4,7 +4,8 @@
|
||||
/* loader.c */
|
||||
int get_image_size(const char *filename);
|
||||
int load_image(const char *filename, uint8_t *addr); /* deprecated */
|
||||
int load_image_targphys(const char *filename, target_phys_addr_t, int max_sz);
|
||||
int load_image_targphys(const char *filename, target_phys_addr_t,
|
||||
uint64_t max_sz);
|
||||
int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
|
||||
void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr,
|
||||
uint64_t *highaddr, int big_endian, int elf_machine,
|
||||
|
||||
@@ -282,6 +282,15 @@ static void msix_free_irq_entries(PCIDevice *dev)
|
||||
}
|
||||
}
|
||||
|
||||
static void msix_clear_all_vectors(PCIDevice *dev)
|
||||
{
|
||||
int vector;
|
||||
|
||||
for (vector = 0; vector < dev->msix_entries_nr; ++vector) {
|
||||
msix_clr_pending(dev, vector);
|
||||
}
|
||||
}
|
||||
|
||||
/* Clean up resources for the device. */
|
||||
int msix_uninit(PCIDevice *dev, MemoryRegion *bar)
|
||||
{
|
||||
@@ -322,7 +331,7 @@ void msix_load(PCIDevice *dev, QEMUFile *f)
|
||||
return;
|
||||
}
|
||||
|
||||
msix_free_irq_entries(dev);
|
||||
msix_clear_all_vectors(dev);
|
||||
qemu_get_buffer(f, dev->msix_table_page, n * PCI_MSIX_ENTRY_SIZE);
|
||||
qemu_get_buffer(f, dev->msix_table_page + MSIX_PAGE_PENDING, (n + 7) / 8);
|
||||
msix_update_function_masked(dev);
|
||||
@@ -372,7 +381,7 @@ void msix_reset(PCIDevice *dev)
|
||||
{
|
||||
if (!(dev->cap_present & QEMU_PCI_CAP_MSIX))
|
||||
return;
|
||||
msix_free_irq_entries(dev);
|
||||
msix_clear_all_vectors(dev);
|
||||
dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &=
|
||||
~dev->wmask[dev->msix_cap + MSIX_CONTROL_OFFSET];
|
||||
memset(dev->msix_table_page, 0, MSIX_PAGE_SIZE);
|
||||
|
||||
+9
-3
@@ -202,10 +202,16 @@ int load_multiboot(void *fw_cfg,
|
||||
uint32_t mh_bss_end_addr = ldl_p(header+i+24);
|
||||
mh_load_addr = ldl_p(header+i+16);
|
||||
uint32_t mb_kernel_text_offset = i - (mh_header_addr - mh_load_addr);
|
||||
uint32_t mb_load_size = mh_load_end_addr - mh_load_addr;
|
||||
|
||||
uint32_t mb_load_size = 0;
|
||||
mh_entry_addr = ldl_p(header+i+28);
|
||||
mb_kernel_size = mh_bss_end_addr - mh_load_addr;
|
||||
|
||||
if (mh_load_end_addr) {
|
||||
mb_kernel_size = mh_bss_end_addr - mh_load_addr;
|
||||
mb_load_size = mh_load_end_addr - mh_load_addr;
|
||||
} else {
|
||||
mb_kernel_size = kernel_file_size - mb_kernel_text_offset;
|
||||
mb_load_size = mb_kernel_size;
|
||||
}
|
||||
|
||||
/* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_VBE.
|
||||
uint32_t mh_mode_type = ldl_p(header+i+32);
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
#include "ui/qemu-spice.h"
|
||||
#include "memory.h"
|
||||
#include "exec-memory.h"
|
||||
#include "arch_init.h"
|
||||
|
||||
/* output Bochs bios info messages */
|
||||
//#define DEBUG_BIOS
|
||||
@@ -343,32 +344,37 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
|
||||
/* various important CMOS locations needed by PC/Bochs bios */
|
||||
|
||||
/* memory size */
|
||||
val = 640; /* base memory in K */
|
||||
/* base memory (first MiB) */
|
||||
val = MIN(ram_size / 1024, 640);
|
||||
rtc_set_memory(s, 0x15, val);
|
||||
rtc_set_memory(s, 0x16, val >> 8);
|
||||
|
||||
val = (ram_size / 1024) - 1024;
|
||||
/* extended memory (next 64MiB) */
|
||||
if (ram_size > 1024 * 1024) {
|
||||
val = (ram_size - 1024 * 1024) / 1024;
|
||||
} else {
|
||||
val = 0;
|
||||
}
|
||||
if (val > 65535)
|
||||
val = 65535;
|
||||
rtc_set_memory(s, 0x17, val);
|
||||
rtc_set_memory(s, 0x18, val >> 8);
|
||||
rtc_set_memory(s, 0x30, val);
|
||||
rtc_set_memory(s, 0x31, val >> 8);
|
||||
|
||||
if (above_4g_mem_size) {
|
||||
rtc_set_memory(s, 0x5b, (unsigned int)above_4g_mem_size >> 16);
|
||||
rtc_set_memory(s, 0x5c, (unsigned int)above_4g_mem_size >> 24);
|
||||
rtc_set_memory(s, 0x5d, (uint64_t)above_4g_mem_size >> 32);
|
||||
}
|
||||
|
||||
if (ram_size > (16 * 1024 * 1024))
|
||||
val = (ram_size / 65536) - ((16 * 1024 * 1024) / 65536);
|
||||
else
|
||||
/* memory between 16MiB and 4GiB */
|
||||
if (ram_size > 16 * 1024 * 1024) {
|
||||
val = (ram_size - 16 * 1024 * 1024) / 65536;
|
||||
} else {
|
||||
val = 0;
|
||||
}
|
||||
if (val > 65535)
|
||||
val = 65535;
|
||||
rtc_set_memory(s, 0x34, val);
|
||||
rtc_set_memory(s, 0x35, val >> 8);
|
||||
/* memory above 4GiB */
|
||||
val = above_4g_mem_size / 65536;
|
||||
rtc_set_memory(s, 0x5b, val);
|
||||
rtc_set_memory(s, 0x5c, val >> 8);
|
||||
rtc_set_memory(s, 0x5d, val >> 16);
|
||||
|
||||
/* set the number of CPU */
|
||||
rtc_set_memory(s, 0x5f, smp_cpus - 1);
|
||||
@@ -382,7 +388,7 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
|
||||
if (floppy) {
|
||||
fdc_get_bs(fd, floppy);
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (fd[i] && bdrv_is_inserted(fd[i])) {
|
||||
if (fd[i]) {
|
||||
bdrv_get_floppy_geometry_hint(fd[i], &nb_heads, &max_track,
|
||||
&last_sect, FDRIVE_DRV_NONE,
|
||||
&fd_type[i], &rate);
|
||||
@@ -1097,7 +1103,7 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
|
||||
qemu_irq pit_alt_irq = NULL;
|
||||
qemu_irq rtc_irq = NULL;
|
||||
qemu_irq *a20_line;
|
||||
ISADevice *i8042, *port92, *vmmouse, *pit;
|
||||
ISADevice *i8042, *port92, *vmmouse, *pit = NULL;
|
||||
qemu_irq *cpu_exit_irq;
|
||||
|
||||
register_ioport_write(0x80, 1, 1, ioport80_write, NULL);
|
||||
@@ -1126,16 +1132,18 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
|
||||
|
||||
qemu_register_boot_set(pc_boot_set, *rtc_state);
|
||||
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
pit = kvm_pit_init(isa_bus, 0x40);
|
||||
} else {
|
||||
pit = pit_init(isa_bus, 0x40, pit_isa_irq, pit_alt_irq);
|
||||
if (!xen_enabled()) {
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
pit = kvm_pit_init(isa_bus, 0x40);
|
||||
} else {
|
||||
pit = pit_init(isa_bus, 0x40, pit_isa_irq, pit_alt_irq);
|
||||
}
|
||||
if (hpet) {
|
||||
/* connect PIT to output control line of the HPET */
|
||||
qdev_connect_gpio_out(hpet, 0, qdev_get_gpio_in(&pit->qdev, 0));
|
||||
}
|
||||
pcspk_init(isa_bus, pit);
|
||||
}
|
||||
if (hpet) {
|
||||
/* connect PIT to output control line of the HPET */
|
||||
qdev_connect_gpio_out(hpet, 0, qdev_get_gpio_in(&pit->qdev, 0));
|
||||
}
|
||||
pcspk_init(isa_bus, pit);
|
||||
|
||||
for(i = 0; i < MAX_SERIAL_PORTS; i++) {
|
||||
if (serial_hds[i]) {
|
||||
|
||||
@@ -1527,7 +1527,6 @@ static int pci_unplug_device(DeviceState *qdev)
|
||||
qerror_report(QERR_DEVICE_NO_HOTPLUG, object_get_typename(OBJECT(dev)));
|
||||
return -1;
|
||||
}
|
||||
object_unparent(OBJECT(dev));
|
||||
return dev->bus->hotplug(dev->bus->hotplug_qdev, dev,
|
||||
PCI_HOTPLUG_DISABLED);
|
||||
}
|
||||
|
||||
+3
-1
@@ -52,7 +52,7 @@ static int pci_bridge_dev_initfn(PCIDevice *dev)
|
||||
{
|
||||
PCIBridge *br = DO_UPCAST(PCIBridge, dev, dev);
|
||||
PCIBridgeDev *bridge_dev = DO_UPCAST(PCIBridgeDev, bridge, br);
|
||||
int err;
|
||||
int err, ret;
|
||||
pci_bridge_map_irq(br, NULL, pci_bridge_dev_map_irq_fn);
|
||||
err = pci_bridge_initfn(dev);
|
||||
if (err) {
|
||||
@@ -86,6 +86,8 @@ slotid_error:
|
||||
shpc_cleanup(dev, &bridge_dev->bar);
|
||||
shpc_error:
|
||||
memory_region_destroy(&bridge_dev->bar);
|
||||
ret = pci_bridge_exitfn(dev);
|
||||
assert(!ret);
|
||||
bridge_error:
|
||||
return err;
|
||||
}
|
||||
|
||||
+20
-7
@@ -20,6 +20,7 @@
|
||||
#include "qdev.h"
|
||||
#include "monitor.h"
|
||||
#include "qmp-commands.h"
|
||||
#include "arch_init.h"
|
||||
|
||||
/*
|
||||
* Aliases were a bad idea from the start. Let's keep them
|
||||
@@ -29,16 +30,18 @@ typedef struct QDevAlias
|
||||
{
|
||||
const char *typename;
|
||||
const char *alias;
|
||||
uint32_t arch_mask;
|
||||
} QDevAlias;
|
||||
|
||||
static const QDevAlias qdev_alias_table[] = {
|
||||
{ "virtio-blk-pci", "virtio-blk" },
|
||||
{ "virtio-net-pci", "virtio-net" },
|
||||
{ "virtio-serial-pci", "virtio-serial" },
|
||||
{ "virtio-balloon-pci", "virtio-balloon" },
|
||||
{ "virtio-blk-s390", "virtio-blk" },
|
||||
{ "virtio-net-s390", "virtio-net" },
|
||||
{ "virtio-serial-s390", "virtio-serial" },
|
||||
{ "virtio-blk-pci", "virtio-blk", QEMU_ARCH_ALL & ~QEMU_ARCH_S390X },
|
||||
{ "virtio-net-pci", "virtio-net", QEMU_ARCH_ALL & ~QEMU_ARCH_S390X },
|
||||
{ "virtio-serial-pci", "virtio-serial", QEMU_ARCH_ALL & ~QEMU_ARCH_S390X },
|
||||
{ "virtio-balloon-pci", "virtio-balloon",
|
||||
QEMU_ARCH_ALL & ~QEMU_ARCH_S390X },
|
||||
{ "virtio-blk-s390", "virtio-blk", QEMU_ARCH_S390X },
|
||||
{ "virtio-net-s390", "virtio-net", QEMU_ARCH_S390X },
|
||||
{ "virtio-serial-s390", "virtio-serial", QEMU_ARCH_S390X },
|
||||
{ "lsi53c895a", "lsi" },
|
||||
{ "ich9-ahci", "ahci" },
|
||||
{ }
|
||||
@@ -50,6 +53,11 @@ static const char *qdev_class_get_alias(DeviceClass *dc)
|
||||
int i;
|
||||
|
||||
for (i = 0; qdev_alias_table[i].typename; i++) {
|
||||
if (qdev_alias_table[i].arch_mask &&
|
||||
!(qdev_alias_table[i].arch_mask & arch_type)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(qdev_alias_table[i].typename, typename) == 0) {
|
||||
return qdev_alias_table[i].alias;
|
||||
}
|
||||
@@ -110,6 +118,11 @@ static const char *find_typename_by_alias(const char *alias)
|
||||
int i;
|
||||
|
||||
for (i = 0; qdev_alias_table[i].alias; i++) {
|
||||
if (qdev_alias_table[i].arch_mask &&
|
||||
!(qdev_alias_table[i].arch_mask & arch_type)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(qdev_alias_table[i].alias, alias) == 0) {
|
||||
return qdev_alias_table[i].typename;
|
||||
}
|
||||
|
||||
@@ -753,10 +753,12 @@ static void set_mac(Object *obj, Visitor *v, void *opaque,
|
||||
}
|
||||
mac->a[i] = strtol(str+pos, &p, 16);
|
||||
}
|
||||
g_free(str);
|
||||
return;
|
||||
|
||||
inval:
|
||||
error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
PropertyInfo qdev_prop_macaddr = {
|
||||
@@ -825,7 +827,7 @@ static void set_pci_devfn(Object *obj, Visitor *v, void *opaque,
|
||||
uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
|
||||
unsigned int slot, fn, n;
|
||||
Error *local_err = NULL;
|
||||
char *str = (char *)"";
|
||||
char *str;
|
||||
|
||||
if (dev->state != DEV_STATE_CREATED) {
|
||||
error_set(errp, QERR_PERMISSION_DENIED);
|
||||
@@ -848,10 +850,12 @@ static void set_pci_devfn(Object *obj, Visitor *v, void *opaque,
|
||||
goto invalid;
|
||||
}
|
||||
*ptr = slot << 3 | fn;
|
||||
g_free(str);
|
||||
return;
|
||||
|
||||
invalid:
|
||||
error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t len)
|
||||
|
||||
@@ -240,7 +240,6 @@ void qbus_reset_all_fn(void *opaque)
|
||||
int qdev_simple_unplug_cb(DeviceState *dev)
|
||||
{
|
||||
/* just zap it */
|
||||
object_unparent(OBJECT(dev));
|
||||
qdev_free(dev);
|
||||
return 0;
|
||||
}
|
||||
@@ -255,9 +254,10 @@ int qdev_simple_unplug_cb(DeviceState *dev)
|
||||
way is somewhat unclean, and best avoided. */
|
||||
void qdev_init_nofail(DeviceState *dev)
|
||||
{
|
||||
const char *typename = object_get_typename(OBJECT(dev));
|
||||
|
||||
if (qdev_init(dev) < 0) {
|
||||
error_report("Initialization of device %s failed",
|
||||
object_get_typename(OBJECT(dev)));
|
||||
error_report("Initialization of device %s failed", typename);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
+13
-11
@@ -781,6 +781,13 @@ static inline dma_addr_t rtl8139_addr64(uint32_t low, uint32_t high)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Workaround for buggy guest driver such as linux who allocates rx
|
||||
* rings after the receiver were enabled. */
|
||||
static bool rtl8139_cp_rx_valid(RTL8139State *s)
|
||||
{
|
||||
return !(s->RxRingAddrLO == 0 && s->RxRingAddrHI == 0);
|
||||
}
|
||||
|
||||
static int rtl8139_can_receive(VLANClientState *nc)
|
||||
{
|
||||
RTL8139State *s = DO_UPCAST(NICState, nc, nc)->opaque;
|
||||
@@ -791,18 +798,15 @@ static int rtl8139_can_receive(VLANClientState *nc)
|
||||
return 1;
|
||||
if (!rtl8139_receiver_enabled(s))
|
||||
return 1;
|
||||
/* network/host communication happens only in normal mode */
|
||||
if ((s->Cfg9346 & Chip9346_op_mask) != Cfg9346_Normal)
|
||||
return 0;
|
||||
|
||||
if (rtl8139_cp_receiver_enabled(s)) {
|
||||
if (rtl8139_cp_receiver_enabled(s) && rtl8139_cp_rx_valid(s)) {
|
||||
/* ??? Flow control not implemented in c+ mode.
|
||||
This is a hack to work around slirp deficiencies anyway. */
|
||||
return 1;
|
||||
} else {
|
||||
avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr,
|
||||
s->RxBufferSize);
|
||||
return (avail == 0 || avail >= 1514);
|
||||
return (avail == 0 || avail >= 1514 || (s->IntrMask & RxOverflow));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -836,12 +840,6 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* check whether we are in normal mode */
|
||||
if ((s->Cfg9346 & Chip9346_op_mask) != Cfg9346_Normal) {
|
||||
DPRINTF("not in normal op mode\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* XXX: check this */
|
||||
if (s->RxConfig & AcceptAllPhys) {
|
||||
/* promiscuous: receive all */
|
||||
@@ -946,6 +944,10 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_
|
||||
|
||||
if (rtl8139_cp_receiver_enabled(s))
|
||||
{
|
||||
if (!rtl8139_cp_rx_valid(s)) {
|
||||
return size;
|
||||
}
|
||||
|
||||
DPRINTF("in C+ Rx mode ================\n");
|
||||
|
||||
/* begin C+ receiver mode */
|
||||
|
||||
@@ -163,8 +163,7 @@ static int s390_virtio_blk_init(VirtIOS390Device *dev)
|
||||
{
|
||||
VirtIODevice *vdev;
|
||||
|
||||
vdev = virtio_blk_init((DeviceState *)dev, &dev->block,
|
||||
&dev->block_serial);
|
||||
vdev = virtio_blk_init((DeviceState *)dev, &dev->blk);
|
||||
if (!vdev) {
|
||||
return -1;
|
||||
}
|
||||
@@ -400,8 +399,11 @@ static TypeInfo s390_virtio_net = {
|
||||
};
|
||||
|
||||
static Property s390_virtio_blk_properties[] = {
|
||||
DEFINE_BLOCK_PROPERTIES(VirtIOS390Device, block),
|
||||
DEFINE_PROP_STRING("serial", VirtIOS390Device, block_serial),
|
||||
DEFINE_BLOCK_PROPERTIES(VirtIOS390Device, blk.conf),
|
||||
DEFINE_PROP_STRING("serial", VirtIOS390Device, blk.serial),
|
||||
#ifdef __linux__
|
||||
DEFINE_PROP_BIT("scsi", VirtIOS390Device, blk.scsi, 0, true),
|
||||
#endif
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "virtio-blk.h"
|
||||
#include "virtio-net.h"
|
||||
#include "virtio-serial.h"
|
||||
#include "virtio-scsi.h"
|
||||
@@ -64,8 +65,7 @@ struct VirtIOS390Device {
|
||||
ram_addr_t feat_offs;
|
||||
uint8_t feat_len;
|
||||
VirtIODevice *vdev;
|
||||
BlockConf block;
|
||||
char *block_serial;
|
||||
VirtIOBlkConf blk;
|
||||
NICConf nic;
|
||||
uint32_t host_features;
|
||||
virtio_serial_conf serial;
|
||||
|
||||
+1
-1
@@ -1561,7 +1561,7 @@ static int get_scsi_requests(QEMUFile *f, void *pv, size_t size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
const VMStateInfo vmstate_info_scsi_requests = {
|
||||
static const VMStateInfo vmstate_info_scsi_requests = {
|
||||
.name = "scsi-requests",
|
||||
.get = get_scsi_requests,
|
||||
.put = put_scsi_requests,
|
||||
|
||||
+33
-23
@@ -67,7 +67,6 @@
|
||||
|
||||
#define KERNEL_LOAD_ADDR 0x00404000
|
||||
#define CMDLINE_ADDR 0x003ff000
|
||||
#define INITRD_LOAD_ADDR 0x00300000
|
||||
#define PROM_SIZE_MAX (4 * 1024 * 1024)
|
||||
#define PROM_VADDR 0x000ffd00000ULL
|
||||
#define APB_SPECIAL_BASE 0x1fe00000000ULL
|
||||
@@ -181,14 +180,18 @@ static int sun4u_NVRAM_set_params(M48t59State *nvram, uint16_t NVRAM_size,
|
||||
|
||||
return 0;
|
||||
}
|
||||
static unsigned long sun4u_load_kernel(const char *kernel_filename,
|
||||
const char *initrd_filename,
|
||||
ram_addr_t RAM_size, long *initrd_size)
|
||||
|
||||
static uint64_t sun4u_load_kernel(const char *kernel_filename,
|
||||
const char *initrd_filename,
|
||||
ram_addr_t RAM_size, uint64_t *initrd_size,
|
||||
uint64_t *initrd_addr, uint64_t *kernel_addr,
|
||||
uint64_t *kernel_entry)
|
||||
{
|
||||
int linux_boot;
|
||||
unsigned int i;
|
||||
long kernel_size;
|
||||
uint8_t *ptr;
|
||||
uint64_t kernel_top;
|
||||
|
||||
linux_boot = (kernel_filename != NULL);
|
||||
|
||||
@@ -201,29 +204,34 @@ static unsigned long sun4u_load_kernel(const char *kernel_filename,
|
||||
#else
|
||||
bswap_needed = 0;
|
||||
#endif
|
||||
kernel_size = load_elf(kernel_filename, NULL, NULL, NULL,
|
||||
NULL, NULL, 1, ELF_MACHINE, 0);
|
||||
if (kernel_size < 0)
|
||||
kernel_size = load_elf(kernel_filename, NULL, NULL, kernel_entry,
|
||||
kernel_addr, &kernel_top, 1, ELF_MACHINE, 0);
|
||||
if (kernel_size < 0) {
|
||||
*kernel_addr = KERNEL_LOAD_ADDR;
|
||||
*kernel_entry = KERNEL_LOAD_ADDR;
|
||||
kernel_size = load_aout(kernel_filename, KERNEL_LOAD_ADDR,
|
||||
RAM_size - KERNEL_LOAD_ADDR, bswap_needed,
|
||||
TARGET_PAGE_SIZE);
|
||||
if (kernel_size < 0)
|
||||
}
|
||||
if (kernel_size < 0) {
|
||||
kernel_size = load_image_targphys(kernel_filename,
|
||||
KERNEL_LOAD_ADDR,
|
||||
RAM_size - KERNEL_LOAD_ADDR);
|
||||
}
|
||||
if (kernel_size < 0) {
|
||||
fprintf(stderr, "qemu: could not load kernel '%s'\n",
|
||||
kernel_filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* load initrd */
|
||||
/* load initrd above kernel */
|
||||
*initrd_size = 0;
|
||||
if (initrd_filename) {
|
||||
*initrd_addr = TARGET_PAGE_ALIGN(kernel_top);
|
||||
|
||||
*initrd_size = load_image_targphys(initrd_filename,
|
||||
INITRD_LOAD_ADDR,
|
||||
RAM_size - INITRD_LOAD_ADDR);
|
||||
if (*initrd_size < 0) {
|
||||
*initrd_addr,
|
||||
RAM_size - *initrd_addr);
|
||||
if ((int)*initrd_size < 0) {
|
||||
fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
|
||||
initrd_filename);
|
||||
exit(1);
|
||||
@@ -231,9 +239,9 @@ static unsigned long sun4u_load_kernel(const char *kernel_filename,
|
||||
}
|
||||
if (*initrd_size > 0) {
|
||||
for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) {
|
||||
ptr = rom_ptr(KERNEL_LOAD_ADDR + i);
|
||||
ptr = rom_ptr(*kernel_addr + i);
|
||||
if (ldl_p(ptr + 8) == 0x48647253) { /* HdrS */
|
||||
stl_p(ptr + 24, INITRD_LOAD_ADDR + KERNEL_LOAD_ADDR - 0x4000);
|
||||
stl_p(ptr + 24, *initrd_addr + *kernel_addr);
|
||||
stl_p(ptr + 28, *initrd_size);
|
||||
break;
|
||||
}
|
||||
@@ -788,7 +796,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
|
||||
CPUSPARCState *env;
|
||||
M48t59State *nvram;
|
||||
unsigned int i;
|
||||
long initrd_size, kernel_size;
|
||||
uint64_t initrd_addr, initrd_size, kernel_addr, kernel_size, kernel_entry;
|
||||
PCIBus *pci_bus, *pci_bus2, *pci_bus3;
|
||||
ISABus *isa_bus;
|
||||
qemu_irq *ivec_irqs, *pbm_irqs;
|
||||
@@ -845,13 +853,15 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
|
||||
nvram = m48t59_init_isa(isa_bus, 0x0074, NVRAM_SIZE, 59);
|
||||
|
||||
initrd_size = 0;
|
||||
initrd_addr = 0;
|
||||
kernel_size = sun4u_load_kernel(kernel_filename, initrd_filename,
|
||||
ram_size, &initrd_size);
|
||||
ram_size, &initrd_size, &initrd_addr,
|
||||
&kernel_addr, &kernel_entry);
|
||||
|
||||
sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", RAM_size, boot_devices,
|
||||
KERNEL_LOAD_ADDR, kernel_size,
|
||||
kernel_addr, kernel_size,
|
||||
kernel_cmdline,
|
||||
INITRD_LOAD_ADDR, initrd_size,
|
||||
initrd_addr, initrd_size,
|
||||
/* XXX: need an option to load a NVRAM image */
|
||||
0,
|
||||
graphic_width, graphic_height, graphic_depth,
|
||||
@@ -861,8 +871,8 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
|
||||
fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
|
||||
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
|
||||
fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id);
|
||||
fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, KERNEL_LOAD_ADDR);
|
||||
fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
|
||||
fw_cfg_add_i64(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_entry);
|
||||
fw_cfg_add_i64(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
|
||||
if (kernel_cmdline) {
|
||||
fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE,
|
||||
strlen(kernel_cmdline) + 1);
|
||||
@@ -872,8 +882,8 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
|
||||
} else {
|
||||
fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, 0);
|
||||
}
|
||||
fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, INITRD_LOAD_ADDR);
|
||||
fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size);
|
||||
fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_ADDR, initrd_addr);
|
||||
fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size);
|
||||
fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, boot_devices[0]);
|
||||
|
||||
fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_WIDTH, graphic_width);
|
||||
|
||||
@@ -27,10 +27,23 @@ static struct BusInfo usb_bus_info = {
|
||||
static int next_usb_bus = 0;
|
||||
static QTAILQ_HEAD(, USBBus) busses = QTAILQ_HEAD_INITIALIZER(busses);
|
||||
|
||||
static int usb_device_post_load(void *opaque, int version_id)
|
||||
{
|
||||
USBDevice *dev = opaque;
|
||||
|
||||
if (dev->state == USB_STATE_NOTATTACHED) {
|
||||
dev->attached = 0;
|
||||
} else {
|
||||
dev->attached = 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const VMStateDescription vmstate_usb_device = {
|
||||
.name = "USBDevice",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.post_load = usb_device_post_load,
|
||||
.fields = (VMStateField []) {
|
||||
VMSTATE_UINT8(addr, USBDevice),
|
||||
VMSTATE_INT32(state, USBDevice),
|
||||
|
||||
+36
-11
@@ -348,6 +348,7 @@ struct EHCIQueue {
|
||||
QTAILQ_ENTRY(EHCIQueue) next;
|
||||
uint32_t seen;
|
||||
uint64_t ts;
|
||||
int revalidate;
|
||||
|
||||
/* cached data from guest - needs to be flushed
|
||||
* when guest removes an entry (doorbell, handshake sequence)
|
||||
@@ -695,7 +696,18 @@ static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void ehci_queues_rip_unused(EHCIState *ehci, int async, int flush)
|
||||
static void ehci_queues_tag_unused_async(EHCIState *ehci)
|
||||
{
|
||||
EHCIQueue *q;
|
||||
|
||||
QTAILQ_FOREACH(q, &ehci->aqueues, next) {
|
||||
if (!q->seen) {
|
||||
q->revalidate = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ehci_queues_rip_unused(EHCIState *ehci, int async)
|
||||
{
|
||||
EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
|
||||
EHCIQueue *q, *tmp;
|
||||
@@ -706,7 +718,7 @@ static void ehci_queues_rip_unused(EHCIState *ehci, int async, int flush)
|
||||
q->ts = ehci->last_run_ns;
|
||||
continue;
|
||||
}
|
||||
if (!flush && ehci->last_run_ns < q->ts + 250000000) {
|
||||
if (ehci->last_run_ns < q->ts + 250000000) {
|
||||
/* allow 0.25 sec idle */
|
||||
continue;
|
||||
}
|
||||
@@ -1064,6 +1076,12 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
|
||||
/* Do any register specific pre-write processing here. */
|
||||
switch(addr) {
|
||||
case USBCMD:
|
||||
if (val & USBCMD_HCRESET) {
|
||||
ehci_reset(s);
|
||||
val = s->usbcmd;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((val & USBCMD_RUNSTOP) && !(s->usbcmd & USBCMD_RUNSTOP)) {
|
||||
qemu_mod_timer(s->frame_timer, qemu_get_clock_ns(vm_clock));
|
||||
SET_LAST_RUN_CLOCK(s);
|
||||
@@ -1077,10 +1095,6 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
|
||||
ehci_set_usbsts(s, USBSTS_HALT);
|
||||
}
|
||||
|
||||
if (val & USBCMD_HCRESET) {
|
||||
ehci_reset(s);
|
||||
val = s->usbcmd;
|
||||
}
|
||||
|
||||
/* not supporting dynamic frame list size at the moment */
|
||||
if ((val & USBCMD_FLS) && !(s->usbcmd & USBCMD_FLS)) {
|
||||
@@ -1451,7 +1465,7 @@ static int ehci_process_itd(EHCIState *ehci,
|
||||
|
||||
dev = ehci_find_device(ehci, devaddr);
|
||||
ep = usb_ep_get(dev, pid, endp);
|
||||
if (ep->type == USB_ENDPOINT_XFER_ISOC) {
|
||||
if (ep && ep->type == USB_ENDPOINT_XFER_ISOC) {
|
||||
usb_packet_setup(&ehci->ipacket, pid, ep);
|
||||
usb_packet_map(&ehci->ipacket, &ehci->isgl);
|
||||
ret = usb_handle_packet(dev, &ehci->ipacket);
|
||||
@@ -1519,7 +1533,7 @@ static int ehci_state_waitlisthead(EHCIState *ehci, int async)
|
||||
ehci_set_usbsts(ehci, USBSTS_REC);
|
||||
}
|
||||
|
||||
ehci_queues_rip_unused(ehci, async, 0);
|
||||
ehci_queues_rip_unused(ehci, async);
|
||||
|
||||
/* Find the head of the list (4.9.1.1) */
|
||||
for(i = 0; i < MAX_QH; i++) {
|
||||
@@ -1603,6 +1617,7 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
|
||||
{
|
||||
uint32_t entry;
|
||||
EHCIQueue *q;
|
||||
EHCIqh qh;
|
||||
|
||||
entry = ehci_get_fetch_addr(ehci, async);
|
||||
q = ehci_find_queue_by_qh(ehci, entry, async);
|
||||
@@ -1620,7 +1635,16 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
|
||||
}
|
||||
|
||||
get_dwords(ehci, NLPTR_GET(q->qhaddr),
|
||||
(uint32_t *) &q->qh, sizeof(EHCIqh) >> 2);
|
||||
(uint32_t *) &qh, sizeof(EHCIqh) >> 2);
|
||||
if (q->revalidate && (q->qh.epchar != qh.epchar ||
|
||||
q->qh.epcap != qh.epcap ||
|
||||
q->qh.current_qtd != qh.current_qtd)) {
|
||||
ehci_free_queue(q, async);
|
||||
q = ehci_alloc_queue(ehci, async);
|
||||
q->seen++;
|
||||
}
|
||||
q->qh = qh;
|
||||
q->revalidate = 0;
|
||||
ehci_trace_qh(q, NLPTR_GET(q->qhaddr), &q->qh);
|
||||
|
||||
if (q->async == EHCI_ASYNC_INFLIGHT) {
|
||||
@@ -2045,7 +2069,7 @@ static void ehci_advance_async_state(EHCIState *ehci)
|
||||
*/
|
||||
if (ehci->usbcmd & USBCMD_IAAD) {
|
||||
/* Remove all unseen qhs from the async qhs queue */
|
||||
ehci_queues_rip_unused(ehci, async, 1);
|
||||
ehci_queues_tag_unused_async(ehci);
|
||||
DPRINTF("ASYNC: doorbell request acknowledged\n");
|
||||
ehci->usbcmd &= ~USBCMD_IAAD;
|
||||
ehci_set_interrupt(ehci, USBSTS_IAA);
|
||||
@@ -2100,7 +2124,7 @@ static void ehci_advance_periodic_state(EHCIState *ehci)
|
||||
ehci_set_fetch_addr(ehci, async,entry);
|
||||
ehci_set_state(ehci, async, EST_FETCHENTRY);
|
||||
ehci_advance_state(ehci, async);
|
||||
ehci_queues_rip_unused(ehci, async, 0);
|
||||
ehci_queues_rip_unused(ehci, async);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -2300,6 +2324,7 @@ static int usb_ehci_initfn(PCIDevice *dev)
|
||||
s->frame_timer = qemu_new_timer_ns(vm_clock, ehci_frame_timer, s);
|
||||
QTAILQ_INIT(&s->aqueues);
|
||||
QTAILQ_INIT(&s->pqueues);
|
||||
usb_packet_init(&s->ipacket);
|
||||
|
||||
qemu_register_reset(ehci_reset, s);
|
||||
|
||||
|
||||
+2
-2
@@ -288,10 +288,10 @@ static void uhci_async_cancel_device(UHCIState *s, USBDevice *dev)
|
||||
|
||||
static void uhci_async_cancel_all(UHCIState *s)
|
||||
{
|
||||
UHCIQueue *queue;
|
||||
UHCIQueue *queue, *nq;
|
||||
UHCIAsync *curr, *n;
|
||||
|
||||
QTAILQ_FOREACH(queue, &s->queues, next) {
|
||||
QTAILQ_FOREACH_SAFE(queue, &s->queues, next, nq) {
|
||||
QTAILQ_FOREACH_SAFE(curr, &queue->asyncs, next, n) {
|
||||
uhci_async_unlink(curr);
|
||||
uhci_async_cancel(curr);
|
||||
|
||||
@@ -1031,6 +1031,8 @@ static int usbredir_handle_status(USBRedirDevice *dev,
|
||||
case usb_redir_inval:
|
||||
WARNING("got invalid param error from usb-host?\n");
|
||||
return USB_RET_NAK;
|
||||
case usb_redir_babble:
|
||||
return USB_RET_BABBLE;
|
||||
case usb_redir_ioerror:
|
||||
case usb_redir_timeout:
|
||||
default:
|
||||
|
||||
@@ -2357,10 +2357,15 @@ void vga_init(VGACommonState *s, MemoryRegion *address_space,
|
||||
void vga_init_vbe(VGACommonState *s, MemoryRegion *system_memory)
|
||||
{
|
||||
#ifdef CONFIG_BOCHS_VBE
|
||||
/* With pc-0.12 and below we map both the PCI BAR and the fixed VBE region,
|
||||
* so use an alias to avoid double-mapping the same region.
|
||||
*/
|
||||
memory_region_init_alias(&s->vram_vbe, "vram.vbe",
|
||||
&s->vram, 0, memory_region_size(&s->vram));
|
||||
/* XXX: use optimized standard vga accesses */
|
||||
memory_region_add_subregion(system_memory,
|
||||
VBE_DISPI_LFB_PHYSICAL_ADDRESS,
|
||||
&s->vram);
|
||||
&s->vram_vbe);
|
||||
s->vbe_mapped = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -105,6 +105,7 @@ typedef struct VGACommonState {
|
||||
MemoryRegion *legacy_address_space;
|
||||
uint8_t *vram_ptr;
|
||||
MemoryRegion vram;
|
||||
MemoryRegion vram_vbe;
|
||||
uint32_t vram_size;
|
||||
uint32_t latch;
|
||||
MemoryRegion *chain4_alias;
|
||||
|
||||
+5
-1
@@ -211,11 +211,15 @@ static void virtio_balloon_save(QEMUFile *f, void *opaque)
|
||||
static int virtio_balloon_load(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
VirtIOBalloon *s = opaque;
|
||||
int ret;
|
||||
|
||||
if (version_id != 1)
|
||||
return -EINVAL;
|
||||
|
||||
virtio_load(&s->vdev, f);
|
||||
ret = virtio_load(&s->vdev, f);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
s->num_pages = qemu_get_be32(f);
|
||||
s->actual = qemu_get_be32(f);
|
||||
|
||||
+64
-45
@@ -29,7 +29,7 @@ typedef struct VirtIOBlock
|
||||
void *rq;
|
||||
QEMUBH *bh;
|
||||
BlockConf *conf;
|
||||
char *serial;
|
||||
VirtIOBlkConf *blk;
|
||||
unsigned short sector_mask;
|
||||
DeviceState *qdev;
|
||||
} VirtIOBlock;
|
||||
@@ -145,19 +145,13 @@ static VirtIOBlockReq *virtio_blk_get_request(VirtIOBlock *s)
|
||||
return req;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
|
||||
{
|
||||
struct sg_io_hdr hdr;
|
||||
#ifdef __linux__
|
||||
int ret;
|
||||
int status;
|
||||
int i;
|
||||
|
||||
if ((req->dev->vdev.guest_features & (1 << VIRTIO_BLK_F_SCSI)) == 0) {
|
||||
virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
|
||||
g_free(req);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
int status = VIRTIO_BLK_S_OK;
|
||||
|
||||
/*
|
||||
* We require at least one output segment each for the virtio_blk_outhdr
|
||||
@@ -172,21 +166,27 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* No support for bidirection commands yet.
|
||||
*/
|
||||
if (req->elem.out_num > 2 && req->elem.in_num > 3) {
|
||||
virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
|
||||
g_free(req);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* The scsi inhdr is placed in the second-to-last input segment, just
|
||||
* before the regular inhdr.
|
||||
*/
|
||||
req->scsi = (void *)req->elem.in_sg[req->elem.in_num - 2].iov_base;
|
||||
|
||||
if (!req->dev->blk->scsi) {
|
||||
status = VIRTIO_BLK_S_UNSUPP;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/*
|
||||
* No support for bidirection commands yet.
|
||||
*/
|
||||
if (req->elem.out_num > 2 && req->elem.in_num > 3) {
|
||||
status = VIRTIO_BLK_S_UNSUPP;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
struct sg_io_hdr hdr;
|
||||
memset(&hdr, 0, sizeof(struct sg_io_hdr));
|
||||
hdr.interface_id = 'S';
|
||||
hdr.cmd_len = req->elem.out_sg[1].iov_len;
|
||||
@@ -230,12 +230,7 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
|
||||
ret = bdrv_ioctl(req->dev->bs, SG_IO, &hdr);
|
||||
if (ret) {
|
||||
status = VIRTIO_BLK_S_UNSUPP;
|
||||
hdr.status = ret;
|
||||
hdr.resid = hdr.dxfer_len;
|
||||
} else if (hdr.status) {
|
||||
status = VIRTIO_BLK_S_IOERR;
|
||||
} else {
|
||||
status = VIRTIO_BLK_S_OK;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -258,14 +253,17 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
|
||||
|
||||
virtio_blk_req_complete(req, status);
|
||||
g_free(req);
|
||||
}
|
||||
return;
|
||||
#else
|
||||
static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
|
||||
{
|
||||
virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
|
||||
abort();
|
||||
#endif
|
||||
|
||||
fail:
|
||||
/* Just put anything nonzero so that the ioctl fails in the guest. */
|
||||
stl_p(&req->scsi->errors, 255);
|
||||
virtio_blk_req_complete(req, status);
|
||||
g_free(req);
|
||||
}
|
||||
#endif /* __linux__ */
|
||||
|
||||
typedef struct MultiReqBuffer {
|
||||
BlockRequest blkreq[32];
|
||||
@@ -394,7 +392,7 @@ static void virtio_blk_handle_request(VirtIOBlockReq *req,
|
||||
* terminated by '\0' only when shorter than buffer.
|
||||
*/
|
||||
strncpy(req->elem.in_sg[0].iov_base,
|
||||
s->serial ? s->serial : "",
|
||||
s->blk->serial ? s->blk->serial : "",
|
||||
MIN(req->elem.in_sg[0].iov_len, VIRTIO_BLK_ID_BYTES));
|
||||
virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
|
||||
g_free(req);
|
||||
@@ -494,7 +492,22 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
|
||||
stw_raw(&blkcfg.min_io_size, s->conf->min_io_size / blk_size);
|
||||
stw_raw(&blkcfg.opt_io_size, s->conf->opt_io_size / blk_size);
|
||||
blkcfg.heads = heads;
|
||||
blkcfg.sectors = secs & ~s->sector_mask;
|
||||
/*
|
||||
* We must ensure that the block device capacity is a multiple of
|
||||
* the logical block size. If that is not the case, lets use
|
||||
* sector_mask to adopt the geometry to have a correct picture.
|
||||
* For those devices where the capacity is ok for the given geometry
|
||||
* we dont touch the sector value of the geometry, since some devices
|
||||
* (like s390 dasd) need a specific value. Here the capacity is already
|
||||
* cyls*heads*secs*blk_size and the sector value is not block size
|
||||
* divided by 512 - instead it is the amount of blk_size blocks
|
||||
* per track (cylinder).
|
||||
*/
|
||||
if (bdrv_getlength(s->bs) / heads / secs % blk_size) {
|
||||
blkcfg.sectors = secs & ~s->sector_mask;
|
||||
} else {
|
||||
blkcfg.sectors = secs;
|
||||
}
|
||||
blkcfg.size_max = 0;
|
||||
blkcfg.physical_block_exp = get_physical_block_exp(s->conf);
|
||||
blkcfg.alignment_offset = 0;
|
||||
@@ -509,6 +522,7 @@ static uint32_t virtio_blk_get_features(VirtIODevice *vdev, uint32_t features)
|
||||
features |= (1 << VIRTIO_BLK_F_GEOMETRY);
|
||||
features |= (1 << VIRTIO_BLK_F_TOPOLOGY);
|
||||
features |= (1 << VIRTIO_BLK_F_BLK_SIZE);
|
||||
features |= (1 << VIRTIO_BLK_F_SCSI);
|
||||
|
||||
if (bdrv_enable_write_cache(s->bs))
|
||||
features |= (1 << VIRTIO_BLK_F_WCACHE);
|
||||
@@ -537,11 +551,16 @@ static void virtio_blk_save(QEMUFile *f, void *opaque)
|
||||
static int virtio_blk_load(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
VirtIOBlock *s = opaque;
|
||||
int ret;
|
||||
|
||||
if (version_id != 2)
|
||||
return -EINVAL;
|
||||
|
||||
virtio_load(&s->vdev, f);
|
||||
ret = virtio_load(&s->vdev, f);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
while (qemu_get_sbyte(f)) {
|
||||
VirtIOBlockReq *req = virtio_blk_alloc_request(s);
|
||||
qemu_get_buffer(f, (unsigned char*)&req->elem, sizeof(req->elem));
|
||||
@@ -568,28 +587,27 @@ static const BlockDevOps virtio_block_ops = {
|
||||
.resize_cb = virtio_blk_resize,
|
||||
};
|
||||
|
||||
VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf,
|
||||
char **serial)
|
||||
VirtIODevice *virtio_blk_init(DeviceState *dev, VirtIOBlkConf *blk)
|
||||
{
|
||||
VirtIOBlock *s;
|
||||
int cylinders, heads, secs;
|
||||
static int virtio_blk_id;
|
||||
DriveInfo *dinfo;
|
||||
|
||||
if (!conf->bs) {
|
||||
if (!blk->conf.bs) {
|
||||
error_report("drive property not set");
|
||||
return NULL;
|
||||
}
|
||||
if (!bdrv_is_inserted(conf->bs)) {
|
||||
if (!bdrv_is_inserted(blk->conf.bs)) {
|
||||
error_report("Device needs media, but drive is empty");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!*serial) {
|
||||
if (!blk->serial) {
|
||||
/* try to fall back to value set with legacy -drive serial=... */
|
||||
dinfo = drive_get_by_blockdev(conf->bs);
|
||||
dinfo = drive_get_by_blockdev(blk->conf.bs);
|
||||
if (*dinfo->serial) {
|
||||
*serial = strdup(dinfo->serial);
|
||||
blk->serial = strdup(dinfo->serial);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -600,9 +618,9 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf,
|
||||
s->vdev.get_config = virtio_blk_update_config;
|
||||
s->vdev.get_features = virtio_blk_get_features;
|
||||
s->vdev.reset = virtio_blk_reset;
|
||||
s->bs = conf->bs;
|
||||
s->conf = conf;
|
||||
s->serial = *serial;
|
||||
s->bs = blk->conf.bs;
|
||||
s->conf = &blk->conf;
|
||||
s->blk = blk;
|
||||
s->rq = NULL;
|
||||
s->sector_mask = (s->conf->logical_block_size / BDRV_SECTOR_SIZE) - 1;
|
||||
bdrv_guess_geometry(s->bs, &cylinders, &heads, &secs);
|
||||
@@ -614,10 +632,10 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf,
|
||||
register_savevm(dev, "virtio-blk", virtio_blk_id++, 2,
|
||||
virtio_blk_save, virtio_blk_load, s);
|
||||
bdrv_set_dev_ops(s->bs, &virtio_block_ops, s);
|
||||
bdrv_set_buffer_alignment(s->bs, conf->logical_block_size);
|
||||
bdrv_set_buffer_alignment(s->bs, s->conf->logical_block_size);
|
||||
|
||||
bdrv_iostatus_enable(s->bs);
|
||||
add_boot_device_path(conf->bootindex, dev, "/disk@0,0");
|
||||
add_boot_device_path(s->conf->bootindex, dev, "/disk@0,0");
|
||||
|
||||
return &s->vdev;
|
||||
}
|
||||
@@ -626,5 +644,6 @@ void virtio_blk_exit(VirtIODevice *vdev)
|
||||
{
|
||||
VirtIOBlock *s = to_virtio_blk(vdev);
|
||||
unregister_savevm(s->qdev, "virtio-blk", s);
|
||||
blockdev_mark_auto_del(s->bs);
|
||||
virtio_cleanup(vdev);
|
||||
}
|
||||
+8
-6
@@ -97,12 +97,14 @@ struct virtio_scsi_inhdr
|
||||
uint32_t residual;
|
||||
};
|
||||
|
||||
#ifdef __linux__
|
||||
#define DEFINE_VIRTIO_BLK_FEATURES(_state, _field) \
|
||||
DEFINE_VIRTIO_COMMON_FEATURES(_state, _field), \
|
||||
DEFINE_PROP_BIT("scsi", _state, _field, VIRTIO_BLK_F_SCSI, true)
|
||||
#else
|
||||
struct VirtIOBlkConf
|
||||
{
|
||||
BlockConf conf;
|
||||
char *serial;
|
||||
uint32_t scsi;
|
||||
};
|
||||
|
||||
#define DEFINE_VIRTIO_BLK_FEATURES(_state, _field) \
|
||||
DEFINE_VIRTIO_COMMON_FEATURES(_state, _field)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+5
-1
@@ -891,11 +891,15 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
VirtIONet *n = opaque;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
if (version_id < 2 || version_id > VIRTIO_NET_VM_VERSION)
|
||||
return -EINVAL;
|
||||
|
||||
virtio_load(&n->vdev, f);
|
||||
ret = virtio_load(&n->vdev, f);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
qemu_get_buffer(f, n->mac, ETH_ALEN);
|
||||
n->tx_waiting = qemu_get_be32(f);
|
||||
|
||||
+9
-6
@@ -130,6 +130,7 @@ static int virtio_pci_load_config(void * opaque, QEMUFile *f)
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
msix_unuse_all_vectors(&proxy->pci_dev);
|
||||
msix_load(&proxy->pci_dev, f);
|
||||
if (msix_present(&proxy->pci_dev)) {
|
||||
qemu_get_be16s(f, &proxy->vdev->config_vector);
|
||||
@@ -278,6 +279,7 @@ void virtio_pci_reset(DeviceState *d)
|
||||
virtio_pci_stop_ioeventfd(proxy);
|
||||
virtio_reset(proxy->vdev);
|
||||
msix_reset(&proxy->pci_dev);
|
||||
msix_unuse_all_vectors(&proxy->pci_dev);
|
||||
proxy->flags &= ~VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
|
||||
}
|
||||
|
||||
@@ -491,7 +493,7 @@ static void virtio_pci_config_writel(void *opaque, uint32_t addr, uint32_t val)
|
||||
virtio_config_writel(proxy->vdev, addr, val);
|
||||
}
|
||||
|
||||
const MemoryRegionPortio virtio_portio[] = {
|
||||
static const MemoryRegionPortio virtio_portio[] = {
|
||||
{ 0, 0x10000, 1, .write = virtio_pci_config_writeb, },
|
||||
{ 0, 0x10000, 2, .write = virtio_pci_config_writew, },
|
||||
{ 0, 0x10000, 4, .write = virtio_pci_config_writel, },
|
||||
@@ -697,8 +699,7 @@ static int virtio_blk_init_pci(PCIDevice *pci_dev)
|
||||
proxy->class_code != PCI_CLASS_STORAGE_OTHER)
|
||||
proxy->class_code = PCI_CLASS_STORAGE_SCSI;
|
||||
|
||||
vdev = virtio_blk_init(&pci_dev->qdev, &proxy->block,
|
||||
&proxy->block_serial);
|
||||
vdev = virtio_blk_init(&pci_dev->qdev, &proxy->blk);
|
||||
if (!vdev) {
|
||||
return -1;
|
||||
}
|
||||
@@ -726,7 +727,6 @@ static int virtio_blk_exit_pci(PCIDevice *pci_dev)
|
||||
|
||||
virtio_pci_stop_ioeventfd(proxy);
|
||||
virtio_blk_exit(proxy->vdev);
|
||||
blockdev_mark_auto_del(proxy->block.bs);
|
||||
return virtio_exit_pci(pci_dev);
|
||||
}
|
||||
|
||||
@@ -814,8 +814,11 @@ static int virtio_balloon_exit_pci(PCIDevice *pci_dev)
|
||||
|
||||
static Property virtio_blk_properties[] = {
|
||||
DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
|
||||
DEFINE_BLOCK_PROPERTIES(VirtIOPCIProxy, block),
|
||||
DEFINE_PROP_STRING("serial", VirtIOPCIProxy, block_serial),
|
||||
DEFINE_BLOCK_PROPERTIES(VirtIOPCIProxy, blk.conf),
|
||||
DEFINE_PROP_STRING("serial", VirtIOPCIProxy, blk.serial),
|
||||
#ifdef __linux__
|
||||
DEFINE_PROP_BIT("scsi", VirtIOPCIProxy, blk.scsi, 0, true),
|
||||
#endif
|
||||
DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
|
||||
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
|
||||
DEFINE_VIRTIO_BLK_FEATURES(VirtIOPCIProxy, host_features),
|
||||
|
||||
+2
-2
@@ -15,6 +15,7 @@
|
||||
#ifndef QEMU_VIRTIO_PCI_H
|
||||
#define QEMU_VIRTIO_PCI_H
|
||||
|
||||
#include "virtio-blk.h"
|
||||
#include "virtio-net.h"
|
||||
#include "virtio-serial.h"
|
||||
#include "virtio-scsi.h"
|
||||
@@ -32,8 +33,7 @@ typedef struct {
|
||||
uint32_t flags;
|
||||
uint32_t class_code;
|
||||
uint32_t nvectors;
|
||||
BlockConf block;
|
||||
char *block_serial;
|
||||
VirtIOBlkConf blk;
|
||||
NICConf nic;
|
||||
uint32_t host_features;
|
||||
#ifdef CONFIG_LINUX
|
||||
|
||||
+6
-1
@@ -564,7 +564,12 @@ static void virtio_scsi_save(QEMUFile *f, void *opaque)
|
||||
static int virtio_scsi_load(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
VirtIOSCSI *s = opaque;
|
||||
virtio_load(&s->vdev, f);
|
||||
int ret;
|
||||
|
||||
ret = virtio_load(&s->vdev, f);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -637,13 +637,17 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
|
||||
VirtIOSerialPort *port;
|
||||
uint32_t max_nr_ports, nr_active_ports, ports_map;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
if (version_id > 3) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* The virtio device */
|
||||
virtio_load(&s->vdev, f);
|
||||
ret = virtio_load(&s->vdev, f);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (version_id < 2) {
|
||||
return 0;
|
||||
|
||||
+2
-2
@@ -191,8 +191,8 @@ void virtio_bind_device(VirtIODevice *vdev, const VirtIOBindings *binding,
|
||||
void *opaque);
|
||||
|
||||
/* Base devices. */
|
||||
VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf,
|
||||
char **serial);
|
||||
typedef struct VirtIOBlkConf VirtIOBlkConf;
|
||||
VirtIODevice *virtio_blk_init(DeviceState *dev, VirtIOBlkConf *blk);
|
||||
struct virtio_net_conf;
|
||||
VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf,
|
||||
struct virtio_net_conf *net);
|
||||
|
||||
+1
-1
@@ -148,6 +148,6 @@ static inline int xen_xc_hvm_inject_msi(XenXC xen_xc, domid_t dom,
|
||||
}
|
||||
#endif
|
||||
|
||||
void destroy_hvm_domain(void);
|
||||
void destroy_hvm_domain(bool reboot);
|
||||
|
||||
#endif /* QEMU_HW_XEN_COMMON_H */
|
||||
+41
-15
@@ -48,7 +48,6 @@
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
|
||||
static int syncwrite = 0;
|
||||
static int batch_maps = 0;
|
||||
|
||||
static int max_requests = 32;
|
||||
@@ -67,6 +66,7 @@ struct ioreq {
|
||||
QEMUIOVector v;
|
||||
int presync;
|
||||
int postsync;
|
||||
uint8_t mapped;
|
||||
|
||||
/* grant mapping */
|
||||
uint32_t domids[BLKIF_MAX_SEGMENTS_PER_REQUEST];
|
||||
@@ -154,7 +154,7 @@ static void ioreq_finish(struct ioreq *ioreq)
|
||||
blkdev->requests_finished++;
|
||||
}
|
||||
|
||||
static void ioreq_release(struct ioreq *ioreq)
|
||||
static void ioreq_release(struct ioreq *ioreq, bool finish)
|
||||
{
|
||||
struct XenBlkDev *blkdev = ioreq->blkdev;
|
||||
|
||||
@@ -162,7 +162,11 @@ static void ioreq_release(struct ioreq *ioreq)
|
||||
memset(ioreq, 0, sizeof(*ioreq));
|
||||
ioreq->blkdev = blkdev;
|
||||
QLIST_INSERT_HEAD(&blkdev->freelist, ioreq, list);
|
||||
blkdev->requests_finished--;
|
||||
if (finish) {
|
||||
blkdev->requests_finished--;
|
||||
} else {
|
||||
blkdev->requests_inflight--;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -189,15 +193,10 @@ static int ioreq_parse(struct ioreq *ioreq)
|
||||
ioreq->presync = 1;
|
||||
return 0;
|
||||
}
|
||||
if (!syncwrite) {
|
||||
ioreq->presync = ioreq->postsync = 1;
|
||||
}
|
||||
ioreq->presync = ioreq->postsync = 1;
|
||||
/* fall through */
|
||||
case BLKIF_OP_WRITE:
|
||||
ioreq->prot = PROT_READ; /* from memory */
|
||||
if (syncwrite) {
|
||||
ioreq->postsync = 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
xen_be_printf(&blkdev->xendev, 0, "error: unknown operation (%d)\n",
|
||||
@@ -248,7 +247,7 @@ static void ioreq_unmap(struct ioreq *ioreq)
|
||||
XenGnttab gnt = ioreq->blkdev->xendev.gnttabdev;
|
||||
int i;
|
||||
|
||||
if (ioreq->v.niov == 0) {
|
||||
if (ioreq->v.niov == 0 || ioreq->mapped == 0) {
|
||||
return;
|
||||
}
|
||||
if (batch_maps) {
|
||||
@@ -274,6 +273,7 @@ static void ioreq_unmap(struct ioreq *ioreq)
|
||||
ioreq->page[i] = NULL;
|
||||
}
|
||||
}
|
||||
ioreq->mapped = 0;
|
||||
}
|
||||
|
||||
static int ioreq_map(struct ioreq *ioreq)
|
||||
@@ -281,7 +281,7 @@ static int ioreq_map(struct ioreq *ioreq)
|
||||
XenGnttab gnt = ioreq->blkdev->xendev.gnttabdev;
|
||||
int i;
|
||||
|
||||
if (ioreq->v.niov == 0) {
|
||||
if (ioreq->v.niov == 0 || ioreq->mapped == 1) {
|
||||
return 0;
|
||||
}
|
||||
if (batch_maps) {
|
||||
@@ -313,9 +313,12 @@ static int ioreq_map(struct ioreq *ioreq)
|
||||
ioreq->blkdev->cnt_map++;
|
||||
}
|
||||
}
|
||||
ioreq->mapped = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ioreq_runio_qemu_aio(struct ioreq *ioreq);
|
||||
|
||||
static void qemu_aio_complete(void *opaque, int ret)
|
||||
{
|
||||
struct ioreq *ioreq = opaque;
|
||||
@@ -327,11 +330,19 @@ static void qemu_aio_complete(void *opaque, int ret)
|
||||
}
|
||||
|
||||
ioreq->aio_inflight--;
|
||||
if (ioreq->presync) {
|
||||
ioreq->presync = 0;
|
||||
ioreq_runio_qemu_aio(ioreq);
|
||||
return;
|
||||
}
|
||||
if (ioreq->aio_inflight > 0) {
|
||||
return;
|
||||
}
|
||||
if (ioreq->postsync) {
|
||||
bdrv_flush(ioreq->blkdev->bs);
|
||||
ioreq->postsync = 0;
|
||||
ioreq->aio_inflight++;
|
||||
bdrv_aio_flush(ioreq->blkdev->bs, qemu_aio_complete, ioreq);
|
||||
return;
|
||||
}
|
||||
|
||||
ioreq->status = ioreq->aio_errors ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY;
|
||||
@@ -351,7 +362,8 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
|
||||
|
||||
ioreq->aio_inflight++;
|
||||
if (ioreq->presync) {
|
||||
bdrv_flush(blkdev->bs); /* FIXME: aio_flush() ??? */
|
||||
bdrv_aio_flush(ioreq->blkdev->bs, qemu_aio_complete, ioreq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (ioreq->req.operation) {
|
||||
@@ -449,7 +461,7 @@ static void blk_send_response_all(struct XenBlkDev *blkdev)
|
||||
while (!QLIST_EMPTY(&blkdev->finished)) {
|
||||
ioreq = QLIST_FIRST(&blkdev->finished);
|
||||
send_notify += blk_send_response_one(ioreq);
|
||||
ioreq_release(ioreq);
|
||||
ioreq_release(ioreq, true);
|
||||
}
|
||||
if (send_notify) {
|
||||
xen_be_send_notify(&blkdev->xendev);
|
||||
@@ -505,7 +517,7 @@ static void blk_handle_requests(struct XenBlkDev *blkdev)
|
||||
if (blk_send_response_one(ioreq)) {
|
||||
xen_be_send_notify(&blkdev->xendev);
|
||||
}
|
||||
ioreq_release(ioreq);
|
||||
ioreq_release(ioreq, false);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -525,6 +537,15 @@ static void blk_bh(void *opaque)
|
||||
blk_handle_requests(blkdev);
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to account for the grant allocations requiring contiguous
|
||||
* chunks; the worst case number would be
|
||||
* max_req * max_seg + (max_req - 1) * (max_seg - 1) + 1,
|
||||
* but in order to keep things simple just use
|
||||
* 2 * max_req * max_seg.
|
||||
*/
|
||||
#define MAX_GRANTS(max_req, max_seg) (2 * (max_req) * (max_seg))
|
||||
|
||||
static void blk_alloc(struct XenDevice *xendev)
|
||||
{
|
||||
struct XenBlkDev *blkdev = container_of(xendev, struct XenBlkDev, xendev);
|
||||
@@ -536,6 +557,11 @@ static void blk_alloc(struct XenDevice *xendev)
|
||||
if (xen_mode != XEN_EMULATE) {
|
||||
batch_maps = 1;
|
||||
}
|
||||
if (xc_gnttab_set_max_grants(xendev->gnttabdev,
|
||||
MAX_GRANTS(max_requests, BLKIF_MAX_SEGMENTS_PER_REQUEST)) < 0) {
|
||||
xen_be_printf(xendev, 0, "xc_gnttab_set_max_grants failed: %s\n",
|
||||
strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
static int blk_init(struct XenDevice *xendev)
|
||||
|
||||
+1
-1
@@ -87,7 +87,7 @@ static void unplug_nic(PCIBus *b, PCIDevice *d)
|
||||
{
|
||||
if (pci_get_word(d->config + PCI_CLASS_DEVICE) ==
|
||||
PCI_CLASS_NETWORK_ETHERNET) {
|
||||
qdev_unplug(&(d->qdev), NULL);
|
||||
qdev_free(&d->qdev);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -77,6 +77,7 @@ int qemu_set_fd_handler2(int fd,
|
||||
ioh->fd_write = fd_write;
|
||||
ioh->opaque = opaque;
|
||||
ioh->deleted = 0;
|
||||
qemu_notify_event();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
+142
-88
@@ -27,6 +27,11 @@
|
||||
typedef struct JSONParserContext
|
||||
{
|
||||
Error *err;
|
||||
struct {
|
||||
QObject **buf;
|
||||
size_t pos;
|
||||
size_t count;
|
||||
} tokens;
|
||||
} JSONParserContext;
|
||||
|
||||
#define BUG_ON(cond) assert(!(cond))
|
||||
@@ -40,7 +45,7 @@ typedef struct JSONParserContext
|
||||
* 4) deal with premature EOI
|
||||
*/
|
||||
|
||||
static QObject *parse_value(JSONParserContext *ctxt, QList **tokens, va_list *ap);
|
||||
static QObject *parse_value(JSONParserContext *ctxt, va_list *ap);
|
||||
|
||||
/**
|
||||
* Token manipulators
|
||||
@@ -270,27 +275,111 @@ out:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static QObject *parser_context_pop_token(JSONParserContext *ctxt)
|
||||
{
|
||||
QObject *token;
|
||||
g_assert(ctxt->tokens.pos < ctxt->tokens.count);
|
||||
token = ctxt->tokens.buf[ctxt->tokens.pos];
|
||||
ctxt->tokens.pos++;
|
||||
return token;
|
||||
}
|
||||
|
||||
/* Note: parser_context_{peek|pop}_token do not increment the
|
||||
* token object's refcount. In both cases the references will continue
|
||||
* to be tracked and cleaned up in parser_context_free(), so do not
|
||||
* attempt to free the token object.
|
||||
*/
|
||||
static QObject *parser_context_peek_token(JSONParserContext *ctxt)
|
||||
{
|
||||
QObject *token;
|
||||
g_assert(ctxt->tokens.pos < ctxt->tokens.count);
|
||||
token = ctxt->tokens.buf[ctxt->tokens.pos];
|
||||
return token;
|
||||
}
|
||||
|
||||
static JSONParserContext parser_context_save(JSONParserContext *ctxt)
|
||||
{
|
||||
JSONParserContext saved_ctxt = {0};
|
||||
saved_ctxt.tokens.pos = ctxt->tokens.pos;
|
||||
saved_ctxt.tokens.count = ctxt->tokens.count;
|
||||
saved_ctxt.tokens.buf = ctxt->tokens.buf;
|
||||
return saved_ctxt;
|
||||
}
|
||||
|
||||
static void parser_context_restore(JSONParserContext *ctxt,
|
||||
JSONParserContext saved_ctxt)
|
||||
{
|
||||
ctxt->tokens.pos = saved_ctxt.tokens.pos;
|
||||
ctxt->tokens.count = saved_ctxt.tokens.count;
|
||||
ctxt->tokens.buf = saved_ctxt.tokens.buf;
|
||||
}
|
||||
|
||||
static void tokens_append_from_iter(QObject *obj, void *opaque)
|
||||
{
|
||||
JSONParserContext *ctxt = opaque;
|
||||
g_assert(ctxt->tokens.pos < ctxt->tokens.count);
|
||||
ctxt->tokens.buf[ctxt->tokens.pos++] = obj;
|
||||
qobject_incref(obj);
|
||||
}
|
||||
|
||||
static JSONParserContext *parser_context_new(QList *tokens)
|
||||
{
|
||||
JSONParserContext *ctxt;
|
||||
size_t count;
|
||||
|
||||
if (!tokens) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
count = qlist_size(tokens);
|
||||
if (count == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctxt = g_malloc0(sizeof(JSONParserContext));
|
||||
ctxt->tokens.pos = 0;
|
||||
ctxt->tokens.count = count;
|
||||
ctxt->tokens.buf = g_malloc(count * sizeof(QObject *));
|
||||
qlist_iter(tokens, tokens_append_from_iter, ctxt);
|
||||
ctxt->tokens.pos = 0;
|
||||
|
||||
return ctxt;
|
||||
}
|
||||
|
||||
/* to support error propagation, ctxt->err must be freed separately */
|
||||
static void parser_context_free(JSONParserContext *ctxt)
|
||||
{
|
||||
int i;
|
||||
if (ctxt) {
|
||||
for (i = 0; i < ctxt->tokens.count; i++) {
|
||||
qobject_decref(ctxt->tokens.buf[i]);
|
||||
}
|
||||
g_free(ctxt->tokens.buf);
|
||||
g_free(ctxt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parsing rules
|
||||
*/
|
||||
static int parse_pair(JSONParserContext *ctxt, QDict *dict, QList **tokens, va_list *ap)
|
||||
static int parse_pair(JSONParserContext *ctxt, QDict *dict, va_list *ap)
|
||||
{
|
||||
QObject *key = NULL, *token = NULL, *value, *peek;
|
||||
QList *working = qlist_copy(*tokens);
|
||||
JSONParserContext saved_ctxt = parser_context_save(ctxt);
|
||||
|
||||
peek = qlist_peek(working);
|
||||
peek = parser_context_peek_token(ctxt);
|
||||
if (peek == NULL) {
|
||||
parse_error(ctxt, NULL, "premature EOI");
|
||||
goto out;
|
||||
}
|
||||
|
||||
key = parse_value(ctxt, &working, ap);
|
||||
key = parse_value(ctxt, ap);
|
||||
if (!key || qobject_type(key) != QTYPE_QSTRING) {
|
||||
parse_error(ctxt, peek, "key is not a string in object");
|
||||
goto out;
|
||||
}
|
||||
|
||||
token = qlist_pop(working);
|
||||
token = parser_context_pop_token(ctxt);
|
||||
if (token == NULL) {
|
||||
parse_error(ctxt, NULL, "premature EOI");
|
||||
goto out;
|
||||
@@ -301,7 +390,7 @@ static int parse_pair(JSONParserContext *ctxt, QDict *dict, QList **tokens, va_l
|
||||
goto out;
|
||||
}
|
||||
|
||||
value = parse_value(ctxt, &working, ap);
|
||||
value = parse_value(ctxt, ap);
|
||||
if (value == NULL) {
|
||||
parse_error(ctxt, token, "Missing value in dict");
|
||||
goto out;
|
||||
@@ -309,28 +398,24 @@ static int parse_pair(JSONParserContext *ctxt, QDict *dict, QList **tokens, va_l
|
||||
|
||||
qdict_put_obj(dict, qstring_get_str(qobject_to_qstring(key)), value);
|
||||
|
||||
qobject_decref(token);
|
||||
qobject_decref(key);
|
||||
QDECREF(*tokens);
|
||||
*tokens = working;
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
qobject_decref(token);
|
||||
parser_context_restore(ctxt, saved_ctxt);
|
||||
qobject_decref(key);
|
||||
QDECREF(working);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static QObject *parse_object(JSONParserContext *ctxt, QList **tokens, va_list *ap)
|
||||
static QObject *parse_object(JSONParserContext *ctxt, va_list *ap)
|
||||
{
|
||||
QDict *dict = NULL;
|
||||
QObject *token, *peek;
|
||||
QList *working = qlist_copy(*tokens);
|
||||
JSONParserContext saved_ctxt = parser_context_save(ctxt);
|
||||
|
||||
token = qlist_pop(working);
|
||||
token = parser_context_pop_token(ctxt);
|
||||
if (token == NULL) {
|
||||
goto out;
|
||||
}
|
||||
@@ -338,23 +423,22 @@ static QObject *parse_object(JSONParserContext *ctxt, QList **tokens, va_list *a
|
||||
if (!token_is_operator(token, '{')) {
|
||||
goto out;
|
||||
}
|
||||
qobject_decref(token);
|
||||
token = NULL;
|
||||
|
||||
dict = qdict_new();
|
||||
|
||||
peek = qlist_peek(working);
|
||||
peek = parser_context_peek_token(ctxt);
|
||||
if (peek == NULL) {
|
||||
parse_error(ctxt, NULL, "premature EOI");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!token_is_operator(peek, '}')) {
|
||||
if (parse_pair(ctxt, dict, &working, ap) == -1) {
|
||||
if (parse_pair(ctxt, dict, ap) == -1) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
token = qlist_pop(working);
|
||||
token = parser_context_pop_token(ctxt);
|
||||
if (token == NULL) {
|
||||
parse_error(ctxt, NULL, "premature EOI");
|
||||
goto out;
|
||||
@@ -365,59 +449,52 @@ static QObject *parse_object(JSONParserContext *ctxt, QList **tokens, va_list *a
|
||||
parse_error(ctxt, token, "expected separator in dict");
|
||||
goto out;
|
||||
}
|
||||
qobject_decref(token);
|
||||
token = NULL;
|
||||
|
||||
if (parse_pair(ctxt, dict, &working, ap) == -1) {
|
||||
if (parse_pair(ctxt, dict, ap) == -1) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
token = qlist_pop(working);
|
||||
token = parser_context_pop_token(ctxt);
|
||||
if (token == NULL) {
|
||||
parse_error(ctxt, NULL, "premature EOI");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
qobject_decref(token);
|
||||
token = NULL;
|
||||
} else {
|
||||
token = qlist_pop(working);
|
||||
qobject_decref(token);
|
||||
token = parser_context_pop_token(ctxt);
|
||||
token = NULL;
|
||||
}
|
||||
|
||||
QDECREF(*tokens);
|
||||
*tokens = working;
|
||||
|
||||
return QOBJECT(dict);
|
||||
|
||||
out:
|
||||
qobject_decref(token);
|
||||
QDECREF(working);
|
||||
parser_context_restore(ctxt, saved_ctxt);
|
||||
QDECREF(dict);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static QObject *parse_array(JSONParserContext *ctxt, QList **tokens, va_list *ap)
|
||||
static QObject *parse_array(JSONParserContext *ctxt, va_list *ap)
|
||||
{
|
||||
QList *list = NULL;
|
||||
QObject *token, *peek;
|
||||
QList *working = qlist_copy(*tokens);
|
||||
JSONParserContext saved_ctxt = parser_context_save(ctxt);
|
||||
|
||||
token = qlist_pop(working);
|
||||
token = parser_context_pop_token(ctxt);
|
||||
if (token == NULL) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!token_is_operator(token, '[')) {
|
||||
token = NULL;
|
||||
goto out;
|
||||
}
|
||||
qobject_decref(token);
|
||||
token = NULL;
|
||||
|
||||
list = qlist_new();
|
||||
|
||||
peek = qlist_peek(working);
|
||||
peek = parser_context_peek_token(ctxt);
|
||||
if (peek == NULL) {
|
||||
parse_error(ctxt, NULL, "premature EOI");
|
||||
goto out;
|
||||
@@ -426,7 +503,7 @@ static QObject *parse_array(JSONParserContext *ctxt, QList **tokens, va_list *ap
|
||||
if (!token_is_operator(peek, ']')) {
|
||||
QObject *obj;
|
||||
|
||||
obj = parse_value(ctxt, &working, ap);
|
||||
obj = parse_value(ctxt, ap);
|
||||
if (obj == NULL) {
|
||||
parse_error(ctxt, token, "expecting value");
|
||||
goto out;
|
||||
@@ -434,7 +511,7 @@ static QObject *parse_array(JSONParserContext *ctxt, QList **tokens, va_list *ap
|
||||
|
||||
qlist_append_obj(list, obj);
|
||||
|
||||
token = qlist_pop(working);
|
||||
token = parser_context_pop_token(ctxt);
|
||||
if (token == NULL) {
|
||||
parse_error(ctxt, NULL, "premature EOI");
|
||||
goto out;
|
||||
@@ -446,10 +523,9 @@ static QObject *parse_array(JSONParserContext *ctxt, QList **tokens, va_list *ap
|
||||
goto out;
|
||||
}
|
||||
|
||||
qobject_decref(token);
|
||||
token = NULL;
|
||||
|
||||
obj = parse_value(ctxt, &working, ap);
|
||||
obj = parse_value(ctxt, ap);
|
||||
if (obj == NULL) {
|
||||
parse_error(ctxt, token, "expecting value");
|
||||
goto out;
|
||||
@@ -457,39 +533,33 @@ static QObject *parse_array(JSONParserContext *ctxt, QList **tokens, va_list *ap
|
||||
|
||||
qlist_append_obj(list, obj);
|
||||
|
||||
token = qlist_pop(working);
|
||||
token = parser_context_pop_token(ctxt);
|
||||
if (token == NULL) {
|
||||
parse_error(ctxt, NULL, "premature EOI");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
qobject_decref(token);
|
||||
token = NULL;
|
||||
} else {
|
||||
token = qlist_pop(working);
|
||||
qobject_decref(token);
|
||||
token = parser_context_pop_token(ctxt);
|
||||
token = NULL;
|
||||
}
|
||||
|
||||
QDECREF(*tokens);
|
||||
*tokens = working;
|
||||
|
||||
return QOBJECT(list);
|
||||
|
||||
out:
|
||||
qobject_decref(token);
|
||||
QDECREF(working);
|
||||
parser_context_restore(ctxt, saved_ctxt);
|
||||
QDECREF(list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static QObject *parse_keyword(JSONParserContext *ctxt, QList **tokens)
|
||||
static QObject *parse_keyword(JSONParserContext *ctxt)
|
||||
{
|
||||
QObject *token, *ret;
|
||||
QList *working = qlist_copy(*tokens);
|
||||
JSONParserContext saved_ctxt = parser_context_save(ctxt);
|
||||
|
||||
token = qlist_pop(working);
|
||||
token = parser_context_pop_token(ctxt);
|
||||
if (token == NULL) {
|
||||
goto out;
|
||||
}
|
||||
@@ -507,29 +577,24 @@ static QObject *parse_keyword(JSONParserContext *ctxt, QList **tokens)
|
||||
goto out;
|
||||
}
|
||||
|
||||
qobject_decref(token);
|
||||
QDECREF(*tokens);
|
||||
*tokens = working;
|
||||
|
||||
return ret;
|
||||
|
||||
out:
|
||||
qobject_decref(token);
|
||||
QDECREF(working);
|
||||
parser_context_restore(ctxt, saved_ctxt);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static QObject *parse_escape(JSONParserContext *ctxt, QList **tokens, va_list *ap)
|
||||
static QObject *parse_escape(JSONParserContext *ctxt, va_list *ap)
|
||||
{
|
||||
QObject *token = NULL, *obj;
|
||||
QList *working = qlist_copy(*tokens);
|
||||
JSONParserContext saved_ctxt = parser_context_save(ctxt);
|
||||
|
||||
if (ap == NULL) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
token = qlist_pop(working);
|
||||
token = parser_context_pop_token(ctxt);
|
||||
if (token == NULL) {
|
||||
goto out;
|
||||
}
|
||||
@@ -553,25 +618,20 @@ static QObject *parse_escape(JSONParserContext *ctxt, QList **tokens, va_list *a
|
||||
goto out;
|
||||
}
|
||||
|
||||
qobject_decref(token);
|
||||
QDECREF(*tokens);
|
||||
*tokens = working;
|
||||
|
||||
return obj;
|
||||
|
||||
out:
|
||||
qobject_decref(token);
|
||||
QDECREF(working);
|
||||
parser_context_restore(ctxt, saved_ctxt);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static QObject *parse_literal(JSONParserContext *ctxt, QList **tokens)
|
||||
static QObject *parse_literal(JSONParserContext *ctxt)
|
||||
{
|
||||
QObject *token, *obj;
|
||||
QList *working = qlist_copy(*tokens);
|
||||
JSONParserContext saved_ctxt = parser_context_save(ctxt);
|
||||
|
||||
token = qlist_pop(working);
|
||||
token = parser_context_pop_token(ctxt);
|
||||
if (token == NULL) {
|
||||
goto out;
|
||||
}
|
||||
@@ -591,35 +651,30 @@ static QObject *parse_literal(JSONParserContext *ctxt, QList **tokens)
|
||||
goto out;
|
||||
}
|
||||
|
||||
qobject_decref(token);
|
||||
QDECREF(*tokens);
|
||||
*tokens = working;
|
||||
|
||||
return obj;
|
||||
|
||||
out:
|
||||
qobject_decref(token);
|
||||
QDECREF(working);
|
||||
parser_context_restore(ctxt, saved_ctxt);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static QObject *parse_value(JSONParserContext *ctxt, QList **tokens, va_list *ap)
|
||||
static QObject *parse_value(JSONParserContext *ctxt, va_list *ap)
|
||||
{
|
||||
QObject *obj;
|
||||
|
||||
obj = parse_object(ctxt, tokens, ap);
|
||||
obj = parse_object(ctxt, ap);
|
||||
if (obj == NULL) {
|
||||
obj = parse_array(ctxt, tokens, ap);
|
||||
obj = parse_array(ctxt, ap);
|
||||
}
|
||||
if (obj == NULL) {
|
||||
obj = parse_escape(ctxt, tokens, ap);
|
||||
obj = parse_escape(ctxt, ap);
|
||||
}
|
||||
if (obj == NULL) {
|
||||
obj = parse_keyword(ctxt, tokens);
|
||||
obj = parse_keyword(ctxt);
|
||||
}
|
||||
if (obj == NULL) {
|
||||
obj = parse_literal(ctxt, tokens);
|
||||
obj = parse_literal(ctxt);
|
||||
}
|
||||
|
||||
return obj;
|
||||
@@ -632,19 +687,18 @@ QObject *json_parser_parse(QList *tokens, va_list *ap)
|
||||
|
||||
QObject *json_parser_parse_err(QList *tokens, va_list *ap, Error **errp)
|
||||
{
|
||||
JSONParserContext ctxt = {};
|
||||
QList *working;
|
||||
JSONParserContext *ctxt = parser_context_new(tokens);
|
||||
QObject *result;
|
||||
|
||||
if (!tokens) {
|
||||
if (!ctxt) {
|
||||
return NULL;
|
||||
}
|
||||
working = qlist_copy(tokens);
|
||||
result = parse_value(&ctxt, &working, ap);
|
||||
|
||||
QDECREF(working);
|
||||
result = parse_value(ctxt, ap);
|
||||
|
||||
error_propagate(errp, ctxt.err);
|
||||
error_propagate(errp, ctxt->err);
|
||||
|
||||
parser_context_free(ctxt);
|
||||
|
||||
return result;
|
||||
}
|
||||
+5
-1
@@ -573,6 +573,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
|
||||
page_dump(stdout);
|
||||
printf("\n");
|
||||
#endif
|
||||
tb_invalidate_phys_range(start, start + len, 0);
|
||||
mmap_unlock();
|
||||
return start;
|
||||
fail:
|
||||
@@ -675,8 +676,10 @@ int target_munmap(abi_ulong start, abi_ulong len)
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
if (ret == 0) {
|
||||
page_set_flags(start, start + len, 0);
|
||||
tb_invalidate_phys_range(start, start + len, 0);
|
||||
}
|
||||
mmap_unlock();
|
||||
return ret;
|
||||
}
|
||||
@@ -754,6 +757,7 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
|
||||
page_set_flags(old_addr, old_addr + old_size, 0);
|
||||
page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID);
|
||||
}
|
||||
tb_invalidate_phys_range(new_addr, new_addr + new_size, 0);
|
||||
mmap_unlock();
|
||||
return new_addr;
|
||||
}
|
||||
|
||||
@@ -2794,7 +2794,7 @@ static inline abi_long do_msgrcv(int msqid, abi_long msgp,
|
||||
if (!lock_user_struct(VERIFY_WRITE, target_mb, msgp, 0))
|
||||
return -TARGET_EFAULT;
|
||||
|
||||
host_mb = malloc(msgsz+sizeof(long));
|
||||
host_mb = g_malloc(msgsz+sizeof(long));
|
||||
ret = get_errno(msgrcv(msqid, host_mb, msgsz, tswapal(msgtyp), msgflg));
|
||||
|
||||
if (ret > 0) {
|
||||
@@ -2809,11 +2809,11 @@ static inline abi_long do_msgrcv(int msqid, abi_long msgp,
|
||||
}
|
||||
|
||||
target_mb->mtype = tswapal(host_mb->mtype);
|
||||
free(host_mb);
|
||||
|
||||
end:
|
||||
if (target_mb)
|
||||
unlock_user_struct(target_mb, msgp, 1);
|
||||
g_free(host_mb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -426,7 +426,7 @@ static void memory_region_iorange_write(IORange *iorange,
|
||||
if (mrp) {
|
||||
mrp->write(mr->opaque, offset, data);
|
||||
} else if (width == 2) {
|
||||
mrp = find_portio(mr, offset - mrio->offset, 1, false);
|
||||
mrp = find_portio(mr, offset - mrio->offset, 1, true);
|
||||
assert(mrp);
|
||||
mrp->write(mr->opaque, offset, data & 0xff);
|
||||
mrp->write(mr->opaque, offset + 1, data >> 8);
|
||||
|
||||
@@ -4501,13 +4501,13 @@ static void monitor_control_event(void *opaque, int event)
|
||||
switch (event) {
|
||||
case CHR_EVENT_OPENED:
|
||||
mon->mc->command_mode = 0;
|
||||
json_message_parser_init(&mon->mc->parser, handle_qmp_command);
|
||||
data = get_qmp_greeting();
|
||||
monitor_json_emitter(mon, data);
|
||||
qobject_decref(data);
|
||||
break;
|
||||
case CHR_EVENT_CLOSED:
|
||||
json_message_parser_destroy(&mon->mc->parser);
|
||||
json_message_parser_init(&mon->mc->parser, handle_qmp_command);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -4605,6 +4605,8 @@ void monitor_init(CharDriverState *chr, int flags)
|
||||
qemu_chr_add_handlers(chr, monitor_can_read, monitor_control_read,
|
||||
monitor_control_event, mon);
|
||||
qemu_chr_fe_set_echo(chr, true);
|
||||
|
||||
json_message_parser_init(&mon->mc->parser, handle_qmp_command);
|
||||
} else {
|
||||
qemu_chr_add_handlers(chr, monitor_can_read, monitor_read,
|
||||
monitor_event, mon);
|
||||
|
||||
+24
-2
@@ -26,6 +26,7 @@
|
||||
#include "config-host.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <pwd.h>
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
#include "net.h"
|
||||
@@ -487,8 +488,27 @@ static int slirp_smb(SlirpState* s, const char *exported_dir,
|
||||
static int instance;
|
||||
char smb_conf[128];
|
||||
char smb_cmdline[128];
|
||||
struct passwd *passwd;
|
||||
FILE *f;
|
||||
|
||||
passwd = getpwuid(geteuid());
|
||||
if (!passwd) {
|
||||
error_report("failed to retrieve user name");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (access(CONFIG_SMBD_COMMAND, F_OK)) {
|
||||
error_report("could not find '%s', please install it",
|
||||
CONFIG_SMBD_COMMAND);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (access(exported_dir, R_OK | X_OK)) {
|
||||
error_report("error accessing shared directory '%s': %s",
|
||||
exported_dir, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
snprintf(s->smb_dir, sizeof(s->smb_dir), "/tmp/qemu-smb.%ld-%d",
|
||||
(long)getpid(), instance++);
|
||||
if (mkdir(s->smb_dir, 0700) < 0) {
|
||||
@@ -517,14 +537,16 @@ static int slirp_smb(SlirpState* s, const char *exported_dir,
|
||||
"[qemu]\n"
|
||||
"path=%s\n"
|
||||
"read only=no\n"
|
||||
"guest ok=yes\n",
|
||||
"guest ok=yes\n"
|
||||
"force user=%s\n",
|
||||
s->smb_dir,
|
||||
s->smb_dir,
|
||||
s->smb_dir,
|
||||
s->smb_dir,
|
||||
s->smb_dir,
|
||||
s->smb_dir,
|
||||
exported_dir
|
||||
exported_dir,
|
||||
passwd->pw_name
|
||||
);
|
||||
fclose(f);
|
||||
|
||||
|
||||
+7
-1
@@ -57,7 +57,13 @@ int setenv(const char *name, const char *value, int overwrite)
|
||||
|
||||
static BOOL WINAPI qemu_ctrl_handler(DWORD type)
|
||||
{
|
||||
exit(STATUS_CONTROL_C_EXIT);
|
||||
qemu_system_shutdown_request();
|
||||
/* Windows 7 kills application when the function returns.
|
||||
Sleep here to give QEMU a try for closing.
|
||||
Sleep period is 10000ms because Windows kills the program
|
||||
after 10 seconds anyway. */
|
||||
Sleep(10000);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@
|
||||
1275-1994 (referred to as Open Firmware) compliant firmware.
|
||||
The included images for PowerPC (for 32 and 64 bit PPC CPUs),
|
||||
Sparc32 and Sparc64 are built from OpenBIOS SVN revision
|
||||
1056.
|
||||
1060.
|
||||
|
||||
- SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware
|
||||
implementation for certain IBM POWER hardware. The sources are at
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
+37
-22
@@ -126,16 +126,19 @@
|
||||
# @guest-shutdown:
|
||||
#
|
||||
# Initiate guest-activated shutdown. Note: this is an asynchronous
|
||||
# shutdown request, with no guaruntee of successful shutdown. Errors
|
||||
# will be logged to guest's syslog.
|
||||
# shutdown request, with no guarantee of successful shutdown.
|
||||
#
|
||||
# @mode: #optional "halt", "powerdown" (default), or "reboot"
|
||||
#
|
||||
# Returns: Nothing on success
|
||||
# This command does NOT return a response on success. Success condition
|
||||
# is indicated by the VM exiting with a zero exit status or, when
|
||||
# running with --no-shutdown, by issuing the query-status QMP command
|
||||
# to confirm the VM status is "shutdown".
|
||||
#
|
||||
# Since: 0.15.0
|
||||
##
|
||||
{ 'command': 'guest-shutdown', 'data': { '*mode': 'str' } }
|
||||
{ 'command': 'guest-shutdown', 'data': { '*mode': 'str' },
|
||||
'success-response': 'no' }
|
||||
|
||||
##
|
||||
# @guest-file-open:
|
||||
@@ -359,17 +362,21 @@
|
||||
# For the best results it's strongly recommended to have the pm-utils
|
||||
# package installed in the guest.
|
||||
#
|
||||
# Returns: nothing on success
|
||||
# This command does NOT return a response on success. There is a high chance
|
||||
# the command succeeded if the VM exits with a zero exit status or, when
|
||||
# running with --no-shutdown, by issuing the query-status QMP command to
|
||||
# to confirm the VM status is "shutdown". However, the VM could also exit
|
||||
# (or set its status to "shutdown") due to other reasons.
|
||||
#
|
||||
# The following errors may be returned:
|
||||
# If suspend to disk is not supported, Unsupported
|
||||
#
|
||||
# Notes: o This is an asynchronous request. There's no guarantee a response
|
||||
# will be sent
|
||||
# o It's strongly recommended to issue the guest-sync command before
|
||||
# sending commands when the guest resumes
|
||||
# Notes: It's strongly recommended to issue the guest-sync command before
|
||||
# sending commands when the guest resumes
|
||||
#
|
||||
# Since: 1.1
|
||||
##
|
||||
{ 'command': 'guest-suspend-disk' }
|
||||
{ 'command': 'guest-suspend-disk', 'success-response': 'no' }
|
||||
|
||||
##
|
||||
# @guest-suspend-ram
|
||||
@@ -387,17 +394,21 @@
|
||||
# command. Thus, it's *required* to query QEMU for the presence of the
|
||||
# 'system_wakeup' command before issuing guest-suspend-ram.
|
||||
#
|
||||
# Returns: nothing on success
|
||||
# This command does NOT return a response on success. There are two options
|
||||
# to check for success:
|
||||
# 1. Wait for the SUSPEND QMP event from QEMU
|
||||
# 2. Issue the query-status QMP command to confirm the VM status is
|
||||
# "suspended"
|
||||
#
|
||||
# The following errors may be returned:
|
||||
# If suspend to ram is not supported, Unsupported
|
||||
#
|
||||
# Notes: o This is an asynchronous request. There's no guarantee a response
|
||||
# will be sent
|
||||
# o It's strongly recommended to issue the guest-sync command before
|
||||
# sending commands when the guest resumes
|
||||
# Notes: It's strongly recommended to issue the guest-sync command before
|
||||
# sending commands when the guest resumes
|
||||
#
|
||||
# Since: 1.1
|
||||
##
|
||||
{ 'command': 'guest-suspend-ram' }
|
||||
{ 'command': 'guest-suspend-ram', 'success-response': 'no' }
|
||||
|
||||
##
|
||||
# @guest-suspend-hybrid
|
||||
@@ -410,17 +421,21 @@
|
||||
# command. Thus, it's *required* to query QEMU for the presence of the
|
||||
# 'system_wakeup' command before issuing guest-suspend-hybrid.
|
||||
#
|
||||
# Returns: nothing on success
|
||||
# This command does NOT return a response on success. There are two options
|
||||
# to check for success:
|
||||
# 1. Wait for the SUSPEND QMP event from QEMU
|
||||
# 2. Issue the query-status QMP command to confirm the VM status is
|
||||
# "suspended"
|
||||
#
|
||||
# The following errors may be returned:
|
||||
# If hybrid suspend is not supported, Unsupported
|
||||
#
|
||||
# Notes: o This is an asynchronous request. There's no guarantee a response
|
||||
# will be sent
|
||||
# o It's strongly recommended to issue the guest-sync command before
|
||||
# sending commands when the guest resumes
|
||||
# Notes: It's strongly recommended to issue the guest-sync command before
|
||||
# sending commands when the guest resumes
|
||||
#
|
||||
# Since: 1.1
|
||||
##
|
||||
{ 'command': 'guest-suspend-hybrid' }
|
||||
{ 'command': 'guest-suspend-hybrid', 'success-response': 'no' }
|
||||
|
||||
##
|
||||
# @GuestIpAddressType:
|
||||
|
||||
+9
-1
@@ -25,16 +25,24 @@ typedef enum QmpCommandType
|
||||
QCT_NORMAL,
|
||||
} QmpCommandType;
|
||||
|
||||
typedef enum QmpCommandOptions
|
||||
{
|
||||
QCO_NO_OPTIONS = 0x0,
|
||||
QCO_NO_SUCCESS_RESP = 0x1,
|
||||
} QmpCommandOptions;
|
||||
|
||||
typedef struct QmpCommand
|
||||
{
|
||||
const char *name;
|
||||
QmpCommandType type;
|
||||
QmpCommandFunc *fn;
|
||||
QmpCommandOptions options;
|
||||
QTAILQ_ENTRY(QmpCommand) node;
|
||||
bool enabled;
|
||||
} QmpCommand;
|
||||
|
||||
void qmp_register_command(const char *name, QmpCommandFunc *fn);
|
||||
void qmp_register_command(const char *name, QmpCommandFunc *fn,
|
||||
QmpCommandOptions options);
|
||||
QmpCommand *qmp_find_command(const char *name);
|
||||
QObject *qmp_dispatch(QObject *request);
|
||||
void qmp_disable_command(const char *name);
|
||||
|
||||
+6
-2
@@ -94,8 +94,12 @@ static QObject *do_qmp_dispatch(QObject *request, Error **errp)
|
||||
switch (cmd->type) {
|
||||
case QCT_NORMAL:
|
||||
cmd->fn(args, &ret, errp);
|
||||
if (!error_is_set(errp) && ret == NULL) {
|
||||
ret = QOBJECT(qdict_new());
|
||||
if (!error_is_set(errp)) {
|
||||
if (cmd->options & QCO_NO_SUCCESS_RESP) {
|
||||
g_assert(!ret);
|
||||
} else if (!ret) {
|
||||
ret = QOBJECT(qdict_new());
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
+3
-1
@@ -17,7 +17,8 @@
|
||||
static QTAILQ_HEAD(QmpCommandList, QmpCommand) qmp_commands =
|
||||
QTAILQ_HEAD_INITIALIZER(qmp_commands);
|
||||
|
||||
void qmp_register_command(const char *name, QmpCommandFunc *fn)
|
||||
void qmp_register_command(const char *name, QmpCommandFunc *fn,
|
||||
QmpCommandOptions options)
|
||||
{
|
||||
QmpCommand *cmd = g_malloc0(sizeof(*cmd));
|
||||
|
||||
@@ -25,6 +26,7 @@ void qmp_register_command(const char *name, QmpCommandFunc *fn)
|
||||
cmd->type = QCT_NORMAL;
|
||||
cmd->fn = fn;
|
||||
cmd->enabled = true;
|
||||
cmd->options = options;
|
||||
QTAILQ_INSERT_TAIL(&qmp_commands, cmd, node);
|
||||
}
|
||||
|
||||
|
||||
@@ -104,16 +104,9 @@ static void quit_handler(int sig)
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
/* reap _all_ terminated children */
|
||||
static void child_handler(int sig)
|
||||
{
|
||||
int status;
|
||||
while (waitpid(-1, &status, WNOHANG) > 0) /* NOTHING */;
|
||||
}
|
||||
|
||||
static gboolean register_signal_handlers(void)
|
||||
{
|
||||
struct sigaction sigact, sigact_chld;
|
||||
struct sigaction sigact;
|
||||
int ret;
|
||||
|
||||
memset(&sigact, 0, sizeof(struct sigaction));
|
||||
@@ -130,15 +123,24 @@ static gboolean register_signal_handlers(void)
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(&sigact_chld, 0, sizeof(struct sigaction));
|
||||
sigact_chld.sa_handler = child_handler;
|
||||
sigact_chld.sa_flags = SA_NOCLDSTOP;
|
||||
ret = sigaction(SIGCHLD, &sigact_chld, NULL);
|
||||
if (ret == -1) {
|
||||
g_error("error configuring signal handler: %s", strerror(errno));
|
||||
return true;
|
||||
}
|
||||
|
||||
/* TODO: use this in place of all post-fork() fclose(std*) callers */
|
||||
void reopen_fd_to_null(int fd)
|
||||
{
|
||||
int nullfd;
|
||||
|
||||
nullfd = open("/dev/null", O_RDWR);
|
||||
if (nullfd < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
return true;
|
||||
dup2(nullfd, fd);
|
||||
|
||||
if (nullfd != fd) {
|
||||
close(nullfd);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -167,7 +169,7 @@ static void usage(const char *cmd)
|
||||
" -h, --help display this help and exit\n"
|
||||
"\n"
|
||||
"Report bugs to <mdroth@linux.vnet.ibm.com>\n"
|
||||
, cmd, QGA_VERSION, QGA_VIRTIO_PATH_DEFAULT, QGA_PIDFILE_DEFAULT,
|
||||
, cmd, QEMU_VERSION, QGA_VIRTIO_PATH_DEFAULT, QGA_PIDFILE_DEFAULT,
|
||||
QGA_STATEDIR_DEFAULT);
|
||||
}
|
||||
|
||||
@@ -246,6 +248,9 @@ static bool ga_open_pidfile(const char *pidfile)
|
||||
pidfd = open(pidfile, O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR);
|
||||
if (pidfd == -1 || lockf(pidfd, F_TLOCK, 0)) {
|
||||
g_critical("Cannot lock pid file, %s", strerror(errno));
|
||||
if (pidfd != -1) {
|
||||
close(pidfd);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -428,13 +433,15 @@ static void become_daemon(const char *pidfile)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
close(STDIN_FILENO);
|
||||
close(STDOUT_FILENO);
|
||||
close(STDERR_FILENO);
|
||||
reopen_fd_to_null(STDIN_FILENO);
|
||||
reopen_fd_to_null(STDOUT_FILENO);
|
||||
reopen_fd_to_null(STDERR_FILENO);
|
||||
return;
|
||||
|
||||
fail:
|
||||
unlink(pidfile);
|
||||
if (pidfile) {
|
||||
unlink(pidfile);
|
||||
}
|
||||
g_critical("failed to daemonize");
|
||||
exit(EXIT_FAILURE);
|
||||
#endif
|
||||
@@ -488,8 +495,6 @@ static void process_command(GAState *s, QDict *req)
|
||||
g_warning("error sending response: %s", strerror(ret));
|
||||
}
|
||||
qobject_decref(rsp);
|
||||
} else {
|
||||
g_warning("error getting response");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -729,7 +734,7 @@ int main(int argc, char **argv)
|
||||
log_level = G_LOG_LEVEL_MASK;
|
||||
break;
|
||||
case 'V':
|
||||
printf("QEMU Guest Agent %s\n", QGA_VERSION);
|
||||
printf("QEMU Guest Agent %s\n", QEMU_VERSION);
|
||||
return 0;
|
||||
case 'd':
|
||||
daemonize = 1;
|
||||
@@ -836,12 +841,13 @@ int main(int argc, char **argv)
|
||||
become_daemon(pid_filepath);
|
||||
}
|
||||
if (log_filepath) {
|
||||
s->log_file = fopen(log_filepath, "a");
|
||||
if (!s->log_file) {
|
||||
FILE *log_file = fopen(log_filepath, "a");
|
||||
if (!log_file) {
|
||||
g_critical("unable to open specified log file: %s",
|
||||
strerror(errno));
|
||||
goto out_bad;
|
||||
}
|
||||
s->log_file = log_file;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,16 @@ usage: qemu-img command [command options]
|
||||
@c man end
|
||||
@end example
|
||||
|
||||
@c man begin DESCRIPTION
|
||||
qemu-img allows you to create, convert and modify images offline. It can handle
|
||||
all image formats supported by QEMU.
|
||||
|
||||
@b{Warning:} Never use qemu-img to modify images in use by a running virtual
|
||||
machine or any other process; this may destroy the image. Also, be aware that
|
||||
querying an image that is being modified by another process may encounter
|
||||
inconsistent state.
|
||||
@c man end
|
||||
|
||||
@c man begin OPTIONS
|
||||
|
||||
The following commands are supported:
|
||||
@@ -159,6 +169,24 @@ It can be used without an accessible old backing file, i.e. you can use it to
|
||||
fix an image whose backing file has already been moved/renamed.
|
||||
@end table
|
||||
|
||||
You can use @code{rebase} to perform a ``diff'' operation on two
|
||||
disk images. This can be useful when you have copied or cloned
|
||||
a guest, and you want to get back to a thin image on top of a
|
||||
template or base image.
|
||||
|
||||
Say that @code{base.img} has been cloned as @code{modified.img} by
|
||||
copying it, and that the @code{modified.img} guest has run so there
|
||||
are now some changes compared to @code{base.img}. To construct a thin
|
||||
image called @code{diff.qcow2} that contains just the differences, do:
|
||||
|
||||
@example
|
||||
qemu-img create -f qcow2 -b modified.img diff.qcow2
|
||||
qemu-img rebase -b base.img diff.qcow2
|
||||
@end example
|
||||
|
||||
At this point, @code{modified.img} can be discarded, since
|
||||
@code{base.img + diff.qcow2} contains the same information.
|
||||
|
||||
@item resize @var{filename} [+ | -]@var{size}
|
||||
|
||||
Change the disk image as if it had been created with @var{size}.
|
||||
@@ -214,6 +242,29 @@ to grow.
|
||||
|
||||
@end table
|
||||
|
||||
@item qed
|
||||
Image format with support for backing files and compact image files (when your
|
||||
filesystem or transport medium does not support holes). Good performance due
|
||||
to less metadata than the more featureful qcow2 format, especially with
|
||||
cache=writethrough or cache=directsync. Consider using qcow2 which will soon
|
||||
have a similar optimization and is most actively developed.
|
||||
|
||||
Supported options:
|
||||
@table @code
|
||||
@item backing_file
|
||||
File name of a base image (see @option{create} subcommand).
|
||||
@item backing_fmt
|
||||
Image file format of backing file (optional). Useful if the format cannot be
|
||||
autodetected because it has no header, like some vhd/vpc files.
|
||||
@item cluster_size
|
||||
Changes the cluster size (must be power-of-2 between 4K and 64K). Smaller
|
||||
cluster sizes can improve the image file size whereas larger cluster sizes
|
||||
generally provide better performance.
|
||||
@item table_size
|
||||
Changes the number of clusters per L1/L2 table (must be power-of-2 between 1
|
||||
and 16). There is normally no need to change this value but this option can be
|
||||
used for performance benchmarking.
|
||||
@end table
|
||||
|
||||
@item qcow
|
||||
Old QEMU image format. Left for compatibility.
|
||||
|
||||
+3
-10
@@ -112,14 +112,10 @@ static int64_t qemu_next_alarm_deadline(void)
|
||||
|
||||
static void qemu_rearm_alarm_timer(struct qemu_alarm_timer *t)
|
||||
{
|
||||
int64_t nearest_delta_ns;
|
||||
if (!rt_clock->active_timers &&
|
||||
!vm_clock->active_timers &&
|
||||
!host_clock->active_timers) {
|
||||
return;
|
||||
int64_t nearest_delta_ns = qemu_next_alarm_deadline();
|
||||
if (nearest_delta_ns < INT64_MAX) {
|
||||
t->rearm(t, nearest_delta_ns);
|
||||
}
|
||||
nearest_delta_ns = qemu_next_alarm_deadline();
|
||||
t->rearm(t, nearest_delta_ns);
|
||||
}
|
||||
|
||||
/* TODO: MIN_TIMER_REARM_NS should be optimized */
|
||||
@@ -763,11 +759,8 @@ int init_timer_alarm(void)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* first event is at time 0 */
|
||||
atexit(quit_timers);
|
||||
t->pending = true;
|
||||
alarm_timer = t;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
|
||||
+86
-108
@@ -14,12 +14,22 @@
|
||||
#include <glib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/wait.h>
|
||||
#include "qga/guest-agent-core.h"
|
||||
#include "qga-qmp-commands.h"
|
||||
#include "qerror.h"
|
||||
#include "qemu-queue.h"
|
||||
#include "host-utils.h"
|
||||
|
||||
#ifndef CONFIG_HAS_ENVIRON
|
||||
#ifdef __APPLE__
|
||||
#include <crt_externs.h>
|
||||
#define environ (*_NSGetEnviron())
|
||||
#else
|
||||
extern char **environ;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <mntent.h>
|
||||
#include <linux/fs.h>
|
||||
@@ -27,36 +37,17 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#if defined(__linux__) && defined(FIFREEZE)
|
||||
#define CONFIG_FSFREEZE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__linux__)
|
||||
/* TODO: use this in place of all post-fork() fclose(std*) callers */
|
||||
static void reopen_fd_to_null(int fd)
|
||||
{
|
||||
int nullfd;
|
||||
|
||||
nullfd = open("/dev/null", O_RDWR);
|
||||
if (nullfd < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
dup2(nullfd, fd);
|
||||
|
||||
if (nullfd != fd) {
|
||||
close(nullfd);
|
||||
}
|
||||
}
|
||||
#endif /* defined(__linux__) */
|
||||
|
||||
void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err)
|
||||
{
|
||||
int ret;
|
||||
const char *shutdown_flag;
|
||||
pid_t rpid, pid;
|
||||
int status;
|
||||
|
||||
slog("guest-shutdown called, mode: %s", mode);
|
||||
if (!has_mode || strcmp(mode, "powerdown") == 0) {
|
||||
@@ -71,23 +62,30 @@ void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err)
|
||||
return;
|
||||
}
|
||||
|
||||
ret = fork();
|
||||
if (ret == 0) {
|
||||
pid = fork();
|
||||
if (pid == 0) {
|
||||
/* child, start the shutdown */
|
||||
setsid();
|
||||
fclose(stdin);
|
||||
fclose(stdout);
|
||||
fclose(stderr);
|
||||
reopen_fd_to_null(0);
|
||||
reopen_fd_to_null(1);
|
||||
reopen_fd_to_null(2);
|
||||
|
||||
ret = execl("/sbin/shutdown", "shutdown", shutdown_flag, "+0",
|
||||
"hypervisor initiated shutdown", (char*)NULL);
|
||||
if (ret) {
|
||||
slog("guest-shutdown failed: %s", strerror(errno));
|
||||
}
|
||||
exit(!!ret);
|
||||
} else if (ret < 0) {
|
||||
error_set(err, QERR_UNDEFINED_ERROR);
|
||||
execle("/sbin/shutdown", "shutdown", shutdown_flag, "+0",
|
||||
"hypervisor initiated shutdown", (char*)NULL, environ);
|
||||
_exit(EXIT_FAILURE);
|
||||
} else if (pid < 0) {
|
||||
goto exit_err;
|
||||
}
|
||||
|
||||
do {
|
||||
rpid = waitpid(pid, &status, 0);
|
||||
} while (rpid == -1 && errno == EINTR);
|
||||
if (rpid == pid && WIFEXITED(status) && !WEXITSTATUS(status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
exit_err:
|
||||
error_set(err, QERR_UNDEFINED_ERROR);
|
||||
}
|
||||
|
||||
typedef struct GuestFileHandle {
|
||||
@@ -347,7 +345,7 @@ static int guest_fsfreeze_build_mount_list(GuestFsfreezeMountList *mounts)
|
||||
{
|
||||
struct mntent *ment;
|
||||
GuestFsfreezeMount *mount;
|
||||
char const *mtab = MOUNTED;
|
||||
char const *mtab = "/proc/self/mounts";
|
||||
FILE *fp;
|
||||
|
||||
fp = setmntent(mtab, "r");
|
||||
@@ -531,117 +529,88 @@ static void guest_fsfreeze_cleanup(void)
|
||||
#define SUSPEND_SUPPORTED 0
|
||||
#define SUSPEND_NOT_SUPPORTED 1
|
||||
|
||||
/**
|
||||
* This function forks twice and the information about the mode support
|
||||
* status is passed to the qemu-ga process via a pipe.
|
||||
*
|
||||
* This approach allows us to keep the way we reap terminated children
|
||||
* in qemu-ga quite simple.
|
||||
*/
|
||||
static void bios_supports_mode(const char *pmutils_bin, const char *pmutils_arg,
|
||||
const char *sysfile_str, Error **err)
|
||||
{
|
||||
pid_t pid;
|
||||
ssize_t ret;
|
||||
char *pmutils_path;
|
||||
int status, pipefds[2];
|
||||
|
||||
if (pipe(pipefds) < 0) {
|
||||
error_set(err, QERR_UNDEFINED_ERROR);
|
||||
return;
|
||||
}
|
||||
pid_t pid, rpid;
|
||||
int status;
|
||||
|
||||
pmutils_path = g_find_program_in_path(pmutils_bin);
|
||||
|
||||
pid = fork();
|
||||
if (!pid) {
|
||||
struct sigaction act;
|
||||
|
||||
memset(&act, 0, sizeof(act));
|
||||
act.sa_handler = SIG_DFL;
|
||||
sigaction(SIGCHLD, &act, NULL);
|
||||
char buf[32]; /* hopefully big enough */
|
||||
ssize_t ret;
|
||||
int fd;
|
||||
|
||||
setsid();
|
||||
close(pipefds[0]);
|
||||
reopen_fd_to_null(0);
|
||||
reopen_fd_to_null(1);
|
||||
reopen_fd_to_null(2);
|
||||
|
||||
pid = fork();
|
||||
if (!pid) {
|
||||
int fd;
|
||||
char buf[32]; /* hopefully big enough */
|
||||
if (pmutils_path) {
|
||||
execle(pmutils_path, pmutils_bin, pmutils_arg, NULL, environ);
|
||||
}
|
||||
|
||||
if (pmutils_path) {
|
||||
execle(pmutils_path, pmutils_bin, pmutils_arg, NULL, environ);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we get here either pm-utils is not installed or execle() has
|
||||
* failed. Let's try the manual method if the caller wants it.
|
||||
*/
|
||||
|
||||
if (!sysfile_str) {
|
||||
_exit(SUSPEND_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
fd = open(LINUX_SYS_STATE_FILE, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
_exit(SUSPEND_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
ret = read(fd, buf, sizeof(buf)-1);
|
||||
if (ret <= 0) {
|
||||
_exit(SUSPEND_NOT_SUPPORTED);
|
||||
}
|
||||
buf[ret] = '\0';
|
||||
|
||||
if (strstr(buf, sysfile_str)) {
|
||||
_exit(SUSPEND_SUPPORTED);
|
||||
}
|
||||
/*
|
||||
* If we get here either pm-utils is not installed or execle() has
|
||||
* failed. Let's try the manual method if the caller wants it.
|
||||
*/
|
||||
|
||||
if (!sysfile_str) {
|
||||
_exit(SUSPEND_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
if (pid > 0) {
|
||||
wait(&status);
|
||||
} else {
|
||||
status = SUSPEND_NOT_SUPPORTED;
|
||||
fd = open(LINUX_SYS_STATE_FILE, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
_exit(SUSPEND_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
ret = write(pipefds[1], &status, sizeof(status));
|
||||
if (ret != sizeof(status)) {
|
||||
_exit(EXIT_FAILURE);
|
||||
ret = read(fd, buf, sizeof(buf)-1);
|
||||
if (ret <= 0) {
|
||||
_exit(SUSPEND_NOT_SUPPORTED);
|
||||
}
|
||||
buf[ret] = '\0';
|
||||
|
||||
if (strstr(buf, sysfile_str)) {
|
||||
_exit(SUSPEND_SUPPORTED);
|
||||
}
|
||||
|
||||
_exit(EXIT_SUCCESS);
|
||||
_exit(SUSPEND_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
close(pipefds[1]);
|
||||
g_free(pmutils_path);
|
||||
|
||||
if (pid < 0) {
|
||||
error_set(err, QERR_UNDEFINED_ERROR);
|
||||
goto out;
|
||||
goto undef_err;
|
||||
}
|
||||
|
||||
ret = read(pipefds[0], &status, sizeof(status));
|
||||
if (ret == sizeof(status) && WIFEXITED(status) &&
|
||||
WEXITSTATUS(status) == SUSPEND_SUPPORTED) {
|
||||
goto out;
|
||||
do {
|
||||
rpid = waitpid(pid, &status, 0);
|
||||
} while (rpid == -1 && errno == EINTR);
|
||||
if (rpid == pid && WIFEXITED(status)) {
|
||||
switch (WEXITSTATUS(status)) {
|
||||
case SUSPEND_SUPPORTED:
|
||||
return;
|
||||
case SUSPEND_NOT_SUPPORTED:
|
||||
error_set(err, QERR_UNSUPPORTED);
|
||||
return;
|
||||
default:
|
||||
goto undef_err;
|
||||
}
|
||||
}
|
||||
|
||||
error_set(err, QERR_UNSUPPORTED);
|
||||
|
||||
out:
|
||||
close(pipefds[0]);
|
||||
undef_err:
|
||||
error_set(err, QERR_UNDEFINED_ERROR);
|
||||
}
|
||||
|
||||
static void guest_suspend(const char *pmutils_bin, const char *sysfile_str,
|
||||
Error **err)
|
||||
{
|
||||
pid_t pid;
|
||||
char *pmutils_path;
|
||||
pid_t rpid, pid;
|
||||
int status;
|
||||
|
||||
pmutils_path = g_find_program_in_path(pmutils_bin);
|
||||
|
||||
@@ -683,9 +652,18 @@ static void guest_suspend(const char *pmutils_bin, const char *sysfile_str,
|
||||
g_free(pmutils_path);
|
||||
|
||||
if (pid < 0) {
|
||||
error_set(err, QERR_UNDEFINED_ERROR);
|
||||
goto exit_err;
|
||||
}
|
||||
|
||||
do {
|
||||
rpid = waitpid(pid, &status, 0);
|
||||
} while (rpid == -1 && errno == EINTR);
|
||||
if (rpid == pid && WIFEXITED(status) && !WEXITSTATUS(status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
exit_err:
|
||||
error_set(err, QERR_UNDEFINED_ERROR);
|
||||
}
|
||||
|
||||
void qmp_guest_suspend_disk(Error **err)
|
||||
|
||||
+1
-1
@@ -52,7 +52,7 @@ struct GuestAgentInfo *qmp_guest_info(Error **err)
|
||||
GuestAgentCommandInfoList *cmd_info_list;
|
||||
char **cmd_list_head, **cmd_list;
|
||||
|
||||
info->version = g_strdup(QGA_VERSION);
|
||||
info->version = g_strdup(QEMU_VERSION);
|
||||
|
||||
cmd_list_head = cmd_list = qmp_get_command_list();
|
||||
if (*cmd_list_head == NULL) {
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include "qapi/qmp-core.h"
|
||||
#include "qemu-common.h"
|
||||
|
||||
#define QGA_VERSION "1.0"
|
||||
#define QGA_READ_COUNT_DEFAULT 4096
|
||||
|
||||
typedef struct GAState GAState;
|
||||
@@ -35,3 +34,7 @@ void ga_set_response_delimited(GAState *s);
|
||||
bool ga_is_frozen(GAState *s);
|
||||
void ga_set_frozen(GAState *s);
|
||||
void ga_unset_frozen(GAState *s);
|
||||
|
||||
#ifndef _WIN32
|
||||
void reopen_fd_to_null(int fd);
|
||||
#endif
|
||||
@@ -124,6 +124,19 @@ int qlist_empty(const QList *qlist)
|
||||
return QTAILQ_EMPTY(&qlist->head);
|
||||
}
|
||||
|
||||
static void qlist_size_iter(QObject *obj, void *opaque)
|
||||
{
|
||||
size_t *count = opaque;
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
size_t qlist_size(const QList *qlist)
|
||||
{
|
||||
size_t count = 0;
|
||||
qlist_iter(qlist, qlist_size_iter, &count);
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* qobject_to_qlist(): Convert a QObject into a QList
|
||||
*/
|
||||
|
||||
@@ -49,6 +49,7 @@ void qlist_iter(const QList *qlist,
|
||||
QObject *qlist_pop(QList *qlist);
|
||||
QObject *qlist_peek(QList *qlist);
|
||||
int qlist_empty(const QList *qlist);
|
||||
size_t qlist_size(const QList *qlist);
|
||||
QList *qobject_to_qlist(const QObject *obj);
|
||||
|
||||
static inline const QListEntry *qlist_first(const QList *qlist)
|
||||
|
||||
+2
-3
@@ -347,8 +347,6 @@ static void object_deinit(Object *obj, TypeImpl *type)
|
||||
if (type_has_parent(type)) {
|
||||
object_deinit(obj, type_get_parent(type));
|
||||
}
|
||||
|
||||
object_unparent(obj);
|
||||
}
|
||||
|
||||
void object_finalize(void *data)
|
||||
@@ -385,8 +383,9 @@ Object *object_new(const char *typename)
|
||||
|
||||
void object_delete(Object *obj)
|
||||
{
|
||||
object_unparent(obj);
|
||||
g_assert(obj->ref == 1);
|
||||
object_unref(obj);
|
||||
g_assert(obj->ref == 0);
|
||||
g_free(obj);
|
||||
}
|
||||
|
||||
|
||||
@@ -337,6 +337,9 @@ static void readline_completion(ReadLineState *rs)
|
||||
}
|
||||
readline_show_prompt(rs);
|
||||
}
|
||||
for (i = 0; i < rs->nb_completions; i++) {
|
||||
g_free(rs->completions[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* return true if command handled */
|
||||
|
||||
+1
-1
Submodule roms/openbios updated: ff61d973e5...d1d2787f87.
Loaded 100 of 137 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user