3 * HPET as an inmate for Jailhouse
12 #define HPET_BASE_QEMU (0x00000000fed00000ULL)
16 * This was taken from IA-PC HPET Specification
18 *----------------------------------------------------------------------------------------
19 * Offset |Register |Type
20 *----------------------------------------------------------------------------------------
21 * 000- 007h General Capabilities and ID Register Read Only
23 * 010- 017h General Configuration Register Read-Write
25 * 020- 027h General Interrupt Status Register Read/Write Clear
27 * 0F0- 0F7h Main Counter Value Register Read/Write
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
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
39 * -3FF ----for Timers 3-31
43 * HPET general capabilities register
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)
56 * HPET general configuration register
59 #define HPET_LEG_RT_CNF_MASK (2UL)
60 #define HPET_ENABLE_CNF_MASK (1UL)
62 typedef struct general_timer_registers
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;
78 /*0 - ENABLE_CNF, 1 - LEG_RT_CNF, 2:63 - reserved*/
83 u64 reserved_48bit : 48;*/
85 u32 reservedforfuture;
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;
93 } __attribute__((packed)) gen_regs;
95 /* 028h -> 0EFh space -- (0F0h - 28 == C8) */
96 #define RESERVED_BEFORE_MAIN_VAL_REG 0x000000C8
97 typedef struct main_counter_value_register
101 } __attribute__((packed)) main_val_reg;
104 * Timer configuration register
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)
124 * Timer FSB Interrupt Route Register
127 #define Tn_FSB_INT_ADDR_MASK (0xffffffff00000000ULL)
128 #define Tn_FSB_INT_ADDR_SHIFT (32UL)
129 #define Tn_FSB_INT_VAL_MASK (0x00000000ffffffffULL)
133 typedef struct timer_N_registers
138 u64 fsb_interrupt_route;
141 } __attribute__((packed)) timer_regs;
143 #define MAX_TIMERS_IN_BLK 32
144 #define MAX_BLK_NUM 8
145 timer_regs * timer[MAX_TIMERS_IN_BLK];
151 #include <jailhouse/hypercall.h>
152 //#include "hpet-demo.h"
154 #ifdef CONFIG_UART_OXPCIE952
155 #define UART_BASE 0xe010
157 #define UART_BASE 0x3f8
160 #define UART_LSR_THRE 0x20
161 #define UART_IDLE_LOOPS 100
163 #define LEG_TIM0_IRQ 32
164 #define LEG_TIM1_IRQ (LEG_TIM0_IRQ + 8)
167 //-------------hpet defines-----------------------------
168 #define NANS_TO_FEMPTS(X) ((X) * 1000000ULL)
170 u64 main_counter_tick_period = 0;
171 main_val_reg * main_counter_reg;
175 static void inline enable_main_counter(void)
177 gen_reg->config_reg |= HPET_ENABLE_CNF_MASK;
180 static void inline disable_main_counter(void)
182 gen_reg->config_reg &= ~HPET_ENABLE_CNF_MASK;
185 static void set_timer_periodic(timer_regs * timer, u64 time)
187 if (! (timer->cap_conf_reg & Tn_PER_INT_CAP_MASK) ) {
188 printk("Timer %p isnt periodic capable.\n", timer );
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);
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();
203 static void __attribute__ ((unused)) set_timer_one_shot(timer_regs * timer, u64 time);
206 static void set_timer_one_shot(timer_regs * timer, u64 time)
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);
213 timer->comparator_val = time + main_counter_reg->value;
214 timer->cap_conf_reg |= Tn_INT_ENB_CNF_MASK;
217 static void set_legacy_mode(void)
219 if ( !(gen_reg->capat_id_reg & HPET_LEG_RT_CAP_MASK) ) {
220 printk("Legacy replacement not implemented in HW.\n");
223 gen_reg->config_reg |= HPET_LEG_RT_CNF_MASK;
227 static void set_timer_interrupt( timer_regs * timer, u8 inti, int_handler_t handler)
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);
238 //set up timer and handling
239 timer->cap_conf_reg |= (inti << Tn_INT_ROUTE_CNF_SHIFT);
241 int_set_handler(irq, handler);
242 ioapic_pin_set_vector(inti, TRIGGER_LEVEL_ACTIVE_HIGH, irq);
245 //------------------------------------------------------
247 static void irq_handler0(void)
249 printk("\nTimer 0 says hi!\n");
252 static void irq_handler1(void)
254 printk("\nTimer 1 says hi!\n");
257 static void irq_handler2(void)
259 printk("\nTimer 2 says hi!\n");
262 #define LEG_IOAPIC_TIM0_PIN 2
263 #define LEG_IOAPIC_TIM1_PIN 8
265 static void init_apic(void)
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);
280 void inmate_main(void)
282 bool allow_terminate = false;
283 bool terminate = false;
287 printk_uart_base = UART_BASE;
289 for (n = 0; n < UART_IDLE_LOOPS; n++)
290 if (!(inb(UART_BASE + UART_LSR) & UART_LSR_THRE))
292 } while (n < UART_IDLE_LOOPS);
294 comm_region->cell_state = JAILHOUSE_CELL_RUNNING_LOCKED;
296 //-------------------------------------------------------
297 //--------------HPET part--------------------------------
301 gen_reg = (gen_regs *) ( (u64) HPET_BASE_QEMU);
303 printk("\nBase Address for HPET registers : %p\n", gen_reg);
304 map_range(gen_reg, PAGE_SIZE, MAP_UNCACHED);
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;
309 main_counter_tick_period = gen_reg->clock_period;
311 main_counter_reg = (main_val_reg *)
314 + RESERVED_BEFORE_MAIN_VAL_REG
320 curr_place = ((u8 *) main_counter_reg) + sizeof(main_val_reg), n = 0;
321 n < comparators_amount;
322 curr_place += sizeof(timer_regs), ++n )
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);
332 enable_main_counter();
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 );
339 set_timer_periodic( timer[2], NANS_TO_FEMPTS(5000000000ULL) / main_counter_tick_period );
342 set_timer_interrupt(timer[2], TIM2_INTI, irq_handler2);
344 printk("Done preparation..\n");
346 //-------------------------------------------------------
350 switch (comm_region->msg_to_cell) {
351 case JAILHOUSE_MSG_SHUTDOWN_REQUEST :
352 if (!allow_terminate) {
353 printk("Rejecting first shutdown request - "
355 jailhouse_send_reply_from_cell(comm_region,
356 JAILHOUSE_MSG_REQUEST_DENIED);
357 allow_terminate = true;
362 jailhouse_send_reply_from_cell(comm_region,
363 JAILHOUSE_MSG_UNKNOWN);
368 printk("Stopped HPET demo\n");
369 comm_region->cell_state = JAILHOUSE_CELL_SHUT_DOWN;