From 8784b7f35caa086328949813b4804d9147b52204 Mon Sep 17 00:00:00 2001 From: minjaesong Date: Sat, 14 Sep 2024 12:23:52 +0900 Subject: [PATCH] RESET and SYSRQ is now trapped by a hypervisor --- assets/disk0/tvdos/bin/command.js | 4 +- assets/disk0/tvdos/hyve.SYS | 50 ++++++++++++++----- terranmon.txt | 11 ++-- .../net/torvald/tsvm/peripheral/IOSpace.kt | 8 +-- .../src/net/torvald/tsvm/VMEmuExecutable.kt | 6 ++- tsvm_executable/src/net/torvald/tsvm/VMGUI.kt | 19 +++++-- 6 files changed, 71 insertions(+), 27 deletions(-) diff --git a/assets/disk0/tvdos/bin/command.js b/assets/disk0/tvdos/bin/command.js index d95dd33..83569a5 100644 --- a/assets/disk0/tvdos/bin/command.js +++ b/assets/disk0/tvdos/bin/command.js @@ -37,7 +37,7 @@ function print_prompt_text() { con.addch(16);con.curs_right() con.color_pair(0,253) print(" \\"+shell_pwd.join("\\").substring(1)+" ") - if (errorlevel != 0) { + if (errorlevel != 0 && errorlevel != "undefined" && errorlevel != undefined) { con.color_pair(166,253) print("["+errorlevel+"] ") } @@ -48,7 +48,7 @@ function print_prompt_text() { } else { // con.color_pair(253,255) - if (errorlevel != 0) + if (errorlevel != 0 && errorlevel != "undefined" && errorlevel != undefined) print(CURRENT_DRIVE + ":\\" + shell_pwd.join("\\") + " [" + errorlevel + "]" + PROMPT_TEXT) else print(CURRENT_DRIVE + ":\\" + shell_pwd.join("\\") + PROMPT_TEXT) diff --git a/assets/disk0/tvdos/hyve.SYS b/assets/disk0/tvdos/hyve.SYS index a42f72c..b71eeee 100644 --- a/assets/disk0/tvdos/hyve.SYS +++ b/assets/disk0/tvdos/hyve.SYS @@ -9,8 +9,7 @@ hyve is a hypervisor for tsvm. 3. hands the control over to the TVDOS until SysRq sequence is struck */ -let context = parallel.spawnNewContext() -let bios = ` +const bios = ` // probe bootable device var _BIOS = {}; @@ -24,8 +23,6 @@ _BIOS.FIRST_BOOTABLE_PORT = [0,1]; // ah screw it Object.freeze(_BIOS); -/////////////////////////////////////////////////////////////////////////////// - // load a bootsector using 'LOADBOOT' let portNumber = 0; let driveStatus = 0; @@ -54,17 +51,46 @@ else { printerrln("No bootable medium found."); } ` -let runner = parallel.attachProgram("TVDOS", context, bios) -parallel.launch(runner) -sys.sleep(1000); +let runner = undefined + +function startNewInstance() { + runner = parallel.attachProgram("TVDOS", parallel.spawnNewContext(), bios) + serial.println("Starting new instance "+runner) + parallel.launch(runner) + sys.sleep(1000) +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +// initial kickstart +startNewInstance() while (parallel.isRunning(runner)) { - graphics.plotPixel( // test fill the framebuffer to prove VM is shared - (Math.random() * 560) | 0, - (Math.random() * 448) | 0, - (Math.random() * 256) | 0 - ) + if (sys.peek(-49) >>> 7 == 1) { + sys.poke(-49, 0) + + parallel.kill(runner) + + graphics.clearText() + graphics.clearPixels(255) + + startNewInstance() + } + else if (sys.peek(-49) >>> 6 == 1) { + sys.poke(-49, 0) + + let threads = parallel.getThreadPool() + + serial.println("======================") + for (let i = 0; i < threads.size; i++) { + serial.println(`Thread #${i+1}: ${threads[i]}`) + } + serial.println("======================") + + sys.sleep(300) + } sys.sleep(0) } diff --git a/terranmon.txt b/terranmon.txt index 20891ea..e2e3b97 100644 --- a/terranmon.txt +++ b/terranmon.txt @@ -74,9 +74,10 @@ MMIO stores keys that are held down. Can accomodate 8-key rollover (in keyboard geeks' terms) 0x0 is written for the empty area; numbers are always sorted 48..51 RO: System flags - 48: 0b r000 000t + 48: 0b rq00 000t t: STOP button (should raise SIGTERM) - r: RESET button (should reset the system) + r: RESET button (hypervisor should reset the system) + q: SysRq button (hypervisor should respond to it) 64..67 RO: User area memory size in bytes 68 WO: Counter latch @@ -104,10 +105,12 @@ MMIO 90 RO: BMS calculated battery percentage where 255 is 100% 91 RO: BMS battery voltage multiplied by 10 (127 = "12.7 V") -92..127 RW: Used by the hypervisor - 1024..2047 RW: Reserved for integrated peripherals (e.g. built-in status display) +2048..4075 RW: Used by the hypervisor + 2048..2051 RW: Status flags + + 4076..4079 RW: 8-bit status code for the port 4080..4083 RO: 8-bit status code for connected device diff --git a/tsvm_core/src/net/torvald/tsvm/peripheral/IOSpace.kt b/tsvm_core/src/net/torvald/tsvm/peripheral/IOSpace.kt index a5e08f6..b129832 100644 --- a/tsvm_core/src/net/torvald/tsvm/peripheral/IOSpace.kt +++ b/tsvm_core/src/net/torvald/tsvm/peripheral/IOSpace.kt @@ -103,7 +103,7 @@ class IOSpace(val vm: VM) : PeriBase("io"), InputProcessor { 38L -> keyboardInputRequested.toInt().toByte() 39L -> rawInputFunctionLatched.toInt().toByte() in 40..47 -> keyEventBuffers[adi - 40] - 48L -> ((vm.resetDown.toInt(7)) or (vm.stopDown.toInt())).toByte() + 48L -> (vm.resetDown.toInt(7) or vm.sysrqDown.toInt(6) or vm.stopDown.toInt()).toByte() in 64..67 -> vm.memsize.shr((adi - 64) * 8).toByte() 68L -> (uptimeCounterLatched.toInt() or RTClatched.toInt(1)).toByte() @@ -116,7 +116,7 @@ class IOSpace(val vm: VM) : PeriBase("io"), InputProcessor { 89L -> ((acpiShutoff.toInt(7)) or (bmsIsBatteryOperated.toInt(3)) or (bmsHasBattery.toInt(1)) or bmsIsCharging.toInt()).toByte() - in 92L..127L -> hyveArea[addr.toInt()] + in 2048L..4075L -> hyveArea[addr.toInt() - 2048] in 1024..2047 -> peripheralFast[addr - 1024] @@ -160,7 +160,7 @@ class IOSpace(val vm: VM) : PeriBase("io"), InputProcessor { } } - private val hyveArea = ByteArray(128) + private val hyveArea = ByteArray(2048) override fun mmio_write(addr: Long, byte: Byte) { val adi = addr.toInt() @@ -190,7 +190,7 @@ class IOSpace(val vm: VM) : PeriBase("io"), InputProcessor { acpiShutoff = byte.and(-128).isNonZero() } - in 92L..127L -> hyveArea[addr.toInt()] = byte + in 2048L..4075L -> hyveArea[addr.toInt() - 2048] = byte in 1024..2047 -> peripheralFast[addr - 1024] = byte diff --git a/tsvm_executable/src/net/torvald/tsvm/VMEmuExecutable.kt b/tsvm_executable/src/net/torvald/tsvm/VMEmuExecutable.kt index 6cdf62e..d54a6dc 100644 --- a/tsvm_executable/src/net/torvald/tsvm/VMEmuExecutable.kt +++ b/tsvm_executable/src/net/torvald/tsvm/VMEmuExecutable.kt @@ -285,11 +285,13 @@ class VMEmuExecutable(val windowWidth: Int, val windowHeight: Int, var panelsX: private fun reboot(profileName: String) { val vm = currentlyLoadedProfiles[profileName]!! - vmRunners[vm.id]!!.close() + /*vmRunners[vm.id]!!.close() coroutineJobs[vm.id]!!.interrupt() vm.init() - initVMenv(vm, profileName) + initVMenv(vm, profileName)*/ + + // hypervisor will take over by monitoring MMIO addr 48 } private fun updateGame(delta: Float) { diff --git a/tsvm_executable/src/net/torvald/tsvm/VMGUI.kt b/tsvm_executable/src/net/torvald/tsvm/VMGUI.kt index a9dc54d..9fbf549 100644 --- a/tsvm_executable/src/net/torvald/tsvm/VMGUI.kt +++ b/tsvm_executable/src/net/torvald/tsvm/VMGUI.kt @@ -59,6 +59,8 @@ class VMGUI(val loaderInfo: EmulInstance, val viewportWidth: Int, val viewportHe private lateinit var crtShader: ShaderProgram + internal val whatToDoOnVmExceptionQueue = ArrayList<() -> Unit>() + fun loadShaderInline(frag0: String): ShaderProgram { // insert version code val frag: String @@ -156,7 +158,7 @@ class VMGUI(val loaderInfo: EmulInstance, val viewportWidth: Int, val viewportHe } catch (e: Throwable) { e.printStackTrace() - killVMenv() + whatToDoOnVmExceptionQueue.add { killVMenv() } } }, "VmRunner:${vm.id}") coroutineJob.start() @@ -192,10 +194,12 @@ class VMGUI(val loaderInfo: EmulInstance, val viewportWidth: Int, val viewportHe private var rebootRequested = false private fun reboot() { - vmRunner.close() + /*vmRunner.close() coroutineJob.interrupt() - init() + init()*/ + + // hypervisor will take over by monitoring MMIO addr 48 } private var updateAkku = 0.0 @@ -226,6 +230,15 @@ class VMGUI(val loaderInfo: EmulInstance, val viewportWidth: Int, val viewportHe renderGame(dt) vm.watchdogs.forEach { (_, watchdog) -> watchdog.update(dt) } + + + val vmExceptionHandlers = whatToDoOnVmExceptionQueue.toList() + vmExceptionHandlers.forEach { it.invoke() } + synchronized(whatToDoOnVmExceptionQueue) { + vmExceptionHandlers.forEach { + whatToDoOnVmExceptionQueue.remove(it) + } + } } private fun updateGame(delta: Float) {