2 * Jailhouse, a Linux-based partitioning hypervisor
4 * Copyright (c) Siemens AG, 2013
7 * Jan Kiszka <jan.kiszka@siemens.com>
9 * This work is licensed under the terms of the GNU GPL, version 2. See
10 * the COPYING file in the top-level directory.
14 #include <jailhouse/hypercall.h>
16 #ifdef CONFIG_UART_OXPCIE952
17 #define UART_BASE 0xe010
19 #define UART_BASE 0x3f8
22 #define UART_LSR_THRE 0x20
23 #define UART_IDLE_LOOPS 100
25 #define NS_PER_MSEC 1000000UL
26 #define NS_PER_SEC 1000000000UL
28 #define NUM_IDT_DESC 33
29 #define APIC_TIMER_VECTOR 32
31 #define X2APIC_EOI 0x80b
32 #define X2APIC_SPIV 0x80f
33 #define X2APIC_LVTT 0x832
34 #define X2APIC_TMICT 0x838
35 #define X2APIC_TMCCT 0x839
36 #define X2APIC_TDCR 0x83e
38 #define APIC_EOI_ACK 0
40 static u32 idt[NUM_IDT_DESC * 4];
41 static unsigned long apic_frequency;
42 static unsigned long expected_time;
43 static unsigned long min = -1, max;
45 static struct jailhouse_comm_region *comm_region =
46 (struct jailhouse_comm_region *)0x100000UL;
48 struct desc_table_reg {
51 } __attribute__((packed));
53 static inline unsigned long read_msr(unsigned int msr)
57 asm volatile("rdmsr" : "=a" (low), "=d" (high) : "c" (msr));
58 return low | ((unsigned long)high << 32);
61 static inline void write_msr(unsigned int msr, unsigned long val)
65 : "c" (msr), "a" (val), "d" (val >> 32)
69 static inline void write_idtr(struct desc_table_reg *val)
71 asm volatile("lidtq %0" : "=m" (*val));
74 void irq_handler(void)
78 write_msr(X2APIC_EOI, APIC_EOI_ACK);
80 delta = read_pm_timer() - expected_time;
85 printk("Timer fired, jitter: %6ld ns, min: %6ld ns, max: %6ld ns\n",
88 expected_time += 100 * NS_PER_MSEC;
89 write_msr(X2APIC_TMICT,
90 (expected_time - read_pm_timer()) * apic_frequency / NS_PER_SEC);
93 static void init_apic(void)
95 unsigned long entry = (unsigned long)irq_entry + FSEGMENT_BASE;
96 struct desc_table_reg dtr;
97 unsigned long start, end;
100 write_msr(X2APIC_SPIV, 0x1ff);
102 write_msr(X2APIC_TDCR, 3);
104 start = read_pm_timer();
105 write_msr(X2APIC_TMICT, 0xffffffff);
107 while (read_pm_timer() - start < 100 * NS_PER_MSEC)
110 end = read_pm_timer();
111 tmr = read_msr(X2APIC_TMCCT);
113 apic_frequency = (0xffffffff - tmr) * NS_PER_SEC / (end - start);
115 printk("Calibrated APIC frequency: %lu kHz\n",
116 (apic_frequency * 16 + 500) / 1000);
118 idt[APIC_TIMER_VECTOR * 4] = (entry & 0xffff) | (INMATE_CS64 << 16);
119 idt[APIC_TIMER_VECTOR * 4 + 1] = 0x8e00 | (entry & 0xffff0000);
120 idt[APIC_TIMER_VECTOR * 4 + 2] = entry >> 32;
122 dtr.limit = NUM_IDT_DESC * 16 - 1;
123 dtr.base = (u64)&idt;
126 write_msr(X2APIC_LVTT, APIC_TIMER_VECTOR);
127 expected_time = read_pm_timer();
128 write_msr(X2APIC_TMICT, 1);
133 void inmate_main(void)
137 printk_uart_base = UART_BASE;
139 for (n = 0; n < UART_IDLE_LOOPS; n++)
140 if (!(inb(UART_BASE + UART_LSR) & UART_LSR_THRE))
142 } while (n < UART_IDLE_LOOPS);
147 while (comm_region->msg_to_cell != JAILHOUSE_MSG_SHUTDOWN_REQUESTED)
150 printk("Rejecting first shutdown - try again!\n");
151 jailhouse_send_reply_from_cell(comm_region,
152 JAILHOUSE_MSG_SHUTDOWN_DENIED);
154 for (n = 0; n < 10; n++)
157 printk("Stopped APIC demo\n");
158 comm_region->cell_state = JAILHOUSE_CELL_SHUT_DOWN;
160 asm volatile("cli; hlt");