Passing multiple modules to Domain0
PATCH 1/1 Passing multiple modules to Domain0
Back in January, Samuel Thibault expressed interest in some patches of ours for passing multiple modules from GRUB to a domain. As it turns out, Samuel was mostly interested in this functionality for domU:s, whereas our patches are only for dom0.
Anyways, if anyone find them useful, here are the patches - perhaps it can inform the development of domU support.
I also have a modified mini-os domain that demonstrates how the modules can be picked up in Domain 0. I can send the patches for this demo if anyone is interested.
All the best,
Magnus
--
This is a patch for passing in all grub modules to Domain0 (with the exception of Domain0 itself and the XSM module, if present). It is enabled by passing the option "multimodules" to xen. Implemented for x86 and x86_64.
When enabled, mod_start and mod_len in start_info_t will have a different interpretation. Instead of pointing to one single module (the ramdisk), mod_start will point to an array of struct v_module's:
struct v_module {
unsigned long mod_start;
unsigned long mod_end;
unsigned long string;
};and mod_len will give the number of elements in this array. Each entry has the virtual addresses to the beginning and end of a module, and the module's command line, as passed in by grub. This all corresponds to module_t in multiboot.h, except we use virtual addresses instead of physical 32-bit addresses.
The argument "multimodules" is also passed on to Domain0, so that it can know how to interpret mod_start and mod_len in start_info_t.
xen/arch/x86/domain_build.c +115 -14
@@ -193,10 +193,104 @@ static void __init process_dom0_ioports_ } } +unsigned long __init modules_size (v_module_t *mods, +unsigned int mods_start, +unsigned int mods_end, +int multimodules, +int physical) +{ +unsigned long mods_size; +unsigned int i; + + mods_size = mods_end > mods_start ? + mods[mods_end-1 ].mod_end - mods[mods_start].mod_start :0 ; +if ( multimodules ) + { +/* Add space for module strings and a v_module_t array */ +for ( i = mods_start; i < mods_end; i++ ) { + mods_size += mods[i].string + ?strlen (physical ? (char *)__va (mods[i].string) + : (char *)mods[i].string) +1 + :0 ; + mods_size +=sizeof (v_module_t); + } + } +return mods_size; +} + +static unsigned long __init get_virtual (int physical,unsigned long addr) +{ +return physical ? (unsigned long )maddr_to_bootstrap_virt (addr) : addr; +} + +v_module_t *__init copy_modules (unsigned long _dest, +v_module_t *mods, +unsigned int mods_start, +unsigned int mods_end, +int multimodules, +int physical) +{ +unsigned long dest =get_virtual (physical, _dest); +unsigned long len = mods[mods_end-1 ].mod_end - mods[mods_start].mod_start; +v_module_t *newmods =0 ; + +if ( multimodules ) + { +/* Check that source and destination don't overlap in a way that +* causes us to step on the source as we copy, because we aren't +* clever enough to handle that. */ +unsigned long mods_size =modules_size (mods, mods_start, mods_end, + multimodules, physical); +unsigned long source =get_virtual (physical, mods[0 ].mod_start); +BUG_ON (dest >= source && dest < source+mods_size); + } + +if ( physical ) +move_memory (_dest, mods[mods_start].mod_start, mods[mods_end-1 ].mod_end); +else +memcpy ((void *)dest, + (void *)(get_virtual (physical, mods[mods_start].mod_start)), len); + +if ( multimodules ) + { +/* Create module array and copy strings */ +v_module_t *p = (v_module_t *) ((char *)dest + len); +char *strings; +int i; + + newmods = p; +for (i = mods_start; i < mods_end; i++,p++) + { + p->mod_start = dest + mods[i].mod_start + - mods[mods_start].mod_start; + p->mod_end = dest + mods[i].mod_end - mods[mods_start].mod_start; + } + strings = (char *)p; + p = newmods; +for (i = mods_start; i < mods_end; i++, p++) + { +if (mods[i].string) + { + p->string = (unsigned long )strings; +strlcpy (strings, (physical ?__va (mods[i].string) + : (char *)mods[i].string), +MAX_GUEST_CMDLINE ); + strings +=strlen (strings) +1 ; + }else { + p->string =0 ; + } + } + } +return newmods; +} +int __init construct_dom0 (struct domain *d, -unsigned long _image_start,unsigned long image_len, -unsigned long _initrd_start,unsigned long initrd_len, +unsigned long _image_start, +int multimodules, +v_module_t *mods, +unsigned int mods_start, +unsigned int mods_end,char *cmdline) {int i, rc, compatible, compat32, order, machine;
@@ -207,17 +301,13 @@ int __init construct_dom0(unsigned long alloc_spfn;unsigned long alloc_epfn;unsigned long count; +unsigned long mods_size; +unsigned long initrd_len;struct page_info *page =NULL ;start_info_t *si;struct vcpu *v = d->vcpu[0 ];unsigned long long value; -#if defined(__i386__) -char *image_start = (char *)_image_start;/* use lowmem mappings */ -char *initrd_start = (char *)_initrd_start;/* use lowmem mappings */ -#elif defined(__x86_64__) -char *image_start =__va (_image_start); -char *initrd_start =__va (_initrd_start); -#endif +char *image_start =maddr_to_bootstrap_virt ((char *)_image_start);#if CONFIG_PAGING_LEVELS >=4 l4_pgentry_t *l4tab =NULL , *l4start =NULL ;#endif
@@ -263,7 +353,10 @@ int __init construct_dom0( nr_pages =compute_dom0_nr_pages (); -if ( (rc =elf_init (&elf, image_start, image_len)) !=0 ) + mods_size =modules_size (mods, mods_start, mods_end, multimodules,0 ); + +if ( (rc =elf_init (&elf, image_start, + mods[0 ].mod_end - mods[0 ].mod_start)) !=0 )return rc;#ifdef VERBOSE elf_set_verbose (&elf);
@@ -380,7 +473,7 @@ int __init construct_dom0( vkern_start = parms.virt_kstart; vkern_end = parms.virt_kend; vinitrd_start =round_pgup (vkern_end); - vinitrd_end = vinitrd_start + initrd_len; + vinitrd_end = vinitrd_start + mods_size; vphysmap_start =round_pgup (vinitrd_end); vphysmap_end = vphysmap_start + (nr_pages * (!is_pv_32on64_domain(d) ? sizeof(unsigned long) :
@@ -803,9 +896,17 @@ int __init construct_dom0(hypercall_page_initialise (d, (void *)(unsigned long )parms.virt_hypercall); } -/* Copy the initial ramdisk. */ -if ( initrd_len !=0 ) -memcpy ((void *)vinitrd_start, initrd_start, initrd_len); + initrd_len = mods_size; + +if ( mods_size !=0 ) { +v_module_t *newmods =copy_modules (vinitrd_start, mods, mods_start, + mods_end, multimodules,0 ); +if ( multimodules ) + { + vinitrd_start = (unsigned long )newmods; + initrd_len = mods_end - mods_start; + } + }/* Free temporary buffers. */ discard_initial_images ();
xen/arch/x86/setup.c +36 -24
119 lines not on this page · raw message
xen/include/asm-x86/page.h +6 -0
@@ -248,6 +248,12 @@ void clear_page_sse2(void *);#define pfn_to_paddr (pfn) ((paddr_t)(pfn) << PAGE_SHIFT)#define paddr_to_pfn (pa) ((unsigned long)((pa) >> PAGE_SHIFT)) +#if defined(CONFIG_X86_64 ) +#define maddr_to_bootstrap_virt (m) maddr_to_virt(m) +#else +#define maddr_to_bootstrap_virt (m) ((void *)(long)(m)) +#endif +#endif /* !defined(__ASSEMBLY__) */ /* High table entries are reserved by the hypervisor. */
xen/include/public/xen.h +14 -2
@@ -541,11 +541,23 @@ struct start_info {unsigned long pt_base;/* VIRTUAL address of page directory. */ unsigned long nr_pt_frames;/* Number of bootstrap p.t. frames. */ unsigned long mfn_list;/* VIRTUAL address of page-frame list. */ -unsigned long mod_start;/* VIRTUAL address of pre-loaded module. */ -unsigned long mod_len;/* Size (bytes) of pre-loaded module. */ +unsigned long mod_start;/* VIRTUAL address of pre-loaded module, */ +/* or VIRTUAL address of v_module_t array.*/ +unsigned long mod_len;/* Size (bytes) of pre-loaded module, */ +/* or length of v_module_t array. */ int8_t cmd_line[MAX_GUEST_CMDLINE ]; };typedef struct start_info start_info_t ; + +/* This corresponds to module_t in multiboot.h, but with virtual +* addresses. +*/ +struct v_module { +unsigned long mod_start; +unsigned long mod_end; +unsigned long string; +}; +typedef struct v_module v_module_t ;/* New console union for dom0 introduced in 0x00030203. */ #if __XEN_INTERFACE_VERSION__ <0x00030203
xen/include/xen/sched.h +29 -2
@@ -315,11 +315,38 @@ struct domain *domain_create(#define _DOMCRF_hap 1#define DOMCRF_hap (1U<<_DOMCRF_hap) +/* Compute size of all modules in mods, starting from mods_start, +* ending at mods_end - 1. Include size of module parameters and mods +* array itself if multimodules is set. If physical is set, assume +* physical addresses. */ +unsigned long modules_size (v_module_t *mods, +unsigned int mods_start, +unsigned int mods_end, +int multimodules, +int physical); + +/* Copy all modules in mods, starting from mods_start, ending at +* mods_end - 1, into dest. Copy module parameters and mods array +* itself if multimodules is set. If physical is set, assume physical +* addresses. */ +v_module_t *copy_modules (unsigned long dest, +v_module_t *mods, +unsigned int mods_start, +unsigned int mods_end, +int multimodules, +int physical); +int construct_dom0 (struct domain *d, -unsigned long image_start,unsigned long image_len, -unsigned long initrd_start,unsigned long initrd_len, +unsigned long image_start, +int multimodules, +v_module_t *mods, +unsigned int mods_start, +unsigned int mods_end,char *cmdline); + +void move_memory (unsigned long dst, +unsigned long src_start,unsigned long src_end);/* * rcu_lock_domain_by_id() is more efficient than get_domain_by_id().
Quoted 6 lines · Samuel Thibault
Quoted 2 lines · Magnus Carlsson, le Mon 21 Apr 2008 11:32:38 -0700, a écrit :
The argument "multimodules" is also passed on to Domain0, so that it can know how to interpret
mod_startandmod_leninstart_info_t.I proposed to use an
SIF_somethingin the "flags" member ofstart_info_tinstead.
Sounds like a good idea!
Magnus
Quoted 2 lines
Samuel