debuggers.hg

view freebsd-5.3-xen-sparse/i386-xen/i386-xen/gnttab.c @ 4628:35357e323f14

bitkeeper revision 1.1338 (4266317ezHysqYzH_WRvfueqwU4i4Q)

Grant tables for FreeBSD.
Signed-off-by: Kip Macy <kmacy@fsmware.com>
Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Wed Apr 20 10:39:58 2005 +0000 (2005-04-20)
parents
children
line source
1 /******************************************************************************
2 * gnttab.c
3 *
4 * Two sets of functionality:
5 * 1. Granting foreign access to our memory reservation.
6 * 2. Accessing others' memory reservations via grant references.
7 * (i.e., mechanisms for both sender and recipient of grant references)
8 *
9 * Copyright (c) 2005, Christopher Clark
10 * Copyright (c) 2004, K A Fraser
11 */
13 #include "opt_pmap.h"
14 #include <sys/param.h>
15 #include <sys/systm.h>
16 #include <sys/bus.h>
17 #include <sys/conf.h>
18 #include <sys/module.h>
19 #include <sys/kernel.h>
20 #include <sys/lock.h>
21 #include <sys/malloc.h>
22 #include <sys/mman.h>
23 #include <vm/vm.h>
24 #include <vm/vm_extern.h>
25 #include <vm/pmap.h>
26 #include <vm/vm_kern.h>
28 #include <machine/gnttab.h>
29 #include <machine/pmap.h>
31 #include <machine/hypervisor-ifs.h>
33 #define cmpxchg(a, b, c) atomic_cmpset_int((volatile u_int *)(a),(b),(c))
36 /* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
37 static inline void rep_nop(void)
38 {
39 __asm__ __volatile__ ( "rep;nop" : : : "memory" );
40 }
41 #define cpu_relax() rep_nop()
43 #if 1
44 #define ASSERT(_p) \
45 if ( !(_p) ) { printk("Assertion '%s': line %d, file %s\n", \
46 #_p , __LINE__, __FILE__); *(int*)0=0; }
47 #else
48 #define ASSERT(_p) ((void)0)
49 #endif
51 #define WPRINTK(fmt, args...) \
52 printk("xen_grant: " fmt, ##args)
54 static grant_ref_t gnttab_free_list[NR_GRANT_ENTRIES];
55 static grant_ref_t gnttab_free_head;
57 static grant_entry_t *shared;
58 #if 0
59 /* /proc/xen/grant */
60 static struct proc_dir_entry *grant_pde;
61 #endif
63 /*
64 * Lock-free grant-entry allocator
65 */
67 static inline int
68 get_free_entry(void)
69 {
70 grant_ref_t fh, nfh = gnttab_free_head;
71 do { if ( unlikely((fh = nfh) == NR_GRANT_ENTRIES) ) return -1; }
72 while ( unlikely((nfh = cmpxchg(&gnttab_free_head, fh,
73 gnttab_free_list[fh])) != fh) );
74 return fh;
75 }
77 static inline void
78 put_free_entry(grant_ref_t ref)
79 {
80 grant_ref_t fh, nfh = gnttab_free_head;
81 do { gnttab_free_list[ref] = fh = nfh; wmb(); }
82 while ( unlikely((nfh = cmpxchg(&gnttab_free_head, fh, ref)) != fh) );
83 }
85 /*
86 * Public grant-issuing interface functions
87 */
89 int
90 gnttab_grant_foreign_access(domid_t domid, unsigned long frame, int readonly)
91 {
92 int ref;
94 if ( unlikely((ref = get_free_entry()) == -1) )
95 return -ENOSPC;
97 shared[ref].frame = frame;
98 shared[ref].domid = domid;
99 wmb();
100 shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0);
102 return ref;
103 }
105 void
106 gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid,
107 unsigned long frame, int readonly)
108 {
109 shared[ref].frame = frame;
110 shared[ref].domid = domid;
111 wmb();
112 shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0);
113 }
116 int
117 gnttab_query_foreign_access(grant_ref_t ref)
118 {
119 uint16_t nflags;
121 nflags = shared[ref].flags;
123 return (nflags & (GTF_reading|GTF_writing));
124 }
126 void
127 gnttab_end_foreign_access(grant_ref_t ref, int readonly)
128 {
129 uint16_t flags, nflags;
131 nflags = shared[ref].flags;
132 do {
133 if ( (flags = nflags) & (GTF_reading|GTF_writing) )
134 printk("WARNING: g.e. still in use!\n");
135 }
136 while ( (nflags = cmpxchg(&shared[ref].flags, flags, 0)) != flags );
138 put_free_entry(ref);
139 }
141 int
142 gnttab_grant_foreign_transfer(domid_t domid, unsigned long pfn)
143 {
144 int ref;
146 if ( unlikely((ref = get_free_entry()) == -1) )
147 return -ENOSPC;
149 shared[ref].frame = pfn;
150 shared[ref].domid = domid;
151 wmb();
152 shared[ref].flags = GTF_accept_transfer;
154 return ref;
155 }
157 void
158 gnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid,
159 unsigned long pfn)
160 {
161 shared[ref].frame = pfn;
162 shared[ref].domid = domid;
163 wmb();
164 shared[ref].flags = GTF_accept_transfer;
165 }
167 unsigned long
168 gnttab_end_foreign_transfer(grant_ref_t ref)
169 {
170 unsigned long frame = 0;
171 uint16_t flags;
173 flags = shared[ref].flags;
174 ASSERT(flags == (GTF_accept_transfer | GTF_transfer_committed));
176 /*
177 * If a transfer is committed then wait for the frame address to appear.
178 * Otherwise invalidate the grant entry against future use.
179 */
180 if ( likely(flags != GTF_accept_transfer) ||
181 (cmpxchg(&shared[ref].flags, flags, 0) != GTF_accept_transfer) )
182 while ( unlikely((frame = shared[ref].frame) == 0) )
183 cpu_relax();
185 put_free_entry(ref);
187 return frame;
188 }
190 void
191 gnttab_free_grant_references(uint16_t count, grant_ref_t head)
192 {
193 /* TODO: O(N)...? */
194 grant_ref_t to_die = 0, next = head;
195 int i;
197 for ( i = 0; i < count; i++ )
198 to_die = next;
199 next = gnttab_free_list[next];
200 put_free_entry( to_die );
201 }
203 int
204 gnttab_alloc_grant_references(uint16_t count, grant_ref_t *head,
205 grant_ref_t *terminal)
206 {
207 int i;
208 grant_ref_t h = gnttab_free_head;
210 for ( i = 0; i < count; i++ )
211 if ( unlikely(get_free_entry() == -1) )
212 goto not_enough_refs;
214 *head = h;
215 *terminal = gnttab_free_head;
217 return 0;
219 not_enough_refs:
220 gnttab_free_head = h;
221 return -ENOSPC;
222 }
224 int
225 gnttab_claim_grant_reference(grant_ref_t *private_head, grant_ref_t terminal )
226 {
227 grant_ref_t g;
228 if ( unlikely((g = *private_head) == terminal) )
229 return -ENOSPC;
230 *private_head = gnttab_free_list[g];
231 return g;
232 }
234 void
235 gnttab_release_grant_reference( grant_ref_t *private_head,
236 grant_ref_t release )
237 {
238 gnttab_free_list[release] = *private_head;
239 *private_head = release;
240 }
241 #ifdef notyet
242 static int
243 grant_ioctl(struct cdev *dev, u_long cmd, caddr_t data,
244 int flag, struct thread *td)
245 {
247 int ret;
248 privcmd_hypercall_t hypercall;
250 /* XXX Need safety checks here if using for anything other
251 * than debugging */
252 return -ENOSYS;
254 if ( cmd != IOCTL_PRIVCMD_HYPERCALL )
255 return -ENOSYS;
257 if ( copy_from_user(&hypercall, (void *)data, sizeof(hypercall)) )
258 return -EFAULT;
260 if ( hypercall.op != __HYPERVISOR_grant_table_op )
261 return -ENOSYS;
263 /* hypercall-invoking asm taken from privcmd.c */
264 __asm__ __volatile__ (
265 "pushl %%ebx; pushl %%ecx; pushl %%edx; pushl %%esi; pushl %%edi; "
266 "movl 4(%%eax),%%ebx ;"
267 "movl 8(%%eax),%%ecx ;"
268 "movl 12(%%eax),%%edx ;"
269 "movl 16(%%eax),%%esi ;"
270 "movl 20(%%eax),%%edi ;"
271 "movl (%%eax),%%eax ;"
272 TRAP_INSTR "; "
273 "popl %%edi; popl %%esi; popl %%edx; popl %%ecx; popl %%ebx"
274 : "=a" (ret) : "0" (&hypercall) : "memory" );
276 return ret;
278 }
280 static struct cdevsw gnttab_cdevsw = {
281 d_ioctl: grant_ioctl,
282 };
284 static int
285 grant_read(char *page, char **start, off_t off,
286 int count, int *eof, void *data)
287 {
288 int len;
289 unsigned int i;
290 grant_entry_t *gt;
292 gt = (grant_entry_t *)shared;
293 len = 0;
295 for ( i = 0; i < NR_GRANT_ENTRIES; i++ )
296 /* TODO: safety catch here until this can handle >PAGE_SIZE output */
297 if (len > (PAGE_SIZE - 200))
298 {
299 len += sprintf( page + len, "Truncated.\n");
300 break;
301 }
303 if ( gt[i].flags )
304 len += sprintf( page + len,
305 "Grant: ref (0x%x) flags (0x%hx) dom (0x%hx) frame (0x%x)\n",
306 i,
307 gt[i].flags,
308 gt[i].domid,
309 gt[i].frame );
311 *eof = 1;
312 return len;
313 }
315 static int
316 grant_write(struct file *file, const char __user *buffer,
317 unsigned long count, void *data)
318 {
319 /* TODO: implement this */
320 return -ENOSYS;
321 }
322 #endif
323 static int
324 gnttab_init(void *unused)
325 {
326 gnttab_setup_table_t setup;
327 unsigned long frames[NR_GRANT_FRAMES];
328 int i;
330 setup.dom = DOMID_SELF;
331 setup.nr_frames = NR_GRANT_FRAMES;
332 setup.frame_list = frames;
334 if (HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1) != 0)
335 panic("grant table setup failed\n");
336 if (setup.status != 0)
337 panic("non-zero status in grant table setup\n");
338 shared = (grant_entry_t *)kmem_alloc_nofault(kernel_map, NR_GRANT_FRAMES);
340 for (i = 0; i < NR_GRANT_FRAMES; i++)
341 pmap_kenter_ma((vm_offset_t)(shared + (i*PAGE_SIZE)), frames[i] << PAGE_SHIFT);
343 for ( i = 0; i < NR_GRANT_ENTRIES; i++ )
344 gnttab_free_list[i] = i + 1;
345 #if 0
346 /*
347 * /proc/xen/grant : used by libxc to access grant tables
348 */
349 if ( (grant_pde = create_xen_proc_entry("grant", 0600)) == NULL )
350 {
351 WPRINTK("Unable to create grant xen proc entry\n");
352 return -1;
353 }
355 grant_file_ops.read = grant_pde->proc_fops->read;
356 grant_file_ops.write = grant_pde->proc_fops->write;
358 grant_pde->proc_fops = &grant_file_ops;
360 grant_pde->read_proc = &grant_read;
361 grant_pde->write_proc = &grant_write;
362 #endif
363 printk("Grant table initialized\n");
364 return 0;
365 }
367 SYSINIT(gnttab, SI_SUB_PSEUDO, SI_ORDER_FIRST, gnttab_init, NULL);