]> rtime.felk.cvut.cz Git - jailhouse.git/commitdiff
inmate example
authorMaxim Baryshnikov <barysmax@fel.cvut.cz>
Thu, 18 Feb 2016 15:11:31 +0000 (16:11 +0100)
committerMaxim Baryshnikov <barysmax@fel.cvut.cz>
Thu, 18 Feb 2016 15:11:31 +0000 (16:11 +0100)
inmates/demos/x86/hpet-inmate.c [new file with mode: 0644]

diff --git a/inmates/demos/x86/hpet-inmate.c b/inmates/demos/x86/hpet-inmate.c
new file mode 100644 (file)
index 0000000..2b0d10c
--- /dev/null
@@ -0,0 +1,550 @@
+
+/**
+ * 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;
+
+}
+