commit 79c00012935cdcaa58b55624137c195c897466f2
parent e46d1e91958eefe8f337e549a11235feff303f86
Author: Luxferre <lux@ferre>
Date: Sat, 13 Aug 2022 11:49:03 +0300
Correctly implemented write protection
Diffstat:
2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/README.md b/README.md
@@ -54,7 +54,7 @@ Address range|Size (bytes)|Purpose
... |varies |General purpose data (GPD) area
...-0x7dff |varies |Command buffer area
-To preserve runtime integrity, Equi implementations are allowed to (but not required to) restrict all writes to the addresses below the GPD area start. Note that command buffer area must not be write-restricted, i.e. Equi programs can be self-modifying. Also, when reading 16-bit from the area below GPD start, only the values at offsets 0x0000 (stack size), 0x0008 (CLT start address), 0x000a (GPD area start address), 0x000c (command buffer start address) and 0x000e (command buffer size) are guaranteed to be populated by the runtime in big-endian, all others will appear in the host endian byte order so the program must not rely on their values in any way.
+To preserve runtime integrity, Equi implementations are allowed to (but not required to) restrict all writes to the addresses below the GPD area start. Note that command buffer area must not be write-restricted, i.e. Equi programs can be self-modifying. Also, when reading 16-bit from the area below GPD start, only the values at offsets 0x0000 (stack size), 0x0008 (CLT start address), 0x000c (command buffer start address) and 0x000e (command buffer size) are guaranteed to be populated by the runtime in big-endian, all others will appear in the host endian byte order so the program must not rely on their values in any way. For GPD area start address, better use `G` instruction exclusively.
Equi is strictly case-sensitive: all uppercase basic Latin letters, as well as a number of special characters, are reserved for machine instructions, and all custom words must be defined in lowercase only (additionally, `_` character is allowed in the identifiers). Within comments (see below), any characters can be used.
diff --git a/equi.c b/equi.c
@@ -125,6 +125,9 @@ static struct EquiRAM ram;
/* Also create an alternative view of the same RAM area for direct offset-based access */
static uchar* flatram = (uchar *)&ram;
+/* write protection threshold RAM address */
+static ushort write_protection_threshold = 0;
+
/* Error reporting codes */
enum EquiErrors {
SUCCESS=0,
@@ -329,8 +332,11 @@ ushort persistOp(FILE *pfd, ushort maddr, ushort dataLen, ushort blk, uchar isWr
fseek(pfd, ((unsigned long) blk << 10), SEEK_SET); /* blocks are 1K-aligned */
if(isWrite) /* writing to the persistent area from the memory */
proc = (ushort) fwrite(&flatram[maddr], 1, dataLen, pfd);
- else /* reading from the persistent area into the memory */
+ else { /* reading from the persistent area into the memory */
+ if(maddr < write_protection_threshold)
+ trapout(RESTRICTED_WRITE_ERROR);
proc = (ushort) fread(&flatram[maddr], 1, dataLen, pfd);
+ }
if(proc != dataLen)
status = PERSIST_IO_ERROR;
}
@@ -459,6 +465,8 @@ void equi_main_loop() {
case INS_STORE: /* main stack -> mem (word) */
pbuf = popMain();
pbuf2 = popMain();
+ if(pbuf < write_protection_threshold)
+ trapout(RESTRICTED_WRITE_ERROR);
flatram[pbuf] = pbuf2 >> 8U;
flatram[pbuf + 1U] = pbuf2 & 255U;
break;
@@ -614,6 +622,7 @@ int main(int argc, char* argv[]) {
ram.cmd_start = (uchar *)&ram.cmdbuf - (uchar *)&ram.stack_size;
ram.cmd_size = CMD_BUF_SIZE;
ram.II = ram.CM = ram.IM = ram.MM = 0; /* reset all flags */
+ write_protection_threshold = ram.gpd_start; /* setup write protection */
/* process command line params */
if(argc > 1 && argv[1][0] == 'm') /* enter minification mode, don't run the programs */
ram.MM = 1;
@@ -638,7 +647,6 @@ int main(int argc, char* argv[]) {
if(host_islittle) {
ram.stack_size = tobig(ram.stack_size);
ram.clt_start = tobig(ram.clt_start);
- ram.gpd_start = tobig(ram.gpd_start);
ram.cmd_start = tobig(ram.cmd_start);
ram.cmd_size = tobig(ram.cmd_size);
}