direct-io.hg

view tools/domain_builder/dom_builder.c @ 204:0e45b167992d

bitkeeper revision 1.65 (3e536858YdNPGFSv3J35Fl8zAGLJjQ)

sched.h, xen_block.c, domain.c:
Now have per-domain IO completion queue.
author kaf24@labyrinth.cl.cam.ac.uk
date Wed Feb 19 11:19:52 2003 +0000 (2003-02-19)
parents efb500abaa15
children 15edce7a072a 7f19fcd72411
line source
1 /*
2 * XenoDomainBuilder, copyright (c) Boris Dragovic, bd240@cl.cam.ac.uk
3 * This code is released under terms and conditions of GNU GPL :).
4 * Usage: <executable> <mem_kb> <os image> <num_vifs>
5 */
7 #include <unistd.h>
8 #include <stdio.h>
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <sys/mman.h>
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <stdlib.h>
16 #include "hypervisor_defs.h"
17 #include "dom0_ops.h"
18 #include "dom0_defs.h"
19 #include "mem_defs.h"
21 #define PERR_STRING "Xeno Domain Builder"
23 #define GUEST_SIG "XenoGues"
24 #define SIG_LEN 8
26 #define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_USER|_PAGE_ACCESSED)
27 #define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_USER|_PAGE_ACCESSED|_PAGE_DIRTY)
29 /* standardized error reporting function */
30 static void dberr(char *msg)
31 {
32 printf("%s: %s\n", PERR_STRING, msg);
33 }
35 /* status reporting function */
36 static void dbstatus(char * msg)
37 {
38 printf("Domain Builder: %s\n", msg);
39 }
41 /* clean up domain's memory allocations */
42 static void dom_mem_cleanup(dom_mem_t * dom_mem)
43 {
44 char mem_path[MAX_PATH];
45 int mem_fd;
47 /* open the domain's /proc mem interface */
48 sprintf(mem_path, "%s%s%s%s%d%s%s", "/proc/", PROC_XENO_ROOT, "/",
49 PROC_DOM_PREFIX, dom_mem->domain, "/", PROC_DOM_MEM);
51 mem_fd = open(mem_path, O_WRONLY);
52 if(mem_fd < 0){
53 perror(PERR_STRING);
54 }
56 if(write(mem_fd, (dom_mem_t *)dom_mem, sizeof(dom_mem_t)) < 0){
57 dbstatus("Error unmapping domain's memory.\n");
58 }
60 close(mem_fd);
61 }
63 /* ask dom0 to export domains memory through /proc */
64 static int setup_dom_memmap(unsigned long pfn, int pages, int dom)
65 {
66 char cmd_path[MAX_PATH];
67 dom0_op_t dop;
68 int cmd_fd;
70 dop.cmd = MAP_DOM_MEM;
71 dop.u.dommem.start_pfn = pfn;
72 dop.u.dommem.tot_pages = pages;
73 dop.u.dommem.domain = dom;
75 /* open the /proc command interface */
76 sprintf(cmd_path, "%s%s%s%s", "/proc/", PROC_XENO_ROOT, "/", PROC_CMD);
77 cmd_fd = open(cmd_path, O_WRONLY);
78 if(cmd_fd < 0){
79 perror(PERR_STRING);
80 return -1;
81 }
83 write(cmd_fd, &dop, sizeof(dom0_op_t));
84 close(cmd_fd);
86 return 0;
87 }
89 /* request the actual mapping from dom0 */
90 static unsigned long get_vaddr(unsigned int dom)
91 {
92 char mem_path[MAX_PATH];
93 unsigned long addr;
94 int mem_fd;
96 /* open the domain's /proc mem interface */
97 sprintf(mem_path, "%s%s%s%s%d%s%s", "/proc/", PROC_XENO_ROOT, "/",
98 PROC_DOM_PREFIX, dom, "/", PROC_DOM_MEM);
100 mem_fd = open(mem_path, O_RDONLY);
101 if(mem_fd < 0){
102 perror(PERR_STRING);
103 return 0;
104 }
106 /* get virtual address of mapped region */
107 read(mem_fd, &addr, sizeof(addr));
109 close(mem_fd);
111 return addr;
112 }
114 static int map_dom_mem(unsigned long pfn, int pages, int dom,
115 dom_mem_t * dom_mem)
116 {
118 if(setup_dom_memmap(pfn, pages, dom)){
119 perror(PERR_STRING);
120 return -1;
121 }
123 dom_mem->domain = dom;
124 dom_mem->start_pfn = pfn;
125 dom_mem->tot_pages = pages;
126 if((dom_mem->vaddr = get_vaddr(dom)) == 0){
127 dberr("Error mapping dom memory.");
128 return -1;
129 }
131 return 0;
132 }
134 /* create new domain */
135 static dom0_newdomain_t * create_new_domain(long req_mem)
136 {
137 dom0_newdomain_t * dom_data;
138 char cmd_path[MAX_PATH];
139 char dom_id_path[MAX_PATH];
140 dom0_op_t dop;
141 int cmd_fd;
142 int id_fd;
144 /* open the /proc command interface */
145 sprintf(cmd_path, "%s%s%s%s", "/proc/", PROC_XENO_ROOT, "/", PROC_CMD);
146 cmd_fd = open(cmd_path, O_WRONLY);
147 if(cmd_fd < 0){
148 perror(PERR_STRING);
149 return 0;
150 }
152 dop.cmd = DOM0_NEWDOMAIN;
153 dop.u.newdomain.memory_kb = req_mem;
155 write(cmd_fd, &dop, sizeof(dom0_op_t));
156 close(cmd_fd);
158 sprintf(dom_id_path, "%s%s%s%s", "/proc/", PROC_XENO_ROOT, "/",
159 PROC_DOM_DATA);
160 while((id_fd = open(dom_id_path, O_RDONLY)) < 0){}
161 dom_data = (dom0_newdomain_t *)malloc(sizeof(dom0_newdomain_t));
162 read(id_fd, dom_data, sizeof(dom0_newdomain_t));
163 close(id_fd);
165 sprintf(cmd_path, "Reserved %ld kbytes memory and assigned id %d to the"
166 "new domain.", req_mem, dom_data->domain);
167 dbstatus(cmd_path);
169 return dom_data;
170 }
172 /* open kernel image and do some sanity checks */
173 static int do_kernel_chcks(char *image, long dom_size,
174 unsigned long * load_addr, size_t * ksize)
175 {
176 char signature[8];
177 char status[MAX_PATH];
178 struct stat stat;
179 int fd;
180 int ret;
182 fd = open(image, O_RDONLY);
183 if(fd < 0){
184 perror(PERR_STRING);
185 ret = -1;
186 goto out;
187 }
189 if(fstat(fd, &stat) < 0){
190 perror(PERR_STRING);
191 ret = -1;
192 close(fd);
193 goto out;
194 }
196 if(stat.st_size > (dom_size << 10)){
197 sprintf(status, "Kernel image size %ld larger than requested "
198 "domain size %ld\n Terminated.\n", stat.st_size, dom_size);
199 dberr(status);
200 ret = -1;
201 close(fd);
202 goto out;
203 }
205 read(fd, signature, SIG_LEN);
206 if(strncmp(signature, GUEST_SIG, SIG_LEN)){
207 dberr("Kernel image does not contain required signature. "
208 "Terminating.\n");
209 ret = -1;
210 close(fd);
211 goto out;
212 }
214 read(fd, load_addr, sizeof(unsigned long));
216 *ksize = stat.st_size - SIG_LEN - sizeof(unsigned long);
218 sprintf(status, "Kernel image %s valid, kernel virtual load address %lx",
219 image, *load_addr);
220 dbstatus(status);
222 ret = fd;
224 out:
225 return ret;
226 }
228 /* this is the main guestos setup function,
229 * returnes domain descriptor structure to be used when launching
230 * the domain by hypervisor to do some last minute initialization.
231 * page table initialization is done by making a list of page table
232 * requests that are handeled by the hypervisor in the ordinary
233 * manner. this way, many potentially messy things are avoided...
234 */
235 #define PAGE_TO_VADDR(_pfn) ((void *)(dom_mem->vaddr + ((_pfn) * PAGE_SIZE)))
236 static dom_meminfo_t *setup_guestos(int dom, int kernel_fd,
237 unsigned long virt_load_addr, size_t ksize, dom_mem_t *dom_mem)
238 {
239 dom_meminfo_t *meminfo;
240 unsigned long *page_array;
241 page_update_request_t *pgt_updates;
242 dom_mem_t mem_map;
243 dom_meminfo_t *ret = NULL;
244 int alloc_index, num_pt_pages;
245 unsigned long l2tab;
246 unsigned long l1tab = 0;
247 unsigned long num_pgt_updates = 0;
248 unsigned long count, pt_start;
249 dom0_op_t pgupdate_req;
250 char cmd_path[MAX_PATH];
251 int cmd_fd;
253 meminfo = (dom_meminfo_t *)malloc(sizeof(dom_meminfo_t));
254 page_array = malloc(dom_mem->tot_pages * 4);
255 pgt_updates = (page_update_request_t *)dom_mem->vaddr;
256 alloc_index = dom_mem->tot_pages - 1;
258 memcpy(page_array, (void *)dom_mem->vaddr, dom_mem->tot_pages * 4);
260 /* Count bottom-level PTs, rounding up. Include one PTE for shared info. */
261 num_pt_pages =
262 (l1_table_offset(virt_load_addr) + dom_mem->tot_pages + 1024) / 1024;
264 /* We must also count the page directory. */
265 num_pt_pages++;
267 /* Index of first PT page. */
268 pt_start = dom_mem->tot_pages - num_pt_pages;
270 /* first allocate page for page dir. allocation goes backwards from the
271 * end of the allocated physical address space.
272 */
273 l2tab = *(page_array + alloc_index) << PAGE_SHIFT;
274 memset(PAGE_TO_VADDR(alloc_index), 0, PAGE_SIZE);
275 alloc_index--;
276 meminfo->l2_pgt_addr = l2tab;
277 meminfo->virt_shinfo_addr = virt_load_addr + nr_2_page(dom_mem->tot_pages);
279 /* pin down l2tab addr as page dir page - causes hypervisor to provide
280 * correct protection for the page
281 */
282 pgt_updates->ptr = l2tab | PGREQ_EXTENDED_COMMAND;
283 pgt_updates->val = PGEXT_PIN_L2_TABLE;
284 pgt_updates++;
285 num_pgt_updates++;
287 /*
288 * Initialise the page tables. The final iteration is for the shared_info
289 * PTE -- we break out before filling in the entry, as that is done by
290 * Xen during final setup.
291 */
292 l2tab += l2_table_offset(virt_load_addr) * sizeof(l2_pgentry_t);
293 for ( count = 0; count < (dom_mem->tot_pages + 1); count++ )
294 {
295 if ( !((unsigned long)l1tab & (PAGE_SIZE-1)) )
296 {
297 l1tab = *(page_array + alloc_index) << PAGE_SHIFT;
298 memset(PAGE_TO_VADDR(alloc_index), 0, PAGE_SIZE);
299 alloc_index--;
301 l1tab += l1_table_offset(virt_load_addr + nr_2_page(count))
302 * sizeof(l1_pgentry_t);
304 /* make apropriate entry in the page directory */
305 pgt_updates->ptr = l2tab;
306 pgt_updates->val = l1tab | L2_PROT;
307 pgt_updates++;
308 num_pgt_updates++;
309 l2tab += sizeof(l2_pgentry_t);
310 }
312 /* The last PTE we consider is filled in later by Xen. */
313 if ( count == dom_mem->tot_pages ) break;
315 if ( count < pt_start )
316 {
317 pgt_updates->ptr = l1tab;
318 pgt_updates->val = (*(page_array + count) << PAGE_SHIFT) | L1_PROT;
319 pgt_updates++;
320 num_pgt_updates++;
321 l1tab += sizeof(l1_pgentry_t);
322 }
323 else
324 {
325 pgt_updates->ptr = l1tab;
326 pgt_updates->val =
327 ((*(page_array + count) << PAGE_SHIFT) | L1_PROT) & ~_PAGE_RW;
328 pgt_updates++;
329 num_pgt_updates++;
330 l1tab += sizeof(l1_pgentry_t);
331 }
333 pgt_updates->ptr =
334 (*(page_array + count) << PAGE_SHIFT) | PGREQ_MPT_UPDATE;
335 pgt_updates->val = count;
336 pgt_updates++;
337 num_pgt_updates++;
338 }
340 meminfo->virt_startinfo_addr = virt_load_addr + nr_2_page(alloc_index - 1);
341 meminfo->domain = dom;
343 /*
344 * Send the page update requests down to the hypervisor.
345 * NB. We must do this before loading the guest OS image!
346 */
347 sprintf(cmd_path, "%s%s%s%s", "/proc/", PROC_XENO_ROOT, "/", PROC_CMD);
348 if ( (cmd_fd = open(cmd_path, O_WRONLY)) < 0 ) goto out;
349 pgupdate_req.cmd = DO_PGUPDATES;
350 pgupdate_req.u.pgupdate.pgt_update_arr = (unsigned long)dom_mem->vaddr;
351 pgupdate_req.u.pgupdate.num_pgt_updates = num_pgt_updates;
352 write(cmd_fd, &pgupdate_req, sizeof(dom0_op_t));
353 close(cmd_fd);
355 /* Load the guest OS image. */
356 if( read(kernel_fd, (char *)dom_mem->vaddr, ksize) != ksize )
357 {
358 dberr("Error reading kernel image, could not"
359 " read the whole image. Terminating.\n");
360 goto out;
361 }
363 ret = meminfo;
364 out:
366 return ret;
367 }
369 static int launch_domain(dom_meminfo_t * meminfo)
370 {
371 char cmd_path[MAX_PATH];
372 dom0_op_t dop;
373 int cmd_fd;
375 sprintf(cmd_path, "%s%s%s%s", "/proc/", PROC_XENO_ROOT, "/", PROC_CMD);
376 cmd_fd = open(cmd_path, O_WRONLY);
377 if(cmd_fd < 0){
378 perror(PERR_STRING);
379 return -1;
380 }
382 dop.cmd = DOM0_STARTDOM;
383 memcpy(&dop.u.meminfo, meminfo, sizeof(dom_meminfo_t));
384 write(cmd_fd, &dop, sizeof(dom0_op_t));
386 dbstatus("Launched the new domain!");
388 close(cmd_fd);
389 }
391 int main(int argc, char **argv)
392 {
394 dom0_newdomain_t * dom_data;
395 dom_mem_t dom_os_image;
396 dom_mem_t dom_pgt;
397 dom_meminfo_t * meminfo;
398 size_t ksize;
399 unsigned long load_addr;
400 char status[1024];
401 int kernel_fd;
402 int count;
403 int cmd_len;
404 int ret = 0;
406 unsigned long addr;
408 if(argc < 4){
409 dberr("Usage: dom_builder <kbytes_mem> <image> <num_vifs> "
410 "<boot_params>\n");
411 ret = -1;
412 goto out;
413 }
415 /* create new domain and set up all the neccessary mappings */
417 kernel_fd = do_kernel_chcks(argv[2], atol(argv[1]), &load_addr, &ksize);
418 if(kernel_fd < 0){
419 ret = -1;
420 goto out;
421 }
423 /* request the creation of new domain */
424 dom_data = create_new_domain(atol(argv[1]));
425 if(dom_data == 0){
426 ret = -1;
427 goto out;
428 }
430 /* map domain's memory */
431 if(map_dom_mem(dom_data->pg_head, dom_data->memory_kb >> (PAGE_SHIFT - 10),
432 dom_data->domain, &dom_os_image)){
433 ret = -1;
434 goto out;
435 }
437 /* the following code does the actual domain building */
438 meminfo = setup_guestos(dom_data->domain, kernel_fd, load_addr, ksize,
439 &dom_os_image);
440 if(meminfo == NULL){
441 printf("Domain Builder: debug: meminfo NULL\n");
442 ret = -1;
443 dom_mem_cleanup(&dom_os_image);
444 goto out;
445 }
447 dom_mem_cleanup(&dom_os_image);
449 meminfo->virt_load_addr = load_addr;
450 meminfo->num_vifs = atoi(argv[3]);
451 meminfo->cmd_line[0] = '\0';
452 cmd_len = 0;
453 for(count = 4; count < argc; count++){
454 if(cmd_len + strlen(argv[count]) > MAX_CMD_LEN - 1){
455 dberr("Size of image boot params too big!\n");
456 break;
457 }
458 strcat(meminfo->cmd_line, argv[count]);
459 strcat(meminfo->cmd_line, " ");
460 cmd_len += strlen(argv[count] + 1);
461 }
463 sprintf(status,
464 "About to launch new domain %d with folowing parameters:\n"
465 " * page table base: %lx \n * load address: %lx \n"
466 " * shared info address: %lx \n * start info address: %lx \n"
467 " * number of vifs: %d \n * cmd line: %s \n", meminfo->domain,
468 meminfo->l2_pgt_addr, meminfo->virt_load_addr,
469 meminfo->virt_shinfo_addr, meminfo->virt_startinfo_addr,
470 meminfo->num_vifs, meminfo->cmd_line);
471 dbstatus(status);
473 /* and launch the domain */
474 if(launch_domain(meminfo) != 0)
475 ret = -1;
477 free(meminfo);
478 out:
479 return ret;
480 }