Merge branch 'master' into arm_coreboot
authorDavid Cock <david.cock@inf.ethz.ch>
Tue, 30 Aug 2016 13:07:17 +0000 (15:07 +0200)
committerDavid Cock <david.cock@inf.ethz.ch>
Tue, 30 Aug 2016 13:07:17 +0000 (15:07 +0200)
Signed-off-by: David Cock <david.cock@inf.ethz.ch>

Conflicts:
include/arch/arm/barrelfish/invocations_arch.h

12 files changed:
1  2 
include/arch/arm/barrelfish/invocations_arch.h
include/arch/arm/barrelfish/syscall_arch.h
include/barrelfish_kpi/capabilities.h
kernel/Hakefile
kernel/arch/arm/irq.c
kernel/arch/arm/misc.c
kernel/arch/armv7/startup_arch.c
kernel/arch/armv7/syscall.c
kernel/include/arch/armv7/exceptions.h
platforms/Hakefile
tools/asmoffsets/asmoffsets.c
usr/drivers/cpuboot/armboot.c

@@@ -128,363 -129,41 +129,58 @@@ invoke_cnode_retype(struct capref root
      assert(cap != CPTR_NULL);
  
      assert(newtype < ObjType_Num);
-     assert(bits <= 0xFF);
-     assert(slot <= 0xFFFF);
-     return cap_invoke8(root, CNodeCmd_Retype, cap, offset,
-                        ((uint32_t)bits << 16) | newtype,
-                        objsize, count, to, slot).error;
- }
- /**
-  * \brief Create a capability.
-  *
-  * Create a new capability of type 'type' and size 'objbits'. The new cap will
-  * be placed in the slot 'dest_slot' of the CNode located at 'dest_cnode_cptr'
-  * in the address space rooted at 'root'.
-  *
-  * See also cap_create(), which wraps this.
-  *
-  * \param root            Capability of the CNode to invoke.
-  * \param type            Kernel object type to create.
-  * \param objbits         Size of created object
-  *                        (ignored for fixed-size objects)
-  * \param dest_cnode_cptr Address of CNode cap, where newly created cap will be
-  *                        placed into.
-  * \param dest_slot       Slot in CNode cap to place new cap.
-  * \param dest_vbits      Number of valid address bits in 'dest_cnode_cptr'.
-  *
-  * \return Error code
-  */
- static inline errval_t invoke_cnode_create(struct capref root,
-                                            enum objtype type, uint8_t objbits,
-                                            capaddr_t dest_cnode_cptr,
-                                            capaddr_t dest_slot,
-                                            uint8_t dest_vbits)
- {
-     /* Pack arguments */
-     assert(dest_cnode_cptr != CPTR_NULL);
-     uint8_t invoke_bits = get_cap_valid_bits(root);
-     capaddr_t invoke_cptr = get_cap_addr(root) >> (CPTR_BITS - invoke_bits);
-     assert(type < ObjType_Num);
-     return syscall5((invoke_bits << 16) | (CNodeCmd_Create << 8) | SYSCALL_INVOKE,
-                     invoke_cptr, (type << 16) | (objbits << 8) | dest_vbits,
-                     dest_cnode_cptr, dest_slot).error;
- }
- /**
-  * \brief "Mint" a capability.
-  *
-  * Copies CPtr 'from' into slot 'slot' in the CNode, addressed by 'to', within
-  * the address space, rooted at 'root' and with 'tobits' and 'frombits' address
-  * bits of 'to' and 'from' valid, respectively.
-  *
-  * See also cap_mint(), which wraps this.
-  *
-  * \param root          Capability of the CNode to invoke
-  * \param to            CNode to place copy into.
-  * \param slot          Slot in CNode cap to place copy into.
-  * \param from          Address of cap to copy.
-  * \param tobits        Number of valid address bits in 'to'.
-  * \param frombits      Number of valid address bits in 'from'.
-  * \param param1        1st cap-dependent parameter.
-  * \param param2        2nd cap-dependent parameter.
-  *
-  * \return Error code
-  */
- //XXX: workaround for inline bug of arm-gcc 4.6.1 and lower
- #if defined(__ARM_ARCH_7A__) && defined(__GNUC__) \
-       && __GNUC__ == 4 && __GNUC_MINOR__ <= 6 && __GNUC_PATCHLEVEL__ <= 1
- static __attribute__((noinline, unused)) errval_t
- #else
- static inline errval_t
- #endif
- invoke_cnode_mint(struct capref root, capaddr_t to,
-               capaddr_t slot, capaddr_t from, int tobits,
-               int frombits, uintptr_t param1,
-               uintptr_t param2)
- {
-     uint8_t invoke_bits = get_cap_valid_bits(root);
-     capaddr_t invoke_cptr = get_cap_addr(root) >> (CPTR_BITS - invoke_bits);
-     assert(slot <= 0xffff);
-     assert(tobits <= 0xff);
-     assert(frombits <= 0xff);
-     return syscall7((invoke_bits << 16) | (CNodeCmd_Mint << 8) | SYSCALL_INVOKE,
-                     invoke_cptr, to, from,
-                     (slot << 16) | (tobits << 8) | frombits,
-                     param1, param2).error;
- }
- /**
-  * \brief Copy a capability.
-  *
-  * Copies CPtr 'from' into slot 'slot' in the CNode, addressed by 'to', within
-  * the address space, rooted at 'root' and with 'tobits' and 'frombits' address
-  * bits of 'to' and 'from' valid, respectively.
-  *
-  * See also cap_copy(), which wraps this.
-  *
-  * \param root          Capability of the CNode to invoke
-  * \param to            CNode to place copy into.
-  * \param slot          Slot in CNode cap to place copy into.
-  * \param from          Address of cap to copy.
-  * \param tobits        Number of valid address bits in 'to'.
-  * \param frombits      Number of valid address bits in 'from'.
-  *
-  * \return Error code
-  */
- //XXX: workaround for inline bug of arm-gcc 4.6.1 and lower
- #if defined(__ARM_ARCH_7A__) && defined(__GNUC__) \
-       && __GNUC__ == 4 && __GNUC_MINOR__ <= 6 && __GNUC_PATCHLEVEL__ <= 1
- static __attribute__((noinline, unused)) errval_t
- #else
- static inline errval_t
- #endif
- invoke_cnode_copy(struct capref root, capaddr_t to,
-                                          capaddr_t slot, capaddr_t from, int tobits,
-                                          int frombits)
- {
-     uint8_t invoke_bits = get_cap_valid_bits(root);
-     capaddr_t invoke_cptr = get_cap_addr(root) >> (CPTR_BITS - invoke_bits);
-     assert(slot <= 0xffff);
-     assert(tobits <= 0xff);
-     assert(frombits <= 0xff);
+     assert(offset <= 0xFFFFFFFF);
+     assert(objsize <= 0xFFFFFFFF);
+     assert(count <= 0xFFFFFFFF);
+     assert(to_level <= 0xF);
  
-     return syscall5((invoke_bits << 16) | (CNodeCmd_Copy << 8) | SYSCALL_INVOKE,
-                     invoke_cptr, to, from,
-                     (slot << 16) | (tobits << 8) | frombits).error;
+     return cap_invoke10(root, CNodeCmd_Retype, src_cspace, cap, offset,
+                         ((uint32_t)to_level << 16) | newtype,
+                         objsize, count, to_cspace, to, slot).error;
  }
  
- /**
-  * \brief Delete a capability.
-  *
-  * Delete the capability pointed to by 'cap', with 'bits' address bits
-  * of it valid, from the address space rooted at 'root'.
-  *
-  * \param root  Capability of the CNode to invoke
-  * \param cap   Address of cap to delete.
-  * \param bits  Number of valid bits within 'cap'.
-  *
-  * \return Error code
-  */
- //XXX: workaround for inline bug of arm-gcc 4.6.1 and lower
- #if defined(__ARM_ARCH_7A__) && defined(__GNUC__) \
-       && __GNUC__ == 4 && __GNUC_MINOR__ <= 6 && __GNUC_PATCHLEVEL__ <= 1
- static __attribute__((noinline, unused)) errval_t
- #else
- static inline errval_t
- #endif
- invoke_cnode_delete(struct capref root, capaddr_t cap,
-                                            int bits)
- {
-     uint8_t invoke_bits = get_cap_valid_bits(root);
-     capaddr_t invoke_cptr = get_cap_addr(root) >> (CPTR_BITS - invoke_bits);
-     assert(bits <= 0xff);
-     return syscall4((invoke_bits << 16) | (CNodeCmd_Delete << 8) | SYSCALL_INVOKE,
-                     invoke_cptr, cap, bits).error;
- }
- //XXX: workaround for inline bug of arm-gcc 4.6.1 and lower
- #if defined(__ARM_ARCH_7A__) && defined(__GNUC__) \
-       && __GNUC__ == 4 && __GNUC_MINOR__ <= 6 && __GNUC_PATCHLEVEL__ <= 1
- static __attribute__((noinline, unused)) errval_t
- #else
- static inline errval_t
- #endif
- invoke_cnode_revoke(struct capref root, capaddr_t cap,
-                                            int bits)
- {
-     uint8_t invoke_bits = get_cap_valid_bits(root);
-     capaddr_t invoke_cptr = get_cap_addr(root) >> (CPTR_BITS - invoke_bits);
-     assert(bits <= 0xff);
-     return syscall4((invoke_bits << 16) | (CNodeCmd_Revoke << 8) | SYSCALL_INVOKE,
-                     invoke_cptr, cap, bits).error;
- }
- //XXX: workaround for inline bug of arm-gcc 4.6.1 and lower
- #if defined(__ARM_ARCH_7A__) && defined(__GNUC__) \
-       && __GNUC__ == 4 && __GNUC_MINOR__ <= 6 && __GNUC_PATCHLEVEL__ <= 1
- static __attribute__((noinline, unused)) errval_t
- #else
- static inline errval_t
- #endif
- invoke_cnode_get_state(struct capref root, capaddr_t cap,
-                                               int bits, distcap_state_t *ret)
- {
-     uint8_t invoke_bits = get_cap_valid_bits(root);
-     capaddr_t invoke_cptr = get_cap_addr(root) >> (CPTR_BITS - invoke_bits);
-     assert (bits <= 0xff);
-     struct sysret sysret =
-         syscall4((invoke_bits << 16) | (CNodeCmd_GetState << 8) | SYSCALL_INVOKE,
-                 invoke_cptr, cap, bits);
-     assert(ret != NULL);
-     if (err_is_ok(sysret.error)) {
-         *ret = sysret.value;
-     }
-     else {
-         *ret = 0;
-     }
-     return sysret.error;
- }
- //XXX: workaround for inline bug of arm-gcc 4.6.1 and lower
- #if defined(__ARM_ARCH_7A__) && defined(__GNUC__) \
-       && __GNUC__ == 4 && __GNUC_MINOR__ <= 6 && __GNUC_PATCHLEVEL__ <= 1
- static __attribute__((noinline, unused)) errval_t
- #else
  static inline errval_t
- #endif
- invoke_vnode_map(struct capref ptable, capaddr_t slot, capaddr_t from,
-                  int frombits, uintptr_t flags, uintptr_t offset,
-                  uintptr_t pte_count, capaddr_t mcn_addr, int mcn_vbits,
-                  cslot_t mapping_slot)
+ invoke_vnode_map(struct capref ptable, capaddr_t slot,
+                  capaddr_t src_root, capaddr_t src,
+                  enum cnode_type srclevel, size_t
+                  flags, size_t offset, size_t pte_count,
+                  capaddr_t mcnroot, capaddr_t mcnaddr,
+                  enum cnode_type mcnlevel, cslot_t mapping_slot)
  {
-     uint8_t invoke_bits = get_cap_valid_bits(ptable);
-     capaddr_t invoke_cptr = get_cap_addr(ptable) >> (CPTR_BITS - invoke_bits);
      assert(slot <= 0xffff);
-     assert(frombits <= 0xff);
+     assert(srclevel <= 0xf);
+     assert(mcnlevel <= 0xf);
+     assert(offset <= 0xffffffff);
+     assert(flags <= 0xffffffff);
+     assert(pte_count <= 0xffff);
+     assert(mapping_slot <= L2_CNODE_SLOTS);
  
-     // XXX: needs check of flags, offset, and pte_count sizes
-     return syscall10((invoke_bits << 16) | (VNodeCmd_Map << 8) | SYSCALL_INVOKE,
-                      invoke_cptr, from, (slot << 16) | frombits,
-                      flags, offset, pte_count, mcn_addr, mcn_vbits,
-                      mapping_slot).error;
- }
+     uintptr_t small_values = srclevel |
+                              (mcnlevel << 4) |
+                              (mapping_slot << 8) |
+                              (slot << 16);
  
- //XXX: workaround for inline bug of arm-gcc 4.6.1 and lower
- #if defined(__ARM_ARCH_7A__) && defined(__GNUC__) \
-       && __GNUC__ == 4 && __GNUC_MINOR__ <= 6 && __GNUC_PATCHLEVEL__ <= 1
- static __attribute__((noinline, unused)) errval_t
- #else
- static inline errval_t
- #endif
- invoke_vnode_unmap(struct capref cap, capaddr_t mapping_cptr, int mapping_bits)
- {
-     uint8_t invoke_bits = get_cap_valid_bits(cap);
-     capaddr_t invoke_cptr = get_cap_addr(cap) >> (CPTR_BITS - invoke_bits);
-     assert(mapping_bits <= 0xff);
-     return syscall4((invoke_bits << 16) | (VNodeCmd_Unmap << 8) | SYSCALL_INVOKE,
-                     invoke_cptr, mapping_cptr, mapping_bits).error;
+     return cap_invoke9(ptable, VNodeCmd_Map, src_root, src, flags, offset,
+                        pte_count, mcnroot, mcnaddr, small_values).error;
  }
  
 +/**
 + * \brief Duplicate ARMv7 core_data into the supplied frame.
 + *
 + * \param frame    CSpace address of frame capability
 + *
 + * \return Error code
 + */
 +
- //XXX: workaround for inline bug of arm-gcc 4.6.1 and lower
- #if defined(__ARM_ARCH_7A__) && defined(__GNUC__) \
-       && __GNUC__ == 4 && __GNUC_MINOR__ <= 6 && __GNUC_PATCHLEVEL__ <= 1
- static __attribute__((noinline, unused)) errval_t
- #else
- static inline errval_t
- #endif
- invoke_kcb_clone (struct capref kcb, struct capref frame)
- {
-     uint8_t invoke_bits = get_cap_valid_bits(kcb);
-     capaddr_t invoke_cptr = get_cap_addr(kcb) >> (CPTR_BITS - invoke_bits);
-     uintptr_t arg1 = ((uintptr_t)invoke_bits) << 16;
-     arg1 |= ((uintptr_t)KCBCmd_Clone<<8);
-     arg1 |= (uintptr_t)SYSCALL_INVOKE;
-     uint8_t frame_bits = get_cap_valid_bits(frame);
-     capaddr_t frame_cptr = get_cap_addr(frame) >> (CPTR_BITS - frame_bits);
-     struct sysret sysret =
-         syscall4(arg1, invoke_cptr, frame_cptr, frame_bits);
-     return sysret.error;
- }
- /**
-  * \brief Return the physical address and size of a frame capability
-  *
-  * \param frame    CSpace address of frame capability
-  * \param ret      frame_identity struct filled in with relevant data
-  *
-  * \return Error code
-  */
- //XXX: workaround for inline bug of arm-gcc 4.6.1 and lower
- #if defined(__ARM_ARCH_7A__) && defined(__GNUC__) \
-       && __GNUC__ == 4 && __GNUC_MINOR__ <= 6 && __GNUC_PATCHLEVEL__ <= 1
- static __attribute__((noinline, unused)) errval_t
- #else
- static inline errval_t
- #endif
- invoke_frame_identify (struct capref frame, struct frame_identity *ret)
- {
-     assert(ret != NULL);
-     uint8_t invoke_bits = get_cap_valid_bits(frame);
-     capaddr_t invoke_cptr = get_cap_addr(frame) >> (CPTR_BITS - invoke_bits);
-     uintptr_t arg1 = ((uintptr_t)invoke_bits) << 16;
-     arg1 |= ((uintptr_t)FrameCmd_Identify<<8);
-     arg1 |= (uintptr_t)SYSCALL_INVOKE;
-     struct sysret sysret =
-         syscall3(arg1, //(invoke_bits << 16) | (FrameCmd_Identify << 8) | SYSCALL_INVOKE,
-                  invoke_cptr, (uintptr_t)ret);
-     if (err_is_ok(sysret.error)) {
-         return sysret.error;
-     }
-     ret->base = 0;
-     ret->bytes = 0;
-     return sysret.error;
- }
- /**
-  * \brief Return the physical address and size of a frame capability
-  *
-  * \param frame    CSpace address of frame capability
-  * \param ret      frame_identity struct filled in with relevant data
-  *
-  * \return Error code
-  */
- //XXX: workaround for inline bug of arm-gcc 4.6.1 and lower
- #if defined(__ARM_ARCH_7A__) && defined(__GNUC__) \
-       && __GNUC__ == 4 && __GNUC_MINOR__ <= 6 && __GNUC_PATCHLEVEL__ <= 1
- static __attribute__((noinline, unused)) errval_t
- #else
 +static inline errval_t
- #endif
- invoke_mapping_modify_flags (struct capref mapping, uintptr_t offset,
-               uintptr_t pages, uintptr_t flags)
++invoke_kcb_clone(struct capref kcb, struct capref frame)
 +{
-     uint8_t invoke_bits = get_cap_valid_bits(mapping);
-     capaddr_t invoke_cptr = get_cap_addr(mapping) >> (CPTR_BITS - invoke_bits);
-     uintptr_t arg1 = ((uintptr_t)invoke_bits) << 16;
-     arg1 |= ((uintptr_t)MappingCmd_Modify<<8);
-     arg1 |= (uintptr_t)SYSCALL_INVOKE;
++    capaddr_t frame_cptr = get_cap_addr(frame);
++    enum cnode_type frame_level = get_cap_level(frame);
 +
-     return syscall5(arg1, invoke_cptr, offset, pages, flags).error;
++    return cap_invoke3(kcb, KCBCmd_Clone, frame_cptr, frame_level).error;
 +}
 +
  static inline errval_t invoke_iocap_in(struct capref iocap, enum io_cmd cmd,
                                         uint16_t port, uint32_t *data)
  {
Simple merge
diff --cc kernel/Hakefile
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -832,71 -865,6 +866,71 @@@ static struct sysret handle_kcb_identif
      return sys_handle_kcb_identify(to, (struct frame_identity *)sa->arg2);
  }
  
 +/* XXX - move. */
 +extern char cpu_start;
 +
 +INVOCATION_HANDLER(handle_kcb_clone)
 +{
 +    INVOCATION_PRELUDE(4);
 +    errval_t err;
 +
-     capaddr_t core_data_cptr= sa->arg2;
-     uint8_t bits= sa->arg3;
++    capaddr_t frame_cptr= sa->arg2;
++    uint8_t frame_level= sa->arg3;
 +
 +    struct capability *frame_cap;
-     err= caps_lookup_cap(&dcb_current->cspace.cap, core_data_cptr, bits,
++    err= caps_lookup_cap(&dcb_current->cspace.cap, frame_cptr, frame_level,
 +                         &frame_cap, CAPRIGHTS_WRITE);
 +    if (err_is_fail(err)) {
 +        return SYSRET(err_push(err, SYS_ERR_CAP_NOT_FOUND));
 +    }
 +
 +    if(frame_cap->type != ObjType_Frame) {
 +        return SYSRET(err_push(err, SYS_ERR_INVARGS_SYSCALL));
 +    }
 +
 +    struct Frame *frame= &frame_cap->u.frame;
 +
 +    if(frame->bytes < sizeof(struct arm_core_data)) {
 +        return SYSRET(err_push(err, SYS_ERR_INVALID_USER_BUFFER));
 +    }
 +
 +    /* Copy those parts of the ARMv7 core data that aren't specific to this
 +     * kernel instance e.g., its text segment addresses, and the address of
 +     * the multiboot header.  Note that the user-level boot driver may
 +     * overwrite some or all of these, if it's booting a custom CPU driver. */
 +    struct arm_core_data *new_cd=
 +        (struct arm_core_data *)local_phys_to_mem((lpaddr_t)frame->base);
 +
 +    new_cd->multiboot_header= core_data->multiboot_header;
 +
 +    new_cd->kernel_l1_low= core_data->kernel_l1_low;
 +    new_cd->kernel_l1_high= core_data->kernel_l1_high;
 +    new_cd->kernel_l2_vec= core_data->kernel_l2_vec;
 +
 +    /* Any kernel started via this mechanism will begin at cpu_start, *not*
 +     * bsp_start. */
 +    new_cd->entry_point= (lvaddr_t)&cpu_start;
 +
 +    new_cd->kernel_module= core_data->kernel_module;
 +    new_cd->kernel_elf= core_data->kernel_elf;
 +
 +    memcpy(new_cd->cmdline_buf, core_data->cmdline_buf, MAXCMDLINE);
 +
 +    new_cd->global= core_data->global;
 +
 +    new_cd->target_bootrecs= core_data->target_bootrecs;
 +
 +    assert(new_cd->build_id.length <= MAX_BUILD_ID);
 +    new_cd->build_id.length= core_data->build_id.length;
 +    memcpy(new_cd->build_id.data,
 +           core_data->build_id.data,
 +           core_data->build_id.length);
 +
 +    new_cd->kernel_load_base= (lvaddr_t)&kernel_first_byte;
 +
 +    return SYSRET(SYS_ERR_OK);
 +}
 +
  typedef struct sysret (*invocation_t)(struct capability*, arch_registers_state_t*, int);
  
  static invocation_t invocations[ObjType_Num][CAP_MAX_CMD] = {
Simple merge
Simple merge
@@@ -299,215 -294,11 +299,211 @@@ static inline errval_
  invoke_monitor_spawn_core(coreid_t core_id, enum cpu_type cpu_type,
                            forvaddr_t entry)
  {
-     uint8_t invoke_bits = get_cap_valid_bits(ipi_cap);
-     capaddr_t invoke_cptr = get_cap_addr(ipi_cap) >> (CPTR_BITS - invoke_bits);
-     return syscall6((invoke_bits << 16) | (KernelCmd_Spawn_core << 8)
-                     | SYSCALL_INVOKE, invoke_cptr, core_id, cpu_type,
-                     (uintptr_t)(entry >> 32), (uintptr_t) entry).error;
 -    return cap_invoke4(ipi_cap, core_id, cpu_type,
++    return cap_invoke5(ipi_cap, IPICmd_Send_Start, core_id, cpu_type,
+             (uintptr_t)(entry >> 32), (uintptr_t) entry).error;
  }
 -#endif
  
 +static void
 +print_build_id(const char *data, size_t length) {
 +    for(size_t i= 0; i < length; i++) printf("%02x", data[i]);
 +}
 +
 +static int
 +compare_build_ids(const char *data1, size_t length1,
 +                  const char *data2, size_t length2) {
 +    if(length1 != length2) return 0;
 +
 +    for(size_t i= 0; i < length1; i++) {
 +        if(data1[i] != data2[i]) return 0;
 +    }
 +
 +    return 1;
 +}
 +
 +/* Return the first program header of type 'type'. */
 +static struct Elf32_Phdr *
 +elf32_find_segment_type(void *elfdata, uint32_t type) {
 +    struct Elf32_Ehdr *ehdr= (struct Elf32_Ehdr *)elfdata;
 +
 +    if(!IS_ELF(*ehdr) ||
 +       ehdr->e_ident[EI_CLASS] != ELFCLASS32 ||
 +       ehdr->e_machine != EM_ARM) {
 +        return NULL;
 +    }
 +
 +    void *phdrs_base= (void *)(elfdata + ehdr->e_phoff);
 +
 +    for(size_t i= 0; i < ehdr->e_phnum; i++) {
 +        struct Elf32_Phdr *phdr= phdrs_base + i * ehdr->e_phentsize;
 +
 +        if(phdr->p_type == type) return phdr;
 +    }
 +
 +    return NULL;
 +}
 +
 +static errval_t
 +load_cpu_relocatable_segment(void *elfdata, void *out, lvaddr_t vbase,
 +                             lvaddr_t text_base, lvaddr_t *got_base) {
 +    /* Find the full loadable segment, as it contains the dynamic table. */
 +    struct Elf32_Phdr *phdr_full= elf32_find_segment_type(elfdata, PT_LOAD);
 +    if(!phdr_full) return ELF_ERR_HEADER;
 +    void *full_segment_data= elfdata + phdr_full->p_offset;
 +
 +    printf("Loadable segment at V:%08"PRIx32"\n", phdr_full->p_vaddr);
 +
 +    /* Find the relocatable segment to load. */
 +    struct Elf32_Phdr *phdr= elf32_find_segment_type(elfdata, PT_BF_RELOC);
 +    if(!phdr) return ELF_ERR_HEADER;
 +
 +    printf("Relocatable segment at V:%08"PRIx32"\n", phdr->p_vaddr);
 +
 +    /* Copy the raw segment data. */
 +    void *in= elfdata + phdr->p_offset;
 +    assert(phdr->p_filesz <= phdr->p_memsz);
 +    memcpy(out, in, phdr->p_filesz);
 +
 +    /* Find the dynamic segment. */
 +    struct Elf32_Phdr *phdr_dyn= elf32_find_segment_type(elfdata, PT_DYNAMIC);
 +    if(!phdr_dyn) return ELF_ERR_HEADER;
 +
 +    printf("Dynamic segment at V:%08"PRIx32"\n", phdr_dyn->p_vaddr);
 +
 +    /* The location of the dynamic segment is specified by its *virtual
 +     * address* (vaddr), relative to the loadable segment, and *not* by its
 +     * p_offset, as for every other segment. */
 +    struct Elf32_Dyn *dyn=
 +        full_segment_data + (phdr_dyn->p_vaddr - phdr_full->p_vaddr);
 +
 +    /* There is no *entsize field for dynamic entries. */
 +    size_t n_dyn= phdr_dyn->p_filesz / sizeof(struct Elf32_Dyn);
 +
 +    /* Find the relocations (REL only). */
 +    void *rel_base= NULL;
 +    size_t relsz= 0, relent= 0;
 +    void *dynsym_base= NULL;
 +    const char *dynstr_base= NULL;
 +    size_t syment= 0, strsz= 0;
 +    for(size_t i= 0; i < n_dyn; i++) {
 +        switch(dyn[i].d_tag) {
 +            /* There shouldn't be any RELA relocations. */
 +            case DT_RELA:
 +                return ELF_ERR_HEADER;
 +
 +            case DT_REL:
 +                if(rel_base != NULL) return ELF_ERR_HEADER;
 +
 +                /* Pointers in the DYNAMIC table are *virtual* addresses,
 +                 * relative to the vaddr base of the segment that contains
 +                 * them. */
 +                rel_base= full_segment_data +
 +                    (dyn[i].d_un.d_ptr - phdr_full->p_vaddr);
 +                break;
 +
 +            case DT_RELSZ:
 +                relsz= dyn[i].d_un.d_val;
 +                break;
 +
 +            case DT_RELENT:
 +                relent= dyn[i].d_un.d_val;
 +                break;
 +
 +            case DT_SYMTAB:
 +                dynsym_base= full_segment_data +
 +                    (dyn[i].d_un.d_ptr - phdr_full->p_vaddr);
 +                break;
 +
 +            case DT_SYMENT:
 +                syment= dyn[i].d_un.d_val;
 +                break;
 +
 +            case DT_STRTAB:
 +                dynstr_base= full_segment_data +
 +                    (dyn[i].d_un.d_ptr - phdr_full->p_vaddr);
 +                break;
 +
 +            case DT_STRSZ:
 +                strsz= dyn[i].d_un.d_val;
 +        }
 +    }
 +    if(rel_base == NULL || relsz == 0 || relent == 0 ||
 +       dynsym_base == NULL || syment == 0 ||
 +       dynstr_base == NULL || strsz == 0)
 +        return ELF_ERR_HEADER;
 +
 +    /* XXX - The dynamic segment doesn't actually tell us the size of the
 +     * dynamic symbol table, which is very annoying.  We should fix this by
 +     * defining and implementing a standard format for dynamic executables on
 +     * Barrelfish, using DT_PLTGOT.  Currently, GNU ld refuses to generate
 +     * that for the CPU driver binary. */
 +    assert((size_t)dynstr_base > (size_t)dynsym_base);
 +    size_t dynsym_len= (size_t)dynstr_base - (size_t)dynsym_base;
 +
 +    /* Walk the symbol table to find got_base. */
 +    size_t dynsym_offset= 0;
 +    struct Elf32_Sym *got_sym= NULL;
 +    while(dynsym_offset < dynsym_len) {
 +        got_sym= dynsym_base + dynsym_offset;
 +        if(!strcmp(dynstr_base + got_sym->st_name, "got_base")) break;
 +
 +        dynsym_offset+= syment;
 +    }
 +    if(dynsym_offset >= dynsym_len) {
 +        printf("got_base not found.\n");
 +        return ELF_ERR_HEADER;
 +    }
 +
 +    /* Addresses in the relocatable segment are relocated to the
 +     * newly-allocated region, relative to their addresses in the relocatable
 +     * segment.  Addresses outside the relocatable segment are relocated to
 +     * the shared text segment, relative to their position in the
 +     * originally-loaded segment. */
 +    uint32_t relocatable_offset= vbase - phdr->p_vaddr;
 +    uint32_t text_offset= text_base - phdr_full->p_vaddr;
 +
 +    /* Relocate the got_base within the relocatable segment. */
 +    *got_base= vbase + (got_sym->st_value - phdr->p_vaddr);
 +
 +    /* Process the relocations. */
 +    size_t n_rel= relsz / relent;
 +    printf("Have %zu relocations of size %zu\n", n_rel, relent);
 +    for(size_t i= 0; i < n_rel; i++) {
 +        struct Elf32_Rel *rel= rel_base + i * relent;
 +
 +        size_t sym=  ELF32_R_SYM(rel->r_info);
 +        size_t type= ELF32_R_TYPE(rel->r_info);
 +
 +        /* We should only see relative relocations (R_ARM_RELATIVE) against
 +         * sections (symbol 0). */
 +        if(sym != 0 || type != R_ARM_RELATIVE) return ELF_ERR_HEADER;
 +
 +        uint32_t offset_in_seg= rel->r_offset - phdr->p_vaddr;
 +        uint32_t *value= out + offset_in_seg;
 +
 +        uint32_t offset;
 +        if(*value >= phdr->p_vaddr &&
 +           (*value - phdr->p_vaddr) < phdr->p_memsz) {
 +            /* We have a relocation to an address *inside* the relocatable
 +             * segment. */
 +            offset= relocatable_offset;
 +            //printf("r ");
 +        }
 +        else {
 +            /* We have a relocation to an address in the shared text segment.
 +             * */
 +            offset= text_offset;
 +            //printf("t ");
 +        }
 +
 +        //printf("REL@%08"PRIx32" %08"PRIx32" -> %08"PRIx32"\n",
 +               //rel->r_offset, *value, *value + offset);
 +        *value+= offset;
 +    }
 +
 +    return SYS_ERR_OK;
 +}
 +
 +/* XXX - this currently only clones the running kernel. */
  errval_t spawn_xcore_monitor(coreid_t coreid, int hwid, 
                               enum cpu_type cpu_type,
                               const char *cmdline,