super dupper system update (it runs)
This commit is contained in:
@@ -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
17
Build/bin/neofetch
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
print(".. *. ..")
|
||||||
|
print(" *= +@* +* ")
|
||||||
|
print(" .@#. -@@@= :#@. ")
|
||||||
|
print(" =@@+ *@@@# +@@= ")
|
||||||
|
print(" %@@%: *@@@# -%@@% ")
|
||||||
|
print(" :@@@@+ *@@@# .*@@@@: ")
|
||||||
|
print(" :*@@@%- *@@@# -@@@@*: ")
|
||||||
|
print(" =%@@#. *@@@# .#@@%= ")
|
||||||
|
print(" :=. :*@@= *@@@# =@@+: .=: ")
|
||||||
|
print(" %@#=..*# +@@@# #*..=#@# ")
|
||||||
|
print(" .@@@@+=# .%@%: #=+@@@@. ")
|
||||||
|
print(" .....=# -@= *+...:. ")
|
||||||
|
print(" -*%*-@= - =@-*%*- ")
|
||||||
|
print(" -@*. -@%. :%@- :*@- ")
|
||||||
|
print(" .#@#@* ")
|
||||||
|
print(" -#- ")
|
||||||
|
print(" ")
|
||||||
1
Build/bin/startup/hello.lua
Normal file
1
Build/bin/startup/hello.lua
Normal file
@@ -0,0 +1 @@
|
|||||||
|
print("hello from hello.lua")
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
2
Build/boot/fstab
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
U $;/
|
||||||
|
U devfs0000;/dev/
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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")
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
U $;/
|
|
||||||
U devfs0000;/dev/
|
|
||||||
U sysfs0000;/sys/
|
|
||||||
151
Build/lib/bit32
Normal file
151
Build/lib/bit32
Normal 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
116
Build/lib/crypto/blake2s
Normal 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
|
||||||
@@ -23,4 +23,4 @@ function driver.main()
|
|||||||
-- Nothing to run
|
-- Nothing to run
|
||||||
end
|
end
|
||||||
|
|
||||||
kernel.drivers.register(driver)
|
-- kernel.drivers.register(driver)
|
||||||
181
Build/lib/modules/CC-Tweaked/51_tty.kmod
Normal file
181
Build/lib/modules/CC-Tweaked/51_tty.kmod
Normal 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
|
||||||
|
|
||||||
@@ -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)
|
|
||||||
@@ -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")
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
local args={...}
|
|
||||||
local kernel=args[1]
|
|
||||||
kernel._U=table.proxy(_G)
|
|
||||||
@@ -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")
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -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")
|
|
||||||
@@ -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")
|
|
||||||
@@ -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")
|
|
||||||
12
Build/lib/modules/Hyperion/13_keventd.kmod
Normal file
12
Build/lib/modules/Hyperion/13_keventd.kmod
Normal 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
|
||||||
@@ -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")
|
|
||||||
17
Build/lib/modules/Hyperion/19_fstab.kmod
Normal file
17
Build/lib/modules/Hyperion/19_fstab.kmod
Normal 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
|
||||||
1
Build/lib/modules/Hyperion/20_firmware.kmod
Normal file
1
Build/lib/modules/Hyperion/20_firmware.kmod
Normal file
@@ -0,0 +1 @@
|
|||||||
|
local kernel = ...
|
||||||
75
Build/lib/modules/Hyperion/20_ipc.kmod
Normal file
75
Build/lib/modules/Hyperion/20_ipc.kmod
Normal 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")
|
||||||
@@ -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")
|
|
||||||
@@ -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)
|
|
||||||
|
|
||||||
@@ -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
|
|
||||||
17
Build/lib/modules/Hyperion/30_userspace.kmod
Normal file
17
Build/lib/modules/Hyperion/30_userspace.kmod
Normal 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
|
||||||
@@ -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
|
|
||||||
65
Build/lib/modules/Hyperion/40_pam.kmod
Normal file
65
Build/lib/modules/Hyperion/40_pam.kmod
Normal 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
|
||||||
|
|
||||||
211
Build/lib/modules/Hyperion/45_hypervisor.kmod
Normal file
211
Build/lib/modules/Hyperion/45_hypervisor.kmod
Normal 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
|
||||||
6
Build/lib/modules/Hyperion/47_dbg.kmod
Normal file
6
Build/lib/modules/Hyperion/47_dbg.kmod
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
local kernel=...
|
||||||
|
local debug=debug
|
||||||
|
kernel._G.debug={
|
||||||
|
getinfo=debug.getinfo,
|
||||||
|
traceback=debug.traceback
|
||||||
|
}
|
||||||
125
Build/lib/modules/Hyperion/50_tty.kmod
Normal file
125
Build/lib/modules/Hyperion/50_tty.kmod
Normal 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"
|
||||||
2
Build/lib/modules/Hyperion/55_tty_rebind.kmod
Normal file
2
Build/lib/modules/Hyperion/55_tty_rebind.kmod
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
local kernel=...
|
||||||
|
kernel.tty.bind("tty0")
|
||||||
28
Build/lib/modules/Hyperion/70_stdlibadv.kmod
Normal file
28
Build/lib/modules/Hyperion/70_stdlibadv.kmod
Normal 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
|
||||||
@@ -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")
|
|
||||||
@@ -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
|
||||||
@@ -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
5
Build/lib/sys/init
Normal 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
3
Build/lib/sys/ipc
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
local ipc = {}
|
||||||
|
|
||||||
|
return ipc
|
||||||
71
Build/lib/sys/term
Normal file
71
Build/lib/sys/term
Normal 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
|
||||||
@@ -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
|
|
||||||
@@ -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
82
Build/sbin/init.lua
Normal 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
|
||||||
@@ -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
|
||||||
|
|||||||
0
Test/Hyperion-core-v1.0.0/bin/bash
Normal file
0
Test/Hyperion-core-v1.0.0/bin/bash
Normal file
17
Test/Hyperion-core-v1.0.0/bin/neofetch
Normal file
17
Test/Hyperion-core-v1.0.0/bin/neofetch
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
print(".. *. ..")
|
||||||
|
print(" *= +@* +* ")
|
||||||
|
print(" .@#. -@@@= :#@. ")
|
||||||
|
print(" =@@+ *@@@# +@@= ")
|
||||||
|
print(" %@@%: *@@@# -%@@% ")
|
||||||
|
print(" :@@@@+ *@@@# .*@@@@: ")
|
||||||
|
print(" :*@@@%- *@@@# -@@@@*: ")
|
||||||
|
print(" =%@@#. *@@@# .#@@%= ")
|
||||||
|
print(" :=. :*@@= *@@@# =@@+: .=: ")
|
||||||
|
print(" %@#=..*# +@@@# #*..=#@# ")
|
||||||
|
print(" .@@@@+=# .%@%: #=+@@@@. ")
|
||||||
|
print(" .....=# -@= *+...:. ")
|
||||||
|
print(" -*%*-@= - =@-*%*- ")
|
||||||
|
print(" -@*. -@%. :%@- :*@- ")
|
||||||
|
print(" .#@#@* ")
|
||||||
|
print(" -#- ")
|
||||||
|
print(" ")
|
||||||
1
Test/Hyperion-core-v1.0.0/bin/startup/hello.lua
Normal file
1
Test/Hyperion-core-v1.0.0/bin/startup/hello.lua
Normal file
@@ -0,0 +1 @@
|
|||||||
|
print("hello from hello.lua")
|
||||||
151
Test/Hyperion-core-v1.0.0/lib/bit32
Normal file
151
Test/Hyperion-core-v1.0.0/lib/bit32
Normal 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
Test/Hyperion-core-v1.0.0/lib/crypto/blake2s
Normal file
116
Test/Hyperion-core-v1.0.0/lib/crypto/blake2s
Normal 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
|
||||||
0
Test/Hyperion-core-v1.0.0/lib/io/init
Normal file
0
Test/Hyperion-core-v1.0.0/lib/io/init
Normal file
0
Test/Hyperion-core-v1.0.0/lib/io/stdout/init
Normal file
0
Test/Hyperion-core-v1.0.0/lib/io/stdout/init
Normal file
0
Test/Hyperion-core-v1.0.0/lib/snip
Normal file
0
Test/Hyperion-core-v1.0.0/lib/snip
Normal file
139
Test/Hyperion-core-v1.0.0/lib/sys/fs
Normal file
139
Test/Hyperion-core-v1.0.0/lib/sys/fs
Normal 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
|
||||||
57
Test/Hyperion-core-v1.0.0/lib/sys/hpv
Normal file
57
Test/Hyperion-core-v1.0.0/lib/sys/hpv
Normal 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
|
||||||
5
Test/Hyperion-core-v1.0.0/lib/sys/init
Normal file
5
Test/Hyperion-core-v1.0.0/lib/sys/init
Normal 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
Test/Hyperion-core-v1.0.0/lib/sys/ipc
Normal file
3
Test/Hyperion-core-v1.0.0/lib/sys/ipc
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
local ipc = {}
|
||||||
|
|
||||||
|
return ipc
|
||||||
71
Test/Hyperion-core-v1.0.0/lib/sys/term
Normal file
71
Test/Hyperion-core-v1.0.0/lib/sys/term
Normal 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
|
||||||
@@ -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
|
|
||||||
@@ -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")()
|
|
||||||
82
Test/Hyperion-core-v1.0.0/sbin/init.lua
Normal file
82
Test/Hyperion-core-v1.0.0/sbin/init.lua
Normal 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
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -23,4 +23,4 @@ function driver.main()
|
|||||||
-- Nothing to run
|
-- Nothing to run
|
||||||
end
|
end
|
||||||
|
|
||||||
kernel.drivers.register(driver)
|
-- kernel.drivers.register(driver)
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -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)
|
|
||||||
0
Test/Hyperion-installer-v1.0.0/bin/install
Normal file
0
Test/Hyperion-installer-v1.0.0/bin/install
Normal file
@@ -1,3 +1,2 @@
|
|||||||
U $;/
|
U $;/
|
||||||
U devfs0000;/dev/
|
U devfs0000;/dev/
|
||||||
U sysfs0000;/sys/
|
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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")
|
||||||
@@ -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")
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
local args={...}
|
|
||||||
local kernel=args[1]
|
|
||||||
kernel._U=table.proxy(_G)
|
|
||||||
@@ -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")
|
||||||
@@ -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
|
||||||
172
Test/Hyperion-kernel-v1.0.0/lib/modules/Hyperion/12_devfs.kmod
Normal file
172
Test/Hyperion-kernel-v1.0.0/lib/modules/Hyperion/12_devfs.kmod
Normal 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)
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
local kernel = ...
|
||||||
75
Test/Hyperion-kernel-v1.0.0/lib/modules/Hyperion/20_ipc.kmod
Normal file
75
Test/Hyperion-kernel-v1.0.0/lib/modules/Hyperion/20_ipc.kmod
Normal 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")
|
||||||
@@ -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
|
|
||||||
@@ -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
|
||||||
@@ -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
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
local kernel = ...
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user