diff options
38 files changed, 2271 insertions, 25 deletions
@@ -2,5 +2,7 @@ set -e test -L tools/domain_builder/dom0_ops.h rm tools/domain_builder/dom0_ops.h +test -L tools/internal/dom0_ops.h +rm tools/internal/dom0_ops.h (find -depth -type d -print | xargs -r rmdir 2>/dev/null) || true exit 0 @@ -3,5 +3,7 @@ set -e mkdir -p tools mkdir -p tools/domain_builder ln -s ../../xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/dom0_ops.h tools/domain_builder/dom0_ops.h +mkdir -p tools/internal +ln -s ../../xenolinux-2.4.21-pre4-sparse/arch/xeno/drivers/dom0/dom0_ops.h tools/internal/dom0_ops.h (find -depth -type d -print | xargs -r rmdir 2>/dev/null) || true exit 0 @@ -15,6 +15,32 @@ 3e71afadoAI0VvAGKebLpToVQxUKfQ tools/domain_builder/mynewdom 3e4d0046VHhXwFuG5FK34AVxqd5A_A tools/domain_builder/newdom 3e4d0046IBzDIeaMbQB-e2QB2ahbig tools/domain_builder/vifinit +3eb781edFwm_pW9FwnQACIe68viLOw tools/domctl/Makefile +3eb781fcTp_LPQwaot3SSSehkaf4eg tools/domctl/build.xml +3eb781fcXf-WczEdAhnTpWfbR55jqA tools/domctl/domctl +3eb781fcabCKRogwxJA3-jJKstw9Vg tools/domctl/domctl.xml +3eb781fcffCXkrcWLBxUTOfQFa3Saw tools/domctl/src/uk/ac/cam/cl/xeno/domctl/Command.java +3eb781fcOLcVAcqnZOAikur6sAP0rA tools/domctl/src/uk/ac/cam/cl/xeno/domctl/CommandDestroy.java +3eb781fcQuQVSKxKtp4fBgPOwx7DDw tools/domctl/src/uk/ac/cam/cl/xeno/domctl/CommandHelp.java +3eb781fcRYdxK1HbjBX7r7VlO5PS0w tools/domctl/src/uk/ac/cam/cl/xeno/domctl/CommandNew.java +3eb781fcbp9IAHTl40CoMavY1FNd_g tools/domctl/src/uk/ac/cam/cl/xeno/domctl/CommandStart.java +3eb781fdRXSsyEre7LxCmPJMpB5BaQ tools/domctl/src/uk/ac/cam/cl/xeno/domctl/CommandStop.java +3eb781fdX_thm9iHSxQ8vqQ0fL7Ncg tools/domctl/src/uk/ac/cam/cl/xeno/domctl/Defaults.java +3eb781fdTWJr8RPdfuG20IC0CzYL2A tools/domctl/src/uk/ac/cam/cl/xeno/domctl/InetAddressPattern.java +3eb781fdA8LFQEYE2fXg1JDB9OceYA tools/domctl/src/uk/ac/cam/cl/xeno/domctl/Main.java +3eb781fd_CgRvlaIBkJjxUSnuvCuHQ tools/domctl/src/uk/ac/cam/cl/xeno/domctl/Settings.java +3eb781fdFDS4lap1-3ZVDtbKZfpVZA tools/domctl/src/uk/ac/cam/cl/xeno/domctl/StringPattern.java +3eb781fdl4lXWYZzmqDDUAYhAThRqQ tools/internal/Makefile +3eb781fdc539MQQm47rYRCCR3N5i-Q tools/internal/dom0_defs.h +3eb781fdEYILyFg60YVBsWNqxWFf1g tools/internal/dom0_ops.h +3eb781fddjylXbsepjppUyIXa5lcaQ tools/internal/hypervisor_defs.h +3eb781fdKiQbgozBsgs_zzJQ9ubehw tools/internal/mem_defs.h +3eb781fdgbSkh2O6JQS-65Dz4n0ItQ tools/internal/xi_build.c +3eb781fdW1SAyiaC4mTsXq_9fRHh-A tools/internal/xi_create.c +3eb781fdcJ0fF7rWfzAOArW-x4-gwA tools/internal/xi_destroy.c +3eb781fd8oRfPgH7qTh7xvgmwD6NgA tools/internal/xi_start.c +3eb781fd0Eo9K1jEFCSAVzO51i_ngg tools/internal/xi_stop.c +3eb781fd7211MZsLxJSiuy7W4KnJXg tools/internal/xi_vifinit 3ea53c6dz47kAOwpk54f8_zOAQ5ngw tools/vdmanager/build.xml 3eaff785PwN0C3-xhCf_zMCL27JIgQ tools/vdmanager/notes.xml 3ea53c6dE-azH1i1VJmJMp9SHnETkQ tools/vdmanager/src/uk/ac/cam/cl/xeno/vdmanager/Extent.java diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index 9ec62d9ca9..9cc9e724e8 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -18,3 +18,4 @@ rn@wyvis.camb.intel-research.net rn@wyvis.research.intel-research.net smh22@boulderdash.cl.cam.ac.uk smh22@uridium.cl.cam.ac.uk +tlh20@elite.cl.cam.ac.uk diff --git a/tools/domain_builder/dom_builder.c b/tools/domain_builder/dom_builder.c index 13ee8d8735..d1cc68d704 100644 --- a/tools/domain_builder/dom_builder.c +++ b/tools/domain_builder/dom_builder.c @@ -49,7 +49,7 @@ static int do_kill_domain(int dom_id, int force) dom0_op_t dop; int cmd_fd; - dop.cmd = DOM0_KILLDOMAIN; + dop.cmd = DOM0_DESTROYDOMAIN; dop.u.killdomain.domain = dom_id; dop.u.killdomain.force = force; @@ -178,8 +178,9 @@ static dom0_newdomain_t * create_new_domain(long req_mem) return 0; } - dop.cmd = DOM0_NEWDOMAIN; + dop.cmd = DOM0_CREATEDOMAIN; dop.u.newdomain.memory_kb = req_mem; + dop.u.newdomain.name[0] = 0; write(cmd_fd, &dop, sizeof(dom0_op_t)); close(cmd_fd); @@ -435,7 +436,11 @@ static int launch_domain(dom_meminfo_t * meminfo) return -1; } - dop.cmd = DOM0_STARTDOM; + dop.cmd = DOM0_BUILDDOMAIN; + memcpy(&dop.u.meminfo, meminfo, sizeof(dom_meminfo_t)); + write(cmd_fd, &dop, sizeof(dom0_op_t)); + + dop.cmd = DOM0_STARTDOMAIN; memcpy(&dop.u.meminfo, meminfo, sizeof(dom_meminfo_t)); write(cmd_fd, &dop, sizeof(dom0_op_t)); diff --git a/tools/domain_builder/dom_kill.c b/tools/domain_builder/dom_kill.c index ddc0f8a4fd..b27fca9a58 100644 --- a/tools/domain_builder/dom_kill.c +++ b/tools/domain_builder/dom_kill.c @@ -21,7 +21,7 @@ static int do_kill_domain(int dom_id, int force) dom0_op_t dop; int cmd_fd; - dop.cmd = DOM0_KILLDOMAIN; + dop.cmd = DOM0_DESTROYDOMAIN; dop.u.killdomain.domain = dom_id; dop.u.killdomain.force = force; diff --git a/tools/domctl/Makefile b/tools/domctl/Makefile new file mode 100644 index 0000000000..054fb95791 --- /dev/null +++ b/tools/domctl/Makefile @@ -0,0 +1,5 @@ +default: + ant dist + +clean: + ant clean diff --git a/tools/domctl/build.xml b/tools/domctl/build.xml new file mode 100644 index 0000000000..88d5ffb5b5 --- /dev/null +++ b/tools/domctl/build.xml @@ -0,0 +1,45 @@ +<project name="domctl project" default="compile"> + <property name="src" location="src"/> + <property name="build" location="build"/> + <property name="dist" location="dist"/> + <property name="lib" location="lib"/> + + <target name="init"> + <tstamp/> + <mkdir dir="${build}"/> + </target> + + <target name="compile" depends="init"> + <javac srcdir="${src}" destdir="${build}" debug="on"/> + </target> + + <target name="dist" depends="compile"> + <jar jarfile="domctl.jar" + excludes="*~" + basedir="${build}"> + <fileset dir="${src}" /> + <fileset dir="."> + <include name="build.xml"/> + <include name="domctl"/> + </fileset> + <manifest> + <attribute name="Built-By" value="${user.name}"/> + <attribute name="Main-Class" value="uk.ac.cam.cl.xeno.domctl.Main"/> + <attribute name="Sealed" value="true"/> + </manifest> + </jar> + </target> + + <target name="test" depends="compile"> + <java fork="true" classname="uk.ac.cam.cl.xeno.domctl.Main"> + <classpath> + <pathelement path="${build}"/> + </classpath> + </java> + </target> + + <target name="clean"> + <delete dir="${build}"/> + <delete dir="${lib}"/> + </target> +</project>
\ No newline at end of file diff --git a/tools/domctl/domctl b/tools/domctl/domctl new file mode 100755 index 0000000000..3f80d21176 --- /dev/null +++ b/tools/domctl/domctl @@ -0,0 +1,31 @@ +#!/bin/bash -x + +if [ -z "$DEFAULTS_FILE" ] ; then DEFAULTS_FILE=domctl.xml ; fi +if [ -z "$DEFAULTS_PATH" ] ; then DEFAULTS_PATH=.:/etc ; fi +if [ -z "$QUERY_DEV" ] ; then QUERY_DEV=eth0 ; fi +if [ -z "$IFCONFIG" ] ; then IFCONFIG=/sbin/ifconfig ; fi +if [ -z "$ROUTE" ] ; then ROUTE=/sbin/route ; fi +if [ -z "$JAVA" ] ; then JAVA=java ; fi + +if [ ! -x "$IFCONFIG" ]; then + echo Could not find executable $IFCONFIG + exit 1 +fi + +if [ ! -x "$ROUTE" ]; then + echo Could not find executable $ROUTE + exit 1 +fi + +# Try to determine dom0 network settings to avoid hard-coding +# particular machines in the defaults file +LOCAL_IP=$(/sbin/ifconfig $QUERY_DEV | grep 'inet addr' | tr ':' '\t' | awk '{print $3}') +LOCAL_MASK=$(/sbin/ifconfig $QUERY_DEV | grep 'Mask' | tr ':' '\t' | awk '{print $7}') +LOCAL_ROUTE=$(/sbin/route -n | grep $QUERY_DEV | grep 'G' | awk '{print $2}') + + +#ARGS="-DTEST -DDEFAULTS_FILE=$DEFAULTS_FILE -DDEFAULTS_PATH=$DEFAULTS_PATH -DLOCAL_IP=$LOCAL_IP -DLOCAL_MASK=$LOCAL_MASK -DLOCAL_ROUTE=$LOCAL_ROUTE" +ARGS="-DDEFAULTS_FILE=$DEFAULTS_FILE -DDEFAULTS_PATH=$DEFAULTS_PATH -DLOCAL_IP=$LOCAL_IP -DLOCAL_MASK=$LOCAL_MASK -DLOCAL_ROUTE=$LOCAL_ROUTE" + + +$JAVA $ARGS -jar domctl.jar $* diff --git a/tools/domctl/domctl.xml b/tools/domctl/domctl.xml new file mode 100644 index 0000000000..168b8da2fa --- /dev/null +++ b/tools/domctl/domctl.xml @@ -0,0 +1,15 @@ +<?xml version="1.0"?> +<domctl_defaults> +<domain_name>XenoLinux</domain_name> +<domain_size_kb>16000</domain_size_kb> +<domain_image>./image</domain_image> +<domain_vifs>1</domain_vifs> +<root_device>/dev/nfs</root_device> +<nw_ip>=+</nw_ip> +<nw_gw>=</nw_gw> +<nw_mask>=</nw_mask> +<nw_nfs_server>128.232.32.20</nw_nfs_server> +<nw_nfs_root>/usr/groups/srgboot/moonraider/roots/root+</nw_nfs_root> +<max_domain_number>2</max_domain_number> +<xi_tools_dir>/tools/internal/</xi_tools_dir> +</domctl_defaults> diff --git a/tools/domctl/src/uk/ac/cam/cl/xeno/domctl/Command.java b/tools/domctl/src/uk/ac/cam/cl/xeno/domctl/Command.java new file mode 100644 index 0000000000..b667e3f274 --- /dev/null +++ b/tools/domctl/src/uk/ac/cam/cl/xeno/domctl/Command.java @@ -0,0 +1,74 @@ +package uk.ac.cam.cl.xeno.domctl; + +public abstract class Command +{ + public abstract int doCommand(Defaults d, String args[]); + public abstract String getName(); + public abstract String getUsage(); + public abstract String getHelpText(); + + public String getStringParameter(String args[], char key, String def) + { + String r = getParameter (args, key); + return (r == null) ? def : r; + } + + public int getIntParameter(String args[], char key, int def) + { + String r = getParameter (args, key); + return (r == null) ? def : (Integer.parseInt (r)); + } + + public boolean getFlagParameter(String args[], char key) + { + String r = getParameter (args, key); + return (r == null) ? false : true; + } + + public String getParameter (String args[], char key) + { + int i; + String result = null; + for (i = 0; i < args.length; i ++) + { + if (args[i].startsWith("-" + key)) + { + if (args[i].length() > 2) + { + result = args[i].substring(2, args[i].length()); + } + else + { + result = ""; + } + } + } + return result; + } + + public int reportXIError (String message, String cmd_array[]) + { + int i; + System.err.print (message + " using: "); + for (i = 0; i < cmd_array.length; i ++) { + System.err.print (cmd_array[i] + " "); + } + System.err.println(); + return -1; + } + + public int reportError (String message) + { + System.err.println (message); + return -1; + } + + public void reportCommand (String cmd_array[]) + { + int i; + for (i = 0; i < cmd_array.length; i ++) { + System.out.print (cmd_array[i] + " "); + } + System.out.println(); + } +} diff --git a/tools/domctl/src/uk/ac/cam/cl/xeno/domctl/CommandDestroy.java b/tools/domctl/src/uk/ac/cam/cl/xeno/domctl/CommandDestroy.java new file mode 100644 index 0000000000..025f373c50 --- /dev/null +++ b/tools/domctl/src/uk/ac/cam/cl/xeno/domctl/CommandDestroy.java @@ -0,0 +1,69 @@ +package uk.ac.cam.cl.xeno.domctl; + +import java.io.*; +import java.net.*; + +public class CommandDestroy extends Command +{ + public int doCommand(Defaults d, String args[]) + { + Runtime r = Runtime.getRuntime (); + int domain_id = getIntParameter(args, 'n', 0); + boolean force = getFlagParameter(args, 'f'); + int rc = 0; + + if (domain_id == 0) { + System.err.println ("Expected -n<domain_id>"); + rc = -1; + return rc; + } + + try + { + Process destroy_p; + String destroy_cmdarray[] = force ? new String[3] : new String[2]; + int destroy_rc; + int idx = 0; + destroy_cmdarray[idx++] = d.XIToolsDir + "xi_destroy"; + if (force) { + destroy_cmdarray[idx++] = "-f"; + } + destroy_cmdarray[idx++] = "" + domain_id; + + if (Settings.TEST) { + reportCommand (destroy_cmdarray); + } else { + destroy_p = r.exec (destroy_cmdarray); + destroy_rc = destroy_p.waitFor (); + + if (destroy_rc != 0) { + return reportXIError ("Could not destroy domain", destroy_cmdarray); + } + } + } + catch (Exception e) + { + System.err.println ("Could not destroy domain (" + e + ")"); + e.printStackTrace (); + rc = -1; + } + + return rc; + } + + public String getName() + { + return "destroy"; + } + + public String getUsage() + { + return "[-f] [-n<domain_id>]"; + } + + public String getHelpText() + { + return + "Destory the specified domain. -f forcibly destroys it."; + } +} diff --git a/tools/domctl/src/uk/ac/cam/cl/xeno/domctl/CommandHelp.java b/tools/domctl/src/uk/ac/cam/cl/xeno/domctl/CommandHelp.java new file mode 100644 index 0000000000..aef1ee9473 --- /dev/null +++ b/tools/domctl/src/uk/ac/cam/cl/xeno/domctl/CommandHelp.java @@ -0,0 +1,58 @@ +package uk.ac.cam.cl.xeno.domctl; + +public class CommandHelp extends Command +{ + public int doCommand(Defaults d, String args[]) + { + if (args.length <= 1) + { + System.out.println ("Usage:"); + for (int i = 0; i < Main.commands.length; i ++) + { + String name = Main.commands[i].getName (); + String usage = Main.commands[i].getUsage (); + while (name.length() < 12) name = name + " "; + System.out.println (" " + name + usage); + } + } + else + { + for (int i = 0; i < Main.commands.length; i ++) + { + String name = Main.commands[i].getName (); + String usage = Main.commands[i].getUsage (); + if (name.equals (args[1])) + { + doHelpFor (Main.commands[i]); + break; + } + } + } + + System.out.println (""); + return 0; + } + + public int doHelpFor (Command c) + { + System.out.println ("domctl " + c.getName() + " " + c.getUsage()); + System.out.println (); + System.out.println (c.getHelpText ()); + return 0; + } + + public String getName() + { + return "help"; + } + + public String getUsage() + { + return ""; + } + + public String getHelpText() + { + return "This message"; + } +} diff --git a/tools/domctl/src/uk/ac/cam/cl/xeno/domctl/CommandNew.java b/tools/domctl/src/uk/ac/cam/cl/xeno/domctl/CommandNew.java new file mode 100644 index 0000000000..1dd915686e --- /dev/null +++ b/tools/domctl/src/uk/ac/cam/cl/xeno/domctl/CommandNew.java @@ -0,0 +1,203 @@ +package uk.ac.cam.cl.xeno.domctl; + +import java.io.*; +import java.net.*; + +public class CommandNew extends Command +{ + public int doCommand(Defaults d, String args[]) + { + Runtime r = Runtime.getRuntime (); + String name = getStringParameter(args, 'n', d.domainName); + int size = getIntParameter(args, 'k', d.domainSizeKB); + String image = getStringParameter(args, 'i', d.domainImage); + String initrd = getStringParameter (args, 'r', d.domainInitRD); + int vifs = getIntParameter(args, 'v', d.domainVIFs); + String bargs = getStringParameter (args, 'a', ""); + String root_dev = getStringParameter (args, 'd', d.rootDevice); + String nfs_root_path = getStringParameter (args, 'f', d.NWNFSRoot); + String nw_ip = getStringParameter (args, '4', d.NWIP); + String nw_gw = getStringParameter (args, 'g', d.NWGW); + String nw_mask = getStringParameter (args, 'm', d.NWMask); + String nw_nfs_server = getStringParameter (args, 's', d.NWNFSServer); + String nw_host = getStringParameter (args, 'h', d.NWHost); + String domain_ip = ""; + int rc = 0; + int domain_id; + DataInputStream dis; + int idx; + int i; + + + try + { + /* Some initial sanity checks */ + if (root_dev.equals ("/dev/nfs") && (vifs == 0)) { + return reportError ("Cannot use NFS root without VIFs configured"); + } + + /* Create a new empty domain */ + Process create_p; + String create_cmdarray[] = new String[3]; + int create_rc; + create_cmdarray[0] = d.XIToolsDir + "xi_create"; + create_cmdarray[1] = "" + size; + create_cmdarray[2] = name; + if (Settings.TEST) { + reportCommand (create_cmdarray); + domain_id=1; + create_rc=0; + } else { + create_p = r.exec (create_cmdarray); + dis = new DataInputStream (new BufferedInputStream (create_p.getInputStream ())); + domain_id = Integer.parseInt (dis.readLine ()); + create_rc = create_p.waitFor (); + } + + if (create_rc != 0) { + return reportXIError ("Failed to create domain", create_cmdarray); + } else if (domain_id > d.MaxDomainNumber) { + return reportError ("Cannot configure more than " + + d.MaxDomainNumber + " domains"); + } + + /* Set up boot parameters to pass to xi_build. */ + bargs = ""; + + if (root_dev.equals ("/dev/nfs")) { + if (vifs == 0) { + return reportError ("Cannot use NFS root without VIFs configured"); + } + bargs = (bargs + + "root=/dev/nfs " + + "nfsroot=" + StringPattern.parse(nfs_root_path).resolve(domain_id) + + " "); + } else { + bargs = ("root=" + StringPattern.parse(root_dev).resolve(domain_id) + + " "); + + } + + if (vifs > 0) { + domain_ip = InetAddressPattern.parse(nw_ip).resolve(domain_id); + if (nw_host == null) { + try { + nw_host = InetAddress.getByName(domain_ip).getHostName(); + } catch (UnknownHostException uhe) { + nw_host = "" + nw_ip; + } + + } + bargs = ("ip=" + domain_ip + + ":" + InetAddressPattern.parse(nw_nfs_server).resolve(domain_id) + + ":" + InetAddressPattern.parse(nw_gw).resolve(domain_id) + + ":" + InetAddressPattern.parse(nw_mask).resolve(domain_id) + + ":" + nw_host + + ":eth0:off " + bargs); + } + + /* Build the domain */ + Process build_p; + String build_cmdarray[] = new String[6]; + int build_rc; + idx = 0; + for (i = 0; i < build_cmdarray.length; i ++) + build_cmdarray[i] = ""; + build_cmdarray[idx ++] = d.XIToolsDir + "xi_build"; + build_cmdarray[idx ++] = "" + domain_id; + build_cmdarray[idx ++] = "" + image; + build_cmdarray[idx ++] = "" + vifs; + if (initrd != null) build_cmdarray[idx ++] = "initrd=" + initrd; + build_cmdarray[idx ++] = "" + bargs; + System.out.println ("Build args: " + bargs); + if (Settings.TEST) { + reportCommand (build_cmdarray); + build_rc = 0; + } else { + build_p = r.exec (build_cmdarray); + build_rc = build_p.waitFor (); + } + + if (build_rc != 0) { + return reportXIError ("Failed to build domain", build_cmdarray); + } + + + /* Set up the first VIF if necessary */ + if (vifs > 0) { + Process vifinit_p; + String vifinit_cmdarray[] = new String[4]; + int vifinit_rc; + vifinit_cmdarray[0] = d.XIToolsDir + "xi_vifinit"; + vifinit_cmdarray[1] = "" + domain_id; + vifinit_cmdarray[2] = "0"; + vifinit_cmdarray[3] = domain_ip; + if (Settings.TEST) { + reportCommand (vifinit_cmdarray); + vifinit_rc = 0; + } else { + vifinit_p = r.exec (vifinit_cmdarray); + vifinit_rc = vifinit_p.waitFor (); + } + + if (vifinit_rc != 0) { + return reportXIError ("Failed to initialise VIF 0", vifinit_cmdarray); + } + } + } + catch (Exception e) + { + System.err.println ("Could not create new domain (" + e + ")"); + e.printStackTrace (); + rc = -1; + } + + return rc; + } + + public String getName() + { + return "new"; + } + + public String getUsage() + { + return "[-n<domain_name>] [-k<size>] [-i<image>] [-v<num_vifs>] [-r<initrd>] [-d<root_device>] [-f<nfs_root>] [-s<nfs_boot_server>] [-4<ipv4_boot_address>] [-g<ipv4_boot_gateway>] [-m<ipv4_boot_netmask>] [-h<hostname>] [-a<args>]"; + } + + public String getHelpText() + { + return + "Create a new domain. Note that most of the parameters will assume\n" + + "default values: it should not be necessary to specify them all. See\n" + + "domctl.xml for the current default settings.\n" + + "\n" + + "General command line options:\n" + + " -n Domain name domain_name\n" + + " -k Domain size (kb) domain_size_kb\n" + + " -i Domain image name domain_image\n" + + " -v Number of VIFs domain_vifs\n" + + " -r InitRD (if required) domain_init_rd\n" + + " -d Root device (e.g /dev/nfs, /dev/hda3) root_device\n" + + " -a Additional boot parameters\n" + + "\n" + + "Networking options:\n" + + " -f NFS root (if /dev/nfs specified) nw_nfs_root\n" + + " -s NFS server nw_nfs_server\n" + + " -4 Domain IPv4 address nw_ip\n" + + " -g Domain gateway nw_gw\n" + + " -m Domain net mask nw_mask\n" + + " -h Domain hostname nw_host\n" + + "\n" + + "Parameters to -d, -f, -4, -g, -h can be specified as patterns into\n" + + "which the allocated domain ID will be incorporated. e.g. for\n" + + "domain 1 patterns would expand as follows:\n" + + "\n" + + " /dev/hda+ /dev/hda1\n" + + " /dev/hda7+ /dev/hda8\n" + + " 128.232.8.50+ 128.232.8.51\n" + + "\n" + + "Additionally, patterns for -4 -g -m can include an = which is\n" + + "expanded to the corresponding setting from the calling domain.\n"; + } +} diff --git a/tools/domctl/src/uk/ac/cam/cl/xeno/domctl/CommandStart.java b/tools/domctl/src/uk/ac/cam/cl/xeno/domctl/CommandStart.java new file mode 100644 index 0000000000..b84b66d306 --- /dev/null +++ b/tools/domctl/src/uk/ac/cam/cl/xeno/domctl/CommandStart.java @@ -0,0 +1,63 @@ +package uk.ac.cam.cl.xeno.domctl; + +import java.io.*; +import java.net.*; + +public class CommandStart extends Command +{ + public int doCommand(Defaults d, String args[]) + { + Runtime r = Runtime.getRuntime (); + int domain_id = getIntParameter(args, 'n', 0); + int rc = 0; + + if (domain_id == 0) { + System.err.println ("Expected -n<domain_id>"); + rc = -1; + return rc; + } + + try + { + Process start_p; + String start_cmdarray[] = new String[2]; + int start_rc; + start_cmdarray[0] = d.XIToolsDir + "xi_start"; + start_cmdarray[1] = "" + domain_id; + + if (Settings.TEST) { + reportCommand (start_cmdarray); + } else { + start_p = r.exec (start_cmdarray); + start_rc = start_p.waitFor (); + if (start_rc != 0) { + return reportXIError ("Could not start domain", start_cmdarray); + } + } + } + catch (Exception e) + { + System.err.println ("Could not start new domain (" + e + ")"); + e.printStackTrace (); + rc = -1; + } + + return rc; + } + + public String getName() + { + return "start"; + } + + public String getUsage() + { + return "[-n<domain_id>]"; + } + + public String getHelpText() + { + return + "Start the specified domain."; + } +} diff --git a/tools/domctl/src/uk/ac/cam/cl/xeno/domctl/CommandStop.java b/tools/domctl/src/uk/ac/cam/cl/xeno/domctl/CommandStop.java new file mode 100644 index 0000000000..c6b4cadd6c --- /dev/null +++ b/tools/domctl/src/uk/ac/cam/cl/xeno/domctl/CommandStop.java @@ -0,0 +1,64 @@ +package uk.ac.cam.cl.xeno.domctl; + +import java.io.*; +import java.net.*; + +public class CommandStop extends Command +{ + public int doCommand(Defaults d, String args[]) + { + Runtime r = Runtime.getRuntime (); + int domain_id = getIntParameter(args, 'n', 0); + int rc = 0; + + if (domain_id == 0) { + System.err.println ("Expected -n<domain_id>"); + rc = -1; + return rc; + } + + try + { + Process stop_p; + String stop_cmdarray[] = new String[2]; + int stop_rc; + stop_cmdarray[0] = d.XIToolsDir + "xi_stop"; + stop_cmdarray[1] = "" + domain_id; + + if (Settings.TEST) { + reportCommand (stop_cmdarray); + } else { + stop_p = r.exec (stop_cmdarray); + stop_rc = stop_p.waitFor (); + + if (stop_rc != 0) { + return reportXIError ("Could not stop domain", stop_cmdarray); + } + } + } + catch (Exception e) + { + System.err.println ("Could not stop new domain (" + e + ")"); + e.printStackTrace (); + rc = -1; + } + + return rc; + } + + public String getName() + { + return "stop"; + } + + public String getUsage() + { + return "[-n<domain_id>]"; + } + + public String getHelpText() + { + return + "Stop the specified domain."; + } +} diff --git a/tools/domctl/src/uk/ac/cam/cl/xeno/domctl/Defaults.java b/tools/domctl/src/uk/ac/cam/cl/xeno/domctl/Defaults.java new file mode 100644 index 0000000000..bacce11a95 --- /dev/null +++ b/tools/domctl/src/uk/ac/cam/cl/xeno/domctl/Defaults.java @@ -0,0 +1,153 @@ +package uk.ac.cam.cl.xeno.domctl; + +import java.net.InetAddress; +import java.io.*; +import org.xml.sax.*; +import org.xml.sax.helpers.*; + +public class Defaults +{ + String domainName; + + int domainSizeKB; + String domainImage; + String domainInitRD; + int domainVIFs; + + String rootDevice; + + String NWIP; + String NWGW; + String NWMask; + String NWHost; + + String NWNFSServer; + String NWNFSRoot; + + int MaxDomainNumber; + + String XIToolsDir; + + /***********************************************************************/ + + public Defaults () + { + File f = Settings.getDefaultsFile (); + System.out.println ("f=" + f); + + try + { + XMLReader xr = new org.apache.crimson.parser.XMLReaderImpl(); + Handler handler = new Handler (); + xr.setContentHandler (handler); + xr.setErrorHandler (handler); + xr.parse (new InputSource(new FileReader (f))); + } + catch (Exception e) + { + System.err.println ("Could not read defaults file " + f + + "\nException: " + e); + e.printStackTrace(); + System.exit(1); + } + + System.out.println ("Domain defaults:"); + System.out.println (" name " + domainName); + System.out.println (" size " + domainSizeKB); + System.out.println (" vifs " + domainVIFs); + System.out.println (" domainImage " + domainImage); + System.out.println (" domainInitRD " + domainInitRD); + System.out.println (" rootDevice " + rootDevice); + System.out.println (" NWIP " + NWIP); + System.out.println (" NWGW " + NWGW); + System.out.println (" NWMask " + NWMask); + System.out.println (" MaxDomainNumber " + MaxDomainNumber); + System.out.println (" NWNFSServer " + NWNFSServer); + System.out.println (" NWNFSRoot " + NWNFSRoot); + System.out.println (" XIToolsDir " + XIToolsDir); + } + + /***********************************************************************/ + + class Handler extends DefaultHandler + { + boolean inDomctlDefaults; + String lastName; + + public void startDocument () + { + } + + public void endDocument () + { + } + + public void startElement (String uri, String name, + String qname, Attributes atts) + { + if (qname.equals ("domctl_defaults")) { + inDomctlDefaults = true; + } else { + lastName = qname; + } + } + + public void endElement (String uri, String name, String qname) + { + lastName = ""; + if (qname.equals ("domctl_defaults")) { + inDomctlDefaults = false; + } + } + + public void characters (char ch[], int start, int length) + { + String s = new String (ch, start, length); + if (lastName != null) + { + if (lastName.equals ("domain_size_kb")) { + domainSizeKB = Integer.parseInt (s); + } else if (lastName.equals ("domain_image")) { + domainImage = s; + } else if (lastName.equals ("domain_name")) { + domainName = s; + } else if (lastName.equals ("domain_init_rd")) { + domainInitRD = s; + } else if (lastName.equals ("domain_vifs")) { + domainVIFs = Integer.parseInt (s); + } else if (lastName.equals ("root_device")) { + rootDevice = s; + } else if (lastName.equals ("nw_ip")) { + NWIP = expandDefault (s, Settings.LOCAL_IP); + } else if (lastName.equals ("nw_gw")) { + NWGW = expandDefault (s, Settings.LOCAL_GW); + } else if (lastName.equals ("nw_mask")) { + NWMask = expandDefault (s, Settings.LOCAL_MASK); + } else if (lastName.equals ("nw_host")) { + NWHost = s; + } else if (lastName.equals ("nw_nfs_server")) { + NWNFSServer = s; + } else if (lastName.equals ("nw_nfs_root")) { + NWNFSRoot = s; + } else if (lastName.equals ("max_domain_number")) { + MaxDomainNumber = Integer.parseInt(s); + } else if (lastName.equals ("xi_tools_dir")) { + XIToolsDir = s; + } + } + } + } + + public String expandDefault (String supplied, String self) + { + if (supplied.startsWith ("=")) { + if (supplied.length() > 1) { + return self + supplied.substring (1, supplied.length()); + } else { + return self; + } + } else { + return supplied; + } + } +} diff --git a/tools/domctl/src/uk/ac/cam/cl/xeno/domctl/InetAddressPattern.java b/tools/domctl/src/uk/ac/cam/cl/xeno/domctl/InetAddressPattern.java new file mode 100644 index 0000000000..5786edde71 --- /dev/null +++ b/tools/domctl/src/uk/ac/cam/cl/xeno/domctl/InetAddressPattern.java @@ -0,0 +1,60 @@ +package uk.ac.cam.cl.xeno.domctl; + +import java.net.*; + +public class InetAddressPattern +{ + InetAddress base; + boolean addDom; + + static InetAddressPattern parse (String t) + { + InetAddressPattern result = new InetAddressPattern (); + char[] ca = t.toCharArray (); + int idx = 0; + int len = ca.length; + + try { + if (len == 0) { + result.base = null; + result.addDom = false; + } else if (ca[len - 1] == '+') { + result.base = InetAddress.getByName(t.substring(0, len - 1)); + result.addDom = true; + } else { + result.base = InetAddress.getByName(t); + result.addDom = false; + } + } catch (UnknownHostException uhe) { + result.base = null; + result.addDom = false; + } + + return result; + } + + public String resolve (int domain_id) { + byte b[] = base.getAddress (); + if (addDom) { + if (((int)b[3]) + domain_id > 255) { + if (((int)b[2]) + domain_id > 255) { + if (((int)b[1]) + domain_id > 255) { + b[0] ++; + } + b[1] ++; + } + b[2] ++; + } + b[3] += domain_id; + } + return "" + + (b[0] + (b[0] < 0 ? 256 : 0)) + "." + + (b[1] + (b[1] < 0 ? 256 : 0)) + "." + + (b[2] + (b[2] < 0 ? 256 : 0)) + "." + + (b[3] + (b[3] < 0 ? 256 : 0)); + } + + public String toString () { + return "[" + base + (addDom ? "+dom_id" : "") + "]"; + } +} diff --git a/tools/domctl/src/uk/ac/cam/cl/xeno/domctl/Main.java b/tools/domctl/src/uk/ac/cam/cl/xeno/domctl/Main.java new file mode 100644 index 0000000000..49b4fb3c54 --- /dev/null +++ b/tools/domctl/src/uk/ac/cam/cl/xeno/domctl/Main.java @@ -0,0 +1,39 @@ +package uk.ac.cam.cl.xeno.domctl; + +public class Main +{ + static CommandHelp help = new CommandHelp (); + static CommandNew newdom = new CommandNew (); + static CommandStart start = new CommandStart (); + static CommandStop stop = new CommandStop (); + static CommandDestroy destroy = new CommandDestroy (); + static Command commands[] = { help, newdom, start, stop, destroy }; + + public static void main (String[] args) + { + Defaults d = new Defaults (); + int ec = -1; + + if (args.length == 0) { + ec = help.doCommand (d, args); + } else { + String c = args[0]; + int i; + for (i = 0; i < commands.length; i ++) { + if (commands[i].getName().equals(c)) { + if (commands[i].getFlagParameter (args, '?')) { + ec = help.doHelpFor (commands[i]); + } else { + ec = commands[i].doCommand (d, args); + } + break; + } + } + if (i == commands.length) { + System.out.println ("Unknown command " + c); + } + } + + System.exit (ec); + } +} diff --git a/tools/domctl/src/uk/ac/cam/cl/xeno/domctl/Settings.java b/tools/domctl/src/uk/ac/cam/cl/xeno/domctl/Settings.java new file mode 100644 index 0000000000..13d1a2d1df --- /dev/null +++ b/tools/domctl/src/uk/ac/cam/cl/xeno/domctl/Settings.java @@ -0,0 +1,38 @@ +package uk.ac.cam.cl.xeno.domctl; + +import java.util.*; +import java.io.*; +import org.xml.sax.*; + +public final class Settings +{ + public static final String DEFAULTS_FILE = System.getProperty ("DEFAULTS_FILE"); + public static final String DEFAULTS_PATH = System.getProperty ("DEFAULTS_PATH"); + public static final String LOCAL_IP = System.getProperty ("LOCAL_IP"); + public static final String LOCAL_MASK = System.getProperty ("LOCAL_MASK"); + public static final String LOCAL_GW = System.getProperty ("LOCAL_ROUTE"); + public static final boolean TEST = (System.getProperty ("TEST") != null); + + + public static File getDefaultsFile() { + StringTokenizer tok = new StringTokenizer (DEFAULTS_PATH, ":"); + File result = null; + File probe; + + while (tok.hasMoreTokens ()) { + String probe_dir = tok.nextToken (); + probe = new File (probe_dir, DEFAULTS_FILE); + if (probe.exists ()) { + result = probe; + break; + } + } + + if (result == null) { + System.err.println ("Could not find " + DEFAULTS_FILE + " in path " + DEFAULTS_PATH); + System.exit (1); + } + + return result; + } +} diff --git a/tools/domctl/src/uk/ac/cam/cl/xeno/domctl/StringPattern.java b/tools/domctl/src/uk/ac/cam/cl/xeno/domctl/StringPattern.java new file mode 100644 index 0000000000..a0486ba2be --- /dev/null +++ b/tools/domctl/src/uk/ac/cam/cl/xeno/domctl/StringPattern.java @@ -0,0 +1,59 @@ +package uk.ac.cam.cl.xeno.domctl; + +public class StringPattern +{ + String base; + int bn; + boolean addDom; + boolean appendDom; + + static StringPattern parse (String t) + { + StringPattern result = new StringPattern (); + char[] ca = t.toCharArray (); + int idx = 0; + int len = ca.length; + + if (len == 0) { + result.base = ""; + result.bn = 0; + result.addDom = false; + } else if (ca[len - 1] == '+') { + idx = len - 2; + if ((idx >= 0) && (ca[idx] >= '0') && (ca[idx] <= '9')) { + while ((idx >= 0) && (ca[idx] >= '0') && (ca[idx] <= '9')) { + idx --; + } + result.base = t.substring(0, idx + 1); + result.bn = Integer.parseInt (t.substring (idx + 1, len - 1)); + result.addDom = true; + } else { + result.base = t.substring(0, len - 1); + result.appendDom = true; + } + } else { + result.base = t; + } + + return result; + } + + public String resolve (int domain_id) { + if (addDom) { + return base + (bn + domain_id); + } else if (appendDom) { + return base + domain_id; + } else { + return base; + } + } + + public String toString () { + return ("[" + + base + + (addDom ? "+" + bn : "") + + ((addDom || appendDom) ? "+ID" : "") + + "]"); + } + +} diff --git a/tools/internal/Makefile b/tools/internal/Makefile new file mode 100644 index 0000000000..d2e19221d1 --- /dev/null +++ b/tools/internal/Makefile @@ -0,0 +1,32 @@ +CC = gcc +XI_CREATE = xi_create +XI_START = xi_start +XI_STOP = xi_stop +XI_DESTROY = xi_destroy +XI_BUILD = xi_build + +all: $(XI_CREATE).o $(XI_START).o $(XI_STOP).o $(XI_DESTROY).o $(XI_BUILD).o + $(CC) -o $(XI_CREATE) $(XI_CREATE).o + $(CC) -o $(XI_BUILD) $(XI_BUILD).o + $(CC) -o $(XI_START) $(XI_START).o + $(CC) -o $(XI_STOP) $(XI_STOP).o + $(CC) -o $(XI_DESTROY) $(XI_DESTROY).o + +$(XI_CREATE).o: $(XI_CREATE).c dom0_defs.h dom0_ops.h hypervisor_defs.h mem_defs.h + $(CC) -c $(XI_CREATE).c + +internal_domain_build.o: internal_domain_build.c dom0_defs.h dom0_ops.h hypervisor_defs.h mem_defs.h + $(CC) -c internal_domain_build.c + +$(XI_START).o: $(XI_START).c dom0_defs.h dom0_ops.h hypervisor_defs.h mem_defs.h + $(CC) -c $(XI_START).c + +$(XI_STOP).o: $(XI_STOP).c dom0_defs.h dom0_ops.h hypervisor_defs.h mem_defs.h + $(CC) -c $(XI_STOP).c + +$(XI_DESTROY).o: $(XI_DESTROY).c dom0_ops.h dom0_defs.h + $(CC) -c $(XI_DESTROY).c + +clean: + $(RM) *.o $(XI_CREATE) $(XI_START) $(XI_STOP) $(XI_DESTROY) $(XI_BUILD) + diff --git a/tools/internal/dom0_defs.h b/tools/internal/dom0_defs.h new file mode 100644 index 0000000000..e79d85d417 --- /dev/null +++ b/tools/internal/dom0_defs.h @@ -0,0 +1,9 @@ +#define PROC_XENO_ROOT "xeno" +#define PROC_CMD "dom0_cmd" +#define PROC_DOM_PREFIX "dom" +#define PROC_DOM_MEM "mem" +#define PROC_DOM_DATA "new_dom_data" +#define PROC_DOMAINS "domains" + +#define MAX_PATH 256 + diff --git a/tools/internal/hypervisor_defs.h b/tools/internal/hypervisor_defs.h new file mode 100644 index 0000000000..7d0aba03d7 --- /dev/null +++ b/tools/internal/hypervisor_defs.h @@ -0,0 +1,36 @@ +/****************************************************************************** + * hypervisor_defs.h + * + * This needs to be kept in sync with Xen's pagetable update interface! + * + * Copyright (c) 2002-2003, Keir Fraser & Boris Dragovic + */ + +/* taken from include/hypervisor-ifs/hypervisor-if.h */ +typedef struct +{ +/* + * PGREQ_XXX: specified in least-significant bits of 'ptr' field. All requests + * specify relevent PTE or PT address in 'ptr'. Normal requests specify update + * value in 'value'. Extended requests specify command in least 8 bits of + * 'value'. + */ + unsigned long ptr, val; /* *ptr = val */ +} page_update_request_t; + +/* A normal page-table update request. */ +#define PGREQ_NORMAL 0 +#define PGREQ_MPT_UPDATE 1 +/* An extended command. */ +#define PGREQ_EXTENDED_COMMAND 2 +/* Announce a new top-level page table. */ +#define PGEXT_PIN_L1_TABLE 0 +#define PGEXT_PIN_L2_TABLE 1 +#define PGEXT_PIN_L3_TABLE 2 +#define PGEXT_PIN_L4_TABLE 3 +#define PGEXT_UNPIN_TABLE 4 +#define PGEXT_NEW_BASEPTR 5 +#define PGEXT_TLB_FLUSH 6 +#define PGEXT_INVLPG 7 +#define PGEXT_CMD_MASK 255 +#define PGEXT_CMD_SHIFT 8 diff --git a/tools/internal/mem_defs.h b/tools/internal/mem_defs.h new file mode 100644 index 0000000000..a9a1441d61 --- /dev/null +++ b/tools/internal/mem_defs.h @@ -0,0 +1,45 @@ +/* + * memory related definitions needed for userspace domain builder dom0 application. these _need_ to + * be kept in sync with the kernel .h files they were copied over from or something horrible will + * happen. remmember: god kills a kitten every time you forget to keep these in sync. + * + * KAF: Boris, these constants are all fixed by x86 hardware. So the kittens are safe for now :-) + * + * Copyright 2002 by B Dragovic + */ + +/* copied over from hypervisor: include/asm-i386/page.h */ + +#define _PAGE_PRESENT 0x001 +#define _PAGE_RW 0x002 +#define _PAGE_USER 0x004 +#define _PAGE_PWT 0x008 +#define _PAGE_PCD 0x010 +#define _PAGE_ACCESSED 0x020 +#define _PAGE_DIRTY 0x040 +#define _PAGE_PAT 0x080 +#define _PAGE_PSE 0x080 +#define _PAGE_GLOBAL 0x100 + + +#define L1_PAGETABLE_SHIFT 12 +#define L2_PAGETABLE_SHIFT 22 + +#define ENTRIES_PER_L1_PAGETABLE 1024 +#define ENTRIES_PER_L2_PAGETABLE 1024 + +#define PAGE_SHIFT L1_PAGETABLE_SHIFT +#define PAGE_SIZE (1UL << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE-1)) + +typedef struct { unsigned long l1_lo; } l1_pgentry_t; +typedef struct { unsigned long l2_lo; } l2_pgentry_t; + +#define l1_table_offset(_a) \ + (((_a) >> L1_PAGETABLE_SHIFT) & (ENTRIES_PER_L1_PAGETABLE - 1)) +#define l2_table_offset(_a) \ + ((_a) >> L2_PAGETABLE_SHIFT) + +/* local definitions */ + +#define nr_2_page(x) (x << PAGE_SHIFT) diff --git a/tools/internal/xi_build.c b/tools/internal/xi_build.c new file mode 100644 index 0000000000..2df44f6532 --- /dev/null +++ b/tools/internal/xi_build.c @@ -0,0 +1,524 @@ +/* + * XenoDomainBuilder, copyright (c) Boris Dragovic, bd240@cl.cam.ac.uk + * This code is released under terms and conditions of GNU GPL :). + * Usage: <executable> <mem_kb> <os image> <num_vifs> + */ + +#include <unistd.h> +#include <stdio.h> +#include <errno.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <stdlib.h> + +#include "hypervisor_defs.h" +#include "dom0_ops.h" +#include "dom0_defs.h" +#include "mem_defs.h" + +#define PERR_STRING "Xeno Domain Builder" + +#define GUEST_SIG "XenoGues" +#define SIG_LEN 8 + +/* + * NB. No ring-3 access in initial guestOS pagetables. Note that we allow + * ring-3 privileges in the page directories, so that the guestOS may later + * decide to share a 4MB region with applications. + */ +#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED) +#define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER) + +/* standardized error reporting function */ +static void dberr(char *msg) +{ + printf("%s: %s\n", PERR_STRING, msg); +} + +/* status reporting function */ +static void dbstatus(char * msg) +{ + printf("Domain Builder: %s\n", msg); +} + + +/* clean up domain's memory allocations */ +static void dom_mem_cleanup(dom_mem_t * dom_mem) +{ + char mem_path[MAX_PATH]; + int mem_fd; + + /* open the domain's /proc mem interface */ + sprintf(mem_path, "%s%s%s%s%d%s%s", "/proc/", PROC_XENO_ROOT, "/", + PROC_DOM_PREFIX, dom_mem->domain, "/", PROC_DOM_MEM); + + mem_fd = open(mem_path, O_WRONLY); + if(mem_fd < 0){ + perror(PERR_STRING); + } + + if(write(mem_fd, (dom_mem_t *)dom_mem, sizeof(dom_mem_t)) < 0){ + dbstatus("Error unmapping domain's memory.\n"); + } + + close(mem_fd); +} + +/* ask dom0 to export domains memory through /proc */ +static int setup_dom_memmap(unsigned long pfn, int pages, int dom) +{ + char cmd_path[MAX_PATH]; + dom0_op_t dop; + int cmd_fd; + + dop.cmd = MAP_DOM_MEM; + dop.u.dommem.start_pfn = pfn; + dop.u.dommem.tot_pages = pages; + dop.u.dommem.domain = dom; + + /* open the /proc command interface */ + sprintf(cmd_path, "%s%s%s%s", "/proc/", PROC_XENO_ROOT, "/", PROC_CMD); + cmd_fd = open(cmd_path, O_WRONLY); + if(cmd_fd < 0){ + perror(PERR_STRING); + return -1; + } + + write(cmd_fd, &dop, sizeof(dom0_op_t)); + close(cmd_fd); + + return 0; +} + +/* request the actual mapping from dom0 */ +static unsigned long get_vaddr(unsigned int dom) +{ + char mem_path[MAX_PATH]; + unsigned long addr; + int mem_fd; + + /* open the domain's /proc mem interface */ + sprintf(mem_path, "%s%s%s%s%d%s%s", "/proc/", PROC_XENO_ROOT, "/", + PROC_DOM_PREFIX, dom, "/", PROC_DOM_MEM); + + mem_fd = open(mem_path, O_RDONLY); + if(mem_fd < 0){ + perror(PERR_STRING); + return 0; + } + + /* get virtual address of mapped region */ + read(mem_fd, &addr, sizeof(addr)); + + close(mem_fd); + + return addr; +} + +static int map_dom_mem(unsigned long pfn, int pages, int dom, + dom_mem_t * dom_mem) +{ + + if(setup_dom_memmap(pfn, pages, dom)){ + perror(PERR_STRING); + return -1; + } + + dom_mem->domain = dom; + dom_mem->start_pfn = pfn; + dom_mem->tot_pages = pages; + if((dom_mem->vaddr = get_vaddr(dom)) == 0){ + dberr("Error mapping dom memory."); + return -1; + } + + return 0; +} + +/* open kernel image and do some sanity checks */ +static int do_kernel_chcks(char *image, long dom_size, + unsigned long * load_addr, size_t * ksize) +{ + char signature[8]; + char status[MAX_PATH]; + struct stat stat; + int fd; + int ret; + + fd = open(image, O_RDONLY); + if(fd < 0){ + perror(PERR_STRING); + ret = -1; + goto out; + } + + if(fstat(fd, &stat) < 0){ + perror(PERR_STRING); + ret = -1; + close(fd); + goto out; + } + + if(stat.st_size > (dom_size << 10)){ + sprintf(status, "Kernel image size %ld larger than requested " + "domain size %ld\n Terminated.\n", stat.st_size, dom_size); + dberr(status); + ret = -1; + close(fd); + goto out; + } + + read(fd, signature, SIG_LEN); + if(strncmp(signature, GUEST_SIG, SIG_LEN)){ + dberr("Kernel image does not contain required signature. " + "Terminating.\n"); + ret = -1; + close(fd); + goto out; + } + + read(fd, load_addr, sizeof(unsigned long)); + + *ksize = stat.st_size - SIG_LEN - sizeof(unsigned long); + + ret = fd; + +out: + return ret; +} + +/* this is the main guestos setup function, + * returnes domain descriptor structure to be used when launching + * the domain by hypervisor to do some last minute initialization. + * page table initialization is done by making a list of page table + * requests that are handeled by the hypervisor in the ordinary + * manner. this way, many potentially messy things are avoided... + */ +#define PAGE_TO_VADDR(_pfn) ((void *)(dom_mem->vaddr + ((_pfn) * PAGE_SIZE))) +static dom_meminfo_t *setup_guestos(int dom, int kernel_fd, int initrd_fd, + unsigned long virt_load_addr, size_t ksize, dom_mem_t *dom_mem) +{ + dom_meminfo_t *meminfo; + unsigned long *page_array; + page_update_request_t *pgt_updates; + dom_mem_t mem_map; + dom_meminfo_t *ret = NULL; + int alloc_index, num_pt_pages; + unsigned long l2tab; + unsigned long l1tab = 0; + unsigned long num_pgt_updates = 0; + unsigned long count, pt_start; + dom0_op_t pgupdate_req; + char cmd_path[MAX_PATH]; + int cmd_fd; + + meminfo = (dom_meminfo_t *)malloc(sizeof(dom_meminfo_t)); + page_array = malloc(dom_mem->tot_pages * 4); + pgt_updates = (page_update_request_t *)dom_mem->vaddr; + alloc_index = dom_mem->tot_pages - 1; + + memset(meminfo, 0, sizeof(meminfo)); + + memcpy(page_array, (void *)dom_mem->vaddr, dom_mem->tot_pages * 4); + + /* Count bottom-level PTs, rounding up. Include one PTE for shared info. */ + num_pt_pages = + (l1_table_offset(virt_load_addr) + dom_mem->tot_pages + 1024) / 1024; + + /* We must also count the page directory. */ + num_pt_pages++; + + /* Index of first PT page. */ + pt_start = dom_mem->tot_pages - num_pt_pages; + + /* first allocate page for page dir. allocation goes backwards from the + * end of the allocated physical address space. + */ + l2tab = *(page_array + alloc_index) << PAGE_SHIFT; + memset(PAGE_TO_VADDR(alloc_index), 0, PAGE_SIZE); + alloc_index--; + meminfo->l2_pgt_addr = l2tab; + meminfo->virt_shinfo_addr = virt_load_addr + nr_2_page(dom_mem->tot_pages); + + /* pin down l2tab addr as page dir page - causes hypervisor to provide + * correct protection for the page + */ + pgt_updates->ptr = l2tab | PGREQ_EXTENDED_COMMAND; + pgt_updates->val = PGEXT_PIN_L2_TABLE; + pgt_updates++; + num_pgt_updates++; + + /* + * Initialise the page tables. The final iteration is for the shared_info + * PTE -- we break out before filling in the entry, as that is done by + * Xen during final setup. + */ + l2tab += l2_table_offset(virt_load_addr) * sizeof(l2_pgentry_t); + for ( count = 0; count < (dom_mem->tot_pages + 1); count++ ) + { + if ( !((unsigned long)l1tab & (PAGE_SIZE-1)) ) + { + l1tab = *(page_array + alloc_index) << PAGE_SHIFT; + memset(PAGE_TO_VADDR(alloc_index), 0, PAGE_SIZE); + alloc_index--; + + l1tab += l1_table_offset(virt_load_addr + nr_2_page(count)) + * sizeof(l1_pgentry_t); + + /* make apropriate entry in the page directory */ + pgt_updates->ptr = l2tab; + pgt_updates->val = l1tab | L2_PROT; + pgt_updates++; + num_pgt_updates++; + l2tab += sizeof(l2_pgentry_t); + } + + /* The last PTE we consider is filled in later by Xen. */ + if ( count == dom_mem->tot_pages ) break; + + if ( count < pt_start ) + { + pgt_updates->ptr = l1tab; + pgt_updates->val = (*(page_array + count) << PAGE_SHIFT) | L1_PROT; + pgt_updates++; + num_pgt_updates++; + l1tab += sizeof(l1_pgentry_t); + } + else + { + pgt_updates->ptr = l1tab; + pgt_updates->val = + ((*(page_array + count) << PAGE_SHIFT) | L1_PROT) & ~_PAGE_RW; + pgt_updates++; + num_pgt_updates++; + l1tab += sizeof(l1_pgentry_t); + } + + pgt_updates->ptr = + (*(page_array + count) << PAGE_SHIFT) | PGREQ_MPT_UPDATE; + pgt_updates->val = count; + pgt_updates++; + num_pgt_updates++; + } + + meminfo->virt_startinfo_addr = virt_load_addr + nr_2_page(alloc_index - 1); + meminfo->domain = dom; + + /* + * Send the page update requests down to the hypervisor. + * NB. We must do this before loading the guest OS image! + */ + sprintf(cmd_path, "%s%s%s%s", "/proc/", PROC_XENO_ROOT, "/", PROC_CMD); + if ( (cmd_fd = open(cmd_path, O_WRONLY)) < 0 ) goto out; + pgupdate_req.cmd = DO_PGUPDATES; + pgupdate_req.u.pgupdate.pgt_update_arr = (unsigned long)dom_mem->vaddr; + pgupdate_req.u.pgupdate.num_pgt_updates = num_pgt_updates; + write(cmd_fd, &pgupdate_req, sizeof(dom0_op_t)); + close(cmd_fd); + + /* Load the guest OS image. */ + if( read(kernel_fd, (char *)dom_mem->vaddr, ksize) != ksize ) + { + dberr("Error reading kernel image, could not" + " read the whole image. Terminating.\n"); + goto out; + } + + if( initrd_fd ) + { + struct stat stat; + unsigned long isize; + + if(fstat(initrd_fd, &stat) < 0){ + perror(PERR_STRING); + close(initrd_fd); + goto out; + } + isize = stat.st_size; + + if( read(initrd_fd, ((char *)dom_mem->vaddr)+ksize, isize) != isize ) + { + dberr("Error reading initrd image, could not" + " read the whole image. Terminating.\n"); + goto out; + } + + meminfo->virt_mod_addr = virt_load_addr + ksize; + meminfo->virt_mod_len = isize; + + } + + + ret = meminfo; +out: + + return ret; +} + +static int launch_domain(dom_meminfo_t * meminfo) +{ + char cmd_path[MAX_PATH]; + dom0_op_t dop; + int cmd_fd; + + sprintf(cmd_path, "%s%s%s%s", "/proc/", PROC_XENO_ROOT, "/", PROC_CMD); + cmd_fd = open(cmd_path, O_WRONLY); + if(cmd_fd < 0){ + perror(PERR_STRING); + return -1; + } + + dop.cmd = DOM0_BUILDDOMAIN; + memcpy(&dop.u.meminfo, meminfo, sizeof(dom_meminfo_t)); + write(cmd_fd, &dop, sizeof(dom0_op_t)); + close(cmd_fd); + + return 0; +} + +static int get_domain_info (int domain_id, + int *pg_head, + int *tot_pages) +{ + FILE *f; + char domains_path[MAX_PATH]; + char domains_line[256]; + int rc = -1; + int read_id; + + sprintf (domains_path, "%s%s%s%s", "/proc/", PROC_XENO_ROOT, "/", PROC_DOMAINS +); + + f = fopen (domains_path, "r"); + if (f == NULL) goto out; + + read_id = -1; + while (fgets (domains_line, 256, f) != 0) + { + int trans; + trans = sscanf (domains_line, "%d %*d %*d %*d %*d %*d %x %d %*s", &read_id +, pg_head, tot_pages); + if (trans == 3) { + if (read_id == domain_id) { + rc = 0; + break; + } + } + } + + if (read_id == -1) { + errno = ESRCH; + } + + fclose (f); + + out: + return rc; +} + + +int main(int argc, char **argv) +{ + + dom_mem_t dom_os_image; + dom_mem_t dom_pgt; + dom_meminfo_t * meminfo; + size_t ksize; + unsigned long load_addr; + char status[1024]; + int kernel_fd, initrd_fd = 0; + int count; + int cmd_len; + int rc = -1; + int args_start = 4; + char initrd_name[1024]; + int domain_id; + int pg_head; + int tot_pages; + + unsigned long addr; + + /**** this argument parsing code is really _gross_. rewrite me! ****/ + + if(argc < 4) { + dberr("Usage: dom_builder <domain_id> <image> <num_vifs> " + "[<initrd=initrd_name>] <boot_params>\n"); + return -1; + } + + /* Look up information about the domain */ + domain_id = atol(argv[1]); + if (get_domain_info (domain_id, &pg_head, &tot_pages) != 0) { + perror ("Could not find domain information"); + rc = -1; + goto out; + } + + kernel_fd = do_kernel_chcks(argv[2], tot_pages << (PAGE_SHIFT - 10), &load_addr, &ksize); + if(kernel_fd < 0) + return -1; + + + /* map domain's memory */ + if(map_dom_mem(pg_head, tot_pages, + domain_id, &dom_os_image)) + goto out; + + if( strncmp("initrd=", argv[args_start], 7) == 0 ) + { + strncpy( initrd_name, argv[args_start]+7, sizeof(initrd_name) ); + initrd_name[sizeof(initrd_name)-1] = 0; + printf("initrd present, name = %s\n", initrd_name ); + args_start++; + + initrd_fd = open(initrd_name, O_RDONLY); + if(initrd_fd < 0){ + perror(PERR_STRING); + goto out; + } + } + + /* the following code does the actual domain building */ + meminfo = setup_guestos(domain_id, kernel_fd, initrd_fd, load_addr, + ksize, &dom_os_image); + + /* and unmap the new domain's memory image since we no longer need it */ + dom_mem_cleanup(&dom_os_image); + + if(!meminfo) { + printf("Domain Builder: debug: meminfo NULL\n"); + goto out; + } + + meminfo->virt_load_addr = load_addr; + meminfo->num_vifs = atoi(argv[3]); + meminfo->cmd_line[0] = '\0'; + cmd_len = 0; + for(count = args_start; count < argc; count++){ + if(cmd_len + strlen(argv[count]) > MAX_CMD_LEN - 1){ + dberr("Size of image boot params too big!\n"); + break; + } + strcat(meminfo->cmd_line, argv[count]); + strcat(meminfo->cmd_line, " "); + cmd_len += strlen(argv[count] + 1); + } + + /* sprintf(status, + "About to launch new domain %d with folowing parameters:\n" + " * page table base: %lx \n * load address: %lx \n" + " * shared info address: %lx \n * start info address: %lx \n" + " * number of vifs: %d \n * cmd line: %s \n", meminfo->domain, + meminfo->l2_pgt_addr, meminfo->virt_load_addr, + meminfo->virt_shinfo_addr, meminfo->virt_startinfo_addr, + meminfo->num_vifs, meminfo->cmd_line); + dbstatus(status);*/ + + /* and launch the domain */ + rc = launch_domain(meminfo); + +out: + return rc; +} diff --git a/tools/internal/xi_create.c b/tools/internal/xi_create.c new file mode 100644 index 0000000000..5162e27bba --- /dev/null +++ b/tools/internal/xi_create.c @@ -0,0 +1,98 @@ +/* + * XenoDomainBuilder, copyright (c) Boris Dragovic, bd240@cl.cam.ac.uk + * This code is released under terms and conditions of GNU GPL :). + * Usage: <executable> <mem_kb> <os image> <num_vifs> + */ + +#include <unistd.h> +#include <stdio.h> +#include <errno.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <stdlib.h> + +#include "hypervisor_defs.h" +#include "dom0_ops.h" +#include "dom0_defs.h" +#include "mem_defs.h" + +/***********************************************************************/ + +static char *argv0 = "internal_domain_create"; + +static void ERROR (char *message) +{ + fprintf (stderr, "%s: %s\n", argv0, message); + exit (-1); +} + +static void PERROR (char *message) +{ + fprintf (stderr, "%s: %s (%s)\n", argv0, message, sys_errlist[errno]); + exit (-1); +} + +/***********************************************************************/ + +static dom0_newdomain_t * create_new_domain(long req_mem, char *name) +{ + dom0_newdomain_t * dom_data; + char cmd_path[MAX_PATH]; + char dom_id_path[MAX_PATH]; + dom0_op_t dop; + int cmd_fd; + int id_fd; + + /* open the /proc command interface */ + sprintf(cmd_path, "%s%s%s%s", "/proc/", PROC_XENO_ROOT, "/", PROC_CMD); + cmd_fd = open(cmd_path, O_WRONLY); + if(cmd_fd < 0){ + PERROR ("Could not open PROC_CMD interface"); + return 0; + } + + dop.cmd = DOM0_CREATEDOMAIN; + dop.u.newdomain.memory_kb = req_mem; + strncpy (dop.u.newdomain.name, name, MAX_DOMAIN_NAME - 1); + dop.u.newdomain.name[MAX_DOMAIN_NAME - 1] = 0; + + write(cmd_fd, &dop, sizeof(dom0_op_t)); + close(cmd_fd); + + sprintf(dom_id_path, "%s%s%s%s", "/proc/", PROC_XENO_ROOT, "/", + PROC_DOM_DATA); + while((id_fd = open(dom_id_path, O_RDONLY)) < 0) continue; + dom_data = (dom0_newdomain_t *)malloc(sizeof(dom0_newdomain_t)); + read(id_fd, dom_data, sizeof(dom0_newdomain_t)); + close(id_fd); + + return dom_data; +} + +/***********************************************************************/ + +int main(int argc, char **argv) +{ + dom0_newdomain_t * dom_data; + + if (argv[0] != NULL) + { + argv0 = argv[0]; + } + + if(argc != 3) + { + fprintf (stderr, "Usage: %s <kbytes-mem> <domain-name>\n", argv0); + return -1; + } + + if(!(dom_data = create_new_domain(atol(argv[1]), argv[2]))) + { + return -1; + } + + fprintf (stdout, "%d\n", dom_data -> domain); + return 0; +} diff --git a/tools/internal/xi_destroy.c b/tools/internal/xi_destroy.c new file mode 100644 index 0000000000..b262609165 --- /dev/null +++ b/tools/internal/xi_destroy.c @@ -0,0 +1,81 @@ +/* + * A very(!) simple program to kill a domain. (c) Boris Dragovic + * Usage: <executable> <mem_kb> <os image> <num_vifs> + */ + +#include <unistd.h> +#include <stdio.h> +#include <errno.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include "dom0_ops.h" +#include "dom0_defs.h" + +/***********************************************************************/ + +static char *argv0 = "internal_domain_stop"; + +static void ERROR (char *message) +{ + fprintf (stderr, "%s: %s\n", argv0, message); + exit (-1); +} + +static void PERROR (char *message) +{ + fprintf (stderr, "%s: %s (%s)\n", argv0, message, sys_errlist[errno]); + exit (-1); +} + +/***********************************************************************/ + +static int do_kill_domain(int dom_id, int force) +{ + char cmd_path[MAX_PATH]; + dom0_op_t dop; + int cmd_fd; + + dop.cmd = DOM0_DESTROYDOMAIN; + dop.u.killdomain.domain = dom_id; + dop.u.killdomain.force = force; + + /* open the /proc command interface */ + sprintf(cmd_path, "%s%s%s%s", "/proc/", PROC_XENO_ROOT, "/", PROC_CMD); + cmd_fd = open(cmd_path, O_WRONLY); + if(cmd_fd < 0){ + PERROR ("Count not open PROC_CMD interface"); + } + + write(cmd_fd, &dop, sizeof(dom0_op_t)); + close(cmd_fd); + + return 0; +} + +int main(int argc, char **argv) +{ + int ret; + + if (argv[0] != NULL) + { + argv0 = argv[0]; + } + + if ( (argc < 2) || (argc > 3) ) + { + usage: + fprintf(stderr, "Usage: %s [-f] <domain_id>\n", argv0); + fprintf(stderr, " -f: Forces immediate destruction of specified domain\n"); + ret = -1; + goto out; + } + + if ( (argc == 3) && strcmp("-f", argv[1]) ) goto usage; + + ret = do_kill_domain(atoi(argv[argc-1]), argc == 3); + +out: + return ret; +} diff --git a/tools/internal/xi_start.c b/tools/internal/xi_start.c new file mode 100644 index 0000000000..7c03180dcc --- /dev/null +++ b/tools/internal/xi_start.c @@ -0,0 +1,80 @@ +#include <unistd.h> +#include <stdio.h> +#include <errno.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <stdlib.h> + +#include "hypervisor_defs.h" +#include "dom0_ops.h" +#include "dom0_defs.h" +#include "mem_defs.h" + +/***********************************************************************/ + +static char *argv0 = "internal_domain_start"; + +static void ERROR (char *message) +{ + fprintf (stderr, "%s: %s\n", argv0, message); + exit (-1); +} + +static void PERROR (char *message) +{ + fprintf (stderr, "%s: %s (%s)\n", argv0, message, sys_errlist[errno]); + exit (-1); +} + +/***********************************************************************/ + +static int start_domain(int id) +{ + dom0_newdomain_t * dom_data; + char cmd_path[MAX_PATH]; + char dom_id_path[MAX_PATH]; + dom0_op_t dop; + int cmd_fd; + int id_fd; + + /* Set up the DOM0_STARTDOMAIN command */ + dop.cmd = DOM0_STARTDOMAIN; + dop.u.meminfo.domain = id; + + /* open the /proc command interface */ + sprintf(cmd_path, "%s%s%s%s", "/proc/", PROC_XENO_ROOT, "/", PROC_CMD); + cmd_fd = open(cmd_path, O_WRONLY); + if(cmd_fd < 0){ + PERROR ("Count not open PROC_CMD interface"); + } + + /* Issue the command */ + write(cmd_fd, &dop, sizeof(dom0_op_t)); + close(cmd_fd); + + return 0; +} + +/***********************************************************************/ + +int main(int argc, char **argv) +{ + int rc; + + if (argv[0] != NULL) + { + argv0 = argv[0]; + } + + if(argc != 2) + { + fprintf (stderr, "Usage: %s <domain-id>\n", argv0); + return -1; + } + + rc = start_domain(atol(argv[1])); + + return rc; +} diff --git a/tools/internal/xi_stop.c b/tools/internal/xi_stop.c new file mode 100644 index 0000000000..cbed24d867 --- /dev/null +++ b/tools/internal/xi_stop.c @@ -0,0 +1,80 @@ +#include <unistd.h> +#include <stdio.h> +#include <errno.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <stdlib.h> + +#include "hypervisor_defs.h" +#include "dom0_ops.h" +#include "dom0_defs.h" +#include "mem_defs.h" + +/***********************************************************************/ + +static char *argv0 = "internal_domain_stop"; + +static void ERROR (char *message) +{ + fprintf (stderr, "%s: %s\n", argv0, message); + exit (-1); +} + +static void PERROR (char *message) +{ + fprintf (stderr, "%s: %s (%s)\n", argv0, message, sys_errlist[errno]); + exit (-1); +} + +/***********************************************************************/ + +static int stop_domain(int id) +{ + dom0_newdomain_t * dom_data; + char cmd_path[MAX_PATH]; + char dom_id_path[MAX_PATH]; + dom0_op_t dop; + int cmd_fd; + int id_fd; + + /* Set up the DOM0_STOPDOMAIN command */ + dop.cmd = DOM0_STOPDOMAIN; + dop.u.meminfo.domain = id; + + /* open the /proc command interface */ + sprintf(cmd_path, "%s%s%s%s", "/proc/", PROC_XENO_ROOT, "/", PROC_CMD); + cmd_fd = open(cmd_path, O_WRONLY); + if(cmd_fd < 0){ + PERROR ("Count not open PROC_CMD interface"); + } + + /* Issue the command */ + write(cmd_fd, &dop, sizeof(dom0_op_t)); + close(cmd_fd); + + return 0; +} + +/***********************************************************************/ + +int main(int argc, char **argv) +{ + int rc; + + if (argv[0] != NULL) + { + argv0 = argv[0]; + } + + if(argc != 2) + { + fprintf (stderr, "Usage: %s <domain-id>\n", argv0); + return -1; + } + + rc = stop_domain(atol(argv[1])); + + return rc; +} diff --git a/tools/internal/xi_vifinit b/tools/internal/xi_vifinit new file mode 100755 index 0000000000..feac666bb6 --- /dev/null +++ b/tools/internal/xi_vifinit @@ -0,0 +1,25 @@ +#!/bin/bash +# +# vifinit +# +# This is a silly little script to dump a couple of simple rules down to +# the hypervisor to assign a full static IP to a given virtual interface. +# +# Usage is: +# +# vifinit [vif dom] [vif idx] [dotted decimal ip address] +# +if [ $# -ne 3 ] ; +then + echo "usage: $0 <domain_id> <vid_ifx> <dotted_decimal_ip_address>" + exit +fi + +#outbound rule: +echo "ADD ACCEPT srcaddr=$3 srcaddrmask=255.255.255.255 srcdom=$1 srcidx=$2 dst=PHYS proto=any" > /proc/vfr + +#inbound rule: +echo "ADD ACCEPT dstaddr=$3 dstaddrmask=255.255.255.255 src=ANY dstdom=$1 dstidx=$2 proto=any" > /proc/vfr + +#----] done. + diff --git a/xen/common/dom0_ops.c b/xen/common/dom0_ops.c index 3ac6e72c0f..fb8d44429e 100644 --- a/xen/common/dom0_ops.c +++ b/xen/common/dom0_ops.c @@ -62,11 +62,19 @@ long do_dom0_op(dom0_op_t *u_dom0_op) switch ( op.cmd ) { - case DOM0_STARTDOM: + case DOM0_BUILDDOMAIN: { struct task_struct * p = find_domain_by_id(op.u.meminfo.domain); if ( (ret = final_setup_guestos(p, &op.u.meminfo)) != 0 ) break; + ret = p->domain; + free_task_struct(p); + } + break; + + case DOM0_STARTDOMAIN: + { + struct task_struct * p = find_domain_by_id(op.u.meminfo.domain); wake_up(p); reschedule(p); ret = p->domain; @@ -74,7 +82,13 @@ long do_dom0_op(dom0_op_t *u_dom0_op) } break; - case DOM0_NEWDOMAIN: + case DOM0_STOPDOMAIN: + { + ret = stop_other_domain (op.u.meminfo.domain); + } + break; + + case DOM0_CREATEDOMAIN: { struct task_struct *p; static unsigned int pro = 0; @@ -89,6 +103,11 @@ long do_dom0_op(dom0_op_t *u_dom0_op) if ( p == NULL ) break; + if (op.u.newdomain.name[0]) { + strncpy (p -> name, op.u.newdomain.name, MAX_DOMAIN_NAME); + p -> name[MAX_DOMAIN_NAME - 1] = 0; + } + ret = alloc_new_dom_mem(p, op.u.newdomain.memory_kb); if ( ret != 0 ) { @@ -108,7 +127,7 @@ long do_dom0_op(dom0_op_t *u_dom0_op) } break; - case DOM0_KILLDOMAIN: + case DOM0_DESTROYDOMAIN: { unsigned int dom = op.u.killdomain.domain; int force = op.u.killdomain.force; @@ -168,6 +187,38 @@ long do_dom0_op(dom0_op_t *u_dom0_op) } break; + case DOM0_GETDOMAININFO: + { + struct task_struct *p; + u_long flags; + + p = idle0_task.next_task; + read_lock_irqsave (&tasklist_lock, flags); + do { + if ((!is_idle_task (p)) && (p -> domain >= op.u.getdominfo.domain)) { + break; + } + } while ((p = p -> next_task) != &idle0_task); + + if (p == &idle0_task) { + ret = -ESRCH; + } else { + op.u.getdominfo.domain = p -> domain; + strcpy (op.u.getdominfo.name, p -> name); + op.u.getdominfo.processor = p -> processor; + op.u.getdominfo.has_cpu = p -> has_cpu; + op.u.getdominfo.state = p -> state; + op.u.getdominfo.hyp_events = p -> hyp_events; + op.u.getdominfo.mcu_advance = p -> mcu_advance; + op.u.getdominfo.pg_head = list_entry(p->pg_head.next, + struct pfn_info, list) - frame_table; + op.u.getdominfo.tot_pages = p -> tot_pages; + } + read_unlock_irqrestore (&tasklist_lock, flags); + copy_to_user(u_dom0_op, &op, sizeof(op)); + break; + } + default: ret = -ENOSYS; diff --git a/xen/common/domain.c b/xen/common/domain.c index f54e7c9d67..35154baf37 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -175,6 +175,29 @@ long kill_other_domain(unsigned int dom, int force) return 0; } +void stop_domain(void) +{ + current -> state = TASK_SUSPENDED; + clear_bit(_HYP_EVENT_STOP, &(current->hyp_events)); + schedule (); +} + +long stop_other_domain(unsigned int dom) +{ + unsigned long cpu_mask; + struct task_struct *p; + + p = find_domain_by_id (dom); + if ( p == NULL) return -ESRCH; + + if ( p -> state != TASK_SUSPENDED ) + { + cpu_mask = mark_hyp_event(p, _HYP_EVENT_STOP); + hyp_event_notify(cpu_mask); + } + + return 0; +} unsigned int alloc_new_dom_mem(struct task_struct *p, unsigned int kbytes) { diff --git a/xen/common/schedule.c b/xen/common/schedule.c index 5749d27d4a..6536bf1ba5 100644 --- a/xen/common/schedule.c +++ b/xen/common/schedule.c @@ -349,6 +349,7 @@ asmlinkage void schedule(void) case TASK_UNINTERRUPTIBLE: case TASK_WAIT: case TASK_DYING: + case TASK_SUSPENDED: default: /* done if not running. Else, continue */ goto deschedule_done; diff --git a/xen/include/xeno/dom0_ops.h b/xen/include/xeno/dom0_ops.h index ea3f829d73..8737e192aa 100644 --- a/xen/include/xeno/dom0_ops.h +++ b/xen/include/xeno/dom0_ops.h @@ -12,14 +12,18 @@ #ifndef __DOM0_OPS_H__ #define __DOM0_OPS_H__ -#define DOM0_NEWDOMAIN 0 -#define DOM0_KILLDOMAIN 1 -#define DOM0_GETMEMLIST 2 -#define DOM0_STARTDOM 4 -#define DOM0_BVTCTL 6 -#define DOM0_ADJUSTDOM 7 +#define DOM0_GETMEMLIST 2 +#define DOM0_BVTCTL 6 +#define DOM0_ADJUSTDOM 7 +#define DOM0_CREATEDOMAIN 8 +#define DOM0_DESTROYDOMAIN 9 +#define DOM0_STARTDOMAIN 10 +#define DOM0_STOPDOMAIN 11 +#define DOM0_GETDOMAININFO 12 +#define DOM0_BUILDDOMAIN 13 #define MAX_CMD_LEN 256 +#define MAX_DOMAIN_NAME 16 typedef struct dom0_newdomain_st { @@ -27,6 +31,7 @@ typedef struct dom0_newdomain_st unsigned int memory_kb; unsigned int num_vifs; // temporary unsigned long pg_head; // return parameter + char name[MAX_DOMAIN_NAME]; } dom0_newdomain_t; typedef struct dom0_killdomain_st @@ -69,6 +74,20 @@ typedef struct dom0_adjustdom_st unsigned long warpu; /* unwarp time requirement */ } dom0_adjustdom_t; +typedef struct dom0_getdominfo_st +{ + unsigned int domain; /* All returns except domain */ + char name[MAX_DOMAIN_NAME]; + int processor; + int has_cpu; + int state; + int hyp_events; + unsigned long mcu_advance; + unsigned long pg_head; + unsigned int tot_pages; +} dom0_getdominfo_t; + + typedef struct dom0_op_st { unsigned long cmd; @@ -80,7 +99,8 @@ typedef struct dom0_op_st dom0_bvtctl_t bvtctl; dom0_adjustdom_t adjustdom; dom_meminfo_t meminfo; - } + dom0_getdominfo_t getdominfo; + } u; } dom0_op_t; diff --git a/xen/include/xeno/sched.h b/xen/include/xeno/sched.h index d29c7f9e49..fe4c49736e 100644 --- a/xen/include/xeno/sched.h +++ b/xen/include/xeno/sched.h @@ -16,6 +16,8 @@ #include <xeno/time.h> #include <xeno/ac_timer.h> +#define MAX_DOMAIN_NAME 16 + extern unsigned long volatile jiffies; extern rwlock_t tasklist_lock; @@ -51,6 +53,7 @@ extern struct mm_struct init_mm; #define _HYP_EVENT_NEED_RESCHED 0 #define _HYP_EVENT_DIE 1 +#define _HYP_EVENT_STOP 2 #define PF_DONEFPUINIT 0x1 /* Has the FPU been initialised for this task? */ #define PF_USEDFPU 0x2 /* Has this task used the FPU since last save? */ @@ -141,6 +144,8 @@ struct task_struct 0-0xFFFFFFFF for kernel-thread */ + char name[MAX_DOMAIN_NAME]; + /* * active_mm stays for now. It's entangled in the tricky TLB flushing * stuff which I haven't addressed yet. It stays until I'm man enough @@ -223,6 +228,8 @@ extern void __kill_domain(struct task_struct *p); extern void kill_domain(void); extern void kill_domain_with_errmsg(const char *err); extern long kill_other_domain(unsigned int dom, int force); +extern void stop_domain(void); +extern long stop_other_domain(unsigned int dom); /* arch/process.c */ void new_thread(struct task_struct *p, 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 index d3e4752eb3..4f03fda0e2 100644 --- 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 @@ -23,6 +23,7 @@ #include <linux/iobuf.h> #include <linux/highmem.h> #include <linux/pagemap.h> +#include <linux/seq_file.h> #include <asm/pgalloc.h> #include <asm/pgtable.h> @@ -31,6 +32,9 @@ #include "dom0_ops.h" +#define TRUE 1 +#define FALSE 0 + /* Private proc-file data structures. */ typedef struct proc_data { unsigned int domain; @@ -45,6 +49,7 @@ typedef struct proc_mem_data { #define XENO_BASE "xeno" #define DOM0_CMD_INTF "dom0_cmd" #define DOM0_NEWDOM "new_dom_data" +#define DOM_LIST_INTF "domains" #define MAX_LEN 16 #define DOM_DIR "dom" @@ -56,6 +61,7 @@ typedef struct proc_mem_data { struct proc_dir_entry *xeno_base; static struct proc_dir_entry *dom0_cmd_intf; static struct proc_dir_entry *proc_ft; +static struct proc_dir_entry *dom_list_intf; unsigned long direct_mmap(unsigned long, unsigned long, pgprot_t, int, int); int direct_unmap(unsigned long, unsigned long); @@ -266,7 +272,7 @@ static int cmd_write_proc(struct file *file, const char *buffer, ret = HYPERVISOR_dom0_op(&op); /* if new domain created, create proc entries */ - if(op.cmd == DOM0_NEWDOMAIN){ + if(op.cmd == DOM0_CREATEDOMAIN) { create_proc_dom_entries(ret); params = (dom0_newdomain_t *)kmalloc(sizeof(dom0_newdomain_t), @@ -295,6 +301,94 @@ out: } +/*********************************************************************** + * + * Implementation of /proc/xeno/domains + */ + +static dom0_op_t proc_domains_op; +static int proc_domains_finished; +static rwlock_t proc_xeno_domains_lock = RW_LOCK_UNLOCKED; + +static void *xeno_domains_next(struct seq_file *s, void *v, loff_t *pos) +{ + int ret; + + if (pos != NULL) { ++ (*pos); } + if (!proc_domains_finished) { + proc_domains_op.u.getdominfo.domain ++; + ret = HYPERVISOR_dom0_op(&proc_domains_op); + if (ret < 0) proc_domains_finished = TRUE; + } + + return (proc_domains_finished) ? NULL : &proc_domains_op; +} + +static void *xeno_domains_start(struct seq_file *s, loff_t *ppos) +{ + loff_t pos = *ppos; + + write_lock (&proc_xeno_domains_lock); + proc_domains_op.cmd = DOM0_GETDOMAININFO; + proc_domains_op.u.getdominfo.domain = 0; + (void)HYPERVISOR_dom0_op(&proc_domains_op); + proc_domains_finished = FALSE; + + while (pos > 0) { + pos --; + xeno_domains_next (s, NULL, NULL); + } + + return (proc_domains_finished) ? NULL : &proc_domains_op; +} + +static void xeno_domains_stop(struct seq_file *s, void *v) +{ + write_unlock (&proc_xeno_domains_lock); +} + +static int xeno_domains_show(struct seq_file *s, void *v) +{ + dom0_op_t *di = v; + + seq_printf (s, + "%8d %2d %1d %2d %8d %8ld %p %8d %s\n", + di -> u.getdominfo.domain, + di -> u.getdominfo.processor, + di -> u.getdominfo.has_cpu, + di -> u.getdominfo.state, + di -> u.getdominfo.hyp_events, + di -> u.getdominfo.mcu_advance, + di -> u.getdominfo.pg_head, + di -> u.getdominfo.tot_pages, + di -> u.getdominfo.name); + + return 0; +} + +struct seq_operations xeno_domains_op = { + .start = xeno_domains_start, + .next = xeno_domains_next, + .stop = xeno_domains_stop, + .show = xeno_domains_show, +}; + +static int xeno_domains_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &xeno_domains_op); +} + +static struct file_operations proc_xeno_domains_operations = { + open: xeno_domains_open, + read: seq_read, + llseek: seq_lseek, + release: seq_release, +}; + +/***********************************************************************/ + + + static int __init init_module(void) { /* xeno proc root setup */ @@ -311,6 +405,15 @@ static int __init init_module(void) dom0_cmd_intf->write_proc = cmd_write_proc; } + /* domain list interface */ + dom_list_intf = create_proc_entry (DOM_LIST_INTF, 0400, xeno_base); + if ( dom_list_intf != NULL ) + { + dom_list_intf -> owner = THIS_MODULE; + dom_list_intf -> nlink = 1; + dom_list_intf -> proc_fops = &proc_xeno_domains_operations; + } + /* set up /proc entries for dom 0 */ create_proc_dom_entries(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 index 74c9b24de7..1a5b63dad2 100644 --- 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 @@ -9,17 +9,21 @@ * MUST BE KEPT IN SYNC WITH tools/domain_builder/dom0_ops.h */ -#define DOM0_NEWDOMAIN 0 -#define DOM0_KILLDOMAIN 1 -#define DOM0_GETMEMLIST 2 -#define DOM0_STARTDOM 4 -#define DOM0_BVTCTL 6 -#define DOM0_ADJUSTDOM 7 -#define MAP_DOM_MEM 8 /* Not passed down to Xen */ -#define DO_PGUPDATES 9 /* Not passed down to Xen */ -#define MAX_CMD 10 +#define DOM0_GETMEMLIST 2 +#define DOM0_BVTCTL 6 +#define DOM0_ADJUSTDOM 7 +#define DOM0_CREATEDOMAIN 8 +#define DOM0_DESTROYDOMAIN 9 +#define DOM0_STARTDOMAIN 10 +#define DOM0_STOPDOMAIN 11 +#define DOM0_GETDOMAININFO 12 +#define DOM0_BUILDDOMAIN 13 +#define MAP_DOM_MEM 14 /* Not passed down to Xen */ +#define DO_PGUPDATES 15 /* Not passed down to Xen */ +#define MAX_CMD 16 #define MAX_CMD_LEN 256 +#define MAX_DOMAIN_NAME 16 typedef struct dom0_newdomain_st { @@ -27,6 +31,7 @@ typedef struct dom0_newdomain_st unsigned int memory_kb; unsigned int num_vifs; /* temporary */ unsigned long pg_head; /* return parameter */ + char name[MAX_DOMAIN_NAME]; } dom0_newdomain_t; typedef struct dom0_killdomain_st @@ -86,6 +91,19 @@ typedef struct domain_launch } dom_meminfo_t; +typedef struct dom0_getdominfo_st +{ + unsigned int domain; /* All returns except domain */ + char name[MAX_DOMAIN_NAME]; + int processor; + int has_cpu; + int state; + int hyp_events; + unsigned long mcu_advance; + unsigned long pg_head; + unsigned int tot_pages; +} dom0_getdominfo_t; + typedef struct dom0_op_st { @@ -100,7 +118,8 @@ typedef struct dom0_op_st dom_mem_t dommem; dom_pgupdate_t pgupdate; dom_meminfo_t meminfo; - } + dom0_getdominfo_t getdominfo; + } u; } dom0_op_t; |