WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] [xen-unstable] [HVM] Move RTC emulation into the hypervi

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] [HVM] Move RTC emulation into the hypervisor.
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Wed, 18 Oct 2006 19:20:19 +0000
Delivery-date: Wed, 18 Oct 2006 12:21:10 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Node ID 71e2a165aa7f81602c569430b18ba1ea705f0b70
# Parent  da66691687dfd90c55420cfdf27f55d18cca7810
[HVM] Move RTC emulation into the hypervisor.
Signed-off-by: Xiaowei Yang <xiaowei.yang@xxxxxxxxx>
---
 tools/ioemu/Makefile.target         |    8 
 tools/ioemu/target-i386-dm/rtc-dm.c |  107 +++++++++
 xen/arch/x86/hvm/Makefile           |    1 
 xen/arch/x86/hvm/hvm.c              |   11 -
 xen/arch/x86/hvm/i8254.c            |   16 -
 xen/arch/x86/hvm/i8259.c            |   48 +++-
 xen/arch/x86/hvm/intercept.c        |   16 -
 xen/arch/x86/hvm/io.c               |    7 
 xen/arch/x86/hvm/rtc.c              |  393 ++++++++++++++++++++++++++++++++++++
 xen/arch/x86/hvm/svm/intr.c         |    4 
 xen/arch/x86/hvm/svm/svm.c          |    4 
 xen/arch/x86/hvm/vmx/vmx.c          |    4 
 xen/arch/x86/time.c                 |    7 
 xen/common/Makefile                 |    3 
 xen/common/time.c                   |   77 +++++++
 xen/include/asm-x86/hvm/vpic.h      |    2 
 xen/include/asm-x86/hvm/vpit.h      |   56 ++++-
 xen/include/xen/time.h              |   14 +
 18 files changed, 722 insertions(+), 56 deletions(-)

diff -r da66691687df -r 71e2a165aa7f tools/ioemu/Makefile.target
--- a/tools/ioemu/Makefile.target       Wed Oct 18 18:13:57 2006 +0100
+++ b/tools/ioemu/Makefile.target       Wed Oct 18 18:35:21 2006 +0100
@@ -294,7 +294,11 @@ endif
 endif
 
 # qemu-dm objects
+ifeq ($(ARCH),ia64)
 LIBOBJS=helper2.o exec-dm.o i8259-dm.o
+else
+LIBOBJS=helper2.o exec-dm.o i8259-dm.o rtc-dm.o
+endif
 
 all: $(PROGS)
 
@@ -354,7 +358,11 @@ ifeq ($(TARGET_BASE_ARCH), i386)
 ifeq ($(TARGET_BASE_ARCH), i386)
 # Hardware support
 VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
+ifeq ($(ARCH),ia64)
 VL_OBJS+= fdc.o mc146818rtc.o serial.o pc.o
+else
+VL_OBJS+= fdc.o serial.o pc.o
+endif
 VL_OBJS+= cirrus_vga.o mixeng.o parallel.o acpi.o piix_pci.o
 VL_OBJS+= usb-uhci.o
 VL_OBJS+= piix4acpi.o
diff -r da66691687df -r 71e2a165aa7f xen/arch/x86/hvm/Makefile
--- a/xen/arch/x86/hvm/Makefile Wed Oct 18 18:13:57 2006 +0100
+++ b/xen/arch/x86/hvm/Makefile Wed Oct 18 18:35:21 2006 +0100
@@ -4,6 +4,7 @@ obj-y += hvm.o
 obj-y += hvm.o
 obj-y += i8254.o
 obj-y += i8259.o
+obj-y += rtc.o
 obj-y += instrlen.o
 obj-y += intercept.o
 obj-y += io.o
diff -r da66691687df -r 71e2a165aa7f xen/arch/x86/hvm/hvm.c
--- a/xen/arch/x86/hvm/hvm.c    Wed Oct 18 18:13:57 2006 +0100
+++ b/xen/arch/x86/hvm/hvm.c    Wed Oct 18 18:35:21 2006 +0100
@@ -40,8 +40,10 @@
 #include <asm/processor.h>
 #include <asm/types.h>
 #include <asm/msr.h>
+#include <asm/mc146818rtc.h>
 #include <asm/spinlock.h>
 #include <asm/hvm/hvm.h>
+#include <asm/hvm/vpit.h>
 #include <asm/hvm/support.h>
 #include <public/sched.h>
 #include <public/hvm/ioreq.h>
@@ -277,6 +279,7 @@ void hvm_setup_platform(struct domain* d
     init_timer(&platform->pl_time.periodic_tm.timer,
                pt_timer_fn, v, v->processor);
     pit_init(v, cpu_khz);
+    rtc_init(v, RTC_PORT(0), RTC_IRQ);
 }
 
 void pic_irq_request(void *data, int level)
@@ -368,7 +371,7 @@ void hvm_hlt(unsigned long rflags)
 {
     struct vcpu *v = current;
     struct periodic_time *pt = &v->domain->arch.hvm_domain.pl_time.periodic_tm;
-    s_time_t next_pit = -1, next_wakeup;
+    s_time_t next_pt = -1, next_wakeup;
 
     /*
      * If we halt with interrupts disabled, that's a pretty sure sign that we
@@ -379,10 +382,10 @@ void hvm_hlt(unsigned long rflags)
         return hvm_vcpu_down();
 
     if ( !v->vcpu_id )
-        next_pit = get_scheduled(v, pt->irq, pt);
+        next_pt = get_scheduled(v, pt->irq, pt);
     next_wakeup = get_apictime_scheduled(v);
-    if ( (next_pit != -1 && next_pit < next_wakeup) || next_wakeup == -1 )
-        next_wakeup = next_pit;
+    if ( (next_pt != -1 && next_pt < next_wakeup) || next_wakeup == -1 )
+        next_wakeup = next_pt;
     if ( next_wakeup != - 1 ) 
         set_timer(&current->arch.hvm_vcpu.hlt_timer, next_wakeup);
     do_sched_op_compat(SCHEDOP_block, 0);
diff -r da66691687df -r 71e2a165aa7f xen/arch/x86/hvm/i8254.c
--- a/xen/arch/x86/hvm/i8254.c  Wed Oct 18 18:13:57 2006 +0100
+++ b/xen/arch/x86/hvm/i8254.c  Wed Oct 18 18:35:21 2006 +0100
@@ -49,7 +49,6 @@
 #define RW_STATE_WORD0 3
 #define RW_STATE_WORD1 4
 
-#define ticks_per_sec(v)      (v->domain->arch.hvm_domain.tsc_frequency)
 static int handle_pit_io(ioreq_t *p);
 static int handle_speaker_io(ioreq_t *p);
 
@@ -77,17 +76,6 @@ uint64_t muldiv64(uint64_t a, uint32_t b
     return res.ll;
 }
 
-/*
- * get processor time.
- * unit: TSC
- */
-int64_t hvm_get_clock(struct vcpu *v)
-{
-    uint64_t  gtsc;
-    gtsc = hvm_get_guest_time(v);
-    return gtsc;
-}
-
 static int pit_get_count(PITChannelState *s)
 {
     uint64_t d;
@@ -215,11 +203,11 @@ static inline void pit_load_count(PITCha
     switch (s->mode) {
         case 2:
             /* create periodic time */
-            s->pt = create_periodic_time (s, period, 0, 0);
+            s->pt = create_periodic_time (period, 0, 0, pit_time_fired, s);
             break;
         case 1:
             /* create one shot time */
-            s->pt = create_periodic_time (s, period, 0, 1);
+            s->pt = create_periodic_time (period, 0, 1, pit_time_fired, s);
 #ifdef DEBUG_PIT
             printk("HVM_PIT: create one shot time.\n");
 #endif
diff -r da66691687df -r 71e2a165aa7f xen/arch/x86/hvm/i8259.c
--- a/xen/arch/x86/hvm/i8259.c  Wed Oct 18 18:13:57 2006 +0100
+++ b/xen/arch/x86/hvm/i8259.c  Wed Oct 18 18:35:21 2006 +0100
@@ -598,23 +598,47 @@ int cpu_get_pic_interrupt(struct vcpu *v
     return intno;
 }
 
-int is_pit_irq(struct vcpu *v, int irq, int type)
-{
-    int pit_vec;
-
-    if (type == APIC_DM_EXTINT)
-        pit_vec = v->domain->arch.hvm_domain.vpic.pics[0].irq_base;
-    else
-        pit_vec =
-          v->domain->arch.hvm_domain.vioapic.redirtbl[0].RedirForm.vector;
-
-    return (irq == pit_vec);
+int is_periodic_irq(struct vcpu *v, int irq, int type)
+{
+    int vec;
+    struct periodic_time *pt =
+        &(v->domain->arch.hvm_domain.pl_time.periodic_tm);
+    struct RTCState *vrtc =
+        &(v->domain->arch.hvm_domain.pl_time.vrtc);
+
+    if (pt->irq == 0) { /* Is it pit irq? */
+        if (type == APIC_DM_EXTINT)
+            vec = v->domain->arch.hvm_domain.vpic.pics[0].irq_base;
+        else
+            vec =
+              v->domain->arch.hvm_domain.vioapic.redirtbl[0].RedirForm.vector;
+
+        if (irq == vec)
+            return 1;
+    }
+
+    if (pt->irq == 8) { /* Or rtc irq? */
+        if (type == APIC_DM_EXTINT)
+            vec = v->domain->arch.hvm_domain.vpic.pics[1].irq_base;
+        else
+            vec =
+              v->domain->arch.hvm_domain.vioapic.redirtbl[8].RedirForm.vector;
+
+        if (irq == vec)
+            return is_rtc_periodic_irq(vrtc);
+    }
+
+    return 0;
 }
 
 int is_irq_enabled(struct vcpu *v, int irq)
 {
+    struct hvm_vioapic *vioapic = &v->domain->arch.hvm_domain.vioapic;
     struct hvm_virpic *vpic=&v->domain->arch.hvm_domain.vpic;
-        
+
+    if (vioapic->redirtbl[irq].RedirForm.mask == 0)
+       return 1;
+
     if ( irq & 8 ) {
         return !( (1 << (irq&7)) & vpic->pics[1].imr);
     }
diff -r da66691687df -r 71e2a165aa7f xen/arch/x86/hvm/intercept.c
--- a/xen/arch/x86/hvm/intercept.c      Wed Oct 18 18:13:57 2006 +0100
+++ b/xen/arch/x86/hvm/intercept.c      Wed Oct 18 18:35:21 2006 +0100
@@ -315,17 +315,14 @@ void pickup_deactive_ticks(struct period
  * period: fire frequency in ns.
  */
 struct periodic_time * create_periodic_time(
-        PITChannelState *s,
         u32 period, 
         char irq,
-        char one_shot)
-{
-    struct vcpu *v = s->vcpu;
-    struct periodic_time *pt = 
&(v->domain->arch.hvm_domain.pl_time.periodic_tm);
+        char one_shot,
+        time_cb *cb,
+        void *data)
+{
+    struct periodic_time *pt = 
&(current->domain->arch.hvm_domain.pl_time.periodic_tm);
     if ( pt->enabled ) {
-        if ( v->vcpu_id != 0 ) {
-            printk("HVM_PIT: start 2nd periodic time on non BSP!\n");
-        }
         stop_timer (&pt->timer);
         pt->enabled = 0;
     }
@@ -345,7 +342,8 @@ struct periodic_time * create_periodic_t
     pt->scheduled = NOW() + period;
     set_timer (&pt->timer,pt->scheduled);
     pt->enabled = 1;
-    pt->priv = s;
+    pt->cb = cb;
+    pt->priv = data;
     return pt;
 }
 
diff -r da66691687df -r 71e2a165aa7f xen/arch/x86/hvm/io.c
--- a/xen/arch/x86/hvm/io.c     Wed Oct 18 18:13:57 2006 +0100
+++ b/xen/arch/x86/hvm/io.c     Wed Oct 18 18:35:21 2006 +0100
@@ -683,7 +683,7 @@ void hvm_interrupt_post(struct vcpu *v, 
     struct  periodic_time *pt = 
         &(v->domain->arch.hvm_domain.pl_time.periodic_tm);
 
-    if ( is_pit_irq(v, vector, type) ) {
+    if ( pt->enabled && is_periodic_irq(v, vector, type) ) {
         if ( !pt->first_injected ) {
             pt->pending_intr_nr = 0;
             pt->last_plt_gtime = hvm_get_guest_time(v);
@@ -694,8 +694,9 @@ void hvm_interrupt_post(struct vcpu *v, 
             pt->pending_intr_nr--;
             pt->last_plt_gtime += pt->period_cycles;
             hvm_set_guest_time(v, pt->last_plt_gtime);
-            pit_time_fired(v, pt->priv);
-        }
+        }
+        if (pt->cb)
+            pt->cb(v, pt->priv);
     }
     
     switch(type) {
diff -r da66691687df -r 71e2a165aa7f xen/arch/x86/hvm/svm/intr.c
--- a/xen/arch/x86/hvm/svm/intr.c       Wed Oct 18 18:13:57 2006 +0100
+++ b/xen/arch/x86/hvm/svm/intr.c       Wed Oct 18 18:35:21 2006 +0100
@@ -140,8 +140,8 @@ asmlinkage void svm_intr_assist(void)
         case APIC_DM_FIXED:
         case APIC_DM_LOWEST:
             /* Re-injecting a PIT interruptt? */
-            if (re_injecting && 
-                is_pit_irq(v, intr_vector, intr_type)) {
+            if (re_injecting && pt->enabled && 
+                is_periodic_irq(v, intr_vector, intr_type)) {
                     ++pt->pending_intr_nr;
             }
             /* let's inject this interrupt */
diff -r da66691687df -r 71e2a165aa7f xen/arch/x86/hvm/svm/svm.c
--- a/xen/arch/x86/hvm/svm/svm.c        Wed Oct 18 18:13:57 2006 +0100
+++ b/xen/arch/x86/hvm/svm/svm.c        Wed Oct 18 18:35:21 2006 +0100
@@ -921,6 +921,7 @@ static void svm_relinquish_guest_resourc
     }
 
     kill_timer(&d->arch.hvm_domain.pl_time.periodic_tm.timer);
+    rtc_deinit(d);
 
     if ( d->arch.hvm_domain.shared_page_va )
         unmap_domain_page_global(
@@ -935,6 +936,7 @@ static void svm_migrate_timers(struct vc
 {
     struct periodic_time *pt = 
         &(v->domain->arch.hvm_domain.pl_time.periodic_tm);
+    struct RTCState *vrtc = &v->domain->arch.hvm_domain.pl_time.vrtc;
 
     if ( pt->enabled )
     {
@@ -943,6 +945,8 @@ static void svm_migrate_timers(struct vc
     }
     if ( VLAPIC(v) != NULL )
         migrate_timer(&VLAPIC(v)->vlapic_timer, v->processor);
+    migrate_timer(&vrtc->second_timer, v->processor);
+    migrate_timer(&vrtc->second_timer2, v->processor);
 }
 
 
diff -r da66691687df -r 71e2a165aa7f xen/arch/x86/hvm/vmx/vmx.c
--- a/xen/arch/x86/hvm/vmx/vmx.c        Wed Oct 18 18:13:57 2006 +0100
+++ b/xen/arch/x86/hvm/vmx/vmx.c        Wed Oct 18 18:35:21 2006 +0100
@@ -146,6 +146,7 @@ static void vmx_relinquish_guest_resourc
     }
 
     kill_timer(&d->arch.hvm_domain.pl_time.periodic_tm.timer);
+    rtc_deinit(d);
 
     if ( d->arch.hvm_domain.shared_page_va )
         unmap_domain_page_global(
@@ -487,6 +488,7 @@ void vmx_migrate_timers(struct vcpu *v)
 void vmx_migrate_timers(struct vcpu *v)
 {
     struct periodic_time *pt = 
&(v->domain->arch.hvm_domain.pl_time.periodic_tm);
+    struct RTCState *vrtc = &v->domain->arch.hvm_domain.pl_time.vrtc;
 
     if ( pt->enabled )
     {
@@ -495,6 +497,8 @@ void vmx_migrate_timers(struct vcpu *v)
     }
     if ( VLAPIC(v) != NULL )
         migrate_timer(&VLAPIC(v)->vlapic_timer, v->processor);
+    migrate_timer(&vrtc->second_timer, v->processor);
+    migrate_timer(&vrtc->second_timer2, v->processor);
 }
 
 static void vmx_store_cpu_guest_regs(
diff -r da66691687df -r 71e2a165aa7f xen/arch/x86/time.c
--- a/xen/arch/x86/time.c       Wed Oct 18 18:13:57 2006 +0100
+++ b/xen/arch/x86/time.c       Wed Oct 18 18:35:21 2006 +0100
@@ -919,6 +919,13 @@ void send_timer_event(struct vcpu *v)
     send_guest_vcpu_virq(v, VIRQ_TIMER);
 }
 
+/* Return secs after 00:00:00 localtime, 1 January, 1970. */
+unsigned long get_localtime(struct domain *d)
+{
+    return wc_sec + (wc_nsec + NOW()) / 1000000000ULL 
+        + d->time_offset_seconds;
+}
+
 /*
  * Local variables:
  * mode: C
diff -r da66691687df -r 71e2a165aa7f xen/common/Makefile
--- a/xen/common/Makefile       Wed Oct 18 18:13:57 2006 +0100
+++ b/xen/common/Makefile       Wed Oct 18 18:35:21 2006 +0100
@@ -20,8 +20,9 @@ obj-y += string.o
 obj-y += string.o
 obj-y += symbols.o
 obj-y += sysctl.o
+obj-y += time.o
+obj-y += timer.o
 obj-y += trace.o
-obj-y += timer.o
 obj-y += version.o
 obj-y += vsprintf.o
 obj-y += xmalloc.o
diff -r da66691687df -r 71e2a165aa7f xen/include/asm-x86/hvm/vpic.h
--- a/xen/include/asm-x86/hvm/vpic.h    Wed Oct 18 18:13:57 2006 +0100
+++ b/xen/include/asm-x86/hvm/vpic.h    Wed Oct 18 18:35:21 2006 +0100
@@ -75,7 +75,7 @@ uint32_t pic_intack_read(struct hvm_virp
 uint32_t pic_intack_read(struct hvm_virpic *s);
 void register_pic_io_hook (void);
 int cpu_get_pic_interrupt(struct vcpu *v, int *type);
-int is_pit_irq(struct vcpu *v, int irq, int type);
+int is_periodic_irq(struct vcpu *v, int irq, int type);
 int is_irq_enabled(struct vcpu *v, int irq);
 void do_pic_irqs (struct hvm_virpic *s, uint16_t irqs);
 void do_pic_irqs_clear (struct hvm_virpic *s, uint16_t irqs);
diff -r da66691687df -r 71e2a165aa7f xen/include/asm-x86/hvm/vpit.h
--- a/xen/include/asm-x86/hvm/vpit.h    Wed Oct 18 18:13:57 2006 +0100
+++ b/xen/include/asm-x86/hvm/vpit.h    Wed Oct 18 18:35:21 2006 +0100
@@ -25,11 +25,12 @@
 #include <xen/lib.h>
 #include <xen/time.h>
 #include <xen/errno.h>
+#include <xen/time.h>
 #include <xen/timer.h>
 #include <asm/hvm/vpic.h>
 
 #define PIT_FREQ 1193181
-#define PIT_BASE        0x40
+#define PIT_BASE 0x40
 
 typedef struct PITChannelState {
     int count; /* can be 65536 */
@@ -49,10 +50,32 @@ typedef struct PITChannelState {
     struct vcpu      *vcpu;
     struct periodic_time *pt;
 } PITChannelState;
+
+typedef struct PITState {
+    PITChannelState channels[3];
+    int speaker_data_on;
+    int dummy_refresh_clock;
+} PITState;
+
+#define RTC_SIZE 14
+typedef struct RTCState {
+    uint8_t cmos_data[RTC_SIZE];  /* Only handle time/interrupt part in HV */
+    uint8_t cmos_index;
+    struct tm current_tm;
+    int irq;
+    /* second update */
+    int64_t next_second_time;
+    struct timer second_timer;
+    struct timer second_timer2;
+    struct vcpu      *vcpu;
+    struct periodic_time *pt;
+} RTCState;
    
 /*
  * Abstract layer of periodic time, one short time.
  */
+typedef void time_cb(struct vcpu *v, void *opaque);
+
 struct periodic_time {
     char enabled;               /* enabled */
     char one_shot;              /* one shot time */
@@ -64,19 +87,15 @@ struct periodic_time {
     s_time_t scheduled;         /* scheduled timer interrupt */
     u64 last_plt_gtime;         /* platform time when last IRQ is injected */
     struct timer timer;         /* ac_timer */
+    time_cb *cb;
     void *priv;                 /* ponit back to platform time source */
 };
-
-typedef struct PITState {
-    PITChannelState channels[3];
-    int speaker_data_on;
-    int dummy_refresh_clock;
-} PITState;
 
 struct pl_time {    /* platform time */
     struct periodic_time periodic_tm;
     struct PITState      vpit;
-    /* TODO: RTC/ACPI time */
+    struct RTCState      vrtc;
+    /* TODO: ACPI time */
 };
 
 static __inline__ s_time_t get_scheduled(
@@ -90,13 +109,30 @@ static __inline__ s_time_t get_scheduled
         return -1;
 }
 
+extern u64 hvm_get_guest_time(struct vcpu *v);
+/*
+ * get processor time.
+ * unit: TSC
+ */
+static __inline__ int64_t hvm_get_clock(struct vcpu *v)
+{
+    uint64_t  gtsc;
+
+    gtsc = hvm_get_guest_time(v);
+    return gtsc;
+}
+
+#define ticks_per_sec(v)      (v->domain->arch.hvm_domain.tsc_frequency)
+
 /* to hook the ioreq packet to get the PIT initialization info */
 extern void hvm_hooks_assist(struct vcpu *v);
 extern void pickup_deactive_ticks(struct periodic_time *vpit);
-extern u64 hvm_get_guest_time(struct vcpu *v);
-extern struct periodic_time *create_periodic_time(PITChannelState *v, u32 
period, char irq, char one_shot);
+extern struct periodic_time *create_periodic_time(u32 period, char irq, char 
one_shot, time_cb *cb, void *data);
 extern void destroy_periodic_time(struct periodic_time *pt);
 void pit_init(struct vcpu *v, unsigned long cpu_khz);
+void rtc_init(struct vcpu *v, int base, int irq);
+void rtc_deinit(struct domain *d);
+int is_rtc_periodic_irq(void *opaque);
 void pt_timer_fn(void *data);
 void pit_time_fired(struct vcpu *v, void *priv);
 
diff -r da66691687df -r 71e2a165aa7f xen/include/xen/time.h
--- a/xen/include/xen/time.h    Wed Oct 18 18:13:57 2006 +0100
+++ b/xen/include/xen/time.h    Wed Oct 18 18:35:21 2006 +0100
@@ -49,6 +49,20 @@ typedef s64 s_time_t;
 typedef s64 s_time_t;
 
 s_time_t get_s_time(void);
+unsigned long get_localtime(struct domain *d);
+
+struct tm {
+    int     tm_sec;         /* seconds */
+    int     tm_min;         /* minutes */
+    int     tm_hour;        /* hours */
+    int     tm_mday;        /* day of the month */
+    int     tm_mon;         /* month */
+    int     tm_year;        /* year */
+    int     tm_wday;        /* day of the week */
+    int     tm_yday;        /* day in the year */
+    int     tm_isdst;       /* daylight saving time */
+};
+struct tm gmtime(unsigned long t);
 
 #define NOW()           ((s_time_t)get_s_time())
 #define SECONDS(_s)     ((s_time_t)((_s)  * 1000000000ULL))
diff -r da66691687df -r 71e2a165aa7f tools/ioemu/target-i386-dm/rtc-dm.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/ioemu/target-i386-dm/rtc-dm.c       Wed Oct 18 18:35:21 2006 +0100
@@ -0,0 +1,107 @@
+/*
+ * QEMU MC146818 RTC emulation
+ * 
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to 
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "vl.h"
+
+//#define DEBUG_CMOS
+
+struct RTCState {
+    uint8_t cmos_data[128];
+    uint8_t cmos_index;
+};
+
+void rtc_set_memory(RTCState *s, int addr, int val)
+{
+    if (addr >= 0 && addr <= 127)
+        s->cmos_data[addr] = val;
+}
+
+static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data)
+{
+    RTCState *s = opaque;
+
+    if ((addr & 1) == 0) {
+        s->cmos_index = data & 0x7f;
+    } else {
+#ifdef DEBUG_CMOS
+        printf("cmos: write index=0x%02x val=0x%02x\n",
+               s->cmos_index, data);
+#endif        
+        s->cmos_data[s->cmos_index] = data;
+    }
+}
+
+static uint32_t cmos_ioport_read(void *opaque, uint32_t addr)
+{
+    RTCState *s = opaque;
+    int ret;
+    if ((addr & 1) == 0) {
+        return 0xff;
+    } else {
+        ret = s->cmos_data[s->cmos_index];
+#ifdef DEBUG_CMOS
+        printf("cmos: read index=0x%02x val=0x%02x\n",
+               s->cmos_index, ret);
+#endif
+        return ret;
+    }
+}
+
+static void rtc_save(QEMUFile *f, void *opaque)
+{
+    RTCState *s = opaque;
+
+    qemu_put_buffer(f, s->cmos_data, 128);
+    qemu_put_8s(f, &s->cmos_index);
+}
+
+static int rtc_load(QEMUFile *f, void *opaque, int version_id)
+{
+    RTCState *s = opaque;
+
+    if (version_id != 1)
+        return -EINVAL;
+
+    qemu_get_buffer(f, s->cmos_data, 128);
+    qemu_get_8s(f, &s->cmos_index);
+
+    return 0;
+}
+
+RTCState *rtc_init(int base, int irq)
+{
+    RTCState *s;
+
+    s = qemu_mallocz(sizeof(RTCState));
+    if (!s)
+        return NULL;
+
+    register_ioport_write(base, 2, 1, cmos_ioport_write, s);
+    register_ioport_read(base, 2, 1, cmos_ioport_read, s);
+
+    register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s);
+    return s;
+}
+
+void rtc_set_date(RTCState *s, const struct tm *tm) {}
diff -r da66691687df -r 71e2a165aa7f xen/arch/x86/hvm/rtc.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/arch/x86/hvm/rtc.c    Wed Oct 18 18:35:21 2006 +0100
@@ -0,0 +1,393 @@
+/*
+ * QEMU MC146818 RTC emulation
+ * 
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to 
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <asm/mc146818rtc.h>
+#include <asm/hvm/vpit.h>
+#include <asm/hvm/io.h>
+#include <asm/hvm/support.h>
+#include <asm/current.h>
+
+/* #define DEBUG_RTC */
+
+void rtc_periodic_cb(struct vcpu *v, void *opaque)
+{
+    RTCState *s = opaque;
+    s->cmos_data[RTC_REG_C] |= 0xc0;
+}
+
+int is_rtc_periodic_irq(void *opaque)
+{
+    RTCState *s = opaque;
+    return !(s->cmos_data[RTC_REG_C] & RTC_AF || 
+           s->cmos_data[RTC_REG_C] & RTC_UF);
+}
+
+static void rtc_timer_update(RTCState *s, int64_t current_time)
+{
+    int period_code; 
+    int period;
+
+    period_code = s->cmos_data[RTC_REG_A] & 0x0f;
+    if (period_code != 0 && (s->cmos_data[RTC_REG_B] & RTC_PIE)) {
+        if (period_code <= 2)
+            period_code += 7;
+        
+        period = 1 << (period_code - 1); /* period in 32 Khz cycles */
+        period = DIV_ROUND((period * 1000000000ULL), 32768); /* period in ns */
+
+#ifdef DEBUG_RTC
+        printk("HVM_RTC: period = %uns\n", period);
+#endif
+
+        s->pt = create_periodic_time(period, RTC_IRQ, 0, rtc_periodic_cb, s);
+    } else if (s->pt) {
+        destroy_periodic_time(s->pt);
+        s->pt = NULL;
+    }
+}
+
+static void rtc_set_time(RTCState *s);
+
+static int rtc_ioport_write(void *opaque, uint32_t addr, uint32_t data)
+{
+    RTCState *s = opaque;
+
+    if ((addr & 1) == 0) {
+        s->cmos_index = data & 0x7f;
+        if (s->cmos_index < RTC_SIZE)
+            return 1;
+    } else if (s->cmos_index < RTC_SIZE) {
+#ifdef DEBUG_RTC
+        printk("HVM_RTC: write index=0x%02x val=0x%02x\n",
+               s->cmos_index, data);
+#endif        
+        switch(s->cmos_index) {
+        case RTC_SECONDS_ALARM:
+        case RTC_MINUTES_ALARM:
+        case RTC_HOURS_ALARM:
+            s->cmos_data[s->cmos_index] = data;
+            break;
+        case RTC_SECONDS:
+        case RTC_MINUTES:
+        case RTC_HOURS:
+        case RTC_DAY_OF_WEEK:
+        case RTC_DAY_OF_MONTH:
+        case RTC_MONTH:
+        case RTC_YEAR:
+            s->cmos_data[s->cmos_index] = data;
+            /* if in set mode, do not update the time */
+            if (!(s->cmos_data[RTC_REG_B] & RTC_SET)) {
+                rtc_set_time(s);
+            }
+            break;
+        case RTC_REG_A:
+            /* UIP bit is read only */
+            s->cmos_data[RTC_REG_A] = (data & ~RTC_UIP) |
+                (s->cmos_data[RTC_REG_A] & RTC_UIP);
+            rtc_timer_update(s, hvm_get_clock(s->vcpu));
+            break;
+        case RTC_REG_B:
+            if (data & RTC_SET) {
+                /* set mode: reset UIP mode */
+                s->cmos_data[RTC_REG_A] &= ~RTC_UIP;
+                data &= ~RTC_UIE;
+            } else {
+                /* if disabling set mode, update the time */
+                if (s->cmos_data[RTC_REG_B] & RTC_SET) {
+                    rtc_set_time(s);
+                }
+            }
+            s->cmos_data[RTC_REG_B] = data;
+            rtc_timer_update(s, hvm_get_clock(s->vcpu));
+            break;
+        case RTC_REG_C:
+        case RTC_REG_D:
+            /* cannot write to them */
+            break;
+        return 1;
+        }
+    }
+    return 0;
+}
+
+static inline int to_bcd(RTCState *s, int a)
+{
+    if (s->cmos_data[RTC_REG_B] & 0x04) {
+        return a;
+    } else {
+        return ((a / 10) << 4) | (a % 10);
+    }
+}
+
+static inline int from_bcd(RTCState *s, int a)
+{
+    if (s->cmos_data[RTC_REG_B] & 0x04) {
+        return a;
+    } else {
+        return ((a >> 4) * 10) + (a & 0x0f);
+    }
+}
+
+static void rtc_set_time(RTCState *s)
+{
+    struct tm *tm = &s->current_tm;
+    
+    tm->tm_sec = from_bcd(s, s->cmos_data[RTC_SECONDS]);
+    tm->tm_min = from_bcd(s, s->cmos_data[RTC_MINUTES]);
+    tm->tm_hour = from_bcd(s, s->cmos_data[RTC_HOURS] & 0x7f);
+    if (!(s->cmos_data[RTC_REG_B] & 0x02) &&
+        (s->cmos_data[RTC_HOURS] & 0x80)) {
+        tm->tm_hour += 12;
+    }
+    tm->tm_wday = from_bcd(s, s->cmos_data[RTC_DAY_OF_WEEK]);
+    tm->tm_mday = from_bcd(s, s->cmos_data[RTC_DAY_OF_MONTH]);
+    tm->tm_mon = from_bcd(s, s->cmos_data[RTC_MONTH]) - 1;
+    tm->tm_year = from_bcd(s, s->cmos_data[RTC_YEAR]) + 100;
+}
+
+static void rtc_copy_date(RTCState *s)
+{
+    const struct tm *tm = &s->current_tm;
+
+    s->cmos_data[RTC_SECONDS] = to_bcd(s, tm->tm_sec);
+    s->cmos_data[RTC_MINUTES] = to_bcd(s, tm->tm_min);
+    if (s->cmos_data[RTC_REG_B] & 0x02) {
+        /* 24 hour format */
+        s->cmos_data[RTC_HOURS] = to_bcd(s, tm->tm_hour);
+    } else {
+        /* 12 hour format */
+        s->cmos_data[RTC_HOURS] = to_bcd(s, tm->tm_hour % 12);
+        if (tm->tm_hour >= 12)
+            s->cmos_data[RTC_HOURS] |= 0x80;
+    }
+    s->cmos_data[RTC_DAY_OF_WEEK] = to_bcd(s, tm->tm_wday);
+    s->cmos_data[RTC_DAY_OF_MONTH] = to_bcd(s, tm->tm_mday);
+    s->cmos_data[RTC_MONTH] = to_bcd(s, tm->tm_mon + 1);
+    s->cmos_data[RTC_YEAR] = to_bcd(s, tm->tm_year % 100);
+}
+
+/* month is between 0 and 11. */
+static int get_days_in_month(int month, int year)
+{
+    static const int days_tab[12] = { 
+        31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 
+    };
+    int d;
+    if ((unsigned )month >= 12)
+        return 31;
+    d = days_tab[month];
+    if (month == 1) {
+        if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0))
+            d++;
+    }
+    return d;
+}
+
+/* update 'tm' to the next second */
+static void rtc_next_second(struct tm *tm)
+{
+    int days_in_month;
+
+    tm->tm_sec++;
+    if ((unsigned)tm->tm_sec >= 60) {
+        tm->tm_sec = 0;
+        tm->tm_min++;
+        if ((unsigned)tm->tm_min >= 60) {
+            tm->tm_min = 0;
+            tm->tm_hour++;
+            if ((unsigned)tm->tm_hour >= 24) {
+                tm->tm_hour = 0;
+                /* next day */
+                tm->tm_wday++;
+                if ((unsigned)tm->tm_wday >= 7)
+                    tm->tm_wday = 0;
+                days_in_month = get_days_in_month(tm->tm_mon, 
+                                                  tm->tm_year + 1900);
+                tm->tm_mday++;
+                if (tm->tm_mday < 1) {
+                    tm->tm_mday = 1;
+                } else if (tm->tm_mday > days_in_month) {
+                    tm->tm_mday = 1;
+                    tm->tm_mon++;
+                    if (tm->tm_mon >= 12) {
+                        tm->tm_mon = 0;
+                        tm->tm_year++;
+                    }
+                }
+            }
+        }
+    }
+}
+
+static void rtc_update_second(void *opaque)
+{
+    RTCState *s = opaque;
+
+    /* if the oscillator is not in normal operation, we do not update */
+    if ((s->cmos_data[RTC_REG_A] & 0x70) != 0x20) {
+        s->next_second_time += 1000000000ULL;
+        set_timer(&s->second_timer, s->next_second_time);
+    } else {
+        rtc_next_second(&s->current_tm);
+        
+        if (!(s->cmos_data[RTC_REG_B] & RTC_SET)) {
+            /* update in progress bit */
+            s->cmos_data[RTC_REG_A] |= RTC_UIP;
+        }
+        /* Delay time before update cycle */
+        set_timer(&s->second_timer2, s->next_second_time + 244000);
+    }
+}
+
+static void rtc_update_second2(void *opaque)
+{
+    RTCState *s = opaque;
+    struct hvm_domain *plat=&s->vcpu->domain->arch.hvm_domain;
+    struct hvm_virpic *pic= &plat->vpic;
+
+    if (!(s->cmos_data[RTC_REG_B] & RTC_SET)) {
+        rtc_copy_date(s);
+    }
+
+    /* check alarm */
+    if (s->cmos_data[RTC_REG_B] & RTC_AIE) {
+        if (((s->cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0 ||
+             s->cmos_data[RTC_SECONDS_ALARM] == s->current_tm.tm_sec) &&
+            ((s->cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0 ||
+             s->cmos_data[RTC_MINUTES_ALARM] == s->current_tm.tm_mon) &&
+            ((s->cmos_data[RTC_HOURS_ALARM] & 0xc0) == 0xc0 ||
+             s->cmos_data[RTC_HOURS_ALARM] == s->current_tm.tm_hour)) {
+
+            s->cmos_data[RTC_REG_C] |= 0xa0; 
+            pic_set_irq(pic, s->irq, 0);
+            pic_set_irq(pic, s->irq, 1);
+        }
+    }
+
+    /* update ended interrupt */
+    if (s->cmos_data[RTC_REG_B] & RTC_UIE) {
+        s->cmos_data[RTC_REG_C] |= 0x90; 
+        pic_set_irq(pic, s->irq, 0);
+        pic_set_irq(pic, s->irq, 1);
+    }
+
+    /* clear update in progress bit */
+    s->cmos_data[RTC_REG_A] &= ~RTC_UIP;
+
+    s->next_second_time += 1000000000ULL;
+    set_timer(&s->second_timer, s->next_second_time);
+}
+
+static uint32_t rtc_ioport_read(void *opaque, uint32_t addr)
+{
+    RTCState *s = opaque;
+    struct hvm_domain *plat=&s->vcpu->domain->arch.hvm_domain;
+    struct hvm_virpic *pic= &plat->vpic;
+    int ret;
+
+    if ((addr & 1) == 0) {
+        return 0xff;
+    } else {
+        switch(s->cmos_index) {
+        case RTC_SECONDS:
+        case RTC_MINUTES:
+        case RTC_HOURS:
+        case RTC_DAY_OF_WEEK:
+        case RTC_DAY_OF_MONTH:
+        case RTC_MONTH:
+        case RTC_YEAR:
+            ret = s->cmos_data[s->cmos_index];
+            break;
+        case RTC_REG_A:
+            ret = s->cmos_data[s->cmos_index];
+            break;
+        case RTC_REG_C:
+            ret = s->cmos_data[s->cmos_index];
+            pic_set_irq(pic, s->irq, 0);
+            s->cmos_data[RTC_REG_C] = 0x00; 
+            break;
+        default:
+            ret = s->cmos_data[s->cmos_index];
+            break;
+        }
+#ifdef DEBUG_RTC
+        printk("HVM_RTC: read index=0x%02x val=0x%02x\n",
+               s->cmos_index, ret);
+#endif
+        return ret;
+    }
+}
+
+static int handle_rtc_io(ioreq_t *p)
+{
+    struct vcpu *v = current;
+    struct RTCState *vrtc = &v->domain->arch.hvm_domain.pl_time.vrtc;
+
+    if (p->size != 1 ||
+        p->pdata_valid ||
+        p->type != IOREQ_TYPE_PIO){
+        printk("HVM_RTC: wrong RTC IO!\n");
+        return 1;
+    }
+    
+    if (p->dir == 0) { /* write */
+        if (rtc_ioport_write(vrtc, p->addr, p->u.data & 0xFF))
+            return 1;
+    } else if (p->dir == 1 && vrtc->cmos_index < RTC_SIZE) { /* read */
+        p->u.data = rtc_ioport_read(vrtc, p->addr);
+        return 1;
+    }
+    return 0;
+}
+
+void rtc_init(struct vcpu *v, int base, int irq)
+{
+    RTCState *s = &v->domain->arch.hvm_domain.pl_time.vrtc;
+
+    s->vcpu = v;
+    s->irq = irq;
+    s->cmos_data[RTC_REG_A] = 0x26;
+    s->cmos_data[RTC_REG_B] = 0x02;
+    s->cmos_data[RTC_REG_C] = 0x00;
+    s->cmos_data[RTC_REG_D] = 0x80;
+
+    s->current_tm = gmtime(get_localtime(v->domain));
+    rtc_copy_date(s);
+
+    init_timer(&s->second_timer, rtc_update_second, s, v->processor);
+    init_timer(&s->second_timer2, rtc_update_second2, s, v->processor);
+
+    s->next_second_time = NOW() + 1000000000ULL;
+    set_timer(&s->second_timer2, s->next_second_time);
+
+    register_portio_handler(base, 2, handle_rtc_io);
+}
+
+void rtc_deinit(struct domain *d)
+{
+    RTCState *s = &d->arch.hvm_domain.pl_time.vrtc;
+
+    kill_timer(&s->second_timer);
+    kill_timer(&s->second_timer2);
+}
diff -r da66691687df -r 71e2a165aa7f xen/common/time.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/common/time.c Wed Oct 18 18:35:21 2006 +0100
@@ -0,0 +1,77 @@
+/******************************************************************************
+ * time.c
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <xen/config.h>
+#include <xen/time.h>
+
+/* Nonzero if YEAR is a leap year (every 4 years,
+   except every 100th isn't, and every 400th is).  */
+#define __isleap(year) \
+  ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
+
+/* How many days are in each month.  */
+const unsigned short int __mon_lengths[2][12] = {
+    /* Normal years.  */
+    {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
+    /* Leap years.  */
+    {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
+};
+
+#define SECS_PER_HOUR (60 * 60)
+#define SECS_PER_DAY  (SECS_PER_HOUR * 24)
+
+struct tm gmtime(unsigned long t)
+{
+    struct tm tbuf;
+    long days, rem;
+    int y;
+    unsigned short int *ip;
+
+    days = t / SECS_PER_DAY;
+    rem = t % SECS_PER_DAY;
+
+    tbuf.tm_hour = rem / SECS_PER_HOUR;
+    rem %= SECS_PER_HOUR;
+    tbuf.tm_min = rem / 60;
+    tbuf.tm_sec = rem % 60;
+    /* January 1, 1970 was a Thursday.  */
+    tbuf.tm_wday = (4 + days) % 7;
+    if ( tbuf.tm_wday < 0 )
+        tbuf.tm_wday += 7;
+    y = 1970;
+    while ( days >= (rem = __isleap(y) ? 366 : 365) )
+    {
+        ++y;
+        days -= rem;
+    }
+    while ( days < 0 )
+    {
+        --y;
+        days += __isleap(y) ? 366 : 365;
+    }
+    tbuf.tm_year = y - 1900;
+    tbuf.tm_yday = days;
+    ip = (unsigned short int *)__mon_lengths[__isleap(y)];
+    for ( y = 0; days >= ip[y]; ++y )
+        days -= ip[y];
+    tbuf.tm_mon = y;
+    tbuf.tm_mday = days + 1;
+    tbuf.tm_isdst = -1;
+
+    return tbuf;
+}

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-unstable] [HVM] Move RTC emulation into the hypervisor., Xen patchbot-unstable <=