hachem.wtf
aboutsummaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/fs.rv83
-rw-r--r--kernel/main.rv9
-rw-r--r--kernel/proc.rv22
-rw-r--r--kernel/seed.rv5
-rw-r--r--kernel/shell.rv56
5 files changed, 136 insertions, 39 deletions
diff --git a/kernel/fs.rv b/kernel/fs.rv
index adb317c..5d72bc1 100644
--- a/kernel/fs.rv
+++ b/kernel/fs.rv
@@ -5,10 +5,7 @@
# sectors 1..8 directory, 128 entries of 32 bytes (16 per sector)
# sectors 9..136 fat, one 2 byte entry per sector on the whole disk
# sectors 137.. file data, one block == one sector
-#
-# a fat entry is the next block in a files chain, 0 means free, END means last
-# block of a chain. a file just stores its first block + byte size in its dir
-# entry and we walk the chain from there
+# a fat entry points at the next block in a files chain, 0 is free, END is the last
const SB_LBA = 0
const DIR_LBA = 1
@@ -66,12 +63,7 @@ end
fn dir_lba(i) DIR_LBA + (i shr 4)
fn dir_off(i) (i band 15) * 32
-# entry byte layout: base is fs.buf + dir_off(i) after loading the sector
-# +0 used (0/1)
-# +1 name length
-# +2 first block (2)
-# +4 size (4)
-# +8 name bytes (up to NAME_MAX)
+# dir entry, 32 bytes: +0 used, +1 name len, +2 first block, +4 size, +8 name bytes
fn name_at(base, len) do
let out = ""
for k in 0..len do out = out ~ string.of_ascii(mem_read(base + 8 + k, 1)) end
@@ -108,13 +100,19 @@ fn fs_init() do
fs.buf = frame_alloc()
fs.fat = frame_alloc()
fs.total = disk_sectors()
- if disk_present() == 0 do fs.ready = :false return :nil end
+ if fs.total == 0 do fs.ready = :false return :nil end
disk_read(SB_LBA, fs.buf)
fs.ready = if mem_read(fs.buf, 4) == MAGIC :true else :false
end
+fn fs_ready() do
+ if fs.ready return :true
+ puts("no filesystem, run mkfs first\n")
+ :false
+end
+
fn fs_format() do
- if disk_present() == 0 do puts("mkfs: no disk\n") return :nil end
+ if disk_sectors() == 0 do puts("mkfs: no disk\n") return :nil end
mem_zero(fs.buf, BLOCK)
mem_write(fs.buf, MAGIC, 4)
mem_write(fs.buf + 4, fs.total, 4)
@@ -126,10 +124,10 @@ fn fs_format() do
puts("formatted " ~ fs.total ~ " sectors, " ~ (fs.total shr 1) ~ " KiB\n")
end
-# write a file, gee i wonder what a function called `fs_write` does
-fn fs_write(name, text) do
- if fs.ready == :false do puts("no filesystem, run mkfs first\n") return :nil end
- if name:len() > NAME_MAX do puts("name too long (max " ~ NAME_MAX ~ ")\n") return :nil end
+# silent core of fs_write, global so the bridge can reach it via getGlobal
+global fs_store = fn(name, text) do
+ if fs_ready() == :false return 0
+ if name:len() > NAME_MAX do puts("name too long (max " ~ NAME_MAX ~ ")\n") return 0 end
let idx = fs_find(name)
if idx >= 0 do
disk_read(dir_lba(idx), fs.buf)
@@ -137,7 +135,7 @@ fn fs_write(name, text) do
end
else do
idx = dir_alloc()
- if idx < 0 do puts("directory full\n") return :nil end
+ if idx < 0 do puts("directory full\n") return 0 end
end
const size = text:len()
@@ -146,7 +144,7 @@ fn fs_write(name, text) do
let written = 0
while written < size do
const block = fat_alloc()
- if block == 0 do puts("disk full\n") return :nil end
+ if block == 0 do puts("disk full\n") return 0 end
fat_set(block, END) # reserve
if first == 0 do first = block end
else do fat_set(prev, block) end
@@ -169,11 +167,52 @@ fn fs_write(name, text) do
mem_write(base + 4, size, 4)
for k in 0..name:len() do mem_write(base + 8 + k, name[k]:ascii(), 1) end
disk_write(dir_lba(idx), fs.buf)
- puts("wrote " ~ name ~ " (" ~ size ~ " bytes)\n")
+ return 1
+end
+
+# write a file, gee i wonder what a function called `fs_write` does
+fn fs_write(name, text) do
+ if fs_store(name, text) == 1 puts("wrote " ~ name ~ " (" ~ text:len() ~ " bytes)\n")
+end
+
+global fs_size = fn(name) do
+ const idx = fs_find(name)
+ if idx < 0 return -1
+ disk_read(dir_lba(idx), fs.buf)
+ return mem_read(fs.buf + dir_off(idx) + 4, 4)
+end
+
+# read up to len bytes from offset, returned as a string (shorter at eof)
+global fs_read_bytes = fn(name, offset, len) do
+ const idx = fs_find(name)
+ if idx < 0 return ""
+ disk_read(dir_lba(idx), fs.buf)
+ const base = fs.buf + dir_off(idx)
+ let block = mem_read(base + 2, 2)
+ const size = mem_read(base + 4, 4)
+ let stop = offset + len
+ if stop > size do stop = size end
+ let pos = 0
+ let out = ""
+ while (block != 0 and block != END and pos < stop) do
+ const nxt = fat_get(block)
+ if (pos + BLOCK > offset and pos < stop) do
+ disk_read(block, fs.buf)
+ let k = 0
+ while (k < BLOCK) do
+ const abs = pos + k
+ if (abs >= offset and abs < stop) do out = out ~ string.of_ascii(mem_read(fs.buf + k, 1)) end
+ k += 1
+ end
+ end
+ pos += BLOCK
+ block = nxt
+ end
+ return out
end
fn fs_cat(name) do
- if fs.ready == :false do puts("no filesystem, run mkfs first\n") return :nil end
+ if fs_ready() == :false return :nil
const idx = fs_find(name)
if idx < 0 do puts("cat: " ~ name ~ ": no such file\n") return :nil end
disk_read(dir_lba(idx), fs.buf)
@@ -194,7 +233,7 @@ fn fs_cat(name) do
end
fn fs_ls() do
- if fs.ready == :false do puts("no filesystem, run mkfs first\n") return :nil end
+ if fs_ready() == :false return :nil
let count = 0
for i in 0..DIR_ENTRIES do
disk_read(dir_lba(i), fs.buf)
@@ -208,7 +247,7 @@ fn fs_ls() do
end
fn fs_rm(name) do
- if fs.ready == :false do puts("no filesystem, run mkfs first\n") return :nil end
+ if fs_ready() == :false return :nil
const idx = fs_find(name)
if idx < 0 do puts("rm: " ~ name ~ ": no such file\n") return :nil end
disk_read(dir_lba(idx), fs.buf)
diff --git a/kernel/main.rv b/kernel/main.rv
index 896bb54..24852fe 100644
--- a/kernel/main.rv
+++ b/kernel/main.rv
@@ -9,9 +9,14 @@ cmd_clear()
dump_memmap()
fs_init()
-if disk_present() == 0 puts("no disk attached\n")
+if disk_sectors() == 0 puts("no disk attached\n")
else if fs.ready puts("mounted revelfs on disk\n")
-else puts("disk has no filesystem, run `mkfs`\n")
+else do
+ # blank disk, first boot after a clone. format it and drop the default files on
+ puts("blank disk, formatting + seeding default files\n")
+ fs_format()
+ seed_fs()
+end
puts("revel shell, live in revo. type `help`\n% ")
flush_console()
diff --git a/kernel/proc.rv b/kernel/proc.rv
index e2f451b..3303bc1 100644
--- a/kernel/proc.rv
+++ b/kernel/proc.rv
@@ -1,12 +1,11 @@
-# parse the embedded elf (physical address from elf_phys()) and run it in ring 3
+# load an embedded elf into a fresh address space and run it in ring 3
const PT_LOAD = 1
const PAGE_FLAGS = 6 # write | user
-fn cmd_run() do
- const base = elf_phys()
+fn load_elf(base) do
if mem_read(base, 4) != 0x464c457f do
- puts("run: not an ELF\n")
+ puts("not an ELF\n")
return :nil
end
const entry = mem_read(base + 24, 8)
@@ -38,3 +37,18 @@ fn cmd_run() do
as_map(space, stack_top - 4096, frame_alloc(), PAGE_FLAGS)
proc_run(space, entry, stack_top)
end
+
+# launch a program by name, :true if one matched
+fn run_prog(name) do
+ for i in 0..prog_count() do
+ if prog_name(i) == name do load_elf(prog_phys(i)) return :true end
+ end
+ puts("no such program: " ~ name ~ "\n")
+ return :false
+end
+
+fn list_progs() do
+ puts("programs:")
+ for i in 0..prog_count() do puts(" " ~ prog_name(i)) end
+ puts("\n")
+end
diff --git a/kernel/seed.rv b/kernel/seed.rv
new file mode 100644
index 0000000..6c0a73f
--- /dev/null
+++ b/kernel/seed.rv
@@ -0,0 +1,5 @@
+# js dw about this ok?
+fn seed_fs() do
+ fs_write("i have big balls.txt", "dude my balls are actually massive")
+ fs_write("balls.txt", "its lowk insane how big my balls are")
+end
diff --git a/kernel/shell.rv b/kernel/shell.rv
index 6e3c2e4..35eac37 100644
--- a/kernel/shell.rv
+++ b/kernel/shell.rv
@@ -1,15 +1,42 @@
# this is just a simple prompt to test that shit is working
fn cmd_help() do
- puts("commands: help, clear, bars, echo <text>, time, mem, uptime, ps, run, zoom in|out\n")
+ puts("commands: help, clear, bars, echo <text>, time, mem, uptime, ps, run <prog>, zoom in|out\n")
puts("fs: mkfs, ls, cat <name>, write <name> <text>, rm <name>\n")
+ puts(" names with spaces go in \"quotes\"\n")
end
-fn cmd_write(line, words) do
- if words:len() < 2 do puts("usage: write <name> <text>\n") return :nil end
- const name = words[1]
- const start = 6 + name:len() + 1
- const text = if line:len() > start line:sub(start, line:len() - start) else ""
- fs_write(name, text)
+fn arg_name(line, start) do
+ let i = start
+ let name = ""
+ if (i < line:len() and line[i]:ascii() == 34) do
+ i += 1
+ while (i < line:len() and line[i]:ascii() != 34) do name = name ~ line[i] i += 1 end
+ if i < line:len() do i += 1 end
+ end
+ else do
+ while (i < line:len() and line[i]:ascii() != 32) do name = name ~ line[i] i += 1 end
+ end
+ if (i < line:len() and line[i]:ascii() == 32) do i += 1 end
+ { name = name, rest = i }
+end
+
+fn cmd_write(line) do
+ const a = arg_name(line, 6)
+ if a.name:len() == 0 do puts("usage: write <name> <text>\n") return :nil end
+ const text = if line:len() > a.rest line:sub(a.rest, line:len() - a.rest) else ""
+ fs_write(a.name, text)
+end
+
+fn cmd_cat(line) do
+ const a = arg_name(line, 4)
+ if a.name:len() == 0 do puts("usage: cat <name>\n") return :nil end
+ fs_cat(a.name)
+end
+
+fn cmd_rm(line) do
+ const a = arg_name(line, 3)
+ if a.name:len() == 0 do puts("usage: rm <name>\n") return :nil end
+ fs_rm(a.name)
end
fn zoom_by(delta) do
@@ -85,7 +112,14 @@ fn run(line) do
if line:trim():len() == 0 do puts("% ") return :nil end
const words = line:split(" ")
const cmd = words[0]
- if cmd == "run" do cmd_run() return :nil end
+ # run launches a process, its prompt gets reprinted by on_tick when it exits so
+ # it lands below the programs output. no arg just lists whats available
+ if cmd == "run" do
+ if words:len() <= 1 do list_progs() puts("% ") return :nil end
+ if run_prog(words[1]) == :true return :nil
+ puts("% ")
+ return :nil
+ end
match cmd
| "help" => cmd_help()
| "clear" => cmd_clear()
@@ -97,9 +131,9 @@ fn run(line) do
| "zoom" => cmd_zoom(words)
| "mkfs" => fs_format()
| "ls" => fs_ls()
- | "cat" => if words:len() > 1 fs_cat(words[1]) else puts("usage: cat <name>\n")
- | "write" => cmd_write(line, words)
- | "rm" => if words:len() > 1 fs_rm(words[1]) else puts("usage: rm <name>\n")
+ | "cat" => cmd_cat(line)
+ | "write" => cmd_write(line)
+ | "rm" => cmd_rm(line)
| "echo" => if line:len() > 5 puts(line:sub(5, line:len() - 5) ~ "\n") else puts("\n")
| _ => puts("unknown command: " ~ cmd ~ "\n")
puts("% ")