RunMu.scala 3.89 KB
Newer Older
Kunshan Wang's avatar
Kunshan Wang committed
1 2 3 4
package uvm.refimpl.cmdline

import uvm.refimpl.MicroVM
import uvm.refimpl.nat.ScalaCInitiater
Kunshan Wang's avatar
Kunshan Wang committed
5 6
import scala.collection.mutable.HashMap
import uvm.refimpl.VMConf
7 8 9 10 11 12 13 14 15
import java.util.zip.ZipFile
import uvm.utils.WithUtils.tryWithResource
import uvm.refimpl.UvmRuntimeException
import java.nio.charset.StandardCharsets
import java.io.InputStreamReader
import java.io.BufferedReader
import uvm.refimpl.nat.NativeSupport
import uvm.refimpl.nat.PlatformConstants
import uvm.refimpl.HowToResume.PassValues
16
import uvm.refimpl.InternalTypes
Kunshan Wang's avatar
Kunshan Wang committed
17 18 19

/** Run Mu from the command line. */
object RunMu {
Kunshan Wang's avatar
Kunshan Wang committed
20 21 22
  private val KVOPT = """--(\w+)=(.+)""".r
  private val SEP = "--"
  private val HELP = "-h|--help".r
Kunshan Wang's avatar
Kunshan Wang committed
23

24 25
  private val ENTRYPOINT_FILE = "entrypoint"

Kunshan Wang's avatar
Kunshan Wang committed
26 27
  def main(args: Array[String]): Unit = {
    val props = new HashMap[String, String]()
28

Kunshan Wang's avatar
Kunshan Wang committed
29 30
    var curArgs = args.toList
    var parsing = true
31 32

    while (parsing) {
Kunshan Wang's avatar
Kunshan Wang committed
33 34 35 36 37 38 39 40 41 42 43 44
      curArgs match {
        case Nil => parsing = false
        case arg :: rest => {
          arg match {
            case HELP() => {
              System.err.println(DOCSTRING)
              return
            }
            case SEP => {
              curArgs = rest
              parsing = false
            }
45
            case KVOPT(k, v) => {
Kunshan Wang's avatar
Kunshan Wang committed
46 47 48 49 50 51 52 53 54
              props(k) = v
              curArgs = rest
            }
            case _ => {
              parsing = false
            }
          }
        }
      }
55

Kunshan Wang's avatar
Kunshan Wang committed
56
    }
57

Kunshan Wang's avatar
Kunshan Wang committed
58
    val (bootImg, appArgs) = curArgs match {
59
      case h :: t => (h, t)
Kunshan Wang's avatar
Kunshan Wang committed
60 61 62 63 64
      case Nil => {
        System.err.println(DOCSTRING)
        return
      }
    }
65

Kunshan Wang's avatar
Kunshan Wang committed
66
    props("bootImg") = bootImg
67

Kunshan Wang's avatar
Kunshan Wang committed
68
    val microVM = new MicroVM(VMConf(props.toMap))
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90

    val entryPoint: Either[Int, String] = {
      tryWithResource(new ZipFile(bootImg)) { zipFile =>
        val entryPointEntry = Option(zipFile.getEntry(ENTRYPOINT_FILE)).getOrElse {
          throw new UvmRuntimeException("Boot image has no entry point. Use tools/mar.py to set entry point. Image: " + bootImg)
        }
        val line = tryWithResource(new BufferedReader(new InputStreamReader(zipFile.getInputStream(entryPointEntry), StandardCharsets.UTF_8))) { br =>
          br.readLine()
        }

        val Array(kind, value) = line.split(" ")

        kind match {
          case "id"   => Left(value.toInt)
          case "name" => Right(value)
        }
      }
    }

    val argc = appArgs.size + 1
    val argvSB = new StringBuilder()
    val argvOffs = new Array[Long](argc)
91
    
92
    for ((arg, i) <- (bootImg :: appArgs).zipWithIndex) {
93
      argvOffs(i) = argvSB.length
94 95
      argvSB ++= arg += '\0'
    }
96 97 98
    
    val cArgv = NativeSupport.jnrMemoryManager.allocateDirect(argvOffs.length * PlatformConstants.WORD_SIZE_BYTES.toInt)
    val cArgvBuf = NativeSupport.jnrMemoryManager.allocateDirect(argvSB.length)
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
    for (i <- 0 until argvOffs.length) {
      cArgv.putAddress(i * PlatformConstants.WORD_SIZE_BYTES, cArgvBuf.address() + argvOffs(i))
    }
    for (i <- 0 until argvSB.length) {
      cArgvBuf.putByte(i, argvSB.charAt(i).toByte)    // Assume single-byte encoding
    }

    tryWithResource(microVM.newContext()) { ctx =>
      val id = entryPoint match {
        case Left(id)    => id
        case Right(name) => ctx.idOf(name)
      }
      val func = ctx.handleFromFunc(id)
      val stack = ctx.newStack(func)
      val hArgc = ctx.handleFromInt(argc, 32)
114
      val hArgv = ctx.handleFromPtr(InternalTypes.C_CHARPP.id, cArgv.address())
115 116 117 118
      val thread = ctx.newThread(stack, None, PassValues(Seq(hArgc, hArgv)))
    }
    
    microVM.execute()
Kunshan Wang's avatar
Kunshan Wang committed
119
  }
120

Kunshan Wang's avatar
Kunshan Wang committed
121 122 123 124 125 126 127 128 129
  private val DOCSTRING = """USAGE: runmu.sh --prop1=value1 --prop2=value2 ... [--] bootimg [args...]

Properties and values are the same as the argument of mu_refimpl_new_ex. See
README.md for more information.

bootimg is the path to the boot image (overrides the bootImg property if set).
It will start execution at the entry point specified in the boot image.
Extra args will be passed to the entry point function.
"""
Kunshan Wang's avatar
Kunshan Wang committed
130
}