syscall: add partial support for mmap2 syscall

master
Anton Lydike 1 year ago
parent c7e14a3b42
commit 207cf918ef

@ -6,8 +6,10 @@ SPDX-License-Identifier: MIT
import sys import sys
from dataclasses import dataclass from dataclasses import dataclass
from math import log2, ceil
from typing import Dict, IO from typing import Dict, IO
from .types import BinaryDataMemorySection, MemoryFlags
from .colors import FMT_SYSCALL, FMT_NONE from .colors import FMT_SYSCALL, FMT_NONE
from .types import Int32, CPU from .types import Int32, CPU
from .types.exceptions import InvalidSyscallException from .types.exceptions import InvalidSyscallException
@ -16,6 +18,7 @@ SYSCALLS = {
63: "read", 63: "read",
64: "write", 64: "write",
93: "exit", 93: "exit",
192: "mmap2",
1024: "open", 1024: "open",
1025: "close", 1025: "close",
} }
@ -27,6 +30,18 @@ dictionary and implement a method with the same name on the SyscallInterface
class. class.
""" """
ADDITIONAL_SYMBOLS = {
'MAP_PRIVATE': 1<<0,
'MAP_SHARED': 1<<1,
'MAP_ANON': 1<<2,
'MAP_ANONYMOUS': 1<<2,
'PROT_READ': 1<<0,
'PROT_WRITE': 1<<1,
}
"""
A set of additional symbols that are used by various syscalls.
"""
OPEN_MODES = { OPEN_MODES = {
0: "rb", 0: "rb",
1: "wb", 1: "wb",
@ -55,7 +70,7 @@ class Syscall:
def __repr__(self): def __repr__(self):
return "Syscall(id={}, name={})".format(self.id, self.name) return "Syscall(id={}, name={})".format(self.id, self.name)
def ret(self, code): def ret(self, code: int | Int32):
self.cpu.regs.set("a0", Int32(code)) self.cpu.regs.set("a0", Int32(code))
@ -65,7 +80,11 @@ def get_syscall_symbols():
:return: dictionary of all syscall symbols (SCALL_<name> -> id) :return: dictionary of all syscall symbols (SCALL_<name> -> id)
""" """
return {("SCALL_" + name.upper()): num for num, name in SYSCALLS.items()} items: Dict[str, int] = {("SCALL_" + name.upper()): num for num, name in SYSCALLS.items()}
items.update(ADDITIONAL_SYMBOLS)
return items
class SyscallInterface: class SyscallInterface:
@ -222,5 +241,53 @@ class SyscallInterface:
scall.cpu.halted = True scall.cpu.halted = True
scall.cpu.exit_code = scall.cpu.regs.get("a0").value scall.cpu.exit_code = scall.cpu.regs.get("a0").value
def mmap2(self, scall: Syscall):
"""
mmap2 syscall:
void *mmap(void *addr, size_t length, int prot, int flags,
int fd, off_t offset);
Only supported modes:
addr = <any>
prot = either PROT_READ or PROT_READ | PROT_WRITE
flags = MAP_PRIVATE | MAP_ANONYMOUS
fd = <ignored>
off_t = <ignored>
"""
addr = scall.cpu.regs.get('a0').unsigned_value
size = scall.cpu.regs.get('a1').unsigned_value
prot = scall.cpu.regs.get('a2').unsigned_value
flags = scall.cpu.regs.get('a3').unsigned_value
# error out if prot is not 1 or 3:
# 1 = PROT_READ
# 3 = PROT_READ | PROT_WRITE
if prot != 1 and prot != 3:
return scall.ret(-1)
# round size up to multiple of 4096
size = 4096 * ceil(size / 4096)
section = BinaryDataMemorySection(
bytearray(size),
'.data.runtime-allocated',
None,
'system',
base=addr,
flags=MemoryFlags(read_only=prot != 3, executable=False)
)
# try to insert section
if scall.cpu.mmu.load_section(section, addr != 0):
return scall.ret(section.base)
# if that failed, and we tried to force an address,
# try again at any address
elif addr != 0:
section.base = 0
if scall.cpu.mmu.load_section(section):
return scall.ret(section.base)
# if that didn't work, return error
return scall.ret(-1)
def __repr__(self): def __repr__(self):
return "{}(\n\tfiles={}\n)".format(self.__class__.__name__, self.open_files) return "{}(\n\tfiles={}\n)".format(self.__class__.__name__, self.open_files)

Loading…
Cancel
Save