implemented syscalls open, read, write, close, exit

float_support
Anton Lydike 4 years ago
parent a483db65c7
commit 5a722c8cf1

@ -0,0 +1,46 @@
# Syscalls:
Performing a syscall is quite simple:
```risc-v asm
; set syscall code:
addi a7, zero, 93 ; or SCALL_EXIT if syscall symbols are mapped
; set syscall args:
addi a0, zero, 1 ; exit with code 1
; invode syscall handler
scall
```
In order to use the global syscall symbols, run with the `--syscall-symbols` flag (not implemented yet)
## Read (63) `SCALL_READ`
* `a0`: source file descriptor
* `a1`: addr in which to read
* `a2`: number of bytes to read (at most)
* `return: a0` number of bytes read or -1
## Write (64) `SCALL_WRITE`
* `a0`: target file descriptor
* `a1`: addr from which to read
* `a2`: number of bytes to read
* `return: a0`: number of bytes written or -1
## Exit (93) `SCALL_EXIT`
* `a0`: exit code
## Open (1024) `SCALL_OPEN`
* `a0`: open mode:
- `0`: read
- `1`: write (truncate)
- `2`: read/write (no truncate)
- `3`: only create
- `4`: append
* `a1`: addr where path is stored
* `a2`: length of path
* `return: a0`: file descriptor of opened file or -1
Requires flag `--scall-fs` to be set to True
## Close (1025) `SCALL_OPEN`
* `a0`: file descriptor to close
* `return: a0`: 0 if closed correctly or -1

@ -1,6 +1,10 @@
from dataclasses import dataclass
from typing import Dict, IO
import sys
from .Registers import Registers
from .Exceptions import InvalidSyscallException
from .helpers import *
import typing
@ -8,9 +12,19 @@ if typing.TYPE_CHECKING:
from . import CPU
SYSCALLS = {
63: 'read',
64: 'write',
93: 'exit'
63: 'read',
64: 'write',
93: 'exit',
1024: 'open',
1025: 'close',
}
OPEN_MODES = {
0: 'rb',
1: 'wb',
2: 'r+b',
3: 'x',
4: 'ab',
}
@ -29,19 +43,124 @@ class Syscall:
self.id, self.name
)
def ret(self, code):
self.registers.set('a0', code)
class SyscallInterface:
open_files: Dict[int, IO]
next_open_handle: int
def handle_syscall(self, scall: Syscall):
self.next_open_handle = 3
self.open_files = {
0: sys.stdin,
1: sys.stdout,
2: sys.stderr
}
if getattr(self, scall.name):
getattr(self, scall.name)(scall)
else:
raise InvalidSyscallException(scall)
def read(self, scall: Syscall):
pass
"""
read syscall (63): read from file no a0, into addr a1, at most a2 bytes
on return a0 will be the number of read bytes or -1 if an error occured
"""
fileno = scall.registers.get('a0')
addr = scall.registers.get('a1')
len = scall.registers.get('a2')
if fileno not in self.open_files:
scall.registers.set('a0', -1)
return
chars = self.open_files[fileno].read(len)
try:
data = bytearray(chars, 'ascii')
scall.cpu.mmu.write(addr, len(data), data)
return scall.ret(len(data))
except UnicodeEncodeError:
print(FMT_ERROR + '[Syscall] read: UnicodeError - invalid input "{}"'.format(chars) + FMT_NONE)
return scall.ret(-1)
def write(self, scall: Syscall):
pass
"""
write syscall (64): write a2 bytes from addr a1 into fileno a0
on return a0 will hold the number of bytes written or -1 if an error occured
"""
fileno = scall.registers.get('a0')
addr = scall.registers.get('a1')
size = scall.registers.get('a2')
if fileno not in self.open_files:
return scall.ret(-1)
data = scall.cpu.mmu.read(addr, size)
if not isinstance(str, bytearray):
print(FMT_ERROR + '[Syscall] write: writing from .text region not supported.' + FMT_NONE)
return scall.ret(-1)
self.open_files[fileno].write(data.decode('ascii'))
return scall.ret(size)
def open(self, scall: Syscall):
"""
open syscall (1024): read path of a2 bytes from addr a1, in mode a0
returns the file no in a0
modes:
- 0: read
- 1: write (truncate)
- 2: read/write (no truncate)
- 3: only create
- 4: append
Requires running with flag scall-fs
"""
if not scall.cpu.conf.scall_fs:
print(FMT_ERROR + '[Syscall] open: opening files not supported without scall-fs flag!' + FMT_NONE)
return scall.ret(-1)
mode = scall.registers.get('a0')
addr = scall.registers.get('a1')
size = scall.registers.get('a2')
mode_st = OPEN_MODES.get(mode, )
if mode_st == -1:
print(FMT_ERROR + '[Syscall] open: unknown opening mode {}!'.format(mode) + FMT_NONE)
return scall.ret(-1)
path = scall.cpu.mmu.read(addr, size).decode('ascii')
fileno = self.next_open_handle
self.next_open_handle += 1
try:
self.open_files[fileno] = open(path, mode_st)
except OSError as err:
print(FMT_ERROR + '[Syscall] open: encountered error during {}!'.format(err.strerror) + FMT_NONE)
return scall.ret(-1)
print(FMT_CYAN + '[Syscall] open: opened fd {} to {}!'.format(fileno, path) + FMT_NONE)
return scall.ret(fileno)
def close(self, scall: Syscall):
"""
close syscall (1025): closes file no a0
return -1 if an error was encountered, otherwise returns 0
"""
fileno = scall.registers.get('a0')
if fileno not in self.open_files:
print(FMT_ERROR + '[Syscall] close: unknown fileno {}!'.format(fileno) + FMT_NONE)
return scall.ret(-1)
self.open_files[fileno].close()
print(FMT_CYAN + '[Syscall] close: closed fd {}!'.format(fileno) + FMT_NONE)
del self.open_files[fileno]
return scall.ret(0)
def exit(self, scall: Syscall):
scall.cpu.exit = True

@ -43,6 +43,7 @@ def int_from_bytes(bytes, unsigned=False):
# Colors
FMT_RED = '\033[31m'
FMT_ORANGE = '\033[33m'
FMT_GRAY = '\033[37m'
FMT_CYAN = '\033[36m'
@ -51,3 +52,5 @@ FMT_BOLD = '\033[1m'
FMT_MAGENTA = '\033[35m'
FMT_NONE = '\033[0m'
FMT_UNDERLINE = '\033[4m'
FMT_ERROR = FMT_RED + FMT_BOLD

Loading…
Cancel
Save