kernel-mode #1
@ -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)
|
|
||||||
|
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.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…
Reference in New Issue
Block a user