def collect_xml(self, iguana_el, ignore_name, namespace, machine, pools, kernel, image): """Handle an Iguana Server Compound Object""" cell = \ kernel.register_cell(iguana_el.name, iguana_el.kernel_heap, max_caps = getattr(iguana_el, "caps", None)) # New namespace for objects living in the root program's PD. ig_namespace = namespace.add_namespace(iguana_el.name) self.namespace = ig_namespace self.s_namespace = self.namespace self.name = iguana_el.name self.space = \ cell.register_space(self.namespace, "MAIN", is_privileged = True, max_clists = getattr(iguana_el, "clists", None), max_spaces = getattr(iguana_el, "spaces", None), max_mutexes = getattr(iguana_el, "mutexes", None), max_threads = getattr(iguana_el, "threads", None), plat_control = \ getattr(iguana_el, "platform_control", False)) self.setup_bootinfo_pools(namespace, pools) self.setup_device_namespace(namespace, machine) self.env = CellEnvironment(iguana_el.name, self.namespace, machine, image, kernel, self.space.mappings) cell.env = self.env pd = weaver.cells.iguana.bootinfo.RootServerPD(iguana_el.name, ig_namespace) # Declare the default memory pools. def_virtpool = getattr(iguana_el, "virtpool", pools.get_default_virtual_pool()) def_physpool = getattr(iguana_el, "physpool", pools.get_default_physical_pool()) def_pager = getattr(iguana_el, "pager", None) def_direct = getattr(iguana_el, "direct", None) # Record any IRQs that are assigned to Iguana for irq_el in iguana_el.find_children("irq"): self.space.register_irq(irq_el.value) self.bootinfo.set_system_default_attrs(def_virtpool, def_physpool, image, def_pager, def_direct) # Iguana is not aware of segment ids. # The old mapping API uses segment 0 for all mapping ops. # Segment 0 needs to cover all of physical memory. # Subsequent segments will be created but never used, # but must still be mapped! # XXX: VVVVV THIS IS PURE EVIL VVVVV physpool_attrs = \ image.new_attrs(self.s_namespace.add_namespace("physpool_hack")) physpool_attrs.phys_addr = 0 #first_phys_base physpool_attrs.size = 0xfffff000 #first_phys_end physpool_attrs.attach = PF_R | PF_W | PF_X physpool_attrs.cache_policy = 0xff # XXX: Define me properly physpool_attrs.mem_type = physpool_attrs.unmapped self.space.register_mapping(physpool_attrs) # XXX: ^^^^^ THIS IS PURE EVIL ^^^^^ filename = os.path.join(iguana_el._path, iguana_el.file) elf = UnpreparedElfFile(filename=filename) pd.set_default_pools(image, self.bootinfo) # Collect the object environment pd.add_env_ms(image, ig_namespace, machine, pools) env, extra_ms = \ collect_environment_element(iguana_el.find_child('environment'), ig_namespace, machine, pools, image, self.bootinfo) segment_els = iguana_el.find_children("segment") segs = collect_elf_segments(elf, image.ROOT_PROGRAM, segment_els, filename, [], ig_namespace, image, machine, pools) self.elf_prog_segments = segs for seg in segs: self.space.register_mapping(seg.attrs) if elf.elf_type != ET_EXEC: raise MergeError, "All the merged ELF files must be of EXEC type." # Find out which version of libokl4 that iguana was built # against sym = elf.find_symbol("okl4_api_version") if sym == None: raise MergeError("Unable to locate the symbol 'okl4_api_version' " "in file \"%s\". Cells must link with libokl4." % filename) self.api_version = elf.get_value(sym.value, sym.size, elf.endianess) if self.api_version == None: raise MergeError("Unable to read the symbol 'okl4_api_version' in " "file \"%s\". Cells must link with libokl4." % filename) # Record any patches being made to the program. patch_els = iguana_el.find_children("patch") for patch in getattr(Iguana_el, "extra_patches", []): addr = get_symbol(elf, patch[0], True) if addr == None: continue addr = int(addr[0])+ int(patch[1]) new_patch = Patch_el(address=hex(addr), bytes=patch[2], value=patch[3]) patch_els.append(new_patch) collect_patches(elf, patch_els, filename, image) for extension_el in iguana_el.find_children("extension"): if not ignore_name.match(extension_el.name): collect_extension_element(extension_el, pd, ig_namespace, elf, image, machine, self.bootinfo, pools) # Collect the main thread. The root program can only have one # thread, so this call chiefly is used to collect information # about the stack. # # The stack is not set up as a memsection, so it is not put in the # object environment. if not hasattr(iguana_el, 'priority'): iguana_el.priority = 255 thread = collect_thread(elf, iguana_el, ignore_name, ig_namespace, image, machine, pools, self.space, entry = elf.entry_point, name = 'iguana', namespace_thread_name = "main", cell_create_thread = True) pd.add_thread(thread) # Collect the heap. Is there no element, create a fake one for # the collection code to use. # # The heap is not set up as a memsection, so it is not put in the # object environment. heap_el = iguana_el.find_child('heap') if heap_el is None: heap_el = ParsedElement('heap') heap_ms = collect_memsection_element(heap_el, ignore_name, ig_namespace, image, machine, pools) pd.attach_heap(heap_ms) self.space.register_mapping(heap_ms.ms.attrs) self.space.register_mapping(thread.get_stack().get_ms().attrs) self.elf_segments.extend([pd.env_ms.get_ms(), thread.get_stack().get_ms(), heap_ms.get_ms()] + [ms.get_ms() for ms in extra_ms]) pd.add_environment(env) pd.utcb_size = image.utcb_size self.bootinfo.add_rootserver_pd(pd) # And now parse the programs and pd's collect_program_pd_elements(iguana_el, ignore_name, ig_namespace, image, machine, self.bootinfo, pools, kernel, cell)
class IguanaCell(Cell): #pylint: disable-msg=R0913 """ Cell for iguana programs, pds, drivers and other matters. """ element = Iguana_el def __init__(self): Cell.__init__(self) self.namespace = None self.bootinfo = weaver.cells.iguana.bootinfo.BootInfo() self.env = None self.api_version = None self.elf_segments = [] self.elf_prog_segments = None self.space = None self.name = None self.s_namespace = None def collect_xml(self, iguana_el, ignore_name, namespace, machine, pools, kernel, image): """Handle an Iguana Server Compound Object""" cell = \ kernel.register_cell(iguana_el.name, iguana_el.kernel_heap, max_caps = getattr(iguana_el, "caps", None)) # New namespace for objects living in the root program's PD. ig_namespace = namespace.add_namespace(iguana_el.name) self.namespace = ig_namespace self.s_namespace = self.namespace self.name = iguana_el.name self.space = \ cell.register_space(self.namespace, "MAIN", is_privileged = True, max_clists = getattr(iguana_el, "clists", None), max_spaces = getattr(iguana_el, "spaces", None), max_mutexes = getattr(iguana_el, "mutexes", None), max_threads = getattr(iguana_el, "threads", None), plat_control = \ getattr(iguana_el, "platform_control", False)) self.setup_bootinfo_pools(namespace, pools) self.setup_device_namespace(namespace, machine) self.env = CellEnvironment(iguana_el.name, self.namespace, machine, image, kernel, self.space.mappings) cell.env = self.env pd = weaver.cells.iguana.bootinfo.RootServerPD(iguana_el.name, ig_namespace) # Declare the default memory pools. def_virtpool = getattr(iguana_el, "virtpool", pools.get_default_virtual_pool()) def_physpool = getattr(iguana_el, "physpool", pools.get_default_physical_pool()) def_pager = getattr(iguana_el, "pager", None) def_direct = getattr(iguana_el, "direct", None) # Record any IRQs that are assigned to Iguana for irq_el in iguana_el.find_children("irq"): self.space.register_irq(irq_el.value) self.bootinfo.set_system_default_attrs(def_virtpool, def_physpool, image, def_pager, def_direct) # Iguana is not aware of segment ids. # The old mapping API uses segment 0 for all mapping ops. # Segment 0 needs to cover all of physical memory. # Subsequent segments will be created but never used, # but must still be mapped! # XXX: VVVVV THIS IS PURE EVIL VVVVV physpool_attrs = \ image.new_attrs(self.s_namespace.add_namespace("physpool_hack")) physpool_attrs.phys_addr = 0 #first_phys_base physpool_attrs.size = 0xfffff000 #first_phys_end physpool_attrs.attach = PF_R | PF_W | PF_X physpool_attrs.cache_policy = 0xff # XXX: Define me properly physpool_attrs.mem_type = physpool_attrs.unmapped self.space.register_mapping(physpool_attrs) # XXX: ^^^^^ THIS IS PURE EVIL ^^^^^ filename = os.path.join(iguana_el._path, iguana_el.file) elf = UnpreparedElfFile(filename=filename) pd.set_default_pools(image, self.bootinfo) # Collect the object environment pd.add_env_ms(image, ig_namespace, machine, pools) env, extra_ms = \ collect_environment_element(iguana_el.find_child('environment'), ig_namespace, machine, pools, image, self.bootinfo) segment_els = iguana_el.find_children("segment") segs = collect_elf_segments(elf, image.ROOT_PROGRAM, segment_els, filename, [], ig_namespace, image, machine, pools) self.elf_prog_segments = segs for seg in segs: self.space.register_mapping(seg.attrs) if elf.elf_type != ET_EXEC: raise MergeError, "All the merged ELF files must be of EXEC type." # Find out which version of libokl4 that iguana was built # against sym = elf.find_symbol("okl4_api_version") if sym == None: raise MergeError("Unable to locate the symbol 'okl4_api_version' " "in file \"%s\". Cells must link with libokl4." % filename) self.api_version = elf.get_value(sym.value, sym.size, elf.endianess) if self.api_version == None: raise MergeError("Unable to read the symbol 'okl4_api_version' in " "file \"%s\". Cells must link with libokl4." % filename) # Record any patches being made to the program. patch_els = iguana_el.find_children("patch") for patch in getattr(Iguana_el, "extra_patches", []): addr = get_symbol(elf, patch[0], True) if addr == None: continue addr = int(addr[0])+ int(patch[1]) new_patch = Patch_el(address=hex(addr), bytes=patch[2], value=patch[3]) patch_els.append(new_patch) collect_patches(elf, patch_els, filename, image) for extension_el in iguana_el.find_children("extension"): if not ignore_name.match(extension_el.name): collect_extension_element(extension_el, pd, ig_namespace, elf, image, machine, self.bootinfo, pools) # Collect the main thread. The root program can only have one # thread, so this call chiefly is used to collect information # about the stack. # # The stack is not set up as a memsection, so it is not put in the # object environment. if not hasattr(iguana_el, 'priority'): iguana_el.priority = 255 thread = collect_thread(elf, iguana_el, ignore_name, ig_namespace, image, machine, pools, self.space, entry = elf.entry_point, name = 'iguana', namespace_thread_name = "main", cell_create_thread = True) pd.add_thread(thread) # Collect the heap. Is there no element, create a fake one for # the collection code to use. # # The heap is not set up as a memsection, so it is not put in the # object environment. heap_el = iguana_el.find_child('heap') if heap_el is None: heap_el = ParsedElement('heap') heap_ms = collect_memsection_element(heap_el, ignore_name, ig_namespace, image, machine, pools) pd.attach_heap(heap_ms) self.space.register_mapping(heap_ms.ms.attrs) self.space.register_mapping(thread.get_stack().get_ms().attrs) self.elf_segments.extend([pd.env_ms.get_ms(), thread.get_stack().get_ms(), heap_ms.get_ms()] + [ms.get_ms() for ms in extra_ms]) pd.add_environment(env) pd.utcb_size = image.utcb_size self.bootinfo.add_rootserver_pd(pd) # And now parse the programs and pd's collect_program_pd_elements(iguana_el, ignore_name, ig_namespace, image, machine, self.bootinfo, pools, kernel, cell) #def generate_dynamic_segments(self, namespace, machine, pools, # kernel, image): def generate_dynamic_segments(self, _, machine, pools, kernel, image): """ Create bootinfo segment and environment buffers. """ self.bootinfo.create_dynamic_segments(self, self.namespace, image, kernel, machine, pools, self.bootinfo) self.space.register_mapping(self.bootinfo.ms.attrs) self.space.utcb = self.bootinfo.utcb self.env.generate_dynamic_segments(self, image, machine, pools) self.elf_segments.append(self.env.memsect) self.group_elf_segments(image) def generate_init(self, machine, pools, kernel, image): """ Generate the bootinfo script for the cell, placing it into a segment. """ self.bootinfo.generate(image, kernel, machine, self.bootinfo) self.env.generate_init(machine, pools, kernel, image) def get_cell_api_version(self): """ Return the libOKL4 API versions that the cell initial program was build against. """ return self.api_version # This used to be done in pools_xml.py but since bootinfo has become part # of the iguana cell we need to do it here def setup_bootinfo_pools(self, namespace, pools): """ Map elfweaver pools into iguana pools. """ for pool in pools.get_virtual_pools(): boot_pool = \ weaver.cells.iguana.bootinfo.VirtPool(pool.get_name(), pool) self.bootinfo.add_virtpool(boot_pool) # New namespace for the memory pool's caps. new_namespace = namespace.add_namespace(pool.get_name()) if pool.get_name() == "direct": master = weaver.cells.iguana.bootinfo.Cap("master", ["master"]) boot_pool.add_cap(master) new_namespace.add(master.get_name(), master) else: # Add the standard caps for the pool. create_standard_caps(boot_pool, new_namespace) for pool in pools.get_physical_pools(): boot_pool = \ weaver.cells.iguana.bootinfo.PhysPool(pool.get_name(), pool) self.bootinfo.add_physpool(boot_pool) # New namespace for the memory pool's caps. new_namespace = namespace.add_namespace(pool.get_name()) # Add the standard caps for the pool. create_standard_caps(boot_pool, new_namespace) def setup_device_namespace(self, namespace, machine): """ Populate the /dev namespace with Iguana aliases to the physical devices. """ dev_ns = namespace.root.add_namespace("dev") for device in machine.physical_device.values(): create_alias_cap(PhysicalDevice(device), dev_ns) def group_elf_segments(self, image): """ Group ELF segments together in a way that avoids domain faults and reduces final image size. - Any memsection that is under 1M goes into Group 1. - Any memsection above 1M but has contents, Group 2. - Any memsection above 1M which is empty, Group 3. """ groups = [[], [], []] for seg in self.elf_segments: if seg.get_attrs().size <= 0x100000: idx = 0 elif seg.get_attrs().data or seg.get_attrs().file: idx = 1 else: idx = 2 groups[idx].append(seg) for grp in groups: grp.sort(lambda x, y: int(x.get_attrs().size - y.get_attrs().size)) if grp is groups[0]: grp = self.elf_prog_segments + grp image.add_group(None, grp)
def collect_xml(self, okl4_el, ignore_name, namespace, machine, pools, kernel, image): """Handle an Iguana Server Compound Object""" self.cell = \ kernel.register_cell(okl4_el.name, okl4_el.kernel_heap, max_caps = getattr(okl4_el, "caps", None), max_priority = getattr(okl4_el, "max_priority", None)) self.name = okl4_el.name self.namespace = namespace.add_namespace(self.name) self.space = \ self.cell.register_space(self.namespace, "MAIN", is_privileged = True, max_clists = getattr(okl4_el, "clists", None), max_spaces = getattr(okl4_el, "spaces", None), max_mutexes = getattr(okl4_el, "mutexes", None), max_threads = getattr(okl4_el, "threads", None), max_priority = getattr(okl4_el, "max_priority", None), plat_control = \ getattr(okl4_el, "platform_control", False)) image.push_attrs(virtual=getattr(okl4_el, "virtpool", None), physical=getattr(okl4_el, "physpool", None), pager=make_pager_attr(getattr(okl4_el, "pager", None)), direct=getattr(okl4_el, "direct", None)) (self.def_virtpool, self.def_physpool) = image.current_pools() self.collect_mutexes(okl4_el, self.namespace, self.space) env_el = okl4_el.find_child("environment") self.env = CellEnvironment(okl4_el.name, self.namespace, machine, image, kernel, self.space.mappings) if env_el != None: self._collect_environment(env_el, self.env) # Set these up now even though we can't actually assign values # till later self.phys_attrs = image.new_attrs( self.namespace.add_namespace("default_physpool")) self.phys_attrs.attach = PF_R | PF_W | PF_X self.phys_attrs.mem_type = self.phys_attrs.unmapped mapping = self.space.register_mapping(self.phys_attrs) self.env.add_physmem_segpool_entry("MAIN_PHYSMEM_SEGPOOL", mapping) self.virt_attrs = image.new_attrs( self.namespace.add_namespace("default_virtpool")) self.env.add_virtmem_pool_entry("MAIN_VIRTMEM_POOL", self.virt_attrs) self.space.utcb = image.new_attrs( self.namespace.add_namespace("main_utcb_area")) self.space.utcb.attach = PF_R filename = os.path.join(okl4_el._path, okl4_el.file) self.elf = UnpreparedElfFile(filename=filename) if self.elf.elf_type != ET_EXEC: raise MergeError("All the merged ELF files must be of EXEC type.") # Find out which version of libokl4 that the cell was built # against sym = self.elf.find_symbol("okl4_api_version") if sym == None: raise MergeError( "Unable to locate the symbol 'okl4_api_version' in file \"%s\". Cells must link with libokl4." % filename) self.api_version = self.elf.get_value(sym.value, sym.size, self.elf.endianess) if self.api_version == None: raise MergeError( "Unable to read the symbol 'okl4_api_version' in file \"%s\". Cells must link with libokl4." % filename) self.env.add_elf_info_entry(os.path.basename(okl4_el.file), image.PROGRAM, self.elf.entry_point) segment_els = okl4_el.find_children("segment") segs = collect_elf_segments(self.elf, image.PROGRAM, segment_els, filename, [], self.namespace, image, machine, pools) self.elf_prog_segments = segs for seg in segs: self.env.add_elf_segment_entry( okl4_el.name + '.' + seg.attrs.ns_node.name, seg.segment) seg_ns = seg.attrs.ns_node mapping = self.space.register_mapping(seg.attrs) self.add_standard_mem_caps(seg_ns, mapping, seg.attrs) patch_els = okl4_el.find_children("patch") collect_patches(self.elf, patch_els, filename, image) # Record any IRQs that are assigned to the initial program. for irq_el in okl4_el.find_children("irq"): self.space.register_irq(irq_el.value) self.env.add_device_irq_list("NO_DEVICE", [irq_el.value for irq_el \ in okl4_el.find_children("irq")]) # Collect the implicit thread if not hasattr(okl4_el, 'priority'): okl4_el.priority = kernel.kernel.MAX_PRIORITY threads = [] threads.append( self.collect_thread(self.elf, okl4_el, self.namespace, image, machine, pools, kernel, self.space, self.elf.entry_point, "main", True)) # FIXME: Need to check up on actual entry point's for thread_el in okl4_el.find_children("thread"): threads.append( self.collect_thread(self.elf, thread_el, self.namespace, image, machine, pools, kernel, self.space, "thread_start", cell_create_thread=True)) device_mem = \ self.collect_use_devices(okl4_el, self.space, self.namespace, image, machine, pools) memsection_objs = \ self.collect_memsections(okl4_el, self.space, self.namespace, image, machine, pools) # Collect all data for any extra spaces defined in the XML for space_el in okl4_el.find_children("space"): space_ns = self.namespace.add_namespace(space_el.name) space = self.cell.register_space(space_ns, space_el.name, max_priority = getattr(space_el, "max_priority", \ getattr(okl4_el, "max_priority", None))) image.push_attrs(virtual=getattr(space_el, "virtpool", None), physical=getattr(space_el, "physpool", None), pager=make_pager_attr( getattr(space_el, "pager", None)), direct=getattr(space_el, "direct", None)) for thread_el in space_el.find_children("thread"): threads.append( self.collect_thread(self.elf, thread_el, space_ns, image, machine, pools, kernel, space, "thread_start", cell_create_thread=True)) self.collect_mutexes(space_el, space_ns, space) device_mem.extend( self.collect_use_devices(space_el, space, space_ns, image, machine, pools)) memsection_objs.extend( self.collect_memsections(space_el, space, space_ns, image, machine, pools)) self.env.add_kspace_entry(space_el.name + "_KSPACE", space) space.utcb = image.new_attrs( space_ns.add_namespace(space_el.name + "_utcb_area")) space.utcb.attach = PF_R # Weave a kclist for the main space. main_kclist = self.env.add_kclist_entry("MAIN_KCLIST", self.cell) # Weave the root kspace object. main_kspace = self.env.add_kspace_entry("MAIN_KSPACE", self.space) # Weave the root protection domain object. self.env.add_pd_entry("MAIN_PD", self.space, main_kspace, 32, machine.min_page_size(), self.elf) # Find heap and add it heap_el = okl4_el.find_child('heap') if heap_el is None: heap_el = ParsedElement('heap') heap_attr = collect_memobj_attrs(heap_el, self.namespace, image, machine) if heap_attr.size == None: heap_attr.size = DEFAULT_HEAP_SIZE self.heap_ms = image.add_memsection(heap_attr, machine, pools) self.cell.heap = self.heap_ms.attrs mapping = self.space.register_mapping(self.heap_ms.attrs) self.add_standard_mem_caps(heap_attr.ns_node, mapping, heap_attr) self.elf_segments = \ [thread.get_stack_ms() for thread in threads] + \ [self.heap_ms] + memsection_objs + device_mem self.env.add_kernel_info_entry(0, 0, kernel) # Add command line arguments commandline_el = okl4_el.find_child("commandline") if commandline_el is not None: args = [ arg_el.value for arg_el in commandline_el.find_children("arg") ] else: args = [] self.env.add_arg_list(args) self.cell.env = self.env
class OKL4Cell(Cell): # disable: Too many arguments # pylint: disable-msg=R0913 """ Cell for iguana programs, pds, drivers and other matters. """ element = OKL4_el def __init__(self): Cell.__init__(self) self.name = "" self.heap_ms = None self.stack_ms = None self.utcb_ms = None self.elf = None self.api_version = None self.elf_segments = [] self.elf_prog_segments = None self.def_virtpool = None self.def_physpool = None self.phys_addr = None self.virt_addr = None self.phys_attrs = None self.virt_attrs = None self.env = None self.cell = None self.namespace = None self.space = None def _collect_environment(self, env_el, env): """ Collect the details of the environmen element. """ # Collect any custom entries in the environment. if env_el is not None: for entry_el in env_el.find_children('entry'): cap_name = None attach = None if hasattr(entry_el, 'value'): env.add_value_entry(entry_el.key, entry_el.value) else: if not hasattr(entry_el, 'cap'): raise MergeError, 'Value or cap attribute required.' cap_name = entry_el.cap if hasattr(entry_el, 'attach'): attach = attach_to_elf_flags(entry_el.attach) env.add_cap_entry(entry_el.key, cap_name=cap_name, attach=attach) def collect_xml(self, okl4_el, ignore_name, namespace, machine, pools, kernel, image): """Handle an Iguana Server Compound Object""" self.cell = \ kernel.register_cell(okl4_el.name, okl4_el.kernel_heap, max_caps = getattr(okl4_el, "caps", None), max_priority = getattr(okl4_el, "max_priority", None)) self.name = okl4_el.name self.namespace = namespace.add_namespace(self.name) self.space = \ self.cell.register_space(self.namespace, "MAIN", is_privileged = True, max_clists = getattr(okl4_el, "clists", None), max_spaces = getattr(okl4_el, "spaces", None), max_mutexes = getattr(okl4_el, "mutexes", None), max_threads = getattr(okl4_el, "threads", None), max_priority = getattr(okl4_el, "max_priority", None), plat_control = \ getattr(okl4_el, "platform_control", False)) image.push_attrs(virtual=getattr(okl4_el, "virtpool", None), physical=getattr(okl4_el, "physpool", None), pager=make_pager_attr(getattr(okl4_el, "pager", None)), direct=getattr(okl4_el, "direct", None)) (self.def_virtpool, self.def_physpool) = image.current_pools() self.collect_mutexes(okl4_el, self.namespace, self.space) env_el = okl4_el.find_child("environment") self.env = CellEnvironment(okl4_el.name, self.namespace, machine, image, kernel, self.space.mappings) if env_el != None: self._collect_environment(env_el, self.env) # Set these up now even though we can't actually assign values # till later self.phys_attrs = image.new_attrs( self.namespace.add_namespace("default_physpool")) self.phys_attrs.attach = PF_R | PF_W | PF_X self.phys_attrs.mem_type = self.phys_attrs.unmapped mapping = self.space.register_mapping(self.phys_attrs) self.env.add_physmem_segpool_entry("MAIN_PHYSMEM_SEGPOOL", mapping) self.virt_attrs = image.new_attrs( self.namespace.add_namespace("default_virtpool")) self.env.add_virtmem_pool_entry("MAIN_VIRTMEM_POOL", self.virt_attrs) self.space.utcb = image.new_attrs( self.namespace.add_namespace("main_utcb_area")) self.space.utcb.attach = PF_R filename = os.path.join(okl4_el._path, okl4_el.file) self.elf = UnpreparedElfFile(filename=filename) if self.elf.elf_type != ET_EXEC: raise MergeError("All the merged ELF files must be of EXEC type.") # Find out which version of libokl4 that the cell was built # against sym = self.elf.find_symbol("okl4_api_version") if sym == None: raise MergeError( "Unable to locate the symbol 'okl4_api_version' in file \"%s\". Cells must link with libokl4." % filename) self.api_version = self.elf.get_value(sym.value, sym.size, self.elf.endianess) if self.api_version == None: raise MergeError( "Unable to read the symbol 'okl4_api_version' in file \"%s\". Cells must link with libokl4." % filename) self.env.add_elf_info_entry(os.path.basename(okl4_el.file), image.PROGRAM, self.elf.entry_point) segment_els = okl4_el.find_children("segment") segs = collect_elf_segments(self.elf, image.PROGRAM, segment_els, filename, [], self.namespace, image, machine, pools) self.elf_prog_segments = segs for seg in segs: self.env.add_elf_segment_entry( okl4_el.name + '.' + seg.attrs.ns_node.name, seg.segment) seg_ns = seg.attrs.ns_node mapping = self.space.register_mapping(seg.attrs) self.add_standard_mem_caps(seg_ns, mapping, seg.attrs) patch_els = okl4_el.find_children("patch") collect_patches(self.elf, patch_els, filename, image) # Record any IRQs that are assigned to the initial program. for irq_el in okl4_el.find_children("irq"): self.space.register_irq(irq_el.value) self.env.add_device_irq_list("NO_DEVICE", [irq_el.value for irq_el \ in okl4_el.find_children("irq")]) # Collect the implicit thread if not hasattr(okl4_el, 'priority'): okl4_el.priority = kernel.kernel.MAX_PRIORITY threads = [] threads.append( self.collect_thread(self.elf, okl4_el, self.namespace, image, machine, pools, kernel, self.space, self.elf.entry_point, "main", True)) # FIXME: Need to check up on actual entry point's for thread_el in okl4_el.find_children("thread"): threads.append( self.collect_thread(self.elf, thread_el, self.namespace, image, machine, pools, kernel, self.space, "thread_start", cell_create_thread=True)) device_mem = \ self.collect_use_devices(okl4_el, self.space, self.namespace, image, machine, pools) memsection_objs = \ self.collect_memsections(okl4_el, self.space, self.namespace, image, machine, pools) # Collect all data for any extra spaces defined in the XML for space_el in okl4_el.find_children("space"): space_ns = self.namespace.add_namespace(space_el.name) space = self.cell.register_space(space_ns, space_el.name, max_priority = getattr(space_el, "max_priority", \ getattr(okl4_el, "max_priority", None))) image.push_attrs(virtual=getattr(space_el, "virtpool", None), physical=getattr(space_el, "physpool", None), pager=make_pager_attr( getattr(space_el, "pager", None)), direct=getattr(space_el, "direct", None)) for thread_el in space_el.find_children("thread"): threads.append( self.collect_thread(self.elf, thread_el, space_ns, image, machine, pools, kernel, space, "thread_start", cell_create_thread=True)) self.collect_mutexes(space_el, space_ns, space) device_mem.extend( self.collect_use_devices(space_el, space, space_ns, image, machine, pools)) memsection_objs.extend( self.collect_memsections(space_el, space, space_ns, image, machine, pools)) self.env.add_kspace_entry(space_el.name + "_KSPACE", space) space.utcb = image.new_attrs( space_ns.add_namespace(space_el.name + "_utcb_area")) space.utcb.attach = PF_R # Weave a kclist for the main space. main_kclist = self.env.add_kclist_entry("MAIN_KCLIST", self.cell) # Weave the root kspace object. main_kspace = self.env.add_kspace_entry("MAIN_KSPACE", self.space) # Weave the root protection domain object. self.env.add_pd_entry("MAIN_PD", self.space, main_kspace, 32, machine.min_page_size(), self.elf) # Find heap and add it heap_el = okl4_el.find_child('heap') if heap_el is None: heap_el = ParsedElement('heap') heap_attr = collect_memobj_attrs(heap_el, self.namespace, image, machine) if heap_attr.size == None: heap_attr.size = DEFAULT_HEAP_SIZE self.heap_ms = image.add_memsection(heap_attr, machine, pools) self.cell.heap = self.heap_ms.attrs mapping = self.space.register_mapping(self.heap_ms.attrs) self.add_standard_mem_caps(heap_attr.ns_node, mapping, heap_attr) self.elf_segments = \ [thread.get_stack_ms() for thread in threads] + \ [self.heap_ms] + memsection_objs + device_mem self.env.add_kernel_info_entry(0, 0, kernel) # Add command line arguments commandline_el = okl4_el.find_child("commandline") if commandline_el is not None: args = [ arg_el.value for arg_el in commandline_el.find_children("arg") ] else: args = [] self.env.add_arg_list(args) self.cell.env = self.env def get_cell_api_version(self): """ Return the libOKL4 API versions that the cell initial program was build against. """ return self.api_version def generate_dynamic_segments(self, namespace, machine, pools, kernel, image): """ Create bootinfo segment and environment buffers. """ utcb_mss = [] for space in self.cell.spaces: space.utcb.size = align_up(space.max_threads * image.utcb_size, machine.min_page_size()) # A space with no threads will get a 0 size as align_up doesn't # change a 0, so we explicity set it to at least one page if space.utcb.size == 0: space.utcb.size = machine.min_page_size() utcb_ms = image.add_utcb_area(space.utcb) utcb_mss.append(utcb_ms) kspace = None for (x, _) in self.env.space_list: if x.space.id == space.id: kspace = x if image.utcb_size: self.env.add_utcb_area_entry("UTCB_AREA_%d" % space.id, space, kspace, image) self.env.add_bitmap_allocator_entry("MAIN_SPACE_ID_POOL", *self.cell.space_list) self.env.add_bitmap_allocator_entry("MAIN_CLIST_ID_POOL", *self.cell.cap_list) self.env.add_bitmap_allocator_entry("MAIN_MUTEX_ID_POOL", *self.cell.mutex_list) self.env.add_int_entry("MAIN_SPACE_ID", self.space.id) self.env.add_int_entry("MAIN_CLIST_ID", self.cell.clist_id) self.env.generate_dynamic_segments(self, image, machine, pools) self.elf_segments.extend(utcb_mss + [self.env.memsect]) self.group_elf_segments(image) def generate_init(self, machine, pools, kernel, image): """ Generate the bootinfo script for the cell, placing it into a segment. """ self.set_free_pools(pools, kernel, image, machine) self.env.generate_init(machine, pools, kernel, image) def set_free_pools(self, pools, kernel, image, machine): phys_free = \ pools.get_physical_pool_by_name(self.def_physpool).get_freelist()[:] virt_free = \ pools.get_virtual_pool_by_name(self.def_virtpool).get_freelist()[:] # Sort biggest to smallest phys_free.sort(key=lambda x: x[0] - x[1]) virt_free.sort(key=lambda x: x[0] - x[1]) # Extract the biggest regions and remove them from the lists. (phys_base, phys_end, _) = phys_free[0] del phys_free[0] (virt_base, virt_end, _) = virt_free[0] del virt_free[0] self.phys_attrs.size = phys_end - phys_base + 1 self.phys_attrs.phys_addr = phys_base def_phys_ms = image.add_memsection(self.phys_attrs, machine, pools) image.add_group(0, [def_phys_ms]) self.virt_attrs.size = virt_end - virt_base + 1 self.virt_attrs.virt_addr = virt_base self.env.add_kernel_info_entry(phys_base, phys_end, kernel) def collect_thread(self, elf, el, namespace, image, machine, pools, kernel, space, entry, thread_name=None, cell_create_thread=False): """Collect the attributes of a thread element.""" if entry is None: raise MergeError, "No entry point specified for thread %s" % el.name user_main = getattr(el, 'start', entry) entry = start_to_value(entry, elf) user_main = start_to_value(user_main, elf) priority = getattr(el, 'priority', kernel.kernel.DEFAULT_PRIORITY) physpool = getattr(el, 'physpool', None) virtpool = getattr(el, 'virtpool', None) # New namespace for objects living in the thread. if thread_name == None: thread_name = el.name thread_namespace = namespace.add_namespace(thread_name) # Push the overriding pools for the thread. image.push_attrs(virtual=virtpool, physical=physpool) utcb = image.new_attrs(thread_namespace.add_namespace("utcb")) # Create the cell thread and assign the entry point thread = space.register_thread(entry, user_main, utcb, priority, create=cell_create_thread) thread_namespace.add('master', ThreadCellCap('master', thread)) # Collect the stack. Is there no element, create a fake one for # the collection code to use. stack_el = el.find_child('stack') if stack_el is None: stack_el = ParsedElement('stack') stack_attr = collect_memobj_attrs(stack_el, thread_namespace, image, machine) if stack_attr.size == None: stack_attr.size = DEFAULT_STACK_SIZE stack_ms = image.add_memsection(stack_attr, machine, pools) mapping = space.register_mapping(stack_ms.attrs) self.add_standard_mem_caps(stack_attr.ns_node, mapping, stack_attr) # Setup the stack for the new cell thread thread.stack = stack_ms.attrs thread.stack_ms = stack_ms # If this is the very first collect_thread call, we assume it is # the cell's main thread and we set the stack_ms accordingly. if self.stack_ms is None: self.stack_ms = stack_ms image.pop_attrs() return thread def collect_use_devices(self, el, space, namespace, image, machine, pools): device_mem = [] for device_el in el.find_children("use_device"): dev = machine.get_phys_device(device_el.name) # Potentially we can have multiple named physical mem sections # each with multiple ranges. for key in dev.physical_mem.keys(): ranges = dev.physical_mem[key] index = 0 for (base, size, rights, cache_policy) in ranges: # If theres only one range just use the key otherwise # append an index to distingiush entries if len(ranges) == 1: name = key else: name = key + '_' + str(index) index += 1 device_ns = namespace.add_namespace(name) attrs = image.new_attrs(device_ns) attrs.attach = PF_R | PF_W if cache_policy is not None: attrs.cache_policy = machine.get_cache_policy( cache_policy) attrs.phys_addr = base attrs.size = size device_ms = image.add_memsection(attrs, machine, pools) device_mem.append(device_ms) mapping = space.register_mapping(device_ms.attrs) self.add_standard_mem_caps(device_ns, mapping, device_ms.attrs) for irq in dev.interrupt.values(): space.register_irq(irq) self.env.add_device_irq_list(dev.name, dev.interrupt.values()) return device_mem def collect_mutexes(self, el, namespace, space): for mutex_el in el.find_children("mutex"): m_ns = namespace.add_namespace(mutex_el.name) mutex = space.register_mutex(mutex_el.name) m_ns.add('master', MutexCellCap('master', mutex)) def add_standard_mem_caps(self, namespace, mapping, attrs): namespace.add('master', PhysSegCellCap('master', mapping)) namespace.add('physical', PhysAddrCellCap('physical', attrs)) def collect_memsections(self, el, space, namespace, image, machine, pools): memsection_objs = [] for memsection_el in el.find_children('memsection'): memsection_attr = \ collect_memobj_attrs(memsection_el, namespace, image, machine) memsection_ns = memsection_attr.ns_node memsection_ms = image.add_memsection(memsection_attr, machine, pools) memsection_objs.append(memsection_ms) mapping = space.register_mapping(memsection_ms.attrs) self.add_standard_mem_caps(memsection_ns, mapping, memsection_ms.attrs) return memsection_objs def group_elf_segments(self, image): """ Group ELF segments together in a way that avoids domain faults and reduces final image size. - Any memsection that is under 1M goes into Group 1. - Any memsection above 1M but has contents, Group 2. - Any memsection above 1M which is empty, Group 3. """ groups = [[], [], []] for seg in self.elf_segments: if seg.get_attrs().size <= 0x100000: idx = 0 elif seg.get_attrs().data or seg.get_attrs().file: idx = 1 else: idx = 2 groups[idx].append(seg) for grp in groups: grp.sort(lambda x, y: int(x.get_attrs().size - y.get_attrs().size)) if grp is groups[0]: grp = self.elf_prog_segments + grp image.add_group(None, grp)
def collect_xml(self, okl4_el, ignore_name, namespace, machine, pools, kernel, image): """Handle an Iguana Server Compound Object""" self.cell = \ kernel.register_cell(okl4_el.name, okl4_el.kernel_heap, max_caps = getattr(okl4_el, "caps", None), max_priority = getattr(okl4_el, "max_priority", None)) self.name = okl4_el.name self.namespace = namespace.add_namespace(self.name) self.space = \ self.cell.register_space(self.namespace, "MAIN", is_privileged = True, max_clists = getattr(okl4_el, "clists", None), max_spaces = getattr(okl4_el, "spaces", None), max_mutexes = getattr(okl4_el, "mutexes", None), max_threads = getattr(okl4_el, "threads", None), max_priority = getattr(okl4_el, "max_priority", None), plat_control = \ getattr(okl4_el, "platform_control", False)) image.push_attrs( virtual = getattr(okl4_el, "virtpool", None), physical = getattr(okl4_el, "physpool", None), pager = make_pager_attr(getattr(okl4_el, "pager", None)), direct = getattr(okl4_el, "direct", None)) (self.def_virtpool, self.def_physpool) = image.current_pools() self.collect_mutexes(okl4_el, self.namespace, self.space) env_el = okl4_el.find_child("environment") self.env = CellEnvironment(okl4_el.name, self.namespace, machine, image, kernel, self.space.mappings) if env_el != None: self._collect_environment(env_el, self.env) # Set these up now even though we can't actually assign values # till later self.phys_attrs = image.new_attrs(self.namespace.add_namespace("default_physpool")) self.phys_attrs.attach = PF_R | PF_W | PF_X self.phys_attrs.mem_type = self.phys_attrs.unmapped mapping = self.space.register_mapping(self.phys_attrs) self.env.add_physmem_segpool_entry("MAIN_PHYSMEM_SEGPOOL", mapping) self.virt_attrs = image.new_attrs(self.namespace.add_namespace("default_virtpool")) self.env.add_virtmem_pool_entry("MAIN_VIRTMEM_POOL", self.virt_attrs) self.space.utcb = image.new_attrs(self.namespace.add_namespace("main_utcb_area")) self.space.utcb.attach = PF_R filename = os.path.join(okl4_el._path, okl4_el.file) self.elf = UnpreparedElfFile(filename=filename) if self.elf.elf_type != ET_EXEC: raise MergeError("All the merged ELF files must be of EXEC type.") # Find out which version of libokl4 that the cell was built # against sym = self.elf.find_symbol("okl4_api_version") if sym == None: raise MergeError("Unable to locate the symbol 'okl4_api_version' in file \"%s\". Cells must link with libokl4." % filename) self.api_version = self.elf.get_value(sym.value, sym.size, self.elf.endianess) if self.api_version == None: raise MergeError("Unable to read the symbol 'okl4_api_version' in file \"%s\". Cells must link with libokl4." % filename) self.env.add_elf_info_entry(os.path.basename(okl4_el.file), image.PROGRAM, self.elf.entry_point) segment_els = okl4_el.find_children("segment") segs = collect_elf_segments(self.elf, image.PROGRAM, segment_els, filename, [], self.namespace, image, machine, pools) self.elf_prog_segments = segs for seg in segs: self.env.add_elf_segment_entry(okl4_el.name + '.' + seg.attrs.ns_node.name, seg.segment) seg_ns = seg.attrs.ns_node mapping = self.space.register_mapping(seg.attrs) self.add_standard_mem_caps(seg_ns, mapping, seg.attrs) patch_els = okl4_el.find_children("patch") collect_patches(self.elf, patch_els, filename, image) # Record any IRQs that are assigned to the initial program. for irq_el in okl4_el.find_children("irq"): self.space.register_irq(irq_el.value) self.env.add_device_irq_list("NO_DEVICE", [irq_el.value for irq_el \ in okl4_el.find_children("irq")]) # Collect the implicit thread if not hasattr(okl4_el, 'priority'): okl4_el.priority = kernel.kernel.MAX_PRIORITY threads = [] threads.append(self.collect_thread(self.elf, okl4_el, self.namespace, image, machine, pools, kernel, self.space, self.elf.entry_point, "main", True)) # FIXME: Need to check up on actual entry point's for thread_el in okl4_el.find_children("thread"): threads.append(self.collect_thread(self.elf, thread_el, self.namespace, image, machine, pools, kernel, self.space, "thread_start", cell_create_thread = True)) device_mem = \ self.collect_use_devices(okl4_el, self.space, self.namespace, image, machine, pools) memsection_objs = \ self.collect_memsections(okl4_el, self.space, self.namespace, image, machine, pools) # Collect all data for any extra spaces defined in the XML for space_el in okl4_el.find_children("space"): space_ns = self.namespace.add_namespace(space_el.name) space = self.cell.register_space(space_ns, space_el.name, max_priority = getattr(space_el, "max_priority", \ getattr(okl4_el, "max_priority", None))) image.push_attrs( virtual = getattr(space_el, "virtpool", None), physical = getattr(space_el, "physpool", None), pager = make_pager_attr(getattr(space_el, "pager", None)), direct = getattr(space_el, "direct", None)) for thread_el in space_el.find_children("thread"): threads.append(self.collect_thread(self.elf, thread_el, space_ns, image, machine, pools, kernel, space, "thread_start", cell_create_thread = True)) self.collect_mutexes(space_el, space_ns, space) device_mem.extend( self.collect_use_devices(space_el, space, space_ns, image, machine, pools)) memsection_objs.extend( self.collect_memsections(space_el, space, space_ns, image, machine, pools)) self.env.add_kspace_entry(space_el.name + "_KSPACE", space) space.utcb = image.new_attrs(space_ns.add_namespace(space_el.name + "_utcb_area")) space.utcb.attach = PF_R # Weave a kclist for the main space. main_kclist = self.env.add_kclist_entry("MAIN_KCLIST", self.cell) # Weave the root kspace object. main_kspace = self.env.add_kspace_entry("MAIN_KSPACE", self.space) # Weave the root protection domain object. self.env.add_pd_entry("MAIN_PD", self.space, main_kspace, 32, machine.min_page_size(), self.elf) # Find heap and add it heap_el = okl4_el.find_child('heap') if heap_el is None: heap_el = ParsedElement('heap') heap_attr = collect_memobj_attrs(heap_el, self.namespace, image, machine) if heap_attr.size == None: heap_attr.size = DEFAULT_HEAP_SIZE self.heap_ms = image.add_memsection(heap_attr, machine, pools) self.cell.heap = self.heap_ms.attrs mapping = self.space.register_mapping(self.heap_ms.attrs) self.add_standard_mem_caps(heap_attr.ns_node, mapping, heap_attr) self.elf_segments = \ [thread.get_stack_ms() for thread in threads] + \ [self.heap_ms] + memsection_objs + device_mem self.env.add_kernel_info_entry(0, 0, kernel) # Add command line arguments commandline_el = okl4_el.find_child("commandline") if commandline_el is not None: args = [arg_el.value for arg_el in commandline_el.find_children("arg")] else: args = [] self.env.add_arg_list(args) self.cell.env = self.env
class OKL4Cell(Cell): # disable: Too many arguments # pylint: disable-msg=R0913 """ Cell for iguana programs, pds, drivers and other matters. """ element = OKL4_el def __init__(self): Cell.__init__(self) self.name = "" self.heap_ms = None self.stack_ms = None self.utcb_ms = None self.elf = None self.api_version = None self.elf_segments = [] self.elf_prog_segments = None self.def_virtpool = None self.def_physpool = None self.phys_addr = None self.virt_addr = None self.phys_attrs = None self.virt_attrs = None self.env = None self.cell = None self.namespace = None self.space = None def _collect_environment(self, env_el, env): """ Collect the details of the environmen element. """ # Collect any custom entries in the environment. if env_el is not None: for entry_el in env_el.find_children('entry'): cap_name = None attach = None if hasattr(entry_el, 'value'): env.add_value_entry(entry_el.key, entry_el.value) else: if not hasattr(entry_el, 'cap'): raise MergeError, 'Value or cap attribute required.' cap_name = entry_el.cap if hasattr(entry_el, 'attach'): attach = attach_to_elf_flags(entry_el.attach) env.add_cap_entry(entry_el.key, cap_name = cap_name, attach = attach) def collect_xml(self, okl4_el, ignore_name, namespace, machine, pools, kernel, image): """Handle an Iguana Server Compound Object""" self.cell = \ kernel.register_cell(okl4_el.name, okl4_el.kernel_heap, max_caps = getattr(okl4_el, "caps", None), max_priority = getattr(okl4_el, "max_priority", None)) self.name = okl4_el.name self.namespace = namespace.add_namespace(self.name) self.space = \ self.cell.register_space(self.namespace, "MAIN", is_privileged = True, max_clists = getattr(okl4_el, "clists", None), max_spaces = getattr(okl4_el, "spaces", None), max_mutexes = getattr(okl4_el, "mutexes", None), max_threads = getattr(okl4_el, "threads", None), max_priority = getattr(okl4_el, "max_priority", None), plat_control = \ getattr(okl4_el, "platform_control", False)) image.push_attrs( virtual = getattr(okl4_el, "virtpool", None), physical = getattr(okl4_el, "physpool", None), pager = make_pager_attr(getattr(okl4_el, "pager", None)), direct = getattr(okl4_el, "direct", None)) (self.def_virtpool, self.def_physpool) = image.current_pools() self.collect_mutexes(okl4_el, self.namespace, self.space) env_el = okl4_el.find_child("environment") self.env = CellEnvironment(okl4_el.name, self.namespace, machine, image, kernel, self.space.mappings) if env_el != None: self._collect_environment(env_el, self.env) # Set these up now even though we can't actually assign values # till later self.phys_attrs = image.new_attrs(self.namespace.add_namespace("default_physpool")) self.phys_attrs.attach = PF_R | PF_W | PF_X self.phys_attrs.mem_type = self.phys_attrs.unmapped mapping = self.space.register_mapping(self.phys_attrs) self.env.add_physmem_segpool_entry("MAIN_PHYSMEM_SEGPOOL", mapping) self.virt_attrs = image.new_attrs(self.namespace.add_namespace("default_virtpool")) self.env.add_virtmem_pool_entry("MAIN_VIRTMEM_POOL", self.virt_attrs) self.space.utcb = image.new_attrs(self.namespace.add_namespace("main_utcb_area")) self.space.utcb.attach = PF_R filename = os.path.join(okl4_el._path, okl4_el.file) self.elf = UnpreparedElfFile(filename=filename) if self.elf.elf_type != ET_EXEC: raise MergeError("All the merged ELF files must be of EXEC type.") # Find out which version of libokl4 that the cell was built # against sym = self.elf.find_symbol("okl4_api_version") if sym == None: raise MergeError("Unable to locate the symbol 'okl4_api_version' in file \"%s\". Cells must link with libokl4." % filename) self.api_version = self.elf.get_value(sym.value, sym.size, self.elf.endianess) if self.api_version == None: raise MergeError("Unable to read the symbol 'okl4_api_version' in file \"%s\". Cells must link with libokl4." % filename) self.env.add_elf_info_entry(os.path.basename(okl4_el.file), image.PROGRAM, self.elf.entry_point) segment_els = okl4_el.find_children("segment") segs = collect_elf_segments(self.elf, image.PROGRAM, segment_els, filename, [], self.namespace, image, machine, pools) self.elf_prog_segments = segs for seg in segs: self.env.add_elf_segment_entry(okl4_el.name + '.' + seg.attrs.ns_node.name, seg.segment) seg_ns = seg.attrs.ns_node mapping = self.space.register_mapping(seg.attrs) self.add_standard_mem_caps(seg_ns, mapping, seg.attrs) patch_els = okl4_el.find_children("patch") collect_patches(self.elf, patch_els, filename, image) # Record any IRQs that are assigned to the initial program. for irq_el in okl4_el.find_children("irq"): self.space.register_irq(irq_el.value) self.env.add_device_irq_list("NO_DEVICE", [irq_el.value for irq_el \ in okl4_el.find_children("irq")]) # Collect the implicit thread if not hasattr(okl4_el, 'priority'): okl4_el.priority = kernel.kernel.MAX_PRIORITY threads = [] threads.append(self.collect_thread(self.elf, okl4_el, self.namespace, image, machine, pools, kernel, self.space, self.elf.entry_point, "main", True)) # FIXME: Need to check up on actual entry point's for thread_el in okl4_el.find_children("thread"): threads.append(self.collect_thread(self.elf, thread_el, self.namespace, image, machine, pools, kernel, self.space, "thread_start", cell_create_thread = True)) device_mem = \ self.collect_use_devices(okl4_el, self.space, self.namespace, image, machine, pools) memsection_objs = \ self.collect_memsections(okl4_el, self.space, self.namespace, image, machine, pools) # Collect all data for any extra spaces defined in the XML for space_el in okl4_el.find_children("space"): space_ns = self.namespace.add_namespace(space_el.name) space = self.cell.register_space(space_ns, space_el.name, max_priority = getattr(space_el, "max_priority", \ getattr(okl4_el, "max_priority", None))) image.push_attrs( virtual = getattr(space_el, "virtpool", None), physical = getattr(space_el, "physpool", None), pager = make_pager_attr(getattr(space_el, "pager", None)), direct = getattr(space_el, "direct", None)) for thread_el in space_el.find_children("thread"): threads.append(self.collect_thread(self.elf, thread_el, space_ns, image, machine, pools, kernel, space, "thread_start", cell_create_thread = True)) self.collect_mutexes(space_el, space_ns, space) device_mem.extend( self.collect_use_devices(space_el, space, space_ns, image, machine, pools)) memsection_objs.extend( self.collect_memsections(space_el, space, space_ns, image, machine, pools)) self.env.add_kspace_entry(space_el.name + "_KSPACE", space) space.utcb = image.new_attrs(space_ns.add_namespace(space_el.name + "_utcb_area")) space.utcb.attach = PF_R # Weave a kclist for the main space. main_kclist = self.env.add_kclist_entry("MAIN_KCLIST", self.cell) # Weave the root kspace object. main_kspace = self.env.add_kspace_entry("MAIN_KSPACE", self.space) # Weave the root protection domain object. self.env.add_pd_entry("MAIN_PD", self.space, main_kspace, 32, machine.min_page_size(), self.elf) # Find heap and add it heap_el = okl4_el.find_child('heap') if heap_el is None: heap_el = ParsedElement('heap') heap_attr = collect_memobj_attrs(heap_el, self.namespace, image, machine) if heap_attr.size == None: heap_attr.size = DEFAULT_HEAP_SIZE self.heap_ms = image.add_memsection(heap_attr, machine, pools) self.cell.heap = self.heap_ms.attrs mapping = self.space.register_mapping(self.heap_ms.attrs) self.add_standard_mem_caps(heap_attr.ns_node, mapping, heap_attr) self.elf_segments = \ [thread.get_stack_ms() for thread in threads] + \ [self.heap_ms] + memsection_objs + device_mem self.env.add_kernel_info_entry(0, 0, kernel) # Add command line arguments commandline_el = okl4_el.find_child("commandline") if commandline_el is not None: args = [arg_el.value for arg_el in commandline_el.find_children("arg")] else: args = [] self.env.add_arg_list(args) self.cell.env = self.env def get_cell_api_version(self): """ Return the libOKL4 API versions that the cell initial program was build against. """ return self.api_version def generate_dynamic_segments(self, namespace, machine, pools, kernel, image): """ Create bootinfo segment and environment buffers. """ utcb_mss = [] for space in self.cell.spaces: space.utcb.size = align_up(space.max_threads * image.utcb_size, machine.min_page_size()) # A space with no threads will get a 0 size as align_up doesn't # change a 0, so we explicity set it to at least one page if space.utcb.size == 0: space.utcb.size = machine.min_page_size() utcb_ms = image.add_utcb_area(space.utcb) utcb_mss.append(utcb_ms) kspace = None for (x, _) in self.env.space_list: if x.space.id == space.id: kspace = x if image.utcb_size: self.env.add_utcb_area_entry("UTCB_AREA_%d" % space.id, space, kspace, image) self.env.add_bitmap_allocator_entry("MAIN_SPACE_ID_POOL", *self.cell.space_list) self.env.add_bitmap_allocator_entry("MAIN_CLIST_ID_POOL", *self.cell.cap_list) self.env.add_bitmap_allocator_entry("MAIN_MUTEX_ID_POOL", *self.cell.mutex_list) self.env.add_int_entry("MAIN_SPACE_ID", self.space.id) self.env.add_int_entry("MAIN_CLIST_ID", self.cell.clist_id) self.env.generate_dynamic_segments(self, image, machine, pools) self.elf_segments.extend(utcb_mss + [self.env.memsect]) self.group_elf_segments(image) def generate_init(self, machine, pools, kernel, image): """ Generate the bootinfo script for the cell, placing it into a segment. """ self.set_free_pools(pools, kernel, image, machine) self.env.generate_init(machine, pools, kernel, image) def set_free_pools(self, pools, kernel, image, machine): phys_free = \ pools.get_physical_pool_by_name(self.def_physpool).get_freelist()[:] virt_free = \ pools.get_virtual_pool_by_name(self.def_virtpool).get_freelist()[:] # Sort biggest to smallest phys_free.sort(key=lambda x: x[0] - x[1]) virt_free.sort(key=lambda x: x[0] - x[1]) # Extract the biggest regions and remove them from the lists. (phys_base, phys_end, _) = phys_free[0] del phys_free[0] (virt_base, virt_end, _) = virt_free[0] del virt_free[0] self.phys_attrs.size = phys_end - phys_base + 1 self.phys_attrs.phys_addr = phys_base def_phys_ms = image.add_memsection(self.phys_attrs, machine, pools) image.add_group(0, [def_phys_ms]) self.virt_attrs.size = virt_end - virt_base + 1 self.virt_attrs.virt_addr = virt_base self.env.add_kernel_info_entry(phys_base, phys_end, kernel) def collect_thread(self, elf, el, namespace, image, machine, pools, kernel, space, entry, thread_name = None, cell_create_thread = False): """Collect the attributes of a thread element.""" if entry is None: raise MergeError, "No entry point specified for thread %s" % el.name user_main = getattr(el, 'start', entry) entry = start_to_value(entry, elf) user_main = start_to_value(user_main, elf) priority = getattr(el, 'priority', kernel.kernel.DEFAULT_PRIORITY) physpool = getattr(el, 'physpool', None) virtpool = getattr(el, 'virtpool', None) # New namespace for objects living in the thread. if thread_name == None: thread_name = el.name thread_namespace = namespace.add_namespace(thread_name) # Push the overriding pools for the thread. image.push_attrs(virtual = virtpool, physical = physpool) utcb = image.new_attrs(thread_namespace.add_namespace("utcb")) # Create the cell thread and assign the entry point thread = space.register_thread(entry, user_main, utcb, priority, create = cell_create_thread) thread_namespace.add('master', ThreadCellCap('master', thread)) # Collect the stack. Is there no element, create a fake one for # the collection code to use. stack_el = el.find_child('stack') if stack_el is None: stack_el = ParsedElement('stack') stack_attr = collect_memobj_attrs(stack_el, thread_namespace, image, machine) if stack_attr.size == None: stack_attr.size = DEFAULT_STACK_SIZE stack_ms = image.add_memsection(stack_attr, machine, pools) mapping = space.register_mapping(stack_ms.attrs) self.add_standard_mem_caps(stack_attr.ns_node, mapping, stack_attr) # Setup the stack for the new cell thread thread.stack = stack_ms.attrs thread.stack_ms = stack_ms # If this is the very first collect_thread call, we assume it is # the cell's main thread and we set the stack_ms accordingly. if self.stack_ms is None: self.stack_ms = stack_ms image.pop_attrs() return thread def collect_use_devices(self, el, space, namespace, image, machine, pools): device_mem = [] for device_el in el.find_children("use_device"): dev = machine.get_phys_device(device_el.name) # Potentially we can have multiple named physical mem sections # each with multiple ranges. for key in dev.physical_mem.keys(): ranges = dev.physical_mem[key] index = 0 for (base, size, rights, cache_policy) in ranges: # If theres only one range just use the key otherwise # append an index to distingiush entries if len(ranges) == 1: name = key else: name = key + '_' + str(index) index += 1 device_ns = namespace.add_namespace(name) attrs = image.new_attrs(device_ns) attrs.attach = PF_R | PF_W if cache_policy is not None: attrs.cache_policy = machine.get_cache_policy(cache_policy) attrs.phys_addr = base attrs.size = size device_ms = image.add_memsection(attrs, machine, pools) device_mem.append(device_ms) mapping = space.register_mapping(device_ms.attrs) self.add_standard_mem_caps(device_ns, mapping, device_ms.attrs) for irq in dev.interrupt.values(): space.register_irq(irq) self.env.add_device_irq_list(dev.name, dev.interrupt.values()) return device_mem def collect_mutexes(self, el, namespace, space): for mutex_el in el.find_children("mutex"): m_ns = namespace.add_namespace(mutex_el.name) mutex = space.register_mutex(mutex_el.name) m_ns.add('master', MutexCellCap('master', mutex)) def add_standard_mem_caps(self, namespace, mapping, attrs): namespace.add('master', PhysSegCellCap('master', mapping)) namespace.add('physical', PhysAddrCellCap('physical', attrs)) def collect_memsections(self, el, space, namespace, image, machine, pools): memsection_objs = [] for memsection_el in el.find_children('memsection'): memsection_attr = \ collect_memobj_attrs(memsection_el, namespace, image, machine) memsection_ns = memsection_attr.ns_node memsection_ms = image.add_memsection(memsection_attr, machine, pools) memsection_objs.append(memsection_ms) mapping = space.register_mapping(memsection_ms.attrs) self.add_standard_mem_caps(memsection_ns, mapping, memsection_ms.attrs) return memsection_objs def group_elf_segments(self, image): """ Group ELF segments together in a way that avoids domain faults and reduces final image size. - Any memsection that is under 1M goes into Group 1. - Any memsection above 1M but has contents, Group 2. - Any memsection above 1M which is empty, Group 3. """ groups = [[], [], []] for seg in self.elf_segments: if seg.get_attrs().size <= 0x100000: idx = 0 elif seg.get_attrs().data or seg.get_attrs().file: idx = 1 else: idx = 2 groups[idx].append(seg) for grp in groups: grp.sort(lambda x, y: int(x.get_attrs().size - y.get_attrs().size)) if grp is groups[0]: grp = self.elf_prog_segments + grp image.add_group(None, grp)