<commit_before>#=======================================================================
# syscalls.py
#=======================================================================
#
# Implementations of emulated syscalls. Call numbers were borrowed from
# the following files:
#
# - https://github.com/cornell-brg/maven-sim-isa/blob/master/common/syscfg.h
# - https://github.com/cornell-brg/pyparc/blob/master/pkernel/pkernel/syscfg.h
# - https://github.com/cornell-brg/maven-sys-xcc/blob/master/src/libgloss/maven/machine/syscfg.h
# - https://github.com/cornell-brg/gem5-mcpat/blob/master/src/arch/mips/linux/process.cc
#
# Implementation details from the Maven proxy kernel:
#
# - https://github.com/cornell-brg/pyparc/blob/master/pkernel/pkernel/pkernel.c#L463-L544
# - https://github.com/cornell-brg/pyparc/blob/master/pkernel/pkernel/pkernel-xcpthandler.S#L78-L89
#
#   // Jump to C function to handle syscalls
#
#   move    $a3, $a2 // arg2
#   move    $a2, $a1 // arg1
#   move    $a1, $a0 // arg0
#   move    $a0, $v0 // syscall number
#   la      $t0, handle_syscall
#   jalr    $t0
#
#   // Restore user context
#
#   move    $k0, $sp
#
# Details for newlib syscalls from the Maven cross compiler:
#
# - https://github.com/cornell-brg/maven-sys-xcc/blob/master/src/libgloss/maven/syscalls.c
#
# According to Berkin, only the following syscalls are needed by pbbs:
#
# - read (2), write (3), open (4), close (5), lseek (8)
#
# Other syscall emulation resources:
#
# - http://brg.csl.cornell.edu/wiki/Proxy%20Kernel%20vs%20Syscall%20Emulation
# - http://wiki.osdev.org/Porting_Newlib
# - http://wiki.osdev.org/OS_Specific_Toolchain
# - http://www.embecosm.com/appnotes/ean9/ean9-howto-newlib-1.0.html
#

from isa import reg_map
import sys
import os

#-----------------------------------------------------------------------
# os state and helpers
#-----------------------------------------------------------------------

# short names for registers

v0 = reg_map['v0']  # return value
a0 = reg_map['a0']  # arg0
a1 = reg_map['a1']  # arg1
a2 = reg_map['a2']  # arg2
a3 = reg_map['a3']  # error

# solaris to linux open flag conversion
# https://docs.python.org/2/library/os.html#open-constants

flag_table = [
  [ 0x0000, os.O_RDONLY   ], # NEWLIB_O_RDONLY
  [ 0x0001, os.O_WRONLY   ], # NEWLIB_O_WRONLY
  [ 0x0002, os.O_RDWR     ], # NEWLIB_O_RDWR
  [ 0x0008, os.O_APPEND   ], # NEWLIB_O_APPEND
  [ 0x0200, os.O_CREAT    ], # NEWLIB_O_CREAT
  [ 0x0400, os.O_TRUNC    ], # NEWLIB_O_TRUNC
  [ 0x0800, os.O_EXCL     ], # NEWLIB_O_EXCL
  [ 0x2000, os.O_SYNC     ], # NEWLIB_O_SYNC
  [ 0x4000, os.O_NDELAY   ], # NEWLIB_O_NDELAY
  [ 0x4000, os.O_NONBLOCK ], # NEWLIB_O_NONBLOCK
  [ 0x8000, os.O_NOCTTY   ], # NEWLIB_O_NOCTTY
 #[ 0x????, os.O_DIRECTORY],
 #[ 0x????, os.O_ASYNC    ],
 #[ 0x????, os.O_DSYNC    ],
 #[ 0x????, os.O_NOATIME  ],
 #[ 0x????, os.O_DIRECT   ],
 #[ 0x????, os.O_LARGEFILE],
 #[ 0x????, os.O_NOFOLLOW ],
 #[ 0x????, os.O_RSYNC    ],
]

# previously, file descriptors was a dict, and the standard io was dup'd
# to new fds. However, this causes issues with translation. So instead,
# we're directly using fds 0, 1, 2. I don't know if this has any adverse
# effects
file_descriptors = [ 0, 1, 2 ]

# TODO: we want verbosity to be set from outside with a command line flag.
# For the time being, we do it here
#verbose = True
verbose = False

#-----------------------------------------------------------------------
# exit
#-----------------------------------------------------------------------
def syscall_exit( s ):
  if verbose:
    print "syscall_exit"

  exit_code = s.rf[ a0 ]
  print
  print "NUM  INSTS:", s.ncycles
  print "STAT INSTS:", s.stat_ncycles
  print "EXIT CODE: ", exit_code
  # TODO: this is an okay way to terminate the simulator?
  #       sys.exit(1) is not valid python
  s.status = exit_code
  s.running = False

#-----------------------------------------------------------------------
# read
#-----------------------------------------------------------------------
def syscall_read( s ):
  if verbose:
    print "syscall_read"

  fd       = s.rf[ a0 ]
  data_ptr = s.rf[ a1 ]
  nbytes   = s.rf[ a2 ]

  if fd not in file_descriptors:
    s.rf[ v0 ] = -1
    # we return a bad file descriptor error (9)
    s.rf[ a3 ] = 9
    return

  errno = 0

  try:
    str = os.read( fd, nbytes )
    nbytes_read = len( str )

    # rpython requires us to use a list of characters instead of string
    data = [ "\0" ] * nbytes_read

    for i in xrange( nbytes_read ):
      data[i] = str[i]

    assert data_ptr >= 0
    s.mem.data[data_ptr : data_ptr + nbytes_read ] = data

    # NOTE: I think newlib relies on the buffer returned to be a
    # null-terminated string, so we explicitly null terminate it. Without
    # this, we were getting buffer overflows.
    s.mem.data[data_ptr + nbytes_read ] = "\0"

  except OSError as e:
    if verbose:
      print "OSError in syscall_read. errno=%d" % e.errno
    nbytes_read = -1
    errno = e.errno

  # return the number of bytes read

  s.rf[ v0 ] = nbytes_read
  s.rf[ a3 ] = errno

#-----------------------------------------------------------------------<commit_msg>[parc] reverted adding null char in syscall_read<commit_after>#=======================================================================
# syscalls.py
#=======================================================================
#
# Implementations of emulated syscalls. Call numbers were borrowed from
# the following files:
#
# - https://github.com/cornell-brg/maven-sim-isa/blob/master/common/syscfg.h
# - https://github.com/cornell-brg/pyparc/blob/master/pkernel/pkernel/syscfg.h
# - https://github.com/cornell-brg/maven-sys-xcc/blob/master/src/libgloss/maven/machine/syscfg.h
# - https://github.com/cornell-brg/gem5-mcpat/blob/master/src/arch/mips/linux/process.cc
#
# Implementation details from the Maven proxy kernel:
#
# - https://github.com/cornell-brg/pyparc/blob/master/pkernel/pkernel/pkernel.c#L463-L544
# - https://github.com/cornell-brg/pyparc/blob/master/pkernel/pkernel/pkernel-xcpthandler.S#L78-L89
#
#   // Jump to C function to handle syscalls
#
#   move    $a3, $a2 // arg2
#   move    $a2, $a1 // arg1
#   move    $a1, $a0 // arg0
#   move    $a0, $v0 // syscall number
#   la      $t0, handle_syscall
#   jalr    $t0
#
#   // Restore user context
#
#   move    $k0, $sp
#
# Details for newlib syscalls from the Maven cross compiler:
#
# - https://github.com/cornell-brg/maven-sys-xcc/blob/master/src/libgloss/maven/syscalls.c
#
# According to Berkin, only the following syscalls are needed by pbbs:
#
# - read (2), write (3), open (4), close (5), lseek (8)
#
# Other syscall emulation resources:
#
# - http://brg.csl.cornell.edu/wiki/Proxy%20Kernel%20vs%20Syscall%20Emulation
# - http://wiki.osdev.org/Porting_Newlib
# - http://wiki.osdev.org/OS_Specific_Toolchain
# - http://www.embecosm.com/appnotes/ean9/ean9-howto-newlib-1.0.html
#

from isa import reg_map
import sys
import os

#-----------------------------------------------------------------------
# os state and helpers
#-----------------------------------------------------------------------

# short names for registers

v0 = reg_map['v0']  # return value
a0 = reg_map['a0']  # arg0
a1 = reg_map['a1']  # arg1
a2 = reg_map['a2']  # arg2
a3 = reg_map['a3']  # error

# solaris to linux open flag conversion
# https://docs.python.org/2/library/os.html#open-constants

flag_table = [
  [ 0x0000, os.O_RDONLY   ], # NEWLIB_O_RDONLY
  [ 0x0001, os.O_WRONLY   ], # NEWLIB_O_WRONLY
  [ 0x0002, os.O_RDWR     ], # NEWLIB_O_RDWR
  [ 0x0008, os.O_APPEND   ], # NEWLIB_O_APPEND
  [ 0x0200, os.O_CREAT    ], # NEWLIB_O_CREAT
  [ 0x0400, os.O_TRUNC    ], # NEWLIB_O_TRUNC
  [ 0x0800, os.O_EXCL     ], # NEWLIB_O_EXCL
  [ 0x2000, os.O_SYNC     ], # NEWLIB_O_SYNC
  [ 0x4000, os.O_NDELAY   ], # NEWLIB_O_NDELAY
  [ 0x4000, os.O_NONBLOCK ], # NEWLIB_O_NONBLOCK
  [ 0x8000, os.O_NOCTTY   ], # NEWLIB_O_NOCTTY
 #[ 0x????, os.O_DIRECTORY],
 #[ 0x????, os.O_ASYNC    ],
 #[ 0x????, os.O_DSYNC    ],
 #[ 0x????, os.O_NOATIME  ],
 #[ 0x????, os.O_DIRECT   ],
 #[ 0x????, os.O_LARGEFILE],
 #[ 0x????, os.O_NOFOLLOW ],
 #[ 0x????, os.O_RSYNC    ],
]

# previously, file descriptors was a dict, and the standard io was dup'd
# to new fds. However, this causes issues with translation. So instead,
# we're directly using fds 0, 1, 2. I don't know if this has any adverse
# effects
file_descriptors = [ 0, 1, 2 ]

# TODO: we want verbosity to be set from outside with a command line flag.
# For the time being, we do it here
#verbose = True
verbose = False

#-----------------------------------------------------------------------
# exit
#-----------------------------------------------------------------------
def syscall_exit( s ):
  if verbose:
    print "syscall_exit"

  exit_code = s.rf[ a0 ]
  print
  print "NUM  INSTS:", s.ncycles
  print "STAT INSTS:", s.stat_ncycles
  print "EXIT CODE: ", exit_code
  # TODO: this is an okay way to terminate the simulator?
  #       sys.exit(1) is not valid python
  s.status = exit_code
  s.running = False

#-----------------------------------------------------------------------
# read
#-----------------------------------------------------------------------
def syscall_read( s ):
  if verbose:
    print "syscall_read"

  fd       = s.rf[ a0 ]
  data_ptr = s.rf[ a1 ]
  nbytes   = s.rf[ a2 ]

  if fd not in file_descriptors:
    s.rf[ v0 ] = -1
    # we return a bad file descriptor error (9)
    s.rf[ a3 ] = 9
    return

  errno = 0

  try:
    str = os.read( fd, nbytes )
    nbytes_read = len( str )

    # rpython requires us to use a list of characters instead of string
    data = [ "\0" ] * nbytes_read

    for i in xrange( nbytes_read ):
      data[i] = str[i]

    assert data_ptr >= 0
    s.mem.data[data_ptr : data_ptr + nbytes_read ] = data

  except OSError as e:
    if verbose:
      print "OSError in syscall_read. errno=%d" % e.errno
    nbytes_read = -1
    errno = e.errno

  # return the number of bytes read

  s.rf[ v0 ] = nbytes_read
  s.rf[ a3 ] = errno

#-----------------------------------------------------------------------
{'fraction_non_alphanumeric': 0.24920886075949367, 'fraction_numerical': 0.027986550632911392, 'mean_word_length': 2.152431421446384, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 16, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3899719', 'n_tokens_mistral': 3852, 'n_tokens_neox': 3542, 'n_words': 848}