As announced earlier (http://lists.xensource.com/archives/html/xen-devel/2005-03/msg01160.html) I''m working on porting ReactOS to Xen. The first stage, getting our bootloader running, is complete now. Progress report and a screenshot on http://reactos.com/wiki/index.php/Xen_port To start ReactOS in a Xen domain, a ReactOS domain builder is needed. Patches to implement that are included below. I''m not sure about the Signed-Off-By stuff, is just including the line below enough or is some paperwork required? Ge van Geldorp. Signed-Off-By: Ge van Geldorp <gvg@reactos.com> --- orig/tools/libxc/xc.h 2005-06-02 23:26:10.000000000 +0200 +++ reactos/tools/libxc/xc.h 2005-06-02 23:23:10.000000000 +0200 @@ -273,6 +273,15 @@ unsigned int control_evtchn, unsigned long flags); +int xc_reactos_build(int xc_handle, + u32 domid, + const char *image_name, + const char *module_name, + const char *cmdline, + unsigned int control_evtchn, + unsigned long flags, + unsigned int vcpus); + int xc_bvtsched_global_set(int xc_handle, unsigned long ctx_allow); --- orig/tools/python/xen/lowlevel/xc/xc.c 2005-06-02 23:26:10.000000000 +0200 +++ reactos/tools/python/xen/lowlevel/xc/xc.c 2005-06-02 23:23:07.000000000 +0200 @@ -391,6 +391,33 @@ return zero; } +static PyObject *pyxc_reactos_build(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + + u32 dom; + char *image, *module = NULL, *cmdline = ""; + int control_evtchn, flags = 0, vcpus = 1; + + static char *kwd_list[] = { "dom", "control_evtchn", + "image", "ramdisk", "cmdline", "flags", "vcpus", + NULL }; + + if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iis|ssii", kwd_list, + &dom, &control_evtchn, + &image, &module, &cmdline, &flags, &vcpus) ) + return NULL; + + if ( xc_reactos_build(xc->xc_handle, dom, image, + module, cmdline, control_evtchn, flags, vcpus) != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; +} + static PyObject *pyxc_bvtsched_global_set(PyObject *self, PyObject *args, PyObject *kwds) @@ -942,6 +969,17 @@ " cmdline [str, n/a]: Kernel parameters, if any.\n\n" "Returns: [int] 0 on success; -1 on error.\n" }, + { "reactos_build", + (PyCFunction)pyxc_reactos_build, + METH_VARARGS | METH_KEYWORDS, "\n" + "Build a new ReactOS guest OS.\n" + " dom [int]: Identifier of domain to build into.\n" + " image [str]: Name of kernel image file. May be gzipped.\n" + " ramdisk [str, n/a]: Name of ramdisk file, if any.\n" + " cmdline [str, n/a]: Kernel parameters, if any.\n\n" + " vcpus [int, 1]: Number of Virtual CPUS in domain.\n\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + { "bvtsched_global_set", (PyCFunction)pyxc_bvtsched_global_set, METH_VARARGS | METH_KEYWORDS, "\n" --- orig/tools/python/xen/xend/XendDomainInfo.py 2005-06-02 23:26:10.000000000 +0200 +++ reactos/tools/python/xen/xend/XendDomainInfo.py 2005-06-02 23:23:01.000000000 +0200 @@ -1167,6 +1167,24 @@ vm.create_domain("vmx", kernel, ramdisk, cmdline, memmap) return vm +def vm_image_reactos(vm, image): + """Create a VM for a ReactOS image. + + @param name: vm name + @param memory: vm memory + @param image: image config + @return: vm + """ + kernel = sxp.child_value(image, "kernel") + cmdline = "" + args = sxp.child_value(image, "args") + if args: + cmdline += " " + args + ramdisk = sxp.child_value(image, "ramdisk", '''') + log.debug("creating reactos domain with cmdline: %s" %(cmdline,)) + vm.create_domain("reactos", kernel, ramdisk, cmdline) + return vm + def vm_field_ignore(vm, config, val, index): """Dummy config field handler used for fields with built-in handling. @@ -1196,9 +1214,10 @@ #=========================================================================== # Register image handlers. -add_image_handler(''linux'', vm_image_linux) -add_image_handler(''plan9'', vm_image_plan9) -add_image_handler(''vmx'', vm_image_vmx) +add_image_handler(''linux'', vm_image_linux) +add_image_handler(''plan9'', vm_image_plan9) +add_image_handler(''vmx'', vm_image_vmx) +add_image_handler(''reactos'', vm_image_reactos) # Ignore the fields we already handle. add_config_handler(''name'', vm_field_ignore) --- orig/tools/libxc/Makefile 2005-05-25 00:20:35 +02:00 +++ reactos/tools/libxc/Makefile 2005-06-01 11:51:19 +02:00 @@ -28,6 +28,7 @@ SRCS += xc_private.c SRCS += xc_ptrace.c SRCS += xc_ptrace_core.c +SRCS += xc_reactos_build.c SRCS += xc_vmx_build.c CFLAGS += -Wall --- /dev/null 2005-06-02 12:46:09.470000000 +0200 +++ reactos/tools/libxc/xc_reactos_build.c 2005-06-02 23:23:10.000000000 +0200 @@ -0,0 +1,652 @@ +/****************************************************************************** + * xc_reactos_build.c + * + * Based on xc_linux_build.c + * + * An executable to be loaded by the reactos domain builder is a simple binary + * image. It''s like a .COM file in MS-DOS. No headers are present. + * The only requirement is that it must have a xen_reactos table somewhere in + * the first 8192 bytes, starting on a 32-bit aligned address. Those familiar + * with the multiboot specification should recognize this, it''s (almost) the + * same as the multiboot header. + * The layout of the xen_reactos table is: + * + * Offset Type Name Note + * 0 u32 magic required + * 4 u32 flags required + * 8 u32 checksum required + * 12 u32 header_addr required + * 16 u32 load_addr required + * 20 u32 load_end_addr required + * 24 u32 bss_end_addr required + * 28 u32 entry_addr required + * + * - magic + * Magic number identifying the table. For images to be loaded by Xen 3, the + * magic value is 0x336ec578 ("xEn3" with the 0x80 bit of the "E" set). + * - flags + * bit 0: indicates whether the image needs to be loaded on a page boundary + * bit 1: reserved, must be 0 (the multiboot spec uses this bit to indicate + * that memory info should be passed to the image) + * bit 2: reserved, must be 0 (the multiboot spec uses this bit to indicate + * that the bootloader should pass video mode info to the image) + * bit 16: reserved, must be 1 (the multiboot spec uses this bit to indicate + * that the values in the fields header_addr - entry_addr are + * valid) + * All other bits should be set to 0. + * - checksum + * When added to "magic" and "flags", the resulting value should be 0. + * - header_addr + * Contains the virtual address corresponding to the beginning of the + * table - the memory location at which the magic value is supposed to be + * loaded. This field serves to synchronize the mapping between OS image + * offsets and virtual memory addresses. + * - load_addr + * Contains the virtual address of the beginning of the text segment. The + * offset in the OS image file at which to start loading is defined by the + * offset at which the table was found, minus (header addr - load addr). + * load addr must be less than or equal to header addr. + * - load_end_addr + * Contains the virtual address of the end of the data segment. + * (load_end_addr - load_addr) specifies how much data to load. This implies + * that the text and data segments must be consecutive in the OS image. If + * this field is zero, the domain builder assumes that the text and data + * segments occupy the whole OS image file. + * - bss_end_addr + * Contains the virtual address of the end of the bss segment. The domain + * builder initializes this area to zero, and reserves the memory it occupies + * to avoid placing boot modules and other data relevant to the loaded image + * in that area. If this field is zero, the domain builder assumes that no bss + * segment is present. + * - entry_addr + * The virtual address at which to start execution of the loaded image. + * + * Some of the field descriptions were copied from "The Multiboot + * Specification", Copyright 1995, 96 Bryan Ford <baford@cs.utah.edu>, + * Erich Stefan Boleyn <erich@uruk.org> Copyright 1999, 2000, 2001, 2002 + * Free Software Foundation, Inc. + */ + +#include "xc_private.h" +#include <stdlib.h> + +#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED) +#define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER) + +#define round_pgup(_p) (((_p)+(PAGE_SIZE-1))&PAGE_MASK) +#define round_pgdown(_p) ((_p)&PAGE_MASK) + +struct xen_reactos_table +{ + unsigned long magic; + unsigned long flags; + unsigned long checksum; + unsigned long header_addr; + unsigned long load_addr; + unsigned long load_end_addr; + unsigned long bss_end_addr; + unsigned long entry_addr; +}; + +#define XEN_REACTOS_MAGIC3 0x336ec578 + +#define XEN_REACTOS_FLAG_ALIGN4K 0x00000001 +#define XEN_REACTOS_FLAG_NEEDMEMINFO 0x00000002 +#define XEN_REACTOS_FLAG_NEEDVIDINFO 0x00000004 +#define XEN_REACTOS_FLAG_ADDRSVALID 0x00010000 + +/* Flags we test for */ +#define FLAGS_MASK ((~ 0) & (~ XEN_REACTOS_FLAG_ALIGN4K)) +#define FLAGS_REQUIRED XEN_REACTOS_FLAG_ADDRSVALID + +static int +parsereactosimage( + char *base, unsigned long size, struct xen_reactos_table **table); +static int +loadreactosimage( + char *image_base, unsigned long image_size, int xch, u32 dom, + unsigned long *parray, struct xen_reactos_table *image_info); + +static int setup_guest(int xc_handle, + u32 dom, + char *image, unsigned long image_size, + int module_fd, unsigned long module_len, + unsigned long nr_pages, + unsigned long *pvsi, unsigned long *pvke, + vcpu_guest_context_t *ctxt, + const char *cmdline, + unsigned long shared_info_frame, + unsigned int control_evtchn, + unsigned long flags, + unsigned int vcpus) +{ + l1_pgentry_t *vl1tab=NULL, *vl1e=NULL; + l2_pgentry_t *vl2tab=NULL, *vl2e=NULL; + unsigned long *page_array = NULL; + unsigned long l2tab; + unsigned long l1tab; + unsigned long count, i; + start_info_t *start_info; + shared_info_t *shared_info; + mmu_t *mmu = NULL; + int rc; + + unsigned long nr_pt_pages; + unsigned long ppt_alloc; + unsigned long *physmap, *physmap_e, physmap_pfn; + + struct xen_reactos_table *image_info; + unsigned long vimage_end; + unsigned long vmodule_start; + unsigned long vmodule_end; + unsigned long vphysmap_start; + unsigned long vphysmap_end; + unsigned long vstartinfo_start; + unsigned long vstartinfo_end; + unsigned long vstack_start; + unsigned long vstack_end; + unsigned long vpt_start; + unsigned long vpt_end; + unsigned long v_end; + + rc = parsereactosimage(image, image_size, &image_info); + if ( rc != 0 ) + goto error_out; + + if ( (image_info->load_addr & (PAGE_SIZE-1)) != 0 ) + { + PERROR("Guest OS must load to a page boundary.\n"); + goto error_out; + } + + /* + * Why do we need this? The number of page-table frames depends on the + * size of the bootstrap address space. But the size of the address space + * depends on the number of page-table frames (since each one is mapped + * read-only). We have a pair of simultaneous equations in two unknowns, + * which we solve by exhaustive search. + */ + if ( 0 != image_info->bss_end_addr ) + { + vimage_end = image_info->bss_end_addr; + } + else if ( 0 != image_info->load_end_addr ) + { + vimage_end = image_info->load_end_addr; + } + else + { + vimage_end = image_info->load_addr + image_size; + } + vmodule_start = round_pgup(vimage_end); + vmodule_end = vmodule_start + module_len; + vphysmap_start = round_pgup(vmodule_end); + vphysmap_end = vphysmap_start + (nr_pages * sizeof(unsigned long)); + vpt_start = round_pgup(vphysmap_end); + for ( nr_pt_pages = 2; ; nr_pt_pages++ ) + { + vpt_end = vpt_start + (nr_pt_pages * PAGE_SIZE); + vstartinfo_start = vpt_end; + vstartinfo_end = vstartinfo_start + PAGE_SIZE; + vstack_start = vstartinfo_end; + vstack_end = vstack_start + PAGE_SIZE; + v_end = (vstack_end + (1<<22)-1) & ~((1<<22)-1); + if ( (v_end - vstack_end) < (512 << 10) ) + v_end += 1 << 22; /* Add extra 4MB to get >= 512kB padding. */ + if ( (((v_end - image_info->load_addr + ((1<<L2_PAGETABLE_SHIFT)-1)) >> + L2_PAGETABLE_SHIFT) + 1) <= nr_pt_pages ) + break; + } + + printf("VIRTUAL MEMORY ARRANGEMENT:\n" + " Loaded image: %08lx->%08lx\n" + " Module: %08lx->%08lx\n" + " Phys-Mach map: %08lx->%08lx\n" + " Page tables: %08lx->%08lx\n" + " Start info: %08lx->%08lx\n" + " Boot stack: %08lx->%08lx\n" + " TOTAL: %08lx->%08lx\n", + image_info->load_addr, vimage_end, + vmodule_start, vmodule_end, + vphysmap_start, vphysmap_end, + vpt_start, vpt_end, + vstartinfo_start, vstartinfo_end, + vstack_start, vstack_end, + image_info->load_addr, v_end); + printf(" ENTRY ADDRESS: %08lx\n", image_info->entry_addr); + + if ( (v_end - image_info->load_addr) > (nr_pages * PAGE_SIZE) ) + { + printf("Initial guest OS requires too much space\n" + "(%luMB is greater than %luMB limit)\n", + (v_end-image_info->load_addr)>>20, (nr_pages<<PAGE_SHIFT)>>20); + goto error_out; + } + + if ( (page_array = malloc(nr_pages * sizeof(unsigned long))) == NULL ) + { + PERROR("Could not allocate memory"); + goto error_out; + } + + if ( xc_get_pfn_list(xc_handle, dom, page_array, nr_pages) != nr_pages ) + { + PERROR("Could not get the page frame list"); + goto error_out; + } + + loadreactosimage(image, image_size, xc_handle, dom, page_array, image_info); + + /* Load the initial ramdisk image. */ + if ( module_len != 0 ) + { + for ( i = (vmodule_start - image_info->load_addr); + i < (vmodule_end - image_info->load_addr); i += PAGE_SIZE ) + { + char page[PAGE_SIZE]; + if ( read(module_fd, page, PAGE_SIZE) == -1 ) + { + PERROR("Error reading module image, could not"); + goto error_out; + } + xc_copy_to_domain_page(xc_handle, dom, + page_array[i>>PAGE_SHIFT], page); + } + } + + if ( (mmu = init_mmu_updates(xc_handle, dom)) == NULL ) + goto error_out; + + /* First allocate page for page dir. */ + ppt_alloc = (vpt_start - image_info->load_addr) >> PAGE_SHIFT; + l2tab = page_array[ppt_alloc++] << PAGE_SHIFT; + ctxt->pt_base = l2tab; + + /* Initialise the page tables. */ + if ( (vl2tab = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, + PROT_READ|PROT_WRITE, + l2tab >> PAGE_SHIFT)) == NULL ) + goto error_out; + memset(vl2tab, 0, PAGE_SIZE); + vl2e = &vl2tab[l2_table_offset(image_info->load_addr)]; + for ( count = 0; count < ((v_end-image_info->load_addr)>>PAGE_SHIFT); count++ ) + { + if ( ((unsigned long)vl1e & (PAGE_SIZE-1)) == 0 ) + { + l1tab = page_array[ppt_alloc++] << PAGE_SHIFT; + if ( vl1tab != NULL ) + munmap(vl1tab, PAGE_SIZE); + if ( (vl1tab = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, + PROT_READ|PROT_WRITE, + l1tab >> PAGE_SHIFT)) == NULL ) + { + munmap(vl2tab, PAGE_SIZE); + goto error_out; + } + memset(vl1tab, 0, PAGE_SIZE); + vl1e = &vl1tab[l1_table_offset(image_info->load_addr + (count<<PAGE_SHIFT))]; + *vl2e++ = l1tab | L2_PROT; + } + + *vl1e = (page_array[count] << PAGE_SHIFT) | L1_PROT; + if ( (count >= ((vpt_start-image_info->load_addr)>>PAGE_SHIFT)) && + (count < ((vpt_end -image_info->load_addr)>>PAGE_SHIFT)) ) + *vl1e &= ~_PAGE_RW; + vl1e++; + } + munmap(vl1tab, PAGE_SIZE); + munmap(vl2tab, PAGE_SIZE); + + /* Write the phys->machine and machine->phys table entries. */ + physmap_pfn = (vphysmap_start - image_info->load_addr) >> PAGE_SHIFT; + physmap = physmap_e = xc_map_foreign_range( + xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE, + page_array[physmap_pfn++]); + for ( count = 0; count < nr_pages; count++ ) + { + if ( add_mmu_update(xc_handle, mmu, + (page_array[count] << PAGE_SHIFT) | + MMU_MACHPHYS_UPDATE, count) ) + { + munmap(physmap, PAGE_SIZE); + goto error_out; + } + *physmap_e++ = page_array[count]; + if ( ((unsigned long)physmap_e & (PAGE_SIZE-1)) == 0 ) + { + munmap(physmap, PAGE_SIZE); + physmap = physmap_e = xc_map_foreign_range( + xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE, + page_array[physmap_pfn++]); + } + } + munmap(physmap, PAGE_SIZE); + + /* + * Pin down l2tab addr as page dir page - causes hypervisor to provide + * correct protection for the page + */ + if ( pin_table(xc_handle, MMUEXT_PIN_L2_TABLE, l2tab>>PAGE_SHIFT, dom) ) + goto error_out; + + start_info = xc_map_foreign_range( + xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE, + page_array[(vstartinfo_start-image_info->load_addr)>>PAGE_SHIFT]); + memset(start_info, 0, sizeof(*start_info)); + start_info->nr_pages = nr_pages; + start_info->shared_info = shared_info_frame << PAGE_SHIFT; + start_info->flags = flags; + start_info->pt_base = vpt_start; + start_info->nr_pt_frames = nr_pt_pages; + start_info->mfn_list = vphysmap_start; + start_info->domain_controller_evtchn = control_evtchn; + if ( module_len != 0 ) + { + start_info->mod_start = vmodule_start; + start_info->mod_len = module_len; + } + strncpy((char *)start_info->cmd_line, cmdline, MAX_CMDLINE); + start_info->cmd_line[MAX_CMDLINE-1] = ''\0''; + munmap(start_info, PAGE_SIZE); + + /* shared_info page starts its life empty. */ + shared_info = xc_map_foreign_range( + xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE, shared_info_frame); + memset(shared_info, 0, sizeof(shared_info_t)); + /* Mask all upcalls... */ + for ( i = 0; i < MAX_VIRT_CPUS; i++ ) + shared_info->vcpu_data[i].evtchn_upcall_mask = 1; + + shared_info->n_vcpu = vcpus; + printf(" VCPUS: %d\n", shared_info->n_vcpu); + + munmap(shared_info, PAGE_SIZE); + + /* Send the page update requests down to the hypervisor. */ + if ( finish_mmu_updates(xc_handle, mmu) ) + goto error_out; + + free(mmu); + free(page_array); + + *pvsi = vstartinfo_start; + *pvke = image_info->entry_addr; + + return 0; + + error_out: + if ( mmu != NULL ) + free(mmu); + if ( page_array != NULL ) + free(page_array); + return -1; +} + +int xc_reactos_build(int xc_handle, + u32 domid, + const char *image_name, + const char *module_name, + const char *cmdline, + unsigned int control_evtchn, + unsigned long flags, + unsigned int vcpus) +{ + dom0_op_t launch_op, op; + int module_fd = -1; + int rc, i; + vcpu_guest_context_t st_ctxt, *ctxt = &st_ctxt; + unsigned long nr_pages; + char *image = NULL; + unsigned long image_size, module_size=0; + unsigned long vstartinfo_start, vkern_entry; + + if ( (nr_pages = xc_get_tot_pages(xc_handle, domid)) < 0 ) + { + PERROR("Could not find total pages for domain"); + goto error_out; + } + + if ( (image = xc_read_kernel_image(image_name, &image_size)) == NULL ) + goto error_out; + + if ( (module_name != NULL) && (strlen(module_name) != 0) ) + { + if ( (module_fd = open(module_name, O_RDONLY)) < 0 ) + { + PERROR("Could not open the module image"); + goto error_out; + } + + module_size = xc_get_filesz(module_fd); + } + + if ( mlock(&st_ctxt, sizeof(st_ctxt) ) ) + { + PERROR("Unable to mlock ctxt"); + return 1; + } + + op.cmd = DOM0_GETDOMAININFO; + op.u.getdomaininfo.domain = (domid_t)domid; + if ( (do_dom0_op(xc_handle, &op) < 0) || + ((u16)op.u.getdomaininfo.domain != domid) ) + { + PERROR("Could not get info on domain"); + goto error_out; + } + + if ( xc_domain_get_vcpu_context(xc_handle, domid, 0, ctxt) ) + { + PERROR("Could not get vcpu context"); + goto error_out; + } + + if ( !(op.u.getdomaininfo.flags & DOMFLAGS_PAUSED) || + (ctxt->pt_base != 0) ) + { + ERROR("Domain is already constructed"); + goto error_out; + } + + if ( setup_guest(xc_handle, domid, image, image_size, + module_fd, module_size, nr_pages, + &vstartinfo_start, &vkern_entry, + ctxt, cmdline, + op.u.getdomaininfo.shared_info_frame, + control_evtchn, flags, vcpus) < 0 ) + { + ERROR("Error constructing guest OS"); + goto error_out; + } + + if ( module_fd >= 0 ) + close(module_fd); + if ( image != NULL ) + free(image); + + ctxt->flags = 0; + + /* + * Initial register values: + * DS,ES,FS,GS = FLAT_KERNEL_DS + * CS:EIP = FLAT_KERNEL_CS:start_pc + * SS:ESP = FLAT_KERNEL_DS:start_stack + * ESI = start_info + * [EAX,EBX,ECX,EDX,EDI,EBP are zero] + * EFLAGS = IF | 2 (bit 1 is reserved and should always be 1) + */ + ctxt->user_regs.ds = FLAT_KERNEL_DS; + ctxt->user_regs.es = FLAT_KERNEL_DS; + ctxt->user_regs.fs = FLAT_KERNEL_DS; + ctxt->user_regs.gs = FLAT_KERNEL_DS; + ctxt->user_regs.ss = FLAT_KERNEL_DS; + ctxt->user_regs.cs = FLAT_KERNEL_CS; + ctxt->user_regs.eip = vkern_entry; + ctxt->user_regs.esp = vstartinfo_start + 2*PAGE_SIZE; + ctxt->user_regs.esi = vstartinfo_start; + ctxt->user_regs.eflags = 1 << 9; /* Interrupt Enable */ + + /* FPU is set up to default initial state. */ + memset(&ctxt->fpu_ctxt, 0, sizeof(ctxt->fpu_ctxt)); + + /* Virtual IDT is empty at start-of-day. */ + for ( i = 0; i < 256; i++ ) + { + ctxt->trap_ctxt[i].vector = i; + ctxt->trap_ctxt[i].cs = FLAT_KERNEL_CS; + } + + /* No LDT. */ + ctxt->ldt_ents = 0; + + /* Use the default Xen-provided GDT. */ + ctxt->gdt_ents = 0; + + /* Ring 1 stack is the initial stack. */ + ctxt->kernel_ss = FLAT_KERNEL_DS; + ctxt->kernel_sp = vstartinfo_start + 2*PAGE_SIZE; + + /* No debugging. */ + memset(ctxt->debugreg, 0, sizeof(ctxt->debugreg)); + + /* No callback handlers. */ +#if defined(__i386__) + ctxt->event_callback_cs = FLAT_KERNEL_CS; + ctxt->event_callback_eip = 0; + ctxt->failsafe_callback_cs = FLAT_KERNEL_CS; + ctxt->failsafe_callback_eip = 0; +#elif defined(__x86_64__) + ctxt->event_callback_eip = 0; + ctxt->failsafe_callback_eip = 0; + ctxt->syscall_callback_eip = 0; +#endif + + memset( &launch_op, 0, sizeof(launch_op) ); + + launch_op.u.setdomaininfo.domain = (domid_t)domid; + launch_op.u.setdomaininfo.vcpu = 0; + launch_op.u.setdomaininfo.ctxt = ctxt; + + launch_op.cmd = DOM0_SETDOMAININFO; + rc = do_dom0_op(xc_handle, &launch_op); + + return rc; + + error_out: + if ( module_fd >= 0 ) + close(module_fd); + if ( image != NULL ) + free(image); + + return -1; +} + +static int parsereactosimage(char *base, + unsigned long size, + struct xen_reactos_table **table) +{ + unsigned long *probe_ptr; + unsigned probe_index; + unsigned probe_count; + + /* Don''t go outside the image */ + if ( size < sizeof(struct xen_reactos_table) ) + { + ERROR("Image does not have a valid xen_reactos table."); + return -EINVAL; + } + probe_count = size; + /* Restrict to first 8k */ + if ( 8192 < probe_count ) + { + probe_count = 8192; + } + probe_count = (probe_count - sizeof(struct xen_reactos_table)) / + sizeof(unsigned long); + + /* Search for the magic header */ + probe_ptr = (unsigned long *) base; + *table = NULL; + for ( probe_index = 0; probe_index < probe_count; probe_index++ ) + { + if ( XEN_REACTOS_MAGIC3 == *probe_ptr ) + { + *table = (struct xen_reactos_table *) probe_ptr; + /* Checksum correct? */ + if ( 0 == (*table)->magic + (*table)->flags + (*table)->checksum ) + { + break; + } + *table = NULL; + } + probe_ptr++; + } + if ( NULL == *table ) + { + ERROR("Image does not have a valid xen_reactos table."); + return -EINVAL; + } + if ( FLAGS_REQUIRED != ((*table)->flags & FLAGS_MASK) ) + { + ERROR("xen_reactos flags required 0x%08x found 0x%08lx", FLAGS_REQUIRED, + (*table)->flags & FLAGS_MASK); + return -EINVAL; + } + + return 0; +} + +static int +loadreactosimage( + char *image_base, unsigned long image_size, int xch, u32 dom, + unsigned long *parray, struct xen_reactos_table *image_info) +{ + unsigned long size; + char *va; + unsigned long done, chunksz; + + /* Determine image size */ + if ( 0 == image_info->load_end_addr ) + { + size = image_size - (((char *) image_info - image_base) - + (image_info->header_addr - + image_info->load_addr)); + } + else + { + size = image_info->load_end_addr - image_info->load_addr; + } + + /* It''s possible that we need to skip the first part of the image */ + image_base += ((char *)image_info - image_base) - + (image_info->header_addr - image_info->load_addr); + + for ( done = 0; done < size; done += chunksz ) + { + va = xc_map_foreign_range( + xch, dom, PAGE_SIZE, PROT_WRITE, parray[done>>PAGE_SHIFT]); + chunksz = size - done; + if ( chunksz > PAGE_SIZE ) + chunksz = PAGE_SIZE; + memcpy(va, image_base + done, chunksz); + munmap(va, PAGE_SIZE); + } + + if ( 0 != image_info->bss_end_addr && + image_info->load_addr + size < image_info->bss_end_addr ) + { + size = image_info->bss_end_addr - image_info->load_addr; + } + for ( ; done < size; done += chunksz ) + { + va = xc_map_foreign_range( + xch, dom, PAGE_SIZE, PROT_WRITE, parray[done>>PAGE_SHIFT]); + chunksz = size - done; + if ( chunksz > (PAGE_SIZE - (done & (PAGE_SIZE-1))) ) + chunksz = PAGE_SIZE - (done & (PAGE_SIZE-1)); + memset(va + (done & (PAGE_SIZE-1)), 0, chunksz); + munmap(va, PAGE_SIZE); + } + + return 0; +} _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Christian Limpach
2005-Jun-02 22:34 UTC
Re: [Xen-devel] [PATCH] domain builder for ReactOS
On 6/2/05, Ge van Geldorp <gvg@reactos.com> wrote:> As announced earlier (http://lists.xensource.com/archives/html/xen-devel/2005-03/msg01160.html) > I''m working on porting ReactOS to Xen. The first stage, getting our bootloader > running, is complete now. Progress report and a screenshot on > http://reactos.com/wiki/index.php/Xen_port > > To start ReactOS in a Xen domain, a ReactOS domain builder is needed. Patches > to implement that are included below.I''m not too keen on this approach: we try to keep the number of domain builders small. Ideally we''d only want one builder for paravirtualized guests and one for hardware assisted guests. For paravirtualized guests, this is the mis-named "linux builder". We have a plan9 specific builder because plan9 uses a.out, but I think it would be preferable to support additional file format loaders within the linux builder. Why do you think that you need a different builder? Especially since you''re going to use a bootloader anyway, your actual kernel image file can be of whatever format you like... If your main/only struggle is with the ELF format, then please consider adding support for additional loaders in the existing builder. christian _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
> From: Christian Limpach > > Why do you think that you need a different builder? > Especially since you''re going to use a bootloader anyway, > your actual kernel image file can be of whatever format you > like... If your main/only struggle is with the ELF format, > then please consider adding support for additional loaders in > the existing builder.Yes, the reason for the different builder is that our bootloader is not in ELF format. I''m not sure the linux ELF loader and my loader are going to have much code in common, which is why I opted for a different builder. However, I don''t see major problems adding the code to the Linux builder, so if that''s what you prefer, that''s how I''ll do it. Gé van Geldorp. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Christian Limpach
2005-Jun-02 23:08 UTC
Re: [Xen-devel] [PATCH] domain builder for ReactOS
On Fri, Jun 03, 2005 at 12:51:09AM +0200, Ge van Geldorp wrote:> > From: Christian Limpach > > > > Why do you think that you need a different builder? > > Especially since you''re going to use a bootloader anyway, > > your actual kernel image file can be of whatever format you > > like... If your main/only struggle is with the ELF format, > > then please consider adding support for additional loaders in > > the existing builder. > > Yes, the reason for the different builder is that our bootloader is not in > ELF format.Well, your webpage says that right now you''re building your loader as an ELF image and I guess use the linux builder? Can''t you stick with that? Even if it''s inconvenient to only being able to build the loader on Linux, how often does the loader need to be rebuilt?> I''m not sure the linux ELF loader and my loader are going to > have much code in common, which is why I opted for a different builder.The elf loading functions in xc_linux_build make up less than half of the file -- ideally you should be able to use the setup_guest and xc_linux_build functions without too many changes. I''d suggest that you move the elf loading functions into a separate file (xc_load_elf.c) and put your load functions in a different file. You''ll also need to add a probe function to identify the type of the image, which could then return a pointer to a struct with function pointers to parseelfimage/loadelfimage in the elf case and then call these through the pointers.> However, I don''t see major problems adding the code to the Linux builder, so > if that''s what you prefer, that''s how I''ll do it.The other question is whether it makes much sense to add a loader/builder before there''s a kernel? christian _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
> From: Christian Limpach > > Well, your webpage says that right now you''re building your > loader as an ELF image and I guess use the linux builder?Correct.> Can''t you stick with that? > Even if it''s inconvenient to only being able to build the > loader on Linux, how often does the loader need to be rebuilt?No, building as an ELF image is only possible as long as I''m using a branch for development. Most of our developers are building on Windows, not on Linux, so the question "how often" becomes kind of moot. They would simply be unable to build the bootloader, ever. We see the bootloader as an integrated part of our project, so that would not be acceptable. Perhaps a little more background on the bootloader and why we need it: it is normally built as a binary (unstructured) image, which is loaded by the partition bootsector. It is also multiboot-compliant, so another way to load it is using Grub. The bootloader will load the kernel and the infamous registry. The registry contains (amongst a lot of other stuff) a list of boot-time drivers. The bootloader will parse the registry and load the required drivers. It will then do some hardware detection and transfer control to the kernel. The tricky part is that it''s the bootloader which determines which drivers to load. I estimate that about 80% of our users (testers really) are not using Grub but are using the bootsector method of getting the loader into memory. This implies the binary format, there simply isn''t enough space in the bootsector to parse ELF headers. So we''re stuck with the binary format.> The other question is whether it makes much sense to add a > loader/builder before there''s a kernel?The reason I''m submitting a Xen patch at this point is that I''ve completed a well-defined task now (getting the bootloader to run under Xen) and it''s a good point to merge the development branch into the main trunk. However, I do need to get rid of the ELF format to do that. And that in turn means I can no longer use the current linux builder/loader in Xen. Ge van Geldorp. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Jacob Gorm Hansen
2005-Jun-05 23:31 UTC
Re: [Xen-devel] [PATCH] domain builder for ReactOS
Ge van Geldorp wrote:> The reason I''m submitting a Xen patch at this point is that I''ve completed a > well-defined task now (getting the bootloader to run under Xen) and it''s a > good point to merge the development branch into the main trunk. However, I > do need to get rid of the ELF format to do that. And that in turn means I > can no longer use the current linux builder/loader in Xen.Xen domUs need to have a bios, so we do not need to have domain-specific stuff like ELF-parsing in dom0. I will post to source to my ''mstrap'' attempt at this tomorrow for people to comment on. Jacob _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Christian Limpach
2005-Jun-06 08:49 UTC
Re: [Xen-devel] [PATCH] domain builder for ReactOS
On 6/6/05, Jacob Gorm Hansen <jacobg@diku.dk> wrote:> Xen domUs need to have a bios, so we do not need to have domain-specific > stuff like ELF-parsing in dom0. I will post to source to my ''mstrap'' > attempt at this tomorrow for people to comment on.This is an option, but definitely not appropriate for every environment. christian _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Jacob Gorm Hansen
2005-Jun-06 09:21 UTC
Re: [Xen-devel] [PATCH] domain builder for ReactOS
Christian Limpach wrote:> On 6/6/05, Jacob Gorm Hansen <jacobg@diku.dk> wrote: > >>Xen domUs need to have a bios, so we do not need to have domain-specific >>stuff like ELF-parsing in dom0. I will post to source to my ''mstrap'' >>attempt at this tomorrow for people to comment on. > > > This is an option, but definitely not appropriate for every environment.Seems to work well for VMWare. Could you give an example of an environment where this would not be appropriate? Jacob _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Christian Limpach
2005-Jun-06 18:33 UTC
Re: [Xen-devel] [PATCH] domain builder for ReactOS
On 6/6/05, Jacob Gorm Hansen <jacobg@diku.dk> wrote:> Christian Limpach wrote: > > On 6/6/05, Jacob Gorm Hansen <jacobg@diku.dk> wrote: > > > >>Xen domUs need to have a bios, so we do not need to have domain-specific > >>stuff like ELF-parsing in dom0. I will post to source to my ''mstrap'' > >>attempt at this tomorrow for people to comment on. > > > > > > This is an option, but definitely not appropriate for every environment. > > Seems to work well for VMWare. Could you give an example of an > environment where this would not be appropriate?The model you suggest requires you to install the kernel such that it is accessible from within the guest environment. This is not always desirable nor practical. [some off-list exchange skipped] I like the loader + "ramdisk" solution. Can you reuse the code we have in the builder now to load elf, elf w/ symtab and bin images? Isn''t the development environment for the loader too hostile? I implemented a similar loader for NetBSD when the linux dom0 loader didn''t support elf yet -- it was quite tedious to relocate stuff in memory so that the layout would be the same for the loader and the image it would execute... christian _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Jacob Gorm Hansen
2005-Jun-06 18:44 UTC
Re: [Xen-devel] [PATCH] domain builder for ReactOS
Christian Limpach wrote:> On 6/6/05, Jacob Gorm Hansen <jacobg@diku.dk> wrote: > > The model you suggest requires you to install the kernel such that it > is accessible from within the guest environment. This is not always > desirable nor practical. > [some off-list exchange skipped] > I like the loader + "ramdisk" solution. Can you reuse the code we > have in the builder now to load elf, elf w/ symtab and bin images? > Isn''t the development environment for the loader too hostile? I > implemented a similar loader for NetBSD when the linux dom0 loader > didn''t support elf yet -- it was quite tedious to relocate stuff in > memory so that the layout would be the same for the loader and the > image it would execute...My code is a port of the loader as per last autumn (I forward-ported my old code to the new Xen), so right now it only loads ELF, I guess I could work in later changes as well. You are right that developing stage2 loaders is harder than writing Linux binaries, though with a serial cable things are not too bad. The worst part is turning over control to the OS itself, because you need a temporary overlap of address spaces, and you would like to free some of the original domain memory, or at least hand it over the OS. Jacob _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel