diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/console.rv | 111 | ||||
| -rw-r--r-- | kernel/fs.rv | 393 | ||||
| -rw-r--r-- | kernel/input.rv | 34 | ||||
| -rw-r--r-- | kernel/main.rv | 2 | ||||
| -rw-r--r-- | kernel/proc.rv | 75 | ||||
| -rw-r--r-- | kernel/seed.rv | 13 | ||||
| -rw-r--r-- | kernel/shell.rv | 277 | ||||
| -rw-r--r-- | kernel/vfs.rv | 38 | ||||
| -rw-r--r-- | kernel/vmm.rv | 14 |
9 files changed, 466 insertions, 491 deletions
diff --git a/kernel/console.rv b/kernel/console.rv index 65fe03c..7948a74 100644 --- a/kernel/console.rv +++ b/kernel/console.rv @@ -1,79 +1,76 @@ -const FW = 8 # glyph width in pixels -const FH = 16 # glyph height in pixels (8x16 vga bitmap font) -const FG = 0xd0d0d0 -const CON_BG = 0x101018 -const CUR = 0x50fa7b +const FONT_WIDTH = 8 # glyph width in pixels +const FONT_HEIGHT = 16 # glyph height in pixels (8x16 vga bitmap font) +const FG_COLOR = 0xd0d0d0 +const BG_COLOR = 0x101018 +const CURSOR_COLOR = 0x50fa7b -global con = { - col = 0, row = 0, scale = 1, shown = :false, cur_x = 0, cur_y = 0, blink = 0, +global console = { + column = 0, row = 0, scale = 1, shown = :false, cursor_x = 0, cursor_y = 0, blink = 0, # cell size in pixels at the current zoom - cell_w = fn(self) FW * self.scale, - cell_h = fn(self) FH * self.scale, - cols = fn(self) fb_width() / self:cell_w(), - rows = fn(self) fb_height() / self:cell_h(), + cell_width = fn(self) FONT_WIDTH * self.scale, + cell_height = fn(self) FONT_HEIGHT * self.scale, + columns = fn(self) fb_width() / self:cell_width(), + rows = fn(self) fb_height() / self:cell_height(), - draw_glyph = fn(self, col, row, ch) do - const x0 = col * self:cell_w() - const y0 = row * self:cell_h() - fill_rect(x0, y0, self:cell_w(), self:cell_h(), CON_BG) # clear the cell - const code = ch:ascii() + draw_glyph = fn(self, column, row, character) do + const origin_x = column * self:cell_width() + const origin_y = row * self:cell_height() + fill_rect(origin_x, origin_y, self:cell_width(), self:cell_height(), BG_COLOR) # clear the cell + const code = character:ascii() if code < 32 return :nil if code > 127 return :nil const glyph = FONT[code - 32] - for fy in 0..FH do - const bits = glyph[fy] - for fx in 0..FW do - if (bits shr fx) band 1 == 1 fill_rect(x0 + fx * self.scale, y0 + fy * self.scale, self.scale, self.scale, FG) + for glyph_row in 0..FONT_HEIGHT do + const bits = glyph[glyph_row] + for glyph_col in 0..FONT_WIDTH do + if (bits shr glyph_col) band 1 == 1 fill_rect(origin_x + glyph_col * self.scale, origin_y + glyph_row * self.scale, self.scale, self.scale, FG_COLOR) end end end, newline = fn(self) do - self.col = 0 + self.column = 0 self.row += 1 if self.row >= self:rows() do - fb_scroll(self:cell_h(), CON_BG) + fb_scroll(self:cell_height(), BG_COLOR) self.row = self:rows() - 1 end end, # we dont do shift/cntrl, thats a job for future me lmao # NOTE: future me kinda delt with it, i was mad drunk - putc = fn(self, ch) do - const code = ch:ascii() + putc = fn(self, character) do + const code = character:ascii() if code == 10 do self:newline() return :nil end # \n - if code == 13 do self.col = 0 return :nil end # \r - if code == 8 do # backspace: move left - if self.col > 0 self.col -= 1 + if code == 13 do self.column = 0 return :nil end # \r + if code == 8 do # backspace: move left + if self.column > 0 self.column -= 1 return :nil end if code < 32 return :nil - self:draw_glyph(self.col, self.row, ch) - self.col += 1 - if self.col >= self:cols() self:newline() + self:draw_glyph(self.column, self.row, character) + self.column += 1 + if self.column >= self:columns() self:newline() end, clear = fn(self) do - fill_rect(0, 0, fb_width(), fb_height(), CON_BG) - self.col = 0 + fill_rect(0, 0, fb_width(), fb_height(), BG_COLOR) + self.column = 0 self.row = 0 end, - # the cursor is an overlay block. its cleared before any drawing and shown after, - # so it never sits under a glyph, cur_x/cur_y remember where it was actually drawn - # so we always clear the right cell even after the head moved (backspace and shit) cursor_clear = fn(self) do if self.shown do - fill_rect(self.cur_x * self:cell_w(), self.cur_y * self:cell_h(), self:cell_w(), self:cell_h(), CON_BG) + fill_rect(self.cursor_x * self:cell_width(), self.cursor_y * self:cell_height(), self:cell_width(), self:cell_height(), BG_COLOR) self.shown = :false end end, cursor_show = fn(self) do - self.cur_x = self.col - self.cur_y = self.row - fill_rect(self.cur_x * self:cell_w(), self.cur_y * self:cell_h(), self:cell_w(), self:cell_h(), CUR) + self.cursor_x = self.column + self.cursor_y = self.row + fill_rect(self.cursor_x * self:cell_width(), self.cursor_y * self:cell_height(), self:cell_width(), self:cell_height(), CURSOR_COLOR) self.shown = :true end, @@ -84,36 +81,36 @@ global con = { end, } -fn puts(str) serial_puts(str) +global puts = fn(text) serial_puts(text) global flush_console = fn() do - con:cursor_clear() - con:drain() - con.blink = 0 - con:cursor_show() + console:cursor_clear() + console:drain() + console.blink = 0 + console:cursor_show() end global on_tick = fn(ticks) do let byte = serial_next() if byte >= 0 do - con:cursor_clear() - con:putc(string.of_ascii(byte)) - con:drain() - con.blink = 0 - con:cursor_show() + console:cursor_clear() + console:putc(string.of_ascii(byte)) + console:drain() + console.blink = 0 + console:cursor_show() return :nil end if proc_exited() do - con:cursor_clear() + console:cursor_clear() puts("% ") - con:drain() - con.blink = 0 - con:cursor_show() + console:drain() + console.blink = 0 + console:cursor_show() return :nil end - con.blink += 1 - if con.blink >= 50 do - con.blink = 0 - if con.shown con:cursor_clear() else con:cursor_show() + console.blink += 1 + if console.blink >= 50 do + console.blink = 0 + if console.shown console:cursor_clear() else console:cursor_show() end end diff --git a/kernel/fs.rv b/kernel/fs.rv index c045950..6229fd5 100644 --- a/kernel/fs.rv +++ b/kernel/fs.rv @@ -20,39 +20,39 @@ const T_FILE = 1 const T_DIR = 2 fn split_path(path) do - const raw = path:split("/") + const raw_parts = path:split("/") let parts = {} - for i in 0..raw:len() do - if raw[i]:len() > 0 parts:push(raw[i]) + for index in 0..raw_parts:len() do + if raw_parts[index]:len() > 0 parts:push(raw_parts[index]) end return parts end -# buf is a scratch sector for superblocks/dirs/data, fat is a separate scratch so -# fat lookups dont trample a dir block were mid edit. +# scratch is a spare sector for superblocks/dirs/data, fat is a separate scratch +# so fat lookups dont trample a dir block were mid edit. global fs = { - buf = 0, fat = 0, ready = :false, total = 0, root = 0, + scratch = 0, fat = 0, ready = :false, total = 0, root = 0, fat_get = fn(self, block) do disk_read(FAT_LBA + (block shr 8), self.fat) mem_read(self.fat + (block band 255) * 2, 2) end, - fat_set = fn(self, block, val) do - const lba = FAT_LBA + (block shr 8) - disk_read(lba, self.fat) - mem_write(self.fat + (block band 255) * 2, val, 2) - disk_write(lba, self.fat) + fat_set = fn(self, block, value) do + const sector = FAT_LBA + (block shr 8) + disk_read(sector, self.fat) + mem_write(self.fat + (block band 255) * 2, value, 2) + disk_write(sector, self.fat) end, fat_alloc = fn(self) do let block = DATA_LBA while block < self.total do disk_read(FAT_LBA + (block shr 8), self.fat) - let off = block band 255 - while (off < 256 and block < self.total) do - if mem_read(self.fat + off * 2, 2) == 0 return block - off += 1 + let offset = block band 255 + while (offset < 256 and block < self.total) do + if mem_read(self.fat + offset * 2, 2) == 0 return block + offset += 1 block += 1 end end @@ -62,9 +62,9 @@ global fs = { free_chain = fn(self, first) do let block = first while (block != 0 and block != END) do - const nxt = self:fat_get(block) + const next_block = self:fat_get(block) self:fat_set(block, 0) - block = nxt + block = next_block end end, @@ -74,33 +74,33 @@ global fs = { # +2 first block # +4 size # +8 name bytes - ent_name = fn(self, eoff) do - const len = mem_read(self.buf + eoff + 1, 1) - let out = "" - for k in 0..len do out = out ~ string.of_ascii(mem_read(self.buf + eoff + 8 + k, 1)) end - out + ent_name = fn(self, entry_offset) do + const name_length = mem_read(self.scratch + entry_offset + 1, 1) + let result = "" + for index in 0..name_length do result = result ~ string.of_ascii(mem_read(self.scratch + entry_offset + 8 + index, 1)) end + result end, - ent_write = fn(self, eoff, type, name, first, size) do - mem_write(self.buf + eoff, type, 1) - mem_write(self.buf + eoff + 1, name:len(), 1) - mem_write(self.buf + eoff + 2, first, 2) - mem_write(self.buf + eoff + 4, size, 4) - for k in 0..name:len() do mem_write(self.buf + eoff + 8 + k, name[k]:ascii(), 1) end + ent_write = fn(self, entry_offset, type, name, first, size) do + mem_write(self.scratch + entry_offset, type, 1) + mem_write(self.scratch + entry_offset + 1, name:len(), 1) + mem_write(self.scratch + entry_offset + 2, first, 2) + mem_write(self.scratch + entry_offset + 4, size, 4) + for index in 0..name:len() do mem_write(self.scratch + entry_offset + 8 + index, name[index]:ascii(), 1) end end, dir_lookup = fn(self, dir_first, name) do let block = dir_first while (block != 0 and block != END) do - const nxt = self:fat_get(block) - disk_read(block, self.buf) + const next_block = self:fat_get(block) + disk_read(block, self.scratch) for slot in 0..ENTS do - const eoff = slot * 32 - if mem_read(self.buf + eoff, 1) != 0 and self:ent_name(eoff) == name do - return { type = mem_read(self.buf + eoff, 1), first = mem_read(self.buf + eoff + 2, 2), size = mem_read(self.buf + eoff + 4, 4) } + const entry_offset = slot * 32 + if mem_read(self.scratch + entry_offset, 1) != 0 and self:ent_name(entry_offset) == name do + return { type = mem_read(self.scratch + entry_offset, 1), first = mem_read(self.scratch + entry_offset + 2, 2), size = mem_read(self.scratch + entry_offset + 4, 4) } end end - block = nxt + block = next_block end return :nil end, @@ -110,62 +110,62 @@ global fs = { dir_set = fn(self, dir_first, name, type, first, size) do let block = dir_first let found_block = 0 - let found_off = 0 + let found_offset = 0 let free_block = 0 - let free_off = -1 + let free_offset = -1 let last_block = dir_first while (block != 0 and block != END) do last_block = block - const nxt = self:fat_get(block) - disk_read(block, self.buf) + const next_block = self:fat_get(block) + disk_read(block, self.scratch) for slot in 0..ENTS do - const eoff = slot * 32 - if mem_read(self.buf + eoff, 1) == 0 do - if free_off < 0 do free_block = block free_off = eoff end + const entry_offset = slot * 32 + if mem_read(self.scratch + entry_offset, 1) == 0 do + if free_offset < 0 do free_block = block free_offset = entry_offset end end else do - if self:ent_name(eoff) == name do found_block = block found_off = eoff end + if self:ent_name(entry_offset) == name do found_block = block found_offset = entry_offset end end end - block = nxt + block = next_block end let target_block = 0 - let target_off = 0 - if found_block != 0 do target_block = found_block target_off = found_off end - else if free_off >= 0 do target_block = free_block target_off = free_off end + let target_offset = 0 + if found_block != 0 do target_block = found_block target_offset = found_offset end + else if free_offset >= 0 do target_block = free_block target_offset = free_offset end else do - const nb = self:fat_alloc() - if nb == 0 return :false - self:fat_set(nb, END) - self:fat_set(last_block, nb) - mem_zero(self.buf, BLOCK) - disk_write(nb, self.buf) - target_block = nb - target_off = 0 + const new_block = self:fat_alloc() + if new_block == 0 return :false + self:fat_set(new_block, END) + self:fat_set(last_block, new_block) + mem_zero(self.scratch, BLOCK) + disk_write(new_block, self.scratch) + target_block = new_block + target_offset = 0 end - disk_read(target_block, self.buf) - self:ent_write(target_off, type, name, first, size) - disk_write(target_block, self.buf) + disk_read(target_block, self.scratch) + self:ent_write(target_offset, type, name, first, size) + disk_write(target_block, self.scratch) return :true end, dir_clear = fn(self, dir_first, name) do let block = dir_first while (block != 0 and block != END) do - const nxt = self:fat_get(block) - disk_read(block, self.buf) + const next_block = self:fat_get(block) + disk_read(block, self.scratch) for slot in 0..ENTS do - const eoff = slot * 32 - if mem_read(self.buf + eoff, 1) != 0 and self:ent_name(eoff) == name do - const info = { type = mem_read(self.buf + eoff, 1), first = mem_read(self.buf + eoff + 2, 2) } - mem_write(self.buf + eoff, 0, 1) - disk_write(block, self.buf) + const entry_offset = slot * 32 + if mem_read(self.scratch + entry_offset, 1) != 0 and self:ent_name(entry_offset) == name do + const info = { type = mem_read(self.scratch + entry_offset, 1), first = mem_read(self.scratch + entry_offset + 2, 2) } + mem_write(self.scratch + entry_offset, 0, 1) + disk_write(block, self.scratch) return info end end - block = nxt + block = next_block end return :nil end, @@ -173,50 +173,50 @@ global fs = { dir_empty = fn(self, dir_first) do let block = dir_first while (block != 0 and block != END) do - const nxt = self:fat_get(block) - disk_read(block, self.buf) + const next_block = self:fat_get(block) + disk_read(block, self.scratch) for slot in 0..ENTS do - if mem_read(self.buf + slot * 32, 1) != 0 return :false + if mem_read(self.scratch + slot * 32, 1) != 0 return :false end - block = nxt + block = next_block end return :true end, resolve = fn(self, path) do const parts = split_path(path) - let cur = self.root - let ent = { type = T_DIR, first = self.root, size = 0 } - for i in 0..parts:len() do - if ent.type != T_DIR return :nil - const found = self:dir_lookup(cur, parts[i]) + let current = self.root + let entry = { type = T_DIR, first = self.root, size = 0 } + for index in 0..parts:len() do + if entry.type != T_DIR return :nil + const found = self:dir_lookup(current, parts[index]) if found == :nil return :nil - ent = found - cur = found.first + entry = found + current = found.first end - return ent + return entry end, resolve_parent = fn(self, path) do const parts = split_path(path) if parts:len() == 0 return :nil - let pdir = self.root - for i in 0..(parts:len() - 1) do - const found = self:dir_lookup(pdir, parts[i]) + let parent_dir = self.root + for index in 0..(parts:len() - 1) do + const found = self:dir_lookup(parent_dir, parts[index]) if found == :nil or found.type != T_DIR return :nil - pdir = found.first + parent_dir = found.first end - return { dir = pdir, name = parts[parts:len() - 1] } + return { dir = parent_dir, name = parts[parts:len() - 1] } end, mount = fn(self) do - self.buf = frame_alloc() + self.scratch = frame_alloc() self.fat = frame_alloc() self.total = disk_sectors() if self.total == 0 do self.ready = :false return :nil end - disk_read(SB_LBA, self.buf) - if mem_read(self.buf, 4) == MAGIC do - self.root = mem_read(self.buf + 8, 2) + disk_read(SB_LBA, self.scratch) + if mem_read(self.scratch, 4) == MAGIC do + self.root = mem_read(self.scratch + 8, 2) self.ready = :true end else do self.ready = :false end @@ -230,68 +230,68 @@ global fs = { format = fn(self) do if disk_sectors() == 0 do puts("mkfs: no disk\n") return :nil end - mem_zero(self.buf, BLOCK) - for s in 0..FAT_SECTORS do disk_write(FAT_LBA + s, self.buf) end + mem_zero(self.scratch, BLOCK) + for sector in 0..FAT_SECTORS do disk_write(FAT_LBA + sector, self.scratch) end const root = self:fat_alloc() self:fat_set(root, END) - mem_zero(self.buf, BLOCK) - disk_write(root, self.buf) + mem_zero(self.scratch, BLOCK) + disk_write(root, self.scratch) self.root = root - mem_zero(self.buf, BLOCK) - mem_write(self.buf, MAGIC, 4) - mem_write(self.buf + 4, self.total, 4) - mem_write(self.buf + 8, root, 2) - disk_write(SB_LBA, self.buf) + mem_zero(self.scratch, BLOCK) + mem_write(self.scratch, MAGIC, 4) + mem_write(self.scratch + 4, self.total, 4) + mem_write(self.scratch + 8, root, 2) + disk_write(SB_LBA, self.scratch) self.ready = :true puts("formatted #{self.total} sectors, #{(self.total shr 1)} KiB\n") end, mkdir = fn(self, path) do if self:ensure() == :false return :nil - const pp = self:resolve_parent(path) - if pp == :nil do puts("mkdir: #{path}: bad path\n") return :nil end - if pp.name:len() > NAME_MAX do puts("name too long (max #{NAME_MAX})\n") return :nil end - if self:dir_lookup(pp.dir, pp.name) != :nil do puts("mkdir: #{pp.name}: already exists\n") return :nil end - const nb = self:fat_alloc() - if nb == 0 do puts("disk full\n") return :nil end - self:fat_set(nb, END) - mem_zero(self.buf, BLOCK) - disk_write(nb, self.buf) - self:dir_set(pp.dir, pp.name, T_DIR, nb, 0) + const parent = self:resolve_parent(path) + if parent == :nil do puts("mkdir: #{path}: bad path\n") return :nil end + if parent.name:len() > NAME_MAX do puts("name too long (max #{NAME_MAX})\n") return :nil end + if self:dir_lookup(parent.dir, parent.name) != :nil do puts("mkdir: #{parent.name}: already exists\n") return :nil end + const new_block = self:fat_alloc() + if new_block == 0 do puts("disk full\n") return :nil end + self:fat_set(new_block, END) + mem_zero(self.scratch, BLOCK) + disk_write(new_block, self.scratch) + self:dir_set(parent.dir, parent.name, T_DIR, new_block, 0) end, store = fn(self, path, text) do if self:ensure() == :false return 0 - const pp = self:resolve_parent(path) - if pp == :nil do puts("#{path}: bad path\n") return 0 end - if pp.name:len() > NAME_MAX do puts("name too long (max #{NAME_MAX})\n") return 0 end - const existing = self:dir_lookup(pp.dir, pp.name) + const parent = self:resolve_parent(path) + if parent == :nil do puts("#{path}: bad path\n") return 0 end + if parent.name:len() > NAME_MAX do puts("name too long (max #{NAME_MAX})\n") return 0 end + const existing = self:dir_lookup(parent.dir, parent.name) if existing != :nil do - if existing.type == T_DIR do puts("#{pp.name}: is a directory\n") return 0 end + if existing.type == T_DIR do puts("#{parent.name}: is a directory\n") return 0 end self:free_chain(existing.first) end const size = text:len() let first = 0 - let prev = 0 + let previous = 0 let written = 0 while written < size do const block = self:fat_alloc() if block == 0 do puts("disk full\n") return 0 end self:fat_set(block, END) if first == 0 do first = block end - else do self:fat_set(prev, block) end - mem_zero(self.buf, BLOCK) - let k = 0 - while (k < BLOCK and written < size) do - mem_write(self.buf + k, text[written]:ascii(), 1) - k += 1 - written += 1 - end - disk_write(block, self.buf) - prev = block + else do self:fat_set(previous, block) end + mem_zero(self.scratch, BLOCK) + # blit a whole block of the string at once, per byte was O(n^2) and choked + # the second files got into the kilobytes + let chunk = size - written + if chunk > BLOCK do chunk = BLOCK end + blit_str(self.scratch, text[written..(written + chunk)]) + disk_write(block, self.scratch) + written += chunk + previous = block end - self:dir_set(pp.dir, pp.name, T_FILE, first, size) + self:dir_set(parent.dir, parent.name, T_FILE, first, size) return 1 end, @@ -300,102 +300,131 @@ global fs = { end, size = fn(self, path) do - const ent = self:resolve(path) - if ent == :nil or ent.type == T_DIR return -1 - return ent.size + const entry = self:resolve(path) + if entry == :nil or entry.type == T_DIR return -1 + return entry.size end, - read_bytes = fn(self, path, offset, len) do - const ent = self:resolve(path) - if ent == :nil or ent.type == T_DIR return "" - let block = ent.first - let stop = offset + len - if stop > ent.size do stop = ent.size end - let pos = 0 - let out = "" - while (block != 0 and block != END and pos < stop) do - const nxt = self:fat_get(block) - if (pos + BLOCK > offset and pos < stop) do - disk_read(block, self.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(self.buf + k, 1)) end - k += 1 - end + read_bytes = fn(self, path, offset, length) do + const entry = self:resolve(path) + if entry == :nil or entry.type == T_DIR return "" + let block = entry.first + let stop = offset + length + if stop > entry.size do stop = entry.size end + let position = 0 + let result = "" + while (block != 0 and block != END and position < stop) do + const next_block = self:fat_get(block) + if (position + BLOCK > offset and position < stop) do + disk_read(block, self.scratch) + # pull this blocks slice in one go, per byte concat was O(n^2) + let from = 0 + if offset > position do from = offset - position end + let to = BLOCK + if stop - position < BLOCK do to = stop - position end + result = result ~ phys_to_str(self.scratch + from, to - from) end - pos += BLOCK - block = nxt + position += BLOCK + block = next_block end - return out + return result end, cat = fn(self, path) do if self:ensure() == :false return :nil - const ent = self:resolve(path) - if ent == :nil do puts("cat: #{path}: no such file\n") return :nil end - if ent.type == T_DIR do puts("cat: #{path}: is a directory\n") return :nil end - let block = ent.first - let remaining = ent.size - let out = "" + const entry = self:resolve(path) + if entry == :nil do puts("cat: #{path}: no such file\n") return :nil end + if entry.type == T_DIR do puts("cat: #{path}: is a directory\n") return :nil end + let block = entry.first + let remaining = entry.size + let result = "" while (block != 0 and block != END and remaining > 0) do - const nxt = self:fat_get(block) - disk_read(block, self.buf) + const next_block = self:fat_get(block) + disk_read(block, self.scratch) const chunk = if remaining > BLOCK BLOCK else remaining - for k in 0..chunk do out = out ~ string.of_ascii(mem_read(self.buf + k, 1)) end + for index in 0..chunk do result = result ~ string.of_ascii(mem_read(self.scratch + index, 1)) end remaining -= chunk - block = nxt + block = next_block end - puts(out) + puts(result) puts("\n") end, ls = fn(self, path) do if self:ensure() == :false return -1 - const ent = self:resolve(path) - if ent == :nil do puts("ls: #{path}: no such file\n") return -1 end - if ent.type != T_DIR do puts(" #{path} #{ent.size} bytes\n") return -1 end + const entry = self:resolve(path) + if entry == :nil do puts("ls: #{path}: no such file\n") return -1 end + if entry.type != T_DIR do puts(" #{path} #{entry.size} bytes\n") return -1 end let count = 0 - let block = ent.first + let block = entry.first while (block != 0 and block != END) do - const nxt = self:fat_get(block) - disk_read(block, self.buf) + const next_block = self:fat_get(block) + disk_read(block, self.scratch) for slot in 0..ENTS do - const eoff = slot * 32 - const t = mem_read(self.buf + eoff, 1) - if t != 0 do - const nm = self:ent_name(eoff) - if t == T_DIR do puts(" #{nm}/\n") end - else do puts(" #{nm} #{mem_read(self.buf + eoff + 4, 4)} bytes\n") end + const entry_offset = slot * 32 + const entry_type = mem_read(self.scratch + entry_offset, 1) + if entry_type != 0 do + const name = self:ent_name(entry_offset) + if entry_type == T_DIR do puts(" #{name}/\n") end + else do puts(" #{name} #{mem_read(self.scratch + entry_offset + 4, 4)} bytes\n") end count += 1 end end - block = nxt + block = next_block end return count end, rm = fn(self, path) do if self:ensure() == :false return :nil - const pp = self:resolve_parent(path) - if pp == :nil do puts("rm: #{path}: no such file\n") return :nil end - const ent = self:dir_lookup(pp.dir, pp.name) - if ent == :nil do puts("rm: #{path}: no such file\n") return :nil end - if ent.type == T_DIR and self:dir_empty(ent.first) == :false do - puts("rm: #{pp.name}: directory not empty\n") + const parent = self:resolve_parent(path) + if parent == :nil do puts("rm: #{path}: no such file\n") return :nil end + const entry = self:dir_lookup(parent.dir, parent.name) + if entry == :nil do puts("rm: #{path}: no such file\n") return :nil end + if entry.type == T_DIR and self:dir_empty(entry.first) == :false do + puts("rm: #{parent.name}: directory not empty\n") return :nil end - self:free_chain(ent.first) - self:dir_clear(pp.dir, pp.name) - puts("removed #{pp.name}\n") + self:free_chain(entry.first) + self:dir_clear(parent.dir, parent.name) + puts("removed #{parent.name}\n") end, is_dir = fn(self, path) do - const ent = self:resolve(path) - return ent != :nil and ent.type == T_DIR + const entry = self:resolve(path) + return entry != :nil and entry.type == T_DIR + end, + + entries = fn(self, path) do + const entry = self:resolve(path) + if entry == :nil or entry.type != T_DIR return :nil + let result = {} + let block = entry.first + while (block != 0 and block != END) do + const next_block = self:fat_get(block) + disk_read(block, self.scratch) + for slot in 0..ENTS do + const entry_offset = slot * 32 + const entry_type = mem_read(self.scratch + entry_offset, 1) + if entry_type != 0 result:push({ name = self:ent_name(entry_offset), type = entry_type, size = mem_read(self.scratch + entry_offset + 4, 4) }) + end + block = next_block + end + return result + end, + + unlink = fn(self, path) do + const parent = self:resolve_parent(path) + if parent == :nil return :false + const entry = self:dir_lookup(parent.dir, parent.name) + if entry == :nil return :false + if (entry.type == T_DIR and self:dir_empty(entry.first) == :false) return :false + self:free_chain(entry.first) + self:dir_clear(parent.dir, parent.name) + return :true end, } global fs_store = fn(name, text) fs:store(name, text) global fs_size = fn(name) fs:size(name) -global fs_read_bytes = fn(name, offset, len) fs:read_bytes(name, offset, len) +global fs_read_bytes = fn(name, offset, length) fs:read_bytes(name, offset, length) diff --git a/kernel/input.rv b/kernel/input.rv index 7e0d156..26ce545 100644 --- a/kernel/input.rv +++ b/kernel/input.rv @@ -1,8 +1,8 @@ # keyboard scancode table # ts is not a good way to write a driver lmao -const KBD = " 1234567890-= qwertyuiop[] asdfghjkl;'` \\zxcvbnm,./ " -const KBD_SHIFT = " !@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"~ |ZXCVBNM<>? " +const KEYMAP = " 1234567890-= qwertyuiop[] asdfghjkl;'` \\zxcvbnm,./ " +const KEYMAP_SHIFT = " !@#$%^&*()_+ QWERTYUIOP{} ASDFGHJKL:\"~ |ZXCVBNM<>? " # 8259 pic fn pic_remap() do @@ -25,7 +25,7 @@ end # she stroke my keys till i handle # no fr this is just a key stroke handler -global shell = { line = "", shift = :false, ext = :false } +global shell = { line = "", shift = :false, extended = :false } fn decode_key(code) do if code == 0x2a or code == 0x36 do shell.shift = :true return :nil end # shift down @@ -34,16 +34,16 @@ fn decode_key(code) do if code == 28 return "\n" # enter if code == 14 return "\x08" # backspace if code < 2 return :nil - if code >= KBD:len() return :nil - const ch = if shell.shift KBD_SHIFT[code] else KBD[code] - if ch == " " and code != 0x39 return :nil # blank cells = modifiers/unmapped - ch + if code >= KEYMAP:len() return :nil + const character = if shell.shift KEYMAP_SHIFT[code] else KEYMAP[code] + if character == " " and code != 0x39 return :nil # blank cells = modifiers/unmapped + character end global on_key = fn(code) do - if code == 0xe0 do shell.ext = :true return :nil end - if shell.ext do - shell.ext = :false + if code == 0xe0 do shell.extended = :true return :nil end + if shell.extended do + shell.extended = :false let final = 0 if code == 0x48 do final = 65 end # up else if code == 0x50 do final = 66 end # down @@ -56,14 +56,14 @@ global on_key = fn(code) do end return :nil end - const ch = decode_key(code) - if ch == :nil return :nil - if stdin_deliver(ch:ascii()) return :nil - if ch == "\n" do puts("\n") run(shell.line) shell.line = "" return :nil end - if ch == "\x08" do + const character = decode_key(code) + if character == :nil return :nil + if stdin_deliver(character:ascii()) return :nil + if character == "\n" do puts("\n") run(shell.line) shell.line = "" return :nil end + if character == "\x08" do if shell.line:len() > 0 do shell.line = shell.line:sub(0, shell.line:len() - 1) puts("\x08 \x08") end return :nil end - shell.line ~= ch - puts(ch) + shell.line ~= character + puts(character) end diff --git a/kernel/main.rv b/kernel/main.rv index 4a6fb58..568d695 100644 --- a/kernel/main.rv +++ b/kernel/main.rv @@ -5,7 +5,7 @@ pit_init() pic_unmask(0) # pit (irq0) -> cursor blink / uptime pic_unmask(1) # keyboard (irq1) -cmd_clear() +wipe() dump_memmap() fs:mount() diff --git a/kernel/proc.rv b/kernel/proc.rv index 2f8bb2f..5019fa8 100644 --- a/kernel/proc.rv +++ b/kernel/proc.rv @@ -10,56 +10,71 @@ fn load_elf(base, arg) do return :nil end const entry = mem_read(base + 24, 8) - const phoff = mem_read(base + 32, 8) - const phnum = mem_read(base + 56, 2) - const phentsize = mem_read(base + 54, 2) + const program_header_offset = mem_read(base + 32, 8) + const program_header_count = mem_read(base + 56, 2) + const program_header_size = mem_read(base + 54, 2) const space = as_create() - for i in 0..phnum do - const phdr = base + phoff + i * phentsize - if mem_read(phdr, 4) == PT_LOAD do - const offset = mem_read(phdr + 8, 8) - const vaddr = mem_read(phdr + 16, 8) - const filesz = mem_read(phdr + 32, 8) - const memsz = mem_read(phdr + 40, 8) - let seg_off = 0 - while seg_off < memsz do + for index in 0..program_header_count do + const header = base + program_header_offset + index * program_header_size + if mem_read(header, 4) == PT_LOAD do + const file_offset = mem_read(header + 8, 8) + const virtual_address = mem_read(header + 16, 8) + const file_size = mem_read(header + 32, 8) + const memory_size = mem_read(header + 40, 8) + let segment_offset = 0 + while segment_offset < memory_size do const frame = frame_alloc() mem_zero(frame, 4096) - if seg_off < filesz do - const left = filesz - seg_off - mem_copy(frame, base + offset + seg_off, if left > 4096 4096 else left) + if segment_offset < file_size do + const remaining = file_size - segment_offset + mem_copy(frame, base + file_offset + segment_offset, if remaining > 4096 4096 else remaining) end - as_map(space, vaddr + seg_off, frame, PAGE_FLAGS) - seg_off = seg_off + 4096 + as_map(space, virtual_address + segment_offset, frame, PAGE_FLAGS) + segment_offset = segment_offset + 4096 end end end const stack_top = 0x7fff0000 - for p in 0..4 do as_map(space, stack_top - (p + 1) * 4096, frame_alloc(), PAGE_FLAGS) end + for page in 0..4 do as_map(space, stack_top - (page + 1) * 4096, frame_alloc(), PAGE_FLAGS) end let arg_ptr = 0 const arg_len = arg:len() if arg_len > 0 do - const argframe = frame_alloc() - mem_zero(argframe, 4096) - for k in 0..arg_len do mem_write(argframe + k, arg[k]:ascii(), 1) end - as_map(space, ARG_VADDR, argframe, PAGE_FLAGS) + const arg_frame = frame_alloc() + mem_zero(arg_frame, 4096) + for index in 0..arg_len do mem_write(arg_frame + index, arg[index]:ascii(), 1) end + as_map(space, ARG_VADDR, arg_frame, PAGE_FLAGS) arg_ptr = ARG_VADDR end proc_run(space, entry, stack_top, arg_ptr, arg_len) end +# one reused contiguous buffer to stage an elf image read off the disk, since +# load_elf wants a flat base to mem_read from and a file lands in scattered frames +# its a weird arch but wtv +global loader = { scratch = 0 } +const SCRATCH_PAGES = 64 + +fn load_file_elf(path, arg) do + const size = fs:size(path) + if size < 0 do puts("#{path}: not found\n") return :false end + if size > SCRATCH_PAGES * 4096 do puts("#{path}: too big to load\n") return :false end + if loader.scratch == 0 do loader.scratch = alloc_contig(SCRATCH_PAGES) end + if loader.scratch == 0 do puts("no memory for elf load\n") return :false end + blit_str(loader.scratch, fs:read_bytes(path, 0, size)) + load_elf(loader.scratch, arg) + return :true +end + fn run_prog(name, arg) do - let n = name - if n:starts_with?("/bin/") n = n[5..] - for i in 0..prog_count() do - if prog_name(i) == n do load_elf(prog_phys(i), arg) return :true end - end - puts("no such program: #{name}\n") - return :false + let bare_name = name + if bare_name:starts_with?("/bin/") bare_name = bare_name[5..] + const path = "/bin/#{bare_name}" + if fs:size(path) < 0 return :false + return load_file_elf(path, arg) end fn list_progs() do puts("programs:") - for i in 0..prog_count() do puts(" #{prog_name(i)}") end + for index in 0..prog_count() do puts(" #{prog_name(index)}") end puts("\n") end diff --git a/kernel/seed.rv b/kernel/seed.rv index 8c0d9b7..ad3f4e9 100644 --- a/kernel/seed.rv +++ b/kernel/seed.rv @@ -1,4 +1,15 @@ # js dw about this ok? + +fn seed_bin() do + fs:mkdir("/bin") + for index in 0..prog_count() do + fs:store("/bin/#{prog_name(index)}", phys_to_str(prog_phys(index), prog_size(index))) + end + for index in 0..script_count() do + fs:store("/bin/#{script_name(index)}.rv", script_src(index)) + end +end + fn seed_fs() do fs:mkdir("/usr") fs:mkdir("/etc") @@ -7,4 +18,6 @@ fn seed_fs() do fs:store("/etc/motd", "welcome to revel") fs:store("/home/balls.txt", "its lowk insane how big my balls are") fs:store("/home/i have big balls.txt", "dude my balls are actually massive") + + seed_bin() end diff --git a/kernel/shell.rv b/kernel/shell.rv index 40930c5..5d0a1c2 100644 --- a/kernel/shell.rv +++ b/kernel/shell.rv @@ -1,190 +1,117 @@ -# this is just a simple prompt to test that shit is working +# i eventually want the shell to be a standalone program and shit -fn pad(s, width) do - let out = s - while out:len() < width do out = out ~ " " end - return out +fn pad(text, width) do + let result = text + while result:len() < width do result = result ~ " " end + return result end -fn help_row(cmd, desc) puts(" #{pad(cmd, 20)}#{desc}\n") +fn help_row(label, description) puts(" #{pad(label, 20)}#{description}\n") -fn cmd_help() do - puts("\n shell\n") - help_row("help", "show this") - help_row("clear", "wipe the screen") - help_row("time", "utc clock") - help_row("mem", "free / total ram") - help_row("uptime", "seconds since boot") - help_row("ps", "running processes") - help_row("zoom in|out", "scale the font") - help_row("echo <text>", "print it back") - puts("\n files\n") - help_row("ls [path]", "list a directory") - help_row("cd <path>", "change directory") - help_row("pwd", "print working dir") - help_row("mkdir <path>", "make a directory") - help_row("cat <path>", "print a file") - help_row("edit <path>", "line editor, . to save") - help_row("write <path> <text>", "create or overwrite") - help_row("rm <path>", "delete a file or empty dir") - help_row("mkfs", "format the disk") - puts("\n programs\n") - help_row("run", "list programs") - help_row("run <name>", "") +fn help_group(title, group_name) do + puts("\n #{title}\n") + for index in 0..commands:len() do + if commands[index].group == group_name do help_row(commands[index].usage, commands[index].help) end + end +end + +fn cmd_help(context) do + help_group("shell", "shell") + help_group("gils (builtin)", "gils") + # the rest of gils, and the programs, are real files in /bin now + const items = fs:entries("/bin") + if items != :nil do + puts("\n gils (/bin scripts)\n") + for index in 0..items:len() do + const name = items[index].name + if (name:len() > 3 and name[(name:len() - 3)..] == ".rv") do help_row(name[0..(name:len() - 3)], "") end + end + puts("\n programs (/bin)\n") + for index in 0..items:len() do + const name = items[index].name + if (name:len() <= 3 or name[(name:len() - 3)..] != ".rv") do help_row(name, "") end + end + end puts("\n") end fn welcome() do - let fsline = "no filesystem" - if fs.ready do fsline = "revelfs mounted" end + let fs_status = "no filesystem" + if fs.ready do fs_status = "revelfs mounted" end puts("\n") puts(" kernel written in revo - by an alcoholic\n") - puts(" #{(mem_total() shr 20)} MiB ram | #{fsline} | #{prog_count()} programs\n") + puts(" #{(mem_total() shr 20)} MiB ram | #{fs_status} | #{prog_count()} programs\n") puts(" type help to see what it does\n\n% ") end -fn arg_name(line, start) do +# global so /bin scripts can call it from a nested eval fiber +global arg_name = fn(line, start) do let quoted = :false let begin = start if (begin < line:len() and line[begin] == "\"") do begin += 1 quoted = :true end - let i = begin + let index = begin if quoted do - while (i < line:len() and line[i] != "\"") do i += 1 end + while (index < line:len() and line[index] != "\"") do index += 1 end end else do - while (i < line:len() and line[i] != " ") do i += 1 end + while (index < line:len() and line[index] != " ") do index += 1 end end - const name = line[begin..i] - let rest = i + const name = line[begin..index] + let rest = index if (quoted and rest < line:len()) do rest += 1 end if (rest < line:len() and line[rest] == " ") do rest += 1 end { name = name, rest = rest } end -global wd = { path = "/" } - -global editor = { active = :false, path = "", buf = "" } - -fn editor_start(path) do - editor.active = :true - editor.path = path - editor.buf = "" - const sz = fs:size(path) - if sz > 0 do - editor.buf = fs:read_bytes(path, 0, sz) - puts(editor.buf) - end - puts("-- editing #{path}, a single . on a line saves and exits --\n") -end - -fn editor_line(line) do - if line == "." do - fs:store(editor.path, editor.buf) - editor.active = :false - puts("saved #{editor.path} (#{editor.buf:len()} bytes)\n% ") - end - else do editor.buf = editor.buf ~ line ~ "\n" end -end - -fn cmd_edit(line) do - const a = arg_name(line, 5) - if a.name:len() == 0 do puts("usage: edit <path>\n% ") return :nil end - editor_start(abspath(a.name)) -end - -fn abspath(arg) do - if arg:len() == 0 return wd.path - let p = arg - if arg[0] != "/" do - if wd.path == "/" do p = "/#{arg}" end - else do p = "#{wd.path}/#{arg}" end - end - while (p:len() > 1 and p[p:len() - 1] == "/") do p = p[0..(p:len() - 1)] end - return p -end - fn parent_of(path) do if path == "/" return "/" - let i = path:len() - 1 - while (i > 0 and path[i] != "/") do i -= 1 end - if i == 0 return "/" - return path[0..i] + let index = path:len() - 1 + while (index > 0 and path[index] != "/") do index -= 1 end + if index == 0 return "/" + return path[0..index] end -fn cmd_cd(words) do - const arg = if words:len() > 1 words[1] else "/" +fn cmd_cd(context) do + const arg = if context.argv:len() > 1 context.argv[1] else "/" const target = if arg == ".." parent_of(wd.path) else abspath(arg) if target == "/proc" or target == "/bin" or fs:is_dir(target) do wd.path = target end else do puts("cd: #{arg}: not a directory\n") end end -fn cmd_pwd() puts("#{wd.path}\n") - -fn cmd_ls(words) do - const target = if words:len() > 1 abspath(words[1]) else wd.path - if vfs_owns(target) do vfs_ls(target) return :nil end - const n = fs:ls(target) - # the virtual mounts arent real dir entries, overlay them on the root listing - if target == "/" do puts(" bin/\n proc/\n") end - else if n == 0 do puts(" (empty)\n") end -end - -fn cmd_mkdir(words) do - if words:len() < 2 do puts("usage: mkdir <name>\n") return :nil end - fs:mkdir(abspath(words[1])) -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 - fs:write(abspath(a.name), line[a.rest..]) -end +fn cmd_pwd(context) puts("#{wd.path}\n") -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 - const p = abspath(a.name) - if vfs_owns(p) do vfs_cat(p) return :nil end - fs:cat(p) -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(abspath(a.name)) -end +fn wipe() console:clear() +fn cmd_clear(context) wipe() fn zoom_by(delta) do - let scale = con.scale + delta + let scale = console.scale + delta if scale < 1 do scale = 1 end if scale > 6 do scale = 6 end - con.scale = scale - cmd_clear() + console.scale = scale + wipe() puts("zoom #{scale}x\n") end -fn cmd_zoom(words) do - const dir = if words:len() > 1 words[1] else "" - if dir == "in" do zoom_by(1) end - else if dir == "out" do zoom_by(-1) end +fn cmd_zoom(context) do + const direction = if context.argv:len() > 1 context.argv[1] else "" + if direction == "in" do zoom_by(1) end + else if direction == "out" do zoom_by(-1) end else do puts("usage: zoom in | zoom out\n") end end -fn cmd_clear() con:clear() - fn bcd(byte) (byte shr 4) * 10 + (byte band 15) -fn rtc(reg) do - outb(0x70, reg) +fn rtc(cmos_reg) do + outb(0x70, cmos_reg) inb(0x71) end -fn cmd_time() puts("utc #{bcd(rtc(4))}:#{bcd(rtc(2))}:#{bcd(rtc(0))}\n") +fn cmd_time(context) puts("utc #{bcd(rtc(4))}:#{bcd(rtc(2))}:#{bcd(rtc(0))}\n") # 0x prefixed 16 digit hex -fn hex(n) do +fn hex(value) do const digits = "0123456789abcdef" - let out = "" - for i in 0..16 do out = out ~ digits[(n shr ((15 - i) * 4)) band 15] end - "0x#{out}" + let result = "" + for index in 0..16 do result = result ~ digits[(value shr ((15 - index) * 4)) band 15] end + "0x#{result}" end fn mem_type_name(kind) do @@ -202,49 +129,55 @@ end # the boot memory map dump fn dump_memmap() do puts("memory map:\n") - for i in 0..memmap_count() do - puts(" #{hex(memmap_base(i))} len=#{hex(memmap_len(i))} type=#{mem_type_name(memmap_kind(i))}\n") + for index in 0..memmap_count() do + puts(" #{hex(memmap_base(index))} len=#{hex(memmap_len(index))} type=#{mem_type_name(memmap_kind(index))}\n") end puts("usable: #{(mem_total() shr 20)} MiB, free: #{(mem_free() shr 20)} MiB\n") end -fn cmd_mem() puts("#{(mem_free() shr 20)} MiB free / #{(mem_total() shr 20)} MiB usable\n") -fn cmd_uptime() puts("#{math.floor(uptime() / 100)}s (#{uptime()} ticks)\n") -fn cmd_ps() puts("#{proc_count()} process(es) running\n") +fn cmd_mem(context) puts("#{(mem_free() shr 20)} MiB free / #{(mem_total() shr 20)} MiB usable\n") +fn cmd_uptime(context) puts("#{math.floor(uptime() / 100)}s (#{uptime()} ticks)\n") +fn cmd_ps(context) puts("#{proc_count()} process(es) running\n") +fn cmd_echo(context) do if context.line:len() > 5 puts("#{context.line[5..]}\n") else puts("\n") end +fn cmd_mkfs(context) fs:format() + +fn cmd_run(context) do + if context.argv:len() <= 1 do list_progs() return :nil end + const parsed = arg_name(context.rest, 0) + if run_prog(parsed.name, context.rest[parsed.rest..]) == :true return :hold + puts("no such program: #{parsed.name}\n") + return :nil +end fn run(line) do - if editor.active do editor_line(line) return :nil end + # the fact that the shell needs to interface directly with ed isnt, very nice + if gils_ed_active() do gils_ed_feed(line) return :nil end if line:trim():len() == 0 do puts("% ") return :nil end - const words = line:split(" ") - const cmd = words[0] - if cmd == "edit" do cmd_edit(line) return :nil end - if cmd == "run" do - if words:len() <= 1 do list_progs() puts("% ") return :nil end - const prog = words[1] - # everything after "run <prog> " is the programs argument string - const start = 4 + prog:len() + 1 - const arg = if line:len() > start line[start..] else "" - if run_prog(prog, arg) == :true return :nil - puts("% ") + const argv = line:split(" ") + const context = make_ctx(line, argv) + const command = lookup(argv[0]) + if command != :nil do + # :hold means the command took over (modal editor / launched a program) so + # we dont draw a fresh prompt, otherwise we do + const result = command.handler(context) + if result != :hold do puts("% ") end return :nil end - match cmd - | "help" => cmd_help() - | "clear" => cmd_clear() - | "time" => cmd_time() - | "mem" => cmd_mem() - | "uptime" => cmd_uptime() - | "ps" => cmd_ps() - | "zoom" => cmd_zoom(words) - | "mkfs" => fs:format() - | "ls" => cmd_ls(words) - | "cat" => cmd_cat(line) - | "write" => cmd_write(line) - | "rm" => cmd_rm(line) - | "mkdir" => cmd_mkdir(words) - | "cd" => cmd_cd(words) - | "pwd" => cmd_pwd() - | "echo" => if line:len() > 5 puts("#{line[5..]}\n") else puts("\n") - | _ => puts("unknown command: #{cmd}\n") - puts("% ") + + if run_script(argv[0], context) == :true do puts("% ") return :nil end + if run_prog(argv[0], context.rest) == :true return :nil + puts("#{argv[0]}: command not found\n% ") end + +register("help", "shell", "show this", cmd_help) +register("clear", "shell", "wipe the screen", cmd_clear) +register("time", "shell", "utc clock", cmd_time) +register("mem", "shell", "free / total ram", cmd_mem) +register("uptime", "shell", "seconds since boot", cmd_uptime) +register("ps", "shell", "running processes", cmd_ps) +register("zoom in|out", "shell", "scale the font", cmd_zoom) +register("echo <text>", "shell", "print it back", cmd_echo) +register("mkfs", "shell", "format the disk", cmd_mkfs) +register("cd <path>", "gils", "change directory", cmd_cd) +register("pwd", "gils", "print working dir", cmd_pwd) +register("run [name] [arg]", "shell", "run a program explicitly", cmd_run) diff --git a/kernel/vfs.rv b/kernel/vfs.rv index 5d2d1de..22c399e 100644 --- a/kernel/vfs.rv +++ b/kernel/vfs.rv @@ -3,37 +3,33 @@ const TASK_STATES = { "free", "ready", "dead", "blocked" } -fn vfs_owns(path) do +global vfs_owns = fn(path) do if path == "/proc" or path:starts_with?("/proc/") return :true - if path == "/bin" or path:starts_with?("/bin/") return :true return :false end -fn parse_pid(s) do - if s:len() == 0 return -1 - let n = 0 - for i in 0..s:len() do - const c = s[i]:ascii() - if c < 48 or c > 57 return -1 - n = n * 10 + (c - 48) +global parse_pid = fn(text) do + if text:len() == 0 return -1 + let number = 0 + for index in 0..text:len() do + const code = text[index]:ascii() + if code < 48 or code > 57 return -1 + number = number * 10 + (code - 48) end - return n + return number end -fn vfs_ls(path) do +global vfs_ls = fn(path) do if path == "/proc" do puts(" uptime\n meminfo\n") - for i in 0..task_max() do - if task_state(i) != 0 puts(" #{i}\n") + for pid in 0..task_max() do + if task_state(pid) != 0 puts(" #{pid}\n") end end - else if path == "/bin" do - for i in 0..prog_count() do puts(" #{prog_name(i)}\n") end - end else do puts("ls: #{path}: no such directory\n") end end -fn vfs_cat(path) do +global vfs_cat = fn(path) do if path == "/proc/uptime" do puts("#{math.floor(uptime() / 100)}s\n") return :nil end if path == "/proc/meminfo" do puts("#{(mem_free() shr 20)} MiB free / #{(mem_total() shr 20)} MiB total\n") return :nil end if path:starts_with?("/proc/") do @@ -45,13 +41,5 @@ fn vfs_cat(path) do puts("cat: #{path}: no such file\n") return :nil end - if path:starts_with?("/bin/") do - const nm = path[5..] - for i in 0..prog_count() do - if prog_name(i) == nm do puts("#{nm}: elf program, #{prog_size(i)} bytes\n") return :nil end - end - puts("cat: #{path}: no such file\n") - return :nil - end puts("cat: #{path}: no such file\n") end diff --git a/kernel/vmm.rv b/kernel/vmm.rv index a4c0eea..0de5f33 100644 --- a/kernel/vmm.rv +++ b/kernel/vmm.rv @@ -2,7 +2,7 @@ # everything here only writes small entries we construct, so its f64 safe const PTE_ADDR = 0x000FFFFFFFFFF000 -fn pte_idx(virt, level) (virt shr (12 + 9 * level)) band 0x1ff +fn pte_index(virtual_address, level) (virtual_address shr (12 + 9 * level)) band 0x1ff fn next_table(table, index) do const slot = table + index * 8 @@ -14,10 +14,10 @@ fn next_table(table, index) do frame end -fn as_map(pml4, virt, phys, flags) do - const pdpt = next_table(pml4, pte_idx(virt, 3)) - const pd = next_table(pdpt, pte_idx(virt, 2)) - const pt = next_table(pd, pte_idx(virt, 1)) - mem_write(pt + pte_idx(virt, 0) * 8, (phys band PTE_ADDR) bor flags bor 1, 8) - invlpg(virt) +fn as_map(pml4, virtual_address, physical_address, flags) do + const pdpt = next_table(pml4, pte_index(virtual_address, 3)) + const pd = next_table(pdpt, pte_index(virtual_address, 2)) + const pt = next_table(pd, pte_index(virtual_address, 1)) + mem_write(pt + pte_index(virtual_address, 0) * 8, (physical_address band PTE_ADDR) bor flags bor 1, 8) + invlpg(virtual_address) end |
