This commit is contained in:
2025-12-11 17:23:07 -05:00
45 changed files with 1376 additions and 792 deletions

BIN
Build.tar Executable file

Binary file not shown.

View File

@@ -14,29 +14,34 @@ kernel.group = "root"
kernel.groups = {0} kernel.groups = {0}
kernel.uid = 0 kernel.uid = 0
kernel.gid = 0 kernel.gid = 0
kernel.stage = "start" kernel.status = "start"
kernel.key = {} kernel.key = {}
kernel.chache = {} kernel.cache = {}
kernel.chache.preload = {} kernel.cache.preload = {}
kernel._G=_G
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.stage == "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)
end end
end end
function kernel.PANIC(msg) function kernel.PANIC(msg)
kernel.log("PANIC: "..msg, "PANIC") if kernel.status~="Panic" then
pcall(kernel["saveLog"]) kernel.log("PANIC: "..msg, "PANIC")
screen:setTextColor(2) pcall(kernel["saveLog"])
screen:setBackgroundColor(0) kernel.status="Panic"
screen:clear() kernel.reason=msg
screen:setCursorPos(1,1) screen:setTextColor(2)
screen:print(LOG_Text) screen:setBackgroundColor(0)
screen:print("KERNEL PANIC!\n"..msg.."\nSystem halted.") screen:clear()
screen:print("Press any key to continue...") screen:setCursorPos(1,1)
screen:print(LOG_Text)
screen:print("KERNEL PANIC!\n"..msg.."\nSystem halted.")
screen:print("Press any key to continue...")
end
while true do while true do
local event={computer:getMachineEvent()} local event={computer:getMachineEvent()}
if event[1]=="keyPressed" then if event[1]=="keyPressed" then
@@ -65,16 +70,12 @@ if windowsExp then
while true do end while true do end
end end
kernel.log("Kernel loaded.", "INFO") kernel.log("Kernel loaded.")
kernel.log("Mounting disks...", "INFO") kernel.log("Mounting init disks...")
disks.refresh() disks.refresh()
ifs.update(disks) ifs.update(disks)
ifs.mount("$", "/") ifs.mount("$", "/")
function kernel.saveLog()
ifs.writeAllText("/var/log/syslog.log", LOG_Text)
end
local fstab=ifs.readAllText("/etc/fstab") local fstab=ifs.readAllText("/etc/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")
@@ -104,11 +105,15 @@ for i,v in ipairs(split(fstab,"\n")) do
end end
end end
local path=v:sub(#id+4) local path=v:sub(#id+4)
kernel.log("Mounted "..id.." to "..path)
ifs.mount(id,path) ifs.mount(id,path)
::endline:: ::endline::
end end
end end
kernel.log("Disks initialized")
function kernel.saveLog()
ifs.writeAllText("/var/log/syslog.log", LOG_Text)
end
ifs.remove("/tmp") ifs.remove("/tmp")
ifs.makeDir("/tmp") ifs.makeDir("/tmp")
@@ -116,29 +121,24 @@ ifs.makeDir("/tmp")
local drivers={} local drivers={}
drivers.raw={} drivers.raw={}
drivers.processes={} drivers.processes={}
drivers.prior={}
drivers.type={} drivers.type={}
for i=0, 99 do
drivers.prior[i]={}
end
function drivers.register(prior,object) function drivers.register(object)
drivers.raw[#drivers.raw+1]=object drivers.raw[#drivers.raw+1]=object
if object.main then drivers.processes[#drivers.processes+1]=object.main end if object.main then drivers.processes[#drivers.processes+1]=object.main end
if drivers.prior[prior]==nil then drivers.prior[prior]={} end
drivers.prior[prior][#drivers.prior[prior]+1]=object
if drivers.type[object.type]==nil then drivers.type[object.type]={} end if drivers.type[object.type]==nil then drivers.type[object.type]={} end
drivers.type[object.type][#drivers.type[object.type]+1]=object drivers.type[object.type][#drivers.type[object.type]+1]=object
end end
local modules={} local modules={[0]={}}
for i=0, 99 do for i=0, 100 do
modules[i]={} modules[i]={}
end end
kernel.log("Gathering modules")
for i,v in ipairs(ifs.list("/lib/modules/Hyperion/")) do for i,v in ipairs(ifs.list("/lib/modules/Hyperion/")) do
local prior=tonumber(v:sub(1,2)) local prior=tonumber(v:sub(1,2))
modules[prior][#modules[prior]+1]="/lib/modules/Hyperion/"..v modules[prior+1][#modules[prior+1]+1]="/lib/modules/Hyperion/"..v
end end
kernel.drivers=drivers kernel.drivers=drivers
@@ -147,19 +147,17 @@ kernel.apis=apis
kernel.computer=computer kernel.computer=computer
kernel.initPath=initPath kernel.initPath=initPath
kernel.arch=arch kernel.arch=arch
kernel.initdisks=initdisks kernel.initdisks=disks
kernel.screen=screen kernel.screen=screen
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)
local func,err=load(code,"@"..v) local func,err=load(code,"@"..v)
if not func then kernel.log("ModuLoadErr: "..tostring(err)) goto skip end if not func then kernel.log("ModuLoadErr: "..tostring(err), "WARN") goto skip end
local status, err = xpcall(func,debug.traceback,kernel) local status, err = xpcall(func,debug.traceback, kernel)
if not status then goto skip end if not status then kernel.log("ModuRunErr: "..tostring(err), "WARN") end
if not err then goto skip end
if not err.init then goto skip end
local ok, err = xpcall(status.main,debug.traceback)
if not ok then kernel.log("ModuInitErr: "..tostring(err)) end
::skip:: ::skip::
end end
end end

View File

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

View File

@@ -0,0 +1,26 @@
local args={...}
local kernel=args[1]
local driver={}
driver.name="CCT Term Module"
driver.version="0.1.0"
driver.type="gpio"
driver.description="CCT redstone Module Kernel Module"
driver.arch="cct"
driver.author="HyperionOS Dev Team"
driver.license="MIT"
driver.api={}
function driver.load()
-- will
end
function driver.unload()
-- Nothing to unload
end
function driver.main()
-- Nothing to run
end
kernel.drivers.register(driver)

View File

@@ -0,0 +1,105 @@
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,5 @@
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
@@ -94,6 +96,62 @@ function table.hasVal(tabl, query)
return false return false
end end
function table.proxy(tbl)
local proxies = setmetatable({}, {__mode = "k"}) -- Weak table to avoid cycles
local function createProxy(t)
if type(t) ~= "table" then return t end
if proxies[t] then return proxies[t] end -- reuse proxy for the same table (handle cycles)
local proxy = {}
proxies[t] = proxy
local mt
mt = {
__index = function(_, k)
local value = t[k]
if type(value) == "table" then
return createProxy(value) -- recursively proxy subtables
else
return value
end
end,
__newindex = function()
error("Attempt to modify read-only table", 2)
end,
__pairs = function()
return function(_, k)
local nextKey, nextValue = next(t, k)
if type(nextValue) == "table" then
nextValue = createProxy(nextValue)
end
return nextKey, nextValue
end, nil, nil
end,
__ipairs = function()
local i = 0
local n = #t
return function()
i = i + 1
if i <= n then
local v = t[i]
if type(v) == "table" then
v = createProxy(v)
end
return i, v
end
end
end,
__metatable = false
}
setmetatable(proxy, mt)
return proxy
end
return createProxy(tbl)
end
local function serialize(table) local function serialize(table)
local output = "{" local output = "{"
for i,v in pairs(table) do for i,v in pairs(table) do
@@ -119,7 +177,7 @@ local function serialize(table)
output=output.."false" output=output.."false"
end end
elseif type(v) == "function" then elseif type(v) == "function" then
output=output.."function() end" output=output..tostring(v)
else else
error("serialization of type \""..type(v).."\" is not supported") error("serialization of type \""..type(v).."\" is not supported")
end end
@@ -135,3 +193,4 @@ local function serialize(table)
end end
table.serialize=serialize table.serialize=serialize
kernel.log("Loaded stdlib")

View File

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

View File

@@ -1,217 +1,321 @@
local args = {...} local args = {...}
local kernel = args[1] local kernel = args[1]
local fs = {} local fs = {}
local disks = {}
local mounts = {["/"]="$"}
-- path normaliing -- =====================================================================
local function normalizePath(path) -- INTERNAL STATE
if not path or path == "" then return "/" end -- =====================================================================
if path:sub(1,1) ~= "/" then path = "/" .. path end
local parts = {}
for part in path:gmatch("[^/]+") do
if part == ".." then
if #parts > 0 then table.remove(parts) end
elseif part ~= "." and part ~= "" then
parts[#parts+1] = part
end
end
return "/" .. table.concat(parts, "/")
end
-- disk resolution local disks = {} -- address → disk object
local function resolvePath(path) local mounts = {["/"] = "$"} -- mountpoint → disk address (root = boot disk)
local abs = normalizePath(path)
local best = "/"
for mount, diskAddr in pairs(mounts) do
if abs:sub(1, #mount) == mount and #mount > #best then
best = mount
end
end
local newPath = abs:sub(#best + 1)
if newPath == "" then newPath = "/" end
return disks[mounts[best]], newPath
end
-- Symlinks
-- Format: #!@SYMLINK[target]
local SYMLINK_PREFIX = "#!@SYMLINK[" local SYMLINK_PREFIX = "#!@SYMLINK["
local SYMLINK_SUFFIX = "]" local SYMLINK_SUFFIX = "]"
local SYMLINK_MAX_DEPTH = 64 local SYMLINK_MAX_DEPTH = 64
local function isSymlink(disk, path)
if not disk:fileExists(path) then return false end
local text = disk:readAllText(path)
if not text then return false end
return text:sub(1, #SYMLINK_PREFIX) == SYMLINK_PREFIX
end
local function readSymlink(disk, path) -- =====================================================================
local text = disk:readAllText(path) -- PATH NORMALIZATION
if not text then return nil end -- =====================================================================
if text:sub(1, #SYMLINK_PREFIX) ~= SYMLINK_PREFIX then return nil end
local target = text:sub(#SYMLINK_PREFIX + 1)
if target:sub(-1) == SYMLINK_SUFFIX then
target = target:sub(1, -2)
end
return target
end
-- Path resolution
local function splitPath(p) local function splitPath(p)
local parts = {} local t = {}
for part in p:gmatch("[^/]+") do parts[#parts+1] = part end for part in p:gmatch("[^/]+") do t[#t+1] = part end
return parts return t
end end
local function resolveSymlink(path) local function normalizePath(path)
path = normalizePath(path) if not path or path == "" then return "/" end
local symlinkDepth = 0
local parts = splitPath(path)
local resolved = {}
local i = 1
while i <= #parts do -- ensure absolute
local comp = parts[i] if path:sub(1,1) ~= "/" then
if comp == "." then path = "/" .. path
elseif comp == ".." then end
if #resolved > 0 then table.remove(resolved) end
else local parts = splitPath(path)
local currentPath = "/" .. table.concat(resolved, "/") local out = {}
local disk, p = resolvePath(currentPath .. "/" .. comp)
if isSymlink(disk, p) then for _,part in ipairs(parts) do
symlinkDepth = symlinkDepth + 1 if part == ".." then
if symlinkDepth > SYMLINK_MAX_DEPTH then if #out > 0 then table.remove(out) end
error("Too many levels of symbolic links: " .. path) elseif part ~= "." and part ~= "" then
end out[#out+1] = part
local target = readSymlink(disk, p) end
if not target then end
resolved[#resolved+1] = comp
else return "/" .. table.concat(out, "/")
if target:sub(1,1) == "/" then end
resolved = splitPath(normalizePath(target))
else
local base = resolved -- =====================================================================
resolved = {} -- DISK & MOUNT RESOLUTION
for _, seg in ipairs(base) do resolved[#resolved+1]=seg end -- =====================================================================
for seg in target:gmatch("[^/]+") do
if seg == ".." then -- Finds which disk owns an absolute path
if #resolved>0 then table.remove(resolved) end local function resolveMount(abs)
elseif seg ~= "." then local best = "/"
resolved[#resolved+1]=seg
end for mount, addr in pairs(mounts) do
end if abs:sub(1, #mount) == mount then
end if #mount > #best then
local remaining = {} best = mount
for j=i+1,#parts do remaining[#remaining+1]=parts[j] end
parts = remaining
i = 0
end
else
resolved[#resolved+1]=comp
end end
end end
i=i+1
end end
local finalPath="/"..table.concat(resolved,"/") local disk = disks[mounts[best]]
local disk,diskPath=resolvePath(finalPath) if not disk then
return disk,diskPath error("No disk registered for mount: " .. best)
end
local sub = abs:sub(#best + 1)
if sub == "" then sub = "/" end
return disk, sub
end end
-- PUBLIC API: MOUNTING
function fs.mount(disk, mountPoint)
if kernel.uid ~= 0 then error("Permission Denied") end -- =====================================================================
mounts[mountPoint]=disk -- SYMLINK HANDLING
-- =====================================================================
local function isSymlinkRaw(disk, p)
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
function fs.unmount(mountPoint)
if kernel.uid ~= 0 then error("Permission Denied") end local function readSymlinkRaw(disk, p)
mounts[mountPoint]=nil local text = disk:readAllText(p)
if not text then return nil end
if text:sub(1, #SYMLINK_PREFIX) ~= SYMLINK_PREFIX then return nil end
local t = text:sub(#SYMLINK_PREFIX + 1)
if t:sub(-1) == SYMLINK_SUFFIX then
t = t:sub(1, -2)
end
return t
end end
-- =====================================================================
-- FULL PATH RESOLUTION (FOLLOWS SYMLINKS)
-- =====================================================================
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
local target = readSymlinkRaw(disk, dpath)
if target then
local newAbs
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
-- rebuild remaining parts
local remaining = {}
for j = idx + 1, #parts do
remaining[#remaining+1] = parts[j]
end
-- restart symlink resolution with new path
abs = newAbs
parts = splitPath(abs)
-- 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
idx = idx + 1
end
local finalAbs = "/" .. table.concat(out, "/")
return resolveMount(finalAbs)
end
-- =====================================================================
-- PUBLIC API
-- =====================================================================
-- MOUNT OPERATIONS -----------------------------------------------------
function fs.virtDisk(diskObj) function fs.virtDisk(diskObj)
if kernel.uid ~= 0 then error("Permission Denied") end if kernel.uid ~= 0 then error("Permission Denied") end
if disks[diskObj.address] then error("Disk exists") end if disks[diskObj.address] then
disks[diskObj.address]=diskObj error("Disk exists: " .. diskObj.address)
end
disks[diskObj.address] = diskObj
end end
function fs.mount(disk, mountPoint)
if kernel.uid ~= 0 then error("Permission Denied") end
mountPoint = normalizePath(mountPoint)
local drive, path = resolveMount(normalizePath(mountPoint))
if not drive:directoryExists(path) then error("Must mount on folder") end
if mountPoint ~= "/" and mounts[mountPoint] then
error("Already mounted: " .. mountPoint)
end
mounts[mountPoint] = disk
end
function fs.unmount(mountPoint)
if kernel.uid ~= 0 then error("Permission Denied") end
mountPoint = normalizePath(mountPoint)
if mountPoint == "/" then error("Cannot unmount root") end
mounts[mountPoint] = nil
end
function fs.eject(addr) function fs.eject(addr)
if kernel.uid ~= 0 then error("Permission Denied") end if kernel.uid ~= 0 then error("Permission Denied") end
disks[addr]=nil disks[addr] = nil
end end
-- SYMLINK API function fs.isMount(path)
if mounts[normalizePath(path)] then return true, mounts[normalizePath(path)] end
end
-- SYMLINK API ----------------------------------------------------------
function fs.symlink(target, linkPath) function fs.symlink(target, linkPath)
local disk, p = resolvePath(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")
return disk:writeAllText(p, SYMLINK_PREFIX..target..SYMLINK_SUFFIX) local disk, p = resolveMount(normalizePath(linkPath))
return disk:writeAllText(p, SYMLINK_PREFIX .. target .. SYMLINK_SUFFIX)
end end
function fs.isLink(path) function fs.isLink(path)
local disk, p = resolvePath(path) local disk, p = resolveMount(normalizePath(path))
return isSymlink(disk,p) return isSymlinkRaw(disk, p)
end end
function fs.readLink(path) function fs.readLink(path)
local disk, p = resolvePath(path) local disk, p = resolveMount(normalizePath(path))
return readSymlink(disk,p) return readSymlinkRaw(disk, p)
end end
-- FILE OPERATIONS
function fs.exists(path) -- FILE OPERATIONS ------------------------------------------------------
function fs.exists(path, ...)
local disk, p = resolveSymlink(path) local disk, p = resolveSymlink(path)
return disk:fileExists(p) or disk:directoryExists(p) return disk:fileExists(p, ...) or disk:directoryExists(p, ...)
end end
function fs.isFile(path) function fs.isFile(path, ...)
local disk, p = resolveSymlink(path) local disk, p = resolveSymlink(path)
if isSymlink(disk, p) then return false end return disk:fileExists(p, ...)
return disk:fileExists(p)
end end
function fs.isDir(path) function fs.isDir(path, ...)
local disk, p = resolveSymlink(path) local disk, p = resolveSymlink(path)
if isSymlink(disk, p) then return false end return disk:directoryExists(p, ...)
return disk:directoryExists(p)
end end
function fs.list(path) function fs.list(path, ...)
local disk, p = resolveSymlink(path) local disk, p = resolveSymlink(path)
return disk:list(p) return disk:list(p, ...)
end end
function fs.makeDir(path) function fs.makeDir(path, ...)
local disk, p = resolveSymlink(path) local disk, p = resolveSymlink(path)
return disk:makeDirectory(p) return disk:makeDirectory(p, ...)
end end
function fs.remove(path) -- remove does NOT follow symlinks (UNIX semantics)
local disk, p = resolvePath(path) function fs.remove(path, ...)
if isSymlink(disk, p) then if fs.isMount(path) then return "Cannot delete mounted folder" end
return disk:remove(p) local abs = normalizePath(path)
end local disk, p = resolveMount(abs)
local d2, p2 = resolveSymlink(path) return disk:remove(p, ...)
return d2:remove(p2)
end end
function fs.readAllText(path) function fs.readAllText(path, ...)
local disk, p = resolveSymlink(path) local disk, p = resolveSymlink(path)
return disk:readAllText(p) return disk:readAllText(p, ...)
end end
function fs.writeAllText(path, text) function fs.writeAllText(path, text, ...)
local disk, p = resolveSymlink(path) local disk, p = resolveSymlink(path)
return disk:writeAllText(p, text) return disk:writeAllText(p, text, ...)
end end
function fs.appendAllText(path, text) function fs.appendAllText(path, text, ...)
local disk, p = resolveSymlink(path) local disk, p = resolveSymlink(path)
return disk:appendAllText(p, text) return disk:appendAllText(p, text, ...)
end end
function fs.getSize(path) 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) local disk, p = resolveSymlink(path)
return disk:getSize(p) return disk:getSize(p, ...)
end end
-- =====================================================================
-- INIT -- INIT
for _,v in kernel.initdisks.list() do fs.virtDisk(v) end -- =====================================================================
kernel.fs=fs
kernel.chache.preload.fs=fs kernel.log("Loading disks for vfs")
kernel.chache.preload.filesystem=fs local ok,err = xpcall(function()
for _,v in kernel.initdisks.list() do
fs.virtDisk(v)
end
end, debug.traceback)
if not ok then kernel.panic(err) end
kernel.disks=disks
kernel.mounts=mounts
kernel.fs = fs
kernel.cache.preload.fs = table.proxy(kernel.fs)
kernel.cache.preload.filesystem = kernel.cache.preload.fs

View File

@@ -1,6 +1,5 @@
local args={...} local args = {...}
local kernel=args[1] local kernel = args[1]
function kernel.fs.mkvirtfs(address, readOnly, label, autoRegister) function kernel.fs.mkvirtfs(address, readOnly, label, autoRegister)
if kernel.uid ~= 0 then error("Permission Denied") end if kernel.uid ~= 0 then error("Permission Denied") end
local disk = {} local disk = {}
@@ -55,34 +54,36 @@ function kernel.fs.mkvirtfs(address, readOnly, label, autoRegister)
-- File IO (supports string or file-object with read/write funcs) -- File IO (supports string or file-object with read/write funcs)
----------------------------------------------------------------- -----------------------------------------------------------------
local function fileRead(node) local function fileRead(node, ...)
if type(node) == "string" then if type(node) == "string" then
return node return node
elseif type(node) == "table" and node.__file and node.read then elseif type(node) == "table" and node.__file and node.read then
return node.read() return node.read(...)
end end
return nil return nil
end end
local function fileWrite(parent, name, text) local function fileWrite(parent, name, text, ...)
local node = parent[name] local node = parent[name]
if type(node) == "string" then if type(node) == "string" then
local ok, err = ensureWrite(); if not ok then return false, err end
parent[name] = text parent[name] = text
return true return true
elseif type(node) == "table" and node.__file and node.write then elseif type(node) == "table" and node.__file and node.write then
return node.write(text) return node.write(text, ...)
end end
parent[name] = text parent[name] = text
return true return true
end end
local function fileAppend(parent, name, text) local function fileAppend(parent, name, text, ...)
local node = parent[name] local node = parent[name]
if type(node) == "string" then if type(node) == "string" then
local ok, err = ensureWrite(); if not ok then return false, err end
parent[name] = node .. text parent[name] = node .. text
return true return true
elseif type(node) == "table" and node.__file and node.write then elseif type(node) == "table" and node.__file and node.write then
return node.write((node.read() or "") .. text) return node.write((node.read() or "") .. text, ...)
end end
parent[name] = text parent[name] = text
return true return true
@@ -96,26 +97,22 @@ function kernel.fs.mkvirtfs(address, readOnly, label, autoRegister)
function disk:spaceUsed() return 0 end function disk:spaceUsed() return 0 end
function disk:spaceTotal() return 0 end function disk:spaceTotal() return 0 end
function disk:readAllText(path) function disk:readAllText(path, ...)
local node = getNode(path) local node = getNode(path)
if not node then return nil, "file not found" end if not node then return nil, "file not found" end
return fileRead(node) return fileRead(node, ...)
end end
function disk:writeAllText(path, text) function disk:writeAllText(path, text, ...)
local ok, err = ensureWrite(); if not ok then return false, err end
local parent, name = getParent(path) local parent, name = getParent(path)
if not parent or not parent.__dir then return false, "invalid directory" end if not parent or not parent.__dir then return false, "invalid directory" end
return fileWrite(parent, name, tostring(text)) return fileWrite(parent, name, tostring(text), ...)
end end
function disk:appendAllText(path, text) function disk:appendAllText(path, text, ...)
local ok, err = ensureWrite(); if not ok then return false, err end
local parent, name = getParent(path) local parent, name = getParent(path)
if not parent or not parent.__dir then return false, "invalid directory" end if not parent or not parent.__dir then return false, "invalid directory" end
return fileAppend(parent, name, tostring(text)) return fileAppend(parent, name, tostring(text), ...)
end end
function disk:list(path) function disk:list(path)
@@ -161,11 +158,11 @@ function kernel.fs.mkvirtfs(address, readOnly, label, autoRegister)
return label return label
end end
function disk:size(path) function disk:size(path, ...)
local node = getNode(path) local node = getNode(path)
if type(node) == "string" then return #node end if type(node) == "string" then return #node end
if type(node) == "table" and node.__file and node.read then if type(node) == "table" and node.__file and node.read then
local v = node.read() local v = node.read(...)
return v and #v or 0 return v and #v or 0
end end
return 0 return 0
@@ -174,7 +171,7 @@ function kernel.fs.mkvirtfs(address, readOnly, label, autoRegister)
----------------------------------------------------------------- -----------------------------------------------------------------
-- Auto-register with kernel and return backend -- Auto-register with kernel and return backend
----------------------------------------------------------------- -----------------------------------------------------------------
if kernel and kernel.fs and kernel.fs.virtDisk and autoRegister then if autoRegister then
kernel.fs.virtDisk(disk) kernel.fs.virtDisk(disk)
end end

View File

@@ -1,6 +1,5 @@
local args = {...} local args = {...}
local kernel = args[1] local kernel = args[1]
-- List of search paths -- List of search paths
local paths = { local paths = {
"/lib/?", "/lib/?",
@@ -11,7 +10,7 @@ local paths = {
-- Custom require implementation -- Custom require implementation
function require(module) function require(module)
-- Return cached module if it already exists -- Return cached module if it already exists
if kernel.cache.preload[module] then if kernel.cache.preload[module]~=nil then
return kernel.cache.preload[module] return kernel.cache.preload[module]
end end
@@ -54,3 +53,4 @@ function require(module)
-- If nothing worked, raise an error with all reasons -- If nothing worked, raise an error with all reasons
error("Unable to require module '" .. module .. "':\n" .. table.concat(err, "\n")) error("Unable to require module '" .. module .. "':\n" .. table.concat(err, "\n"))
end end
kernel.log("Created require")

View File

@@ -1,7 +1,9 @@
local args={...} local args = {...}
local kernel = args[1] local kernel = args[1]
local data = kernel.fs.mkvirtfs("devfs0000", true, "devfs", true)
local data = kernel.fs.mkvirtfs("devfs0000", true, "devfs", false) if not kernel.fs.isDir("/dev") then kernel.fs.makeDir("/dev") end
kernel.devfs={}
kernel.devfs.data=data
data["/"]["OSVERSION"]="Hyperion 1.0.0" data["/"]["OSVERSION"]="Hyperion 1.0.0"
data["/"]["eeprom"]={ data["/"]["eeprom"]={
@@ -14,4 +16,42 @@ data["/"]["eeprom"]={
kernel.computer:setEEPROM(text) kernel.computer:setEEPROM(text)
end 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

@@ -0,0 +1,18 @@
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

@@ -1,11 +1,11 @@
local args={...} local args = {...}
local kernel=args[1] local kernel = args[1]
local ifs=kernel.ifs local ifs=kernel.ifs
local initdisks=kernel.initdisks
kernel.log("Mounting fstab")
local fstab=ifs.readAllText("/etc/fstab") local fstab=ifs.readAllText("/etc/fstab")
kernel.fs.update(initdisks) local entrys = string.split(fstab,"\n")
for i,v in ipairs(string.split(fstab,"\n")) do for i,v in ipairs(entrys) do
if v:sub(1,1)=="U" then if v:sub(1,1)=="U" then
local id="" local id=""
for i=3,#v do for i=3,#v do
@@ -14,9 +14,13 @@ for i,v in ipairs(string.split(fstab,"\n")) do
id=v:sub(3,i-1) id=v:sub(3,i-1)
end end
end end
local path=v:sub(#id+4) 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.log("Mounted "..id.." to "..path)
kernel.fs.mount(id,path) kernel.fs.mount(id,path)
::endline:: ::endline::
end end
end end
kernel.log("Mounted all disks")

View File

@@ -1,5 +1,5 @@
local args={...} local args = {...}
local kernel=args[1] local kernel = args[1]
kernel.drivers.processes[#kernel.drivers.processes+1]=function() kernel.drivers.processes[#kernel.drivers.processes+1]=function()
while true do while true do
local event={kernel.computer:getMachineEvent()} local event={kernel.computer:getMachineEvent()}
@@ -10,3 +10,4 @@ kernel.drivers.processes[#kernel.drivers.processes+1]=function()
coroutine.yield() coroutine.yield()
end end
end end
kernel.log("Created keventd daemon")

View File

@@ -1,17 +1,20 @@
local args={...} local args = {...}
local kernel=args[2] local kernel = args[1]
kernel.log("Loading third party drivers")
for _,subf in ipairs(kernel.fs.list("/lib/modules/")) do for _,subf in ipairs(kernel.fs.list("/lib/modules/")) do
if subf~="Hyperion" then if kernel.fs.isDir("/lib/modules/"..subf) then
for _,driver in ipairs(kernel.fs.list("/lib/modules/"..subf)) do if subf~="Hyperion" then
local code = kernel.fs.readAllText("/lib/modules/"..subf.."/"..driver) for _,driver in ipairs(kernel.fs.list("/lib/modules/"..subf)) do
local func, err = load(code, "@"..driver) kernel.log("Compiling driver \""..subf..":"..driver.."\"")
if not func then local code = kernel.fs.readAllText("/lib/modules/"..subf.."/"..driver)
kernel.log("DriverLoadErr: "..tostring(err), "ERROR") local func, err = load(code, "@"..driver)
else if not func then
local ok, err = xpcall(func, debug.traceback) kernel.log("DriverCompileErr: "..tostring(err), "ERROR")
if not ok then else
kernel.log("DriverLoadErr: "..tostring(err), "ERROR") 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 end

View File

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

View File

@@ -1,17 +1,25 @@
local args={...} local args = {...}
local kernel = args[1] local kernel = args[1]
local tasks={} local tasks={}
local currentTask={} local currentTask={}
local signals={} local signals={}
local tid=1 local tid=2
local gid=1 local gid=2
local hookuuid=0
local sys={} local sys={}
function sys.hookSig(sig, func) function sys.hookSig(sig, func)
if not signals[tostring(currentTask.pid)][sig] then if not currentTask.signal[sig] then
signals[tostring(currentTask.pid)][sig]={} currentTask.signal[sig]={}
end end
signals[tostring(currentTask.pid)][sig][#signals[tostring(currentTask.pid)][sig]+1]=func 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.clearSigHooks(typ) function sys.clearSigHooks(typ)
@@ -27,7 +35,7 @@ end
function sys.sendSig(pid, signal, ...) function sys.sendSig(pid, signal, ...)
if pid=="all" then if pid=="all" then
for i,v in pairs(tasks) do for i,v in pairs(tasks) do+
v.sigQ[#v.sigQ+1]={signal, ...} v.sigQ[#v.sigQ+1]={signal, ...}
end end
return return
@@ -38,31 +46,35 @@ function sys.sendSig(pid, signal, ...)
end end
function sys.flushSigs() function sys.flushSigs()
local ret = {} local sigs = {}
for i=1, #currentTask.sigQ do for i,v in ipairs(currentTask.sigQ) do
if currentTask.signal[currentTask.sigQ[i][1]] then sigs[i]=v
for _,v in ipairs(currentTask.signal[currentTask.sigQ[1][1]]) do 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() coroutine.resumeWithTimeout(coroutine.create(function()
local ok, err = xpcall(v, debug.traceback, table.unpack(table.remove(currentTask.sigQ, 1))) local ok,err = xpcall(v,debug.traceback,table.unpack(sig))
if not ok then if not ok and sig[1]~="callbackErr" then
table.insert(ret, err) sys.sendSig(currentTask.pid, "callbackErr", sig[1], k, err)
end end
end), 10) end),10)
end end
else else
for _,v in ipairs(currentTask.signal["unhandledEvent"]) do for k,v in pairs(currentTask.signal["unhandledSignal"]) do
coroutine.resumeWithTimeout(coroutine.create(function() coroutine.resumeWithTimeout(coroutine.create(function()
local ok, err = xpcall(v, debug.traceback, table.unpack(table.remove(currentTask.sigQ, 1))) local ok,err = xpcall(v,debug.traceback,table.unpack(sig))
if not ok then if not ok and sig[1]~="callbackErr" then
table.insert(ret, err) sys.sendSig(currentTask.pid, "callbackErr", sig[1], k, err)
end end
end), 10) end),10)
end end
end end
end end
end end
function sys.spawn(func, name, evars, args) function sys.spawn(func, name, evars, args, stdin, stdout, stderr)
local id=tid local id=tid
tid=tid+1 tid=tid+1
name=name or tostring(id) name=name or tostring(id)
@@ -89,6 +101,7 @@ function sys.spawn(func, name, evars, args)
vy=0, vy=0,
ivy=0, ivy=0,
status="R", status="R",
sleep=0,
signal=signals[tostring(id)], signal=signals[tostring(id)],
parent=currentTask, parent=currentTask,
children={}, children={},
@@ -97,6 +110,12 @@ function sys.spawn(func, name, evars, args)
} }
end end
function sys.exit(...)
sys.sendSig(currentTask.ppid, "ChildTaskExit", currentTask.pid, ...)
currentTask.status="Z"
coroutine.yield()
end
local function collectZombieProc() local function collectZombieProc()
local ret = {} local ret = {}
for _,v in pairs(tasks) do for _,v in pairs(tasks) do
@@ -116,13 +135,23 @@ local function collectZombieProc()
return ret return ret
end end
kernel.log("initPath is: " .. tostring(kernel.initPath))
signals["1"]={} signals["1"]={}
tasks["1"]={ tasks["1"]={
coro=coroutine.create(function() coro=coroutine.create(function()
local ret = {xpcall(kernel.fs.load(kernel.initPath), debug.traceback)} 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(err) kernel.panic(err)
else else
currentTask.status="Z"
kernel.panic("Attempted to kill init!") kernel.panic("Attempted to kill init!")
end end
end), end),
@@ -130,27 +159,38 @@ tasks["1"]={
pid=1, pid=1,
ppid=0, ppid=0,
tgid=1, tgid=1,
user=kernel.user, user="root",
uid=kernel.uid, uid=0,
evars={}, evars={},
args={kernel}, args={kernel},
vy=0, vy=0,
ivy=0, ivy=0,
status="R", status="R",
sleep=0,
signal=signals["1"], signal=signals["1"],
parent={name="Hyprkrnl",pid=0}, parent={name="Hyprkrnl",pid=0},
children={}, children={},
sibling={}, sibling={},
sigQ={} sigQ={}
} }
kernel.chache.preload.sys=sys tasks["1"].sibling={tasks["1"]}
kernel.chache.preload.system=sys
kernel.log("Created pid 1")
kernel.cache.preload.sys=table.proxy(sys)
kernel.cache.preload.system=kernel.cache.preload.sys
kernel.cache.preload.os=kernel.cache.preload.sys
kernel.hpv=sys kernel.hpv=sys
kernel.tasks=tasks
kernel.signals=signals
kernel.currentTask=currentTask
kernel.saveLog() kernel.saveLog()
while true do kernel.status="running"
for _,v in pairs(tasks) do while kernel.status~="Panic" do
for k,v in pairs(tasks) do
currentTask=v currentTask=v
kernel.currentTask=v
kernel.process=currentTask.name
kernel.user=currentTask.user kernel.user=currentTask.user
kernel.uid=currentTask.uid kernel.uid=currentTask.uid
sys.flushSigs() sys.flushSigs()
@@ -164,4 +204,7 @@ while true do
collectZombieProc() collectZombieProc()
end end
kernel.panic("Exited pid 0") kernel.process="Kernel"
kernel.user="root"
kernel.uid=0
kernel.panic(kernel.reason or "Exited pid 0")

View File

@@ -1,109 +0,0 @@
local args={...}
local apis=args[1]
local drivers=args[2]
local driver={}
driver.name="CCT TTO Module"
driver.version="0.1.0"
driver.description="CCT TTO Module Kernel Module"
driver.arch="cct"
driver.author="HyperionOS Dev Team"
driver.license="MIT"
driver.api={}
colors={
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
}
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
}
function driver.load()
end
function driver.unload()
-- Nothing to unload
end
function driver.reload()
-- Nothing to reload
end
function driver.main()
-- Nothing to run
end
function driver.api.print(text)
apis.term.write(text.."\n")
end
function driver.api.printInline(text)
apis.term.write(text)
end
function driver.api.clear()
apis.term.clear()
apis.term.setCursorPos(1,1)
end
function driver.api.getSize()
return apis.term.getSize()
end
function driver.api.setBackgroundColor(index)
apis.term.setBackgroundColor(colors[index] or 0)
end
function driver.api.setForegroundColor(index)
apis.term.setTextColor(colors[index] or 0)
end
function driver.api.setCursorPos(x, y)
apis.term.setCursorPos(x, y)
end
function driver.api.getCursorPos()
return apis.term.getCursorPos()
end
function driver.api.getBackgroundColor()
return icolors[apis.term.getBackgroundColor()]
end
function driver.api.getForegroundColor()
return icolors[apis.term.getTextColor()]
end
drivers.register(driver)

View File

@@ -1,8 +1,3 @@
local args={...} local args={...}
local kernel=args[1] local kernel=args[1]
kernel.fs.load("/bin/bash")()
kernel.panic("text")
for i,v in ipairs(kernel.fs.list("/dev")) do
kernl.log(v)
end

View File

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

View File

@@ -1,8 +1,3 @@
local args={...} local args={...}
local kernel=args[1] local kernel=args[1]
kernel.fs.load("/bin/bash")()
kernel.panic("text")
for i,v in ipairs(kernel.fs.list("/dev")) do
kernl.log(v)
end

View File

@@ -0,0 +1,26 @@
local args={...}
local kernel=args[1]
local driver={}
driver.name="CCT Term Module"
driver.version="0.1.0"
driver.type="gpio"
driver.description="CCT redstone Module Kernel Module"
driver.arch="cct"
driver.author="HyperionOS Dev Team"
driver.license="MIT"
driver.api={}
function driver.load()
-- will
end
function driver.unload()
-- Nothing to unload
end
function driver.main()
-- Nothing to run
end
kernel.drivers.register(driver)

View File

@@ -0,0 +1,105 @@
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,109 +0,0 @@
local args={...}
local apis=args[1]
local drivers=args[2]
local driver={}
driver.name="CCT TTO Module"
driver.version="0.1.0"
driver.description="CCT TTO Module Kernel Module"
driver.arch="cct"
driver.author="HyperionOS Dev Team"
driver.license="MIT"
driver.api={}
colors={
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
}
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
}
function driver.load()
end
function driver.unload()
-- Nothing to unload
end
function driver.reload()
-- Nothing to reload
end
function driver.main()
-- Nothing to run
end
function driver.api.print(text)
apis.term.write(text.."\n")
end
function driver.api.printInline(text)
apis.term.write(text)
end
function driver.api.clear()
apis.term.clear()
apis.term.setCursorPos(1,1)
end
function driver.api.getSize()
return apis.term.getSize()
end
function driver.api.setBackgroundColor(index)
apis.term.setBackgroundColor(colors[index] or 0)
end
function driver.api.setForegroundColor(index)
apis.term.setTextColor(colors[index] or 0)
end
function driver.api.setCursorPos(x, y)
apis.term.setCursorPos(x, y)
end
function driver.api.getCursorPos()
return apis.term.getCursorPos()
end
function driver.api.getBackgroundColor()
return icolors[apis.term.getBackgroundColor()]
end
function driver.api.getForegroundColor()
return icolors[apis.term.getTextColor()]
end
drivers.register(driver)

View File

@@ -14,29 +14,34 @@ kernel.group = "root"
kernel.groups = {0} kernel.groups = {0}
kernel.uid = 0 kernel.uid = 0
kernel.gid = 0 kernel.gid = 0
kernel.stage = "start" kernel.status = "start"
kernel.key = {} kernel.key = {}
kernel.chache = {} kernel.cache = {}
kernel.chache.preload = {} kernel.cache.preload = {}
kernel._G=_G
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.stage == "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)
end end
end end
function kernel.PANIC(msg) function kernel.PANIC(msg)
kernel.log("PANIC: "..msg, "PANIC") if kernel.status~="Panic" then
pcall(kernel["saveLog"]) kernel.log("PANIC: "..msg, "PANIC")
screen:setTextColor(2) pcall(kernel["saveLog"])
screen:setBackgroundColor(0) kernel.status="Panic"
screen:clear() kernel.reason=msg
screen:setCursorPos(1,1) screen:setTextColor(2)
screen:print(LOG_Text) screen:setBackgroundColor(0)
screen:print("KERNEL PANIC!\n"..msg.."\nSystem halted.") screen:clear()
screen:print("Press any key to continue...") screen:setCursorPos(1,1)
screen:print(LOG_Text)
screen:print("KERNEL PANIC!\n"..msg.."\nSystem halted.")
screen:print("Press any key to continue...")
end
while true do while true do
local event={computer:getMachineEvent()} local event={computer:getMachineEvent()}
if event[1]=="keyPressed" then if event[1]=="keyPressed" then
@@ -65,16 +70,12 @@ if windowsExp then
while true do end while true do end
end end
kernel.log("Kernel loaded.", "INFO") kernel.log("Kernel loaded.")
kernel.log("Mounting disks...", "INFO") kernel.log("Mounting init disks...")
disks.refresh() disks.refresh()
ifs.update(disks) ifs.update(disks)
ifs.mount("$", "/") ifs.mount("$", "/")
function kernel.saveLog()
ifs.writeAllText("/var/log/syslog.log", LOG_Text)
end
local fstab=ifs.readAllText("/etc/fstab") local fstab=ifs.readAllText("/etc/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")
@@ -104,11 +105,15 @@ for i,v in ipairs(split(fstab,"\n")) do
end end
end end
local path=v:sub(#id+4) local path=v:sub(#id+4)
kernel.log("Mounted "..id.." to "..path)
ifs.mount(id,path) ifs.mount(id,path)
::endline:: ::endline::
end end
end end
kernel.log("Disks initialized")
function kernel.saveLog()
ifs.writeAllText("/var/log/syslog.log", LOG_Text)
end
ifs.remove("/tmp") ifs.remove("/tmp")
ifs.makeDir("/tmp") ifs.makeDir("/tmp")
@@ -116,29 +121,24 @@ ifs.makeDir("/tmp")
local drivers={} local drivers={}
drivers.raw={} drivers.raw={}
drivers.processes={} drivers.processes={}
drivers.prior={}
drivers.type={} drivers.type={}
for i=0, 99 do
drivers.prior[i]={}
end
function drivers.register(prior,object) function drivers.register(object)
drivers.raw[#drivers.raw+1]=object drivers.raw[#drivers.raw+1]=object
if object.main then drivers.processes[#drivers.processes+1]=object.main end if object.main then drivers.processes[#drivers.processes+1]=object.main end
if drivers.prior[prior]==nil then drivers.prior[prior]={} end
drivers.prior[prior][#drivers.prior[prior]+1]=object
if drivers.type[object.type]==nil then drivers.type[object.type]={} end if drivers.type[object.type]==nil then drivers.type[object.type]={} end
drivers.type[object.type][#drivers.type[object.type]+1]=object drivers.type[object.type][#drivers.type[object.type]+1]=object
end end
local modules={} local modules={[0]={}}
for i=0, 99 do for i=0, 100 do
modules[i]={} modules[i]={}
end end
kernel.log("Gathering modules")
for i,v in ipairs(ifs.list("/lib/modules/Hyperion/")) do for i,v in ipairs(ifs.list("/lib/modules/Hyperion/")) do
local prior=tonumber(v:sub(1,2)) local prior=tonumber(v:sub(1,2))
modules[prior][#modules[prior]+1]="/lib/modules/Hyperion/"..v modules[prior+1][#modules[prior+1]+1]="/lib/modules/Hyperion/"..v
end end
kernel.drivers=drivers kernel.drivers=drivers
@@ -147,19 +147,17 @@ kernel.apis=apis
kernel.computer=computer kernel.computer=computer
kernel.initPath=initPath kernel.initPath=initPath
kernel.arch=arch kernel.arch=arch
kernel.initdisks=initdisks kernel.initdisks=disks
kernel.screen=screen kernel.screen=screen
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)
local func,err=load(code,"@"..v) local func,err=load(code,"@"..v)
if not func then kernel.log("ModuLoadErr: "..tostring(err)) goto skip end if not func then kernel.log("ModuLoadErr: "..tostring(err), "WARN") goto skip end
local status, err = xpcall(func,debug.traceback,kernel) local status, err = xpcall(func,debug.traceback, kernel)
if not status then goto skip end if not status then kernel.log("ModuRunErr: "..tostring(err), "WARN") end
if not err then goto skip end
if not err.init then goto skip end
local ok, err = xpcall(status.main,debug.traceback)
if not ok then kernel.log("ModuInitErr: "..tostring(err)) end
::skip:: ::skip::
end end
end end

View File

@@ -1,3 +1,5 @@
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
@@ -94,6 +96,62 @@ function table.hasVal(tabl, query)
return false return false
end end
function table.proxy(tbl)
local proxies = setmetatable({}, {__mode = "k"}) -- Weak table to avoid cycles
local function createProxy(t)
if type(t) ~= "table" then return t end
if proxies[t] then return proxies[t] end -- reuse proxy for the same table (handle cycles)
local proxy = {}
proxies[t] = proxy
local mt
mt = {
__index = function(_, k)
local value = t[k]
if type(value) == "table" then
return createProxy(value) -- recursively proxy subtables
else
return value
end
end,
__newindex = function()
error("Attempt to modify read-only table", 2)
end,
__pairs = function()
return function(_, k)
local nextKey, nextValue = next(t, k)
if type(nextValue) == "table" then
nextValue = createProxy(nextValue)
end
return nextKey, nextValue
end, nil, nil
end,
__ipairs = function()
local i = 0
local n = #t
return function()
i = i + 1
if i <= n then
local v = t[i]
if type(v) == "table" then
v = createProxy(v)
end
return i, v
end
end
end,
__metatable = false
}
setmetatable(proxy, mt)
return proxy
end
return createProxy(tbl)
end
local function serialize(table) local function serialize(table)
local output = "{" local output = "{"
for i,v in pairs(table) do for i,v in pairs(table) do
@@ -119,7 +177,7 @@ local function serialize(table)
output=output.."false" output=output.."false"
end end
elseif type(v) == "function" then elseif type(v) == "function" then
output=output.."function() end" output=output..tostring(v)
else else
error("serialization of type \""..type(v).."\" is not supported") error("serialization of type \""..type(v).."\" is not supported")
end end
@@ -135,3 +193,4 @@ local function serialize(table)
end end
table.serialize=serialize table.serialize=serialize
kernel.log("Loaded stdlib")

View File

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

View File

@@ -1,217 +1,321 @@
local args = {...} local args = {...}
local kernel = args[1] local kernel = args[1]
local fs = {} local fs = {}
local disks = {}
local mounts = {["/"]="$"}
-- path normaliing -- =====================================================================
local function normalizePath(path) -- INTERNAL STATE
if not path or path == "" then return "/" end -- =====================================================================
if path:sub(1,1) ~= "/" then path = "/" .. path end
local parts = {}
for part in path:gmatch("[^/]+") do
if part == ".." then
if #parts > 0 then table.remove(parts) end
elseif part ~= "." and part ~= "" then
parts[#parts+1] = part
end
end
return "/" .. table.concat(parts, "/")
end
-- disk resolution local disks = {} -- address → disk object
local function resolvePath(path) local mounts = {["/"] = "$"} -- mountpoint → disk address (root = boot disk)
local abs = normalizePath(path)
local best = "/"
for mount, diskAddr in pairs(mounts) do
if abs:sub(1, #mount) == mount and #mount > #best then
best = mount
end
end
local newPath = abs:sub(#best + 1)
if newPath == "" then newPath = "/" end
return disks[mounts[best]], newPath
end
-- Symlinks
-- Format: #!@SYMLINK[target]
local SYMLINK_PREFIX = "#!@SYMLINK[" local SYMLINK_PREFIX = "#!@SYMLINK["
local SYMLINK_SUFFIX = "]" local SYMLINK_SUFFIX = "]"
local SYMLINK_MAX_DEPTH = 64 local SYMLINK_MAX_DEPTH = 64
local function isSymlink(disk, path)
if not disk:fileExists(path) then return false end
local text = disk:readAllText(path)
if not text then return false end
return text:sub(1, #SYMLINK_PREFIX) == SYMLINK_PREFIX
end
local function readSymlink(disk, path) -- =====================================================================
local text = disk:readAllText(path) -- PATH NORMALIZATION
if not text then return nil end -- =====================================================================
if text:sub(1, #SYMLINK_PREFIX) ~= SYMLINK_PREFIX then return nil end
local target = text:sub(#SYMLINK_PREFIX + 1)
if target:sub(-1) == SYMLINK_SUFFIX then
target = target:sub(1, -2)
end
return target
end
-- Path resolution
local function splitPath(p) local function splitPath(p)
local parts = {} local t = {}
for part in p:gmatch("[^/]+") do parts[#parts+1] = part end for part in p:gmatch("[^/]+") do t[#t+1] = part end
return parts return t
end end
local function resolveSymlink(path) local function normalizePath(path)
path = normalizePath(path) if not path or path == "" then return "/" end
local symlinkDepth = 0
local parts = splitPath(path)
local resolved = {}
local i = 1
while i <= #parts do -- ensure absolute
local comp = parts[i] if path:sub(1,1) ~= "/" then
if comp == "." then path = "/" .. path
elseif comp == ".." then end
if #resolved > 0 then table.remove(resolved) end
else local parts = splitPath(path)
local currentPath = "/" .. table.concat(resolved, "/") local out = {}
local disk, p = resolvePath(currentPath .. "/" .. comp)
if isSymlink(disk, p) then for _,part in ipairs(parts) do
symlinkDepth = symlinkDepth + 1 if part == ".." then
if symlinkDepth > SYMLINK_MAX_DEPTH then if #out > 0 then table.remove(out) end
error("Too many levels of symbolic links: " .. path) elseif part ~= "." and part ~= "" then
end out[#out+1] = part
local target = readSymlink(disk, p) end
if not target then end
resolved[#resolved+1] = comp
else return "/" .. table.concat(out, "/")
if target:sub(1,1) == "/" then end
resolved = splitPath(normalizePath(target))
else
local base = resolved -- =====================================================================
resolved = {} -- DISK & MOUNT RESOLUTION
for _, seg in ipairs(base) do resolved[#resolved+1]=seg end -- =====================================================================
for seg in target:gmatch("[^/]+") do
if seg == ".." then -- Finds which disk owns an absolute path
if #resolved>0 then table.remove(resolved) end local function resolveMount(abs)
elseif seg ~= "." then local best = "/"
resolved[#resolved+1]=seg
end for mount, addr in pairs(mounts) do
end if abs:sub(1, #mount) == mount then
end if #mount > #best then
local remaining = {} best = mount
for j=i+1,#parts do remaining[#remaining+1]=parts[j] end
parts = remaining
i = 0
end
else
resolved[#resolved+1]=comp
end end
end end
i=i+1
end end
local finalPath="/"..table.concat(resolved,"/") local disk = disks[mounts[best]]
local disk,diskPath=resolvePath(finalPath) if not disk then
return disk,diskPath error("No disk registered for mount: " .. best)
end
local sub = abs:sub(#best + 1)
if sub == "" then sub = "/" end
return disk, sub
end end
-- PUBLIC API: MOUNTING
function fs.mount(disk, mountPoint)
if kernel.uid ~= 0 then error("Permission Denied") end -- =====================================================================
mounts[mountPoint]=disk -- SYMLINK HANDLING
-- =====================================================================
local function isSymlinkRaw(disk, p)
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
function fs.unmount(mountPoint)
if kernel.uid ~= 0 then error("Permission Denied") end local function readSymlinkRaw(disk, p)
mounts[mountPoint]=nil local text = disk:readAllText(p)
if not text then return nil end
if text:sub(1, #SYMLINK_PREFIX) ~= SYMLINK_PREFIX then return nil end
local t = text:sub(#SYMLINK_PREFIX + 1)
if t:sub(-1) == SYMLINK_SUFFIX then
t = t:sub(1, -2)
end
return t
end end
-- =====================================================================
-- FULL PATH RESOLUTION (FOLLOWS SYMLINKS)
-- =====================================================================
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
local target = readSymlinkRaw(disk, dpath)
if target then
local newAbs
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
-- rebuild remaining parts
local remaining = {}
for j = idx + 1, #parts do
remaining[#remaining+1] = parts[j]
end
-- restart symlink resolution with new path
abs = newAbs
parts = splitPath(abs)
-- 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
idx = idx + 1
end
local finalAbs = "/" .. table.concat(out, "/")
return resolveMount(finalAbs)
end
-- =====================================================================
-- PUBLIC API
-- =====================================================================
-- MOUNT OPERATIONS -----------------------------------------------------
function fs.virtDisk(diskObj) function fs.virtDisk(diskObj)
if kernel.uid ~= 0 then error("Permission Denied") end if kernel.uid ~= 0 then error("Permission Denied") end
if disks[diskObj.address] then error("Disk exists") end if disks[diskObj.address] then
disks[diskObj.address]=diskObj error("Disk exists: " .. diskObj.address)
end
disks[diskObj.address] = diskObj
end end
function fs.mount(disk, mountPoint)
if kernel.uid ~= 0 then error("Permission Denied") end
mountPoint = normalizePath(mountPoint)
local drive, path = resolveMount(normalizePath(mountPoint))
if not drive:directoryExists(path) then error("Must mount on folder") end
if mountPoint ~= "/" and mounts[mountPoint] then
error("Already mounted: " .. mountPoint)
end
mounts[mountPoint] = disk
end
function fs.unmount(mountPoint)
if kernel.uid ~= 0 then error("Permission Denied") end
mountPoint = normalizePath(mountPoint)
if mountPoint == "/" then error("Cannot unmount root") end
mounts[mountPoint] = nil
end
function fs.eject(addr) function fs.eject(addr)
if kernel.uid ~= 0 then error("Permission Denied") end if kernel.uid ~= 0 then error("Permission Denied") end
disks[addr]=nil disks[addr] = nil
end end
-- SYMLINK API function fs.isMount(path)
if mounts[normalizePath(path)] then return true, mounts[normalizePath(path)] end
end
-- SYMLINK API ----------------------------------------------------------
function fs.symlink(target, linkPath) function fs.symlink(target, linkPath)
local disk, p = resolvePath(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")
return disk:writeAllText(p, SYMLINK_PREFIX..target..SYMLINK_SUFFIX) local disk, p = resolveMount(normalizePath(linkPath))
return disk:writeAllText(p, SYMLINK_PREFIX .. target .. SYMLINK_SUFFIX)
end end
function fs.isLink(path) function fs.isLink(path)
local disk, p = resolvePath(path) local disk, p = resolveMount(normalizePath(path))
return isSymlink(disk,p) return isSymlinkRaw(disk, p)
end end
function fs.readLink(path) function fs.readLink(path)
local disk, p = resolvePath(path) local disk, p = resolveMount(normalizePath(path))
return readSymlink(disk,p) return readSymlinkRaw(disk, p)
end end
-- FILE OPERATIONS
function fs.exists(path) -- FILE OPERATIONS ------------------------------------------------------
function fs.exists(path, ...)
local disk, p = resolveSymlink(path) local disk, p = resolveSymlink(path)
return disk:fileExists(p) or disk:directoryExists(p) return disk:fileExists(p, ...) or disk:directoryExists(p, ...)
end end
function fs.isFile(path) function fs.isFile(path, ...)
local disk, p = resolveSymlink(path) local disk, p = resolveSymlink(path)
if isSymlink(disk, p) then return false end return disk:fileExists(p, ...)
return disk:fileExists(p)
end end
function fs.isDir(path) function fs.isDir(path, ...)
local disk, p = resolveSymlink(path) local disk, p = resolveSymlink(path)
if isSymlink(disk, p) then return false end return disk:directoryExists(p, ...)
return disk:directoryExists(p)
end end
function fs.list(path) function fs.list(path, ...)
local disk, p = resolveSymlink(path) local disk, p = resolveSymlink(path)
return disk:list(p) return disk:list(p, ...)
end end
function fs.makeDir(path) function fs.makeDir(path, ...)
local disk, p = resolveSymlink(path) local disk, p = resolveSymlink(path)
return disk:makeDirectory(p) return disk:makeDirectory(p, ...)
end end
function fs.remove(path) -- remove does NOT follow symlinks (UNIX semantics)
local disk, p = resolvePath(path) function fs.remove(path, ...)
if isSymlink(disk, p) then if fs.isMount(path) then return "Cannot delete mounted folder" end
return disk:remove(p) local abs = normalizePath(path)
end local disk, p = resolveMount(abs)
local d2, p2 = resolveSymlink(path) return disk:remove(p, ...)
return d2:remove(p2)
end end
function fs.readAllText(path) function fs.readAllText(path, ...)
local disk, p = resolveSymlink(path) local disk, p = resolveSymlink(path)
return disk:readAllText(p) return disk:readAllText(p, ...)
end end
function fs.writeAllText(path, text) function fs.writeAllText(path, text, ...)
local disk, p = resolveSymlink(path) local disk, p = resolveSymlink(path)
return disk:writeAllText(p, text) return disk:writeAllText(p, text, ...)
end end
function fs.appendAllText(path, text) function fs.appendAllText(path, text, ...)
local disk, p = resolveSymlink(path) local disk, p = resolveSymlink(path)
return disk:appendAllText(p, text) return disk:appendAllText(p, text, ...)
end end
function fs.getSize(path) 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) local disk, p = resolveSymlink(path)
return disk:getSize(p) return disk:getSize(p, ...)
end end
-- =====================================================================
-- INIT -- INIT
for _,v in kernel.initdisks.list() do fs.virtDisk(v) end -- =====================================================================
kernel.fs=fs
kernel.chache.preload.fs=fs kernel.log("Loading disks for vfs")
kernel.chache.preload.filesystem=fs local ok,err = xpcall(function()
for _,v in kernel.initdisks.list() do
fs.virtDisk(v)
end
end, debug.traceback)
if not ok then kernel.panic(err) end
kernel.disks=disks
kernel.mounts=mounts
kernel.fs = fs
kernel.cache.preload.fs = table.proxy(kernel.fs)
kernel.cache.preload.filesystem = kernel.cache.preload.fs

View File

@@ -1,6 +1,5 @@
local args={...} local args = {...}
local kernel=args[1] local kernel = args[1]
function kernel.fs.mkvirtfs(address, readOnly, label, autoRegister) function kernel.fs.mkvirtfs(address, readOnly, label, autoRegister)
if kernel.uid ~= 0 then error("Permission Denied") end if kernel.uid ~= 0 then error("Permission Denied") end
local disk = {} local disk = {}
@@ -55,34 +54,36 @@ function kernel.fs.mkvirtfs(address, readOnly, label, autoRegister)
-- File IO (supports string or file-object with read/write funcs) -- File IO (supports string or file-object with read/write funcs)
----------------------------------------------------------------- -----------------------------------------------------------------
local function fileRead(node) local function fileRead(node, ...)
if type(node) == "string" then if type(node) == "string" then
return node return node
elseif type(node) == "table" and node.__file and node.read then elseif type(node) == "table" and node.__file and node.read then
return node.read() return node.read(...)
end end
return nil return nil
end end
local function fileWrite(parent, name, text) local function fileWrite(parent, name, text, ...)
local node = parent[name] local node = parent[name]
if type(node) == "string" then if type(node) == "string" then
local ok, err = ensureWrite(); if not ok then return false, err end
parent[name] = text parent[name] = text
return true return true
elseif type(node) == "table" and node.__file and node.write then elseif type(node) == "table" and node.__file and node.write then
return node.write(text) return node.write(text, ...)
end end
parent[name] = text parent[name] = text
return true return true
end end
local function fileAppend(parent, name, text) local function fileAppend(parent, name, text, ...)
local node = parent[name] local node = parent[name]
if type(node) == "string" then if type(node) == "string" then
local ok, err = ensureWrite(); if not ok then return false, err end
parent[name] = node .. text parent[name] = node .. text
return true return true
elseif type(node) == "table" and node.__file and node.write then elseif type(node) == "table" and node.__file and node.write then
return node.write((node.read() or "") .. text) return node.write((node.read() or "") .. text, ...)
end end
parent[name] = text parent[name] = text
return true return true
@@ -96,26 +97,22 @@ function kernel.fs.mkvirtfs(address, readOnly, label, autoRegister)
function disk:spaceUsed() return 0 end function disk:spaceUsed() return 0 end
function disk:spaceTotal() return 0 end function disk:spaceTotal() return 0 end
function disk:readAllText(path) function disk:readAllText(path, ...)
local node = getNode(path) local node = getNode(path)
if not node then return nil, "file not found" end if not node then return nil, "file not found" end
return fileRead(node) return fileRead(node, ...)
end end
function disk:writeAllText(path, text) function disk:writeAllText(path, text, ...)
local ok, err = ensureWrite(); if not ok then return false, err end
local parent, name = getParent(path) local parent, name = getParent(path)
if not parent or not parent.__dir then return false, "invalid directory" end if not parent or not parent.__dir then return false, "invalid directory" end
return fileWrite(parent, name, tostring(text)) return fileWrite(parent, name, tostring(text), ...)
end end
function disk:appendAllText(path, text) function disk:appendAllText(path, text, ...)
local ok, err = ensureWrite(); if not ok then return false, err end
local parent, name = getParent(path) local parent, name = getParent(path)
if not parent or not parent.__dir then return false, "invalid directory" end if not parent or not parent.__dir then return false, "invalid directory" end
return fileAppend(parent, name, tostring(text)) return fileAppend(parent, name, tostring(text), ...)
end end
function disk:list(path) function disk:list(path)
@@ -161,11 +158,11 @@ function kernel.fs.mkvirtfs(address, readOnly, label, autoRegister)
return label return label
end end
function disk:size(path) function disk:size(path, ...)
local node = getNode(path) local node = getNode(path)
if type(node) == "string" then return #node end if type(node) == "string" then return #node end
if type(node) == "table" and node.__file and node.read then if type(node) == "table" and node.__file and node.read then
local v = node.read() local v = node.read(...)
return v and #v or 0 return v and #v or 0
end end
return 0 return 0
@@ -174,7 +171,7 @@ function kernel.fs.mkvirtfs(address, readOnly, label, autoRegister)
----------------------------------------------------------------- -----------------------------------------------------------------
-- Auto-register with kernel and return backend -- Auto-register with kernel and return backend
----------------------------------------------------------------- -----------------------------------------------------------------
if kernel and kernel.fs and kernel.fs.virtDisk and autoRegister then if autoRegister then
kernel.fs.virtDisk(disk) kernel.fs.virtDisk(disk)
end end

View File

@@ -1,6 +1,5 @@
local args = {...} local args = {...}
local kernel = args[1] local kernel = args[1]
-- List of search paths -- List of search paths
local paths = { local paths = {
"/lib/?", "/lib/?",
@@ -11,7 +10,7 @@ local paths = {
-- Custom require implementation -- Custom require implementation
function require(module) function require(module)
-- Return cached module if it already exists -- Return cached module if it already exists
if kernel.cache.preload[module] then if kernel.cache.preload[module]~=nil then
return kernel.cache.preload[module] return kernel.cache.preload[module]
end end
@@ -54,3 +53,4 @@ function require(module)
-- If nothing worked, raise an error with all reasons -- If nothing worked, raise an error with all reasons
error("Unable to require module '" .. module .. "':\n" .. table.concat(err, "\n")) error("Unable to require module '" .. module .. "':\n" .. table.concat(err, "\n"))
end end
kernel.log("Created require")

View File

@@ -1,7 +1,9 @@
local args={...} local args = {...}
local kernel = args[1] local kernel = args[1]
local data = kernel.fs.mkvirtfs("devfs0000", true, "devfs", true)
local data = kernel.fs.mkvirtfs("devfs0000", true, "devfs", false) if not kernel.fs.isDir("/dev") then kernel.fs.makeDir("/dev") end
kernel.devfs={}
kernel.devfs.data=data
data["/"]["OSVERSION"]="Hyperion 1.0.0" data["/"]["OSVERSION"]="Hyperion 1.0.0"
data["/"]["eeprom"]={ data["/"]["eeprom"]={
@@ -14,4 +16,42 @@ data["/"]["eeprom"]={
kernel.computer:setEEPROM(text) kernel.computer:setEEPROM(text)
end 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

@@ -0,0 +1,18 @@
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

@@ -1,11 +1,11 @@
local args={...} local args = {...}
local kernel=args[1] local kernel = args[1]
local ifs=kernel.ifs local ifs=kernel.ifs
local initdisks=kernel.initdisks
kernel.log("Mounting fstab")
local fstab=ifs.readAllText("/etc/fstab") local fstab=ifs.readAllText("/etc/fstab")
kernel.fs.update(initdisks) local entrys = string.split(fstab,"\n")
for i,v in ipairs(string.split(fstab,"\n")) do for i,v in ipairs(entrys) do
if v:sub(1,1)=="U" then if v:sub(1,1)=="U" then
local id="" local id=""
for i=3,#v do for i=3,#v do
@@ -14,9 +14,13 @@ for i,v in ipairs(string.split(fstab,"\n")) do
id=v:sub(3,i-1) id=v:sub(3,i-1)
end end
end end
local path=v:sub(#id+4) 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.log("Mounted "..id.." to "..path)
kernel.fs.mount(id,path) kernel.fs.mount(id,path)
::endline:: ::endline::
end end
end end
kernel.log("Mounted all disks")

View File

@@ -1,5 +1,5 @@
local args={...} local args = {...}
local kernel=args[1] local kernel = args[1]
kernel.drivers.processes[#kernel.drivers.processes+1]=function() kernel.drivers.processes[#kernel.drivers.processes+1]=function()
while true do while true do
local event={kernel.computer:getMachineEvent()} local event={kernel.computer:getMachineEvent()}
@@ -10,3 +10,4 @@ kernel.drivers.processes[#kernel.drivers.processes+1]=function()
coroutine.yield() coroutine.yield()
end end
end end
kernel.log("Created keventd daemon")

View File

@@ -1,17 +1,20 @@
local args={...} local args = {...}
local kernel=args[2] local kernel = args[1]
kernel.log("Loading third party drivers")
for _,subf in ipairs(kernel.fs.list("/lib/modules/")) do for _,subf in ipairs(kernel.fs.list("/lib/modules/")) do
if subf~="Hyperion" then if kernel.fs.isDir("/lib/modules/"..subf) then
for _,driver in ipairs(kernel.fs.list("/lib/modules/"..subf)) do if subf~="Hyperion" then
local code = kernel.fs.readAllText("/lib/modules/"..subf.."/"..driver) for _,driver in ipairs(kernel.fs.list("/lib/modules/"..subf)) do
local func, err = load(code, "@"..driver) kernel.log("Compiling driver \""..subf..":"..driver.."\"")
if not func then local code = kernel.fs.readAllText("/lib/modules/"..subf.."/"..driver)
kernel.log("DriverLoadErr: "..tostring(err), "ERROR") local func, err = load(code, "@"..driver)
else if not func then
local ok, err = xpcall(func, debug.traceback) kernel.log("DriverCompileErr: "..tostring(err), "ERROR")
if not ok then else
kernel.log("DriverLoadErr: "..tostring(err), "ERROR") 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 end

View File

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

View File

@@ -1,17 +1,25 @@
local args={...} local args = {...}
local kernel = args[1] local kernel = args[1]
local tasks={} local tasks={}
local currentTask={} local currentTask={}
local signals={} local signals={}
local tid=1 local tid=2
local gid=1 local gid=2
local hookuuid=0
local sys={} local sys={}
function sys.hookSig(sig, func) function sys.hookSig(sig, func)
if not signals[tostring(currentTask.pid)][sig] then if not currentTask.signal[sig] then
signals[tostring(currentTask.pid)][sig]={} currentTask.signal[sig]={}
end end
signals[tostring(currentTask.pid)][sig][#signals[tostring(currentTask.pid)][sig]+1]=func 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.clearSigHooks(typ) function sys.clearSigHooks(typ)
@@ -27,7 +35,7 @@ end
function sys.sendSig(pid, signal, ...) function sys.sendSig(pid, signal, ...)
if pid=="all" then if pid=="all" then
for i,v in pairs(tasks) do for i,v in pairs(tasks) do+
v.sigQ[#v.sigQ+1]={signal, ...} v.sigQ[#v.sigQ+1]={signal, ...}
end end
return return
@@ -38,31 +46,35 @@ function sys.sendSig(pid, signal, ...)
end end
function sys.flushSigs() function sys.flushSigs()
local ret = {} local sigs = {}
for i=1, #currentTask.sigQ do for i,v in ipairs(currentTask.sigQ) do
if currentTask.signal[currentTask.sigQ[i][1]] then sigs[i]=v
for _,v in ipairs(currentTask.signal[currentTask.sigQ[1][1]]) do 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() coroutine.resumeWithTimeout(coroutine.create(function()
local ok, err = xpcall(v, debug.traceback, table.unpack(table.remove(currentTask.sigQ, 1))) local ok,err = xpcall(v,debug.traceback,table.unpack(sig))
if not ok then if not ok and sig[1]~="callbackErr" then
table.insert(ret, err) sys.sendSig(currentTask.pid, "callbackErr", sig[1], k, err)
end end
end), 10) end),10)
end end
else else
for _,v in ipairs(currentTask.signal["unhandledEvent"]) do for k,v in pairs(currentTask.signal["unhandledSignal"]) do
coroutine.resumeWithTimeout(coroutine.create(function() coroutine.resumeWithTimeout(coroutine.create(function()
local ok, err = xpcall(v, debug.traceback, table.unpack(table.remove(currentTask.sigQ, 1))) local ok,err = xpcall(v,debug.traceback,table.unpack(sig))
if not ok then if not ok and sig[1]~="callbackErr" then
table.insert(ret, err) sys.sendSig(currentTask.pid, "callbackErr", sig[1], k, err)
end end
end), 10) end),10)
end end
end end
end end
end end
function sys.spawn(func, name, evars, args) function sys.spawn(func, name, evars, args, stdin, stdout, stderr)
local id=tid local id=tid
tid=tid+1 tid=tid+1
name=name or tostring(id) name=name or tostring(id)
@@ -89,6 +101,7 @@ function sys.spawn(func, name, evars, args)
vy=0, vy=0,
ivy=0, ivy=0,
status="R", status="R",
sleep=0,
signal=signals[tostring(id)], signal=signals[tostring(id)],
parent=currentTask, parent=currentTask,
children={}, children={},
@@ -97,6 +110,12 @@ function sys.spawn(func, name, evars, args)
} }
end end
function sys.exit(...)
sys.sendSig(currentTask.ppid, "ChildTaskExit", currentTask.pid, ...)
currentTask.status="Z"
coroutine.yield()
end
local function collectZombieProc() local function collectZombieProc()
local ret = {} local ret = {}
for _,v in pairs(tasks) do for _,v in pairs(tasks) do
@@ -116,13 +135,23 @@ local function collectZombieProc()
return ret return ret
end end
kernel.log("initPath is: " .. tostring(kernel.initPath))
signals["1"]={} signals["1"]={}
tasks["1"]={ tasks["1"]={
coro=coroutine.create(function() coro=coroutine.create(function()
local ret = {xpcall(kernel.fs.load(kernel.initPath), debug.traceback)} 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(err) kernel.panic(err)
else else
currentTask.status="Z"
kernel.panic("Attempted to kill init!") kernel.panic("Attempted to kill init!")
end end
end), end),
@@ -130,27 +159,38 @@ tasks["1"]={
pid=1, pid=1,
ppid=0, ppid=0,
tgid=1, tgid=1,
user=kernel.user, user="root",
uid=kernel.uid, uid=0,
evars={}, evars={},
args={kernel}, args={kernel},
vy=0, vy=0,
ivy=0, ivy=0,
status="R", status="R",
sleep=0,
signal=signals["1"], signal=signals["1"],
parent={name="Hyprkrnl",pid=0}, parent={name="Hyprkrnl",pid=0},
children={}, children={},
sibling={}, sibling={},
sigQ={} sigQ={}
} }
kernel.chache.preload.sys=sys tasks["1"].sibling={tasks["1"]}
kernel.chache.preload.system=sys
kernel.log("Created pid 1")
kernel.cache.preload.sys=table.proxy(sys)
kernel.cache.preload.system=kernel.cache.preload.sys
kernel.cache.preload.os=kernel.cache.preload.sys
kernel.hpv=sys kernel.hpv=sys
kernel.tasks=tasks
kernel.signals=signals
kernel.currentTask=currentTask
kernel.saveLog() kernel.saveLog()
while true do kernel.status="running"
for _,v in pairs(tasks) do while kernel.status~="Panic" do
for k,v in pairs(tasks) do
currentTask=v currentTask=v
kernel.currentTask=v
kernel.process=currentTask.name
kernel.user=currentTask.user kernel.user=currentTask.user
kernel.uid=currentTask.uid kernel.uid=currentTask.uid
sys.flushSigs() sys.flushSigs()
@@ -164,4 +204,7 @@ while true do
collectZombieProc() collectZombieProc()
end end
kernel.panic("Exited pid 0") kernel.process="Kernel"
kernel.user="root"
kernel.uid=0
kernel.panic(kernel.reason or "Exited pid 0")

View File

@@ -4,22 +4,24 @@
Hyperion OS supports many driver types to allow it to run on any hardware Hyperion OS supports many driver types to allow it to run on any hardware
``` ```
Driver types Driver types
tto - Supports basic text terminal output tty - Supports basic teletype devices
gpio - Supports things like redstone gpio - Supports things like redstone
runner - Kernel level programs (no api) runner - Kernel level programs (no api)
timer - Timers and time related timer - Timers and time related
periph - Basic peripheral info periph - Basic peripheral info
gfx - PixelScreens gfx - PixelScreens
modem - networking
``` ```
Hyperion also has a base driver api Hyperion also has a base driver api
``` ```
Driver API Driver API
name - Name of driver+ name - Name of driver
type - Type of driver type - Type of driver
init - Ran before init load - loading code
unload - unloading code
main - Ran as a process and has normal behavior (used for checking network like things) main - Ran as a process and has normal behavior (used for checking network like things)
api - api difined by type api - api difined by type
arch - architecture difined in bootloader (EX: cct, oc, ac, cc, ccpc) arch - architecture difined in bootloader (EX: cct, oc, ac, cc, ccpc, or all)
description - discription description - discription
author - author of driver author - author of driver
prior - priority (low first) prior - priority (low first)