|
|
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 */ ! 49: static void store_put(hyp_store_transaction_t t, unsigned32_t type, struct store_req *req, unsigned nr_reqs) { ! 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: ! 108: static void *store_put_wait(hyp_store_transaction_t t, unsigned32_t type, struct store_req *req, unsigned nr_reqs) { ! 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.