forgot to commit image loader code

kernel-mode
Anton Lydike 3 years ago
parent 1f03449694
commit df9e610d14

@ -0,0 +1,104 @@
"""
Laods a memory image with debug information into memory
"""
from ..MMU import MMU
from ..Config import RunConfig
from ..Executable import Executable, LoadedExecutable, LoadedMemorySection, LoadedInstruction, MemoryFlags
from .ElfLoader import ElfInstruction, ElfLoadedMemorySection, InstructionAccessFault, InstructionAddressMisalignedTrap
from ..decoder import decode
from ..IO.IOModule import IOModule
from .privmodes import PrivModes
from ..colors import FMT_ERROR, FMT_NONE
from functools import lru_cache
from typing import Dict, List, Tuple, Optional, TYPE_CHECKING
if TYPE_CHECKING:
from .PrivCPU import PrivCPU
class ContinuousMMU(MMU):
io: List[IOModule]
data: bytearray
io_start: int
debug_info: Dict[str, Dict[str, str]]
def __init__(self, data: bytes, debug_info: Dict, cpu, io_start: int = 0xFF0000):
super(ContinuousMMU, self).__init__(conf=RunConfig())
self.cpu: 'PrivCPU' = cpu
self.data = bytearray(data)
if len(data) < io_start:
self.data += bytearray(io_start - len(data))
self.debug_info = debug_info
self.io_start = io_start
self.io = list()
self.kernel_end = 0
for start, name in debug_info['sections'].items():
if name.startswith('programs'):
self.kernel_end = int(start)
break
@lru_cache(maxsize=2048)
def read_ins(self, addr: int) -> ElfInstruction:
if addr >= self.io_start:
raise InstructionAccessFault(addr)
if addr % 4 != 0:
raise InstructionAddressMisalignedTrap(addr)
return ElfInstruction(*decode(self.data[addr:addr + 4]))
def read(self, addr: int, size: int) -> bytearray:
if addr < 0x100:
pc = self.cpu.pc
text_sec = self.get_sec_containing(pc)
print(FMT_ERROR + "[MMU] possible null dereference (read {:x}) from (pc={:x},sec={},rel={:x})".format(
addr, pc, text_sec.owner + ':' + text_sec.name, pc - text_sec.base
) + FMT_NONE)
if addr >= self.io_start:
return self.io_at(addr).read(addr, size)
return self.data[addr: addr + size]
def write(self, addr: int, size: int, data):
if addr < 0x100:
pc = self.cpu.pc
text_sec = self.get_sec_containing(pc)
print(FMT_ERROR + "[MMU] possible null dereference (write {:x}) from (pc={:x},sec={},rel={:x})".format(
addr, pc, text_sec.owner + ':' + text_sec.name, pc - text_sec.base
) + FMT_NONE)
if addr < self.kernel_end:
if self.cpu.mode != PrivModes.MACHINE:
pc = self.cpu.pc
text_sec = self.get_sec_containing(pc)
print(FMT_ERROR + "[MMU] kernel access to {:x} from outside kernel mode! (pc={:x},sec={},rel={:x})".format(
addr, pc, text_sec.owner + ':' + text_sec.name, pc - text_sec.base
) + FMT_NONE)
if addr >= self.io_start:
return self.io_at(addr).write(addr, data, size)
self.data[addr:addr + size] = data[0:size]
def io_at(self, addr) -> IOModule:
for mod in self.io:
if mod.contains(addr):
return mod
raise InstructionAccessFault(addr)
def add_io(self, io: IOModule):
self.io.append(io)
def __repr__(self):
return "ImageMMU()"
@lru_cache(maxsize=32)
def get_sec_containing(self, addr: int) -> Optional[LoadedMemorySection]:
next_sec = len(self.data)
for sec_addr, name in sorted(self.debug_info['sections'].items(), key=lambda x: int(x[0]), reverse=True):
if addr >= int(sec_addr):
owner, name = name.split(':')
base = int(sec_addr)
size = next_sec - base
flags = MemoryFlags('.text' in name, '.text' in name)
return ElfLoadedMemorySection(name, base, size, self.data[base:next_sec], flags, owner)
else:
next_sec = int(sec_addr)
Loading…
Cancel
Save