/* Set the correct value in the timer, accounting for time elapsed * since the last time we did that. */ static void pmt_update_time(PMTState *s) { uint64_t curr_gtime, tmp; uint32_t tmr_val = s->pm.tmr_val, msb = tmr_val & TMR_VAL_MSB; ASSERT(spin_is_locked(&s->lock)); /* Update the timer */ curr_gtime = hvm_get_guest_time(s->vcpu); tmp = ((curr_gtime - s->last_gtime) * s->scale) + s->not_accounted; s->not_accounted = (uint32_t)tmp; tmr_val += tmp >> 32; tmr_val &= TMR_VAL_MASK; s->last_gtime = curr_gtime; /* Update timer value atomically wrt lock-free reads in handle_pmt_io(). */ *(volatile uint32_t *)&s->pm.tmr_val = tmr_val; /* If the counter's MSB has changed, set the status bit */ if ( (tmr_val & TMR_VAL_MSB) != msb ) { s->pm.pm1a_sts |= TMR_STS; pmt_update_sci(s); } }
void hvm_acpi_sleep_button(struct domain *d) { PMTState *s = &d->arch.hvm_domain.pl_time.vpmt; spin_lock(&s->lock); s->pm.pm1a_sts |= SLPBTN_STS; pmt_update_sci(s); spin_unlock(&s->lock); }
/* Handle port I/O to the PM1a_STS and PM1a_EN registers */ static int handle_evt_io( int dir, uint32_t port, uint32_t bytes, uint32_t *val) { struct vcpu *v = current; PMTState *s = &v->domain->arch.hvm_domain.pl_time.vpmt; uint32_t addr, data, byte; int i; addr = port - ((v->domain->arch.hvm_domain.params[ HVM_PARAM_ACPI_IOPORTS_LOCATION] == 0) ? PM1a_STS_ADDR_V0 : PM1a_STS_ADDR_V1); spin_lock(&s->lock); if ( dir == IOREQ_WRITE ) { /* Handle this I/O one byte at a time */ for ( i = bytes, data = *val; i > 0; i--, addr++, data >>= 8 ) { byte = data & 0xff; switch ( addr ) { /* PM1a_STS register bits are write-to-clear */ case 0 /* PM1a_STS_ADDR */: s->pm.pm1a_sts &= ~byte; break; case 1 /* PM1a_STS_ADDR + 1 */: s->pm.pm1a_sts &= ~(byte << 8); break; case 2 /* PM1a_EN_ADDR */: s->pm.pm1a_en = (s->pm.pm1a_en & 0xff00) | byte; break; case 3 /* PM1a_EN_ADDR + 1 */: s->pm.pm1a_en = (s->pm.pm1a_en & 0xff) | (byte << 8); break; default: gdprintk(XENLOG_WARNING, "Bad ACPI PM register write: %x bytes (%x) at %x\n", bytes, *val, port); } } /* Fix up the SCI state to match the new register state */ pmt_update_sci(s); } else /* p->dir == IOREQ_READ */ {
/* Set the correct value in the timer, accounting for time elapsed * since the last time we did that. */ static void pmt_update_time(PMTState *s) { uint64_t curr_gtime; uint32_t msb = s->pm.tmr_val & TMR_VAL_MSB; ASSERT(spin_is_locked(&s->lock)); /* Update the timer */ curr_gtime = hvm_get_guest_time(s->vcpu); s->pm.tmr_val += ((curr_gtime - s->last_gtime) * s->scale) >> 32; s->pm.tmr_val &= TMR_VAL_MASK; s->last_gtime = curr_gtime; /* If the counter's MSB has changed, set the status bit */ if ( (s->pm.tmr_val & TMR_VAL_MSB) != msb ) { s->pm.pm1a_sts |= TMR_STS; pmt_update_sci(s); } }