xref: /netbsd-src/sys/arch/xen/xen/xengnt.c (revision fad4c9f71477ae11cea2ee75ec82151ac770a534)
1 /*      $NetBSD: xengnt.c,v 1.2 2006/03/19 00:28:02 bouyer Exp $      */
2 
3 /*
4  * Copyright (c) 2006 Manuel Bouyer.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *      This product includes software developed by Manuel Bouyer.
17  * 4. The name of the author may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  *
31  */
32 
33 #include <sys/types.h>
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/malloc.h>
37 #include <sys/queue.h>
38 #include <sys/extent.h>
39 #include <sys/kernel.h>
40 #include <uvm/uvm.h>
41 
42 #include <machine/hypervisor.h>
43 #include <machine/xen.h>
44 #include <machine/granttables.h>
45 
46 #undef XENDEBUG
47 #ifdef XENDEBUG
48 #define DPRINTF(x) printf x
49 #else
50 #define DPRINTF(x)
51 #endif
52 
53 #define NR_GRANT_ENTRIES (NR_GRANT_FRAMES * PAGE_SIZE / sizeof(grant_entry_t))
54 
55 /* bitmask of free grant entries. 1 = entrie is free */
56 #define NR_BITMASK_ENTRIES ((NR_GRANT_ENTRIES + 31) / 32)
57 u_int32_t gnt_entries_bitmask[NR_BITMASK_ENTRIES];
58 
59 /* VM address of the grant table */
60 grant_entry_t *grant_table;
61 
62 static grant_ref_t xengnt_get_entry(void);
63 #define XENGNT_NO_ENTRY 0xffffffff
64 static void xengnt_free_entry(grant_ref_t);
65 static void xengnt_resume(void);
66 
67 void
68 xengnt_init()
69 {
70 	grant_table = (void *)uvm_km_alloc(kernel_map,
71 	    NR_GRANT_FRAMES * PAGE_SIZE, 0, UVM_KMF_VAONLY);
72 	if (grant_table == NULL)
73 		panic("xengnt_init() no VM space");
74 
75 	xengnt_resume();
76 
77 	memset(gnt_entries_bitmask, 0xff, sizeof(gnt_entries_bitmask));
78 }
79 
80 static void
81 xengnt_resume()
82 {
83 	gnttab_setup_table_t setup;
84 	unsigned long pages[NR_GRANT_FRAMES];
85 	int i = 0;
86 
87 	setup.dom = DOMID_SELF;
88 	setup.nr_frames = NR_GRANT_FRAMES;
89 	setup.frame_list = pages;
90 
91 	if (HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1) != 0)
92 		panic("xengnt_resume: setup table failed");
93 	if (setup.status != 0)
94 		panic("xengnt_resume: setup table returned %d", setup.status);
95 
96 	for (i = 0; i < NR_GRANT_FRAMES; i++) {
97 		DPRINTF(("xengnt_resume: map 0x%lx -> %p\n",
98 			pages[i], (char *)grant_table + i * PAGE_SIZE));
99 
100 		pmap_kenter_ma(((vaddr_t)grant_table) + i * PAGE_SIZE,
101 		    pages[i] << PAGE_SHIFT, VM_PROT_WRITE);
102 	}
103 }
104 
105 static grant_ref_t
106 xengnt_get_entry()
107 {
108 	int i;
109 	grant_ref_t entry;
110 	int s = splvm();
111 
112 	for (i = 0; i < NR_BITMASK_ENTRIES; i++) {
113 		entry = ffs(gnt_entries_bitmask[i]);
114 		if (entry != 0) {
115 			entry--;
116 			gnt_entries_bitmask[i] &= ~(1 << (entry & 0x1f));
117 			splx(s);
118 			return ((i << 5) + entry);
119 		}
120 	}
121 	splx(s);
122 	return XENGNT_NO_ENTRY;
123 }
124 
125 static void
126 xengnt_free_entry(grant_ref_t entry)
127 {
128 	int s = splvm();
129 	KASSERT((entry >> 5) < NR_BITMASK_ENTRIES);
130 	gnt_entries_bitmask[entry >> 5] |= (1 << (entry & 0x1f));
131 	splx(s);
132 }
133 
134 int
135 xengnt_grant_access(domid_t dom, paddr_t ma, int ro, grant_ref_t *entryp)
136 {
137 	*entryp = xengnt_get_entry();
138 	if (__predict_false(*entryp == XENGNT_NO_ENTRY))
139 		return ENOMEM;
140 
141 	grant_table[*entryp].frame = ma >> PAGE_SHIFT;
142 	grant_table[*entryp].domid  = dom;
143 	x86_lfence();
144 	grant_table[*entryp].flags =
145 	    GTF_permit_access | (ro ? GTF_readonly : 0);
146 	return 0;
147 }
148 
149 void
150 xengnt_revoke_access(grant_ref_t entry)
151 {
152 	uint16_t flags, nflags;
153 
154 	nflags = grant_table[entry].flags;
155 
156 	do {
157 		if ((flags = nflags) & (GTF_reading|GTF_writing))
158 			panic("xengnt_revoke_access: still in use");
159 		nflags = xen_atomic_cmpxchg16(&grant_table[entry].flags,
160 		    flags, 0);
161 	} while (nflags != flags);
162 	xengnt_free_entry(entry);
163 }
164 
165 int
166 xengnt_grant_transfer(domid_t dom, grant_ref_t *entryp)
167 {
168 	*entryp = xengnt_get_entry();
169 	if (__predict_false(*entryp == XENGNT_NO_ENTRY))
170 		return ENOMEM;
171 
172 	grant_table[*entryp].frame = 0;
173 	grant_table[*entryp].domid  =dom;
174 	x86_lfence();
175 	grant_table[*entryp].flags = GTF_accept_transfer;
176 	return 0;
177 }
178 
179 paddr_t
180 xengnt_revoke_transfer(grant_ref_t entry)
181 {
182 	paddr_t page;
183 	uint16_t flags;
184 
185 	/* if the transfer has not started, free the entry and return 0 */
186 	while (!((flags = grant_table[entry].flags) & GTF_transfer_committed)) {
187 		if (xen_atomic_cmpxchg16(&grant_table[entry].flags,
188 		    flags, 0) == flags ) {
189 			xengnt_free_entry(entry);
190 			return 0;
191 		}
192 		HYPERVISOR_yield();
193 	}
194 
195 	/* If transfer in progress, wait for completion */
196 	while (!((flags = grant_table[entry].flags) & GTF_transfer_completed))
197 		HYPERVISOR_yield();
198 
199 	/* Read the frame number /after/ reading completion status. */
200 	__insn_barrier();
201 	page = grant_table[entry].frame;
202 	if (page == 0)
203 		printf("xengnt_revoke_transfer: guest sent pa 0\n");
204 
205 	xengnt_free_entry(entry);
206 	return page;
207 }
208 
209 int
210 xengnt_status(grant_ref_t entry)
211 {
212 	return (grant_table[entry].flags & (GTF_reading|GTF_writing));
213 }
214