From patchwork Tue Mar 5 15:42:01 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 2220261 Return-Path: X-Original-To: patchwork-kvm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork2.kernel.org (Postfix) with ESMTP id ACA89DF24C for ; Tue, 5 Mar 2013 15:42:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756149Ab3CEPmI (ORCPT ); Tue, 5 Mar 2013 10:42:08 -0500 Received: from mx1.redhat.com ([209.132.183.28]:49417 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756015Ab3CEPmG (ORCPT ); Tue, 5 Mar 2013 10:42:06 -0500 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id r25Fg6KD018405 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Tue, 5 Mar 2013 10:42:06 -0500 Received: from yakj.usersys.redhat.com (ovpn-112-30.ams2.redhat.com [10.36.112.30]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id r25Fg4Ii007829 for ; Tue, 5 Mar 2013 10:42:05 -0500 From: Paolo Bonzini To: kvm@vger.kernel.org Subject: [PATCH kvm-unit-tests] x86: add INIT test Date: Tue, 5 Mar 2013 16:42:01 +0100 Message-Id: <1362498121-26136-1-git-send-email-pbonzini@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Test various ways of sending an INIT interrupt to the bootstrap processor. In all cases, the processor should start executing from 0xfffffff0 and other devices should be untouched. With the patches I just sent to qemu-devel (also at branch x86-soft-reset of git://github.com/bonzini/qemu.git), this passes with TCG and the userspace irqchip. It fails with in-kernel irqchip. Signed-off-by: Paolo Bonzini --- config-x86-common.mak | 5 +- x86/init.c | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 x86/init.c diff --git a/config-x86-common.mak b/config-x86-common.mak index 8f909f7..8af1ceb 100644 --- a/config-x86-common.mak +++ b/config-x86-common.mak @@ -35,7 +35,8 @@ tests-common = $(TEST_DIR)/vmexit.flat $(TEST_DIR)/tsc.flat \ $(TEST_DIR)/hypercall.flat $(TEST_DIR)/sieve.flat \ $(TEST_DIR)/kvmclock_test.flat $(TEST_DIR)/eventinj.flat \ $(TEST_DIR)/s3.flat $(TEST_DIR)/pmu.flat \ - $(TEST_DIR)/tsc_adjust.flat $(TEST_DIR)/asyncpf.flat + $(TEST_DIR)/tsc_adjust.flat $(TEST_DIR)/asyncpf.flat \ + $(TEST_DIR)/init.flat ifdef API tests-common += api/api-sample @@ -69,6 +70,8 @@ $(TEST_DIR)/tsc_adjust.elf: $(cstart.o) $(TEST_DIR)/tsc_adjust.o $(TEST_DIR)/apic.elf: $(cstart.o) $(TEST_DIR)/apic.o +$(TEST_DIR)/init.elf: $(cstart.o) $(TEST_DIR)/init.o + $(TEST_DIR)/realmode.elf: $(TEST_DIR)/realmode.o $(CC) -m32 -nostdlib -o $@ -Wl,-T,$(TEST_DIR)/realmode.lds $^ diff --git a/x86/init.c b/x86/init.c new file mode 100644 index 0000000..110780a --- /dev/null +++ b/x86/init.c @@ -0,0 +1,129 @@ +#include "libcflat.h" +#include "apic.h" +#include "io.h" + +#define KBD_CCMD_READ_OUTPORT 0xD0 /* read output port */ +#define KBD_CCMD_WRITE_OUTPORT 0xD1 /* write output port */ +#define KBD_CCMD_RESET 0xFE /* CPU reset */ + +static inline void kbd_cmd(u8 val) +{ + while (inb(0x64) & 2); + outb(val, 0x64); +} + +static inline u8 kbd_in(void) +{ + kbd_cmd(KBD_CCMD_READ_OUTPORT); + while (inb(0x64) & 2); + return inb(0x60); +} + +static inline void kbd_out(u8 val) +{ + kbd_cmd(KBD_CCMD_WRITE_OUTPORT); + while (inb(0x64) & 2); + outb(val, 0x60); +} + +static inline void rtc_out(u8 reg, u8 val) +{ + outb(reg, 0x70); + outb(val, 0x71); +} + +extern char resume_start, resume_end; + +#define state (*(volatile int *)0x2000) +#define bad (*(volatile int *)0x2004) +#define resumed (*(volatile int *)0x2008) + +int main(int argc, char **argv) +{ + volatile u16 *resume_vector_ptr = (u16 *)0x467L; + char *addr, *resume_vec = (void*)0x1000; + + /* resume execution by indirect jump via 40h:0067h */ + rtc_out(0x0f, 0x0a); + resume_vector_ptr[0] = ((u32)(ulong)resume_vec); + resume_vector_ptr[1] = 0; + + for (addr = &resume_start; addr < &resume_end; addr++) + *resume_vec++ = *addr; + + if (state != 0) { + /* + * Strictly speaking this is a firmware problem, but let's check + * for it as well... + */ + if (resumed != 1) { + printf("Uh, resume vector visited %d times?\n", resumed); + bad |= 2; + } + /* + * Port 92 bit 0 is cleared on system reset. On a soft reset it + * is left to 1. Use this to distinguish INIT from hard reset. + */ + if (resumed != 0 && (inb(0x92) & 1) == 0) { + printf("Uh, hard reset!\n"); + bad |= 1; + } + } + + resumed = 0; + + switch (state++) { + case 0: + printf("testing port 92 init... "); + outb(inb(0x92) & ~1, 0x92); + outb(inb(0x92) | 1, 0x92); + break; + + case 1: + printf("testing kbd controller reset... "); + kbd_cmd(KBD_CCMD_RESET); + break; + + case 2: + printf("testing kbd controller init... "); + kbd_out(kbd_in() & ~1); + break; + + case 3: + printf("testing 0xcf9h init... "); + outb(0, 0xcf9); + outb(4, 0xcf9); + break; + + case 4: + printf("testing init to BSP... "); + apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL + | APIC_DM_INIT, 0); + break; + + case 5: + exit(bad); + } + + /* The resume code will get us back to main. */ + asm("cli; hlt"); +} + +asm ( + ".global resume_start\n" + ".global resume_end\n" + ".code16\n" + "resume_start:\n" + "incb %cs:0x2008\n" // resumed++; + "mov $0x0f, %al\n" // rtc_out(0x0f, 0x00); + "out %al, $0x70\n" + "mov $0x00, %al\n" + "out %al, $0x71\n" + "jmp $0xffff, $0x0000\n" // BIOS reset + "resume_end:\n" +#ifdef __i386__ + ".code32\n" +#else + ".code64\n" +#endif + );