Module Name: src Committed By: bouyer Date: Fri Jun 3 10:42:17 UTC 2022
Modified Files: src/sys/arch/xen/xen: xengnt.c Log Message: Restore (again) support for grant tables v1: pvshim doesn't support v2 (it doesn't even support GNTTABOP_set_version) some setups will likely require pvshim in the future. To generate a diff of this commit: cvs rdiff -u -r1.38 -r1.39 src/sys/arch/xen/xen/xengnt.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/arch/xen/xen/xengnt.c diff -u src/sys/arch/xen/xen/xengnt.c:1.38 src/sys/arch/xen/xen/xengnt.c:1.39 --- src/sys/arch/xen/xen/xengnt.c:1.38 Wed May 13 16:13:14 2020 +++ src/sys/arch/xen/xen/xengnt.c Fri Jun 3 10:42:17 2022 @@ -1,4 +1,4 @@ -/* $NetBSD: xengnt.c,v 1.38 2020/05/13 16:13:14 jdolecek Exp $ */ +/* $NetBSD: xengnt.c,v 1.39 2022/06/03 10:42:17 bouyer Exp $ */ /* * Copyright (c) 2006 Manuel Bouyer. @@ -26,7 +26,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: xengnt.c,v 1.38 2020/05/13 16:13:14 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: xengnt.c,v 1.39 2022/06/03 10:42:17 bouyer Exp $"); #include <sys/types.h> #include <sys/param.h> @@ -54,6 +54,10 @@ __KERNEL_RCSID(0, "$NetBSD: xengnt.c,v 1 /* External tools reserve first few grant table entries. */ #define NR_RESERVED_ENTRIES 8 +/* current supported version */ +int gnt_v = 0; +#define GNT_ISV1 (gnt_v == 1) +#define GNT_ISV2 (gnt_v == 2) /* Current number of frames making up the grant table */ int gnt_nr_grant_frames; /* Maximum number of frames that can make up the grant table */ @@ -67,11 +71,19 @@ int last_gnt_entry; #define XENGNT_NO_ENTRY 0xffffffff /* VM address of the grant table */ -#define NR_GRANT_ENTRIES_PER_PAGE (PAGE_SIZE / sizeof(grant_entry_v2_t)) +#define NR_GRANT_ENTRIES_PER_PAGE_V1 (PAGE_SIZE / sizeof(grant_entry_v1_t)) +#define NR_GRANT_ENTRIES_PER_PAGE_V2 (PAGE_SIZE / sizeof(grant_entry_v2_t)) +#define NR_GRANT_ENTRIES_PER_PAGE \ + ((gnt_v == 1) ? NR_GRANT_ENTRIES_PER_PAGE_V1 : NR_GRANT_ENTRIES_PER_PAGE_V2) #define NR_GRANT_STATUS_PER_PAGE (PAGE_SIZE / sizeof(grant_status_t)) -grant_entry_v2_t *grant_table; -/* Number of grant status frames */ +union { + grant_entry_v1_t *gntt_v1; + grant_entry_v2_t *gntt_v2; + void *gntt; +} grant_table; + +/* Number of grant status frames (v2 only)*/ int gnt_status_frames; grant_status_t *grant_status; @@ -81,6 +93,7 @@ static grant_ref_t xengnt_get_entry(void static void xengnt_free_entry(grant_ref_t); static int xengnt_more_entries(void); static int xengnt_map_status(void); +static bool xengnt_finish_init(void); void xengnt_init(void) @@ -90,6 +103,16 @@ xengnt_init(void) int nr_grant_entries; int i; + /* first try to see which version we support */ + struct gnttab_set_version gntversion; + gnt_v = gntversion.version = 2; + rc = HYPERVISOR_grant_table_op(GNTTABOP_set_version, &gntversion, 1); + if (rc < 0 || gntversion.version != 2) { + aprint_debug("GNTTABOP_set_version 2 failed (%d), " + "fall back to version 1\n", rc); + gnt_v = 1; + } + query.dom = DOMID_SELF; rc = HYPERVISOR_grant_table_op(GNTTABOP_query_size, &query, 1); if ((rc < 0) || (query.status != GNTST_okay)) @@ -105,9 +128,9 @@ xengnt_init(void) nr_grant_entries = gnt_max_grant_frames * NR_GRANT_ENTRIES_PER_PAGE; - grant_table = (void *)uvm_km_alloc(kernel_map, + grant_table.gntt = (void *)uvm_km_alloc(kernel_map, gnt_max_grant_frames * PAGE_SIZE, 0, UVM_KMF_VAONLY); - if (grant_table == NULL) + if (grant_table.gntt == NULL) panic("xengnt_init() table no VM space"); gnt_entries = kmem_alloc((nr_grant_entries + 1) * sizeof(grant_ref_t), @@ -115,16 +138,18 @@ xengnt_init(void) for (i = 0; i <= nr_grant_entries; i++) gnt_entries[i] = XENGNT_NO_ENTRY; - gnt_status_frames = - round_page(nr_grant_entries * sizeof(grant_status_t)) / PAGE_SIZE; - grant_status = (void *)uvm_km_alloc(kernel_map, - gnt_status_frames * PAGE_SIZE, 0, UVM_KMF_VAONLY); - if (grant_status == NULL) - panic("xengnt_init() status no VM space"); + if (GNT_ISV2) { + gnt_status_frames = + round_page(nr_grant_entries * sizeof(grant_status_t)) / PAGE_SIZE; + grant_status = (void *)uvm_km_alloc(kernel_map, + gnt_status_frames * PAGE_SIZE, 0, UVM_KMF_VAONLY); + if (grant_status == NULL) + panic("xengnt_init() status no VM space"); + } mutex_init(&grant_lock, MUTEX_DEFAULT, IPL_VM); - xengnt_resume(); + xengnt_finish_init(); } /* @@ -134,13 +159,29 @@ bool xengnt_resume(void) { int rc; - int previous_nr_grant_frames = gnt_nr_grant_frames; struct gnttab_set_version gntversion; - gntversion.version = 2; + KASSERT(gnt_v == 1 || gnt_v == 2); + gntversion.version = gnt_v; rc = HYPERVISOR_grant_table_op(GNTTABOP_set_version, &gntversion, 1); - if (rc < 0 || gntversion.version != 2) - panic("GNTTABOP_set_version 2 failed %d", rc); + + if (GNT_ISV2) { + if (rc < 0 || gntversion.version != 2) { + panic("GNTTABOP_set_version 2 failed %d", rc); + } + } else { + if (rc == 0 && gntversion.version != 1) { + panic("GNTTABOP_set_version 1 failed"); + } + } + + return xengnt_finish_init(); +} + +static bool +xengnt_finish_init(void) +{ + int previous_nr_grant_frames = gnt_nr_grant_frames; last_gnt_entry = 0; gnt_nr_grant_frames = 0; @@ -150,7 +191,8 @@ xengnt_resume(void) if (xengnt_more_entries() != 0) panic("xengnt_resume: can't restore grant frames"); } - xengnt_map_status(); + if (GNT_ISV2) + xengnt_map_status(); mutex_exit(&grant_lock); return true; } @@ -172,10 +214,12 @@ xengnt_suspend(void) { } /* Remove virtual => machine mapping for grant table */ - pmap_kremove((vaddr_t)grant_table, gnt_nr_grant_frames * PAGE_SIZE); + pmap_kremove((vaddr_t)grant_table.gntt, gnt_nr_grant_frames * PAGE_SIZE); - /* Remove virtual => machine mapping for status table */ - pmap_kremove((vaddr_t)grant_status, gnt_status_frames * PAGE_SIZE); + if (GNT_ISV2) { + /* Remove virtual => machine mapping for status table */ + pmap_kremove((vaddr_t)grant_status, gnt_status_frames * PAGE_SIZE); + } pmap_update(pmap_kernel()); mutex_exit(&grant_lock); @@ -191,6 +235,7 @@ xengnt_map_status(void) uint64_t *pages; size_t sz; KASSERT(mutex_owned(&grant_lock)); + KASSERT(GNT_ISV2); sz = gnt_status_frames * sizeof(*pages); pages = kmem_alloc(sz, KM_NOSLEEP); @@ -320,7 +365,7 @@ xengnt_more_entries(void) * map between grant_table addresses and the machine addresses of * the grant table frames */ - pmap_kenter_ma(((vaddr_t)grant_table) + gnt_nr_grant_frames * PAGE_SIZE, + pmap_kenter_ma(((vaddr_t)grant_table.gntt) + gnt_nr_grant_frames * PAGE_SIZE, ((paddr_t)pages[gnt_nr_grant_frames]) << PAGE_SHIFT, VM_PROT_WRITE, 0); pmap_update(pmap_kernel()); @@ -401,38 +446,79 @@ xengnt_grant_access(domid_t dom, paddr_t return ENOMEM; } - grant_table[*entryp].full_page.frame = ma >> PAGE_SHIFT; - grant_table[*entryp].hdr.domid = dom; - /* - * ensure that the above values reach global visibility - * before permitting frame's access (done when we set flags) - */ - xen_rmb(); - grant_table[*entryp].hdr.flags = - GTF_permit_access | (ro ? GTF_readonly : 0); + if (GNT_ISV2) { + grant_table.gntt_v2[*entryp].full_page.frame = ma >> PAGE_SHIFT; + grant_table.gntt_v2[*entryp].hdr.domid = dom; + /* + * ensure that the above values reach global visibility + * before permitting frame's access (done when we set flags) + */ + xen_rmb(); + grant_table.gntt_v2[*entryp].hdr.flags = + GTF_permit_access | (ro ? GTF_readonly : 0); + } else { + grant_table.gntt_v1[*entryp].frame = ma >> PAGE_SHIFT; + grant_table.gntt_v1[*entryp].domid = dom; + /* + * ensure that the above values reach global visibility + * before permitting frame's access (done when we set flags) + */ + xen_rmb(); + grant_table.gntt_v1[*entryp].flags = + GTF_permit_access | (ro ? GTF_readonly : 0); + } mutex_exit(&grant_lock); return 0; } +static inline uint16_t +xen_atomic_cmpxchg16(volatile uint16_t *ptr, uint16_t val, uint16_t newval) +{ + unsigned long result; + + __asm volatile(__LOCK_PREFIX + "cmpxchgw %w1,%2" + :"=a" (result) + :"q"(newval), "m" (*ptr), "0" (val) + :"memory"); + + return result; +} + void xengnt_revoke_access(grant_ref_t entry) { - grant_table[entry].hdr.flags = 0; - xen_mb(); /* Concurrent access by hypervisor */ + if (GNT_ISV2) { + grant_table.gntt_v2[entry].hdr.flags = 0; + xen_mb(); /* Concurrent access by hypervisor */ + + if (__predict_false( + (grant_status[entry] & (GTF_reading|GTF_writing)) != 0)) { + printf("xengnt_revoke_access(%u): still in use\n", + entry); + } else { + + /* + * The read of grant_status needs to have acquire + * semantics. + * Reads already have that on x86, so need only protect + * against compiler reordering. May need full barrier + * on other architectures. + */ + __insn_barrier(); + } + } else { + uint16_t flags, nflags; - if (__predict_false((grant_status[entry] & (GTF_reading|GTF_writing)) - != 0)) - printf("xengnt_revoke_access(%u): still in use\n", - entry); - else { + nflags = grant_table.gntt_v1[entry].flags; + + do { + if ((flags = nflags) & (GTF_reading|GTF_writing)) + panic("xengnt_revoke_access: still in use"); + nflags = xen_atomic_cmpxchg16( + &grant_table.gntt_v1[entry].flags, flags, 0); + } while (nflags != flags); - /* - * The read of grant_status needs to have acquire semantics. - * Reads already have that on x86, so need only protect - * against compiler reordering. May need full barrier - * on other architectures. - */ - __insn_barrier(); } xengnt_free_entry(entry); } @@ -440,5 +526,8 @@ xengnt_revoke_access(grant_ref_t entry) int xengnt_status(grant_ref_t entry) { - return grant_status[entry] & (GTF_reading|GTF_writing); + if (GNT_ISV2) + return grant_status[entry] & (GTF_reading|GTF_writing); + else + return (grant_table.gntt_v1[entry].flags & (GTF_reading|GTF_writing)); }