All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] domain builder for ReactOS
@ 2005-06-02 21:51 Ge van Geldorp
  2005-06-02 22:34 ` Christian Limpach
  0 siblings, 1 reply; 10+ messages in thread
From: Ge van Geldorp @ 2005-06-02 21:51 UTC (permalink / raw)
  To: xen-devel

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;
+}

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] domain builder for ReactOS
  2005-06-02 21:51 [PATCH] domain builder for ReactOS Ge van Geldorp
@ 2005-06-02 22:34 ` Christian Limpach
  2005-06-02 22:51   ` Ge van Geldorp
  0 siblings, 1 reply; 10+ messages in thread
From: Christian Limpach @ 2005-06-02 22:34 UTC (permalink / raw)
  To: Ge van Geldorp; +Cc: xen-devel

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

^ permalink raw reply	[flat|nested] 10+ messages in thread

* RE: [PATCH] domain builder for ReactOS
  2005-06-02 22:34 ` Christian Limpach
@ 2005-06-02 22:51   ` Ge van Geldorp
  2005-06-02 23:08     ` Christian Limpach
  0 siblings, 1 reply; 10+ messages in thread
From: Ge van Geldorp @ 2005-06-02 22:51 UTC (permalink / raw)
  To: Christian.Limpach; +Cc: 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.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] domain builder for ReactOS
  2005-06-02 22:51   ` Ge van Geldorp
@ 2005-06-02 23:08     ` Christian Limpach
  2005-06-02 23:53       ` Ge van Geldorp
  0 siblings, 1 reply; 10+ messages in thread
From: Christian Limpach @ 2005-06-02 23:08 UTC (permalink / raw)
  To: Ge van Geldorp; +Cc: xen-devel

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

^ permalink raw reply	[flat|nested] 10+ messages in thread

* RE: [PATCH] domain builder for ReactOS
  2005-06-02 23:08     ` Christian Limpach
@ 2005-06-02 23:53       ` Ge van Geldorp
  2005-06-05 23:31         ` Jacob Gorm Hansen
  0 siblings, 1 reply; 10+ messages in thread
From: Ge van Geldorp @ 2005-06-02 23:53 UTC (permalink / raw)
  To: 'Christian Limpach'; +Cc: 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.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] domain builder for ReactOS
  2005-06-02 23:53       ` Ge van Geldorp
@ 2005-06-05 23:31         ` Jacob Gorm Hansen
  2005-06-06  8:49           ` Christian Limpach
  0 siblings, 1 reply; 10+ messages in thread
From: Jacob Gorm Hansen @ 2005-06-05 23:31 UTC (permalink / raw)
  To: Ge van Geldorp; +Cc: xen-devel, 'Christian Limpach'

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

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] domain builder for ReactOS
  2005-06-05 23:31         ` Jacob Gorm Hansen
@ 2005-06-06  8:49           ` Christian Limpach
  2005-06-06  9:21             ` Jacob Gorm Hansen
  0 siblings, 1 reply; 10+ messages in thread
From: Christian Limpach @ 2005-06-06  8:49 UTC (permalink / raw)
  To: Jacob Gorm Hansen; +Cc: Ge van Geldorp, xen-devel

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

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] domain builder for ReactOS
  2005-06-06  8:49           ` Christian Limpach
@ 2005-06-06  9:21             ` Jacob Gorm Hansen
  2005-06-06 18:33               ` Christian Limpach
  0 siblings, 1 reply; 10+ messages in thread
From: Jacob Gorm Hansen @ 2005-06-06  9:21 UTC (permalink / raw)
  To: Christian.Limpach; +Cc: xen-devel

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

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] domain builder for ReactOS
  2005-06-06  9:21             ` Jacob Gorm Hansen
@ 2005-06-06 18:33               ` Christian Limpach
  2005-06-06 18:44                 ` Jacob Gorm Hansen
  0 siblings, 1 reply; 10+ messages in thread
From: Christian Limpach @ 2005-06-06 18:33 UTC (permalink / raw)
  To: Jacob Gorm Hansen; +Cc: xen-devel

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

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] domain builder for ReactOS
  2005-06-06 18:33               ` Christian Limpach
@ 2005-06-06 18:44                 ` Jacob Gorm Hansen
  0 siblings, 0 replies; 10+ messages in thread
From: Jacob Gorm Hansen @ 2005-06-06 18:44 UTC (permalink / raw)
  To: Christian.Limpach; +Cc: xen-devel

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

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2005-06-06 18:44 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-06-02 21:51 [PATCH] domain builder for ReactOS Ge van Geldorp
2005-06-02 22:34 ` Christian Limpach
2005-06-02 22:51   ` Ge van Geldorp
2005-06-02 23:08     ` Christian Limpach
2005-06-02 23:53       ` Ge van Geldorp
2005-06-05 23:31         ` Jacob Gorm Hansen
2005-06-06  8:49           ` Christian Limpach
2005-06-06  9:21             ` Jacob Gorm Hansen
2005-06-06 18:33               ` Christian Limpach
2005-06-06 18:44                 ` Jacob Gorm Hansen

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.