mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 01:55:51 +02:00
hyperv-fixes for v6.19-rc7
-----BEGIN PGP SIGNATURE----- iQFHBAABCgAxFiEEIbPD0id6easf0xsudhRwX5BBoF4FAmlxrcETHHdlaS5saXVA a2VybmVsLm9yZwAKCRB2FHBfkEGgXjzQB/9F3mR6KlsoootEHlMiVKa6cT12vSiJ /1U+5cJbu8tLA1S3VtuLqhz3jw5ClQpsZyAfmWb4m0Rgdh1LEfq8Tzjlf4Ee9W77 JLC6JJNxBtEdAPL0XjQGHL42P3pFtkAbFO/WA9A8LJmMxL/2455Jmg9q4JyllFU4 k2a5GS6EpyvxW5VYKqBqihgSSY+zQ0Ob/gsZF1xdZB1v8ATdGf3vFMg0F+XmaPld h1M/sxZSutfx1C9wgghLzqg2nP9+izSlvbwx0rXP35mmfcQyLo5Ita1gbiJI5OZy AR83I4fa6sopruS/aIfGcNG9uEaxxWkexMGaVcpwmtD4qKrGc4gf0A9C =At1m -----END PGP SIGNATURE----- Merge tag 'hyperv-fixes-signed-20260121' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux Pull hyperv fixes from Wei Liu: - Fix ARM64 port of the MSHV driver (Anirudh Rayabharam) - Fix huge page handling in the MSHV driver (Stanislav Kinsburskii) - Minor fixes to driver code (Julia Lawall, Michael Kelley) * tag 'hyperv-fixes-signed-20260121' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux: mshv: handle gpa intercepts for arm64 mshv: add definitions for arm64 gpa intercepts mshv: Add __user attribute to argument passed to access_ok() mshv: Store the result of vfs_poll in a variable of type __poll_t mshv: Align huge page stride with guest mapping Drivers: hv: Always do Hyper-V panic notification in hv_kmsg_dump() Drivers: hv: vmbus: fix typo in function name reference
This commit is contained in:
commit
a66191c590
|
|
@ -195,13 +195,15 @@ static void hv_kmsg_dump(struct kmsg_dumper *dumper,
|
|||
|
||||
/*
|
||||
* Write dump contents to the page. No need to synchronize; panic should
|
||||
* be single-threaded.
|
||||
* be single-threaded. Ignore failures from kmsg_dump_get_buffer() since
|
||||
* panic notification should be done even if there is no message data.
|
||||
* Don't assume bytes_written is set in case of failure, so initialize it.
|
||||
*/
|
||||
kmsg_dump_rewind(&iter);
|
||||
kmsg_dump_get_buffer(&iter, false, hv_panic_page, HV_HYP_PAGE_SIZE,
|
||||
bytes_written = 0;
|
||||
(void)kmsg_dump_get_buffer(&iter, false, hv_panic_page, HV_HYP_PAGE_SIZE,
|
||||
&bytes_written);
|
||||
if (!bytes_written)
|
||||
return;
|
||||
|
||||
/*
|
||||
* P3 to contain the physical address of the panic page & P4 to
|
||||
* contain the size of the panic data in that page. Rest of the
|
||||
|
|
@ -210,7 +212,7 @@ static void hv_kmsg_dump(struct kmsg_dumper *dumper,
|
|||
hv_set_msr(HV_MSR_CRASH_P0, 0);
|
||||
hv_set_msr(HV_MSR_CRASH_P1, 0);
|
||||
hv_set_msr(HV_MSR_CRASH_P2, 0);
|
||||
hv_set_msr(HV_MSR_CRASH_P3, virt_to_phys(hv_panic_page));
|
||||
hv_set_msr(HV_MSR_CRASH_P3, bytes_written ? virt_to_phys(hv_panic_page) : 0);
|
||||
hv_set_msr(HV_MSR_CRASH_P4, bytes_written);
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -375,7 +375,7 @@ static inline void vmbus_signal_eom(struct hv_message *msg, u32 old_msg_type)
|
|||
return;
|
||||
|
||||
/*
|
||||
* The cmxchg() above does an implicit memory barrier to
|
||||
* The cmpxchg() above does an implicit memory barrier to
|
||||
* ensure the write to MessageType (ie set to
|
||||
* HVMSG_NONE) happens before we read the
|
||||
* MessagePending and EOMing. Otherwise, the EOMing
|
||||
|
|
|
|||
|
|
@ -388,7 +388,7 @@ static int mshv_irqfd_assign(struct mshv_partition *pt,
|
|||
{
|
||||
struct eventfd_ctx *eventfd = NULL, *resamplefd = NULL;
|
||||
struct mshv_irqfd *irqfd, *tmp;
|
||||
unsigned int events;
|
||||
__poll_t events;
|
||||
int ret;
|
||||
int idx;
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,41 @@
|
|||
|
||||
#define MSHV_MAP_FAULT_IN_PAGES PTRS_PER_PMD
|
||||
|
||||
/**
|
||||
* mshv_chunk_stride - Compute stride for mapping guest memory
|
||||
* @page : The page to check for huge page backing
|
||||
* @gfn : Guest frame number for the mapping
|
||||
* @page_count: Total number of pages in the mapping
|
||||
*
|
||||
* Determines the appropriate stride (in pages) for mapping guest memory.
|
||||
* Uses huge page stride if the backing page is huge and the guest mapping
|
||||
* is properly aligned; otherwise falls back to single page stride.
|
||||
*
|
||||
* Return: Stride in pages, or -EINVAL if page order is unsupported.
|
||||
*/
|
||||
static int mshv_chunk_stride(struct page *page,
|
||||
u64 gfn, u64 page_count)
|
||||
{
|
||||
unsigned int page_order;
|
||||
|
||||
/*
|
||||
* Use single page stride by default. For huge page stride, the
|
||||
* page must be compound and point to the head of the compound
|
||||
* page, and both gfn and page_count must be huge-page aligned.
|
||||
*/
|
||||
if (!PageCompound(page) || !PageHead(page) ||
|
||||
!IS_ALIGNED(gfn, PTRS_PER_PMD) ||
|
||||
!IS_ALIGNED(page_count, PTRS_PER_PMD))
|
||||
return 1;
|
||||
|
||||
page_order = folio_order(page_folio(page));
|
||||
/* The hypervisor only supports 2M huge page */
|
||||
if (page_order != PMD_ORDER)
|
||||
return -EINVAL;
|
||||
|
||||
return 1 << page_order;
|
||||
}
|
||||
|
||||
/**
|
||||
* mshv_region_process_chunk - Processes a contiguous chunk of memory pages
|
||||
* in a region.
|
||||
|
|
@ -45,25 +80,23 @@ static long mshv_region_process_chunk(struct mshv_mem_region *region,
|
|||
int (*handler)(struct mshv_mem_region *region,
|
||||
u32 flags,
|
||||
u64 page_offset,
|
||||
u64 page_count))
|
||||
u64 page_count,
|
||||
bool huge_page))
|
||||
{
|
||||
u64 count, stride;
|
||||
unsigned int page_order;
|
||||
u64 gfn = region->start_gfn + page_offset;
|
||||
u64 count;
|
||||
struct page *page;
|
||||
int ret;
|
||||
int stride, ret;
|
||||
|
||||
page = region->pages[page_offset];
|
||||
if (!page)
|
||||
return -EINVAL;
|
||||
|
||||
page_order = folio_order(page_folio(page));
|
||||
/* The hypervisor only supports 4K and 2M page sizes */
|
||||
if (page_order && page_order != PMD_ORDER)
|
||||
return -EINVAL;
|
||||
stride = mshv_chunk_stride(page, gfn, page_count);
|
||||
if (stride < 0)
|
||||
return stride;
|
||||
|
||||
stride = 1 << page_order;
|
||||
|
||||
/* Start at stride since the first page is validated */
|
||||
/* Start at stride since the first stride is validated */
|
||||
for (count = stride; count < page_count; count += stride) {
|
||||
page = region->pages[page_offset + count];
|
||||
|
||||
|
|
@ -71,12 +104,13 @@ static long mshv_region_process_chunk(struct mshv_mem_region *region,
|
|||
if (!page)
|
||||
break;
|
||||
|
||||
/* Break if page size changes */
|
||||
if (page_order != folio_order(page_folio(page)))
|
||||
/* Break if stride size changes */
|
||||
if (stride != mshv_chunk_stride(page, gfn + count,
|
||||
page_count - count))
|
||||
break;
|
||||
}
|
||||
|
||||
ret = handler(region, flags, page_offset, count);
|
||||
ret = handler(region, flags, page_offset, count, stride > 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -108,7 +142,8 @@ static int mshv_region_process_range(struct mshv_mem_region *region,
|
|||
int (*handler)(struct mshv_mem_region *region,
|
||||
u32 flags,
|
||||
u64 page_offset,
|
||||
u64 page_count))
|
||||
u64 page_count,
|
||||
bool huge_page))
|
||||
{
|
||||
long ret;
|
||||
|
||||
|
|
@ -162,11 +197,10 @@ struct mshv_mem_region *mshv_region_create(u64 guest_pfn, u64 nr_pages,
|
|||
|
||||
static int mshv_region_chunk_share(struct mshv_mem_region *region,
|
||||
u32 flags,
|
||||
u64 page_offset, u64 page_count)
|
||||
u64 page_offset, u64 page_count,
|
||||
bool huge_page)
|
||||
{
|
||||
struct page *page = region->pages[page_offset];
|
||||
|
||||
if (PageHuge(page) || PageTransCompound(page))
|
||||
if (huge_page)
|
||||
flags |= HV_MODIFY_SPA_PAGE_HOST_ACCESS_LARGE_PAGE;
|
||||
|
||||
return hv_call_modify_spa_host_access(region->partition->pt_id,
|
||||
|
|
@ -188,11 +222,10 @@ int mshv_region_share(struct mshv_mem_region *region)
|
|||
|
||||
static int mshv_region_chunk_unshare(struct mshv_mem_region *region,
|
||||
u32 flags,
|
||||
u64 page_offset, u64 page_count)
|
||||
u64 page_offset, u64 page_count,
|
||||
bool huge_page)
|
||||
{
|
||||
struct page *page = region->pages[page_offset];
|
||||
|
||||
if (PageHuge(page) || PageTransCompound(page))
|
||||
if (huge_page)
|
||||
flags |= HV_MODIFY_SPA_PAGE_HOST_ACCESS_LARGE_PAGE;
|
||||
|
||||
return hv_call_modify_spa_host_access(region->partition->pt_id,
|
||||
|
|
@ -212,11 +245,10 @@ int mshv_region_unshare(struct mshv_mem_region *region)
|
|||
|
||||
static int mshv_region_chunk_remap(struct mshv_mem_region *region,
|
||||
u32 flags,
|
||||
u64 page_offset, u64 page_count)
|
||||
u64 page_offset, u64 page_count,
|
||||
bool huge_page)
|
||||
{
|
||||
struct page *page = region->pages[page_offset];
|
||||
|
||||
if (PageHuge(page) || PageTransCompound(page))
|
||||
if (huge_page)
|
||||
flags |= HV_MAP_GPA_LARGE_PAGE;
|
||||
|
||||
return hv_call_map_gpa_pages(region->partition->pt_id,
|
||||
|
|
@ -295,11 +327,10 @@ int mshv_region_pin(struct mshv_mem_region *region)
|
|||
|
||||
static int mshv_region_chunk_unmap(struct mshv_mem_region *region,
|
||||
u32 flags,
|
||||
u64 page_offset, u64 page_count)
|
||||
u64 page_offset, u64 page_count,
|
||||
bool huge_page)
|
||||
{
|
||||
struct page *page = region->pages[page_offset];
|
||||
|
||||
if (PageHuge(page) || PageTransCompound(page))
|
||||
if (huge_page)
|
||||
flags |= HV_UNMAP_GPA_LARGE_PAGE;
|
||||
|
||||
return hv_call_unmap_gpa_pages(region->partition->pt_id,
|
||||
|
|
|
|||
|
|
@ -611,7 +611,6 @@ mshv_partition_region_by_gfn(struct mshv_partition *partition, u64 gfn)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
static struct mshv_mem_region *
|
||||
mshv_partition_region_by_gfn_get(struct mshv_partition *p, u64 gfn)
|
||||
{
|
||||
|
|
@ -643,12 +642,17 @@ static bool mshv_handle_gpa_intercept(struct mshv_vp *vp)
|
|||
{
|
||||
struct mshv_partition *p = vp->vp_partition;
|
||||
struct mshv_mem_region *region;
|
||||
struct hv_x64_memory_intercept_message *msg;
|
||||
bool ret;
|
||||
u64 gfn;
|
||||
|
||||
msg = (struct hv_x64_memory_intercept_message *)
|
||||
#if defined(CONFIG_X86_64)
|
||||
struct hv_x64_memory_intercept_message *msg =
|
||||
(struct hv_x64_memory_intercept_message *)
|
||||
vp->vp_intercept_msg_page->u.payload;
|
||||
#elif defined(CONFIG_ARM64)
|
||||
struct hv_arm64_memory_intercept_message *msg =
|
||||
(struct hv_arm64_memory_intercept_message *)
|
||||
vp->vp_intercept_msg_page->u.payload;
|
||||
#endif
|
||||
|
||||
gfn = HVPFN_DOWN(msg->guest_physical_address);
|
||||
|
||||
|
|
@ -666,9 +670,6 @@ static bool mshv_handle_gpa_intercept(struct mshv_vp *vp)
|
|||
|
||||
return ret;
|
||||
}
|
||||
#else /* CONFIG_X86_64 */
|
||||
static bool mshv_handle_gpa_intercept(struct mshv_vp *vp) { return false; }
|
||||
#endif /* CONFIG_X86_64 */
|
||||
|
||||
static bool mshv_vp_handle_intercept(struct mshv_vp *vp)
|
||||
{
|
||||
|
|
@ -1280,7 +1281,7 @@ mshv_map_user_memory(struct mshv_partition *partition,
|
|||
long ret;
|
||||
|
||||
if (mem.flags & BIT(MSHV_SET_MEM_BIT_UNMAP) ||
|
||||
!access_ok((const void *)mem.userspace_addr, mem.size))
|
||||
!access_ok((const void __user *)mem.userspace_addr, mem.size))
|
||||
return -EINVAL;
|
||||
|
||||
mmap_read_lock(current->mm);
|
||||
|
|
|
|||
|
|
@ -800,6 +800,53 @@ struct hv_x64_memory_intercept_message {
|
|||
u8 instruction_bytes[16];
|
||||
} __packed;
|
||||
|
||||
#if IS_ENABLED(CONFIG_ARM64)
|
||||
union hv_arm64_vp_execution_state {
|
||||
u16 as_uint16;
|
||||
struct {
|
||||
u16 cpl:2; /* Exception Level (EL) */
|
||||
u16 debug_active:1;
|
||||
u16 interruption_pending:1;
|
||||
u16 vtl:4;
|
||||
u16 virtualization_fault_active:1;
|
||||
u16 reserved:7;
|
||||
} __packed;
|
||||
};
|
||||
|
||||
struct hv_arm64_intercept_message_header {
|
||||
u32 vp_index;
|
||||
u8 instruction_length;
|
||||
u8 intercept_access_type;
|
||||
union hv_arm64_vp_execution_state execution_state;
|
||||
u64 pc;
|
||||
u64 cpsr;
|
||||
} __packed;
|
||||
|
||||
union hv_arm64_memory_access_info {
|
||||
u8 as_uint8;
|
||||
struct {
|
||||
u8 gva_valid:1;
|
||||
u8 gva_gpa_valid:1;
|
||||
u8 hypercall_output_pending:1;
|
||||
u8 reserved:5;
|
||||
} __packed;
|
||||
};
|
||||
|
||||
struct hv_arm64_memory_intercept_message {
|
||||
struct hv_arm64_intercept_message_header header;
|
||||
u32 cache_type; /* enum hv_cache_type */
|
||||
u8 instruction_byte_count;
|
||||
union hv_arm64_memory_access_info memory_access_info;
|
||||
u16 reserved1;
|
||||
u8 instruction_bytes[4];
|
||||
u32 reserved2;
|
||||
u64 guest_virtual_address;
|
||||
u64 guest_physical_address;
|
||||
u64 syndrome;
|
||||
} __packed;
|
||||
|
||||
#endif /* CONFIG_ARM64 */
|
||||
|
||||
/*
|
||||
* Dispatch state for the VP communicated by the hypervisor to the
|
||||
* VP-dispatching thread in the root on return from HVCALL_DISPATCH_VP.
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user