You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
97 lines
2.9 KiB
Ruby
97 lines
2.9 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
# SPDX-License-Identifier: MIT OR Apache-2.0
|
|
#
|
|
# Copyright (c) 2021-2022 Andre Richter <andre.o.richter@gmail.com>
|
|
|
|
# KernelELF
|
|
class KernelELF
|
|
SECTION_FLAG_ALLOC = 2
|
|
|
|
def initialize(kernel_elf_path)
|
|
@elf = ELFTools::ELFFile.new(File.open(kernel_elf_path))
|
|
@symtab_section = @elf.section_by_name('.symtab')
|
|
end
|
|
|
|
def machine
|
|
@elf.machine.to_sym
|
|
end
|
|
|
|
def symbol_value(symbol_name)
|
|
@symtab_section.symbol_by_name(symbol_name).header.st_value
|
|
end
|
|
|
|
def segment_containing_virt_addr(virt_addr)
|
|
@elf.each_segments do |segment|
|
|
return segment if segment.vma_in?(virt_addr)
|
|
end
|
|
end
|
|
|
|
def virt_to_phys(virt_addr)
|
|
segment = segment_containing_virt_addr(virt_addr)
|
|
translation_offset = segment.header.p_vaddr - segment.header.p_paddr
|
|
|
|
virt_addr - translation_offset
|
|
end
|
|
|
|
def virt_addr_to_file_offset(virt_addr)
|
|
segment = segment_containing_virt_addr(virt_addr)
|
|
segment.vma_to_offset(virt_addr)
|
|
end
|
|
|
|
def sections_in_segment(segment)
|
|
head = segment.mem_head
|
|
tail = segment.mem_tail
|
|
|
|
sections = @elf.each_sections.select do |section|
|
|
file_offset = section.header.sh_addr
|
|
flags = section.header.sh_flags
|
|
|
|
file_offset >= head && file_offset < tail && (flags & SECTION_FLAG_ALLOC != 0)
|
|
end
|
|
|
|
sections.map(&:name).join(' ')
|
|
end
|
|
|
|
def select_load_segments
|
|
@elf.each_segments.select do |segment|
|
|
segment.instance_of?(ELFTools::Segments::LoadSegment)
|
|
end
|
|
end
|
|
|
|
def segment_get_acc_perms(segment)
|
|
if segment.readable? && segment.writable?
|
|
:ReadWrite
|
|
elsif segment.readable?
|
|
:ReadOnly
|
|
else
|
|
:Invalid
|
|
end
|
|
end
|
|
|
|
def update_max_section_name_length(descriptors)
|
|
MappingDescriptor.update_max_section_name_length(descriptors.map { |i| i.name.size }.max)
|
|
end
|
|
|
|
def generate_mapping_descriptors
|
|
descriptors = select_load_segments.map do |segment|
|
|
# Assume each segment is page aligned.
|
|
size = segment.mem_size.align_up(BSP.kernel_granule::SIZE)
|
|
virt_start_addr = segment.header.p_vaddr
|
|
phys_start_addr = segment.header.p_paddr
|
|
acc_perms = segment_get_acc_perms(segment)
|
|
execute_never = !segment.executable?
|
|
section_names = sections_in_segment(segment)
|
|
|
|
virt_region = MemoryRegion.new(virt_start_addr, size, BSP.kernel_granule::SIZE)
|
|
phys_region = MemoryRegion.new(phys_start_addr, size, BSP.kernel_granule::SIZE)
|
|
attributes = AttributeFields.new(:CacheableDRAM, acc_perms, execute_never)
|
|
|
|
MappingDescriptor.new(section_names, virt_region, phys_region, attributes)
|
|
end
|
|
|
|
update_max_section_name_length(descriptors)
|
|
descriptors
|
|
end
|
|
end
|