ia64/xen-unstable

view extras/mini-os/xenbus/xenbus_comms.c @ 6726:0c7379b702e5

common/kernel.o contains changeset/compiler info.
Blow away on every build.
author kaf24@firebug.cl.cam.ac.uk
date Fri Sep 09 16:26:20 2005 +0000 (2005-09-09)
parents cdfa7dd00c44
children b2f4823b6ff0 b35215021b32 9af349b055e5 3233e7ecfa9f
line source
1 /******************************************************************************
2 * xenbus_comms.c
3 *
4 * Low level code to talks to Xen Store: ringbuffer and event channel.
5 *
6 * Copyright (C) 2005 Rusty Russell, IBM Corporation
7 *
8 * This file may be distributed separately from the Linux kernel, or
9 * incorporated into other software packages, subject to the following license:
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a copy
12 * of this source file (the "Software"), to deal in the Software without
13 * restriction, including without limitation the rights to use, copy, modify,
14 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
15 * and to permit persons to whom the Software is furnished to do so, subject to
16 * the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included in
19 * all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
27 * IN THE SOFTWARE.
28 */
29 #include <types.h>
30 #include <wait.h>
31 #include <mm.h>
32 #include <hypervisor.h>
33 #include <events.h>
34 #include <os.h>
35 #include <lib.h>
38 #ifdef XENBUS_COMMS_DEBUG
39 #define DEBUG(_f, _a...) \
40 printk("MINI_OS(file=xenbus_comms.c, line=%d) " _f "\n", __LINE__, ## _a)
41 #else
42 #define DEBUG(_f, _a...) ((void)0)
43 #endif
46 #define RINGBUF_DATASIZE ((PAGE_SIZE / 2) - sizeof(struct ringbuf_head))
47 struct ringbuf_head
48 {
49 u32 write; /* Next place to write to */
50 u32 read; /* Next place to read from */
51 u8 flags;
52 char buf[0];
53 } __attribute__((packed));
55 DECLARE_WAIT_QUEUE_HEAD(xb_waitq);
57 static inline struct ringbuf_head *outbuf(void)
58 {
59 return mfn_to_virt(start_info.store_mfn);
60 }
62 static inline struct ringbuf_head *inbuf(void)
63 {
64 return (struct ringbuf_head *)((char *)mfn_to_virt(start_info.store_mfn) + PAGE_SIZE/2);
65 }
67 static void wake_waiting(int port, struct pt_regs *regs)
68 {
69 wake_up(&xb_waitq);
70 }
72 static int check_buffer(const struct ringbuf_head *h)
73 {
74 return (h->write < RINGBUF_DATASIZE && h->read < RINGBUF_DATASIZE);
75 }
77 /* We can't fill last byte: would look like empty buffer. */
78 static void *get_output_chunk(const struct ringbuf_head *h,
79 void *buf, u32 *len)
80 {
81 u32 read_mark;
83 if (h->read == 0)
84 read_mark = RINGBUF_DATASIZE - 1;
85 else
86 read_mark = h->read - 1;
88 /* Here to the end of buffer, unless they haven't read some out. */
89 *len = RINGBUF_DATASIZE - h->write;
90 if (read_mark >= h->write)
91 *len = read_mark - h->write;
92 return (void *)((char *)buf + h->write);
93 }
95 static const void *get_input_chunk(const struct ringbuf_head *h,
96 const void *buf, u32 *len)
97 {
98 /* Here to the end of buffer, unless they haven't written some. */
99 *len = RINGBUF_DATASIZE - h->read;
100 if (h->write >= h->read)
101 *len = h->write - h->read;
102 return (void *)((char *)buf + h->read);
103 }
105 static void update_output_chunk(struct ringbuf_head *h, u32 len)
106 {
107 h->write += len;
108 if (h->write == RINGBUF_DATASIZE)
109 h->write = 0;
110 }
112 static void update_input_chunk(struct ringbuf_head *h, u32 len)
113 {
114 h->read += len;
115 if (h->read == RINGBUF_DATASIZE)
116 h->read = 0;
117 }
119 static int output_avail(struct ringbuf_head *out)
120 {
121 unsigned int avail;
123 get_output_chunk(out, out->buf, &avail);
124 return avail != 0;
125 }
127 int xb_write(const void *data, unsigned len)
128 {
129 struct ringbuf_head h;
130 struct ringbuf_head *out = outbuf();
132 do {
133 void *dst;
134 unsigned int avail;
136 wait_event(xb_waitq, output_avail(out));
138 /* Read, then check: not that we don't trust store.
139 * Hell, some of my best friends are daemons. But,
140 * in this post-911 world... */
141 h = *out;
142 mb();
143 if (!check_buffer(&h)) {
144 return -1; /* ETERRORIST! */
145 }
147 dst = get_output_chunk(&h, out->buf, &avail);
148 if (avail > len)
149 avail = len;
150 memcpy(dst, data, avail);
151 data = (void *)((char *)data + avail);
152 len -= avail;
153 update_output_chunk(out, avail);
154 notify_via_evtchn(start_info.store_evtchn);
155 } while (len != 0);
157 return 0;
158 }
160 int xs_input_avail(void)
161 {
162 unsigned int avail;
163 struct ringbuf_head *in = inbuf();
165 get_input_chunk(in, in->buf, &avail);
166 return avail != 0;
167 }
169 int xb_read(void *data, unsigned len)
170 {
171 struct ringbuf_head h;
172 struct ringbuf_head *in = inbuf();
173 int was_full;
175 while (len != 0) {
176 unsigned int avail;
177 const char *src;
179 wait_event(xb_waitq, xs_input_avail());
180 h = *in;
181 mb();
182 if (!check_buffer(&h)) {
183 return -1;
184 }
186 src = get_input_chunk(&h, in->buf, &avail);
187 if (avail > len)
188 avail = len;
189 was_full = !output_avail(&h);
191 memcpy(data, src, avail);
192 data = (void *)((char *)data + avail);
193 len -= avail;
194 update_input_chunk(in, avail);
195 DEBUG("Finished read of %i bytes (%i to go)\n", avail, len);
196 /* If it was full, tell them we've taken some. */
197 if (was_full)
198 notify_via_evtchn(start_info.store_evtchn);
199 }
201 /* If we left something, wake watch thread to deal with it. */
202 if (xs_input_avail())
203 wake_up(&xb_waitq);
205 return 0;
206 }
208 /* Set up interrupt handler off store event channel. */
209 int xb_init_comms(void)
210 {
211 printk("Init xenbus comms, store event channel %d\n", start_info.store_evtchn);
212 if (!start_info.store_evtchn)
213 return 0;
214 printk("Binding virq\n");
215 bind_evtchn(start_info.store_evtchn, &wake_waiting);
217 /* FIXME zero out page -- domain builder should probably do this*/
218 memset(mfn_to_virt(start_info.store_mfn), 0, PAGE_SIZE);
219 notify_via_evtchn(start_info.store_evtchn);
220 return 0;
221 }
223 void xb_suspend_comms(void)
224 {
226 if (!start_info.store_evtchn)
227 return;
229 // TODO
230 //unbind_evtchn_from_irqhandler(xen_start_info.store_evtchn, &xb_waitq);
231 }