From: Maxim Baryshnikov Date: Thu, 18 Feb 2016 15:11:31 +0000 (+0100) Subject: inmate example X-Git-Url: http://rtime.felk.cvut.cz/gitweb/jailhouse.git/commitdiff_plain/1dfd39c4c750fd9c180040d1a49545e552f52647 inmate example --- diff --git a/inmates/demos/x86/hpet-inmate.c b/inmates/demos/x86/hpet-inmate.c new file mode 100644 index 0000000..2b0d10c --- /dev/null +++ b/inmates/demos/x86/hpet-inmate.c @@ -0,0 +1,550 @@ + +/** + * HPET as an inmate for Jailhouse + * + */ +#include + + + +/** + * 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 +//#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; + +} +