direct-io.hg

changeset 3326:f36de623daa0

bitkeeper revision 1.1159.187.81 (41cc934bUot13IO0-1LsmhYl0sW9Zw)

Add plan9 builder support.
author iap10@labyrinth.cl.cam.ac.uk
date Fri Dec 24 22:08:11 2004 +0000 (2004-12-24)
parents d3386947d930
children 6b1aa25ff284 708bd9c8362b
files .rootkeys tools/libxc/Makefile tools/libxc/plan9a.out.h tools/libxc/xc.h tools/libxc/xc_plan9_build.c tools/python/xen/lowlevel/xc/xc.c tools/python/xen/xend/XendDomainInfo.py
line diff
     1.1 --- a/.rootkeys	Thu Dec 23 14:04:36 2004 +0000
     1.2 +++ b/.rootkeys	Fri Dec 24 22:08:11 2004 +0000
     1.3 @@ -320,6 +320,7 @@ 40ee75a93cqxHp6MiYXxxwR5j2_8QQ tools/exa
     1.4  41090ec8Pj_bkgCBpg2W7WfmNkumEA tools/examples/xmexample1
     1.5  40cf2937oKlROYOJTN8GWwWM5AmjBg tools/examples/xmexample2
     1.6  3fbba6dbDfYvJSsw9500b4SZyUhxjQ tools/libxc/Makefile
     1.7 +41cc934abX-QLXJXW_clV_wRjM0zYg tools/libxc/plan9a.out.h
     1.8  3fbba6dc1uU7U3IFeF6A-XEOYF2MkQ tools/libxc/rpm.spec
     1.9  3fbba6dcrNxtygEcgJYAJJ1gCQqfsA tools/libxc/xc.h
    1.10  40589968oCfoUlXd460CjVAkBE8IBA tools/libxc/xc_atropos.c
    1.11 @@ -334,6 +335,7 @@ 3fbba6dbl267zZOAVHYLOdLCdhcZMw tools/lib
    1.12  3fbba6db7li3FJiABYtCmuGxOJxEGw tools/libxc/xc_linux_save.c
    1.13  3fbba6db7WnnJr0KFrIFrqNlSKvFYg tools/libxc/xc_misc.c
    1.14  4051bce6CHAsYh8P5t2OHDtRWOP9og tools/libxc/xc_physdev.c
    1.15 +41cc934aO1m6NxEh_8eDr9bJIMoLFA tools/libxc/xc_plan9_build.c
    1.16  3fbba6dctWRWlFJkYb6hdix2X4WMuw tools/libxc/xc_private.c
    1.17  3fbba6dcbVrG2hPzEzwdeV_UC8kydQ tools/libxc/xc_private.h
    1.18  40589968UQFnJeOMn8UIFLbXBuwXjw tools/libxc/xc_rrobin.c
     2.1 --- a/tools/libxc/Makefile	Thu Dec 23 14:04:36 2004 +0000
     2.2 +++ b/tools/libxc/Makefile	Fri Dec 24 22:08:11 2004 +0000
     2.3 @@ -18,6 +18,7 @@ SRCS     += xc_domain.c
     2.4  SRCS     += xc_evtchn.c
     2.5  SRCS     += xc_io.c
     2.6  SRCS     += xc_linux_build.c
     2.7 +SRCS     += xc_plan9_build.c
     2.8  SRCS     += xc_linux_restore.c
     2.9  SRCS     += xc_linux_save.c
    2.10  SRCS     += xc_misc.c
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/tools/libxc/plan9a.out.h	Fri Dec 24 22:08:11 2004 +0000
     3.3 @@ -0,0 +1,28 @@
     3.4 +
     3.5 +typedef struct	Exec
     3.6 +{
     3.7 +	long	magic;		/* magic number */
     3.8 +	long	text;	 	/* size of text segment */
     3.9 +	long	data;	 	/* size of initialized data */
    3.10 +	long	bss;	  	/* size of uninitialized data */
    3.11 +	long	syms;	 	/* size of symbol table */
    3.12 +	long	entry;	 	/* entry point */
    3.13 +	long	spsz;		/* size of pc/sp offset table */
    3.14 +	long	pcsz;		/* size of pc/line number table */
    3.15 +} Exec;
    3.16 +
    3.17 +#define	_MAGIC(b)	((((4*b)+0)*b)+7)
    3.18 +#define	A_MAGIC		_MAGIC(8)	/* 68020 */
    3.19 +#define	I_MAGIC		_MAGIC(11)	/* intel 386 */
    3.20 +#define	J_MAGIC		_MAGIC(12)	/* intel 960 */
    3.21 +#define	K_MAGIC		_MAGIC(13)	/* sparc */
    3.22 +#define	V_MAGIC		_MAGIC(16)	/* mips 3000 */
    3.23 +#define	X_MAGIC		_MAGIC(17)	/* att dsp 3210 */
    3.24 +#define	M_MAGIC		_MAGIC(18)	/* mips 4000 */
    3.25 +#define	D_MAGIC		_MAGIC(19)	/* amd 29000 */
    3.26 +#define	E_MAGIC		_MAGIC(20)	/* arm 7-something */
    3.27 +#define	Q_MAGIC		_MAGIC(21)	/* powerpc */
    3.28 +#define	N_MAGIC		_MAGIC(22)	/* mips 4000 LE */
    3.29 +#define	L_MAGIC		_MAGIC(23)	/* dec alpha */
    3.30 +#define	P_MAGIC		_MAGIC(24)	/* mips 3000 LE */
    3.31 +
     4.1 --- a/tools/libxc/xc.h	Thu Dec 23 14:04:36 2004 +0000
     4.2 +++ b/tools/libxc/xc.h	Fri Dec 24 22:08:11 2004 +0000
     4.3 @@ -97,6 +97,14 @@ int xc_linux_build(int xc_handle,
     4.4                     unsigned int control_evtchn,
     4.5                     unsigned long flags);
     4.6  
     4.7 +int
     4.8 +xc_plan9_build (int xc_handle,
     4.9 +                u32 domid, 
    4.10 +                const char *image_name,
    4.11 +                const char *cmdline, 
    4.12 +		unsigned int control_evtchn, 
    4.13 +		unsigned long flags);
    4.14 +
    4.15  int xc_bvtsched_global_set(int xc_handle,
    4.16                             unsigned long ctx_allow);
    4.17  
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/tools/libxc/xc_plan9_build.c	Fri Dec 24 22:08:11 2004 +0000
     5.3 @@ -0,0 +1,744 @@
     5.4 +/******************************************************************************
     5.5 + * xc_plan9_build.c
     5.6 + * derived from xc_linux_build.c
     5.7 + */
     5.8 +
     5.9 +#include "xc_private.h"
    5.10 +
    5.11 +#include <zlib.h>
    5.12 +
    5.13 +#define DEBUG 1
    5.14 +#ifdef DEBUG
    5.15 +#define DPRINTF(x) printf x; fflush(stdout);
    5.16 +#else
    5.17 +#define DPRINTF(x)
    5.18 +#endif
    5.19 +
    5.20 +#include "plan9a.out.h"
    5.21 +
    5.22 +/* really TOS which means stack starts at 0x2000, and uses page 1*/
    5.23 +#define STACKPAGE 2
    5.24 +struct Exec header, origheader;
    5.25 +
    5.26 +typedef struct page {
    5.27 +	char data[PAGE_SIZE];
    5.28 +} PAGE;
    5.29 +
    5.30 +
    5.31 +int
    5.32 +memcpy_toguest(int xc_handle, u32 dom, void *v, int size,
    5.33 +	       unsigned long *page_array, unsigned int to_page)
    5.34 +{
    5.35 +	int ret;
    5.36 +	unsigned char *cp = v;
    5.37 +	unsigned int whichpage;
    5.38 +	unsigned char *vaddr;
    5.39 +
    5.40 +//  DPRINTF(("memcpy_to_guest: to_page 0x%x, count %d\n", to_page, size));
    5.41 +	for (ret = 0, whichpage = to_page; size > 0;
    5.42 +	     whichpage++, size -= PAGE_SIZE, cp += PAGE_SIZE) {
    5.43 +
    5.44 +		//     DPRINTF (("map_pfn_writeable(%p, 0x%lx)\n", pm_handle,
    5.45 +//                page_array[whichpage]));
    5.46 +		vaddr = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
    5.47 +					     PROT_READ | PROT_WRITE,
    5.48 +					     page_array[whichpage]);
    5.49 +		//    DPRINTF (("vaddr is %p\n", vaddr));
    5.50 +		if (vaddr == NULL) {
    5.51 +			ret = -1;
    5.52 +			ERROR("Couldn't map guest memory");
    5.53 +			goto out;
    5.54 +		}
    5.55 +		//   DPRINTF (("copy %p to %p, count 0x%x\n", cp, vaddr, 4096));
    5.56 +		memcpy(vaddr, cp, 4096);
    5.57 +		munmap(vaddr, PAGE_SIZE);
    5.58 +		//  DPRINTF (("Did %ud'th pages\n", whichpage));
    5.59 +	}
    5.60 +      out:
    5.61 +	return ret;
    5.62 +}
    5.63 +
    5.64 +/* this is a function which can go away. It dumps a hunk of 
    5.65 + * guest pages to a file (/tmp/dumpit); handy for debugging
    5.66 + * your image builder. 
    5.67 + * Xen guys, nuke this if you wish.
    5.68 + */
    5.69 +void
    5.70 +dumpit(int xc_handle, u32 dom,
    5.71 +       int start_page, int tot, unsigned long *page_array)
    5.72 +{
    5.73 +	int i, ofd;
    5.74 +	unsigned char *vaddr;
    5.75 +
    5.76 +	ofd = open("/tmp/dumpit", O_RDWR);
    5.77 +	for (i = start_page; i < tot; i++) {
    5.78 +		vaddr = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
    5.79 +					     PROT_READ | PROT_WRITE,
    5.80 +					     page_array[i]);
    5.81 +		if (!vaddr) {
    5.82 +			fprintf(stderr, "Page %d\n", i);
    5.83 +			perror("shit");
    5.84 +			read(0, &i, 1);
    5.85 +			return;
    5.86 +		}
    5.87 +		write(ofd, vaddr, 4096);
    5.88 +		munmap(vaddr, PAGE_SIZE);
    5.89 +	}
    5.90 +}
    5.91 +int
    5.92 +blah(char *b)
    5.93 +{
    5.94 +	fprintf(stderr, "Error in xc_plan9_build!\n");
    5.95 +	perror(b);
    5.96 +	return errno;
    5.97 +}
    5.98 +
    5.99 +/* swap bytes. For plan 9 headers */
   5.100 +void
   5.101 +swabby(unsigned long *s, char *name)
   5.102 +{
   5.103 +	unsigned long it;
   5.104 +	it = ((*s & 0xff000000) >> 24) | ((*s & 0xff0000) >> 8) |
   5.105 +	    ((*s & 0xff00) << 8) | ((*s & 0xff) << 24);
   5.106 +	DPRINTF(("Item %s is 0x%lx\n", name, it));
   5.107 +	*s = it;
   5.108 +}
   5.109 +
   5.110 +void
   5.111 +plan9header(Exec * header)
   5.112 +{
   5.113 +	/* header is big-endian */
   5.114 +	swabby(&header->magic, "magic");
   5.115 +	swabby(&header->text, "text");
   5.116 +	swabby(&header->data, "data");
   5.117 +	swabby(&header->bss, "bss");
   5.118 +	swabby(&header->syms, "syms");
   5.119 +	swabby(&header->entry, "entry");
   5.120 +	swabby(&header->spsz, "spsz");
   5.121 +	swabby(&header->pcsz, "pcsz");
   5.122 +
   5.123 +}
   5.124 +
   5.125 +static int
   5.126 + loadp9image(gzFile kernel_gfd, int xc_handle, u32 dom,
   5.127 +	     unsigned long *page_array,
   5.128 +	     unsigned long tot_pages, unsigned long *virt_load_addr,
   5.129 +	     unsigned long *ksize, unsigned long *symtab_addr,
   5.130 +	     unsigned long *symtab_len,
   5.131 +	     unsigned long *first_data_page, unsigned long *pdb_page);
   5.132 +
   5.133 +#define P9ROUND (P9SIZE / 8)
   5.134 +
   5.135 +#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED)
   5.136 +#define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
   5.137 +
   5.138 +static long
   5.139 +get_tot_pages(int xc_handle, u32 domid)
   5.140 +{
   5.141 +	dom0_op_t op;
   5.142 +	op.cmd = DOM0_GETDOMAININFO;
   5.143 +	op.u.getdomaininfo.domain = (domid_t) domid;
   5.144 +	op.u.getdomaininfo.ctxt = NULL;
   5.145 +	return (do_dom0_op(xc_handle, &op) < 0) ?
   5.146 +	    -1 : op.u.getdomaininfo.tot_pages;
   5.147 +}
   5.148 +
   5.149 +static int
   5.150 +get_pfn_list(int xc_handle,
   5.151 +	     u32 domid, unsigned long *pfn_buf, unsigned long max_pfns)
   5.152 +{
   5.153 +	dom0_op_t op;
   5.154 +	int ret;
   5.155 +	op.cmd = DOM0_GETMEMLIST;
   5.156 +	op.u.getmemlist.domain = (domid_t) domid;
   5.157 +	op.u.getmemlist.max_pfns = max_pfns;
   5.158 +	op.u.getmemlist.buffer = pfn_buf;
   5.159 +
   5.160 +	if (mlock(pfn_buf, max_pfns * sizeof (unsigned long)) != 0)
   5.161 +		return -1;
   5.162 +
   5.163 +	ret = do_dom0_op(xc_handle, &op);
   5.164 +
   5.165 +	(void) munlock(pfn_buf, max_pfns * sizeof (unsigned long));
   5.166 +
   5.167 +#if 0
   5.168 +#ifdef DEBUG
   5.169 +	DPRINTF(("Ret for get_pfn_list is %d\n", ret));
   5.170 +	if (ret >= 0) {
   5.171 +		int i, j;
   5.172 +		for (i = 0; i < op.u.getmemlist.num_pfns; i += 16) {
   5.173 +			fprintf(stderr, "0x%x: ", i);
   5.174 +			for (j = 0; j < 16; j++)
   5.175 +				fprintf(stderr, "0x%lx ", pfn_buf[i + j]);
   5.176 +			fprintf(stderr, "\n");
   5.177 +		}
   5.178 +	}
   5.179 +#endif
   5.180 +#endif
   5.181 +	return (ret < 0) ? -1 : op.u.getmemlist.num_pfns;
   5.182 +}
   5.183 +
   5.184 +static int
   5.185 +setup_guestos(int xc_handle,
   5.186 +	      u32 dom,
   5.187 +	      gzFile kernel_gfd,
   5.188 +	      unsigned long tot_pages,
   5.189 +	      unsigned long *virt_startinfo_addr,
   5.190 +	      unsigned long *virt_load_addr,
   5.191 +	      full_execution_context_t * ctxt,
   5.192 +	      const char *cmdline,
   5.193 +	      unsigned long shared_info_frame, 
   5.194 +	      unsigned int control_evtchn,
   5.195 +	      int flags)
   5.196 +{
   5.197 +	l1_pgentry_t *vl1e = NULL;
   5.198 +	l2_pgentry_t *vl2tab = NULL, *vl2e = NULL;
   5.199 +	unsigned long *cpage_array = NULL;
   5.200 +	unsigned long *pte_array = NULL;
   5.201 +	unsigned long l2tab;
   5.202 +	unsigned long l1tab;
   5.203 +	unsigned long count;
   5.204 +	unsigned long symtab_addr = 0, symtab_len = 0;
   5.205 +	start_info_t *start_info;
   5.206 +	shared_info_t *shared_info;
   5.207 +	unsigned long ksize;
   5.208 +	mmu_t *mmu = NULL;
   5.209 +	int i;
   5.210 +	unsigned long first_page_after_kernel, 
   5.211 +	  first_data_page, 
   5.212 +	  page_array_page;
   5.213 +	unsigned long cpu0pdb, cpu0pte, cpu0ptelast;
   5.214 +	unsigned long /*last_pfn, */ tot_pte_pages;
   5.215 +
   5.216 +	DPRINTF(("tot pages is %ld\n", tot_pages));
   5.217 +	if ((cpage_array = malloc(tot_pages * sizeof (unsigned long))) == NULL) {
   5.218 +		PERROR("Could not allocate cpage array");
   5.219 +		goto error_out;
   5.220 +	}
   5.221 +
   5.222 +	if (get_pfn_list(xc_handle, dom, cpage_array, tot_pages) != tot_pages) {
   5.223 +		PERROR("Could not get the page frame list");
   5.224 +		goto error_out;
   5.225 +	}
   5.226 +
   5.227 +	for (i = 0; i < 64; i++)
   5.228 +		DPRINTF(("First %d page is 0x%lx\n", i, cpage_array[i]));
   5.229 +
   5.230 +	tot_pte_pages = tot_pages >> 10;
   5.231 +	DPRINTF(("Page range is 0 to 0x%lx, which requires 0x%lx pte pages\n",
   5.232 +		 tot_pte_pages, tot_pte_pages));
   5.233 +
   5.234 +	if (loadp9image(kernel_gfd, xc_handle, dom, cpage_array, tot_pages,
   5.235 +			virt_load_addr, &ksize, &symtab_addr, &symtab_len,
   5.236 +			&first_data_page, &first_page_after_kernel))
   5.237 +		goto error_out;
   5.238 +	DPRINTF(("First data page is 0x%lx\n", first_data_page));
   5.239 +	DPRINTF(("First page after kernel is 0x%lx\n",
   5.240 +		 first_page_after_kernel));
   5.241 +
   5.242 +	/*
   5.243 +	   NEED TO INCREMENT first page after kernel by:
   5.244 +	   + 1 (pdb)
   5.245 +	   + tot_pte_pages (pte)
   5.246 +	   + tot_pte_pages (page_array)
   5.247 +	 */
   5.248 +	/* SO, have to copy the first kernel pages pfns right into the 
   5.249 +	 * page_array, then do identity maps for the rest. 
   5.250 +	 */
   5.251 +	DPRINTF(("mapped kernel pages\n"));
   5.252 +
   5.253 +	/* now loop over all ptes and store into the page_array, so as
   5.254 +	 * to get the identity map. 
   5.255 +	 */
   5.256 +	if ((pte_array =
   5.257 +	     malloc(tot_pte_pages * 1024 * sizeof (unsigned long))) == NULL) {
   5.258 +		PERROR("Could not allocate pte array");
   5.259 +		goto error_out;
   5.260 +	}
   5.261 +
   5.262 +	/* plan 9 on startup expects a "l2" (xen parlance) at 0x2000, 
   5.263 +	 * this "l2" should have one PTE pointer for a va of 0x80000000. 
   5.264 +	 * and an l1 (PTEs to you) at 0x3000. (physical). 
   5.265 +	 * the PTEs should map the first 4M of memory. 
   5.266 +	 */
   5.267 +	/* get a physical address for the L2. This means take the PFN and 
   5.268 +	 * shift left.
   5.269 +	 */
   5.270 +	/* this terminology is plan 9 terminology. 
   5.271 +	 * pdb is essentially the Xen L2. 'Page Directory Block'? 
   5.272 +	 * I need to ask JMK.
   5.273 +	 * cpupte is the pte array. 
   5.274 +	 * Plan 9 counts on these being set up for cpu0. 
   5.275 +	 * SO: cpu0pdb (Xen L2)
   5.276 +	 * and cpupte  (Xen L1)
   5.277 +	 */
   5.278 +	/* cpu0pdb is right after kernel */
   5.279 +	cpu0pdb = first_page_after_kernel;
   5.280 +	/* cpu0pte comes right after cpu0pdb */
   5.281 +	cpu0pte = cpu0pdb + 1;
   5.282 +	/* number of the past cpu0pte page */
   5.283 +	cpu0ptelast = cpu0pte + tot_pte_pages - 1;
   5.284 +	/* first page of the page array (mfn) */
   5.285 +	page_array_page = cpu0ptelast + 1;
   5.286 +
   5.287 +	DPRINTF(("cpu0pdb 0x%lx, cpu0pte 0x%lx cpu0ptelast 0x%lx\n", cpu0pdb,
   5.288 +		 cpu0pte, cpu0ptelast));
   5.289 +	l2tab = cpage_array[cpu0pdb] << PAGE_SHIFT;
   5.290 +	DPRINTF(("l2tab 0x%lx\n", l2tab));
   5.291 +	ctxt->pt_base = l2tab;
   5.292 +
   5.293 +	/* get a physical address for the L1. This means take the PFN and 
   5.294 +	 * shift left.
   5.295 +	 */
   5.296 +	l1tab = cpage_array[cpu0pte] << PAGE_SHIFT;
   5.297 +	DPRINTF(("l1tab 0x%lx\n", l1tab));
   5.298 +	if ((mmu = init_mmu_updates(xc_handle, dom)) == NULL)
   5.299 +		goto error_out;
   5.300 +	DPRINTF(("now map in l2tab\n"));
   5.301 +
   5.302 +	/* Initialise the page tables. */
   5.303 +	/* mmap in the l2tab */
   5.304 +	if ((vl2tab = xc_map_foreign_range(xc_handle, dom,
   5.305 +					   PAGE_SIZE, PROT_READ | PROT_WRITE,
   5.306 +					   l2tab >> PAGE_SHIFT)) == NULL)
   5.307 +		goto error_out;
   5.308 +	DPRINTF(("vl2tab 0x%p\n", vl2tab));
   5.309 +	/* now we have the cpu0pdb for the kernel, starting at 0x2000, 
   5.310 +	 * so we can plug in the physical pointer to the 0x3000 pte
   5.311 +	 */
   5.312 +	/* zero it */
   5.313 +	memset(vl2tab, 0, PAGE_SIZE);
   5.314 +	/* get a pointer in the l2tab for the virt_load_addr */
   5.315 +	DPRINTF(("&vl2tab[l2_table_offset(*virt_load_addr)] is 0x%p[0x%lx]\n",
   5.316 +		 &vl2tab[l2_table_offset(*virt_load_addr)],
   5.317 +		 l2_table_offset(*virt_load_addr)));
   5.318 +
   5.319 +	vl2e = &vl2tab[l2_table_offset(*virt_load_addr)];
   5.320 +
   5.321 +	/* OK, for all the available PTE, set the PTE pointer up */
   5.322 +	DPRINTF(("For i  = %ld to %ld ...\n", cpu0pte, cpu0ptelast));
   5.323 +	for (i = cpu0pte; i <= cpu0ptelast; i++) {
   5.324 +		DPRINTF(("Index %d Set %p to 0x%lx\n", i, vl2e,
   5.325 +			 (cpage_array[i] << PAGE_SHIFT) | L2_PROT));
   5.326 +		*vl2e++ = (cpage_array[i] << PAGE_SHIFT) | L2_PROT;
   5.327 +	}
   5.328 +
   5.329 +	/* unmap it ... */
   5.330 +	munmap(vl2tab, PAGE_SIZE);
   5.331 +
   5.332 +	/* for the pages from virt_load_pointer to the end of this 
   5.333 +	 * set of PTEs, map in the PFN for that VA
   5.334 +	 */
   5.335 +	for (vl1e = (l1_pgentry_t *) pte_array, count = 0;
   5.336 +	     count < tot_pte_pages * 1024; count++, vl1e++) {
   5.337 +
   5.338 +		*vl1e = cpage_array[count];
   5.339 +		if (!cpage_array[count])
   5.340 +			continue;
   5.341 +		/* set in the PFN for this entry */
   5.342 +		*vl1e = (cpage_array[count] << PAGE_SHIFT) | L1_PROT;
   5.343 +/*
   5.344 +      DPRINTF (("vl1e # %d 0x%lx gets 0x%lx\n",
   5.345 +		count, vl1e, *vl1e));
   5.346 +*/
   5.347 +		if ((count >= cpu0pdb) && (count <= cpu0ptelast)) {
   5.348 +			//DPRINTF(("   Fix up page %d as it is in pte ville: ", count));
   5.349 +			*vl1e &= ~_PAGE_RW;
   5.350 +			DPRINTF(("0x%lx\n", *vl1e));
   5.351 +		}
   5.352 +		if ((count >= (0x100000 >> 12))
   5.353 +		    && (count < (first_data_page >> 12))) {
   5.354 +			//DPRINTF(("   Fix up page %d as it is in text ", count));
   5.355 +			*vl1e &= ~_PAGE_RW;
   5.356 +			//DPRINTF (("0x%lx\n", *vl1e));
   5.357 +		}
   5.358 +	}
   5.359 +	/* special thing. Pre-map the shared info page */
   5.360 +	vl1e = &pte_array[2];
   5.361 +	*vl1e = (shared_info_frame << PAGE_SHIFT) | L1_PROT;
   5.362 +	DPRINTF(("v1l1 %p, has value 0x%lx\n", vl1e, *(unsigned long *) vl1e));
   5.363 +	/* another special thing. VA 80005000 has to point to 80006000 */
   5.364 +	/* this is a Plan 9 thing -- the 'mach' pointer */
   5.365 +	/* 80005000 is the mach pointer per-cpu, and the actual
   5.366 +	 * mach pointers are 80006000, 80007000 etc. 
   5.367 +	 */
   5.368 +	vl1e = &pte_array[5];
   5.369 +	*vl1e = (cpage_array[6] << PAGE_SHIFT) | L1_PROT;
   5.370 +
   5.371 +	/* OK, it's all set up, copy it in */
   5.372 +	memcpy_toguest(xc_handle, dom, pte_array,
   5.373 +		       (tot_pte_pages * 1024 * sizeof (unsigned long) /**/),
   5.374 +		       cpage_array, cpu0pte);
   5.375 +
   5.376 +	/* We really need to have the vl1tab unmapped or the add_mmu_update
   5.377 +	 * below will fail bigtime. 
   5.378 +	 */
   5.379 +	/* Xen guys: remember my errors on domain exit? Something I'm doing
   5.380 +	 * wrong in here? We never did find out ...
   5.381 +	 */
   5.382 +	/* get rid of the entries we can not use ... */
   5.383 +	memcpy_toguest(xc_handle, dom, cpage_array,
   5.384 +		       (tot_pte_pages * 1024 * sizeof (unsigned long) /**/),
   5.385 +		       cpage_array, page_array_page);
   5.386 +	/* last chance to dump all of memory */
   5.387 +	// dumpit(xc_handle, dom, 0 /*0x100000>>12*/, tot_pages, cpage_array) ;
   5.388 +	/*
   5.389 +	 * Pin down l2tab addr as page dir page - causes hypervisor to provide
   5.390 +	 * correct protection for the page
   5.391 +	 */
   5.392 +	if (add_mmu_update(xc_handle, mmu,
   5.393 +			   l2tab | MMU_EXTENDED_COMMAND, MMUEXT_PIN_L2_TABLE))
   5.394 +		goto error_out;
   5.395 +
   5.396 +	for (count = 0; count < tot_pages; count++) {
   5.397 +/*
   5.398 +      DPRINTF (("add_mmu_update(0x%x, 0x%x, 0x%x, %d)\n", xc_handle, mmu,
   5.399 +							   (cpage_array[count]
   5.400 +							    << PAGE_SHIFT) |
   5.401 +							   MMU_MACHPHYS_UPDATE,
   5.402 +							   count));
   5.403 +*/
   5.404 +		if (add_mmu_update(xc_handle, mmu,
   5.405 +				   (cpage_array[count] << PAGE_SHIFT) |
   5.406 +				   MMU_MACHPHYS_UPDATE, count))
   5.407 +			goto error_out;
   5.408 +		//DPRINTF(("Do the next one\n"));
   5.409 +	}
   5.410 +/*
   5.411 + */
   5.412 +
   5.413 +	//dumpit(pm_handle, 3, 4, page_array);
   5.414 +	/* put the virt_startinfo_addr at KZERO */
   5.415 +	/* just hard-code for now */
   5.416 +	*virt_startinfo_addr = 0x80000000;
   5.417 +
   5.418 +	DPRINTF(("virt_startinfo_addr = 0x%lx\n", *virt_startinfo_addr));
   5.419 +	start_info = xc_map_foreign_range(xc_handle, dom,
   5.420 +					  PAGE_SIZE, PROT_READ | PROT_WRITE,
   5.421 +					  cpage_array[0]);
   5.422 +	DPRINTF(("startinfo = 0x%p\n", start_info));
   5.423 +	DPRINTF(("shared_info_frame is %lx\n", shared_info_frame));
   5.424 +	memset(start_info, 0, sizeof (*start_info));
   5.425 +	start_info->pt_base = 0x80000000 | cpu0pdb << PAGE_SHIFT;
   5.426 +	start_info->mfn_list = 0x80000000 | (page_array_page) << PAGE_SHIFT;
   5.427 +	DPRINTF(("mfn_list 0x%lx\n", start_info->mfn_list));
   5.428 +	start_info->mod_start = 0;
   5.429 +	start_info->mod_len = 0;
   5.430 +	start_info->nr_pages = tot_pte_pages * 1024;
   5.431 +	start_info->nr_pt_frames = tot_pte_pages + 1;
   5.432 +	start_info->shared_info = shared_info_frame;
   5.433 +	start_info->flags = 0;
   5.434 +	DPRINTF((" control event channel is %d\n", control_evtchn));
   5.435 +	start_info->domain_controller_evtchn = control_evtchn;
   5.436 +	strncpy(start_info->cmd_line, cmdline, MAX_CMDLINE);
   5.437 +	start_info->cmd_line[MAX_CMDLINE - 1] = '\0';
   5.438 +	munmap(start_info, PAGE_SIZE);
   5.439 +
   5.440 +	DPRINTF(("done setting up start_info\n"));
   5.441 +	DPRINTF(("shared_info_frame = 0x%lx\n", shared_info_frame));
   5.442 +	/* shared_info page starts its life empty. */
   5.443 +
   5.444 +	shared_info = xc_map_foreign_range(xc_handle, dom,
   5.445 +					   PAGE_SIZE, PROT_READ | PROT_WRITE,
   5.446 +					   shared_info_frame);
   5.447 +	memset(shared_info, 0, PAGE_SIZE);
   5.448 +	/* Mask all upcalls... */
   5.449 +	DPRINTF(("mask all upcalls\n"));
   5.450 +	for (i = 0; i < MAX_VIRT_CPUS; i++)
   5.451 +		shared_info->vcpu_data[i].evtchn_upcall_mask = 1;
   5.452 +	munmap(shared_info, PAGE_SIZE);
   5.453 +
   5.454 +	/* Send the page update requests down to the hypervisor. */
   5.455 +	DPRINTF(("send page update reqs down.\n"));
   5.456 +	if (finish_mmu_updates(xc_handle, mmu))
   5.457 +		goto error_out;
   5.458 +
   5.459 +	//DPRINTF (("call dumpit.\n"));
   5.460 +	//dumpit(pm_handle, 0x100000>>12, tot_pages, page_array) ;
   5.461 +	//dumpit (pm_handle, 2, 0x100, page_array);
   5.462 +	free(mmu);
   5.463 +
   5.464 +	/* we don't bother freeing anything at this point -- 
   5.465 +	 * we're exiting and it is pointless
   5.466 +	 */
   5.467 +	return 0;
   5.468 +
   5.469 +      error_out:
   5.470 +	/* oh well we still free some things -- I oughtta nuke this */
   5.471 +	if (mmu != NULL)
   5.472 +		free(mmu);
   5.473 +	;
   5.474 +	return -1;
   5.475 +}
   5.476 +
   5.477 +int
   5.478 +xc_plan9_build(int xc_handle,
   5.479 +	       u32 domid,
   5.480 +	       const char *image_name,
   5.481 +	       const char *cmdline,
   5.482 +	       unsigned int control_evtchn, unsigned long flags)
   5.483 +{
   5.484 +	dom0_op_t launch_op, op;
   5.485 +	unsigned long load_addr;
   5.486 +	long tot_pages;
   5.487 +	int kernel_fd = -1;
   5.488 +	gzFile kernel_gfd = NULL;
   5.489 +	int rc, i;
   5.490 +	full_execution_context_t st_ctxt, *ctxt = &st_ctxt;
   5.491 +	unsigned long virt_startinfo_addr;
   5.492 +
   5.493 +	if ((tot_pages = get_tot_pages(xc_handle, domid)) < 0) {
   5.494 +		PERROR("Could not find total pages for domain");
   5.495 +		return 1;
   5.496 +	}
   5.497 +	DPRINTF(("get_tot_pages returns %ld pages\n", tot_pages));
   5.498 +
   5.499 +	kernel_fd = open(image_name, O_RDONLY);
   5.500 +	if (kernel_fd < 0) {
   5.501 +		PERROR("Could not open kernel image");
   5.502 +		return 1;
   5.503 +	}
   5.504 +
   5.505 +	if ((kernel_gfd = gzdopen(kernel_fd, "rb")) == NULL) {
   5.506 +		PERROR("Could not allocate decompression state for state file");
   5.507 +		close(kernel_fd);
   5.508 +		return 1;
   5.509 +	}
   5.510 +
   5.511 +	DPRINTF(("get_tot_pages returns %ld pages\n", tot_pages));
   5.512 +	if (mlock(&st_ctxt, sizeof (st_ctxt))) {
   5.513 +		PERROR("Unable to mlock ctxt");
   5.514 +		return 1;
   5.515 +	}
   5.516 +
   5.517 +	op.cmd = DOM0_GETDOMAININFO;
   5.518 +	op.u.getdomaininfo.domain = (domid_t) domid;
   5.519 +	op.u.getdomaininfo.ctxt = ctxt;
   5.520 +	if ((do_dom0_op(xc_handle, &op) < 0) ||
   5.521 +	    ((u32) op.u.getdomaininfo.domain != domid)) {
   5.522 +		PERROR("Could not get info on domain");
   5.523 +		goto error_out;
   5.524 +	}
   5.525 +	DPRINTF(("get_tot_pages returns %ld pages\n", tot_pages));
   5.526 +
   5.527 +	if (!(op.u.getdomaininfo.flags & DOMFLAGS_PAUSED)
   5.528 +	    || (op.u.getdomaininfo.ctxt->pt_base != 0)) {
   5.529 +		ERROR("Domain is already constructed");
   5.530 +		goto error_out;
   5.531 +	}
   5.532 +
   5.533 +	DPRINTF(("get_tot_pages returns %ld pages\n", tot_pages));
   5.534 +	if (setup_guestos(xc_handle, domid, kernel_gfd, tot_pages,
   5.535 +			  &virt_startinfo_addr,
   5.536 +			  &load_addr, &st_ctxt, cmdline,
   5.537 +			  op.u.getdomaininfo.shared_info_frame,
   5.538 +			  control_evtchn, flags) < 0) {
   5.539 +		ERROR("Error constructing guest OS");
   5.540 +		goto error_out;
   5.541 +	}
   5.542 +
   5.543 +	/* leave the leak in here for now
   5.544 +	   if ( kernel_fd >= 0 )
   5.545 +	   close(kernel_fd);
   5.546 +	   if( kernel_gfd )
   5.547 +	   gzclose(kernel_gfd);
   5.548 +	 */
   5.549 +	ctxt->flags = 0;
   5.550 +
   5.551 +	/*
   5.552 +	 * Initial register values:
   5.553 +	 *  DS,ES,FS,GS = FLAT_GUESTOS_DS
   5.554 +	 *       CS:EIP = FLAT_GUESTOS_CS:start_pc
   5.555 +	 *       SS:ESP = FLAT_GUESTOS_DS:start_stack
   5.556 +	 *          ESI = start_info
   5.557 +	 *  [EAX,EBX,ECX,EDX,EDI,EBP are zero]
   5.558 +	 *       EFLAGS = IF | 2 (bit 1 is reserved and should always be 1)
   5.559 +	 */
   5.560 +	ctxt->cpu_ctxt.ds = FLAT_GUESTOS_DS;
   5.561 +	ctxt->cpu_ctxt.es = FLAT_GUESTOS_DS;
   5.562 +	ctxt->cpu_ctxt.fs = FLAT_GUESTOS_DS;
   5.563 +	ctxt->cpu_ctxt.gs = FLAT_GUESTOS_DS;
   5.564 +	ctxt->cpu_ctxt.ss = FLAT_GUESTOS_DS;
   5.565 +	ctxt->cpu_ctxt.cs = FLAT_GUESTOS_CS;
   5.566 +	ctxt->cpu_ctxt.eip = load_addr;
   5.567 +	ctxt->cpu_ctxt.eip = 0x80100020;
   5.568 +	/* put stack at top of second page */
   5.569 +	ctxt->cpu_ctxt.esp = 0x80000000 + (STACKPAGE << PAGE_SHIFT);
   5.570 +
   5.571 +	/* why is this set? */
   5.572 +	ctxt->cpu_ctxt.esi = ctxt->cpu_ctxt.esp;
   5.573 +	ctxt->cpu_ctxt.eflags = (1 << 9) | (1 << 2);
   5.574 +
   5.575 +	/* FPU is set up to default initial state. */
   5.576 +	memset(ctxt->fpu_ctxt, 0, sizeof (ctxt->fpu_ctxt));
   5.577 +
   5.578 +	/* Virtual IDT is empty at start-of-day. */
   5.579 +	for (i = 0; i < 256; i++) {
   5.580 +		ctxt->trap_ctxt[i].vector = i;
   5.581 +		ctxt->trap_ctxt[i].cs = FLAT_GUESTOS_CS;
   5.582 +	}
   5.583 +	ctxt->fast_trap_idx = 0;
   5.584 +
   5.585 +	/* No LDT. */
   5.586 +	ctxt->ldt_ents = 0;
   5.587 +
   5.588 +	/* Use the default Xen-provided GDT. */
   5.589 +	ctxt->gdt_ents = 0;
   5.590 +
   5.591 +	/* Ring 1 stack is the initial stack. */
   5.592 +	/* put stack at top of second page */
   5.593 +	ctxt->guestos_ss = FLAT_GUESTOS_DS;
   5.594 +	ctxt->guestos_esp = ctxt->cpu_ctxt.esp;
   5.595 +
   5.596 +	/* No debugging. */
   5.597 +	memset(ctxt->debugreg, 0, sizeof (ctxt->debugreg));
   5.598 +
   5.599 +	/* No callback handlers. */
   5.600 +	ctxt->event_callback_cs = FLAT_GUESTOS_CS;
   5.601 +	ctxt->event_callback_eip = 0;
   5.602 +	ctxt->failsafe_callback_cs = FLAT_GUESTOS_CS;
   5.603 +	ctxt->failsafe_callback_eip = 0;
   5.604 +
   5.605 +	memset(&launch_op, 0, sizeof (launch_op));
   5.606 +
   5.607 +	launch_op.u.builddomain.domain = (domid_t) domid;
   5.608 +	//  launch_op.u.builddomain.num_vifs = 1;
   5.609 +	launch_op.u.builddomain.ctxt = ctxt;
   5.610 +	launch_op.cmd = DOM0_BUILDDOMAIN;
   5.611 +	rc = do_dom0_op(xc_handle, &launch_op);
   5.612 +
   5.613 +	fprintf(stderr, "RC is %d\n", rc);
   5.614 +	return rc;
   5.615 +
   5.616 +      error_out:
   5.617 +	if (kernel_fd >= 0)
   5.618 +		close(kernel_fd);
   5.619 +	if (kernel_gfd)
   5.620 +		gzclose(kernel_gfd);
   5.621 +
   5.622 +	return -1;
   5.623 +}
   5.624 +
   5.625 +/* 
   5.626 + * Plan 9 memory layout (initial)
   5.627 + * ----------------
   5.628 + * | info from xen| @0
   5.629 + * ----------------
   5.630 + * | stack        |
   5.631 + * ----------------<--- page 2
   5.632 + * | empty        |
   5.633 + * ---------------<---- page 5 MACHADDR (always points to machp[cpuno]
   5.634 + * | aliased      |
   5.635 + * ---------------<----- page 6 CPU0MACH
   5.636 + * | CPU0MACH     |
   5.637 + * ----------------
   5.638 + * | empty        |
   5.639 + * ---------------- *virt_load_addr = ehdr.e_entry (0x80100000)
   5.640 + * | kernel       |
   5.641 + * |              |
   5.642 + * ---------------- <----- page aligned boundary.
   5.643 + * | data         |
   5.644 + * |              | 
   5.645 + * ----------------
   5.646 + * | bss          |
   5.647 + * ----------------<---  end of kernel (page aligned)
   5.648 + * | PMD cpu0pdb  |
   5.649 + * ----------------<--- page +1
   5.650 + * | PTE cpu0pte  |
   5.651 + * ----------------<--- page (tot_pte_pages)/1024
   5.652 + * | page_array   |
   5.653 + * ---------------- <--- page (tot_pte_pages)/1024
   5.654 + * | empty to TOM |
   5.655 + * ----------------
   5.656 + */
   5.657 +
   5.658 +static int
   5.659 +loadp9image(gzFile kernel_gfd, int xc_handle, u32 dom,
   5.660 +	    unsigned long *page_array,
   5.661 +	    unsigned long tot_pages, unsigned long *virt_load_addr,
   5.662 +	    unsigned long *ksize, unsigned long *symtab_addr,
   5.663 +	    unsigned long *symtab_len,
   5.664 +	    unsigned long *first_data_page, unsigned long *pdb_page)
   5.665 +{
   5.666 +	unsigned long datapage;
   5.667 +	Exec ehdr;
   5.668 +
   5.669 +	char *p;
   5.670 +	unsigned long maxva;
   5.671 +	int curpos, ret;
   5.672 +	PAGE *image = 0;
   5.673 +	unsigned long image_tot_pages = 0;
   5.674 +	unsigned long textround;
   5.675 +
   5.676 +	ret = -1;
   5.677 +
   5.678 +	p = NULL;
   5.679 +	maxva = 0;
   5.680 +
   5.681 +	if (gzread(kernel_gfd, &ehdr, sizeof (Exec)) != sizeof (Exec)) {
   5.682 +		PERROR("Error reading kernel image P9 header.");
   5.683 +		goto out;
   5.684 +	}
   5.685 +
   5.686 +	plan9header(&ehdr);
   5.687 +	curpos = sizeof (Exec);
   5.688 +
   5.689 +	if (ehdr.magic != I_MAGIC) {
   5.690 +		PERROR("Image does not have an P9 header.");
   5.691 +		goto out;
   5.692 +	}
   5.693 +
   5.694 +	textround = ((ehdr.text + 0x20 + 4095) >> 12) << 12;
   5.695 +	*first_data_page = 0x100000 + textround;
   5.696 +	DPRINTF(("ehrd.text is 0x%lx, textround is 0x%lx\n",
   5.697 +		 ehdr.text, textround));
   5.698 +
   5.699 +	image_tot_pages =
   5.700 +	    (textround + ehdr.data + ehdr.bss + PAGE_SIZE - 1) >> PAGE_SHIFT;
   5.701 +	DPRINTF(("tot pages is %ld\n", image_tot_pages));
   5.702 +
   5.703 +	*virt_load_addr = 0x80100000;
   5.704 +
   5.705 +	if ((*virt_load_addr & (PAGE_SIZE - 1)) != 0) {
   5.706 +		ERROR("We can only deal with page-aligned load addresses");
   5.707 +		goto out;
   5.708 +	}
   5.709 +
   5.710 +	if ((*virt_load_addr + (image_tot_pages << PAGE_SHIFT)) >
   5.711 +	    HYPERVISOR_VIRT_START) {
   5.712 +		ERROR("Cannot map all domain memory without hitting Xen space");
   5.713 +		goto out;
   5.714 +	}
   5.715 +
   5.716 +	/* just malloc an image that is image_tot_pages  in size. Then read in 
   5.717 +	 * the image -- text, data, -- to page-rounded alignments. 
   5.718 +	 * then copy into xen .
   5.719 +	 * this gets BSS zeroed for free
   5.720 +	 */
   5.721 +	DPRINTF(("Allocate %ld bytes\n", image_tot_pages * sizeof (*image)));
   5.722 +	image = calloc(image_tot_pages, sizeof (*image));
   5.723 +	if (!image)
   5.724 +		return blah("alloc data");
   5.725 +	/* text starts at 0x20, after the header, just like Unix long ago */
   5.726 +	if (gzread(kernel_gfd, &image[0].data[sizeof (Exec)], ehdr.text) <
   5.727 +	    ehdr.text)
   5.728 +		return blah("read text");
   5.729 +	DPRINTF(("READ TEXT %ld bytes\n", ehdr.text));
   5.730 +	datapage = ((ehdr.text + sizeof (Exec)) / PAGE_SIZE) + 1;
   5.731 +	if (gzread(kernel_gfd, image[datapage].data, ehdr.data) < ehdr.data)
   5.732 +		return blah("read data");
   5.733 +	DPRINTF(("READ DATA %ld bytes\n", ehdr.data));
   5.734 +
   5.735 +	/* nice contig stuff */
   5.736 +	/* oops need to start at 0x100000 */
   5.737 +
   5.738 +	ret = memcpy_toguest(xc_handle, dom,
   5.739 +			     image, image_tot_pages * 4096, page_array, 0x100);
   5.740 +	DPRINTF(("done copying kernel to guest memory\n"));
   5.741 +
   5.742 +      out:
   5.743 +	if (image)
   5.744 +		free(image);
   5.745 +	*pdb_page = image_tot_pages + (0x100000 >> PAGE_SHIFT);
   5.746 +	return ret;
   5.747 +}
     6.1 --- a/tools/python/xen/lowlevel/xc/xc.c	Thu Dec 23 14:04:36 2004 +0000
     6.2 +++ b/tools/python/xen/lowlevel/xc/xc.c	Fri Dec 24 22:08:11 2004 +0000
     6.3 @@ -366,6 +366,33 @@ static PyObject *pyxc_linux_build(PyObje
     6.4      return zero;
     6.5  }
     6.6  
     6.7 +static PyObject *pyxc_plan9_build(PyObject *self,
     6.8 +                                  PyObject *args,
     6.9 +                                  PyObject *kwds)
    6.10 +{
    6.11 +    XcObject *xc = (XcObject *)self;
    6.12 +
    6.13 +    u32   dom;
    6.14 +    char *image, *ramdisk = NULL, *cmdline = "";
    6.15 +    int   control_evtchn, flags = 0;
    6.16 +
    6.17 +    static char *kwd_list[] = { "dom", "control_evtchn",
    6.18 +                                "image", "ramdisk", "cmdline", "flags",
    6.19 +                                NULL };
    6.20 +
    6.21 +    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iis|ssi", kwd_list,
    6.22 +                                      &dom, &control_evtchn,
    6.23 +                                      &image, &ramdisk, &cmdline, &flags) )
    6.24 +        return NULL;
    6.25 +
    6.26 +    if ( xc_plan9_build(xc->xc_handle, dom, image,
    6.27 +                        cmdline, control_evtchn, flags) != 0 )
    6.28 +        return PyErr_SetFromErrno(xc_error);
    6.29 +
    6.30 +    Py_INCREF(zero);
    6.31 +    return zero;
    6.32 +}
    6.33 +
    6.34  static PyObject *pyxc_bvtsched_global_set(PyObject *self,
    6.35                                            PyObject *args,
    6.36                                            PyObject *kwds)
    6.37 @@ -889,6 +916,14 @@ static PyMethodDef pyxc_methods[] = {
    6.38        " state_file [str]:    Name of state file. Must not currently exist.\n"
    6.39        " progress   [int, 1]: Bool - display a running progress indication?\n\n"
    6.40        "Returns: [int] 0 on success; -1 on error.\n" },
    6.41 +    { "plan9_build",
    6.42 +      (PyCFunction)pyxc_plan9_build,
    6.43 +      METH_VARARGS | METH_KEYWORDS, "\n"
    6.44 +      "Build a new Plan 9 guest OS.\n"
    6.45 +      " dom     [long]:     Identifier of domain to build into.\n"
    6.46 +      " image   [str]:      Name of kernel image file. May be gzipped.\n"
    6.47 +      " cmdline [str, n/a]: Kernel parameters, if any.\n\n"
    6.48 +      "Returns: [int] 0 on success; -1 on error.\n" },
    6.49  
    6.50      { "linux_restore", 
    6.51        (PyCFunction)pyxc_linux_restore, 
     7.1 --- a/tools/python/xen/xend/XendDomainInfo.py	Thu Dec 23 14:04:36 2004 +0000
     7.2 +++ b/tools/python/xen/xend/XendDomainInfo.py	Fri Dec 24 22:08:11 2004 +0000
     7.3 @@ -1065,6 +1065,34 @@ def vm_image_linux(vm, image):
     7.4      vm.create_domain("linux", kernel, ramdisk, cmdline)
     7.5      return vm
     7.6  
     7.7 +def vm_image_plan9(vm, image):
     7.8 +    """Create a VM for a Plan 9 image.
     7.9 +
    7.10 +    name      vm name
    7.11 +    memory    vm memory
    7.12 +    image     image config
    7.13 +
    7.14 +    returns vm 
    7.15 +    """
    7.16 +    #todo: Same as for linux. Is that right? If so can unify them.
    7.17 +    kernel = sxp.child_value(image, "kernel")
    7.18 +    cmdline = ""
    7.19 +    ip = sxp.child_value(image, "ip", "dhcp")
    7.20 +    if ip:
    7.21 +        cmdline += "ip=" + ip
    7.22 +    root = sxp.child_value(image, "root")
    7.23 +    if root:
    7.24 +        cmdline += "root=" + root
    7.25 +    args = sxp.child_value(image, "args")
    7.26 +    if args:
    7.27 +        cmdline += " " + args
    7.28 +    ramdisk = sxp.child_value(image, "ramdisk", '')
    7.29 +    vifs = vm.config_devices("vif")
    7.30 +    vm.create_domain("plan9", kernel, ramdisk, cmdline)
    7.31 +    return vm
    7.32 +    
    7.33 +    
    7.34 +
    7.35  def vm_dev_vif(vm, val, index, change=0):
    7.36      """Create a virtual network interface (vif).
    7.37  
    7.38 @@ -1186,6 +1214,7 @@ def vm_field_maxmem(vm, config, val, ind
    7.39  
    7.40  # Register image handlers.
    7.41  add_image_handler('linux',  vm_image_linux)
    7.42 +add_image_handler('plan9',  vm_image_plan9)
    7.43  
    7.44  # Register device handlers.
    7.45  add_device_handler('vif',  vm_dev_vif)