[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v1 07/11] xsplice: Implement payload loading
On Thu, Nov 05, 2015 at 11:15:34AM +0000, Ross Lagerwall wrote: > On 11/04/2015 10:21 PM, Konrad Rzeszutek Wilk wrote: > snip > >> > >>+ > >>+/* > >>+ * The following functions prepare an xSplice module to be executed by > >>+ * allocating space, loading the allocated sections, resolving symbols, > >>+ * performing relocations, etc. > >>+ */ > >>+#ifdef CONFIG_X86 > >>+static void *alloc_module(size_t size) > > > >s/module/payload/ > > My intention was that all the code which implements the "module loader" > functionality (and is sort of independent from xSplice) uses the term > "module" whereas the payload implies the loaded module + the other > xSplice-specific bits. Your thoughts? Aaah. I had module == payload in mind. > > >>+{ > >>+ mfn_t *mfn, *mfn_ptr; > >>+ size_t pages, i; > >>+ struct page_info *pg; > >>+ unsigned long hole_start, hole_end, cur; > >>+ struct payload *data, *data2; > >>+ > >>+ ASSERT(size); > >>+ > >>+ pages = PFN_UP(size); > >>+ mfn = xmalloc_array(mfn_t, pages); > >>+ if ( mfn == NULL ) > >>+ return NULL; > >>+ > >>+ for ( i = 0; i < pages; i++ ) > >>+ { > >>+ pg = alloc_domheap_page(NULL, 0); > >>+ if ( pg == NULL ) > >>+ goto error; > >>+ mfn[i] = _mfn(page_to_mfn(pg)); > >>+ } > > > >This looks like 'vmalloc'. Why not use that? > >(That explanation should be part of the commit description probably) > > vmalloc allocates pages and then maps them to an arbitrary virtual address > with PAGE_HYPERVISOR. I needed to use a specific virtual address with > PAGE_HYPERVISOR_RWX. /me nods. > > > > >>+ > >>+ hole_start = (unsigned long)module_virt_start; > >>+ hole_end = hole_start + pages * PAGE_SIZE; > >>+ spin_lock(&payload_list_lock); > >>+ list_for_each_entry ( data, &payload_list, list ) > >>+ { > >>+ list_for_each_entry ( data2, &payload_list, list ) > >>+ { > >>+ unsigned long start, end; > >>+ > >>+ start = (unsigned long)data2->module_address; > >>+ end = start + data2->module_pages * PAGE_SIZE; > >>+ if ( hole_end > start && hole_start < end ) > >>+ { > >>+ hole_start = end; > >>+ hole_end = hole_start + pages * PAGE_SIZE; > >>+ break; > >>+ } > >>+ } > >>+ if ( &data2->list == &payload_list ) > >>+ break; > >>+ } > >>+ spin_unlock(&payload_list_lock); > > > >This could be made in a nice function. 'find_hole' perhaps? > > > >>+ > >>+ if ( hole_end >= module_virt_end ) > >>+ goto error; > >>+ > >>+ for ( cur = hole_start, mfn_ptr = mfn; pages--; ++mfn_ptr, cur += > >>PAGE_SIZE ) > >>+ { > >>+ if ( map_pages_to_xen(cur, mfn_x(*mfn_ptr), 1, > >>PAGE_HYPERVISOR_RWX) ) > >>+ { > >>+ if ( cur != hole_start ) > >>+ destroy_xen_mappings(hole_start, cur); > > > >I think 'destroy_xen_mappings' is OK handling hole_start == cur. > > > >>+ goto error; > >>+ } > >>+ } > >>+ xfree(mfn); > >>+ return (void *)hole_start; > >>+ > >>+ error: > >>+ while ( i-- ) > >>+ free_domheap_page(mfn_to_page(mfn_x(mfn[i]))); > >>+ xfree(mfn); > >>+ return NULL; > >>+} > >>+#else > >>+static void *alloc_module(size_t size) > > > >s/module/payload/ > >>+{ > >>+ return NULL; > >>+} > >>+#endif > >>+ > >>+static void free_module(struct payload *payload) > >>+{ > >>+ int i; > > > >unsigned int; > > > >>+ struct page_info *pg; > >>+ PAGE_LIST_HEAD(pg_list); > >>+ void *va = payload->module_address; > >>+ unsigned long addr = (unsigned long)va; > >>+ > >>+ if ( !payload->module_address ) > >>+ return; > > > >How about 'if ( !addr ) > > return; > >? > > > >>+ > >>+ payload->module_address = NULL; > >>+ > >>+ for ( i = 0; i < payload->module_pages; i++ ) > >>+ page_list_add(vmap_to_page(va + i * PAGE_SIZE), &pg_list); > >>+ > >>+ destroy_xen_mappings(addr, addr + payload->module_pages * PAGE_SIZE); > >>+ > >>+ while ( (pg = page_list_remove_head(&pg_list)) != NULL ) > >>+ free_domheap_page(pg); > >>+ > >>+ payload->module_pages = 0; > >>+} > >>+ > >>+static void alloc_section(struct xsplice_elf_sec *sec, size_t *core_size) > > > >s/alloc/compute/? > > > >>+{ > >>+ size_t align_size = ROUNDUP(*core_size, sec->sec->sh_addralign); > >>+ sec->sec->sh_entsize = align_size; > >>+ *core_size = sec->sec->sh_size + align_size; > >>+} > >>+ > >>+static int move_module(struct payload *payload, struct xsplice_elf *elf) > >>+{ > >>+ uint8_t *buf; > >>+ int i; > > > >unsigned int i; > > > >>+ size_t core_size = 0; > >>+ > >>+ /* Allocate text regions */ > > > >s/Allocate/Compute/ > > > >>+ for ( i = 0; i < elf->hdr->e_shnum; i++ ) > >>+ { > >>+ if ( (elf->sec[i].sec->sh_flags & (SHF_ALLOC|SHF_EXECINSTR)) == > >>+ (SHF_ALLOC|SHF_EXECINSTR) ) > >>+ alloc_section(&elf->sec[i], &core_size); > >>+ } > >>+ > >>+ /* Allocate rw data */ > >>+ for ( i = 0; i < elf->hdr->e_shnum; i++ ) > >>+ { > >>+ if ( (elf->sec[i].sec->sh_flags & SHF_ALLOC) && > >>+ !(elf->sec[i].sec->sh_flags & SHF_EXECINSTR) && > >>+ (elf->sec[i].sec->sh_flags & SHF_WRITE) ) > >>+ alloc_section(&elf->sec[i], &core_size); > >>+ } > >>+ > >>+ /* Allocate ro data */ > >>+ for ( i = 0; i < elf->hdr->e_shnum; i++ ) > >>+ { > >>+ if ( (elf->sec[i].sec->sh_flags & SHF_ALLOC) && > >>+ !(elf->sec[i].sec->sh_flags & SHF_EXECINSTR) && > >>+ !(elf->sec[i].sec->sh_flags & SHF_WRITE) ) > >>+ alloc_section(&elf->sec[i], &core_size); > >>+ } > >>+ > >>+ buf = alloc_module(core_size); > >>+ if ( !buf ) { > >>+ printk(XENLOG_ERR "Could not allocate memory for module\n"); > > > >(%s: Could not allocate %u memory for payload!\n", elf->name, core_size); > > > >>+ return -ENOMEM; > >>+ } > >>+ memset(buf, 0, core_size); > > > >Perhaps for fun it ought to be 'ud2' ? > > There's no point. It either gets memcpy'd over or needs to be set to zero > for BSS. Or 0xcc. Was thinking it may be good have it poison so that we would trip over bugs more easily. Maybe for debug builds? > > > > >>+ > >>+ for ( i = 0; i < elf->hdr->e_shnum; i++ ) > >>+ { > >>+ if ( elf->sec[i].sec->sh_flags & SHF_ALLOC ) > >>+ { > >>+ elf->sec[i].load_addr = buf + elf->sec[i].sec->sh_entsize; > >>+ memcpy(elf->sec[i].load_addr, elf->sec[i].data, > >>+ elf->sec[i].sec->sh_size); > >>+ printk(XENLOG_DEBUG "Loaded %s at 0x%p\n", > > > >Add %s: at the start .. > >>+ elf->sec[i].name, elf->sec[i].load_addr); > > > >which would be elf->name. > > > >>+ } > >>+ } > >>+ > >>+ payload->module_address = buf; > >>+ payload->module_pages = PFN_UP(core_size); > > > >Instead of module could we name it payload? > > See comment above. > > > > >>+ > >>+ return 0; > >>+} > >>+ > >>+static int resolve_symbols(struct xsplice_elf *elf) > > > >s/resolve/check/ > > No, this is resolving section symbols. > > > > >>+{ > >>+ int i; > > > >unsigned int; > > > >>+ > >>+ for ( i = 1; i < elf->nsym; i++ ) > > > >Why 1? Please explain as comment. > > The first entry of an ELF symbol table is the "undefined symbol index". This > code is expected to be read alongside the ELF specification :-) > > > > > > >>+ { > >>+ switch ( elf->sym[i].sym->st_shndx ) > >>+ { > >>+ case SHN_COMMON: > >>+ printk(XENLOG_ERR "Unexpected common symbol: %s\n", > >>+ elf->sym[i].name); > > > >Please also include elf->name in the error. > > > >>+ return -EINVAL; > >>+ break; > >>+ case SHN_UNDEF: > >>+ printk(XENLOG_ERR "Unknown symbol: %s\n", > >>elf->sym[i].name); > > > >Ditto. > >>+ return -ENOENT; > >>+ break; > >>+ case SHN_ABS: > >>+ printk(XENLOG_DEBUG "Absolute symbol: %s => 0x%p\n", > >>+ elf->sym[i].name, (void > >>*)elf->sym[i].sym->st_value); > >>+ break; > >>+ default: > >>+ if ( elf->sec[elf->sym[i].sym->st_shndx].sec->sh_flags & > >>SHF_ALLOC ) > >>+ { > >>+ elf->sym[i].sym->st_value += > >>+ (unsigned > >>long)elf->sec[elf->sym[i].sym->st_shndx].load_addr; > >>+ printk(XENLOG_DEBUG "Symbol resolved: %s => 0x%p\n", > > > >Ditto; > >>+ elf->sym[i].name, (void > >>*)elf->sym[i].sym->st_value); > >>+ } > >>+ } > >>+ } > >>+ > >>+ return 0; > >>+} > >>+ > >>+static int perform_relocs(struct xsplice_elf *elf) > >>+{ > >>+ struct xsplice_elf_sec *rela, *base; > >>+ int i, rc; > >>+ > > > >unsigned int i; > > > >>+ for ( i = 0; i < elf->hdr->e_shnum; i++ ) > >>+ { > >>+ rela = &elf->sec[i]; > >>+ > >>+ /* Is it a valid relocation section? */ > >>+ if ( rela->sec->sh_info >= elf->hdr->e_shnum ) > >>+ continue; > > > >Um, don't we want to mark it as invalid or such? > >Or overwrite it so we won't use it? > > The code doesn't use it. I don't understand the concern. The comment. Perhaps change it to /* Ignore invalid relocation sections. */ > > > > >>+ > >>+ base = &elf->sec[rela->sec->sh_info]; > >>+ > >>+ /* Don't relocate non-allocated sections */ > >>+ if ( !(base->sec->sh_flags & SHF_ALLOC) ) > >>+ continue; > > > >>+ > >>+ if ( elf->sec[i].sec->sh_type == SHT_RELA ) > >>+ rc = xsplice_perform_rela(elf, base, rela); > >>+ else if ( elf->sec[i].sec->sh_type == SHT_REL ) > >>+ rc = xsplice_perform_rel(elf, base, rela); > >>+ > >>+ if ( rc ) > >>+ return rc; > >>+ } > >>+ > >>+ return 0; > >>+} > >>+ > >>+static int load_module(struct payload *payload, uint8_t *raw, ssize_t len) > >>+{ > >>+ struct xsplice_elf elf; > > > >Wait a minute? We ditch it after this? > > > >>+ int rc = 0; > >>+ > >>+ rc = xsplice_verify_elf(raw, len); > >>+ if ( rc ) > >>+ return rc; > >>+ > >>+ rc = xsplice_elf_load(&elf, raw, len); > >>+ if ( rc ) > >>+ return rc; > >>+ > >>+ rc = move_module(payload, &elf); > >>+ if ( rc ) > >>+ goto err_elf; > >>+ > >>+ rc = resolve_symbols(&elf); > >>+ if ( rc ) > >>+ goto err_module; > >>+ > >>+ rc = perform_relocs(&elf); > >>+ if ( rc ) > >>+ goto err_module; > >>+ > > > >Shouldn't you call xsplice_elf_free(&elf) here? Or > >hook up the elf to the 'struct payload'? > > > > > >If not, who is going to clean up elf->sec and elf->sym when the > >payload is unloaded? > > Yes, I forgot to free it here. > > >>+ return 0; > >>+ > >>+ err_module: > >>+ free_module(payload); > >>+ err_elf: > >>+ xsplice_elf_free(&elf); > >>+ > >>+ return rc; > >>+} > >>+ > >> static int __init xsplice_init(void) > >> { > >> register_keyhandler('x', xsplice_printall, "print xsplicing info", 1); > >>diff --git a/xen/include/asm-x86/x86_64/page.h > >>b/xen/include/asm-x86/x86_64/page.h > >>index 19ab4d0..e6f08e9 100644 > >>--- a/xen/include/asm-x86/x86_64/page.h > >>+++ b/xen/include/asm-x86/x86_64/page.h > >>@@ -38,6 +38,8 @@ > >> #include <xen/pdx.h> > >> > >> extern unsigned long xen_virt_end; > >>+extern unsigned long module_virt_start; > >>+extern unsigned long module_virt_end; > >> > >> #define spage_to_pdx(spg) (((spg) - > >> spage_table)<<(SUPERPAGE_SHIFT-PAGE_SHIFT)) > >> #define pdx_to_spage(pdx) (spage_table + > >> ((pdx)>>(SUPERPAGE_SHIFT-PAGE_SHIFT))) > >>diff --git a/xen/include/xen/xsplice.h b/xen/include/xen/xsplice.h > >>index 41e28da..a3946a3 100644 > >>--- a/xen/include/xen/xsplice.h > >>+++ b/xen/include/xen/xsplice.h > >>@@ -1,9 +1,31 @@ > >> #ifndef __XEN_XSPLICE_H__ > >> #define __XEN_XSPLICE_H__ > >> > >>+struct xsplice_elf; > >>+struct xsplice_elf_sec; > >>+struct xsplice_elf_sym; > >>+ > >>+struct xsplice_patch_func { > >>+ unsigned long new_addr; > >>+ unsigned long new_size; > >>+ unsigned long old_addr; > >>+ unsigned long old_size; > >>+ char *name; > >>+ unsigned char undo[8]; > >>+}; > > > >We don't use them in this patch. They could be moved to another patch. > > OK. > > -- > Ross Lagerwall _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |