GitLab will continue to be upgraded from 11.4.5-ce.0 on November 25th 2019 at 4.00pm (AEDT) to 5.00pm (AEDT) due to Critical Security Patch Availability. During the update, GitLab and Mattermost services will not be available.

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