Пример #1
0
class Kernel(XmlCollector):
    """
    Kernel initialisation parameters built from the XML file.
    These parameters are then merged into the kconfig section in the
    ELF file.
    """

    DEFAULT_MAX_CAPS = DEFAULT_MAX_CAPS
    element = Kernel_el

    class Cell(object):
        """
        Kernel information pertaining to a cell.
        """
        class Space(object):
            """An address space within a cell."""
            class Thread(object):
                """ A thread within a space """
                def __init__(self,
                             entry,
                             user_start,
                             utcb,
                             priority,
                             create=True):

                    assert (priority is not None)

                    self.cap_slot = 0
                    self.priority = priority
                    self.stack = None
                    self.stack_ms = None
                    self.entry = entry
                    self.user_start = user_start
                    self.create = create
                    self.utcb = utcb
                    self.offset = None

                def get_sp(self):
                    """
                    Return the stack pointer for the thread.
                    """
                    virt_addr = self.stack.virt_addr
                    if virt_addr is None:
                        virt_addr = 0

                    size = self.stack.size
                    if size is None:
                        size = 0

                    return virt_addr + size

                def get_stack_ms(self):
                    """
                    Return the stack memsection for the thread.
                    """
                    return self.stack_ms

            class Mutex(object):
                """A mutex within a space."""
                def __init__(self, name, create=True):
                    self.name = name
                    self.offset = 0
                    self.create = create

            class Cap(LocalCap):
                """A cap slot that references another object."""
                def __init__(self, obj):
                    self.clist = None
                    self.cap_slot = None
                    self.obj = obj

                def get_cap_slot(self):
                    return self.cap_slot

            # for class Space.
            def __init__(self,
                         ns_node,
                         env_prefix,
                         is_privileged=False,
                         plat_control=False,
                         max_spaces=None,
                         max_clists=None,
                         max_mutexes=None,
                         max_threads=None,
                         max_phys_segs=0,
                         max_priority=None,
                         create=True):
                self.ns_node = ns_node
                self.env_prefix = env_prefix
                self.create = create
                self.is_privileged = is_privileged
                self.plat_control = plat_control
                self.id = 0
                self.utcb = None
                self.space_id_base = 0
                self.max_spaces = max_spaces
                self.clist_id_base = 0
                self.max_clists = max_clists
                self.mutex_id_base = 0
                self.max_mutexes = max_mutexes
                self.max_threads = max_threads
                self.max_phys_segs = max_phys_segs
                self.total_threads = 0
                self.seg_id = 0
                self.max_priority = max_priority
                self.phys_segs = []
                self.threads = []
                self.mappings = []
                self.irqs = []
                self.mutexes = []
                self.ipc_caps = []
                self.mutex_caps = []

            def calc_maxes(self):
                """
                Calculate the correct maximum values in the space.
                """
                # Can always access his own space.
                if self.max_spaces is None or self.max_spaces == 0:
                    self.max_spaces = 1

                # Can always access his own clist.
                if self.max_clists is None or self.max_clists == 0:
                    self.max_clists = 1

                # Can access max or created mutexes.
                if self.max_mutexes is None or \
                   self.max_mutexes < len(self.mutexes):
                    self.max_mutexes = len(self.mutexes)

                # Can access max or created physical segments.
                if self.max_phys_segs is None or \
                   self.max_phys_segs < len(self.phys_segs):
                    self.max_phys_segs = len(self.phys_segs)

                num_threads = len(self.threads)

                if self.max_threads is None:
                    self.max_threads = num_threads

                if self.max_threads < num_threads:
                    raise MergeError, \
                          "Number of threads created in space \"%s\" (%d) exceed the maximum allowed (%d)." % \
                          (self.ns_node.abs_name(), num_threads, self.max_threads)

            def register_thread(self,
                                entry,
                                user_start,
                                utcb,
                                priority,
                                create=True):
                assert self.create or not create

                if self.max_priority is not None and \
                        priority > self.max_priority:
                    raise MergeError("Tried to create thread with priority %s," \
                    " but space (%s) max priority is %s." % (priority,
                                                             self.ns_node.abs_name(),
                                                             self.max_priority))

                thread = self.Thread(entry, user_start, utcb, priority, create)
                self.threads.append(thread)

                return thread

            def get_static_threads(self):
                """
                Return all threads that should be created
                statically.
                """
                return [t for t in self.threads if t.create]

            def register_irq(self, irq):
                """Assign an irq number to the space."""
                self.irqs.append(irq)

            def register_mapping(self, attrs):
                mapping = (self.seg_id,
                           self.env_prefix + attrs.ns_node.abs_name()
                           [len(self.ns_node.abs_name()):].replace("/", "_"),
                           attrs)
                self.seg_id += 1
                self.max_phys_segs += 1
                self.mappings.append(mapping)
                return mapping

            def register_mutex(self, name, create=True):
                assert self.create or not create

                mutex = self.Mutex(name, create)
                self.mutexes.append(mutex)
                return mutex

            def get_static_mutexes(self):
                """
                Return all mutexes that should be created
                statically.
                """
                return [m for m in self.mutexes if m.create]

            def add_ipc_cap(self, target):
                """
                Create a cap to the target thread.
                """
                cap = self.Cap(target)
                self.ipc_caps.append(cap)

                return cap

            def add_mutex_cap(self, target):
                """
                Create a cap to the target mutex.
                """
                cap = self.Cap(target)
                self.mutex_caps.append(cap)

                return cap

        # For class Cell
        def __init__(self,
                     kernel_heap,
                     max_caps=None,
                     max_priority=None,
                     kernel_max_priority=None):
            if max_caps is None:
                max_caps = DEFAULT_MAX_CAPS

            self.heap_size = kernel_heap
            self.heap_phys_base = None
            self.clist_id = 0
            self.max_threads = 0
            self.max_caps = max_caps
            self.spaces = []
            self.mutexes = []
            self.env = None
            self.space_list = None
            self.caps_list = None
            self.mutex_list = None
            self.clist_offset = None
            self.max_priority = max_priority
            self.kernel_max_priority = kernel_max_priority
            self.total_spaces = 0

            assert self.max_priority <= self.kernel_max_priority

        def register_space(self,
                           ns_node,
                           env_prefix,
                           is_privileged=False,
                           plat_control=False,
                           max_clists=None,
                           max_spaces=None,
                           max_mutexes=None,
                           max_threads=None,
                           max_phys_segs=0,
                           max_priority=None,
                           create=True):

            if max_priority is None:
                max_priority = self.max_priority
            elif max_priority > self.kernel_max_priority:
                raise MergeError, "Maximum priority of the Space %s (%s) " \
                      "exceeds the kernel max priority (%s)" % (ns_node.abs_name(),
                                     max_priority, self.kernel_max_priority)

            space = self.Space(ns_node, env_prefix, is_privileged,
                               plat_control, max_spaces, max_clists,
                               max_mutexes, max_threads, max_phys_segs,
                               max_priority, create)
            self.spaces.append(space)
            return space

        def get_static_spaces(self):
            """
            Return all spaces that should be created statically.
            """
            return [s for s in self.spaces if s.create]

        def get_mr1(self):
            if self.env.memsect.attrs == None or \
                    self.env.memsect.attrs.virt_addr == None:
                return 0xfee1dead

            return self.env.memsect.attrs.virt_addr

    # For class Kernel
    def __init__(self, machine, section="kernel.roinit"):
        self.kernel = None
        self.machine = machine
        self.section = section
        self.configs = []
        self.total_spaces = 0
        self.total_mutexes = 0
        self.total_clists = 0
        self.total_threads = None
        self.base_segment = None
        self.cells = {}
        self.heap_attrs = None
        self.thread_array_base = None
        self.thread_array_count = 0
        self.thread_array_size = None
        self.dynamic_heap_size = False

    def register_heap(self, attrs):
        self.heap_attrs = attrs

        if attrs.size is None:
            self.dynamic_heap_size = True
            attrs.size = 0
        else:
            self.dynamic_heap_size = False

    def register_cell(self,
                      cell_tag,
                      kernel_heap,
                      max_caps=DEFAULT_MAX_CAPS,
                      max_priority=None):
        """Register a cell with the kernel."""
        if max_priority is None:
            max_priority = self.kernel.MAX_PRIORITY
        elif max_priority > self.kernel.MAX_PRIORITY:
            raise MergeError, "Maximum priority of the Cell %s (%s) " \
                  "exceeds the kernel max priority (%s)" % (cell_tag,
                                   max_priority, self.kernel.MAX_PRIORITY)

        cell = self.Cell(kernel_heap, max_caps, max_priority,
                         self.kernel.MAX_PRIORITY)
        self.cells[cell_tag] = cell

        if self.dynamic_heap_size:
            self.heap_attrs.size += kernel_heap

        return cell

    def get_cell(self, cell_tag):
        """Return the details of the named cell."""
        return self.cells.get(cell_tag, None)

    def add_config(self, key, value):
        """Record a configuration property."""

        if key == "threads":
            kernel_max = self.kernel.ABSOLUTE_MAX_THREADS
            if value > kernel_max:
                raise MergeError, \
                      "Maximum number of threads (%d) exceeded: %d" % \
                      (kernel_max, value)

            self.total_threads = value

    def calc_thread_array_sizes(self):
        self.thread_array_count = (self.total_threads)

        self.thread_array_size = self.thread_array_count  * \
                                 self.machine.sizeof_pointer

        if self.dynamic_heap_size:
            self.heap_attrs.size += align_up(self.thread_array_size,
                                             self.machine.min_page_size())

    def layout_cells_pre(self):
        # This is called before dynamic elements of cells as we should
        # be able to decide the number of cells, clists and mutexes at that
        # time

        clist_id = 0
        space_id = 0
        mutex_id = 0

        self.total_spaces = 0
        self.total_clists = 0
        self.total_mutexes = 0

        total_threads = 0

        for cell in self.cells.values():
            cap_slot = 0

            cell.clist_id = clist_id

            # Store the base id for the space, caps and mutex lists
            space_list_base = space_id
            cap_list_base = clist_id
            mutex_list_base = mutex_id

            # Init the number of used entries in the lists
            space_list_used = 0
            cap_list_used = 0
            mutex_list_used = len(cell.mutexes)

            cell_threads = 0

            tmp_cell_max_spaces = 0

            for space in cell.get_static_spaces():
                space.calc_maxes()
                if space.is_privileged and len(cell.spaces) > space.max_spaces:
                    space.max_spaces = len(cell.spaces)

                space.id = space_id
                space.space_id_base = space_id
                space_id += space.max_spaces
                if space.is_privileged:
                    cell.total_spaces += 1
                    self.total_spaces += space.max_spaces
                    tmp_cell_max_spaces = space.max_spaces
                else:
                    cell.total_spaces += space.max_spaces

                space.clist_id_base = clist_id
                clist_id += space.max_clists
                self.total_clists += space.max_clists

                space.mutex_id_base = mutex_id
                mutex_id += space.max_mutexes
                self.total_mutexes += space.max_mutexes

                for thread in space.get_static_threads():
                    thread.cap_slot = cap_slot
                    cap_slot += 1

                cell_threads += space.max_threads

                assigned_mutex_id = space.mutex_id_base
                for mutex in space.get_static_mutexes():
                    mutex.id = assigned_mutex_id
                    assigned_mutex_id += 1

                for cap in space.ipc_caps:
                    cap.clist = cell
                    cap.cap_slot = cap_slot
                    cap_slot += 1

                for cap in space.mutex_caps:
                    cap.clist = cell
                    cap.cap_slot = cap_slot
                    cap_slot += 1

                space_list_used += 1
                cap_list_used += cap_slot
                mutex_list_used += len(space.mutexes)

            if tmp_cell_max_spaces != 0 and \
               tmp_cell_max_spaces < cell.total_spaces:
                raise MergeError(
                    "Tried to allocate %s spaces, but cell max spaces is %s." %
                    (cell.total_spaces, tmp_cell_max_spaces))

            if cell.max_threads < cell_threads:
                cell.max_threads = cell_threads

            cell.space_list = (space_list_base, space_id - space_list_base,
                               space_list_used)
            cell.cap_list = (cap_list_base, clist_id - cap_list_base,
                             cap_list_used)
            cell.mutex_list = (mutex_list_base, mutex_id - mutex_list_base,
                               mutex_list_used)

            total_threads += cell_threads

        if self.total_threads < total_threads:
            raise MergeError, \
                  "Total number of threads (%d) exceeds kernel maximum of %d." % \
                  (total_threads, self.total_threads)

        # Now do any kernel specific layout
        self.kernel.layout_cells_pre(self)

    def layout_cells_post(self, image):
        # This must be called after image.layout() and before the cell
        # init scripts are written out.
        #
        # Do any required layout here

        self.kernel.layout_cells_post(self, image)

        if self.machine.arch_max_spaces != 0 and \
                self.total_spaces > self.machine.arch_max_spaces:
            raise MergeError(
                "Tried to allocate %d spaces, kernel only allows %d." %
                (self.total_spaces, self.machine.arch_max_spaces))

    def create_dynamic_segments(self, namespace, image, machine, pools):
        """ Do final thread array and heap calculations. """
        self.kernel.create_dynamic_segments(self, namespace, image, machine,
                                            pools, self.base_segment)

        # We need to mark the heap since its size is now known
        pools.mark_physical(self.heap_attrs.abs_name(),
                            self.heap_attrs.phys_addr, self.heap_attrs.size,
                            self.heap_attrs.cache_policy)

    def generate_init_script(self, image, machine):
        self.kernel.generate_init_script(self, image.elf, image, machine)

    def update_elf(self, elf, image, machine):
        """Perform any required updates to the kernel elf."""
        self.kernel.update_elf(self, elf, image, machine)

    def collect_use_devices(self, el, image, machine, pools):
        """Collect information about devices used by the kernel."""

        # Initialise the kernel virtual pool if necessary
        self.kernel.init_kernel_pool(machine, pools)

        # Iterate through devices used by the kernel, store their memory ranges
        for device_el in el.find_children("use_device"):
            dev = machine.get_phys_device(device_el.name)
            # print "driver %s has keys: %s" % (dev.name, dev.physical_mem.keys())
            self.kernel.add_device_mem(dev, image, machine, pools)

        if self.kernel.devices:
            # collect the memsections
            device_ms = []
            for (_, mem) in self.kernel.devices:
                device_ms.extend(mem)
            image.add_group(None, device_ms)

    def collect_xml(self, kernel_el, kernel_heap_size, namespace, image,
                    machine, pools):
        """Collect the attributes of the kernel element."""

        (elf, kernel_file, kernel_tmp) = get_kernel_file(kernel_el, machine)

        if elf.elf_type != ET_EXEC:
            raise MergeError, \
                  "All the merged ELF files must be of EXEC type."

        # New namespace for objects living in the kernel.
        kernel_namespace = namespace.add_namespace('kernel')

        # We setup our kernel type depending on the api version number
        kern_ver = check_api_versions(elf)
        if kern_ver == NANO_KERNEL_API_VERSION:
            self.kernel = NanoKernel(elf, kernel_namespace, machine)
        else:
            self.kernel = MicroKernel(kernel_namespace)

        assert self.total_threads is None
        self.total_threads = self.kernel.ABSOLUTE_MAX_THREADS

        # Record the default pools for cells to use if they don't have
        # defaults set.
        virtpool = getattr(kernel_el, "virtpool", None)
        physpool = getattr(kernel_el, "physpool", None)
        image.set_attrs_stack(def_virt=virtpool, def_phys=physpool)
        pools.set_default_pools(virtpool, physpool)

        segment_els = kernel_el.find_children("segment")
        patch_els = kernel_el.find_children("patch")

        machine.set_cache_attributes(elf)

        image.set_kernel(elf)
        segs = collect_elf_segments(elf, image.KERNEL, segment_els, 'kernel',
                                    self.kernel.segment_drops,
                                    kernel_namespace, image, machine, pools)
        # Set base segment
        self.base_segment = self.kernel.get_base_segment(elf, segs, image)

        if self.base_segment.attrs.phys_addr is not None and \
            (self.base_segment.attrs.phys_addr & ((1024 * 1024) - 1)) != 0:
            raise MergeError("Physical address of %s must be 1MB aligned!" %
                             self.base_segment.attrs.abs_name())

        elf = elf.prepare(elf.wordsize, elf.endianess)
        # The extra_patches attr may be added by a plugin.
        for patch in getattr(Kernel_el, "extra_patches", []):
            addr = get_symbol(elf, patch[0], True)
            if addr != None:
                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, kernel_file, image)

        # Collect the config elements, some of these relate to
        # heap and thread array, so do it first
        config_el = kernel_el.find_child("config")
        if config_el is not None:
            for option in config_el.find_children("option"):
                self.add_config(option.key, option.value)

        heap_attrs = image.new_attrs(
            namespace.root.add_namespace("kernel_heap"))
        heap_attrs.align = machine.kernel_heap_align
        heap_el = kernel_el.find_child("heap")
        if heap_el is not None:
            heap_attrs.phys_addr = getattr(heap_el, 'phys_addr',
                                           heap_attrs.phys_addr)
            heap_attrs.size = getattr(heap_el, 'size', heap_attrs.size)
            heap_attrs.align = getattr(heap_el, 'align', heap_attrs.align)

        # Override the size with the command line value, if present.
        if kernel_heap_size != 0:
            heap_attrs.size = kernel_heap_size

        # Nano needs a heap size set early on
        # Micro remains unassigned since it will get dynamically calculated later
        if not heap_attrs.size and isinstance(self.kernel, NanoKernel):
            heap_attrs.size = self.kernel.DEFAULT_KERNEL_HEAP_SIZE

        self.heap = image.set_kernel_heap(heap_attrs, machine, pools,
                                          self.base_segment.segment,
                                          isinstance(self.kernel, NanoKernel))
        image.add_group(machine.kernel_heap_proximity,
                        (self.base_segment, self.heap))
        self.register_heap(heap_attrs)

        if isinstance(self.kernel, MicroKernel):
            image.utcb_size = self.kernel.get_utcb_size(elf, image)

        self.collect_use_devices(kernel_el, image, machine, pools)

        if kernel_tmp:
            kernel_tmp.close()
Пример #2
0
class Kernel(XmlCollector):
    """
    Kernel initialisation parameters built from the XML file.
    These parameters are then merged into the kconfig section in the
    ELF file.
    """

    DEFAULT_MAX_CAPS = DEFAULT_MAX_CAPS
    element = Kernel_el

    class Cell(object):
        """
        Kernel information pertaining to a cell.
        """

        class Space(object):
            """An address space within a cell."""

            class Thread(object):
                """ A thread within a space """
                def __init__(self, entry, user_start, utcb, priority,
                        create = True):

                    assert(priority is not None)

                    self.cap_slot   = 0
                    self.priority   = priority
                    self.stack      = None
                    self.stack_ms   = None
                    self.entry      = entry
                    self.user_start = user_start
                    self.create     = create
                    self.utcb       = utcb
                    self.offset     = None

                def get_sp(self):
                    """
                    Return the stack pointer for the thread.
                    """
                    virt_addr = self.stack.virt_addr
                    if virt_addr is None:
                        virt_addr = 0

                    size = self.stack.size - 4
                    if size is None:
                        size = 0

                    return virt_addr + size

                def get_stack_ms(self):
                    """
                    Return the stack memsection for the thread.
                    """
                    return self.stack_ms

            class Mutex(object):
                """A mutex within a space."""
                def __init__(self, name, create = True):
                    self.name   = name
                    self.offset = 0
                    self.create = create

            class Cap(LocalCap):
                """A cap slot that references another object."""
                def __init__(self, obj):
                    self.clist     = None
                    self.cap_slot  = None
                    self.obj       = obj

                def get_cap_slot(self):
                    return self.cap_slot

            # for class Space.
            def __init__(self, ns_node, env_prefix, is_privileged = False,
                         plat_control = False,
                         max_spaces = None,
                         max_clists = None,
                         max_mutexes = None,
                         max_threads = None,
                         max_phys_segs = 0,
                         max_priority = None,
                         create = True):
                self.ns_node       = ns_node
                self.env_prefix    = env_prefix
                self.create        = create
                self.is_privileged = is_privileged
                self.plat_control  = plat_control
                self.id            = 0
                self.utcb          = None
                self.space_id_base = 0
                self.max_spaces    = max_spaces
                self.clist_id_base = 0
                self.max_clists    = max_clists
                self.mutex_id_base = 0
                self.max_mutexes   = max_mutexes
                self.max_threads   = max_threads
                self.max_phys_segs = max_phys_segs
                self.total_threads = 0
                self.seg_id        = 0
                self.max_priority  = max_priority
                self.phys_segs     = []
                self.threads       = []
                self.mappings      = []
                self.irqs          = []
                self.mutexes       = []
                self.ipc_caps      = []
                self.mutex_caps    = []

            def calc_maxes(self):
                """
                Calculate the correct maximum values in the space.
                """
                # Can always access his own space.
                if self.max_spaces is None or self.max_spaces == 0:
                    self.max_spaces = 1

                # Can always access his own clist.
                if self.max_clists is None or self.max_clists == 0:
                    self.max_clists = 1

                # Can access max or created mutexes.
                if self.max_mutexes is None or \
                   self.max_mutexes < len(self.mutexes):
                    self.max_mutexes = len(self.mutexes)

                # Can access max or created physical segments.
                if self.max_phys_segs is None or \
                   self.max_phys_segs < len(self.phys_segs):
                    self.max_phys_segs = len(self.phys_segs)

                num_threads = len(self.threads)

                if self.max_threads is None:
                    self.max_threads = num_threads

                if self.max_threads < num_threads:
                    raise MergeError, \
                          "Number of threads created in space \"%s\" (%d) exceed the maximum allowed (%d)." % \
                          (self.ns_node.abs_name(), num_threads, self.max_threads)

            def register_thread(self, entry, user_start, utcb, priority,
                    create = True):
                assert self.create or not create

                if self.max_priority is not None and \
                        priority > self.max_priority:
                    raise MergeError("Tried to create thread with priority %s," \
                    " but space (%s) max priority is %s." % (priority,
                                                             self.ns_node.abs_name(),
                                                             self.max_priority))

                thread = self.Thread(entry, user_start, utcb, priority, create)
                self.threads.append(thread)

                return thread

            def get_static_threads(self):
                """
                Return all threads that should be created
                statically.
                """
                return [t for t in self.threads if t.create]

            def register_irq(self, irq):
                """Assign an irq number to the space."""
                self.irqs.append(irq)

            def register_mapping(self, attrs):
                mapping = (self.seg_id,
                           self.env_prefix + attrs.ns_node.abs_name()[len(self.ns_node.abs_name()):].replace("/", "_"),
                           attrs)
                self.seg_id += 1
                self.max_phys_segs += 1
                self.mappings.append(mapping)
                return mapping

            def register_mutex(self, name, create = True):
                assert self.create or not create

                mutex = self.Mutex(name, create)
                self.mutexes.append(mutex)
                return mutex

            def get_static_mutexes(self):
                """
                Return all mutexes that should be created
                statically.
                """
                return [m for m in self.mutexes if m.create]

            def add_ipc_cap(self, target):
                """
                Create a cap to the target thread.
                """
                cap = self.Cap(target)
                self.ipc_caps.append(cap)

                return cap

            def add_mutex_cap(self, target):
                """
                Create a cap to the target mutex.
                """
                cap = self.Cap(target)
                self.mutex_caps.append(cap)

                return cap

        # For class Cell
        def __init__(self, kernel_heap,
                     max_caps = None, max_priority = None,
                     kernel_max_priority = None):
            if max_caps is None:
                max_caps = DEFAULT_MAX_CAPS

            self.heap_size   = kernel_heap
            self.heap_phys_base = None
            self.clist_id    = 0
            self.max_threads = 0
            self.max_caps    = max_caps
            self.spaces      = []
            self.mutexes     = []
            self.env         = None
            self.space_list  = None
            self.caps_list   = None
            self.mutex_list  = None
            self.clist_offset = None
            self.max_priority = max_priority
            self.kernel_max_priority = kernel_max_priority
            self.total_spaces = 0

            assert self.max_priority <= self.kernel_max_priority

        def register_space(self, ns_node, env_prefix,
                           is_privileged = False,
                           plat_control = False,
                           max_clists = None,
                           max_spaces = None,
                           max_mutexes = None,
                           max_threads = None,
                           max_phys_segs = 0,
                           max_priority = None,
                           create = True):

            if max_priority is None:
                max_priority = self.max_priority
            elif max_priority > self.kernel_max_priority:
                raise MergeError, "Maximum priority of the Space %s (%s) " \
                      "exceeds the kernel max priority (%s)" % (ns_node.abs_name(),
                                     max_priority, self.kernel_max_priority)

            space = self.Space(ns_node, env_prefix, is_privileged, plat_control,
                               max_spaces, max_clists, max_mutexes, max_threads,
                               max_phys_segs, max_priority, create)
            self.spaces.append(space)
            return space

        def get_static_spaces(self):
            """
            Return all spaces that should be created statically.
            """
            return [s for s in self.spaces if s.create]

        def get_mr1(self):
            if self.env.memsect.attrs == None or \
                    self.env.memsect.attrs.virt_addr == None:
                return 0xfee1dead

            return self.env.memsect.attrs.virt_addr

    # For class Kernel
    def __init__(self, machine, section = "kernel.roinit"):
        self.kernel        = None
        self.machine       = machine
        self.section       = section
        self.configs       = []
        self.total_spaces  = 0
        self.total_mutexes = 0
        self.total_clists  = 0
        self.total_threads = None
        self.base_segment  = None
        self.cells         = {}
        self.heap_attrs    = None
        self.thread_array_base  = None
        self.thread_array_count = 0
        self.thread_array_size  = None
        self.dynamic_heap_size  = False

    def register_heap(self, attrs):
        self.heap_attrs = attrs

        if attrs.size is None:
            self.dynamic_heap_size = True
            attrs.size = 0
        else:
            self.dynamic_heap_size = False

    def register_cell(self, cell_tag, kernel_heap,
                     max_caps = DEFAULT_MAX_CAPS,
                     max_priority = None):
        """Register a cell with the kernel."""
        if max_priority is None:
            max_priority = self.kernel.MAX_PRIORITY
        elif max_priority > self.kernel.MAX_PRIORITY:
            raise MergeError, "Maximum priority of the Cell %s (%s) " \
                  "exceeds the kernel max priority (%s)" % (cell_tag,
                                   max_priority, self.kernel.MAX_PRIORITY)

        cell = self.Cell(kernel_heap, max_caps, max_priority,
                                           self.kernel.MAX_PRIORITY)
        self.cells[cell_tag] = cell

        if self.dynamic_heap_size:
            self.heap_attrs.size += kernel_heap

        return cell

    def get_cell(self, cell_tag):
        """Return the details of the named cell."""
        return self.cells.get(cell_tag, None)

    def add_config(self, key, value):
        """Record a configuration property."""

        if key == "threads":
            kernel_max = self.kernel.ABSOLUTE_MAX_THREADS
            if value > kernel_max:
                raise MergeError, \
                      "Maximum number of threads (%d) exceeded: %d" % \
                      (kernel_max, value)

            self.total_threads = value

    def calc_thread_array_sizes(self):
        self.thread_array_count = (self.total_threads)

        self.thread_array_size = self.thread_array_count  * \
                                 self.machine.sizeof_pointer

        if self.dynamic_heap_size:
            self.heap_attrs.size += align_up(self.thread_array_size,
                                             self.machine.min_page_size())

    def layout_cells_pre(self):
        # This is called before dynamic elements of cells as we should
        # be able to decide the number of cells, clists and mutexes at that
        # time

        clist_id = 0
        space_id = 0
        mutex_id = 0

        self.total_spaces  = 0
        self.total_clists  = 0
        self.total_mutexes = 0

        total_threads = 0

        for cell in self.cells.values():
            cap_slot = 0

            cell.clist_id = clist_id

            # Store the base id for the space, caps and mutex lists
            space_list_base = space_id
            cap_list_base = clist_id
            mutex_list_base = mutex_id

            # Init the number of used entries in the lists
            space_list_used = 0
            cap_list_used = 0
            mutex_list_used = len(cell.mutexes)

            cell_threads = 0

            tmp_cell_max_spaces = 0

            for space in cell.get_static_spaces():
                space.calc_maxes()
                if space.is_privileged and len(cell.spaces) > space.max_spaces:
                    space.max_spaces = len(cell.spaces)

                space.id = space_id
                space.space_id_base = space_id
                space_id += space.max_spaces
                if space.is_privileged:
                    cell.total_spaces += 1
                    self.total_spaces += space.max_spaces
                    tmp_cell_max_spaces = space.max_spaces
                else:
                    cell.total_spaces += space.max_spaces

                space.clist_id_base = clist_id
                clist_id += space.max_clists
                self.total_clists += space.max_clists

                space.mutex_id_base = mutex_id
                mutex_id += space.max_mutexes
                self.total_mutexes += space.max_mutexes

                for thread in space.get_static_threads():
                    thread.cap_slot = cap_slot
                    cap_slot += 1

                cell_threads += space.max_threads

                assigned_mutex_id = space.mutex_id_base
                for mutex in space.get_static_mutexes():
                    mutex.id = assigned_mutex_id
                    assigned_mutex_id += 1

                for cap in space.ipc_caps:
                    cap.clist = cell
                    cap.cap_slot = cap_slot
                    cap_slot += 1

                for cap in space.mutex_caps:
                    cap.clist = cell
                    cap.cap_slot = cap_slot
                    cap_slot += 1

                space_list_used += 1
                cap_list_used += cap_slot
                mutex_list_used += len(space.mutexes)

            if tmp_cell_max_spaces != 0 and \
               tmp_cell_max_spaces < cell.total_spaces:
                raise MergeError("Tried to allocate %s spaces, but cell max spaces is %s."
                % (cell.total_spaces, tmp_cell_max_spaces))

            if cell.max_threads < cell_threads:
                cell.max_threads = cell_threads

            cell.space_list = (space_list_base, space_id - space_list_base,
                    space_list_used)
            cell.cap_list = (cap_list_base, clist_id - cap_list_base,
                    cap_list_used)
            cell.mutex_list = (mutex_list_base, mutex_id - mutex_list_base,
                    mutex_list_used)

            total_threads += cell_threads

        if self.total_threads < total_threads:
            raise MergeError, \
                  "Total number of threads (%d) exceeds kernel maximum of %d." % \
                  (total_threads, self.total_threads)

        # Now do any kernel specific layout
        self.kernel.layout_cells_pre(self)


    def layout_cells_post(self, image):
        # This must be called after image.layout() and before the cell
        # init scripts are written out.
        #
        # Do any required layout here

        self.kernel.layout_cells_post(self, image)

        if self.machine.arch_max_spaces != 0 and \
                self.total_spaces > self.machine.arch_max_spaces:
            raise MergeError("Tried to allocate %d spaces, kernel only allows %d."
            % (self.total_spaces, self.machine.arch_max_spaces))

    def create_dynamic_segments(self, namespace, image, machine, pools):
        """ Do final thread array and heap calculations. """
        self.kernel.create_dynamic_segments(self, namespace, image,
                                            machine, pools, self.base_segment)

        # We need to mark the heap since its size is now known
        pools.mark_physical(self.heap_attrs.abs_name(),
                            self.heap_attrs.phys_addr,
                            self.heap_attrs.size,
                            self.heap_attrs.cache_policy)

    def generate_init_script(self, image, machine):
        self.kernel.generate_init_script(self, image.elf, image, machine)

    def update_elf(self, elf, image, machine):
        """Perform any required updates to the kernel elf."""
        self.kernel.update_elf(self, elf, image, machine)

    def collect_use_devices(self, el, image, machine, pools):
        """Collect information about devices used by the kernel."""

        # Initialise the kernel virtual pool if necessary
        self.kernel.init_kernel_pool(machine, pools)

        # Iterate through devices used by the kernel, store their memory ranges
        for device_el in el.find_children("use_device"):
            dev = machine.get_phys_device(device_el.name)
            # print "driver %s has keys: %s" % (dev.name, dev.physical_mem.keys())
            self.kernel.add_device_mem(dev, image, machine, pools)

        if self.kernel.devices:
            # collect the memsections
            device_ms = []
            for (_, mem) in self.kernel.devices:
                device_ms.extend(mem)
            image.add_group(None, device_ms)

    def collect_xml(self, kernel_el, kernel_heap_size, namespace, image,
                    machine, pools):
        """Collect the attributes of the kernel element."""

        (elf, kernel_file, kernel_tmp) = get_kernel_file(kernel_el, machine)

        if elf.elf_type != ET_EXEC:
            raise MergeError, \
                  "All the merged ELF files must be of EXEC type."

        # New namespace for objects living in the kernel.
        kernel_namespace = namespace.add_namespace('kernel')

        # We setup our kernel type depending on the api version number
        kern_ver = check_api_versions(elf)
        if kern_ver == NANO_KERNEL_API_VERSION:
            self.kernel = NanoKernel(elf, kernel_namespace, machine)
        else:
            self.kernel = MicroKernel(kernel_namespace)

        assert self.total_threads is None
        self.total_threads = self.kernel.ABSOLUTE_MAX_THREADS

        # Record the default pools for cells to use if they don't have
        # defaults set.
        virtpool = getattr(kernel_el, "virtpool", None)
        physpool = getattr(kernel_el, "physpool", None)
        image.set_attrs_stack(def_virt = virtpool,
                              def_phys = physpool)
        pools.set_default_pools(virtpool, physpool)

        segment_els = kernel_el.find_children("segment")
        patch_els   = kernel_el.find_children("patch")

        machine.set_cache_attributes(elf)

        image.set_kernel(elf)
        segs = collect_elf_segments(elf, image.KERNEL, segment_els,
                                    'kernel', self.kernel.segment_drops,
                                    kernel_namespace, image, machine, pools)
        # Set base segment
        self.base_segment = self.kernel.get_base_segment(elf, segs, image)

        if self.base_segment.attrs.phys_addr is not None and \
            (self.base_segment.attrs.phys_addr & ((1024 * 1024) - 1)) != 0:
            raise MergeError("Physical address of %s must be 1MB aligned!" %
                                    self.base_segment.attrs.abs_name())

        elf = elf.prepare(elf.wordsize, elf.endianess)
        # The extra_patches attr may be added by a plugin.
        for patch in getattr(Kernel_el, "extra_patches", []):
            addr = get_symbol(elf, patch[0], True)
            if addr != None:
                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, kernel_file, image)

        # Collect the config elements, some of these relate to
        # heap and thread array, so do it first
        config_el = kernel_el.find_child("config")
        if config_el is not None:
            for option in config_el.find_children("option"):
                self.add_config(option.key, option.value)

        heap_attrs       = image.new_attrs(namespace.root.add_namespace("kernel_heap"))
        heap_attrs.align = machine.kernel_heap_align
        heap_el          = kernel_el.find_child("heap")
        if heap_el is not None:
            heap_attrs.phys_addr = getattr(heap_el, 'phys_addr',
                                           heap_attrs.phys_addr)
            heap_attrs.size      = getattr(heap_el, 'size', heap_attrs.size)
            heap_attrs.align     = getattr(heap_el, 'align', heap_attrs.align)

        # Override the size with the command line value, if present.
        if kernel_heap_size != 0:
            heap_attrs.size = kernel_heap_size

        # Nano needs a heap size set early on
        # Micro remains unassigned since it will get dynamically calculated later
        if not heap_attrs.size and isinstance(self.kernel, NanoKernel):
            heap_attrs.size = self.kernel.DEFAULT_KERNEL_HEAP_SIZE

        self.heap = image.set_kernel_heap(heap_attrs, machine,
                                          pools, self.base_segment.segment,
                                          isinstance(self.kernel, NanoKernel))
        image.add_group(machine.kernel_heap_proximity, (self.base_segment, self.heap))
        self.register_heap(heap_attrs)

        if isinstance(self.kernel, MicroKernel):
            image.utcb_size = self.kernel.get_utcb_size(elf, image)

        self.collect_use_devices(kernel_el, image, machine, pools)

        if kernel_tmp:
            kernel_tmp.close()
Пример #3
0
    def collect_xml(self, kernel_el, kernel_heap_size, namespace, image,
                    machine, pools):
        """Collect the attributes of the kernel element."""

        (elf, kernel_file, kernel_tmp) = get_kernel_file(kernel_el, machine)

        if elf.elf_type != ET_EXEC:
            raise MergeError, \
                  "All the merged ELF files must be of EXEC type."

        # New namespace for objects living in the kernel.
        kernel_namespace = namespace.add_namespace('kernel')

        # We setup our kernel type depending on the api version number
        kern_ver = check_api_versions(elf)
        if kern_ver == NANO_KERNEL_API_VERSION:
            self.kernel = NanoKernel(elf, kernel_namespace, machine)
        else:
            self.kernel = MicroKernel(kernel_namespace)

        assert self.total_threads is None
        self.total_threads = self.kernel.ABSOLUTE_MAX_THREADS

        # Record the default pools for cells to use if they don't have
        # defaults set.
        virtpool = getattr(kernel_el, "virtpool", None)
        physpool = getattr(kernel_el, "physpool", None)
        image.set_attrs_stack(def_virt=virtpool, def_phys=physpool)
        pools.set_default_pools(virtpool, physpool)

        segment_els = kernel_el.find_children("segment")
        patch_els = kernel_el.find_children("patch")

        machine.set_cache_attributes(elf)

        image.set_kernel(elf)
        segs = collect_elf_segments(elf, image.KERNEL, segment_els, 'kernel',
                                    self.kernel.segment_drops,
                                    kernel_namespace, image, machine, pools)
        # Set base segment
        self.base_segment = self.kernel.get_base_segment(elf, segs, image)

        if self.base_segment.attrs.phys_addr is not None and \
            (self.base_segment.attrs.phys_addr & ((1024 * 1024) - 1)) != 0:
            raise MergeError("Physical address of %s must be 1MB aligned!" %
                             self.base_segment.attrs.abs_name())

        elf = elf.prepare(elf.wordsize, elf.endianess)
        # The extra_patches attr may be added by a plugin.
        for patch in getattr(Kernel_el, "extra_patches", []):
            addr = get_symbol(elf, patch[0], True)
            if addr != None:
                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, kernel_file, image)

        # Collect the config elements, some of these relate to
        # heap and thread array, so do it first
        config_el = kernel_el.find_child("config")
        if config_el is not None:
            for option in config_el.find_children("option"):
                self.add_config(option.key, option.value)

        heap_attrs = image.new_attrs(
            namespace.root.add_namespace("kernel_heap"))
        heap_attrs.align = machine.kernel_heap_align
        heap_el = kernel_el.find_child("heap")
        if heap_el is not None:
            heap_attrs.phys_addr = getattr(heap_el, 'phys_addr',
                                           heap_attrs.phys_addr)
            heap_attrs.size = getattr(heap_el, 'size', heap_attrs.size)
            heap_attrs.align = getattr(heap_el, 'align', heap_attrs.align)

        # Override the size with the command line value, if present.
        if kernel_heap_size != 0:
            heap_attrs.size = kernel_heap_size

        # Nano needs a heap size set early on
        # Micro remains unassigned since it will get dynamically calculated later
        if not heap_attrs.size and isinstance(self.kernel, NanoKernel):
            heap_attrs.size = self.kernel.DEFAULT_KERNEL_HEAP_SIZE

        self.heap = image.set_kernel_heap(heap_attrs, machine, pools,
                                          self.base_segment.segment,
                                          isinstance(self.kernel, NanoKernel))
        image.add_group(machine.kernel_heap_proximity,
                        (self.base_segment, self.heap))
        self.register_heap(heap_attrs)

        if isinstance(self.kernel, MicroKernel):
            image.utcb_size = self.kernel.get_utcb_size(elf, image)

        self.collect_use_devices(kernel_el, image, machine, pools)

        if kernel_tmp:
            kernel_tmp.close()
Пример #4
0
    def collect_xml(self, kernel_el, kernel_heap_size, namespace, image,
                    machine, pools):
        """Collect the attributes of the kernel element."""

        (elf, kernel_file, kernel_tmp) = get_kernel_file(kernel_el, machine)

        if elf.elf_type != ET_EXEC:
            raise MergeError, \
                  "All the merged ELF files must be of EXEC type."

        # New namespace for objects living in the kernel.
        kernel_namespace = namespace.add_namespace('kernel')

        # We setup our kernel type depending on the api version number
        kern_ver = check_api_versions(elf)
        if kern_ver == NANO_KERNEL_API_VERSION:
            self.kernel = NanoKernel(elf, kernel_namespace, machine)
        else:
            self.kernel = MicroKernel(kernel_namespace)

        assert self.total_threads is None
        self.total_threads = self.kernel.ABSOLUTE_MAX_THREADS

        # Record the default pools for cells to use if they don't have
        # defaults set.
        virtpool = getattr(kernel_el, "virtpool", None)
        physpool = getattr(kernel_el, "physpool", None)
        image.set_attrs_stack(def_virt = virtpool,
                              def_phys = physpool)
        pools.set_default_pools(virtpool, physpool)

        segment_els = kernel_el.find_children("segment")
        patch_els   = kernel_el.find_children("patch")

        machine.set_cache_attributes(elf)

        image.set_kernel(elf)
        segs = collect_elf_segments(elf, image.KERNEL, segment_els,
                                    'kernel', self.kernel.segment_drops,
                                    kernel_namespace, image, machine, pools)
        # Set base segment
        self.base_segment = self.kernel.get_base_segment(elf, segs, image)

        if self.base_segment.attrs.phys_addr is not None and \
            (self.base_segment.attrs.phys_addr & ((1024 * 1024) - 1)) != 0:
            raise MergeError("Physical address of %s must be 1MB aligned!" %
                                    self.base_segment.attrs.abs_name())

        elf = elf.prepare(elf.wordsize, elf.endianess)
        # The extra_patches attr may be added by a plugin.
        for patch in getattr(Kernel_el, "extra_patches", []):
            addr = get_symbol(elf, patch[0], True)
            if addr != None:
                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, kernel_file, image)

        # Collect the config elements, some of these relate to
        # heap and thread array, so do it first
        config_el = kernel_el.find_child("config")
        if config_el is not None:
            for option in config_el.find_children("option"):
                self.add_config(option.key, option.value)

        heap_attrs       = image.new_attrs(namespace.root.add_namespace("kernel_heap"))
        heap_attrs.align = machine.kernel_heap_align
        heap_el          = kernel_el.find_child("heap")
        if heap_el is not None:
            heap_attrs.phys_addr = getattr(heap_el, 'phys_addr',
                                           heap_attrs.phys_addr)
            heap_attrs.size      = getattr(heap_el, 'size', heap_attrs.size)
            heap_attrs.align     = getattr(heap_el, 'align', heap_attrs.align)

        # Override the size with the command line value, if present.
        if kernel_heap_size != 0:
            heap_attrs.size = kernel_heap_size

        # Nano needs a heap size set early on
        # Micro remains unassigned since it will get dynamically calculated later
        if not heap_attrs.size and isinstance(self.kernel, NanoKernel):
            heap_attrs.size = self.kernel.DEFAULT_KERNEL_HEAP_SIZE

        self.heap = image.set_kernel_heap(heap_attrs, machine,
                                          pools, self.base_segment.segment,
                                          isinstance(self.kernel, NanoKernel))
        image.add_group(machine.kernel_heap_proximity, (self.base_segment, self.heap))
        self.register_heap(heap_attrs)

        if isinstance(self.kernel, MicroKernel):
            image.utcb_size = self.kernel.get_utcb_size(elf, image)

        self.collect_use_devices(kernel_el, image, machine, pools)

        if kernel_tmp:
            kernel_tmp.close()