@@ -3,6 +3,7 @@
#include "io.h"
#include "processor.h"
#include "msr.h"
+#include "smp.h"
#define CHECK_HARD_RESET 0
@@ -36,18 +37,30 @@ static inline void rtc_out(u8 reg, u8 val)
outb(val, 0x71);
}
+static inline void send_init(void)
+{
+ char *reset_vec = (void*)0xfffffff0;
+
+ reset_vec[0] = 0xeb;
+ reset_vec[1] = 0xfe;
+ apic_icr_write(APIC_DEST_ALLINC | APIC_DEST_PHYSICAL
+ | APIC_DM_INIT, 0);
+}
+
extern char resume_start, resume_end;
struct expected_state {
bool init;
+ unsigned int bsp;
};
static struct expected_state expected[] = {
- {.init = false},
- {.init = false},
- {.init = false},
- {.init = false},
- {.init = true},
+ {.init = false, .bsp = 0},
+ {.init = false, .bsp = 0},
+ {.init = false, .bsp = 0},
+ {.init = false, .bsp = 0},
+ {.init = true, .bsp = 0},
+ {.init = true, .bsp = 1},
};
#define state (*(volatile int *)0x2000)
@@ -56,6 +69,7 @@ static struct expected_state expected[] = {
#define dr0 (*(volatile int*)0x200c)
#define cr2 (*(volatile int*)0x2010)
#define sysenter_eip (*(volatile int*)0x2014)
+#define boot_apic_id (*(volatile int *)0x2018)
static void set_test_regs(void)
{
@@ -84,6 +98,39 @@ static bool check_test_regs(bool init)
return error;
}
+static void change_bsp(bool bsp)
+{
+ unsigned long apicbase = rdmsr(MSR_IA32_APICBASE);
+
+ if (bsp)
+ apicbase |= MSR_IA32_APICBASE_BSP;
+ else
+ apicbase &= ~MSR_IA32_APICBASE_BSP;
+ wrmsr(MSR_IA32_APICBASE, apicbase);
+}
+
+static void set_bsp(void *data)
+{
+ set_test_regs();
+ change_bsp(true);
+}
+
+static bool change_bsp_test(void)
+{
+ int ncpus;
+
+ smp_init();
+ ncpus = cpu_count();
+ if (ncpus != 2) {
+ printf("Skipping BSP test\n");
+ return false;
+ }
+ on_cpu(1, set_bsp, NULL);
+ change_bsp(false);
+ return true;
+}
+
+
int main(int argc, char **argv)
{
volatile u16 *resume_vector_ptr = (u16 *)0x467L;
@@ -110,6 +157,12 @@ int main(int argc, char **argv)
if (check_test_regs(expected[state-1].init))
bad |= 4;
+ if (expected[state-1].bsp != boot_apic_id) {
+ printf("error: wrong BSP: %x expected: %x\n",
+ boot_apic_id, expected[state-1].bsp);
+ bad |= 8;
+ }
+
#if CHECK_HARD_RESET
/*
* Port 92 bit 0 is cleared on system reset. On a soft reset it
@@ -151,11 +204,17 @@ int main(int argc, char **argv)
case 4:
printf("testing init to BSP... ");
- apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL
- | APIC_DM_INIT, 0);
+ send_init();
break;
case 5:
+ printf("testing init to BSP (2nd core)... ");
+ if (change_bsp_test()) {
+ send_init();
+ break;
+ }
+ state++; /* fall through */
+ case 6:
exit(bad);
}
@@ -177,6 +236,10 @@ asm (
"mov $0x176, %ecx\n"
"rdmsr\n"
"mov %eax, %cs:0x2014\n" // sysenter_eip
+ "mov $1, %eax\n"
+ "cpuid\n"
+ "shrl $24, %ebx\n"
+ "mov %ebx, %cs:0x2018\n" // apic_id
"mov $0x0f, %al\n" // rtc_out(0x0f, 0x00);
"out %al, $0x70\n"
"mov $0x00, %al\n"
@@ -85,6 +85,7 @@ arch = x86_64
[init]
file = init.flat
+smp = 2
[msr]
file = msr.flat
Testing whether changing the BSP, followed by INIT works correctly. The APIC ID is saved after resume and compared. For this test to pass, a fix of QEMU is needed in addition to a KVM fix. Signed-off-by: Nadav Amit <namit@cs.technion.ac.il> --- x86/init.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++----- x86/unittests.cfg | 1 + 2 files changed, 71 insertions(+), 7 deletions(-)