From: Naveen N Rao <naveen@kernel.org>
To: Manali Shukla <manali.shukla@amd.com>
Cc: seanjc@google.com, pbonzini@redhat.com, mingo@redhat.com,
bp@alien8.de, dave.hansen@linux.intel.com, kvm@vger.kernel.org,
x86@kernel.org, santosh.shukla@amd.com, nikunj.dadhania@amd.com,
dapeng1.mi@linux.intel.com
Subject: Re: [PATCH v1 6/9] KVM: Add KVM_GET_LAPIC2 and KVM_SET_LAPIC2 for extended APIC
Date: Thu, 14 May 2026 20:11:09 +0530 [thread overview]
Message-ID: <agXeBPq5nTUxuxcS@blrnaveerao1> (raw)
In-Reply-To: <20260204074452.55453-7-manali.shukla@amd.com>
On Wed, Feb 04, 2026 at 07:44:49AM +0000, Manali Shukla wrote:
> Add KVM_GET_LAPIC2 and KVM_SET_LAPIC2 ioctls to save and restore APIC
> state using a 4KB buffer (kvm_lapic_state2). The larger buffer allows
> saving additional APIC registers beyond the standard APIC registers
> supported by the existing 1KB KVM_GET/SET_LAPIC ioctls.
>
> The 4KB buffer size matches the LAPIC2 capability, which enables the
> full APIC register page including extended APIC registers for AMD
> processors.
>
> KVM_GET/SET_LAPIC continue to work as before for backward compatibility.
> Document the new ioctls in Documentation/virt/kvm/api.rst.
>
> Suggested-by: Sean Christopherson <seanjc@google.com>
> Signed-off-by: Manali Shukla <manali.shukla@amd.com>
> ---
> Documentation/virt/kvm/api.rst | 45 +++++++++++++++++++++++++
> arch/x86/include/uapi/asm/kvm.h | 5 +++
> arch/x86/kvm/x86.c | 59 +++++++++++++++++++++++++++++++++
> include/uapi/linux/kvm.h | 2 ++
> 4 files changed, 111 insertions(+)
>
> diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
> index 71b4d24f009a..c49cf3104b2c 100644
> --- a/Documentation/virt/kvm/api.rst
> +++ b/Documentation/virt/kvm/api.rst
> @@ -6517,6 +6517,51 @@ the capability to be present.
>
> `flags` must currently be zero.
>
> +4.144 KVM_GET_LAPIC2
> +----------------------
> +
> +:Capability: KVM_CAP_LAPIC2
> +:Architectures: x86
> +:Type: vcpu ioctl
> +:Parameters: struct kvm_lapic_state2 (out)
> +:Returns: 0 on success, negative on failure
> +
> +Reads the extended Local APIC registers, including both the standard APIC
> +register space (offsets 0h-3FFh) and the extended APIC register space (offsets
> +400h-500h and beyond).
> +
> +This ioctl is similar to KVM_GET_LAPIC but operates on a 4KB APIC
> +register space that includes extended LVT registers available on AMD processors
> +with the ExtApicSpace feature.
> +
> +::
> +
> + #define KVM_APIC_EXT_REG_SIZE 0x1000
> + struct kvm_lapic_state2 {
> + char regs[KVM_APIC_EXT_REG_SIZE];
> + };
> +
> +4.145 KVM_SET_LAPIC2
> +----------------------
> +
> +:Capability: KVM_CAP_LAPIC2
> +:Architectures: x86
> +:Type: vcpu ioctl
> +:Parameters: struct kvm_lapic_state2 (in)
> +:Returns: 0 on success, negative on failure
> +
> +Sets the extended Local APIC registers, including both the standard APIC
> +register space and the extended APIC register space.
> +
> +This ioctl is similar to KVM_SET_LAPIC but operates on a 4KB APIC register space
> +that includes extended LVT registers for AMD processors.
> +
> +::
> +
> + #define KVM_APIC_EXT_REG_SIZE 0x1000
> + struct kvm_lapic_stat2 {
> + char regs[KVM_APIC_EXT_REG_SIZE];
> + };
>
> .. _kvm_run:
>
> diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h
> index 7ceff6583652..516d4a0be25a 100644
> --- a/arch/x86/include/uapi/asm/kvm.h
> +++ b/arch/x86/include/uapi/asm/kvm.h
> @@ -129,6 +129,11 @@ struct kvm_lapic_state {
> char regs[KVM_APIC_REG_SIZE];
> };
>
> +#define KVM_APIC_EXT_REG_SIZE 0x1000
> +struct kvm_lapic_state2 {
> + char regs[KVM_APIC_EXT_REG_SIZE];
> +};
> +
> struct kvm_segment {
> __u64 base;
> __u32 limit;
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index 669c894f1061..ccd16bdff56a 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -5331,6 +5331,17 @@ static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu,
> return kvm_apic_get_state(vcpu, s->regs, sizeof(*s));
> }
>
> +static int kvm_vcpu_ioctl_get_lapic2(struct kvm_vcpu *vcpu,
> + struct kvm_lapic_state2 *s)
> +{
> + if (vcpu->arch.apic->guest_apic_protected)
> + return -EINVAL;
> +
> + kvm_x86_call(sync_pir_to_irr)(vcpu);
> +
> + return kvm_apic_get_state(vcpu, s->regs, sizeof(*s));
> +}
> +
Instead of introducing additional functions/helpers, I think we should
unify handling of the existing and the new IOCTLs.
Along with a change to revert the previous patch, how about the below on
top of your series (completely untested, so likely buggy but should
hopefully give a sense of the approach):
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h
index 552d416e5fc6..c7a9687bdd7f 100644
--- a/arch/x86/kvm/lapic.h
+++ b/arch/x86/kvm/lapic.h
@@ -136,8 +136,8 @@ static inline int kvm_irq_delivery_to_apic(struct kvm *kvm,
void kvm_apic_send_ipi(struct kvm_lapic *apic, u32 icr_low, u32 icr_high);
int kvm_apic_set_base(struct kvm_vcpu *vcpu, u64 value, bool host_initiated);
-int kvm_apic_get_state(struct kvm_vcpu *vcpu, void *regs, unsigned int size);
-int kvm_apic_set_state(struct kvm_vcpu *vcpu, void *regs, unsigned int size);
+int kvm_apic_get_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state2 *s);
+int kvm_apic_set_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state2 *s, bool is_lapic2);
int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu);
u64 kvm_get_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu);
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index ed20e0b21be7..434607374423 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -3236,12 +3236,12 @@ void kvm_apic_ack_interrupt(struct kvm_vcpu *vcpu, int vector)
EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_apic_ack_interrupt);
static int kvm_apic_state_fixup(struct kvm_vcpu *vcpu,
- void *regs, bool set)
+ struct kvm_lapic_state2 *s, bool set)
{
if (apic_x2apic_mode(vcpu->arch.apic)) {
u32 x2apic_id = kvm_x2apic_id(vcpu->arch.apic);
- u32 *id = (u32 *)(regs + APIC_ID);
- u32 *ldr = (u32 *)(regs + APIC_LDR);
+ u32 *id = (u32 *)(s->regs + APIC_ID);
+ u32 *ldr = (u32 *)(s->regs + APIC_LDR);
u64 icr;
if (vcpu->kvm->arch.x2apic_format) {
@@ -3274,12 +3274,12 @@ static int kvm_apic_state_fixup(struct kvm_vcpu *vcpu,
if (!kvm_x86_ops.x2apic_icr_is_split) {
if (set) {
- icr = apic_get_reg(regs, APIC_ICR) |
- (u64)apic_get_reg(regs, APIC_ICR2) << 32;
- apic_set_reg64(regs, APIC_ICR, icr);
+ icr = apic_get_reg(s->regs, APIC_ICR) |
+ (u64)apic_get_reg(s->regs, APIC_ICR2) << 32;
+ apic_set_reg64(s->regs, APIC_ICR, icr);
} else {
- icr = apic_get_reg64(regs, APIC_ICR);
- apic_set_reg(regs, APIC_ICR2, icr >> 32);
+ icr = apic_get_reg64(s->regs, APIC_ICR);
+ apic_set_reg(s->regs, APIC_ICR2, icr >> 32);
}
}
}
@@ -3287,20 +3287,20 @@ static int kvm_apic_state_fixup(struct kvm_vcpu *vcpu,
return 0;
}
-int kvm_apic_get_state(struct kvm_vcpu *vcpu, void *regs, unsigned int size)
+int kvm_apic_get_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state2 *s)
{
- memcpy(regs, vcpu->arch.apic->regs, size);
+ memcpy(s->regs, vcpu->arch.apic->regs, sizeof(*s));
/*
* Get calculated timer current count for remaining timer period (if
* any) and store it in the returned register set.
*/
- apic_set_reg(regs, APIC_TMCCT, __apic_read(vcpu->arch.apic, APIC_TMCCT));
+ apic_set_reg(s->regs, APIC_TMCCT, __apic_read(vcpu->arch.apic, APIC_TMCCT));
- return kvm_apic_state_fixup(vcpu, regs, false);
+ return kvm_apic_state_fixup(vcpu, s, false);
}
-int kvm_apic_set_state(struct kvm_vcpu *vcpu, void *regs, unsigned int size)
+int kvm_apic_set_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state2 *s, bool is_lapic2)
{
struct kvm_lapic *apic = vcpu->arch.apic;
int r;
@@ -3308,14 +3308,16 @@ int kvm_apic_set_state(struct kvm_vcpu *vcpu, void *regs, unsigned int size)
kvm_x86_call(apicv_pre_state_restore)(vcpu);
/* set SPIV separately to get count of SW disabled APICs right */
- apic_set_spiv(apic, *((u32 *)(regs + APIC_SPIV)));
+ apic_set_spiv(apic, *((u32 *)(s->regs + APIC_SPIV)));
- r = kvm_apic_state_fixup(vcpu, regs, true);
+ r = kvm_apic_state_fixup(vcpu, s, true);
if (r) {
kvm_recalculate_apic_map(vcpu->kvm);
return r;
}
- memcpy(vcpu->arch.apic->regs, regs, size);
+ memcpy(vcpu->arch.apic->regs, s->regs, is_lapic2 ?
+ sizeof(struct kvm_lapic_state2) :
+ sizeof(struct kvm_lapic_state));
atomic_set_release(&apic->vcpu->kvm->arch.apic_map_dirty, DIRTY);
kvm_recalculate_apic_map(vcpu->kvm);
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index f8a115f50f8e..2e66a1bc94a7 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -5326,17 +5326,6 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
}
static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu,
- struct kvm_lapic_state *s)
-{
- if (vcpu->arch.apic->guest_apic_protected)
- return -EINVAL;
-
- kvm_x86_call(sync_pir_to_irr)(vcpu);
-
- return kvm_apic_get_state(vcpu, s->regs, sizeof(*s));
-}
-
-static int kvm_vcpu_ioctl_get_lapic2(struct kvm_vcpu *vcpu,
struct kvm_lapic_state2 *s)
{
if (vcpu->arch.apic->guest_apic_protected)
@@ -5344,34 +5333,19 @@ static int kvm_vcpu_ioctl_get_lapic2(struct kvm_vcpu *vcpu,
kvm_x86_call(sync_pir_to_irr)(vcpu);
- return kvm_apic_get_state(vcpu, s->regs, sizeof(*s));
+ return kvm_apic_get_state(vcpu, s);
}
static int kvm_vcpu_ioctl_set_lapic(struct kvm_vcpu *vcpu,
- struct kvm_lapic_state *s)
+ struct kvm_lapic_state2 *s,
+ bool is_lapic2)
{
int r;
if (vcpu->arch.apic->guest_apic_protected)
return -EINVAL;
- r = kvm_apic_set_state(vcpu, s->regs, sizeof(*s));
- if (r)
- return r;
- update_cr8_intercept(vcpu);
-
- return 0;
-}
-
-static int kvm_vcpu_ioctl_set_lapic2(struct kvm_vcpu *vcpu,
- struct kvm_lapic_state2 *s)
-{
- int r;
-
- if (vcpu->arch.apic->guest_apic_protected)
- return -EINVAL;
-
- r = kvm_apic_set_state(vcpu, s->regs, sizeof(*s));
+ r = kvm_apic_set_state(vcpu, s, is_lapic2);
if (r)
return r;
update_cr8_intercept(vcpu);
@@ -6251,7 +6225,6 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
int r;
union {
struct kvm_sregs2 *sregs2;
- struct kvm_lapic_state *lapic;
struct kvm_lapic_state2 *lapic2;
struct kvm_xsave *xsave;
struct kvm_xcrs *xcrs;
@@ -6262,37 +6235,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
u.buffer = NULL;
switch (ioctl) {
- case KVM_GET_LAPIC: {
- r = -EINVAL;
- if (!lapic_in_kernel(vcpu))
- goto out;
- u.lapic = kzalloc_obj(struct kvm_lapic_state);
-
- r = -ENOMEM;
- if (!u.lapic)
- goto out;
- r = kvm_vcpu_ioctl_get_lapic(vcpu, u.lapic);
- if (r)
- goto out;
- r = -EFAULT;
- if (copy_to_user(argp, u.lapic, sizeof(struct kvm_lapic_state)))
- goto out;
- r = 0;
- break;
- }
- case KVM_SET_LAPIC: {
- r = -EINVAL;
- if (!lapic_in_kernel(vcpu))
- goto out;
- u.lapic = memdup_user(argp, sizeof(*u.lapic));
- if (IS_ERR(u.lapic)) {
- r = PTR_ERR(u.lapic);
- goto out_nofree;
- }
-
- r = kvm_vcpu_ioctl_set_lapic(vcpu, u.lapic);
- break;
- }
+ case KVM_GET_LAPIC:
case KVM_GET_LAPIC2: {
r = -EINVAL;
if (!lapic_in_kernel(vcpu))
@@ -6302,26 +6245,33 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
r = -ENOMEM;
if (!u.lapic2)
goto out;
- r = kvm_vcpu_ioctl_get_lapic2(vcpu, u.lapic2);
+ r = kvm_vcpu_ioctl_get_lapic(vcpu, u.lapic2);
if (r)
goto out;
r = -EFAULT;
- if (copy_to_user(argp, u.lapic2, sizeof(struct kvm_lapic_state2)))
+ if (copy_to_user(argp, u.lapic2, ioctl == KVM_GET_LAPIC2 ?
+ sizeof(struct kvm_lapic_state2) :
+ sizeof(struct kvm_lapic_state)))
goto out;
r = 0;
break;
}
+ case KVM_SET_LAPIC:
case KVM_SET_LAPIC2: {
r = -EINVAL;
if (!lapic_in_kernel(vcpu))
goto out;
- u.lapic2 = memdup_user(argp, sizeof(*u.lapic2));
- if (IS_ERR(u.lapic2)) {
- r = PTR_ERR(u.lapic2);
- goto out_nofree;
- }
+ u.lapic2 = kzalloc(sizeof(struct kvm_lapic_state2), GFP_KERNEL);
+ r = -ENOMEM;
+ if (!u.lapic2)
+ goto out;
+ r = -EINVAL;
+ if (copy_from_user(u.lapic2, argp, ioctl == KVM_SET_LAPIC2 ?
+ sizeof(struct kvm_lapic_state2) :
+ sizeof(struct kvm_lapic_state)))
+ goto out;
- r = kvm_vcpu_ioctl_set_lapic2(vcpu, u.lapic2);
+ r = kvm_vcpu_ioctl_set_lapic(vcpu, u.lapic2, ioctl == KVM_SET_LAPIC2);
break;
}
case KVM_INTERRUPT: {
- Naveen
next prev parent reply other threads:[~2026-05-14 14:49 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-04 7:44 [PATCH v1 0/9] KVM: x86: Add support for AMD Extended APIC registers Manali Shukla
2026-02-04 7:44 ` [PATCH v1 1/9] KVM: x86: Refactor APIC register mask handling to support extended " Manali Shukla
2026-05-14 12:48 ` Naveen N Rao
2026-02-04 7:44 ` [PATCH v1 2/9] x86/apic: Add helper to get maximum number of Extended LVT registers Manali Shukla
2026-05-06 11:22 ` Borislav Petkov
2026-05-14 12:50 ` Naveen N Rao
2026-02-04 7:44 ` [PATCH v1 3/9] KVM: SVM: Set kvm_caps.has_extapic when CPU supports Extended APIC Manali Shukla
2026-05-14 12:58 ` Naveen N Rao
2026-02-04 7:44 ` [PATCH v1 4/9] KVM: x86: Introduce KVM_CAP_LAPIC2 for 4KB APIC register space support Manali Shukla
2026-05-14 13:08 ` Naveen N Rao
2026-02-04 7:44 ` [PATCH v1 5/9] KVM: x86: Refactor APIC state get/set to accept variable-sized buffers Manali Shukla
2026-05-14 14:20 ` Naveen N Rao
2026-02-04 7:44 ` [PATCH v1 6/9] KVM: Add KVM_GET_LAPIC2 and KVM_SET_LAPIC2 for extended APIC Manali Shukla
2026-03-16 13:00 ` Nikunj A. Dadhania
2026-03-23 11:15 ` Manali Shukla
2026-05-14 14:36 ` Naveen N Rao
2026-05-14 14:41 ` Naveen N Rao [this message]
2026-02-04 7:44 ` [PATCH v1 7/9] KVM: x86: Emulate Extended LVT registers for AMD guests Manali Shukla
2026-05-14 14:48 ` Naveen N Rao
2026-02-04 7:44 ` [PATCH v1 8/9] x86/cpufeatures: Add CPUID feature bit for Extended LVT AVIC acceleration Manali Shukla
2026-02-04 7:44 ` [PATCH v1 9/9] KVM: SVM: Add AVIC support for extended LVT MSRs Manali Shukla
2026-05-14 15:10 ` Naveen N Rao
2026-03-10 6:17 ` [PATCH v1 0/9] KVM: x86: Add support for AMD Extended APIC registers Manali Shukla
2026-04-27 4:34 ` Shukla, Manali
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=agXeBPq5nTUxuxcS@blrnaveerao1 \
--to=naveen@kernel.org \
--cc=bp@alien8.de \
--cc=dapeng1.mi@linux.intel.com \
--cc=dave.hansen@linux.intel.com \
--cc=kvm@vger.kernel.org \
--cc=manali.shukla@amd.com \
--cc=mingo@redhat.com \
--cc=nikunj.dadhania@amd.com \
--cc=pbonzini@redhat.com \
--cc=santosh.shukla@amd.com \
--cc=seanjc@google.com \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox