always := lib.a lib32.a
-TARGETS := header.o hypercall.o ioapic.o printk.o
+TARGETS := header.o hypercall.o ioapic.o printk.o smp.o
TARGETS_64_ONLY := int.o mem.o pci.o timing.o
lib-y := $(TARGETS) $(TARGETS_64_ONLY)
or $MTRR_ENABLE,%eax
wrmsr
- mov $stack_top,%esp
-
mov $INMATE_DS32,%eax
mov %eax,%ds
mov %eax,%es
mov %eax,%ss
+ xor %ebx,%ebx
+ xchg ap_entry,%ebx
+ or %ebx,%ebx
+ jnz call_entry
+
+ mov $1,%edi
+ lock xadd %edi,cpu_number + FSEGMENT_BASE
+
+ cmp $SMP_MAX_CPUS,%edi
+ jae stop
+
+ mov $0x01,%eax
+ cpuid
+ shr $24,%ebx
+ mov %bl,smp_cpu_ids(%edi)
+
+ lock incl smp_num_cpus
+
+ cmp $0,%edi
+ jne stop
+
xor %eax,%eax
mov $bss_start,%edi
mov $bss_dwords,%ecx
rep stosl
- mov $inmate_main,%eax
- call *%eax
+ mov $inmate_main,%ebx
+
+call_entry:
+ mov $stack_top,%esp
+ call *%ebx
stop: cli
hlt
jmp stop
+ .pushsection ".data"
+
+ .globl ap_entry
+ap_entry:
+ .long 0
+
+ .globl smp_num_cpus
+smp_num_cpus:
+ .long 0
+
+ .globl smp_cpu_ids
+smp_cpu_ids:
+ .fill SMP_MAX_CPUS, 1, 0
+
+ .popsection
+
+cpu_number:
+ .long 0
+
.align(16)
.global loader_gdt
loader_gdt:
.code64
start64:
- mov $stack_top,%rsp
+ xor %rbx,%rbx
+ xchg ap_entry,%rbx
+ or %rbx,%rbx
+ jnz call_entry
+
+ mov $1,%edi
+ lock xadd %edi,cpu_number + FSEGMENT_BASE
+
+ cmp $SMP_MAX_CPUS,%edi
+ jae stop
+
+ mov $0x01,%eax
+ cpuid
+ shr $24,%ebx
+ mov %bl,smp_cpu_ids(%edi)
+
+ lock incl smp_num_cpus
+
+ cmp $0,%edi
+ jne stop
xor %rax,%rax
mov $bss_start,%rdi
mov $bss_qwords,%rcx
rep stosq
- mov $inmate_main,%rax
- callq *%rax
+ mov $inmate_main,%rbx
+
+call_entry:
+ mov $stack_top,%rsp
+ callq *%rbx
stop: cli
hlt
jmp stop
+ .pushsection ".data"
+
+ .globl ap_entry
+ap_entry:
+ .quad 0
+
+ .globl smp_num_cpus
+smp_num_cpus:
+ .long 0
+
+ .globl smp_cpu_ids
+smp_cpu_ids:
+ .fill SMP_MAX_CPUS, 1, 0
+
+ .popsection
+
+cpu_number:
+ .long 0
+
.align(16)
gdt:
.quad 0
#define HUGE_PAGE_MASK (~(HUGE_PAGE_SIZE - 1))
#define X2APIC_ID 0x802
+#define X2APIC_ICR 0x830
+
+#define APIC_LVL_ASSERT (1 << 14)
#define PCI_CFG_VENDOR_ID 0x000
#define PCI_CFG_DEVICE_ID 0x002
#define MSIX_CTRL_ENABLE 0x8000
#define MSIX_CTRL_FMASK 0x4000
+#define SMP_MAX_CPUS 255
+
#ifndef __ASSEMBLY__
typedef signed char s8;
typedef unsigned char u8;
void int_init(void);
void int_set_handler(unsigned int vector, int_handler_t handler);
+void int_send_ipi(unsigned int cpu_id, unsigned int vector);
enum ioapic_trigger_mode {
TRIGGER_EDGE = 0,
int pci_find_cap(u16 bdf, u16 cap);
void pci_msi_set_vector(u16 bdf, unsigned int vector);
void pci_msix_set_vector(u16 bdf, unsigned int vector, u32 index);
+
+extern volatile u32 smp_num_cpus;
+extern u8 smp_cpu_ids[SMP_MAX_CPUS];
+void smp_wait_for_all_cpus(void);
+void smp_start_cpu(unsigned int cpu_id, void (*entry)(void));
#endif
#else
#error implement me!
#endif
+
+void int_send_ipi(unsigned int cpu_id, unsigned int vector)
+{
+ write_msr(X2APIC_ICR, ((u64)cpu_id << 32) | APIC_LVL_ASSERT | vector);
+}
--- /dev/null
+/*
+ * Jailhouse, a Linux-based partitioning hypervisor
+ *
+ * Copyright (c) Siemens AG, 2015
+ *
+ * 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 APIC_DM_INIT (5 << 8)
+#define APIC_DM_SIPI (6 << 8)
+
+extern void (* volatile ap_entry)(void);
+
+void smp_wait_for_all_cpus(void)
+{
+ while (smp_num_cpus < comm_region->num_cpus)
+ cpu_relax();
+}
+
+void smp_start_cpu(unsigned int cpu_id, void (*entry)(void))
+{
+ u64 base_val = ((u64)cpu_id << 32) | APIC_LVL_ASSERT;
+
+ ap_entry = entry;
+
+ write_msr(X2APIC_ICR, base_val | APIC_DM_INIT);
+ delay_us(10000);
+ write_msr(X2APIC_ICR, base_val | APIC_DM_SIPI | 0xf0);
+ delay_us(200);
+ write_msr(X2APIC_ICR, base_val | APIC_DM_SIPI | 0xf0);
+
+ while (ap_entry != NULL)
+ cpu_relax();
+}