diff --git a/.gitignore b/.gitignore index b973370..6407c51 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -*.velx /.doc .ktmp -debug.lua +/build/** diff --git a/build.lua b/build.lua index 0647514..c089ff7 100644 --- a/build.lua +++ b/build.lua @@ -1,3 +1,6 @@ +os.execute("mkdir -p build") +os.execute("rm -rf build/*") + --[[---------------------------------------------------------------------------- LZSS - encoder / decoder This is free and unencumbered software released into the public domain. @@ -158,45 +161,78 @@ local velx_spec = struct { {ssize="I3"}, {rsize="I4"} } +local actions = {} + +function actions.kernel() + -- This builds Tsuki into a VELX executable. + os.execute("mkdir -p build/kernel") + print("Compiling kernel...") + local h = io.popen("luacomp ksrc/init.lua", "r") + local krnl = h:read("*a") + h:close() + os.execute("luacomp ksrc/init.lua -O build/kernel/debug.lua 2>/dev/null") + print("Generating docs and stripping comments...") + os.execute("mkdir .docs") + h = io.popen("lua utils/gendocs.lua .docs 2>.ktmp", "w") + h:write(krnl) + h:close() + h = io.popen("find .docs -depth | tsar -o", "r") + local arc = h:read("*a") + h:close() + h = io.open(".ktmp", "rb") + local data = h:read("*a") + h:close() + print("Compressing kernel...") + data = M.compress(data) + print("Writing out tkrnl.velx...") + local h = io.open("build/kernel/tkrnl.velx", "wb") + local header = velx_spec({ + magic = "\27VelX", + compression = 1, + lver = 0x53, + fver = 1, + os = 0x7F, + psize = #data, + lsize=0, + ssize=0, + rsize=#arc, + arctype="tsar" + }) + h:write(header) + h:write(data) + h:write(arc) + h:close() +end + +function actions.crescent() + os.execute("mkdir -p build/crescent") + os.execute("cd extras; lua ../utils/mkvelx.lua crescent/init.lua ../build/crescent/boot.velx") + os.execute("cp extras/crescent/bootvelxloader.lua build/crescent/init.lua") +end + +function actions.velxboot() + os.execute("mkdir -p build/velxboot") + os.execute("cd extras; luacomp velxboot/init.lua -O ../build/velxboot/bios.lua") + os.execute("cd extras; luacomp velxboot/flashvelxboot.lua -O ../build/velxboot/flashvelxboot.lua") +end + +function actions.clean() + print("Cleaning up...") + os.execute("rm -rf .docs") + os.execute("rm -rf .ktmp") +end + +function actions.all() + actions.kernel() + actions.crescent() + actions.velxboot() + actions.clean() +end + +if not arg[1] then + arg[1] = "all" +end + +actions[arg[1]]() --- This builds Tsuki into a VELX executable. -print("Compiling kernel...") -local h = io.popen("luacomp ksrc/init.lua", "r") -local krnl = h:read("*a") -h:close() -os.execute("luacomp ksrc/init.lua -O debug.lua 2>/dev/null") -print("Generating docs and stripping comments...") -os.execute("mkdir .docs") -h = io.popen("lua utils/gendocs.lua .docs 2>.ktmp", "w") -h:write(krnl) -h:close() -h = io.popen("find .docs -depth | tsar -o", "r") -local arc = h:read("*a") -h:close() -h = io.open(".ktmp", "rb") -local data = h:read("*a") -h:close() -print("Compressing kernel...") -data = M.compress(data) -print("Writing out tkrnl.velx...") -local h = io.open("tkrnl.velx", "wb") -local header = velx_spec({ - magic = "\27VelX", - compression = 1, - lver = 0x53, - fver = 1, - os = 0x7F, - psize = #data, - lsize=0, - ssize=0, - rsize=#arc, - arctype="tsar" -}) -h:write(header) -h:write(data) -h:write(arc) -h:close() -print("Cleaning up...") -os.execute("rm -rf .docs") -os.execute("rm -rf .ktmp") print("Build complete.") \ No newline at end of file diff --git a/debug.lua b/debug.lua new file mode 100644 index 0000000..9a7d096 --- /dev/null +++ b/debug.lua @@ -0,0 +1,324 @@ + +function struct(tbl) + local pat = tbl.endian or "=" + local args = {} + for i=1, do + local a, b = pairs(tbl[i]) + local k, v = a(b) + args[i] = k + pat = pat .. v + end + return setmetatable({}, {__call=function(_, arg) + checkArg(1, arg, "string", "table") + if (type(arg) == "string") then + local sval = {string.unpack(pat, arg)} + local rtn = {} + for i=1, #args do + rtn[args[i]] = sval[i] + end + return rtn, sval[#sval] + elseif (type(arg) == "table") then + local sval = {} + for i=1, #args do + sval[i] = arg[args[i]] + end + return string.pack(pat, unpack(sval)) + end + end, __len=function() + return string.packsize(pat) + end}) +end + +function string.trim(self) + return self:gsub("^%s+", ""):gsub("%s+$", "") +end + +function string.explode(self, pat) + local t, ll + t={} + ll=0 + if(#p == 1) then + return {p} + end + while true do + l = string.find(self, pat, ll, true) -- find the next d in the string + if l ~= nil then -- if "not not" found then.. + table.insert(t, string.sub(self,ll,l-1)) -- Save it in our array. + ll = l + 1 -- save just after where we found it for searching next time. + else + table.insert(t, string.sub(self,ll)) -- Save what's left in our array. + break -- Break at end, as it should be, according to the lua manual. + end + end + return t +end + + + +---@module security Security +local security = {} + +---@func checkacl +---@arg permission string "The permission to check." +---@return boolean "True if the current process has this permission." +function security.checkacl(permission) + local perms = acl.get("group", thread.info().egid, {}) +end + +---@func getmode +---@return string "The current security mode." +function security.getmode() + +end + +function security.init() + klog("security", 1, "Security init started.") + +end + + + +local velx = (function() + + +local velx_spec = struct { + endian = "<", + {magic="c5"}, + {fver="B"}, + {compression="B"}, + {lver="B"}, + {os="B"}, + {psize="I3"}, + {lsize="I3"}, + {ssize="I3"}, + {rsize="I4"} +} + +local velx = {} + +local exec = {} + +function velx.identify(path) + local h = io.open(path, "rb") + local header = velx_spec(h:read(#velx_spec)) + h:close() + return header.magic == "\27VelX" +end + +function velx.load(path) + +end + +function velx.verify(path) + local h = io.open(path, "rb") + local header = velx_spec(h:read(#velx_spec)) + local code = h:read(header.psize) + h:seek("cur", lsize) + local sig = h:read(header.ssize) + h:close() + return security.verify(code, sig) +end + +function exec:link() + self.file:seek("set", #velx_spec+self.header.psize) + local linkinfo = self.file:read(self.header.lsize) + local linker = {} + local pos = 1 + while true do + local size = string.unpack(">k&1<1 and b<#a then +i=c.unpack('>I2',a,b)j=1+(i>>4)g=h(d,j,j+(i&15)+2)b=b+1 +end +b=b+1 +c=c..g +d=h(d..g,-4^6)end +end +return c end + +local drive, part = eeprom.getData():match("^([%x%-]+);(%d)$") +part = tonumber(part) + diff --git a/extras/crescent/bootvelxloader.lua b/extras/crescent/bootvelxloader.lua new file mode 100644 index 0000000..ca85015 --- /dev/null +++ b/extras/crescent/bootvelxloader.lua @@ -0,0 +1,16 @@ +local fs = component.proxy(computer.getBootAddress()) +local f = fs.open("boot.velx") +fs.seek(f, "set", 14) +local psize = string.unpack("" +end +local function read_header(dat) + local e = get_end(en) + local m = string.unpack(e.."I2", dat) + if m ~= magic and m ~= magic_rev then return nil, "bad magic" end + if m ~= magic then + e = get_end(not en) + end + local ent = {} + ent.magic, ent.namesize, ent.mode, ent.uid, ent.gid, ent.filesize, ent.mtime = string.unpack(e..header_fmt, dat) + return ent +end + +local arc = {} + +function arc:fetch(path) + for i=1, #self.tbl do + if (self.tbl[i].name == path and self.tbl[i].mode & 32768 > 0) then + self.seek(self.tbl[i].pos-self.seek(0)) + return self.read(self.tbl[i].filesize), self.tbl[i] + end + end + return nil, "file not found" +end + +function arc:exists(path) + for i=1, #self.tbl do + if (self.tbl[i].name == path) then + return true + end + end + return false +end + +function arc:list(path) + if path:sub(#path) ~= "/" then path = path .. "/" end + local ent = {} + for i=1, #self.tbl do + if (self.tbl[i].name:sub(1, #path) == path and not self.tbl[i].name:find("/", #path+1, false)) then + ent[#ent+1] = self.tbl[i].name + end + end + return ent +end + +function arc:close() + self.close() +end + +function load_tsar(addr, path) + local fs = component.proxy(addr) + local h = fs.open(path) + status("loading initramfs... "..lsc()) + local dat = "" + local buf = "" + repeat + buf = fs.read(h, math.huge) + if (buf) then + dat = dat .. buf + end + y = y - 1 + status("loading initramfs... "..lsc()) + until not buf or buf == "" + local idx = 1 + local function read(a) + local dat = buf:sub(idx, idx+a-1) + idx = idx + a + return dat + end + local function seek(a) + idx = idx + a + return idx + end + local function close()end + local tbl = {} + local lname = "" + while lname ~= "TRAILER!!!" do + y = y - 1 + status("loading initramfs... "..lsc()) + local dat = read(22) + local et = read_header(dat) + et.name = read(et.namesize) + et.pos = seek(et.namesize & 1) + seek(et.filesize + (et.filesize & 1)) + lname = et.name + if lname ~= "TRAILER!!!" then + tbl[#tbl+1] = et + end + end + return setmetatable({tbl = tbl, read = read, seek = seek, close = close}, {__index=arc}) +end diff --git a/extras/crescent/velx.lua b/extras/crescent/velx.lua index 98149da..9c6945a 100644 --- a/extras/crescent/velx.lua +++ b/extras/crescent/velx.lua @@ -34,6 +34,9 @@ local function load_velx(addr, path) status("loading kernel... ") if (comp == 1) then status("decompressing kernel...") - buf = lzss_decompress(buf) + dat = lzss_decompress(dat) end + local env = {} + env._G = env + return load(dat, "="..path, "t", setmetatable(env, {__index=_G})), env end \ No newline at end of file diff --git a/extras/velxboot/flashvelxboot.lua b/extras/velxboot/flashvelxboot.lua new file mode 100644 index 0000000..6c67591 --- /dev/null +++ b/extras/velxboot/flashvelxboot.lua @@ -0,0 +1,72 @@ +local component = require("component") +local computer = require("computer") +print("Flashing velxboot...") +component.eeprom.set([[ +--#include "velxboot/init.lua" +]]) +component.eeprom.setData(computer.getBootAddress()..";boot.velx") +print("Creating boot.velx...") +local f = io.open("/init.lua") +local prog = f:read("*a") +f:close() + +local function struct(tbl) + local pat = tbl.endian or "=" + local args = {} + for i=1, #tbl do + local a, b = pairs(tbl[i]) + local k, v = a(b) + args[i] = k + pat = pat .. v + end + return setmetatable({}, {__call=function(_, arg) + --checkArg(1, arg, "string", "table") + if (type(arg) == "string") then + local sval = {string.unpack(pat, arg)} + local rtn = {} + for i=1, #args do + rtn[args[i]] = sval[i] + end + return rtn, sval[#sval] + elseif (type(arg) == "table") then + local sval = {} + for i=1, #args do + sval[i] = arg[args[i]] + end + return string.pack(pat, unpack(sval)) + end + end, __len=function() + return string.packsize(pat) + end}) +end + + +local velx_spec = struct { + endian = "<", + {magic="c5"}, + {fver="B"}, + {compression="B"}, + {lver="B"}, + {os="B"}, + {arctype="c4"}, + {psize="I3"}, + {lsize="I3"}, + {ssize="I3"}, + {rsize="I4"} +} + +f = io.open("/boot.velx", "wb") +f:write(velx_spec({ + magic="\27VelX", + fver=1, + compression=0, + lver=0x53, + os=127, + arctype="", + psize=#prog + lsize=0, + ssize=0, + rsize=0, +})) +f:write(prog) +f:close() \ No newline at end of file diff --git a/extras/velxboot/init.lua b/extras/velxboot/init.lua index 5523bf8..6f79a81 100644 --- a/extras/velxboot/init.lua +++ b/extras/velxboot/init.lua @@ -1,3 +1,4 @@ +local eeprom = component.proxy(component.list("eeprom")()) local function lzss_decompress(a)local b,c,d,e,j,i,h,g=1,'',''while b<=#a do e=c.byte(a,b)b=b+1 for k=0,7 do h=c.sub @@ -27,12 +28,26 @@ local function boot_velx(addr, path) rdat = psize - #dat until rdat == 0 or not buf or buf == "" if (comp == 1) then - buf = lzss_decompress(buf) + dat = lzss_decompress(dat) end - assert(load(buf, "="..path))() + local baddr = addr + local bpath = path + function computer.getBootAddress() + return baddr + end + function computer.getBootPath() + return bpath + end + function computer.setBootAddress(a) + eeprom.setData(a..";"..path) + addr = a + end + function computer.setBootPath(p) + eeprom.setData(addr..";"..p) + path = p + end + assert(load(dat, "="..path))() end - -local eeprom = component.proxy(component.list("eeprom")()) local config = eeprom.getData() local addr, path = config:match("^(.+);(.+)$") if not addr then diff --git a/ksrc/blk/eeprom.lua b/ksrc/blk/eeprom.lua new file mode 100644 index 0000000..e69de29 diff --git a/ksrc/blk/hdd.lua b/ksrc/blk/hdd.lua new file mode 100644 index 0000000..e69de29 diff --git a/ksrc/blk/partition.lua b/ksrc/blk/partition.lua new file mode 100644 index 0000000..e69de29 diff --git a/ksrc/blk/promcard.lua b/ksrc/blk/promcard.lua new file mode 100644 index 0000000..e69de29 diff --git a/utils/mkvelx.lua b/utils/mkvelx.lua new file mode 100644 index 0000000..05825f0 --- /dev/null +++ b/utils/mkvelx.lua @@ -0,0 +1,64 @@ +local f = io.popen("luacomp "..arg[1], "r") +local prog = f:read("*a") +f:close() + +local function struct(tbl) + local pat = tbl.endian or "=" + local args = {} + for i=1, #tbl do + local a, b = pairs(tbl[i]) + local k, v = a(b) + args[i] = k + pat = pat .. v + end + return setmetatable({}, {__call=function(_, arg) + --checkArg(1, arg, "string", "table") + if (type(arg) == "string") then + local sval = {string.unpack(pat, arg)} + local rtn = {} + for i=1, #args do + rtn[args[i]] = sval[i] + end + return rtn, sval[#sval] + elseif (type(arg) == "table") then + local sval = {} + for i=1, #args do + sval[i] = arg[args[i]] + end + return string.pack(pat, unpack(sval)) + end + end, __len=function() + return string.packsize(pat) + end}) +end + + +local velx_spec = struct { + endian = "<", + {magic="c5"}, + {fver="B"}, + {compression="B"}, + {lver="B"}, + {os="B"}, + {arctype="c4"}, + {psize="I3"}, + {lsize="I3"}, + {ssize="I3"}, + {rsize="I4"} +} + +f = io.open(arg[2], "wb") +f:write(velx_spec({ + magic="\27VelX", + fver=1, + compression=0, + lver=0x53, + os=127, + arctype="", + psize=#prog, + lsize=0, + ssize=0, + rsize=0, +})) +f:write(prog) +f:close() \ No newline at end of file diff --git a/utils/velxdump.lua b/utils/velxdump.lua index 9fc3ebf..36c994d 100644 --- a/utils/velxdump.lua +++ b/utils/velxdump.lua @@ -195,9 +195,11 @@ compression[header.compression] or "Unknown", os[header.os & 0x7F] or "Unknown", lver, header.arctype:gsub("\0", "")),"\n") -local h = io.popen(commands[header.arctype:gsub("\0", "")], "w") -h:write(archive) -h:close() +if (header.arctype ~= "\0\0\0\0" and archive ~= "") then + local h = io.popen(commands[header.arctype:gsub("\0", "")], "w") + h:write(archive) + h:close() +end if (header.compression == 1) then io.stderr:write(M.decompress(program)) elseif (header.compression == 0) then