2
* hvm/pmtimer.c: emulation of the ACPI PM timer
4
* Copyright (c) 2007, XenSource inc.
5
* Copyright (c) 2006, Intel Corporation.
7
* This program is free software; you can redistribute it and/or modify it
8
* under the terms and conditions of the GNU General Public License,
9
* version 2, as published by the Free Software Foundation.
11
* This program is distributed in the hope it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16
* You should have received a copy of the GNU General Public License along with
17
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
18
* Place - Suite 330, Boston, MA 02111-1307 USA.
21
#include <asm/hvm/vpt.h>
22
#include <asm/hvm/io.h>
23
#include <asm/hvm/support.h>
24
#include <asm/acpi.h> /* for hvm_acpi_power_button prototype */
26
/* Slightly more readable port I/O addresses for the registers we intercept */
27
#define PM1a_STS_ADDR (ACPI_PM1A_EVT_BLK_ADDRESS)
28
#define PM1a_EN_ADDR (ACPI_PM1A_EVT_BLK_ADDRESS + 2)
29
#define TMR_VAL_ADDR (ACPI_PM_TMR_BLK_ADDRESS)
31
/* The interesting bits of the PM1a_STS register */
32
#define TMR_STS (1 << 0)
33
#define GBL_STS (1 << 5)
34
#define PWRBTN_STS (1 << 8)
35
#define SLPBTN_STS (1 << 9)
37
/* The same in PM1a_EN */
38
#define TMR_EN (1 << 0)
39
#define GBL_EN (1 << 5)
40
#define PWRBTN_EN (1 << 8)
41
#define SLPBTN_EN (1 << 9)
43
/* Mask of bits in PM1a_STS that can generate an SCI. */
44
#define SCI_MASK (TMR_STS|PWRBTN_STS|SLPBTN_STS|GBL_STS)
46
/* SCI IRQ number (must match SCI_INT number in ACPI FADT in hvmloader) */
49
/* We provide a 32-bit counter (must match the TMR_VAL_EXT bit in the FADT) */
50
#define TMR_VAL_MASK (0xffffffff)
51
#define TMR_VAL_MSB (0x80000000)
53
/* Dispatch SCIs based on the PM1a_STS and PM1a_EN registers */
54
static void pmt_update_sci(PMTState *s)
56
ASSERT(spin_is_locked(&s->lock));
58
if ( s->pm.pm1a_en & s->pm.pm1a_sts & SCI_MASK )
59
hvm_isa_irq_assert(s->vcpu->domain, SCI_IRQ);
61
hvm_isa_irq_deassert(s->vcpu->domain, SCI_IRQ);
64
void hvm_acpi_power_button(struct domain *d)
66
PMTState *s = &d->arch.hvm_domain.pl_time.vpmt;
68
s->pm.pm1a_sts |= PWRBTN_STS;
70
spin_unlock(&s->lock);
73
void hvm_acpi_sleep_button(struct domain *d)
75
PMTState *s = &d->arch.hvm_domain.pl_time.vpmt;
77
s->pm.pm1a_sts |= SLPBTN_STS;
79
spin_unlock(&s->lock);
82
/* Set the correct value in the timer, accounting for time elapsed
83
* since the last time we did that. */
84
static void pmt_update_time(PMTState *s)
87
uint32_t msb = s->pm.tmr_val & TMR_VAL_MSB;
89
ASSERT(spin_is_locked(&s->lock));
91
/* Update the timer */
92
curr_gtime = hvm_get_guest_time(s->vcpu);
93
s->pm.tmr_val += ((curr_gtime - s->last_gtime) * s->scale) >> 32;
94
s->pm.tmr_val &= TMR_VAL_MASK;
95
s->last_gtime = curr_gtime;
97
/* If the counter's MSB has changed, set the status bit */
98
if ( (s->pm.tmr_val & TMR_VAL_MSB) != msb )
100
s->pm.pm1a_sts |= TMR_STS;
105
/* This function should be called soon after each time the MSB of the
106
* pmtimer register rolls over, to make sure we update the status
107
* registers and SCI at least once per rollover */
108
static void pmt_timer_callback(void *opaque)
110
PMTState *s = opaque;
111
uint32_t pmt_cycles_until_flip;
112
uint64_t time_until_flip;
116
/* Recalculate the timer and make sure we get an SCI if we need one */
119
/* How close are we to the next MSB flip? */
120
pmt_cycles_until_flip = TMR_VAL_MSB - (s->pm.tmr_val & (TMR_VAL_MSB - 1));
122
/* Overall time between MSB flips */
123
time_until_flip = (1000000000ULL << 23) / FREQUENCE_PMTIMER;
125
/* Reduced appropriately */
126
time_until_flip = (time_until_flip * pmt_cycles_until_flip) >> 23;
128
/* Wake up again near the next bit-flip */
129
set_timer(&s->timer, NOW() + time_until_flip + MILLISECS(1));
131
spin_unlock(&s->lock);
134
/* Handle port I/O to the PM1a_STS and PM1a_EN registers */
135
static int handle_evt_io(
136
int dir, uint32_t port, uint32_t bytes, uint32_t *val)
138
struct vcpu *v = current;
139
PMTState *s = &v->domain->arch.hvm_domain.pl_time.vpmt;
140
uint32_t addr, data, byte;
145
if ( dir == IOREQ_WRITE )
147
/* Handle this I/O one byte at a time */
148
for ( i = bytes, addr = port, data = *val;
150
i--, addr++, data >>= 8 )
155
/* PM1a_STS register bits are write-to-clear */
157
s->pm.pm1a_sts &= ~byte;
159
case PM1a_STS_ADDR + 1:
160
s->pm.pm1a_sts &= ~(byte << 8);
164
s->pm.pm1a_en = (s->pm.pm1a_en & 0xff00) | byte;
166
case PM1a_EN_ADDR + 1:
167
s->pm.pm1a_en = (s->pm.pm1a_en & 0xff) | (byte << 8);
171
gdprintk(XENLOG_WARNING,
172
"Bad ACPI PM register write: %x bytes (%x) at %x\n",
176
/* Fix up the SCI state to match the new register state */
179
else /* p->dir == IOREQ_READ */
181
data = s->pm.pm1a_sts | (((uint32_t) s->pm.pm1a_en) << 16);
182
data >>= 8 * (port - PM1a_STS_ADDR);
183
if ( bytes == 1 ) data &= 0xff;
184
else if ( bytes == 2 ) data &= 0xffff;
188
spin_unlock(&s->lock);
194
/* Handle port I/O to the TMR_VAL register */
195
static int handle_pmt_io(
196
int dir, uint32_t port, uint32_t bytes, uint32_t *val)
198
struct vcpu *v = current;
199
PMTState *s = &v->domain->arch.hvm_domain.pl_time.vpmt;
203
gdprintk(XENLOG_WARNING, "HVM_PMT bad access\n");
207
if ( dir == IOREQ_READ )
211
*val = s->pm.tmr_val;
212
spin_unlock(&s->lock);
216
return X86EMUL_UNHANDLEABLE;
219
static int pmtimer_save(struct domain *d, hvm_domain_context_t *h)
221
PMTState *s = &d->arch.hvm_domain.pl_time.vpmt;
222
uint32_t x, msb = s->pm.tmr_val & TMR_VAL_MSB;
227
/* Update the counter to the guest's current time. We always save
228
* with the domain paused, so the saved time should be after the
229
* last_gtime, but just in case, make sure we only go forwards */
230
x = ((s->vcpu->arch.hvm_vcpu.guest_time - s->last_gtime) * s->scale) >> 32;
233
if ( (s->pm.tmr_val & TMR_VAL_MSB) != msb )
234
s->pm.pm1a_sts |= TMR_STS;
235
/* No point in setting the SCI here because we'll already have saved the
236
* IRQ and *PIC state; we'll fix it up when we restore the domain */
238
rc = hvm_save_entry(PMTIMER, 0, h, &s->pm);
240
spin_unlock(&s->lock);
245
static int pmtimer_load(struct domain *d, hvm_domain_context_t *h)
247
PMTState *s = &d->arch.hvm_domain.pl_time.vpmt;
251
/* Reload the registers */
252
if ( hvm_load_entry(PMTIMER, h, &s->pm) )
254
spin_unlock(&s->lock);
258
/* Calculate future counter values from now. */
259
s->last_gtime = hvm_get_guest_time(s->vcpu);
261
/* Set the SCI state from the registers */
264
spin_unlock(&s->lock);
269
HVM_REGISTER_SAVE_RESTORE(PMTIMER, pmtimer_save, pmtimer_load,
272
void pmtimer_init(struct vcpu *v)
274
PMTState *s = &v->domain->arch.hvm_domain.pl_time.vpmt;
276
spin_lock_init(&s->lock);
278
s->scale = ((uint64_t)FREQUENCE_PMTIMER << 32) / SYSTEM_TIME_HZ;
281
/* Intercept port I/O (need two handlers because PM1a_CNT is between
282
* PM1a_EN and TMR_VAL and is handled by qemu) */
283
register_portio_handler(v->domain, TMR_VAL_ADDR, 4, handle_pmt_io);
284
register_portio_handler(v->domain, PM1a_STS_ADDR, 4, handle_evt_io);
286
/* Set up callback to fire SCIs when the MSB of TMR_VAL changes */
287
init_timer(&s->timer, pmt_timer_callback, s, v->processor);
288
pmt_timer_callback(s);
292
void pmtimer_deinit(struct domain *d)
294
PMTState *s = &d->arch.hvm_domain.pl_time.vpmt;
295
kill_timer(&s->timer);
298
void pmtimer_reset(struct domain *d)
300
/* Reset the counter. */
301
d->arch.hvm_domain.pl_time.vpmt.pm.tmr_val = 0;