From patchwork Sat Sep 7 00:54:36 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maxim Levitsky X-Patchwork-Id: 13794886 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 260DDA927 for ; Sat, 7 Sep 2024 00:54:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725670489; cv=none; b=ioT2EuW4C2VKpC60CgNEB9I2aTodjhTPtFB+04/F+wtn+hTEr/Orc8n6NFkzH3YVWdL33vYMkglMsoD1C1/l1sCtNbJZSHXuR9q+diIaAiphe2lKJDzFd2uLiAHZ588+dGaKfweQVGSna6DXlO+68BmxCL/2VHofOzVEpzLe0h8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725670489; c=relaxed/simple; bh=7VD03Qntmthy9Q7Vyr/9df/LJOaQhqhvOBK94YTE8to=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=FCA/cJJF9/9mBSCxXl0T02DqQ8rS8YaVZo4MNq3PYycNbEbSBstsIP3MiHvhyRX8oXzZyeilkVFrXJS6b7PUqVmcRmFGPHBIBDy3iB6qAptgIJF/Nk+IcbHBXuvzJxxmBK5Ms6x+pBhv8scqiJUqwz23e3n8vg5D1PVu7bKpfHY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=PvhmUoM8; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="PvhmUoM8" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1725670485; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=EEzbdXP/pX9sHfOe1VBFNARTLHFaigbuH1Y/01sWsrM=; b=PvhmUoM8J60zjo6zl8P0tZHZjIJmHFzlpNQByoNudkBL4fE6LYk7oxhmUY9dFadl+f8opB kc7rA5p0RJdy7locxFMp9/wAxXJHHFpk6GRvd8g/2Nuyu9vQXs5pMAC2IdwEBYnqGOvXWt lUrFL15Rj4CjRJK7QoLA5XpK5Nc/wB0= Received: from mx-prod-mc-02.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-55-vfWr-JEsMiaaVXSGvFnezQ-1; Fri, 06 Sep 2024 20:54:44 -0400 X-MC-Unique: vfWr-JEsMiaaVXSGvFnezQ-1 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 460FD19560B0 for ; Sat, 7 Sep 2024 00:54:43 +0000 (UTC) Received: from starship.lan (unknown [10.22.65.51]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 4565619560AF; Sat, 7 Sep 2024 00:54:42 +0000 (UTC) From: Maxim Levitsky To: kvm@vger.kernel.org Cc: Paolo Bonzini , Maxim Levitsky Subject: [kvm-unit-tests PATCH 1/5] x86: add _safe and _fep_safe variants to segment base load instructions Date: Fri, 6 Sep 2024 20:54:36 -0400 Message-Id: <20240907005440.500075-2-mlevitsk@redhat.com> In-Reply-To: <20240907005440.500075-1-mlevitsk@redhat.com> References: <20240907005440.500075-1-mlevitsk@redhat.com> Precedence: bulk X-Mailing-List: kvm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 _safe and _fep_safe functions will be used to validate various ways of setting the segment bases and GDT/LDT bases. Signed-off-by: Maxim Levitsky --- lib/x86/desc.h | 4 ++-- lib/x86/processor.h | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/lib/x86/desc.h b/lib/x86/desc.h index 92c45a48f..5349ea572 100644 --- a/lib/x86/desc.h +++ b/lib/x86/desc.h @@ -286,8 +286,8 @@ extern unsigned long get_gdt_entry_limit(gdt_entry_t *entry); #define asm_safe(insn, inputs...) \ __asm_safe("", insn, inputs) -#define asm_fep_safe(insn, output, inputs...) \ - __asm_safe_out1(KVM_FEP, insn, output, inputs) +#define asm_fep_safe(insn, inputs...) \ + __asm_safe_out1(KVM_FEP, insn,, inputs) #define __asm_safe_out1(fep, insn, output, inputs...) \ ({ \ diff --git a/lib/x86/processor.h b/lib/x86/processor.h index da1ed6628..9248a06b2 100644 --- a/lib/x86/processor.h +++ b/lib/x86/processor.h @@ -468,6 +468,11 @@ static inline int rdmsr_safe(u32 index, uint64_t *val) return rdreg64_safe("rdmsr", index, val); } +static inline int rdmsr_fep_safe(u32 index, uint64_t *val) +{ + return __rdreg64_safe(KVM_FEP, "rdmsr", index, val); +} + static inline int wrmsr_safe(u32 index, u64 val) { return wrreg64_safe("wrmsr", index, val); @@ -597,6 +602,16 @@ static inline void lgdt(const struct descriptor_table_ptr *ptr) asm volatile ("lgdt %0" : : "m"(*ptr)); } +static inline int lgdt_safe(const struct descriptor_table_ptr *ptr) +{ + return asm_safe("lgdt %0", "m"(*ptr)); +} + +static inline int lgdt_fep_safe(const struct descriptor_table_ptr *ptr) +{ + return asm_fep_safe("lgdt %0", "m"(*ptr)); +} + static inline void sgdt(struct descriptor_table_ptr *ptr) { asm volatile ("sgdt %0" : "=m"(*ptr)); @@ -607,6 +622,16 @@ static inline void lidt(const struct descriptor_table_ptr *ptr) asm volatile ("lidt %0" : : "m"(*ptr)); } +static inline int lidt_safe(const struct descriptor_table_ptr *ptr) +{ + return asm_safe("lidt %0", "m"(*ptr)); +} + +static inline int lidt_fep_safe(const struct descriptor_table_ptr *ptr) +{ + return asm_fep_safe("lidt %0", "m"(*ptr)); +} + static inline void sidt(struct descriptor_table_ptr *ptr) { asm volatile ("sidt %0" : "=m"(*ptr)); @@ -617,6 +642,16 @@ static inline void lldt(u16 val) asm volatile ("lldt %0" : : "rm"(val)); } +static inline int lldt_safe(u16 val) +{ + return asm_safe("lldt %0", "rm"(val)); +} + +static inline int lldt_fep_safe(u16 val) +{ + return asm_safe("lldt %0", "rm"(val)); +} + static inline u16 sldt(void) { u16 val; @@ -629,6 +664,16 @@ static inline void ltr(u16 val) asm volatile ("ltr %0" : : "rm"(val)); } +static inline int ltr_safe(u16 val) +{ + return asm_safe("ltr %0", "rm"(val)); +} + +static inline int ltr_fep_safe(u16 val) +{ + return asm_safe("ltr %0", "rm"(val)); +} + static inline u16 str(void) { u16 val; From patchwork Sat Sep 7 00:54:37 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maxim Levitsky X-Patchwork-Id: 13794885 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 944D5A92D for ; Sat, 7 Sep 2024 00:54:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725670489; cv=none; b=U85e2qxM/MTffIzOpXAzeyZ6ylY3i3+ocjwInNKrEWuig2Q71bRaQMCWljVOowtbZFScTMjaHCcQdUZIUtPH4ivw2/W2ROkpp9+0uHLCficgsibWUAfoBqx4JlKSUY09oO9RMlV8gomvCu2PaayLabh7xaKAzpzIwwwr7ihs3EQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725670489; c=relaxed/simple; bh=OsdQ1yj4JSnzx5SG0hg8J9bx/31o5WGXXyh6SF5GT04=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=DYMsUy3+g0wTl09HSjLF1KxnykbwrGrWqxZYPdeUtloUq6WO6qNW1WHB+umLnlIMDyU54FR0wSYtWT93oqcfxN2mtYPmnf/zruNLiKsmNMweG4aGF59Ga+7ndS5tfm7sBcl6/gwrN/fZ9dK35rHGUMn9HbnbPkIAGetB3lHqURM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=h8gnfmtD; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="h8gnfmtD" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1725670486; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=+P8w1LwrK/piZdxoBKsUBjaw9FgpEeIXszfCDXcGJMc=; b=h8gnfmtDu4lZDFOuAoloBO1fJ4s64cFPBme5YgxwOW+YW7G8N/fu5Ewp75wjSjP2Ezvgdy 1F5JOEfkpN8rdgoyV3Y6y931Ef2hf9XI/PHWv8AsflI9qMrLUW4Os8zl0O37L57edwDJf5 b8HoLmPdXxWOTUvyK3Q+XNbrREwiLQk= Received: from mx-prod-mc-02.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-74--C7svMowN8GHpe3hfh1Ixw-1; Fri, 06 Sep 2024 20:54:45 -0400 X-MC-Unique: -C7svMowN8GHpe3hfh1Ixw-1 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 4F9921956096 for ; Sat, 7 Sep 2024 00:54:44 +0000 (UTC) Received: from starship.lan (unknown [10.22.65.51]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 5267219560AA; Sat, 7 Sep 2024 00:54:43 +0000 (UTC) From: Maxim Levitsky To: kvm@vger.kernel.org Cc: Paolo Bonzini , Maxim Levitsky Subject: [kvm-unit-tests PATCH 2/5] x86: add a few functions for gdt manipulation Date: Fri, 6 Sep 2024 20:54:37 -0400 Message-Id: <20240907005440.500075-3-mlevitsk@redhat.com> In-Reply-To: <20240907005440.500075-1-mlevitsk@redhat.com> References: <20240907005440.500075-1-mlevitsk@redhat.com> Precedence: bulk X-Mailing-List: kvm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 Add a few functions that will be used to manipulate various segment bases that are loaded via GDT. Signed-off-by: Maxim Levitsky --- lib/x86/desc.c | 39 ++++++++++++++++++++++++++++++++------- lib/x86/desc.h | 5 +++++ 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/lib/x86/desc.c b/lib/x86/desc.c index d054899c6..52e33f201 100644 --- a/lib/x86/desc.c +++ b/lib/x86/desc.c @@ -338,7 +338,7 @@ bool exception_rflags_rf(void) static char intr_alt_stack[4096]; -void set_gdt_entry(int sel, unsigned long base, u32 limit, u8 type, u8 flags) +void set_gdt_entry_base(int sel, unsigned long base) { gdt_entry_t *entry = &gdt[sel >> 3]; @@ -347,10 +347,6 @@ void set_gdt_entry(int sel, unsigned long base, u32 limit, u8 type, u8 flags) entry->base2 = (base >> 16) & 0xFF; entry->base3 = (base >> 24) & 0xFF; - /* Setup the descriptor limits, type and flags */ - entry->limit1 = (limit & 0xFFFF); - entry->type_limit_flags = ((limit & 0xF0000) >> 8) | ((flags & 0xF0) << 8) | type; - #ifdef __x86_64__ if (!entry->s) { struct system_desc64 *entry16 = (struct system_desc64 *)entry; @@ -360,6 +356,25 @@ void set_gdt_entry(int sel, unsigned long base, u32 limit, u8 type, u8 flags) #endif } +void set_gdt_entry(int sel, unsigned long base, u32 limit, u8 type, u8 flags) +{ + gdt_entry_t *entry = &gdt[sel >> 3]; + + /* Setup the descriptor limits, type and flags */ + entry->limit1 = (limit & 0xFFFF); + entry->type_limit_flags = ((limit & 0xF0000) >> 8) | ((flags & 0xF0) << 8) | type; + set_gdt_entry_base(sel, base); +} + +void clear_tss_busy(int sel) +{ + gdt_entry_t *entry = &gdt[sel >> 3]; + + entry->type_limit_flags &= ~0xFF; + entry->type_limit_flags |= 0x89; +} + + void load_gdt_tss(size_t tss_offset) { lgdt(&gdt_descr); @@ -483,14 +498,24 @@ void __set_exception_jmpbuf(jmp_buf *addr) exception_jmpbuf = addr; } -gdt_entry_t *get_tss_descr(void) +gdt_entry_t *get_gdt_entry(u16 sel) { struct descriptor_table_ptr gdt_ptr; gdt_entry_t *gdt; sgdt(&gdt_ptr); gdt = (gdt_entry_t *)gdt_ptr.base; - return &gdt[str() / 8]; + return &gdt[sel / 8]; +} + +gdt_entry_t *get_tss_descr(void) +{ + return get_gdt_entry(str()); +} + +gdt_entry_t *get_ldt_descr(void) +{ + return get_gdt_entry(sldt()); } unsigned long get_gdt_entry_base(gdt_entry_t *entry) diff --git a/lib/x86/desc.h b/lib/x86/desc.h index 5349ea572..a50c8f61b 100644 --- a/lib/x86/desc.h +++ b/lib/x86/desc.h @@ -246,6 +246,8 @@ void set_idt_entry(int vec, void *addr, int dpl); void set_idt_sel(int vec, u16 sel); void set_idt_dpl(int vec, u16 dpl); void set_gdt_entry(int sel, unsigned long base, u32 limit, u8 access, u8 gran); +void set_gdt_entry_base(int sel, unsigned long base); +void clear_tss_busy(int sel); void load_gdt_tss(size_t tss_offset); void set_intr_alt_stack(int e, void *fn); void print_current_tss_info(void); @@ -268,7 +270,10 @@ static inline void *get_idt_addr(idt_entry_t *entry) return (void *)addr; } +extern gdt_entry_t *get_gdt_entry(u16 sel); extern gdt_entry_t *get_tss_descr(void); +gdt_entry_t *get_ldt_descr(void); + extern unsigned long get_gdt_entry_base(gdt_entry_t *entry); extern unsigned long get_gdt_entry_limit(gdt_entry_t *entry); From patchwork Sat Sep 7 00:54:38 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maxim Levitsky X-Patchwork-Id: 13794887 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B2480A955 for ; Sat, 7 Sep 2024 00:54:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725670491; cv=none; b=q7c6Av+9FEC7o2Tt1829h6s9Iuu3T70pg31w16H47b9GdbHkZtZl2mVPhOqLYfH79JUdi2NAFWJkPuP8qfxiLLMUek38xt0+VpDaWjbrN/C4VCoLSrG1b0o3KY/no3RpAbckQuyJ7DLFyZ407HdhBjhGh2MPRxJc/GYTkpPRZXM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725670491; c=relaxed/simple; bh=nBzQQeqPoijkXHBzuHJkYQhj0AQCnRnBaJJLJt/TSMI=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=X/foW5zAB9WhuNJXFrFzXLSy4e0ItfN08n0zEjP/olvL8+qNiwSeeP8hPLi/hMX9c/pCsliVw3VS9W5FoyFNuv6zif80baiaydi61GLw3naGi8UI+vxF4MPwjgdBz18kRLYxJjSXzx+XvpRFBFx06QNDkW41bJBHrL0RjWtzURs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=HaHrKCRi; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="HaHrKCRi" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1725670488; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=xjQA3iE37qNV/MLoVQx3n4C5CMw2Ex62y0UtX6RoYjY=; b=HaHrKCRiLrNYK8s6hPglNaeLfTxHQza8nMKCvkPSrrZI9BEXEV/kcEWWgJjyeb6ttWtmSA tfrLBLbSNnjScHnmvAQy13OLYDes7U7Uo1KUU+hdkOY4j2tyf3hPuiJYd7AI1NOavLrwK8 /WhpQap9iFsM84C46lMyWwwrX18rIPU= Received: from mx-prod-mc-04.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-208-gHI43MC4Orenhh3d3T6IPw-1; Fri, 06 Sep 2024 20:54:46 -0400 X-MC-Unique: gHI43MC4Orenhh3d3T6IPw-1 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-04.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 7F4B919560AB for ; Sat, 7 Sep 2024 00:54:45 +0000 (UTC) Received: from starship.lan (unknown [10.22.65.51]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 58FCF19560AA; Sat, 7 Sep 2024 00:54:44 +0000 (UTC) From: Maxim Levitsky To: kvm@vger.kernel.org Cc: Paolo Bonzini , Maxim Levitsky Subject: [kvm-unit-tests PATCH 3/5] x86: move struct invpcid_desc descriptor to processor.h Date: Fri, 6 Sep 2024 20:54:38 -0400 Message-Id: <20240907005440.500075-4-mlevitsk@redhat.com> In-Reply-To: <20240907005440.500075-1-mlevitsk@redhat.com> References: <20240907005440.500075-1-mlevitsk@redhat.com> Precedence: bulk X-Mailing-List: kvm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 Move struct invpcid_desc descriptor to processor.h so that it can be used in tests that are external to pcid.c Signed-off-by: Maxim Levitsky --- lib/x86/processor.h | 7 ++++++- x86/pcid.c | 6 ------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/x86/processor.h b/lib/x86/processor.h index 9248a06b2..bb54ec610 100644 --- a/lib/x86/processor.h +++ b/lib/x86/processor.h @@ -836,8 +836,13 @@ static inline void invlpg(volatile void *va) asm volatile("invlpg (%0)" ::"r" (va) : "memory"); } +struct invpcid_desc { + u64 pcid : 12; + u64 rsv : 52; + u64 addr : 64; +}; -static inline int invpcid_safe(unsigned long type, void *desc) +static inline int invpcid_safe(unsigned long type, struct invpcid_desc *desc) { /* invpcid (%rax), %rbx */ return asm_safe(".byte 0x66,0x0f,0x38,0x82,0x18", "a" (desc), "b" (type)); diff --git a/x86/pcid.c b/x86/pcid.c index c503efb83..7425e0fe8 100644 --- a/x86/pcid.c +++ b/x86/pcid.c @@ -4,12 +4,6 @@ #include "processor.h" #include "desc.h" -struct invpcid_desc { - u64 pcid : 12; - u64 rsv : 52; - u64 addr : 64; -}; - static void test_pcid_enabled(void) { int passed = 0; From patchwork Sat Sep 7 00:54:39 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maxim Levitsky X-Patchwork-Id: 13794888 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B24B1A95E for ; Sat, 7 Sep 2024 00:54:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725670491; cv=none; b=EvgkDshE9GSsYGjOGRHmsVT40NRX+WkL+x54unRy+Hi6Iy1gL3lEKzZIHujYdTSPnD0J5R+IxyDekvaZL5HZf3QAwsM2bsqKB26MaJj8seQbxyNEisT8/2SvAwcSn+ueR6OOTbzjCf8YT86dVvIcWCdzCCkEnp4ySXfPXVmZF4k= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725670491; c=relaxed/simple; bh=keUjaZS1E4JmSd2wqzoiYjUV+Cluk2k4s/L75vUHkwI=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=L6ZXcP0u9F1+AxKi1iZIwnqAq0U0f0itpkpogW1msoMimFdemsTjJGXKTUGEaeykkW4RB3CIDroG5+vHMBQV04HmobgX5g72sLX1e97rxwLQRGgvIgkhd3OIo+gNdoGFY7OZXxWVqhMG/h1YwMBwsbh295do8hi6tj13FcAj7yg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=Yi50GdrZ; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="Yi50GdrZ" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1725670488; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=H1i+WYeL0K3IZGrZjYeKsMzO6yl/hkrAy/65CwXy8es=; b=Yi50GdrZuur/XB2qAYUQBa9IrOzSuB65V/1I0DqwPovbfQIAWfiYm8ugd9q2uRtMJF1u50 hr36sROr3eATlkpoS2BoHdG2IC3nGVRms+E4+N4cBPoLpkenuRAW0FiobfdkBoyOidJdHp vm3lxTdoPnbpm2WaQOJfgVEf3WF5brM= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-76-PKP83PpdMUezs6zYya0s0Q-1; Fri, 06 Sep 2024 20:54:47 -0400 X-MC-Unique: PKP83PpdMUezs6zYya0s0Q-1 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 763FD195608B for ; Sat, 7 Sep 2024 00:54:46 +0000 (UTC) Received: from starship.lan (unknown [10.22.65.51]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 7425719560AF; Sat, 7 Sep 2024 00:54:45 +0000 (UTC) From: Maxim Levitsky To: kvm@vger.kernel.org Cc: Paolo Bonzini , Maxim Levitsky Subject: [kvm-unit-tests PATCH 4/5] Add a test for writing canonical values to various msrs and fields Date: Fri, 6 Sep 2024 20:54:39 -0400 Message-Id: <20240907005440.500075-5-mlevitsk@redhat.com> In-Reply-To: <20240907005440.500075-1-mlevitsk@redhat.com> References: <20240907005440.500075-1-mlevitsk@redhat.com> Precedence: bulk X-Mailing-List: kvm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 Add a test that thoroughly tests the canonical checks that are done when setting various msrs and cpu registers, especially on CPUs that support 5 level paging. Signed-off-by: Maxim Levitsky --- lib/x86/msr.h | 42 ++++++ lib/x86/processor.h | 6 +- x86/Makefile.x86_64 | 1 + x86/canonical_57.c | 346 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 394 insertions(+), 1 deletion(-) create mode 100644 x86/canonical_57.c diff --git a/lib/x86/msr.h b/lib/x86/msr.h index 8abccf867..658d237fd 100644 --- a/lib/x86/msr.h +++ b/lib/x86/msr.h @@ -131,6 +131,48 @@ #define MSR_P6_EVNTSEL0 0x00000186 #define MSR_P6_EVNTSEL1 0x00000187 +#define MSR_IA32_RTIT_CTL 0x00000570 +#define RTIT_CTL_TRACEEN BIT(0) +#define RTIT_CTL_CYCLEACC BIT(1) +#define RTIT_CTL_OS BIT(2) +#define RTIT_CTL_USR BIT(3) +#define RTIT_CTL_PWR_EVT_EN BIT(4) +#define RTIT_CTL_FUP_ON_PTW BIT(5) +#define RTIT_CTL_FABRIC_EN BIT(6) +#define RTIT_CTL_CR3EN BIT(7) +#define RTIT_CTL_TOPA BIT(8) +#define RTIT_CTL_MTC_EN BIT(9) +#define RTIT_CTL_TSC_EN BIT(10) +#define RTIT_CTL_DISRETC BIT(11) +#define RTIT_CTL_PTW_EN BIT(12) +#define RTIT_CTL_BRANCH_EN BIT(13) +#define RTIT_CTL_EVENT_EN BIT(31) +#define RTIT_CTL_NOTNT BIT_ULL(55) +#define RTIT_CTL_MTC_RANGE_OFFSET 14 +#define RTIT_CTL_MTC_RANGE (0x0full << RTIT_CTL_MTC_RANGE_OFFSET) +#define RTIT_CTL_CYC_THRESH_OFFSET 19 +#define RTIT_CTL_CYC_THRESH (0x0full << RTIT_CTL_CYC_THRESH_OFFSET) +#define RTIT_CTL_PSB_FREQ_OFFSET 24 +#define RTIT_CTL_PSB_FREQ (0x0full << RTIT_CTL_PSB_FREQ_OFFSET) +#define RTIT_CTL_ADDR0_OFFSET 32 +#define RTIT_CTL_ADDR0 (0x0full << RTIT_CTL_ADDR0_OFFSET) +#define RTIT_CTL_ADDR1_OFFSET 36 +#define RTIT_CTL_ADDR1 (0x0full << RTIT_CTL_ADDR1_OFFSET) +#define RTIT_CTL_ADDR2_OFFSET 40 +#define RTIT_CTL_ADDR2 (0x0full << RTIT_CTL_ADDR2_OFFSET) +#define RTIT_CTL_ADDR3_OFFSET 44 +#define RTIT_CTL_ADDR3 (0x0full << RTIT_CTL_ADDR3_OFFSET) + + +#define MSR_IA32_RTIT_ADDR0_A 0x00000580 +#define MSR_IA32_RTIT_ADDR0_B 0x00000581 +#define MSR_IA32_RTIT_ADDR1_A 0x00000582 +#define MSR_IA32_RTIT_ADDR1_B 0x00000583 +#define MSR_IA32_RTIT_ADDR2_A 0x00000584 +#define MSR_IA32_RTIT_ADDR2_B 0x00000585 +#define MSR_IA32_RTIT_ADDR3_A 0x00000586 +#define MSR_IA32_RTIT_ADDR3_B 0x00000587 + /* AMD64 MSRs. Not complete. See the architecture manual for a more complete list. */ diff --git a/lib/x86/processor.h b/lib/x86/processor.h index bb54ec610..f05175af5 100644 --- a/lib/x86/processor.h +++ b/lib/x86/processor.h @@ -7,7 +7,9 @@ #include #include -#define NONCANONICAL 0xaaaaaaaaaaaaaaaaull +#define CANONICAL_48_VAL 0xffffaaaaaaaaaaaaull +#define CANONICAL_57_VAL 0xffaaaaaaaaaaaaaaull +#define NONCANONICAL 0xaaaaaaaaaaaaaaaaull #ifdef __x86_64__ # define R "r" @@ -241,6 +243,7 @@ static inline bool is_intel(void) #define X86_FEATURE_MCE (CPUID(0x1, 0, EDX, 7)) #define X86_FEATURE_APIC (CPUID(0x1, 0, EDX, 9)) #define X86_FEATURE_CLFLUSH (CPUID(0x1, 0, EDX, 19)) +#define X86_FEATURE_DS (CPUID(0x1, 0, EDX, 21)) #define X86_FEATURE_XMM (CPUID(0x1, 0, EDX, 25)) #define X86_FEATURE_XMM2 (CPUID(0x1, 0, EDX, 26)) #define X86_FEATURE_TSC_ADJUST (CPUID(0x7, 0, EBX, 1)) @@ -252,6 +255,7 @@ static inline bool is_intel(void) #define X86_FEATURE_PCOMMIT (CPUID(0x7, 0, EBX, 22)) #define X86_FEATURE_CLFLUSHOPT (CPUID(0x7, 0, EBX, 23)) #define X86_FEATURE_CLWB (CPUID(0x7, 0, EBX, 24)) +#define X86_FEATURE_INTEL_PT (CPUID(0x7, 0, EBX, 25)) #define X86_FEATURE_UMIP (CPUID(0x7, 0, ECX, 2)) #define X86_FEATURE_PKU (CPUID(0x7, 0, ECX, 3)) #define X86_FEATURE_LA57 (CPUID(0x7, 0, ECX, 16)) diff --git a/x86/Makefile.x86_64 b/x86/Makefile.x86_64 index 2771a6fad..0a7eb2c34 100644 --- a/x86/Makefile.x86_64 +++ b/x86/Makefile.x86_64 @@ -38,6 +38,7 @@ tests += $(TEST_DIR)/rdpru.$(exe) tests += $(TEST_DIR)/pks.$(exe) tests += $(TEST_DIR)/pmu_lbr.$(exe) tests += $(TEST_DIR)/pmu_pebs.$(exe) +tests += $(TEST_DIR)/canonical_57.$(exe) ifeq ($(CONFIG_EFI),y) tests += $(TEST_DIR)/amd_sev.$(exe) diff --git a/x86/canonical_57.c b/x86/canonical_57.c new file mode 100644 index 000000000..a2f2438b5 --- /dev/null +++ b/x86/canonical_57.c @@ -0,0 +1,346 @@ +#include "libcflat.h" +#include "apic.h" +#include "processor.h" +#include "msr.h" +#include "x86/vm.h" +#include "asm/setup.h" + +enum TEST_REGISTER { + TEST_REGISTER_GDTR_BASE, + TEST_REGISTER_IDTR_BASE, + TEST_REGISTER_TR_BASE, + TEST_REGISTER_LDT_BASE, + TEST_REGISTER_MSR /* upper 32 bits = msr address */ +}; + +static u64 get_test_register_value(u64 test_register) +{ + struct descriptor_table_ptr dt_ptr; + u32 msr = test_register >> 32; + + /* + * Note: value for LDT and TSS base might not reflect the actual base + * that the CPU currently uses, because the (hidden) base value can't be + * directly read. + */ + + switch ((u32)test_register) { + case TEST_REGISTER_GDTR_BASE: + sgdt(&dt_ptr); + return dt_ptr.base; + case TEST_REGISTER_IDTR_BASE: + sidt(&dt_ptr); + return dt_ptr.base; + case TEST_REGISTER_TR_BASE: + return get_gdt_entry_base(get_tss_descr()); + case TEST_REGISTER_LDT_BASE: + return get_gdt_entry_base(get_ldt_descr()); + case TEST_REGISTER_MSR: + return rdmsr(msr); + default: + assert(0); + return 0; + } +} + +enum SET_REGISTER_MODE { + SET_REGISTER_MODE_UNSAFE, + SET_REGISTER_MODE_SAFE, + SET_REGISTER_MODE_FEP, +}; + +static bool set_test_register_value(u64 test_register, int test_mode, u64 value) +{ + struct descriptor_table_ptr dt_ptr; + u32 msr = test_register >> 32; + u16 sel; + + switch ((u32)test_register) { + case TEST_REGISTER_GDTR_BASE: + sgdt(&dt_ptr); + dt_ptr.base = value; + + switch (test_mode) { + case SET_REGISTER_MODE_UNSAFE: + lgdt(&dt_ptr); + return true; + case SET_REGISTER_MODE_SAFE: + return lgdt_safe(&dt_ptr) == 0; + case SET_REGISTER_MODE_FEP: + return lgdt_fep_safe(&dt_ptr) == 0; + } + case TEST_REGISTER_IDTR_BASE: + sidt(&dt_ptr); + dt_ptr.base = value; + + switch (test_mode) { + case SET_REGISTER_MODE_UNSAFE: + lidt(&dt_ptr); + return true; + case SET_REGISTER_MODE_SAFE: + return lidt_safe(&dt_ptr) == 0; + case SET_REGISTER_MODE_FEP: + return lidt_fep_safe(&dt_ptr) == 0; + } + case TEST_REGISTER_TR_BASE: + sel = str(); + set_gdt_entry_base(sel, value); + clear_tss_busy(sel); + + switch (test_mode) { + case SET_REGISTER_MODE_UNSAFE: + ltr(sel); + return true; + case SET_REGISTER_MODE_SAFE: + return ltr_safe(sel) == 0; + case SET_REGISTER_MODE_FEP: + return ltr_fep_safe(sel) == 0; + } + + case TEST_REGISTER_LDT_BASE: + sel = sldt(); + set_gdt_entry_base(sel, value); + + switch (test_mode) { + case SET_REGISTER_MODE_UNSAFE: + lldt(sel); + return true; + case SET_REGISTER_MODE_SAFE: + return lldt_safe(sel) == 0; + case SET_REGISTER_MODE_FEP: + return lldt_fep_safe(sel) == 0; + } + case TEST_REGISTER_MSR: + switch (test_mode) { + case SET_REGISTER_MODE_UNSAFE: + wrmsr(msr, value); + return true; + case SET_REGISTER_MODE_SAFE: + return wrmsr_safe(msr, value) == 0; + case SET_REGISTER_MODE_FEP: + return wrmsr_fep_safe(msr, value) == 0; + } + default: + assert(false); + return 0; + } +} + +static void test_register_write(const char *register_name, u64 test_register, + bool force_emulation, u64 test_value, + bool expect_success) +{ + u64 old_value, expected_value; + bool success, test_passed = false; + int test_mode = (force_emulation ? SET_REGISTER_MODE_FEP : SET_REGISTER_MODE_SAFE); + + old_value = get_test_register_value(test_register); + expected_value = expect_success ? test_value : old_value; + + /* + * TODO: Successful write to the MSR_GS_BASE corrupts it, + * and that breaks the wrmsr_safe macro. + */ + if ((test_register >> 32) == MSR_GS_BASE && expect_success) + test_mode = SET_REGISTER_MODE_UNSAFE; + + /* Write the test value*/ + success = set_test_register_value(test_register, test_mode, test_value); + + if (success != expect_success) { + report(false, + "Write of test register %s with value %lx unexpectedly %s", + register_name, test_value, + (success ? "succeeded" : "failed")); + goto exit; + } + + /* + * Check that the value was really written. + * Don't test TR and LDTR, because it's not possible to read them + * directly. + */ + + if (test_register != TEST_REGISTER_TR_BASE && + test_register != TEST_REGISTER_LDT_BASE) { + u64 new_value = get_test_register_value(test_register); + + if (new_value != expected_value) { + report(false, + "Register %s wasn't set to %lx as expected (actual value %lx)", + register_name, expected_value, new_value); + goto exit; + } + } + + /* + * Restore the old value directly without safety wrapper, + * to avoid test crashes related to temporary clobbered GDT/IDT/etc bases. + */ + + set_test_register_value(test_register, SET_REGISTER_MODE_UNSAFE, old_value); + test_passed = true; +exit: + report(test_passed, "Tested setting %s to 0x%lx value - %s", register_name, + test_value, success ? "success" : "failure"); +} + +static void test_register(const char *register_name, u64 test_register, + bool force_emulation) +{ + /* Canonical 48 bit value should always succeed */ + test_register_write(register_name, test_register, force_emulation, + CANONICAL_48_VAL, true); + + /* 57-canonical value will work on CPUs that *support* LA57 */ + test_register_write(register_name, test_register, force_emulation, + CANONICAL_57_VAL, this_cpu_has(X86_FEATURE_LA57)); + + /* Non 57 canonical value should never work */ + test_register_write(register_name, test_register, force_emulation, + NONCANONICAL, false); +} + + +#define TEST_REGISTER(register_name, force_emulation) \ + test_register(#register_name, register_name, force_emulation) + +#define __TEST_MSR(msr_name, address, force_emulation) \ + test_register(msr_name, ((u64)TEST_REGISTER_MSR | \ + ((u64)(address) << 32)), force_emulation) + +#define TEST_MSR(msr_name, force_emulation) \ + __TEST_MSR(#msr_name, msr_name, force_emulation) + +static void __test_invpcid(u64 test_value, bool expect_success) +{ + struct invpcid_desc desc; + + memset(&desc, 0, sizeof(desc)); + bool success; + + desc.addr = test_value; + desc.pcid = 10; /* Arbitrary number*/ + + success = invpcid_safe(0, &desc) == 0; + + report(success == expect_success, + "Tested invpcid type 0 with 0x%lx value - %s", + test_value, success ? "success" : "failure"); +} + +static void test_invpcid(void) +{ + /* + * Note that this test tests the kvm's behavior only when ept=0. + * Otherwise invpcid is not intercepted. + * + * Also KVM's x86 emulator doesn't support invpcid, thus testing invpcid + * with FEP is pointless. + */ + + assert(write_cr4_safe(read_cr4() | X86_CR4_PCIDE) == 0); + + __test_invpcid(CANONICAL_48_VAL, true); + __test_invpcid(CANONICAL_57_VAL, this_cpu_has(X86_FEATURE_LA57)); + __test_invpcid(NONCANONICAL, false); +} + +static void __do_test(bool force_emulation) +{ + /* Direct DT addresses */ + TEST_REGISTER(TEST_REGISTER_GDTR_BASE, force_emulation); + TEST_REGISTER(TEST_REGISTER_IDTR_BASE, force_emulation); + + /* Indirect DT addresses */ + TEST_REGISTER(TEST_REGISTER_TR_BASE, force_emulation); + TEST_REGISTER(TEST_REGISTER_LDT_BASE, force_emulation); + + /* x86_64 extended segment bases */ + TEST_MSR(MSR_FS_BASE, force_emulation); + TEST_MSR(MSR_GS_BASE, force_emulation); + TEST_MSR(MSR_KERNEL_GS_BASE, force_emulation); + + /* + * SYSENTER ESP/EIP MSRs have canonical checks only on Intel, + * because only on Intel these instructions were extended to 64 bit. + * + * TODO: KVM emulation however ignores canonical checks for these MSRs + * even on Intel, to support cross-vendor migration. + * + * Thus only run the check on bare metal. + * + */ + if (is_intel() && !force_emulation) { + TEST_MSR(MSR_IA32_SYSENTER_ESP, force_emulation); + TEST_MSR(MSR_IA32_SYSENTER_EIP, force_emulation); + } else + report_skip("skipping MSR_IA32_SYSENTER_ESP/MSR_IA32_SYSENTER_EIP %s", + (is_intel() ? "due to known errata in KVM": "due to AMD host")); + + /* SYSCALL target MSRs */ + TEST_MSR(MSR_CSTAR, force_emulation); + TEST_MSR(MSR_LSTAR, force_emulation); + + /* PEBS DS area */ + if (this_cpu_has(X86_FEATURE_DS)) + TEST_MSR(MSR_IA32_DS_AREA, force_emulation); + else + report_skip("Skipping MSR_IA32_DS_AREA - PEBS not supported"); + + /* PT filter ranges */ + if (this_cpu_has(X86_FEATURE_INTEL_PT)) { + int n_ranges = cpuid_indexed(0x14, 0x1).a & 0x7; + int i; + + for (i = 0 ; i < n_ranges ; i++) { + wrmsr(MSR_IA32_RTIT_CTL, (1ull << (RTIT_CTL_ADDR0_OFFSET+i*4))); + __TEST_MSR("MSR_IA32_RTIT_ADDR_A", + MSR_IA32_RTIT_ADDR0_A + i*2, force_emulation); + __TEST_MSR("MSR_IA32_RTIT_ADDR_B", + MSR_IA32_RTIT_ADDR0_B + i*2, force_emulation); + } + } else + report_skip("Skipping MSR_IA32_RTIT_ADDR* - Intel PT is not supported"); + + /* Test that INVPCID type 0 #GPs correctly */ + if (this_cpu_has(X86_FEATURE_INVPCID)) + test_invpcid(); + else + report_skip("Skipping INVPCID - not supported"); +} + +static void do_test(void) +{ + printf("\n"); + printf("Running the test without emulation:\n"); + __do_test(false); + + printf("\n"); + + if (is_fep_available()) { + printf("Running the test with forced emulation:\n"); + __do_test(true); + } else + report_skip("force emulation prefix not enabled - skipping"); +} + +int main(int ac, char **av) +{ + /* set dummy LDTR pointer */ + set_gdt_entry(FIRST_SPARE_SEL, 0xffaabb, 0xffff, 0x82, 0); + lldt(FIRST_SPARE_SEL); + + do_test(); + + printf("\n"); + + if (this_cpu_has(X86_FEATURE_LA57)) { + printf("Switching to 5 level paging mode and rerunning the test...\n"); + setup_5level_page_table(); + do_test(); + } else + report_skip("Skipping the test in 5-level paging mode - not supported on the host"); + + return report_summary(); +} From patchwork Sat Sep 7 00:54:40 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maxim Levitsky X-Patchwork-Id: 13794889 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AE70ADF53 for ; Sat, 7 Sep 2024 00:54:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725670492; cv=none; b=d3uwgvDbAom3PnfBagUBKTu5kn+UIMifSj51LmXBaQNH2udYlfkb/e0e3MukkELKc1e1JFcR0YMqXL1gcYdbMAiMVLobGB13on0um2IVziS5qLe3XoXwOC5r/cqkxmynhswvUnAIxOsnpvbq87EPkCEEDMsc0qa1dW9SLVjKOo0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725670492; c=relaxed/simple; bh=F4ePPmI3gDH5O+DwY0vdY9lSgrLAMbdGPLLfp7ZeH4s=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=mtETk0ju6A9fXfq4DNeUeQPdJRgsGbgWdnjDN9DqMlzRlTFE7S9rY8FdvvQ6kSUQSx+51+h9s6VX4MipVnM/ZgZKfjPKZTnqWPiER3bcqTHadFhR4HVlrURs1u8tNA3I6C8XIJSNghimmyUzlaj5FylZV8lqB2+VbSVLqmSG4Vs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=GleRFjFi; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="GleRFjFi" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1725670489; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Y4kLuQDMZmBfnp63eJmV4ivAZwFMoB3pkf7oqhzqTE8=; b=GleRFjFieJUPDiqXk+AA9uRMTw0xZ++WCSZ9mODzqVu1rkacQsvCCtmco8Zhxg7icOP8XF je8/2vjvjHFHNFGuDUb/uAKrA9U483+a5n5Osr59olyBWtHSRwles5oq9Dm5nt8/lD7L0P 3N3DzdvExCkrg+p68GkMKjh7PxYNN1k= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-231--q0IpI-hPI6-Xs_KICb8bA-1; Fri, 06 Sep 2024 20:54:48 -0400 X-MC-Unique: -q0IpI-hPI6-Xs_KICb8bA-1 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 5ED8D195608C for ; Sat, 7 Sep 2024 00:54:47 +0000 (UTC) Received: from starship.lan (unknown [10.22.65.51]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 7BE1F19560AA; Sat, 7 Sep 2024 00:54:46 +0000 (UTC) From: Maxim Levitsky To: kvm@vger.kernel.org Cc: Paolo Bonzini , Maxim Levitsky Subject: [kvm-unit-tests PATCH 5/5] nVMX: add a test for canonical checks of various host state vmcs12 fields. Date: Fri, 6 Sep 2024 20:54:40 -0400 Message-Id: <20240907005440.500075-6-mlevitsk@redhat.com> In-Reply-To: <20240907005440.500075-1-mlevitsk@redhat.com> References: <20240907005440.500075-1-mlevitsk@redhat.com> Precedence: bulk X-Mailing-List: kvm@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 This test tests canonical VM entry checks of various host state fields (mostly segment bases) in vmcs12. Signed-off-by: Maxim Levitsky --- x86/vmx_tests.c | 183 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c index ffe7064c9..b6f3d634d 100644 --- a/x86/vmx_tests.c +++ b/x86/vmx_tests.c @@ -10732,6 +10732,7 @@ static void handle_exception_in_l1(u32 vector) vmcs_write(EXC_BITMAP, old_eb); } + static void vmx_exception_test(void) { struct vmx_exception_test *t; @@ -10754,6 +10755,187 @@ static void vmx_exception_test(void) test_set_guest_finished(); } + +#define TEST_VALUE1 0xff45454545000000 +#define TEST_VALUE2 0xff55555555000000 + +static void vmx_canonical_test_guest(void) +{ + while (true) + vmcall(); +} + +static int get_host_value(u64 vmcs_field, u64 *value) +{ + struct descriptor_table_ptr dt_ptr; + + switch (vmcs_field) { + case HOST_SYSENTER_ESP: + *value = rdmsr(MSR_IA32_SYSENTER_ESP); + break; + case HOST_SYSENTER_EIP: + *value = rdmsr(MSR_IA32_SYSENTER_EIP); + break; + case HOST_BASE_FS: + *value = rdmsr(MSR_FS_BASE); + break; + case HOST_BASE_GS: + *value = rdmsr(MSR_GS_BASE); + break; + case HOST_BASE_GDTR: + sgdt(&dt_ptr); + *value = dt_ptr.base; + break; + case HOST_BASE_IDTR: + sidt(&dt_ptr); + *value = dt_ptr.base; + break; + case HOST_BASE_TR: + *value = get_gdt_entry_base(get_tss_descr()); + /* value might not reflect the actual base if changed by VMX */ + return 1; + default: + assert(0); + } + return 0; +} + +static int set_host_value(u64 vmcs_field, u64 value) +{ + struct descriptor_table_ptr dt_ptr; + + switch (vmcs_field) { + case HOST_SYSENTER_ESP: + return wrmsr_safe(MSR_IA32_SYSENTER_ESP, value); + case HOST_SYSENTER_EIP: + return wrmsr_safe(MSR_IA32_SYSENTER_EIP, value); + case HOST_BASE_FS: + return wrmsr_safe(MSR_FS_BASE, value); + case HOST_BASE_GS: + /* TODO: _safe variants assume per-cpu gs base*/ + wrmsr(MSR_GS_BASE, value); + return 0; + case HOST_BASE_GDTR: + sgdt(&dt_ptr); + dt_ptr.base = value; + lgdt(&dt_ptr); + return lgdt_fep_safe(&dt_ptr); + case HOST_BASE_IDTR: + sidt(&dt_ptr); + dt_ptr.base = value; + return lidt_fep_safe(&dt_ptr); + case HOST_BASE_TR: + /* Set the base and clear the busy bit */ + set_gdt_entry(FIRST_SPARE_SEL, value, 0x200, 0x89, 0); + return ltr_safe(FIRST_SPARE_SEL); + default: + assert(0); + } +} + +static void test_host_value_natively(const char *field_name, u64 vmcs_field, u64 value) +{ + int vector; + u64 actual_value; + + /* + * Set the register via host native interface (e.g lgdt) and check + * that we got no exception + */ + vector = set_host_value(vmcs_field, value); + if (vector) { + report(false, + "Exception %d when setting %s to 0x%lx via host", + vector, field_name, value); + return; + } + + /* + * Now check that the host value matches what we expect for fields + * that can be read back (these that we can't we assume that are correct) + */ + + if (get_host_value(vmcs_field, &actual_value)) + actual_value = value; + + report(actual_value == value, + "%s: HOST value is set to test value 0x%lx directly", + field_name, value); +} + +static void test_host_value_via_guest(const char *field_name, u64 vmcs_field, u64 value) +{ + u64 actual_value; + + /* Set host state field in the vmcs and do the VM entry + * Success of VM entry already shows that L0 accepted the value + */ + vmcs_write(vmcs_field, TEST_VALUE2); + enter_guest(); + skip_exit_vmcall(); + + /* + * Now check that the host value matches what we expect for fields + * that can be read back (these that we can't we assume that are correct) + */ + + if (get_host_value(vmcs_field, &actual_value)) + actual_value = value; + + /* Check that now the msr value is the same as the field value */ + report(actual_value == TEST_VALUE2, + "%s: HOST value is set to test value 0x%lx via VMLAUNCH/VMRESUME", + field_name, value); +} + +static void do_vmx_canonical_test_one_field(const char *field_name, u64 field) +{ + u64 host_org_value, field_org_value; + + /* Backup the current host value and vmcs field value values */ + get_host_value(field, &host_org_value); + field_org_value = vmcs_read(field); + + /* + * Write TEST_VALUE1 57-canonical value on the host + * and check that it was written correctly + */ + test_host_value_natively(field_name, field, TEST_VALUE1); + + /* + * Write TEST_VALUE2 57-canonical value on the host + * via VM entry/exit and check that it was written correctly + */ + test_host_value_via_guest(field_name, field, TEST_VALUE2); + + /* Restore original values */ + vmcs_write(field, field_org_value); + set_host_value(field, host_org_value); +} + +#define vmx_canonical_test_one_field(field) \ + do_vmx_canonical_test_one_field(#field, field) + +static void vmx_canonical_test(void) +{ + report(!(read_cr4() & X86_CR4_LA57), "4 level paging"); + + if (!this_cpu_has(X86_FEATURE_LA57)) + test_skip("5 level paging not supported"); + + test_set_guest(vmx_canonical_test_guest); + + vmx_canonical_test_one_field(HOST_SYSENTER_ESP); + vmx_canonical_test_one_field(HOST_SYSENTER_EIP); + vmx_canonical_test_one_field(HOST_BASE_FS); + vmx_canonical_test_one_field(HOST_BASE_GS); + vmx_canonical_test_one_field(HOST_BASE_GDTR); + vmx_canonical_test_one_field(HOST_BASE_IDTR); + vmx_canonical_test_one_field(HOST_BASE_TR); + + test_set_guest_finished(); +} + enum Vid_op { VID_OP_SET_ISR, VID_OP_NOP, @@ -11262,5 +11444,6 @@ struct vmx_test vmx_tests[] = { TEST(vmx_pf_invvpid_test), TEST(vmx_pf_vpid_test), TEST(vmx_exception_test), + TEST(vmx_canonical_test), { NULL, NULL, NULL, NULL, NULL, {0} }, };