kernel-mode #1
@ -2,7 +2,7 @@
|
||||
Laods a memory image with debug information into memory
|
||||
"""
|
||||
|
||||
from ..MMU import MMU
|
||||
from .PrivMMU import PrivMMU
|
||||
from ..Config import RunConfig
|
||||
from ..Executable import Executable, LoadedExecutable, LoadedMemorySection, LoadedInstruction, MemoryFlags
|
||||
from .ElfLoader import ElfInstruction, ElfLoadedMemorySection, InstructionAccessFault, InstructionAddressMisalignedTrap
|
||||
@ -10,6 +10,7 @@ from ..decoder import decode
|
||||
from ..IO.IOModule import IOModule
|
||||
from .privmodes import PrivModes
|
||||
from ..colors import FMT_ERROR, FMT_NONE
|
||||
import json
|
||||
|
||||
from functools import lru_cache
|
||||
from typing import Dict, List, Tuple, Optional, TYPE_CHECKING
|
||||
@ -18,26 +19,37 @@ if TYPE_CHECKING:
|
||||
from .PrivCPU import PrivCPU
|
||||
|
||||
|
||||
class ContinuousMMU(MMU):
|
||||
class MemoryImageMMU(PrivMMU):
|
||||
io: List[IOModule]
|
||||
data: bytearray
|
||||
io_start: int
|
||||
debug_info: Dict[str, Dict[str, str]]
|
||||
debug_info: Dict[str, Dict[str, Dict[str, str]]]
|
||||
|
||||
def __init__(self, file_name: str, io_start: int = 0xFF0000):
|
||||
super(MemoryImageMMU, self).__init__(conf=RunConfig())
|
||||
|
||||
with open(file_name, 'rb') as memf:
|
||||
data = memf.read()
|
||||
with open(file_name + '.dbg', 'r') as dbgf:
|
||||
debug_info: Dict = json.load(dbgf)
|
||||
|
||||
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)
|
||||
# TODO: super wasteful memory allocation happening here
|
||||
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
|
||||
|
||||
def get_entrypoint(self):
|
||||
try:
|
||||
start = self.debug_info['symbols']['kernel'].get('_start', None)
|
||||
if start is not None:
|
||||
return start
|
||||
return self.debug_info['symbols']['kernel'].get('_ftext')
|
||||
except KeyError:
|
||||
print(FMT_ERROR + '[MMU] cannot find kernel entry in debug information! Falling back to 0x100' + FMT_NONE)
|
||||
return 0x100
|
||||
|
||||
@lru_cache(maxsize=2048)
|
||||
def read_ins(self, addr: int) -> ElfInstruction:
|
||||
@ -66,13 +78,6 @@ class ContinuousMMU(MMU):
|
||||
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)
|
||||
@ -88,7 +93,7 @@ class ContinuousMMU(MMU):
|
||||
self.io.append(io)
|
||||
|
||||
def __repr__(self):
|
||||
return "ImageMMU()"
|
||||
return "MemoryImageMMU()"
|
||||
|
||||
@lru_cache(maxsize=32)
|
||||
def get_sec_containing(self, addr: int) -> Optional[LoadedMemorySection]:
|
||||
|
@ -8,7 +8,7 @@ import time
|
||||
from riscemu.CPU import *
|
||||
from .CSR import CSR
|
||||
from .ElfLoader import ElfExecutable
|
||||
from .ImageLoader import ContinuousMMU
|
||||
from .ImageLoader import MemoryImageMMU
|
||||
from .Exceptions import *
|
||||
from .PrivMMU import PrivMMU
|
||||
from ..IO import TextIO
|
||||
@ -47,22 +47,19 @@ class PrivCPU(CPU):
|
||||
the equivalent of "1 byte" (this is actually impossible)
|
||||
"""
|
||||
|
||||
def __init__(self, conf):
|
||||
def __init__(self, conf, mmu: PrivMMU):
|
||||
super().__init__(conf, [PrivRV32I, RV32M])
|
||||
self.mode: PrivModes = PrivModes.MACHINE
|
||||
|
||||
with open('mem.img', 'rb') as memf:
|
||||
data = memf.read()
|
||||
with open('mem.img.dbg', 'r') as dbgf:
|
||||
debug_info = json.load(dbgf)
|
||||
mmu.set_cpu(self)
|
||||
self.pc = mmu.get_entrypoint()
|
||||
self.mmu = mmu
|
||||
|
||||
if hasattr(self.mmu, 'add_io'):
|
||||
self.mmu.add_io(TextIO.TextIO(0xff0000, 64))
|
||||
|
||||
self.mmu = ContinuousMMU(data, debug_info, self)
|
||||
self.pc = 0x100
|
||||
self.mmu.add_io(TextIO.TextIO(0xff0000, 64))
|
||||
self.syscall_int = None
|
||||
|
||||
self.launch_debug = False
|
||||
|
||||
self.pending_traps: List[CpuTrap] = list()
|
||||
|
||||
self._time_start = 0
|
||||
@ -87,7 +84,7 @@ class PrivCPU(CPU):
|
||||
self.launch_debug = True
|
||||
self.pc += self.INS_XLEN
|
||||
else:
|
||||
print(FMT_ERROR + "[CPU] excpetion caught at 0x{:08X}: {}:".format(self.pc - 1, ins) + FMT_NONE)
|
||||
print(FMT_ERROR + "[CPU] exception caught at 0x{:08X}: {}:".format(self.pc - 1, ins) + FMT_NONE)
|
||||
print(ex.message())
|
||||
if self.conf.debug_on_exception:
|
||||
self.launch_debug = True
|
||||
|
@ -1,13 +1,29 @@
|
||||
from ..MMU import *
|
||||
from abc import abstractmethod
|
||||
|
||||
import typing
|
||||
|
||||
from .ElfLoader import ElfExecutable
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from .PrivCPU import PrivCPU
|
||||
|
||||
|
||||
class PrivMMU(MMU):
|
||||
cpu: 'PrivCPU'
|
||||
|
||||
@abstractmethod
|
||||
def get_entrypoint(self) -> int:
|
||||
raise
|
||||
|
||||
def set_cpu(self, cpu: 'PrivCPU'):
|
||||
self.cpu = cpu
|
||||
|
||||
|
||||
class LoadedElfMMU(PrivMMU):
|
||||
def __init__(self, elf: ElfExecutable):
|
||||
super(PrivMMU, self).__init__(conf=RunConfig())
|
||||
super().__init__(conf=RunConfig())
|
||||
self.entrypoint = elf.symbols['_start']
|
||||
|
||||
self.binaries.append(elf)
|
||||
for sec in elf.sections:
|
||||
@ -18,3 +34,6 @@ class PrivMMU(MMU):
|
||||
|
||||
def allocate_section(self, name: str, req_size: int, flag: MemoryFlags):
|
||||
raise NotImplementedError("Not supported!")
|
||||
|
||||
def get_entrypoint(self):
|
||||
return self.entrypoint
|
||||
|
@ -1,4 +1,7 @@
|
||||
from .PrivCPU import PrivCPU, RunConfig
|
||||
from .ImageLoader import MemoryImageMMU
|
||||
from .PrivMMU import LoadedElfMMU
|
||||
from .ElfLoader import ElfExecutable
|
||||
|
||||
from ..Tokenizer import RiscVInput
|
||||
from ..ExecutableParser import ExecutableParser
|
||||
@ -8,14 +11,23 @@ import sys
|
||||
if __name__ == '__main__':
|
||||
import argparse
|
||||
|
||||
#parser = argparse.ArgumentParser(description='RISC-V privileged architecture emulator', prog='riscemu')
|
||||
parser = argparse.ArgumentParser(description='RISC-V privileged architecture emulator', prog='riscemu')
|
||||
|
||||
#parser.add_argument('--kernel', type=str, help='Kernel elf loaded with user programs', nargs='?')
|
||||
#parser.add_argument('--image', type=str, help='Memory image containing kernel', nargs='?')
|
||||
parser.add_argument('--kernel', type=str, help='Kernel elf loaded with user programs', nargs='?')
|
||||
parser.add_argument('--image', type=str, help='Memory image containing kernel', nargs='?')
|
||||
|
||||
#args = parser.parse_args()
|
||||
args = parser.parse_args()
|
||||
mmu = None
|
||||
|
||||
cpu = PrivCPU(RunConfig())
|
||||
if args.kernel is not None:
|
||||
mmu = LoadedElfMMU(ElfExecutable(args.kernel))
|
||||
elif args.image is not None:
|
||||
mmu = MemoryImageMMU(args.image)
|
||||
|
||||
if mmu is None:
|
||||
print("You must specify one of --kernel or --image for running in privilege mode!")
|
||||
|
||||
cpu = PrivCPU(RunConfig(), mmu)
|
||||
|
||||
cpu.run()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user