--- /dev/null
+
+/**
+ * HPET as an inmate for Jailhouse
+ *
+ */
+#include <inmate.h>
+
+
+
+/**
+ * Definitions for ACPI
+ *
+ */
+
+struct rsdp {
+ char signature[8];
+ u8 checksum;
+ char oem[6];
+ u8 rev;
+ u32 rsdt;
+ u32 size;
+ u64 xsdt;
+ u8 ext_checksum;
+ char _res[3];
+} __attribute__((packed));
+
+struct acpi_table {
+ char signature[4];
+ u32 size;
+ u8 rev;
+ u8 checksum;
+ char oemid[6];
+ char oemtabid[8];
+ u32 oemrev;
+ char creator[4];
+ u32 crev;
+} __attribute__((packed));
+
+struct device_scope {
+ u8 type;
+ u8 size;
+ u16 _res;
+ u8 enum_id;
+ u8 start_bus;
+ /* XXX Hardcode PCI device scope: path = (device, function) */
+ u8 path[2];
+ //u8 path[];
+} __attribute__((packed));
+
+enum {
+ TYPE_DMAR = 0,
+ TYPE_RMRR = 1,
+ SCOPE_PCI_ENDPOINT = 1,
+};
+
+struct dmar_entry {
+ u16 type;
+ u16 size;
+
+ union {
+ struct {
+ u32 _res;
+ u64 phys;
+ } dmar;
+ /* If we include more than RMRRs here, we need to fix the DMAR
+ duplication code in zapp.c */
+ struct rmrr {
+ u16 _res;
+ u16 segment;
+ u64 base;
+ u64 limit;
+ struct device_scope first_scope;
+ } rmrr;
+ };
+} __attribute__((packed));
+
+struct dmar {
+ struct acpi_table generic;
+ u8 host_addr_width;
+ u8 flags;
+ char _res[10];
+ struct dmar_entry first_entry;
+};
+
+char acpi_checksum(const char *table, unsigned long count);
+void acpi_fix_checksum(struct acpi_table *tab);
+
+struct rsdp *acpi_get_rsdp(void);
+struct acpi_table **acpi_get_table_ptr(struct acpi_table *rsdt, const char signature[4]);
+
+static inline struct dmar_entry *acpi_dmar_next(struct dmar_entry *cur)
+{ return (struct dmar_entry *)((char *)cur + cur->size); }
+
+static inline bool acpi_in_table(struct acpi_table *tab, const void *p)
+{ return ((unsigned int *)tab + tab->size) > (unsigned int *)p; }
+
+typedef void *(*memory_alloc_t)(unsigned long len, unsigned align);
+
+struct acpi_table *acpi_dup_table(struct acpi_table *rsdt, const char signature[4],
+ memory_alloc_t alloc);
+
+/* ACPI code inspired by Vancouver. */
+
+/**
+ * @brief memory compare
+ * @details [long description]
+ *
+ * @param s1 [description]
+ * @param s2 [description]
+ * @param n [description]
+ */
+ typedef unsigned long size_t;
+static int memcmp(const void *s1, const void *s2, size_t n)
+{
+ const char *p1 = s1;
+ const char *p2 = s2;
+ int res = 0;
+ while (n-- && (res == 0)) {
+ res = *(p1++) - *(p2++);
+ }
+ return res;
+}
+
+
+/**
+ * Calculate the ACPI checksum of a table.
+ */
+char acpi_checksum(const char *table, unsigned long count)
+{
+ char res = 0;
+ while (count--) res += *(table++);
+ return res;
+}
+
+void acpi_fix_checksum(struct acpi_table *tab)
+{
+ tab->checksum -= acpi_checksum((const char *)tab, tab->size);
+}
+
+/**
+ * Return the rsdp.
+ */
+struct rsdp *acpi_get_rsdp(void)
+{
+ __label__ done;
+ struct rsdp *ret = 0;
+
+ void check(char *p) {
+ if ((memcmp(p, "RSD PTR ", 8) == 0) &&
+ (acpi_checksum(p, 20) == 0)) {
+ //ret = (char *)(((u32 *)p)[4]);
+ ret = (struct rsdp *)p;
+ goto done;
+ }
+ }
+
+ void find(unsigned int * start, unsigned long len) {
+ unsigned int * cur;
+ for (cur = start; cur < start + len; cur += 16)//was 16
+ check((char *)cur);
+ }
+
+ find( (unsigned int *) 0x40e, 0x400); /* BDA */
+ find( (unsigned int *) 0xe0000, 0x2000); /* BIOS read-only memory */
+
+done:
+ return ret;
+}
+
+struct acpi_table **acpi_get_table_ptr(struct acpi_table *rsdt, const char signature[4])
+{
+ const char *cur;
+ for (cur = (const char*)rsdt + sizeof(struct acpi_table);
+ acpi_in_table(rsdt, cur);
+ cur += sizeof(unsigned int *)) {
+ struct acpi_table *entry = *(struct acpi_table **)cur;
+ if (acpi_checksum((const char *)entry, entry->size) != 0)
+ continue;
+ if (memcmp(signature, entry->signature, sizeof(signature)) == 0)
+ return (struct acpi_table **)cur;
+ }
+
+ return 0;
+}
+
+/** Duplicate an ACPI table. */
+struct acpi_table *acpi_dup_table(struct acpi_table *rsdt, const char signature[4],
+ memory_alloc_t alloc)
+{
+ struct acpi_table **tab = acpi_get_table_ptr(rsdt, signature);
+ struct acpi_table *newtab = alloc((*tab)->size, 0x1000); /* 4K aligned */
+ memcpy(newtab, *tab, (*tab)->size);
+ *tab = newtab;
+ acpi_fix_checksum(rsdt);
+ return newtab;
+}
+
+/**
+ * HPET defenitions
+ */
+struct address_structure
+{
+ u8 address_space_id; // 0 - system memory, 1 - system I/O
+ u8 register_bit_width;
+ u8 register_bit_offset;
+ u8 reserved;
+ u64 base_address;
+} __attribute__((packed));
+
+typedef struct hpet_description_table_header
+{
+ struct acpi_table table_header;
+
+ u8 hardware_rev_id;
+ u8 comparator_count : 5;
+ u8 counter_size : 1;
+ u8 reserved : 1;
+ u8 legacy_replacement : 1;
+ u16 pci_vendor_id;
+
+ struct address_structure address_st;
+
+ u8 hpet_number;
+ u16 minimum_tick;
+ u8 page_protection;
+} __attribute__((packed)) acpi_hpet_tbl;
+
+/*
+* This was taken from IA-PC HPET Specification
+*
+*----------------------------------------------------------------------------------------
+* Offset |Register |Type
+*----------------------------------------------------------------------------------------
+* 000- 007h General Capabilities and ID Register Read Only
+* 008- 00Fh Reserved
+* 010- 017h General Configuration Register Read-Write
+* 018- 01Fh Reserved
+* 020- 027h General Interrupt Status Register Read/Write Clear
+* 028- 0EFh Reserved
+* 0F0- 0F7h Main Counter Value Register Read/Write
+* 0F8- 0FFh Reserved
+* 100- 107h Timer 0 Configuration and Capability Register Read/Write
+* 108- 10Fh Timer 0 Comparator Value Register Read/Write
+* 110- 117h Timer 0 FSB Interrupt Route Register Read/Write
+* 118- 11Fh Reserved
+*
+*(100+20*N )- (100+20*N+7)h Timer N Configuration and Capability Register Read/Write
+*(100+20*N+8)- (100+20*N+F)h Timer N Comparator Value Register Read/Write
+*(100+30*N )- (100+30*N+7)h Timer N FSB Interrupt Route Register Read/Write
+*(100+30*N+8)- (100+30*N+F)h Reserved
+*
+* -3FF ----for Timers 3-31
+*/
+
+/*
+ * HPET general capabilities register
+ */
+
+#define HPET_COUNTER_CLK_PERIOD_MASK (0xffffffff00000000ULL)
+#define HPET_COUNTER_CLK_PERIOD_SHIFT (32UL)
+#define HPET_VENDOR_ID_MASK (0x00000000ffff0000ULL)
+#define HPET_VENDOR_ID_SHIFT (16ULL)
+#define HPET_LEG_RT_CAP_MASK (0x8000)
+#define HPET_COUNTER_SIZE_MASK (0x2000)
+#define HPET_NUM_TIM_CAP_MASK (0x1f00)
+#define HPET_NUM_TIM_CAP_SHIFT (8ULL)
+
+/*
+ * HPET general configuration register
+ */
+
+#define HPET_LEG_RT_CNF_MASK (2UL)
+#define HPET_ENABLE_CNF_MASK (1UL)
+
+typedef struct general_timer_registers
+{
+
+ u32 capat_id_reg;
+ // u8 rev_id;
+ // /*8:12 - Number of timers, 13 - count_size_cap,
+ // 14 - reserved, 15 -legacy repl route hw support */
+ // u8 num_tim_cap : 5;
+ // u8 count_size_cap : 1;
+ // u8 reserved_bit : 1;
+ // u8 leg_rt_cap : 1;
+ // u16 vendor_id;
+ u32 clock_period;
+
+ u64 reserved1;
+ //u64 configuration;
+ /*0 - ENABLE_CNF, 1 - LEG_RT_CNF, 2:63 - reserved*/
+ /*u8 enable_cnf : 1;
+ u8 leg_rt_cnf : 1;
+ u8 reserved_5bit : 6;
+ u8 reserved_non_os;
+ u64 reserved_48bit : 48;*/
+ u32 config_reg;
+ u32 reservedforfuture;
+ u64 reserved2;
+
+ //u64 int_status_register
+ /*when level-triggered mode is used
+ each bit in the vector shows if the Timer N interrupt is ACTIVE.*/;
+ u32 int_status_vector;
+ u32 reserved_32bit;
+} __attribute__((packed)) gen_regs;
+
+/* 028h -> 0EFh space -- (0F0h - 28 == C8) */
+#define RESERVED_BEFORE_MAIN_VAL_REG 0x000000C8
+typedef struct main_counter_value_register
+{
+ u64 value;
+ u64 reserved;
+} __attribute__((packed)) main_val_reg;
+
+/*
+ * Timer configuration register
+ */
+
+#define Tn_INT_ROUTE_CAP_MASK (0xffffffff00000000ULL)
+#define Tn_INT_ROUTE_CAP_SHIFT (32UL)
+#define Tn_FSB_INT_DELCAP_MASK (0x8000UL)
+#define Tn_FSB_INT_DELCAP_SHIFT (15)
+#define Tn_FSB_EN_CNF_MASK (0x4000UL)
+#define Tn_FSB_EN_CNF_SHIFT (14)
+#define Tn_INT_ROUTE_CNF_MASK (0x3e00UL)
+#define Tn_INT_ROUTE_CNF_SHIFT (9)
+#define Tn_32MODE_CNF_MASK (0x0100UL)
+#define Tn_VAL_SET_CNF_MASK (0x0040UL)
+#define Tn_SIZE_CAP_MASK (0x0020UL)
+#define Tn_PER_INT_CAP_MASK (0x0010UL)
+#define Tn_TYPE_CNF_MASK (0x0008UL)
+#define Tn_INT_ENB_CNF_MASK (0x0004UL)
+#define Tn_INT_TYPE_CNF_MASK (0x0002UL)
+
+/*
+ * Timer FSB Interrupt Route Register
+ */
+
+#define Tn_FSB_INT_ADDR_MASK (0xffffffff00000000ULL)
+#define Tn_FSB_INT_ADDR_SHIFT (32UL)
+#define Tn_FSB_INT_VAL_MASK (0x00000000ffffffffULL)
+
+
+
+typedef struct timer_N_registers
+{
+ u32 cap_conf_reg;
+ u32 int_route_cap;
+
+ u64 comparator_val;
+ u64 fsb_interrupt_route;
+
+ u64 reserved;
+} __attribute__((packed)) timer_regs;
+
+#define MAX_TIMERS_IN_BLK 32
+#define MAX_BLK_NUM 8
+timer_regs * timer[MAX_TIMERS_IN_BLK];
+
+/**
+ * HPET functions
+ */
+
+#include <jailhouse/hypercall.h>
+//#include "hpet-demo.h"
+
+#ifdef CONFIG_UART_OXPCIE952
+#define UART_BASE 0xe010
+#else
+#define UART_BASE 0x3f8
+#endif
+#define UART_LSR 0x5
+#define UART_LSR_THRE 0x20
+#define UART_IDLE_LOOPS 100
+
+#define APIC_TIMER_VECTOR 32
+
+//-------------hpet defines-----------------------------
+#define NANS_TO_FEMPTS(X) ((X) * 1000000ULL)
+
+u64 main_counter_tick_period = 0;
+main_val_reg * main_counter_reg;
+gen_regs * gen_reg;
+
+
+static void inline enable_main_counter(void)
+{
+ gen_reg->config_reg |= HPET_ENABLE_CNF_MASK;
+}
+
+static void inline disable_main_counter(void)
+{
+ gen_reg->config_reg &= ~HPET_ENABLE_CNF_MASK;
+}
+
+static void set_timer_periodic(timer_regs * timer, u64 time)
+{
+ if (! (timer->cap_conf_reg & Tn_PER_INT_CAP_MASK) ) {
+ printk("Timer %p isnt periodic capable.\n", timer );
+ return;
+ }
+ if (time < main_counter_tick_period) {
+ time = main_counter_tick_period;
+ printk("Timer %p was set on minimal tick that's possible.\n", timer);
+ }
+
+ disable_main_counter();
+ main_counter_reg->value = 0ULL;
+ //enable int, set periodical, set value notification
+ timer->cap_conf_reg |= Tn_INT_ENB_CNF_MASK | Tn_TYPE_CNF_MASK | Tn_VAL_SET_CNF_MASK;
+ timer->comparator_val = time;
+ enable_main_counter();
+}
+
+static void set_timer_one_shot(timer_regs * timer, u64 time)
+{
+ if (time < (u64) main_counter_tick_period) {
+ time = main_counter_tick_period;
+ printk("Timer %p was set on minimal tick that's possible.\n", timer);
+ }
+
+ timer->comparator_val = time + main_counter_reg->value;
+ timer->cap_conf_reg |= Tn_INT_ENB_CNF_MASK;
+}
+
+static void set_legacy_mode(void)
+{
+ if ( !(gen_reg->capat_id_reg & HPET_LEG_RT_CAP_MASK) ) {
+ printk("Legacy replacement not implemented in HW.\n");
+ return;
+ }
+ gen_reg->config_reg |= HPET_LEG_RT_CNF_MASK;
+
+}
+
+//------------------------------------------------------
+
+static void irq_handler(void)
+{
+ printk("\nTimer 0 says hi!\n");
+}
+
+static void init_apic(void)
+{
+ //unsigned long apic_freq_khz;
+
+ int_init();
+ int_set_handler(APIC_TIMER_VECTOR, irq_handler);
+
+ //apic_freq_khz = apic_timer_init(APIC_TIMER_VECTOR);
+ //printk("Calibrated APIC frequency: %lu kHz\n", apic_freq_khz);
+
+ //expected_time = tsc_read() + NS_PER_MSEC;
+ //apic_timer_set(NS_PER_MSEC);
+
+ asm volatile("sti");
+}
+
+void inmate_main(void)
+{
+ bool allow_terminate = false;
+ bool terminate = false;
+
+ unsigned int n;
+
+ printk_uart_base = UART_BASE;
+ do {
+ for (n = 0; n < UART_IDLE_LOOPS; n++)
+ if (!(inb(UART_BASE + UART_LSR) & UART_LSR_THRE))
+ break;
+ } while (n < UART_IDLE_LOOPS);
+
+ comm_region->cell_state = JAILHOUSE_CELL_RUNNING_LOCKED;
+
+ //-------------------------------------------------------
+ //--------------HPET part--------------------------------
+
+ //struct rsdp *rsdp = acpi_get_rsdp();
+ //struct acpi_table *rsdt = (struct acpi_table *)((u64) rsdp->rsdt);
+ //printk("\nRSDT at %p.\n", rsdt);
+
+ //acpi_hpet_tbl ** acpi_table = (acpi_hpet_tbl **) acpi_get_table_ptr(rsdt, "HPET");
+
+ // if (acpi_table == 0) {
+ // printk("There is no HPET in ACPI tables.");
+ // goto job_done;
+ // }
+
+ //gen_reg = (gen_regs *) ( (u64) (*acpi_table)->address_st.base_address);
+ gen_reg = (gen_regs *) ( (u64) 0x00000003f1ff000ULL);
+
+ printk("\nBase Address for HPET registers : %p\n", gen_reg);
+ u8 comparators_amount = (gen_reg->capat_id_reg & HPET_NUM_TIM_CAP_MASK) >> HPET_NUM_TIM_CAP_SHIFT;
+
+ main_counter_tick_period = gen_reg->clock_period;
+
+ main_counter_reg = (main_val_reg *)
+ ( ((u8 *) gen_reg)
+ + sizeof(gen_regs)
+ + RESERVED_BEFORE_MAIN_VAL_REG
+ );
+
+ u8 * curr_place;
+
+ for (
+ curr_place = ((u8 *) main_counter_reg) + sizeof(main_val_reg), n = 0;
+ n < comparators_amount;
+ curr_place += sizeof(timer_regs), ++n )
+ {
+ timer[n] = (timer_regs *) curr_place;
+ printk("\nTimer %u on: %p, ", n, timer[n]);
+ printk("Timer comparator : 0x%llx\n", timer[n]->comparator_val);
+ }
+
+ set_legacy_mode();
+ enable_main_counter();
+
+ set_timer_periodic( timer[0], NANS_TO_FEMPTS(1000000000ULL) / main_counter_tick_period );
+ set_timer_one_shot( timer[1], NANS_TO_FEMPTS(10000000000ULL) / main_counter_tick_period );
+
+ init_apic();
+
+ //-------------------------------------------------------
+ while (!terminate) {
+ asm volatile("hlt");
+
+ switch (comm_region->msg_to_cell) {
+ case JAILHOUSE_MSG_SHUTDOWN_REQUEST:
+ if (!allow_terminate) {
+ printk("Rejecting first shutdown request - "
+ "try again!\n");
+ jailhouse_send_reply_from_cell(comm_region,
+ JAILHOUSE_MSG_REQUEST_DENIED);
+ allow_terminate = true;
+ } else
+ terminate = true;
+ break;
+ default:
+ jailhouse_send_reply_from_cell(comm_region,
+ JAILHOUSE_MSG_UNKNOWN);
+ break;
+ }
+ }
+job_done:
+ printk("Stopped APIC demo\n");
+ comm_region->cell_state = JAILHOUSE_CELL_SHUT_DOWN;
+
+}
+