]> rtime.felk.cvut.cz Git - jailhouse.git/blob - inmates/demos/x86/hpet-inmate.c
inmate example
[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
10 /**
11  * Definitions for ACPI
12  *
13  */
14
15 struct rsdp {
16         char signature[8];
17         u8 checksum;
18         char oem[6];
19         u8 rev;
20         u32 rsdt;
21         u32 size;
22         u64 xsdt;
23         u8 ext_checksum;
24         char _res[3];
25 } __attribute__((packed));
26
27 struct acpi_table {
28         char signature[4];
29         u32 size;
30         u8  rev;
31         u8  checksum;
32         char oemid[6];
33         char oemtabid[8];
34         u32 oemrev;
35         char creator[4];
36         u32 crev;
37 } __attribute__((packed));
38
39 struct device_scope {
40         u8 type;
41         u8 size;
42         u16 _res;
43         u8 enum_id;
44         u8 start_bus;
45         /* XXX Hardcode PCI device scope: path = (device, function) */
46         u8 path[2];
47         //u8 path[];
48 } __attribute__((packed));
49
50 enum {
51         TYPE_DMAR          = 0,
52         TYPE_RMRR          = 1,
53         SCOPE_PCI_ENDPOINT = 1,
54 };
55
56 struct dmar_entry {
57         u16 type;
58         u16 size;
59
60         union {
61                 struct {
62                         u32 _res;
63                         u64 phys;
64                 } dmar;
65                 /* If we include more than RMRRs here, we need to fix the DMAR
66                    duplication code in zapp.c */
67                 struct rmrr {
68                         u16 _res;
69                         u16 segment;
70                         u64 base;
71                         u64 limit;
72                         struct device_scope first_scope;
73                 } rmrr;
74         };
75 } __attribute__((packed));
76
77 struct dmar {
78         struct acpi_table generic;
79         u8 host_addr_width;
80         u8 flags;
81         char _res[10];
82         struct dmar_entry first_entry;
83 };
84
85 char acpi_checksum(const char *table, unsigned long count);
86 void acpi_fix_checksum(struct acpi_table *tab);
87
88 struct rsdp *acpi_get_rsdp(void);
89 struct acpi_table **acpi_get_table_ptr(struct acpi_table *rsdt, const char signature[4]);
90
91 static inline struct dmar_entry *acpi_dmar_next(struct dmar_entry *cur)
92 { return (struct dmar_entry *)((char *)cur + cur->size); }
93
94 static inline bool acpi_in_table(struct acpi_table *tab, const void *p)
95 { return ((unsigned int *)tab + tab->size) > (unsigned int *)p; }
96
97 typedef void *(*memory_alloc_t)(unsigned long len, unsigned align);
98
99 struct acpi_table *acpi_dup_table(struct acpi_table *rsdt, const char signature[4],
100                                   memory_alloc_t alloc);
101
102 /* ACPI code inspired by Vancouver. */
103
104 /**
105  * @brief memory compare
106  * @details [long description]
107  * 
108  * @param s1 [description]
109  * @param s2 [description]
110  * @param n [description]
111  */
112  typedef unsigned long size_t;
113 static int memcmp(const void *s1, const void *s2, size_t n)
114 {
115   const char *p1 = s1;
116   const char *p2 = s2;
117   int res = 0;
118   while (n-- && (res == 0)) {
119     res = *(p1++) - *(p2++);
120   }
121   return res;
122 }
123
124
125 /**
126  * Calculate the ACPI checksum of a table.
127  */
128 char acpi_checksum(const char *table, unsigned long count)
129 {
130         char res = 0;
131         while (count--) res += *(table++);
132         return res;
133 }
134
135 void acpi_fix_checksum(struct acpi_table *tab)
136 {
137         tab->checksum -= acpi_checksum((const char *)tab, tab->size);
138 }
139
140 /**
141  * Return the rsdp.
142  */
143 struct rsdp *acpi_get_rsdp(void)
144 {
145         __label__ done;
146         struct rsdp *ret = 0;
147
148         void check(char *p) {
149                 if ((memcmp(p, "RSD PTR ", 8) == 0) &&
150                         (acpi_checksum(p, 20) == 0)) {
151                         //ret = (char *)(((u32 *)p)[4]);
152                         ret = (struct rsdp *)p;
153                         goto done;
154                 }
155         }
156
157         void find(unsigned int * start, unsigned long len) {
158                 unsigned int * cur;
159                 for (cur = start; cur < start + len; cur += 16)//was 16
160                         check((char *)cur);
161         }
162
163         find( (unsigned int *) 0x40e, 0x400);           /* BDA */
164         find( (unsigned int *) 0xe0000, 0x2000);        /* BIOS read-only memory */
165
166 done:
167         return ret;
168 }
169
170 struct acpi_table **acpi_get_table_ptr(struct acpi_table *rsdt, const char signature[4])
171 {
172         const char *cur;
173         for (cur = (const char*)rsdt + sizeof(struct acpi_table);
174                 acpi_in_table(rsdt, cur);
175                 cur += sizeof(unsigned int *)) {
176                 struct acpi_table *entry = *(struct acpi_table **)cur;
177                 if (acpi_checksum((const char *)entry, entry->size) != 0)
178                         continue;
179                 if (memcmp(signature, entry->signature, sizeof(signature)) == 0)
180                         return (struct acpi_table **)cur;
181         }
182
183         return 0;
184 }
185
186 /** Duplicate an ACPI table. */
187 struct acpi_table *acpi_dup_table(struct acpi_table *rsdt, const char signature[4],
188                                   memory_alloc_t alloc)
189 {
190         struct acpi_table **tab   = acpi_get_table_ptr(rsdt, signature);
191         struct acpi_table *newtab = alloc((*tab)->size, 0x1000); /* 4K aligned */
192         memcpy(newtab, *tab, (*tab)->size);
193         *tab = newtab;
194         acpi_fix_checksum(rsdt);
195         return newtab;
196 }
197
198 /**
199  * HPET defenitions
200  */
201 struct address_structure
202 {
203         u8 address_space_id;    // 0 - system memory, 1 - system I/O
204         u8 register_bit_width;
205         u8 register_bit_offset;
206         u8 reserved;
207         u64 base_address;
208 } __attribute__((packed));
209
210 typedef struct hpet_description_table_header
211 {
212         struct acpi_table table_header;
213
214         u8 hardware_rev_id;
215         u8 comparator_count    : 5;
216         u8 counter_size        : 1;
217         u8 reserved            : 1;
218         u8 legacy_replacement  : 1;
219         u16 pci_vendor_id;
220
221         struct address_structure address_st;
222
223         u8 hpet_number;
224         u16 minimum_tick;
225         u8 page_protection;
226 } __attribute__((packed)) acpi_hpet_tbl;
227
228 /*
229 *   This was taken from IA-PC HPET Specification
230 *
231 *----------------------------------------------------------------------------------------
232 *    Offset                 |Register                                       |Type
233 *----------------------------------------------------------------------------------------
234 *    000-        007h        General Capabilities and ID Register            Read Only
235 *    008-        00Fh        Reserved
236 *    010-        017h        General Configuration Register                  Read-Write
237 *    018-        01Fh        Reserved
238 *    020-        027h        General Interrupt Status Register               Read/Write Clear
239 *    028-        0EFh        Reserved
240 *    0F0-        0F7h        Main Counter Value Register                     Read/Write
241 *    0F8-        0FFh        Reserved
242 *    100-        107h        Timer 0 Configuration and Capability Register   Read/Write
243 *    108-        10Fh        Timer 0 Comparator Value Register               Read/Write
244 *    110-        117h        Timer 0 FSB Interrupt Route Register            Read/Write
245 *    118-        11Fh        Reserved
246 *
247 *(100+20*N  )- (100+20*N+7)h Timer N Configuration and Capability Register   Read/Write
248 *(100+20*N+8)- (100+20*N+F)h Timer N Comparator Value Register               Read/Write
249 *(100+30*N  )- (100+30*N+7)h Timer N FSB Interrupt Route Register            Read/Write
250 *(100+30*N+8)- (100+30*N+F)h Reserved
251 *
252 *                -3FF        ----for Timers 3-31
253 */
254
255 /*
256  * HPET general capabilities register
257  */
258
259 #define HPET_COUNTER_CLK_PERIOD_MASK    (0xffffffff00000000ULL)
260 #define HPET_COUNTER_CLK_PERIOD_SHIFT   (32UL)
261 #define HPET_VENDOR_ID_MASK     (0x00000000ffff0000ULL)
262 #define HPET_VENDOR_ID_SHIFT        (16ULL)
263 #define HPET_LEG_RT_CAP_MASK        (0x8000)
264 #define HPET_COUNTER_SIZE_MASK      (0x2000)
265 #define HPET_NUM_TIM_CAP_MASK       (0x1f00)
266 #define HPET_NUM_TIM_CAP_SHIFT      (8ULL)
267
268 /*
269  * HPET general configuration register
270  */
271
272 #define HPET_LEG_RT_CNF_MASK        (2UL)
273 #define HPET_ENABLE_CNF_MASK        (1UL)
274
275 typedef struct general_timer_registers
276 {
277
278         u32 capat_id_reg;
279         // u8 rev_id;
280         // /*8:12 - Number of timers, 13 - count_size_cap,
281         //         14 - reserved, 15 -legacy repl route hw support */
282         // u8 num_tim_cap     : 5;
283         // u8 count_size_cap  : 1;
284         // u8 reserved_bit    : 1;
285         // u8 leg_rt_cap      : 1;
286         // u16 vendor_id;
287         u32 clock_period;
288
289         u64 reserved1;
290         //u64 configuration;
291         /*0 - ENABLE_CNF, 1 - LEG_RT_CNF, 2:63 - reserved*/
292         /*u8 enable_cnf      : 1;
293         u8 leg_rt_cnf      : 1;
294         u8 reserved_5bit   : 6;
295         u8 reserved_non_os;
296         u64 reserved_48bit : 48;*/
297         u32 config_reg;
298         u32 reservedforfuture;
299         u64 reserved2;
300
301         //u64 int_status_register
302         /*when level-triggered mode is used
303         each bit in the vector shows if the Timer N interrupt is ACTIVE.*/;
304         u32 int_status_vector;
305         u32 reserved_32bit;
306 } __attribute__((packed)) gen_regs;
307
308 /* 028h -> 0EFh space -- (0F0h - 28 == C8) */
309 #define RESERVED_BEFORE_MAIN_VAL_REG 0x000000C8
310 typedef struct main_counter_value_register
311 {
312         u64 value;
313         u64 reserved;
314 } __attribute__((packed)) main_val_reg;
315
316 /*
317  * Timer configuration register
318  */
319
320 #define Tn_INT_ROUTE_CAP_MASK       (0xffffffff00000000ULL)
321 #define Tn_INT_ROUTE_CAP_SHIFT      (32UL)
322 #define Tn_FSB_INT_DELCAP_MASK      (0x8000UL)
323 #define Tn_FSB_INT_DELCAP_SHIFT     (15)
324 #define Tn_FSB_EN_CNF_MASK      (0x4000UL)
325 #define Tn_FSB_EN_CNF_SHIFT     (14)
326 #define Tn_INT_ROUTE_CNF_MASK       (0x3e00UL)
327 #define Tn_INT_ROUTE_CNF_SHIFT      (9)
328 #define Tn_32MODE_CNF_MASK      (0x0100UL)
329 #define Tn_VAL_SET_CNF_MASK     (0x0040UL)
330 #define Tn_SIZE_CAP_MASK        (0x0020UL)
331 #define Tn_PER_INT_CAP_MASK     (0x0010UL)
332 #define Tn_TYPE_CNF_MASK        (0x0008UL)
333 #define Tn_INT_ENB_CNF_MASK     (0x0004UL)
334 #define Tn_INT_TYPE_CNF_MASK        (0x0002UL)
335
336 /*
337  * Timer FSB Interrupt Route Register
338  */
339
340 #define Tn_FSB_INT_ADDR_MASK        (0xffffffff00000000ULL)
341 #define Tn_FSB_INT_ADDR_SHIFT       (32UL)
342 #define Tn_FSB_INT_VAL_MASK     (0x00000000ffffffffULL)
343
344
345
346 typedef struct timer_N_registers
347 {
348         u32 cap_conf_reg;
349         u32 int_route_cap;
350
351         u64 comparator_val;
352         u64 fsb_interrupt_route;
353
354         u64 reserved;
355 } __attribute__((packed)) timer_regs;
356
357 #define MAX_TIMERS_IN_BLK   32
358 #define MAX_BLK_NUM         8
359 timer_regs * timer[MAX_TIMERS_IN_BLK];
360
361 /**
362  * HPET functions
363  */
364
365 #include <jailhouse/hypercall.h>
366 //#include "hpet-demo.h"
367
368 #ifdef CONFIG_UART_OXPCIE952
369 #define UART_BASE               0xe010
370 #else
371 #define UART_BASE               0x3f8
372 #endif
373 #define UART_LSR                0x5
374 #define UART_LSR_THRE           0x20
375 #define UART_IDLE_LOOPS         100
376
377 #define APIC_TIMER_VECTOR       32
378
379 //-------------hpet defines-----------------------------
380 #define NANS_TO_FEMPTS(X) ((X) * 1000000ULL)
381
382 u64 main_counter_tick_period = 0;
383 main_val_reg * main_counter_reg;
384 gen_regs * gen_reg;
385
386
387 static void inline enable_main_counter(void)
388 {
389         gen_reg->config_reg |= HPET_ENABLE_CNF_MASK;
390 }
391
392 static void inline disable_main_counter(void)
393 {
394         gen_reg->config_reg &= ~HPET_ENABLE_CNF_MASK;
395 }
396
397 static void set_timer_periodic(timer_regs * timer, u64 time)
398 {
399         if (! (timer->cap_conf_reg & Tn_PER_INT_CAP_MASK) ) {
400                 printk("Timer %p isnt periodic capable.\n", timer );
401                 return;
402         }
403         if (time < main_counter_tick_period) {
404                 time = main_counter_tick_period;
405                 printk("Timer %p was set on minimal tick that's possible.\n", timer);
406         }
407
408         disable_main_counter();
409         main_counter_reg->value = 0ULL;
410         //enable int, set periodical, set value notification
411         timer->cap_conf_reg |= Tn_INT_ENB_CNF_MASK | Tn_TYPE_CNF_MASK | Tn_VAL_SET_CNF_MASK;
412         timer->comparator_val = time;
413         enable_main_counter();
414 }
415  
416 static void set_timer_one_shot(timer_regs * timer, u64 time)
417 {
418         if (time < (u64) main_counter_tick_period) {
419                 time = main_counter_tick_period;
420                 printk("Timer %p was set on minimal tick that's possible.\n", timer);
421         }
422
423         timer->comparator_val = time + main_counter_reg->value;
424         timer->cap_conf_reg |= Tn_INT_ENB_CNF_MASK;
425 }
426
427 static void set_legacy_mode(void)
428 {
429         if ( !(gen_reg->capat_id_reg & HPET_LEG_RT_CAP_MASK) ) {
430                 printk("Legacy replacement not implemented in HW.\n");
431                 return;
432         }
433         gen_reg->config_reg |= HPET_LEG_RT_CNF_MASK;
434
435 }
436
437 //------------------------------------------------------
438
439 static void irq_handler(void)
440 {
441         printk("\nTimer 0 says hi!\n");
442 }
443
444 static void init_apic(void)
445 {
446         //unsigned long apic_freq_khz;
447
448         int_init();
449         int_set_handler(APIC_TIMER_VECTOR, irq_handler);
450
451         //apic_freq_khz = apic_timer_init(APIC_TIMER_VECTOR);
452         //printk("Calibrated APIC frequency: %lu kHz\n", apic_freq_khz);
453
454         //expected_time = tsc_read() + NS_PER_MSEC;
455         //apic_timer_set(NS_PER_MSEC);
456
457         asm volatile("sti");
458 }
459
460 void inmate_main(void)
461 {
462         bool allow_terminate = false;
463         bool terminate = false;
464
465         unsigned int n;
466
467         printk_uart_base = UART_BASE;
468         do {
469                 for (n = 0; n < UART_IDLE_LOOPS; n++)
470                         if (!(inb(UART_BASE + UART_LSR) & UART_LSR_THRE))
471                                 break;
472         } while (n < UART_IDLE_LOOPS);
473
474         comm_region->cell_state = JAILHOUSE_CELL_RUNNING_LOCKED;
475
476         //-------------------------------------------------------
477         //--------------HPET part--------------------------------
478
479         //struct rsdp *rsdp = acpi_get_rsdp();
480         //struct acpi_table *rsdt = (struct acpi_table *)((u64) rsdp->rsdt);
481         //printk("\nRSDT at %p.\n", rsdt);
482
483         //acpi_hpet_tbl ** acpi_table = (acpi_hpet_tbl **) acpi_get_table_ptr(rsdt, "HPET");
484
485         // if (acpi_table == 0) {
486         //      printk("There is no HPET in ACPI tables.");
487         //      goto job_done;
488         // }
489
490         //gen_reg =  (gen_regs *) ( (u64) (*acpi_table)->address_st.base_address);
491         gen_reg =  (gen_regs *) ( (u64) 0x00000003f1ff000ULL);
492         
493         printk("\nBase Address for HPET registers : %p\n", gen_reg);
494         u8 comparators_amount = (gen_reg->capat_id_reg & HPET_NUM_TIM_CAP_MASK) >> HPET_NUM_TIM_CAP_SHIFT;
495         
496         main_counter_tick_period = gen_reg->clock_period;
497
498         main_counter_reg = (main_val_reg *)
499                            (   ((u8 *) gen_reg)
500                                + sizeof(gen_regs)
501                                + RESERVED_BEFORE_MAIN_VAL_REG
502                            );
503
504         u8 * curr_place;
505
506         for (
507             curr_place = ((u8 *) main_counter_reg) + sizeof(main_val_reg), n = 0;
508             n < comparators_amount;
509             curr_place += sizeof(timer_regs), ++n )
510         {
511                 timer[n] = (timer_regs *) curr_place;
512                 printk("\nTimer %u on: %p, ", n,  timer[n]);
513                 printk("Timer comparator : 0x%llx\n", timer[n]->comparator_val);
514         }
515
516         set_legacy_mode();
517         enable_main_counter();
518
519         set_timer_periodic( timer[0], NANS_TO_FEMPTS(1000000000ULL) / main_counter_tick_period );
520         set_timer_one_shot( timer[1], NANS_TO_FEMPTS(10000000000ULL) / main_counter_tick_period );
521
522         init_apic();
523
524         //-------------------------------------------------------
525         while (!terminate) {
526                 asm volatile("hlt");
527
528                 switch (comm_region->msg_to_cell) {
529                 case JAILHOUSE_MSG_SHUTDOWN_REQUEST:
530                         if (!allow_terminate) {
531                                 printk("Rejecting first shutdown request - "
532                                        "try again!\n");
533                                 jailhouse_send_reply_from_cell(comm_region,
534                                                                JAILHOUSE_MSG_REQUEST_DENIED);
535                                 allow_terminate = true;
536                         } else
537                                 terminate = true;
538                         break;
539                 default:
540                         jailhouse_send_reply_from_cell(comm_region,
541                                                        JAILHOUSE_MSG_UNKNOWN);
542                         break;
543                 }
544         }
545 job_done:
546         printk("Stopped APIC demo\n");
547         comm_region->cell_state = JAILHOUSE_CELL_SHUT_DOWN;
548
549 }
550