1551bc2a6Smrj /* 2551bc2a6Smrj * CDDL HEADER START 3551bc2a6Smrj * 4551bc2a6Smrj * The contents of this file are subject to the terms of the 5551bc2a6Smrj * Common Development and Distribution License (the "License"). 6551bc2a6Smrj * You may not use this file except in compliance with the License. 7551bc2a6Smrj * 8551bc2a6Smrj * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9551bc2a6Smrj * or http://www.opensolaris.org/os/licensing. 10551bc2a6Smrj * See the License for the specific language governing permissions 11551bc2a6Smrj * and limitations under the License. 12551bc2a6Smrj * 13551bc2a6Smrj * When distributing Covered Code, include this CDDL HEADER in each 14551bc2a6Smrj * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15551bc2a6Smrj * If applicable, add the following below this CDDL HEADER, with the 16551bc2a6Smrj * fields enclosed by brackets "[]" replaced with your own identifying 17551bc2a6Smrj * information: Portions Copyright [yyyy] [name of copyright owner] 18551bc2a6Smrj * 19551bc2a6Smrj * CDDL HEADER END 20551bc2a6Smrj */ 21551bc2a6Smrj 22551bc2a6Smrj /* 23a576ab5bSrab * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24551bc2a6Smrj * Use is subject to license terms. 25551bc2a6Smrj */ 26551bc2a6Smrj 27551bc2a6Smrj #pragma ident "%Z%%M% %I% %E% SMI" 28551bc2a6Smrj 29551bc2a6Smrj /* 30551bc2a6Smrj * gnttab.c 31551bc2a6Smrj * 32551bc2a6Smrj * Granting foreign access to our memory reservation. 33551bc2a6Smrj * 34a576ab5bSrab * Copyright (c) 2005-2006, Christopher Clark 35551bc2a6Smrj * Copyright (c) 2004-2005, K A Fraser 36551bc2a6Smrj * 37a576ab5bSrab * This program is free software; you can redistribute it and/or 38a576ab5bSrab * modify it under the terms of the GNU General Public License version 2 39a576ab5bSrab * as published by the Free Software Foundation; or, when distributed 40a576ab5bSrab * separately from the Linux kernel or incorporated into other 41a576ab5bSrab * software packages, subject to the following license: 42551bc2a6Smrj * 43551bc2a6Smrj * Permission is hereby granted, free of charge, to any person obtaining a copy 44551bc2a6Smrj * of this source file (the "Software"), to deal in the Software without 45551bc2a6Smrj * restriction, including without limitation the rights to use, copy, modify, 46551bc2a6Smrj * merge, publish, distribute, sublicense, and/or sell copies of the Software, 47551bc2a6Smrj * and to permit persons to whom the Software is furnished to do so, subject to 48551bc2a6Smrj * the following conditions: 49551bc2a6Smrj * 50551bc2a6Smrj * The above copyright notice and this permission notice shall be included in 51551bc2a6Smrj * all copies or substantial portions of the Software. 52551bc2a6Smrj * 53551bc2a6Smrj * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 54551bc2a6Smrj * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 55551bc2a6Smrj * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 56551bc2a6Smrj * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 57551bc2a6Smrj * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 58551bc2a6Smrj * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 59551bc2a6Smrj * IN THE SOFTWARE. 60551bc2a6Smrj */ 61551bc2a6Smrj 62551bc2a6Smrj #include <sys/types.h> 63551bc2a6Smrj #include <sys/archsystm.h> 64551bc2a6Smrj #ifdef XPV_HVM_DRIVER 65551bc2a6Smrj #include <sys/xpv_support.h> 66551bc2a6Smrj #include <sys/mman.h> 67551bc2a6Smrj #include <vm/hat.h> 68551bc2a6Smrj #endif 69551bc2a6Smrj #include <sys/hypervisor.h> 70551bc2a6Smrj #include <sys/gnttab.h> 71551bc2a6Smrj #include <sys/sysmacros.h> 72551bc2a6Smrj #include <sys/machsystm.h> 73551bc2a6Smrj #include <sys/systm.h> 74551bc2a6Smrj #include <sys/mutex.h> 75551bc2a6Smrj #include <sys/atomic.h> 76551bc2a6Smrj #include <sys/spl.h> 77551bc2a6Smrj #include <sys/condvar.h> 78551bc2a6Smrj #include <sys/cpuvar.h> 79551bc2a6Smrj #include <sys/taskq.h> 80551bc2a6Smrj #include <sys/panic.h> 81551bc2a6Smrj #include <sys/cmn_err.h> 82551bc2a6Smrj #include <sys/promif.h> 83551bc2a6Smrj #include <sys/cpu.h> 84551bc2a6Smrj #include <sys/vmem.h> 85551bc2a6Smrj #include <vm/hat_i86.h> 86551bc2a6Smrj #include <sys/bootconf.h> 87551bc2a6Smrj #include <sys/bootsvcs.h> 88551bc2a6Smrj #ifndef XPV_HVM_DRIVER 89551bc2a6Smrj #include <sys/bootinfo.h> 90551bc2a6Smrj #include <sys/multiboot.h> 91551bc2a6Smrj #include <vm/kboot_mmu.h> 92551bc2a6Smrj #endif 93551bc2a6Smrj #include <sys/bootvfs.h> 94551bc2a6Smrj #include <sys/bootprops.h> 95551bc2a6Smrj #include <vm/seg_kmem.h> 96a576ab5bSrab #include <sys/mman.h> 97551bc2a6Smrj 98a576ab5bSrab /* Globals */ 99551bc2a6Smrj 100a576ab5bSrab static grant_ref_t **gnttab_list; 101a576ab5bSrab static uint_t nr_grant_frames; 102551bc2a6Smrj static int gnttab_free_count; 103551bc2a6Smrj static grant_ref_t gnttab_free_head; 104551bc2a6Smrj static kmutex_t gnttab_list_lock; 105551bc2a6Smrj static grant_entry_t *shared; 106a576ab5bSrab static struct gnttab_free_callback *gnttab_free_callback_list; 107551bc2a6Smrj 108a576ab5bSrab /* Macros */ 109551bc2a6Smrj 110a576ab5bSrab #define GT_PGADDR(i) ((uintptr_t)shared + ((i) << MMU_PAGESHIFT)) 111a576ab5bSrab #define VALID_GRANT_REF(r) ((r) < (nr_grant_frames * GREFS_PER_GRANT_FRAME)) 112a576ab5bSrab #define RPP (PAGESIZE / sizeof (grant_ref_t)) 113a576ab5bSrab #define GNTTAB_ENTRY(entry) (gnttab_list[(entry) / RPP][(entry) % RPP]) 114a576ab5bSrab #define CMPXCHG(t, c, n) atomic_cas_16((t), (c), (n)) 115a576ab5bSrab /* External tools reserve first few grant table entries. */ 116a576ab5bSrab #define NR_RESERVED_ENTRIES 8 117a576ab5bSrab #define GNTTAB_LIST_END 0xffffffff 118a576ab5bSrab #define GREFS_PER_GRANT_FRAME (PAGESIZE / sizeof (grant_entry_t)) 119a576ab5bSrab 120a576ab5bSrab /* Implementation */ 121a576ab5bSrab 122a576ab5bSrab static uint_t 123a576ab5bSrab max_nr_grant_frames(void) 124551bc2a6Smrj { 125a576ab5bSrab struct gnttab_query_size query; 126a576ab5bSrab int rc; 127551bc2a6Smrj 128a576ab5bSrab query.dom = DOMID_SELF; 129551bc2a6Smrj 130a576ab5bSrab rc = HYPERVISOR_grant_table_op(GNTTABOP_query_size, &query, 1); 131a576ab5bSrab if ((rc < 0) || (query.status != GNTST_okay)) 132a576ab5bSrab return (4); /* Legacy max supported number of frames */ 133a576ab5bSrab 134a576ab5bSrab ASSERT(query.max_nr_frames); 135a576ab5bSrab return (query.max_nr_frames); 136a576ab5bSrab } 137551bc2a6Smrj 138551bc2a6Smrj static void 139551bc2a6Smrj do_free_callbacks(void) 140551bc2a6Smrj { 141551bc2a6Smrj struct gnttab_free_callback *callback, *next; 142551bc2a6Smrj 143551bc2a6Smrj callback = gnttab_free_callback_list; 144551bc2a6Smrj gnttab_free_callback_list = NULL; 145551bc2a6Smrj 146551bc2a6Smrj while (callback != NULL) { 147551bc2a6Smrj next = callback->next; 148551bc2a6Smrj if (gnttab_free_count >= callback->count) { 149551bc2a6Smrj callback->next = NULL; 150551bc2a6Smrj callback->fn(callback->arg); 151551bc2a6Smrj } else { 152551bc2a6Smrj callback->next = gnttab_free_callback_list; 153551bc2a6Smrj gnttab_free_callback_list = callback; 154551bc2a6Smrj } 155551bc2a6Smrj callback = next; 156551bc2a6Smrj } 157551bc2a6Smrj } 158551bc2a6Smrj 159551bc2a6Smrj static void 160551bc2a6Smrj check_free_callbacks(void) 161551bc2a6Smrj { 162551bc2a6Smrj if (gnttab_free_callback_list) 163551bc2a6Smrj do_free_callbacks(); 164551bc2a6Smrj } 165551bc2a6Smrj 166a576ab5bSrab static int 167a576ab5bSrab grow_gnttab_list(uint_t more_frames) 168a576ab5bSrab { 169a576ab5bSrab uint_t new_nr_grant_frames, extra_entries, i; 1701213c83cSgarypen uint_t nr_glist_frames, new_nr_glist_frames; 171a576ab5bSrab 172a576ab5bSrab ASSERT(MUTEX_HELD(&gnttab_list_lock)); 173a576ab5bSrab 174a576ab5bSrab new_nr_grant_frames = nr_grant_frames + more_frames; 175a576ab5bSrab extra_entries = more_frames * GREFS_PER_GRANT_FRAME; 176a576ab5bSrab 1771213c83cSgarypen nr_glist_frames = (nr_grant_frames * GREFS_PER_GRANT_FRAME + RPP - 1) 1781213c83cSgarypen / RPP; 1791213c83cSgarypen new_nr_glist_frames = (new_nr_grant_frames * GREFS_PER_GRANT_FRAME 1801213c83cSgarypen + RPP - 1) / RPP; 1811213c83cSgarypen for (i = nr_glist_frames; i < new_nr_glist_frames; i++) 182a576ab5bSrab gnttab_list[i] = kmem_alloc(PAGESIZE, KM_SLEEP); 183a576ab5bSrab 184a576ab5bSrab for (i = GREFS_PER_GRANT_FRAME * nr_grant_frames; 185a576ab5bSrab i < GREFS_PER_GRANT_FRAME * new_nr_grant_frames - 1; i++) 186a576ab5bSrab GNTTAB_ENTRY(i) = i + 1; 187a576ab5bSrab 188a576ab5bSrab GNTTAB_ENTRY(i) = gnttab_free_head; 189a576ab5bSrab gnttab_free_head = GREFS_PER_GRANT_FRAME * nr_grant_frames; 190a576ab5bSrab gnttab_free_count += extra_entries; 191a576ab5bSrab 192a576ab5bSrab nr_grant_frames = new_nr_grant_frames; 193a576ab5bSrab 194a576ab5bSrab check_free_callbacks(); 195a576ab5bSrab 196a576ab5bSrab return (0); 197a576ab5bSrab } 198a576ab5bSrab 199a576ab5bSrab static int 200a576ab5bSrab gnttab_expand(uint_t req_entries) 201a576ab5bSrab { 202a576ab5bSrab uint_t cur, extra; 203a576ab5bSrab 204a576ab5bSrab ASSERT(MUTEX_HELD(&gnttab_list_lock)); 205a576ab5bSrab 206a576ab5bSrab cur = nr_grant_frames; 207a576ab5bSrab extra = ((req_entries + (GREFS_PER_GRANT_FRAME - 1)) / 208a576ab5bSrab GREFS_PER_GRANT_FRAME); 209a576ab5bSrab if (cur + extra > max_nr_grant_frames()) 210a576ab5bSrab return (-1); 211a576ab5bSrab 212a576ab5bSrab return (grow_gnttab_list(extra)); 213a576ab5bSrab } 214a576ab5bSrab 215a576ab5bSrab static int 216a576ab5bSrab get_free_entries(int count) 217a576ab5bSrab { 218a576ab5bSrab int ref, rc; 219a576ab5bSrab grant_ref_t head; 220a576ab5bSrab 221a576ab5bSrab mutex_enter(&gnttab_list_lock); 222a576ab5bSrab if (gnttab_free_count < count && 223a576ab5bSrab ((rc = gnttab_expand(count - gnttab_free_count)) < 0)) { 224a576ab5bSrab mutex_exit(&gnttab_list_lock); 225a576ab5bSrab return (rc); 226a576ab5bSrab } 227a576ab5bSrab ref = head = gnttab_free_head; 228a576ab5bSrab gnttab_free_count -= count; 229a576ab5bSrab while (count-- > 1) 230a576ab5bSrab head = GNTTAB_ENTRY(head); 231a576ab5bSrab gnttab_free_head = GNTTAB_ENTRY(head); 232a576ab5bSrab GNTTAB_ENTRY(head) = GNTTAB_LIST_END; 233a576ab5bSrab mutex_exit(&gnttab_list_lock); 234a576ab5bSrab return (ref); 235a576ab5bSrab } 236a576ab5bSrab 237551bc2a6Smrj static void 238551bc2a6Smrj put_free_entry(grant_ref_t ref) 239551bc2a6Smrj { 240551bc2a6Smrj ASSERT(VALID_GRANT_REF(ref)); 241551bc2a6Smrj 242551bc2a6Smrj mutex_enter(&gnttab_list_lock); 243a576ab5bSrab GNTTAB_ENTRY(ref) = gnttab_free_head; 244551bc2a6Smrj gnttab_free_head = ref; 245551bc2a6Smrj gnttab_free_count++; 246551bc2a6Smrj check_free_callbacks(); 247551bc2a6Smrj mutex_exit(&gnttab_list_lock); 248551bc2a6Smrj } 249551bc2a6Smrj 250551bc2a6Smrj /* 251551bc2a6Smrj * Public grant-issuing interface functions 252551bc2a6Smrj */ 253551bc2a6Smrj 254551bc2a6Smrj int 255551bc2a6Smrj gnttab_grant_foreign_access(domid_t domid, gnttab_frame_t frame, int readonly) 256551bc2a6Smrj { 257551bc2a6Smrj int ref; 258551bc2a6Smrj 259a576ab5bSrab if ((ref = get_free_entries(1)) == -1) 260551bc2a6Smrj return (-1); 261551bc2a6Smrj 262551bc2a6Smrj ASSERT(VALID_GRANT_REF(ref)); 263551bc2a6Smrj 264551bc2a6Smrj shared[ref].frame = frame; 265551bc2a6Smrj shared[ref].domid = domid; 266551bc2a6Smrj membar_producer(); 267551bc2a6Smrj shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0); 268551bc2a6Smrj 269551bc2a6Smrj return (ref); 270551bc2a6Smrj } 271551bc2a6Smrj 272551bc2a6Smrj void 273551bc2a6Smrj gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid, 274551bc2a6Smrj gnttab_frame_t frame, int readonly) 275551bc2a6Smrj { 276551bc2a6Smrj ASSERT(VALID_GRANT_REF(ref)); 277551bc2a6Smrj 278551bc2a6Smrj shared[ref].frame = frame; 279551bc2a6Smrj shared[ref].domid = domid; 280551bc2a6Smrj membar_producer(); 281551bc2a6Smrj shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0); 282551bc2a6Smrj } 283551bc2a6Smrj 284551bc2a6Smrj 285551bc2a6Smrj int 286551bc2a6Smrj gnttab_query_foreign_access(grant_ref_t ref) 287551bc2a6Smrj { 288551bc2a6Smrj uint16_t nflags; 289551bc2a6Smrj 290551bc2a6Smrj ASSERT(VALID_GRANT_REF(ref)); 291551bc2a6Smrj 292551bc2a6Smrj nflags = shared[ref].flags; 293551bc2a6Smrj 294551bc2a6Smrj return (nflags & (GTF_reading|GTF_writing)); 295551bc2a6Smrj } 296551bc2a6Smrj 297551bc2a6Smrj /* ARGSUSED */ 298551bc2a6Smrj int 299551bc2a6Smrj gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly) 300551bc2a6Smrj { 301551bc2a6Smrj uint16_t flags, nflags; 302551bc2a6Smrj 303551bc2a6Smrj ASSERT(VALID_GRANT_REF(ref)); 304551bc2a6Smrj 305551bc2a6Smrj nflags = shared[ref].flags; 306551bc2a6Smrj do { 307551bc2a6Smrj if ((flags = nflags) & (GTF_reading|GTF_writing)) { 308551bc2a6Smrj cmn_err(CE_WARN, "g.e. still in use!"); 309551bc2a6Smrj return (0); 310551bc2a6Smrj } 311a576ab5bSrab } while ((nflags = CMPXCHG(&shared[ref].flags, flags, 0)) != flags); 312551bc2a6Smrj 313551bc2a6Smrj return (1); 314551bc2a6Smrj } 315551bc2a6Smrj 316551bc2a6Smrj void 317551bc2a6Smrj gnttab_end_foreign_access(grant_ref_t ref, int readonly, gnttab_frame_t page) 318551bc2a6Smrj { 319551bc2a6Smrj ASSERT(VALID_GRANT_REF(ref)); 320551bc2a6Smrj 321551bc2a6Smrj if (gnttab_end_foreign_access_ref(ref, readonly)) { 322551bc2a6Smrj put_free_entry(ref); 323551bc2a6Smrj /* 324551bc2a6Smrj * XXPV - we don't support freeing a page here 325551bc2a6Smrj */ 326551bc2a6Smrj if (page != 0) { 327551bc2a6Smrj cmn_err(CE_WARN, 328551bc2a6Smrj "gnttab_end_foreign_access_ref: using unsupported free_page interface"); 329551bc2a6Smrj /* free_page(page); */ 330551bc2a6Smrj } 331551bc2a6Smrj } else { 332551bc2a6Smrj /* 333551bc2a6Smrj * XXX This needs to be fixed so that the ref and page are 334551bc2a6Smrj * placed on a list to be freed up later. 335551bc2a6Smrj */ 336551bc2a6Smrj cmn_err(CE_WARN, "leaking g.e. and page still in use!"); 337551bc2a6Smrj } 338551bc2a6Smrj } 339551bc2a6Smrj 340551bc2a6Smrj int 341a576ab5bSrab gnttab_grant_foreign_transfer(domid_t domid, pfn_t pfn) 342551bc2a6Smrj { 343551bc2a6Smrj int ref; 344551bc2a6Smrj 345a576ab5bSrab if ((ref = get_free_entries(1)) == -1) 346551bc2a6Smrj return (-1); 347551bc2a6Smrj 348551bc2a6Smrj ASSERT(VALID_GRANT_REF(ref)); 349551bc2a6Smrj 350a576ab5bSrab gnttab_grant_foreign_transfer_ref(ref, domid, pfn); 351551bc2a6Smrj 352551bc2a6Smrj return (ref); 353551bc2a6Smrj } 354551bc2a6Smrj 355551bc2a6Smrj void 356a576ab5bSrab gnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid, pfn_t pfn) 357551bc2a6Smrj { 358551bc2a6Smrj ASSERT(VALID_GRANT_REF(ref)); 359551bc2a6Smrj 360a576ab5bSrab shared[ref].frame = pfn; 361551bc2a6Smrj shared[ref].domid = domid; 362551bc2a6Smrj membar_producer(); 363551bc2a6Smrj shared[ref].flags = GTF_accept_transfer; 364551bc2a6Smrj } 365551bc2a6Smrj 366551bc2a6Smrj gnttab_frame_t 367551bc2a6Smrj gnttab_end_foreign_transfer_ref(grant_ref_t ref) 368551bc2a6Smrj { 369551bc2a6Smrj gnttab_frame_t frame; 370551bc2a6Smrj uint16_t flags; 371551bc2a6Smrj 372551bc2a6Smrj ASSERT(VALID_GRANT_REF(ref)); 373551bc2a6Smrj 374551bc2a6Smrj /* 375551bc2a6Smrj * If a transfer is not even yet started, try to reclaim the grant 376551bc2a6Smrj * reference and return failure (== 0). 377551bc2a6Smrj */ 378551bc2a6Smrj while (!((flags = shared[ref].flags) & GTF_transfer_committed)) { 379a576ab5bSrab if (CMPXCHG(&shared[ref].flags, flags, 0) == flags) 380551bc2a6Smrj return (0); 381551bc2a6Smrj (void) HYPERVISOR_yield(); 382551bc2a6Smrj } 383551bc2a6Smrj 384551bc2a6Smrj /* If a transfer is in progress then wait until it is completed. */ 385551bc2a6Smrj while (!(flags & GTF_transfer_completed)) { 386551bc2a6Smrj flags = shared[ref].flags; 387551bc2a6Smrj (void) HYPERVISOR_yield(); 388551bc2a6Smrj } 389551bc2a6Smrj 390551bc2a6Smrj /* Read the frame number /after/ reading completion status. */ 391551bc2a6Smrj membar_consumer(); 392551bc2a6Smrj frame = shared[ref].frame; 393551bc2a6Smrj ASSERT(frame != 0); 394551bc2a6Smrj 395551bc2a6Smrj return (frame); 396551bc2a6Smrj } 397551bc2a6Smrj 398551bc2a6Smrj gnttab_frame_t 399551bc2a6Smrj gnttab_end_foreign_transfer(grant_ref_t ref) 400551bc2a6Smrj { 401551bc2a6Smrj gnttab_frame_t frame; 402551bc2a6Smrj 403551bc2a6Smrj ASSERT(VALID_GRANT_REF(ref)); 404551bc2a6Smrj 405551bc2a6Smrj frame = gnttab_end_foreign_transfer_ref(ref); 406551bc2a6Smrj put_free_entry(ref); 407551bc2a6Smrj return (frame); 408551bc2a6Smrj } 409551bc2a6Smrj 410551bc2a6Smrj void 411551bc2a6Smrj gnttab_free_grant_reference(grant_ref_t ref) 412551bc2a6Smrj { 413551bc2a6Smrj ASSERT(VALID_GRANT_REF(ref)); 414551bc2a6Smrj 415551bc2a6Smrj put_free_entry(ref); 416551bc2a6Smrj } 417551bc2a6Smrj 418551bc2a6Smrj void 419551bc2a6Smrj gnttab_free_grant_references(grant_ref_t head) 420551bc2a6Smrj { 421551bc2a6Smrj grant_ref_t ref; 422551bc2a6Smrj int count = 1; 423551bc2a6Smrj 424551bc2a6Smrj if (head == GNTTAB_LIST_END) 425551bc2a6Smrj return; 426551bc2a6Smrj mutex_enter(&gnttab_list_lock); 427551bc2a6Smrj ref = head; 428a576ab5bSrab while (GNTTAB_ENTRY(ref) != GNTTAB_LIST_END) { 429a576ab5bSrab ref = GNTTAB_ENTRY(ref); 430551bc2a6Smrj count++; 431551bc2a6Smrj } 432a576ab5bSrab GNTTAB_ENTRY(ref) = gnttab_free_head; 433551bc2a6Smrj gnttab_free_head = head; 434551bc2a6Smrj gnttab_free_count += count; 435551bc2a6Smrj check_free_callbacks(); 436551bc2a6Smrj mutex_exit(&gnttab_list_lock); 437551bc2a6Smrj } 438551bc2a6Smrj 439551bc2a6Smrj int 440551bc2a6Smrj gnttab_alloc_grant_references(uint16_t count, grant_ref_t *head) 441551bc2a6Smrj { 442551bc2a6Smrj int h = get_free_entries(count); 443551bc2a6Smrj 444551bc2a6Smrj if (h == -1) 445551bc2a6Smrj return (-1); 446551bc2a6Smrj 447551bc2a6Smrj *head = h; 448551bc2a6Smrj 449551bc2a6Smrj return (0); 450551bc2a6Smrj } 451551bc2a6Smrj 452551bc2a6Smrj int 453a576ab5bSrab gnttab_empty_grant_references(const grant_ref_t *private_head) 454a576ab5bSrab { 455a576ab5bSrab return (*private_head == GNTTAB_LIST_END); 456a576ab5bSrab } 457a576ab5bSrab 458a576ab5bSrab int 459551bc2a6Smrj gnttab_claim_grant_reference(grant_ref_t *private_head) 460551bc2a6Smrj { 461551bc2a6Smrj grant_ref_t g = *private_head; 462551bc2a6Smrj 463551bc2a6Smrj if (g == GNTTAB_LIST_END) 464551bc2a6Smrj return (-1); 465a576ab5bSrab *private_head = GNTTAB_ENTRY(g); 466551bc2a6Smrj return (g); 467551bc2a6Smrj } 468551bc2a6Smrj 469551bc2a6Smrj void 470551bc2a6Smrj gnttab_release_grant_reference(grant_ref_t *private_head, grant_ref_t release) 471551bc2a6Smrj { 472551bc2a6Smrj ASSERT(VALID_GRANT_REF(release)); 473551bc2a6Smrj 474a576ab5bSrab GNTTAB_ENTRY(release) = *private_head; 475551bc2a6Smrj *private_head = release; 476551bc2a6Smrj } 477551bc2a6Smrj 478551bc2a6Smrj void 479551bc2a6Smrj gnttab_request_free_callback(struct gnttab_free_callback *callback, 480551bc2a6Smrj void (*fn)(void *), void *arg, uint16_t count) 481551bc2a6Smrj { 482551bc2a6Smrj mutex_enter(&gnttab_list_lock); 483551bc2a6Smrj if (callback->next) 484551bc2a6Smrj goto out; 485551bc2a6Smrj callback->fn = fn; 486551bc2a6Smrj callback->arg = arg; 487551bc2a6Smrj callback->count = count; 488551bc2a6Smrj callback->next = gnttab_free_callback_list; 489551bc2a6Smrj gnttab_free_callback_list = callback; 490551bc2a6Smrj check_free_callbacks(); 491551bc2a6Smrj out: 492551bc2a6Smrj mutex_exit(&gnttab_list_lock); 493551bc2a6Smrj } 494551bc2a6Smrj 495a576ab5bSrab void 496a576ab5bSrab gnttab_cancel_free_callback(struct gnttab_free_callback *callback) 497a576ab5bSrab { 498a576ab5bSrab struct gnttab_free_callback **pcb; 499551bc2a6Smrj 500a576ab5bSrab mutex_enter(&gnttab_list_lock); 501a576ab5bSrab for (pcb = &gnttab_free_callback_list; *pcb; pcb = &(*pcb)->next) { 502a576ab5bSrab if (*pcb == callback) { 503a576ab5bSrab *pcb = callback->next; 504a576ab5bSrab break; 505a576ab5bSrab } 506a576ab5bSrab } 507a576ab5bSrab mutex_exit(&gnttab_list_lock); 508a576ab5bSrab } 509a576ab5bSrab 510a576ab5bSrab static gnttab_frame_t * 511a576ab5bSrab gnttab_setup(gnttab_setup_table_t *pset) 512a576ab5bSrab { 513a576ab5bSrab gnttab_frame_t *frames; 514a576ab5bSrab 515a576ab5bSrab frames = kmem_alloc(pset->nr_frames * sizeof (gnttab_frame_t), 516a576ab5bSrab KM_SLEEP); 517a576ab5bSrab 518a576ab5bSrab /*LINTED: constant in conditional context*/ 519a576ab5bSrab set_xen_guest_handle(pset->frame_list, frames); 520a576ab5bSrab 521*6eb35ee7Srab #ifndef XPV_HVM_DRIVER 522a576ab5bSrab /* 523a576ab5bSrab * Take pset->nr_frames pages of grant table space from 524a576ab5bSrab * the hypervisor and map it 525a576ab5bSrab */ 526a576ab5bSrab if ((HYPERVISOR_grant_table_op(GNTTABOP_setup_table, pset, 1) != 0) || 527a576ab5bSrab (pset->status != 0)) { 528a576ab5bSrab cmn_err(CE_PANIC, "Grant Table setup failed"); 529a576ab5bSrab } 530*6eb35ee7Srab #endif 531a576ab5bSrab 532a576ab5bSrab return (frames); 533a576ab5bSrab } 534a576ab5bSrab 535a576ab5bSrab #ifdef XPV_HVM_DRIVER 536551bc2a6Smrj static void 537551bc2a6Smrj gnttab_map(void) 538551bc2a6Smrj { 539551bc2a6Smrj struct xen_add_to_physmap xatp; 540551bc2a6Smrj caddr_t va; 541551bc2a6Smrj pfn_t pfn; 542551bc2a6Smrj int i; 543551bc2a6Smrj 544551bc2a6Smrj va = (caddr_t)shared; 545a576ab5bSrab for (i = 0; i < max_nr_grant_frames(); i++) { 546a576ab5bSrab if ((pfn = hat_getpfnum(kas.a_hat, va)) == PFN_INVALID) 547a576ab5bSrab cmn_err(CE_PANIC, "gnttab_map: Invalid pfn"); 548551bc2a6Smrj 549551bc2a6Smrj xatp.domid = DOMID_SELF; 550551bc2a6Smrj xatp.idx = i; 551551bc2a6Smrj xatp.space = XENMAPSPACE_grant_table; 552551bc2a6Smrj xatp.gpfn = pfn; 553551bc2a6Smrj hat_unload(kas.a_hat, va, MMU_PAGESIZE, HAT_UNLOAD); 554a576ab5bSrab /* 555a576ab5bSrab * This call replaces the existing machine page backing 556a576ab5bSrab * the given gpfn with the page from the allocated grant 557a576ab5bSrab * table at index idx. The existing machine page is 558a576ab5bSrab * returned to the free list. 559a576ab5bSrab */ 560551bc2a6Smrj if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp) != 0) 561551bc2a6Smrj panic("Couldn't map grant table"); 562551bc2a6Smrj hat_devload(kas.a_hat, va, MMU_PAGESIZE, pfn, 5635b1df0b5Sjohnlev PROT_READ | PROT_WRITE | HAT_STORECACHING_OK, 564551bc2a6Smrj HAT_LOAD | HAT_LOAD_LOCK | HAT_LOAD_NOCONSIST); 565551bc2a6Smrj va += MMU_PAGESIZE; 566551bc2a6Smrj } 567551bc2a6Smrj } 568a576ab5bSrab #endif /* XPV_HVM_DRIVER */ 569551bc2a6Smrj 570551bc2a6Smrj void 571551bc2a6Smrj gnttab_init(void) 572551bc2a6Smrj { 573a576ab5bSrab gnttab_setup_table_t set; 574551bc2a6Smrj int i; 5751213c83cSgarypen uint_t nr_init_grefs, max_nr_glist_frames, nr_glist_frames; 576a576ab5bSrab gnttab_frame_t *frames; 577551bc2a6Smrj 578a576ab5bSrab /* 579a576ab5bSrab * gnttab_init() should only be invoked once. 580a576ab5bSrab */ 581a576ab5bSrab mutex_enter(&gnttab_list_lock); 582a576ab5bSrab ASSERT(nr_grant_frames == 0); 583a576ab5bSrab nr_grant_frames = 1; 584a576ab5bSrab mutex_exit(&gnttab_list_lock); 585a576ab5bSrab 586a576ab5bSrab max_nr_glist_frames = (max_nr_grant_frames() * 5871213c83cSgarypen GREFS_PER_GRANT_FRAME / RPP); 588a576ab5bSrab 589a576ab5bSrab set.dom = DOMID_SELF; 590a576ab5bSrab set.nr_frames = max_nr_grant_frames(); 591a576ab5bSrab frames = gnttab_setup(&set); 592a576ab5bSrab 593a576ab5bSrab #ifdef XPV_HVM_DRIVER 594a576ab5bSrab shared = (grant_entry_t *)xen_alloc_pages(set.nr_frames); 595551bc2a6Smrj 596551bc2a6Smrj gnttab_map(); 597551bc2a6Smrj #else /* XPV_HVM_DRIVER */ 598a576ab5bSrab shared = vmem_xalloc(heap_arena, set.nr_frames * MMU_PAGESIZE, 599a576ab5bSrab MMU_PAGESIZE, 0, 0, 0, 0, VM_SLEEP); 600a576ab5bSrab for (i = 0; i < set.nr_frames; i++) { 601a576ab5bSrab hat_devload(kas.a_hat, (caddr_t)GT_PGADDR(i), PAGESIZE, 6025b1df0b5Sjohnlev xen_assign_pfn(frames[i]), 6035b1df0b5Sjohnlev PROT_READ | PROT_WRITE | HAT_STORECACHING_OK, 604a576ab5bSrab HAT_LOAD_LOCK); 605a576ab5bSrab } 606a576ab5bSrab #endif 607551bc2a6Smrj 608a576ab5bSrab gnttab_list = kmem_alloc(max_nr_glist_frames * sizeof (grant_ref_t *), 609a576ab5bSrab KM_SLEEP); 610551bc2a6Smrj 6111213c83cSgarypen nr_glist_frames = (nr_grant_frames * GREFS_PER_GRANT_FRAME + RPP - 1) 6121213c83cSgarypen / RPP; 6131213c83cSgarypen for (i = 0; i < nr_glist_frames; i++) { 614a576ab5bSrab gnttab_list[i] = kmem_alloc(PAGESIZE, KM_SLEEP); 615551bc2a6Smrj } 616551bc2a6Smrj 617a576ab5bSrab kmem_free(frames, set.nr_frames * sizeof (gnttab_frame_t)); 618551bc2a6Smrj 619a576ab5bSrab nr_init_grefs = nr_grant_frames * GREFS_PER_GRANT_FRAME; 620551bc2a6Smrj 621a576ab5bSrab for (i = NR_RESERVED_ENTRIES; i < nr_init_grefs - 1; i++) 622a576ab5bSrab GNTTAB_ENTRY(i) = i + 1; 623a576ab5bSrab 624a576ab5bSrab GNTTAB_ENTRY(nr_init_grefs - 1) = GNTTAB_LIST_END; 625a576ab5bSrab gnttab_free_count = nr_init_grefs - NR_RESERVED_ENTRIES; 626551bc2a6Smrj gnttab_free_head = NR_RESERVED_ENTRIES; 627551bc2a6Smrj } 628551bc2a6Smrj 629551bc2a6Smrj void 630551bc2a6Smrj gnttab_resume(void) 631551bc2a6Smrj { 632551bc2a6Smrj gnttab_setup_table_t set; 633551bc2a6Smrj int i; 634a576ab5bSrab gnttab_frame_t *frames; 635a576ab5bSrab uint_t available_frames = max_nr_grant_frames(); 636551bc2a6Smrj 637a576ab5bSrab if (available_frames < nr_grant_frames) { 638a576ab5bSrab cmn_err(CE_PANIC, "Hypervisor does not have enough grant " 639a576ab5bSrab "frames: required(%u), available(%u)", nr_grant_frames, 640a576ab5bSrab available_frames); 641551bc2a6Smrj } 642551bc2a6Smrj 643a576ab5bSrab #ifdef XPV_HVM_DRIVER 644a576ab5bSrab gnttab_map(); 645a576ab5bSrab #endif /* XPV_HVM_DRIVER */ 646a576ab5bSrab 647a576ab5bSrab set.dom = DOMID_SELF; 648a576ab5bSrab set.nr_frames = available_frames; 649a576ab5bSrab frames = gnttab_setup(&set); 650a576ab5bSrab 651a576ab5bSrab for (i = 0; i < available_frames; i++) { 652551bc2a6Smrj (void) HYPERVISOR_update_va_mapping(GT_PGADDR(i), 653551bc2a6Smrj FRAME_TO_MA(frames[i]) | PT_VALID | PT_WRITABLE, 654551bc2a6Smrj UVMF_INVLPG | UVMF_ALL); 655551bc2a6Smrj } 656a576ab5bSrab kmem_free(frames, set.nr_frames * sizeof (gnttab_frame_t)); 657551bc2a6Smrj } 658551bc2a6Smrj 659551bc2a6Smrj void 660551bc2a6Smrj gnttab_suspend(void) 661551bc2a6Smrj { 662551bc2a6Smrj int i; 663551bc2a6Smrj 664551bc2a6Smrj /* 665551bc2a6Smrj * clear grant table mappings before suspending 666551bc2a6Smrj */ 667a576ab5bSrab for (i = 0; i < max_nr_grant_frames(); i++) { 668551bc2a6Smrj (void) HYPERVISOR_update_va_mapping(GT_PGADDR(i), 669551bc2a6Smrj 0, UVMF_INVLPG); 670551bc2a6Smrj } 671551bc2a6Smrj } 672551bc2a6Smrj 673551bc2a6Smrj /* 674551bc2a6Smrj * Local variables: 675551bc2a6Smrj * c-file-style: "solaris" 676551bc2a6Smrj * indent-tabs-mode: t 677551bc2a6Smrj * c-indent-level: 8 678551bc2a6Smrj * c-basic-offset: 8 679551bc2a6Smrj * tab-width: 8 680551bc2a6Smrj * End: 681551bc2a6Smrj */ 682