]> rtime.felk.cvut.cz Git - jailhouse.git/blob - inmates/demos/x86/hpet-inmate.c
inmates: hpet-demo: avoid warning on the unused func
[jailhouse.git] / inmates / demos / x86 / hpet-inmate.c
1
2 /**
3  * HPET as an inmate for Jailhouse
4  *
5  */
6 #include <inmate.h>
7
8 /**
9  * HPET defenitions
10  */
11
12 #define HPET_BASE_QEMU (0x00000000fed00000ULL)
13
14
15 /*
16 *   This was taken from IA-PC HPET Specification
17 *
18 *----------------------------------------------------------------------------------------
19 *    Offset                 |Register                                       |Type
20 *----------------------------------------------------------------------------------------
21 *    000-        007h        General Capabilities and ID Register            Read Only
22 *    008-        00Fh        Reserved
23 *    010-        017h        General Configuration Register                  Read-Write
24 *    018-        01Fh        Reserved
25 *    020-        027h        General Interrupt Status Register               Read/Write Clear
26 *    028-        0EFh        Reserved
27 *    0F0-        0F7h        Main Counter Value Register                     Read/Write
28 *    0F8-        0FFh        Reserved
29 *    100-        107h        Timer 0 Configuration and Capability Register   Read/Write
30 *    108-        10Fh        Timer 0 Comparator Value Register               Read/Write
31 *    110-        117h        Timer 0 FSB Interrupt Route Register            Read/Write
32 *    118-        11Fh        Reserved
33 *
34 *(100+20*N  )- (100+20*N+7)h Timer N Configuration and Capability Register   Read/Write
35 *(100+20*N+8)- (100+20*N+F)h Timer N Comparator Value Register               Read/Write
36 *(100+30*N  )- (100+30*N+7)h Timer N FSB Interrupt Route Register            Read/Write
37 *(100+30*N+8)- (100+30*N+F)h Reserved
38 *
39 *                -3FF        ----for Timers 3-31
40 */
41
42 /*
43  * HPET general capabilities register
44  */
45
46 #define HPET_COUNTER_CLK_PERIOD_MASK    (0xffffffff00000000ULL)
47 #define HPET_COUNTER_CLK_PERIOD_SHIFT   (32UL)
48 #define HPET_VENDOR_ID_MASK     (0x00000000ffff0000ULL)
49 #define HPET_VENDOR_ID_SHIFT        (16ULL)
50 #define HPET_LEG_RT_CAP_MASK        (0x8000)
51 #define HPET_COUNTER_SIZE_MASK      (0x2000)
52 #define HPET_NUM_TIM_CAP_MASK       (0x1f00)
53 #define HPET_NUM_TIM_CAP_SHIFT      (8ULL)
54
55 /*
56  * HPET general configuration register
57  */
58
59 #define HPET_LEG_RT_CNF_MASK        (2UL)
60 #define HPET_ENABLE_CNF_MASK        (1UL)
61
62 typedef struct general_timer_registers
63 {
64
65         u32 capat_id_reg;
66         // u8 rev_id;
67         // /*8:12 - Number of timers, 13 - count_size_cap,
68         //         14 - reserved, 15 -legacy repl route hw support */
69         // u8 num_tim_cap     : 5;
70         // u8 count_size_cap  : 1;
71         // u8 reserved_bit    : 1;
72         // u8 leg_rt_cap      : 1;
73         // u16 vendor_id;
74         u32 clock_period;
75
76         u64 reserved1;
77         //u64 configuration;
78         /*0 - ENABLE_CNF, 1 - LEG_RT_CNF, 2:63 - reserved*/
79         /*u8 enable_cnf      : 1;
80         u8 leg_rt_cnf      : 1;
81         u8 reserved_5bit   : 6;
82         u8 reserved_non_os;
83         u64 reserved_48bit : 48;*/
84         u32 config_reg;
85         u32 reservedforfuture;
86         u64 reserved2;
87
88         //u64 int_status_register
89         /*when level-triggered mode is used
90         each bit in the vector shows if the Timer N interrupt is ACTIVE.*/;
91         u32 int_status_vector;
92         u32 reserved_32bit;
93 } __attribute__((packed)) gen_regs;
94
95 /* 028h -> 0EFh space -- (0F0h - 28 == C8) */
96 #define RESERVED_BEFORE_MAIN_VAL_REG 0x000000C8
97 typedef struct main_counter_value_register
98 {
99         u64 value;
100         u64 reserved;
101 } __attribute__((packed)) main_val_reg;
102
103 /*
104  * Timer configuration register
105  */
106
107 #define Tn_INT_ROUTE_CAP_MASK       (0xffffffff00000000ULL)
108 #define Tn_INT_ROUTE_CAP_SHIFT      (32UL)
109 #define Tn_FSB_INT_DELCAP_MASK      (0x8000UL)
110 #define Tn_FSB_INT_DELCAP_SHIFT     (15)
111 #define Tn_FSB_EN_CNF_MASK      (0x4000UL)
112 #define Tn_FSB_EN_CNF_SHIFT     (14)
113 #define Tn_INT_ROUTE_CNF_MASK       (0x3e00UL)
114 #define Tn_INT_ROUTE_CNF_SHIFT      (9)
115 #define Tn_32MODE_CNF_MASK      (0x0100UL)
116 #define Tn_VAL_SET_CNF_MASK     (0x0040UL)
117 #define Tn_SIZE_CAP_MASK        (0x0020UL)
118 #define Tn_PER_INT_CAP_MASK     (0x0010UL)
119 #define Tn_TYPE_CNF_MASK        (0x0008UL)
120 #define Tn_INT_ENB_CNF_MASK     (0x0004UL)
121 #define Tn_INT_TYPE_CNF_MASK        (0x0002UL)
122
123 /*
124  * Timer FSB Interrupt Route Register
125  */
126
127 #define Tn_FSB_INT_ADDR_MASK        (0xffffffff00000000ULL)
128 #define Tn_FSB_INT_ADDR_SHIFT       (32UL)
129 #define Tn_FSB_INT_VAL_MASK     (0x00000000ffffffffULL)
130
131
132
133 typedef struct timer_N_registers
134 {
135         u64 cap_conf_reg;
136         //u32 int_route_cap;
137         u64 comparator_val;
138         u64 fsb_interrupt_route;
139
140         u64 reserved;
141 } __attribute__((packed)) timer_regs;
142
143 #define MAX_TIMERS_IN_BLK   32
144 #define MAX_BLK_NUM         8
145 timer_regs * timer[MAX_TIMERS_IN_BLK];
146
147 /**
148  * HPET functions
149  */
150
151 #include <jailhouse/hypercall.h>
152 //#include "hpet-demo.h"
153
154 #ifdef CONFIG_UART_OXPCIE952
155 #define UART_BASE               0xe010
156 #else
157 #define UART_BASE               0x3f8
158 #endif
159 #define UART_LSR                0x5
160 #define UART_LSR_THRE           0x20
161 #define UART_IDLE_LOOPS         100
162
163 #define LEG_TIM0_IRQ    32
164 #define LEG_TIM1_IRQ    (LEG_TIM0_IRQ + 8)
165 #define TIM2_INTI               16
166
167 //-------------hpet defines-----------------------------
168 #define NANS_TO_FEMPTS(X) ((X) * 1000000ULL)
169
170 u64 main_counter_tick_period = 0;
171 main_val_reg * main_counter_reg;
172 gen_regs * gen_reg;
173
174
175 static void inline enable_main_counter(void)
176 {
177         gen_reg->config_reg |= HPET_ENABLE_CNF_MASK;
178 }
179
180 static void inline disable_main_counter(void)
181 {
182         gen_reg->config_reg &= ~HPET_ENABLE_CNF_MASK;
183 }
184
185 static void set_timer_periodic(timer_regs * timer, u64 time)
186 {
187         if (! (timer->cap_conf_reg & Tn_PER_INT_CAP_MASK) ) {
188                 printk("Timer %p isnt periodic capable.\n", timer );
189                 return;
190         }
191         if (time < main_counter_tick_period) {
192                 time = main_counter_tick_period;
193                 printk("Timer %p was set on minimal tick that's possible.\n", timer);
194         }
195
196         disable_main_counter();
197         main_counter_reg->value = 0ULL;
198         //enable int, set periodical, set value notification
199         timer->cap_conf_reg |= Tn_INT_ENB_CNF_MASK | Tn_TYPE_CNF_MASK | Tn_VAL_SET_CNF_MASK;
200         timer->comparator_val = time;
201         enable_main_counter();
202 }
203 static void __attribute__ ((unused)) set_timer_one_shot(timer_regs * timer, u64 time);
204
205
206 static void set_timer_one_shot(timer_regs * timer, u64 time)
207 {
208         if (time < (u64) main_counter_tick_period) {
209                 time = main_counter_tick_period;
210                 printk("Timer %p was set on minimal tick that's possible.\n", timer);
211         }
212
213         timer->comparator_val = time + main_counter_reg->value;
214         timer->cap_conf_reg |= Tn_INT_ENB_CNF_MASK;
215 }
216
217 static void set_legacy_mode(void)
218 {
219         if ( !(gen_reg->capat_id_reg & HPET_LEG_RT_CAP_MASK) ) {
220                 printk("Legacy replacement not implemented in HW.\n");
221                 return;
222         }
223         gen_reg->config_reg |= HPET_LEG_RT_CNF_MASK;
224
225 }
226
227 static void set_timer_interrupt( timer_regs * timer, u8 inti, int_handler_t handler)
228 {
229         //only INTI0 - INTI31 are allowed
230         if ( inti > 0x1f ) { return; }
231         //check if timer can use this routing
232         u32 support_irqs_bitmask = 
233                 (timer->cap_conf_reg & Tn_INT_ROUTE_CAP_MASK) >> Tn_INT_ROUTE_CAP_SHIFT;
234         if (! ( (support_irqs_bitmask >> inti) & 0x01UL) ) {
235                 printk("INTI%u is not supported by timer.\n", inti);
236                 return;
237         }
238         //set up timer and handling
239         timer->cap_conf_reg |= (inti << Tn_INT_ROUTE_CNF_SHIFT);
240         u8 irq = 32 + inti;
241         int_set_handler(irq, handler);
242         ioapic_pin_set_vector(inti, TRIGGER_LEVEL_ACTIVE_HIGH, irq);
243 }
244
245 //------------------------------------------------------
246
247 static void irq_handler0(void)
248 {
249         printk("\nTimer 0 says hi!\n");
250 }
251
252 static void irq_handler1(void)
253 {
254         printk("\nTimer 1 says hi!\n");
255 }
256
257 static void irq_handler2(void)
258 {
259         printk("\nTimer 2 says hi!\n");
260 }
261
262 #define LEG_IOAPIC_TIM0_PIN 2
263 #define LEG_IOAPIC_TIM1_PIN 8
264
265 static void init_apic(void)
266 {
267         int_init();
268
269         ioapic_init();
270         if ( gen_reg->config_reg & HPET_LEG_RT_CNF_MASK) {
271                 //legacy interrupts settings
272                 int_set_handler (LEG_TIM0_IRQ, irq_handler0);
273                 int_set_handler (LEG_TIM0_IRQ + 8, irq_handler1);
274                 ioapic_pin_set_vector(LEG_IOAPIC_TIM0_PIN, TRIGGER_LEVEL_ACTIVE_HIGH, LEG_TIM0_IRQ);
275                 ioapic_pin_set_vector(LEG_IOAPIC_TIM1_PIN, TRIGGER_LEVEL_ACTIVE_HIGH, LEG_TIM1_IRQ);
276         }
277         asm volatile("sti");
278 }
279
280 void inmate_main(void)
281 {
282         bool allow_terminate = false;
283         bool terminate = false;
284
285         unsigned int n;
286
287         printk_uart_base = UART_BASE;
288         do {
289                 for (n = 0; n < UART_IDLE_LOOPS; n++)
290                         if (!(inb(UART_BASE + UART_LSR) & UART_LSR_THRE))
291                                 break;
292         } while (n < UART_IDLE_LOOPS);
293
294         comm_region->cell_state = JAILHOUSE_CELL_RUNNING_LOCKED;
295
296         //-------------------------------------------------------
297         //--------------HPET part--------------------------------
298
299         asm volatile("cli");
300
301         gen_reg =  (gen_regs *) ( (u64) HPET_BASE_QEMU);
302
303         printk("\nBase Address for HPET registers : %p\n", gen_reg);
304         map_range(gen_reg, PAGE_SIZE, MAP_UNCACHED);
305
306         //value in reg is an index of the last timer avaliable
307         u8 comparators_amount = ((gen_reg->capat_id_reg & HPET_NUM_TIM_CAP_MASK) >> HPET_NUM_TIM_CAP_SHIFT) + 1;
308
309         main_counter_tick_period = gen_reg->clock_period;
310
311         main_counter_reg = (main_val_reg *)
312                            (   ((u8 *) gen_reg)
313                                + sizeof(gen_regs)
314                                + RESERVED_BEFORE_MAIN_VAL_REG
315                            );
316
317         u8 * curr_place;
318
319         for (
320             curr_place = ((u8 *) main_counter_reg) + sizeof(main_val_reg), n = 0;
321             n < comparators_amount;
322             curr_place += sizeof(timer_regs), ++n )
323         {
324                 timer[n] = (timer_regs *) curr_place;
325                 printk("\nTimer %u on: %p, ", n,  timer[n]);
326                 printk("Timer comparator : 0x%016lx, ", timer[n]->comparator_val);
327                 printk("Interrupts where to route: 0x%016lx\n",
328                        (timer[n]->cap_conf_reg & Tn_INT_ROUTE_CAP_MASK) >> Tn_INT_ROUTE_CAP_SHIFT);
329         }
330
331         set_legacy_mode();
332         enable_main_counter();
333
334
335         
336         set_timer_periodic( timer[0], NANS_TO_FEMPTS(1000000000ULL) / main_counter_tick_period );
337         set_timer_periodic( timer[1], NANS_TO_FEMPTS(3000000000ULL) / main_counter_tick_period );
338
339         set_timer_periodic( timer[2], NANS_TO_FEMPTS(5000000000ULL) / main_counter_tick_period );
340
341         init_apic();
342         set_timer_interrupt(timer[2], TIM2_INTI, irq_handler2);
343
344         printk("Done preparation..\n");
345
346         //-------------------------------------------------------
347         while (!terminate) {
348                 asm volatile("hlt");
349
350                 switch (comm_region->msg_to_cell) {
351                 case JAILHOUSE_MSG_SHUTDOWN_REQUEST :
352                         if (!allow_terminate) {
353                                 printk("Rejecting first shutdown request - "
354                                        "try again!\n");
355                                 jailhouse_send_reply_from_cell(comm_region,
356                                                                JAILHOUSE_MSG_REQUEST_DENIED);
357                                 allow_terminate = true;
358                         } else
359                                 terminate = true;
360                         break;
361                 default:
362                         jailhouse_send_reply_from_cell(comm_region,
363                                                        JAILHOUSE_MSG_UNKNOWN);
364                         break;
365                 }
366         }
367
368         printk("Stopped HPET demo\n");
369         comm_region->cell_state = JAILHOUSE_CELL_SHUT_DOWN;
370
371 }
372