1 /////////////////////////////////////////////////////////////////////////
2 // $Id: hpet.h 14112 2021-01-31 10:50:53Z vruppert $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 //  High Precision Event Timer emulation ported from Qemu
6 //
7 //  Copyright (c) 2007 Alexander Graf
8 //  Copyright (c) 2008 IBM Corporation
9 //
10 //  Authors: Beth Kon <bkon@us.ibm.com>
11 //
12 //  Copyright (C) 2017-2021  The Bochs Project
13 //
14 //  This library is free software; you can redistribute it and/or
15 //  modify it under the terms of the GNU Lesser General Public
16 //  License as published by the Free Software Foundation; either
17 //  version 2 of the License, or (at your option) any later version.
18 //
19 //  This library is distributed in the hope that it will be useful,
20 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
21 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22 //  Lesser General Public License for more details.
23 //
24 //  You should have received a copy of the GNU Lesser General Public
25 //  License along with this library; if not, write to the Free Software
26 //  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
27 //
28 /////////////////////////////////////////////////////////////////////////
29 
30 #ifndef BX_IODEV_HPET_H
31 #define BX_IODEV_HPET_H
32 
33 #if BX_SUPPORT_PCI
34 
35 /* HPET will set up timers to fire after a certain period of time.
36  * These values can be used to clamp this period to reasonable/supported values.
37  * The values are in ticks.
38  */
39 #define HPET_MAX_ALLOWED_PERIOD 0x0400000000000000ull // Must not overflow when multiplied by HPET_CLK_PERIOD
40 #define HPET_MIN_ALLOWED_PERIOD 1
41 
42 #define RTC_ISA_IRQ 8
43 
44 #define HPET_BASE               0xfed00000
45 #define HPET_LEN                0x400
46 #define HPET_CLK_PERIOD         10 // 10 ns
47 #define HPET_ROUTING_CAP        0xffffffull // allowed irq routing
48 
49 #define FS_PER_NS 1000000       /* 1000000 femtosectons == 1 ns */
50 #define HPET_MIN_TIMERS         3
51 #define HPET_MAX_TIMERS         32
52 
53 #define HPET_CFG_ENABLE 0x001
54 #define HPET_CFG_LEGACY 0x002
55 
56 #define HPET_ID         0x000
57 #define HPET_PERIOD     0x004
58 #define HPET_CFG        0x010
59 #define HPET_STATUS     0x020
60 #define HPET_COUNTER    0x0f0
61 #define HPET_TN_CFG     0x000
62 #define HPET_TN_CMP     0x008
63 #define HPET_TN_ROUTE   0x010
64 #define HPET_CFG_WRITE_MASK  0x3
65 
66 #define HPET_TN_TYPE_LEVEL       0x002
67 #define HPET_TN_ENABLE           0x004
68 #define HPET_TN_PERIODIC         0x008
69 #define HPET_TN_PERIODIC_CAP     0x010
70 #define HPET_TN_SIZE_CAP         0x020
71 #define HPET_TN_SETVAL           0x040
72 #define HPET_TN_32BIT            0x100
73 #define HPET_TN_INT_ROUTE_MASK  0x3e00
74 #define HPET_TN_FSB_ENABLE      0x4000
75 #define HPET_TN_CFG_WRITE_MASK  0x7f4e
76 #define HPET_TN_INT_ROUTE_SHIFT      9
77 
78 typedef struct {
79   Bit8u  tn;
80   int    timer_id;
81   Bit64u config;
82   Bit64u cmp;
83   Bit64u fsb;
84   Bit64u period;
85   Bit64u last_checked;
86 } HPETTimer;
87 
88 class bx_hpet_c : public bx_devmodel_c {
89 public:
90   bx_hpet_c();
91   virtual ~bx_hpet_c();
92   virtual void init();
93   virtual void reset(unsigned type);
94   virtual void register_state(void);
95 #if BX_DEBUGGER
96   virtual void debug_dump(int argc, char **argv);
97 #endif
98 
99   Bit32u read_aligned(bx_phy_address address);
100   void write_aligned(bx_phy_address address, Bit32u data);
101 
102 private:
hpet_in_legacy_mode(void)103   Bit32u hpet_in_legacy_mode(void) {return s.config & HPET_CFG_LEGACY;}
timer_int_route(HPETTimer * timer)104   Bit32u timer_int_route(HPETTimer *timer)
105   {
106     return (timer->config & HPET_TN_INT_ROUTE_MASK) >> HPET_TN_INT_ROUTE_SHIFT;
107   }
timer_fsb_route(HPETTimer * t)108   Bit32u timer_fsb_route(HPETTimer *t) {return t->config & HPET_TN_FSB_ENABLE;}
hpet_enabled(void)109   Bit32u hpet_enabled(void) {return s.config & HPET_CFG_ENABLE;}
timer_is_periodic(HPETTimer * t)110   Bit32u timer_is_periodic(HPETTimer *t) {return t->config & HPET_TN_PERIODIC;}
timer_enabled(HPETTimer * t)111   Bit32u timer_enabled(HPETTimer *t) {return t->config & HPET_TN_ENABLE;}
112   Bit64u hpet_get_ticks(void);
113   Bit64u hpet_calculate_diff(HPETTimer *t, Bit64u current);
114   void   update_irq(HPETTimer *timer, bool set);
115   void   hpet_set_timer(HPETTimer *t);
116   void   hpet_del_timer(HPETTimer *t);
117 
118   static void timer_handler(void *);
119   void   hpet_timer(void);
120 
121   struct {
122     Bit8u  num_timers;
123     Bit64u hpet_reference_value;
124     Bit64u hpet_reference_time;
125     Bit64u capability;
126     Bit64u config;
127     Bit64u isr;
128     Bit64u hpet_counter;
129     HPETTimer timer[HPET_MAX_TIMERS];
130   } s;
131 };
132 
133 #endif
134 
135 #endif
136