[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v3 05/16] apic: Open-code timer save/restore
From: |
Jan Kiszka |
Subject: |
[Qemu-devel] [PATCH v3 05/16] apic: Open-code timer save/restore |
Date: |
Tue, 6 Dec 2011 13:58:05 +0100 |
To enable migration between accelerated and non-accelerated APIC models,
we will need to handle the timer saving and restoring specially and can
no longer rely on the automatics of VMSTATE_TIMER. Specifically,
accelerated model will not start any QEMUTimer.
This patch therefore factors out the generic bits into apic_next_timer
and introduces a post-load callback that can be implemented differently
by both models.
Signed-off-by: Jan Kiszka <address@hidden>
---
hw/apic.c | 30 ++++++++++++------------------
hw/apic_common.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++--
hw/apic_internal.h | 3 +++
3 files changed, 64 insertions(+), 20 deletions(-)
diff --git a/hw/apic.c b/hw/apic.c
index 8c8f658..d5a3f84 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -516,25 +516,9 @@ static uint32_t apic_get_current_count(APICState *s)
static void apic_timer_update(APICState *s, int64_t current_time)
{
- int64_t next_time, d;
-
- if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) {
- d = (current_time - s->initial_count_load_time) >>
- s->count_shift;
- if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
- if (!s->initial_count)
- goto no_timer;
- d = ((d / ((uint64_t)s->initial_count + 1)) + 1) *
((uint64_t)s->initial_count + 1);
- } else {
- if (d >= s->initial_count)
- goto no_timer;
- d = (uint64_t)s->initial_count + 1;
- }
- next_time = s->initial_count_load_time + (d << s->count_shift);
- qemu_mod_timer(s->timer, next_time);
- s->next_time = next_time;
+ if (apic_next_timer(s, current_time)) {
+ qemu_mod_timer(s->timer, s->next_time);
} else {
- no_timer:
qemu_del_timer(s->timer);
}
}
@@ -765,11 +749,21 @@ static void apic_backend_init(APICState *s)
local_apics[s->idx] = s;
}
+static void apic_post_load(APICState *s)
+{
+ if (s->timer_expiry != -1) {
+ qemu_mod_timer(s->timer, s->timer_expiry);
+ } else {
+ qemu_del_timer(s->timer);
+ }
+}
+
static APICBackend apic_backend = {
.name = "QEMU",
.init = apic_backend_init,
.set_base = apic_set_base,
.set_tpr = apic_set_tpr,
+ .post_load = apic_post_load,
};
static void apic_register_devices(void)
diff --git a/hw/apic_common.c b/hw/apic_common.c
index 1e6f287..e6ac1af 100644
--- a/hw/apic_common.c
+++ b/hw/apic_common.c
@@ -82,6 +82,39 @@ int apic_get_irq_delivered(void)
return apic_irq_delivered;
}
+bool apic_next_timer(APICState *s, int64_t current_time)
+{
+ int64_t d;
+
+ /* We need to store the timer state separately to support APIC
+ * implementations that maintain a non-QEMU timer, e.g. inside the
+ * host kernel. This open-coded state allows us to migrate between
+ * both models. */
+ s->timer_expiry = -1;
+
+ if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED) {
+ return false;
+ }
+
+ d = (current_time - s->initial_count_load_time) >> s->count_shift;
+
+ if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
+ if (!s->initial_count) {
+ return false;
+ }
+ d = ((d / ((uint64_t)s->initial_count + 1)) + 1) *
+ ((uint64_t)s->initial_count + 1);
+ } else {
+ if (d >= s->initial_count) {
+ return false;
+ }
+ d = (uint64_t)s->initial_count + 1;
+ }
+ s->next_time = s->initial_count_load_time + (d << s->count_shift);
+ s->timer_expiry = s->next_time;
+ return true;
+}
+
void apic_init_reset(DeviceState *d)
{
APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
@@ -109,7 +142,10 @@ void apic_init_reset(DeviceState *d)
s->next_time = 0;
s->wait_for_sipi = 1;
- qemu_del_timer(s->timer);
+ if (s->timer) {
+ qemu_del_timer(s->timer);
+ }
+ s->timer_expiry = -1;
}
static void apic_reset(DeviceState *d)
@@ -174,12 +210,23 @@ static int apic_load_old(QEMUFile *f, void *opaque, int
version_id)
return 0;
}
+static int apic_dispatch_post_load(void *opaque, int version_id)
+{
+ APICState *s = opaque;
+
+ if (s->backend->post_load) {
+ s->backend->post_load(s);
+ }
+ return 0;
+}
+
static const VMStateDescription vmstate_apic = {
.name = "apic",
.version_id = 3,
.minimum_version_id = 3,
.minimum_version_id_old = 1,
.load_state_old = apic_load_old,
+ .post_load = apic_dispatch_post_load,
.fields = (VMStateField[]) {
VMSTATE_UINT32(apicbase, APICState),
VMSTATE_UINT8(id, APICState),
@@ -199,7 +246,7 @@ static const VMStateDescription vmstate_apic = {
VMSTATE_UINT32(initial_count, APICState),
VMSTATE_INT64(initial_count_load_time, APICState),
VMSTATE_INT64(next_time, APICState),
- VMSTATE_TIMER(timer, APICState),
+ VMSTATE_INT64(timer_expiry, APICState), /* open-coded timer state */
VMSTATE_END_OF_LIST()
}
};
diff --git a/hw/apic_internal.h b/hw/apic_internal.h
index e0b4977..0865ae6 100644
--- a/hw/apic_internal.h
+++ b/hw/apic_internal.h
@@ -74,6 +74,7 @@ struct APICBackend {
void (*init)(APICState *s);
void (*set_base)(APICState *s, uint64_t val);
void (*set_tpr)(APICState *s, uint8_t val);
+ void (*post_load)(APICState *s);
QSIMPLEQ_ENTRY(APICBackend) entry;
};
@@ -103,6 +104,7 @@ struct APICState {
int64_t next_time;
int idx;
QEMUTimer *timer;
+ int64_t timer_expiry;
int sipi_vector;
int wait_for_sipi;
@@ -113,6 +115,7 @@ struct APICState {
void apic_register_device(void);
void apic_register_backend(APICBackend *backend);
+bool apic_next_timer(APICState *s, int64_t current_time);
void apic_set_irq_delivered(int delivered);
#endif /* !QEMU_APIC_INTERNAL_H */
--
1.7.3.4
- [Qemu-devel] [PATCH v3 00/16] uq/master: Introduce basic irqchip support, Jan Kiszka, 2011/12/06
- [Qemu-devel] [PATCH v3 02/16] kvm: Move kvmclock into hw/kvm folder, Jan Kiszka, 2011/12/06
- [Qemu-devel] [PATCH v3 05/16] apic: Open-code timer save/restore,
Jan Kiszka <=
- [Qemu-devel] [PATCH v3 12/16] kvm: x86: Establish IRQ0 override control, Jan Kiszka, 2011/12/06
- [Qemu-devel] [PATCH v3 04/16] apic: Introduce backend/frontend infrastructure for KVM reuse, Jan Kiszka, 2011/12/06
- [Qemu-devel] [PATCH v3 09/16] ioapic: Introduce backend/frontend infrastructure for KVM reuse, Jan Kiszka, 2011/12/06
- [Qemu-devel] [PATCH v3 01/16] msi: Generalize msix_supported to msi_supported, Jan Kiszka, 2011/12/06
- [Qemu-devel] [PATCH v3 10/16] memory: Introduce memory_region_init_reservation, Jan Kiszka, 2011/12/06
- [Qemu-devel] [PATCH v3 07/16] ioapic: Convert to memory API, Jan Kiszka, 2011/12/06
- [Qemu-devel] [PATCH v3 11/16] kvm: Introduce core services for in-kernel irqchip support, Jan Kiszka, 2011/12/06
- [Qemu-devel] [PATCH v3 13/16] kvm: x86: Add user space part for in-kernel APIC, Jan Kiszka, 2011/12/06
- [Qemu-devel] [PATCH v3 15/16] kvm: x86: Add user space part for in-kernel IOAPIC, Jan Kiszka, 2011/12/06
- [Qemu-devel] [PATCH v3 08/16] ioapic: Reject non-dword accesses to IOWIN register, Jan Kiszka, 2011/12/06