]> rtime.felk.cvut.cz Git - jailhouse.git/blob - inmates/apic-demo.c
71c307a9ca24c8d00b37bb2290f0b68afb71006a
[jailhouse.git] / inmates / apic-demo.c
1 /*
2  * Jailhouse, a Linux-based partitioning hypervisor
3  *
4  * Copyright (c) Siemens AG, 2013
5  *
6  * Authors:
7  *  Jan Kiszka <jan.kiszka@siemens.com>
8  *
9  * This work is licensed under the terms of the GNU GPL, version 2.  See
10  * the COPYING file in the top-level directory.
11  */
12
13 #include <inmate.h>
14 #include <jailhouse/hypercall.h>
15
16 #ifdef CONFIG_UART_OXPCIE952
17 #define UART_BASE               0xe010
18 #else
19 #define UART_BASE               0x3f8
20 #endif
21 #define UART_LSR                0x5
22 #define UART_LSR_THRE           0x20
23 #define UART_IDLE_LOOPS         100
24
25 #define NS_PER_MSEC             1000000UL
26 #define NS_PER_SEC              1000000000UL
27
28 #define NUM_IDT_DESC            33
29 #define APIC_TIMER_VECTOR       32
30
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
37
38 #define APIC_EOI_ACK            0
39
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;
44
45 static struct jailhouse_comm_region *comm_region =
46         (struct jailhouse_comm_region *)0x100000UL;
47
48 struct desc_table_reg {
49         u16 limit;
50         u64 base;
51 } __attribute__((packed));
52
53 static inline unsigned long read_msr(unsigned int msr)
54 {
55         u32 low, high;
56
57         asm volatile("rdmsr" : "=a" (low), "=d" (high) : "c" (msr));
58         return low | ((unsigned long)high << 32);
59 }
60
61 static inline void write_msr(unsigned int msr, unsigned long val)
62 {
63         asm volatile("wrmsr"
64                 : /* no output */
65                 : "c" (msr), "a" (val), "d" (val >> 32)
66                 : "memory");
67 }
68
69 static inline void write_idtr(struct desc_table_reg *val)
70 {
71         asm volatile("lidtq %0" : "=m" (*val));
72 }
73
74 void irq_handler(void)
75 {
76         unsigned long delta;
77
78         write_msr(X2APIC_EOI, APIC_EOI_ACK);
79
80         delta = read_pm_timer() - expected_time;
81         if (delta < min)
82                 min = delta;
83         if (delta > max)
84                 max = delta;
85         printk("Timer fired, jitter: %6ld ns, min: %6ld ns, max: %6ld ns\n",
86                delta, min, max);
87
88         expected_time += 100 * NS_PER_MSEC;
89         write_msr(X2APIC_TMICT,
90                   (expected_time - read_pm_timer()) * apic_frequency / NS_PER_SEC);
91 }
92
93 static void init_apic(void)
94 {
95         unsigned long entry = (unsigned long)irq_entry + FSEGMENT_BASE;
96         struct desc_table_reg dtr;
97         unsigned long start, end;
98         unsigned long tmr;
99
100         write_msr(X2APIC_SPIV, 0x1ff);
101
102         write_msr(X2APIC_TDCR, 3);
103
104         start = read_pm_timer();
105         write_msr(X2APIC_TMICT, 0xffffffff);
106
107         while (read_pm_timer() - start < 100 * NS_PER_MSEC)
108                 cpu_relax();
109
110         end = read_pm_timer();
111         tmr = read_msr(X2APIC_TMCCT);
112
113         apic_frequency = (0xffffffff - tmr) * NS_PER_SEC / (end - start);
114
115         printk("Calibrated APIC frequency: %lu kHz\n",
116                (apic_frequency * 16 + 500) / 1000);
117
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;
121
122         dtr.limit = NUM_IDT_DESC * 16 - 1;
123         dtr.base = (u64)&idt;
124         write_idtr(&dtr);
125
126         write_msr(X2APIC_LVTT, APIC_TIMER_VECTOR);
127         expected_time = read_pm_timer();
128         write_msr(X2APIC_TMICT, 1);
129
130         asm volatile("sti");
131 }
132
133 void inmate_main(void)
134 {
135         unsigned int n;
136
137         printk_uart_base = UART_BASE;
138         do {
139                 for (n = 0; n < UART_IDLE_LOOPS; n++)
140                         if (!(inb(UART_BASE + UART_LSR) & UART_LSR_THRE))
141                                 break;
142         } while (n < UART_IDLE_LOOPS);
143
144         if (init_pm_timer())
145                 init_apic();
146
147         while (comm_region->msg_to_cell != JAILHOUSE_MSG_SHUTDOWN_REQUESTED)
148                 asm volatile("hlt");
149
150         printk("Rejecting first shutdown - try again!\n");
151         jailhouse_send_reply_from_cell(comm_region,
152                                        JAILHOUSE_MSG_SHUTDOWN_DENIED);
153
154         for (n = 0; n < 10; n++)
155                 asm volatile("hlt");
156
157         printk("Stopped APIC demo\n");
158         comm_region->cell_state = JAILHOUSE_CELL_SHUT_DOWN;
159
160         asm volatile("cli; hlt");
161 }