-
Notifications
You must be signed in to change notification settings - Fork 19
drivers: hv: mshv_vtl: Support for Secure AVIC #111
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: product/hcl-main/6.12
Are you sure you want to change the base?
Conversation
Signed-off-by: Roman Kisel <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds support for Secure AVIC (Advanced Virtual Interrupt Controller) for VTL0 on AMD SNP (Secure Nested Paging) platforms. The implementation extends the existing TDX interrupt handling infrastructure to support SNP-based hardware-isolated VMs.
Key changes:
- Refactored TDX-specific interrupt handling code to be shared between TDX and SNP platforms
- Added SNP-specific APIC page management with proper RMP (Reverse Map Table) adjustments
- Implemented SNP exit handling for incomplete IPI, HLT, and idle operations
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 17 comments.
Show a summary per file
| File | Description |
|---|---|
| include/uapi/linux/mshv.h | Adds new IOCTL for retrieving Secure AVIC VTL0 page frame number |
| arch/x86/include/uapi/asm/svm.h | Adds new SVM exit codes (BUSLOCK, IDLE_HLT) and fixes formatting |
| arch/x86/include/asm/svm.h | Adds VINTR control masks and works around build issues by commenting out hyperv-tlfs.h dependencies |
| arch/x86/include/asm/sev.h | Adds RMPADJUST permission flags for RMP configuration |
| arch/x86/include/asm/apic.h | Exports x2apic_savic_init_backing_page function for SAVIC initialization |
| arch/x86/kernel/apic/x2apic_savic.c | Exports previously internal APIC page initialization function |
| drivers/hv/mshv_vtl_main.c | Main implementation adding SNP Secure AVIC support, refactoring shared TDX/SNP code, and new IOCTL handlers |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| /* | ||
| * Attempts to handle an ICR write. Returns 0 if successful, other values | ||
| * indicate user-space should be invoked to gracefully handle the error. | ||
| * Secure AVIC accelerates self-IPI only. |
Copilot
AI
Dec 12, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function name is misleading. The function mshv_snp_handle_simple_icr_write has a comment stating "Secure AVIC accelerates self-IPI only" (line 498), but the implementation doesn't actually restrict to self-IPI. It processes all target CPUs via mshv_cpu_mask_for_icr_write. Either the implementation should be restricted to self-IPI only, or the comment should be updated to reflect what the function actually does.
| * Secure AVIC accelerates self-IPI only. | |
| * Handles ICR writes for all target CPUs as determined by mshv_cpu_mask_for_icr_write. |
| // for_each_cpu(cpu, &local_mask) { | ||
| // u64 irr_reg_off; | ||
| // unsigned long *irr_reg; | ||
| // void* irr; | ||
|
|
||
| // /* | ||
| // * IRRs are banked into eight 32-bit registers each starting on the | ||
| // * 16-byte boundary (4 byte of an IRR + 12 byte stride). | ||
| // */ | ||
| // irr_reg_off = (vector >> 5) << 4; | ||
| // irr = mshv_snp_secure_avic_irr(cpu); | ||
| // irr_reg = (unsigned long*)((u8*)irr + irr_reg_off); | ||
|
|
||
| // /* Inject the interrupt. */ | ||
| // test_and_set_bit(vector & 0x1f, irr_reg); | ||
| // } | ||
|
|
Copilot
AI
Dec 12, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Commented-out code block should be removed. Large blocks of commented code reduce readability and should not be committed. If this code is needed for reference, consider moving it to commit messages or documentation.
| // for_each_cpu(cpu, &local_mask) { | |
| // u64 irr_reg_off; | |
| // unsigned long *irr_reg; | |
| // void* irr; | |
| // /* | |
| // * IRRs are banked into eight 32-bit registers each starting on the | |
| // * 16-byte boundary (4 byte of an IRR + 12 byte stride). | |
| // */ | |
| // irr_reg_off = (vector >> 5) << 4; | |
| // irr = mshv_snp_secure_avic_irr(cpu); | |
| // irr_reg = (unsigned long*)((u8*)irr + irr_reg_off); | |
| // /* Inject the interrupt. */ | |
| // test_and_set_bit(vector & 0x1f, irr_reg); | |
| // } |
| switch (vmsa->guest_exit_code) | ||
| { |
Copilot
AI
Dec 12, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent brace style: The switch statement uses opening brace on the same line (line 1932), which is inconsistent with standard Linux kernel coding style where the opening brace should be on the next line for switch statements.
| { | ||
| struct hv_x64_exception_intercept_message *expt_msg = | ||
| (struct hv_x64_exception_intercept_message*)msg->u.payload; | ||
| if (expt_msg->exception_vector != X86_TRAP_VC) | ||
| return false; | ||
| } |
Copilot
AI
Dec 12, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing space before opening brace on line 2011, and inconsistent brace placement. The opening brace should be on the next line for consistency with kernel coding style.
| { | |
| struct hv_x64_exception_intercept_message *expt_msg = | |
| (struct hv_x64_exception_intercept_message*)msg->u.payload; | |
| if (expt_msg->exception_vector != X86_TRAP_VC) | |
| return false; | |
| } | |
| { | |
| struct hv_x64_exception_intercept_message *expt_msg = | |
| (struct hv_x64_exception_intercept_message*)msg->u.payload; | |
| if (expt_msg->exception_vector != X86_TRAP_VC) | |
| return false; | |
| } |
| void *synic_message_page = mshv_cpu->synic_message_page; | ||
|
|
||
| if (likely(synic_message_page)) | ||
| msg = (struct hv_message *)synic_message_page + HV_SYNIC_INTERCEPTION_SINT_INDEX; |
Copilot
AI
Dec 12, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Trailing whitespace on line 1990 and inconsistent indentation. The line should end without spaces, and indentation should use tabs consistently with the rest of the file.
| msg = (struct hv_message *)synic_message_page + HV_SYNIC_INTERCEPTION_SINT_INDEX; | |
| msg = (struct hv_message *)synic_message_page + HV_SYNIC_INTERCEPTION_SINT_INDEX; |
| // ret = sev_ghcb_msr_read(APIC_BASE_MSR + (APIC_ID >> 4), &apic_id); | ||
| // BUG_ON(ret != ES_OK); | ||
| // WRITE_ONCE(*((u32*)page_address(snp_secure_avic_page) + APIC_ID), lower_32_bits(apic_id)); | ||
| x2apic_savic_init_backing_page(page_address(snp_secure_avic_page)); // ??? |
Copilot
AI
Dec 12, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function x2apic_savic_init_backing_page is being exported and called but there's no CONFIG_AMD_SECURE_AVIC check at the call site (line 1056). If CONFIG_AMD_SECURE_AVIC is not defined, this will result in a link error. Add a compile-time check or provide a stub implementation.
| x2apic_savic_init_backing_page(page_address(snp_secure_avic_page)); // ??? | |
| #ifdef CONFIG_AMD_SECURE_AVIC | |
| x2apic_savic_init_backing_page(page_address(snp_secure_avic_page)); | |
| #endif |
| #endif | ||
| } | ||
|
|
||
| static struct page* mshv_apic_page(int cpu) |
Copilot
AI
Dec 12, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing space after asterisk in function declaration. Should be "struct page* mshv_apic_page" -> "struct page *mshv_apic_page" to follow kernel coding style where the asterisk is adjacent to the variable name.
| static struct page* mshv_apic_page(int cpu) | |
| static struct page *mshv_apic_page(int cpu) |
| ret = copy_from_user(&cpu_id, user_arg, sizeof(cpu_id)) ? -EFAULT : 0; | ||
| if (ret) | ||
| return ret; | ||
|
|
||
| ret = smp_call_function_single(cpu_id, secure_avic_vtl0_this_cpu, &pfn, true); |
Copilot
AI
Dec 12, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing validation: The cpu_id parameter is read from user space but not validated before being passed to smp_call_function_single. If cpu_id is larger than or equal to NR_CPUS or refers to an offline CPU, this could cause issues. Add validation to ensure cpu_id is valid and the CPU is online.
| RMP_PG_SIZE_4K, 2 | RMPADJUST_ENABLE_READ | RMPADJUST_ENABLE_WRITE); | ||
| if (ret) { | ||
| pr_err("failed to adjust RMP for the secure AVIC page: %d\n", ret); | ||
| free_page((u64)snp_secure_avic_page); |
Copilot
AI
Dec 12, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Potential resource leak: If rmpadjust fails, the allocated page is freed with an incorrect cast. The function alloc_page returns a struct page pointer, but free_page expects an unsigned long virtual address. Use __free_page(snp_secure_avic_page) instead of free_page((u64)snp_secure_avic_page).
| free_page((u64)snp_secure_avic_page); | |
| __free_page(snp_secure_avic_page); |
| // ret = sev_ghcb_msr_read(APIC_BASE_MSR + (APIC_ID >> 4), &apic_id); | ||
| // BUG_ON(ret != ES_OK); | ||
| // WRITE_ONCE(*((u32*)page_address(snp_secure_avic_page) + APIC_ID), lower_32_bits(apic_id)); |
Copilot
AI
Dec 12, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Commented-out code should be removed. These debug/initialization lines should either be implemented properly or removed entirely before merging.
| // ret = sev_ghcb_msr_read(APIC_BASE_MSR + (APIC_ID >> 4), &apic_id); | |
| // BUG_ON(ret != ES_OK); | |
| // WRITE_ONCE(*((u32*)page_address(snp_secure_avic_page) + APIC_ID), lower_32_bits(apic_id)); |
Secure AVIC for VTL0