]> rtime.felk.cvut.cz Git - jailhouse.git/blob - inmates/demos/x86/apic-demo.c
inmates: Map Comm Region always at 0x100000 for inmates framework
[jailhouse.git] / inmates / demos / x86 / 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 struct desc_table_reg {
46         u16 limit;
47         u64 base;
48 } __attribute__((packed));
49
50 static inline unsigned long read_msr(unsigned int msr)
51 {
52         u32 low, high;
53
54         asm volatile("rdmsr" : "=a" (low), "=d" (high) : "c" (msr));
55         return low | ((unsigned long)high << 32);
56 }
57
58 static inline void write_msr(unsigned int msr, unsigned long val)
59 {
60         asm volatile("wrmsr"
61                 : /* no output */
62                 : "c" (msr), "a" (val), "d" (val >> 32)
63                 : "memory");
64 }
65
66 static inline void write_idtr(struct desc_table_reg *val)
67 {
68         asm volatile("lidtq %0" : "=m" (*val));
69 }
70
71 void irq_handler(void)
72 {
73         unsigned long delta;
74
75         write_msr(X2APIC_EOI, APIC_EOI_ACK);
76
77         delta = read_pm_timer() - expected_time;
78         if (delta < min)
79                 min = delta;
80         if (delta > max)
81                 max = delta;
82         printk("Timer fired, jitter: %6ld ns, min: %6ld ns, max: %6ld ns\n",
83                delta, min, max);
84
85         expected_time += 100 * NS_PER_MSEC;
86         write_msr(X2APIC_TMICT, (expected_time - read_pm_timer()) *
87                                 apic_frequency / NS_PER_SEC);
88 }
89
90 static void init_apic(void)
91 {
92         unsigned long entry = (unsigned long)irq_entry + FSEGMENT_BASE;
93         struct desc_table_reg dtr;
94         unsigned long start, end;
95         unsigned long tmr;
96
97         write_msr(X2APIC_SPIV, 0x1ff);
98
99         write_msr(X2APIC_TDCR, 3);
100
101         start = read_pm_timer();
102         write_msr(X2APIC_TMICT, 0xffffffff);
103
104         while (read_pm_timer() - start < 100 * NS_PER_MSEC)
105                 cpu_relax();
106
107         end = read_pm_timer();
108         tmr = read_msr(X2APIC_TMCCT);
109
110         apic_frequency = (0xffffffff - tmr) * NS_PER_SEC / (end - start);
111
112         printk("Calibrated APIC frequency: %lu kHz\n",
113                (apic_frequency * 16 + 500) / 1000);
114
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;
118
119         dtr.limit = NUM_IDT_DESC * 16 - 1;
120         dtr.base = (u64)&idt;
121         write_idtr(&dtr);
122
123         write_msr(X2APIC_LVTT, APIC_TIMER_VECTOR);
124         expected_time = read_pm_timer();
125         write_msr(X2APIC_TMICT, 1);
126
127         asm volatile("sti");
128 }
129
130 void inmate_main(void)
131 {
132         bool terminate = false;
133         unsigned int n;
134
135         printk_uart_base = UART_BASE;
136         do {
137                 for (n = 0; n < UART_IDLE_LOOPS; n++)
138                         if (!(inb(UART_BASE + UART_LSR) & UART_LSR_THRE))
139                                 break;
140         } while (n < UART_IDLE_LOOPS);
141
142         comm_region->cell_state = JAILHOUSE_CELL_RUNNING_LOCKED;
143
144         init_apic();
145
146         while (!terminate) {
147                 asm volatile("hlt");
148
149                 switch (comm_region->msg_to_cell) {
150                 case JAILHOUSE_MSG_SHUTDOWN_REQUEST:
151                         printk("Rejecting first shutdown request - "
152                                "try again!\n");
153                         jailhouse_send_reply_from_cell(comm_region,
154                                         JAILHOUSE_MSG_REQUEST_DENIED);
155                         terminate = true;
156                         break;
157                 default:
158                         jailhouse_send_reply_from_cell(comm_region,
159                                         JAILHOUSE_MSG_UNKNOWN);
160                         break;
161                 }
162         }
163
164         for (n = 0; n < 10; n++)
165                 asm volatile("hlt");
166
167         printk("Stopped APIC demo\n");
168         comm_region->cell_state = JAILHOUSE_CELL_SHUT_DOWN;
169
170         asm volatile("cli; hlt");
171 }