DevHPET.cpp revision af5224eb6b6676bc892a3f5abeb21f602547d31c
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/* $Id$ */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/** @file
5b281ba489ca18f0380d7efc7a5108b606cce449vboxsync * HPET virtual device - high precision event timer emulation
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/*
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Copyright (C) 2009-2010 Sun Microsystems, Inc.
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync *
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * available from http://www.virtualbox.org. This file is free software;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * you can redistribute it and/or modify it under the terms of the GNU
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * General Public License (GPL) as published by the Free Software
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync *
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * additional information or have any questions.
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync */
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync/*******************************************************************************
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync* Header Files *
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync*******************************************************************************/
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync#define LOG_GROUP LOG_GROUP_DEV_HPET
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync#include <VBox/pdmdev.h>
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync#include <VBox/log.h>
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync#include <VBox/stam.h>
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync#include <iprt/assert.h>
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync#include <iprt/string.h>
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#include <iprt/asm.h>
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#include "../Builtins.h"
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/*
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Current limitations:
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * - not entirely correct time of interrupt, i.e. never
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * schedule interrupt earlier than in 1ms
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * - statistics not implemented
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * - level-triggered mode not implemented
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/*
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Base address for MMIO
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#define HPET_BASE 0xfed00000
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/*
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Number of available timers, cannot be changed without
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * breaking saved states.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#define HPET_NUM_TIMERS 3
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/*
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * 10000000 femtoseconds == 10ns
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#define HPET_CLK_PERIOD 10000000UL
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/*
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Femptosecods in nanosecond
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#define FS_PER_NS 1000000
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/*
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Interrupt type
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#define HPET_TIMER_TYPE_LEVEL 1
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#define HPET_TIMER_TYPE_EDGE 0
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/* Delivery mode */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/* Via APIC */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#define HPET_TIMER_DELIVERY_APIC 0
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/* Via FSB */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#define HPET_TIMER_DELIVERY_FSB 1
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#define HPET_TIMER_CAP_FSB_INT_DEL (1 << 15)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#define HPET_TIMER_CAP_PER_INT (1 << 4)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#define HPET_CFG_ENABLE 0x001 /* ENABLE_CNF */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#define HPET_CFG_LEGACY 0x002 /* LEG_RT_CNF */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#define HPET_ID 0x000
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#define HPET_PERIOD 0x004
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#define HPET_CFG 0x010
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#define HPET_STATUS 0x020
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#define HPET_COUNTER 0x0f0
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#define HPET_TN_CFG 0x000
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#define HPET_TN_CMP 0x008
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#define HPET_TN_ROUTE 0x010
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#define HPET_CFG_WRITE_MASK 0x3
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#define HPET_TN_INT_TYPE (1 << 1)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#define HPET_TN_ENABLE (1 << 2)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#define HPET_TN_PERIODIC (1 << 3)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#define HPET_TN_PERIODIC_CAP (1 << 4)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#define HPET_TN_SIZE_CAP (1 << 5)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#define HPET_TN_SETVAL (1 << 6)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#define HPET_TN_32BIT (1 << 8)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#define HPET_TN_INT_ROUTE_MASK 0x3e00
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#define HPET_TN_CFG_WRITE_MASK 0x3f4e
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#define HPET_TN_INT_ROUTE_SHIFT 9
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#define HPET_TN_INT_ROUTE_CAP_SHIFT 32
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#define HPET_TN_CFG_BITS_READONLY_OR_RESERVED 0xffff80b1U
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/** The version of the saved state. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#define HPET_SAVED_STATE_VERSION 2
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/* Empty saved state */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#define HPET_SAVED_STATE_VERSION_EMPTY 1
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstruct HpetState;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsynctypedef struct HpetTimer
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /** The HPET timer - R3 Ptr. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync PTMTIMERR3 pTimerR3;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /** Pointer to the instance data - R3 Ptr. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync R3PTRTYPE(struct HpetState *) pHpetR3;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /** The HPET timer - R0 Ptr. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync PTMTIMERR0 pTimerR0;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /** Pointer to the instance data - R0 Ptr. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync R0PTRTYPE(struct HpetState *) pHpetR0;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /** The HPET timer - RC Ptr. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync PTMTIMERRC pTimerRC;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /** Pointer to the instance data - RC Ptr. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync RCPTRTYPE(struct HpetState *) pHpetRC;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* timer number*/
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint8_t u8TimerNumber;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* Wrap */
cf3aad827eee194a3e6e68796710074b44164371vboxsync uint8_t u8Wrap;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* Alignment */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint32_t alignment0;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* Memory-mapped, software visible timer registers */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* Configuration/capabilities */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint64_t u64Config;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* comparator */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint64_t u64Cmp;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* FSB route, not supported now */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint64_t u64Fsb;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* Hidden register state */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* Last value written to comparator */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint64_t u64Period;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync} HpetTimer;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsynctypedef struct HpetState
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /** Pointer to the device instance. - R3 ptr. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync PPDMDEVINSR3 pDevInsR3;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /** The HPET helpers - R3 Ptr. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync PCPDMHPETHLPR3 pHpetHlpR3;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /** Pointer to the device instance. - R0 ptr. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync PPDMDEVINSR0 pDevInsR0;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /** The HPET helpers - R0 Ptr. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync PCPDMHPETHLPR0 pHpetHlpR0;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /** Pointer to the device instance. - RC ptr. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync PPDMDEVINSRC pDevInsRC;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /** The HPET helpers - RC Ptr. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync PCPDMHPETHLPRC pHpetHlpRC;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* Timer structures */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync HpetTimer aTimers[HPET_NUM_TIMERS];
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* Offset realtive to the system clock */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint64_t u64HpetOffset;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* Memory-mapped, software visible registers */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* capabilities */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint64_t u64Capabilities;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* configuration */
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync uint64_t u64Config;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* interrupt status register */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint64_t u64Isr;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* main counter */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint64_t u64HpetCounter;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync /* Global device lock */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync PDMCRITSECT csLock;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync} HpetState;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#ifndef VBOX_DEVICE_STRUCT_TESTCASE
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/*
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * We shall declare MMIO accessors as extern "C" to avoid name mangling
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * and let them be found during R0/RC module init.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Maybe PDMBOTHCBDECL macro shall have extern "C" part in it.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncRT_C_DECLS_BEGIN
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncPDMBOTHCBDECL(int) hpetMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncPDMBOTHCBDECL(int) hpetMMIORead (PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsyncRT_C_DECLS_END
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync/*
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Temporary control to disble locking if problems found
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic const bool fHpetLocking = true;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncDECLINLINE(int) hpetLock(HpetState* pThis, int rcBusy)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (!fHpetLocking)
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync return VINF_SUCCESS;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return PDMCritSectEnter(&pThis->csLock, rcBusy);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncDECLINLINE(void) hpetUnlock(HpetState* pThis)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (!fHpetLocking)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync PDMCritSectLeave(&pThis->csLock);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic uint32_t hpetTimeAfter32(uint64_t a, uint64_t b)
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync{
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync return ((int32_t)(b) - (int32_t)(a) <= 0);
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync}
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsyncstatic uint32_t hpetTimeAfter64(uint64_t a, uint64_t b)
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync{
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync return ((int64_t)(b) - (int64_t)(a) <= 0);
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync}
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsyncstatic uint64_t hpetTicksToNs(uint64_t value)
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync{
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync return (ASMMultU64ByU32DivByU32(value, HPET_CLK_PERIOD, FS_PER_NS));
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync}
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsyncstatic uint64_t nsToHpetTicks(uint64_t u64Value)
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync{
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync return (ASMMultU64ByU32DivByU32(u64Value, FS_PER_NS, HPET_CLK_PERIOD));
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync}
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsyncstatic uint64_t hpetGetTicks(HpetState* pThis)
3ae788d4138a852743619b65c7404deb5cbae3e7vboxsync{
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync /*
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * We can use any timer to get current time, they all go
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * with the same speed.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return nsToHpetTicks(TMTimerGet(pThis->aTimers[0].CTX_SUFF(pTimer)) +
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync pThis->u64HpetOffset);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic uint64_t updateMasked(uint64_t u64NewValue,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint64_t u64OldValue,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint64_t u64Mask)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync u64NewValue &= u64Mask;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync u64NewValue |= u64OldValue & ~u64Mask;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return u64NewValue;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic bool isBitJustSet(uint64_t u64OldValue,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint64_t u64NewValue,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint64_t u64Mask)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return (!(u64OldValue & u64Mask) && (u64NewValue & u64Mask));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic bool isBitJustCleared(uint64_t u64OldValue,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint64_t u64NewValue,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint64_t u64Mask)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return ((u64OldValue & u64Mask) && !(u64NewValue & u64Mask));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncDECLINLINE(uint64_t) hpetComputeDiff(HpetTimer* pTimer,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint64_t u64Now)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (pTimer->u64Config & HPET_TN_32BIT)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint32_t u32Diff;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync u32Diff = (uint32_t)pTimer->u64Cmp - (uint32_t)u64Now;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync u32Diff = ((int32_t)u32Diff > 0) ? u32Diff : (uint32_t)0;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return (uint64_t)u32Diff;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync } else {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint64_t u64Diff;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync u64Diff = pTimer->u64Cmp - u64Now;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync u64Diff = ((int64_t)u64Diff > 0) ? u64Diff : (uint64_t)0;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return u64Diff;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic void hpetAdjustComparator(HpetTimer* pTimer,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint64_t u64Now)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint64_t u64Period = pTimer->u64Period;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if ((pTimer->u64Config & HPET_TN_PERIODIC) && (u64Period != 0))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* While loop is suboptimal */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (pTimer->u64Config & HPET_TN_32BIT)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync while (hpetTimeAfter32(u64Now, pTimer->u64Cmp))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pTimer->u64Cmp = (uint32_t)(pTimer->u64Cmp + u64Period);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync else
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync while (hpetTimeAfter64(u64Now, pTimer->u64Cmp))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pTimer->u64Cmp += u64Period;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic void hpetProgramTimer(HpetTimer *pTimer)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint64_t u64Diff;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint32_t u32TillWrap;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint64_t u64Ticks = hpetGetTicks(pTimer->CTX_SUFF(pHpet));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* no wrapping on new timers */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pTimer->u8Wrap = 0;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync hpetAdjustComparator(pTimer, u64Ticks);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync u64Diff = hpetComputeDiff(pTimer, u64Ticks);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* Spec says in one-shot 32-bit mode, generate an interrupt when
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * counter wraps in addition to an interrupt with comparator match.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if ((pTimer->u64Config & HPET_TN_32BIT) && !(pTimer->u64Config & HPET_TN_PERIODIC))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync u32TillWrap = 0xffffffff - (uint32_t)u64Ticks;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (u32TillWrap < (uint32_t)u64Diff)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync u64Diff = u32TillWrap;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pTimer->u8Wrap = 1;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* Avoid killing VM with interrupts */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#if 1
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* @todo: HACK, rethink, may have negative impact on the guest */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (u64Diff == 0)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync u64Diff = 100000; /* 1 millisecond */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#endif
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync Log4(("HPET: next IRQ in %lld ticks (%lld ns)\n", u64Diff, hpetTicksToNs(u64Diff)));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync TMTimerSetNano(pTimer->CTX_SUFF(pTimer), hpetTicksToNs(u64Diff));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic uint32_t getTimerIrq(struct HpetTimer *pTimer)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /*
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * Per spec, in legacy mode HPET timers wired as:
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * timer 0: IRQ0 for PIC and IRQ2 for APIC
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * timer 1: IRQ8 for both PIC and APIC
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync *
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * ISA IRQ delivery logic will take care of correct delivery
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * to the different ICs.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if ((pTimer->u8TimerNumber <= 1) &&
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync (pTimer->CTX_SUFF(pHpet)->u64Config & HPET_CFG_LEGACY))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return (pTimer->u8TimerNumber == 0) ? 0 : 8;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync else
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return (pTimer->u64Config & HPET_TN_INT_ROUTE_MASK) >> HPET_TN_INT_ROUTE_SHIFT;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic int timerRegRead32(HpetState* pThis,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint32_t iTimerNo,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint32_t iTimerReg,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint32_t * pValue)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync HpetTimer *pTimer;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (iTimerNo >= HPET_NUM_TIMERS)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync LogRel(("HPET: using timer above configured range: %d\n", iTimerNo));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return VINF_SUCCESS;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pTimer = &pThis->aTimers[iTimerNo];
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync switch (iTimerReg)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync case HPET_TN_CFG:
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync Log(("read HPET_TN_CFG on %d\n", pTimer->u8TimerNumber));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync *pValue = (uint32_t)(pTimer->u64Config);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync break;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync case HPET_TN_CFG + 4:
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync Log(("read HPET_TN_CFG+4 on %d\n", pTimer->u8TimerNumber));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync *pValue = (uint32_t)(pTimer->u64Config >> 32);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync break;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync case HPET_TN_CMP:
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync Log(("read HPET_TN_CMP on %d, cmp=%llx\n", pTimer->u8TimerNumber, pTimer->u64Cmp));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync *pValue = (uint32_t)(pTimer->u64Cmp);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync break;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync case HPET_TN_CMP + 4:
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync Log(("read HPET_TN_CMP+4 on %d, cmp=%llx\n", pTimer->u8TimerNumber, pTimer->u64Cmp));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync *pValue = (uint32_t)(pTimer->u64Cmp >> 32);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync break;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync case HPET_TN_ROUTE:
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync Log(("read HPET_TN_ROUTE on %d\n", pTimer->u8TimerNumber));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync *pValue = (uint32_t)(pTimer->u64Fsb >> 32);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync break;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync default:
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync LogRel(("invalid HPET register read %d on %d\n", iTimerReg, pTimer->u8TimerNumber));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync break;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return VINF_SUCCESS;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic int configRegRead32(HpetState* pThis,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint32_t iIndex,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint32_t *pValue)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync switch (iIndex)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync case HPET_ID:
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync Log(("read HPET_ID\n"));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync *pValue = (uint32_t)(pThis->u64Capabilities);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync break;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync case HPET_PERIOD:
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync Log(("read HPET_PERIOD\n"));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync *pValue = (uint32_t)(pThis->u64Capabilities >> 32);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync break;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync case HPET_CFG:
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync Log(("read HPET_CFG\n"));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync *pValue = (uint32_t)(pThis->u64Config);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync break;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync case HPET_CFG + 4:
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync Log(("read of HPET_CFG + 4\n"));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync *pValue = (uint32_t)(pThis->u64Config >> 32);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync break;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync case HPET_COUNTER:
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync case HPET_COUNTER + 4:
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint64_t u64Ticks;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync Log(("read HPET_COUNTER\n"));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (pThis->u64Config & HPET_CFG_ENABLE)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync u64Ticks = hpetGetTicks(pThis);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync else
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync u64Ticks = pThis->u64HpetCounter;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /** @todo: is it correct? */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync *pValue = (iIndex == HPET_COUNTER) ? (uint32_t)u64Ticks : (uint32_t)(u64Ticks >> 32);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync break;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync case HPET_STATUS:
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync Log(("read HPET_STATUS\n"));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync *pValue = (uint32_t)(pThis->u64Isr);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync break;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync default:
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync Log(("invalid HPET register read: %x\n", iIndex));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync break;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return VINF_SUCCESS;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic int timerRegWrite32(HpetState* pThis,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint32_t iTimerNo,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint32_t iTimerReg,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint32_t iNewValue)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync HpetTimer * pTimer;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint64_t iOldValue = 0;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint32_t u32Temp;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync int rc;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (iTimerNo >= HPET_NUM_TIMERS)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync LogRel(("HPET: using timer above configured range: %d\n", iTimerNo));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return VINF_SUCCESS;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pTimer = &pThis->aTimers[iTimerNo];
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync rc = timerRegRead32(pThis, iTimerNo, iTimerReg, &u32Temp);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (RT_FAILURE(rc))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return rc;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync iOldValue = u32Temp;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync switch (iTimerReg)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync case HPET_TN_CFG:
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync Log(("write HPET_TN_CFG: %d\n", iTimerNo));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (iNewValue & HPET_TN_32BIT)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pTimer->u64Cmp = (uint32_t)pTimer->u64Cmp;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pTimer->u64Period = (uint32_t)pTimer->u64Period;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if ((iNewValue & HPET_TN_INT_TYPE) == HPET_TIMER_TYPE_LEVEL)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync LogRel(("level-triggered config not yet supported\n"));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync Assert(false);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /** We only care about lower 32-bits so far */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pTimer->u64Config =
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync updateMasked(iNewValue, iOldValue, HPET_TN_CFG_WRITE_MASK);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync break;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync case HPET_TN_CFG + 4: /* Interrupt capabilities */
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync Log(("write HPET_TN_CFG + 4, useless\n"));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync break;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync case HPET_TN_CMP: /* lower bits of comparator register */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync Log(("write HPET_TN_CMP on %d: %x\n", iTimerNo, iNewValue));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (pTimer->u64Config & HPET_TN_32BIT)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync iNewValue = (uint32_t)iNewValue;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (pTimer->u64Config & HPET_TN_SETVAL)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* HPET_TN_SETVAL allows to adjust comparator w/o updating period, and it's cleared on access */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (pTimer->u64Config & HPET_TN_32BIT)
cf3aad827eee194a3e6e68796710074b44164371vboxsync pTimer->u64Config &= ~HPET_TN_SETVAL;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync } else if (pTimer->u64Config & HPET_TN_PERIODIC)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync iNewValue &= (pTimer->u64Config & HPET_TN_32BIT ? ~0U : ~0ULL) >> 1;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pTimer->u64Period = (pTimer->u64Period & 0xffffffff00000000ULL)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync | iNewValue;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pTimer->u64Cmp = (pTimer->u64Cmp & 0xffffffff00000000ULL)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync | iNewValue;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync Log2(("after HPET_TN_CMP cmp=%llx per=%llx\n", pTimer->u64Cmp, pTimer->u64Period));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (pThis->u64Config & HPET_CFG_ENABLE)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync hpetProgramTimer(pTimer);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync break;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync case HPET_TN_CMP + 4: /* upper bits of comparator register */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync Log(("write HPET_TN_CMP + 4 on %d: %x\n", iTimerNo, iNewValue));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (pTimer->u64Config & HPET_TN_32BIT)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync break;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (pTimer->u64Config & HPET_TN_SETVAL)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* HPET_TN_SETVAL allows to adjust comparator w/o updating period, and it's cleared on access */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pTimer->u64Config &= ~HPET_TN_SETVAL;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync } else if (pTimer->u64Config & HPET_TN_PERIODIC)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pTimer->u64Period = (pTimer->u64Period & 0xffffffffULL)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync | ((uint64_t)iNewValue << 32);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pTimer->u64Cmp = (pTimer->u64Cmp & 0xffffffffULL)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync | ((uint64_t)iNewValue << 32);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync Log2(("after HPET_TN_CMP+4 cmp=%llx per=%llx\n", pTimer->u64Cmp, pTimer->u64Period));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (pThis->u64Config & HPET_CFG_ENABLE)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync hpetProgramTimer(pTimer);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync break;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync case HPET_TN_ROUTE:
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync Log(("write HPET_TN_ROUTE\n"));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync break;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync case HPET_TN_ROUTE + 4:
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync Log(("write HPET_TN_ROUTE + 4\n"));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync break;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync default:
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync LogRel(("invalid timer register write: %d\n", iTimerReg));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync Assert(false);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync break;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return VINF_SUCCESS;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic int hpetLegacyMode(HpetState* pThis,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync bool fActivate)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync int rc = VINF_SUCCESS;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#ifndef IN_RING3
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* Don't do anything complicated outside of R3 */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync rc = VINF_IOM_HC_MMIO_WRITE;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#else /* IN_RING3 */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (pThis->pHpetHlpR3)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync rc = pThis->pHpetHlpR3->pfnSetLegacyMode(pThis->pDevInsR3, fActivate);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync#endif
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return rc;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync}
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsyncstatic int configRegWrite32(HpetState* pThis,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint32_t iIndex,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint32_t iNewValue)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync int rc = VINF_SUCCESS;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync switch (iIndex)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync case HPET_ID:
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync case HPET_ID + 4:
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync Log(("write HPET_ID, useless\n"));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync break;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync case HPET_CFG:
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint32_t i, iOldValue;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync Log(("write HPET_CFG: %x\n", iNewValue));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync iOldValue = (uint32_t)(pThis->u64Config);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /*
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * This check must be here, before actual update, as hpetLegacyMode
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync * may request retry in R3 - so we must keep state intact.
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (isBitJustSet(iOldValue, iNewValue, HPET_CFG_LEGACY))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync rc = hpetLegacyMode(pThis, true);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync else if (isBitJustCleared(iOldValue, iNewValue, HPET_CFG_LEGACY))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync rc = hpetLegacyMode(pThis, false);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (rc != VINF_SUCCESS)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync return rc;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pThis->u64Config = updateMasked(iNewValue, iOldValue, HPET_CFG_WRITE_MASK);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (isBitJustSet(iOldValue, iNewValue, HPET_CFG_ENABLE))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* Enable main counter and interrupt generation. */
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pThis->u64HpetOffset = hpetTicksToNs(pThis->u64HpetCounter)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync - TMTimerGet(pThis->aTimers[0].CTX_SUFF(pTimer));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync for (i = 0; i < HPET_NUM_TIMERS; i++)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (pThis->aTimers[i].u64Cmp != ~0ULL)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync hpetProgramTimer(&pThis->aTimers[i]);
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync }
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync else if (isBitJustCleared(iOldValue, iNewValue, HPET_CFG_ENABLE))
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync /* Halt main counter and disable interrupt generation. */
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync pThis->u64HpetCounter = hpetGetTicks(pThis);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync for (i = 0; i < HPET_NUM_TIMERS; i++)
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync TMTimerStop(pThis->aTimers[i].CTX_SUFF(pTimer));
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync }
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync break;
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync }
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync case HPET_CFG + 4:
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync {
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync Log(("write HPET_CFG + 4: %x\n", iNewValue));
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync pThis->u64Config = updateMasked((uint64_t)iNewValue << 32,
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync pThis->u64Config,
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync 0xffffffff00000000ULL);
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync break;
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync }
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync case HPET_STATUS:
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync {
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync Log(("write HPET_STATUS: %x\n", iNewValue));
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync // clear ISR for all set bits in iNewValue, see p. 14 of HPET spec
6c2750d8e30830bf114880ca33922b108ab3e942vboxsync pThis->u64Isr &= ~((uint64_t)iNewValue);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync break;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync case HPET_STATUS + 4:
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync Log(("write HPET_STATUS + 4: %x\n", iNewValue));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync if (iNewValue != 0)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync LogRel(("Writing HPET_STATUS + 4 with non-zero, ignored\n"));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync break;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync case HPET_COUNTER:
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pThis->u64HpetCounter = (pThis->u64HpetCounter & 0xffffffff00000000ULL) | iNewValue;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync Log(("write HPET_COUNTER: %#x -> %llx\n",
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync iNewValue, pThis->u64HpetCounter));
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync break;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync }
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync case HPET_COUNTER + 4:
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync {
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync pThis->u64HpetCounter = (pThis->u64HpetCounter & 0xffffffffULL)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync | (((uint64_t)iNewValue) << 32);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync Log(("write HPET_COUNTER + 4: %#x -> %llx\n",
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync iNewValue, pThis->u64HpetCounter));
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync break;
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync }
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync default:
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync LogRel(("invalid HPET config write: %x\n", iIndex));
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync break;
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync }
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync return rc;
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync}
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsyncPDMBOTHCBDECL(int) hpetMMIORead(PPDMDEVINS pDevIns,
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync void * pvUser,
192a1d418422c3b5905dd2577527c07a8ed8b61evboxsync RTGCPHYS GCPhysAddr,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync void * pv,
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync unsigned cb)
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync{
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync HpetState * pThis = PDMINS_2_DATA(pDevIns, HpetState*);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync int rc = VINF_SUCCESS;
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync uint32_t iIndex = (uint32_t)(GCPhysAddr - HPET_BASE);
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync
809e0c4b84167932d92a1df4edcbab2edf0ddf25vboxsync LogFlow(("hpetMMIORead: %llx (%x)\n", (uint64_t)GCPhysAddr, iIndex));
rc = hpetLock(pThis, VINF_IOM_HC_MMIO_READ);
if (RT_UNLIKELY(rc != VINF_SUCCESS))
return rc;
switch (cb)
{
case 1:
case 2:
Log(("Narrow read: %d\n", cb));
rc = VERR_INTERNAL_ERROR;
break;
case 4:
{
if ((iIndex >= 0x100) && (iIndex < 0x400))
rc = timerRegRead32(pThis, (iIndex - 0x100) / 0x20, (iIndex - 0x100) % 0x20, (uint32_t*)pv);
else
rc = configRegRead32(pThis, iIndex, (uint32_t*)pv);
break;
}
case 8:
{
union {
uint32_t u32[2];
uint64_t u64;
} value;
/* Unaligned accesses not allowed */
if (iIndex % 8 != 0)
{
AssertMsgFailed(("Unaligned HPET read access\n"));
rc = VERR_INTERNAL_ERROR;
break;
}
// for 8-byte accesses we just split them, happens under lock anyway
if ((iIndex >= 0x100) && (iIndex < 0x400))
{
uint32_t iTimer = (iIndex - 0x100) / 0x20;
uint32_t iTimerReg = (iIndex - 0x100) % 0x20;
rc = timerRegRead32(pThis, iTimer, iTimerReg, &value.u32[0]);
if (RT_UNLIKELY(rc != VINF_SUCCESS))
break;
rc = timerRegRead32(pThis, iTimer, iTimerReg + 4, &value.u32[1]);
}
else
{
rc = configRegRead32(pThis, iIndex, &value.u32[0]);
if (RT_UNLIKELY(rc != VINF_SUCCESS))
break;
rc = configRegRead32(pThis, iIndex+4, &value.u32[1]);
}
if (rc == VINF_SUCCESS)
*(uint64_t*)pv = value.u64;
break;
}
default:
AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */
rc = VERR_INTERNAL_ERROR;
}
hpetUnlock(pThis);
return rc;
}
PDMBOTHCBDECL(int) hpetMMIOWrite(PPDMDEVINS pDevIns,
void * pvUser,
RTGCPHYS GCPhysAddr,
void * pv,
unsigned cb)
{
HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState*);
int rc = VINF_SUCCESS;
uint32_t iIndex = (uint32_t)(GCPhysAddr - HPET_BASE);
LogFlow(("hpetMMIOWrite: %llx (%x) <- %x\n",
(uint64_t)GCPhysAddr, iIndex, *(uint32_t*)pv));
rc = hpetLock(pThis, VINF_IOM_HC_MMIO_WRITE);
if (RT_UNLIKELY(rc != VINF_SUCCESS))
return rc;
switch (cb)
{
case 1:
case 2:
Log(("Narrow write: %d\n", cb));
rc = VERR_INTERNAL_ERROR;
break;
case 4:
{
if ((iIndex >= 0x100) && (iIndex < 0x400))
rc = timerRegWrite32(pThis,
(iIndex - 0x100) / 0x20,
(iIndex - 0x100) % 0x20,
*(uint32_t*)pv);
else
rc = configRegWrite32(pThis, iIndex, *(uint32_t*)pv);
break;
}
case 8:
{
union {
uint32_t u32[2];
uint64_t u64;
} value;
/* Unaligned accesses not allowed */
if (iIndex % 8 != 0)
{
AssertMsgFailed(("Unaligned HPET write access\n"));
rc = VERR_INTERNAL_ERROR;
break;
}
value.u64 = *(uint64_t*)pv;
// for 8-byte accesses we just split them, happens under lock anyway
if ((iIndex >= 0x100) && (iIndex < 0x400))
{
uint32_t iTimer = (iIndex - 0x100) / 0x20;
uint32_t iTimerReg = (iIndex - 0x100) % 0x20;
rc = timerRegWrite32(pThis, iTimer, iTimerReg, value.u32[0]);
if (RT_UNLIKELY(rc != VINF_SUCCESS))
break;
rc = timerRegWrite32(pThis, iTimer, iTimerReg + 4, value.u32[1]);
}
else
{
rc = configRegWrite32(pThis, iIndex, value.u32[0]);
if (RT_UNLIKELY(rc != VINF_SUCCESS))
break;
rc = configRegWrite32(pThis, iIndex+4, value.u32[1]);
}
break;
}
default:
AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */
rc = VERR_INTERNAL_ERROR;
}
hpetUnlock(pThis);
return rc;
}
#ifdef IN_RING3
static int hpetSaveTimer(HpetTimer *pTimer,
PSSMHANDLE pSSM)
{
TMR3TimerSave(pTimer->pTimerR3, pSSM);
SSMR3PutU8 (pSSM, pTimer->u8Wrap);
SSMR3PutU64 (pSSM, pTimer->u64Config);
SSMR3PutU64 (pSSM, pTimer->u64Cmp);
SSMR3PutU64 (pSSM, pTimer->u64Fsb);
SSMR3PutU64 (pSSM, pTimer->u64Period);
return VINF_SUCCESS;
}
static int hpetLoadTimer(HpetTimer *pTimer,
PSSMHANDLE pSSM)
{
TMR3TimerLoad(pTimer->pTimerR3, pSSM);
SSMR3GetU8(pSSM, &pTimer->u8Wrap);
SSMR3GetU64(pSSM, &pTimer->u64Config);
SSMR3GetU64(pSSM, &pTimer->u64Cmp);
SSMR3GetU64(pSSM, &pTimer->u64Fsb);
SSMR3GetU64(pSSM, &pTimer->u64Period);
return VINF_SUCCESS;
}
/**
* @copydoc FNSSMDEVLIVEEXEC
*/
static DECLCALLBACK(int) hpetLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
{
HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
SSMR3PutU8(pSSM, HPET_NUM_TIMERS);
return VINF_SSM_DONT_CALL_AGAIN;
}
/**
* Saves a state of the HPET device.
*
* @returns VBox status code.
* @param pDevIns The device instance.
* @param pSSMHandle The handle to save the state to.
*/
static DECLCALLBACK(int) hpetSaveExec(PPDMDEVINS pDevIns,
PSSMHANDLE pSSM)
{
HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
uint32_t iTimer;
int rc;
/* The config. */
hpetLiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
for (iTimer = 0; iTimer < HPET_NUM_TIMERS; iTimer++)
{
rc = hpetSaveTimer(&pThis->aTimers[iTimer], pSSM);
AssertRCReturn(rc, rc);
}
SSMR3PutU64(pSSM, pThis->u64HpetOffset);
SSMR3PutU64(pSSM, pThis->u64Capabilities);
SSMR3PutU64(pSSM, pThis->u64Config);
SSMR3PutU64(pSSM, pThis->u64Isr);
SSMR3PutU64(pSSM, pThis->u64HpetCounter);
return VINF_SUCCESS;
}
/**
* Loads a HPET device state.
*
* @returns VBox status code.
* @param pDevIns The device instance.
* @param pSSMHandle The handle to the saved state.
* @param uVersion The data unit version number.
* @param uPass The data pass.
*/
static DECLCALLBACK(int) hpetLoadExec(PPDMDEVINS pDevIns,
PSSMHANDLE pSSM,
uint32_t uVersion,
uint32_t uPass)
{
HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
uint32_t iTimer;
int rc;
if (uVersion == HPET_SAVED_STATE_VERSION_EMPTY)
return VINF_SUCCESS;
if (uVersion != HPET_SAVED_STATE_VERSION)
return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
uint8_t u8NumTimers;
rc = SSMR3GetU8(pSSM, &u8NumTimers); AssertRCReturn(rc, rc);
if (u8NumTimers != HPET_NUM_TIMERS)
return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - wrong number of timers: saved=%#x config=%#x"), u8NumTimers, HPET_NUM_TIMERS);
if (uPass != SSM_PASS_FINAL)
return VINF_SUCCESS;
for (iTimer = 0; iTimer < HPET_NUM_TIMERS; iTimer++)
{
rc = hpetLoadTimer(&pThis->aTimers[iTimer], pSSM);
AssertRCReturn(rc, rc);
}
SSMR3GetU64(pSSM, &pThis->u64HpetOffset);
SSMR3GetU64(pSSM, &pThis->u64Capabilities);
SSMR3GetU64(pSSM, &pThis->u64Config);
SSMR3GetU64(pSSM, &pThis->u64Isr);
SSMR3GetU64(pSSM, &pThis->u64HpetCounter);
return VINF_SUCCESS;
}
static void irqUpdate(struct HpetTimer *pTimer)
{
uint32_t irq = getTimerIrq(pTimer);
HpetState* pThis = pTimer->CTX_SUFF(pHpet);
/** @todo: is it correct? */
if ((pTimer->u64Config & HPET_TN_ENABLE) &&
(pThis->u64Config & HPET_CFG_ENABLE))
{
Log4(("HPET: raising IRQ %d\n", irq));
/* ISR bits are only set in level-triggered mode */
if ((pTimer->u64Config & HPET_TN_INT_TYPE) == HPET_TIMER_TYPE_LEVEL)
pThis->u64Isr |= (uint64_t)(1 << pTimer->u8TimerNumber);
/* We trigger flip/flop in edge-triggered mode and do nothing in level-triggered mode yet */
if ((pTimer->u64Config & HPET_TN_INT_TYPE) == HPET_TIMER_TYPE_EDGE)
pThis->pHpetHlpR3->pfnSetIrq(pThis->CTX_SUFF(pDevIns), irq, PDM_IRQ_LEVEL_FLIP_FLOP);
else
Assert(false);
/* @todo: implement IRQs in level-triggered mode */
}
}
/**
* Device timer callback function.
*
* @param pDevIns Device instance of the device which registered the timer.
* @param pTimer The timer handle.
* @param pvUser Pointer to the HPET timer state.
*/
static DECLCALLBACK(void) hpetTimer(PPDMDEVINS pDevIns,
PTMTIMER pTmTimer,
void * pvUser)
{
HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
HpetTimer *pTimer = (HpetTimer *)pvUser;
uint64_t u64Period = pTimer->u64Period;
uint64_t u64CurTick = hpetGetTicks(pThis);
uint64_t u64Diff;
int rc;
if (pTimer == NULL)
return;
/* Lock in R3 must either block or succeed */
rc = hpetLock(pThis, VERR_IGNORED);
AssertLogRelRCReturnVoid(rc);
if ((pTimer->u64Config & HPET_TN_PERIODIC) && (u64Period != 0))
{
hpetAdjustComparator(pTimer, u64CurTick);
u64Diff = hpetComputeDiff(pTimer, u64CurTick);
Log4(("HPET: periodical: next in %lld\n", hpetTicksToNs(u64Diff)));
TMTimerSetNano(pTmTimer, hpetTicksToNs(u64Diff));
}
else if ((pTimer->u64Config & HPET_TN_32BIT) &&
!(pTimer->u64Config & HPET_TN_PERIODIC))
{
if (pTimer->u8Wrap)
{
u64Diff = hpetComputeDiff(pTimer, u64CurTick);
TMTimerSetNano(pTmTimer, hpetTicksToNs(u64Diff));
pTimer->u8Wrap = 0;
}
}
/* Should it really be under lock, does it really matter? */
irqUpdate(pTimer);
hpetUnlock(pThis);
}
/**
* Relocation notification.
*
* @returns VBox status.
* @param pDevIns The device instance data.
* @param offDelta The delta relative to the old address.
*/
static DECLCALLBACK(void) hpetRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
{
HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
unsigned i;
LogFlow(("hpetRelocate:\n"));
pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
pThis->pHpetHlpRC = pThis->pHpetHlpR3->pfnGetRCHelpers(pDevIns);
for (i = 0; i < RT_ELEMENTS(pThis->aTimers); i++)
{
HpetTimer *pTm = &pThis->aTimers[i];
if (pTm->pTimerR3)
pTm->pTimerRC = TMTimerRCPtr(pTm->pTimerR3);
pTm->pHpetRC = PDMINS_2_DATA_RCPTR(pDevIns);
}
}
/**
* Reset notification.
*
* @returns VBox status.
* @param pDevIns The device instance data.
*/
static DECLCALLBACK(void) hpetReset(PPDMDEVINS pDevIns)
{
HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
unsigned i;
LogFlow(("hpetReset:\n"));
pThis->u64Config = 0;
for (i = 0; i < HPET_NUM_TIMERS; i++)
{
HpetTimer *pTimer = &pThis->aTimers[i];
pTimer->u8TimerNumber = i;
pTimer->u64Cmp = ~0ULL;
/* capable of periodic operations and 64-bits */
pTimer->u64Config = HPET_TN_PERIODIC_CAP | HPET_TN_SIZE_CAP;
/* We can do all IRQs */
uint32_t u32RoutingCap = 0xffffffff;
pTimer->u64Config |= ((uint64_t)u32RoutingCap) << 32;
pTimer->u64Period = 0ULL;
pTimer->u8Wrap = 0;
}
pThis->u64HpetCounter = 0ULL;
pThis->u64HpetOffset = 0ULL;
/* 64-bit main counter; 3 timers supported; LegacyReplacementRoute. */
uint32_t u32Vendor = 0x8086;
uint32_t u32Caps =
(1 << 15) /* LEG_RT_CAP, LegacyReplacementRoute capable */ |
(1 << 13) /* COUNTER_SIZE_CAP, main counter is 64-bit capable */ |
((HPET_NUM_TIMERS-1) << 8) /* NUM_TIM_CAP, number of timers -1 */ |
1 /* REV_ID, revision, must not be 0 */;
pThis->u64Capabilities = (u32Vendor << 16) | u32Caps;
pThis->u64Capabilities |= ((uint64_t)(HPET_CLK_PERIOD) << 32);
}
/**
* Initialization routine.
*
* @returns VBox status.
* @param pDevIns The device instance data.
*/
static int hpetInit(PPDMDEVINS pDevIns)
{
unsigned i;
int rc;
HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
memset(pThis, 0, sizeof(*pThis));
pThis->pDevInsR3 = pDevIns;
pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
for (i = 0; i < HPET_NUM_TIMERS; i++)
{
HpetTimer *timer = &pThis->aTimers[i];
timer->pHpetR3 = pThis;
timer->pHpetR0 = PDMINS_2_DATA_R0PTR(pDevIns);
timer->pHpetRC = PDMINS_2_DATA_RCPTR(pDevIns);
rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, hpetTimer, timer,
TMTIMER_FLAGS_DEFAULT_CRIT_SECT, "HPET Timer",
&pThis->aTimers[i].pTimerR3);
if (RT_FAILURE(rc))
return rc;
pThis->aTimers[i].pTimerRC = TMTimerRCPtr(pThis->aTimers[i].pTimerR3);
pThis->aTimers[i].pTimerR0 = TMTimerR0Ptr(pThis->aTimers[i].pTimerR3);
}
hpetReset(pDevIns);
return VINF_SUCCESS;
}
/**
* Info handler, device version.
*
* @param pDevIns Device instance which registered the info.
* @param pHlp Callback functions for doing output.
* @param pszArgs Argument string. Optional and specific to the handler.
*/
static DECLCALLBACK(void) hpetInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
{
HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
int i;
pHlp->pfnPrintf(pHlp,
"HPET status:\n"
" config = %016RX64\n"
" offset = %016RX64 counter = %016RX64 isr = %016RX64\n"
" legacy mode is %s\n",
pThis->u64Config,
pThis->u64HpetOffset, pThis->u64HpetCounter, pThis->u64Isr,
(pThis->u64Config & HPET_CFG_LEGACY) ? "on" : "off");
pHlp->pfnPrintf(pHlp,
"Timers:\n");
for (i = 0; i < HPET_NUM_TIMERS; i++)
{
pHlp->pfnPrintf(pHlp, " %d: comparator=%016RX64 period(hidden)=%016RX64 cfg=%016RX64\n",
pThis->aTimers[i].u8TimerNumber,
pThis->aTimers[i].u64Cmp,
pThis->aTimers[i].u64Period,
pThis->aTimers[i].u64Config);
}
}
/**
* @interface_method_impl{PDMDEVREG,pfnConstruct}
*/
static DECLCALLBACK(int) hpetConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
{
HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *);
int rc;
bool fRCEnabled = false;
bool fR0Enabled = false;
PDMHPETREG HpetReg;
/* Only one HPET device now */
Assert(iInstance == 0);
/*
* Validate configuration.
*/
if (!CFGMR3AreValuesValid(pCfg, "GCEnabled\0" "R0Enabled\0"))
return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
/* Query configuration. */
#if 1
rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fRCEnabled, true);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: Querying \"GCEnabled\" as a bool failed"));
rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc,
N_("Configuration error: failed to read R0Enabled as boolean"));
#endif
/* Initialize the device state */
rc = hpetInit(pDevIns);
if (RT_FAILURE(rc))
return rc;
pThis->pDevInsR3 = pDevIns;
pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
/*
* Register the HPET and get helpers.
*/
HpetReg.u32Version = PDM_HPETREG_VERSION;
rc = PDMDevHlpHPETRegister(pDevIns, &HpetReg, &pThis->pHpetHlpR3);
if (RT_FAILURE(rc))
{
AssertMsgRC(rc, ("Cannot HPETRegister: %Rrc\n", rc));
return rc;
}
/*
* Initialize critical section.
*/
rc = PDMDevHlpCritSectInit(pDevIns, &pThis->csLock, RT_SRC_POS, "HPET");
if (RT_FAILURE(rc))
return PDMDEV_SET_ERROR(pDevIns, rc, N_("HPET cannot initialize critical section"));
/*
* Register the MMIO range, PDM API requests page aligned
* addresses and sizes.
*/
rc = PDMDevHlpMMIORegister(pDevIns, HPET_BASE, 0x1000, pThis,
hpetMMIOWrite, hpetMMIORead, NULL, "HPET Memory");
if (RT_FAILURE(rc))
{
AssertMsgRC(rc, ("Cannot register MMIO: %Rrc\n", rc));
return rc;
}
if (fRCEnabled)
{
rc = PDMDevHlpMMIORegisterRC(pDevIns, HPET_BASE, 0x1000, 0,
"hpetMMIOWrite", "hpetMMIORead", NULL);
if (RT_FAILURE(rc))
return rc;
pThis->pHpetHlpRC = pThis->pHpetHlpR3->pfnGetRCHelpers(pDevIns);
if (!pThis->pHpetHlpRC)
{
AssertReleaseMsgFailed(("cannot get RC helper\n"));
return VERR_INTERNAL_ERROR;
}
}
if (fR0Enabled)
{
rc = PDMDevHlpMMIORegisterR0(pDevIns, HPET_BASE, 0x1000, 0,
"hpetMMIOWrite", "hpetMMIORead", NULL);
if (RT_FAILURE(rc))
return rc;
pThis->pHpetHlpR0 = pThis->pHpetHlpR3->pfnGetR0Helpers(pDevIns);
if (!pThis->pHpetHlpR0)
{
AssertReleaseMsgFailed(("cannot get R0 helper\n"));
return VERR_INTERNAL_ERROR;
}
}
/* Register SSM callbacks */
rc = PDMDevHlpSSMRegister3(pDevIns, HPET_SAVED_STATE_VERSION, sizeof(*pThis), hpetLiveExec, hpetSaveExec, hpetLoadExec);
if (RT_FAILURE(rc))
return rc;
/**
* @todo Register statistics.
*/
PDMDevHlpDBGFInfoRegister(pDevIns, "hpet", "Display HPET status. (no arguments)", hpetInfo);
return VINF_SUCCESS;
}
/**
* The device registration structure.
*/
const PDMDEVREG g_DeviceHPET =
{
/* u32Version */
PDM_DEVREG_VERSION,
/* szName */
"hpet",
/* szRCMod */
"VBoxDDGC.gc",
/* szR0Mod */
"VBoxDDR0.r0",
/* pszDescription */
" High Precision Event Timer (HPET) Device",
/* fFlags */
PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32_64 | PDM_DEVREG_FLAGS_PAE36 | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
/* fClass */
PDM_DEVREG_CLASS_PIT,
/* cMaxInstances */
1,
/* cbInstance */
sizeof(HpetState),
/* pfnConstruct */
hpetConstruct,
/* pfnDestruct */
NULL,
/* pfnRelocate */
hpetRelocate,
/* pfnIOCtl */
NULL,
/* pfnPowerOn */
NULL,
/* pfnReset */
hpetReset,
/* pfnSuspend */
NULL,
/* pfnResume */
NULL,
/* pfnAttach */
NULL,
/* pfnDetach */
NULL,
/* pfnQueryInterface. */
NULL,
/* pfnInitComplete */
NULL,
/* pfnPowerOff */
NULL,
/* pfnSoftReset */
NULL,
/* u32VersionEnd */
PDM_DEVREG_VERSION
};
#endif /* IN_RING3 */
#endif /* VBOX_DEVICE_STRUCT_TESTCASE */