From a48212cb65e09669ed243581556529681cebba0a Mon Sep 17 00:00:00 2001 From: "iap10@labyrinth.cl.cam.ac.uk" Date: Mon, 24 Feb 2003 16:55:07 +0000 Subject: bitkeeper revision 1.93 (3e5a4e6bkPheUp3x1uufN2MS3LAB7A) Latest and Greatest version of XenoLinux based on the Linux-2.4.21-pre4 kernel. --- .../arch/xeno/drivers/dom0/Makefile | 3 + .../arch/xeno/drivers/dom0/dom0_block.c | 27 ++ .../arch/xeno/drivers/dom0/dom0_core.c | 334 +++++++++++++++++++ .../arch/xeno/drivers/dom0/dom0_memory.c | 368 +++++++++++++++++++++ .../arch/xeno/drivers/dom0/dom0_ops.h | 80 +++++ .../arch/xeno/drivers/dom0/vfr.c | 306 +++++++++++++++++ 6 files changed, 1118 insertions(+) create mode 100644 xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/Makefile create mode 100644 xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/dom0_block.c create mode 100644 xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/dom0_core.c create mode 100644 xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/dom0_memory.c create mode 100644 xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/dom0_ops.h create mode 100644 xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/vfr.c (limited to 'xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0') diff --git a/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/Makefile b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/Makefile new file mode 100644 index 0000000000..4738fc0ba4 --- /dev/null +++ b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/Makefile @@ -0,0 +1,3 @@ +O_TARGET := dom0.o +obj-y := dom0_memory.o dom0_core.o vfr.o +include $(TOPDIR)/Rules.make diff --git a/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/dom0_block.c b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/dom0_block.c new file mode 100644 index 0000000000..97d4a65b78 --- /dev/null +++ b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/dom0_block.c @@ -0,0 +1,27 @@ +/* + * domain 0 block driver interface + * + */ + +#include +#include +#include +#include + +static int __init init_module(void) +{ + request_module("xl_block"); + printk("Successfully installed domain 0 block interface\n"); + + + return 0; +} + +static void __exit cleanup_module(void) +{ + printk("Successfully de-installed domain-0 block interface\n"); + return 0; +} + +module_init(init_module); +module_exit(cleanup_module); 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#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); diff --git a/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/dom0_memory.c b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/dom0_memory.c new file mode 100644 index 0000000000..9d14070a1e --- /dev/null +++ b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/dom0_memory.c @@ -0,0 +1,368 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "dom0_ops.h" + +#define MAP_CONT 0 +#define MAP_DISCONT 1 + +extern struct list_head * find_direct(struct list_head *, unsigned long); + +/* + * bd240: functions below perform direct mapping to the real physical pages + * needed for mapping various hypervisor specific structures needed in dom0 + * userspace by various management applications such as domain builder etc. + */ + +#define direct_set_pte(pteptr, pteval) queue_l1_entry_update(__pa(pteptr)|PGREQ_UNCHECKED_UPDATE, (pteval).pte_low) + +#define direct_pte_clear(pteptr) queue_l1_entry_update(__pa(pteptr)|PGREQ_UNCHECKED_UPDATE, 0) + +#define __direct_pte(x) ((pte_t) { (x) } ) +#define __direct_mk_pte(page_nr,pgprot) __direct_pte(((page_nr) << PAGE_SHIFT) | pgprot_val(pgprot)) +#define direct_mk_pte_phys(physpage, pgprot) __direct_mk_pte((physpage) >> PAGE_SHIFT, pgprot) + +static inline void forget_pte(pte_t page) +{ + if (!pte_none(page)) { + printk("forget_pte: old mapping existed!\n"); + BUG(); + } +} + +static inline void direct_remappte_range(pte_t * pte, unsigned long address, unsigned long size, + unsigned long phys_addr, pgprot_t prot) +{ + unsigned long end; + + address &= ~PMD_MASK; + end = address + size; + if (end > PMD_SIZE) + end = PMD_SIZE; + do { + pte_t oldpage; + oldpage = ptep_get_and_clear(pte); + + direct_set_pte(pte, direct_mk_pte_phys(phys_addr, prot)); + + forget_pte(oldpage); + address += PAGE_SIZE; + phys_addr += PAGE_SIZE; + pte++; + } while (address && (address < end)); + +} + +static inline int direct_remappmd_range(struct mm_struct *mm, pmd_t * pmd, unsigned long address, unsigned long size, + unsigned long phys_addr, pgprot_t prot) +{ + unsigned long end; + + address &= ~PGDIR_MASK; + end = address + size; + if (end > PGDIR_SIZE) + end = PGDIR_SIZE; + phys_addr -= address; + do { + pte_t * pte = pte_alloc(mm, pmd, address); + if (!pte) + return -ENOMEM; + direct_remappte_range(pte, address, end - address, address + phys_addr, prot); + address = (address + PMD_SIZE) & PMD_MASK; + pmd++; + } while (address && (address < end)); + return 0; +} + +/* Note: this is only safe if the mm semaphore is held when called. */ +int direct_remap_page_range(unsigned long from, unsigned long phys_addr, unsigned long size, pgprot_t prot) +{ + int error = 0; + pgd_t * dir; + unsigned long beg = from; + unsigned long end = from + size; + struct mm_struct *mm = current->mm; + + phys_addr -= from; + dir = pgd_offset(mm, from); + flush_cache_range(mm, beg, end); + if (from >= end) + BUG(); + + spin_lock(&mm->page_table_lock); + do { + pmd_t *pmd = pmd_alloc(mm, dir, from); + error = -ENOMEM; + if (!pmd) + break; + error = direct_remappmd_range(mm, pmd, from, end - from, phys_addr + from, prot); + if (error) + break; + from = (from + PGDIR_SIZE) & PGDIR_MASK; + dir++; + } while (from && (from < end)); + spin_unlock(&mm->page_table_lock); + flush_tlb_range(mm, beg, end); + return error; +} + +/* + * used for remapping discontiguous bits of domain's memory, pages to map are + * found from frame table beginning at the given first_pg index + */ +int direct_remap_disc_page_range(unsigned long from, + unsigned long first_pg, int tot_pages, pgprot_t prot) +{ + dom0_op_t dom0_op; + unsigned long *pfns = get_free_page(GFP_KERNEL); + unsigned long start = from; + int pages, i; + + while ( tot_pages != 0 ) + { + dom0_op.cmd = DOM0_GETMEMLIST; + dom0_op.u.getmemlist.start_pfn = first_pg; + pages = 1023; + dom0_op.u.getmemlist.num_pfns = 1024; + if ( tot_pages < 1024 ) + dom0_op.u.getmemlist.num_pfns = pages = tot_pages; + dom0_op.u.getmemlist.buffer = pfns; + (void)HYPERVISOR_dom0_op(&dom0_op); + first_pg = pfns[1023]; + + for ( i = 0; i < pages; i++ ) + { + if(direct_remap_page_range(start, pfns[i] << PAGE_SHIFT, + PAGE_SIZE, prot)) + goto out; + start += PAGE_SIZE; + tot_pages--; + } + } + +out: + free_page(pfns); + return tot_pages; +} + +/* below functions replace standard sys_mmap and sys_munmap which are absolutely useless + * for direct memory mapping. direct_zap* functions are minor ammendments to the + * original versions in mm/memory.c. the changes are to enable unmapping of real physical + * addresses. + */ + +unsigned long direct_mmap(unsigned long phys_addr, unsigned long size, + pgprot_t prot, int flag, int tot_pages) +{ + direct_mmap_node_t * dmmap; + struct list_head * entry; + unsigned long addr; + int ret = 0; + + if(!capable(CAP_SYS_ADMIN)){ + ret = -EPERM; + goto out; + } + + /* get unmapped area invokes xen specific arch_get_unmapped_area */ + addr = get_unmapped_area(NULL, 0, size, 0, 0); + if(addr & ~PAGE_MASK){ + ret = -ENOMEM; + goto out; + } + + /* add node on the list of directly mapped areas, make sure the + * list remains sorted. + */ + dmmap = (direct_mmap_node_t *)kmalloc(sizeof(direct_mmap_node_t), GFP_KERNEL); + dmmap->vm_start = addr; + dmmap->vm_end = addr + size; + entry = find_direct(¤t->mm->context.direct_list, addr); + if(entry != ¤t->mm->context.direct_list){ + list_add_tail(&dmmap->list, entry); + } else { + list_add_tail(&dmmap->list, ¤t->mm->context.direct_list); + } + + /* and perform the mapping */ + if(flag == MAP_DISCONT){ + ret = direct_remap_disc_page_range(addr, phys_addr >> PAGE_SHIFT, + tot_pages, prot); + } else { + ret = direct_remap_page_range(addr, phys_addr, size, prot); + } + + if(ret == 0) + ret = addr; + +out: + return ret; +} + +/* most of the checks, refcnt updates, cache stuff have been thrown out as they are not + * needed + */ +static inline int direct_zap_pte_range(mmu_gather_t *tlb, pmd_t * pmd, unsigned long address, + unsigned long size) +{ + unsigned long offset; + pte_t * ptep; + int freed = 0; + + if (pmd_none(*pmd)) + return 0; + if (pmd_bad(*pmd)) { + pmd_ERROR(*pmd); + pmd_clear(pmd); + return 0; + } + ptep = pte_offset(pmd, address); + offset = address & ~PMD_MASK; + if (offset + size > PMD_SIZE) + size = PMD_SIZE - offset; + size &= PAGE_MASK; + for (offset=0; offset < size; ptep++, offset += PAGE_SIZE) { + pte_t pte = *ptep; + if (pte_none(pte)) + continue; + freed ++; + direct_pte_clear(ptep); + } + + return freed; +} + +static inline int direct_zap_pmd_range(mmu_gather_t *tlb, pgd_t * dir, + unsigned long address, unsigned long size) +{ + pmd_t * pmd; + unsigned long end; + int freed; + + if (pgd_none(*dir)) + return 0; + if (pgd_bad(*dir)) { + pgd_ERROR(*dir); + pgd_clear(dir); + return 0; + } + pmd = pmd_offset(dir, address); + end = address + size; + if (end > ((address + PGDIR_SIZE) & PGDIR_MASK)) + end = ((address + PGDIR_SIZE) & PGDIR_MASK); + freed = 0; + do { + freed += direct_zap_pte_range(tlb, pmd, address, end - address); + address = (address + PMD_SIZE) & PMD_MASK; + pmd++; + } while (address < end); + return freed; +} + +/* + * remove user pages in a given range. + */ +void direct_zap_page_range(struct mm_struct *mm, unsigned long address, unsigned long size) +{ + mmu_gather_t *tlb; + pgd_t * dir; + unsigned long start = address, end = address + size; + int freed = 0; + + dir = pgd_offset(mm, address); + + /* + * This is a long-lived spinlock. That's fine. + * There's no contention, because the page table + * lock only protects against kswapd anyway, and + * even if kswapd happened to be looking at this + * process we _want_ it to get stuck. + */ + if (address >= end) + BUG(); + spin_lock(&mm->page_table_lock); + flush_cache_range(mm, address, end); + tlb = tlb_gather_mmu(mm); + + do { + freed += direct_zap_pmd_range(tlb, dir, address, end - address); + address = (address + PGDIR_SIZE) & PGDIR_MASK; + dir++; + } while (address && (address < end)); + + /* this will flush any remaining tlb entries */ + tlb_finish_mmu(tlb, start, end); + + /* decrementing rss removed */ + + spin_unlock(&mm->page_table_lock); +} + +int direct_unmap(unsigned long addr, unsigned long size) +{ + direct_mmap_node_t * node; + struct list_head * curr; + struct list_head * direct_list = ¤t->mm->context.direct_list; + + curr = direct_list->next; + while(curr != direct_list){ + node = list_entry(curr, direct_mmap_node_t, list); + if(node->vm_start == addr) + break; + curr = curr->next; + } + + if(curr == direct_list) + return -1; + + list_del(&node->list); + kfree(node); + + direct_zap_page_range(current->mm, addr, size); + + return 0; +} + +int direct_disc_unmap(unsigned long from, unsigned long first_pg, int tot_pages) +{ + int count = 0; + direct_mmap_node_t * node; + struct list_head * curr; + struct list_head * direct_list = ¤t->mm->context.direct_list; + + curr = direct_list->next; + while(curr != direct_list){ + node = list_entry(curr, direct_mmap_node_t, list); + + if(node->vm_start == from) + break; + curr = curr->next; + } + + if(curr == direct_list) + return -1; + + list_del(&node->list); + kfree(node); + + while(count < tot_pages){ + direct_zap_page_range(current->mm, from, PAGE_SIZE); + from += PAGE_SIZE; + count++; + } + + return 0; +} diff --git a/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/dom0_ops.h b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/dom0_ops.h new file mode 100644 index 0000000000..d98ce1b1eb --- /dev/null +++ b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/dom0_ops.h @@ -0,0 +1,80 @@ +/****************************************************************************** + * dom0_ops.h + * + * Process command requests from domain-0 guest OS. + * + * Copyright (c) 2002, K A Fraser, B Dragovic + */ + +#define DOM0_NEWDOMAIN 0 +#define DOM0_KILLDOMAIN 1 +#define DOM0_GETMEMLIST 2 +#define DOM0_STARTDOM 4 +#define MAP_DOM_MEM 6 /* Not passed down to Xen */ +#define DO_PGUPDATES 7 /* Not passed down to Xen */ +#define MAX_CMD 8 + +#define MAX_CMD_LEN 256 + +typedef struct dom0_newdomain_st +{ + unsigned int domain; + unsigned int memory_kb; + unsigned int num_vifs; // temporary + unsigned long pg_head; // return parameter +} dom0_newdomain_t; + +typedef struct dom0_killdomain_st +{ + unsigned int domain; +} dom0_killdomain_t; + +typedef struct dom0_getmemlist_st +{ + unsigned long start_pfn; + unsigned long num_pfns; + void *buffer; +} dom0_getmemlist_t; + +/* This is entirely processed by XenoLinux */ +typedef struct dom_mem +{ + unsigned int domain; + unsigned long vaddr; + unsigned long start_pfn; + int tot_pages; +} dom_mem_t; + +/* This is entirely processed by XenoLinux */ +typedef struct dom_pgupdate +{ + unsigned long pgt_update_arr; + unsigned long num_pgt_updates; +} dom_pgupdate_t; + +typedef struct domain_launch +{ + unsigned int domain; + unsigned long l2_pgt_addr; + unsigned long virt_load_addr; + unsigned long virt_shinfo_addr; + unsigned long virt_startinfo_addr; + unsigned int num_vifs; + char cmd_line[MAX_CMD_LEN]; +} dom_meminfo_t; + +typedef struct dom0_op_st +{ + unsigned long cmd; + union + { + dom0_newdomain_t newdomain; + dom0_killdomain_t killdomain; + dom0_getmemlist_t getmemlist; + dom_mem_t dommem; + dom_pgupdate_t pgupdate; + dom_meminfo_t meminfo; + } + u; +} dom0_op_t; + diff --git a/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/vfr.c b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/vfr.c new file mode 100644 index 0000000000..13fe25ec9c --- /dev/null +++ b/xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/vfr.c @@ -0,0 +1,306 @@ +/****************************************************************************** + * vfr.c + * + * Interface to the virtual firewall/router. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static struct proc_dir_entry *proc_vfr; + +static unsigned char readbuf[1024]; + +/* Helpers, implemented at the bottom. */ +u32 getipaddr(const char *buff, unsigned int len); +u16 antous(const char *buff, int len); +int anton(const char *buff, int len); + +static int vfr_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); +} + +/* The format for the vfr interface is as follows: + * + * COMMAND = [= [...]] + * + * where: + * + * COMMAND = { ACCEPT | COUNT } + * + * field=val pairs are as follows: + * + * field = { srcaddr | dstaddr } + * val is a dot seperated, numeric IP address. + * + * field = { srcport | dstport } + * val is a (16-bit) unsigned int + * + * field = { proto } + * val = { IP | TCP | UDP | ARP } + * + */ + +#define isspace(_x) ( ((_x)==' ') || ((_x)=='\t') || ((_x)=='\v') || \ + ((_x)=='\f') || ((_x)=='\r') || ((_x)=='\n') ) + +static int vfr_write_proc(struct file *file, const char *buffer, + u_long count, void *data) +{ + network_op_t op; + int ret, len; + int ts, te, tl; // token start, end, and length + int fs, fe, fl; // field. + + len = count; + ts = te = 0; + + memset(&op, 0, sizeof(network_op_t)); + + // get the command: + while ( count && isspace(buffer[ts]) ) { ts++; count--; } // skip spaces. + te = ts; + while ( count && !isspace(buffer[te]) ) { te++; count--; } // command end + if ( te <= ts ) goto bad; + tl = te - ts; + + if ( strncmp(&buffer[ts], "ADD", tl) == 0 ) + { + op.cmd = NETWORK_OP_ADDRULE; + } + else if ( strncmp(&buffer[ts], "DELETE", tl) == 0 ) + { + op.cmd = NETWORK_OP_DELETERULE; + } + else if ( strncmp(&buffer[ts], "PRINT", tl) == 0 ) + { + op.cmd = NETWORK_OP_GETRULELIST; + goto doneparsing; + } + + ts = te; + + // get the action + while ( count && (buffer[ts] == ' ') ) { ts++; count--; } // skip spaces. + te = ts; + while ( count && (buffer[te] != ' ') ) { te++; count--; } // command end + if ( te <= ts ) goto bad; + tl = te - ts; + + if ( strncmp(&buffer[ts], "ACCEPT", tl) == 0 ) + { + op.u.net_rule.action = NETWORK_ACTION_ACCEPT; + goto keyval; + } + if ( strncmp(&buffer[ts], "COUNT", tl) == 0 ) + { + op.u.net_rule.action = NETWORK_ACTION_COUNT; + goto keyval; + } + + // default case; + return (len); + + + // get the key=val pairs. + keyval: + while (count) + { + //get field + ts = te; while ( count && isspace(buffer[ts]) ) { ts++; count--; } + te = ts; + while ( count && !isspace(buffer[te]) && (buffer[te] != '=') ) + { te++; count--; } + if ( te <= ts ) + goto doneparsing; + tl = te - ts; + fs = ts; fe = te; fl = tl; // save the field markers. + // skip " = " (ignores extra equals.) + while ( count && (isspace(buffer[te]) || (buffer[te] == '=')) ) + { te++; count--; } + ts = te; + while ( count && !isspace(buffer[te]) ) { te++; count--; } + tl = te - ts; + + if ( (fl <= 0) || (tl <= 0) ) goto bad; + + if (strncmp(&buffer[fs], "srcaddr", fl) == 0) + { + op.u.net_rule.src_addr = getipaddr(&buffer[ts], tl); + } + else if (strncmp(&buffer[fs], "dstaddr", fl) == 0) + { + op.u.net_rule.dst_addr = getipaddr(&buffer[ts], tl); + } + else if (strncmp(&buffer[fs], "srcaddrmask", fl) == 0) + { + op.u.net_rule.src_addr_mask = getipaddr(&buffer[ts], tl); + } + else if (strncmp(&buffer[fs], "dstaddrmask", fl) == 0) + { + op.u.net_rule.dst_addr_mask = getipaddr(&buffer[ts], tl); + } + else if (strncmp(&buffer[fs], "srcport", fl) == 0) + { + op.u.net_rule.src_port = antous(&buffer[ts], tl); + } + else if (strncmp(&buffer[fs], "dstport", fl) == 0) + { + op.u.net_rule.dst_port = antous(&buffer[ts], tl); + } + else if (strncmp(&buffer[fs], "srcportmask", fl) == 0) + { + op.u.net_rule.src_port_mask = antous(&buffer[ts], tl); + } + else if (strncmp(&buffer[fs], "dstportmask", fl) == 0) + { + op.u.net_rule.dst_port_mask = antous(&buffer[ts], tl); + } + else if (strncmp(&buffer[fs], "srcint", fl) == 0) + { + op.u.net_rule.src_interface = anton(&buffer[ts], tl); + } + else if (strncmp(&buffer[fs], "dstint", fl) == 0) + { + op.u.net_rule.dst_interface = anton(&buffer[ts], tl); + } + else if ( (strncmp(&buffer[fs], "proto", fl) == 0)) + { + if (strncmp(&buffer[ts], "any", tl) == 0) + op.u.net_rule.proto = NETWORK_PROTO_ANY; + if (strncmp(&buffer[ts], "ip", tl) == 0) + op.u.net_rule.proto = NETWORK_PROTO_IP; + if (strncmp(&buffer[ts], "tcp", tl) == 0) + op.u.net_rule.proto = NETWORK_PROTO_TCP; + if (strncmp(&buffer[ts], "udp", tl) == 0) + op.u.net_rule.proto = NETWORK_PROTO_UDP; + if (strncmp(&buffer[ts], "arp", tl) == 0) + op.u.net_rule.proto = NETWORK_PROTO_ARP; + + } + } + + doneparsing: + ret = HYPERVISOR_network_op(&op); + return(len); + + bad: + return(len); + + +} + +static int __init init_module(void) +{ + *readbuf = '\0'; + proc_vfr = create_proc_entry ("vfr", 0600, &proc_root); + if ( proc_vfr != NULL ) + { + proc_vfr->owner = THIS_MODULE; + proc_vfr->nlink = 1; + proc_vfr->read_proc = vfr_read_proc; + proc_vfr->write_proc = vfr_write_proc; + printk("Successfully installed virtual firewall/router interface\n"); + } + return 0; +} + +static void __exit cleanup_module(void) +{ + if ( proc_vfr == NULL ) return; + remove_proc_entry("vfr", &proc_root); + proc_vfr = NULL; +} + +module_init(init_module); +module_exit(cleanup_module); + +/* Helper functions start here: */ + +int anton(const char *buff, int len) +{ + int ret; + char c; + int sign = 1; + + ret = 0; + + if (len == 0) return 0; + if (*buff == '-') { sign = -1; buff++; len--; } + + while ( (len) && ((c = *buff) >= '0') && (c <= '9') ) + { + ret *= 10; + ret += c - '0'; + buff++; len--; + } + + ret *= sign; + return ret; +} + +u16 antous(const char *buff, int len) +{ + u16 ret; + char c; + + ret = 0; + + while ( (len) && ((c = *buff) >= '0') && (c <= '9') ) + { + ret *= 10; + ret += c - '0'; + buff++; len--; + } + + return ret; +} + +u32 getipaddr(const char *buff, unsigned int len) +{ + int i; + char c; + u32 ret, val; + + ret = 0; val = 0; + + while ( len ) + { + if (!((((c = *buff) >= '0') && ( c <= '9')) || ( c == '.' ) ) ) + { + return(0); // malformed. + } + + if ( c == '.' ) { + if (val > 255) return (0); //malformed. + ret = ret << 8; + ret += val; + val = 0; + len--; buff++; + continue; + } + val *= 10; + val += c - '0'; + buff++; len--; + } + ret = ret << 8; + ret += val; + + return (ret); +} + -- cgit v1.2.3