aboutsummaryrefslogtreecommitdiffstats
path: root/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/dom0_core.c
diff options
context:
space:
mode:
Diffstat (limited to 'xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/dom0_core.c')
-rw-r--r--xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/dom0_core.c334
1 files changed, 334 insertions, 0 deletions
diff --git a/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/dom0_core.c b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/dom0_core.c
new file mode 100644
index 0000000000..f8af85358b
--- /dev/null
+++ b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/dom0_core.c
@@ -0,0 +1,334 @@
+/******************************************************************************
+ * dom0_core.c
+ *
+ * Interface to privileged domain-0 commands.
+ *
+ * Copyright (c) 2002, K A Fraser, B Dragovic
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/swap.h>
+#include <linux/smp_lock.h>
+#include <linux/swapctl.h>
+#include <linux/iobuf.h>
+#include <linux/highmem.h>
+#include <linux/pagemap.h>
+
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <asm/tlb.h>
+
+#include "dom0_ops.h"
+
+/* Private proc-file data structures. */
+typedef struct proc_data {
+ unsigned int domain;
+ unsigned long map_size;
+} dom_procdata_t;
+
+typedef struct proc_mem_data {
+ unsigned long pfn;
+ int tot_pages;
+} proc_memdata_t;
+
+#define XENO_BASE "xeno"
+#define DOM0_CMD_INTF "dom0_cmd"
+#define DOM0_NEWDOM "new_dom_data"
+
+#define MAX_LEN 16
+#define DOM_DIR "dom"
+#define DOM_MEM "mem"
+#define DOM_VIF "vif"
+
+#define MAP_DISCONT 1
+
+static struct proc_dir_entry *xeno_base;
+static struct proc_dir_entry *dom0_cmd_intf;
+static struct proc_dir_entry *proc_ft;
+
+unsigned long direct_mmap(unsigned long, unsigned long, pgprot_t, int, int);
+int direct_unmap(unsigned long, unsigned long);
+int direct_disc_unmap(unsigned long, unsigned long, int);
+
+static unsigned char readbuf[1204];
+
+static int cmd_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ strcpy(page, readbuf);
+ *readbuf = '\0';
+ *eof = 1;
+ *start = page;
+ return strlen(page);
+}
+
+static ssize_t dom_vif_read(struct file * file, char * buff, size_t size, loff_t * off)
+{
+ char hyp_buf[128]; // Hypervisor is going to write its reply here.
+ network_op_t op;
+ static int finished = 0;
+
+ // This seems to be the only way to make the OS stop making read requests
+ // to the file. When we use the fileoperations version of read, offset
+ // seems to be ignored altogether.
+
+ if (finished)
+ {
+ finished = 0;
+ return 0;
+ }
+
+ op.cmd = NETWORK_OP_VIFQUERY;
+ op.u.vif_query.domain = (unsigned int) ((struct proc_dir_entry *)file->f_dentry->d_inode->u.generic_ip)->data;
+ op.u.vif_query.buf = hyp_buf;
+
+ strcpy(hyp_buf, "Error getting domain's vif list from hypervisor.\n"); // This will be replaced if everything works.
+
+ (void)HYPERVISOR_network_op(&op);
+
+ if (*off >= (strlen(hyp_buf)+1)) return 0;
+
+ copy_to_user(buff, hyp_buf, strlen(hyp_buf));
+
+ finished = 1;
+
+ return strlen(hyp_buf)+1;
+}
+
+struct file_operations dom_vif_ops = {
+ read: dom_vif_read
+};
+
+
+static void create_proc_dom_entries(int dom)
+{
+ struct proc_dir_entry * dir;
+ dom_procdata_t * dom_data;
+ char dir_name[MAX_LEN];
+ struct proc_dir_entry * file;
+
+ snprintf(dir_name, MAX_LEN, "%s%d", DOM_DIR, dom);
+
+ dom_data = (dom_procdata_t *)kmalloc(sizeof(dom_procdata_t), GFP_KERNEL);
+ dom_data->domain = dom;
+
+ dir = proc_mkdir(dir_name, xeno_base);
+ dir->data = dom_data;
+
+ file = create_proc_entry(DOM_VIF, 0600, dir);
+ if (file != NULL)
+ {
+ file->owner = THIS_MODULE;
+ file->nlink = 1;
+ file->proc_fops = &dom_vif_ops;
+ file->data = (void *) dom;
+ }
+}
+
+static ssize_t dom_mem_write(struct file * file, const char * buff,
+ size_t size , loff_t * off)
+{
+ dom_mem_t mem_data;
+
+ copy_from_user(&mem_data, (dom_mem_t *)buff, sizeof(dom_mem_t));
+
+ if(direct_disc_unmap(mem_data.vaddr, mem_data.start_pfn,
+ mem_data.tot_pages) == 0){
+ return sizeof(sizeof(dom_mem_t));
+ } else {
+ return -1;
+ }
+}
+
+static ssize_t dom_mem_read(struct file * file, char * buff, size_t size, loff_t * off)
+{
+ unsigned long addr;
+ pgprot_t prot;
+
+ proc_memdata_t * mem_data = (proc_memdata_t *)((struct proc_dir_entry *)file->f_dentry->d_inode->u.generic_ip)->data;
+
+ prot = PAGE_SHARED;
+
+ /* remap the range using xen specific routines */
+
+ addr = direct_mmap(mem_data->pfn << PAGE_SHIFT, mem_data->tot_pages << PAGE_SHIFT, prot, MAP_DISCONT, mem_data->tot_pages);
+
+ copy_to_user((unsigned long *)buff, &addr, sizeof(addr));
+
+ return sizeof(addr);
+}
+
+struct file_operations dom_mem_ops = {
+ read: dom_mem_read,
+ write: dom_mem_write,
+};
+
+static int dom_map_mem(unsigned int dom, unsigned long pfn, int tot_pages)
+{
+ int ret = -ENOENT;
+ struct proc_dir_entry * pd = xeno_base->subdir;
+ struct proc_dir_entry * file;
+ proc_memdata_t * memdata;
+
+ while(pd != NULL){
+
+ if((pd->mode & S_IFDIR) && ((dom_procdata_t *)pd->data)->domain == dom){
+
+ /* check if there is already an entry for mem and if so
+ * remove it.
+ */
+ remove_proc_entry(DOM_MEM, pd);
+
+ /* create new entry with parameters describing what to do
+ * when it is mmaped.
+ */
+ file = create_proc_entry(DOM_MEM, 0600, pd);
+ if(file != NULL)
+ {
+ file->owner = THIS_MODULE;
+ file->nlink = 1;
+ file->proc_fops = &dom_mem_ops;
+
+ memdata = (proc_memdata_t *)kmalloc(sizeof(proc_memdata_t), GFP_KERNEL);
+ memdata->pfn = pfn;
+ memdata->tot_pages = tot_pages;
+ file->data = memdata;
+
+ ret = 0;
+ break;
+ }
+
+ ret = -EAGAIN;
+ break;
+ }
+ pd = pd->next;
+ }
+
+ return ret;
+}
+
+/* function used to retrieve data associated with new domain */
+static ssize_t dom_data_read(struct file * file, char * buff, size_t size, loff_t * off)
+{
+ dom0_newdomain_t * dom_data = (dom0_newdomain_t *)
+ ((struct proc_dir_entry *)file->f_dentry->d_inode->u.generic_ip)->data;
+
+ copy_to_user((dom0_newdomain_t *)buff, dom_data, sizeof(dom0_newdomain_t));
+
+ remove_proc_entry(DOM0_NEWDOM, xeno_base);
+
+ kfree(dom_data);
+
+ return sizeof(dom0_newdomain_t);
+}
+
+struct file_operations newdom_data_fops = {
+ read: dom_data_read,
+};
+
+static int cmd_write_proc(struct file *file, const char *buffer,
+ u_long count, void *data)
+{
+ dom0_op_t op;
+ int ret = 0;
+ struct proc_dir_entry * new_dom_id;
+ dom0_newdomain_t * params;
+ int i;
+ unsigned long p;
+
+ copy_from_user(&op, buffer, sizeof(dom0_op_t));
+
+ /* do some sanity checks */
+ if(op.cmd > MAX_CMD){
+ ret = -ENOSYS;
+ goto out;
+ }
+
+ if ( op.cmd == MAP_DOM_MEM )
+ {
+ ret = dom_map_mem(op.u.dommem.domain, op.u.dommem.start_pfn,
+ op.u.dommem.tot_pages);
+ }
+ else if ( op.cmd == DO_PGUPDATES )
+ {
+ ret = HYPERVISOR_pt_update(op.u.pgupdate.pgt_update_arr,
+ op.u.pgupdate.num_pgt_updates);
+ }
+ else
+ {
+ ret = HYPERVISOR_dom0_op(&op);
+
+ /* if new domain created, create proc entries */
+ if(op.cmd == DOM0_NEWDOMAIN){
+ create_proc_dom_entries(ret);
+
+ params = (dom0_newdomain_t *)kmalloc(sizeof(dom0_newdomain_t),
+ GFP_KERNEL);
+ params->memory_kb = op.u.newdomain.memory_kb;
+ params->pg_head = op.u.newdomain.pg_head;
+ params->num_vifs = op.u.newdomain.num_vifs;
+ params->domain = op.u.newdomain.domain;
+
+ /* now notify user space of the new domain's id */
+ new_dom_id = create_proc_entry(DOM0_NEWDOM, 0600, xeno_base);
+ if ( new_dom_id != NULL )
+ {
+ new_dom_id->owner = THIS_MODULE;
+ new_dom_id->nlink = 1;
+ new_dom_id->proc_fops = &newdom_data_fops;
+ new_dom_id->data = (void *)params;
+ }
+
+ }
+
+ }
+
+out:
+ return ret;
+
+}
+
+static int __init init_module(void)
+{
+ /* xeno proc root setup */
+ xeno_base = proc_mkdir(XENO_BASE, &proc_root);
+
+ /* xeno control interface */
+ *readbuf = '\0';
+ dom0_cmd_intf = create_proc_entry (DOM0_CMD_INTF, 0600, xeno_base);
+ if ( dom0_cmd_intf != NULL )
+ {
+ dom0_cmd_intf->owner = THIS_MODULE;
+ dom0_cmd_intf->nlink = 1;
+ dom0_cmd_intf->read_proc = cmd_read_proc;
+ dom0_cmd_intf->write_proc = cmd_write_proc;
+ }
+
+ /* set up /proc entries for dom 0 */
+ create_proc_dom_entries(0);
+
+ return 0;
+}
+
+
+static void __exit cleanup_module(void)
+{
+ if ( dom0_cmd_intf == NULL ) return;
+ remove_proc_entry("dom0", &proc_root);
+ dom0_cmd_intf = NULL;
+}
+
+
+module_init(init_module);
+module_exit(cleanup_module);