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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.