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

# 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