Пример #1
0
  def read( self, start_addr, num_bytes ):
    assert 0 < num_bytes <= 4
    start_addr = r_uint( start_addr )
    word = start_addr >> 2
    byte = start_addr &  0b11

    if self.debug.enabled( "mem" ):
      print ':: RD.MEM[%s] = ' % pad_hex( start_addr ),
    if self.debug.enabled( "memcheck" ):
      self.bounds_check( start_addr, 'RD' )

    value = 0
    if   num_bytes == 4:  # TODO: byte should only be 0 (only aligned)
      value = widen( self.data[ word ] )
    elif num_bytes == 2:  # TODO: byte should only be 0, 1, 2, not 3
      mask = 0xFFFF << (byte * 8)
      value = ( widen( self.data[ word ] ) & mask) >> (byte * 8)
    elif num_bytes == 1:
      mask = 0xFF   << (byte * 8)
      value = ( widen( self.data[ word ] ) & mask) >> (byte * 8)
    else:
      raise Exception('Invalid num_bytes: %d!' % num_bytes)

    if self.debug.enabled( "mem" ):
      print '%s' % pad_hex( value ),

    return r_uint( value )
Пример #2
0
    def write(self, start_addr, num_bytes, value):
        assert 0 < num_bytes <= 4
        start_addr = r_uint(start_addr)
        value = r_uint(value)
        word = start_addr >> 2
        byte = start_addr & 0b11

        if self.debug.enabled("memcheck") and not self.suppress_debug:
            self.bounds_check(start_addr, 'WR')

        if num_bytes == 4:  # TODO: byte should only be 0 (only aligned)
            pass  # no masking needed
        elif num_bytes == 2:  # TODO: byte should only be 0, 1, 2, not 3
            mask = ~(0xFFFF << (byte * 8)) & r_uint(0xFFFFFFFF)
            value = ( widen( self.data[ word ] ) & mask ) \
                    | ( (value & 0xFFFF) << (byte * 8) )
        elif num_bytes == 1:
            mask = ~(0xFF << (byte * 8)) & r_uint(0xFFFFFFFF)
            value = ( widen( self.data[ word ] ) & mask ) \
                    | ( (value & 0xFF  ) << (byte * 8) )
        else:
            raise Exception('Invalid num_bytes: %d!' % num_bytes)

        if self.debug.enabled("mem") and not self.suppress_debug:
            print ':: WR.MEM[%s] = %s' % (pad_hex(start_addr), pad_hex(value)),
        self.data[word] = r_uint32(value)
Пример #3
0
  def write( self, start_addr, num_bytes, value ):
    assert 0 < num_bytes <= 4
    start_addr = r_uint( start_addr )
    value = r_uint( value )
    word = start_addr >> 2
    byte = start_addr &  0b11

    if self.debug.enabled( "memcheck" ):
      self.bounds_check( start_addr, 'WR' )

    if   num_bytes == 4:  # TODO: byte should only be 0 (only aligned)
      pass # no masking needed
    elif num_bytes == 2:  # TODO: byte should only be 0, 1, 2, not 3
      mask  = ~(0xFFFF << (byte * 8)) & r_uint( 0xFFFFFFFF )
      value = ( widen( self.data[ word ] ) & mask ) \
              | ( (value & 0xFFFF) << (byte * 8) )
    elif num_bytes == 1:
      mask  = ~(0xFF   << (byte * 8)) & r_uint( 0xFFFFFFFF )
      value = ( widen( self.data[ word ] ) & mask ) \
              | ( (value & 0xFF  ) << (byte * 8) )
    else:
      raise Exception('Invalid num_bytes: %d!' % num_bytes)

    if self.debug.enabled( "mem" ):
      print ':: WR.MEM[%s] = %s' % ( pad_hex( start_addr ),
                                     pad_hex( value ) ),
    self.data[ word ] = r_uint32( value )
Пример #4
0
    def read(self, start_addr, num_bytes):
        assert 0 < num_bytes <= 4
        start_addr = r_uint(start_addr)
        word = start_addr >> 2
        byte = start_addr & 0b11

        if self.debug.enabled("mem") and not self.suppress_debug:
            print ':: RD.MEM[%s] = ' % pad_hex(start_addr),
        if self.debug.enabled("memcheck") and not self.suppress_debug:
            self.bounds_check(start_addr, 'RD')

        value = 0
        if num_bytes == 4:  # TODO: byte should only be 0 (only aligned)
            value = widen(self.data[word])
        elif num_bytes == 2:  # TODO: byte should only be 0, 1, 2, not 3
            mask = 0xFFFF << (byte * 8)
            value = (widen(self.data[word]) & mask) >> (byte * 8)
        elif num_bytes == 1:
            mask = 0xFF << (byte * 8)
            value = (widen(self.data[word]) & mask) >> (byte * 8)
        else:
            raise Exception('Invalid num_bytes: %d!' % num_bytes)

        if self.debug.enabled("mem"):
            print '%s' % pad_hex(value),

        return r_uint(value)
Пример #5
0
    def __init__(self, memory, debug, reset_addr=0x400):
        Machine.__init__(self,
                         memory,
                         ArmRegisterFile(self, num_regs=16),
                         debug,
                         reset_addr=reset_addr)
        self.rf[15] = self.pc

        # current program status register (CPSR)
        self.N = r_uint(0b0)  # Negative condition
        self.Z = r_uint(0b0)  # Zero condition
        self.C = r_uint(0b0)  # Carry condition
        self.V = r_uint(0b0)  # Overflow condition
        #self.J    = 0b0      # Jazelle state flag
        #self.I    = 0b0      # IRQ Interrupt Mask
        #self.F    = 0b0      # FIQ Interrupt Mask
        #self.T    = 0b0      # Thumb state flag
        #self.M    = 0b00000  # Processor Mode

        # processor modes:
        # 0b10000     usr
        # 0b10001     fiq
        # 0b10010     irq
        # 0b10011     svc (supervisor)
        # 0b10111     abt (abort)
        # 0b11011     und (undefined)
        # 0b11111     sys
        self.mode = r_uint(0b10000)

        # syscall stuff... TODO: should this be here?
        self.breakpoint = 0
Пример #6
0
  def __init__( self, memory, debug, reset_addr=0x400 ):
    Machine.__init__(self,
                     memory,
                     ArmRegisterFile( self, num_regs=16 ),
                     debug,
                     reset_addr=reset_addr )
    self.rf[ 15 ]  = self.pc

    # current program status register (CPSR)
    self.N    = r_uint( 0b0 )     # Negative condition
    self.Z    = r_uint( 0b0 )     # Zero condition
    self.C    = r_uint( 0b0 )     # Carry condition
    self.V    = r_uint( 0b0 )     # Overflow condition
    #self.J    = 0b0      # Jazelle state flag
    #self.I    = 0b0      # IRQ Interrupt Mask
    #self.F    = 0b0      # FIQ Interrupt Mask
    #self.T    = 0b0      # Thumb state flag
    #self.M    = 0b00000  # Processor Mode

    # processor modes:
    # 0b10000     usr
    # 0b10001     fiq
    # 0b10010     irq
    # 0b10011     svc (supervisor)
    # 0b10111     abt (abort)
    # 0b11011     und (undefined)
    # 0b11111     sys
    self.mode = r_uint( 0b10000 )

    # syscall stuff... TODO: should this be here?
    self.breakpoint = 0
Пример #7
0
    def __init__(self, data=None, size=2**10):
        self.data = data if data else [r_uint32(0)] * (size >> 2)
        self.size = r_uint(len(self.data) << 2)
        self.debug = Debug()

        # TODO: pass data_section to memory for bounds checking
        self.data_section = 0x00000000
Пример #8
0
  def __init__( self, data=None, size=2**10 ):
    self.data  = data if data else [ r_uint32(0) ] * (size >> 2)
    self.size  = r_uint(len( self.data ) << 2)
    self.debug = Debug()

    # TODO: pass data_section to memory for bounds checking
    self.data_section = 0x00000000
Пример #9
0
    def __init__(self, constant_zero=True, num_regs=32, nbits=32):
        self.num_regs = num_regs
        self.regs = [r_uint(0)] * self.num_regs
        self.debug = Debug()
        self.nbits = nbits
        self.debug_nchars = nbits / 4

        if constant_zero: self._setitemimpl = self._set_item_const_zero
        else: self._setitemimpl = self._set_item
Пример #10
0
  def __init__( self, constant_zero=True, num_regs=32, nbits=32 ):
    self.num_regs = num_regs
    self.regs     = [ r_uint(0) ] * self.num_regs
    self.debug    = Debug()
    self.nbits    = nbits
    self.debug_nchars = nbits / 4

    if constant_zero: self._setitemimpl = self._set_item_const_zero
    else:             self._setitemimpl = self._set_item
Пример #11
0
 def __setitem__(self, idx, value):
     value = r_uint(value)
     if idx == 15:
         self.state.pc = value
         if self.debug.enabled("rf"):
             print ':: WR.RF[15] = %s' % (pad_hex(value)),
     else:
         self.regs[idx] = value
         if self.debug.enabled("rf"):
             print ':: WR.RF[%s] = %s' % (pad("%d" % idx,
                                              2), pad_hex(value)),
Пример #12
0
def syscall_brk( s, arg0, arg1, arg2 ):

  new_brk = arg0

  if s.debug.enabled( "syscalls" ):
    print "syscall_brk( addr=%x )" % new_brk,

  if new_brk != 0:
    s.breakpoint = r_uint( new_brk )

  return intmask( s.breakpoint ), 0
Пример #13
0
def syscall_exit( s, arg0, arg1, arg2 ):

  exit_code = arg0

  if s.debug.enabled( "syscalls" ):
    print "syscall_exit( status=%x )" % exit_code

  s.status = r_uint( exit_code )
  s.running = False

  #      ret_val    errno
  return exit_code, 0
Пример #14
0
 def __setitem__( self, idx, value ):
   value = r_uint( value )
   if idx == 15:
     self.state.pc = value
     if self.debug.enabled( "rf" ):
       print ':: WR.RF[15] = %s' % ( pad_hex( value ) ),
   else:
     self.regs[idx] = value
     if self.debug.enabled( "rf" ):
       print ':: WR.RF[%s] = %s' % (
                         pad( "%d" % idx, 2 ),
                         pad_hex( value ) ),
Пример #15
0
  def __init__( self, memory, debug, reset_addr=0x400):
    Machine.__init__(self, memory, RegisterFile(), debug, reset_addr=reset_addr )

    # parc special
    self.src_ptr  = 0
    self.sink_ptr = 0

    # indicate if this is running a self-checking test
    self.testbin  = False

    # executable name
    self.exe_name = ""

    # syscall stuff... TODO: should this be here?
    self.breakpoint = r_uint( 0 )
Пример #16
0
  def bounds_check( self, addr, x ):
    # check if the accessed data is larger than the memory size
    if addr > self.size:
      print ("WARNING: %s accessing larger address than memory size. "
             "addr=%s size=%s") % ( x, pad_hex( addr ), pad_hex( self.size ) )
      raise Exception()
    if addr == 0:
      print "WARNING: accessing null pointer!"
      raise Exception()

    # Special write checks
    if x == 'WR' and addr < r_uint( self.data_section ):
      print ("WARNING: %s writing address below .data section!!!. "
             "addr=%s size=%s") % ( x, pad_hex( addr ), pad_hex( self.data_section ) )
      raise Exception()
Пример #17
0
    def get_mcpuid(self):
        if self.state.xlen == 32:
            base = 0b00
            # TODO: not currently representing RV32E
        elif self.state.xlen == 64:
            base = 0b10
        elif self.state.xlen == 128:
            base = 0b11
        else:
            raise FatalError("XLEN=%d not supported" % self.state.xlen)

        extensions = 0
        for e in self.state.extensions:
            extensions |= 1 << (ord(e) - ord("a"))

        return r_uint((base << (self.state.xlen - 2)) | extensions)
Пример #18
0
  def get_mcpuid( self ):
    if self.state.xlen == 32:
      base = 0b00
      # TODO: not currently representing RV32E
    elif self.state.xlen == 64:
      base = 0b10
    elif self.state.xlen == 128:
      base = 0b11
    else:
      raise FatalError( "XLEN=%d not supported" % self.state.xlen )

    extensions = 0
    for e in self.state.extensions:
      extensions |= 1 << ( ord(e) - ord("a") )

    return r_uint( ( base << (self.state.xlen - 2) ) | extensions )
Пример #19
0
    def bounds_check(self, addr, x):
        # check if the accessed data is larger than the memory size
        if addr > self.size:
            print(
                "WARNING: %s accessing larger address than memory size. "
                "addr=%s size=%s") % (x, pad_hex(addr), pad_hex(self.size))
            raise Exception()
        if addr == 0:
            print "WARNING: accessing null pointer!"
            raise Exception()

        # Special write checks
        if x == 'WR' and addr < r_uint(self.data_section):
            print(
                "WARNING: %s writing address below .data section!!!. "
                "addr=%s size=%s") % (x, pad_hex(addr),
                                      pad_hex(self.data_section))
            raise Exception()
Пример #20
0
def shifter_operand_imm( s, inst ):
  shift_op  = inst.shift
  Rm        = s.rf[ inst.rm ]
  shift_imm = inst.shift_amt
  assert 0 <= shift_imm <= 31

  if   shift_op == LOGIC_SHIFT_LEFT:
    out  = Rm   if (shift_imm == 0) else Rm << shift_imm
    cout = s.C  if (shift_imm == 0) else (Rm >> 32 - shift_imm)&1

  elif shift_op == LOGIC_SHIFT_RIGHT:
    # NOTE: shift_imm == 0 signifies a shift by 32
    out  = 0        if (shift_imm == 0) else Rm >> shift_imm
    cout = Rm >> 31 if (shift_imm == 0) else (Rm >> shift_imm - 1)&1

  elif shift_op == ARITH_SHIFT_RIGHT:
    # NOTE: shift_imm == 0 signifies a shift by 32
    if shift_imm == 0:
      if (Rm >> 31) == 0: out, cout = 0,          Rm >> 31
      else:               out, cout = 0xFFFFFFFF, Rm >> 31
    else:
      out  = arith_shift( Rm, shift_imm )
      cout = (Rm >> shift_imm - 1)&1

  elif shift_op == ROTATE_RIGHT:
    # NOTE: shift_imm == 0 signifies a rotate right with extend (RRX)
    if shift_imm == 0:
      out  = ( r_uint(s.C) << 31 ) | (Rm >> 1)
      cout = Rm & 1
    else:
      out  = rotate_right( Rm, shift_imm )
      cout = (Rm >> shift_imm - 1)&1

  else:
    raise FatalError('Impossible shift_op!')

  return trim_32(out), cout
Пример #21
0
def shifter_operand_imm(s, inst):
    shift_op = inst.shift
    Rm = s.rf[inst.rm]
    shift_imm = inst.shift_amt
    assert 0 <= shift_imm <= 31

    if shift_op == LOGIC_SHIFT_LEFT:
        out = Rm if (shift_imm == 0) else Rm << shift_imm
        cout = s.C if (shift_imm == 0) else (Rm >> 32 - shift_imm) & 1

    elif shift_op == LOGIC_SHIFT_RIGHT:
        # NOTE: shift_imm == 0 signifies a shift by 32
        out = 0 if (shift_imm == 0) else Rm >> shift_imm
        cout = Rm >> 31 if (shift_imm == 0) else (Rm >> shift_imm - 1) & 1

    elif shift_op == ARITH_SHIFT_RIGHT:
        # NOTE: shift_imm == 0 signifies a shift by 32
        if shift_imm == 0:
            if (Rm >> 31) == 0: out, cout = 0, Rm >> 31
            else: out, cout = 0xFFFFFFFF, Rm >> 31
        else:
            out = arith_shift(Rm, shift_imm)
            cout = (Rm >> shift_imm - 1) & 1

    elif shift_op == ROTATE_RIGHT:
        # NOTE: shift_imm == 0 signifies a rotate right with extend (RRX)
        if shift_imm == 0:
            out = (r_uint(s.C) << 31) | (Rm >> 1)
            cout = Rm & 1
        else:
            out = rotate_right(Rm, shift_imm)
            cout = (Rm >> shift_imm - 1) & 1

    else:
        raise FatalError('Impossible shift_op!')

    return trim_32(out), cout
Пример #22
0
 def get_mhartid(self):
     return r_uint(0)
Пример #23
0
 def __init__(self, num_regs=32, nbits=64):
     self.num_regs = num_regs
     self.regs = [r_uint(0)] * self.num_regs
     self.debug = Debug()
     self.nbits = nbits
     self.debug_nchars = nbits / 4
Пример #24
0
 def __setitem__( self, idx, value ):
   value = r_uint( value )
   self._setitemimpl( idx, value )
Пример #25
0
def syscall_init( mem, entrypoint, breakpoint, argv, envp, debug ):

  #---------------------------------------------------------------------
  # memory map initialization
  #---------------------------------------------------------------------

  # TODO: for multicore allocate 8MB for each process
  #proc_stack_base[pid] = stack_base - pid * 8 * 1024 * 1024

  # top of heap (breakpoint)  # TODO: handled in load program

  # memory maps: 1GB above top of heap
  # mmap_start = mmap_end = break_point + 0x40000000

  #---------------------------------------------------------------------
  # stack argument initialization
  #---------------------------------------------------------------------
  # http://articles.manugarg.com/aboutelfauxiliaryvectors.html
  #
  #                contents         size
  #
  #   0x7FFF.FFFF  [ end marker ]               4    (NULL)
  #                [ environment str data ]   >=0
  #                [ arguments   str data ]   >=0
  #                [ padding ]               0-16
  #                [ auxv[n]  data ]            8    (AT_NULL Vector)
  #                                             8*x
  #                [ auxv[0]  data ]            8
  #                [ envp[n]  pointer ]         4    (NULL)
  #                                             4*x
  #                [ envp[0]  pointer ]         4
  #                [ argv[n]  pointer ]         4    (NULL)
  #                                             4*x
  #                [ argv[0]  pointer ]         4    (program name)
  #   stack ptr->  [ argc ]                     4    (size of argv)
  #
  #                (stack grows down!!!)
  #
  #   0x7F7F.FFFF  < stack limit for pid 0 >
  #

  # auxv variables initialized by gem5, are these needed?
  #
  # - PAGESZ:    system page size
  # - PHDR:      virtual addr of program header tables
  #              (for statically linked binaries)
  # - PHENT:     size of program header entries in elf file
  # - PHNUM:     number of program headers in elf file
  # - AT_ENRTY:  program entry point
  # - UID:       user ID
  # - EUID:      effective user ID
  # - GID:       group ID
  # - EGID:      effective group ID

  # TODO: handle auxv, envp variables
  auxv = []
  if EMULATE_GEM5:
    argv = argv[1:]
  argc = len( argv )

  def sum_( x ):
    val = 0
    for i in x:
      val += i
    return val

  # calculate sizes of sections
  # TODO: parameterize auxv/envp/argv calc for variable int size?
  stack_nbytes  = [ 4,                              # end mark nbytes (sentry)
                    sum_([len(x)+1 for x in envp]), # envp_str nbytes
                    sum_([len(x)+1 for x in argv]), # argv_str nbytes
                    0,                              # padding  nbytes
                    8*(len(auxv) + 1),              # auxv     nbytes
                    4*(len(envp) + 1),              # envp     nbytes
                    4*(len(argv) + 1),              # argv     nbytes
                    4 ]                             # argc     nbytes

  if EMULATE_SIMIT:
    stack_nbytes[4] = 0  # don't to auxv for simit

  def round_up( val ):
    alignment = 16
    return (val + alignment - 1) & ~(alignment - 1)

  # calculate padding to align boundary
  # NOTE: MIPs approach (but ignored by gem5)
  #stack_nbytes[3] = 16 - (sum_(stack_nbytes[:3]) % 16)
  # NOTE: gem5 ARM approach
  stack_nbytes[3] = round_up( sum_(stack_nbytes) ) - sum_(stack_nbytes)
  if EMULATE_SIMIT:
    stack_nbytes[3] = 0

  def round_down( val ):
    alignment = 16
    return val & ~(alignment - 1)

  # calculate stack pointer based on size of storage needed for args
  # TODO: round to nearest page size?
  stack_ptr = round_down( stack_base - sum_( stack_nbytes ) )
  if EMULATE_SIMIT:
    stack_ptr = stack_base - MAX_ENVIRON


  offset  = stack_ptr + sum_( stack_nbytes )
  # FIXME: this offset seems really wrong, but this is how gem5 does it!
  if EMULATE_GEM5:
    offset = stack_base

  print "XXX", offset

  stack_off = []
  for nbytes in stack_nbytes:
    offset -= nbytes
    stack_off.append( offset )
  # FIXME: this is fails for GEM5's hacky offset...
  if not EMULATE_GEM5:
    assert offset == stack_ptr

  if debug.enabled( 'bootstrap' ):
    print 'stack base', hex( stack_base )
    print 'stack min ', hex( stack_ptr )
    print 'stack size', stack_base - stack_ptr
    print
    print 'sentry ', stack_nbytes[0]
    print 'env d  ', stack_nbytes[1]
    print 'arg d  ', stack_nbytes[2]
    print 'padding', stack_nbytes[3]
    print 'auxv   ', stack_nbytes[4]
    print 'envp   ', stack_nbytes[5]
    print 'argv   ', stack_nbytes[6]
    print 'argc   ', stack_nbytes[7]

  # utility functions

  def str_to_mem( mem, val, addr ):
    for i, char in enumerate(val+'\0'):
      mem.write( addr + i, 1, ord( char ) )
    return addr + len(val) + 1

  def int_to_mem( mem, val, addr ):
    # TODO properly handle endianess
    for i in range( 4 ):
      mem.write( addr+i, 1, (val >> 8*i) & 0xFF )
    return addr + 4

  # write end marker to memory
  int_to_mem( mem, 0, stack_off[0] )

  # write environment strings to memory
  envp_ptrs = []
  offset   = stack_off[1]
  for x in envp:
    envp_ptrs.append( offset )
    offset = str_to_mem( mem, x, offset )
  assert offset == stack_off[0]

  # write argument strings to memory
  argv_ptrs = []
  offset   = stack_off[2]
  for x in argv:
    argv_ptrs.append( offset )
    offset = str_to_mem( mem, x, offset )
  assert offset == stack_off[1]

  # write auxv vectors to memory
  offset   = stack_off[4]
  if not EMULATE_SIMIT:
    for type_, value in auxv + [(0,0)]:
      offset = int_to_mem( mem, type_, offset )
      offset = int_to_mem( mem, value, offset )
  assert offset == stack_off[3]

  # write envp pointers to memory
  offset   = stack_off[5]
  for env in envp_ptrs + [0]:
    offset = int_to_mem( mem, env, offset )
  assert offset == stack_off[4]

  # write argv pointers to memory
  offset   = stack_off[6]
  for arg in argv_ptrs + [0]:
    offset = int_to_mem( mem, arg, offset )
  assert offset == stack_off[5]

  # write argc to memory
  offset = stack_off[7]
  offset = int_to_mem( mem, argc, offset )
  assert offset == stack_off[6]

  # write zeros to bottom of stack
  # TODO: why does gem5 do this?
  offset = stack_off[7] - 1
  while offset >= stack_ptr:
    mem.write( offset, 1, ord( '\0' ) )
    offset -= 1

  # initialize processor state
  state = State( mem, debug, reset_addr=0x1000 )

  if debug.enabled( 'bootstrap' ):
    print '---'
    #print 'argc = %d (%x)' % ( argc,         stack_off[-1] )
    #for i, ptr in enumerate(argv_ptrs):
    #  print 'argv[%2d] = %x (%x)' % ( i, argv_ptrs[i], stack_off[-2]+4*i ),
    #  print len( argv[i] ), argv[i]
    #print 'argd = %s (%x)' % ( argv[0],      stack_off[-6] )
    print '---'
    print 'envd-base', hex(stack_off[-7])
    print 'argd-base', hex(stack_off[-6])
    print 'auxv-base', hex(stack_off[-4])
    print 'envp-base', hex(stack_off[-3])
    print 'argv-base', hex(stack_off[-2])
    print 'argc-base', hex(stack_off[-1])
    print 'STACK_PTR', hex( stack_ptr )

  # TODO: where should this go?
  #state.pc         = entrypoint
  state.breakpoint = r_uint( breakpoint )

  # initialize processor registers
  state.rf[  0 ] = 0            # ptr to func to run when program exits, disable
  state.rf[  1 ] = stack_off[6] # argument 1 reg = argv ptr addr
  state.rf[  2 ] = stack_off[5] # argument 2 reg = envp ptr addr
  if EMULATE_SIMIT:
    state.rf[  1 ] = argc         # argument 1 reg = argc
    state.rf[  2 ] = stack_off[6] # argument 2 reg = argv ptr addr
  state.rf[ 13 ] = stack_ptr    # stack pointer reg
  state.rf[ 15 ] = entrypoint   # program counter

  if debug.enabled( 'bootstrap' ):
    state.rf.print_regs( per_row=4 )
    print '='* 20, 'end bootstrap', '='*20

  return state
Пример #26
0
 def iread( self, start_addr, num_bytes ):
   assert start_addr & 0b11 == 0  # only aligned accesses allowed
   return r_uint( widen( self.data[ start_addr >> 2 ] ) )
Пример #27
0
 def cpsr( self ):
   return ( r_uint( self.N ) << 31 ) | \
          ( r_uint( self.Z ) << 30 ) | \
          ( r_uint( self.C ) << 29 ) | \
          ( r_uint( self.V ) << 28 ) | \
          ( r_uint( self.mode ) )
Пример #28
0
def syscall_init(mem, entrypoint, breakpoint, argv, envp, debug):

    #---------------------------------------------------------------------
    # memory map initialization
    #---------------------------------------------------------------------

    # TODO: for multicore allocate 8MB for each process
    #proc_stack_base[pid] = stack_base - pid * 8 * 1024 * 1024

    # top of heap (breakpoint)  # TODO: handled in load program

    # memory maps: 1GB above top of heap
    # mmap_start = mmap_end = break_point + 0x40000000

    #---------------------------------------------------------------------
    # stack argument initialization
    #---------------------------------------------------------------------
    # http://articles.manugarg.com/aboutelfauxiliaryvectors.html
    #
    #                contents         size
    #
    #   0x7FFF.FFFF  [ end marker ]               4    (NULL)
    #                [ environment str data ]   >=0
    #                [ arguments   str data ]   >=0
    #                [ padding ]               0-16
    #                [ auxv[n]  data ]            8    (AT_NULL Vector)
    #                                             8*x
    #                [ auxv[0]  data ]            8
    #                [ envp[n]  pointer ]         4    (NULL)
    #                                             4*x
    #                [ envp[0]  pointer ]         4
    #                [ argv[n]  pointer ]         4    (NULL)
    #                                             4*x
    #                [ argv[0]  pointer ]         4    (program name)
    #   stack ptr->  [ argc ]                     4    (size of argv)
    #
    #                (stack grows down!!!)
    #
    #   0x7F7F.FFFF  < stack limit for pid 0 >
    #

    # auxv variables initialized by gem5, are these needed?
    #
    # - PAGESZ:    system page size
    # - PHDR:      virtual addr of program header tables
    #              (for statically linked binaries)
    # - PHENT:     size of program header entries in elf file
    # - PHNUM:     number of program headers in elf file
    # - AT_ENRTY:  program entry point
    # - UID:       user ID
    # - EUID:      effective user ID
    # - GID:       group ID
    # - EGID:      effective group ID

    # TODO: handle auxv, envp variables
    auxv = []
    if EMULATE_GEM5:
        argv = argv[1:]
    argc = len(argv)

    def sum_(x):
        val = 0
        for i in x:
            val += i
        return val

    # calculate sizes of sections
    # TODO: parameterize auxv/envp/argv calc for variable int size?
    stack_nbytes = [
        4,  # end mark nbytes (sentry)
        sum_([len(x) + 1 for x in envp]),  # envp_str nbytes
        sum_([len(x) + 1 for x in argv]),  # argv_str nbytes
        0,  # padding  nbytes
        8 * (len(auxv) + 1),  # auxv     nbytes
        4 * (len(envp) + 1),  # envp     nbytes
        4 * (len(argv) + 1),  # argv     nbytes
        4
    ]  # argc     nbytes

    if EMULATE_SIMIT:
        stack_nbytes[4] = 0  # don't to auxv for simit

    def round_up(val):
        alignment = 16
        return (val + alignment - 1) & ~(alignment - 1)

    # calculate padding to align boundary
    # NOTE: MIPs approach (but ignored by gem5)
    #stack_nbytes[3] = 16 - (sum_(stack_nbytes[:3]) % 16)
    # NOTE: gem5 ARM approach
    stack_nbytes[3] = round_up(sum_(stack_nbytes)) - sum_(stack_nbytes)
    if EMULATE_SIMIT:
        stack_nbytes[3] = 0

    def round_down(val):
        alignment = 16
        return val & ~(alignment - 1)

    # calculate stack pointer based on size of storage needed for args
    # TODO: round to nearest page size?
    stack_ptr = round_down(stack_base - sum_(stack_nbytes))
    if EMULATE_SIMIT:
        stack_ptr = stack_base - MAX_ENVIRON

    offset = stack_ptr + sum_(stack_nbytes)
    # FIXME: this offset seems really wrong, but this is how gem5 does it!
    if EMULATE_GEM5:
        offset = stack_base

    print "XXX", offset

    stack_off = []
    for nbytes in stack_nbytes:
        offset -= nbytes
        stack_off.append(offset)
    # FIXME: this is fails for GEM5's hacky offset...
    if not EMULATE_GEM5:
        assert offset == stack_ptr

    if debug.enabled('bootstrap'):
        print 'stack base', hex(stack_base)
        print 'stack min ', hex(stack_ptr)
        print 'stack size', stack_base - stack_ptr
        print
        print 'sentry ', stack_nbytes[0]
        print 'env d  ', stack_nbytes[1]
        print 'arg d  ', stack_nbytes[2]
        print 'padding', stack_nbytes[3]
        print 'auxv   ', stack_nbytes[4]
        print 'envp   ', stack_nbytes[5]
        print 'argv   ', stack_nbytes[6]
        print 'argc   ', stack_nbytes[7]

    # utility functions

    def str_to_mem(mem, val, addr):
        for i, char in enumerate(val + '\0'):
            mem.write(addr + i, 1, ord(char))
        return addr + len(val) + 1

    def int_to_mem(mem, val, addr):
        # TODO properly handle endianess
        for i in range(4):
            mem.write(addr + i, 1, (val >> 8 * i) & 0xFF)
        return addr + 4

    # write end marker to memory
    int_to_mem(mem, 0, stack_off[0])

    # write environment strings to memory
    envp_ptrs = []
    offset = stack_off[1]
    for x in envp:
        envp_ptrs.append(offset)
        offset = str_to_mem(mem, x, offset)
    assert offset == stack_off[0]

    # write argument strings to memory
    argv_ptrs = []
    offset = stack_off[2]
    for x in argv:
        argv_ptrs.append(offset)
        offset = str_to_mem(mem, x, offset)
    assert offset == stack_off[1]

    # write auxv vectors to memory
    offset = stack_off[4]
    if not EMULATE_SIMIT:
        for type_, value in auxv + [(0, 0)]:
            offset = int_to_mem(mem, type_, offset)
            offset = int_to_mem(mem, value, offset)
    assert offset == stack_off[3]

    # write envp pointers to memory
    offset = stack_off[5]
    for env in envp_ptrs + [0]:
        offset = int_to_mem(mem, env, offset)
    assert offset == stack_off[4]

    # write argv pointers to memory
    offset = stack_off[6]
    for arg in argv_ptrs + [0]:
        offset = int_to_mem(mem, arg, offset)
    assert offset == stack_off[5]

    # write argc to memory
    offset = stack_off[7]
    offset = int_to_mem(mem, argc, offset)
    assert offset == stack_off[6]

    # write zeros to bottom of stack
    # TODO: why does gem5 do this?
    offset = stack_off[7] - 1
    while offset >= stack_ptr:
        mem.write(offset, 1, ord('\0'))
        offset -= 1

    # initialize processor state
    state = State(mem, debug, reset_addr=0x1000)

    if debug.enabled('bootstrap'):
        print '---'
        #print 'argc = %d (%x)' % ( argc,         stack_off[-1] )
        #for i, ptr in enumerate(argv_ptrs):
        #  print 'argv[%2d] = %x (%x)' % ( i, argv_ptrs[i], stack_off[-2]+4*i ),
        #  print len( argv[i] ), argv[i]
        #print 'argd = %s (%x)' % ( argv[0],      stack_off[-6] )
        print '---'
        print 'envd-base', hex(stack_off[-7])
        print 'argd-base', hex(stack_off[-6])
        print 'auxv-base', hex(stack_off[-4])
        print 'envp-base', hex(stack_off[-3])
        print 'argv-base', hex(stack_off[-2])
        print 'argc-base', hex(stack_off[-1])
        print 'STACK_PTR', hex(stack_ptr)

    # TODO: where should this go?
    #state.pc         = entrypoint
    state.breakpoint = r_uint(breakpoint)

    # initialize processor registers
    state.rf[0] = 0  # ptr to func to run when program exits, disable
    state.rf[1] = stack_off[6]  # argument 1 reg = argv ptr addr
    state.rf[2] = stack_off[5]  # argument 2 reg = envp ptr addr
    if EMULATE_SIMIT:
        state.rf[1] = argc  # argument 1 reg = argc
        state.rf[2] = stack_off[6]  # argument 2 reg = argv ptr addr
    state.rf[13] = stack_ptr  # stack pointer reg
    state.rf[15] = entrypoint  # program counter

    if debug.enabled('bootstrap'):
        state.rf.print_regs(per_row=4)
        print '=' * 20, 'end bootstrap', '=' * 20

    return state
Пример #29
0
def execute_jal( s, inst ):
  s.rf[31] = s.pc + 4
  s.pc = ((s.pc + 4) & r_uint( 0xF0000000 ) ) | (inst.jtarg << 2)
Пример #30
0
 def __init__(self, bits, str):
     self.bits = r_uint(bits)
     self.str = str
Пример #31
0
def syscall_init( mem, breakpoint, argv, envp, debug ):

  #---------------------------------------------------------------------
  # stack argument initialization
  #---------------------------------------------------------------------
  # http://articles.manugarg.com/aboutelfauxiliaryvectors.html
  #
  #                contents         size
  #
  #   0x7FFF.FFFF  [ end marker ]               8    (NULL)
  #                [ environment str data ]   >=0
  #                [ arguments   str data ]   >=0
  #                [ padding ]               0-16
  #                [ auxv[n]  data ]            8    (AT_NULL Vector)
  #                                             8*x
  #                [ auxv[0]  data ]            8
  #                [ envp[n]  pointer ]         8    (NULL)
  #                                             8*x
  #                [ envp[0]  pointer ]         8
  #                [ argv[n]  pointer ]         8    (NULL)
  #                                             8*x
  #                [ argv[0]  pointer ]         8    (program name)
  #   stack ptr->  [ argc ]                     8    (size of argv)
  #
  #                (stack grows down!!!)
  #
  #   0x7F7F.FFFF  < stack limit for pid 0 >
  #

  # auxv variables initialized by gem5, are these needed?
  #
  # - PAGESZ:    system page size
  # - PHDR:      virtual addr of program header tables
  #              (for statically linked binaries)
  # - PHENT:     size of program header entries in elf file
  # - PHNUM:     number of program headers in elf file
  # - AT_ENRTY:  program entry point
  # - UID:       user ID
  # - EUID:      effective user ID
  # - GID:       group ID
  # - EGID:      effective group ID

  # TODO: handle auxv, envp variables
  auxv = []
  argc = len( argv )

  def sum_( x ):
    val = 0
    for i in x:
      val += i
    return val

  # calculate sizes of sections
  # TODO: parameterize auxv/envp/argv calc for variable int size?
  stack_nbytes  = [ 8,                              # end mark nbytes
                    sum_([len(x)+1 for x in envp]), # envp_str nbytes
                    sum_([len(x)+1 for x in argv]), # argv_str nbytes
                    0,                              # padding  nbytes
                    16*(len(auxv) + 1),             # auxv     nbytes
                    8*(len(envp) + 1),              # envp     nbytes
                    8*(len(argv) + 1),              # argv     nbytes
                    8 ]                             # argc     nbytes

  # calculate padding to align boundary
  # TODO: gem5 doesn't do this step, temporarily remove it. There should
  #       really be padding to align argv to a 16 byte boundary!!!
  #stack_nbytes[3] = 16 - (sum_(stack_nbytes[:3]) % 16)

  def round_down( val ):
    return val & ~(page_size - 1)

  # calculate stack pointer based on size of storage needed for args
  # TODO: round to nearest page size?
  stack_ptr = round_down( stack_base - sum_( stack_nbytes ) )
  offset    = stack_ptr + sum_( stack_nbytes )
  stack_off = []
  for nbytes in stack_nbytes:
    offset -= nbytes
    stack_off.append( offset )
  assert offset == stack_ptr

  #print 'stack min', hex( stack_ptr )
  #print 'stack size', stack_base - stack_ptr

  #print 'argv', stack_nbytes[-2]
  #print 'envp', stack_nbytes[-3]
  #print 'auxv', stack_nbytes[-4]
  #print 'argd', stack_nbytes[-6]
  #print 'envd', stack_nbytes[-7]

  # utility functions

  def str_to_mem( mem, val, addr ):
    for i, char in enumerate(val+'\0'):
      mem.write( addr + i, 1, ord( char ) )
    return addr + len(val) + 1

  def int_to_mem( mem, val, addr ):
    # TODO properly handle endianess
    for i in range( 8 ):
      mem.write( addr+i, 1, (val >> 8*i) & 0xFF )
    return addr + 8

  # write end marker to memory
  int_to_mem( mem, 0, stack_off[0] )

  # write environment strings to memory
  envp_ptrs = []
  offset   = stack_off[1]
  for x in envp:
    envp_ptrs.append( offset )
    offset = str_to_mem( mem, x, offset )
  assert offset == stack_off[0]

  # write argument strings to memory
  argv_ptrs = []
  offset   = stack_off[2]
  for x in argv:
    argv_ptrs.append( offset )
    offset = str_to_mem( mem, x, offset )
  assert offset == stack_off[1]

  # write auxv vectors to memory
  offset   = stack_off[4]
  for type_, value in auxv + [(0,0)]:
    offset = int_to_mem( mem, type_, offset )
    offset = int_to_mem( mem, value, offset )
  assert offset == stack_off[3]

  # write envp pointers to memory
  offset   = stack_off[5]
  for env in envp_ptrs + [0]:
    offset = int_to_mem( mem, env, offset )
  assert offset == stack_off[4]

  # write argv pointers to memory
  offset   = stack_off[6]
  for arg in argv_ptrs + [0]:
    offset = int_to_mem( mem, arg, offset )
  assert offset == stack_off[5]

  # write argc to memory
  offset = stack_off[7]
  offset = int_to_mem( mem, argc, offset )
  assert offset == stack_off[6]

  # initialize processor state
  state = State( mem, debug, reset_addr=0x10000 )

  # TODO: where should this go?
  state.breakpoint = r_uint( breakpoint )

  #print '---'
  #print 'argc = %d (%x)' % ( argc,         stack_off[-1] )
  #for i, ptr in enumerate(argv_ptrs):
  #  print 'argv[%d] = %x (%x)' % ( i, argv_ptrs[i], stack_off[-2]+4*i ),
  #  print len( argv[i] ), argv[i]
  #print 'argd = %s (%x)' % ( argv[0],      stack_off[-6] )
  #print '---'
  #print 'argv-base', hex(stack_off[-2])
  #print 'envp-base', hex(stack_off[-3])
  #print 'auxv-base', hex(stack_off[-4])
  #print 'argd-base', hex(stack_off[-6])
  #print 'envd-base', hex(stack_off[-7])

  # initialize processor registers
  state.rf[ reg_map['a0'] ] = argc         # argument 0 reg = argc
  state.rf[ reg_map['a1'] ] = stack_off[6] # argument 1 reg = argv ptr addr
  state.rf[ reg_map['sp'] ] = stack_ptr    # stack pointer reg

  return state
  # instantiate architectural state with memory and reset address

  return state
Пример #32
0
 def __setitem__(self, idx, value):
     value = r_uint(value)
     self._setitemimpl(idx, value)
Пример #33
0
def arith_shift( data, shift ):
  fill = r_uint( 0xFFFFFFFF if (data >> 31) else 0 )
  return (fill << (32-shift)) | (data >> shift)
Пример #34
0
    def get_mstatus(self):

        ie = r_uint(0)
        prv = r_uint(self.state.prv)
        ie1 = r_uint(0)
        prv1 = r_uint(0)
        ie2 = r_uint(0)
        prv2 = r_uint(0)
        ie3 = r_uint(0)
        prv3 = r_uint(0)
        fs = r_uint(0)
        xs = r_uint(0)
        mprv = r_uint(0)
        vm = r_uint(0)
        sd = r_uint(0)

        xlen = self.state.xlen

        return (ie
                | (prv << 1)
                | (ie1 << 3)
                | (prv1 << 4)
                | (ie2 << 6)
                | (prv2 << 7)
                | (ie3 << 9)
                | (prv3 << 10)
                | (fs << 12)
                | (xs << 14)
                | (mprv << 16)
                | (vm << 17)
                | (sd << (xlen - 1)))
Пример #35
0
 def iread(self, start_addr, num_bytes):
     assert start_addr & 0b11 == 0  # only aligned accesses allowed
     return r_uint(widen(self.data[start_addr >> 2]))
Пример #36
0
 def cpsr(self):
     return ( r_uint( self.N ) << 31 ) | \
            ( r_uint( self.Z ) << 30 ) | \
            ( r_uint( self.C ) << 29 ) | \
            ( r_uint( self.V ) << 28 ) | \
            ( r_uint( self.mode ) )
Пример #37
0
 def __init__( self, bits, str ):
   self.bits = r_uint( bits )
   self.str  = str
Пример #38
0
 def get_mhartid( self ):
   return r_uint( 0 )
Пример #39
0
def execute_j( s, inst ):
  s.pc = ((s.pc + 4) & r_uint( 0xF0000000 ) ) | (inst.jtarg << 2)
Пример #40
0
  def get_mstatus( self ):

    ie   = r_uint( 0 )
    prv  = r_uint( self.state.prv )
    ie1  = r_uint( 0 )
    prv1 = r_uint( 0 )
    ie2  = r_uint( 0 )
    prv2 = r_uint( 0 )
    ie3  = r_uint( 0 )
    prv3 = r_uint( 0 )
    fs   = r_uint( 0 )
    xs   = r_uint( 0 )
    mprv = r_uint( 0 )
    vm   = r_uint( 0 )
    sd   = r_uint( 0 )

    xlen = self.state.xlen

    return (     ie
             | ( prv  << 1        )
             | ( ie1  << 3        )
             | ( prv1 << 4        )
             | ( ie2  << 6        )
             | ( prv2 << 7        )
             | ( ie3  << 9        )
             | ( prv3 << 10       )
             | ( fs   << 12       )
             | ( xs   << 14       )
             | ( mprv << 16       )
             | ( vm   << 17       )
             | ( sd   << (xlen-1) ) )
Пример #41
0
 def __init__( self, num_regs=32, nbits=64 ):
   self.num_regs = num_regs
   self.regs     = [ r_uint(0) ] * self.num_regs
   self.debug    = Debug()
   self.nbits    = nbits
   self.debug_nchars = nbits / 4
Пример #42
0
def arith_shift(data, shift):
    fill = r_uint(0xFFFFFFFF if (data >> 31) else 0)
    return (fill << (32 - shift)) | (data >> shift)