Esempio n. 1
0
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)
Esempio n. 2
0
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)
Esempio n. 3
0
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)