Commit 10171176 authored by Kunshan Wang's avatar Kunshan Wang

WIP: Boot image hello world. Still has bugs.

parent 794b90c4
......@@ -21,6 +21,7 @@ import uvm.refimpl.nat.NativeCallHelper
import uvm.refimpl.nat.NativeLibraryHolder
import uvm.staticanalysis.StaticAnalyzer
import uvm.utils.IDFactory
import uvm.utils.WithUtils.tryWithResource
object MicroVM {
val DEFAULT_SOS_SIZE: Word = 2L * 1024L * 1024L; // 2MiB
......@@ -179,8 +180,9 @@ class MicroVM(val vmConf: VMConf) {
* Load from a boot image.
*/
def loadBootImage(file: String): Unit = {
val bil = new BootImageLoader(file)
bil.load()
tryWithResource(new BootImageLoader(file)) { bil =>
bil.load()
}
}
/**
......
......@@ -23,12 +23,14 @@ import uvm.utils.WithUtils.tryWithResource
import uvm.refimpl.itpr.OpHelper
import uvm.Function
import java.io.FileNotFoundException
import java.util.zip.ZipEntry
object BootImageLoader {
val MUTATOR_NAME = "bootimgldr"
val EXTRALIBS_FILE = "extralibs"
}
class BootImageLoader(file: String)(implicit microVM: MicroVM) {
class BootImageLoader(file: String)(implicit microVM: MicroVM) extends AutoCloseable {
import BootImageLoader._
import BootImageWriter._
......@@ -44,7 +46,7 @@ class BootImageLoader(file: String)(implicit microVM: MicroVM) {
new ZipFile(bootImagePath.toFile())
} catch {
case e: FileNotFoundException => throw new BootImageLoaderException(
"Boot image not found: " + file, e)
"Boot image not found: " + file, e)
}
val objNumToAddr = new HashMap[Long, Word]()
......@@ -53,16 +55,38 @@ class BootImageLoader(file: String)(implicit microVM: MicroVM) {
globalMemory.addrForGlobalCell(g)
}
def zipFile(name: String): InputStream = zip.getInputStream(zip.getEntry(name))
def zipFileText(name: String): Reader = new InputStreamReader(zip.getInputStream(zip.getEntry(name)), StandardCharsets.UTF_8)
def zipFileTextBuf(name: String): BufferedReader = new BufferedReader(zipFileText(name))
private def zipFile(entry: ZipEntry): InputStream = zip.getInputStream(entry)
private def zipFile(name: String): InputStream = zipFile(zip.getEntry(name))
private def zipFileText(name: String): Reader = new InputStreamReader(zipFile(name), StandardCharsets.UTF_8)
private def zipFileTextBuf(name: String): BufferedReader = new BufferedReader(zipFileText(name))
override def close(): Unit = {
zip.close()
}
def load(): Unit = {
loadExtraLibs()
loadUIRBundle()
initializeMemory()
}
private def loadExtraLibs(): Unit = {
Option(zip.getEntry(EXTRALIBS_FILE)) foreach { entry =>
val line = tryWithResource(zipFileTextBuf(EXTRALIBS_FILE)) { br =>
br.readLine()
}
val libs = line.split(":")
for (lib <- libs) {
logger.info("Loading extra library: " + lib)
microVM.nativeLibraryHolder.loadLibrary(lib)
}
}
}
private def loadUIRBundle(): Unit = {
val map = loadIDNameMap()
val mappedIDFactory = new MappedIDFactory(map)
......
......@@ -4,6 +4,15 @@ import uvm.refimpl.MicroVM
import uvm.refimpl.nat.ScalaCInitiater
import scala.collection.mutable.HashMap
import uvm.refimpl.VMConf
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
/** Run Mu from the command line. */
object RunMu {
......@@ -11,13 +20,15 @@ object RunMu {
private val SEP = "--"
private val HELP = "-h|--help".r
private val ENTRYPOINT_FILE = "entrypoint"
def main(args: Array[String]): Unit = {
val props = new HashMap[String, String]()
var curArgs = args.toList
var parsing = true
while(parsing) {
while (parsing) {
curArgs match {
case Nil => parsing = false
case arg :: rest => {
......@@ -30,7 +41,7 @@ object RunMu {
curArgs = rest
parsing = false
}
case KVOPT(k,v) => {
case KVOPT(k, v) => {
props(k) = v
curArgs = rest
}
......@@ -40,22 +51,72 @@ object RunMu {
}
}
}
}
val (bootImg, appArgs) = curArgs match {
case h::t => (h, t)
case h :: t => (h, t)
case Nil => {
System.err.println(DOCSTRING)
return
}
}
props("bootImg") = bootImg
val microVM = new MicroVM(VMConf(props.toMap))
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)
for ((arg, i) <- (bootImg :: appArgs).zipWithIndex) {
argvOffs(i) = argvOffs.length
argvSB ++= arg += '\0'
}
val cArgv = NativeSupport.jnrMemoryManager.allocate(argvOffs.length * PlatformConstants.WORD_SIZE_BYTES.toInt)
val cArgvBuf = NativeSupport.jnrMemoryManager.allocate(argvSB.length)
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)
val hArgv = ctx.handleFromPtr(ctx.idOf("@charpp"), cArgv.address())
val thread = ctx.newThread(stack, None, PassValues(Seq(hArgc, hArgv)))
}
microVM.execute()
}
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
......
......@@ -38,3 +38,6 @@ class UvmHailParsingException(message: String = null, cause: Throwable = null) e
/** Thrown if a number does not match any entity when using ObjectKeepers. */
class UvmUnknownIDException(message: String = null, cause: Throwable = null) extends UvmRuntimeException(message, cause)
/** Thrown when there is an error involving opening external libraries or resolving symbols. */
class UvmExternalLibraryException(message: String = null, cause: Throwable = null) extends UvmRuntimeException(message, cause)
\ No newline at end of file
package uvm.refimpl.nat
import scala.collection.mutable.ArrayBuffer
import com.kenai.jffi.Library
import uvm.refimpl.UvmRuntimeException
import uvm.refimpl.UvmExternalLibraryException
object NativeLibraryHolder {
/**
......@@ -44,7 +46,7 @@ class NativeLibraryHolder() {
def loadLibrary(path: String): Library = {
val lib = Option(Library.openLibrary(path, Library.NOW))
lib match {
case None => throw new UvmRuntimeException("Cannot load library: %s".format(path))
case None => throw new UvmExternalLibraryException("Cannot load library: %s".format(path))
case Some(l) =>
libs += l
l
......@@ -63,6 +65,6 @@ class NativeLibraryHolder() {
return addr
}
}
throw new UvmRuntimeException("Symbol cannot be resolved: %s".format(symbol))
throw new UvmExternalLibraryException("Symbol cannot be resolved: %s".format(symbol))
}
}
package uvm.refimpl.bootimg
import uvm.refimpl.MicroVM
import uvm.refimpl.VMConf
import uvm.refimpl.UvmBundleTesterBase
import uvm.ir.textinput.ExtraMatchers
import uvm.ir.textinput.TestingBundlesValidators.MagicalOur
import uvm.refimpl.mem.HeaderUtils
import uvm.types.Type
import uvm.refimpl.mem.TypeSizes.Word
class BootImageEchoExample extends UvmBundleTesterBase with ExtraMatchers {
override def makeMicroVM = new MicroVM(new VMConf())
preloadBundles("tests/uvm-refimpl-test/boot-image-echo.uir")
preloadHails("tests/uvm-refimpl-test/boot-image-echo.hail")
val our = new MagicalOur(microVM.globalBundle)
behavior of "The boot image echo example"
it should "write to the boot image" in {
val filename = "target/boot-image-echo.muref"
val everything = Seq("@main", "@charpp").map(idOf)
microVM.makeBootImage(everything, filename)
}
}
\ No newline at end of file
.newhybrid $hw <@charh> 14
// "Hello world!\n"
.init $hw = {{72 101 108 108 111 32 119 111 114 108 100 33 10 0}}
.init @hw = $hw
.typedef @char = int<8>
.typedef @int = int<32>
.typedef @charh = hybrid<@char>
.typedef @charr = ref<@char>
.typedef @charp = uptr<@char>
.typedef @charpp = uptr<@charp>
.funcsig @puts.sig = (@charp) -> (@int)
.typedef @puts.fp = ufuncptr<@puts.sig>
.const @puts <@puts.fp> = EXTERN "puts"
.global @hw <@charr>
.const @I32_0 <@int> = 0
.const @I32_1 <@int> = 1
.funcsig @main.sig = (@int @charpp) -> ()
.funcdef @main VERSION %1 <@main.sig> {
%entry(<@int> %argc <@charpp> %argv):
%hwr = LOAD <@charr> @hw
%hwp = COMMINST @uvm.native.pin <@charr> (%hwr)
%n = CCALL #DEFAULT <@puts.fp @puts.sig> @puts (%hwp)
COMMINST @uvm.native.unpin <@charr> (%hwr)
BRANCH %head(%argc %argv @I32_0)
%head(<@int> %argc <@charpp> %argv <@int> %i):
%inbound = SLT <@int> %i %argc
BRANCH2 %inbound %body(%argc %argv %i) %exit()
%body(<@int> %argc <@charpp> %argv <@int> %i):
%p = SHIFTIREF PTR <@charpp @int> %argv %i
%n = CCALL #DEFAULT <@puts.fp @puts.sig> @puts (%p)
%i2 = ADD <@int> %i @I32_1
BRANCH %head(%argc %argv %i2)
%exit():
COMMINST @uvm.thread_exit
}
......@@ -58,7 +58,7 @@ with tempfile.NamedTemporaryFile(delete=False) as tf:
if args.entry_point_name is not None:
entrypoint = "name {}".format(args.entry_point_name).encode("utf8")
if args.extra_libraries is not None:
extra_libraries = args.extra_libraries.encode("utf8")
extralibs = args.extra_libraries.encode("utf8")
if entrypoint is not None:
zo.writestr("entrypoint", entrypoint)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment