$(LIBDIR)/header.o $(LIBDIR)/printk.o $(LIBDIR)/pm-timer.o
apic-demo-y := apic-demo.o \
- $(LIBDIR)/header.o $(LIBDIR)/printk.o $(LIBDIR)/pm-timer.o
+ $(LIBDIR)/header.o $(LIBDIR)/printk.o $(LIBDIR)/pm-timer.o \
+ $(LIBDIR)/int.o
$(eval $(call DECLARE_TARGETS,$(INMATES)))
#define NS_PER_MSEC 1000000UL
#define NS_PER_SEC 1000000000UL
-#define NUM_IDT_DESC 33
#define APIC_TIMER_VECTOR 32
-#define X2APIC_EOI 0x80b
-#define X2APIC_SPIV 0x80f
#define X2APIC_LVTT 0x832
#define X2APIC_TMICT 0x838
#define X2APIC_TMCCT 0x839
#define X2APIC_TDCR 0x83e
-#define APIC_EOI_ACK 0
-
-static u32 idt[NUM_IDT_DESC * 4];
static unsigned long apic_frequency;
static unsigned long expected_time;
static unsigned long min = -1, max;
-struct desc_table_reg {
- u16 limit;
- u64 base;
-} __attribute__((packed));
-
-static inline unsigned long read_msr(unsigned int msr)
-{
- u32 low, high;
-
- asm volatile("rdmsr" : "=a" (low), "=d" (high) : "c" (msr));
- return low | ((unsigned long)high << 32);
-}
-
-static inline void write_msr(unsigned int msr, unsigned long val)
-{
- asm volatile("wrmsr"
- : /* no output */
- : "c" (msr), "a" (val), "d" (val >> 32)
- : "memory");
-}
-
-static inline void write_idtr(struct desc_table_reg *val)
-{
- asm volatile("lidtq %0" : "=m" (*val));
-}
-
-void irq_handler(void)
+static void irq_handler(void)
{
unsigned long delta;
- write_msr(X2APIC_EOI, APIC_EOI_ACK);
-
delta = read_pm_timer() - expected_time;
if (delta < min)
min = delta;
static void init_apic(void)
{
- unsigned long entry = (unsigned long)irq_entry + FSEGMENT_BASE;
- struct desc_table_reg dtr;
unsigned long start, end;
unsigned long tmr;
- write_msr(X2APIC_SPIV, 0x1ff);
+ int_init();
+ int_set_handler(APIC_TIMER_VECTOR, irq_handler);
write_msr(X2APIC_TDCR, 3);
printk("Calibrated APIC frequency: %lu kHz\n",
(apic_frequency * 16 + 500) / 1000);
- idt[APIC_TIMER_VECTOR * 4] = (entry & 0xffff) | (INMATE_CS64 << 16);
- idt[APIC_TIMER_VECTOR * 4 + 1] = 0x8e00 | (entry & 0xffff0000);
- idt[APIC_TIMER_VECTOR * 4 + 2] = entry >> 32;
-
- dtr.limit = NUM_IDT_DESC * 16 - 1;
- dtr.base = (u64)&idt;
- write_idtr(&dtr);
-
write_msr(X2APIC_LVTT, APIC_TIMER_VECTOR);
expected_time = read_pm_timer();
write_msr(X2APIC_TMICT, 1);
.align(4096)
pd:
.quad 0x0000000000000083
-
-
- .global irq_entry
- .balign 16
-irq_entry:
- push %rax
- push %rcx
- push %rdx
- push %rsi
- push %rdi
- push %r8
- push %r9
- push %r10
- push %r11
-
- call irq_handler - FSEGMENT_BASE
-
- pop %r11
- pop %r10
- pop %r9
- pop %r8
- pop %rdi
- pop %rsi
- pop %rdx
- pop %rcx
- pop %rax
-
- iretq
-
-
-/* to please linker if irq_entry remains unused */
- .weak irq_handler
-irq_handler:
#define INMATE_CS64 0x10
#define INMATE_DS32 0x18
+#define X2APIC_ID 0x802
+
#ifndef __ASSEMBLY__
typedef signed char s8;
typedef unsigned char u8;
typedef signed int s32;
typedef unsigned int u32;
-typedef signed long s64;
-typedef unsigned long u64;
+typedef signed long long s64;
+typedef unsigned long long u64;
typedef s8 __s8;
typedef u8 __u8;
return v;
}
+static inline u64 read_msr(unsigned int msr)
+{
+ u32 low, high;
+
+ asm volatile("rdmsr" : "=a" (low), "=d" (high) : "c" (msr));
+ return low | ((u64)high << 32);
+}
+
+static inline void write_msr(unsigned int msr, u64 val)
+{
+ asm volatile("wrmsr"
+ : /* no output */
+ : "c" (msr), "a" (val), "d" (val >> 32)
+ : "memory");
+}
+
+static inline unsigned int cpu_id(void)
+{
+ return read_msr(X2APIC_ID);
+}
+
#include <jailhouse/hypercall.h>
#define comm_region ((struct jailhouse_comm_region *)COMM_REGION_BASE)
void *memset(void *s, int c, unsigned long n);
-extern u8 irq_entry[];
-void irq_handler(void);
+typedef void(*int_handler_t)(void);
+
+void int_init(void);
+void int_set_handler(unsigned int vector, int_handler_t handler);
void inmate_main(void);
--- /dev/null
+/*
+ * Jailhouse, a Linux-based partitioning hypervisor
+ *
+ * Copyright (c) Siemens AG, 2014
+ *
+ * Authors:
+ * Jan Kiszka <jan.kiszka@siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#include <inmate.h>
+
+#define NUM_IDT_DESC 64
+
+#define X2APIC_EOI 0x80b
+#define X2APIC_SPIV 0x80f
+
+#define APIC_EOI_ACK 0
+
+struct desc_table_reg {
+ u16 limit;
+ u64 base;
+} __attribute__((packed));
+
+static u32 idt[NUM_IDT_DESC * 4];
+static int_handler_t int_handler[NUM_IDT_DESC];
+
+extern u8 irq_entry[];
+
+static inline void write_idtr(struct desc_table_reg *val)
+{
+ asm volatile("lidt %0" : : "m" (*val));
+}
+
+void int_init(void)
+{
+ struct desc_table_reg dtr;
+
+ write_msr(X2APIC_SPIV, 0x1ff);
+
+ dtr.limit = NUM_IDT_DESC * 16 - 1;
+ dtr.base = (u64)&idt;
+ write_idtr(&dtr);
+}
+
+static void __attribute__((used)) handle_interrupt(unsigned int vector)
+{
+ int_handler[vector]();
+ write_msr(X2APIC_EOI, APIC_EOI_ACK);
+}
+
+void int_set_handler(unsigned int vector, int_handler_t handler)
+{
+ unsigned long entry = (unsigned long)irq_entry + vector * 16;
+
+ int_handler[vector] = handler;
+
+ idt[vector * 4] = (entry & 0xffff) | (INMATE_CS64 << 16);
+ idt[vector * 4 + 1] = 0x8e00 | (entry & 0xffff0000);
+ idt[vector * 4 + 2] = entry >> 32;
+}
+
+#ifdef __x86_64__
+asm(
+".macro irq_prologue vector\n\t"
+ "push %rdi\n\t"
+ "mov $vector,%rdi\n\t"
+ "jmp irq_common\n"
+".endm\n\t"
+
+ ".global irq_entry\n\t"
+ ".balign 16\n"
+"irq_entry:\n"
+"vector=0\n"
+".rept 64\n"
+ "irq_prologue vector\n\t"
+ "vector=vector+1\n\t"
+ ".balign 16\n\t"
+".endr\n"
+
+"irq_common:\n\t"
+ "push %rax\n\t"
+ "push %rcx\n\t"
+ "push %rdx\n\t"
+ "push %rsi\n\t"
+ "push %r8\n\t"
+ "push %r9\n\t"
+ "push %r10\n\t"
+ "push %r11\n\t"
+
+ "call handle_interrupt\n\t"
+
+ "pop %r11\n\t"
+ "pop %r10\n\t"
+ "pop %r9\n\t"
+ "pop %r8\n\t"
+ "pop %rsi\n\t"
+ "pop %rdx\n\t"
+ "pop %rcx\n\t"
+ "pop %rax\n\t"
+ "pop %rdi\n\t"
+
+ "iretq"
+);
+#else
+#error implement me!
+#endif