1 /*
2  * vpt.h: Virtual Platform Timer definitions
3  *
4  * Copyright (c) 2004, Intel Corporation.
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * this program; If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #ifndef __ASM_X86_HVM_VPT_H__
20 #define __ASM_X86_HVM_VPT_H__
21 
22 #include <xen/timer.h>
23 #include <xen/list.h>
24 #include <xen/rwlock.h>
25 #include <asm/hvm/hvm.h>
26 
27 /*
28  * Abstract layer of periodic time, one short time.
29  */
30 typedef void time_cb(struct vcpu *v, void *opaque);
31 
32 struct periodic_time {
33     struct list_head list;
34     bool on_list;
35     bool one_shot;
36     bool do_not_freeze;
37     bool irq_issued;
38     bool warned_timeout_too_short;
39     bool level;
40 #define PTSRC_isa    1 /* ISA time source */
41 #define PTSRC_lapic  2 /* LAPIC time source */
42 #define PTSRC_ioapic 3 /* IOAPIC time source */
43     u8 source;                  /* PTSRC_ */
44     u8 irq;
45     struct vcpu *vcpu;          /* vcpu timer interrupt delivers to */
46     u32 pending_intr_nr;        /* pending timer interrupts */
47     u64 period;                 /* frequency in ns */
48     s_time_t scheduled;         /* scheduled timer interrupt */
49     u64 last_plt_gtime;         /* platform time when last IRQ is injected */
50     struct timer timer;         /* ac_timer */
51     time_cb *cb;
52     void *priv;                 /* point back to platform time source */
53 };
54 
55 
56 #define PIT_FREQ 1193182
57 #define PIT_BASE 0x40
58 
59 typedef struct PITState {
60     /* Hardware state */
61     struct hvm_hw_pit hw;
62     /* Last time the counters read zero, for calcuating counter reads */
63     int64_t count_load_time[3];
64     /* Channel 0 IRQ handling. */
65     struct periodic_time pt0;
66     spinlock_t lock;
67 } PITState;
68 
69 struct hpet_registers {
70     /* Memory-mapped, software visible registers */
71     uint64_t capability;        /* capabilities */
72     uint64_t config;            /* configuration */
73     uint64_t isr;               /* interrupt status reg */
74     uint64_t mc64;              /* main counter */
75     struct {                    /* timers */
76         uint64_t config;        /* configuration/cap */
77         uint64_t cmp;           /* comparator */
78         uint64_t fsb;           /* FSB route, not supported now */
79     } timers[HPET_TIMER_NUM];
80 
81     /* Hidden register state */
82     uint64_t period[HPET_TIMER_NUM]; /* Last value written to comparator */
83     uint64_t comparator64[HPET_TIMER_NUM]; /* 64 bit running comparator */
84 };
85 
86 typedef struct HPETState {
87     struct hpet_registers hpet;
88     uint64_t stime_freq;
89     uint64_t hpet_to_ns_scale; /* hpet ticks to ns (multiplied by 2^10) */
90     uint64_t hpet_to_ns_limit; /* max hpet ticks convertable to ns      */
91     uint64_t mc_offset;
92     struct periodic_time pt[HPET_TIMER_NUM];
93     rwlock_t lock;
94 } HPETState;
95 
96 typedef struct RTCState {
97     /* Hardware state */
98     struct hvm_hw_rtc hw;
99     /* RTC's idea of the current time */
100     struct tm current_tm;
101     /* update-ended timer */
102     struct timer update_timer;
103     struct timer update_timer2;
104     uint64_t next_update_time;
105     /* alarm timer */
106     struct timer alarm_timer;
107     /* periodic timer */
108     struct periodic_time pt;
109     s_time_t start_time;
110     s_time_t check_ticks_since;
111     int period;
112     uint8_t pt_dead_ticks;
113     uint32_t use_timer;
114     spinlock_t lock;
115 } RTCState;
116 
117 #define FREQUENCE_PMTIMER  3579545  /* Timer should run at 3.579545 MHz */
118 typedef struct PMTState {
119     struct vcpu *vcpu;          /* Keeps sync with this vcpu's guest-time */
120     uint64_t last_gtime;        /* Last (guest) time we updated the timer */
121     uint32_t not_accounted;     /* time not accounted at last update */
122     uint64_t scale;             /* Multiplier to get from tsc to timer ticks */
123     struct timer timer;         /* To make sure we send SCIs */
124     spinlock_t lock;
125 } PMTState;
126 
127 struct pl_time {    /* platform time */
128     struct RTCState  vrtc;
129     struct HPETState vhpet;
130     struct PMTState  vpmt;
131     /*
132      * rwlock to prevent periodic_time vCPU migration. Take the lock in read
133      * mode in order to prevent the vcpu field of periodic_time from changing.
134      * Lock must be taken in write mode when changes to the vcpu field are
135      * performed, as it allows exclusive access to all the timers of a domain.
136      */
137     rwlock_t pt_migrate;
138     /* guest_time = Xen sys time + stime_offset */
139     int64_t stime_offset;
140     /* Ensures monotonicity in appropriate timer modes. */
141     uint64_t last_guest_time;
142     spinlock_t pl_time_lock;
143     struct domain *domain;
144 };
145 
146 void pt_save_timer(struct vcpu *v);
147 void pt_restore_timer(struct vcpu *v);
148 int pt_update_irq(struct vcpu *v);
149 struct hvm_intack;
150 void pt_intr_post(struct vcpu *v, struct hvm_intack intack);
151 void pt_migrate(struct vcpu *v);
152 
153 void pt_adjust_global_vcpu_target(struct vcpu *v);
154 #define pt_global_vcpu_target(d) \
155     (is_hvm_domain(d) && (d)->arch.hvm.i8259_target ? \
156      (d)->arch.hvm.i8259_target : \
157      (d)->vcpu ? (d)->vcpu[0] : NULL)
158 
159 void pt_may_unmask_irq(struct domain *d, struct periodic_time *vlapic_pt);
160 
161 /* Is given periodic timer active? */
162 #define pt_active(pt) ((pt)->on_list || (pt)->pending_intr_nr)
163 
164 /*
165  * Create/destroy a periodic (or one-shot!) timer.
166  * The given periodic timer structure must be initialised with zero bytes,
167  * except for the 'source' field which must be initialised with the
168  * correct PTSRC_ value. The initialised timer structure can then be passed
169  * to {create,destroy}_periodic_time() any number of times and in any order.
170  * Note that, for a given periodic timer, invocations of these functions MUST
171  * be serialised.
172  */
173 void create_periodic_time(
174     struct vcpu *v, struct periodic_time *pt, uint64_t delta,
175     uint64_t period, uint8_t irq, time_cb *cb, void *data, bool level);
176 void destroy_periodic_time(struct periodic_time *pt);
177 
178 int pv_pit_handler(int port, int data, int write);
179 void pit_reset(struct domain *d);
180 
181 void pit_init(struct domain *d, unsigned long cpu_khz);
182 void pit_stop_channel0_irq(PITState * pit);
183 void pit_deinit(struct domain *d);
184 void rtc_init(struct domain *d);
185 void rtc_migrate_timers(struct vcpu *v);
186 void rtc_deinit(struct domain *d);
187 void rtc_reset(struct domain *d);
188 void rtc_update_clock(struct domain *d);
189 
190 void pmtimer_init(struct vcpu *v);
191 void pmtimer_deinit(struct domain *d);
192 void pmtimer_reset(struct domain *d);
193 int pmtimer_change_ioport(struct domain *d, uint64_t version);
194 
195 void hpet_init(struct domain *d);
196 void hpet_deinit(struct domain *d);
197 void hpet_reset(struct domain *d);
198 
199 #endif /* __ASM_X86_HVM_VPT_H__ */
200