super dupper system update (it runs)

This commit is contained in:
2026-01-14 14:11:50 -08:00
parent 9b268810a7
commit 4b2be8be44
332 changed files with 46911 additions and 9123 deletions

BIN
Build.tar Normal file

Binary file not shown.

View File

@@ -1,20 +0,0 @@
local args={...}
local os=require("os")
local io=require("io")
local text=""
local blockKeyEvents=false
io.link(io.focas)
os.hookSignal("keyTyped", function(_, screen, key)
if blockKeyEvents then return end
if key == "\n" then
blockKeyEvents=true
elseif key == "\b" then
text=text:sub(1,#text-1)
io.stdout.printInline("\b")
else
text=text..key
io.stdout.printInline(key)
end
end)

17
Build/bin/neofetch Normal file
View File

@@ -0,0 +1,17 @@
print(".. *. ..")
print(" *= +@* +* ")
print(" .@#. -@@@= :#@. ")
print(" =@@+ *@@@# +@@= ")
print(" %@@%: *@@@# -%@@% ")
print(" :@@@@+ *@@@# .*@@@@: ")
print(" :*@@@%- *@@@# -@@@@*: ")
print(" =%@@#. *@@@# .#@@%= ")
print(" :=. :*@@= *@@@# =@@+: .=: ")
print(" %@#=..*# +@@@# #*..=#@# ")
print(" .@@@@+=# .%@%: #=+@@@@. ")
print(" .....=# -@= *+...:. ")
print(" -*%*-@= - =@-*%*- ")
print(" -@*. -@%. :%@- :*@- ")
print(" .#@#@* ")
print(" -#- ")
print(" ")

View File

@@ -0,0 +1 @@
print("hello from hello.lua")

View File

@@ -1,3 +1,4 @@
local BOOT_DRIVE_PATH="/$"
local term = term local term = term
local os = os local os = os
-- Function to write text to the terminal with special character handling -- Function to write text to the terminal with special character handling
@@ -100,6 +101,7 @@ local ok, err = xpcall(function()
} }
-- Move all non-Lua standard library globals into the apis table -- Move all non-Lua standard library globals into the apis table
local debug = debug
for i,v in pairs(_G) do for i,v in pairs(_G) do
if not lua[i] or lua[i]==nil then if not lua[i] or lua[i]==nil then
apis[i]=v apis[i]=v
@@ -107,6 +109,11 @@ local ok, err = xpcall(function()
end end
end end
function sleep(time)
local stoptime = apis.os.clock() + (time)
while stoptime > apis.os.clock() do end
end
-- Set up terminal default colors -- Set up terminal default colors
apis.term.setPaletteColor(0x1, 0x000000) -- #000000 apis.term.setPaletteColor(0x1, 0x000000) -- #000000
apis.term.setPaletteColor(0x2, 0xFFFFFF) -- #FFFFFF apis.term.setPaletteColor(0x2, 0xFFFFFF) -- #FFFFFF
@@ -135,9 +142,9 @@ local ok, err = xpcall(function()
end end
-- Load kernel first if it fails, we can't continue so we display an error -- Load kernel first if it fails, we can't continue so we display an error
local Kernel = load(getFile("/$/boot/kernel.lua"),"@Kernel") local Kernel = load(getFile(BOOT_DRIVE_PATH.."/boot/kernel.lua"),"@Kernel")
local initFs = load(getFile("/$/boot/cct/initdisks","@Init_disks"))(apis) local initFs = load(getFile(BOOT_DRIVE_PATH.."/boot/cct/initdisks","@Init_disks"))(apis)
local fs = load(getFile("/$/boot/initfs"),"@InitFs")() local fs = load(getFile(BOOT_DRIVE_PATH.."/boot/initfs"),"@InitFs")()
if not Kernel then if not Kernel then
displaySuperBadError("Could not load kernel.") displaySuperBadError("Could not load kernel.")
end end
@@ -163,7 +170,7 @@ local ok, err = xpcall(function()
-- Set up computer api -- Set up computer api
local computer = { local computer = {
time = function() return apis.os.epoch("utc") end, time = function() return apis.os.epoch("utc") end,
clock = apis.os.clock, clock = function() return apis.os.clock()/1000 end,
shutdown = apis.os.shutdown, shutdown = apis.os.shutdown,
reboot = apis.os.reboot, reboot = apis.os.reboot,
getMachineEvent = function() getMachineEvent = function()
@@ -255,13 +262,13 @@ local ok, err = xpcall(function()
end end
end, "", 1000) end, "", 1000)
local ret = {coroutine.resume(co, ...)} local ret = {coroutine.resume(co, ...)}
if ret[1]=="timeout" then if ret[1] and ret[2]=="timeout" then
return nil, "Coroutine timed out" return "timeout"
elseif ret[1]==false then elseif ret[1]==false then
return false, ret[2] return "error", ret[2]
else else
debug.sethook(co) debug.sethook(co)
return true, table.unpack(ret) return "success", table.unpack(ret, 2)
end end
end end
@@ -291,12 +298,13 @@ local ok, err = xpcall(function()
exit=true exit=true
end end
end end
if status == false or coroutine.status(kernelCoro)=="dead" then if status == "error" or coroutine.status(kernelCoro)=="dead" then
displaySuperBadError("Kernel error: "..tostring(err)) displaySuperBadError("Kernel error: "..tostring(err))
coroutine.yield("key") coroutine.yield("key")
end end
end end
end, debug.traceback) end, debug.traceback)
if not ok then if not ok then
displaySuperBadError("Fatal error during boot: "..err) displaySuperBadError("Fatal error during boot: "..err)
end end

View File

@@ -1,3 +1,5 @@
sleep(1)
local BOOT_DRIVE_PATH="/$"
-- UnBIOS by JackMacWindows -- UnBIOS by JackMacWindows
-- This will undo most of the changes/additions made in the BIOS, but some things may remain wrapped if `debug` is unavailable -- This will undo most of the changes/additions made in the BIOS, but some things may remain wrapped if `debug` is unavailable
-- To use, just place a `bios.lua` in the root of the drive, and run this program -- To use, just place a `bios.lua` in the root of the drive, and run this program
@@ -58,7 +60,7 @@ function _G.term.native()
term.setCursorPos(1, 1) term.setCursorPos(1, 1)
term.setCursorBlink(true) term.setCursorBlink(true)
term.clear() term.clear()
local file = fs.open("/$/boot/cct/boot.lua", "r") local file = fs.open(BOOT_DRIVE_PATH.."/boot/cct/boot.lua", "r")
if file == nil then if file == nil then
term.setCursorBlink(false) term.setCursorBlink(false)
term.setTextColor(16384) term.setTextColor(16384)

View File

@@ -1,4 +1,5 @@
local apis = ({...})[1] local apis = ({...})[1]
local BOOT_DRIVE_PATH="/$"
local fs = apis.fs local fs = apis.fs
local native = apis.peripheral local native = apis.peripheral
local peripheral = {} local peripheral = {}
@@ -62,33 +63,6 @@ local function createDisk(id, basePath, readonly, periph)
return fs.getCapacity(basePath) return fs.getCapacity(basePath)
end end
function disk:readAllText(path)
local p = fs.combine(basePath, path)
if not fs.exists(p) then return nil, "file not found" end
local h = fs.open(p, "r")
local t = h.readAll()
h.close()
return t
end
function disk:writeAllText(path, text)
local p = fs.combine(basePath, path)
local h = fs.open(p, "w")
if not h then return nil, "cannot write" end
h.write(text)
h.close()
return true
end
function disk:appendAllText(path, text)
local p = fs.combine(basePath, path)
local h = fs.open(p, "a")
if not h then return nil, "cannot append" end
h.write(text)
h.close()
return true
end
function disk:list(path) function disk:list(path)
local p = fs.combine(basePath, path) local p = fs.combine(basePath, path)
if not fs.exists(p) or not fs.isDir(p) then return nil, "not directory" end if not fs.exists(p) or not fs.isDir(p) then return nil, "not directory" end
@@ -105,6 +79,17 @@ local function createDisk(id, basePath, readonly, periph)
return fs.exists(p) and fs.isDir(p) return fs.exists(p) and fs.isDir(p)
end end
function disk:type(path)
local p = fs.combine(basePath, path)
if not fs.exists(p) then
return nil
elseif fs.isDir(p) then
return "directory"
else
return "file"
end
end
function disk:makeDirectory(path) function disk:makeDirectory(path)
local p = fs.combine(basePath, path) local p = fs.combine(basePath, path)
fs.makeDir(p) fs.makeDir(p)
@@ -125,9 +110,14 @@ local function createDisk(id, basePath, readonly, periph)
return periph.getLabel() return periph.getLabel()
end end
function disk:size(path) function disk:attributes(path)
local p = fs.combine(basePath, path) local p = fs.combine(basePath, path)
return fs.getSize(p) return fs.attributes(p)
end
function disk:open(path, mode)
local p = fs.combine(basePath, path)
return fs.open(p, mode)
end end
return disk return disk
@@ -136,7 +126,7 @@ end
--------------------------------------------------------- ---------------------------------------------------------
-- INTERNAL DISK "$" (mapped to "/") -- INTERNAL DISK "$" (mapped to "/")
--------------------------------------------------------- ---------------------------------------------------------
internal["$"] = createDisk("$", "/$", false, { internal["$"] = createDisk("$", BOOT_DRIVE_PATH, false, {
setLabel=function(label) setLabel=function(label)
local h = fs.open("/.label", "w") local h = fs.open("/.label", "w")
h.write(label) h.write(label)

2
Build/boot/fstab Normal file
View File

@@ -0,0 +1,2 @@
U $;/
U devfs0000;/dev/

View File

@@ -49,15 +49,23 @@ function fs.remove(path)
end end
function fs.readAllText(path) function fs.readAllText(path)
local disk, newPath = resolve(path) local disk, newPath = resolve(path)
return disk:readAllText(newPath) local handle = disk:open(newPath, "r")
if not handle then return nil end
local content = handle.readAll()
handle.close()
return content
end end
function fs.writeAllText(path, text) function fs.writeAllText(path, text)
local disk, newPath = resolve(path) local disk, newPath = resolve(path)
return disk:writeAllText(newPath, text) local handle = disk:open(newPath, "w")
handle.write(text)
handle.close()
end end
function fs.appendAllText(path, text) function fs.appendAllText(path, text)
local disk, newPath = resolve(path) local disk, newPath = resolve(path)
return disk:appendAllText(newPath, text) local handle = disk:open(newPath, "a")
handle.write(text)
handle.close()
end end
function fs.load(path) function fs.load(path)
return load(fs.readAllText(path), path) return load(fs.readAllText(path), path)

View File

@@ -2,7 +2,6 @@ local args = {...}
local apis = args[1] local apis = args[1]
local disks = args[2] local disks = args[2]
local arch = args[3] local arch = args[3]
local initPath = args[4]
local screen = args[5] local screen = args[5]
local computer = args[6] local computer = args[6]
local ifs = args[7] local ifs = args[7]
@@ -19,12 +18,22 @@ kernel.key = {}
kernel.cache = {} kernel.cache = {}
kernel.cache.preload = {} kernel.cache.preload = {}
kernel._G=_G kernel._G=_G
kernel.sleep=sleep
kernel.debug=true
_G.sleep=nil
local windowsExp = false local windowsExp = false
function kernel.log(msg, level) function kernel.log(msg, level)
LOG_Text = LOG_Text..tostring(computer.time()).." "..kernel.user.." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg.."\n" LOG_Text = LOG_Text..tostring(computer:time()).." "..kernel.user.." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg.."\n"
if kernel.status == "start" then if kernel.status == "start" then
screen:print(tostring(computer.time()).." "..kernel.user.." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg) screen:print(tostring(computer:time()).." "..kernel.user.." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg)
elseif kernel.status == "init" then
kernel.standbyTask=kernel.currentTask
kernel.currentTask=kernel.kernelTask
kernel.tty.print(tostring(computer:time()).." "..kernel.user.." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg)
kernel.currentTask=kernel.standbyTask
end end
end end
@@ -74,9 +83,13 @@ kernel.log("Kernel loaded.")
kernel.log("Mounting init disks...") kernel.log("Mounting init disks...")
disks.refresh() disks.refresh()
ifs.update(disks) ifs.update(disks)
kernel.disks={}
for _,v in disks.list() do
kernel.disks[v.address] = v
end
ifs.mount("$", "/") ifs.mount("$", "/")
local fstab=ifs.readAllText("/etc/fstab") local fstab=ifs.readAllText("/boot/fstab")
local split = function(str, delim, maxResultCountOrNil) local split = function(str, delim, maxResultCountOrNil)
assert(#delim == 1, "only delim len 1 supported for now") assert(#delim == 1, "only delim len 1 supported for now")
maxResultCountOrNil = (maxResultCountOrNil or 0)-1 maxResultCountOrNil = (maxResultCountOrNil or 0)-1
@@ -95,6 +108,33 @@ local split = function(str, delim, maxResultCountOrNil)
return rv return rv
end end
if not ifs.isFile("/boot/boot.cfg") then
kernel.log("boot.cfg missing or corrupted!, Attempting to write recovery boot.cfg", "ERROR")
ifs.writeAllText("/boot/boot.cfg",[[
-- DO NOT EDIT THIS FILE IF YOU DO NOT KNOW WHAT YOU ARE DOING!
-- DOING SO MAY RENDER YOUR SYSTEM UNBOOTABLE!
-- This file is auto-generated during the build process.
-- RECOVERY BOOT CONFIGURATION FILE
return {
initPath = "/sbin/init.lua",
maxOpenFiles = 128,
maxFilesPerTask = 16,
preempt=true
}
]])
end
local initCfgFunc, err = load(ifs.readAllText("/boot/boot.cfg"), "@boot.cfg")
if not initCfgFunc then
kernel.PANIC("Failed to load /boot/boot.cfg: "..tostring(err))
end
local initCfgStatus, config = pcall(initCfgFunc)
if not initCfgStatus then
kernel.PANIC("Error in /boot/boot.cfg: "..tostring(config))
end
kernel.config = config
for i,v in ipairs(split(fstab,"\n")) do for i,v in ipairs(split(fstab,"\n")) do
if v:sub(1,1)=="U" then if v:sub(1,1)=="U" then
local id="" local id=""
@@ -118,47 +158,94 @@ end
ifs.remove("/tmp") ifs.remove("/tmp")
ifs.makeDir("/tmp") ifs.makeDir("/tmp")
local drivers={} function kernel.newFifo()
drivers.raw={} local fifo = {}
drivers.processes={} fifo.push=function(data)
drivers.type={} table.insert(data)
end
function drivers.register(object) fifo.pop=function()
drivers.raw[#drivers.raw+1]=object return table.remove(fifo,1)
if object.main then drivers.processes[#drivers.processes+1]=object.main end end
if drivers.type[object.type]==nil then drivers.type[object.type]={} end return fifo
drivers.type[object.type][#drivers.type[object.type]+1]=object
end end
function kernel.newUUID()
local template = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"
local uuid = ""
for i = 1, #template do
local c = template:sub(i,i)
if c == "x" then
uuid = uuid .. string.format("%x", math.random(0, 15))
elseif c == "y" then
uuid = uuid .. string.format("%x", math.random(8, 11))
else
uuid = uuid .. c
end
end
return uuid
end
kernel.syscalls={}
local modules={[0]={}} local modules={[0]={}}
for i=0, 100 do for i=0, 100 do
modules[i]={} modules[i]={}
end end
kernel.log("Gathering modules") kernel.log("Gathering modules")
for i,v in ipairs(ifs.list("/lib/modules/Hyperion/")) do for _, i in ipairs(ifs.list("/lib/modules")) do
for _,v in ipairs(ifs.list("/lib/modules/"..i)) do
local prior=tonumber(v:sub(1,2)) local prior=tonumber(v:sub(1,2))
modules[prior+1][#modules[prior+1]+1]="/lib/modules/Hyperion/"..v modules[prior+1][#modules[prior+1]+1]="/lib/modules/"..i.."/"..v
end
end end
kernel.drivers=drivers
kernel.ifs=ifs kernel.ifs=ifs
kernel.apis=apis kernel.apis=apis
kernel.computer=computer kernel.computer=computer
kernel.initPath=initPath
kernel.arch=arch kernel.arch=arch
kernel.initdisks=disks kernel.initdisks=disks
kernel.screen=screen kernel.screen=screen
kernel.processes={}
kernel.fstab=fstab
kernel.kernelTask = {
name="kernel",
status="R",
pid=0,
tgid=0,
user="root",
uid=0,
fd={},
exit="",
sleep=0,
ivs=0,
vs=0,
children={},
syscallReturn={},
cwd="/",
timeSlice=0,
lastTime=0,
totalTime=0,
numRuns=0
}
kernel.currentTask = kernel.kernelTask
kernel.log("Running modules") kernel.log("Running modules")
for _,p in ipairs(modules) do for _,p in ipairs(modules) do
for _,v in ipairs(p) do for _,v in ipairs(p) do
local code=ifs.readAllText(v) local code=ifs.readAllText(v)
if not code then
kernel.log("ModuReadErr: "..v, "WARN")
goto skip
end
local func,err=load(code,"@"..v) local func,err=load(code,"@"..v)
if not func then kernel.log("ModuLoadErr: "..tostring(err), "WARN") goto skip end if not func then kernel.panic("ModuLoadErr: "..tostring(err)) goto skip end
local status, err = xpcall(func,debug.traceback, kernel) local status, err = xpcall(func,debug.traceback, kernel)
if not status then kernel.log("ModuRunErr: "..tostring(err), "WARN") end if not status then kernel.panic("ModuRunErr: "..tostring(err)) end
::skip:: ::skip::
end end
end end
kernel.log("Kernel initialized successfully.")
kernel.main()
kernel.PANIC("Execution complete") kernel.PANIC("Execution complete")

View File

@@ -1,3 +0,0 @@
U $;/
U devfs0000;/dev/
U sysfs0000;/sys/

151
Build/lib/bit32 Normal file
View File

@@ -0,0 +1,151 @@
-- bit32.lua
-- Full pure-Lua implementation of Lua 5.2 bit32 library
-- NO Lua 5.3 operators used
local bit32 = {}
local MOD32 = 2^32
local MOD31 = 2^31
local function norm(x)
return x % MOD32
end
-- Convert number to bit table
local function tobits(x)
x = norm(x)
local t = {}
for i = 0, 31 do
local b = x % 2
t[i] = b
x = (x - b) / 2
end
return t
end
-- Convert bit table to number
local function frombits(t)
local x = 0
local p = 1
for i = 0, 31 do
if t[i] == 1 then
x = x + p
end
p = p * 2
end
return norm(x)
end
-- ===== Logical ops =====
function bit32.band(...)
local args = {...}
if #args == 0 then return 0xFFFFFFFF end
local bits = tobits(args[1])
for i = 2, #args do
local b = tobits(args[i])
for j = 0, 31 do
bits[j] = (bits[j] == 1 and b[j] == 1) and 1 or 0
end
end
return frombits(bits)
end
function bit32.bor(...)
local args = {...}
if #args == 0 then return 0 end
local bits = tobits(args[1])
for i = 2, #args do
local b = tobits(args[i])
for j = 0, 31 do
bits[j] = (bits[j] == 1 or b[j] == 1) and 1 or 0
end
end
return frombits(bits)
end
function bit32.bxor(...)
local args = {...}
if #args == 0 then return 0 end
local bits = tobits(args[1])
for i = 2, #args do
local b = tobits(args[i])
for j = 0, 31 do
bits[j] = (bits[j] ~= b[j]) and 1 or 0
end
end
return frombits(bits)
end
function bit32.bnot(x)
local bits = tobits(x)
for i = 0, 31 do
bits[i] = bits[i] == 1 and 0 or 1
end
return frombits(bits)
end
-- ===== Shifts =====
function bit32.lshift(x, n)
return norm(norm(x) * 2^n)
end
function bit32.rshift(x, n)
return math.floor(norm(x) / 2^n)
end
function bit32.arshift(x, n)
x = norm(x)
if x >= MOD31 then
return math.floor((x - MOD32) / 2^n)
else
return math.floor(x / 2^n)
end
end
-- ===== Rotates =====
function bit32.lrotate(x, n)
n = n % 32
x = norm(x)
local left = (x * 2^n) % MOD32
local right = math.floor(x / 2^(32 - n))
return norm(left + right)
end
function bit32.rrotate(x, n)
n = n % 32
x = norm(x)
local right = math.floor(x / 2^n)
local left = (x * 2^(32 - n)) % MOD32
return norm(left + right)
end
-- ===== Bit fields =====
function bit32.extract(x, field, width)
width = width or 1
return bit32.band(bit32.rshift(x, field), 2^width - 1)
end
function bit32.replace(x, v, field, width)
width = width or 1
local mask = bit32.lshift(2^width - 1, field)
x = bit32.band(x, bit32.bnot(mask))
return bit32.bor(x, bit32.lshift(v, field))
end
-- ===== Test =====
function bit32.test(x, ...)
local args = {...}
for i = 1, #args do
if bit32.band(x, args[i]) ~= 0 then
return true
end
end
return false
end
return bit32

116
Build/lib/crypto/blake2s Normal file
View File

@@ -0,0 +1,116 @@
-- blake2s.lua
-- Pure Lua 5.2, 32-bit only, supports keyed hashing
local bit32 = require("bit32")
local band, bor, bxor = bit32.band, bit32.bor, bit32.bxor
local rshift, lshift = bit32.rshift, bit32.lshift
local MOD32 = 2^32
local function rotr(x, n)
return bor(rshift(x, n), lshift(x, 32 - n))
end
local IV = {
0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19
}
local SIGMA = {
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15},
{14,10,4,8,9,15,13,6,1,12,0,2,11,7,5,3},
{11,8,12,0,5,2,15,13,10,14,3,6,7,1,9,4},
{7,9,3,1,13,12,11,14,2,6,5,10,4,0,15,8},
{9,0,5,7,2,4,10,15,14,1,11,12,6,8,3,13},
{2,12,6,10,0,11,8,3,4,13,7,5,15,14,1,9},
{12,5,1,15,14,13,4,10,0,7,6,3,9,2,8,11},
{13,11,7,14,12,1,3,9,5,0,15,4,8,6,2,10},
{6,15,14,9,11,3,0,8,12,2,13,7,1,4,10,5},
{10,2,8,4,7,6,1,5,15,11,9,14,3,12,13,0}
}
local function G(v, a, b, c, d, x, y)
v[a] = (v[a] + v[b] + x) % MOD32
v[d] = rotr(bxor(v[d], v[a]), 16)
v[c] = (v[c] + v[d]) % MOD32
v[b] = rotr(bxor(v[b], v[c]), 12)
v[a] = (v[a] + v[b] + y) % MOD32
v[d] = rotr(bxor(v[d], v[a]), 8)
v[c] = (v[c] + v[d]) % MOD32
v[b] = rotr(bxor(v[b], v[c]), 7)
end
local function compress(h, block, t, last)
local v = {}
for i = 1, 8 do v[i] = h[i] end
for i = 1, 8 do v[i + 8] = IV[i] end
v[13] = bxor(v[13], t)
if last then
v[15] = bxor(v[15], 0xFFFFFFFF)
end
local m = {}
for i = 0, 15 do
local p = i * 4 + 1
m[i] =
(block:byte(p) or 0) +
((block:byte(p + 1) or 0) * 0x100) +
((block:byte(p + 2) or 0) * 0x10000) +
((block:byte(p + 3) or 0) * 0x1000000)
end
for r = 1, 10 do
local s = SIGMA[r]
G(v,1,5,9,13, m[s[1]], m[s[2]])
G(v,2,6,10,14, m[s[3]], m[s[4]])
G(v,3,7,11,15, m[s[5]], m[s[6]])
G(v,4,8,12,16, m[s[7]], m[s[8]])
G(v,1,6,11,16, m[s[9]], m[s[10]])
G(v,2,7,12,13, m[s[11]], m[s[12]])
G(v,3,8,9,14, m[s[13]], m[s[14]])
G(v,4,5,10,15, m[s[15]], m[s[16]])
end
for i = 1, 8 do
h[i] = bxor(h[i], v[i], v[i + 8])
end
end
local function blake2s(msg, key)
key = key or ""
local h = {}
for i = 1, 8 do h[i] = IV[i] end
local outlen = 32 -- bytes
h[1] = bxor(
h[1],
0x01010000 + lshift(#key, 8) + outlen
)
local t = 0
if #key > 0 then
local block = key .. string.rep("\0", 64 - #key)
t = #key
compress(h, block, t, false)
end
for i = 1, #msg, 64 do
local block = msg:sub(i, i + 63)
if #block < 64 then
block = block .. string.rep("\0", 64 - #block)
end
t = t + math.min(64, #msg - i + 1)
compress(h, block, t, i + 64 > #msg)
end
local out = ""
for i = 1, 8 do
out = out .. string.format("%08x", h[i])
end
return out
end
return blake2s

View File

@@ -23,4 +23,4 @@ function driver.main()
-- Nothing to run -- Nothing to run
end end
kernel.drivers.register(driver) -- kernel.drivers.register(driver)

View File

@@ -0,0 +1,181 @@
local kernel=...
local apis=kernel.apis
local main=apis.term
local native=apis.peripheral
local sides = {"top", "bottom", "left", "right", "front", "back"}
local function getType(name)
if native.isPresent(name) then
return native.getType(name)
end
for n = 1, #sides do
local side = sides[n]
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
return native.call(side, "getTypeRemote", name)
end
end
return nil
end
local function getNames()
local names = {}
for n = 1, #sides do
local side = sides[n]
if native.isPresent(side) then
table.insert(names, side)
end
if native.hasType(side, "peripheral_hub") then
local hubSides = native.call(side, "getConnectedSides")
for _, hubSide in ipairs(hubSides) do
table.insert(names, hubSide)
end
end
end
return names
end
local function wrapPeripheral(name)
if native.isPresent(name) then
return native.wrap(name)
end
for n = 1, #sides do
local side = sides[n]
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
return native.call(side, "wrapRemote", name)
end
end
return nil
end
local colors={
[0]=0x000000, -- #000000
0xFFFFFF, -- #FFFFFF
0xFF0000, -- #FF0000
0x00FF00, -- #00FF00
0x0000FF, -- #0000FF
0x00FFFF, -- #00FFFF
0xFF00FF, -- #FF00FF
0xFFFF00, -- #FFFF00
0xFF6D00, -- #FF6D00
0x6DFF55, -- #6DFF55
0x24FFFF, -- #24FFFF
0x924900, -- #924900
0x6D6D55, -- #6D6D55
0xDBDBAA, -- #DBDBAA
0x6D00FF, -- #6D00FF
0xB6FF00 -- #B6FF00
}
local icolors={
[0x1] =0, -- #000000
[0x2] =1, -- #FFFFFF
[0x4] =2, -- #FF0000
[0x8] =3, -- #00FF00
[0x10] =4, -- #0000FF
[0x20] =5, -- #00FFFF
[0x40] =6, -- #FF00FF
[0x80] =7, -- #FFFF00
[0x100] =8, -- #FF6D00
[0x200] =9, -- #6DFF55
[0x400] =10, -- #24FFFF
[0x800] =11, -- #924900
[0x1000] =12, -- #6D6D55
[0x2000] =13, -- #DBDBAA
[0x4000] =14, -- #6D00FF
[0x8000] =15 -- #B6FF00
}
local function write(text, term)
local x, y = term.getCursorPos()
local w, h = term.getSize()
for i = 1, #text do
local c = text:sub(i, i)
if c == "\n" then
y = y + 1
x = 1
elseif c == "\t" then
local tabSize = 4
local spaces = tabSize - ((x - 1) % tabSize)
term.write(string.rep(" ", spaces))
x = x + spaces
elseif c == "\b" then
if x > 1 then
x = x - 1
term.setCursorPos(x, y)
term.write(" ")
term.setCursorPos(x, y)
end
else
if x <= w and y <= h then
term.setCursorPos(x, y)
term.write(c)
x = x + 1
end
end
-- Handle wrapping if we go past right edge
if x > w then
x = 1
y = y + 1
end
-- Handle scrolling if we go past bottom
if y-1 > h then
term.scroll(1)
y = h
term.setCursorPos(x, y)
end
end
term.setCursorPos(x, y)
end
local function newTTY(term)
local ret={}
function ret.print(text)
write(text.."\n", term)
end
function ret.printInline(text)
write(text, term)
end
function ret.clear()
term.clear()
term.setCursorPos(1,1)
end
function ret.setCursorPos(x,y)
term.setCursorPos(x,y)
end
function ret.getCursorPos()
return term.getCursorPos()
end
function ret.getSize()
return term.getSize()
end
function ret.setBackgroundColor(color)
term.setBackgroundColor(colors[color])
end
function ret.setTextColor(color)
term.setTextColor(colors[color])
end
function ret.getBackgroundColor()
return icolors[term.getBackgroundColor()]
end
function ret.getTextColor()
return icolors[term.getTextColor()]
end
return ret
end
kernel.tty.register("tty0", newTTY(main))
for _, name in ipairs(getNames()) do
local t = getType(name)
if t == "monitor" then
local monitorTerm = wrapPeripheral(name)
monitorTerm.setTextScale(0.5)
kernel.tty.register(name, newTTY(monitorTerm))
end
end

View File

@@ -1,105 +0,0 @@
local args={...}
local kernel=args[1]
local apis=kernel.apis
local native=apis.peripheral
local driver={}
local sides = {"top", "bottom", "left", "right", "front", "back"}
local function getType(name)
if native.isPresent(name) then
return native.getType(name)
end
for n = 1, #sides do
local side = sides[n]
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
return native.call(side, "getTypeRemote", name)
end
end
return nil
end
local function getNames()
local names = {}
for n = 1, #sides do
local side = sides[n]
if native.isPresent(side) then
table.insert(names, side)
end
if native.hasType(side, "peripheral_hub") then
local hubSides = native.call(side, "getConnectedSides")
for _, hubSide in ipairs(hubSides) do
table.insert(names, hubSide)
end
end
end
return names
end
driver.name="CCT TTY Module"
driver.version="0.1.0"
driver.type="tty"
driver.description="CCT TTY Module Kernel Module"
driver.arch="cct"
driver.author="HyperionOS Dev Team"
driver.license="MIT"
driver.api={}
local colors={
[0]=0x000000, -- #000000
0xFFFFFF, -- #FFFFFF
0xFF0000, -- #FF0000
0x00FF00, -- #00FF00
0x0000FF, -- #0000FF
0x00FFFF, -- #00FFFF
0xFF00FF, -- #FF00FF
0xFFFF00, -- #FFFF00
0xFF6D00, -- #FF6D00
0x6DFF55, -- #6DFF55
0x24FFFF, -- #24FFFF
0x924900, -- #924900
0x6D6D55, -- #6D6D55
0xDBDBAA, -- #DBDBAA
0x6D00FF, -- #6D00FF
0xB6FF00 -- #B6FF00
}
local icolors={
[0x1] =0, -- #000000
[0x2] =1, -- #FFFFFF
[0x4] =2, -- #FF0000
[0x8] =3, -- #00FF00
[0x10] =4, -- #0000FF
[0x20] =5, -- #00FFFF
[0x40] =6, -- #FF00FF
[0x80] =7, -- #FFFF00
[0x100] =8, -- #FF6D00
[0x200] =9, -- #6DFF55
[0x400] =10, -- #24FFFF
[0x800] =11, -- #924900
[0x1000] =12, -- #6D6D55
[0x2000] =13, -- #DBDBAA
[0x4000] =14, -- #6D00FF
[0x8000] =15 -- #B6FF00
}
local function getAllScreens()
end
local function wrapScreens()
end
function driver.load()
-- Nothing to load
end
function driver.unload()
-- Nothing to unload
end
function driver.main()
-- Nothing to run
end
kernel.drivers.register(driver)

View File

@@ -1,5 +1,4 @@
local args={...}
local kernel=args[1]
function string.hasSuffix(str, suffix) function string.hasSuffix(str, suffix)
return string.sub(str, #suffix+1) == suffix return string.sub(str, #suffix+1) == suffix
end end
@@ -117,7 +116,7 @@ function table.proxy(tbl)
end end
end, end,
__newindex = function() __newindex = function()
error("Attempt to modify read-only table", 2) error("Attempt to modify table proxy", 2)
end, end,
__pairs = function() __pairs = function()
return function(_, k) return function(_, k)
@@ -158,6 +157,8 @@ local function serialize(table)
local coma=true local coma=true
if type(i) == "string" then if type(i) == "string" then
output=output.."[\""..i.."\"]=" output=output.."[\""..i.."\"]="
elseif type(i) == "number" then
output=output.."["..tostring(i).."]="
end end
if type(v) == "table" then if type(v) == "table" then
if v == table then if v == table then
@@ -224,6 +225,46 @@ function getmetatable(object)
end end
end end
function isEqual(a, ...)
local args={...}
for i=0, #args do
if a==args[i] then
return true
end
end
return false
end
function table.keys(t)
local a = {}
for n in pairs(t) do table.insert(a, n) end
return a
end
function table.values(t)
local a = {}
for _, n in pairs(t) do table.insert(a, n) end
return a
end
function table.indexOf(t, value)
for i,v in ipairs(t) do
if v==value then
return i
end
end
return -1
end
syscall = setmetatable({}, {__index = function(self, name)
return function(...)
local res = table.pack(coroutine.yield("syscall", name, ...))
if res[1] then
return table.unpack(res, 2, res.n)
else
error(res[2], 2)
end
end
end})
table.serialize=serialize table.serialize=serialize
kernel.log("Loaded stdlib")

View File

@@ -1,3 +0,0 @@
local args={...}
local kernel=args[1]
kernel._U=table.proxy(_G)

View File

@@ -1,351 +1,277 @@
local args = {...} local kernel = ...
local kernel = args[1] local vfs = {}
local fs = {} vfs.mounts = { ["$"] = "/" }
local disks = kernel.disks
-- ===================================================================== -- Path handling
-- INTERNAL STATE local function normalizePath(path)
-- ===================================================================== local parts = {}
for part in path:gmatch("[^/]+") do
local disks = {} -- address → disk object if part == ".." then
local mounts = {["/"] = "$"} -- mountpoint → disk address (root = boot disk) if #parts > 0 then table.remove(parts) end
local cwd = "/" elseif part ~= "." and part ~= "" then
table.insert(parts, part)
local SYMLINK_PREFIX = "#!@SYMLINK[" end
local SYMLINK_SUFFIX = "]" end
local SYMLINK_MAX_DEPTH = 64 return "/" .. table.concat(parts, "/") .. (path:sub(-1) == "/" and "/" or "")
-- =====================================================================
-- PATH NORMALIZATION
-- =====================================================================
local function splitPath(p)
local t = {}
for part in p:gmatch("[^/]+") do t[#t+1] = part end
return t
end end
local function normalizePath(path) local function resolvePath(path)
if not path or path == "" then return "/" end local task = kernel.currentTask
local cwd = task.cwd or "/"
-- cwd
if path:sub(1,1) ~= "/" then if path:sub(1,1) ~= "/" then
path = cwd .. path path = cwd .. path
end end
path = normalizePath(path)
local parts = splitPath(path) local mountPoint = "/"
local out = {} local mountId = "$"
for k,v in pairs(vfs.mounts) do
for _,part in ipairs(parts) do if path:sub(1,#v) == v and #v > #mountPoint then
if part == ".." then mountPoint = v
if #out > 0 then table.remove(out) end mountId = k
elseif part ~= "." and part ~= "" then
out[#out+1] = part
end end
end end
return "/" .. table.concat(out, "/") local diskPath = path:sub(#mountPoint + 1)
return disks[mountId], diskPath
end end
-- File object creation
-- ===================================================================== local function newFileObject(disk, handle, mode, path)
-- DISK & MOUNT RESOLUTION return {
-- ===================================================================== disk = disk,
handle = handle,
-- Finds which disk owns an absolute path mode = mode,
local function resolveMount(abs) path = path,
local best = "/" refcount = 1
}
for mount, addr in pairs(mounts) do
if abs:sub(1, #mount) == mount then
if #mount > #best then
best = mount
end
end
end end
local disk = disks[mounts[best]] local function allocFD(task)
local fd = 0
while task.fd[fd] do fd = fd + 1 end
return fd
end
local function allocFD(task)
-- enforce per-task limit
local count = 0
for _ in pairs(task.fd) do count = count + 1 end
if count >= kernel.config.maxFilesPerTask then
error("EMFILE") -- Too many open files in this task
end
-- find first free FD
local fd = 0
while task.fd[fd] do fd = fd + 1 end
return fd
end
local function checkSystemLimit()
-- enforce system-wide limit
local total = 0
for _, task in pairs(kernel.tasks or {}) do
for _ in pairs(task.fd) do total = total + 1 end
end
if total >= kernel.config.maxOpenFiles then
error("ENFILE") -- Too many open files in the system
end
end
-- VFS syscalls
function vfs.open(path, mode)
local task = kernel.currentTask
-- check limits
checkSystemLimit()
local disk, diskPath = resolvePath(path)
if not disk then if not disk then
error("No disk registered for mount: " .. best) error("No disk mounted for path '"..path.."'")
end end
local sub = abs:sub(#best + 1) local handle = disk:open(diskPath, mode)
if sub == "" then sub = "/" end if not handle then return nil end
return disk, sub
local file = newFileObject(disk.address, handle, mode, path)
local fd = allocFD(task)
task.fd[fd] = file
return fd
end end
function vfs.close(fd)
local task = kernel.currentTask
local file = task.fd[fd]
if not file then error("EBADF") end
task.fd[fd] = nil
-- ===================================================================== file.refcount = file.refcount - 1
-- SYMLINK HANDLING if file.refcount == 0 then
-- ===================================================================== file.handle.close()
end
local function isSymlinkRaw(disk, p) return true
if not disk:fileExists(p) then return false end
local text = disk:readAllText(p)
return text and text:sub(1, #SYMLINK_PREFIX) == SYMLINK_PREFIX
end end
local function readSymlinkRaw(disk, p) function vfs.read(fd, count)
local text = disk:readAllText(p) local file = kernel.currentTask.fd[fd]
if not text then return nil end if not file then error("EBADF") end
if text:sub(1, #SYMLINK_PREFIX) ~= SYMLINK_PREFIX then return nil end if not file.mode:find("r") then error("File not open for reading") end
return file.handle.read(count)
local t = text:sub(#SYMLINK_PREFIX + 1)
if t:sub(-1) == SYMLINK_SUFFIX then
t = t:sub(1, -2)
end
return t
end end
function vfs.write(fd, data)
-- ===================================================================== local file = kernel.currentTask.fd[fd]
-- FULL PATH RESOLUTION (FOLLOWS SYMLINKS) if not file then error("EBADF") end
-- ===================================================================== if not file.mode:find("w") then error("File not open for writing") end
return file.handle.write(data)
local function resolveSymlink(path)
local abs = normalizePath(path)
local parts = splitPath(abs)
local out = {}
local depth = 0
local idx = 1
while idx <= #parts do
local comp = parts[idx]
if comp == "." then
-- nothing
elseif comp == ".." then
if #out > 0 then table.remove(out) end
else
local curAbs = "/" .. table.concat(out, "/")
if curAbs ~= "/" then curAbs = curAbs .. "/" end
curAbs = curAbs .. comp
local disk, dpath = resolveMount(curAbs)
if isSymlinkRaw(disk, dpath) then
depth = depth + 1
if depth > SYMLINK_MAX_DEPTH then
error("Too many symlink levels: " .. path)
end end
local target = readSymlinkRaw(disk, dpath) function vfs.whereis(fd)
if target then local file = kernel.currentTask.fd[fd]
local newAbs if not file then error("EBADF") end
return file.path
if target:sub(1,1) == "/" then
-- absolute target
newAbs = normalizePath(target)
else
-- relative to current out[]
local tmp = "/" .. table.concat(out, "/")
if tmp ~= "/" then tmp = tmp .. "/" end
tmp = tmp .. target
newAbs = normalizePath(tmp)
end end
-- rebuild remaining parts -- Filesystem operations
local remaining = {} function vfs.mkdir(path)
for j = idx + 1, #parts do local disk, diskPath = resolvePath(path)
remaining[#remaining+1] = parts[j] if not disk then error("No disk mounted") end
return disk:makeDirectory(diskPath)
end end
-- restart symlink resolution with new path function vfs.remove(path)
abs = newAbs local disk, diskPath = resolvePath(path)
parts = splitPath(abs) if not disk then error("No disk mounted") end
return disk:remove(diskPath)
-- append remaining
for _,x in ipairs(remaining) do parts[#parts+1] = x end
out = {}
idx = 0
else
out[#out+1] = comp
end
else
out[#out+1] = comp
end
end end
idx = idx + 1 function vfs.attributes(path)
if type(path) == "number" then
local file = kernel.currentTask.fd[path]
if not file then error("EBADF") end
return disks[file.disk]:attributes(file.path)
end
local disk, diskPath = resolvePath(path)
if not disk then error("No disk mounted") end
return disk:attributes(diskPath)
end end
local finalAbs = "/" .. table.concat(out, "/") function vfs.list(path)
return resolveMount(finalAbs) local disk, diskPath = resolvePath(path)
if not disk then error("No disk mounted") end
return disk:list(diskPath)
end end
function vfs.exists(path)
local disk, diskPath = resolvePath(path)
-- ===================================================================== if not disk then return false end
-- PUBLIC API return disk:directoryExists(diskPath) or disk:fileExists(diskPath)
-- =====================================================================
-- MOUNT OPERATIONS -----------------------------------------------------
function fs.virtDisk(diskObj)
if kernel.uid ~= 0 then error("Permission Denied") end
if disks[diskObj.address] then
error("Disk exists: " .. diskObj.address)
end
disks[diskObj.address] = diskObj
end end
function fs.mount(disk, mountPoint) function vfs.type(path)
if kernel.uid ~= 0 then error("Permission Denied") end if type(path) == "number" then
mountPoint = normalizePath(mountPoint) local file = kernel.currentTask.fd[path]
if not file then error("EBADF") end
local drive, path = resolveMount(normalizePath(mountPoint)) return disks[file.disk]:type(file.path)
if not drive:directoryExists(path) then error("Must mount on folder") end end
local disk, diskPath = resolvePath(path)
if mountPoint ~= "/" and mounts[mountPoint] then if not disk then error("No disk mounted") end
error("Already mounted: " .. mountPoint) return disk:type(diskPath)
end end
mounts[mountPoint] = disk -- CWD
function vfs.getcwd()
return kernel.currentTask.cwd
end end
function fs.unmount(mountPoint) function vfs.setcwd(path)
if kernel.uid ~= 0 then error("Permission Denied") end if path:sub(-1) ~= "/" then path = path .. "/" end
mountPoint = normalizePath(mountPoint) if path:sub(1,1) ~= "/" then path = "/" .. path end
kernel.currentTask.cwd = normalizePath(path)
if mountPoint == "/" then error("Cannot unmount root") end
mounts[mountPoint] = nil
end end
function fs.eject(addr) -- Mounting
if kernel.uid ~= 0 then error("Permission Denied") end function vfs.mount(diskId, path)
disks[addr] = nil if kernel.uid ~= 0 then error("Permission denied") end
if not disks[diskId] then error("Unknown disk '"..diskId.."'") end
if path:sub(-1) ~= "/" then path = path .. "/" end
for _,v in pairs(vfs.mounts) do
if v == path then error("Mount point already used") end
end
vfs.mounts[diskId] = path
end end
function fs.isMount(path) function vfs.unmount(path)
if mounts[normalizePath(path)] then return true, mounts[normalizePath(path)] end if kernel.uid ~= 0 then error("Permission denied") end
end for k,v in pairs(vfs.mounts) do
if v == path then
-- SYMLINK API ---------------------------------------------------------- vfs.mounts[k] = nil
return true
function fs.symlink(target, linkPath)
kernel.log("WARNING: Symlinks are a untested feature if you find any bugs please report them to https://git.astronand.dev/Hyperion/HyperionOS","WARN")
local disk, p = resolveMount(normalizePath(linkPath))
return disk:writeAllText(p, SYMLINK_PREFIX .. target .. SYMLINK_SUFFIX)
end
function fs.isLink(path)
local disk, p = resolveMount(normalizePath(path))
return isSymlinkRaw(disk, p)
end
function fs.readLink(path)
local disk, p = resolveMount(normalizePath(path))
return readSymlinkRaw(disk, p)
end
-- FILE OPERATIONS ------------------------------------------------------
function fs.exists(path, ...)
local disk, p = resolveSymlink(path)
return disk:fileExists(p, ...) or disk:directoryExists(p, ...)
end
function fs.isFile(path, ...)
local disk, p = resolveSymlink(path)
return disk:fileExists(p, ...)
end
function fs.isDir(path, ...)
local disk, p = resolveSymlink(path)
return disk:directoryExists(p, ...)
end
function fs.list(path, ...)
local disk, p = resolveSymlink(path)
return disk:list(p, ...)
end
function fs.makeDir(path, ...)
local disk, p = resolveSymlink(path)
return disk:makeDirectory(p, ...)
end
-- remove does NOT follow symlinks (UNIX semantics)
function fs.remove(path, ...)
if fs.isMount(path) then return "Cannot delete mounted folder" end
local abs = normalizePath(path)
local disk, p = resolveMount(abs)
return disk:remove(p, ...)
end
function fs.readAllText(path, ...)
local disk, p = resolveSymlink(path)
return disk:readAllText(p, ...)
end
function fs.writeAllText(path, text, ...)
local disk, p = resolveSymlink(path)
return disk:writeAllText(p, text, ...)
end
function fs.appendAllText(path, text, ...)
local disk, p = resolveSymlink(path)
return disk:appendAllText(p, text, ...)
end
function fs.load(path, name, ...)
return load(fs.readAllText(path, ...), name or path, nil, kernel._U)
end
function fs.getSize(path, ...)
local disk, p = resolveSymlink(path)
return disk:getSize(p, ...)
end
-- =====================================================================
-- WD STUFF
-- =====================================================================
function fs.setCwd(path)
if not path or path == "" then return "/" end
-- ensure absolute
if path:sub(1,1) ~= "/" then
path = "/" .. path
end
local parts = splitPath(path)
local out = {}
for _,part in ipairs(parts) do
if part == ".." then
if #out > 0 then table.remove(out) end
elseif part ~= "." and part ~= "" then
out[#out+1] = part
end end
end end
return false
cwd="/" .. table.concat(out, "/")
end end
function fs.getCwd(path) function vfs.getMounts()
return cwd return vfs.mounts
end end
-- ===================================================================== function vfs.virtdisk(obj)
-- INIT kernel.disks[obj.address] = obj
-- ===================================================================== kernel.log("Registered virtual disk at "..obj.address)
kernel.log("Loading disks for vfs")
local ok,err = xpcall(function()
for _,v in kernel.initdisks.list() do
fs.virtDisk(v)
end end
end, debug.traceback)
if not ok then kernel.panic(err) end
kernel.disks=disks -- Redirect file operations to VFS
kernel.mounts=mounts function vfs.dup(oldfd)
kernel.fs = fs local task = kernel.currentTask
kernel.cache.preload.fs = fs local file = task.fd[oldfd]
kernel.cache.preload.filesystem = kernel.cache.preload.fs if not file then error("EBADF") end
local newfd = allocFD(task)
task.fd[newfd] = file
file.refcount = file.refcount + 1
return newfd
end
function vfs.dup2(oldfd, newfd)
local task = kernel.currentTask
local file = task.fd[oldfd]
if not file then error("EBADF") end
if oldfd == newfd then return newfd end
if task.fd[newfd] then
vfs.close(newfd)
end
task.fd[newfd] = file
file.refcount = file.refcount + 1
return newfd
end
-- Syscall registration
kernel.vfs = vfs
kernel.syscalls["VFS_open"] = vfs.open
kernel.syscalls["VFS_read"] = vfs.read
kernel.syscalls["VFS_write"] = vfs.write
kernel.syscalls["VFS_close"] = vfs.close
kernel.syscalls["VFS_list"] = vfs.list
kernel.syscalls["VFS_type"] = vfs.type
kernel.syscalls["VFS_attributes"] = vfs.attributes
kernel.syscalls["VFS_mkdir"] = vfs.mkdir
kernel.syscalls["VFS_remove"] = vfs.remove
kernel.syscalls["VFS_exists"] = vfs.exists
kernel.syscalls["VFS_mount"] = vfs.mount
kernel.syscalls["VFS_unmount"] = vfs.unmount
kernel.syscalls["VFS_getcwd"] = vfs.getcwd
kernel.syscalls["VFS_setcwd"] = vfs.setcwd
kernel.syscalls["VFS_whereis"] = vfs.whereis
kernel.syscalls["VFS_dup"] = vfs.dup
kernel.syscalls["VFS_dup2"] = vfs.dup2
kernel.log("VFS module loaded")

View File

@@ -1,179 +0,0 @@
local args = {...}
local kernel = args[1]
function kernel.fs.mkvirtfs(address, readOnly, label, autoRegister)
if kernel.uid ~= 0 then error("Permission Denied") end
local disk = {}
disk.address = address
local isRO = readOnly or false
local backend = {
["/"] = { __dir = true }
}
-----------------------------------------------------------------
-- Helpers
-----------------------------------------------------------------
local function norm(path)
if not path or path == "" then return "/" end
if path:sub(1,1) ~= "/" then path = "/" .. path end
path = path:gsub("/+", "/")
return path
end
local function split(path)
local parts = {}
for p in path:gmatch("[^/]+") do table.insert(parts, p) end
return parts
end
local function getNode(path)
path = norm(path)
if path == "/" then return backend["/"] end
local node = backend["/"]
for _, part in ipairs(split(path)) do
node = node[part]
if not node then return nil end
end
return node
end
local function getParent(path)
local parts = split(norm(path))
local name = table.remove(parts)
local parentPath = "/" .. table.concat(parts, "/")
return getNode(parentPath), name
end
local function ensureWrite()
if isRO then return false, "read-only" end
return true
end
-----------------------------------------------------------------
-- File IO (supports string or file-object with read/write funcs)
-----------------------------------------------------------------
local function fileRead(node, ...)
if type(node) == "string" then
return node
elseif type(node) == "table" and node.__file and node.read then
return node.read(...)
end
return nil
end
local function fileWrite(parent, name, text, ...)
local node = parent[name]
if type(node) == "string" then
local ok, err = ensureWrite(); if not ok then return false, err end
parent[name] = text
return true
elseif type(node) == "table" and node.__file and node.write then
return node.write(text, ...)
end
parent[name] = text
return true
end
local function fileAppend(parent, name, text, ...)
local node = parent[name]
if type(node) == "string" then
local ok, err = ensureWrite(); if not ok then return false, err end
parent[name] = node .. text
return true
elseif type(node) == "table" and node.__file and node.write then
return node.write((node.read() or "") .. text, ...)
end
parent[name] = text
return true
end
-----------------------------------------------------------------
-- API
-----------------------------------------------------------------
function disk:isReadOnly() return isRO end
function disk:spaceUsed() return 0 end
function disk:spaceTotal() return 0 end
function disk:readAllText(path, ...)
local node = getNode(path)
if not node then return nil, "file not found" end
return fileRead(node, ...)
end
function disk:writeAllText(path, text, ...)
local parent, name = getParent(path)
if not parent or not parent.__dir then return false, "invalid directory" end
return fileWrite(parent, name, tostring(text), ...)
end
function disk:appendAllText(path, text, ...)
local parent, name = getParent(path)
if not parent or not parent.__dir then return false, "invalid directory" end
return fileAppend(parent, name, tostring(text), ...)
end
function disk:list(path)
local node = getNode(path)
if not node or not node.__dir then return nil, "not a directory" end
local out = {}
for k, _ in pairs(node) do if k ~= "__dir" then table.insert(out, k) end end
return out
end
function disk:fileExists(path)
local node = getNode(path)
return type(node) == "string" or (type(node) == "table" and node.__file)
end
function disk:directoryExists(path)
local node = getNode(path)
return node and type(node) == "table" and node.__dir or false
end
function disk:makeDirectory(path)
local ok, err = ensureWrite(); if not ok then return false, err end
local parent, name = getParent(path)
if not parent or not parent.__dir then return false, "invalid parent directory" end
parent[name] = { __dir = true }
return true
end
function disk:remove(path)
local ok, err = ensureWrite(); if not ok then return false, err end
local parent, name = getParent(path)
if not parent or not parent[name] then return false, "not found" end
parent[name] = nil
return true
end
function disk:setLabel(new)
local ok, err = ensureWrite(); if not ok then return false, err end
label = tostring(new)
end
function disk:getLabel()
return label
end
function disk:size(path, ...)
local node = getNode(path)
if type(node) == "string" then return #node end
if type(node) == "table" and node.__file and node.read then
local v = node.read(...)
return v and #v or 0
end
return 0
end
-----------------------------------------------------------------
-- Auto-register with kernel and return backend
-----------------------------------------------------------------
if autoRegister then
kernel.fs.virtDisk(disk)
end
return backend, disk
end

View File

@@ -1,56 +1,42 @@
local args = {...} local kernel = ...
local kernel = args[1] local cache = {}
-- List of search paths local searchpaths = {
local paths = { "/lib/?.lua",
"/lib/?", "/lib/?",
"/usr/lib/?.lua",
"/usr/lib/?", "/usr/lib/?",
"/usr/local/lib/?" "/usr/local/lib/?.lua",
"/usr/local/lib/?",
"?.lua",
"?"
} }
-- Custom require implementation function require(module,...)
function require(module) if cache[module] then
-- Return cached module if it already exists return cache[module]
if kernel.cache.preload[module]~=nil then
return kernel.cache.preload[module]
end end
local modpath = module:gsub("%.", "/")
local err = {} local failed = {}
for _, path in ipairs(searchpaths) do
for _, path in ipairs(paths) do local full_path = string.gsub(path, "%?", modpath)
-- Replace "?" with module name if full_path:sub(1,1)~="/" then
local filePath = string.replace(path, "?", module) full_path=kernel.currentTask.cwd..full_path
end
-- Try to open file if kernel.vfs.exists(full_path) then
local file = kernel.fs.isFile(filePath) if kernel.vfs.type(full_path)=="directory" then
if file then full_path = full_path .. "/init"
local content = kernel.fs.readAllText(filePath) end
if kernel.vfs.exists(full_path) then
-- Load the module as Lua code local handle = kernel.vfs.open(full_path, "r")
local chunk, loadErr = load(content, filePath) local file_content = kernel.vfs.read(handle, 1024 * 1024 * 4)
if not chunk then kernel.vfs.close(handle)
table.insert(err, "Error loading: " .. filePath .. ": " .. loadErr) return assert(load(file_content, full_path, "t", kernel._U))(...)
else else
-- Execute the module. If the module returns a value, cache it. table.insert(failed, full_path)
local ok, result = xpcall(chunk, debug.traceback)
if not ok then
table.insert(err, "Error executing: "..filePath..": "..tostring(result))
else
if result ~= nil then
kernel.cache.preload[module] = result
return result
end
-- If module doesn't return anything, cache `true` like Lua does
kernel.cache.preload[module] = true
return true
end
end end
else else
table.insert(err, "Module not found: " .. filePath) table.insert(failed, full_path)
end end
end end
error("Module not found: " .. module .. " (searched paths: " .. table.concat(failed, ", ") .. ")")
-- If nothing worked, raise an error with all reasons
error("Unable to require module '" .. module .. "':\n" .. table.concat(err, "\n"))
end end
kernel.log("Created require")

View File

@@ -1,57 +1,196 @@
local args = {...} local kernel = ...
local kernel = args[1]
local data = kernel.fs.mkvirtfs("devfs0000", true, "devfs", true) local proxy = {}
if not kernel.fs.isDir("/dev") then kernel.fs.makeDir("/dev") end local data = {}
proxy.address = "devfs0000"
proxy.isReadOnly = false
proxy.spaceUsed = function() return 0 end
proxy.spaceTotal = function() return 0 end
proxy.makeDirectory = function() error("Permission denied") end
proxy.remove = function() error("Permission denied") end
proxy.setLabel = function() error("Permission denied") end
proxy.getLabel = function() return "devfs" end
proxy.attributes = function(path) return {
type = proxy.type(path),
isReadOnly = false,
size = 0,
lastModified = 0,
created = 0,
Permissions = "666",
owner = "root",
group = "root"
} end
local function getNode(path)
local parts = string.split(path, "/")
if parts[1] == "" then
table.remove(parts, 1)
end
local node = data
for _, part in ipairs(parts) do
if node[part] then
node = node[part]
else
return nil
end
end
return node
end
proxy.type = function(path)
local node = getNode(path)
if node then
return node.type
else
return nil
end
end
proxy.list = function(path)
local node = getNode(path)
if node and node.type == "directory" then
local content = table.keys(node)
table.remove(content, table.indexOf(content, "type"))
return content
else
error("Not a directory")
end
end
proxy.open = function(path, mode)
local node = getNode(path)
if node and (node.type == "file" or node.type == "character device") then
if mode == "r" then
return {
read = node.read,
close = function() end
}
elseif mode == "w" then
return {
write = node.write,
close = function() end
}
else
error("Invalid mode")
end
else
error("Not a file"..type(node))
end
end
local function newStringFile(content)
return {
type = "file",
read = function() return content end,
write = function(newContent) content = newContent end
}
end
local function newDirectory()
return {
type = "directory"
}
end
data["random"] = {
type = "character device",
read = function(amount)
local result = ""
for _ = 1, amount do
result = result .. string.char(math.random(0, 255))
end
return result
end,
write = function() error("Permission denied") end
}
data["null"] = {
type = "character device",
read = function() return "" end,
write = function() end
}
data["zero"] = {
type = "character device",
read = function(amount)
return string.rep("\0", amount)
end,
write = function() error("Permission denied") end
}
data["rtc"] = {
type = "character device",
read = function() return kernel.computer:time() end,
write = function() error("Permission denied") end
}
data["rtc0"] = {
type = "character device",
read = function() return kernel.computer:time() end,
write = function() error("Permission denied") end
}
data["eeprom"] = {
type = "character device",
read = function() return kernel.computer:getEEPROM() end,
write = function(data)
if kernel.uid ~= 0 then
error("Permission denied")
end
kernel.computer:setEEPROM(data)
end
}
data["stdin"] = {
type = "link",
read = function(amount)
return kernel.currentTask.fd[0].read(amount)
end,
write = function() error("Permission denied") end
}
data["stdout"] = {
type = "link",
read = function() error("Permission denied") end,
write = function(data)
kernel.currentTask.fd[1].write(data)
end
}
data["stderr"] = {
type = "link",
read = function() error("Permission denied") end,
write = function(data)
kernel.currentTask.fd[2] = data
end
}
local keyboard = kernel.newFifo()
local mouse = kernel.newFifo()
data["input"] = newDirectory()
data["input"]["keyboard"] = {
type = "pipe",
read = function(amount)
return keyboard.pop()
end,
write = function() error("Permission denied") end
}
data["input"]["mouse"] = {
type = "pipe",
read = function(amount)
return mouse.pop()
end,
write = function() error("Permission denied") end
}
data["pts"] = newDirectory()
kernel.devfs = {} kernel.devfs = {}
kernel.devfs.keyboard = keyboard
kernel.devfs.mouse = mouse
kernel.devfs.proxy = proxy
kernel.devfs.data = data kernel.devfs.data = data
kernel.vfs.virtdisk(proxy)
data["/"]["OSVERSION"]="Hyperion 1.0.0"
data["/"]["eeprom"]={
__file=true,
read=function()
return kernel.computer:getEEPROM()
end,
write=function(text)
if kernel.uid ~= 0 then error("Permission Denied") end
kernel.computer:setEEPROM(text)
end
}
data["/"]["null"]={
__file=true,
read=function() end,
write=function() end
}
data["/"]["random"]={
__file=true,
read=function(amount)
local s = ""
for i = 1, amount do
s = s .. string.char(math.random(0, 255))
end
return s
end,
write=function() end
}
data["/"]["zero"]={
__file=true,
read=function(amount)
return ("\0"):rep(amount)
end,
write=function() end
}
data["/"]["rtc0"]={
__file=true,
read=function()
return kernel.computer:time()
end,
write=function() end
}
data["/"]["rtc"]={
__file=true,
read=function()
return kernel.computer:time()
end,
write=function() end
}
kernel.log("Created devfs")

View File

@@ -1,18 +0,0 @@
local args = {...}
local kernel = args[1]
local data = kernel.fs.mkvirtfs("sysfs0000", true, "sysfs", true)
if not kernel.fs.isDir("/sys") then kernel.fs.makeDir("/sys") end
data["/"]["OSVERSION"]="Hyperion 1.0.0"
data["/"]["eeprom"]={
__file=true,
read=function()
return kernel.computer:getEEPROM()
end,
write=function(text)
if kernel.uid ~= 0 then error("Permission Denied") end
kernel.computer:setEEPROM(text)
end
}
kernel.log("Created sysfs")

View File

@@ -0,0 +1,12 @@
local kernel = ...
kernel.processes.keventd = function()
while true do
local event = {kernel.computer:getMachineEvent()}
if event[1] then
if event[1] == "key" or event[1] == "keyPressed" or event[1] == "keyReleased" then
kernel.devfs.keyboard.push(event)
end
end
end
end

View File

@@ -1,26 +0,0 @@
local args = {...}
local kernel = args[1]
local ifs=kernel.ifs
kernel.log("Mounting fstab")
local fstab=ifs.readAllText("/etc/fstab")
local entrys = string.split(fstab,"\n")
for i,v in ipairs(entrys) do
if v:sub(1,1)=="U" then
local id=""
for i=3,#v do
if v:sub(i,i)==";" then
if i==3 then kernel.log("Invalid fstab line... Skipping.","WARN") goto endline end
id=v:sub(3,i-1)
end
end
local path=v:sub(#id+4,#v)
if i~=#entrys then
path=path:sub(1,#path-1)
end
kernel.log("Mounted "..id.." to "..path)
kernel.fs.mount(id,path)
::endline::
end
end
kernel.log("Mounted all disks")

View File

@@ -0,0 +1,17 @@
local kernel=...
for i,v in ipairs(string.split(kernel.fstab,"\n")) do
if v:sub(1,1)=="U" then
local id=""
for i=3,#v do
if v:sub(i,i)==";" then
if i==3 then kernel.log("Invalid fstab line... Skipping.","WARN") goto endline end
id=v:sub(3,i-1)
end
end
local path=v:sub(#id+4)
if id~="$" then
kernel.vfs.mount(id,path)
end
::endline::
end
end

View File

@@ -0,0 +1 @@
local kernel = ...

View File

@@ -0,0 +1,75 @@
local kernel = ...
local ports = {}
local signals = {}
local ipc = {}
function ipc.open(port)
if not ports[port] then
local handle = kernel.newUUID()
ports[port] = {owner = kernel.currentProcess.pid, handle = handle, messages = {}}
return ports[port].handle
end
error("Port already opened")
end
function ipc.close(port)
if ports[port] then
if ports[port].owner == kernel.currentProcess.pid then
ports[port] = nil
return true
else
error("Cannot close port you do not own")
end
end
error("Port not opened")
end
function ipc.send(port, message)
if ports[port] then
table.insert(ports[port].messages, {from = kernel.currentProcess.pid, message = message})
if signals[ports[port].owner] then
signals[ports[port].owner](port, message)
end
return true
end
error("Port not opened")
end
function ipc.receive(port)
if ports[port] then
if #ports[port].messages > 0 then
return table.remove(ports[port].messages, 1)
else
return nil
end
end
error("Port not opened")
end
function ipc.setSignalHandler(pid, handler)
signals[pid] = handler
end
function ipc.clearSignalHandler(pid)
signals[pid] = nil
end
function ipc.sendSignal(pid, ...)
coroutine.resumeWithTimeout(coroutine.create(function(...)
if signals[pid] then
signals[pid](...)
return true
end
end), 100)
return false
end
kernel.ipc = ipc
kernel.syscalls["ipc_open"] = ipc.open
kernel.syscalls["ipc_close"] = ipc.close
kernel.syscalls["ipc_send"] = ipc.send
kernel.syscalls["ipc_receive"] = ipc.receive
kernel.syscalls["ipc_setSignalHandler"] = ipc.setSignalHandler
kernel.syscalls["ipc_clearSignalHandler"] = ipc.clearSignalHandler
kernel.syscalls["ipc_sendSignal"] = ipc.sendSignal
kernel.log("Loaded IPC module")

View File

@@ -1,13 +0,0 @@
local args = {...}
local kernel = args[1]
kernel.drivers.processes["keventd"]=function()
while true do
local event={kernel.computer:getMachineEvent()}
while event[1]~=nil do
kernel.hpv.sendSignal("all", table.unpack(event))
event={kernel.computer:getMachineEvent()}
end
coroutine.yield()
end
end
kernel.log("Created keventd daemon")

View File

@@ -1,15 +0,0 @@
local args={...}
local kernel=args[1]
local io={}
local iolib={}
io.stdout={}
io.stdin={}
io.stderr={}
iolib.stdout=io.stdout
iolib.stdin =io.stdin
iolib.stderr=io.stderr
function io.register(ttyObj)

View File

@@ -1,22 +0,0 @@
local args = {...}
local kernel = args[1]
kernel.log("Loading third party drivers")
for _,subf in ipairs(kernel.fs.list("/lib/modules/")) do
if kernel.fs.isDir("/lib/modules/"..subf) then
if subf~="Hyperion" then
for _,driver in ipairs(kernel.fs.list("/lib/modules/"..subf)) do
kernel.log("Compiling driver \""..subf..":"..driver.."\"")
local code = kernel.fs.readAllText("/lib/modules/"..subf.."/"..driver)
local func, err = load(code, "@"..driver)
if not func then
kernel.log("DriverCompileErr: "..tostring(err), "ERROR")
else
local ok, err = xpcall(func, debug.traceback, table.unpack(args))
if not ok then
kernel.log("DriverExecErr: "..tostring(err), "ERROR")
end
end
end
end
end
end

View File

@@ -0,0 +1,17 @@
local args={...}
local kernel=args[1]
kernel._G=_G
kernel._U=setmetatable({},{
__index = kernel._G,
__newindex = function(t,k,v)
if kernel.config.allowGlobalOverwrites or kernel.allowGlobalOverwrites then
rawset(t,k,v)
return
end
error("Attempt to modify global variable '"..k.."'",2)
end,
__metatable = false
})
kernel.allowGlobalOverwrites=true
kernel._U._G=kernel._U
kernel.allowGlobalOverwrites=false

View File

@@ -1,14 +0,0 @@
local args = {...}
local kernel = args[1]
kernel.log("initializing third party drivers")
for _,v in ipairs(kernel.drivers.raw) do
if v.arch==kernel.arch then
if v.load then
kernel.log("Loading "..v.name)
local ok,err = xpcall(v.load, debug.traceback)
if not ok then
kernel.log("DriverLoadErr: "..tostring(err))
end
end
end
end

View File

@@ -0,0 +1,65 @@
local kernel = ...
local pam = {}
kernel.pam = pam
local loggedIn = {}
local function getFile(path)
local file = kernel.vfs.open(path, "r")
if not file then error("Failed to open file: "..path) end
local content = kernel.vfs.read(file, 1024000)
kernel.vfs.close(file)
return content
end
local blake2s = require("crypto.blake2s")
if not blake2s then error("Failed to load blake2s") end
if not kernel.vfs.exists("/etc/pam.d/secret") then
local key = ""
for i=1, 256 do
key=key..string.char(math.random(1,255))
end
local handle = kernel.vfs.open("/etc/pam.d/secret", "w")
kernel.vfs.write(handle, key)
kernel.vfs.close(handle)
end
local pepper = getFile("/etc/pam.d/secret")
function pam.authenticate(username, password)
local fpasswd = getFile("/etc/passwd")
local fshadow = getFile("/etc/shadow")
local passwdLines = string.split(fpasswd, "\n")
local shadowLines = string.split(fshadow, "\n")
local passwd = {}
local shadow = {}
for _, line in ipairs(passwdLines) do
local fields = string.split(line, ":")
passwd[fields[1]] = fields
end
for _, line in ipairs(shadowLines) do
local fields = string.split(line, ":")
shadow[fields[1]] = fields
end
for user, fields in pairs(passwd) do
if user == username then
local shadowPasswd = string.split(shadow[user][2], "$")
local salt = shadowPasswd[2]
local hashedPassword = blake2s(password .. salt, pepper)
if hashedPassword == shadowPasswd[3] then
loggedIn[username] = kernel.newUUID()
return loggedIn[username]
else
return false
end
end
end
end
function pam.authToken(username, token)
return loggedIn[username] == token
end

View File

@@ -0,0 +1,211 @@
local kernel = ...
local tasks = {}
local sys = {}
local nextpid = 2
kernel.exitMain=false
function sys.spawn(func, name, envars, args, tgid, fshandles)
local id = nextpid
nextpid = nextpid + 1
tasks[tostring(id)] = {
coro=coroutine.create(function()
local ok, err = xpcall(func, debug.traceback, table.unpack(args or {}))
if not ok then
tasks[tostring(id)].status="Z"
tasks[tostring(id)].exit=tostring(err)
else
tasks[tostring(id)].status="Z"
tasks[tostring(id)].exit=err
end
end),
name=name or "task"..tostring(id),
envars=envars or {},
args=args or {},
status="R",
pid=id,
tgid=tgid or kernel.currentTask.tgid,
user=kernel.user,
uid=kernel.uid,
fd=fshandles or {},
exit="",
sleep=0,
ivs=0,
vs=0,
children={},
parent=kernel.currentTask,
siblings=kernel.currentTask.children,
syscallReturn={},
cwd=kernel.currentTask.cwd,
term=kernel.currentTask.term,
timeSlice=0,
lastTime=0,
totalTime=0,
numRuns=0
}
table.insert(kernel.currentTask.children, tasks[tostring(id)])
end
function sys.sleep(ms)
kernel.currentTask.status="S"
kernel.currentTask.sleep=kernel.computer:time()+ms
coroutine.yield()
end
kernel.syscalls["HPV_spawn"]=sys.spawn
kernel.syscalls["HPV_sleep"]=sys.sleep
kernel._G.sleep=function(...)coroutine.yield("HPV_sleep",...)end
local function reapDeadTasks()
for pid, task in pairs(tasks) do
if task.status == "Z" and not task.reapTime then
task.coro = nil
task.ivs = nil
task.vs = nil
task.args = nil
task.envars = nil
task.cwd = nil
task.term = nil
task.numRuns = nil
task.totalTime = nil
task.lastTime = nil
task.timeSlice = nil
task.syscallReturn = nil
task.sleep = nil
for k,v in pairs(task.fd) do
kernel.vfs.close(v)
end
task.fd = nil
task.reapTime = kernel.computer:time() + 30000
elseif task.reapTime and kernel.computer:time() > task.reapTime then
for _,child in ipairs(task.children) do
child.parent = tasks["1"]
child.siblings = tasks["1"].children
table.insert(tasks["1"].children, child)
end
for i, sibling in ipairs(task.siblings) do
if sibling.pid == task.pid then
table.remove(task.siblings, i)
break
end
end
tasks[pid] = nil
end
end
end
local alpha = 0.85
local C_target = 0.01
local Tmin = 0.0005
local Tmax = 0.5
local lambda_budget = 0.08
local lambda_clamp = 0.03
local lambda_var = 0.02
local k_min = 0.5
local k_max = 0.5
local B = 0.01
function kernel.main()
while not kernel.exitMain do
local N = 0
local Tmin_hit = 0
local Tmax_hit = 0
local totalTaskTime = 0
local taskTimes = {}
for pid, task in pairs(tasks) do
if task.status == "S" then
if kernel.computer:time() >= task.sleep then
task.status="R"
task.sleep=0
end
end
if task.status == "R" then
kernel.currentTask = task
kernel.vfs.cwd = task.cwd
kernel.user = task.user
kernel.uid = task.uid
N = N + 1
-- assign adaptive time slice
task.timeSlice = math.min(Tmax, math.max(Tmin, B / (N ^ alpha)))
-- measure execution time
local startTime = kernel.computer:time()
local ret
if kernel.config.preempt then
ret = {coroutine.resumeWithTimeout(task.coro, task.timeSlice, table.unpack(task.syscallReturn))}
else
ret = {coroutine.resume(task.coro, table.unpack(task.syscallReturn))}
end
local elapsed = kernel.computer:time() - startTime
task.lastTime = elapsed
task.totalTime = (task.totalTime or 0) + elapsed
task.numRuns = (task.numRuns or 0) + 1
taskTimes[#taskTimes + 1] = elapsed
totalTaskTime = totalTaskTime + elapsed
if elapsed <= Tmin then Tmin_hit = Tmin_hit + 1 end
if elapsed >= Tmax then Tmax_hit = Tmax_hit + 1 end
-- handle task results
if ret[1] == "error" then
kernel.log("processHandlerException: "..ret[2])
task.status = "Z"
task.exit = "processHandlerException: "..ret[2]
elseif ret[1] == "timeout" then
task.ivs=task.ivs+1
task.syscallReturn = {}
elseif ret[1] == "success" then
task.vs=task.vs+1
if ret[2]=="syscall" then
if kernel.syscalls[ret[3]] then
if kernel.config.debugSyscalls then
kernel.log("Task "..task.pid.." invoking syscall: "..ret[3])
end
local sysret = {xpcall(kernel.syscalls[ret[3]], debug.traceback, table.unpack(ret, 4))}
if kernel.config.debugSyscalls then
if not sysret[1] then
kernel.log("Task "..task.pid.." syscall "..ret[3].." failed: "..tostring(sysret[2]))
else
kernel.log("Task "..task.pid.." syscall "..ret[3].." completed returning "..tostring(#sysret-1).." values")
for i=2,#sysret do
kernel.log(" retval["..tostring(i-1).."] = "..tostring(sysret[i]))
end
end
end
if not sysret[1] then
task.syscallReturn={false, sysret[2]}
else
task.syscallReturn={true, table.unpack(sysret,2)}
end
else
task.syscallReturn={false, "Unknown syscall: "..tostring(ret[3])}
end
end
end
end
end
local T_prev_avg = (N > 0) and (totalTaskTime / N) or 0
local T_prev_var = 0
for _, t in ipairs(taskTimes) do
T_prev_var = T_prev_var + (t - T_prev_avg)^2
end
if N > 0 then T_prev_var = T_prev_var / N end
if N > 0 then
local f_clamp = k_min*(Tmin_hit/N) - k_max*(Tmax_hit/N)
local B_budget = (C_target * (N^(alpha-1))) / math.max(T_prev_avg, 1e-8)
B = B + lambda_budget * (B_budget - B)
+ lambda_clamp * f_clamp
- lambda_var * T_prev_var
end
-- clean up dead tasks
reapDeadTasks()
end
end
kernel.tasks=tasks
kernel.hpv=sys

View File

@@ -0,0 +1,6 @@
local kernel=...
local debug=debug
kernel._G.debug={
getinfo=debug.getinfo,
traceback=debug.traceback
}

View File

@@ -0,0 +1,125 @@
local kernel=...
kernel.tty={}
function kernel.tty.register(tty, ttyo)
kernel.tty[tty]=ttyo
end
function kernel.tty.print(text)
local term=kernel.currentTask.term
if term and kernel.tty[term] then
kernel.tty[term].print(text)
end
end
function kernel.tty.printInline(text)
local term=kernel.currentTask.term
if term and kernel.tty[term] then
kernel.tty[term].printInline(text)
end
end
function kernel.tty.size()
local term=kernel.currentTask.term
if term and kernel.tty[term] then
return kernel.tty[term].size()
end
end
function kernel.tty.setCursorPos(x,y)
local term=kernel.currentTask.term
if term and kernel.tty[term] then
return kernel.tty[term].setCursorPos(x,y)
end
end
function kernel.tty.getCursorPos()
local term=kernel.currentTask.term
if term and kernel.tty[term] then
return kernel.tty[term].getCursorPos()
end
end
function kernel.tty.clear()
local term=kernel.currentTask.term
if term and kernel.tty[term] then
return kernel.tty[term].clear()
end
end
function kernel.tty.setTextColor(color)
local term=kernel.currentTask.term
if term and kernel.tty[term] then
return kernel.tty[term].setTextColor(color)
end
end
function kernel.tty.setBackgroundColor(color)
local term=kernel.currentTask.term
if term and kernel.tty[term] then
return kernel.tty[term].setBackgroundColor(color)
end
end
function kernel.tty.scroll(n)
local term=kernel.currentTask.term
if term and kernel.tty[term] then
return kernel.tty[term].scroll(n)
end
end
function kernel.tty.getTextColor()
local term=kernel.currentTask.term
if term and kernel.tty[term] and kernel.tty[term].getTextColor then
return kernel.tty[term].getTextColor()
end
end
function kernel.tty.getBackgroundColor()
local term=kernel.currentTask.term
if term and kernel.tty[term] and kernel.tty[term].getBackgroundColor then
return kernel.tty[term].getBackgroundColor()
end
end
function kernel.tty.bind(ttyid)
if not ttyid then
return false, "No TTY ID specified"
end
if not kernel.tty[ttyid] then
return false, "TTY "..tostring(ttyid).." not registered"
end
kernel.currentTask.term=ttyid
return true
end
function kernel.tty.unbind()
kernel.currentTask.term=false
end
function kernel.tty.isBound()
return kernel.currentTask.term ~= nil
end
function kernel.tty.getBoundTTY()
return kernel.currentTask.term
end
kernel.syscalls["TTY_print"]=kernel.tty.print
kernel.syscalls["TTY_printInline"]=kernel.tty.printInline
kernel.syscalls["TTY_size"]=kernel.tty.size
kernel.syscalls["TTY_setCursorPos"]=kernel.tty.setCursorPos
kernel.syscalls["TTY_getCursorPos"]=kernel.tty.getCursorPos
kernel.syscalls["TTY_clear"]=kernel.tty.clear
kernel.syscalls["TTY_setTextColor"]=kernel.tty.setTextColor
kernel.syscalls["TTY_setBackgroundColor"]=kernel.tty.setBackgroundColor
kernel.syscalls["TTY_scroll"]=kernel.tty.scroll
kernel.syscalls["TTY_getTextColor"]=kernel.tty.getTextColor
kernel.syscalls["TTY_getBackgroundColor"]=kernel.tty.getBackgroundColor
kernel.syscalls["TTY_bind"]=kernel.tty.bind
kernel.syscalls["TTY_unbind"]=kernel.tty.unbind
kernel.syscalls["TTY_isBound"]=kernel.tty.isBound
kernel.syscalls["TTY_getBoundTTY"]=kernel.tty.getBoundTTY
kernel.log("TTY module loaded attempting to register console tty")
kernel.status="init"

View File

@@ -0,0 +1,2 @@
local kernel=...
kernel.tty.bind("tty0")

View File

@@ -0,0 +1,28 @@
local kernel=...
function print(...)
coroutine.yield()
local args={...}
local output=""
for i=1,#args do
output=output..tostring(args[i]).."\t"
end
output=output:sub(1,-2)
kernel.tty.print(output)
end
function printf(fmt, ...)
coroutine.yield()
local output=string.format(fmt,...)
kernel.tty.print(output)
end
function printInline(...)
coroutine.yield()
local args={...}
local output=""
for i=1,#args do
output=output..tostring(args[i]).."\t"
end
output=output:sub(1,-2)
kernel.tty.printInline(output)
end

View File

@@ -1,251 +1,44 @@
local args = {...} local kernel = ...
local kernel = args[1] kernel.log("Loading init system...")
local tasks={} kernel.log("InitPath: "..kernel.config.initPath)
local currentTask={} local handle = kernel.vfs.open(kernel.config.initPath, "r")
local signals={} local data = kernel.vfs.read(handle, 1024 * 1024 * 4)
local tid=2 kernel.vfs.close(handle)
local gid=2
local hookuuid=0
local sys={}
function sys.hookSignal(sig, func) local initFunc, err = load(data, "@sysinit")
if not currentTask.signal[sig] then if not initFunc then
currentTask.signal[sig]={} error("Failed to load init system: "..err)
end
hookuuid=hookuuid+1
currentTask.signal[sig][tostring(hookuuid)]=func
callbackid=tostring(hookuuid)
return {
remove=function()
currentTask.signal[sig][callbackid]=nil
end
}
end end
function sys.clearSignalHooks(typ) kernel.tasks["1"] = {
if not typ or typ == "all" then
signals[tostring(currentTask.pid)]={}
currentTask.signal=signals[tostring(currentTask.pid)]
else
if currentTask.signal[typ] then
currentTask.signal[typ]={}
end
end
end
function sys.sendSignal(pid, signal, ...)
if pid=="all" then
for i,v in pairs(tasks) do
v.sigQ[#v.sigQ+1]={signal, ...}
end
return
end
if not tasks[tostring(pid)] then return false end
tasks[tostring(pid)].sigQ[#tasks[tostring(pid)].sigQ+1]={signal, ...}
return true
end
function sys.flushSigs()
local sigs = {}
for i,v in ipairs(currentTask.sigQ) do
sigs[i]=v
end
for i=1, #sigs do
local sig = sigs[i]
if currentTask.signal[sig[1]] then
for k,v in pairs(currentTask.signal[sig[1]]) do
coroutine.resumeWithTimeout(coroutine.create(function()
local ok,err = xpcall(v,debug.traceback,table.unpack(sig))
if not ok and sig[1]~="callbackErr" then
sys.sendSignal(currentTask.pid, "callbackErr", sig[1], k, err)
end
end),10)
end
else
for k,v in pairs(currentTask.signal["unhandledSignal"]) do
coroutine.resumeWithTimeout(coroutine.create(function()
local ok,err = xpcall(v,debug.traceback,table.unpack(sig))
if not ok and sig[1]~="callbackErr" then
sys.sendSignal(currentTask.pid, "callbackErr", sig[1], k, err)
end
end),10)
end
end
end
end
function sys.spawn(func, name, evars, args)
local id=tid
tid=tid+1
name=name or tostring(id)
signals[tostring(id)]={}
tasks[tostring(id)]={
coro=coroutine.create(function() coro=coroutine.create(function()
local ret = {xpcall(func, debug.traceback, table.unpack(args))} local ok, err = xpcall(initFunc, debug.traceback, kernel)
if not ret[1] then
sys.sendSignal(currentTask.ppid, "ChildTaskError", id, err)
else
sys.sendSignal(currentTask.ppid, "ChildTaskExit", id, table.unpack(ret, 2))
end
currentTask.status="Z"
end),
name=name,
pid=id,
cwd=currentTask.cwd,
ppid=currentTask.pid,
tgid=currentTask.tgid,
user=kernel.user,
uid=kernel.uid,
evars=evars,
args=args,
vy=0,
ivy=0,
status="R",
sleep=0,
signal=signals[tostring(id)],
parent=currentTask,
children={},
sibling=currentTask.children,
sigQ={}
}
return id
end
function sys.spawnFromFile(path, name, envars, args)
sys.spawn(kernel.fs.load(path), name, envars, args)
end
function sys.spawnAndWait(func, name, envars, args)
local id=sys.spawn(func, name, envars, args)
local exit = false
local errored = false
local rets = {}
local hext=sys.hookSignal("ChildTaskExit",function(pid, ...)
if pid==id then
rets={...}
exit=true
end
end)
local herr=sys.hookSignal("ChildTaskError",function(pid, ...)
if pid==id then
rets={...}
exit=true
errored=true
end
end)
while not exit do
coroutine.yield()
end
return not errored, table.unpack(rets)
end
function sys.spawnFromFileAndWait(path, name, envars, args)
return sys.spawnAndWait(kernel.fs.load(path), name, envars, args)
end
function sys.exit(...)
sys.sendSignal(currentTask.ppid, "ChildTaskExit", currentTask.pid, ...)
currentTask.status="Z"
coroutine.yield()
end
local function collectZombieProc()
local ret = {}
for _,v in pairs(tasks) do
if v.status=="Z" then
local pid = v.pid
for _,c in ipairs(v.children) do
c.parent=tasks["1"]
c.sibling=tasks["1"].children
c.ppid=1
c.tgid=1
end
signals[tostring(pid)]=nil
tasks[tostring(pid)]=nil
table.insert(ret, pid)
end
end
return ret
end
kernel.log("initPath is: " .. tostring(kernel.initPath))
signals["1"]={}
tasks["1"]={
coro=coroutine.create(function()
local ok, code_or_err = xpcall(function() return kernel.fs.readAllText(kernel.initPath) end, debug.traceback)
if not ok then currentTask.status="Z"; kernel.panic(code_or_err) end
local code = code_or_err
local func, err = load(code, "@SysInit", nil, kernel._U)
if not func then currentTask.status="Z"; kernel.panic(err) end
local ok, err = xpcall(func, debug.traceback, kernel)
if not ok then if not ok then
currentTask.status="Z" kernel.panic("Init system crashed: "..tostring(err))
kernel.panic(err)
else else
currentTask.status="Z" kernel.panic("Init system exited: "..tostring(err))
kernel.panic("Attempted to kill init!")
end end
end), end),
name="SysInit", name="sysinit",
status="R",
pid=1, pid=1,
cwd="",
ppid=0,
tgid=1, tgid=1,
user="root", user="root",
uid=0, uid=0,
evars={}, fd={},
args={kernel}, exit="",
vy=0,
ivy=0,
status="R",
sleep=0, sleep=0,
signal=signals["1"], ivs=0,
parent={name="Hyprkrnl",pid=0}, vs=0,
parent=kernel.kernelTask,
siblings=kernel.kernelTask.children,
children={}, children={},
sibling={}, syscallReturn={},
sigQ={} cwd="/",
timeSlice=0,
lastTime=0,
totalTime=0,
numRuns=0
} }
tasks["1"].sibling={tasks["1"]} kernel.log("created init task with PID 1")
kernel.log("Initializing init system...")
kernel.log("Created pid 1")
kernel.cache.preload.sys=sys
kernel.cache.preload.system=kernel.cache.preload.sys
kernel.cache.preload.os=kernel.cache.preload.sys
kernel.hpv=sys
kernel.tasks=tasks
kernel.signals=signals
kernel.currentTask=currentTask
kernel.saveLog()
kernel.status="running"
while kernel.status~="Panic" do
for k,v in pairs(tasks) do
currentTask=v
kernel.computer:print(currentTask.name)
kernel.currentTask=v
kernel.process=currentTask.name
kernel.user=currentTask.user
kernel.uid=currentTask.uid
kernel.fs.setCwd(currentTask.cwd)
sys.flushSigs()
local status = coroutine.resumeWithTimeout(currentTask.coro, 50)
if status then
currentTask.vy=currentTask.vy+1
else
currentTask.ivy=currentTask.ivy+1
end
currentTask.cwd=kernel.fs.getCwd()
end
collectZombieProc()
end
kernel.process="Kernel"
kernel.user="root"
kernel.uid=0
kernel.panic(kernel.reason or "Exited pid 0")

View File

@@ -1,40 +1,41 @@
local fs={} local fs={}
-- 1 : open -- "VFS_open" : open
-- 2 : read -- "VFS_read" : read
-- 3 : write -- "VFS_write" : write
-- 4 : close -- "VFS_close" : close
function fs.open(path, mode) function fs.open(path, mode)
local fd=cororoutine.yield(1,path,mode) local fd=syscall.VFS_open(path,mode)
local ret={ local ret={
close=function() close=function()
-- close file -- close file
return coroutine.yield(4,fd) return syscall.VFS_close(fd)
end, end,
flush=function() flush=function()
-- close and reopen file to flush buffers -- close and reopen file to flush buffers
coroutine.yield(4,fd) syscall.VFS_close(fd)
fd=coroutine.yield(1,path,mode) fd=syscall.VFS_open(path,mode)
end end
} }
if mode=="r" then if mode=="r" then
ret.read=function(count) ret.read=function(count)
return coroutine.yield(2,fd,count) local data = syscall.VFS_read(fd,count)
return data
end end
ret.readAll=function() ret.readAll=function(chunkSize)
local chunks={} -- to store read chunks local chunks={} -- to store read chunks
while true do while true do
local chunk=coroutine.yield(2,fd,math.huge) local chunk=syscall.VFS_read(fd,chunkSize or 65536)
if chunk==nil or #chunk==0 then break end if chunk==nil or #chunk==0 then break end
table.insert(chunks,chunk) table.insert(chunks,chunk)
end end
return table.concat(chunks) return table.concat(chunks)
end end
ret.readLine = function() ret.readLine = function(chunkSize)
local buffer = {} -- stores leftover data local buffer = {} -- stores leftover data
local buffer_str = "" -- concatenated buffer local buffer_str = "" -- concatenated buffer
local chunk_size = 4096 -- adjust chunk size for performance local chunk_size = chunkSize or 65536 -- adjust chunk size for performance
local eof = false local eof = false
while true do while true do
@@ -58,7 +59,7 @@ function fs.open(path, mode)
end end
-- Read the next chunk -- Read the next chunk
local chunk = coroutine.yield(2, fd, chunk_size) local chunk = syscall.VFS_read(fd, chunk_size)
if not chunk or chunk == "" then if not chunk or chunk == "" then
eof = true eof = true
else else
@@ -69,12 +70,12 @@ function fs.open(path, mode)
elseif mode=="w" then elseif mode=="w" then
ret.write=function(data) ret.write=function(data)
-- write data to file -- write data to file
return coroutine.yield(3,fd,data) return syscall.VFS_write(fd,data)
end end
elseif mode=="a" then elseif mode=="a" then
ret.write=function(data) ret.write=function(data)
-- append data to file -- append data to file
return coroutine.yield(3,fd,data) return syscall.VFS_write(fd,data)
end end
else else
error("Invalid mode '"..mode.."'",2) error("Invalid mode '"..mode.."'",2)
@@ -104,35 +105,35 @@ function fs.appendAllText(path, data)
end end
function fs.mkdir(path) function fs.mkdir(path)
coroutine.yield(8,path) return syscall.VFS_mkdir(path)
end end
function fs.remove(path) function fs.remove(path)
coroutine.yield(9,path) return syscall.VFS_remove(path)
end end
function fs.list(path) function fs.list(path)
return coroutine.yield(5,path) return syscall.VFS_list(path)
end end
function fs.type(path) function fs.type(path)
return coroutine.yield(6,path) return syscall.VFS_type(path)
end end
function fs.attributes(path) function fs.attributes(path)
return coroutine.yield(7,path) return syscall.VFS_attributes(path)
end end
function fs.exists(path) function fs.exists(path)
return coroutine.yield(10, path) return syscall.VFS_exists(path)
end end
function fs.getcwd() function fs.getcwd()
return coroutine.yield(11) return syscall.VFS_getcwd()
end end
function fs.setcwd(path) function fs.setcwd(path)
return coroutine.yield(12, path) return syscall.VFS_setcwd(path)
end end
return fs return fs

View File

@@ -1,5 +1,5 @@
local sys = {} local sys = {}
local fs = require("fs") local fs = require("sys.fs")
function sys.spawn(func, name, envars, args) function sys.spawn(func, name, envars, args)
return coroutine.yield(0x10, func, name, envars, args) return coroutine.yield(0x10, func, name, envars, args)
@@ -18,12 +18,12 @@ function sys.spawnFromFile(path, name, envars, args)
end end
function sys.spawnAndWait(func, name, envars, args) function sys.spawnAndWait(func, name, envars, args)
local pid = coroutine.yield(0x10, func, name, envars, args) local task = coroutine.yield(0x10, func, name, envars, args)
local oldsignal = sys.getSignalHandler(17) local oldsignal = sys.getSignalHandler(17)
local exit = false local exit = false
sys.setSignalHandler(17, function() sys.setSignalHandler(17, function()
local tasks = sys.getChildrenTasks(pid) local tasks = sys.getChildrenTasks(task)
if not tasks[pid] then if not tasks[task] then
exit = true exit = true
end end
end) end)
@@ -31,7 +31,7 @@ function sys.spawnAndWait(func, name, envars, args)
coroutine.yield() coroutine.yield()
end end
sys.setSignalHandler(17, oldsignal) sys.setSignalHandler(17, oldsignal)
return pid return task
end end
function sys.spawnFromFileAndWait(path, name, envars, args) function sys.spawnFromFileAndWait(path, name, envars, args)
@@ -47,28 +47,11 @@ function sys.spawnFromFileAndWait(path, name, envars, args)
end end
function sys.exit(code) function sys.exit(code)
return coroutine.yield(0x14, code) return coroutine.yield(0x11, code)
end end
function sys.setSignalHandler(signal, func) function sys.getTaskInfo(task)
return coroutine.yield(0x11, signal, func) return coroutine.yield(0x12, task)
end
function sys.sendSignal(pid, signal)
return coroutine.yield(0x12, pid, signal)
end
function sys.getSignalHandler(signal)
return coroutine.yield(0x13, signal)
end
function sys.getChildrenTasks(PID)
PID = PID or sys.getCurrentTaskID()
return coroutine.yield(0x15, PID)
end
function sys.getCurrentTaskID()
return coroutine.yield(0x16)
end end
return sys return sys

5
Build/lib/sys/init Normal file
View File

@@ -0,0 +1,5 @@
local sys = {}
sys.fs = require("sys.fs")
sys.hpv = require("sys.hpv")
sys.ipc = require("sys.ipc")
return sys

3
Build/lib/sys/ipc Normal file
View File

@@ -0,0 +1,3 @@
local ipc = {}
return ipc

71
Build/lib/sys/term Normal file
View File

@@ -0,0 +1,71 @@
local term = {}
function term.clear()
coroutine.yield("VFS_write", 1, "\27C\25")
end
function term.setCursorPos(x, y)
coroutine.yield("VFS_write", 1, "\27cs"..tostring(y)..";"..tostring(x).."\25")
end
function term.size()
coroutine.yield("VFS_write", 1, "\27ts\25")
local ok, data = coroutine.yield("VFS_read", 0, 16) -- read response
if not ok then error("Failed to get terminal size") end
local x, y = string.match(data, "%R(%d+);(%d+)\25")
return tonumber(x), tonumber(y)
end
function term.getCursorPos()
coroutine.yield("VFS_write", 1, "\27gc\25")
local ok, data = coroutine.yield("VFS_read", 0, 16) -- read response
if not ok then error("Failed to get cursor position") end
local y, x = string.match(data, "%R(%d+);(%d+)\25")
return tonumber(x), tonumber(y)
end
function term.write(data)
coroutine.yield("VFS_write", 1, data)
end
function term.setTextColor(color)
local ok, err = coroutine.yield("VFS_type", 1)
if not ok then error(err) end
if ok ~= "tty" then return end
coroutine.yield("VFS_write", 1, "\27f"..tostring(color).."\25")
end
function term.setBackgroundColor(color)
local ok, err = coroutine.yield("VFS_type", 1)
if not ok then error(err) end
if ok ~= "tty" then return end
coroutine.yield("VFS_write", 1, "\27b"..tostring(color).."\25")
end
function term.isColor()
local ok, err = coroutine.yield("VFS_type", 1)
if not ok then error(err) end
return ok == "tty"
end
function term.scroll(n)
coroutine.yield("VFS_write", 1, "\27S"..tostring(n).."\25")
end
function term.setDefault(color, layer)
if layer then
coroutine.yield("VFS_write", 1, "\27F"..tostring(color).."\25")
else
coroutine.yield("VFS_write", 1, "\27B"..tostring(color).."\25")
end
end
function term.showCursor(show)
if show then
coroutine.yield("VFS_write", 1, "\27sc\25")
else
coroutine.yield("VFS_write", 1, "\27hc\25")
end
end
return term

View File

@@ -1,11 +0,0 @@
local userdata={}
userdata.policy={}
userdata.policy.readOnly=1
userdata.policy.readWrite=2
userdata.policy.WriteOnly=3
userdata.policy.hidden=4
userdata.policy.custom=5
function userdata.create()
return setmetatable()
end

View File

@@ -1,6 +0,0 @@
local args={...}
local kernel=args[1]
for i,v in pairs(kernel.drivers.processes) do
os.spawn(v, i, {}, {})
end
kernel.fs.load("/bin/bash")()

82
Build/sbin/init.lua Normal file
View File

@@ -0,0 +1,82 @@
local kernel=...
local fs=require("sys.fs")
syscall.TTY_bind("tty0")
local files = fs.list("/bin/startup")
if not files then error("Failed to list /bin/startup") end
for i,v in ipairs(files) do
if v:sub(-4) == ".lua" then
local filepath = "/bin/startup/" .. v
kernel.log("Executing startup script: " .. filepath, "INFO")
local startupFunc, err = load(fs.readAllText(filepath), "@" .. filepath)
if not startupFunc then
kernel.log("Error loading startup script '" .. filepath .. "': " .. err, "ERROR")
else
kernel.hpv.spawn(function()
local status, err = pcall(startupFunc)
if not status then
kernel.log("Error executing startup script '" .. filepath .. "': " .. err, "ERROR")
else
kernel.log("Successfully executed startup script: " .. filepath, "INFO")
end
end, "startup:" .. v)
end
end
end
local function serialize(table, seen)
seen = seen or {}
if seen[tostring(table)] then
return "\"<circular reference>\""
end
seen[tostring(table)] = true
local output = "{"
for i,v in pairs(table) do
local coma=true
if type(i) == "string" then
output=output.."[\""..i.."\"]="
elseif type(i) == "number" then
output=output.."["..tostring(i).."]="
end
if type(v) == "table" then
if v == table then
output=string.sub(output,1,#output-(#i+1))
coma=false
else
output=output..serialize(v, seen)
end
elseif type(v) == "string" then
output=output.."[=["..v.."]=]"
elseif type(v) == "number" then
output=output..tostring(v)
elseif type(v) == "boolean" then
if v == true then
output=output.."true"
else
output=output.."false"
end
elseif type(v) == "function" then
output=output..tostring(v)
elseif type(v) == "userdata" then
output=output..tostring(v)
elseif type(v) == "thread" then
output=output..tostring(v)
else
error("serialization of type \""..type(v).."\" is not supported")
end
if coma then
output=output..","
end
end
if #table>0 or string.sub(output,#output,#output) == "," then
output=string.sub(output,1,#output-1)
end
output=output.."}"
return output
end
while true do
--print(serialize(kernel.tasks))
kernel.saveLog()
sleep(1000)
end

View File

@@ -1,4 +1,7 @@
local args={...} local args={...}
<<<<<<< HEAD
local sys = require("sys")
=======
local os=require("os") local os=require("os")
local io=require("io") local io=require("io")
local text="" local text=""
@@ -18,3 +21,4 @@ os.hookSignal("keyTyped", function(_, screen, key)
end end
end) end)
>>>>>>> 9b268810a7ea44e586d5faf6e2717f1d02497c03

View File

View File

@@ -0,0 +1,17 @@
print(".. *. ..")
print(" *= +@* +* ")
print(" .@#. -@@@= :#@. ")
print(" =@@+ *@@@# +@@= ")
print(" %@@%: *@@@# -%@@% ")
print(" :@@@@+ *@@@# .*@@@@: ")
print(" :*@@@%- *@@@# -@@@@*: ")
print(" =%@@#. *@@@# .#@@%= ")
print(" :=. :*@@= *@@@# =@@+: .=: ")
print(" %@#=..*# +@@@# #*..=#@# ")
print(" .@@@@+=# .%@%: #=+@@@@. ")
print(" .....=# -@= *+...:. ")
print(" -*%*-@= - =@-*%*- ")
print(" -@*. -@%. :%@- :*@- ")
print(" .#@#@* ")
print(" -#- ")
print(" ")

View File

@@ -0,0 +1 @@
print("hello from hello.lua")

View File

@@ -0,0 +1,151 @@
-- bit32.lua
-- Full pure-Lua implementation of Lua 5.2 bit32 library
-- NO Lua 5.3 operators used
local bit32 = {}
local MOD32 = 2^32
local MOD31 = 2^31
local function norm(x)
return x % MOD32
end
-- Convert number to bit table
local function tobits(x)
x = norm(x)
local t = {}
for i = 0, 31 do
local b = x % 2
t[i] = b
x = (x - b) / 2
end
return t
end
-- Convert bit table to number
local function frombits(t)
local x = 0
local p = 1
for i = 0, 31 do
if t[i] == 1 then
x = x + p
end
p = p * 2
end
return norm(x)
end
-- ===== Logical ops =====
function bit32.band(...)
local args = {...}
if #args == 0 then return 0xFFFFFFFF end
local bits = tobits(args[1])
for i = 2, #args do
local b = tobits(args[i])
for j = 0, 31 do
bits[j] = (bits[j] == 1 and b[j] == 1) and 1 or 0
end
end
return frombits(bits)
end
function bit32.bor(...)
local args = {...}
if #args == 0 then return 0 end
local bits = tobits(args[1])
for i = 2, #args do
local b = tobits(args[i])
for j = 0, 31 do
bits[j] = (bits[j] == 1 or b[j] == 1) and 1 or 0
end
end
return frombits(bits)
end
function bit32.bxor(...)
local args = {...}
if #args == 0 then return 0 end
local bits = tobits(args[1])
for i = 2, #args do
local b = tobits(args[i])
for j = 0, 31 do
bits[j] = (bits[j] ~= b[j]) and 1 or 0
end
end
return frombits(bits)
end
function bit32.bnot(x)
local bits = tobits(x)
for i = 0, 31 do
bits[i] = bits[i] == 1 and 0 or 1
end
return frombits(bits)
end
-- ===== Shifts =====
function bit32.lshift(x, n)
return norm(norm(x) * 2^n)
end
function bit32.rshift(x, n)
return math.floor(norm(x) / 2^n)
end
function bit32.arshift(x, n)
x = norm(x)
if x >= MOD31 then
return math.floor((x - MOD32) / 2^n)
else
return math.floor(x / 2^n)
end
end
-- ===== Rotates =====
function bit32.lrotate(x, n)
n = n % 32
x = norm(x)
local left = (x * 2^n) % MOD32
local right = math.floor(x / 2^(32 - n))
return norm(left + right)
end
function bit32.rrotate(x, n)
n = n % 32
x = norm(x)
local right = math.floor(x / 2^n)
local left = (x * 2^(32 - n)) % MOD32
return norm(left + right)
end
-- ===== Bit fields =====
function bit32.extract(x, field, width)
width = width or 1
return bit32.band(bit32.rshift(x, field), 2^width - 1)
end
function bit32.replace(x, v, field, width)
width = width or 1
local mask = bit32.lshift(2^width - 1, field)
x = bit32.band(x, bit32.bnot(mask))
return bit32.bor(x, bit32.lshift(v, field))
end
-- ===== Test =====
function bit32.test(x, ...)
local args = {...}
for i = 1, #args do
if bit32.band(x, args[i]) ~= 0 then
return true
end
end
return false
end
return bit32

View File

@@ -0,0 +1,116 @@
-- blake2s.lua
-- Pure Lua 5.2, 32-bit only, supports keyed hashing
local bit32 = require("bit32")
local band, bor, bxor = bit32.band, bit32.bor, bit32.bxor
local rshift, lshift = bit32.rshift, bit32.lshift
local MOD32 = 2^32
local function rotr(x, n)
return bor(rshift(x, n), lshift(x, 32 - n))
end
local IV = {
0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19
}
local SIGMA = {
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15},
{14,10,4,8,9,15,13,6,1,12,0,2,11,7,5,3},
{11,8,12,0,5,2,15,13,10,14,3,6,7,1,9,4},
{7,9,3,1,13,12,11,14,2,6,5,10,4,0,15,8},
{9,0,5,7,2,4,10,15,14,1,11,12,6,8,3,13},
{2,12,6,10,0,11,8,3,4,13,7,5,15,14,1,9},
{12,5,1,15,14,13,4,10,0,7,6,3,9,2,8,11},
{13,11,7,14,12,1,3,9,5,0,15,4,8,6,2,10},
{6,15,14,9,11,3,0,8,12,2,13,7,1,4,10,5},
{10,2,8,4,7,6,1,5,15,11,9,14,3,12,13,0}
}
local function G(v, a, b, c, d, x, y)
v[a] = (v[a] + v[b] + x) % MOD32
v[d] = rotr(bxor(v[d], v[a]), 16)
v[c] = (v[c] + v[d]) % MOD32
v[b] = rotr(bxor(v[b], v[c]), 12)
v[a] = (v[a] + v[b] + y) % MOD32
v[d] = rotr(bxor(v[d], v[a]), 8)
v[c] = (v[c] + v[d]) % MOD32
v[b] = rotr(bxor(v[b], v[c]), 7)
end
local function compress(h, block, t, last)
local v = {}
for i = 1, 8 do v[i] = h[i] end
for i = 1, 8 do v[i + 8] = IV[i] end
v[13] = bxor(v[13], t)
if last then
v[15] = bxor(v[15], 0xFFFFFFFF)
end
local m = {}
for i = 0, 15 do
local p = i * 4 + 1
m[i] =
(block:byte(p) or 0) +
((block:byte(p + 1) or 0) * 0x100) +
((block:byte(p + 2) or 0) * 0x10000) +
((block:byte(p + 3) or 0) * 0x1000000)
end
for r = 1, 10 do
local s = SIGMA[r]
G(v,1,5,9,13, m[s[1]], m[s[2]])
G(v,2,6,10,14, m[s[3]], m[s[4]])
G(v,3,7,11,15, m[s[5]], m[s[6]])
G(v,4,8,12,16, m[s[7]], m[s[8]])
G(v,1,6,11,16, m[s[9]], m[s[10]])
G(v,2,7,12,13, m[s[11]], m[s[12]])
G(v,3,8,9,14, m[s[13]], m[s[14]])
G(v,4,5,10,15, m[s[15]], m[s[16]])
end
for i = 1, 8 do
h[i] = bxor(h[i], v[i], v[i + 8])
end
end
local function blake2s(msg, key)
key = key or ""
local h = {}
for i = 1, 8 do h[i] = IV[i] end
local outlen = 32 -- bytes
h[1] = bxor(
h[1],
0x01010000 + lshift(#key, 8) + outlen
)
local t = 0
if #key > 0 then
local block = key .. string.rep("\0", 64 - #key)
t = #key
compress(h, block, t, false)
end
for i = 1, #msg, 64 do
local block = msg:sub(i, i + 63)
if #block < 64 then
block = block .. string.rep("\0", 64 - #block)
end
t = t + math.min(64, #msg - i + 1)
compress(h, block, t, i + 64 > #msg)
end
local out = ""
for i = 1, 8 do
out = out .. string.format("%08x", h[i])
end
return out
end
return blake2s

View File

View File

View File

@@ -0,0 +1,139 @@
local fs={}
-- "VFS_open" : open
-- "VFS_read" : read
-- "VFS_write" : write
-- "VFS_close" : close
function fs.open(path, mode)
local fd=syscall.VFS_open(path,mode)
local ret={
close=function()
-- close file
return syscall.VFS_close(fd)
end,
flush=function()
-- close and reopen file to flush buffers
syscall.VFS_close(fd)
fd=syscall.VFS_open(path,mode)
end
}
if mode=="r" then
ret.read=function(count)
local data = syscall.VFS_read(fd,count)
return data
end
ret.readAll=function(chunkSize)
local chunks={} -- to store read chunks
while true do
local chunk=syscall.VFS_read(fd,chunkSize or 65536)
if chunk==nil or #chunk==0 then break end
table.insert(chunks,chunk)
end
return table.concat(chunks)
end
ret.readLine = function(chunkSize)
local buffer = {} -- stores leftover data
local buffer_str = "" -- concatenated buffer
local chunk_size = chunkSize or 65536 -- adjust chunk size for performance
local eof = false
while true do
-- Try to find a newline in the current buffer
local line_end = buffer_str:find("\n")
if line_end then
local line = buffer_str:sub(1, line_end - 1)
buffer_str = buffer_str:sub(line_end + 1)
return line
end
-- If EOF was reached previously and buffer is empty, stop
if eof then
if buffer_str ~= "" then
local last_line = buffer_str
buffer_str = ""
return last_line
else
return nil
end
end
-- Read the next chunk
local chunk = syscall.VFS_read(fd, chunk_size)
if not chunk or chunk == "" then
eof = true
else
buffer_str = buffer_str .. chunk
end
end
end
elseif mode=="w" then
ret.write=function(data)
-- write data to file
return syscall.VFS_write(fd,data)
end
elseif mode=="a" then
ret.write=function(data)
-- append data to file
return syscall.VFS_write(fd,data)
end
else
error("Invalid mode '"..mode.."'",2)
end
return ret
end
function fs.readAllText(path)
local file=fs.open(path,"r")
if not file then return false end
local content=file.readAll()
file.close()
return content
end
function fs.writeAllText(path, data)
local file=fs.open(path,"w")
file.write(data)
file.close()
end
function fs.appendAllText(path, data)
local file=fs.open(path,"a")
if not file then return false end
file.write(data)
file.close()
end
function fs.mkdir(path)
return syscall.VFS_mkdir(path)
end
function fs.remove(path)
return syscall.VFS_remove(path)
end
function fs.list(path)
return syscall.VFS_list(path)
end
function fs.type(path)
return syscall.VFS_type(path)
end
function fs.attributes(path)
return syscall.VFS_attributes(path)
end
function fs.exists(path)
return syscall.VFS_exists(path)
end
function fs.getcwd()
return syscall.VFS_getcwd()
end
function fs.setcwd(path)
return syscall.VFS_setcwd(path)
end
return fs

View File

@@ -0,0 +1,57 @@
local sys = {}
local fs = require("sys.fs")
function sys.spawn(func, name, envars, args)
return coroutine.yield(0x10, func, name, envars, args)
end
function sys.spawnFromFile(path, name, envars, args)
local data = fs.readAllText(path)
if not data then
error("File not found: "..path,2)
end
local func, err = load(data, "@"..path)
if not func then
error("Error loading file "..path..": "..tostring(err),2)
end
return coroutine.yield(0x10, func, name, envars, args)
end
function sys.spawnAndWait(func, name, envars, args)
local task = coroutine.yield(0x10, func, name, envars, args)
local oldsignal = sys.getSignalHandler(17)
local exit = false
sys.setSignalHandler(17, function()
local tasks = sys.getChildrenTasks(task)
if not tasks[task] then
exit = true
end
end)
while not exit do
coroutine.yield()
end
sys.setSignalHandler(17, oldsignal)
return task
end
function sys.spawnFromFileAndWait(path, name, envars, args)
local data = fs.readAllText(path)
if not data then
error("File not found: "..path,2)
end
local func, err = load(data, "@"..path)
if not func then
error("Error loading file "..path..": "..tostring(err),2)
end
return sys.spawnAndWait(func, name, envars, args)
end
function sys.exit(code)
return coroutine.yield(0x11, code)
end
function sys.getTaskInfo(task)
return coroutine.yield(0x12, task)
end
return sys

View File

@@ -0,0 +1,5 @@
local sys = {}
sys.fs = require("sys.fs")
sys.hpv = require("sys.hpv")
sys.ipc = require("sys.ipc")
return sys

View File

@@ -0,0 +1,3 @@
local ipc = {}
return ipc

View File

@@ -0,0 +1,71 @@
local term = {}
function term.clear()
coroutine.yield("VFS_write", 1, "\27C\25")
end
function term.setCursorPos(x, y)
coroutine.yield("VFS_write", 1, "\27cs"..tostring(y)..";"..tostring(x).."\25")
end
function term.size()
coroutine.yield("VFS_write", 1, "\27ts\25")
local ok, data = coroutine.yield("VFS_read", 0, 16) -- read response
if not ok then error("Failed to get terminal size") end
local x, y = string.match(data, "%R(%d+);(%d+)\25")
return tonumber(x), tonumber(y)
end
function term.getCursorPos()
coroutine.yield("VFS_write", 1, "\27gc\25")
local ok, data = coroutine.yield("VFS_read", 0, 16) -- read response
if not ok then error("Failed to get cursor position") end
local y, x = string.match(data, "%R(%d+);(%d+)\25")
return tonumber(x), tonumber(y)
end
function term.write(data)
coroutine.yield("VFS_write", 1, data)
end
function term.setTextColor(color)
local ok, err = coroutine.yield("VFS_type", 1)
if not ok then error(err) end
if ok ~= "tty" then return end
coroutine.yield("VFS_write", 1, "\27f"..tostring(color).."\25")
end
function term.setBackgroundColor(color)
local ok, err = coroutine.yield("VFS_type", 1)
if not ok then error(err) end
if ok ~= "tty" then return end
coroutine.yield("VFS_write", 1, "\27b"..tostring(color).."\25")
end
function term.isColor()
local ok, err = coroutine.yield("VFS_type", 1)
if not ok then error(err) end
return ok == "tty"
end
function term.scroll(n)
coroutine.yield("VFS_write", 1, "\27S"..tostring(n).."\25")
end
function term.setDefault(color, layer)
if layer then
coroutine.yield("VFS_write", 1, "\27F"..tostring(color).."\25")
else
coroutine.yield("VFS_write", 1, "\27B"..tostring(color).."\25")
end
end
function term.showCursor(show)
if show then
coroutine.yield("VFS_write", 1, "\27sc\25")
else
coroutine.yield("VFS_write", 1, "\27hc\25")
end
end
return term

View File

@@ -1,11 +0,0 @@
local userdata={}
userdata.policy={}
userdata.policy.readOnly=1
userdata.policy.readWrite=2
userdata.policy.WriteOnly=3
userdata.policy.hidden=4
userdata.policy.custom=5
function userdata.create()
return setmetatable()
end

View File

@@ -1,7 +0,0 @@
local args={...}
local kernel=args[1]
local os=require("os")
for i,v in pairs(kernel.drivers.processes) do
os.spawn(v, i, {}, {})
end
kernel.fs.load("/bin/bash")()

View File

@@ -0,0 +1,82 @@
local kernel=...
local fs=require("sys.fs")
syscall.TTY_bind("tty0")
local files = fs.list("/bin/startup")
if not files then error("Failed to list /bin/startup") end
for i,v in ipairs(files) do
if v:sub(-4) == ".lua" then
local filepath = "/bin/startup/" .. v
kernel.log("Executing startup script: " .. filepath, "INFO")
local startupFunc, err = load(fs.readAllText(filepath), "@" .. filepath)
if not startupFunc then
kernel.log("Error loading startup script '" .. filepath .. "': " .. err, "ERROR")
else
kernel.hpv.spawn(function()
local status, err = pcall(startupFunc)
if not status then
kernel.log("Error executing startup script '" .. filepath .. "': " .. err, "ERROR")
else
kernel.log("Successfully executed startup script: " .. filepath, "INFO")
end
end, "startup:" .. v)
end
end
end
local function serialize(table, seen)
seen = seen or {}
if seen[tostring(table)] then
return "\"<circular reference>\""
end
seen[tostring(table)] = true
local output = "{"
for i,v in pairs(table) do
local coma=true
if type(i) == "string" then
output=output.."[\""..i.."\"]="
elseif type(i) == "number" then
output=output.."["..tostring(i).."]="
end
if type(v) == "table" then
if v == table then
output=string.sub(output,1,#output-(#i+1))
coma=false
else
output=output..serialize(v, seen)
end
elseif type(v) == "string" then
output=output.."[=["..v.."]=]"
elseif type(v) == "number" then
output=output..tostring(v)
elseif type(v) == "boolean" then
if v == true then
output=output.."true"
else
output=output.."false"
end
elseif type(v) == "function" then
output=output..tostring(v)
elseif type(v) == "userdata" then
output=output..tostring(v)
elseif type(v) == "thread" then
output=output..tostring(v)
else
error("serialization of type \""..type(v).."\" is not supported")
end
if coma then
output=output..","
end
end
if #table>0 or string.sub(output,#output,#output) == "," then
output=string.sub(output,1,#output-1)
end
output=output.."}"
return output
end
while true do
kernel.log(serialize(kernel.tasks))
kernel.saveLog()
sleep(1000)
end

View File

@@ -1,3 +1,4 @@
local BOOT_DRIVE_PATH="/$"
local term = term local term = term
local os = os local os = os
-- Function to write text to the terminal with special character handling -- Function to write text to the terminal with special character handling
@@ -100,6 +101,7 @@ local ok, err = xpcall(function()
} }
-- Move all non-Lua standard library globals into the apis table -- Move all non-Lua standard library globals into the apis table
local debug = debug
for i,v in pairs(_G) do for i,v in pairs(_G) do
if not lua[i] or lua[i]==nil then if not lua[i] or lua[i]==nil then
apis[i]=v apis[i]=v
@@ -108,7 +110,7 @@ local ok, err = xpcall(function()
end end
function sleep(time) function sleep(time)
local stoptime = apis.os.clock() + (time*1000) local stoptime = apis.os.clock() + (time)
while stoptime > apis.os.clock() do end while stoptime > apis.os.clock() do end
end end
@@ -140,9 +142,9 @@ local ok, err = xpcall(function()
end end
-- Load kernel first if it fails, we can't continue so we display an error -- Load kernel first if it fails, we can't continue so we display an error
local Kernel = load(getFile("/$/boot/kernel.lua"),"@Kernel") local Kernel = load(getFile(BOOT_DRIVE_PATH.."/boot/kernel.lua"),"@Kernel")
local initFs = load(getFile("/$/boot/cct/initdisks","@Init_disks"))(apis) local initFs = load(getFile(BOOT_DRIVE_PATH.."/boot/cct/initdisks","@Init_disks"))(apis)
local fs = load(getFile("/$/boot/initfs"),"@InitFs")() local fs = load(getFile(BOOT_DRIVE_PATH.."/boot/initfs"),"@InitFs")()
if not Kernel then if not Kernel then
displaySuperBadError("Could not load kernel.") displaySuperBadError("Could not load kernel.")
end end
@@ -168,7 +170,7 @@ local ok, err = xpcall(function()
-- Set up computer api -- Set up computer api
local computer = { local computer = {
time = function() return apis.os.epoch("utc") end, time = function() return apis.os.epoch("utc") end,
clock = apis.os.clock, clock = function() return apis.os.clock()/1000 end,
shutdown = apis.os.shutdown, shutdown = apis.os.shutdown,
reboot = apis.os.reboot, reboot = apis.os.reboot,
getMachineEvent = function() getMachineEvent = function()
@@ -260,13 +262,13 @@ local ok, err = xpcall(function()
end end
end, "", 1000) end, "", 1000)
local ret = {coroutine.resume(co, ...)} local ret = {coroutine.resume(co, ...)}
if ret[1]=="timeout" then if ret[1] and ret[2]=="timeout" then
return true, "Coroutine timed out" return "timeout"
elseif ret[1]==false then elseif ret[1]==false then
return false, ret[2] return "error", ret[2]
else else
debug.sethook(co) debug.sethook(co)
return computer.time()-startTime, table.unpack(ret) return "success", table.unpack(ret, 2)
end end
end end
@@ -296,12 +298,13 @@ local ok, err = xpcall(function()
exit=true exit=true
end end
end end
if status == false or coroutine.status(kernelCoro)=="dead" then if status == "error" or coroutine.status(kernelCoro)=="dead" then
displaySuperBadError("Kernel error: "..tostring(err)) displaySuperBadError("Kernel error: "..tostring(err))
coroutine.yield("key") coroutine.yield("key")
end end
end end
end, debug.traceback) end, debug.traceback)
if not ok then if not ok then
displaySuperBadError("Fatal error during boot: "..err) displaySuperBadError("Fatal error during boot: "..err)
end end

View File

@@ -1,3 +1,5 @@
sleep(1)
local BOOT_DRIVE_PATH="/$"
-- UnBIOS by JackMacWindows -- UnBIOS by JackMacWindows
-- This will undo most of the changes/additions made in the BIOS, but some things may remain wrapped if `debug` is unavailable -- This will undo most of the changes/additions made in the BIOS, but some things may remain wrapped if `debug` is unavailable
-- To use, just place a `bios.lua` in the root of the drive, and run this program -- To use, just place a `bios.lua` in the root of the drive, and run this program
@@ -58,7 +60,7 @@ function _G.term.native()
term.setCursorPos(1, 1) term.setCursorPos(1, 1)
term.setCursorBlink(true) term.setCursorBlink(true)
term.clear() term.clear()
local file = fs.open("/$/boot/cct/boot.lua", "r") local file = fs.open(BOOT_DRIVE_PATH.."/boot/cct/boot.lua", "r")
if file == nil then if file == nil then
term.setCursorBlink(false) term.setCursorBlink(false)
term.setTextColor(16384) term.setTextColor(16384)

View File

@@ -1,4 +1,5 @@
local apis = ({...})[1] local apis = ({...})[1]
local BOOT_DRIVE_PATH="/$"
local fs = apis.fs local fs = apis.fs
local native = apis.peripheral local native = apis.peripheral
local peripheral = {} local peripheral = {}
@@ -125,7 +126,7 @@ end
--------------------------------------------------------- ---------------------------------------------------------
-- INTERNAL DISK "$" (mapped to "/") -- INTERNAL DISK "$" (mapped to "/")
--------------------------------------------------------- ---------------------------------------------------------
internal["$"] = createDisk("$", "/$", false, { internal["$"] = createDisk("$", BOOT_DRIVE_PATH, false, {
setLabel=function(label) setLabel=function(label)
local h = fs.open("/.label", "w") local h = fs.open("/.label", "w")
h.write(label) h.write(label)

View File

@@ -23,4 +23,4 @@ function driver.main()
-- Nothing to run -- Nothing to run
end end
kernel.drivers.register(driver) -- kernel.drivers.register(driver)

View File

@@ -0,0 +1,181 @@
local kernel=...
local apis=kernel.apis
local main=apis.term
local native=apis.peripheral
local sides = {"top", "bottom", "left", "right", "front", "back"}
local function getType(name)
if native.isPresent(name) then
return native.getType(name)
end
for n = 1, #sides do
local side = sides[n]
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
return native.call(side, "getTypeRemote", name)
end
end
return nil
end
local function getNames()
local names = {}
for n = 1, #sides do
local side = sides[n]
if native.isPresent(side) then
table.insert(names, side)
end
if native.hasType(side, "peripheral_hub") then
local hubSides = native.call(side, "getConnectedSides")
for _, hubSide in ipairs(hubSides) do
table.insert(names, hubSide)
end
end
end
return names
end
local function wrapPeripheral(name)
if native.isPresent(name) then
return native.wrap(name)
end
for n = 1, #sides do
local side = sides[n]
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
return native.call(side, "wrapRemote", name)
end
end
return nil
end
local colors={
[0]=0x000000, -- #000000
0xFFFFFF, -- #FFFFFF
0xFF0000, -- #FF0000
0x00FF00, -- #00FF00
0x0000FF, -- #0000FF
0x00FFFF, -- #00FFFF
0xFF00FF, -- #FF00FF
0xFFFF00, -- #FFFF00
0xFF6D00, -- #FF6D00
0x6DFF55, -- #6DFF55
0x24FFFF, -- #24FFFF
0x924900, -- #924900
0x6D6D55, -- #6D6D55
0xDBDBAA, -- #DBDBAA
0x6D00FF, -- #6D00FF
0xB6FF00 -- #B6FF00
}
local icolors={
[0x1] =0, -- #000000
[0x2] =1, -- #FFFFFF
[0x4] =2, -- #FF0000
[0x8] =3, -- #00FF00
[0x10] =4, -- #0000FF
[0x20] =5, -- #00FFFF
[0x40] =6, -- #FF00FF
[0x80] =7, -- #FFFF00
[0x100] =8, -- #FF6D00
[0x200] =9, -- #6DFF55
[0x400] =10, -- #24FFFF
[0x800] =11, -- #924900
[0x1000] =12, -- #6D6D55
[0x2000] =13, -- #DBDBAA
[0x4000] =14, -- #6D00FF
[0x8000] =15 -- #B6FF00
}
local function write(text, term)
local x, y = term.getCursorPos()
local w, h = term.getSize()
for i = 1, #text do
local c = text:sub(i, i)
if c == "\n" then
y = y + 1
x = 1
elseif c == "\t" then
local tabSize = 4
local spaces = tabSize - ((x - 1) % tabSize)
term.write(string.rep(" ", spaces))
x = x + spaces
elseif c == "\b" then
if x > 1 then
x = x - 1
term.setCursorPos(x, y)
term.write(" ")
term.setCursorPos(x, y)
end
else
if x <= w and y <= h then
term.setCursorPos(x, y)
term.write(c)
x = x + 1
end
end
-- Handle wrapping if we go past right edge
if x > w then
x = 1
y = y + 1
end
-- Handle scrolling if we go past bottom
if y-1 > h then
term.scroll(1)
y = h
term.setCursorPos(x, y)
end
end
term.setCursorPos(x, y)
end
local function newTTY(term)
local ret={}
function ret.print(text)
write(text.."\n", term)
end
function ret.printInline(text)
write(text, term)
end
function ret.clear()
term.clear()
term.setCursorPos(1,1)
end
function ret.setCursorPos(x,y)
term.setCursorPos(x,y)
end
function ret.getCursorPos()
return term.getCursorPos()
end
function ret.getSize()
return term.getSize()
end
function ret.setBackgroundColor(color)
term.setBackgroundColor(colors[color])
end
function ret.setTextColor(color)
term.setTextColor(colors[color])
end
function ret.getBackgroundColor()
return icolors[term.getBackgroundColor()]
end
function ret.getTextColor()
return icolors[term.getTextColor()]
end
return ret
end
kernel.tty.register("tty0", newTTY(main))
for _, name in ipairs(getNames()) do
local t = getType(name)
if t == "monitor" then
local monitorTerm = wrapPeripheral(name)
monitorTerm.setTextScale(0.5)
kernel.tty.register(name, newTTY(monitorTerm))
end
end

View File

@@ -1,105 +0,0 @@
local args={...}
local kernel=args[1]
local apis=kernel.apis
local native=apis.peripheral
local driver={}
local sides = {"top", "bottom", "left", "right", "front", "back"}
local function getType(name)
if native.isPresent(name) then
return native.getType(name)
end
for n = 1, #sides do
local side = sides[n]
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
return native.call(side, "getTypeRemote", name)
end
end
return nil
end
local function getNames()
local names = {}
for n = 1, #sides do
local side = sides[n]
if native.isPresent(side) then
table.insert(names, side)
end
if native.hasType(side, "peripheral_hub") then
local hubSides = native.call(side, "getConnectedSides")
for _, hubSide in ipairs(hubSides) do
table.insert(names, hubSide)
end
end
end
return names
end
driver.name="CCT TTY Module"
driver.version="0.1.0"
driver.type="tty"
driver.description="CCT TTY Module Kernel Module"
driver.arch="cct"
driver.author="HyperionOS Dev Team"
driver.license="MIT"
driver.api={}
local colors={
[0]=0x000000, -- #000000
0xFFFFFF, -- #FFFFFF
0xFF0000, -- #FF0000
0x00FF00, -- #00FF00
0x0000FF, -- #0000FF
0x00FFFF, -- #00FFFF
0xFF00FF, -- #FF00FF
0xFFFF00, -- #FFFF00
0xFF6D00, -- #FF6D00
0x6DFF55, -- #6DFF55
0x24FFFF, -- #24FFFF
0x924900, -- #924900
0x6D6D55, -- #6D6D55
0xDBDBAA, -- #DBDBAA
0x6D00FF, -- #6D00FF
0xB6FF00 -- #B6FF00
}
local icolors={
[0x1] =0, -- #000000
[0x2] =1, -- #FFFFFF
[0x4] =2, -- #FF0000
[0x8] =3, -- #00FF00
[0x10] =4, -- #0000FF
[0x20] =5, -- #00FFFF
[0x40] =6, -- #FF00FF
[0x80] =7, -- #FFFF00
[0x100] =8, -- #FF6D00
[0x200] =9, -- #6DFF55
[0x400] =10, -- #24FFFF
[0x800] =11, -- #924900
[0x1000] =12, -- #6D6D55
[0x2000] =13, -- #DBDBAA
[0x4000] =14, -- #6D00FF
[0x8000] =15 -- #B6FF00
}
local function getAllScreens()
end
local function wrapScreens()
end
function driver.load()
-- Nothing to load
end
function driver.unload()
-- Nothing to unload
end
function driver.main()
-- Nothing to run
end
kernel.drivers.register(driver)

View File

@@ -1,3 +1,2 @@
U $;/ U $;/
U devfs0000;/dev/ U devfs0000;/dev/
U sysfs0000;/sys/

View File

@@ -49,15 +49,23 @@ function fs.remove(path)
end end
function fs.readAllText(path) function fs.readAllText(path)
local disk, newPath = resolve(path) local disk, newPath = resolve(path)
return disk:readAllText(newPath) local handle = disk:open(newPath, "r")
if not handle then return nil end
local content = handle.readAll()
handle.close()
return content
end end
function fs.writeAllText(path, text) function fs.writeAllText(path, text)
local disk, newPath = resolve(path) local disk, newPath = resolve(path)
return disk:writeAllText(newPath, text) local handle = disk:open(newPath, "w")
handle.write(text)
handle.close()
end end
function fs.appendAllText(path, text) function fs.appendAllText(path, text)
local disk, newPath = resolve(path) local disk, newPath = resolve(path)
return disk:appendAllText(newPath, text) local handle = disk:open(newPath, "a")
handle.write(text)
handle.close()
end end
function fs.load(path) function fs.load(path)
return load(fs.readAllText(path), path) return load(fs.readAllText(path), path)

View File

@@ -2,7 +2,6 @@ local args = {...}
local apis = args[1] local apis = args[1]
local disks = args[2] local disks = args[2]
local arch = args[3] local arch = args[3]
local initPath = args[4]
local screen = args[5] local screen = args[5]
local computer = args[6] local computer = args[6]
local ifs = args[7] local ifs = args[7]
@@ -20,13 +19,20 @@ kernel.cache = {}
kernel.cache.preload = {} kernel.cache.preload = {}
kernel._G=_G kernel._G=_G
kernel.sleep=sleep kernel.sleep=sleep
kernel.debug=true
_G.sleep=nil _G.sleep=nil
local windowsExp = false local windowsExp = false
function kernel.log(msg, level) function kernel.log(msg, level)
LOG_Text = LOG_Text..tostring(computer.time()).." "..kernel.user.." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg.."\n" LOG_Text = LOG_Text..tostring(computer:time()).." "..kernel.user.." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg.."\n"
if kernel.status == "start" then if kernel.status == "start" then
screen:print(tostring(computer.time()).." "..kernel.user.." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg) screen:print(tostring(computer:time()).." "..kernel.user.." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg)
elseif kernel.status == "init" then
kernel.standbyTask=kernel.currentTask
kernel.currentTask=kernel.kernelTask
kernel.tty.print(tostring(computer:time()).." "..kernel.user.." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg)
kernel.currentTask=kernel.standbyTask
end end
end end
@@ -76,9 +82,13 @@ kernel.log("Kernel loaded.")
kernel.log("Mounting init disks...") kernel.log("Mounting init disks...")
disks.refresh() disks.refresh()
ifs.update(disks) ifs.update(disks)
kernel.disks={}
for _,v in disks.list() do
kernel.disks[v.address] = v
end
ifs.mount("$", "/") ifs.mount("$", "/")
local fstab=ifs.readAllText("/etc/fstab") local fstab=ifs.readAllText("/boot/fstab")
local split = function(str, delim, maxResultCountOrNil) local split = function(str, delim, maxResultCountOrNil)
assert(#delim == 1, "only delim len 1 supported for now") assert(#delim == 1, "only delim len 1 supported for now")
maxResultCountOrNil = (maxResultCountOrNil or 0)-1 maxResultCountOrNil = (maxResultCountOrNil or 0)-1
@@ -97,6 +107,33 @@ local split = function(str, delim, maxResultCountOrNil)
return rv return rv
end end
if not ifs.isFile("/boot/boot.cfg") then
kernel.log("boot.cfg missing or corrupted!, Attempting to write recovery boot.cfg", "ERROR")
ifs.writeAllText("/boot/boot.cfg",[[
-- DO NOT EDIT THIS FILE IF YOU DO NOT KNOW WHAT YOU ARE DOING!
-- DOING SO MAY RENDER YOUR SYSTEM UNBOOTABLE!
-- This file is auto-generated during the build process.
-- RECOVERY BOOT CONFIGURATION FILE
return {
initPath = "/sbin/init.lua",
maxOpenFiles = 128,
maxFilesPerTask = 16,
preempt=true
}
]])
end
local initCfgFunc, err = load(ifs.readAllText("/boot/boot.cfg"), "@boot.cfg")
if not initCfgFunc then
kernel.PANIC("Failed to load /boot/boot.cfg: "..tostring(err))
end
local initCfgStatus, config = pcall(initCfgFunc)
if not initCfgStatus then
kernel.PANIC("Error in /boot/boot.cfg: "..tostring(config))
end
kernel.config = config
for i,v in ipairs(split(fstab,"\n")) do for i,v in ipairs(split(fstab,"\n")) do
if v:sub(1,1)=="U" then if v:sub(1,1)=="U" then
local id="" local id=""
@@ -131,7 +168,7 @@ function kernel.newFifo()
return fifo return fifo
end end
function kernel.generateUUID() function kernel.newUUID()
local template = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx" local template = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"
local uuid = "" local uuid = ""
for i = 1, #template do for i = 1, #template do
@@ -147,45 +184,67 @@ function kernel.generateUUID()
return uuid return uuid
end end
kernel.syscalls={[0]=0} kernel.syscalls={}
for i=1, 100 do
kernel.syscalls[i]=0
end
function kernel.registerSyscall(name, func)
kernel.syscalls[name]=func
end
local modules={[0]={}} local modules={[0]={}}
for i=0, 100 do for i=0, 100 do
modules[i]={} modules[i]={}
end end
kernel.log("Gathering modules") kernel.log("Gathering modules")
for i,v in ipairs(ifs.list("/lib/modules/Hyperion/")) do for _, i in ipairs(ifs.list("/lib/modules")) do
for _,v in ipairs(ifs.list("/lib/modules/"..i)) do
local prior=tonumber(v:sub(1,2)) local prior=tonumber(v:sub(1,2))
modules[prior+1][#modules[prior+1]+1]="/lib/modules/Hyperion/"..v modules[prior+1][#modules[prior+1]+1]="/lib/modules/"..i.."/"..v
end
end end
kernel.ifs=ifs kernel.ifs=ifs
kernel.apis=apis kernel.apis=apis
kernel.computer=computer kernel.computer=computer
kernel.initPath=initPath
kernel.arch=arch kernel.arch=arch
kernel.initdisks=disks kernel.initdisks=disks
kernel.screen=screen kernel.screen=screen
kernel.processes={} kernel.processes={}
kernel.fstab=fstab
kernel.kernelTask = {
name="kernel",
status="R",
pid=0,
tgid=0,
user="root",
uid=0,
fd={},
exit="",
sleep=0,
ivs=0,
vs=0,
children={},
syscallReturn={},
cwd="/",
timeSlice=0,
lastTime=0,
totalTime=0,
numRuns=0
}
kernel.currentTask = kernel.kernelTask
kernel.log("Running modules") kernel.log("Running modules")
for _,p in ipairs(modules) do for _,p in ipairs(modules) do
for _,v in ipairs(p) do for _,v in ipairs(p) do
local code=ifs.readAllText(v) local code=ifs.readAllText(v)
if not code then
kernel.log("ModuReadErr: "..v, "WARN")
goto skip
end
local func,err=load(code,"@"..v) local func,err=load(code,"@"..v)
if not func then kernel.panic("ModuLoadErr: "..tostring(err), "WARN") goto skip end if not func then kernel.panic("ModuLoadErr: "..tostring(err)) goto skip end
local status, err = xpcall(func,debug.traceback, kernel) local status, err = xpcall(func,debug.traceback, kernel)
if not status then kernel.panic("ModuRunErr: "..tostring(err), "WARN") end if not status then kernel.panic("ModuRunErr: "..tostring(err)) end
::skip:: ::skip::
end end
end end
kernel.log("Kernel initialized successfully.") kernel.log("Kernel initialized successfully.")
kernel.main() kernel.main()
kernel.PANIC("Execution complete") kernel.PANIC("Execution complete")

View File

@@ -1,5 +1,3 @@
local args={...}
local kernel=args[1]
function string.hasSuffix(str, suffix) function string.hasSuffix(str, suffix)
return string.sub(str, #suffix+1) == suffix return string.sub(str, #suffix+1) == suffix
end end
@@ -158,6 +156,8 @@ local function serialize(table)
local coma=true local coma=true
if type(i) == "string" then if type(i) == "string" then
output=output.."[\""..i.."\"]=" output=output.."[\""..i.."\"]="
elseif type(i) == "number" then
output=output.."["..tostring(i).."]="
end end
if type(v) == "table" then if type(v) == "table" then
if v == table then if v == table then
@@ -194,7 +194,10 @@ end
local oldtype=type local oldtype=type
local oldgetmetatable=getmetatable local oldgetmetatable=getmetatable
function type(object) function type(object, trueType)
if trueType then
return oldtype(object)
end
if oldtype(object)~="table" then if oldtype(object)~="table" then
return oldtype(object) return oldtype(object)
else else
@@ -224,7 +227,7 @@ function getmetatable(object)
end end
end end
function isEqual(a, ...) function isEqualToAny(a, ...)
local args={...} local args={...}
for i=0, #args do for i=0, #args do
if a==args[i] then if a==args[i] then
@@ -234,5 +237,48 @@ function isEqual(a, ...)
return false return false
end end
function isEqualToAll(a, ...)
local args={...}
for i=0, #args do
if a~=args[i] then
return false
end
end
return true
end
function table.keys(t)
local a = {}
for n in pairs(t) do table.insert(a, n) end
return a
end
function table.values(t)
local a = {}
for _, n in pairs(t) do table.insert(a, n) end
return a
end
function table.indexOf(t, value)
for i,v in ipairs(t) do
if v==value then
return i
end
end
return -1
end
syscall = setmetatable({}, {
__index = function(self, name)
return function(...)
local res = table.pack(coroutine.yield("syscall", name, ...))
if res[1] then
return table.unpack(res, 2, res.n)
else
error(res[2], 2)
end
end
end
})
table.serialize=serialize table.serialize=serialize
kernel.log("Loaded stdlib")

View File

@@ -1,3 +0,0 @@
local args={...}
local kernel=args[1]
kernel._U=table.proxy(_G)

View File

@@ -1,41 +1,207 @@
local kernel = ... local kernel = ...
local openFiles = {}
kernel.openFiles = openFiles
local vfs = {} local vfs = {}
vfs.mounts = {} vfs.mounts = { ["$"] = "/" }
local disks = kernel.disks local disks = kernel.disks
vfs.cwd = ""
-- Path handling
local function normalizePath(path)
local parts = {}
for part in path:gmatch("[^/]+") do
if part == ".." then
if #parts > 0 then table.remove(parts) end
elseif part ~= "." and part ~= "" then
table.insert(parts, part)
end
end
return "/" .. table.concat(parts, "/") .. (path:sub(-1) == "/" and "/" or "")
end
local function resolvePath(path) local function resolvePath(path)
local task = kernel.currentTask
local cwd = task.cwd or "/"
if path:sub(1,1) ~= "/" then
path = cwd .. path
end
path = normalizePath(path)
local mountPoint = "/" local mountPoint = "/"
local mountId = "$" local mountId = "$"
if path:sub(1,1)~="/" then path=vfs.cwd..path end
for k,v in pairs(vfs.mounts) do for k,v in pairs(vfs.mounts) do
if path:sub(1,#v) == v and #v > #mountPoint then if path:sub(1,#v) == v and #v > #mountPoint then
mountPoint = v mountPoint = v
mountId = k mountId = k
end end
end end
local diskPath = path:sub(#mountPoint + 1) local diskPath = path:sub(#mountPoint + 1)
return disks[mountId], diskPath return disks[mountId], diskPath
end end
-- File object creation
local function newFileObject(disk, handle, mode, path)
return {
disk = disk,
handle = handle,
mode = mode,
path = path,
refcount = 1
}
end
local function allocFD(task)
local fd = 0
while task.fd[fd] do fd = fd + 1 end
return fd
end
local function allocFD(task)
-- enforce per-task limit
local count = 0
for _ in pairs(task.fd) do count = count + 1 end
if count >= kernel.config.maxFilesPerTask then
error("EMFILE") -- Too many open files in this task
end
-- find first free FD
local fd = 0
while task.fd[fd] do fd = fd + 1 end
return fd
end
local function checkSystemLimit()
-- enforce system-wide limit
local total = 0
for _, task in pairs(kernel.tasks or {}) do
for _ in pairs(task.fd) do total = total + 1 end
end
if total >= kernel.config.maxOpenFiles then
error("ENFILE") -- Too many open files in the system
end
end
-- VFS syscalls
function vfs.open(path, mode)
local task = kernel.currentTask
-- check limits
checkSystemLimit()
local disk, diskPath = resolvePath(path)
if not disk then
error("No disk mounted for path '"..path.."'")
end
local handle = disk:open(diskPath, mode)
if not handle then return nil end
local file = newFileObject(disk.address, handle, mode, path)
local fd = allocFD(task)
task.fd[fd] = file
return fd
end
function vfs.close(fd)
local task = kernel.currentTask
local file = task.fd[fd]
if not file then error("EBADF") end
task.fd[fd] = nil
file.refcount = file.refcount - 1
if file.refcount == 0 then
file.handle.close()
end
return true
end
function vfs.read(fd, count)
local file = kernel.currentTask.fd[fd]
if not file then error("EBADF") end
if not file.mode:find("r") then error("File not open for reading") end
return file.handle.read(count)
end
function vfs.write(fd, data)
local file = kernel.currentTask.fd[fd]
if not file then error("EBADF") end
if not file.mode:find("w") then error("File not open for writing") end
return file.handle.write(data)
end
function vfs.whereis(fd)
local file = kernel.currentTask.fd[fd]
if not file then error("EBADF") end
return file.path
end
-- Filesystem operations
function vfs.mkdir(path)
local disk, diskPath = resolvePath(path)
if not disk then error("No disk mounted") end
return disk:makeDirectory(diskPath)
end
function vfs.remove(path)
local disk, diskPath = resolvePath(path)
if not disk then error("No disk mounted") end
return disk:remove(diskPath)
end
function vfs.attributes(path)
if type(path) == "number" then
local file = kernel.currentTask.fd[path]
if not file then error("EBADF") end
return disks[file.disk]:attributes(file.path)
end
local disk, diskPath = resolvePath(path)
if not disk then error("No disk mounted") end
return disk:attributes(diskPath)
end
function vfs.list(path)
local disk, diskPath = resolvePath(path)
if not disk then error("No disk mounted") end
return disk:list(diskPath)
end
function vfs.exists(path)
local disk, diskPath = resolvePath(path)
if not disk then return false end
return disk:directoryExists(diskPath) or disk:fileExists(diskPath)
end
function vfs.type(path)
if type(path) == "number" then
local file = kernel.currentTask.fd[path]
if not file then error("EBADF") end
return disks[file.disk]:type(file.path)
end
local disk, diskPath = resolvePath(path)
if not disk then error("No disk mounted") end
return disk:type(diskPath)
end
-- CWD
function vfs.getcwd()
return kernel.currentTask.cwd
end
function vfs.setcwd(path)
if path:sub(-1) ~= "/" then path = path .. "/" end
if path:sub(1,1) ~= "/" then path = "/" .. path end
kernel.currentTask.cwd = normalizePath(path)
end
-- Mounting
function vfs.mount(diskId, path) function vfs.mount(diskId, path)
if kernel.uid ~= 0 then error("Permission denied") end if kernel.uid ~= 0 then error("Permission denied") end
if not disks[diskId] then if not disks[diskId] then error("Unknown disk '"..diskId.."'") end
error("Attempted to mount unknown disk '"..diskId.."'") if path:sub(-1) ~= "/" then path = path .. "/" end
return false
end for _,v in pairs(vfs.mounts) do
if vfs.mounts[diskId] then if v == path then error("Mount point already used") end
error("Disk '"..diskId.."' is already mounted")
return false
end
if path:sub(#path,#path)~="/" then path=path.."/" end
for i,v in pairs(vfs.mounts) do
if v == path then
error("Mount point '"..path.."' is already in use")
return false
end
end end
vfs.mounts[diskId] = path vfs.mounts[diskId] = path
end end
@@ -51,135 +217,61 @@ function vfs.unmount(path)
return false return false
end end
function vfs.open(path, mode) function vfs.getMounts()
local disk, diskPath = resolvePath(path) return vfs.mounts
if not disk then
error("No disk mounted for path '"..path.."'")
return nil
end
local uuid = kernel.newUUID()
openFiles[uuid] = {disk=disk.address, path=path, mode=mode, handle=disk:open(diskPath, mode)}
return uuid
end end
function vfs.close(fileId) function vfs.virtdisk(obj)
local file = openFiles[fileId] kernel.disks[obj.address] = obj
if not file then kernel.log("Registered virtual disk at "..obj.address)
error("Invalid file handle")
return false
end
local disk = disks[file.disk]
disk:close(file.handle)
openFiles[fileId] = nil
return true
end end
function vfs.read(fileId, count) -- Redirect file operations to VFS
local file = openFiles[fileId] function vfs.dup(oldfd)
if not file then local task = kernel.currentTask
error("Invalid file handle") local file = task.fd[oldfd]
return nil if not file then error("EBADF") end
end
if not file.mode:find("r") then local newfd = allocFD(task)
error("File not opened in read mode") task.fd[newfd] = file
return nil file.refcount = file.refcount + 1
end return newfd
local disk = disks[file.disk]
return disk:read(file.handle, count)
end end
function vfs.write(fileId, data) function vfs.dup2(oldfd, newfd)
local file = openFiles[fileId] local task = kernel.currentTask
if not file then local file = task.fd[oldfd]
error("Invalid file handle") if not file then error("EBADF") end
return false
end if oldfd == newfd then return newfd end
if not file.mode:find("w") then
error("File not opened in write mode") if task.fd[newfd] then
return false vfs.close(newfd)
end
local disk = disks[file.disk]
return disk:write(file.handle, data)
end end
function vfs.mkdir(path) task.fd[newfd] = file
local disk, diskPath = resolvePath(path) file.refcount = file.refcount + 1
if not disk then return newfd
error("No disk mounted for path '"..path.."'")
return false
end
return disk:mkdir(diskPath)
end
function vfs.remove(path)
local disk, diskPath = resolvePath(path)
if not disk then
error("No disk mounted for path '"..path.."'")
return false
end
return disk:remove(diskPath)
end
function vfs.atributes(path)
local disk, diskPath = resolvePath(path)
if not disk then
error("No disk mounted for path '"..path.."'")
return nil
end
return disk:attributes(diskPath)
end
function vfs.list(path)
local disk, diskPath = resolvePath(path)
if not disk then
error("No disk mounted for path '"..path.."'")
return nil
end
return disk:list(diskPath)
end
function vfs.exists(path)
local disk, diskPath = resolvePath(path)
if not disk then
error("No disk mounted for path '"..path.."'")
return false
end
return disk:directoryExists(diskPath) or disk:fileExists(diskPath)
end
function vfs.type(path)
local disk, diskPath = resolvePath(path)
if not disk then
error("No disk mounted for path '"..path.."'")
return nil
end
return disk:type(diskPath)
end
function vfs.getcwd()
return vfs.cwd
end
function vfs.setcwd(path)
if path:sub(#path,#path)~="/" then path=path.."/" end
if path:sub(1,1)~="/" then path="/"..path end
vfs.cwd=path
end end
-- Syscall registration
kernel.vfs = vfs kernel.vfs = vfs
kernel.registerSyscall(0x01, vfs.open) kernel.syscalls["VFS_open"] = vfs.open
kernel.registerSyscall(0x02, vfs.read) kernel.syscalls["VFS_read"] = vfs.read
kernel.registerSyscall(0x03, vfs.write) kernel.syscalls["VFS_write"] = vfs.write
kernel.registerSyscall(0x04, vfs.close) kernel.syscalls["VFS_close"] = vfs.close
kernel.registerSyscall(0x05, vfs.list) kernel.syscalls["VFS_list"] = vfs.list
kernel.registerSyscall(0x06, vfs.type) kernel.syscalls["VFS_type"] = vfs.type
kernel.registerSyscall(0x07, vfs.atributes) kernel.syscalls["VFS_attributes"] = vfs.attributes
kernel.registerSyscall(0x08, vfs.mkdir) kernel.syscalls["VFS_mkdir"] = vfs.mkdir
kernel.registerSyscall(0x09, vfs.remove) kernel.syscalls["VFS_remove"] = vfs.remove
kernel.registerSyscall(0x0a, vfs.exists) kernel.syscalls["VFS_exists"] = vfs.exists
kernel.registerSyscall(0x0b, vfs.mount) kernel.syscalls["VFS_mount"] = vfs.mount
kernel.registerSyscall(0x0c, vfs.unmount) kernel.syscalls["VFS_unmount"] = vfs.unmount
kernel.registerSyscall(0x0d, vfs.getcwd) kernel.syscalls["VFS_getcwd"] = vfs.getcwd
kernel.registerSyscall(0x0e, vfs.setcwd) kernel.syscalls["VFS_setcwd"] = vfs.setcwd
kernel.syscalls["VFS_whereis"] = vfs.whereis
kernel.syscalls["VFS_dup"] = vfs.dup
kernel.syscalls["VFS_dup2"] = vfs.dup2
kernel.log("VFS module loaded") kernel.log("VFS module loaded")

View File

@@ -0,0 +1,42 @@
local kernel = ...
local cache = {}
local searchpaths = {
"/lib/?.lua",
"/lib/?",
"/usr/lib/?.lua",
"/usr/lib/?",
"/usr/local/lib/?.lua",
"/usr/local/lib/?",
"?.lua",
"?"
}
function require(module,...)
if cache[module] then
return cache[module]
end
local modpath = module:gsub("%.", "/")
local failed = {}
for _, path in ipairs(searchpaths) do
local full_path = string.gsub(path, "%?", modpath)
if full_path:sub(1,1)~="/" then
full_path=kernel.currentTask.cwd..full_path
end
if kernel.vfs.exists(full_path) then
if kernel.vfs.type(full_path)=="directory" then
full_path = full_path .. "/init"
end
if kernel.vfs.exists(full_path) then
local handle = kernel.vfs.open(full_path, "r")
local file_content = kernel.vfs.read(handle, 1024 * 1024 * 4)
kernel.vfs.close(handle)
return assert(load(file_content, full_path, "t", kernel._U))(...)
else
table.insert(failed, full_path)
end
else
table.insert(failed, full_path)
end
end
error("Module not found: " .. module .. " (searched paths: " .. table.concat(failed, ", ") .. ")")
end

View File

@@ -0,0 +1,172 @@
local kernel = ...
local proxy = {}
local data = {}
proxy.address = "devfs0000"
proxy.isReadOnly = false
proxy.spaceUsed = function() return 0 end
proxy.spaceTotal = function() return 0 end
proxy.makeDirectory = function() error("Permission denied") end
proxy.remove = function() error("Permission denied") end
proxy.setLabel = function() error("Permission denied") end
proxy.getLabel = function() return "devfs" end
proxy.attributes = function(path) return {
type = proxy.type(path),
isReadOnly = false,
size = 0,
lastModified = 0,
created = 0,
Permissions = "666",
owner = "root",
group = "root"
} end
local function getNode(path)
local parts = string.split(path, "/")
if parts[1] == "" then
table.remove(parts, 1)
end
local node = data
for _, part in ipairs(parts) do
if node[part] then
node = node[part]
else
return nil
end
end
return node
end
proxy.type = function(path)
local node = getNode(path)
if node then
return node.type
else
return nil
end
end
proxy.list = function(path)
local node = getNode(path)
if node and node.type == "directory" then
local content = table.keys(node)
table.remove(content, table.indexOf(content, "type"))
return content
else
error("Not a directory")
end
end
proxy.open = function(path, mode)
local node = getNode(path)
if node and (node.type == "file" or node.type == "character device") then
if mode == "r" then
return {
read = node.read,
close = function() end
}
elseif mode == "w" then
return {
write = node.write,
close = function() end
}
else
error("Invalid mode")
end
else
error("Not a file"..type(node))
end
end
local function newStringFile(content)
return {
type = "file",
read = function() return content end,
write = function(newContent) content = newContent end
}
end
local function newDirectory()
return {
type = "directory"
}
end
data["random"] = {
type = "character device",
read = function(amount)
local result = ""
for _ = 1, amount do
result = result .. string.char(math.random(0, 255))
end
return result
end,
write = function() error("Permission denied") end
}
data["null"] = {
type = "character device",
read = function() return "" end,
write = function() end
}
data["zero"] = {
type = "character device",
read = function(amount)
return string.rep("\0", amount)
end,
write = function() error("Permission denied") end
}
data["rtc"] = {
type = "character device",
read = function() return kernel.computer:time() end,
write = function() error("Permission denied") end
}
data["rtc0"] = {
type = "character device",
read = function() return kernel.computer:time() end,
write = function() error("Permission denied") end
}
data["eeprom"] = {
type = "character device",
read = function() return kernel.computer:getEEPROM() end,
write = function(data)
if kernel.uid ~= 0 then
error("Permission denied")
end
kernel.computer:setEEPROM(data)
end
}
local keyboard = kernel.newFifo()
local mouse = kernel.newFifo()
data["input"] = newDirectory()
data["input"]["keyboard"] = {
type = "pipe",
read = function(amount)
return keyboard.pop()
end,
write = function() error("Permission denied") end
}
data["input"]["mouse"] = {
type = "pipe",
read = function(amount)
return mouse.pop()
end,
write = function() error("Permission denied") end
}
data["pts"] = newDirectory()
kernel.devfs = {}
kernel.devfs.keyboard = keyboard
kernel.devfs.mouse = mouse
kernel.devfs.proxy = proxy
kernel.devfs.data = data
kernel.vfs.virtdisk(proxy)

View File

@@ -0,0 +1,12 @@
local kernel = ...
kernel.processes.keventd = function()
while true do
local event = {kernel.computer:getMachineEvent()}
if event[1] then
if event[1] == "key" or event[1] == "keyPressed" or event[1] == "keyReleased" then
kernel.devfs.keyboard.push(event)
end
end
end
end

View File

@@ -0,0 +1,17 @@
local kernel=...
for i,v in ipairs(string.split(kernel.fstab,"\n")) do
if v:sub(1,1)=="U" then
local id=""
for i=3,#v do
if v:sub(i,i)==";" then
if i==3 then kernel.log("Invalid fstab line... Skipping.","WARN") goto endline end
id=v:sub(3,i-1)
end
end
local path=v:sub(#id+4)
if id~="$" then
kernel.vfs.mount(id,path)
end
::endline::
end
end

View File

@@ -0,0 +1 @@
local kernel = ...

View File

@@ -0,0 +1,75 @@
local kernel = ...
local ports = {}
local signals = {}
local ipc = {}
function ipc.open(port)
if not ports[port] then
local handle = kernel.newUUID()
ports[port] = {owner = kernel.currentProcess.pid, handle = handle, messages = {}}
return ports[port].handle
end
error("Port already opened")
end
function ipc.close(port)
if ports[port] then
if ports[port].owner == kernel.currentProcess.pid then
ports[port] = nil
return true
else
error("Cannot close port you do not own")
end
end
error("Port not opened")
end
function ipc.send(port, message)
if ports[port] then
table.insert(ports[port].messages, {from = kernel.currentProcess.pid, message = message})
if signals[ports[port].owner] then
signals[ports[port].owner](port, message)
end
return true
end
error("Port not opened")
end
function ipc.receive(port)
if ports[port] then
if #ports[port].messages > 0 then
return table.remove(ports[port].messages, 1)
else
return nil
end
end
error("Port not opened")
end
function ipc.setSignalHandler(pid, handler)
signals[pid] = handler
end
function ipc.clearSignalHandler(pid)
signals[pid] = nil
end
function ipc.sendSignal(pid, ...)
coroutine.resumeWithTimeout(coroutine.create(function(...)
if signals[pid] then
signals[pid](...)
return true
end
end), 100)
return false
end
kernel.ipc = ipc
kernel.syscalls["ipc_open"] = ipc.open
kernel.syscalls["ipc_close"] = ipc.close
kernel.syscalls["ipc_send"] = ipc.send
kernel.syscalls["ipc_receive"] = ipc.receive
kernel.syscalls["ipc_setSignalHandler"] = ipc.setSignalHandler
kernel.syscalls["ipc_clearSignalHandler"] = ipc.clearSignalHandler
kernel.syscalls["ipc_sendSignal"] = ipc.sendSignal
kernel.log("Loaded IPC module")

View File

@@ -1,22 +0,0 @@
local args = {...}
local kernel = args[1]
kernel.log("Loading third party drivers")
for _,subf in ipairs(kernel.fs.list("/lib/modules/")) do
if kernel.fs.isDir("/lib/modules/"..subf) then
if subf~="Hyperion" then
for _,driver in ipairs(kernel.fs.list("/lib/modules/"..subf)) do
kernel.log("Compiling driver \""..subf..":"..driver.."\"")
local code = kernel.fs.readAllText("/lib/modules/"..subf.."/"..driver)
local func, err = load(code, "@"..driver)
if not func then
kernel.log("DriverCompileErr: "..tostring(err), "ERROR")
else
local ok, err = xpcall(func, debug.traceback, table.unpack(args))
if not ok then
kernel.log("DriverExecErr: "..tostring(err), "ERROR")
end
end
end
end
end
end

View File

@@ -0,0 +1,17 @@
local args={...}
local kernel=args[1]
kernel._G=_G
kernel._U=setmetatable({},{
__index = kernel._G,
__newindex = function(t,k,v)
if kernel.config.allowGlobalOverwrites or kernel.allowGlobalOverwrites then
rawset(t,k,v)
return
end
error("Attempt to modify global variable '"..k.."'",2)
end,
__metatable = false
})
kernel.allowGlobalOverwrites=true
kernel._U._G=kernel._U
kernel.allowGlobalOverwrites=false

View File

@@ -1,14 +0,0 @@
local args = {...}
local kernel = args[1]
kernel.log("Initializing third party drivers")
for _,v in ipairs(kernel.drivers.raw) do
if v.arch==kernel.arch then
if v.load then
kernel.log("Loading "..v.name)
local ok,err = xpcall(v.load, debug.traceback)
if not ok then
kernel.log("DriverLoadErr: "..tostring(err))
end
end
end
end

View File

@@ -1 +0,0 @@
local kernel = ...

Some files were not shown because too many files have changed in this diff Show More