11c7850f9SSasha Levin #include "kvm/virtio-pci-dev.h" 21c7850f9SSasha Levin #include "kvm/ioport.h" 31c7850f9SSasha Levin #include "kvm/util.h" 41c7850f9SSasha Levin #include "kvm/threadpool.h" 560eb42d5SSasha Levin #include "kvm/ioeventfd.h" 6bfc15268SAneesh Kumar K.V #include "kvm/irq.h" 7bfc15268SAneesh Kumar K.V #include "kvm/virtio-9p.h" 81c7850f9SSasha Levin 9bfc15268SAneesh Kumar K.V #include <stdio.h> 10bfc15268SAneesh Kumar K.V #include <stdlib.h> 111c7850f9SSasha Levin #include <fcntl.h> 121c7850f9SSasha Levin #include <sys/stat.h> 13bfc15268SAneesh Kumar K.V #include <unistd.h> 14bfc15268SAneesh Kumar K.V #include <string.h> 15bfc15268SAneesh Kumar K.V #include <errno.h> 161c7850f9SSasha Levin 172daa28d4SAneesh Kumar K.V #include <linux/virtio_ring.h> 182daa28d4SAneesh Kumar K.V #include <linux/virtio_9p.h> 192daa28d4SAneesh Kumar K.V #include <net/9p/9p.h> 202daa28d4SAneesh Kumar K.V 211c7850f9SSasha Levin /* Warning: Immediately use value returned from this function */ 22b4422bf3SAneesh Kumar K.V static const char *rel_to_abs(struct p9_dev *p9dev, 23b4422bf3SAneesh Kumar K.V const char *path, char *abs_path) 241c7850f9SSasha Levin { 25b4422bf3SAneesh Kumar K.V sprintf(abs_path, "%s/%s", p9dev->root_dir, path); 261c7850f9SSasha Levin 271c7850f9SSasha Levin return abs_path; 281c7850f9SSasha Levin } 291c7850f9SSasha Levin 30b4422bf3SAneesh Kumar K.V static bool virtio_p9_dev_in(struct p9_dev *p9dev, void *data, 31b4422bf3SAneesh Kumar K.V unsigned long offset, 32b4422bf3SAneesh Kumar K.V int size, u32 count) 331c7850f9SSasha Levin { 34b4422bf3SAneesh Kumar K.V u8 *config_space = (u8 *) p9dev->config; 351c7850f9SSasha Levin 361c7850f9SSasha Levin if (size != 1 || count != 1) 371c7850f9SSasha Levin return false; 381c7850f9SSasha Levin 391c7850f9SSasha Levin ioport__write8(data, config_space[offset - VIRTIO_MSI_CONFIG_VECTOR]); 401c7850f9SSasha Levin 411c7850f9SSasha Levin return true; 421c7850f9SSasha Levin } 431c7850f9SSasha Levin 44b4422bf3SAneesh Kumar K.V static bool virtio_p9_pci_io_in(struct ioport *ioport, struct kvm *kvm, 45b4422bf3SAneesh Kumar K.V u16 port, void *data, int size, u32 count) 461c7850f9SSasha Levin { 471c7850f9SSasha Levin bool ret = true; 48b4422bf3SAneesh Kumar K.V unsigned long offset; 49b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev = ioport->priv; 501c7850f9SSasha Levin 51b4422bf3SAneesh Kumar K.V 52b4422bf3SAneesh Kumar K.V offset = port - p9dev->base_addr; 531c7850f9SSasha Levin 541c7850f9SSasha Levin switch (offset) { 551c7850f9SSasha Levin case VIRTIO_PCI_HOST_FEATURES: 56b4422bf3SAneesh Kumar K.V ioport__write32(data, p9dev->features); 571c7850f9SSasha Levin ret = true; 581c7850f9SSasha Levin break; 591c7850f9SSasha Levin case VIRTIO_PCI_GUEST_FEATURES: 601c7850f9SSasha Levin case VIRTIO_PCI_QUEUE_SEL: 611c7850f9SSasha Levin case VIRTIO_PCI_QUEUE_NOTIFY: 621c7850f9SSasha Levin ret = false; 631c7850f9SSasha Levin break; 641c7850f9SSasha Levin case VIRTIO_PCI_QUEUE_PFN: 65b4422bf3SAneesh Kumar K.V ioport__write32(data, p9dev->vqs[p9dev->queue_selector].pfn); 661c7850f9SSasha Levin break; 671c7850f9SSasha Levin case VIRTIO_PCI_QUEUE_NUM: 68612038c5SAneesh Kumar K.V ioport__write16(data, VIRTQUEUE_NUM); 691c7850f9SSasha Levin break; 701c7850f9SSasha Levin case VIRTIO_PCI_STATUS: 71b4422bf3SAneesh Kumar K.V ioport__write8(data, p9dev->status); 721c7850f9SSasha Levin break; 731c7850f9SSasha Levin case VIRTIO_PCI_ISR: 74b4422bf3SAneesh Kumar K.V ioport__write8(data, p9dev->isr); 75b4422bf3SAneesh Kumar K.V kvm__irq_line(kvm, p9dev->pci_hdr.irq_line, VIRTIO_IRQ_LOW); 76b4422bf3SAneesh Kumar K.V p9dev->isr = VIRTIO_IRQ_LOW; 771c7850f9SSasha Levin break; 781c7850f9SSasha Levin default: 79b4422bf3SAneesh Kumar K.V ret = virtio_p9_dev_in(p9dev, data, offset, size, count); 801c7850f9SSasha Levin break; 811c7850f9SSasha Levin }; 821c7850f9SSasha Levin 831c7850f9SSasha Levin return ret; 841c7850f9SSasha Levin } 851c7850f9SSasha Levin 861c7850f9SSasha Levin static int omode2uflags(u8 mode) 871c7850f9SSasha Levin { 881c7850f9SSasha Levin int ret = 0; 891c7850f9SSasha Levin 901c7850f9SSasha Levin /* Basic open modes are same as uflags */ 911c7850f9SSasha Levin ret = mode & 3; 921c7850f9SSasha Levin 931c7850f9SSasha Levin /* Everything else is different */ 941c7850f9SSasha Levin if (mode & P9_OTRUNC) 951c7850f9SSasha Levin ret |= O_TRUNC; 961c7850f9SSasha Levin 971c7850f9SSasha Levin if (mode & P9_OAPPEND) 981c7850f9SSasha Levin ret |= O_APPEND; 991c7850f9SSasha Levin 1001c7850f9SSasha Levin if (mode & P9_OEXCL) 1011c7850f9SSasha Levin ret |= O_EXCL; 1021c7850f9SSasha Levin 1031c7850f9SSasha Levin return ret; 1041c7850f9SSasha Levin } 1051c7850f9SSasha Levin 1061c7850f9SSasha Levin static void st2qid(struct stat *st, struct p9_qid *qid) 1071c7850f9SSasha Levin { 1081c7850f9SSasha Levin *qid = (struct p9_qid) { 1091c7850f9SSasha Levin .path = st->st_ino, 1101c7850f9SSasha Levin .version = st->st_mtime, 1111c7850f9SSasha Levin }; 1121c7850f9SSasha Levin 1131c7850f9SSasha Levin if (S_ISDIR(st->st_mode)) 1141c7850f9SSasha Levin qid->type |= P9_QTDIR; 1151c7850f9SSasha Levin } 1161c7850f9SSasha Levin 117b4422bf3SAneesh Kumar K.V static void close_fid(struct p9_dev *p9dev, u32 fid) 1181c7850f9SSasha Levin { 119b4422bf3SAneesh Kumar K.V if (p9dev->fids[fid].fd > 0) { 120b4422bf3SAneesh Kumar K.V close(p9dev->fids[fid].fd); 121b4422bf3SAneesh Kumar K.V p9dev->fids[fid].fd = -1; 1221c7850f9SSasha Levin } 123b4422bf3SAneesh Kumar K.V if (p9dev->fids[fid].dir) { 124b4422bf3SAneesh Kumar K.V closedir(p9dev->fids[fid].dir); 125b4422bf3SAneesh Kumar K.V p9dev->fids[fid].dir = NULL; 1261c7850f9SSasha Levin } 1271c7850f9SSasha Levin } 1281c7850f9SSasha Levin 129bfc15268SAneesh Kumar K.V static void virtio_p9_set_reply_header(struct p9_pdu *pdu, u32 size) 1301c7850f9SSasha Levin { 131bfc15268SAneesh Kumar K.V u8 cmd; 132bfc15268SAneesh Kumar K.V u16 tag; 133bfc15268SAneesh Kumar K.V 134bfc15268SAneesh Kumar K.V pdu->read_offset = sizeof(u32); 135bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "bw", &cmd, &tag); 136bfc15268SAneesh Kumar K.V pdu->write_offset = 0; 137bfc15268SAneesh Kumar K.V /* cmd + 1 is the reply message */ 138bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "dbw", size, cmd + 1, tag); 1391c7850f9SSasha Levin } 1401c7850f9SSasha Levin 1416b163a87SAneesh Kumar K.V static u16 virtio_p9_update_iov_cnt(struct iovec iov[], u32 count, int iov_cnt) 1426b163a87SAneesh Kumar K.V { 1436b163a87SAneesh Kumar K.V int i; 1446b163a87SAneesh Kumar K.V u32 total = 0; 1456b163a87SAneesh Kumar K.V for (i = 0; (i < iov_cnt) && (total < count); i++) { 1466b163a87SAneesh Kumar K.V if (total + iov[i].iov_len > count) { 1476b163a87SAneesh Kumar K.V /* we don't need this iov fully */ 1486b163a87SAneesh Kumar K.V iov[i].iov_len -= ((total + iov[i].iov_len) - count); 1496b163a87SAneesh Kumar K.V i++; 1506b163a87SAneesh Kumar K.V break; 1516b163a87SAneesh Kumar K.V } 1526b163a87SAneesh Kumar K.V total += iov[i].iov_len; 1536b163a87SAneesh Kumar K.V } 1546b163a87SAneesh Kumar K.V return i; 1556b163a87SAneesh Kumar K.V } 1566b163a87SAneesh Kumar K.V 157eee1ba8eSAneesh Kumar K.V static void virtio_p9_error_reply(struct p9_dev *p9dev, 158eee1ba8eSAneesh Kumar K.V struct p9_pdu *pdu, int err, u32 *outlen) 159eee1ba8eSAneesh Kumar K.V { 160bfc15268SAneesh Kumar K.V u16 tag; 161eee1ba8eSAneesh Kumar K.V char *err_str; 162eee1ba8eSAneesh Kumar K.V 163eee1ba8eSAneesh Kumar K.V err_str = strerror(err); 164bfc15268SAneesh Kumar K.V pdu->write_offset = VIRTIO_P9_HDR_LEN; 165bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "s", err_str); 166bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 167eee1ba8eSAneesh Kumar K.V 168bfc15268SAneesh Kumar K.V pdu->read_offset = sizeof(u32) + sizeof(u8); 169bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "w", &tag); 170bfc15268SAneesh Kumar K.V 171bfc15268SAneesh Kumar K.V pdu->write_offset = 0; 172bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "dbw", *outlen, P9_RERROR, tag); 173eee1ba8eSAneesh Kumar K.V } 174eee1ba8eSAneesh Kumar K.V 175ead43b01SAneesh Kumar K.V static void virtio_p9_version(struct p9_dev *p9dev, 176af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1771c7850f9SSasha Levin { 178bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "ds", 4096, VIRTIO_P9_VERSION); 1791c7850f9SSasha Levin 180bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 181bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 182ead43b01SAneesh Kumar K.V return; 1831c7850f9SSasha Levin } 1841c7850f9SSasha Levin 185ead43b01SAneesh Kumar K.V static void virtio_p9_clunk(struct p9_dev *p9dev, 186af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1871c7850f9SSasha Levin { 188bfc15268SAneesh Kumar K.V u32 fid; 1891c7850f9SSasha Levin 190bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "d", &fid); 191bfc15268SAneesh Kumar K.V close_fid(p9dev, fid); 1921c7850f9SSasha Levin 193bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 194bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 195ead43b01SAneesh Kumar K.V return; 1961c7850f9SSasha Levin } 1971c7850f9SSasha Levin 198ead43b01SAneesh Kumar K.V static void virtio_p9_open(struct p9_dev *p9dev, 199af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 2001c7850f9SSasha Levin { 201bfc15268SAneesh Kumar K.V u8 mode; 202bfc15268SAneesh Kumar K.V u32 fid; 2031c7850f9SSasha Levin struct stat st; 204bfc15268SAneesh Kumar K.V struct p9_qid qid; 205bfc15268SAneesh Kumar K.V struct p9_fid *new_fid; 206bfc15268SAneesh Kumar K.V 207bfc15268SAneesh Kumar K.V 208bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "db", &fid, &mode); 209bfc15268SAneesh Kumar K.V new_fid = &p9dev->fids[fid]; 2101c7850f9SSasha Levin 21130204a77SAneesh Kumar K.V if (lstat(new_fid->abs_path, &st) < 0) 212eee1ba8eSAneesh Kumar K.V goto err_out; 2131c7850f9SSasha Levin 214bfc15268SAneesh Kumar K.V st2qid(&st, &qid); 2151c7850f9SSasha Levin 216eee1ba8eSAneesh Kumar K.V if (new_fid->is_dir) { 2171c7850f9SSasha Levin new_fid->dir = opendir(new_fid->abs_path); 218eee1ba8eSAneesh Kumar K.V if (!new_fid->dir) 219eee1ba8eSAneesh Kumar K.V goto err_out; 220eee1ba8eSAneesh Kumar K.V } else { 221eee1ba8eSAneesh Kumar K.V new_fid->fd = open(new_fid->abs_path, 222bfc15268SAneesh Kumar K.V omode2uflags(mode) | O_NOFOLLOW); 223eee1ba8eSAneesh Kumar K.V if (new_fid->fd < 0) 224eee1ba8eSAneesh Kumar K.V goto err_out; 225eee1ba8eSAneesh Kumar K.V } 226bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Qd", &qid, 0); 227bfc15268SAneesh Kumar K.V 228bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 229bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 230ead43b01SAneesh Kumar K.V return; 231eee1ba8eSAneesh Kumar K.V err_out: 232eee1ba8eSAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 233ead43b01SAneesh Kumar K.V return; 2341c7850f9SSasha Levin } 2351c7850f9SSasha Levin 236ead43b01SAneesh Kumar K.V static void virtio_p9_create(struct p9_dev *p9dev, 237af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 2381c7850f9SSasha Levin { 2391c7850f9SSasha Levin u8 mode; 2401c7850f9SSasha Levin u32 perm; 241bfc15268SAneesh Kumar K.V char *name; 242bfc15268SAneesh Kumar K.V u32 fid_val; 243af045e53SAneesh Kumar K.V struct stat st; 244bfc15268SAneesh Kumar K.V struct p9_qid qid; 245bfc15268SAneesh Kumar K.V struct p9_fid *fid; 246af045e53SAneesh Kumar K.V 247bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsdb", &fid_val, &name, &perm, &mode); 248bfc15268SAneesh Kumar K.V fid = &p9dev->fids[fid_val]; 2491c7850f9SSasha Levin 250bfc15268SAneesh Kumar K.V sprintf(fid->path, "%s/%.*s", fid->path, (int)strlen(name), name); 251bfc15268SAneesh Kumar K.V close_fid(p9dev, fid_val); 2521c7850f9SSasha Levin 2531c7850f9SSasha Levin if (perm & P9_DMDIR) { 2541c7850f9SSasha Levin mkdir(fid->abs_path, perm & 0xFFFF); 2551c7850f9SSasha Levin fid->dir = opendir(fid->abs_path); 2561c7850f9SSasha Levin fid->is_dir = 1; 2571c7850f9SSasha Levin } else { 258bfc15268SAneesh Kumar K.V fid->fd = open(fid->abs_path, 259bfc15268SAneesh Kumar K.V omode2uflags(mode) | O_CREAT, 0777); 2601c7850f9SSasha Levin } 26130204a77SAneesh Kumar K.V if (lstat(fid->abs_path, &st) < 0) 2626c8ca053SAneesh Kumar K.V goto err_out; 2631c7850f9SSasha Levin 264bfc15268SAneesh Kumar K.V st2qid(&st, &qid); 265bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Qd", &qid, 0); 266bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 267bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 2686c8ca053SAneesh Kumar K.V return; 2696c8ca053SAneesh Kumar K.V err_out: 2706c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 271ead43b01SAneesh Kumar K.V return; 2721c7850f9SSasha Levin } 2731c7850f9SSasha Levin 274ead43b01SAneesh Kumar K.V static void virtio_p9_walk(struct p9_dev *p9dev, 275af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 2761c7850f9SSasha Levin { 277af045e53SAneesh Kumar K.V u8 i; 278bfc15268SAneesh Kumar K.V u16 nwqid; 279bfc15268SAneesh Kumar K.V char *str; 280bfc15268SAneesh Kumar K.V u16 nwname; 281bfc15268SAneesh Kumar K.V u32 fid_val; 282bfc15268SAneesh Kumar K.V u32 newfid_val; 283bfc15268SAneesh Kumar K.V struct p9_qid wqid; 284bfc15268SAneesh Kumar K.V struct p9_fid *new_fid; 285af045e53SAneesh Kumar K.V 2861c7850f9SSasha Levin 287bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "ddw", &fid_val, &newfid_val, &nwname); 288bfc15268SAneesh Kumar K.V new_fid = &p9dev->fids[newfid_val]; 2891c7850f9SSasha Levin 290bfc15268SAneesh Kumar K.V nwqid = 0; 291bfc15268SAneesh Kumar K.V if (nwname) { 292bfc15268SAneesh Kumar K.V struct p9_fid *fid = &p9dev->fids[fid_val]; 293bfc15268SAneesh Kumar K.V 294bfc15268SAneesh Kumar K.V /* skip the space for count */ 295bfc15268SAneesh Kumar K.V pdu->write_offset += sizeof(u16); 296bfc15268SAneesh Kumar K.V for (i = 0; i < nwname; i++) { 297bfc15268SAneesh Kumar K.V struct stat st; 2981c7850f9SSasha Levin char tmp[PATH_MAX] = {0}; 2991c7850f9SSasha Levin char full_path[PATH_MAX]; 300bfc15268SAneesh Kumar K.V 301bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "s", &str); 3021c7850f9SSasha Levin 3031c7850f9SSasha Levin /* Format the new path we're 'walk'ing into */ 304bfc15268SAneesh Kumar K.V sprintf(tmp, "%s/%.*s", 305bfc15268SAneesh Kumar K.V fid->path, (int)strlen(str), str); 30630204a77SAneesh Kumar K.V if (lstat(rel_to_abs(p9dev, tmp, full_path), &st) < 0) 3076c8ca053SAneesh Kumar K.V goto err_out; 3081c7850f9SSasha Levin 309bfc15268SAneesh Kumar K.V st2qid(&st, &wqid); 3101c7850f9SSasha Levin new_fid->is_dir = S_ISDIR(st.st_mode); 3111c7850f9SSasha Levin strcpy(new_fid->path, tmp); 312bfc15268SAneesh Kumar K.V new_fid->fid = newfid_val; 313bfc15268SAneesh Kumar K.V nwqid++; 314bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Q", &wqid); 3151c7850f9SSasha Levin } 3161c7850f9SSasha Levin } else { 317bfc15268SAneesh Kumar K.V /* 318bfc15268SAneesh Kumar K.V * update write_offset so our outlen get correct value 319bfc15268SAneesh Kumar K.V */ 320bfc15268SAneesh Kumar K.V pdu->write_offset += sizeof(u16); 321bfc15268SAneesh Kumar K.V new_fid->is_dir = p9dev->fids[fid_val].is_dir; 322bfc15268SAneesh Kumar K.V strcpy(new_fid->path, p9dev->fids[fid_val].path); 323bfc15268SAneesh Kumar K.V new_fid->fid = newfid_val; 3241c7850f9SSasha Levin } 325bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 326bfc15268SAneesh Kumar K.V pdu->write_offset = VIRTIO_P9_HDR_LEN; 327bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", nwqid); 328bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 3296c8ca053SAneesh Kumar K.V return; 3306c8ca053SAneesh Kumar K.V err_out: 3316c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 332ead43b01SAneesh Kumar K.V return; 3331c7850f9SSasha Levin } 3341c7850f9SSasha Levin 335ead43b01SAneesh Kumar K.V static void virtio_p9_attach(struct p9_dev *p9dev, 336af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 3371c7850f9SSasha Levin { 338af045e53SAneesh Kumar K.V u32 i; 339bfc15268SAneesh Kumar K.V u32 fid_val; 340bfc15268SAneesh Kumar K.V u32 afid; 341bfc15268SAneesh Kumar K.V char *uname; 342bfc15268SAneesh Kumar K.V char *aname; 3431c7850f9SSasha Levin struct stat st; 344bfc15268SAneesh Kumar K.V struct p9_qid qid; 3451c7850f9SSasha Levin struct p9_fid *fid; 346bfc15268SAneesh Kumar K.V 347bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "ddss", &fid_val, &afid, &uname, &aname); 3481c7850f9SSasha Levin 3491c7850f9SSasha Levin /* Reset everything */ 3501c7850f9SSasha Levin for (i = 0; i < VIRTIO_P9_MAX_FID; i++) 351b4422bf3SAneesh Kumar K.V p9dev->fids[i].fid = P9_NOFID; 3521c7850f9SSasha Levin 35330204a77SAneesh Kumar K.V if (lstat(p9dev->root_dir, &st) < 0) 3546c8ca053SAneesh Kumar K.V goto err_out; 3551c7850f9SSasha Levin 356bfc15268SAneesh Kumar K.V st2qid(&st, &qid); 3571c7850f9SSasha Levin 358bfc15268SAneesh Kumar K.V fid = &p9dev->fids[fid_val]; 359bfc15268SAneesh Kumar K.V fid->fid = fid_val; 3601c7850f9SSasha Levin fid->is_dir = 1; 3611c7850f9SSasha Levin strcpy(fid->path, "/"); 3621c7850f9SSasha Levin 363bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Q", &qid); 364bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 365bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 3666c8ca053SAneesh Kumar K.V return; 3676c8ca053SAneesh Kumar K.V err_out: 3686c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 369ead43b01SAneesh Kumar K.V return; 3701c7850f9SSasha Levin } 3711c7850f9SSasha Levin 372bfc15268SAneesh Kumar K.V static void virtio_p9_fill_stat(struct p9_dev *p9dev, const char *name, 373bfc15268SAneesh Kumar K.V struct stat *st, struct p9_wstat *wstat) 3741c7850f9SSasha Levin { 375bfc15268SAneesh Kumar K.V wstat->type = 0; 376bfc15268SAneesh Kumar K.V wstat->dev = 0; 377bfc15268SAneesh Kumar K.V st2qid(st, &wstat->qid); 378bfc15268SAneesh Kumar K.V wstat->mode = st->st_mode; 379bfc15268SAneesh Kumar K.V wstat->length = st->st_size; 3801c7850f9SSasha Levin if (S_ISDIR(st->st_mode)) { 381bfc15268SAneesh Kumar K.V wstat->length = 0; 382bfc15268SAneesh Kumar K.V wstat->mode |= P9_DMDIR; 3831c7850f9SSasha Levin } 3841c7850f9SSasha Levin 385bfc15268SAneesh Kumar K.V wstat->atime = st->st_atime; 386bfc15268SAneesh Kumar K.V wstat->mtime = st->st_mtime; 3871c7850f9SSasha Levin 388bfc15268SAneesh Kumar K.V wstat->name = strdup(name); 389bfc15268SAneesh Kumar K.V wstat->uid = NULL; 390bfc15268SAneesh Kumar K.V wstat->gid = NULL; 391bfc15268SAneesh Kumar K.V wstat->muid = NULL; 3921c7850f9SSasha Levin 393bfc15268SAneesh Kumar K.V /* NOTE: size shouldn't include its own length */ 394bfc15268SAneesh Kumar K.V /* size[2] type[2] dev[4] qid[13] */ 395bfc15268SAneesh Kumar K.V /* mode[4] atime[4] mtime[4] length[8]*/ 396bfc15268SAneesh Kumar K.V /* name[s] uid[s] gid[s] muid[s] */ 397bfc15268SAneesh Kumar K.V wstat->size = 2+4+13+4+4+4+8+2+2+2+2; 398bfc15268SAneesh Kumar K.V if (wstat->name) 399bfc15268SAneesh Kumar K.V wstat->size += strlen(wstat->name); 4001c7850f9SSasha Levin } 4011c7850f9SSasha Levin 402ead43b01SAneesh Kumar K.V static void virtio_p9_read(struct p9_dev *p9dev, 403af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 4041c7850f9SSasha Levin { 405bfc15268SAneesh Kumar K.V u64 offset; 406bfc15268SAneesh Kumar K.V u32 fid_val; 407bfc15268SAneesh Kumar K.V u32 count, rcount; 4081c7850f9SSasha Levin struct stat st; 409bfc15268SAneesh Kumar K.V struct p9_fid *fid; 410bfc15268SAneesh Kumar K.V struct p9_wstat wstat; 4111c7850f9SSasha Levin 412bfc15268SAneesh Kumar K.V rcount = 0; 413bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count); 414bfc15268SAneesh Kumar K.V fid = &p9dev->fids[fid_val]; 4151c7850f9SSasha Levin if (fid->is_dir) { 4161c7850f9SSasha Levin /* If reading a dir, fill the buffer with p9_stat entries */ 4171c7850f9SSasha Levin char full_path[PATH_MAX]; 418bfc15268SAneesh Kumar K.V struct dirent *cur = readdir(fid->dir); 4191c7850f9SSasha Levin 420bfc15268SAneesh Kumar K.V /* Skip the space for writing count */ 421bfc15268SAneesh Kumar K.V pdu->write_offset += sizeof(u32); 4221c7850f9SSasha Levin while (cur) { 4231c7850f9SSasha Levin u32 read; 4241c7850f9SSasha Levin 42530204a77SAneesh Kumar K.V lstat(rel_to_abs(p9dev, cur->d_name, full_path), &st); 426bfc15268SAneesh Kumar K.V virtio_p9_fill_stat(p9dev, cur->d_name, &st, &wstat); 427bfc15268SAneesh Kumar K.V 428bfc15268SAneesh Kumar K.V read = pdu->write_offset; 429bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "S", &wstat); 430bfc15268SAneesh Kumar K.V rcount += pdu->write_offset - read; 431bfc15268SAneesh Kumar K.V 4321c7850f9SSasha Levin cur = readdir(fid->dir); 4331c7850f9SSasha Levin } 4341c7850f9SSasha Levin } else { 435af045e53SAneesh Kumar K.V pdu->in_iov[0].iov_base += VIRTIO_P9_HDR_LEN + sizeof(u32); 436af045e53SAneesh Kumar K.V pdu->in_iov[0].iov_len -= VIRTIO_P9_HDR_LEN + sizeof(u32); 4376b163a87SAneesh Kumar K.V pdu->in_iov_cnt = virtio_p9_update_iov_cnt(pdu->in_iov, 438bfc15268SAneesh Kumar K.V count, 4396b163a87SAneesh Kumar K.V pdu->in_iov_cnt); 440bfc15268SAneesh Kumar K.V rcount = preadv(fid->fd, pdu->in_iov, 441bfc15268SAneesh Kumar K.V pdu->in_iov_cnt, offset); 442bfc15268SAneesh Kumar K.V if (rcount > count) 443bfc15268SAneesh Kumar K.V rcount = count; 444bfc15268SAneesh Kumar K.V /* 445bfc15268SAneesh Kumar K.V * Update the iov_base back, so that rest of 446bfc15268SAneesh Kumar K.V * pdu_writef works correctly. 447bfc15268SAneesh Kumar K.V */ 448bfc15268SAneesh Kumar K.V pdu->in_iov[0].iov_base -= VIRTIO_P9_HDR_LEN + sizeof(u32); 449bfc15268SAneesh Kumar K.V pdu->in_iov[0].iov_len += VIRTIO_P9_HDR_LEN + sizeof(u32); 4501c7850f9SSasha Levin 451bfc15268SAneesh Kumar K.V } 452bfc15268SAneesh Kumar K.V pdu->write_offset = VIRTIO_P9_HDR_LEN; 453bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", rcount); 454bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset + rcount; 455bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 4561c7850f9SSasha Levin 457ead43b01SAneesh Kumar K.V return; 4581c7850f9SSasha Levin } 4591c7850f9SSasha Levin 460ead43b01SAneesh Kumar K.V static void virtio_p9_stat(struct p9_dev *p9dev, 461af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 4621c7850f9SSasha Levin { 463bfc15268SAneesh Kumar K.V u32 fid_val; 464af045e53SAneesh Kumar K.V struct stat st; 465bfc15268SAneesh Kumar K.V struct p9_fid *fid; 466bfc15268SAneesh Kumar K.V struct p9_wstat wstat; 4671c7850f9SSasha Levin 468bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "d", &fid_val); 469bfc15268SAneesh Kumar K.V fid = &p9dev->fids[fid_val]; 47030204a77SAneesh Kumar K.V if (lstat(fid->abs_path, &st) < 0) 4716c8ca053SAneesh Kumar K.V goto err_out; 4721c7850f9SSasha Levin 473bfc15268SAneesh Kumar K.V virtio_p9_fill_stat(p9dev, fid->path, &st, &wstat); 4741c7850f9SSasha Levin 475bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "wS", 0, &wstat); 476bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 477bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 478ead43b01SAneesh Kumar K.V return; 4796c8ca053SAneesh Kumar K.V err_out: 4806c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 4816c8ca053SAneesh Kumar K.V return; 4821c7850f9SSasha Levin } 4831c7850f9SSasha Levin 484ead43b01SAneesh Kumar K.V static void virtio_p9_wstat(struct p9_dev *p9dev, 485af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 4861c7850f9SSasha Levin { 487aec426f0SCyrill Gorcunov int res = 0; 488bfc15268SAneesh Kumar K.V u32 fid_val; 489bfc15268SAneesh Kumar K.V u16 unused; 490bfc15268SAneesh Kumar K.V struct p9_fid *fid; 491bfc15268SAneesh Kumar K.V struct p9_wstat wstat; 492af045e53SAneesh Kumar K.V 493bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dwS", &fid_val, &unused, &wstat); 494bfc15268SAneesh Kumar K.V fid = &p9dev->fids[fid_val]; 4951c7850f9SSasha Levin 496bfc15268SAneesh Kumar K.V if (wstat.length != -1UL) 497bfc15268SAneesh Kumar K.V res = ftruncate(fid->fd, wstat.length); 4981c7850f9SSasha Levin 499bfc15268SAneesh Kumar K.V if (wstat.mode != -1U) 500bfc15268SAneesh Kumar K.V chmod(fid->abs_path, wstat.mode & 0xFFFF); 5011c7850f9SSasha Levin 502bfc15268SAneesh Kumar K.V if (strlen(wstat.name) > 0) { 5031c7850f9SSasha Levin char new_name[PATH_MAX] = {0}; 5041c7850f9SSasha Levin char full_path[PATH_MAX]; 5051c7850f9SSasha Levin char *last_dir = strrchr(fid->path, '/'); 5061c7850f9SSasha Levin 5071c7850f9SSasha Levin /* We need to get the full file name out of twstat->name */ 5081c7850f9SSasha Levin if (last_dir) 5091c7850f9SSasha Levin strncpy(new_name, fid->path, last_dir - fid->path + 1); 5101c7850f9SSasha Levin 511bfc15268SAneesh Kumar K.V memcpy(new_name + strlen(new_name), 512bfc15268SAneesh Kumar K.V wstat.name, strlen(wstat.name)); 5131c7850f9SSasha Levin 5141c7850f9SSasha Levin /* fid is reused for the new file */ 515b4422bf3SAneesh Kumar K.V rename(fid->abs_path, rel_to_abs(p9dev, new_name, full_path)); 5161c7850f9SSasha Levin sprintf(fid->path, "%s", new_name); 5171c7850f9SSasha Levin } 5181c7850f9SSasha Levin *outlen = VIRTIO_P9_HDR_LEN; 519bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 520ead43b01SAneesh Kumar K.V return; 5211c7850f9SSasha Levin } 5221c7850f9SSasha Levin 523ead43b01SAneesh Kumar K.V static void virtio_p9_remove(struct p9_dev *p9dev, 524af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 5251c7850f9SSasha Levin { 526bfc15268SAneesh Kumar K.V u32 fid_val; 527bfc15268SAneesh Kumar K.V struct p9_fid *fid; 5281c7850f9SSasha Levin 529bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "d", &fid_val); 530bfc15268SAneesh Kumar K.V fid = &p9dev->fids[fid_val]; 531bfc15268SAneesh Kumar K.V close_fid(p9dev, fid_val); 5321c7850f9SSasha Levin if (fid->is_dir) 5331c7850f9SSasha Levin rmdir(fid->abs_path); 5341c7850f9SSasha Levin else 5351c7850f9SSasha Levin unlink(fid->abs_path); 5361c7850f9SSasha Levin 5371c7850f9SSasha Levin *outlen = VIRTIO_P9_HDR_LEN; 538bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 539ead43b01SAneesh Kumar K.V return; 5401c7850f9SSasha Levin } 5411c7850f9SSasha Levin 542ead43b01SAneesh Kumar K.V static void virtio_p9_write(struct p9_dev *p9dev, 543af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 5441c7850f9SSasha Levin { 545bfc15268SAneesh Kumar K.V u64 offset; 546bfc15268SAneesh Kumar K.V u32 fid_val; 547bfc15268SAneesh Kumar K.V u32 count, rcount; 548bfc15268SAneesh Kumar K.V struct p9_fid *fid; 5491c7850f9SSasha Levin 550bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count); 551bfc15268SAneesh Kumar K.V fid = &p9dev->fids[fid_val]; 552af045e53SAneesh Kumar K.V 553bfc15268SAneesh Kumar K.V /* Adjust the iovec to skip the header and meta data */ 554bfc15268SAneesh Kumar K.V pdu->out_iov[0].iov_base += (sizeof(struct p9_msg) + 555bfc15268SAneesh Kumar K.V sizeof(struct p9_twrite)); 556bfc15268SAneesh Kumar K.V pdu->out_iov[0].iov_len -= (sizeof(struct p9_msg) + 557bfc15268SAneesh Kumar K.V sizeof(struct p9_twrite)); 558bfc15268SAneesh Kumar K.V pdu->out_iov_cnt = virtio_p9_update_iov_cnt(pdu->out_iov, count, 5596b163a87SAneesh Kumar K.V pdu->out_iov_cnt); 560bfc15268SAneesh Kumar K.V rcount = pwritev(fid->fd, pdu->out_iov, pdu->out_iov_cnt, offset); 561bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", rcount); 562bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 563bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 564ead43b01SAneesh Kumar K.V return; 5651c7850f9SSasha Levin } 5661c7850f9SSasha Levin 567ead43b01SAneesh Kumar K.V typedef void p9_handler(struct p9_dev *p9dev, 568af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen); 569b4422bf3SAneesh Kumar K.V 570b4422bf3SAneesh Kumar K.V static p9_handler *virtio_9p_handler [] = { 571b4422bf3SAneesh Kumar K.V [P9_TVERSION] = virtio_p9_version, 572b4422bf3SAneesh Kumar K.V [P9_TATTACH] = virtio_p9_attach, 573b4422bf3SAneesh Kumar K.V [P9_TSTAT] = virtio_p9_stat, 574b4422bf3SAneesh Kumar K.V [P9_TCLUNK] = virtio_p9_clunk, 575b4422bf3SAneesh Kumar K.V [P9_TWALK] = virtio_p9_walk, 576b4422bf3SAneesh Kumar K.V [P9_TOPEN] = virtio_p9_open, 577b4422bf3SAneesh Kumar K.V [P9_TREAD] = virtio_p9_read, 578b4422bf3SAneesh Kumar K.V [P9_TCREATE] = virtio_p9_create, 579b4422bf3SAneesh Kumar K.V [P9_TWSTAT] = virtio_p9_wstat, 580b4422bf3SAneesh Kumar K.V [P9_TREMOVE] = virtio_p9_remove, 581b4422bf3SAneesh Kumar K.V [P9_TWRITE] = virtio_p9_write, 582b4422bf3SAneesh Kumar K.V }; 583b4422bf3SAneesh Kumar K.V 584af045e53SAneesh Kumar K.V static struct p9_pdu *virtio_p9_pdu_init(struct kvm *kvm, struct virt_queue *vq) 585af045e53SAneesh Kumar K.V { 586af045e53SAneesh Kumar K.V struct p9_pdu *pdu = calloc(1, sizeof(*pdu)); 587af045e53SAneesh Kumar K.V if (!pdu) 588af045e53SAneesh Kumar K.V return NULL; 589af045e53SAneesh Kumar K.V 590bfc15268SAneesh Kumar K.V /* skip the pdu header p9_msg */ 591bfc15268SAneesh Kumar K.V pdu->read_offset = VIRTIO_P9_HDR_LEN; 592bfc15268SAneesh Kumar K.V pdu->write_offset = VIRTIO_P9_HDR_LEN; 593af045e53SAneesh Kumar K.V pdu->queue_head = virt_queue__get_inout_iov(kvm, vq, pdu->in_iov, 594af045e53SAneesh Kumar K.V pdu->out_iov, 595af045e53SAneesh Kumar K.V &pdu->in_iov_cnt, 596af045e53SAneesh Kumar K.V &pdu->out_iov_cnt); 597af045e53SAneesh Kumar K.V return pdu; 598af045e53SAneesh Kumar K.V } 599af045e53SAneesh Kumar K.V 600af045e53SAneesh Kumar K.V static u8 virtio_p9_get_cmd(struct p9_pdu *pdu) 601af045e53SAneesh Kumar K.V { 602af045e53SAneesh Kumar K.V struct p9_msg *msg; 603af045e53SAneesh Kumar K.V /* 604af045e53SAneesh Kumar K.V * we can peek directly into pdu for a u8 605af045e53SAneesh Kumar K.V * value. The host endianess won't be an issue 606af045e53SAneesh Kumar K.V */ 607af045e53SAneesh Kumar K.V msg = pdu->out_iov[0].iov_base; 608af045e53SAneesh Kumar K.V return msg->cmd; 609af045e53SAneesh Kumar K.V } 610af045e53SAneesh Kumar K.V 61197b408afSAneesh Kumar K.V static void virtio_p9_eopnotsupp(struct p9_dev *p9dev, 61297b408afSAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 61397b408afSAneesh Kumar K.V { 61497b408afSAneesh Kumar K.V return virtio_p9_error_reply(p9dev, pdu, EOPNOTSUPP, outlen); 61597b408afSAneesh Kumar K.V } 61697b408afSAneesh Kumar K.V 617b4422bf3SAneesh Kumar K.V static bool virtio_p9_do_io_request(struct kvm *kvm, struct p9_dev_job *job) 6181c7850f9SSasha Levin { 619af045e53SAneesh Kumar K.V u8 cmd; 620b4422bf3SAneesh Kumar K.V u32 len = 0; 621b4422bf3SAneesh Kumar K.V p9_handler *handler; 622b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev; 623af045e53SAneesh Kumar K.V struct virt_queue *vq; 624af045e53SAneesh Kumar K.V struct p9_pdu *p9pdu; 6251c7850f9SSasha Levin 626b4422bf3SAneesh Kumar K.V vq = job->vq; 627b4422bf3SAneesh Kumar K.V p9dev = job->p9dev; 6281c7850f9SSasha Levin 629af045e53SAneesh Kumar K.V p9pdu = virtio_p9_pdu_init(kvm, vq); 630af045e53SAneesh Kumar K.V cmd = virtio_p9_get_cmd(p9pdu); 631af045e53SAneesh Kumar K.V 632af045e53SAneesh Kumar K.V if (cmd >= ARRAY_SIZE(virtio_9p_handler) || 633af045e53SAneesh Kumar K.V !virtio_9p_handler[cmd]) { 63497b408afSAneesh Kumar K.V handler = virtio_p9_eopnotsupp; 635b4422bf3SAneesh Kumar K.V } else { 636af045e53SAneesh Kumar K.V handler = virtio_9p_handler[cmd]; 637af045e53SAneesh Kumar K.V handler(p9dev, p9pdu, &len); 638b4422bf3SAneesh Kumar K.V } 639af045e53SAneesh Kumar K.V virt_queue__set_used_elem(vq, p9pdu->queue_head, len); 640af045e53SAneesh Kumar K.V free(p9pdu); 6411c7850f9SSasha Levin return true; 6421c7850f9SSasha Levin } 6431c7850f9SSasha Levin 6441c7850f9SSasha Levin static void virtio_p9_do_io(struct kvm *kvm, void *param) 6451c7850f9SSasha Levin { 646b4422bf3SAneesh Kumar K.V struct p9_dev_job *job = (struct p9_dev_job *)param; 647b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev = job->p9dev; 648b4422bf3SAneesh Kumar K.V struct virt_queue *vq = job->vq; 6491c7850f9SSasha Levin 6501c7850f9SSasha Levin while (virt_queue__available(vq)) { 651b4422bf3SAneesh Kumar K.V virtio_p9_do_io_request(kvm, job); 652b4422bf3SAneesh Kumar K.V virt_queue__trigger_irq(vq, p9dev->pci_hdr.irq_line, 653b4422bf3SAneesh Kumar K.V &p9dev->isr, kvm); 6541c7850f9SSasha Levin } 6551c7850f9SSasha Levin } 6561c7850f9SSasha Levin 65760eb42d5SSasha Levin static void ioevent_callback(struct kvm *kvm, void *param) 65860eb42d5SSasha Levin { 65960eb42d5SSasha Levin struct p9_dev_job *job = param; 66060eb42d5SSasha Levin 661*df0c7f57SSasha Levin thread_pool__do_job(&job->job_id); 66260eb42d5SSasha Levin } 66360eb42d5SSasha Levin 664b4422bf3SAneesh Kumar K.V static bool virtio_p9_pci_io_out(struct ioport *ioport, struct kvm *kvm, 665b4422bf3SAneesh Kumar K.V u16 port, void *data, int size, u32 count) 6661c7850f9SSasha Levin { 6671c7850f9SSasha Levin unsigned long offset; 6681c7850f9SSasha Levin bool ret = true; 669b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev; 67060eb42d5SSasha Levin struct ioevent ioevent; 6711c7850f9SSasha Levin 672b4422bf3SAneesh Kumar K.V p9dev = ioport->priv; 673b4422bf3SAneesh Kumar K.V offset = port - p9dev->base_addr; 6741c7850f9SSasha Levin 6751c7850f9SSasha Levin switch (offset) { 6761c7850f9SSasha Levin case VIRTIO_MSI_QUEUE_VECTOR: 6771c7850f9SSasha Levin case VIRTIO_PCI_GUEST_FEATURES: 6781c7850f9SSasha Levin break; 6791c7850f9SSasha Levin case VIRTIO_PCI_QUEUE_PFN: { 6801c7850f9SSasha Levin void *p; 681b4422bf3SAneesh Kumar K.V struct p9_dev_job *job; 682b4422bf3SAneesh Kumar K.V struct virt_queue *queue; 6831c7850f9SSasha Levin 684b4422bf3SAneesh Kumar K.V job = &p9dev->jobs[p9dev->queue_selector]; 685b4422bf3SAneesh Kumar K.V queue = &p9dev->vqs[p9dev->queue_selector]; 6861c7850f9SSasha Levin queue->pfn = ioport__read32(data); 6871c7850f9SSasha Levin p = guest_pfn_to_host(kvm, queue->pfn); 6881c7850f9SSasha Levin 689612038c5SAneesh Kumar K.V vring_init(&queue->vring, VIRTQUEUE_NUM, p, 690b4422bf3SAneesh Kumar K.V VIRTIO_PCI_VRING_ALIGN); 6911c7850f9SSasha Levin 692b4422bf3SAneesh Kumar K.V *job = (struct p9_dev_job) { 693b4422bf3SAneesh Kumar K.V .vq = queue, 694b4422bf3SAneesh Kumar K.V .p9dev = p9dev, 695b4422bf3SAneesh Kumar K.V }; 696*df0c7f57SSasha Levin thread_pool__init_job(&job->job_id, kvm, virtio_p9_do_io, job); 69760eb42d5SSasha Levin 69860eb42d5SSasha Levin ioevent = (struct ioevent) { 69960eb42d5SSasha Levin .io_addr = p9dev->base_addr + VIRTIO_PCI_QUEUE_NOTIFY, 70060eb42d5SSasha Levin .io_len = sizeof(u16), 70160eb42d5SSasha Levin .fn = ioevent_callback, 70260eb42d5SSasha Levin .datamatch = p9dev->queue_selector, 70360eb42d5SSasha Levin .fn_ptr = &p9dev->jobs[p9dev->queue_selector], 70460eb42d5SSasha Levin .fn_kvm = kvm, 70560eb42d5SSasha Levin .fd = eventfd(0, 0), 70660eb42d5SSasha Levin }; 70760eb42d5SSasha Levin 70860eb42d5SSasha Levin ioeventfd__add_event(&ioevent); 70960eb42d5SSasha Levin 7101c7850f9SSasha Levin break; 7111c7850f9SSasha Levin } 7121c7850f9SSasha Levin case VIRTIO_PCI_QUEUE_SEL: 713b4422bf3SAneesh Kumar K.V p9dev->queue_selector = ioport__read16(data); 7141c7850f9SSasha Levin break; 7151c7850f9SSasha Levin case VIRTIO_PCI_QUEUE_NOTIFY: { 7161c7850f9SSasha Levin u16 queue_index; 71760eb42d5SSasha Levin 7181c7850f9SSasha Levin queue_index = ioport__read16(data); 719*df0c7f57SSasha Levin thread_pool__do_job(&p9dev->jobs[queue_index].job_id); 7201c7850f9SSasha Levin break; 7211c7850f9SSasha Levin } 7221c7850f9SSasha Levin case VIRTIO_PCI_STATUS: 723b4422bf3SAneesh Kumar K.V p9dev->status = ioport__read8(data); 7241c7850f9SSasha Levin break; 7251c7850f9SSasha Levin case VIRTIO_MSI_CONFIG_VECTOR: 726b4422bf3SAneesh Kumar K.V p9dev->config_vector = VIRTIO_MSI_NO_VECTOR; 7271c7850f9SSasha Levin break; 7281c7850f9SSasha Levin default: 7291c7850f9SSasha Levin ret = false; 7301c7850f9SSasha Levin break; 7311c7850f9SSasha Levin }; 7321c7850f9SSasha Levin 7331c7850f9SSasha Levin return ret; 7341c7850f9SSasha Levin } 7351c7850f9SSasha Levin 7361c7850f9SSasha Levin static struct ioport_operations virtio_p9_io_ops = { 7371c7850f9SSasha Levin .io_in = virtio_p9_pci_io_in, 7381c7850f9SSasha Levin .io_out = virtio_p9_pci_io_out, 7391c7850f9SSasha Levin }; 7401c7850f9SSasha Levin 741b4422bf3SAneesh Kumar K.V void virtio_9p__init(struct kvm *kvm, const char *root, const char *tag_name) 7421c7850f9SSasha Levin { 7431c7850f9SSasha Levin u8 pin, line, dev; 7441c7850f9SSasha Levin u32 i, root_len; 745f884f920SSasha Levin u16 p9_base_addr; 746b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev; 7471c7850f9SSasha Levin 748b4422bf3SAneesh Kumar K.V p9dev = calloc(1, sizeof(*p9dev)); 749b4422bf3SAneesh Kumar K.V if (!p9dev) 7501c7850f9SSasha Levin return; 751b4422bf3SAneesh Kumar K.V if (!tag_name) 752b4422bf3SAneesh Kumar K.V tag_name = VIRTIO_P9_DEFAULT_TAG; 753b4422bf3SAneesh Kumar K.V p9dev->config = calloc(1, sizeof(*p9dev->config) + strlen(tag_name) + 1); 754b4422bf3SAneesh Kumar K.V if (p9dev->config == NULL) 755b4422bf3SAneesh Kumar K.V goto free_p9dev; 7561c7850f9SSasha Levin 757b4422bf3SAneesh Kumar K.V strcpy(p9dev->root_dir, root); 7581c7850f9SSasha Levin root_len = strlen(root); 7591c7850f9SSasha Levin /* 7601c7850f9SSasha Levin * We prefix the full path in all fids, This allows us to get the 7611c7850f9SSasha Levin * absolute path of an fid without playing with strings. 7621c7850f9SSasha Levin */ 7631c7850f9SSasha Levin for (i = 0; i < VIRTIO_P9_MAX_FID; i++) { 764b4422bf3SAneesh Kumar K.V strcpy(p9dev->fids[i].abs_path, root); 765b4422bf3SAneesh Kumar K.V p9dev->fids[i].path = p9dev->fids[i].abs_path + root_len; 7661c7850f9SSasha Levin } 767b4422bf3SAneesh Kumar K.V p9dev->config->tag_len = strlen(tag_name); 768b4422bf3SAneesh Kumar K.V if (p9dev->config->tag_len > MAX_TAG_LEN) 769b4422bf3SAneesh Kumar K.V goto free_p9dev_config; 7701c7850f9SSasha Levin 771b4422bf3SAneesh Kumar K.V memcpy(p9dev->config->tag, tag_name, strlen(tag_name)); 772b4422bf3SAneesh Kumar K.V p9dev->features |= 1 << VIRTIO_9P_MOUNT_TAG; 7731c7850f9SSasha Levin 7741c7850f9SSasha Levin if (irq__register_device(VIRTIO_ID_9P, &dev, &pin, &line) < 0) 775b4422bf3SAneesh Kumar K.V goto free_p9dev_config; 7761c7850f9SSasha Levin 777b4422bf3SAneesh Kumar K.V p9_base_addr = ioport__register(IOPORT_EMPTY, 778b4422bf3SAneesh Kumar K.V &virtio_p9_io_ops, 779b4422bf3SAneesh Kumar K.V IOPORT_SIZE, p9dev); 780b4422bf3SAneesh Kumar K.V p9dev->base_addr = p9_base_addr; 781b4422bf3SAneesh Kumar K.V p9dev->pci_hdr = (struct pci_device_header) { 782b4422bf3SAneesh Kumar K.V .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, 783b4422bf3SAneesh Kumar K.V .device_id = PCI_DEVICE_ID_VIRTIO_P9, 784b4422bf3SAneesh Kumar K.V .header_type = PCI_HEADER_TYPE_NORMAL, 785b4422bf3SAneesh Kumar K.V .revision_id = 0, 786b4422bf3SAneesh Kumar K.V .class = 0x010000, 787b4422bf3SAneesh Kumar K.V .subsys_vendor_id = PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET, 788b4422bf3SAneesh Kumar K.V .subsys_id = VIRTIO_ID_9P, 789b4422bf3SAneesh Kumar K.V .irq_pin = pin, 790b4422bf3SAneesh Kumar K.V .irq_line = line, 791b4422bf3SAneesh Kumar K.V .bar[0] = p9_base_addr | PCI_BASE_ADDRESS_SPACE_IO, 792b4422bf3SAneesh Kumar K.V }; 793b4422bf3SAneesh Kumar K.V pci__register(&p9dev->pci_hdr, dev); 794b4422bf3SAneesh Kumar K.V 795b4422bf3SAneesh Kumar K.V return; 796b4422bf3SAneesh Kumar K.V free_p9dev_config: 797b4422bf3SAneesh Kumar K.V free(p9dev->config); 798b4422bf3SAneesh Kumar K.V free_p9dev: 799b4422bf3SAneesh Kumar K.V free(p9dev); 8001c7850f9SSasha Levin } 801