162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef ASM_KVM_SMM_H
362306a36Sopenharmony_ci#define ASM_KVM_SMM_H
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <linux/build_bug.h>
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#ifdef CONFIG_KVM_SMM
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci/*
1162306a36Sopenharmony_ci * 32 bit KVM's emulated SMM layout. Based on Intel P6 layout
1262306a36Sopenharmony_ci * (https://www.sandpile.org/x86/smm.htm).
1362306a36Sopenharmony_ci */
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cistruct kvm_smm_seg_state_32 {
1662306a36Sopenharmony_ci	u32 flags;
1762306a36Sopenharmony_ci	u32 limit;
1862306a36Sopenharmony_ci	u32 base;
1962306a36Sopenharmony_ci} __packed;
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cistruct kvm_smram_state_32 {
2262306a36Sopenharmony_ci	u32 reserved1[62];
2362306a36Sopenharmony_ci	u32 smbase;
2462306a36Sopenharmony_ci	u32 smm_revision;
2562306a36Sopenharmony_ci	u16 io_inst_restart;
2662306a36Sopenharmony_ci	u16 auto_hlt_restart;
2762306a36Sopenharmony_ci	u32 io_restart_rdi;
2862306a36Sopenharmony_ci	u32 io_restart_rcx;
2962306a36Sopenharmony_ci	u32 io_restart_rsi;
3062306a36Sopenharmony_ci	u32 io_restart_rip;
3162306a36Sopenharmony_ci	u32 cr4;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	/* A20M#, CPL, shutdown and other reserved/undocumented fields */
3462306a36Sopenharmony_ci	u16 reserved2;
3562306a36Sopenharmony_ci	u8 int_shadow; /* KVM extension */
3662306a36Sopenharmony_ci	u8 reserved3[17];
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	struct kvm_smm_seg_state_32 ds;
3962306a36Sopenharmony_ci	struct kvm_smm_seg_state_32 fs;
4062306a36Sopenharmony_ci	struct kvm_smm_seg_state_32 gs;
4162306a36Sopenharmony_ci	struct kvm_smm_seg_state_32 idtr; /* IDTR has only base and limit */
4262306a36Sopenharmony_ci	struct kvm_smm_seg_state_32 tr;
4362306a36Sopenharmony_ci	u32 reserved;
4462306a36Sopenharmony_ci	struct kvm_smm_seg_state_32 gdtr; /* GDTR has only base and limit */
4562306a36Sopenharmony_ci	struct kvm_smm_seg_state_32 ldtr;
4662306a36Sopenharmony_ci	struct kvm_smm_seg_state_32 es;
4762306a36Sopenharmony_ci	struct kvm_smm_seg_state_32 cs;
4862306a36Sopenharmony_ci	struct kvm_smm_seg_state_32 ss;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	u32 es_sel;
5162306a36Sopenharmony_ci	u32 cs_sel;
5262306a36Sopenharmony_ci	u32 ss_sel;
5362306a36Sopenharmony_ci	u32 ds_sel;
5462306a36Sopenharmony_ci	u32 fs_sel;
5562306a36Sopenharmony_ci	u32 gs_sel;
5662306a36Sopenharmony_ci	u32 ldtr_sel;
5762306a36Sopenharmony_ci	u32 tr_sel;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	u32 dr7;
6062306a36Sopenharmony_ci	u32 dr6;
6162306a36Sopenharmony_ci	u32 gprs[8]; /* GPRS in the "natural" X86 order (EAX/ECX/EDX.../EDI) */
6262306a36Sopenharmony_ci	u32 eip;
6362306a36Sopenharmony_ci	u32 eflags;
6462306a36Sopenharmony_ci	u32 cr3;
6562306a36Sopenharmony_ci	u32 cr0;
6662306a36Sopenharmony_ci} __packed;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci/* 64 bit KVM's emulated SMM layout. Based on AMD64 layout */
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistruct kvm_smm_seg_state_64 {
7262306a36Sopenharmony_ci	u16 selector;
7362306a36Sopenharmony_ci	u16 attributes;
7462306a36Sopenharmony_ci	u32 limit;
7562306a36Sopenharmony_ci	u64 base;
7662306a36Sopenharmony_ci};
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistruct kvm_smram_state_64 {
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	struct kvm_smm_seg_state_64 es;
8162306a36Sopenharmony_ci	struct kvm_smm_seg_state_64 cs;
8262306a36Sopenharmony_ci	struct kvm_smm_seg_state_64 ss;
8362306a36Sopenharmony_ci	struct kvm_smm_seg_state_64 ds;
8462306a36Sopenharmony_ci	struct kvm_smm_seg_state_64 fs;
8562306a36Sopenharmony_ci	struct kvm_smm_seg_state_64 gs;
8662306a36Sopenharmony_ci	struct kvm_smm_seg_state_64 gdtr; /* GDTR has only base and limit*/
8762306a36Sopenharmony_ci	struct kvm_smm_seg_state_64 ldtr;
8862306a36Sopenharmony_ci	struct kvm_smm_seg_state_64 idtr; /* IDTR has only base and limit*/
8962306a36Sopenharmony_ci	struct kvm_smm_seg_state_64 tr;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	/* I/O restart and auto halt restart are not implemented by KVM */
9262306a36Sopenharmony_ci	u64 io_restart_rip;
9362306a36Sopenharmony_ci	u64 io_restart_rcx;
9462306a36Sopenharmony_ci	u64 io_restart_rsi;
9562306a36Sopenharmony_ci	u64 io_restart_rdi;
9662306a36Sopenharmony_ci	u32 io_restart_dword;
9762306a36Sopenharmony_ci	u32 reserved1;
9862306a36Sopenharmony_ci	u8 io_inst_restart;
9962306a36Sopenharmony_ci	u8 auto_hlt_restart;
10062306a36Sopenharmony_ci	u8 amd_nmi_mask; /* Documented in AMD BKDG as NMI mask, not used by KVM */
10162306a36Sopenharmony_ci	u8 int_shadow;
10262306a36Sopenharmony_ci	u32 reserved2;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	u64 efer;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	/*
10762306a36Sopenharmony_ci	 * Two fields below are implemented on AMD only, to store
10862306a36Sopenharmony_ci	 * SVM guest vmcb address if the #SMI was received while in the guest mode.
10962306a36Sopenharmony_ci	 */
11062306a36Sopenharmony_ci	u64 svm_guest_flag;
11162306a36Sopenharmony_ci	u64 svm_guest_vmcb_gpa;
11262306a36Sopenharmony_ci	u64 svm_guest_virtual_int; /* unknown purpose, not implemented */
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	u32 reserved3[3];
11562306a36Sopenharmony_ci	u32 smm_revison;
11662306a36Sopenharmony_ci	u32 smbase;
11762306a36Sopenharmony_ci	u32 reserved4[5];
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	/* ssp and svm_* fields below are not implemented by KVM */
12062306a36Sopenharmony_ci	u64 ssp;
12162306a36Sopenharmony_ci	u64 svm_guest_pat;
12262306a36Sopenharmony_ci	u64 svm_host_efer;
12362306a36Sopenharmony_ci	u64 svm_host_cr4;
12462306a36Sopenharmony_ci	u64 svm_host_cr3;
12562306a36Sopenharmony_ci	u64 svm_host_cr0;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	u64 cr4;
12862306a36Sopenharmony_ci	u64 cr3;
12962306a36Sopenharmony_ci	u64 cr0;
13062306a36Sopenharmony_ci	u64 dr7;
13162306a36Sopenharmony_ci	u64 dr6;
13262306a36Sopenharmony_ci	u64 rflags;
13362306a36Sopenharmony_ci	u64 rip;
13462306a36Sopenharmony_ci	u64 gprs[16]; /* GPRS in a reversed "natural" X86 order (R15/R14/../RCX/RAX.) */
13562306a36Sopenharmony_ci};
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ciunion kvm_smram {
13862306a36Sopenharmony_ci	struct kvm_smram_state_64 smram64;
13962306a36Sopenharmony_ci	struct kvm_smram_state_32 smram32;
14062306a36Sopenharmony_ci	u8 bytes[512];
14162306a36Sopenharmony_ci};
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cistatic inline int kvm_inject_smi(struct kvm_vcpu *vcpu)
14462306a36Sopenharmony_ci{
14562306a36Sopenharmony_ci	kvm_make_request(KVM_REQ_SMI, vcpu);
14662306a36Sopenharmony_ci	return 0;
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic inline bool is_smm(struct kvm_vcpu *vcpu)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	return vcpu->arch.hflags & HF_SMM_MASK;
15262306a36Sopenharmony_ci}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_civoid kvm_smm_changed(struct kvm_vcpu *vcpu, bool in_smm);
15562306a36Sopenharmony_civoid enter_smm(struct kvm_vcpu *vcpu);
15662306a36Sopenharmony_ciint emulator_leave_smm(struct x86_emulate_ctxt *ctxt);
15762306a36Sopenharmony_civoid process_smi(struct kvm_vcpu *vcpu);
15862306a36Sopenharmony_ci#else
15962306a36Sopenharmony_cistatic inline int kvm_inject_smi(struct kvm_vcpu *vcpu) { return -ENOTTY; }
16062306a36Sopenharmony_cistatic inline bool is_smm(struct kvm_vcpu *vcpu) { return false; }
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci/*
16362306a36Sopenharmony_ci * emulator_leave_smm is used as a function pointer, so the
16462306a36Sopenharmony_ci * stub is defined in x86.c.
16562306a36Sopenharmony_ci */
16662306a36Sopenharmony_ci#endif
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci#endif
169