* [Qemu-devel] [PATCH 01/15] pseries: Split xics irq configuration from state information
2012-10-15 0:24 [Qemu-devel] RFC: savevm/migration support for pseries David Gibson
@ 2012-10-15 0:24 ` David Gibson
2012-10-15 0:24 ` [Qemu-devel] [PATCH 02/15] target-pcc: Convert ppcemb_tlb_t to use fixed 64-bit RPN David Gibson
` (13 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: David Gibson @ 2012-10-15 0:24 UTC (permalink / raw)
To: agraf, quintela; +Cc: qemu-ppc, qemu-devel, David Gibson
Currently the XICS irq controller code has a per-irq state structure which
amongst other things includes whether the interrupt is level or message
triggered - this is configured by the platform code, and is not directly
visible to the guest. This leads to a slightly awkward construct at reset
time where we need to reset everything in the state structure _except_ the
lsi/msi flag, which needs to retain the information given at platform init
time.
More importantly this flag will make matching the qemu state to the KVM
state for the upcoming in-kernel XICS implementation more awkward. This
patch, therefore, removes this flag from the per-irq state structure,
instead adding a parallel array giving the lsi/msi configuration per irq.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
hw/xics.c | 20 ++++++++------------
1 file changed, 8 insertions(+), 12 deletions(-)
diff --git a/hw/xics.c b/hw/xics.c
index 403afdb..5e20f0f 100644
--- a/hw/xics.c
+++ b/hw/xics.c
@@ -179,13 +179,13 @@ struct ics_irq_state {
#define XICS_STATUS_REJECTED 0x4
#define XICS_STATUS_MASKED_PENDING 0x8
uint8_t status;
- bool lsi;
};
struct ics_state {
int nr_irqs;
int offset;
qemu_irq *qirqs;
+ bool *islsi;
struct ics_irq_state *irqs;
struct icp_state *icp;
};
@@ -254,9 +254,8 @@ static void set_irq_lsi(struct ics_state *ics, int srcno, int val)
static void ics_set_irq(void *opaque, int srcno, int val)
{
struct ics_state *ics = (struct ics_state *)opaque;
- struct ics_irq_state *irq = ics->irqs + srcno;
- if (irq->lsi) {
+ if (ics->islsi[srcno]) {
set_irq_lsi(ics, srcno, val);
} else {
set_irq_msi(ics, srcno, val);
@@ -293,7 +292,7 @@ static void ics_write_xive(struct ics_state *ics, int nr, int server,
trace_xics_ics_write_xive(nr, srcno, server, priority);
- if (irq->lsi) {
+ if (ics->islsi[srcno]) {
write_xive_lsi(ics, srcno);
} else {
write_xive_msi(ics, srcno);
@@ -314,10 +313,8 @@ static void ics_resend(struct ics_state *ics)
int i;
for (i = 0; i < ics->nr_irqs; i++) {
- struct ics_irq_state *irq = ics->irqs + i;
-
/* FIXME: filter by server#? */
- if (irq->lsi) {
+ if (ics->islsi[i]) {
resend_lsi(ics, i);
} else {
resend_msi(ics, i);
@@ -332,7 +329,7 @@ static void ics_eoi(struct ics_state *ics, int nr)
trace_xics_ics_eoi(nr);
- if (irq->lsi) {
+ if (ics->islsi[srcno]) {
irq->status &= ~XICS_STATUS_SENT;
}
}
@@ -354,7 +351,7 @@ void xics_set_irq_type(struct icp_state *icp, int irq, bool lsi)
{
assert(ics_valid_irq(icp->ics, irq));
- icp->ics->irqs[irq - icp->ics->offset].lsi = lsi;
+ icp->ics->islsi[irq - icp->ics->offset] = lsi;
}
static target_ulong h_cppr(CPUPPCState *env, sPAPREnvironment *spapr,
@@ -515,10 +512,8 @@ static void xics_reset(void *opaque)
qemu_set_irq(icp->ss[i].output, 0);
}
+ memset(ics->irqs, 0, sizeof(struct ics_irq_state) * ics->nr_irqs);
for (i = 0; i < ics->nr_irqs; i++) {
- /* Reset everything *except* the type */
- ics->irqs[i].server = 0;
- ics->irqs[i].status = 0;
ics->irqs[i].priority = 0xff;
ics->irqs[i].saved_priority = 0xff;
}
@@ -559,6 +554,7 @@ struct icp_state *xics_system_init(int nr_servers, int nr_irqs)
ics->nr_irqs = nr_irqs;
ics->offset = XICS_IRQ_BASE;
ics->irqs = g_malloc0(nr_irqs * sizeof(struct ics_irq_state));
+ ics->islsi = g_malloc0(nr_irqs * sizeof(bool));
icp->ics = ics;
ics->icp = icp;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 02/15] target-pcc: Convert ppcemb_tlb_t to use fixed 64-bit RPN
2012-10-15 0:24 [Qemu-devel] RFC: savevm/migration support for pseries David Gibson
2012-10-15 0:24 ` [Qemu-devel] [PATCH 01/15] pseries: Split xics irq configuration from state information David Gibson
@ 2012-10-15 0:24 ` David Gibson
2012-10-15 0:24 ` [Qemu-devel] [PATCH 03/15] savevm: Add VMSTATE_UINT64_EQUAL helpers David Gibson
` (12 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: David Gibson @ 2012-10-15 0:24 UTC (permalink / raw)
To: agraf, quintela; +Cc: qemu-ppc, qemu-devel, David Gibson
Currently the ppcemb_tlb_t struct, used on a number of embedded ppc models
to represent a TLB entry contains a target_phys_addr_t. That works
reasonably for now, but is troublesome for saving the state, which we'll
want to do in future. target_phys_addr_t is a large enough type to contain
a physical address for any supported machine - and can thus, in theory at
least, vary depending on what machines are enabled other than the one
we're actually using right now. This makes it unsuitable for describing
in vmstate.
This patch therefore changes ppcemb_tlb_t to use a fixed 64-bit integer
which we know is sufficient for all the machines which use this structure.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
target-ppc/cpu.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index cde6da0..f30e0c7 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -355,7 +355,7 @@ struct ppc6xx_tlb_t {
typedef struct ppcemb_tlb_t ppcemb_tlb_t;
struct ppcemb_tlb_t {
- target_phys_addr_t RPN;
+ uint64_t RPN;
target_ulong EPN;
target_ulong PID;
target_ulong size;
--
1.7.10.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 03/15] savevm: Add VMSTATE_UINT64_EQUAL helpers
2012-10-15 0:24 [Qemu-devel] RFC: savevm/migration support for pseries David Gibson
2012-10-15 0:24 ` [Qemu-devel] [PATCH 01/15] pseries: Split xics irq configuration from state information David Gibson
2012-10-15 0:24 ` [Qemu-devel] [PATCH 02/15] target-pcc: Convert ppcemb_tlb_t to use fixed 64-bit RPN David Gibson
@ 2012-10-15 0:24 ` David Gibson
2012-10-15 0:24 ` [Qemu-devel] [PATCH 04/15] savevm: Add VMSTATE_UINTTL_EQUAL helper David Gibson
` (11 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: David Gibson @ 2012-10-15 0:24 UTC (permalink / raw)
To: agraf, quintela; +Cc: qemu-ppc, qemu-devel, David Gibson
The savevm code already includes a number of *_EQUAL helpers which act as
sanity checks verifying that the configuration of the saved state matches
that of the machine we're loading into to work. Variants already exist
for 8 bit 16 bit and 32 bit integers, but not 64 bit integers. This patch
fills that hole, adding a UINT64 version.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
v2: Added missing braces
---
savevm.c | 21 +++++++++++++++++++++
vmstate.h | 7 +++++++
2 files changed, 28 insertions(+)
diff --git a/savevm.c b/savevm.c
index 31fd2e0..fcbc706 100644
--- a/savevm.c
+++ b/savevm.c
@@ -1043,6 +1043,27 @@ const VMStateInfo vmstate_info_uint64 = {
.put = put_uint64,
};
+/* 64 bit unsigned int. See that the received value is the same than the one
+ in the field */
+
+static int get_uint64_equal(QEMUFile *f, void *pv, size_t size)
+{
+ uint64_t *v = pv;
+ uint64_t v2;
+ qemu_get_be64s(f, &v2);
+
+ if (*v == v2) {
+ return 0;
+ }
+ return -EINVAL;
+}
+
+const VMStateInfo vmstate_info_uint64_equal = {
+ .name = "int64 equal",
+ .get = get_uint64_equal,
+ .put = put_uint64,
+};
+
/* 8 bit int. See that the received value is the same than the one
in the field */
diff --git a/vmstate.h b/vmstate.h
index c9c320e..6c7fbe0 100644
--- a/vmstate.h
+++ b/vmstate.h
@@ -129,6 +129,7 @@ extern const VMStateInfo vmstate_info_uint8_equal;
extern const VMStateInfo vmstate_info_uint16_equal;
extern const VMStateInfo vmstate_info_int32_equal;
extern const VMStateInfo vmstate_info_uint32_equal;
+extern const VMStateInfo vmstate_info_uint64_equal;
extern const VMStateInfo vmstate_info_int32_le;
extern const VMStateInfo vmstate_info_uint8;
@@ -488,6 +489,12 @@ extern const VMStateInfo vmstate_info_unused_buffer;
#define VMSTATE_UINT32_EQUAL(_f, _s) \
VMSTATE_SINGLE(_f, _s, 0, vmstate_info_uint32_equal, uint32_t)
+#define VMSTATE_UINT64_EQUAL_V(_f, _s, _v) \
+ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint64_equal, uint64_t)
+
+#define VMSTATE_UINT64_EQUAL(_f, _s) \
+ VMSTATE_UINT64_EQUAL_V(_f, _s, 0)
+
#define VMSTATE_INT32_LE(_f, _s) \
VMSTATE_SINGLE(_f, _s, 0, vmstate_info_int32_le, int32_t)
--
1.7.10.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 04/15] savevm: Add VMSTATE_UINTTL_EQUAL helper
2012-10-15 0:24 [Qemu-devel] RFC: savevm/migration support for pseries David Gibson
` (2 preceding siblings ...)
2012-10-15 0:24 ` [Qemu-devel] [PATCH 03/15] savevm: Add VMSTATE_UINT64_EQUAL helpers David Gibson
@ 2012-10-15 0:24 ` David Gibson
2012-10-15 0:24 ` [Qemu-devel] [PATCH 05/15] savevm: Add VMSTATE_FLOAT64 helpers David Gibson
` (10 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: David Gibson @ 2012-10-15 0:24 UTC (permalink / raw)
To: agraf, quintela; +Cc: qemu-ppc, qemu-devel, David Gibson
This adds an _EQUAL VMSTATE helper for target_ulongs, defined in terms of
VMSTATE_UINT32_EQUAL or VMSTATE_UINT64_EQUAL as appropriate.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
hw/hw.h | 6 ++++++
vmstate.h | 7 +++++--
2 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/hw/hw.h b/hw/hw.h
index 16101de..b727b0e 100644
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -50,16 +50,22 @@ int qemu_boot_set(const char *boot_devices);
#if TARGET_LONG_BITS == 64
#define VMSTATE_UINTTL_V(_f, _s, _v) \
VMSTATE_UINT64_V(_f, _s, _v)
+#define VMSTATE_UINTTL_EQUAL_V(_f, _s, _v) \
+ VMSTATE_UINT64_EQUAL_V(_f, _s, _v)
#define VMSTATE_UINTTL_ARRAY_V(_f, _s, _n, _v) \
VMSTATE_UINT64_ARRAY_V(_f, _s, _n, _v)
#else
#define VMSTATE_UINTTL_V(_f, _s, _v) \
VMSTATE_UINT32_V(_f, _s, _v)
+#define VMSTATE_UINTTL_EQUAL_V(_f, _s, _v) \
+ VMSTATE_UINT32_EQUAL_V(_f, _s, _v)
#define VMSTATE_UINTTL_ARRAY_V(_f, _s, _n, _v) \
VMSTATE_UINT32_ARRAY_V(_f, _s, _n, _v)
#endif
#define VMSTATE_UINTTL(_f, _s) \
VMSTATE_UINTTL_V(_f, _s, 0)
+#define VMSTATE_UINTTL_EQUAL(_f, _s) \
+ VMSTATE_UINTTL_EQUAL_V(_f, _s, 0)
#define VMSTATE_UINTTL_ARRAY(_f, _s, _n) \
VMSTATE_UINTTL_ARRAY_V(_f, _s, _n, 0)
diff --git a/vmstate.h b/vmstate.h
index 6c7fbe0..5d1c4f5 100644
--- a/vmstate.h
+++ b/vmstate.h
@@ -486,8 +486,11 @@ extern const VMStateInfo vmstate_info_unused_buffer;
#define VMSTATE_INT32_EQUAL(_f, _s) \
VMSTATE_SINGLE(_f, _s, 0, vmstate_info_int32_equal, int32_t)
-#define VMSTATE_UINT32_EQUAL(_f, _s) \
- VMSTATE_SINGLE(_f, _s, 0, vmstate_info_uint32_equal, uint32_t)
+#define VMSTATE_UINT32_EQUAL_V(_f, _s, _v) \
+ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint32_equal, uint32_t)
+
+#define VMSTATE_UINT32_EQUAL(_f, _s) \
+ VMSTATE_UINT32_EQUAL_V(_f, _s, 0)
#define VMSTATE_UINT64_EQUAL_V(_f, _s, _v) \
VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint64_equal, uint64_t)
--
1.7.10.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 05/15] savevm: Add VMSTATE_FLOAT64 helpers
2012-10-15 0:24 [Qemu-devel] RFC: savevm/migration support for pseries David Gibson
` (3 preceding siblings ...)
2012-10-15 0:24 ` [Qemu-devel] [PATCH 04/15] savevm: Add VMSTATE_UINTTL_EQUAL helper David Gibson
@ 2012-10-15 0:24 ` David Gibson
2012-10-15 0:24 ` [Qemu-devel] [PATCH 06/15] savevm: Add VMSTATE_STRUCT_VARRAY_POINTER_UINT32 David Gibson
` (9 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: David Gibson @ 2012-10-15 0:24 UTC (permalink / raw)
To: agraf, quintela; +Cc: qemu-ppc, qemu-devel, David Gibson
The current savevm code includes VMSTATE helpers for a number of commonly
used data types, but not for the float64 type used by the internal floating
point emulation code. This patch fixes the deficiency.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
savevm.c | 23 +++++++++++++++++++++++
vmstate.h | 15 +++++++++++++++
2 files changed, 38 insertions(+)
diff --git a/savevm.c b/savevm.c
index fcbc706..02e9da0 100644
--- a/savevm.c
+++ b/savevm.c
@@ -1104,6 +1104,29 @@ const VMStateInfo vmstate_info_uint16_equal = {
.put = put_uint16,
};
+/* floating point */
+
+static int get_float64(QEMUFile *f, void *pv, size_t size)
+{
+ float64 *v = pv;
+
+ *v = make_float64(qemu_get_be64(f));
+ return 0;
+}
+
+static void put_float64(QEMUFile *f, void *pv, size_t size)
+{
+ uint64_t *v = pv;
+
+ qemu_put_be64(f, float64_val(*v));
+}
+
+const VMStateInfo vmstate_info_float64 = {
+ .name = "float64",
+ .get = get_float64,
+ .put = put_float64,
+};
+
/* timers */
static int get_timer(QEMUFile *f, void *pv, size_t size)
diff --git a/vmstate.h b/vmstate.h
index 5d1c4f5..a04561e 100644
--- a/vmstate.h
+++ b/vmstate.h
@@ -137,6 +137,8 @@ extern const VMStateInfo vmstate_info_uint16;
extern const VMStateInfo vmstate_info_uint32;
extern const VMStateInfo vmstate_info_uint64;
+extern const VMStateInfo vmstate_info_float64;
+
extern const VMStateInfo vmstate_info_timer;
extern const VMStateInfo vmstate_info_buffer;
extern const VMStateInfo vmstate_info_unused_buffer;
@@ -510,6 +512,13 @@ extern const VMStateInfo vmstate_info_unused_buffer;
#define VMSTATE_UINT32_TEST(_f, _s, _t) \
VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_uint32, uint32_t)
+
+#define VMSTATE_FLOAT64_V(_f, _s, _v) \
+ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_float64, float64)
+
+#define VMSTATE_FLOAT64(_f, _s) \
+ VMSTATE_FLOAT64_V(_f, _s, 0)
+
#define VMSTATE_TIMER_TEST(_f, _s, _test) \
VMSTATE_POINTER_TEST(_f, _s, _test, vmstate_info_timer, QEMUTimer *)
@@ -576,6 +585,12 @@ extern const VMStateInfo vmstate_info_unused_buffer;
#define VMSTATE_INT64_ARRAY(_f, _s, _n) \
VMSTATE_INT64_ARRAY_V(_f, _s, _n, 0)
+#define VMSTATE_FLOAT64_ARRAY_V(_f, _s, _n, _v) \
+ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_float64, float64)
+
+#define VMSTATE_FLOAT64_ARRAY(_f, _s, _n) \
+ VMSTATE_FLOAT64_ARRAY_V(_f, _s, _n, 0)
+
#define VMSTATE_BUFFER_V(_f, _s, _v) \
VMSTATE_STATIC_BUFFER(_f, _s, _v, NULL, 0, sizeof(typeof_field(_s, _f)))
--
1.7.10.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 06/15] savevm: Add VMSTATE_STRUCT_VARRAY_POINTER_UINT32
2012-10-15 0:24 [Qemu-devel] RFC: savevm/migration support for pseries David Gibson
` (4 preceding siblings ...)
2012-10-15 0:24 ` [Qemu-devel] [PATCH 05/15] savevm: Add VMSTATE_FLOAT64 helpers David Gibson
@ 2012-10-15 0:24 ` David Gibson
2012-10-15 0:24 ` [Qemu-devel] [PATCH 07/15] savevm: Fix bugs in the VMSTATE_VBUFFER_MULTIPLY definition David Gibson
` (8 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: David Gibson @ 2012-10-15 0:24 UTC (permalink / raw)
To: agraf, quintela; +Cc: qemu-ppc, qemu-devel, David Gibson
Currently the savevm code contains a VMSTATE_STRUCT_VARRAY_POINTER_INT32
helper (a variably sized array with the number of elements in an int32_t),
but not VMSTATE_STRUCT_VARRAY_POINTER_UINT32 (... with the number of
elements in a uint32_t). This patch (trivially) fixes the deficiency.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
vmstate.h | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/vmstate.h b/vmstate.h
index a04561e..4b393a0 100644
--- a/vmstate.h
+++ b/vmstate.h
@@ -322,6 +322,16 @@ extern const VMStateInfo vmstate_info_unused_buffer;
.offset = vmstate_offset_pointer(_state, _field, _type), \
}
+#define VMSTATE_STRUCT_VARRAY_POINTER_UINT32(_field, _state, _field_num, _vmsd, _type) { \
+ .name = (stringify(_field)), \
+ .version_id = 0, \
+ .num_offset = vmstate_offset_value(_state, _field_num, uint32_t),\
+ .size = sizeof(_type), \
+ .vmsd = &(_vmsd), \
+ .flags = VMS_POINTER | VMS_VARRAY_INT32 | VMS_STRUCT, \
+ .offset = vmstate_offset_pointer(_state, _field, _type), \
+}
+
#define VMSTATE_STRUCT_VARRAY_POINTER_UINT16(_field, _state, _field_num, _vmsd, _type) { \
.name = (stringify(_field)), \
.version_id = 0, \
--
1.7.10.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 07/15] savevm: Fix bugs in the VMSTATE_VBUFFER_MULTIPLY definition
2012-10-15 0:24 [Qemu-devel] RFC: savevm/migration support for pseries David Gibson
` (5 preceding siblings ...)
2012-10-15 0:24 ` [Qemu-devel] [PATCH 06/15] savevm: Add VMSTATE_STRUCT_VARRAY_POINTER_UINT32 David Gibson
@ 2012-10-15 0:24 ` David Gibson
2012-10-15 0:24 ` [Qemu-devel] [PATCH 08/15] savevm: Implement VMS_DIVIDE flag David Gibson
` (7 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: David Gibson @ 2012-10-15 0:24 UTC (permalink / raw)
To: agraf, quintela; +Cc: qemu-ppc, qemu-devel, David Gibson
The VMSTATE_BUFFER_MULTIPLY macro is misnamed - it actually specifies
a variably sized buffer with VMS_VBUFFER, so should be named
VMSTATE_VBUFFER_MULTIPLY. This patch fixes this (the macro had no current
users under either name).
In addition, unlike the other VMSTATE_VBUFFER variants, this macro did not
specify VMS_POINTER. This patch fixes this bug as well.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
vmstate.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/vmstate.h b/vmstate.h
index 4b393a0..6bfdb6a 100644
--- a/vmstate.h
+++ b/vmstate.h
@@ -372,14 +372,14 @@ extern const VMStateInfo vmstate_info_unused_buffer;
.offset = vmstate_offset_buffer(_state, _field) + _start, \
}
-#define VMSTATE_BUFFER_MULTIPLY(_field, _state, _version, _test, _start, _field_size, _multiply) { \
+#define VMSTATE_VBUFFER_MULTIPLY(_field, _state, _version, _test, _start, _field_size, _multiply) { \
.name = (stringify(_field)), \
.version_id = (_version), \
.field_exists = (_test), \
.size_offset = vmstate_offset_value(_state, _field_size, uint32_t),\
.size = (_multiply), \
.info = &vmstate_info_buffer, \
- .flags = VMS_VBUFFER|VMS_MULTIPLY, \
+ .flags = VMS_VBUFFER|VMS_POINTER|VMS_MULTIPLY, \
.offset = offsetof(_state, _field), \
.start = (_start), \
}
--
1.7.10.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 08/15] savevm: Implement VMS_DIVIDE flag
2012-10-15 0:24 [Qemu-devel] RFC: savevm/migration support for pseries David Gibson
` (6 preceding siblings ...)
2012-10-15 0:24 ` [Qemu-devel] [PATCH 07/15] savevm: Fix bugs in the VMSTATE_VBUFFER_MULTIPLY definition David Gibson
@ 2012-10-15 0:24 ` David Gibson
2012-10-15 0:24 ` [Qemu-devel] [PATCH 09/15] target-ppc: Convert ppc cpu savevm to VMStateDescription David Gibson
` (6 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: David Gibson @ 2012-10-15 0:24 UTC (permalink / raw)
To: agraf, quintela; +Cc: qemu-ppc, qemu-devel, David Gibson
The vmstate infrastructure includes a VMS_MULTIPY flag, and associated
VMSTATE_VBUFFER_MULTIPLY helper macro. These can be used to save a
variably sized buffer where the size in bytes of the buffer isn't directly
accessible as a structure field, but an element count from which the size
can be derived is.
This patch adds an analogous VMS_DIVIDE option, which handles a variably
sized buffer whose size is a submultiple of a field, rather than a
multiple. For example a buffer containing per-page structures whose size
is derived from a field storing the total address space described by the
structures could use this construct.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
savevm.c | 8 ++++++++
vmstate.h | 13 +++++++++++++
2 files changed, 21 insertions(+)
diff --git a/savevm.c b/savevm.c
index 02e9da0..d830837 100644
--- a/savevm.c
+++ b/savevm.c
@@ -1460,6 +1460,10 @@ int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
if (field->flags & VMS_MULTIPLY) {
size *= field->size;
}
+ if (field->flags & VMS_DIVIDE) {
+ assert((size % field->size) == 0);
+ size /= field->size;
+ }
}
if (field->flags & VMS_ARRAY) {
n_elems = field->num;
@@ -1524,6 +1528,10 @@ void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
if (field->flags & VMS_MULTIPLY) {
size *= field->size;
}
+ if (field->flags & VMS_DIVIDE) {
+ assert((size % field->size) == 0);
+ size /= field->size;
+ }
}
if (field->flags & VMS_ARRAY) {
n_elems = field->num;
diff --git a/vmstate.h b/vmstate.h
index 6bfdb6a..634dbde 100644
--- a/vmstate.h
+++ b/vmstate.h
@@ -82,6 +82,7 @@ enum VMStateFlags {
VMS_MULTIPLY = 0x200, /* multiply "size" field by field_size */
VMS_VARRAY_UINT8 = 0x400, /* Array with size in uint8_t field*/
VMS_VARRAY_UINT32 = 0x800, /* Array with size in uint32_t field*/
+ VMS_DIVIDE = 0x1000, /* divide "size" field by field_size */
};
typedef struct {
@@ -384,6 +385,18 @@ extern const VMStateInfo vmstate_info_unused_buffer;
.start = (_start), \
}
+#define VMSTATE_VBUFFER_DIVIDE(_field, _state, _version, _test, _start, _field_size, _divide) { \
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .field_exists = (_test), \
+ .size_offset = vmstate_offset_value(_state, _field_size, uint32_t),\
+ .size = (_divide), \
+ .info = &vmstate_info_buffer, \
+ .flags = VMS_VBUFFER|VMS_POINTER|VMS_DIVIDE, \
+ .offset = offsetof(_state, _field), \
+ .start = (_start), \
+}
+
#define VMSTATE_VBUFFER(_field, _state, _version, _test, _start, _field_size) { \
.name = (stringify(_field)), \
.version_id = (_version), \
--
1.7.10.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 09/15] target-ppc: Convert ppc cpu savevm to VMStateDescription
2012-10-15 0:24 [Qemu-devel] RFC: savevm/migration support for pseries David Gibson
` (7 preceding siblings ...)
2012-10-15 0:24 ` [Qemu-devel] [PATCH 08/15] savevm: Implement VMS_DIVIDE flag David Gibson
@ 2012-10-15 0:24 ` David Gibson
2012-10-15 0:24 ` [Qemu-devel] [PATCH 10/15] pseries: savevm support for XICS interrupt controller David Gibson
` (5 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: David Gibson @ 2012-10-15 0:24 UTC (permalink / raw)
To: agraf, quintela; +Cc: qemu-ppc, qemu-devel, David Gibson
The savevm code for the powerpc cpu emulation is currently based around
the old register_savevm() rather than register_vmstate() method. It's also
rather broken, missing some important state on some CPU models.
This patch completely rewrites the savevm for target-ppc, using the new
VMStateDescription approach. Exactly what needs to be saved in what
configurations has been more carefully examined, too. This introduces a
new version (5) of the cpu save format. The old load function is retained
to support version 4 images.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Conflicts:
target-ppc/machine.c
---
target-ppc/cpu.h | 9 +-
target-ppc/machine.c | 543 ++++++++++++++++++++++++++++++++++++++++++--------
2 files changed, 462 insertions(+), 90 deletions(-)
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index f30e0c7..c6c01d1 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -980,7 +980,7 @@ struct CPUPPCState {
target_ulong asr;
/* PowerPC 64 SLB area */
ppc_slb_t slb[64];
- int slb_nr;
+ int32_t slb_nr;
#endif
/* segment registers */
target_phys_addr_t htab_base;
@@ -989,11 +989,11 @@ struct CPUPPCState {
/* externally stored hash table */
uint8_t *external_htab;
/* BATs */
- int nb_BATs;
+ uint32_t nb_BATs;
target_ulong DBAT[2][8];
target_ulong IBAT[2][8];
/* PowerPC TLB registers (for 4xx, e500 and 60x software driven TLBs) */
- int nb_tlb; /* Total number of TLB */
+ int32_t nb_tlb; /* Total number of TLB */
int tlb_per_way; /* Speed-up helper: used to avoid divisions at run time */
int nb_ways; /* Number of ways in the TLB set */
int last_way; /* Last used way used to allocate TLB in a LRU way */
@@ -1010,6 +1010,7 @@ struct CPUPPCState {
/* Other registers */
/* Special purpose registers */
target_ulong spr[1024];
+ uint32_t cr; /* Full CR value used during vmsave/load */
ppc_spr_t spr_cb[1024];
/* Altivec registers */
ppc_avr_t avr[32];
@@ -1237,7 +1238,7 @@ static inline CPUPPCState *cpu_init(const char *cpu_model)
#define cpu_signal_handler cpu_ppc_signal_handler
#define cpu_list ppc_cpu_list
-#define CPU_SAVE_VERSION 4
+#define CPU_SAVE_VERSION 5
/* MMU modes definitions */
#define MMU_MODE0_SUFFIX _user
diff --git a/target-ppc/machine.c b/target-ppc/machine.c
index 5e7bc00..90617d3 100644
--- a/target-ppc/machine.c
+++ b/target-ppc/machine.c
@@ -1,93 +1,9 @@
#include "hw/hw.h"
#include "hw/boards.h"
#include "kvm.h"
+#include "helper_regs.h"
-void cpu_save(QEMUFile *f, void *opaque)
-{
- CPUPPCState *env = (CPUPPCState *)opaque;
- unsigned int i, j;
- uint32_t fpscr;
-
- for (i = 0; i < 32; i++)
- qemu_put_betls(f, &env->gpr[i]);
-#if !defined(TARGET_PPC64)
- for (i = 0; i < 32; i++)
- qemu_put_betls(f, &env->gprh[i]);
-#endif
- qemu_put_betls(f, &env->lr);
- qemu_put_betls(f, &env->ctr);
- for (i = 0; i < 8; i++)
- qemu_put_be32s(f, &env->crf[i]);
- qemu_put_betls(f, &env->xer);
- qemu_put_betls(f, &env->reserve_addr);
- qemu_put_betls(f, &env->msr);
- for (i = 0; i < 4; i++)
- qemu_put_betls(f, &env->tgpr[i]);
- for (i = 0; i < 32; i++) {
- union {
- float64 d;
- uint64_t l;
- } u;
- u.d = env->fpr[i];
- qemu_put_be64(f, u.l);
- }
- fpscr = env->fpscr;
- qemu_put_be32s(f, &fpscr);
- qemu_put_sbe32s(f, &env->access_type);
-#if defined(TARGET_PPC64)
- qemu_put_betls(f, &env->asr);
- qemu_put_sbe32s(f, &env->slb_nr);
-#endif
- qemu_put_betls(f, &env->spr[SPR_SDR1]);
- for (i = 0; i < 32; i++)
- qemu_put_betls(f, &env->sr[i]);
- for (i = 0; i < 2; i++)
- for (j = 0; j < 8; j++)
- qemu_put_betls(f, &env->DBAT[i][j]);
- for (i = 0; i < 2; i++)
- for (j = 0; j < 8; j++)
- qemu_put_betls(f, &env->IBAT[i][j]);
- qemu_put_sbe32s(f, &env->nb_tlb);
- qemu_put_sbe32s(f, &env->tlb_per_way);
- qemu_put_sbe32s(f, &env->nb_ways);
- qemu_put_sbe32s(f, &env->last_way);
- qemu_put_sbe32s(f, &env->id_tlbs);
- qemu_put_sbe32s(f, &env->nb_pids);
- if (env->tlb.tlb6) {
- // XXX assumes 6xx
- for (i = 0; i < env->nb_tlb; i++) {
- qemu_put_betls(f, &env->tlb.tlb6[i].pte0);
- qemu_put_betls(f, &env->tlb.tlb6[i].pte1);
- qemu_put_betls(f, &env->tlb.tlb6[i].EPN);
- }
- }
- for (i = 0; i < 4; i++)
- qemu_put_betls(f, &env->pb[i]);
- for (i = 0; i < 1024; i++)
- qemu_put_betls(f, &env->spr[i]);
- qemu_put_be32s(f, &env->vscr);
- qemu_put_be64s(f, &env->spe_acc);
- qemu_put_be32s(f, &env->spe_fscr);
- qemu_put_betls(f, &env->msr_mask);
- qemu_put_be32s(f, &env->flags);
- qemu_put_sbe32s(f, &env->error_code);
- qemu_put_be32s(f, &env->pending_interrupts);
- qemu_put_be32s(f, &env->irq_input_state);
- for (i = 0; i < POWERPC_EXCP_NB; i++)
- qemu_put_betls(f, &env->excp_vectors[i]);
- qemu_put_betls(f, &env->excp_prefix);
- qemu_put_betls(f, &env->hreset_excp_prefix);
- qemu_put_betls(f, &env->ivor_mask);
- qemu_put_betls(f, &env->ivpr_mask);
- qemu_put_betls(f, &env->hreset_vector);
- qemu_put_betls(f, &env->nip);
- qemu_put_betls(f, &env->hflags);
- qemu_put_betls(f, &env->hflags_nmsr);
- qemu_put_sbe32s(f, &env->mmu_idx);
- qemu_put_sbe32(f, 0);
-}
-
-int cpu_load(QEMUFile *f, void *opaque, int version_id)
+static int cpu_load_old(QEMUFile *f, void *opaque, int version_id)
{
CPUPPCState *env = (CPUPPCState *)opaque;
unsigned int i, j;
@@ -175,3 +91,458 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
return 0;
}
+
+static int get_avr(QEMUFile *f, void *pv, size_t size)
+{
+ ppc_avr_t *v = pv;
+
+ v->u64[0] = qemu_get_be64(f);
+ v->u64[1] = qemu_get_be64(f);
+
+ return 0;
+}
+
+static void put_avr(QEMUFile *f, void *pv, size_t size)
+{
+ ppc_avr_t *v = pv;
+
+ qemu_put_be64(f, v->u64[0]);
+ qemu_put_be64(f, v->u64[1]);
+}
+
+const VMStateInfo vmstate_info_avr = {
+ .name = "avr",
+ .get = get_avr,
+ .put = put_avr,
+};
+
+#define VMSTATE_AVR_ARRAY_V(_f, _s, _n, _v) \
+ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_avr, ppc_avr_t)
+
+#define VMSTATE_AVR_ARRAY(_f, _s, _n) \
+ VMSTATE_AVR_ARRAY_V(_f, _s, _n, 0)
+
+static void cpu_pre_save(void *opaque)
+{
+ CPUPPCState *env = opaque;
+ int i;
+
+ env->spr[SPR_LR] = env->lr;
+ env->spr[SPR_CTR] = env->ctr;
+ env->spr[SPR_XER] = env->xer;
+#if defined(TARGET_PPC64)
+ env->spr[SPR_CFAR] = env->cfar;
+ env->spr[SPR_ASR] = env->asr;
+#endif
+ env->spr[SPR_BOOKE_SPEFSCR] = env->spe_fscr;
+
+ env->cr = 0;
+ for (i = 0; i < 8; i++) {
+ env->cr = (env->cr << 4) | (env->crf[i] & 0xf);
+ }
+
+ for (i = 0; (i < 4) && (i < env->nb_BATs); i++) {
+ env->spr[SPR_DBAT0U + 2*i] = env->DBAT[0][i];
+ env->spr[SPR_DBAT0U + 2*i + 1] = env->DBAT[1][i];
+ env->spr[SPR_IBAT0U + 2*i] = env->IBAT[0][i];
+ env->spr[SPR_IBAT0U + 2*i + 1] = env->IBAT[1][i];
+ }
+ for (i = 0; (i < 4) && ((i+4) < env->nb_BATs); i++) {
+ env->spr[SPR_DBAT4U + 2*i] = env->DBAT[0][i+4];
+ env->spr[SPR_DBAT4U + 2*i + 1] = env->DBAT[1][i+4];
+ env->spr[SPR_IBAT4U + 2*i] = env->IBAT[0][i+4];
+ env->spr[SPR_IBAT4U + 2*i + 1] = env->IBAT[1][i+4];
+ }
+}
+
+static int cpu_post_load(void *opaque, int version_id)
+{
+ CPUPPCState *env = opaque;
+ int i;
+
+ env->lr = env->spr[SPR_LR];
+ env->ctr = env->spr[SPR_CTR];
+ env->xer = env->spr[SPR_XER];
+#if defined(TARGET_PPC64)
+ env->cfar = env->spr[SPR_CFAR];
+ env->asr = env->spr[SPR_ASR];
+#endif
+ env->spe_fscr = env->spr[SPR_BOOKE_SPEFSCR];
+
+ for (i = 0; i < 8; i++) {
+ env->crf[i] = env->cr >> (4*(7-i)) & 0xf;
+ }
+
+ for (i = 0; (i < 4) && (i < env->nb_BATs); i++) {
+ env->DBAT[0][i] = env->spr[SPR_DBAT0U + 2*i];
+ env->DBAT[1][i] = env->spr[SPR_DBAT0U + 2*i + 1];
+ env->IBAT[0][i] = env->spr[SPR_IBAT0U + 2*i];
+ env->IBAT[1][i] = env->spr[SPR_IBAT0U + 2*i + 1];
+ }
+ for (i = 0; (i < 4) && ((i+4) < env->nb_BATs); i++) {
+ env->DBAT[0][i+4] = env->spr[SPR_DBAT4U + 2*i];
+ env->DBAT[1][i+4] = env->spr[SPR_DBAT4U + 2*i + 1];
+ env->IBAT[0][i+4] = env->spr[SPR_IBAT4U + 2*i];
+ env->IBAT[1][i+4] = env->spr[SPR_IBAT4U + 2*i + 1];
+ }
+
+ /* Restore htab_base and htab_mask variables */
+ ppc_store_sdr1(env, env->spr[SPR_SDR1]);
+
+ hreg_compute_hflags(env);
+ hreg_compute_mem_idx(env);
+
+ return 0;
+}
+
+static bool fpu_needed(void *opaque)
+{
+ CPUPPCState *env = opaque;
+
+ return (env->insns_flags & PPC_FLOAT);
+}
+
+static const VMStateDescription vmstate_fpu = {
+ .name = "cpu/fpu",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_FLOAT64_ARRAY(fpr, CPUPPCState, 32),
+ VMSTATE_UINTTL(fpscr, CPUPPCState),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static bool altivec_needed(void *opaque)
+{
+ CPUPPCState *env = opaque;
+
+ return (env->insns_flags & PPC_ALTIVEC);
+}
+
+static const VMStateDescription vmstate_altivec = {
+ .name = "cpu/altivec",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_AVR_ARRAY(avr, CPUPPCState, 32),
+ VMSTATE_UINT32(vscr, CPUPPCState),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static bool vsx_needed(void *opaque)
+{
+ CPUPPCState *env = opaque;
+
+ return (env->insns_flags2 & PPC2_VSX);
+}
+
+static const VMStateDescription vmstate_vsx = {
+ .name = "cpu/vsx",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT64_ARRAY(vsr, CPUPPCState, 32),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static bool sr_needed(void *opaque)
+{
+#ifdef TARGET_PPC64
+ CPUPPCState *env = opaque;
+
+ return !(env->mmu_model & POWERPC_MMU_64);
+#else
+ return true;
+#endif
+}
+
+static const VMStateDescription vmstate_sr = {
+ .name = "cpu/sr",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_UINTTL_ARRAY(sr, CPUPPCState, 32),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+#ifdef TARGET_PPC64
+static int get_slbe(QEMUFile *f, void *pv, size_t size)
+{
+ ppc_slb_t *v = pv;
+
+ v->esid = qemu_get_be64(f);
+ v->vsid = qemu_get_be64(f);
+
+ return 0;
+}
+
+static void put_slbe(QEMUFile *f, void *pv, size_t size)
+{
+ ppc_slb_t *v = pv;
+
+ qemu_put_be64(f, v->esid);
+ qemu_put_be64(f, v->vsid);
+}
+
+const VMStateInfo vmstate_info_slbe = {
+ .name = "slbe",
+ .get = get_slbe,
+ .put = put_slbe,
+};
+
+#define VMSTATE_SLB_ARRAY_V(_f, _s, _n, _v) \
+ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_slbe, ppc_slb_t)
+
+#define VMSTATE_SLB_ARRAY(_f, _s, _n) \
+ VMSTATE_SLB_ARRAY_V(_f, _s, _n, 0)
+
+static bool slb_needed(void *opaque)
+{
+ CPUPPCState *env = opaque;
+
+ /* We don't support any of the old segment table based 64-bit CPUs */
+ return (env->mmu_model & POWERPC_MMU_64);
+}
+
+static const VMStateDescription vmstate_slb = {
+ .name = "cpu/slb",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_INT32_EQUAL(slb_nr, CPUPPCState),
+ VMSTATE_SLB_ARRAY(slb, CPUPPCState, 64),
+ VMSTATE_END_OF_LIST()
+ }
+};
+#endif /* TARGET_PPC64 */
+
+static const VMStateDescription vmstate_tlb6xx_entry = {
+ .name = "cpu/tlb6xx_entry",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_UINTTL(pte0, ppc6xx_tlb_t),
+ VMSTATE_UINTTL(pte1, ppc6xx_tlb_t),
+ VMSTATE_UINTTL(EPN, ppc6xx_tlb_t),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static bool tlb6xx_needed(void *opaque)
+{
+ CPUPPCState *env = opaque;
+
+ return env->nb_tlb && (env->tlb_type == TLB_6XX);
+}
+
+static const VMStateDescription vmstate_tlb6xx = {
+ .name = "cpu/tlb6xx",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_INT32_EQUAL(nb_tlb, CPUPPCState),
+ VMSTATE_STRUCT_VARRAY_POINTER_INT32(tlb.tlb6, CPUPPCState, nb_tlb,
+ vmstate_tlb6xx_entry,
+ ppc6xx_tlb_t),
+ VMSTATE_UINTTL_ARRAY(tgpr, CPUPPCState, 4),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_tlbemb_entry = {
+ .name = "cpu/tlbemb_entry",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT64(RPN, ppcemb_tlb_t),
+ VMSTATE_UINTTL(EPN, ppcemb_tlb_t),
+ VMSTATE_UINTTL(PID, ppcemb_tlb_t),
+ VMSTATE_UINTTL(size, ppcemb_tlb_t),
+ VMSTATE_UINT32(prot, ppcemb_tlb_t),
+ VMSTATE_UINT32(attr, ppcemb_tlb_t),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static bool tlbemb_needed(void *opaque)
+{
+ CPUPPCState *env = opaque;
+
+ return env->nb_tlb && (env->tlb_type == TLB_EMB);
+}
+
+static bool pbr403_needed(void *opaque)
+{
+ CPUPPCState *env = opaque;
+ uint32_t pvr = env->spr[SPR_PVR];
+
+ return (pvr & 0xffff0000) == 0x00200000;
+}
+
+static const VMStateDescription vmstate_pbr403 = {
+ .name = "cpu/pbr403",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_UINTTL_ARRAY(pb, CPUPPCState, 4),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static const VMStateDescription vmstate_tlbemb = {
+ .name = "cpu/tlb6xx",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_INT32_EQUAL(nb_tlb, CPUPPCState),
+ VMSTATE_STRUCT_VARRAY_POINTER_INT32(tlb.tlbe, CPUPPCState, nb_tlb,
+ vmstate_tlbemb_entry,
+ ppcemb_tlb_t),
+ /* 403 protection registers */
+ VMSTATE_END_OF_LIST()
+ },
+ .subsections = (VMStateSubsection []) {
+ {
+ .vmsd = &vmstate_pbr403,
+ .needed = pbr403_needed,
+ } , {
+ /* empty */
+ }
+ }
+};
+
+static const VMStateDescription vmstate_tlbmas_entry = {
+ .name = "cpu/tlbmas_entry",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT32(mas8, ppcmas_tlb_t),
+ VMSTATE_UINT32(mas1, ppcmas_tlb_t),
+ VMSTATE_UINT64(mas2, ppcmas_tlb_t),
+ VMSTATE_UINT64(mas7_3, ppcmas_tlb_t),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static bool tlbmas_needed(void *opaque)
+{
+ CPUPPCState *env = opaque;
+
+ return env->nb_tlb && (env->tlb_type == TLB_MAS);
+}
+
+static const VMStateDescription vmstate_tlbmas = {
+ .name = "cpu/tlbmas",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_INT32_EQUAL(nb_tlb, CPUPPCState),
+ VMSTATE_STRUCT_VARRAY_POINTER_INT32(tlb.tlbm, CPUPPCState, nb_tlb,
+ vmstate_tlbmas_entry,
+ ppcmas_tlb_t),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_cpu = {
+ .name = "cpu",
+ .version_id = CPU_SAVE_VERSION,
+ .minimum_version_id = 5,
+ .minimum_version_id_old = 4,
+ .load_state_old = cpu_load_old,
+ .pre_save = cpu_pre_save,
+ .post_load = cpu_post_load,
+ .fields = (VMStateField []) {
+ /* Verify we haven't changed the pvr */
+ VMSTATE_UINTTL_EQUAL(spr[SPR_PVR], CPUPPCState),
+
+ /* User mode architected state */
+ VMSTATE_UINTTL_ARRAY(gpr, CPUPPCState, 32),
+#if !defined(TARGET_PPC64)
+ VMSTATE_UINTTL_ARRAY(gprh, CPUPPCState, 32),
+#endif
+ VMSTATE_UINT32(cr, CPUPPCState),
+ VMSTATE_UINTTL(nip, CPUPPCState),
+
+ /* SPRs */
+ VMSTATE_UINTTL_ARRAY(spr, CPUPPCState, 1024),
+ VMSTATE_UINT64(spe_acc, CPUPPCState),
+
+ /* Reservation */
+ VMSTATE_UINTTL(reserve_addr, CPUPPCState),
+
+ /* Supervisor mode architected state */
+ VMSTATE_UINTTL(msr, CPUPPCState),
+
+ /* Internal state */
+ VMSTATE_UINTTL(hflags_nmsr, CPUPPCState),
+ /* FIXME: access_type? */
+
+ /* Sanity checking */
+ VMSTATE_UINTTL_EQUAL(msr_mask, CPUPPCState),
+ VMSTATE_UINT64_EQUAL(insns_flags, CPUPPCState),
+ VMSTATE_UINT64_EQUAL(insns_flags2, CPUPPCState),
+ VMSTATE_UINT32_EQUAL(nb_BATs, CPUPPCState),
+ VMSTATE_END_OF_LIST()
+ },
+ .subsections = (VMStateSubsection []) {
+ {
+ .vmsd = &vmstate_fpu,
+ .needed = fpu_needed,
+ } , {
+ .vmsd = &vmstate_altivec,
+ .needed = altivec_needed,
+ } , {
+ .vmsd = &vmstate_vsx,
+ .needed = vsx_needed,
+ } , {
+ .vmsd = &vmstate_sr,
+ .needed = sr_needed,
+ } , {
+#ifdef TARGET_PPC64
+ .vmsd = &vmstate_slb,
+ .needed = slb_needed,
+ } , {
+#endif /* TARGET_PPC64 */
+ .vmsd = &vmstate_tlb6xx,
+ .needed = tlb6xx_needed,
+ } , {
+ .vmsd = &vmstate_tlbemb,
+ .needed = tlbemb_needed,
+ } , {
+ .vmsd = &vmstate_tlbmas,
+ .needed = tlbmas_needed,
+ } , {
+ /* FIXME: DCRs? */
+ /* FIXME: timebase? */
+ /* empty */
+ }
+ }
+};
+
+void cpu_save(QEMUFile *f, void *opaque)
+{
+ vmstate_save_state(f, &vmstate_cpu, opaque);
+
+}
+
+int cpu_load(QEMUFile *f, void *opaque, int version_id)
+{
+ return vmstate_load_state(f, &vmstate_cpu, opaque, version_id);
+}
--
1.7.10.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 10/15] pseries: savevm support for XICS interrupt controller
2012-10-15 0:24 [Qemu-devel] RFC: savevm/migration support for pseries David Gibson
` (8 preceding siblings ...)
2012-10-15 0:24 ` [Qemu-devel] [PATCH 09/15] target-ppc: Convert ppc cpu savevm to VMStateDescription David Gibson
@ 2012-10-15 0:24 ` David Gibson
2012-10-15 0:24 ` [Qemu-devel] [PATCH 11/15] pseries: savevm support for VIO devices David Gibson
` (4 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: David Gibson @ 2012-10-15 0:24 UTC (permalink / raw)
To: agraf, quintela; +Cc: qemu-ppc, qemu-devel, David Gibson
This patch adds the necessary VMStateDescription information to allow
savevm/loadvm for the XICS interrupt controller.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
hw/xics.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 53 insertions(+), 4 deletions(-)
diff --git a/hw/xics.c b/hw/xics.c
index 5e20f0f..c4dcde5 100644
--- a/hw/xics.c
+++ b/hw/xics.c
@@ -50,7 +50,7 @@ struct icp_server_state {
struct ics_state;
struct icp_state {
- long nr_servers;
+ uint32_t nr_servers;
struct icp_server_state *ss;
struct ics_state *ics;
};
@@ -171,7 +171,7 @@ static void icp_irq(struct icp_state *icp, int server, int nr, uint8_t priority)
*/
struct ics_irq_state {
- int server;
+ uint32_t server;
uint8_t priority;
uint8_t saved_priority;
#define XICS_STATUS_ASSERTED 0x1
@@ -182,8 +182,8 @@ struct ics_irq_state {
};
struct ics_state {
- int nr_irqs;
- int offset;
+ uint32_t nr_irqs;
+ uint32_t offset;
qemu_irq *qirqs;
bool *islsi;
struct ics_irq_state *irqs;
@@ -519,6 +519,48 @@ static void xics_reset(void *opaque)
}
}
+static const VMStateDescription vmstate_icp_server = {
+ .name = "icp/server",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ /* Sanity check */
+ VMSTATE_UINT32(xirr, struct icp_server_state),
+ VMSTATE_UINT8(pending_priority, struct icp_server_state),
+ VMSTATE_UINT8(mfrr, struct icp_server_state),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static const VMStateDescription vmstate_ics_irq = {
+ .name = "ics/irq",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT32(server, struct ics_irq_state),
+ VMSTATE_UINT8(priority, struct ics_irq_state),
+ VMSTATE_UINT8(saved_priority, struct ics_irq_state),
+ VMSTATE_UINT8(status, struct ics_irq_state),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static const VMStateDescription vmstate_ics = {
+ .name = "ics",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ /* Sanity check */
+ VMSTATE_UINT32_EQUAL(nr_irqs, struct ics_state),
+
+ VMSTATE_STRUCT_VARRAY_POINTER_UINT32(irqs, struct ics_state, nr_irqs, vmstate_ics_irq, struct ics_irq_state),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
void xics_cpu_setup(struct icp_state *icp, CPUPPCState *env)
{
struct icp_server_state *ss = &icp->ss[env->cpu_index];
@@ -539,6 +581,8 @@ void xics_cpu_setup(struct icp_state *icp, CPUPPCState *env)
"bus model\n");
abort();
}
+
+ vmstate_register(NULL, env->cpu_index, &vmstate_icp_server, ss);
}
struct icp_state *xics_system_init(int nr_servers, int nr_irqs)
@@ -573,5 +617,10 @@ struct icp_state *xics_system_init(int nr_servers, int nr_irqs)
qemu_register_reset(xics_reset, icp);
+ /* We use each the ICS's offset into the global irq number space
+ * as an instance id. This means we can extend to multiple ICS
+ * instances without needing to change the savevm format */
+ vmstate_register(NULL, ics->offset, &vmstate_ics, ics);
+
return icp;
}
--
1.7.10.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 11/15] pseries: savevm support for VIO devices
2012-10-15 0:24 [Qemu-devel] RFC: savevm/migration support for pseries David Gibson
` (9 preceding siblings ...)
2012-10-15 0:24 ` [Qemu-devel] [PATCH 10/15] pseries: savevm support for XICS interrupt controller David Gibson
@ 2012-10-15 0:24 ` David Gibson
2012-10-15 0:24 ` [Qemu-devel] [PATCH 12/15] pseries: savevm support for PAPR VIO logical lan David Gibson
` (3 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: David Gibson @ 2012-10-15 0:24 UTC (permalink / raw)
To: agraf, quintela; +Cc: qemu-ppc, qemu-devel, David Gibson
This patch adds helpers to allow PAPR VIO devices to save state common
to all VIO devices during savevm.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
hw/spapr_vio.c | 20 ++++++++++++++++++++
hw/spapr_vio.h | 5 +++++
2 files changed, 25 insertions(+)
diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
index 848806d..acb2ba9 100644
--- a/hw/spapr_vio.c
+++ b/hw/spapr_vio.c
@@ -543,6 +543,26 @@ static TypeInfo spapr_vio_bridge_info = {
.class_init = spapr_vio_bridge_class_init,
};
+const VMStateDescription vmstate_spapr_vio = {
+ .name = "spapr_vio",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ /* Sanity check */
+ VMSTATE_UINT32_EQUAL(reg, VIOsPAPRDevice),
+ VMSTATE_UINT32_EQUAL(irq, VIOsPAPRDevice),
+
+ /* General VIO device state */
+ VMSTATE_UINTTL(signal_state, VIOsPAPRDevice),
+ VMSTATE_UINT64(crq.qladdr, VIOsPAPRDevice),
+ VMSTATE_UINT32(crq.qsize, VIOsPAPRDevice),
+ VMSTATE_UINT32(crq.qnext, VIOsPAPRDevice),
+
+ VMSTATE_END_OF_LIST()
+ },
+};
+
static void vio_spapr_device_class_init(ObjectClass *klass, void *data)
{
DeviceClass *k = DEVICE_CLASS(klass);
diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h
index cc85d26..ad8d271 100644
--- a/hw/spapr_vio.h
+++ b/hw/spapr_vio.h
@@ -133,4 +133,9 @@ VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus);
void spapr_vio_quiesce(void);
+extern const VMStateDescription vmstate_spapr_vio;
+
+#define VMSTATE_SPAPR_VIO(_f, _s) \
+ VMSTATE_STRUCT(_f, _s, 0, vmstate_spapr_vio, VIOsPAPRDevice)
+
#endif /* _HW_SPAPR_VIO_H */
--
1.7.10.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 12/15] pseries: savevm support for PAPR VIO logical lan
2012-10-15 0:24 [Qemu-devel] RFC: savevm/migration support for pseries David Gibson
` (10 preceding siblings ...)
2012-10-15 0:24 ` [Qemu-devel] [PATCH 11/15] pseries: savevm support for VIO devices David Gibson
@ 2012-10-15 0:24 ` David Gibson
2012-10-15 0:24 ` [Qemu-devel] [PATCH 13/15] pseries: savevm support for PAPR TCE tables David Gibson
` (2 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: David Gibson @ 2012-10-15 0:24 UTC (permalink / raw)
To: agraf, quintela; +Cc: qemu-ppc, qemu-devel, David Gibson
This patch adds the necessary VMStateDescription information to support
savevm/loadvm for the spapr_llan (PAPR logical lan) device.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
hw/spapr_llan.c | 24 ++++++++++++++++++++++--
hw/spapr_vty.c | 16 ++++++++++++++++
2 files changed, 38 insertions(+), 2 deletions(-)
diff --git a/hw/spapr_llan.c b/hw/spapr_llan.c
index bd3f131..cd30df8 100644
--- a/hw/spapr_llan.c
+++ b/hw/spapr_llan.c
@@ -77,9 +77,9 @@ typedef struct VIOsPAPRVLANDevice {
VIOsPAPRDevice sdev;
NICConf nicconf;
NICState *nic;
- int isopen;
+ bool isopen;
target_ulong buf_list;
- int add_buf_ptr, use_buf_ptr, rx_bufs;
+ uint32_t add_buf_ptr, use_buf_ptr, rx_bufs;
target_ulong rxq_ptr;
} VIOsPAPRVLANDevice;
@@ -486,6 +486,25 @@ static Property spapr_vlan_properties[] = {
DEFINE_PROP_END_OF_LIST(),
};
+static const VMStateDescription vmstate_spapr_llan = {
+ .name = "spapr_llan",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_SPAPR_VIO(sdev, VIOsPAPRVLANDevice),
+ /* LLAN state */
+ VMSTATE_BOOL(isopen, VIOsPAPRVLANDevice),
+ VMSTATE_UINTTL(buf_list, VIOsPAPRVLANDevice),
+ VMSTATE_UINT32(add_buf_ptr, VIOsPAPRVLANDevice),
+ VMSTATE_UINT32(use_buf_ptr, VIOsPAPRVLANDevice),
+ VMSTATE_UINT32(rx_bufs, VIOsPAPRVLANDevice),
+ VMSTATE_UINTTL(rxq_ptr, VIOsPAPRVLANDevice),
+
+ VMSTATE_END_OF_LIST()
+ },
+};
+
static void spapr_vlan_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -500,6 +519,7 @@ static void spapr_vlan_class_init(ObjectClass *klass, void *data)
k->signal_mask = 0x1;
dc->props = spapr_vlan_properties;
k->rtce_window_size = 0x10000000;
+ dc->vmsd = &vmstate_spapr_llan;
}
static TypeInfo spapr_vlan_info = {
diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c
index 5da17a3..5b36301 100644
--- a/hw/spapr_vty.c
+++ b/hw/spapr_vty.c
@@ -138,6 +138,21 @@ static Property spapr_vty_properties[] = {
DEFINE_PROP_END_OF_LIST(),
};
+static const VMStateDescription vmstate_spapr_vty = {
+ .name = "spapr_vty",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_SPAPR_VIO(sdev, VIOsPAPRVTYDevice),
+
+ VMSTATE_UINT32(in, VIOsPAPRVTYDevice),
+ VMSTATE_UINT32(out, VIOsPAPRVTYDevice),
+ VMSTATE_BUFFER(buf, VIOsPAPRVTYDevice),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
static void spapr_vty_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -148,6 +163,7 @@ static void spapr_vty_class_init(ObjectClass *klass, void *data)
k->dt_type = "serial";
k->dt_compatible = "hvterm1";
dc->props = spapr_vty_properties;
+ dc->vmsd = &vmstate_spapr_vty;
}
static TypeInfo spapr_vty_info = {
--
1.7.10.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 13/15] pseries: savevm support for PAPR TCE tables
2012-10-15 0:24 [Qemu-devel] RFC: savevm/migration support for pseries David Gibson
` (11 preceding siblings ...)
2012-10-15 0:24 ` [Qemu-devel] [PATCH 12/15] pseries: savevm support for PAPR VIO logical lan David Gibson
@ 2012-10-15 0:24 ` David Gibson
2012-10-15 0:24 ` [Qemu-devel] [PATCH 14/15] pseries: savevm support for PAPR virtual SCSI David Gibson
2012-10-15 0:24 ` [Qemu-devel] [PATCH 15/15] pseries: savevm support for pseries machine David Gibson
14 siblings, 0 replies; 16+ messages in thread
From: David Gibson @ 2012-10-15 0:24 UTC (permalink / raw)
To: agraf, quintela; +Cc: qemu-ppc, qemu-devel, David Gibson
This patch adds the necessary VMStateDescription information to save the
state of PAPR TCE tables (that is, the PAPR specified IOMMU).
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
hw/spapr_iommu.c | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/hw/spapr_iommu.c b/hw/spapr_iommu.c
index 38034c0..29e76eb 100644
--- a/hw/spapr_iommu.c
+++ b/hw/spapr_iommu.c
@@ -115,6 +115,26 @@ static int spapr_tce_translate(DMAContext *dma,
return 0;
}
+static const VMStateDescription vmstate_spapr_tce_table = {
+ .name = "spapr_iommu",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ /* Sanity check */
+ VMSTATE_UINT32_EQUAL(liobn, sPAPRTCETable),
+ VMSTATE_UINT32_EQUAL(window_size, sPAPRTCETable),
+
+ /* IOMMU state */
+ VMSTATE_BOOL(bypass, sPAPRTCETable),
+ VMSTATE_VBUFFER_DIVIDE(table, sPAPRTCETable, 0, NULL, 0, window_size,
+ SPAPR_TCE_PAGE_SIZE / sizeof(sPAPRTCE)),
+
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+
DMAContext *spapr_tce_new_dma_context(uint32_t liobn, size_t window_size)
{
sPAPRTCETable *tcet;
@@ -148,6 +168,8 @@ DMAContext *spapr_tce_new_dma_context(uint32_t liobn, size_t window_size)
QLIST_INSERT_HEAD(&spapr_tce_tables, tcet, list);
+ vmstate_register(NULL, tcet->liobn, &vmstate_spapr_tce_table, tcet);
+
return &tcet->dma;
}
@@ -157,6 +179,8 @@ void spapr_tce_free(DMAContext *dma)
if (dma) {
sPAPRTCETable *tcet = DO_UPCAST(sPAPRTCETable, dma, dma);
+ vmstate_unregister(NULL, &vmstate_spapr_tce_table, tcet);
+
QLIST_REMOVE(tcet, list);
if (!kvm_enabled() ||
--
1.7.10.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 14/15] pseries: savevm support for PAPR virtual SCSI
2012-10-15 0:24 [Qemu-devel] RFC: savevm/migration support for pseries David Gibson
` (12 preceding siblings ...)
2012-10-15 0:24 ` [Qemu-devel] [PATCH 13/15] pseries: savevm support for PAPR TCE tables David Gibson
@ 2012-10-15 0:24 ` David Gibson
2012-10-15 0:24 ` [Qemu-devel] [PATCH 15/15] pseries: savevm support for pseries machine David Gibson
14 siblings, 0 replies; 16+ messages in thread
From: David Gibson @ 2012-10-15 0:24 UTC (permalink / raw)
To: agraf, quintela; +Cc: qemu-ppc, qemu-devel, David Gibson
This patch adds the necessary support for saving the state of the PAPR VIO
virtual SCSI device. This turns out to be trivial, because the generiC
SCSI code already quiesces the attached virtual SCSI bus.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
hw/spapr_vscsi.c | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c
index e3d4b23..8c81326 100644
--- a/hw/spapr_vscsi.c
+++ b/hw/spapr_vscsi.c
@@ -952,6 +952,33 @@ static Property spapr_vscsi_properties[] = {
DEFINE_PROP_END_OF_LIST(),
};
+static void spapr_vscsi_pre_save(void *opaque)
+{
+ VSCSIState *s = opaque;
+ int i;
+
+ /* Can't save active requests, apparently the general SCSI code
+ * quiesces the queue for us on vmsave */
+ for (i = 0; i < VSCSI_REQ_LIMIT; i++) {
+ assert(!s->reqs[i].active);
+ }
+}
+
+static const VMStateDescription vmstate_spapr_vscsi = {
+ .name = "spapr_vscsi",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .pre_save = spapr_vscsi_pre_save,
+ .fields = (VMStateField []) {
+ VMSTATE_SPAPR_VIO(vdev, VSCSIState),
+ /* VSCSI state */
+ /* ???? */
+
+ VMSTATE_END_OF_LIST()
+ },
+};
+
static void spapr_vscsi_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -966,6 +993,7 @@ static void spapr_vscsi_class_init(ObjectClass *klass, void *data)
k->signal_mask = 0x00000001;
dc->props = spapr_vscsi_properties;
k->rtce_window_size = 0x10000000;
+ dc->vmsd = &vmstate_spapr_vscsi;
}
static TypeInfo spapr_vscsi_info = {
--
1.7.10.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [Qemu-devel] [PATCH 15/15] pseries: savevm support for pseries machine
2012-10-15 0:24 [Qemu-devel] RFC: savevm/migration support for pseries David Gibson
` (13 preceding siblings ...)
2012-10-15 0:24 ` [Qemu-devel] [PATCH 14/15] pseries: savevm support for PAPR virtual SCSI David Gibson
@ 2012-10-15 0:24 ` David Gibson
14 siblings, 0 replies; 16+ messages in thread
From: David Gibson @ 2012-10-15 0:24 UTC (permalink / raw)
To: agraf, quintela; +Cc: qemu-ppc, qemu-devel, David Gibson
This adds the necessary pieces to implement savevm / migration for the
pseries machine. The most complex part here is migrating the hash
table - for the paravirtualized pseries machine the guest's hash page
table is not stored within guest memory, but externally and the guest
accesses it via hypercalls.
This patch uses a hypervisor reserved bit of the HPTE as a dirty bit
(tracking changes to the HPTE itself, not the page it references).
This is used to implement a live migration style incremental save and
restore of the hash table contents.
In addition it adds VMStateDescription information to save and restore
the (few) remaining pieces of state information needed by the pseries
machine.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
hw/spapr.c | 268 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
hw/spapr.h | 52 ++++++++++-
hw/spapr_hcall.c | 41 +--------
3 files changed, 319 insertions(+), 42 deletions(-)
diff --git a/hw/spapr.c b/hw/spapr.c
index e8dbd97..2b05fb4 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -648,7 +648,7 @@ static void spapr_cpu_reset(void *opaque)
env->spr[SPR_HIOR] = 0;
- env->external_htab = spapr->htab;
+ env->external_htab = (uint8_t *)spapr->htab;
env->htab_base = -1;
env->htab_mask = HTAB_SIZE(spapr) - 1;
env->spr[SPR_SDR1] = (unsigned long)spapr->htab |
@@ -670,6 +670,268 @@ static int spapr_vga_init(PCIBus *pci_bus)
}
}
+static const VMStateDescription vmstate_spapr = {
+ .name = "spapr",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ /* Sanity check */
+ VMSTATE_UINT32_EQUAL(next_irq, sPAPREnvironment),
+
+ /* RTC offset */
+ VMSTATE_UINT64(rtc_offset, sPAPREnvironment),
+
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+#define HPTE(_table, _i) (void *)(((uint64_t *)(_table)) + ((_i) * 2))
+#define HPTE_VALID(_hpte) (tswap64(*((uint64_t *)(_hpte))) & HPTE_V_VALID)
+#define HPTE_DIRTY(_hpte) (tswap64(*((uint64_t *)(_hpte))) & HPTE_V_HPTE_DIRTY)
+#define CLEAN_HPTE(_hpte) ((*(uint64_t *)(_hpte)) &= tswap64(~HPTE_V_HPTE_DIRTY))
+
+static int htab_save_setup(QEMUFile *f, void *opaque)
+{
+ sPAPREnvironment *spapr = opaque;
+
+ spapr->htab_save_index = 0;
+ spapr->htab_first_pass = true;
+
+ /* "Iteration" header */
+ qemu_put_be32(f, spapr->htab_shift);
+
+ return 0;
+}
+
+#define MAX_ITERATION_NS 5000000 /* 5 ms */
+
+static void htab_save_first_pass(QEMUFile *f, sPAPREnvironment *spapr,
+ int64_t max_ns)
+{
+ int htabslots = HTAB_SIZE(spapr) / HPTE_SIZE;
+ int index = spapr->htab_save_index;
+ int64_t starttime = qemu_get_clock_ns(rt_clock);
+
+ assert(spapr->htab_first_pass);
+
+ do {
+ int chunkstart;
+
+ /* Consume invalid HPTEs */
+ while ((index < htabslots)
+ && !HPTE_VALID(HPTE(spapr->htab, index))) {
+ index++;
+ CLEAN_HPTE(HPTE(spapr->htab, index));
+ }
+
+ /* Consume valid HPTEs */
+ chunkstart = index;
+ while ((index < htabslots)
+ && HPTE_VALID(HPTE(spapr->htab, index))) {
+ index++;
+ CLEAN_HPTE(HPTE(spapr->htab, index));
+ }
+
+ if (index > chunkstart) {
+ int n_valid = index - chunkstart;
+
+ qemu_put_be32(f, chunkstart);
+ qemu_put_be16(f, n_valid);
+ qemu_put_be16(f, 0);
+ qemu_put_buffer(f, HPTE(spapr->htab, chunkstart),
+ HPTE_SIZE * n_valid);
+
+ if ((qemu_get_clock_ns(rt_clock) - starttime) > max_ns) {
+ break;
+ }
+ }
+ } while ((index < htabslots) && !qemu_file_rate_limit(f));
+
+ if (index >= htabslots) {
+ assert(index == htabslots);
+ index = 0;
+ spapr->htab_first_pass = false;
+ }
+ spapr->htab_save_index = index;
+}
+
+static bool htab_save_later_pass(QEMUFile *f, sPAPREnvironment *spapr,
+ int64_t max_ns)
+{
+ bool final = max_ns < 0;
+ int htabslots = HTAB_SIZE(spapr) / HPTE_SIZE;
+ int examined = 0, sent = 0;
+ int index = spapr->htab_save_index;
+ int64_t starttime = qemu_get_clock_ns(rt_clock);
+
+ assert(!spapr->htab_first_pass);
+
+ do {
+ int chunkstart, invalidstart;
+
+ /* Consume non-dirty HPTEs */
+ while ((index < htabslots)
+ && !HPTE_DIRTY(HPTE(spapr->htab, index))) {
+ index++;
+ examined++;
+ }
+
+ chunkstart = index;
+ /* Consume valid dirty HPTEs */
+ while ((index < htabslots)
+ && HPTE_DIRTY(HPTE(spapr->htab, index))
+ && HPTE_VALID(HPTE(spapr->htab, index))) {
+ CLEAN_HPTE(HPTE(spapr->htab, index));
+ index++;
+ examined++;
+ }
+
+ invalidstart = index;
+ /* Consume invalid dirty HPTEs */
+ while ((index < htabslots)
+ && HPTE_DIRTY(HPTE(spapr->htab, index))
+ && !HPTE_VALID(HPTE(spapr->htab, index))) {
+ CLEAN_HPTE(HPTE(spapr->htab, index));
+ index++;
+ examined++;
+ }
+
+ if (index > chunkstart) {
+ int n_valid = invalidstart - chunkstart;
+ int n_invalid = index - invalidstart;
+
+ qemu_put_be32(f, chunkstart);
+ qemu_put_be16(f, n_valid);
+ qemu_put_be16(f, n_invalid);
+ qemu_put_buffer(f, HPTE(spapr->htab, chunkstart),
+ HPTE_SIZE * n_valid);
+ sent += index - chunkstart;
+
+ if (!final && (qemu_get_clock_ns(rt_clock) - starttime) > max_ns) {
+ break;
+ }
+ }
+
+ if (examined >= htabslots) {
+ break;
+ }
+
+ if (index >= htabslots) {
+ assert(index == htabslots);
+ index = 0;
+ }
+ } while ((examined < htabslots) && (!qemu_file_rate_limit(f) || final));
+
+ if (index >= htabslots) {
+ assert(index == htabslots);
+ index = 0;
+ }
+
+ spapr->htab_save_index = index;
+
+ return (examined >= htabslots) && (sent == 0);
+}
+
+static int htab_save_iterate(QEMUFile *f, void *opaque)
+{
+ sPAPREnvironment *spapr = opaque;
+ bool nothingleft = false;;
+
+ /* Iteration header */
+ qemu_put_be32(f, 0);
+
+ if (spapr->htab_first_pass) {
+ htab_save_first_pass(f, spapr, MAX_ITERATION_NS);
+ } else {
+ nothingleft = htab_save_later_pass(f, spapr, MAX_ITERATION_NS);
+ }
+
+ /* End marker */
+ qemu_put_be32(f, 0);
+ qemu_put_be16(f, 0);
+ qemu_put_be16(f, 0);
+
+ return nothingleft ? 1 : 0;
+}
+
+static int htab_save_complete(QEMUFile *f, void *opaque)
+{
+ sPAPREnvironment *spapr = opaque;
+
+ /* Iteration header */
+ qemu_put_be32(f, 0);
+
+ htab_save_later_pass(f, spapr, -1);
+
+ /* End marker */
+ qemu_put_be32(f, 0);
+ qemu_put_be16(f, 0);
+ qemu_put_be16(f, 0);
+
+ return 0;
+}
+
+static int htab_load(QEMUFile *f, void *opaque, int version_id)
+{
+ sPAPREnvironment *spapr = opaque;
+ uint32_t section_hdr;
+
+ if (version_id < 1 || version_id > 1) {
+ fprintf(stderr, "htab_load() bad version\n");
+ return -EINVAL;
+ }
+
+ section_hdr = qemu_get_be32(f);
+
+ if (section_hdr) {
+ /* First section, just the hash shift */
+ if (spapr->htab_shift != section_hdr) {
+ return -EINVAL;
+ }
+ return 0;
+ }
+
+ while (true) {
+ uint32_t index;
+ uint16_t n_valid, n_invalid;
+
+ index = qemu_get_be32(f);
+ n_valid = qemu_get_be16(f);
+ n_invalid = qemu_get_be16(f);
+
+ if ((index == 0) && (n_valid == 0) && (n_invalid == 0)) {
+ /* End of Stream */
+ break;
+ }
+
+ if ((index + n_valid + n_invalid) >=
+ (HTAB_SIZE(spapr) / HASH_PTE_SIZE_64)) {
+ /* Bad index in stream */
+ fprintf(stderr, "htab_load() bad index %d (%hd+%hd entries) "
+ "in htab stream\n", index, n_valid, n_invalid);
+ return -EINVAL;
+ }
+
+ if (n_valid) {
+ qemu_get_buffer(f, HPTE(spapr->htab, index), HPTE_SIZE * n_valid);
+ }
+ if (n_invalid) {
+ memset(HPTE(spapr->htab, index + n_valid), 0,
+ HPTE_SIZE * n_invalid);
+ }
+ }
+
+ return 0;
+}
+
+static SaveVMHandlers savevm_htab_handlers = {
+ .save_live_setup = htab_save_setup,
+ .save_live_iterate = htab_save_iterate,
+ .save_live_complete = htab_save_complete,
+ .load_state = htab_load,
+};
+
/* pSeries LPAR / sPAPR hardware init */
static void ppc_spapr_init(ram_addr_t ram_size,
const char *boot_device,
@@ -910,6 +1172,10 @@ static void ppc_spapr_init(ram_addr_t ram_size,
spapr->entry_point = 0x100;
+ vmstate_register(NULL, 0, &vmstate_spapr, spapr);
+ register_savevm_live(NULL, "spapr/htab", -1, 1,
+ &savevm_htab_handlers, spapr);
+
/* Prepare the device tree */
spapr->fdt_skel = spapr_create_fdt_skel(cpu_model,
initrd_base, initrd_size,
diff --git a/hw/spapr.h b/hw/spapr.h
index f6864da..c306c83 100644
--- a/hw/spapr.h
+++ b/hw/spapr.h
@@ -8,27 +8,71 @@ struct VIOsPAPRBus;
struct sPAPRPHBState;
struct icp_state;
+#define HPTE_SIZE 16
+#define HPTES_PER_GROUP 8
+
+#define HPTE_V_SSIZE_SHIFT 62
+#define HPTE_V_AVPN_SHIFT 7
+#define HPTE_V_AVPN 0x3fffffffffffff80ULL
+#define HPTE_V_AVPN_VAL(x) (((x) & HPTE_V_AVPN) >> HPTE_V_AVPN_SHIFT)
+#define HPTE_V_COMPARE(x, y) (!(((x) ^ (y)) & 0xffffffffffffff80UL))
+#define HPTE_V_BOLTED 0x0000000000000010ULL
+#define HPTE_V_LOCK 0x0000000000000008ULL
+#define HPTE_V_LARGE 0x0000000000000004ULL
+#define HPTE_V_SECONDARY 0x0000000000000002ULL
+#define HPTE_V_VALID 0x0000000000000001ULL
+
+#define HPTE_R_PP0 0x8000000000000000ULL
+#define HPTE_R_TS 0x4000000000000000ULL
+#define HPTE_R_KEY_HI 0x3000000000000000ULL
+#define HPTE_R_RPN_SHIFT 12
+#define HPTE_R_RPN 0x3ffffffffffff000ULL
+#define HPTE_R_FLAGS 0x00000000000003ffULL
+#define HPTE_R_PP 0x0000000000000003ULL
+#define HPTE_R_N 0x0000000000000004ULL
+#define HPTE_R_G 0x0000000000000008ULL
+#define HPTE_R_M 0x0000000000000010ULL
+#define HPTE_R_I 0x0000000000000020ULL
+#define HPTE_R_W 0x0000000000000040ULL
+#define HPTE_R_WIMG 0x0000000000000078ULL
+#define HPTE_R_C 0x0000000000000080ULL
+#define HPTE_R_R 0x0000000000000100ULL
+#define HPTE_R_KEY_LO 0x0000000000000e00ULL
+
+#define HPTE_V_1TB_SEG 0x4000000000000000ULL
+#define HPTE_V_VRMA_MASK 0x4001ffffff000000ULL
+
+#define HPTE_V_HPTE_DIRTY 0x0000000000000040ULL
+
+typedef struct {
+ uint64_t pte0, pte1;
+} HashPTE;
+
typedef struct sPAPREnvironment {
struct VIOsPAPRBus *vio_bus;
QLIST_HEAD(, sPAPRPHBState) phbs;
struct icp_state *icp;
target_phys_addr_t ram_limit;
- void *htab;
- long htab_shift;
+ HashPTE *htab;
+ uint32_t htab_shift;
target_phys_addr_t rma_size;
int vrma_adjust;
target_phys_addr_t fdt_addr, rtas_addr;
long rtas_size;
void *fdt_skel;
target_ulong entry_point;
- int next_irq;
- int rtc_offset;
+ uint32_t next_irq;
+ uint64_t rtc_offset;
char *cpu_model;
bool has_graphics;
uint32_t epow_irq;
Notifier epow_notifier;
+
+ /* Migration state */
+ int htab_save_index;
+ bool htab_first_pass;
} sPAPREnvironment;
#define H_SUCCESS 0
diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c
index 621dabd..0d7675b 100644
--- a/hw/spapr_hcall.c
+++ b/hw/spapr_hcall.c
@@ -6,39 +6,6 @@
#include "helper_regs.h"
#include "hw/spapr.h"
-#define HPTES_PER_GROUP 8
-
-#define HPTE_V_SSIZE_SHIFT 62
-#define HPTE_V_AVPN_SHIFT 7
-#define HPTE_V_AVPN 0x3fffffffffffff80ULL
-#define HPTE_V_AVPN_VAL(x) (((x) & HPTE_V_AVPN) >> HPTE_V_AVPN_SHIFT)
-#define HPTE_V_COMPARE(x, y) (!(((x) ^ (y)) & 0xffffffffffffff80UL))
-#define HPTE_V_BOLTED 0x0000000000000010ULL
-#define HPTE_V_LOCK 0x0000000000000008ULL
-#define HPTE_V_LARGE 0x0000000000000004ULL
-#define HPTE_V_SECONDARY 0x0000000000000002ULL
-#define HPTE_V_VALID 0x0000000000000001ULL
-
-#define HPTE_R_PP0 0x8000000000000000ULL
-#define HPTE_R_TS 0x4000000000000000ULL
-#define HPTE_R_KEY_HI 0x3000000000000000ULL
-#define HPTE_R_RPN_SHIFT 12
-#define HPTE_R_RPN 0x3ffffffffffff000ULL
-#define HPTE_R_FLAGS 0x00000000000003ffULL
-#define HPTE_R_PP 0x0000000000000003ULL
-#define HPTE_R_N 0x0000000000000004ULL
-#define HPTE_R_G 0x0000000000000008ULL
-#define HPTE_R_M 0x0000000000000010ULL
-#define HPTE_R_I 0x0000000000000020ULL
-#define HPTE_R_W 0x0000000000000040ULL
-#define HPTE_R_WIMG 0x0000000000000078ULL
-#define HPTE_R_C 0x0000000000000080ULL
-#define HPTE_R_R 0x0000000000000100ULL
-#define HPTE_R_KEY_LO 0x0000000000000e00ULL
-
-#define HPTE_V_1TB_SEG 0x4000000000000000ULL
-#define HPTE_V_VRMA_MASK 0x4001ffffff000000ULL
-
static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r,
target_ulong pte_index)
{
@@ -149,7 +116,7 @@ static target_ulong h_enter(CPUPPCState *env, sPAPREnvironment *spapr,
}
stq_p(hpte + (HASH_PTE_SIZE_64/2), ptel);
/* eieio(); FIXME: need some sort of barrier for smp? */
- stq_p(hpte, pteh);
+ stq_p(hpte, pteh | HPTE_V_HPTE_DIRTY);
args[0] = pte_index + i;
return H_SUCCESS;
@@ -186,7 +153,7 @@ static target_ulong remove_hpte(CPUPPCState *env, target_ulong ptex,
}
*vp = v;
*rp = r;
- stq_p(hpte, 0);
+ stq_p(hpte, HPTE_V_HPTE_DIRTY);
rb = compute_tlbie_rb(v, r, ptex);
ppc_tlb_invalidate_one(env, rb);
return REMOVE_SUCCESS;
@@ -313,11 +280,11 @@ static target_ulong h_protect(CPUPPCState *env, sPAPREnvironment *spapr,
r |= (flags << 48) & HPTE_R_KEY_HI;
r |= flags & (HPTE_R_PP | HPTE_R_N | HPTE_R_KEY_LO);
rb = compute_tlbie_rb(v, r, pte_index);
- stq_p(hpte, v & ~HPTE_V_VALID);
+ stq_p(hpte, (v & ~HPTE_V_VALID) | HPTE_V_HPTE_DIRTY);
ppc_tlb_invalidate_one(env, rb);
stq_p(hpte + (HASH_PTE_SIZE_64/2), r);
/* Don't need a memory barrier, due to qemu's global lock */
- stq_p(hpte, v);
+ stq_p(hpte, v | HPTE_V_HPTE_DIRTY);
return H_SUCCESS;
}
--
1.7.10.4
^ permalink raw reply related [flat|nested] 16+ messages in thread