diff --git a/assets/DOSBOOT.tevd b/assets/DOSBOOT.tevd index ee152ab..e564ad3 100644 Binary files a/assets/DOSBOOT.tevd and b/assets/DOSBOOT.tevd differ diff --git a/assets/DOSBOOT.tevd.original b/assets/DOSBOOT.tevd.original index 7259863..e564ad3 100644 Binary files a/assets/DOSBOOT.tevd.original and b/assets/DOSBOOT.tevd.original differ diff --git a/assets/disk0/tvdos/installer/install.js b/assets/disk0/tvdos/installer/install.js index 7907664..0893f3c 100644 --- a/assets/disk0/tvdos/installer/install.js +++ b/assets/disk0/tvdos/installer/install.js @@ -23,7 +23,17 @@ function copyFiles(destDrive) { }) // bare files in the root dir - ;["!BOOTSEC", "AUTOEXEC.BAT"].forEach((name)=>{ + ;["AUTOEXEC.BAT"].forEach((name)=>{ dos.cp(`A:\\tvdos\\installer\\${name}`, `${destDrive}:\\${name}`) }) + + // install bootloader + val bootloader = files.open("A:\\tvdos\\installer\\!BOOTSEC").sread() + let [port, poru] = _TVDOS.DRV.FS.SERIAL._toPorts(destDrive)[0] + com.sendMessage(port, "FLUSH");com.sendMessage(port, "CLOSE") + com.sendMessage(port, `NEWTEVDBOOT,${poru}`) // read-only check will be performed by the other writes + com.sendMessage(port, bootloader) + com.sendMessage(port, "FLUSH");com.sendMessage(port, "CLOSE") + + } \ No newline at end of file diff --git a/tsvm_core/src/net/torvald/tsvm/peripheral/TestDiskDrive.kt b/tsvm_core/src/net/torvald/tsvm/peripheral/TestDiskDrive.kt index 55b09f2..7852d8c 100644 --- a/tsvm_core/src/net/torvald/tsvm/peripheral/TestDiskDrive.kt +++ b/tsvm_core/src/net/torvald/tsvm/peripheral/TestDiskDrive.kt @@ -150,6 +150,16 @@ class TestDiskDrive(private val vm: VM, private val driveNum: Int, theRootPath: appendMode = false } } + else if (fileOpenMode == 17) { + if (!fileOpen) throw InternalError("Bootloader file is not open but the drive is in boot write mode") + + val inputData = if (inputData.size != BLOCK_SIZE) ByteArray(BLOCK_SIZE) { if (it < inputData.size) inputData[it] else 0 } + else inputData + + file.writeBytes(inputData) + + fileOpenMode = -1 + } else { val inputString = inputData.trimNull().toString(VM.CHARSET) @@ -311,6 +321,21 @@ class TestDiskDrive(private val vm: VM, private val driveNum: Int, theRootPath: return } } + else if (inputString.startsWith("NEWTEVDBOOT")) { + var commaIndex = 0 + while (commaIndex < inputString.length) { + if (inputString[commaIndex] == ',') break + commaIndex += 1 + } + val driveNum = if (commaIndex >= inputString.length) null else commaIndex + + // TODO driveNum is for disk drives that may have two or more slots built; for testing purposes we'll ignore it + + statusCode.set(STATE_CODE_STANDBY) + fileOpen = true + fileOpenMode = 17 + blockSendCount = 0 + } else if (inputString.startsWith("LOADBOOT")) { var commaIndex = 0 while (commaIndex < inputString.length) { diff --git a/tsvm_core/src/net/torvald/tsvm/peripheral/TevdDiskDrive.kt b/tsvm_core/src/net/torvald/tsvm/peripheral/TevdDiskDrive.kt index 39a4167..03963a8 100644 --- a/tsvm_core/src/net/torvald/tsvm/peripheral/TevdDiskDrive.kt +++ b/tsvm_core/src/net/torvald/tsvm/peripheral/TevdDiskDrive.kt @@ -14,7 +14,7 @@ import java.util.concurrent.atomic.AtomicBoolean class TevdDiskDrive(private val vm: VM, private val driveNum: Int, private val theTevdPath: String, val diskUUIDstr: String) : BlockTransferInterface(false, true) { - private val DBGPRN = false + private val DBGPRN = true val diskID: UUID = UUID.fromString(diskUUIDstr) @@ -30,8 +30,10 @@ class TevdDiskDrive(private val vm: VM, private val driveNum: Int, private val t private var fileOpenMode = -1 // 1: 'W", 2: 'A' private var file: TevdFileDescriptor = TevdFileDescriptor(DOM, "") //private var readModeLength = -1 // always 4096 - private var writeMode = false - private var appendMode = false + private val writeMode + get() = fileOpenMode == 1 + private val appendMode + get() = fileOpenMode == 2 private var writeModeLength = -1 private val messageComposeBuffer = ByteArrayOutputStream(BLOCK_SIZE) // always use this and don't alter blockSendBuffer please @@ -113,13 +115,25 @@ class TevdDiskDrive(private val vm: VM, private val driveNum: Int, private val t else if (writeMode) file.writeBytes(writeBuffer) - writeMode = false - appendMode = false + fileOpenMode = -1 printdbg("Notifying disk commit (end of write)") notifyDiskCommit() } } + else if (fileOpenMode == 17) { + if (!fileOpen) throw InternalError("Bootloader file is not open but the drive is in boot write mode") + + val inputData = if (inputData.size != BLOCK_SIZE) ByteArray(BLOCK_SIZE) { if (it < inputData.size) inputData[it] else 0 } + else inputData + + file.writeBytes(inputData) + + fileOpenMode = -1 + + printdbg("Notifying disk commit (end of bootloader write)") + notifyDiskCommit() + } else { val inputString = inputData.trimNull().toString(VM.CHARSET) @@ -131,7 +145,6 @@ class TevdDiskDrive(private val vm: VM, private val driveNum: Int, private val t file = TevdFileDescriptor(DOM, "") blockSendCount = 0 statusCode.set(TestDiskDrive.STATE_CODE_STANDBY) - writeMode = false writeModeLength = -1 } else if (inputString.startsWith("DEVSTU\u0017")) @@ -297,6 +310,27 @@ class TevdDiskDrive(private val vm: VM, private val driveNum: Int, private val t return } } + else if (inputString.startsWith("NEWTEVDBOOT")) { + var commaIndex = 0 + while (commaIndex < inputString.length) { + if (inputString[commaIndex] == ',') break + commaIndex += 1 + } + val driveNum = if (commaIndex >= inputString.length) null else commaIndex + + // TODO driveNum is for disk drives that may have two or more slots built; for testing purposes we'll ignore it + + if (DOM.isReadOnly) { + printdbg("! disk is read-only") + statusCode.set(TestDiskDrive.STATE_CODE_READ_ONLY) + return + } + + statusCode.set(TestDiskDrive.STATE_CODE_STANDBY) + fileOpen = true + fileOpenMode = 17 + blockSendCount = 0 + } else if (inputString.startsWith("LOADBOOT")) { var commaIndex = 0 while (commaIndex < inputString.length) { @@ -307,17 +341,17 @@ class TevdDiskDrive(private val vm: VM, private val driveNum: Int, private val t // TODO driveNum is for disk drives that may have two or more slots built; for testing purposes we'll ignore it - val bootFile = TevdFileDescriptor(DOM, "!BOOTSEC") + val bootFile = DOM.entries[1] - printdbg("bootFile = $bootFile, ID: ${bootFile.entryID}, exists = ${bootFile.exists()}") + printdbg("bootFile = $bootFile, ID: 1, exists = ${bootFile != null}") - if (!bootFile.exists()) { + if (bootFile == null) { printdbg("bootfile not exists!") statusCode.set(TestDiskDrive.STATE_CODE_NO_SUCH_FILE_EXISTS) return } try { - val retMsg = bootFile.getHeadBytes(BLOCK_SIZE) + val retMsg = VDUtil.getAsNormalFile(DOM, 1).getContent().sliceArray(0 until BLOCK_SIZE) printdbg("retMsg = ${retMsg.toString(VM.CHARSET)}") @@ -412,8 +446,6 @@ class TevdDiskDrive(private val vm: VM, private val driveNum: Int, private val t statusCode.set(TestDiskDrive.STATE_CODE_OPERATION_NOT_PERMITTED) return } - if (fileOpenMode == 1) { writeMode = true; appendMode = false } - else if (fileOpenMode == 2) { writeMode = false; appendMode = true } if (!file.exists()) { val f1 = file.createNewFile() statusCode.set(if (f1) TestDiskDrive.STATE_CODE_STANDBY else TestDiskDrive.STATE_CODE_OPERATION_FAILED) diff --git a/tsvm_executable/src/net/torvald/tsvm/BuildTvdosBootable.kt b/tsvm_executable/src/net/torvald/tsvm/BuildTvdosBootable.kt index d19ae71..3b68357 100644 --- a/tsvm_executable/src/net/torvald/tsvm/BuildTvdosBootable.kt +++ b/tsvm_executable/src/net/torvald/tsvm/BuildTvdosBootable.kt @@ -1,7 +1,8 @@ package net.torvald.tsvm +import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.EntryFile import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.VDUtil -import net.torvald.tsvm.VM +import net.torvald.terrarum.modulecomputers.virtualcomputer.tvd.VDUtil.checkReadOnly import java.io.File /** @@ -33,12 +34,22 @@ fun main(args: Array) { // bare file in root dir listOf( - VDUtil.importFile(File("assets/disk0/root.bootable/!BOOTSEC"), disk.generateUniqueID(), VM.CHARSET), VDUtil.importFile(File("assets/disk0/root.bootable/AUTOEXEC.BAT"), disk.generateUniqueID(), VM.CHARSET), ).forEach { VDUtil.addFile(disk, 0, it) } + VDUtil.importFile(File("assets/disk0/root.bootable/!BOOTSEC"), 1, VM.CHARSET).let { + disk.checkReadOnly() +// disk.checkCapacity(4096) + + (it.contents as EntryFile).let { file -> + val bytes = file.getContent() + bytes.appendBytes(ByteArray(4096 - bytes.size.toInt())) + } + + disk.entries[1] = it + } VDUtil.dumpToRealMachine(disk, File(args[0])) }