|
|
1.1 root 1: /*
2: * Copyright (C) 2006-2009 Free Software Foundation
3: *
4: * This program is free software ; you can redistribute it and/or modify
5: * it under the terms of the GNU General Public License as published by
6: * the Free Software Foundation ; either version 2 of the License, or
7: * (at your option) any later version.
8: *
9: * This program is distributed in the hope that it will be useful,
10: * but WITHOUT ANY WARRANTY ; without even the implied warranty of
11: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12: * GNU General Public License for more details.
13: *
14: * You should have received a copy of the GNU General Public License
15: * along with the program ; if not, write to the Free Software
16: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17: */
18:
19: #include <sys/types.h>
20: #include <mach/mig_support.h>
21: #include <machine/pmap.h>
22: #include <machine/ipl.h>
23: #include <kern/kalloc.h>
24: #include <stdarg.h>
25: #include <string.h>
26: #include <alloca.h>
27: #include <xen/public/xen.h>
28: #include <xen/public/io/xs_wire.h>
29: #include <util/atoi.h>
30: #include "store.h"
31: #include "ring.h"
32: #include "evt.h"
33: #include "xen.h"
34:
35: /* TODO use events instead of just yielding */
36:
37: /* Hypervisor part */
38:
39: decl_simple_lock_data(static, lock);
40:
41: static struct xenstore_domain_interface *store;
42:
43: struct store_req {
44: const char *data;
45: unsigned len;
46: };
47:
48: /* Send a request */
1.1.1.2 ! root 49: static void store_put(hyp_store_transaction_t t, uint32_t type, struct store_req *req, unsigned nr_reqs) {
1.1 root 50: struct xsd_sockmsg head = {
51: .type = type,
52: .req_id = 0,
53: .tx_id = t,
54: };
55: unsigned totlen, len;
56: unsigned i;
57:
58: totlen = 0;
59: for (i = 0; i < nr_reqs; i++)
60: totlen += req[i].len;
61: head.len = totlen;
62: totlen += sizeof(head);
63:
64: if (totlen > sizeof(store->req) - 1)
65: panic("too big store message %d, max %d", totlen, sizeof(store->req));
66:
67: while (hyp_ring_available(store->req, store->req_prod, store->req_cons) < totlen)
68: hyp_yield();
69:
70: mb();
71: hyp_ring_store(&hyp_ring_cell(store->req, store->req_prod), &head, sizeof(head), store->req, store->req + sizeof(store->req));
72: len = sizeof(head);
73: for (i=0; i<nr_reqs; i++) {
74: hyp_ring_store(&hyp_ring_cell(store->req, store->req_prod + len), req[i].data, req[i].len, store->req, store->req + sizeof(store->req));
75: len += req[i].len;
76: }
77:
78: wmb();
79: store->req_prod += totlen;
80: hyp_event_channel_send(boot_info.store_evtchn);
81: }
82:
83: static const char *errors[] = {
84: "EINVAL",
85: "EACCES",
86: "EEXIST",
87: "EISDIR",
88: "ENOENT",
89: "ENOMEM",
90: "ENOSPC",
91: "EIO",
92: "ENOTEMPTY",
93: "ENOSYS",
94: "EROFS",
95: "EBUSY",
96: "EAGAIN",
97: "EISCONN",
98: NULL,
99: };
100:
101: /* Send a request and wait for a reply, whose header is put in head, and
102: * data is returned (beware, that's in the ring !)
103: * On error, returns NULL. Else takes the lock and return pointer on data and
104: * store_put_wait_end shall be called after reading it. */
105: static struct xsd_sockmsg head;
106: const char *hyp_store_error;
107:
1.1.1.2 ! root 108: static void *store_put_wait(hyp_store_transaction_t t, uint32_t type, struct store_req *req, unsigned nr_reqs) {
1.1 root 109: unsigned len;
110: const char **error;
111: void *data;
112:
113: simple_lock(&lock);
114: store_put(t, type, req, nr_reqs);
115: again:
116: while (store->rsp_prod - store->rsp_cons < sizeof(head))
117: hyp_yield();
118: rmb();
119: hyp_ring_fetch(&head, &hyp_ring_cell(store->rsp, store->rsp_cons), sizeof(head), store->rsp, store->rsp + sizeof(store->rsp));
120: len = sizeof(head) + head.len;
121: while (store->rsp_prod - store->rsp_cons < len)
122: hyp_yield();
123: rmb();
124: if (head.type == XS_WATCH_EVENT) {
125: /* Spurious watch event, drop */
126: store->rsp_cons += sizeof(head) + head.len;
127: hyp_event_channel_send(boot_info.store_evtchn);
128: goto again;
129: }
130: data = &hyp_ring_cell(store->rsp, store->rsp_cons + sizeof(head));
131: if (head.len <= 10) {
132: char c[10];
133: hyp_ring_fetch(c, data, head.len, store->rsp, store->rsp + sizeof(store->rsp));
134: for (error = errors; *error; error++) {
135: if (head.len == strlen(*error) + 1 && !memcmp(*error, c, head.len)) {
136: hyp_store_error = *error;
137: store->rsp_cons += len;
138: hyp_event_channel_send(boot_info.store_evtchn);
139: simple_unlock(&lock);
140: return NULL;
141: }
142: }
143: }
144: return data;
145: }
146:
147: /* Must be called after each store_put_wait. Releases lock. */
148: static void store_put_wait_end(void) {
149: mb();
150: store->rsp_cons += sizeof(head) + head.len;
151: hyp_event_channel_send(boot_info.store_evtchn);
152: simple_unlock(&lock);
153: }
154:
155: /* Start a transaction. */
156: hyp_store_transaction_t hyp_store_transaction_start(void) {
157: struct store_req req = {
158: .data = "",
159: .len = 1,
160: };
161: char *rep;
162: char *s;
163: int i;
164:
165: rep = store_put_wait(0, XS_TRANSACTION_START, &req, 1);
166: if (!rep)
167: panic("couldn't start transaction (%s)", hyp_store_error);
168: s = alloca(head.len);
169: hyp_ring_fetch(s, rep, head.len, store->rsp, store->rsp + sizeof(store->rsp));
170: mach_atoi((u_char*) s, &i);
171: if (i == MACH_ATOI_DEFAULT)
172: panic("bogus transaction id len %d '%s'", head.len, s);
173: store_put_wait_end();
174: return i;
175: }
176:
177: /* Stop a transaction. */
178: int hyp_store_transaction_stop(hyp_store_transaction_t t) {
179: struct store_req req = {
180: .data = "T",
181: .len = 2,
182: };
183: int ret = 1;
184: void *rep;
185: rep = store_put_wait(t, XS_TRANSACTION_END, &req, 1);
186: if (!rep)
187: return 0;
188: store_put_wait_end();
189: return ret;
190: }
191:
192: /* List a directory: returns an array to file names, terminated by NULL. Free
193: * with kfree. */
194: char **hyp_store_ls(hyp_store_transaction_t t, int n, ...) {
195: struct store_req req[n];
196: va_list listp;
197: int i;
198: char *rep;
199: char *c;
200: char **res, **rsp;
201:
202: va_start (listp, n);
203: for (i = 0; i < n; i++) {
204: req[i].data = va_arg(listp, char *);
205: req[i].len = strlen(req[i].data);
206: }
207: req[n - 1].len++;
208: va_end (listp);
209:
210: rep = store_put_wait(t, XS_DIRECTORY, req, n);
211: if (!rep)
212: return NULL;
213: i = 0;
214: for ( c = rep, n = 0;
215: n < head.len;
216: n += hyp_ring_next_word(&c, store->rsp, store->rsp + sizeof(store->rsp)) + 1)
217: i++;
218: res = (void*) kalloc((i + 1) * sizeof(char*) + head.len);
219: if (!res)
220: hyp_store_error = "ENOMEM";
221: else {
222: hyp_ring_fetch(res + (i + 1), rep, head.len, store->rsp, store->rsp + sizeof(store->rsp));
223: rsp = res;
224: for (c = (char*) (res + (i + 1)); i; i--, c += strlen(c) + 1)
225: *rsp++ = c;
226: *rsp = NULL;
227: }
228: store_put_wait_end();
229: return res;
230: }
231:
232: /* Get the value of an entry, va version. */
233: static void *hyp_store_read_va(hyp_store_transaction_t t, int n, va_list listp) {
234: struct store_req req[n];
235: int i;
236: void *rep;
237: char *res;
238:
239: for (i = 0; i < n; i++) {
240: req[i].data = va_arg(listp, char *);
241: req[i].len = strlen(req[i].data);
242: }
243: req[n - 1].len++;
244:
245: rep = store_put_wait(t, XS_READ, req, n);
246: if (!rep)
247: return NULL;
248: res = (void*) kalloc(head.len + 1);
249: if (!res)
250: hyp_store_error = "ENOMEM";
251: else {
252: hyp_ring_fetch(res, rep, head.len, store->rsp, store->rsp + sizeof(store->rsp));
253: res[head.len] = 0;
254: }
255: store_put_wait_end();
256: return res;
257: }
258:
259: /* Get the value of an entry. Free with kfree. */
260: void *hyp_store_read(hyp_store_transaction_t t, int n, ...) {
261: va_list listp;
262: char *res;
263:
264: va_start(listp, n);
265: res = hyp_store_read_va(t, n, listp);
266: va_end(listp);
267: return res;
268: }
269:
270: /* Get the integer value of an entry, -1 on error. */
271: int hyp_store_read_int(hyp_store_transaction_t t, int n, ...) {
272: va_list listp;
273: char *res;
274: int i;
275:
276: va_start(listp, n);
277: res = hyp_store_read_va(t, n, listp);
278: va_end(listp);
279: if (!res)
280: return -1;
281: mach_atoi((u_char *) res, &i);
282: if (i == MACH_ATOI_DEFAULT)
283: printf("bogus integer '%s'\n", res);
284: kfree((vm_offset_t) res, strlen(res)+1);
285: return i;
286: }
287:
288: /* Set the value of an entry. */
289: char *hyp_store_write(hyp_store_transaction_t t, const char *data, int n, ...) {
290: struct store_req req[n + 1];
291: va_list listp;
292: int i;
293: void *rep;
294: char *res;
295:
296: va_start (listp, n);
297: for (i = 0; i < n; i++) {
298: req[i].data = va_arg(listp, char *);
299: req[i].len = strlen(req[i].data);
300: }
301: req[n - 1].len++;
302: req[n].data = data;
303: req[n].len = strlen (data);
304: va_end (listp);
305:
306: rep = store_put_wait (t, XS_WRITE, req, n + 1);
307: if (!rep)
308: return NULL;
309: res = (void*) kalloc(head.len + 1);
310: if (!res)
311: hyp_store_error = NULL;
312: else {
313: hyp_ring_fetch(res, rep, head.len, store->rsp, store->rsp + sizeof(store->rsp));
314: res[head.len] = 0;
315: }
316: store_put_wait_end();
317: return res;
318: }
319:
320: static void hyp_store_handler(int unit)
321: {
322: thread_wakeup(&boot_info.store_evtchn);
323: }
324:
325: /* Map store's shared page. */
326: void hyp_store_init(void)
327: {
328: if (store)
329: return;
330: simple_lock_init(&lock);
331: store = (void*) mfn_to_kv(boot_info.store_mfn);
332: #ifdef MACH_PV_PAGETABLES
333: pmap_set_page_readwrite(store);
334: #endif /* MACH_PV_PAGETABLES */
335: /* SPL sched */
336: hyp_evt_handler(boot_info.store_evtchn, hyp_store_handler, 0, SPL7);
337: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.