ljmpl $BOOT_CS32,$bootsym_rel(trampoline_protmode_entry,6)
.code32
+GLOBAL(txt_ap_entry)
+ /*
+ * APs enter here in protected mode without paging. GDT is set in JOIN
+ * structure, it points to trampoline_gdt. Interrupts are disabled by
+ * TXT (including NMI and SMI), so IDT doesn't matter at this point.
+ * The only missing point is telling that we are AP by saving non-zero
+ * value in EBX.
+ */
+ mov $1, %ebx
+
trampoline_protmode_entry:
/* Set up a few descriptors: on entry only CS is guaranteed good. */
mov $BOOT_DS,%eax
.word 0
idt_48: .word 0, 0, 0 # base = limit = 0
-trampoline_gdt:
+GLOBAL(trampoline_gdt)
.word 0 /* 0x0000: unused (reused for GDTR) */
gdt_48:
.word .Ltrampoline_gdt_end - trampoline_gdt - 1
.quad 0x00cf93000000ffff /* 0x0018: ring 0 data */
.quad 0x00009b000000ffff /* 0x0020: real-mode code @ BOOT_TRAMPOLINE */
.quad 0x000093000000ffff /* 0x0028: real-mode data @ BOOT_TRAMPOLINE */
+ /*
+ * Intel TXT requires these two in exact order. This isn't compatible
+ * with order required by syscall, so we have duplicated entries...
+ * If order ever changes, update selector numbers in asm/intel_txt.h.
+ */
+ .quad 0x00cf9b000000ffff /* 0x0030: ring 0 code, 32-bit mode */
+ .quad 0x00cf93000000ffff /* 0x0038: ring 0 data */
.Ltrampoline_gdt_end:
/* Relocations for trampoline Real Mode segments. */
#include <asm/div64.h>
#include <asm/flushtlb.h>
#include <asm/guest.h>
+#include <asm/intel_txt.h>
#include <asm/microcode.h>
#include <asm/msr.h>
#include <asm/mtrr.h>
*/
unsigned int cpu = booting_cpu;
+ if ( slaunch_active ) {
+ uint64_t misc_enable;
+ uint32_t my_apicid;
+ struct txt_sinit_mle_data *sinit_mle =
+ txt_sinit_mle_data_start(__va(read_txt_reg(TXTCR_HEAP_BASE)));
+
+ /* TXT released us with MONITOR disabled in IA32_MISC_ENABLE. */
+ rdmsrl(MSR_IA32_MISC_ENABLE, misc_enable);
+ wrmsrl(MSR_IA32_MISC_ENABLE,
+ misc_enable | MSR_IA32_MISC_ENABLE_MONITOR_ENABLE);
+
+ /* get_apic_id() reads from x2APIC if it thinks it is enabled. */
+ x2apic_ap_setup();
+ my_apicid = get_apic_id();
+
+ while ( my_apicid != x86_cpu_to_apicid[cpu] ) {
+ asm volatile ("monitor; xor %0,%0; mwait"
+ :: "a"(__va(sinit_mle->rlp_wakeup_addr)), "c"(0),
+ "d"(0) : "memory");
+ cpu = booting_cpu;
+ }
+ }
+
/* Critical region without IDT or TSS. Any fault is deadly! */
set_current(idle_vcpu[cpu]);
startup_cpu_idle_loop();
}
+static int slaunch_wake_aps(unsigned long trampoline_rm)
+{
+ struct txt_sinit_mle_data *sinit_mle =
+ txt_sinit_mle_data_start(__va(read_txt_reg(TXTCR_HEAP_BASE)));
+ uint32_t *wakeup_addr = __va(sinit_mle->rlp_wakeup_addr);
+#define trampoline_relative(x) (trampoline_rm + ((char *)(x) - trampoline_realmode_entry))
+ uint32_t join[4] = {
+ trampoline_gdt[1], /* GDT limit */
+ trampoline_relative(trampoline_gdt), /* GDT base */
+ TXT_AP_BOOT_CS, /* CS selector, DS = CS+8 */
+ trampoline_relative(txt_ap_entry) /* EIP */
+ };
+
+ write_txt_reg(TXTCR_MLE_JOIN, __pa(join));
+
+ smp_mb();
+
+ *wakeup_addr = 1;
+
+ return 0;
+}
+
static int wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
{
unsigned long send_status = 0, accept_status = 0;
if ( tboot_in_measured_env() && !tboot_wake_ap(phys_apicid, start_eip) )
return 0;
+ if ( slaunch_active )
+ return slaunch_wake_aps(start_eip);
+
/*
* Be paranoid about clearing APIC errors.
*/