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 struct desc_table_reg {
48 } __attribute__((packed));
50 static inline unsigned long read_msr(unsigned int msr)
54 asm volatile("rdmsr" : "=a" (low), "=d" (high) : "c" (msr));
55 return low | ((unsigned long)high << 32);
58 static inline void write_msr(unsigned int msr, unsigned long val)
62 : "c" (msr), "a" (val), "d" (val >> 32)
66 static inline void write_idtr(struct desc_table_reg *val)
68 asm volatile("lidtq %0" : "=m" (*val));
71 void irq_handler(void)
75 write_msr(X2APIC_EOI, APIC_EOI_ACK);
77 delta = read_pm_timer() - expected_time;
82 printk("Timer fired, jitter: %6ld ns, min: %6ld ns, max: %6ld ns\n",
85 expected_time += 100 * NS_PER_MSEC;
86 write_msr(X2APIC_TMICT, (expected_time - read_pm_timer()) *
87 apic_frequency / NS_PER_SEC);
90 static void init_apic(void)
92 unsigned long entry = (unsigned long)irq_entry + FSEGMENT_BASE;
93 struct desc_table_reg dtr;
94 unsigned long start, end;
97 write_msr(X2APIC_SPIV, 0x1ff);
99 write_msr(X2APIC_TDCR, 3);
101 start = read_pm_timer();
102 write_msr(X2APIC_TMICT, 0xffffffff);
104 while (read_pm_timer() - start < 100 * NS_PER_MSEC)
107 end = read_pm_timer();
108 tmr = read_msr(X2APIC_TMCCT);
110 apic_frequency = (0xffffffff - tmr) * NS_PER_SEC / (end - start);
112 printk("Calibrated APIC frequency: %lu kHz\n",
113 (apic_frequency * 16 + 500) / 1000);
115 idt[APIC_TIMER_VECTOR * 4] = (entry & 0xffff) | (INMATE_CS64 << 16);
116 idt[APIC_TIMER_VECTOR * 4 + 1] = 0x8e00 | (entry & 0xffff0000);
117 idt[APIC_TIMER_VECTOR * 4 + 2] = entry >> 32;
119 dtr.limit = NUM_IDT_DESC * 16 - 1;
120 dtr.base = (u64)&idt;
123 write_msr(X2APIC_LVTT, APIC_TIMER_VECTOR);
124 expected_time = read_pm_timer();
125 write_msr(X2APIC_TMICT, 1);
130 void inmate_main(void)
132 bool terminate = false;
135 printk_uart_base = UART_BASE;
137 for (n = 0; n < UART_IDLE_LOOPS; n++)
138 if (!(inb(UART_BASE + UART_LSR) & UART_LSR_THRE))
140 } while (n < UART_IDLE_LOOPS);
142 comm_region->cell_state = JAILHOUSE_CELL_RUNNING_LOCKED;
149 switch (comm_region->msg_to_cell) {
150 case JAILHOUSE_MSG_SHUTDOWN_REQUEST:
151 printk("Rejecting first shutdown request - "
153 jailhouse_send_reply_from_cell(comm_region,
154 JAILHOUSE_MSG_REQUEST_DENIED);
158 jailhouse_send_reply_from_cell(comm_region,
159 JAILHOUSE_MSG_UNKNOWN);
164 for (n = 0; n < 10; n++)
167 printk("Stopped APIC demo\n");
168 comm_region->cell_state = JAILHOUSE_CELL_SHUT_DOWN;
170 asm volatile("cli; hlt");