def guard_pages(obj_space, cspaces, elfs, options, **_): '''Introduce a guard page around each stack and IPC buffer. Note that the templates should have ensured a three page region for each stack in order to enable this.''' for group, space in cspaces.items(): cnode = space.cnode for index, tcb in [(k, v.referent) for (k, v) in cnode.slots.items() \ if v is not None and isinstance(v.referent, TCB)]: perspective = Perspective(group=group, tcb=tcb.name) if perspective['pool']: # This TCB is part of the (cap allocator's) TCB pool. continue elf_name = perspective['elf_name'] # Find the page directory. pd = None pd_name = perspective['pd'] pds = [x for x in obj_space.spec.objs if x.name == pd_name] if len(pds) > 1: raise Exception('Multiple PDs found for group %s' % group) elif len(pds) == 1: pd, = pds tcb['vspace'] = Cap(pd) # If no PD was found we were probably just not passed any ELF files # in this pass. elf = elfs.get(elf_name) if pd and elf: ipc_symbol = perspective['ipc_buffer_symbol'] # Find the IPC buffer's preceding guard page's virtual address. assert get_symbol_size(elf, ipc_symbol) == PAGE_SIZE * 3 pre_guard = get_symbol_vaddr(elf, ipc_symbol) # Relate this virtual address to a PT. pt_index = page_table_index(get_elf_arch(elf), pre_guard, options.hyp) if pt_index not in pd: raise Exception('IPC buffer region of TCB %s in ' \ 'group %s does not appear to be backed by a frame' \ % (tcb.name, group)) pt = pd[pt_index].referent # Continue on to infer the page. p_index = page_index(get_elf_arch(elf), pre_guard, options.hyp) if p_index not in pt: raise Exception('IPC buffer region of TCB %s in ' \ 'group %s does not appear to be backed by a frame' \ % (tcb.name, group)) # Delete the page. frame = pt[p_index].referent del pt[p_index] obj_space.remove(frame) # Now do the same for the following guard page. We do this # calculation separately just in case the region crosses a PT # boundary and the two guard pages are in separate PTs. post_guard = pre_guard + 2 * PAGE_SIZE pt_index = page_table_index(get_elf_arch(elf), post_guard, options.hyp) if pt_index not in pd: raise Exception('IPC buffer region of TCB %s in ' \ 'group %s does not appear to be backed by a frame' \ % (tcb.name, group)) pt = pd[pt_index].referent p_index = page_index(get_elf_arch(elf), post_guard, options.hyp) if p_index not in pt: raise Exception('IPC buffer region of TCB %s in ' \ 'group %s does not appear to be backed by a frame' \ % (tcb.name, group)) frame = pt[p_index].referent del pt[p_index] obj_space.remove(frame) # Now we do the same thing for the preceding guard page of the # thread's stack... stack_symbol = perspective['stack_symbol'] pre_guard = get_symbol_vaddr(elf, stack_symbol) pt_index = page_table_index(get_elf_arch(elf), pre_guard, options.hyp) if pt_index not in pd: raise Exception('stack region of TCB %s in ' \ 'group %s does not appear to be backed by a frame' \ % (tcb.name, group)) pt = pd[pt_index].referent p_index = page_index(get_elf_arch(elf), pre_guard, options.hyp) if p_index not in pt: raise Exception('stack region of TCB %s in ' \ 'group %s does not appear to be backed by a frame' \ % (tcb.name, group)) frame = pt[p_index].referent del pt[p_index] obj_space.remove(frame) # ...and the following guard page. stack_region_size = get_symbol_size(elf, stack_symbol) assert stack_region_size % PAGE_SIZE == 0, \ 'stack region is not page-aligned' assert stack_region_size >= 3 * PAGE_SIZE, \ 'stack region has no room for guard pages' post_guard = pre_guard + stack_region_size - PAGE_SIZE pt_index = page_table_index(get_elf_arch(elf), post_guard, options.hyp) if pt_index not in pd: raise Exception('stack region of TCB %s in ' \ 'group %s does not appear to be backed by a frame' \ % (tcb.name, group)) pt = pd[pt_index].referent p_index = page_index(get_elf_arch(elf), post_guard, options.hyp) if p_index not in pt: raise Exception('stack region of TCB %s in ' \ 'group %s does not appear to be backed by a frame' \ % (tcb.name, group)) frame = pt[p_index].referent del pt[p_index] obj_space.remove(frame)
def collapse_shared_frames(ast, obj_space, elfs, options, **_): """Find regions in virtual address spaces that are intended to be backed by shared frames and adjust the capability distribution to reflect this.""" if not elfs: # If we haven't been passed any ELF files this step is not relevant yet. return assembly = find_assembly(ast) # We want to track the frame objects backing shared regions with a dict # keyed on the name of the connection linking the regions. shared_frames = {} for i in (x for x in assembly.composition.instances if not x.type.hardware): perspective = Perspective(instance=i.name, group=i.address_space) elf_name = perspective['elf_name'] assert elf_name in elfs elf = elfs[elf_name] # Find this instance's page directory. pd_name = perspective['pd'] pds = [x for x in obj_space.spec.objs if x.name == pd_name] assert len(pds) == 1 pd, = pds large_frame_uid = 0 for d in i.type.dataports: # Find the connection that associates this dataport with another. connections = [x for x in assembly.composition.connections if \ ((x.from_instance == i and x.from_interface == d) or \ (x.to_instance == i and x.to_interface == d))] if len(connections) == 0: # This dataport is unconnected. continue #assert len(connections) == 1 conn_name = connections[0].name if connections[0].from_instance == i and \ connections[0].from_interface == d: direction = 'from' else: assert connections[0].to_instance == i assert connections[0].to_interface == d direction = 'to' # Reverse the logic in the Makefile template. p = Perspective(instance=i.name, dataport=d.name) sym = p['dataport_symbol'] vaddr = get_symbol_vaddr(elf, sym) assert vaddr is not None, 'failed to find dataport symbol \'%s\'' \ ' in ELF %s' % (sym, elf_name) assert vaddr != 0 assert vaddr % PAGE_SIZE == 0, 'dataport not page-aligned' sz = get_symbol_size(elf, sym) assert sz != 0 arch = get_elf_arch(elf) # Infer the page table(s) and page(s) that back this region. pts, p_indices = zip(*[\ (pd[page_table_index(arch, v, options.hyp)].referent, page_index(arch, v, options.hyp)) \ for v in xrange(vaddr, vaddr + sz, PAGE_SIZE)]) # Determine the rights this mapping should have. We use these to # recreate the mapping below. Technically we may not need to # recreate this mapping if it's already correct, but do it anyway # for simplicity. # FIXME: stop hard coding this name mangling. rights_setting = assembly.configuration[conn_name].get('%s_access' % direction) if rights_setting is not None and \ re.match(r'^"R?W?(G|X)?"$', rights_setting): read = 'R' in rights_setting write = 'W' in rights_setting execute = 'X' in rights_setting or 'G' in rights_setting else: # default read = True write = True execute = False # Check if the dataport is connected *TO* a hardware component. if connections[0].to_instance.type.hardware: p = Perspective(to_interface=connections[0].to_interface.name) hardware_attribute = p['hardware_attribute'] conf = assembly.configuration[connections[0].to_instance.name].get(hardware_attribute) assert conf is not None paddr, size = conf.strip('"').split(':') # Round up the MMIO size to PAGE_SIZE paddr = int(paddr, 0) size = int(size, 0) instance_name = connections[0].to_instance.name if size == 0: raise Exception('Hardware dataport %s.%s has zero size!' % (instance_name, connections[0].to_interface.name)) # determine the size of a large frame, and the type of kernel # object that will be used, both of which depend on the architecture if get_elf_arch(elf) == 'ARM': large_size = 1024 * 1024 large_object_type = seL4_ARM_SectionObject else: large_size = 4 * 1024 * 1024 large_object_type = seL4_IA32_4M # Check if MMIO start and end is aligned to page table coverage. # This will indicate that we should use pagetable-sized pages # to back the device region to be consistent with the kernel. if paddr % large_size == 0 and size % large_size == 0: # number of page tables backing device memory n_pts = size / large_size # index of first page table in page directory backing the device memory base_pt_index = page_table_index(get_elf_arch(elf), vaddr) pt_indices = xrange(base_pt_index, base_pt_index + n_pts) # loop over all the page table indices and replace the page tables # with large frames for count, pt_index in enumerate(pt_indices): # look up the page table at the current index pt = pd[pt_index].referent name = 'large_frame_%s_%d' % (instance_name, large_frame_uid) large_frame_uid += 1 frame_paddr = paddr + large_size * count # allocate a new large frame frame = obj_space.alloc(large_object_type, name, paddr=frame_paddr) # insert the frame cap into the page directory frame_cap = Cap(frame, read, write, execute) frame_cap.set_cached(False) pd[pt_index] = frame_cap # remove all the small frames from the spec for p_index in pt: small_frame = pt[p_index].referent obj_space.remove(small_frame) # remove the page table from the spec obj_space.remove(pt) else: # If the MMIO start and end are not aligned to page table coverage, # loop over all the frames and set their paddrs based on the # paddr in the spec. for idx in xrange(0, (size + PAGE_SIZE - 1) / PAGE_SIZE): try: frame_obj = pts[idx][p_indices[idx]].referent except IndexError: raise Exception('MMIO attributes specify device ' \ 'memory that is larger than the dataport it is ' \ 'associated with') frame_obj.paddr = paddr + PAGE_SIZE * idx cap = Cap(frame_obj, read, write, execute) cap.set_cached(False) pts[idx].slots[p_indices[idx]] = cap obj_space.relabel(conn_name, frame_obj) continue shm_keys = [] for c in connections: shm_keys.append('%s_%s' % (c.from_instance.name, c.from_interface.name)) shm_keys.append('%s_%s' % (c.to_instance.name, c.to_interface.name)) mapped = [x for x in shm_keys if x in shared_frames] if mapped: # We've already encountered the other side of this dataport. # The region had better be the same size in all address spaces. for key in mapped: assert len(shared_frames[key]) == sz / PAGE_SIZE # This is the first side of this dataport. # Save all the frames backing this region. for key in shm_keys: if mapped: shared_frames[key] = shared_frames[mapped[0]] else: shared_frames[key] = [pt[p_index].referent \ for (pt, p_index) in zip(pts, p_indices)] # Overwrite the caps backing this region with caps to the shared # frames. for j, f in enumerate(shared_frames[shm_keys[0]]): existing = pts[j].slots[p_indices[j]].referent if existing != f: # We're actually modifying this mapping. Delete the # unneeded frame. obj_space.remove(existing) pts[j].slots[p_indices[j]] = Cap(f, read, write, execute) obj_space.relabel(conn_name, f)
def replace_dma_frames(ast, obj_space, elfs, options, **_): '''Locate the DMA pool (a region that needs to have frames whose mappings can be reversed) and replace its backing frames with pre-allocated, reversible ones.''' # TODO: Large parts of this function clagged from collapse_shared_frames; Refactor. if not elfs: # If we haven't been passed any ELF files this step is not relevant yet. return assembly = find_assembly(ast) for i in (x for x in assembly.composition.instances if not x.type.hardware): perspective = Perspective(instance=i.name, group=i.address_space) elf_name = perspective['elf_name'] assert elf_name in elfs elf = elfs[elf_name] # Find this instance's page directory. pd_name = perspective['pd'] pds = filter(lambda x: x.name == pd_name, obj_space.spec.objs) assert len(pds) == 1 pd, = pds sym = perspective['dma_pool_symbol'] base = get_symbol_vaddr(elf, sym) if base is None: # We don't have a DMA pool. continue assert base != 0 sz = get_symbol_size(elf, sym) assert sz % PAGE_SIZE == 0 # DMA pool should be page-aligned. # Generate a list of the base addresses of the pages we need to # replace. base_vaddrs = [PAGE_SIZE * x + base for x in range(int(sz / PAGE_SIZE))] for index, v in enumerate(base_vaddrs): # Locate the mapping. pt_index = page_table_index(get_elf_arch(elf), v, options.hyp) p_index = page_index(get_elf_arch(elf), v, options.hyp) # It should contain an existing frame. assert pt_index in pd pt = pd[pt_index].referent assert p_index in pt discard_frame = pt[p_index].referent # Locate the frame we're going to replace it with. The logic that # constructs this object name is in component.template.c. Note that # we need to account for the guard-prefix of the instance name # introduced by the template context. p = Perspective(instance=i.name, group=i.address_space, dma_frame_index=index) dma_frames = [x for x in obj_space.spec.objs if x.name == p['dma_frame_symbol']] assert len(dma_frames) == 1 dma_frame, = dma_frames # Replace the existing mapping. c = Cap(dma_frame, True, True, False) # RW c.set_cached(False) pt.slots[p_index] = c # We can now remove the old frame as we know it's not referenced # anywhere else. TODO: assert this somehow. obj_space.remove(discard_frame)
def set_tcb_caps(ast, obj_space, cspaces, elfs, options, **_): assembly = find_assembly(ast) for group, space in cspaces.items(): cnode = space.cnode for index, tcb in [(k, v.referent) for (k, v) in cnode.slots.items() \ if v is not None and isinstance(v.referent, TCB)]: perspective = Perspective(tcb=tcb.name, group=group) # Finalise the CNode so that we know what its absolute size will # be. Note that we are assuming no further caps will be added to # the CNode after this point. cnode.finalise_size() # Allow the user to override CNode sizes with the 'cnode_size_bits' # attribute. cnode_size = assembly.configuration[group].get('cnode_size_bits') if cnode_size is not None: try: if isinstance(cnode_size, str): size = int(cnode_size, 0) else: size = cnode_size except ValueError: raise Exception('illegal value for CNode size for %s' % \ group) if size < cnode.size_bits: raise Exception('%d-bit CNode specified for %s, but this ' \ 'CSpace needs to be at least %d bits' % \ (size, group, cnode.size_bits)) cnode.size_bits = size cspace = Cap(cnode) cspace.set_guard_size(32 - cnode.size_bits) tcb['cspace'] = cspace elf_name = perspective['elf_name'] pd = None pd_name = perspective['pd'] pds = [x for x in obj_space.spec.objs if x.name == pd_name] if len(pds) > 1: raise Exception('Multiple PDs found for %s' % group) elif len(pds) == 1: pd, = pds tcb['vspace'] = Cap(pd) # If no PD was found we were probably just not passed any ELF files # in this pass. if perspective['pool']: # This TCB is part of the (cap allocator's) TCB pool. continue elf = elfs.get(elf_name) if pd and elf: ipc_symbol = perspective['ipc_buffer_symbol'] # Find the IPC buffer's virtual address. assert get_symbol_size(elf, ipc_symbol) == PAGE_SIZE * 3 ipc_vaddr = get_symbol_vaddr(elf, ipc_symbol) + PAGE_SIZE # Relate this virtual address to a PT. pt_index = page_table_index(get_elf_arch(elf), ipc_vaddr, options.hyp) if pt_index not in pd: raise Exception('IPC buffer of TCB %s in group %s does ' \ 'not appear to be backed by a frame' % (tcb.name, group)) pt = pd[pt_index].referent # Continue on to infer the physical frame. p_index = page_index(get_elf_arch(elf), ipc_vaddr, options.hyp) if p_index not in pt: raise Exception('IPC buffer of TCB %s in group %s does ' \ 'not appear to be backed by a frame' % (tcb.name, group)) frame = pt[p_index].referent tcb['ipc_buffer_slot'] = Cap(frame, True, True, False) # RW
def collapse_shared_frames(ast, obj_space, cspaces, elfs, options, **_): """Find regions in virtual address spaces that are intended to be backed by shared frames and adjust the capability distribution to reflect this.""" if not elfs: # If we haven't been passed any ELF files this step is not relevant yet. return assembly = find_assembly(ast) # We want to track the frame objects backing shared regions with a dict # keyed on the name of the connection linking the regions. shared_frames = {} for i in (x for x in assembly.composition.instances if not x.type.hardware): perspective = Perspective(instance=i.name, group=i.address_space) elf_name = perspective['elf_name'] assert elf_name in elfs elf = elfs[elf_name] # Find this instance's page directory. pd_name = perspective['pd'] pds = [x for x in obj_space.spec.objs if x.name == pd_name] assert len(pds) == 1 pd, = pds for d in i.type.dataports: # Find the connection that associates this dataport with another. connections = [x for x in assembly.composition.connections if \ ((x.from_instance == i and x.from_interface == d) or \ (x.to_instance == i and x.to_interface == d))] if len(connections) == 0: # This dataport is unconnected. continue #assert len(connections) == 1 conn_name = connections[0].name if connections[0].from_instance == i and \ connections[0].from_interface == d: direction = 'from' else: assert connections[0].to_instance == i assert connections[0].to_interface == d direction = 'to' # Reverse the logic in the Makefile template. p = Perspective(instance=i.name, dataport=d.name) sym = p['dataport_symbol'] vaddr = get_symbol_vaddr(elf, sym) assert vaddr is not None, 'failed to find dataport symbol \'%s\'' \ ' in ELF %s' % (sym, elf_name) assert vaddr != 0 assert vaddr % PAGE_SIZE == 0, 'dataport %s not page-aligned' % sym sz = get_symbol_size(elf, sym) assert sz != 0 # Infer the page table(s) and page(s) that back this region. pts, p_indices = zip(*[\ (pd[page_table_index(options.architecture, v)].referent, page_index(options.architecture, v)) \ for v in xrange(vaddr, vaddr + sz, PAGE_SIZE)]) # Determine the rights this mapping should have. We use these to # recreate the mapping below. Technically we may not need to # recreate this mapping if it's already correct, but do it anyway # for simplicity. # FIXME: stop hard coding this name mangling. rights_setting = assembly.configuration[conn_name].get('%s_access' % direction) if rights_setting is not None and \ re.match(r'^"R?W?(G|X)?"$', rights_setting): read = 'R' in rights_setting write = 'W' in rights_setting execute = 'X' in rights_setting or 'G' in rights_setting else: # default read = True write = True execute = False # Check if the dataport is connected *TO* a hardware component. if connections[0].to_instance.type.hardware: p = Perspective(to_interface=connections[0].to_interface.name) hardware_attribute = p['hardware_attribute'] conf = assembly.configuration[connections[0].to_instance.name].get(hardware_attribute) assert conf is not None, "%s.%s not found in configuration" % \ (connections[0].to_instance.name, hardware_attribute) paddr, size = conf.strip('"').split(':') # Round up the MMIO size to PAGE_SIZE try: paddr = int(paddr, 0) except ValueError: raise Exception("Invalid physical address specified for %s.%s: %s\n" % (me.to_instance.name, me.to_interface.name, paddr)) try: size = int(size, 0) except ValueError: raise Exception("Invalid size specified for %s.%s: %s\n" % (me.to_instance.name, me.to_interface.name, size)) hardware_cached = p['hardware_cached'] cached = assembly.configuration[connections[0].to_instance.name].get(hardware_cached) if cached is None: cached = False elif cached.lower() == 'true': cached = True elif cached.lower() == 'false': cached = False else: raise Exception("Value of %s.%s_cached must be either 'true' or 'false'. Got '%s'." % (me.to_instance.name, me.to_interface.name, cached)) instance_name = connections[0].to_instance.name if size == 0: raise Exception('Hardware dataport %s.%s has zero size!' % (instance_name, connections[0].to_interface.name)) # determine the size of a large frame, and the type of kernel # object that will be used, both of which depend on the architecture if get_elf_arch(elf) == 'ARM': large_size = 1024 * 1024 large_object_type = seL4_ARM_SectionObject else: large_size = 4 * 1024 * 1024 large_object_type = seL4_IA32_4M # Check if MMIO start and end is aligned to page table coverage. # This will indicate that we should use pagetable-sized pages # to back the device region to be consistent with the kernel. if paddr % large_size == 0 and size % large_size == 0: # number of page tables backing device memory n_pts = size / large_size # index of first page table in page directory backing the device memory base_pt_index = page_table_index(options.architecture, vaddr) pt_indices = xrange(base_pt_index, base_pt_index + n_pts) # loop over all the page table indices and replace the page tables # with large frames for count, pt_index in enumerate(pt_indices): # look up the page table at the current index pt = pd[pt_index].referent offset = count * large_size frame_paddr = paddr + offset # lookup the frame, already allocated by a template frame_cap = find_hardware_frame_in_cspace( cspaces[i.address_space], frame_paddr, connections[0].to_instance.name, connections[0].to_interface.name) frame_obj = frame_cap.referent # create a new cap for the frame to use for its mapping mapping_frame_cap = Cap(frame_obj, read, write, execute) mapping_frame_cap.set_cached(cached) # add the mapping to the spec pd[pt_index] = mapping_frame_cap # add the mapping information to the original cap frame_cap.set_mapping(pd, pt_index) # remove all the small frames from the spec for p_index in pt: small_frame = pt[p_index].referent obj_space.remove(small_frame) # remove the page table from the spec obj_space.remove(pt) else: # If the MMIO start and end are not aligned to page table coverage, # loop over all the frames and set their paddrs based on the # paddr in the spec. for idx in xrange(0, (size + PAGE_SIZE - 1) / PAGE_SIZE): try: frame_obj = pts[idx][p_indices[idx]].referent except IndexError: raise Exception('MMIO attributes specify device ' \ 'memory that is larger than the dataport it is ' \ 'associated with') offset = idx * PAGE_SIZE frame_paddr = paddr + offset # lookup the frame, already allocated by a template frame_cap = find_hardware_frame_in_cspace( cspaces[i.address_space], frame_paddr, connections[0].to_instance.name, connections[0].to_interface.name) frame_obj = frame_cap.referent # create a new cap for the frame to use for its mapping mapping_frame_cap = Cap(frame_obj, read, write, execute) mapping_frame_cap.set_cached(cached) # add the mapping to the spec pt = pts[idx] slot = p_indices[idx] pt.slots[slot] = mapping_frame_cap # add the mapping information to the original cap frame_cap.set_mapping(pt, slot) obj_space.relabel(conn_name, frame_obj) continue # If any objects still have names indicating they are part of a hardware # dataport, it means that dataport hasn't been given a paddr or size. # This indicates an error, and the object name is invalid in capdl, # so catch the error here rather than having the capdl translator fail. for cap in (v for v in cspaces[i.address_space].cnode.slots.values() if v is not None): obj = cap.referent match = HARDWARE_FRAME_NAME_PATTERN.match(obj.name) assert (match is None or match.group(2) != connections[0].to_instance.name), \ "Missing hardware attributes for %s.%s" % (match.group(2), match.group(3)) shm_keys = [] for c in connections: shm_keys.append('%s_%s' % (c.from_instance.name, c.from_interface.name)) shm_keys.append('%s_%s' % (c.to_instance.name, c.to_interface.name)) mapped = [x for x in shm_keys if x in shared_frames] if mapped: # We've already encountered the other side of this dataport. # The region had better be the same size in all address spaces. for key in mapped: assert len(shared_frames[key]) == sz / PAGE_SIZE # This is the first side of this dataport. # Save all the frames backing this region. for key in shm_keys: if mapped: shared_frames[key] = shared_frames[mapped[0]] else: shared_frames[key] = [pt[p_index].referent \ for (pt, p_index) in zip(pts, p_indices)] # Overwrite the caps backing this region with caps to the shared # frames. for j, f in enumerate(shared_frames[shm_keys[0]]): existing = pts[j].slots[p_indices[j]].referent if existing != f: # We're actually modifying this mapping. Delete the # unneeded frame. obj_space.remove(existing) pts[j].slots[p_indices[j]] = Cap(f, read, write, execute) obj_space.relabel(conn_name, f)
def collapse_shared_frames(ast, obj_space, cspaces, elfs, *_): """Find regions in virtual address spaces that are intended to be backed by shared frames and adjust the capability distribution to reflect this.""" if not elfs: # If we haven't been passed any ELF files this step is not relevant yet. return assembly = find_assembly(ast) settings = \ assembly.configuration.settings if assembly.configuration is not None \ else [] # We want to track the frame objects backing shared regions with a dict # keyed on the name of the connection linking the regions. shared_frames = {} for i in assembly.composition.instances: if i.type.hardware: continue perspective = Perspective(instance=i.name, group=i.address_space) elf_name = perspective['elf_name'] assert elf_name in elfs elf = elfs[elf_name] # Find this instance's page directory. pd_name = perspective['pd'] pds = filter(lambda x: x.name == pd_name, obj_space.spec.objs) assert len(pds) == 1 pd, = pds for d in i.type.dataports: # Find the connection that associates this dataport with another. connections = filter(lambda x: \ (x.from_instance == i and x.from_interface == d) or \ (x.to_instance == i and x.to_interface == d), \ assembly.composition.connections) if len(connections) == 0: # This dataport is unconnected. continue #assert len(connections) == 1 conn_name = connections[0].name if connections[0].from_instance == i and \ connections[0].from_interface == d: direction = 'from' else: assert connections[0].to_instance == i assert connections[0].to_interface == d direction = 'to' # Reverse the logic in the Makefile template. p = Perspective(instance=i.name, dataport=d.name) sym = p['dataport_symbol'] vaddr = get_symbol_vaddr(elf, sym) assert vaddr is not None, 'failed to find dataport symbol \'%s\'' \ ' in ELF %s' % (sym, elf_name) assert vaddr != 0 sz = get_symbol_size(elf, sym) assert sz != 0 # Infer the page table that backs this vaddr. pt_index = page_table_index(get_elf_arch(elf), vaddr) assert pt_index in pd pt = pd[pt_index].referent # Infer the starting page index of this vaddr. p_index = page_index(get_elf_arch(elf), vaddr) # TODO: If the following assertion fails it means that the shared # region crosses a PT boundary (i.e. it is backed by more than one # PT). In theory we could support this with a bit more cleverness # here. assert page_table_index(get_elf_arch(elf), vaddr + sz - 1) == pt_index # Determine the rights this mapping should have. We use these to # recreate the mapping below. Technically we may not need to # recreate this mapping if it's already correct, but do it anyway # for simplicity. # FIXME: stop hard coding this name mangling. rights_setting = filter(lambda x: x.instance == conn_name and \ x.attribute == '%s_access' % direction, settings) if len(rights_setting) == 1 and \ re.match(r'^"R?W?(G|X)?"$', rights_setting[0].value): read = 'R' in rights_setting[0].value write = 'W' in rights_setting[0].value execute = 'X' in rights_setting[0].value or \ 'G' in rights_setting[0].value else: # default read = True write = True execute = False # Check if the dataport is connected *TO* a hardware component. if connections[0].to_instance.type.hardware and \ assembly.configuration is not None: p = Perspective(to_interface=connections[0].to_interface.name) hardware_attribute = p['hardware_attribute'] configurations = filter(lambda x: \ (x.instance == connections[0].to_instance.name and \ x.attribute == hardware_attribute), \ assembly.configuration.settings) assert len(configurations) == 1 paddr, size = configurations[0].value.strip('"').split(':') # Round up the MMIO size to PAGE_SIZE size = int(size, 16) for idx in range(0, (size + PAGE_SIZE - 1) / PAGE_SIZE): frame_obj = pt[p_index + idx].referent frame_obj.paddr = int(paddr, 16) + PAGE_SIZE * idx cap = Cap(frame_obj, read, write, execute) cap.set_cached(False) pt.slots[p_index + idx] = cap obj_space.relabel(conn_name, frame_obj) continue shm_keys = [] for c in connections: shm_keys.append('%s_%s' % (c.from_instance.name, c.from_interface.name)) shm_keys.append('%s_%s' % (c.to_instance.name, c.to_interface.name)) mapped = filter(lambda x: x in shared_frames, shm_keys) if mapped: # We've already encountered the other side of tnhis dataport. # The region had better be the same size in all address spaces. for key in mapped: assert len(shared_frames[key]) == sz / PAGE_SIZE # This is the first side of this dataport. # Save all the frames backing this region. for key in shm_keys: if mapped: shared_frames[key] = shared_frames[mapped[0]] else: shared_frames[key] = \ map(lambda x: pt[p_index + x].referent, \ range(0, sz / PAGE_SIZE)) # Overwrite the caps backing this region with caps to the shared # frames. Again, note we may not need to do this, but doing it # unconditionally is simpler. for j in range(0, sz / PAGE_SIZE): f = shared_frames[shm_keys[0]][j] pt.slots[p_index + j] = Cap(f, read, write, execute) obj_space.relabel(conn_name, f)
def set_tcb_caps(ast, obj_space, cspaces, elfs, *_): for group, space in cspaces.items(): cnode = space.cnode for index, cap in cnode.slots.items(): if cap is None: continue tcb = cap.referent if not isinstance(tcb, TCB): continue perspective = Perspective(tcb=tcb.name, group=group) # Finalise the CNode so that we know what its absolute size will # be. Note that we are assuming no further caps will be added to # the CNode after this point. cnode.finalise_size() cspace = Cap(cnode) cspace.set_guard_size(32 - cnode.size_bits) tcb['cspace'] = cspace elf_name = perspective['elf_name'] pd = None pd_name = perspective['pd'] pds = filter(lambda x: x.name == pd_name, obj_space.spec.objs) if len(pds) > 1: raise Exception('Multiple PDs found for %s' % group) elif len(pds) == 1: pd, = pds tcb['vspace'] = Cap(pd) # If no PD was found we were probably just not passed any ELF files # in this pass. if perspective['pool']: # This TCB is part of the (cap allocator's) TCB pool. continue elf = elfs.get(elf_name) if pd and elf: ipc_symbol = perspective['ipc_buffer_symbol'] # Find the IPC buffer's virtual address. assert get_symbol_size(elf, ipc_symbol) == PAGE_SIZE * 3 ipc_vaddr = get_symbol_vaddr(elf, ipc_symbol) + PAGE_SIZE # Relate this virtual address to a PT. pt_index = page_table_index(get_elf_arch(elf), ipc_vaddr) if pt_index not in pd: raise Exception('IPC buffer of TCB %s in group %s does ' \ 'not appear to be backed by a frame' % (tcb.name, group)) pt = pd[pt_index].referent # Continue on to infer the physical frame. p_index = page_index(get_elf_arch(elf), ipc_vaddr) if p_index not in pt: raise Exception('IPC buffer of TCB %s in group %s does ' \ 'not appear to be backed by a frame' % (tcb.name, group)) frame = pt[p_index].referent tcb['ipc_buffer_slot'] = Cap(frame, True, True, True) # RWG