priv: added __main__ script to module which correctly configures the cpu depending on --kernel or --image options

kernel-mode
Anton Lydike 3 years ago
parent 0651eabe18
commit f2d07f90b5

@ -2,7 +2,7 @@
Laods a memory image with debug information into memory Laods a memory image with debug information into memory
""" """
from ..MMU import MMU from .PrivMMU import PrivMMU
from ..Config import RunConfig from ..Config import RunConfig
from ..Executable import Executable, LoadedExecutable, LoadedMemorySection, LoadedInstruction, MemoryFlags from ..Executable import Executable, LoadedExecutable, LoadedMemorySection, LoadedInstruction, MemoryFlags
from .ElfLoader import ElfInstruction, ElfLoadedMemorySection, InstructionAccessFault, InstructionAddressMisalignedTrap from .ElfLoader import ElfInstruction, ElfLoadedMemorySection, InstructionAccessFault, InstructionAddressMisalignedTrap
@ -10,6 +10,7 @@ from ..decoder import decode
from ..IO.IOModule import IOModule from ..IO.IOModule import IOModule
from .privmodes import PrivModes from .privmodes import PrivModes
from ..colors import FMT_ERROR, FMT_NONE from ..colors import FMT_ERROR, FMT_NONE
import json
from functools import lru_cache from functools import lru_cache
from typing import Dict, List, Tuple, Optional, TYPE_CHECKING from typing import Dict, List, Tuple, Optional, TYPE_CHECKING
@ -18,26 +19,37 @@ if TYPE_CHECKING:
from .PrivCPU import PrivCPU from .PrivCPU import PrivCPU
class ContinuousMMU(MMU): class MemoryImageMMU(PrivMMU):
io: List[IOModule] io: List[IOModule]
data: bytearray data: bytearray
io_start: int 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) self.data = bytearray(data)
# TODO: super wasteful memory allocation happening here
if len(data) < io_start: if len(data) < io_start:
self.data += bytearray(io_start - len(data)) self.data += bytearray(io_start - len(data))
self.debug_info = debug_info self.debug_info = debug_info
self.io_start = io_start self.io_start = io_start
self.io = list() self.io = list()
self.kernel_end = 0
for start, name in debug_info['sections'].items(): def get_entrypoint(self):
if name.startswith('programs'): try:
self.kernel_end = int(start) start = self.debug_info['symbols']['kernel'].get('_start', None)
break 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) @lru_cache(maxsize=2048)
def read_ins(self, addr: int) -> ElfInstruction: 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( 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 addr, pc, text_sec.owner + ':' + text_sec.name, pc - text_sec.base
) + FMT_NONE) ) + 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: if addr >= self.io_start:
return self.io_at(addr).write(addr, data, size) return self.io_at(addr).write(addr, data, size)
@ -88,7 +93,7 @@ class ContinuousMMU(MMU):
self.io.append(io) self.io.append(io)
def __repr__(self): def __repr__(self):
return "ImageMMU()" return "MemoryImageMMU()"
@lru_cache(maxsize=32) @lru_cache(maxsize=32)
def get_sec_containing(self, addr: int) -> Optional[LoadedMemorySection]: def get_sec_containing(self, addr: int) -> Optional[LoadedMemorySection]:

@ -8,7 +8,7 @@ import time
from riscemu.CPU import * from riscemu.CPU import *
from .CSR import CSR from .CSR import CSR
from .ElfLoader import ElfExecutable from .ElfLoader import ElfExecutable
from .ImageLoader import ContinuousMMU from .ImageLoader import MemoryImageMMU
from .Exceptions import * from .Exceptions import *
from .PrivMMU import PrivMMU from .PrivMMU import PrivMMU
from ..IO import TextIO from ..IO import TextIO
@ -47,22 +47,19 @@ class PrivCPU(CPU):
the equivalent of "1 byte" (this is actually impossible) the equivalent of "1 byte" (this is actually impossible)
""" """
def __init__(self, conf): def __init__(self, conf, mmu: PrivMMU):
super().__init__(conf, [PrivRV32I, RV32M]) super().__init__(conf, [PrivRV32I, RV32M])
self.mode: PrivModes = PrivModes.MACHINE self.mode: PrivModes = PrivModes.MACHINE
with open('mem.img', 'rb') as memf: mmu.set_cpu(self)
data = memf.read() self.pc = mmu.get_entrypoint()
with open('mem.img.dbg', 'r') as dbgf: self.mmu = mmu
debug_info = json.load(dbgf)
self.mmu = ContinuousMMU(data, debug_info, self) if hasattr(self.mmu, 'add_io'):
self.pc = 0x100
self.mmu.add_io(TextIO.TextIO(0xff0000, 64)) self.mmu.add_io(TextIO.TextIO(0xff0000, 64))
self.syscall_int = None
self.syscall_int = None
self.launch_debug = False self.launch_debug = False
self.pending_traps: List[CpuTrap] = list() self.pending_traps: List[CpuTrap] = list()
self._time_start = 0 self._time_start = 0
@ -87,7 +84,7 @@ class PrivCPU(CPU):
self.launch_debug = True self.launch_debug = True
self.pc += self.INS_XLEN self.pc += self.INS_XLEN
else: 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()) print(ex.message())
if self.conf.debug_on_exception: if self.conf.debug_on_exception:
self.launch_debug = True self.launch_debug = True

@ -1,13 +1,29 @@
from ..MMU import * from ..MMU import *
from abc import abstractmethod
import typing import typing
from .ElfLoader import ElfExecutable from .ElfLoader import ElfExecutable
if typing.TYPE_CHECKING:
from .PrivCPU import PrivCPU
class PrivMMU(MMU): 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): def __init__(self, elf: ElfExecutable):
super(PrivMMU, self).__init__(conf=RunConfig()) super().__init__(conf=RunConfig())
self.entrypoint = elf.symbols['_start']
self.binaries.append(elf) self.binaries.append(elf)
for sec in elf.sections: for sec in elf.sections:
@ -18,3 +34,6 @@ class PrivMMU(MMU):
def allocate_section(self, name: str, req_size: int, flag: MemoryFlags): def allocate_section(self, name: str, req_size: int, flag: MemoryFlags):
raise NotImplementedError("Not supported!") raise NotImplementedError("Not supported!")
def get_entrypoint(self):
return self.entrypoint

@ -1,4 +1,7 @@
from .PrivCPU import PrivCPU, RunConfig from .PrivCPU import PrivCPU, RunConfig
from .ImageLoader import MemoryImageMMU
from .PrivMMU import LoadedElfMMU
from .ElfLoader import ElfExecutable
from ..Tokenizer import RiscVInput from ..Tokenizer import RiscVInput
from ..ExecutableParser import ExecutableParser from ..ExecutableParser import ExecutableParser
@ -8,14 +11,23 @@ import sys
if __name__ == '__main__': if __name__ == '__main__':
import argparse 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('--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('--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() cpu.run()

Loading…
Cancel
Save