Note: the addition of x0vncserver as a binary is by intent. Crufty to add as source right now
-all: v3_ctrl v3_stop v3_cons v3_mem v3_monitor v3_serial v3_net
+all: v3_ctrl v3_stop v3_cons v3_mem v3_monitor v3_serial v3_net v3_user_host_dev_example
+
v3_ctrl : v3_ctrl.c v3_ctrl.h
v3_net : v3_net.c v3_ctrl.h
gcc -static v3_net.c -o v3_net
+v3_user_host_dev_example: v3_user_host_dev_example.c v3_user_host_dev.h v3_user_host_dev.c
+ gcc -static -I../linux_module v3_user_host_dev_example.c v3_user_host_dev.c -o v3_user_host_dev_example
+
clean:
rm -f v3_ctrl v3_cons v3_mem v3_monitor v3_serial v3_net
--- /dev/null
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <malloc.h>
+
+#include "v3_user_host_dev.h"
+
+
+int v3_user_host_dev_rendezvous(char *vmdev, char *url)
+{
+ int vmfd;
+ int devfd;
+
+ if ((vmfd=open(vmdev,O_RDWR))<0) {
+ return -1;
+ }
+
+ devfd = ioctl(vmfd,V3_VM_HOST_DEV_CONNECT,url);
+
+ close(vmfd);
+
+ return devfd;
+
+}
+int v3_user_host_dev_depart(int devfd)
+{
+ return close(devfd);
+}
+
+
+int v3_user_host_dev_have_request(int devfd)
+{
+ uint64_t len;
+
+ return ioctl(devfd,V3_HOST_DEV_HOST_REQUEST_SIZE_IOCTL,&len)==1;
+}
+
+int v3_user_host_dev_pull_request(int devfd, struct palacios_host_dev_host_request_response **req)
+{
+ uint64_t len;
+ int rc;
+
+ rc=ioctl(devfd,V3_HOST_DEV_HOST_REQUEST_SIZE_IOCTL,&len);
+
+ if (rc<=0) {
+ return -1;
+ } else {
+ struct palacios_host_dev_host_request_response *r = malloc(len);
+
+ rc=ioctl(devfd, V3_HOST_DEV_HOST_REQUEST_PULL_IOCTL,r);
+
+ if (rc<=0) {
+ free(r);
+ return -1;
+ } else {
+ *req=r;
+ return 0;
+ }
+ }
+}
+
+
+int v3_user_host_dev_push_response(int devfd, struct palacios_host_dev_host_request_response *resp)
+{
+ int rc;
+
+ rc=ioctl(devfd, V3_HOST_DEV_USER_RESPONSE_PUSH_IOCTL,resp);
+
+ if (rc<=0) {
+ return -1;
+ } else {
+ return 0;
+ }
+}
+
+
+
+static uint64_t do_user(int devfd, struct palacios_host_dev_user_op *op)
+{
+ return ioctl(devfd, V3_HOST_DEV_USER_REQUEST_PUSH_IOCTL,op);
+}
+
+uint64_t v3_user_host_dev_read_guest_mem(int devfd, void *gpa, void *dest, uint64_t len)
+{
+ struct palacios_host_dev_user_op op;
+
+ op.type= PALACIOS_HOST_DEV_USER_REQUEST_READ_GUEST;
+ op.gpa=gpa;
+ op.data=dest;
+ op.len=len;
+ op.irq=0;
+
+ return do_user(devfd,&op);
+}
+
+uint64_t v3_user_host_dev_write_guest_mem(int devfd, void *gpa, void *src, uint64_t len)
+{
+ struct palacios_host_dev_user_op op;
+
+ op.type= PALACIOS_HOST_DEV_USER_REQUEST_WRITE_GUEST;
+ op.gpa=gpa;
+ op.data=src;
+ op.len=len;
+ op.irq=0;
+
+ return do_user(devfd,&op);
+}
+
+int v3_user_host_dev_inject_irq(int devfd, uint8_t irq)
+{
+ struct palacios_host_dev_user_op op;
+
+ op.type= PALACIOS_HOST_DEV_USER_REQUEST_IRQ_GUEST;
+ op.gpa=0;
+ op.data=0;
+ op.len=0;
+ op.irq=irq;
+
+ return do_user(devfd,&op);
+}
+
+
+
--- /dev/null
+#ifndef _V3_USER_HOST_DEV_
+#define _V3_USER_HOST_DEV_
+
+#include <stdint.h>
+#include "palacios-host-dev-user.h"
+
+int v3_user_host_dev_rendezvous(char *vmdev, char *url); // returns devfd for use in poll/select
+int v3_user_host_dev_depart(int devfd);
+
+int v3_user_host_dev_have_request(int devfd);
+int v3_user_host_dev_pull_request(int devfd, struct palacios_host_dev_host_request_response **req);
+int v3_user_host_dev_push_response(int devfd, struct palacios_host_dev_host_request_response *resp);
+
+uint64_t v3_user_host_dev_read_guest_mem(int devfd, void *gpa, void *dest, uint64_t len);
+uint64_t v3_user_host_dev_write_guest_mem(int devfd, void *gpa, void *src, uint64_t len);
+int v3_user_host_dev_inject_guest_irq(int devfd, uint8_t irq);
+
+#endif
+
--- /dev/null
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/select.h>
+#include <malloc.h>
+
+#include "v3_user_host_dev.h"
+
+void usage()
+{
+ fprintf(stderr,"v3_host_dev_example /dev/v3-vm0 user:mydev busywait|select\n");
+}
+
+
+int do_work(struct palacios_host_dev_host_request_response *req,
+ struct palacios_host_dev_host_request_response **resp)
+{
+ uint64_t datasize;
+
+ //
+ //
+ // Process request here, perhaps calling these functions:
+ //
+ // uint64_t v3_user_host_dev_read_guest_mem(int devfd, void *gpa, void *dest, uint64_t len);
+ // uint64_t v3_user_host_dev_write_guest_mem(int devfd, void *gpa, void *src, uint64_t len);
+ // int v3_user_host_dev_inject_guest_irq(int devfd, uint8_t irq);
+ //
+ // determine datasize - # bytes to include in response
+ //
+ // now built a response
+ *resp = malloc(sizeof(struct palacios_host_dev_host_request_response) + datasize);
+ (*resp)->data_len = sizeof(struct palacios_host_dev_host_request_response) + datasize;
+
+ //
+ // Fill out the fields of the response - notice that there are six kinds of things to response to:
+ // - read/write device port
+ // - read/write device mem
+ // - read/write device configuration space
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int devfd;
+ int mode=0;
+ char *vm, *url;
+
+ if (argc!=4) {
+ usage();
+ exit(-1);
+ }
+
+ vm=argv[1];
+ url=argv[2];
+ mode = argv[3][0]=='s';
+
+ fprintf(stderr,"Attempting to rendezvous with host device %s on vm %s\n", url, vm);
+
+ if ((devfd = v3_user_host_dev_rendezvous(vm,url))<0) {
+ perror("failed to rendezvous");
+ exit(-1);
+ }
+
+ fprintf(stderr,"Rendezvous succeeded, I will now operate in %s mode\n", mode==0 ? "busywait" : "select");
+
+ if (mode==0) {
+ //busywait
+
+ struct palacios_host_dev_host_request_response *req;
+ struct palacios_host_dev_host_request_response *resp;
+ uint64_t datasize;
+
+ while (1) {
+ while (!(v3_user_host_dev_have_request(devfd))) {
+ }
+ v3_user_host_dev_pull_request(devfd, &req);
+
+ do_work(req, &resp);
+
+ v3_user_host_dev_push_response(devfd, resp);
+
+ free(resp);
+ free(req);
+ }
+ } else {
+
+ struct palacios_host_dev_host_request_response *req;
+ struct palacios_host_dev_host_request_response *resp;
+ uint64_t datasize;
+ fd_set readset;
+ int rc;
+
+ // select-based operation so that you can wait for multiple things
+
+ while (1) {
+ FD_ZERO(&readset);
+ FD_SET(devfd,&readset);
+
+ rc = select(devfd+1, &readset, 0, 0, 0); // pick whatever you want to select on, just include devfd
+
+ if (rc>0) {
+ if (FD_ISSET(devfd,&readset)) {
+ // a request is read for us!
+ v3_user_host_dev_pull_request(devfd, &req);
+
+ do_work(req, &resp);
+
+ v3_user_host_dev_push_response(devfd, resp);
+
+ free(resp);
+ free(req);
+ }
+ }
+ }
+ }
+
+ v3_user_host_dev_depart(devfd);
+
+ return 0;
+
+}