Skip to content

Commit a66191c

Browse files
committed
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
2 parents 79f255b + 12ffd56 commit a66191c

6 files changed

Lines changed: 127 additions & 46 deletions

File tree

drivers/hv/hv_common.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -195,13 +195,15 @@ static void hv_kmsg_dump(struct kmsg_dumper *dumper,
195195

196196
/*
197197
* Write dump contents to the page. No need to synchronize; panic should
198-
* be single-threaded.
198+
* be single-threaded. Ignore failures from kmsg_dump_get_buffer() since
199+
* panic notification should be done even if there is no message data.
200+
* Don't assume bytes_written is set in case of failure, so initialize it.
199201
*/
200202
kmsg_dump_rewind(&iter);
201-
kmsg_dump_get_buffer(&iter, false, hv_panic_page, HV_HYP_PAGE_SIZE,
203+
bytes_written = 0;
204+
(void)kmsg_dump_get_buffer(&iter, false, hv_panic_page, HV_HYP_PAGE_SIZE,
202205
&bytes_written);
203-
if (!bytes_written)
204-
return;
206+
205207
/*
206208
* P3 to contain the physical address of the panic page & P4 to
207209
* 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,
210212
hv_set_msr(HV_MSR_CRASH_P0, 0);
211213
hv_set_msr(HV_MSR_CRASH_P1, 0);
212214
hv_set_msr(HV_MSR_CRASH_P2, 0);
213-
hv_set_msr(HV_MSR_CRASH_P3, virt_to_phys(hv_panic_page));
215+
hv_set_msr(HV_MSR_CRASH_P3, bytes_written ? virt_to_phys(hv_panic_page) : 0);
214216
hv_set_msr(HV_MSR_CRASH_P4, bytes_written);
215217

216218
/*

drivers/hv/hyperv_vmbus.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,7 @@ static inline void vmbus_signal_eom(struct hv_message *msg, u32 old_msg_type)
375375
return;
376376

377377
/*
378-
* The cmxchg() above does an implicit memory barrier to
378+
* The cmpxchg() above does an implicit memory barrier to
379379
* ensure the write to MessageType (ie set to
380380
* HVMSG_NONE) happens before we read the
381381
* MessagePending and EOMing. Otherwise, the EOMing

drivers/hv/mshv_eventfd.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ static int mshv_irqfd_assign(struct mshv_partition *pt,
388388
{
389389
struct eventfd_ctx *eventfd = NULL, *resamplefd = NULL;
390390
struct mshv_irqfd *irqfd, *tmp;
391-
unsigned int events;
391+
__poll_t events;
392392
int ret;
393393
int idx;
394394

drivers/hv/mshv_regions.c

Lines changed: 62 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,41 @@
1919

2020
#define MSHV_MAP_FAULT_IN_PAGES PTRS_PER_PMD
2121

22+
/**
23+
* mshv_chunk_stride - Compute stride for mapping guest memory
24+
* @page : The page to check for huge page backing
25+
* @gfn : Guest frame number for the mapping
26+
* @page_count: Total number of pages in the mapping
27+
*
28+
* Determines the appropriate stride (in pages) for mapping guest memory.
29+
* Uses huge page stride if the backing page is huge and the guest mapping
30+
* is properly aligned; otherwise falls back to single page stride.
31+
*
32+
* Return: Stride in pages, or -EINVAL if page order is unsupported.
33+
*/
34+
static int mshv_chunk_stride(struct page *page,
35+
u64 gfn, u64 page_count)
36+
{
37+
unsigned int page_order;
38+
39+
/*
40+
* Use single page stride by default. For huge page stride, the
41+
* page must be compound and point to the head of the compound
42+
* page, and both gfn and page_count must be huge-page aligned.
43+
*/
44+
if (!PageCompound(page) || !PageHead(page) ||
45+
!IS_ALIGNED(gfn, PTRS_PER_PMD) ||
46+
!IS_ALIGNED(page_count, PTRS_PER_PMD))
47+
return 1;
48+
49+
page_order = folio_order(page_folio(page));
50+
/* The hypervisor only supports 2M huge page */
51+
if (page_order != PMD_ORDER)
52+
return -EINVAL;
53+
54+
return 1 << page_order;
55+
}
56+
2257
/**
2358
* mshv_region_process_chunk - Processes a contiguous chunk of memory pages
2459
* in a region.
@@ -45,38 +80,37 @@ static long mshv_region_process_chunk(struct mshv_mem_region *region,
4580
int (*handler)(struct mshv_mem_region *region,
4681
u32 flags,
4782
u64 page_offset,
48-
u64 page_count))
83+
u64 page_count,
84+
bool huge_page))
4985
{
50-
u64 count, stride;
51-
unsigned int page_order;
86+
u64 gfn = region->start_gfn + page_offset;
87+
u64 count;
5288
struct page *page;
53-
int ret;
89+
int stride, ret;
5490

5591
page = region->pages[page_offset];
5692
if (!page)
5793
return -EINVAL;
5894

59-
page_order = folio_order(page_folio(page));
60-
/* The hypervisor only supports 4K and 2M page sizes */
61-
if (page_order && page_order != PMD_ORDER)
62-
return -EINVAL;
95+
stride = mshv_chunk_stride(page, gfn, page_count);
96+
if (stride < 0)
97+
return stride;
6398

64-
stride = 1 << page_order;
65-
66-
/* Start at stride since the first page is validated */
99+
/* Start at stride since the first stride is validated */
67100
for (count = stride; count < page_count; count += stride) {
68101
page = region->pages[page_offset + count];
69102

70103
/* Break if current page is not present */
71104
if (!page)
72105
break;
73106

74-
/* Break if page size changes */
75-
if (page_order != folio_order(page_folio(page)))
107+
/* Break if stride size changes */
108+
if (stride != mshv_chunk_stride(page, gfn + count,
109+
page_count - count))
76110
break;
77111
}
78112

79-
ret = handler(region, flags, page_offset, count);
113+
ret = handler(region, flags, page_offset, count, stride > 1);
80114
if (ret)
81115
return ret;
82116

@@ -108,7 +142,8 @@ static int mshv_region_process_range(struct mshv_mem_region *region,
108142
int (*handler)(struct mshv_mem_region *region,
109143
u32 flags,
110144
u64 page_offset,
111-
u64 page_count))
145+
u64 page_count,
146+
bool huge_page))
112147
{
113148
long ret;
114149

@@ -162,11 +197,10 @@ struct mshv_mem_region *mshv_region_create(u64 guest_pfn, u64 nr_pages,
162197

163198
static int mshv_region_chunk_share(struct mshv_mem_region *region,
164199
u32 flags,
165-
u64 page_offset, u64 page_count)
200+
u64 page_offset, u64 page_count,
201+
bool huge_page)
166202
{
167-
struct page *page = region->pages[page_offset];
168-
169-
if (PageHuge(page) || PageTransCompound(page))
203+
if (huge_page)
170204
flags |= HV_MODIFY_SPA_PAGE_HOST_ACCESS_LARGE_PAGE;
171205

172206
return hv_call_modify_spa_host_access(region->partition->pt_id,
@@ -188,11 +222,10 @@ int mshv_region_share(struct mshv_mem_region *region)
188222

189223
static int mshv_region_chunk_unshare(struct mshv_mem_region *region,
190224
u32 flags,
191-
u64 page_offset, u64 page_count)
225+
u64 page_offset, u64 page_count,
226+
bool huge_page)
192227
{
193-
struct page *page = region->pages[page_offset];
194-
195-
if (PageHuge(page) || PageTransCompound(page))
228+
if (huge_page)
196229
flags |= HV_MODIFY_SPA_PAGE_HOST_ACCESS_LARGE_PAGE;
197230

198231
return hv_call_modify_spa_host_access(region->partition->pt_id,
@@ -212,11 +245,10 @@ int mshv_region_unshare(struct mshv_mem_region *region)
212245

213246
static int mshv_region_chunk_remap(struct mshv_mem_region *region,
214247
u32 flags,
215-
u64 page_offset, u64 page_count)
248+
u64 page_offset, u64 page_count,
249+
bool huge_page)
216250
{
217-
struct page *page = region->pages[page_offset];
218-
219-
if (PageHuge(page) || PageTransCompound(page))
251+
if (huge_page)
220252
flags |= HV_MAP_GPA_LARGE_PAGE;
221253

222254
return hv_call_map_gpa_pages(region->partition->pt_id,
@@ -295,11 +327,10 @@ int mshv_region_pin(struct mshv_mem_region *region)
295327

296328
static int mshv_region_chunk_unmap(struct mshv_mem_region *region,
297329
u32 flags,
298-
u64 page_offset, u64 page_count)
330+
u64 page_offset, u64 page_count,
331+
bool huge_page)
299332
{
300-
struct page *page = region->pages[page_offset];
301-
302-
if (PageHuge(page) || PageTransCompound(page))
333+
if (huge_page)
303334
flags |= HV_UNMAP_GPA_LARGE_PAGE;
304335

305336
return hv_call_unmap_gpa_pages(region->partition->pt_id,

drivers/hv/mshv_root_main.c

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -611,7 +611,6 @@ mshv_partition_region_by_gfn(struct mshv_partition *partition, u64 gfn)
611611
return NULL;
612612
}
613613

614-
#ifdef CONFIG_X86_64
615614
static struct mshv_mem_region *
616615
mshv_partition_region_by_gfn_get(struct mshv_partition *p, u64 gfn)
617616
{
@@ -643,12 +642,17 @@ static bool mshv_handle_gpa_intercept(struct mshv_vp *vp)
643642
{
644643
struct mshv_partition *p = vp->vp_partition;
645644
struct mshv_mem_region *region;
646-
struct hv_x64_memory_intercept_message *msg;
647645
bool ret;
648646
u64 gfn;
649-
650-
msg = (struct hv_x64_memory_intercept_message *)
647+
#if defined(CONFIG_X86_64)
648+
struct hv_x64_memory_intercept_message *msg =
649+
(struct hv_x64_memory_intercept_message *)
650+
vp->vp_intercept_msg_page->u.payload;
651+
#elif defined(CONFIG_ARM64)
652+
struct hv_arm64_memory_intercept_message *msg =
653+
(struct hv_arm64_memory_intercept_message *)
651654
vp->vp_intercept_msg_page->u.payload;
655+
#endif
652656

653657
gfn = HVPFN_DOWN(msg->guest_physical_address);
654658

@@ -666,9 +670,6 @@ static bool mshv_handle_gpa_intercept(struct mshv_vp *vp)
666670

667671
return ret;
668672
}
669-
#else /* CONFIG_X86_64 */
670-
static bool mshv_handle_gpa_intercept(struct mshv_vp *vp) { return false; }
671-
#endif /* CONFIG_X86_64 */
672673

673674
static bool mshv_vp_handle_intercept(struct mshv_vp *vp)
674675
{
@@ -1280,7 +1281,7 @@ mshv_map_user_memory(struct mshv_partition *partition,
12801281
long ret;
12811282

12821283
if (mem.flags & BIT(MSHV_SET_MEM_BIT_UNMAP) ||
1283-
!access_ok((const void *)mem.userspace_addr, mem.size))
1284+
!access_ok((const void __user *)mem.userspace_addr, mem.size))
12841285
return -EINVAL;
12851286

12861287
mmap_read_lock(current->mm);

include/hyperv/hvhdk.h

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -800,6 +800,53 @@ struct hv_x64_memory_intercept_message {
800800
u8 instruction_bytes[16];
801801
} __packed;
802802

803+
#if IS_ENABLED(CONFIG_ARM64)
804+
union hv_arm64_vp_execution_state {
805+
u16 as_uint16;
806+
struct {
807+
u16 cpl:2; /* Exception Level (EL) */
808+
u16 debug_active:1;
809+
u16 interruption_pending:1;
810+
u16 vtl:4;
811+
u16 virtualization_fault_active:1;
812+
u16 reserved:7;
813+
} __packed;
814+
};
815+
816+
struct hv_arm64_intercept_message_header {
817+
u32 vp_index;
818+
u8 instruction_length;
819+
u8 intercept_access_type;
820+
union hv_arm64_vp_execution_state execution_state;
821+
u64 pc;
822+
u64 cpsr;
823+
} __packed;
824+
825+
union hv_arm64_memory_access_info {
826+
u8 as_uint8;
827+
struct {
828+
u8 gva_valid:1;
829+
u8 gva_gpa_valid:1;
830+
u8 hypercall_output_pending:1;
831+
u8 reserved:5;
832+
} __packed;
833+
};
834+
835+
struct hv_arm64_memory_intercept_message {
836+
struct hv_arm64_intercept_message_header header;
837+
u32 cache_type; /* enum hv_cache_type */
838+
u8 instruction_byte_count;
839+
union hv_arm64_memory_access_info memory_access_info;
840+
u16 reserved1;
841+
u8 instruction_bytes[4];
842+
u32 reserved2;
843+
u64 guest_virtual_address;
844+
u64 guest_physical_address;
845+
u64 syndrome;
846+
} __packed;
847+
848+
#endif /* CONFIG_ARM64 */
849+
803850
/*
804851
* Dispatch state for the VP communicated by the hypervisor to the
805852
* VP-dispatching thread in the root on return from HVCALL_DISPATCH_VP.

0 commit comments

Comments
 (0)