15741Smrj /*
25741Smrj * CDDL HEADER START
35741Smrj *
45741Smrj * The contents of this file are subject to the terms of the
55741Smrj * Common Development and Distribution License (the "License").
65741Smrj * You may not use this file except in compliance with the License.
75741Smrj *
85741Smrj * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95741Smrj * or http://www.opensolaris.org/os/licensing.
105741Smrj * See the License for the specific language governing permissions
115741Smrj * and limitations under the License.
125741Smrj *
135741Smrj * When distributing Covered Code, include this CDDL HEADER in each
145741Smrj * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155741Smrj * If applicable, add the following below this CDDL HEADER, with the
165741Smrj * fields enclosed by brackets "[]" replaced with your own identifying
175741Smrj * information: Portions Copyright [yyyy] [name of copyright owner]
185741Smrj *
195741Smrj * CDDL HEADER END
205741Smrj */
215741Smrj
225741Smrj /*
236144Srab * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
245741Smrj * Use is subject to license terms.
255741Smrj */
265741Smrj
275741Smrj #pragma ident "%Z%%M% %I% %E% SMI"
285741Smrj
295741Smrj /*
305741Smrj * gnttab.c
315741Smrj *
325741Smrj * Granting foreign access to our memory reservation.
335741Smrj *
346144Srab * Copyright (c) 2005-2006, Christopher Clark
355741Smrj * Copyright (c) 2004-2005, K A Fraser
365741Smrj *
376144Srab * This program is free software; you can redistribute it and/or
386144Srab * modify it under the terms of the GNU General Public License version 2
396144Srab * as published by the Free Software Foundation; or, when distributed
406144Srab * separately from the Linux kernel or incorporated into other
416144Srab * software packages, subject to the following license:
425741Smrj *
435741Smrj * Permission is hereby granted, free of charge, to any person obtaining a copy
445741Smrj * of this source file (the "Software"), to deal in the Software without
455741Smrj * restriction, including without limitation the rights to use, copy, modify,
465741Smrj * merge, publish, distribute, sublicense, and/or sell copies of the Software,
475741Smrj * and to permit persons to whom the Software is furnished to do so, subject to
485741Smrj * the following conditions:
495741Smrj *
505741Smrj * The above copyright notice and this permission notice shall be included in
515741Smrj * all copies or substantial portions of the Software.
525741Smrj *
535741Smrj * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
545741Smrj * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
555741Smrj * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
565741Smrj * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
575741Smrj * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
585741Smrj * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
595741Smrj * IN THE SOFTWARE.
605741Smrj */
615741Smrj
625741Smrj #include <sys/types.h>
635741Smrj #include <sys/archsystm.h>
645741Smrj #ifdef XPV_HVM_DRIVER
655741Smrj #include <sys/xpv_support.h>
665741Smrj #include <sys/mman.h>
675741Smrj #include <vm/hat.h>
685741Smrj #endif
695741Smrj #include <sys/hypervisor.h>
705741Smrj #include <sys/gnttab.h>
715741Smrj #include <sys/sysmacros.h>
725741Smrj #include <sys/machsystm.h>
735741Smrj #include <sys/systm.h>
745741Smrj #include <sys/mutex.h>
755741Smrj #include <sys/atomic.h>
765741Smrj #include <sys/spl.h>
775741Smrj #include <sys/condvar.h>
785741Smrj #include <sys/cpuvar.h>
795741Smrj #include <sys/taskq.h>
805741Smrj #include <sys/panic.h>
815741Smrj #include <sys/cmn_err.h>
825741Smrj #include <sys/promif.h>
835741Smrj #include <sys/cpu.h>
845741Smrj #include <sys/vmem.h>
855741Smrj #include <vm/hat_i86.h>
865741Smrj #include <sys/bootconf.h>
875741Smrj #include <sys/bootsvcs.h>
885741Smrj #ifndef XPV_HVM_DRIVER
895741Smrj #include <sys/bootinfo.h>
905741Smrj #include <sys/multiboot.h>
915741Smrj #include <vm/kboot_mmu.h>
925741Smrj #endif
935741Smrj #include <sys/bootvfs.h>
945741Smrj #include <sys/bootprops.h>
955741Smrj #include <vm/seg_kmem.h>
966144Srab #include <sys/mman.h>
975741Smrj
986144Srab /* Globals */
995741Smrj
1006144Srab static grant_ref_t **gnttab_list;
1016144Srab static uint_t nr_grant_frames;
1025741Smrj static int gnttab_free_count;
1035741Smrj static grant_ref_t gnttab_free_head;
1045741Smrj static kmutex_t gnttab_list_lock;
1056144Srab static grant_entry_t *shared;
1066144Srab static struct gnttab_free_callback *gnttab_free_callback_list;
1075741Smrj
1086144Srab /* Macros */
1095741Smrj
1106144Srab #define GT_PGADDR(i) ((uintptr_t)shared + ((i) << MMU_PAGESHIFT))
1116144Srab #define VALID_GRANT_REF(r) ((r) < (nr_grant_frames * GREFS_PER_GRANT_FRAME))
1126144Srab #define RPP (PAGESIZE / sizeof (grant_ref_t))
1136144Srab #define GNTTAB_ENTRY(entry) (gnttab_list[(entry) / RPP][(entry) % RPP])
1146144Srab #define CMPXCHG(t, c, n) atomic_cas_16((t), (c), (n))
1156144Srab /* External tools reserve first few grant table entries. */
1166144Srab #define NR_RESERVED_ENTRIES 8
1176144Srab #define GNTTAB_LIST_END 0xffffffff
1186144Srab #define GREFS_PER_GRANT_FRAME (PAGESIZE / sizeof (grant_entry_t))
1195741Smrj
1206144Srab /* Implementation */
1216144Srab
1226144Srab static uint_t
max_nr_grant_frames(void)1236144Srab max_nr_grant_frames(void)
1246144Srab {
1256144Srab struct gnttab_query_size query;
1266144Srab int rc;
1276144Srab
1286144Srab query.dom = DOMID_SELF;
1296144Srab
1306144Srab rc = HYPERVISOR_grant_table_op(GNTTABOP_query_size, &query, 1);
1316144Srab if ((rc < 0) || (query.status != GNTST_okay))
1326144Srab return (4); /* Legacy max supported number of frames */
1336144Srab
1346144Srab ASSERT(query.max_nr_frames);
1356144Srab return (query.max_nr_frames);
1365741Smrj }
1375741Smrj
1385741Smrj static void
do_free_callbacks(void)1395741Smrj do_free_callbacks(void)
1405741Smrj {
1415741Smrj struct gnttab_free_callback *callback, *next;
1425741Smrj
1435741Smrj callback = gnttab_free_callback_list;
1445741Smrj gnttab_free_callback_list = NULL;
1455741Smrj
1465741Smrj while (callback != NULL) {
1475741Smrj next = callback->next;
1485741Smrj if (gnttab_free_count >= callback->count) {
1495741Smrj callback->next = NULL;
1505741Smrj callback->fn(callback->arg);
1515741Smrj } else {
1525741Smrj callback->next = gnttab_free_callback_list;
1535741Smrj gnttab_free_callback_list = callback;
1545741Smrj }
1555741Smrj callback = next;
1565741Smrj }
1575741Smrj }
1585741Smrj
1595741Smrj static void
check_free_callbacks(void)1605741Smrj check_free_callbacks(void)
1615741Smrj {
1625741Smrj if (gnttab_free_callback_list)
1635741Smrj do_free_callbacks();
1645741Smrj }
1655741Smrj
1666144Srab static int
grow_gnttab_list(uint_t more_frames)1676144Srab grow_gnttab_list(uint_t more_frames)
1686144Srab {
1696144Srab uint_t new_nr_grant_frames, extra_entries, i;
1706415Sgarypen uint_t nr_glist_frames, new_nr_glist_frames;
1716144Srab
1726144Srab ASSERT(MUTEX_HELD(&gnttab_list_lock));
1736144Srab
1746144Srab new_nr_grant_frames = nr_grant_frames + more_frames;
1756144Srab extra_entries = more_frames * GREFS_PER_GRANT_FRAME;
1766144Srab
1776415Sgarypen nr_glist_frames = (nr_grant_frames * GREFS_PER_GRANT_FRAME + RPP - 1)
1786415Sgarypen / RPP;
1796415Sgarypen new_nr_glist_frames = (new_nr_grant_frames * GREFS_PER_GRANT_FRAME
1806415Sgarypen + RPP - 1) / RPP;
1816415Sgarypen for (i = nr_glist_frames; i < new_nr_glist_frames; i++)
1826144Srab gnttab_list[i] = kmem_alloc(PAGESIZE, KM_SLEEP);
1836144Srab
1846144Srab for (i = GREFS_PER_GRANT_FRAME * nr_grant_frames;
1856144Srab i < GREFS_PER_GRANT_FRAME * new_nr_grant_frames - 1; i++)
1866144Srab GNTTAB_ENTRY(i) = i + 1;
1876144Srab
1886144Srab GNTTAB_ENTRY(i) = gnttab_free_head;
1896144Srab gnttab_free_head = GREFS_PER_GRANT_FRAME * nr_grant_frames;
1906144Srab gnttab_free_count += extra_entries;
1916144Srab
1926144Srab nr_grant_frames = new_nr_grant_frames;
1936144Srab
1946144Srab check_free_callbacks();
1956144Srab
1966144Srab return (0);
1976144Srab }
1986144Srab
1996144Srab static int
gnttab_expand(uint_t req_entries)2006144Srab gnttab_expand(uint_t req_entries)
2016144Srab {
2026144Srab uint_t cur, extra;
2036144Srab
2046144Srab ASSERT(MUTEX_HELD(&gnttab_list_lock));
2056144Srab
2066144Srab cur = nr_grant_frames;
2076144Srab extra = ((req_entries + (GREFS_PER_GRANT_FRAME - 1)) /
2086144Srab GREFS_PER_GRANT_FRAME);
2096144Srab if (cur + extra > max_nr_grant_frames())
2106144Srab return (-1);
2116144Srab
2126144Srab return (grow_gnttab_list(extra));
2136144Srab }
2146144Srab
2156144Srab static int
get_free_entries(int count)2166144Srab get_free_entries(int count)
2176144Srab {
2186144Srab int ref, rc;
2196144Srab grant_ref_t head;
2206144Srab
2216144Srab mutex_enter(&gnttab_list_lock);
2226144Srab if (gnttab_free_count < count &&
2236144Srab ((rc = gnttab_expand(count - gnttab_free_count)) < 0)) {
2246144Srab mutex_exit(&gnttab_list_lock);
2256144Srab return (rc);
2266144Srab }
2276144Srab ref = head = gnttab_free_head;
2286144Srab gnttab_free_count -= count;
2296144Srab while (count-- > 1)
2306144Srab head = GNTTAB_ENTRY(head);
2316144Srab gnttab_free_head = GNTTAB_ENTRY(head);
2326144Srab GNTTAB_ENTRY(head) = GNTTAB_LIST_END;
2336144Srab mutex_exit(&gnttab_list_lock);
2346144Srab return (ref);
2356144Srab }
2366144Srab
2375741Smrj static void
put_free_entry(grant_ref_t ref)2385741Smrj put_free_entry(grant_ref_t ref)
2395741Smrj {
2405741Smrj ASSERT(VALID_GRANT_REF(ref));
2415741Smrj
2425741Smrj mutex_enter(&gnttab_list_lock);
2436144Srab GNTTAB_ENTRY(ref) = gnttab_free_head;
2445741Smrj gnttab_free_head = ref;
2455741Smrj gnttab_free_count++;
2465741Smrj check_free_callbacks();
2475741Smrj mutex_exit(&gnttab_list_lock);
2485741Smrj }
2495741Smrj
2505741Smrj /*
2515741Smrj * Public grant-issuing interface functions
2525741Smrj */
2535741Smrj
2545741Smrj int
gnttab_grant_foreign_access(domid_t domid,gnttab_frame_t frame,int readonly)2555741Smrj gnttab_grant_foreign_access(domid_t domid, gnttab_frame_t frame, int readonly)
2565741Smrj {
2575741Smrj int ref;
2585741Smrj
2596144Srab if ((ref = get_free_entries(1)) == -1)
2605741Smrj return (-1);
2615741Smrj
2625741Smrj ASSERT(VALID_GRANT_REF(ref));
2635741Smrj
2645741Smrj shared[ref].frame = frame;
2655741Smrj shared[ref].domid = domid;
2665741Smrj membar_producer();
2675741Smrj shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0);
2685741Smrj
2695741Smrj return (ref);
2705741Smrj }
2715741Smrj
2725741Smrj void
gnttab_grant_foreign_access_ref(grant_ref_t ref,domid_t domid,gnttab_frame_t frame,int readonly)2735741Smrj gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid,
2745741Smrj gnttab_frame_t frame, int readonly)
2755741Smrj {
2765741Smrj ASSERT(VALID_GRANT_REF(ref));
2775741Smrj
2785741Smrj shared[ref].frame = frame;
2795741Smrj shared[ref].domid = domid;
2805741Smrj membar_producer();
2815741Smrj shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0);
2825741Smrj }
2835741Smrj
2845741Smrj
2855741Smrj int
gnttab_query_foreign_access(grant_ref_t ref)2865741Smrj gnttab_query_foreign_access(grant_ref_t ref)
2875741Smrj {
2885741Smrj uint16_t nflags;
2895741Smrj
2905741Smrj ASSERT(VALID_GRANT_REF(ref));
2915741Smrj
2925741Smrj nflags = shared[ref].flags;
2935741Smrj
2945741Smrj return (nflags & (GTF_reading|GTF_writing));
2955741Smrj }
2965741Smrj
2975741Smrj /* ARGSUSED */
2985741Smrj int
gnttab_end_foreign_access_ref(grant_ref_t ref,int readonly)2995741Smrj gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly)
3005741Smrj {
3015741Smrj uint16_t flags, nflags;
3025741Smrj
3035741Smrj ASSERT(VALID_GRANT_REF(ref));
3045741Smrj
3055741Smrj nflags = shared[ref].flags;
3065741Smrj do {
3075741Smrj if ((flags = nflags) & (GTF_reading|GTF_writing)) {
3085741Smrj cmn_err(CE_WARN, "g.e. still in use!");
3095741Smrj return (0);
3105741Smrj }
3116144Srab } while ((nflags = CMPXCHG(&shared[ref].flags, flags, 0)) != flags);
3125741Smrj
3135741Smrj return (1);
3145741Smrj }
3155741Smrj
3165741Smrj void
gnttab_end_foreign_access(grant_ref_t ref,int readonly,gnttab_frame_t page)3175741Smrj gnttab_end_foreign_access(grant_ref_t ref, int readonly, gnttab_frame_t page)
3185741Smrj {
3195741Smrj ASSERT(VALID_GRANT_REF(ref));
3205741Smrj
3215741Smrj if (gnttab_end_foreign_access_ref(ref, readonly)) {
3225741Smrj put_free_entry(ref);
3235741Smrj /*
3245741Smrj * XXPV - we don't support freeing a page here
3255741Smrj */
3265741Smrj if (page != 0) {
3275741Smrj cmn_err(CE_WARN,
3285741Smrj "gnttab_end_foreign_access_ref: using unsupported free_page interface");
3295741Smrj /* free_page(page); */
3305741Smrj }
3315741Smrj } else {
3325741Smrj /*
3335741Smrj * XXX This needs to be fixed so that the ref and page are
3345741Smrj * placed on a list to be freed up later.
3355741Smrj */
3365741Smrj cmn_err(CE_WARN, "leaking g.e. and page still in use!");
3375741Smrj }
3385741Smrj }
3395741Smrj
3405741Smrj int
gnttab_grant_foreign_transfer(domid_t domid,pfn_t pfn)3416144Srab gnttab_grant_foreign_transfer(domid_t domid, pfn_t pfn)
3425741Smrj {
3435741Smrj int ref;
3445741Smrj
3456144Srab if ((ref = get_free_entries(1)) == -1)
3465741Smrj return (-1);
3475741Smrj
3485741Smrj ASSERT(VALID_GRANT_REF(ref));
3495741Smrj
3506144Srab gnttab_grant_foreign_transfer_ref(ref, domid, pfn);
3515741Smrj
3525741Smrj return (ref);
3535741Smrj }
3545741Smrj
3555741Smrj void
gnttab_grant_foreign_transfer_ref(grant_ref_t ref,domid_t domid,pfn_t pfn)3566144Srab gnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid, pfn_t pfn)
3575741Smrj {
3585741Smrj ASSERT(VALID_GRANT_REF(ref));
3595741Smrj
3606144Srab shared[ref].frame = pfn;
3615741Smrj shared[ref].domid = domid;
3625741Smrj membar_producer();
3635741Smrj shared[ref].flags = GTF_accept_transfer;
3645741Smrj }
3655741Smrj
3665741Smrj gnttab_frame_t
gnttab_end_foreign_transfer_ref(grant_ref_t ref)3675741Smrj gnttab_end_foreign_transfer_ref(grant_ref_t ref)
3685741Smrj {
3695741Smrj gnttab_frame_t frame;
3705741Smrj uint16_t flags;
3715741Smrj
3725741Smrj ASSERT(VALID_GRANT_REF(ref));
3735741Smrj
3745741Smrj /*
3755741Smrj * If a transfer is not even yet started, try to reclaim the grant
3765741Smrj * reference and return failure (== 0).
3775741Smrj */
3785741Smrj while (!((flags = shared[ref].flags) & GTF_transfer_committed)) {
3796144Srab if (CMPXCHG(&shared[ref].flags, flags, 0) == flags)
3805741Smrj return (0);
3815741Smrj (void) HYPERVISOR_yield();
3825741Smrj }
3835741Smrj
3845741Smrj /* If a transfer is in progress then wait until it is completed. */
3855741Smrj while (!(flags & GTF_transfer_completed)) {
3865741Smrj flags = shared[ref].flags;
3875741Smrj (void) HYPERVISOR_yield();
3885741Smrj }
3895741Smrj
3905741Smrj /* Read the frame number /after/ reading completion status. */
3915741Smrj membar_consumer();
3925741Smrj frame = shared[ref].frame;
3935741Smrj ASSERT(frame != 0);
3945741Smrj
3955741Smrj return (frame);
3965741Smrj }
3975741Smrj
3985741Smrj gnttab_frame_t
gnttab_end_foreign_transfer(grant_ref_t ref)3995741Smrj gnttab_end_foreign_transfer(grant_ref_t ref)
4005741Smrj {
4015741Smrj gnttab_frame_t frame;
4025741Smrj
4035741Smrj ASSERT(VALID_GRANT_REF(ref));
4045741Smrj
4055741Smrj frame = gnttab_end_foreign_transfer_ref(ref);
4065741Smrj put_free_entry(ref);
4075741Smrj return (frame);
4085741Smrj }
4095741Smrj
4105741Smrj void
gnttab_free_grant_reference(grant_ref_t ref)4115741Smrj gnttab_free_grant_reference(grant_ref_t ref)
4125741Smrj {
4135741Smrj ASSERT(VALID_GRANT_REF(ref));
4145741Smrj
4155741Smrj put_free_entry(ref);
4165741Smrj }
4175741Smrj
4185741Smrj void
gnttab_free_grant_references(grant_ref_t head)4195741Smrj gnttab_free_grant_references(grant_ref_t head)
4205741Smrj {
4215741Smrj grant_ref_t ref;
4225741Smrj int count = 1;
4235741Smrj
4245741Smrj if (head == GNTTAB_LIST_END)
4255741Smrj return;
4265741Smrj mutex_enter(&gnttab_list_lock);
4275741Smrj ref = head;
4286144Srab while (GNTTAB_ENTRY(ref) != GNTTAB_LIST_END) {
4296144Srab ref = GNTTAB_ENTRY(ref);
4305741Smrj count++;
4315741Smrj }
4326144Srab GNTTAB_ENTRY(ref) = gnttab_free_head;
4335741Smrj gnttab_free_head = head;
4345741Smrj gnttab_free_count += count;
4355741Smrj check_free_callbacks();
4365741Smrj mutex_exit(&gnttab_list_lock);
4375741Smrj }
4385741Smrj
4395741Smrj int
gnttab_alloc_grant_references(uint16_t count,grant_ref_t * head)4405741Smrj gnttab_alloc_grant_references(uint16_t count, grant_ref_t *head)
4415741Smrj {
4425741Smrj int h = get_free_entries(count);
4435741Smrj
4445741Smrj if (h == -1)
4455741Smrj return (-1);
4465741Smrj
4475741Smrj *head = h;
4485741Smrj
4495741Smrj return (0);
4505741Smrj }
4515741Smrj
4525741Smrj int
gnttab_empty_grant_references(const grant_ref_t * private_head)4536144Srab gnttab_empty_grant_references(const grant_ref_t *private_head)
4546144Srab {
4556144Srab return (*private_head == GNTTAB_LIST_END);
4566144Srab }
4576144Srab
4586144Srab int
gnttab_claim_grant_reference(grant_ref_t * private_head)4595741Smrj gnttab_claim_grant_reference(grant_ref_t *private_head)
4605741Smrj {
4615741Smrj grant_ref_t g = *private_head;
4625741Smrj
4635741Smrj if (g == GNTTAB_LIST_END)
4645741Smrj return (-1);
4656144Srab *private_head = GNTTAB_ENTRY(g);
4665741Smrj return (g);
4675741Smrj }
4685741Smrj
4695741Smrj void
gnttab_release_grant_reference(grant_ref_t * private_head,grant_ref_t release)4705741Smrj gnttab_release_grant_reference(grant_ref_t *private_head, grant_ref_t release)
4715741Smrj {
4725741Smrj ASSERT(VALID_GRANT_REF(release));
4735741Smrj
4746144Srab GNTTAB_ENTRY(release) = *private_head;
4755741Smrj *private_head = release;
4765741Smrj }
4775741Smrj
4785741Smrj void
gnttab_request_free_callback(struct gnttab_free_callback * callback,void (* fn)(void *),void * arg,uint16_t count)4795741Smrj gnttab_request_free_callback(struct gnttab_free_callback *callback,
4805741Smrj void (*fn)(void *), void *arg, uint16_t count)
4815741Smrj {
4825741Smrj mutex_enter(&gnttab_list_lock);
4835741Smrj if (callback->next)
4845741Smrj goto out;
4855741Smrj callback->fn = fn;
4865741Smrj callback->arg = arg;
4875741Smrj callback->count = count;
4885741Smrj callback->next = gnttab_free_callback_list;
4895741Smrj gnttab_free_callback_list = callback;
4905741Smrj check_free_callbacks();
4915741Smrj out:
4925741Smrj mutex_exit(&gnttab_list_lock);
4935741Smrj }
4945741Smrj
4956144Srab void
gnttab_cancel_free_callback(struct gnttab_free_callback * callback)4966144Srab gnttab_cancel_free_callback(struct gnttab_free_callback *callback)
4976144Srab {
4986144Srab struct gnttab_free_callback **pcb;
4996144Srab
5006144Srab mutex_enter(&gnttab_list_lock);
5016144Srab for (pcb = &gnttab_free_callback_list; *pcb; pcb = &(*pcb)->next) {
5026144Srab if (*pcb == callback) {
5036144Srab *pcb = callback->next;
5046144Srab break;
5056144Srab }
5066144Srab }
5076144Srab mutex_exit(&gnttab_list_lock);
5086144Srab }
5096144Srab
5106144Srab static gnttab_frame_t *
gnttab_setup(gnttab_setup_table_t * pset)5116144Srab gnttab_setup(gnttab_setup_table_t *pset)
5126144Srab {
5136144Srab gnttab_frame_t *frames;
5146144Srab
5156144Srab frames = kmem_alloc(pset->nr_frames * sizeof (gnttab_frame_t),
5166144Srab KM_SLEEP);
5176144Srab
5186144Srab /*LINTED: constant in conditional context*/
5196144Srab set_xen_guest_handle(pset->frame_list, frames);
5206144Srab
521*6450Srab #ifndef XPV_HVM_DRIVER
5226144Srab /*
5236144Srab * Take pset->nr_frames pages of grant table space from
5246144Srab * the hypervisor and map it
5256144Srab */
5266144Srab if ((HYPERVISOR_grant_table_op(GNTTABOP_setup_table, pset, 1) != 0) ||
5276144Srab (pset->status != 0)) {
5286144Srab cmn_err(CE_PANIC, "Grant Table setup failed");
5296144Srab }
530*6450Srab #endif
5316144Srab
5326144Srab return (frames);
5336144Srab }
5346144Srab
5355741Smrj #ifdef XPV_HVM_DRIVER
5365741Smrj static void
gnttab_map(void)5375741Smrj gnttab_map(void)
5385741Smrj {
5395741Smrj struct xen_add_to_physmap xatp;
5405741Smrj caddr_t va;
5415741Smrj pfn_t pfn;
5425741Smrj int i;
5435741Smrj
5445741Smrj va = (caddr_t)shared;
5456144Srab for (i = 0; i < max_nr_grant_frames(); i++) {
5466144Srab if ((pfn = hat_getpfnum(kas.a_hat, va)) == PFN_INVALID)
5476144Srab cmn_err(CE_PANIC, "gnttab_map: Invalid pfn");
5485741Smrj
5495741Smrj xatp.domid = DOMID_SELF;
5505741Smrj xatp.idx = i;
5515741Smrj xatp.space = XENMAPSPACE_grant_table;
5525741Smrj xatp.gpfn = pfn;
5535741Smrj hat_unload(kas.a_hat, va, MMU_PAGESIZE, HAT_UNLOAD);
5546144Srab /*
5556144Srab * This call replaces the existing machine page backing
5566144Srab * the given gpfn with the page from the allocated grant
5576144Srab * table at index idx. The existing machine page is
5586144Srab * returned to the free list.
5596144Srab */
5605741Smrj if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp) != 0)
5615741Smrj panic("Couldn't map grant table");
5625741Smrj hat_devload(kas.a_hat, va, MMU_PAGESIZE, pfn,
5636303Sjohnlev PROT_READ | PROT_WRITE | HAT_STORECACHING_OK,
5645741Smrj HAT_LOAD | HAT_LOAD_LOCK | HAT_LOAD_NOCONSIST);
5655741Smrj va += MMU_PAGESIZE;
5665741Smrj }
5675741Smrj }
5686144Srab #endif /* XPV_HVM_DRIVER */
5695741Smrj
5705741Smrj void
gnttab_init(void)5715741Smrj gnttab_init(void)
5725741Smrj {
5735741Smrj gnttab_setup_table_t set;
5745741Smrj int i;
5756415Sgarypen uint_t nr_init_grefs, max_nr_glist_frames, nr_glist_frames;
5766144Srab gnttab_frame_t *frames;
5775741Smrj
5785741Smrj /*
5796144Srab * gnttab_init() should only be invoked once.
5805741Smrj */
5816144Srab mutex_enter(&gnttab_list_lock);
5826144Srab ASSERT(nr_grant_frames == 0);
5836144Srab nr_grant_frames = 1;
5846144Srab mutex_exit(&gnttab_list_lock);
5856144Srab
5866144Srab max_nr_glist_frames = (max_nr_grant_frames() *
5876415Sgarypen GREFS_PER_GRANT_FRAME / RPP);
5886144Srab
5896144Srab set.dom = DOMID_SELF;
5906144Srab set.nr_frames = max_nr_grant_frames();
5916144Srab frames = gnttab_setup(&set);
5926144Srab
5936144Srab #ifdef XPV_HVM_DRIVER
5946144Srab shared = (grant_entry_t *)xen_alloc_pages(set.nr_frames);
5956144Srab
5966144Srab gnttab_map();
5976144Srab #else /* XPV_HVM_DRIVER */
5986144Srab shared = vmem_xalloc(heap_arena, set.nr_frames * MMU_PAGESIZE,
5996144Srab MMU_PAGESIZE, 0, 0, 0, 0, VM_SLEEP);
6006144Srab for (i = 0; i < set.nr_frames; i++) {
6016144Srab hat_devload(kas.a_hat, (caddr_t)GT_PGADDR(i), PAGESIZE,
6026303Sjohnlev xen_assign_pfn(frames[i]),
6036303Sjohnlev PROT_READ | PROT_WRITE | HAT_STORECACHING_OK,
6046144Srab HAT_LOAD_LOCK);
6056144Srab }
6066144Srab #endif
6076144Srab
6086144Srab gnttab_list = kmem_alloc(max_nr_glist_frames * sizeof (grant_ref_t *),
6096144Srab KM_SLEEP);
6106144Srab
6116415Sgarypen nr_glist_frames = (nr_grant_frames * GREFS_PER_GRANT_FRAME + RPP - 1)
6126415Sgarypen / RPP;
6136415Sgarypen for (i = 0; i < nr_glist_frames; i++) {
6146144Srab gnttab_list[i] = kmem_alloc(PAGESIZE, KM_SLEEP);
6155741Smrj }
6165741Smrj
6176144Srab kmem_free(frames, set.nr_frames * sizeof (gnttab_frame_t));
6185741Smrj
6196144Srab nr_init_grefs = nr_grant_frames * GREFS_PER_GRANT_FRAME;
6205741Smrj
6216144Srab for (i = NR_RESERVED_ENTRIES; i < nr_init_grefs - 1; i++)
6226144Srab GNTTAB_ENTRY(i) = i + 1;
6236144Srab
6246144Srab GNTTAB_ENTRY(nr_init_grefs - 1) = GNTTAB_LIST_END;
6256144Srab gnttab_free_count = nr_init_grefs - NR_RESERVED_ENTRIES;
6265741Smrj gnttab_free_head = NR_RESERVED_ENTRIES;
6275741Smrj }
6285741Smrj
6295741Smrj void
gnttab_resume(void)6305741Smrj gnttab_resume(void)
6315741Smrj {
6325741Smrj gnttab_setup_table_t set;
6335741Smrj int i;
6346144Srab gnttab_frame_t *frames;
6356144Srab uint_t available_frames = max_nr_grant_frames();
6366144Srab
6376144Srab if (available_frames < nr_grant_frames) {
6386144Srab cmn_err(CE_PANIC, "Hypervisor does not have enough grant "
6396144Srab "frames: required(%u), available(%u)", nr_grant_frames,
6406144Srab available_frames);
6416144Srab }
6426144Srab
6436144Srab #ifdef XPV_HVM_DRIVER
6446144Srab gnttab_map();
6456144Srab #endif /* XPV_HVM_DRIVER */
6465741Smrj
6475741Smrj set.dom = DOMID_SELF;
6486144Srab set.nr_frames = available_frames;
6496144Srab frames = gnttab_setup(&set);
6505741Smrj
6516144Srab for (i = 0; i < available_frames; i++) {
6525741Smrj (void) HYPERVISOR_update_va_mapping(GT_PGADDR(i),
6535741Smrj FRAME_TO_MA(frames[i]) | PT_VALID | PT_WRITABLE,
6545741Smrj UVMF_INVLPG | UVMF_ALL);
6555741Smrj }
6566144Srab kmem_free(frames, set.nr_frames * sizeof (gnttab_frame_t));
6575741Smrj }
6585741Smrj
6595741Smrj void
gnttab_suspend(void)6605741Smrj gnttab_suspend(void)
6615741Smrj {
6625741Smrj int i;
6635741Smrj
6645741Smrj /*
6655741Smrj * clear grant table mappings before suspending
6665741Smrj */
6676144Srab for (i = 0; i < max_nr_grant_frames(); i++) {
6685741Smrj (void) HYPERVISOR_update_va_mapping(GT_PGADDR(i),
6695741Smrj 0, UVMF_INVLPG);
6705741Smrj }
6715741Smrj }
6725741Smrj
6735741Smrj /*
6745741Smrj * Local variables:
6755741Smrj * c-file-style: "solaris"
6765741Smrj * indent-tabs-mode: t
6775741Smrj * c-indent-level: 8
6785741Smrj * c-basic-offset: 8
6795741Smrj * tab-width: 8
6805741Smrj * End:
6815741Smrj */
682