ia64/xen-unstable

changeset 1714:376d3fcd1ceb

bitkeeper revision 1.1041.1.22 (40ec4148dQ8Asmho3L6_MWS2lfI5JQ)

Move machdep stuff from domain.c to arch/x86/domain.c
author djm@kirby.fc.hp.com
date Wed Jul 07 18:30:32 2004 +0000 (2004-07-07)
parents b1477b06e393
children 15cbfb844361
files xen/arch/x86/domain.c xen/common/domain.c xen/include/asm-x86/config.h xen/include/xen/sched.h
line diff
     1.1 --- a/xen/arch/x86/domain.c	Wed Jul 07 16:59:37 2004 +0000
     1.2 +++ b/xen/arch/x86/domain.c	Wed Jul 07 18:30:32 2004 +0000
     1.3 @@ -24,6 +24,28 @@
     1.4  #include <xen/irq.h>
     1.5  #include <xen/event.h>
     1.6  #include <xen/shadow.h>
     1.7 +#include <xen/console.h>
     1.8 +
     1.9 +#include <xen/elf.h>
    1.10 +
    1.11 +extern int loadelfimage(char *);
    1.12 +extern int readelfimage_base_and_size(char *, unsigned long,
    1.13 +                  unsigned long *, unsigned long *, unsigned long *);
    1.14 +
    1.15 +#if !defined(CONFIG_X86_64BITMODE)
    1.16 +/* No ring-3 access in initial page tables. */
    1.17 +#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED)
    1.18 +#else
    1.19 +/* Allow ring-3 access in long mode as guest cannot use ring 1. */
    1.20 +#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_USER)
    1.21 +#endif
    1.22 +#define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
    1.23 +#define L3_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
    1.24 +#define L4_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
    1.25 +
    1.26 +#define round_pgup(_p)    (((_p)+(PAGE_SIZE-1))&PAGE_MASK)
    1.27 +#define round_pgdown(_p)  ((_p)&PAGE_MASK)
    1.28 +
    1.29  
    1.30  int hlt_counter;
    1.31  
    1.32 @@ -422,3 +444,375 @@ long do_iopl(domid_t domain, unsigned in
    1.33  }
    1.34  
    1.35  #endif
    1.36 +
    1.37 +void domain_relinquish_memory(struct domain *d)
    1.38 +{
    1.39 +    struct list_head *ent, *tmp;
    1.40 +    struct pfn_info  *page;
    1.41 +    unsigned long     x, y;
    1.42 +
    1.43 +    /*
    1.44 +     * If we're executing the idle task then we may still be running over the 
    1.45 +     * dead domain's page tables. We'd better fix that before freeing them!
    1.46 +     */
    1.47 +    if ( is_idle_task(current) )
    1.48 +        write_ptbase(&current->mm);
    1.49 +
    1.50 +    /* Exit shadow mode before deconstructing final guest page table. */
    1.51 +    if ( shadow_mode(d) )
    1.52 +        shadow_mode_disable(d);
    1.53 +
    1.54 +    /* Drop the in-use reference to the page-table base. */
    1.55 +    if ( pagetable_val(d->mm.pagetable) != 0 )
    1.56 +        put_page_and_type(&frame_table[pagetable_val(d->mm.pagetable) >>
    1.57 +                                      PAGE_SHIFT]);
    1.58 +
    1.59 +    /* Relinquish Xen-heap pages. Currently this can only be 'shared_info'. */
    1.60 +    page = virt_to_page(d->shared_info);
    1.61 +    if ( test_and_clear_bit(_PGC_allocated, &page->count_and_flags) )
    1.62 +        put_page(page);
    1.63 +
    1.64 +    /* Relinquish all pages on the domain's allocation list. */
    1.65 +    spin_lock_recursive(&d->page_alloc_lock); /* may enter free_domain_page */
    1.66 +    list_for_each_safe ( ent, tmp, &d->page_list )
    1.67 +    {
    1.68 +        page = list_entry(ent, struct pfn_info, list);
    1.69 +
    1.70 +        if ( test_and_clear_bit(_PGC_guest_pinned, &page->count_and_flags) )
    1.71 +            put_page_and_type(page);
    1.72 +
    1.73 +        if ( test_and_clear_bit(_PGC_allocated, &page->count_and_flags) )
    1.74 +            put_page(page);
    1.75 +
    1.76 +        /*
    1.77 +         * Forcibly invalidate base page tables at this point to break circular
    1.78 +         * 'linear page table' references. This is okay because MMU structures
    1.79 +         * are not shared across domains and this domain is now dead. Thus base
    1.80 +         * tables are not in use so a non-zero count means circular reference.
    1.81 +         */
    1.82 +        y = page->type_and_flags;
    1.83 +        do {
    1.84 +            x = y;
    1.85 +            if ( likely((x & (PGT_type_mask|PGT_validated)) != 
    1.86 +                        (PGT_base_page_table|PGT_validated)) )
    1.87 +                break;
    1.88 +            y = cmpxchg(&page->type_and_flags, x, x & ~PGT_validated);
    1.89 +            if ( likely(y == x) )
    1.90 +                free_page_type(page, PGT_base_page_table);
    1.91 +        }
    1.92 +        while ( unlikely(y != x) );
    1.93 +    }
    1.94 +    spin_unlock_recursive(&d->page_alloc_lock);
    1.95 +}
    1.96 +
    1.97 +
    1.98 +int construct_dom0(struct domain *p, 
    1.99 +                   unsigned long alloc_start,
   1.100 +                   unsigned long alloc_end,
   1.101 +                   char *image_start, unsigned long image_len, 
   1.102 +                   char *initrd_start, unsigned long initrd_len,
   1.103 +                   char *cmdline)
   1.104 +{
   1.105 +    char *dst;
   1.106 +    int i, rc;
   1.107 +    unsigned long pfn, mfn;
   1.108 +    unsigned long nr_pages = (alloc_end - alloc_start) >> PAGE_SHIFT;
   1.109 +    unsigned long nr_pt_pages;
   1.110 +    unsigned long count;
   1.111 +    l2_pgentry_t *l2tab, *l2start;
   1.112 +    l1_pgentry_t *l1tab = NULL, *l1start = NULL;
   1.113 +    struct pfn_info *page = NULL;
   1.114 +    start_info_t *si;
   1.115 +
   1.116 +    /*
   1.117 +     * This fully describes the memory layout of the initial domain. All 
   1.118 +     * *_start address are page-aligned, except v_start (and v_end) which are 
   1.119 +     * superpage-aligned.
   1.120 +     */
   1.121 +    unsigned long v_start;
   1.122 +    unsigned long vkern_start;
   1.123 +    unsigned long vkern_entry;
   1.124 +    unsigned long vkern_end;
   1.125 +    unsigned long vinitrd_start;
   1.126 +    unsigned long vinitrd_end;
   1.127 +    unsigned long vphysmap_start;
   1.128 +    unsigned long vphysmap_end;
   1.129 +    unsigned long vstartinfo_start;
   1.130 +    unsigned long vstartinfo_end;
   1.131 +    unsigned long vstack_start;
   1.132 +    unsigned long vstack_end;
   1.133 +    unsigned long vpt_start;
   1.134 +    unsigned long vpt_end;
   1.135 +    unsigned long v_end;
   1.136 +
   1.137 +    /* Machine address of next candidate page-table page. */
   1.138 +    unsigned long mpt_alloc;
   1.139 +
   1.140 +    extern void physdev_init_dom0(struct domain *);
   1.141 +
   1.142 +    /* Sanity! */
   1.143 +    if ( p->domain != 0 ) 
   1.144 +        BUG();
   1.145 +    if ( test_bit(DF_CONSTRUCTED, &p->flags) ) 
   1.146 +        BUG();
   1.147 +
   1.148 +    printk("*** LOADING DOMAIN 0 ***\n");
   1.149 +
   1.150 +    /*
   1.151 +     * This is all a bit grim. We've moved the modules to the "safe" physical 
   1.152 +     * memory region above MAP_DIRECTMAP_ADDRESS (48MB). Later in this 
   1.153 +     * routine we're going to copy it down into the region that's actually 
   1.154 +     * been allocated to domain 0. This is highly likely to be overlapping, so 
   1.155 +     * we use a forward copy.
   1.156 +     * 
   1.157 +     * MAP_DIRECTMAP_ADDRESS should be safe. The worst case is a machine with 
   1.158 +     * 4GB and lots of network/disk cards that allocate loads of buffers. 
   1.159 +     * We'll have to revisit this if we ever support PAE (64GB).
   1.160 +     */
   1.161 +
   1.162 +    rc = readelfimage_base_and_size(image_start, image_len,
   1.163 +                                    &vkern_start, &vkern_end, &vkern_entry);
   1.164 +    if ( rc != 0 )
   1.165 +        return rc;
   1.166 +
   1.167 +    /*
   1.168 +     * Why do we need this? The number of page-table frames depends on the 
   1.169 +     * size of the bootstrap address space. But the size of the address space 
   1.170 +     * depends on the number of page-table frames (since each one is mapped 
   1.171 +     * read-only). We have a pair of simultaneous equations in two unknowns, 
   1.172 +     * which we solve by exhaustive search.
   1.173 +     */
   1.174 +    for ( nr_pt_pages = 2; ; nr_pt_pages++ )
   1.175 +    {
   1.176 +        v_start          = vkern_start & ~((1<<22)-1);
   1.177 +        vinitrd_start    = round_pgup(vkern_end);
   1.178 +        vinitrd_end      = vinitrd_start + initrd_len;
   1.179 +        vphysmap_start   = round_pgup(vinitrd_end);
   1.180 +        vphysmap_end     = vphysmap_start + (nr_pages * sizeof(unsigned long));
   1.181 +        vpt_start        = round_pgup(vphysmap_end);
   1.182 +        vpt_end          = vpt_start + (nr_pt_pages * PAGE_SIZE);
   1.183 +        vstartinfo_start = vpt_end;
   1.184 +        vstartinfo_end   = vstartinfo_start + PAGE_SIZE;
   1.185 +        vstack_start     = vstartinfo_end;
   1.186 +        vstack_end       = vstack_start + PAGE_SIZE;
   1.187 +        v_end            = (vstack_end + (1<<22)-1) & ~((1<<22)-1);
   1.188 +        if ( (v_end - vstack_end) < (512 << 10) )
   1.189 +            v_end += 1 << 22; /* Add extra 4MB to get >= 512kB padding. */
   1.190 +        if ( (((v_end - v_start) >> L2_PAGETABLE_SHIFT) + 1) <= nr_pt_pages )
   1.191 +            break;
   1.192 +    }
   1.193 +
   1.194 +    if ( (v_end - v_start) > (nr_pages * PAGE_SIZE) )
   1.195 +    {
   1.196 +        printk("Initial guest OS requires too much space\n"
   1.197 +               "(%luMB is greater than %luMB limit)\n",
   1.198 +               (v_end-v_start)>>20, (nr_pages<<PAGE_SHIFT)>>20);
   1.199 +        return -ENOMEM;
   1.200 +    }
   1.201 +
   1.202 +    printk("PHYSICAL MEMORY ARRANGEMENT:\n"
   1.203 +           " Kernel image:  %p->%p\n"
   1.204 +           " Initrd image:  %p->%p\n"
   1.205 +           " Dom0 alloc.:   %08lx->%08lx\n",
   1.206 +           image_start, image_start + image_len,
   1.207 +           initrd_start, initrd_start + initrd_len,
   1.208 +           alloc_start, alloc_end);
   1.209 +    printk("VIRTUAL MEMORY ARRANGEMENT:\n"
   1.210 +           " Loaded kernel: %08lx->%08lx\n"
   1.211 +           " Init. ramdisk: %08lx->%08lx\n"
   1.212 +           " Phys-Mach map: %08lx->%08lx\n"
   1.213 +           " Page tables:   %08lx->%08lx\n"
   1.214 +           " Start info:    %08lx->%08lx\n"
   1.215 +           " Boot stack:    %08lx->%08lx\n"
   1.216 +           " TOTAL:         %08lx->%08lx\n",
   1.217 +           vkern_start, vkern_end, 
   1.218 +           vinitrd_start, vinitrd_end,
   1.219 +           vphysmap_start, vphysmap_end,
   1.220 +           vpt_start, vpt_end,
   1.221 +           vstartinfo_start, vstartinfo_end,
   1.222 +           vstack_start, vstack_end,
   1.223 +           v_start, v_end);
   1.224 +    printk(" ENTRY ADDRESS: %08lx\n", vkern_entry);
   1.225 +
   1.226 +    /*
   1.227 +     * Protect the lowest 1GB of memory. We use a temporary mapping there
   1.228 +     * from which we copy the kernel and ramdisk images.
   1.229 +     */
   1.230 +    if ( v_start < (1<<30) )
   1.231 +    {
   1.232 +        printk("Initial loading isn't allowed to lowest 1GB of memory.\n");
   1.233 +        return -EINVAL;
   1.234 +    }
   1.235 +
   1.236 +    /* Construct a frame-allocation list for the initial domain. */
   1.237 +    for ( mfn = (alloc_start>>PAGE_SHIFT); 
   1.238 +          mfn < (alloc_end>>PAGE_SHIFT); 
   1.239 +          mfn++ )
   1.240 +    {
   1.241 +        page = &frame_table[mfn];
   1.242 +        page->u.domain        = p;
   1.243 +        page->type_and_flags  = 0;
   1.244 +        page->count_and_flags = PGC_allocated | 1;
   1.245 +        list_add_tail(&page->list, &p->page_list);
   1.246 +        p->tot_pages++; p->max_pages++;
   1.247 +    }
   1.248 +
   1.249 +    mpt_alloc = (vpt_start - v_start) + alloc_start;
   1.250 +
   1.251 +    SET_GDT_ENTRIES(p, DEFAULT_GDT_ENTRIES);
   1.252 +    SET_GDT_ADDRESS(p, DEFAULT_GDT_ADDRESS);
   1.253 +
   1.254 +    /*
   1.255 +     * We're basically forcing default RPLs to 1, so that our "what privilege
   1.256 +     * level are we returning to?" logic works.
   1.257 +     */
   1.258 +    p->failsafe_selector = FLAT_GUESTOS_CS;
   1.259 +    p->event_selector    = FLAT_GUESTOS_CS;
   1.260 +    p->thread.guestos_ss = FLAT_GUESTOS_DS;
   1.261 +    for ( i = 0; i < 256; i++ ) 
   1.262 +        p->thread.traps[i].cs = FLAT_GUESTOS_CS;
   1.263 +
   1.264 +    /* WARNING: The new domain must have its 'processor' field filled in! */
   1.265 +    l2start = l2tab = (l2_pgentry_t *)mpt_alloc; mpt_alloc += PAGE_SIZE;
   1.266 +    memcpy(l2tab, &idle_pg_table[0], PAGE_SIZE);
   1.267 +    l2tab[LINEAR_PT_VIRT_START >> L2_PAGETABLE_SHIFT] =
   1.268 +        mk_l2_pgentry((unsigned long)l2start | __PAGE_HYPERVISOR);
   1.269 +    l2tab[PERDOMAIN_VIRT_START >> L2_PAGETABLE_SHIFT] =
   1.270 +        mk_l2_pgentry(__pa(p->mm.perdomain_pt) | __PAGE_HYPERVISOR);
   1.271 +    p->mm.pagetable = mk_pagetable((unsigned long)l2start);
   1.272 +
   1.273 +    l2tab += l2_table_offset(v_start);
   1.274 +    mfn = alloc_start >> PAGE_SHIFT;
   1.275 +    for ( count = 0; count < ((v_end-v_start)>>PAGE_SHIFT); count++ )
   1.276 +    {
   1.277 +        if ( !((unsigned long)l1tab & (PAGE_SIZE-1)) )
   1.278 +        {
   1.279 +            l1start = l1tab = (l1_pgentry_t *)mpt_alloc; 
   1.280 +            mpt_alloc += PAGE_SIZE;
   1.281 +            *l2tab++ = mk_l2_pgentry((unsigned long)l1start | L2_PROT);
   1.282 +            clear_page(l1tab);
   1.283 +        }
   1.284 +        *l1tab++ = mk_l1_pgentry((mfn << PAGE_SHIFT) | L1_PROT);
   1.285 +        
   1.286 +        page = &frame_table[mfn];
   1.287 +        set_bit(_PGC_tlb_flush_on_type_change, &page->count_and_flags);
   1.288 +        if ( !get_page_and_type(page, p, PGT_writeable_page) )
   1.289 +            BUG();
   1.290 +
   1.291 +        mfn++;
   1.292 +    }
   1.293 +
   1.294 +    /* Pages that are part of page tables must be read only. */
   1.295 +    l2tab = l2start + l2_table_offset(vpt_start);
   1.296 +    l1start = l1tab = (l1_pgentry_t *)l2_pgentry_to_phys(*l2tab);
   1.297 +    l1tab += l1_table_offset(vpt_start);
   1.298 +    l2tab++;
   1.299 +    for ( count = 0; count < nr_pt_pages; count++ ) 
   1.300 +    {
   1.301 +        *l1tab = mk_l1_pgentry(l1_pgentry_val(*l1tab) & ~_PAGE_RW);
   1.302 +        page = &frame_table[l1_pgentry_to_pagenr(*l1tab)];
   1.303 +        if ( count == 0 )
   1.304 +        {
   1.305 +            page->type_and_flags &= ~PGT_type_mask;
   1.306 +            page->type_and_flags |= PGT_l2_page_table;
   1.307 +            get_page(page, p); /* an extra ref because of readable mapping */
   1.308 +            /* Get another ref to L2 page so that it can be pinned. */
   1.309 +            if ( !get_page_and_type(page, p, PGT_l2_page_table) )
   1.310 +                BUG();
   1.311 +            set_bit(_PGC_guest_pinned, &page->count_and_flags);
   1.312 +        }
   1.313 +        else
   1.314 +        {
   1.315 +            page->type_and_flags &= ~PGT_type_mask;
   1.316 +            page->type_and_flags |= PGT_l1_page_table;
   1.317 +            get_page(page, p); /* an extra ref because of readable mapping */
   1.318 +        }
   1.319 +        l1tab++;
   1.320 +        if( !((unsigned long)l1tab & (PAGE_SIZE - 1)) )
   1.321 +            l1start = l1tab = (l1_pgentry_t *)l2_pgentry_to_phys(*l2tab);
   1.322 +    }
   1.323 +
   1.324 +    /* Set up shared-info area. */
   1.325 +    update_dom_time(p->shared_info);
   1.326 +    p->shared_info->domain_time = 0;
   1.327 +    /* Mask all upcalls... */
   1.328 +    for ( i = 0; i < MAX_VIRT_CPUS; i++ )
   1.329 +        p->shared_info->vcpu_data[i].evtchn_upcall_mask = 1;
   1.330 +
   1.331 +    /* Install the new page tables. */
   1.332 +    __cli();
   1.333 +    write_ptbase(&p->mm);
   1.334 +
   1.335 +    /* Copy the OS image. */
   1.336 +    (void)loadelfimage(image_start);
   1.337 +
   1.338 +    /* Copy the initial ramdisk. */
   1.339 +    if ( initrd_len != 0 )
   1.340 +        memcpy((void *)vinitrd_start, initrd_start, initrd_len);
   1.341 +    
   1.342 +    /* Set up start info area. */
   1.343 +    si = (start_info_t *)vstartinfo_start;
   1.344 +    memset(si, 0, PAGE_SIZE);
   1.345 +    si->nr_pages     = p->tot_pages;
   1.346 +    si->shared_info  = virt_to_phys(p->shared_info);
   1.347 +    si->flags        = SIF_PRIVILEGED | SIF_INITDOMAIN;
   1.348 +    si->pt_base      = vpt_start;
   1.349 +    si->nr_pt_frames = nr_pt_pages;
   1.350 +    si->mfn_list     = vphysmap_start;
   1.351 +
   1.352 +    /* Write the phys->machine and machine->phys table entries. */
   1.353 +    for ( mfn = (alloc_start>>PAGE_SHIFT); 
   1.354 +          mfn < (alloc_end>>PAGE_SHIFT); 
   1.355 +          mfn++ )
   1.356 +    {
   1.357 +        pfn = mfn - (alloc_start>>PAGE_SHIFT);
   1.358 +        ((unsigned long *)vphysmap_start)[pfn] = mfn;
   1.359 +        machine_to_phys_mapping[mfn] = pfn;
   1.360 +    }
   1.361 +
   1.362 +    if ( initrd_len != 0 )
   1.363 +    {
   1.364 +        si->mod_start = vinitrd_start;
   1.365 +        si->mod_len   = initrd_len;
   1.366 +        printk("Initrd len 0x%lx, start at 0x%08lx\n",
   1.367 +               si->mod_len, si->mod_start);
   1.368 +    }
   1.369 +
   1.370 +    dst = si->cmd_line;
   1.371 +    if ( cmdline != NULL )
   1.372 +    {
   1.373 +        for ( i = 0; i < 255; i++ )
   1.374 +        {
   1.375 +            if ( cmdline[i] == '\0' )
   1.376 +                break;
   1.377 +            *dst++ = cmdline[i];
   1.378 +        }
   1.379 +    }
   1.380 +    *dst = '\0';
   1.381 +
   1.382 +    /* Reinstate the caller's page tables. */
   1.383 +    write_ptbase(&current->mm);
   1.384 +    __sti();
   1.385 +
   1.386 +    /* Destroy low mappings - they were only for our convenience. */
   1.387 +    for ( i = 0; i < DOMAIN_ENTRIES_PER_L2_PAGETABLE; i++ )
   1.388 +        if ( l2_pgentry_val(l2start[i]) & _PAGE_PSE )
   1.389 +            l2start[i] = mk_l2_pgentry(0);
   1.390 +    zap_low_mappings(); /* Do the same for the idle page tables. */
   1.391 +    
   1.392 +    /* Give up the VGA console if DOM0 is configured to grab it. */
   1.393 +    console_endboot(strstr(cmdline, "tty0") != NULL);
   1.394 +
   1.395 +    /* DOM0 gets access to everything. */
   1.396 +    physdev_init_dom0(p);
   1.397 +
   1.398 +    set_bit(DF_CONSTRUCTED, &p->flags);
   1.399 +
   1.400 +#if 0 /* XXXXX DO NOT CHECK IN ENABLED !!! (but useful for testing so leave) */
   1.401 +    shadow_mode_enable(&p->mm, SHM_test); 
   1.402 +#endif
   1.403 +
   1.404 +    new_thread(p, vkern_entry, vstack_end, vstartinfo_start);
   1.405 +
   1.406 +    return 0;
   1.407 +}
     2.1 --- a/xen/common/domain.c	Wed Jul 07 16:59:37 2004 +0000
     2.2 +++ b/xen/common/domain.c	Wed Jul 07 18:30:32 2004 +0000
     2.3 @@ -5,48 +5,22 @@
     2.4  #include <xen/errno.h>
     2.5  #include <xen/sched.h>
     2.6  #include <xen/mm.h>
     2.7 -#include <xen/delay.h>
     2.8  #include <xen/event.h>
     2.9  #include <xen/time.h>
    2.10 -#include <xen/shadow.h>
    2.11  #include <xen/console.h>
    2.12  #include <xen/shadow.h>
    2.13 -#include <xen/irq.h>
    2.14 -#include <asm/io.h>
    2.15 -#include <asm/domain_page.h>
    2.16 -#include <asm/flushtlb.h>
    2.17 -#include <asm/i387.h>
    2.18 +#include <xen/elf.h>
    2.19  #include <hypervisor-ifs/dom0_ops.h>
    2.20  
    2.21 -#if defined(__x86_64__)
    2.22 -#define ELFSIZE 64
    2.23 -#else
    2.24 -#define ELFSIZE 32
    2.25 -#endif
    2.26 -#include <xen/elf.h>
    2.27 -
    2.28 -#if !defined(CONFIG_X86_64BITMODE)
    2.29 -/* No ring-3 access in initial page tables. */
    2.30 -#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED)
    2.31 -#else
    2.32 -/* Allow ring-3 access in long mode as guest cannot use ring 1. */
    2.33 -#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_USER)
    2.34 -#endif
    2.35 -#define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
    2.36 -#define L3_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
    2.37 -#define L4_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
    2.38 -
    2.39 -#define round_pgup(_p)    (((_p)+(PAGE_SIZE-1))&PAGE_MASK)
    2.40 -#define round_pgdown(_p)  ((_p)&PAGE_MASK)
    2.41 -
    2.42  /* Both these structures are protected by the tasklist_lock. */
    2.43  rwlock_t tasklist_lock __cacheline_aligned = RW_LOCK_UNLOCKED;
    2.44  struct domain *task_hash[TASK_HASH_SIZE];
    2.45  struct domain *task_list;
    2.46  
    2.47 -void arch_do_createdomain(struct domain *);
    2.48 -void arch_final_setup_guestos(struct domain *, full_execution_context_t *c);
    2.49 -void free_perdomain_pt(struct domain *);
    2.50 +extern void arch_do_createdomain(struct domain *);
    2.51 +extern void arch_final_setup_guestos(struct domain *, full_execution_context_t *c);
    2.52 +extern void free_perdomain_pt(struct domain *);
    2.53 +extern void domain_relinquish_memory(struct domain *d);
    2.54  
    2.55  struct domain *do_createdomain(domid_t dom_id, unsigned int cpu)
    2.56  {
    2.57 @@ -314,68 +288,6 @@ void free_domain_page(struct pfn_info *p
    2.58          put_domain(d);
    2.59  }
    2.60  
    2.61 -
    2.62 -void domain_relinquish_memory(struct domain *d)
    2.63 -{
    2.64 -    struct list_head *ent, *tmp;
    2.65 -    struct pfn_info  *page;
    2.66 -    unsigned long     x, y;
    2.67 -
    2.68 -    /*
    2.69 -     * If we're executing the idle task then we may still be running over the 
    2.70 -     * dead domain's page tables. We'd better fix that before freeing them!
    2.71 -     */
    2.72 -    if ( is_idle_task(current) )
    2.73 -        write_ptbase(&current->mm);
    2.74 -
    2.75 -    /* Exit shadow mode before deconstructing final guest page table. */
    2.76 -    if ( shadow_mode(d) )
    2.77 -        shadow_mode_disable(d);
    2.78 -
    2.79 -    /* Drop the in-use reference to the page-table base. */
    2.80 -    if ( pagetable_val(d->mm.pagetable) != 0 )
    2.81 -        put_page_and_type(&frame_table[pagetable_val(d->mm.pagetable) >>
    2.82 -                                      PAGE_SHIFT]);
    2.83 -
    2.84 -    /* Relinquish Xen-heap pages. Currently this can only be 'shared_info'. */
    2.85 -    page = virt_to_page(d->shared_info);
    2.86 -    if ( test_and_clear_bit(_PGC_allocated, &page->count_and_flags) )
    2.87 -        put_page(page);
    2.88 -
    2.89 -    /* Relinquish all pages on the domain's allocation list. */
    2.90 -    spin_lock_recursive(&d->page_alloc_lock); /* may enter free_domain_page */
    2.91 -    list_for_each_safe ( ent, tmp, &d->page_list )
    2.92 -    {
    2.93 -        page = list_entry(ent, struct pfn_info, list);
    2.94 -
    2.95 -        if ( test_and_clear_bit(_PGC_guest_pinned, &page->count_and_flags) )
    2.96 -            put_page_and_type(page);
    2.97 -
    2.98 -        if ( test_and_clear_bit(_PGC_allocated, &page->count_and_flags) )
    2.99 -            put_page(page);
   2.100 -
   2.101 -        /*
   2.102 -         * Forcibly invalidate base page tables at this point to break circular
   2.103 -         * 'linear page table' references. This is okay because MMU structures
   2.104 -         * are not shared across domains and this domain is now dead. Thus base
   2.105 -         * tables are not in use so a non-zero count means circular reference.
   2.106 -         */
   2.107 -        y = page->type_and_flags;
   2.108 -        do {
   2.109 -            x = y;
   2.110 -            if ( likely((x & (PGT_type_mask|PGT_validated)) != 
   2.111 -                        (PGT_base_page_table|PGT_validated)) )
   2.112 -                break;
   2.113 -            y = cmpxchg(&page->type_and_flags, x, x & ~PGT_validated);
   2.114 -            if ( likely(y == x) )
   2.115 -                free_page_type(page, PGT_base_page_table);
   2.116 -        }
   2.117 -        while ( unlikely(y != x) );
   2.118 -    }
   2.119 -    spin_unlock_recursive(&d->page_alloc_lock);
   2.120 -}
   2.121 -
   2.122 -
   2.123  unsigned int alloc_new_dom_mem(struct domain *d, unsigned int kbytes)
   2.124  {
   2.125      unsigned int alloc_pfns, nr_pages;
   2.126 @@ -492,7 +404,7 @@ static inline int is_loadable_phdr(Elf_P
   2.127              ((phdr->p_flags & (PF_W|PF_X)) != 0));
   2.128  }
   2.129  
   2.130 -static int readelfimage_base_and_size(char *elfbase, 
   2.131 +int readelfimage_base_and_size(char *elfbase, 
   2.132                                        unsigned long elfsize,
   2.133                                        unsigned long *pkernstart,
   2.134                                        unsigned long *pkernend,
   2.135 @@ -581,7 +493,7 @@ static int readelfimage_base_and_size(ch
   2.136      return 0;
   2.137  }
   2.138  
   2.139 -static int loadelfimage(char *elfbase)
   2.140 +int loadelfimage(char *elfbase)
   2.141  {
   2.142      Elf_Ehdr *ehdr = (Elf_Ehdr *)elfbase;
   2.143      Elf_Phdr *phdr;
   2.144 @@ -602,314 +514,3 @@ static int loadelfimage(char *elfbase)
   2.145  
   2.146      return 0;
   2.147  }
   2.148 -
   2.149 -int construct_dom0(struct domain *p, 
   2.150 -                   unsigned long alloc_start,
   2.151 -                   unsigned long alloc_end,
   2.152 -                   char *image_start, unsigned long image_len, 
   2.153 -                   char *initrd_start, unsigned long initrd_len,
   2.154 -                   char *cmdline)
   2.155 -{
   2.156 -    char *dst;
   2.157 -    int i, rc;
   2.158 -    unsigned long pfn, mfn;
   2.159 -    unsigned long nr_pages = (alloc_end - alloc_start) >> PAGE_SHIFT;
   2.160 -    unsigned long nr_pt_pages;
   2.161 -    unsigned long count;
   2.162 -    l2_pgentry_t *l2tab, *l2start;
   2.163 -    l1_pgentry_t *l1tab = NULL, *l1start = NULL;
   2.164 -    struct pfn_info *page = NULL;
   2.165 -    start_info_t *si;
   2.166 -
   2.167 -    /*
   2.168 -     * This fully describes the memory layout of the initial domain. All 
   2.169 -     * *_start address are page-aligned, except v_start (and v_end) which are 
   2.170 -     * superpage-aligned.
   2.171 -     */
   2.172 -    unsigned long v_start;
   2.173 -    unsigned long vkern_start;
   2.174 -    unsigned long vkern_entry;
   2.175 -    unsigned long vkern_end;
   2.176 -    unsigned long vinitrd_start;
   2.177 -    unsigned long vinitrd_end;
   2.178 -    unsigned long vphysmap_start;
   2.179 -    unsigned long vphysmap_end;
   2.180 -    unsigned long vstartinfo_start;
   2.181 -    unsigned long vstartinfo_end;
   2.182 -    unsigned long vstack_start;
   2.183 -    unsigned long vstack_end;
   2.184 -    unsigned long vpt_start;
   2.185 -    unsigned long vpt_end;
   2.186 -    unsigned long v_end;
   2.187 -
   2.188 -    /* Machine address of next candidate page-table page. */
   2.189 -    unsigned long mpt_alloc;
   2.190 -
   2.191 -    extern void physdev_init_dom0(struct domain *);
   2.192 -
   2.193 -    /* Sanity! */
   2.194 -    if ( p->domain != 0 ) 
   2.195 -        BUG();
   2.196 -    if ( test_bit(DF_CONSTRUCTED, &p->flags) ) 
   2.197 -        BUG();
   2.198 -
   2.199 -    printk("*** LOADING DOMAIN 0 ***\n");
   2.200 -
   2.201 -    /*
   2.202 -     * This is all a bit grim. We've moved the modules to the "safe" physical 
   2.203 -     * memory region above MAP_DIRECTMAP_ADDRESS (48MB). Later in this 
   2.204 -     * routine we're going to copy it down into the region that's actually 
   2.205 -     * been allocated to domain 0. This is highly likely to be overlapping, so 
   2.206 -     * we use a forward copy.
   2.207 -     * 
   2.208 -     * MAP_DIRECTMAP_ADDRESS should be safe. The worst case is a machine with 
   2.209 -     * 4GB and lots of network/disk cards that allocate loads of buffers. 
   2.210 -     * We'll have to revisit this if we ever support PAE (64GB).
   2.211 -     */
   2.212 -
   2.213 -    rc = readelfimage_base_and_size(image_start, image_len,
   2.214 -                                    &vkern_start, &vkern_end, &vkern_entry);
   2.215 -    if ( rc != 0 )
   2.216 -        return rc;
   2.217 -
   2.218 -    /*
   2.219 -     * Why do we need this? The number of page-table frames depends on the 
   2.220 -     * size of the bootstrap address space. But the size of the address space 
   2.221 -     * depends on the number of page-table frames (since each one is mapped 
   2.222 -     * read-only). We have a pair of simultaneous equations in two unknowns, 
   2.223 -     * which we solve by exhaustive search.
   2.224 -     */
   2.225 -    for ( nr_pt_pages = 2; ; nr_pt_pages++ )
   2.226 -    {
   2.227 -        v_start          = vkern_start & ~((1<<22)-1);
   2.228 -        vinitrd_start    = round_pgup(vkern_end);
   2.229 -        vinitrd_end      = vinitrd_start + initrd_len;
   2.230 -        vphysmap_start   = round_pgup(vinitrd_end);
   2.231 -        vphysmap_end     = vphysmap_start + (nr_pages * sizeof(unsigned long));
   2.232 -        vpt_start        = round_pgup(vphysmap_end);
   2.233 -        vpt_end          = vpt_start + (nr_pt_pages * PAGE_SIZE);
   2.234 -        vstartinfo_start = vpt_end;
   2.235 -        vstartinfo_end   = vstartinfo_start + PAGE_SIZE;
   2.236 -        vstack_start     = vstartinfo_end;
   2.237 -        vstack_end       = vstack_start + PAGE_SIZE;
   2.238 -        v_end            = (vstack_end + (1<<22)-1) & ~((1<<22)-1);
   2.239 -        if ( (v_end - vstack_end) < (512 << 10) )
   2.240 -            v_end += 1 << 22; /* Add extra 4MB to get >= 512kB padding. */
   2.241 -        if ( (((v_end - v_start) >> L2_PAGETABLE_SHIFT) + 1) <= nr_pt_pages )
   2.242 -            break;
   2.243 -    }
   2.244 -
   2.245 -    if ( (v_end - v_start) > (nr_pages * PAGE_SIZE) )
   2.246 -    {
   2.247 -        printk("Initial guest OS requires too much space\n"
   2.248 -               "(%luMB is greater than %luMB limit)\n",
   2.249 -               (v_end-v_start)>>20, (nr_pages<<PAGE_SHIFT)>>20);
   2.250 -        return -ENOMEM;
   2.251 -    }
   2.252 -
   2.253 -    printk("PHYSICAL MEMORY ARRANGEMENT:\n"
   2.254 -           " Kernel image:  %p->%p\n"
   2.255 -           " Initrd image:  %p->%p\n"
   2.256 -           " Dom0 alloc.:   %08lx->%08lx\n",
   2.257 -           image_start, image_start + image_len,
   2.258 -           initrd_start, initrd_start + initrd_len,
   2.259 -           alloc_start, alloc_end);
   2.260 -    printk("VIRTUAL MEMORY ARRANGEMENT:\n"
   2.261 -           " Loaded kernel: %08lx->%08lx\n"
   2.262 -           " Init. ramdisk: %08lx->%08lx\n"
   2.263 -           " Phys-Mach map: %08lx->%08lx\n"
   2.264 -           " Page tables:   %08lx->%08lx\n"
   2.265 -           " Start info:    %08lx->%08lx\n"
   2.266 -           " Boot stack:    %08lx->%08lx\n"
   2.267 -           " TOTAL:         %08lx->%08lx\n",
   2.268 -           vkern_start, vkern_end, 
   2.269 -           vinitrd_start, vinitrd_end,
   2.270 -           vphysmap_start, vphysmap_end,
   2.271 -           vpt_start, vpt_end,
   2.272 -           vstartinfo_start, vstartinfo_end,
   2.273 -           vstack_start, vstack_end,
   2.274 -           v_start, v_end);
   2.275 -    printk(" ENTRY ADDRESS: %08lx\n", vkern_entry);
   2.276 -
   2.277 -    /*
   2.278 -     * Protect the lowest 1GB of memory. We use a temporary mapping there
   2.279 -     * from which we copy the kernel and ramdisk images.
   2.280 -     */
   2.281 -    if ( v_start < (1<<30) )
   2.282 -    {
   2.283 -        printk("Initial loading isn't allowed to lowest 1GB of memory.\n");
   2.284 -        return -EINVAL;
   2.285 -    }
   2.286 -
   2.287 -    /* Construct a frame-allocation list for the initial domain. */
   2.288 -    for ( mfn = (alloc_start>>PAGE_SHIFT); 
   2.289 -          mfn < (alloc_end>>PAGE_SHIFT); 
   2.290 -          mfn++ )
   2.291 -    {
   2.292 -        page = &frame_table[mfn];
   2.293 -        page->u.domain        = p;
   2.294 -        page->type_and_flags  = 0;
   2.295 -        page->count_and_flags = PGC_allocated | 1;
   2.296 -        list_add_tail(&page->list, &p->page_list);
   2.297 -        p->tot_pages++; p->max_pages++;
   2.298 -    }
   2.299 -
   2.300 -    mpt_alloc = (vpt_start - v_start) + alloc_start;
   2.301 -
   2.302 -    SET_GDT_ENTRIES(p, DEFAULT_GDT_ENTRIES);
   2.303 -    SET_GDT_ADDRESS(p, DEFAULT_GDT_ADDRESS);
   2.304 -
   2.305 -    /*
   2.306 -     * We're basically forcing default RPLs to 1, so that our "what privilege
   2.307 -     * level are we returning to?" logic works.
   2.308 -     */
   2.309 -    p->failsafe_selector = FLAT_GUESTOS_CS;
   2.310 -    p->event_selector    = FLAT_GUESTOS_CS;
   2.311 -    p->thread.guestos_ss = FLAT_GUESTOS_DS;
   2.312 -    for ( i = 0; i < 256; i++ ) 
   2.313 -        p->thread.traps[i].cs = FLAT_GUESTOS_CS;
   2.314 -
   2.315 -    /* WARNING: The new domain must have its 'processor' field filled in! */
   2.316 -    l2start = l2tab = (l2_pgentry_t *)mpt_alloc; mpt_alloc += PAGE_SIZE;
   2.317 -    memcpy(l2tab, &idle_pg_table[0], PAGE_SIZE);
   2.318 -    l2tab[LINEAR_PT_VIRT_START >> L2_PAGETABLE_SHIFT] =
   2.319 -        mk_l2_pgentry((unsigned long)l2start | __PAGE_HYPERVISOR);
   2.320 -    l2tab[PERDOMAIN_VIRT_START >> L2_PAGETABLE_SHIFT] =
   2.321 -        mk_l2_pgentry(__pa(p->mm.perdomain_pt) | __PAGE_HYPERVISOR);
   2.322 -    p->mm.pagetable = mk_pagetable((unsigned long)l2start);
   2.323 -
   2.324 -    l2tab += l2_table_offset(v_start);
   2.325 -    mfn = alloc_start >> PAGE_SHIFT;
   2.326 -    for ( count = 0; count < ((v_end-v_start)>>PAGE_SHIFT); count++ )
   2.327 -    {
   2.328 -        if ( !((unsigned long)l1tab & (PAGE_SIZE-1)) )
   2.329 -        {
   2.330 -            l1start = l1tab = (l1_pgentry_t *)mpt_alloc; 
   2.331 -            mpt_alloc += PAGE_SIZE;
   2.332 -            *l2tab++ = mk_l2_pgentry((unsigned long)l1start | L2_PROT);
   2.333 -            clear_page(l1tab);
   2.334 -        }
   2.335 -        *l1tab++ = mk_l1_pgentry((mfn << PAGE_SHIFT) | L1_PROT);
   2.336 -        
   2.337 -        page = &frame_table[mfn];
   2.338 -        set_bit(_PGC_tlb_flush_on_type_change, &page->count_and_flags);
   2.339 -        if ( !get_page_and_type(page, p, PGT_writeable_page) )
   2.340 -            BUG();
   2.341 -
   2.342 -        mfn++;
   2.343 -    }
   2.344 -
   2.345 -    /* Pages that are part of page tables must be read only. */
   2.346 -    l2tab = l2start + l2_table_offset(vpt_start);
   2.347 -    l1start = l1tab = (l1_pgentry_t *)l2_pgentry_to_phys(*l2tab);
   2.348 -    l1tab += l1_table_offset(vpt_start);
   2.349 -    l2tab++;
   2.350 -    for ( count = 0; count < nr_pt_pages; count++ ) 
   2.351 -    {
   2.352 -        *l1tab = mk_l1_pgentry(l1_pgentry_val(*l1tab) & ~_PAGE_RW);
   2.353 -        page = &frame_table[l1_pgentry_to_pagenr(*l1tab)];
   2.354 -        if ( count == 0 )
   2.355 -        {
   2.356 -            page->type_and_flags &= ~PGT_type_mask;
   2.357 -            page->type_and_flags |= PGT_l2_page_table;
   2.358 -            get_page(page, p); /* an extra ref because of readable mapping */
   2.359 -            /* Get another ref to L2 page so that it can be pinned. */
   2.360 -            if ( !get_page_and_type(page, p, PGT_l2_page_table) )
   2.361 -                BUG();
   2.362 -            set_bit(_PGC_guest_pinned, &page->count_and_flags);
   2.363 -        }
   2.364 -        else
   2.365 -        {
   2.366 -            page->type_and_flags &= ~PGT_type_mask;
   2.367 -            page->type_and_flags |= PGT_l1_page_table;
   2.368 -            get_page(page, p); /* an extra ref because of readable mapping */
   2.369 -        }
   2.370 -        l1tab++;
   2.371 -        if( !((unsigned long)l1tab & (PAGE_SIZE - 1)) )
   2.372 -            l1start = l1tab = (l1_pgentry_t *)l2_pgentry_to_phys(*l2tab);
   2.373 -    }
   2.374 -
   2.375 -    /* Set up shared-info area. */
   2.376 -    update_dom_time(p->shared_info);
   2.377 -    p->shared_info->domain_time = 0;
   2.378 -    /* Mask all upcalls... */
   2.379 -    for ( i = 0; i < MAX_VIRT_CPUS; i++ )
   2.380 -        p->shared_info->vcpu_data[i].evtchn_upcall_mask = 1;
   2.381 -
   2.382 -    /* Install the new page tables. */
   2.383 -    __cli();
   2.384 -    write_ptbase(&p->mm);
   2.385 -
   2.386 -    /* Copy the OS image. */
   2.387 -    (void)loadelfimage(image_start);
   2.388 -
   2.389 -    /* Copy the initial ramdisk. */
   2.390 -    if ( initrd_len != 0 )
   2.391 -        memcpy((void *)vinitrd_start, initrd_start, initrd_len);
   2.392 -    
   2.393 -    /* Set up start info area. */
   2.394 -    si = (start_info_t *)vstartinfo_start;
   2.395 -    memset(si, 0, PAGE_SIZE);
   2.396 -    si->nr_pages     = p->tot_pages;
   2.397 -    si->shared_info  = virt_to_phys(p->shared_info);
   2.398 -    si->flags        = SIF_PRIVILEGED | SIF_INITDOMAIN;
   2.399 -    si->pt_base      = vpt_start;
   2.400 -    si->nr_pt_frames = nr_pt_pages;
   2.401 -    si->mfn_list     = vphysmap_start;
   2.402 -
   2.403 -    /* Write the phys->machine and machine->phys table entries. */
   2.404 -    for ( mfn = (alloc_start>>PAGE_SHIFT); 
   2.405 -          mfn < (alloc_end>>PAGE_SHIFT); 
   2.406 -          mfn++ )
   2.407 -    {
   2.408 -        pfn = mfn - (alloc_start>>PAGE_SHIFT);
   2.409 -        ((unsigned long *)vphysmap_start)[pfn] = mfn;
   2.410 -        machine_to_phys_mapping[mfn] = pfn;
   2.411 -    }
   2.412 -
   2.413 -    if ( initrd_len != 0 )
   2.414 -    {
   2.415 -        si->mod_start = vinitrd_start;
   2.416 -        si->mod_len   = initrd_len;
   2.417 -        printk("Initrd len 0x%lx, start at 0x%08lx\n",
   2.418 -               si->mod_len, si->mod_start);
   2.419 -    }
   2.420 -
   2.421 -    dst = si->cmd_line;
   2.422 -    if ( cmdline != NULL )
   2.423 -    {
   2.424 -        for ( i = 0; i < 255; i++ )
   2.425 -        {
   2.426 -            if ( cmdline[i] == '\0' )
   2.427 -                break;
   2.428 -            *dst++ = cmdline[i];
   2.429 -        }
   2.430 -    }
   2.431 -    *dst = '\0';
   2.432 -
   2.433 -    /* Reinstate the caller's page tables. */
   2.434 -    write_ptbase(&current->mm);
   2.435 -    __sti();
   2.436 -
   2.437 -    /* Destroy low mappings - they were only for our convenience. */
   2.438 -    for ( i = 0; i < DOMAIN_ENTRIES_PER_L2_PAGETABLE; i++ )
   2.439 -        if ( l2_pgentry_val(l2start[i]) & _PAGE_PSE )
   2.440 -            l2start[i] = mk_l2_pgentry(0);
   2.441 -    zap_low_mappings(); /* Do the same for the idle page tables. */
   2.442 -    
   2.443 -    /* Give up the VGA console if DOM0 is configured to grab it. */
   2.444 -    console_endboot(strstr(cmdline, "tty0") != NULL);
   2.445 -
   2.446 -    /* DOM0 gets access to everything. */
   2.447 -    physdev_init_dom0(p);
   2.448 -
   2.449 -    set_bit(DF_CONSTRUCTED, &p->flags);
   2.450 -
   2.451 -#if 0 /* XXXXX DO NOT CHECK IN ENABLED !!! (but useful for testing so leave) */
   2.452 -    shadow_mode_enable(&p->mm, SHM_test); 
   2.453 -#endif
   2.454 -
   2.455 -    new_thread(p, vkern_entry, vstack_end, vstartinfo_start);
   2.456 -
   2.457 -    return 0;
   2.458 -}
     3.1 --- a/xen/include/asm-x86/config.h	Wed Jul 07 16:59:37 2004 +0000
     3.2 +++ b/xen/include/asm-x86/config.h	Wed Jul 07 18:30:32 2004 +0000
     3.3 @@ -220,4 +220,10 @@ extern unsigned long xenheap_phys_end; /
     3.4  #define LDT_VIRT_START        (GDT_VIRT_END)
     3.5  #define LDT_VIRT_END          (LDT_VIRT_START + (64*1024))
     3.6  
     3.7 +#if defined(__x86_64__)
     3.8 +#define ELFSIZE 64
     3.9 +#else
    3.10 +#define ELFSIZE 32
    3.11 +#endif
    3.12 +
    3.13  #endif /* __XEN_I386_CONFIG_H__ */
     4.1 --- a/xen/include/xen/sched.h	Wed Jul 07 16:59:37 2004 +0000
     4.2 +++ b/xen/include/xen/sched.h	Wed Jul 07 18:30:32 2004 +0000
     4.3 @@ -188,7 +188,6 @@ extern void domain_destruct(struct domai
     4.4  extern void domain_kill(struct domain *d);
     4.5  extern void domain_crash(void);
     4.6  extern void domain_shutdown(u8 reason);
     4.7 -extern void domain_relinquish_memory(struct domain *d);
     4.8  
     4.9  void new_thread(struct domain *d,
    4.10                  unsigned long start_pc,