summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenji Dial <Benji3.141@gmail.com>2020-11-08 11:11:49 -0500
committerBenji Dial <Benji3.141@gmail.com>2020-11-08 11:11:49 -0500
commit21491514b3642a321ce65f2a07428f63c4d9feb5 (patch)
treecf2384926e9d8e4cb0dcf2c9babd37fc7809c5da
parent594aeeb09bc24de7064eb1bddf6e86c1a134838e (diff)
downloadportland-os-21491514b3642a321ce65f2a07428f63c4d9feb5.tar.gz
manual viewer, "swap colors" system call
-rw-r--r--doc/ints.txt35
-rw-r--r--doc/man.txt20
-rw-r--r--makefile13
-rw-r--r--src/kernel/idt.c3
-rw-r--r--src/kernel/isrs.asm2
-rw-r--r--src/kernel/vga.c5
-rw-r--r--src/kernel/vga.h1
-rw-r--r--src/man/dev/kmemmap.pre34
-rw-r--r--src/man/index.pre13
-rw-r--r--src/user/include/pland/syscall.h7
-rw-r--r--src/user/manual/manual.c268
-rw-r--r--tools/man-gen.py135
12 files changed, 513 insertions, 23 deletions
diff --git a/doc/ints.txt b/doc/ints.txt
index 45c09b3..c89b433 100644
--- a/doc/ints.txt
+++ b/doc/ints.txt
@@ -24,23 +24,24 @@ invalid system call numbers change eax to -1, and have no other effect.
table 1:
- function | eax | eax out | ebx | ecx | edx | esi | edi
-----------------|-----|-----------------|----------------|-------------|-------------|--------|-----
- open file | 0x0 | handle | drive number | path | | |
- close file | 0x1 | | handle | | | |
- file read | 0x2 | read | handle | file offset | count | buffer |
- get file size | 0x3 | size | handle | | | |
- start task | 0x4 | handle | drive number | path | passed sz | |
- log string | 0x5 | | sz string | | | |
- get key | 0x6 | keycode | | | | |
- allocate ram | 0x7 | start pointer | pages | | | |
- memory info | 0x8 | see table 2 | see table 2 | | | |
- wait for task | 0x9 | | handle | | | |
- enumerate dir | 0xa | count | drive number | path | see table 3 | max |
- vga print at | 0xb | | row << 8 | col | sz string | | |
- count of dir | 0xc | number of files | drive number | path | | |
- clear screen | 0xd | | | | | |
- set color | 0xe | | VGA color code | | | |
+ function | eax | eax out | ebx | ecx | edx | esi | edi
+----------------|-----|-----------------|----------------|----------------|-------------|--------|-----
+ open file | 0x0 | handle | drive number | path | | |
+ close file | 0x1 | | handle | | | |
+ file read | 0x2 | read | handle | file offset | count | buffer |
+ get file size | 0x3 | size | handle | | | |
+ start task | 0x4 | handle | drive number | path | passed sz | |
+ log string | 0x5 | | sz string | | | |
+ get key | 0x6 | keycode | | | | |
+ allocate ram | 0x7 | start pointer | pages | | | |
+ memory info | 0x8 | see table 2 | see table 2 | | | |
+ wait for task | 0x9 | | handle | | | |
+ enumerate dir | 0xa | count | drive number | path | see table 3 | max |
+ vga print at | 0xb | | row << 8 | col | sz string | | |
+ count of dir | 0xc | number of files | drive number | path | | |
+ clear screen | 0xd | | | | | |
+ set color | 0xe | | VGA color code | | | |
+ swap color | 0xf | | row << 8 | col | | | |
table 2:
diff --git a/doc/man.txt b/doc/man.txt
new file mode 100644
index 0000000..37a2642
--- /dev/null
+++ b/doc/man.txt
@@ -0,0 +1,20 @@
+manual format:
+
+dword: length of title (without sz)
+title (sz)
+dword: number of links
+dword: length of link table (in bytes)
+link table
+ entry:
+ dword: line
+ byte: start column
+ byte: text length
+ dword: length of file pointed to (without sz)
+ file pointed to (sz)
+dword: length of line pointer list (in dwords)
+line pointer list
+ dword offsets into file
+
+lines
+ 0x00 - 0x7f are characters
+ 0x80 - 0xff are color codes | 0x80 \ No newline at end of file
diff --git a/makefile b/makefile
index a0500b7..421f963 100644
--- a/makefile
+++ b/makefile
@@ -8,7 +8,6 @@ out/disk.vdi: out/disk.img
VBoxManage convertfromraw out/disk.img out/disk.vdi --uuid a61929ed-3bf2-45ff-b98a-44f87c616dba
out/disk.img: out/kernel.bin out/boot.bin out/fs
- #TODO: have this regenerate after out/fs
mkdir -p obj
/sbin/mkfs.fat -C -f 1 -F 16 -n "PORTLAND OS" -R 65 -s 1 -S 512 obj/shadow.img 8192
echo -n -e '\xeb\x3c' > obj/jmp.bin
@@ -28,10 +27,15 @@ out/fs/bin/%: obj/%.elf
mkdir -p $(shell dirname $@)
objcopy -S $< $@
+out/fs/man/%.man: src/man/%.pre
+ mkdir -p $(shell dirname $@)
+ python3 tools/man-gen.py $< $@
+
out/fs: out/fs/bin/init out/fs/bin/meminfo out/fs/bin/highway \
out/fs/bin/hello out/fs/bin/dumptext out/fs/bin/dumphex \
- out/fs/bin/dirinfo out/fs/bin/fileman
- mkdir -p out/fs
+ out/fs/bin/dirinfo out/fs/bin/fileman out/fs/bin/manual \
+ out/fs/man/index.man out/fs/man/dev/kmemmap.man
+ touch out/fs
cp -r fs-skel/* out/fs/
obj/kernel/%.ko: src/kernel/%.c
@@ -98,4 +102,7 @@ obj/dirinfo.elf: obj/dirinfo/dirinfo.o obj/knob.so obj/c.rto
ld -T src/user/runtimes/c/elf.ld $^ -o $@
obj/fileman.elf: obj/fileman/fileman.o obj/knob.so obj/c.rto
+ ld -T src/user/runtimes/c/elf.ld $^ -o $@
+
+obj/manual.elf: obj/manual/manual.o obj/knob.so obj/c.rto
ld -T src/user/runtimes/c/elf.ld $^ -o $@ \ No newline at end of file
diff --git a/src/kernel/idt.c b/src/kernel/idt.c
index 1b8e548..ebeea17 100644
--- a/src/kernel/idt.c
+++ b/src/kernel/idt.c
@@ -120,7 +120,8 @@ void const *syscall_table[] = {
&vga_print_at,
&sc_count_of_dir,
&vga_blank,
- &vga_set_color
+ &vga_set_color,
+ &vga_swap_color
};
//these aren't really void ()'s, but gcc complains if we take an address of a void, so we give it a type
diff --git a/src/kernel/isrs.asm b/src/kernel/isrs.asm
index e7573ae..472bb40 100644
--- a/src/kernel/isrs.asm
+++ b/src/kernel/isrs.asm
@@ -23,7 +23,7 @@ extern on_kbd_isr
extern make_sure_tasks
extern exception_halt
-n_syscalls equ 0xf
+n_syscalls equ 0x10
;section .bss
;_debug_is_start_task resb 1
diff --git a/src/kernel/vga.c b/src/kernel/vga.c
index 42da312..6ae1588 100644
--- a/src/kernel/vga.c
+++ b/src/kernel/vga.c
@@ -12,6 +12,11 @@ void vga_set_color(uint8_t new_color) {
mask = new_color << 8;
}
+void vga_swap_color(uint16_t pos) {
+ uint8_t *color_byte = (uint8_t *)(VGA_START + (pos >> 8) * VGA_COLUMNS + (pos & 0xff)) + 1;
+ *color_byte = (*color_byte << 4) + (*color_byte >> 4);
+}
+
static void vga_scroll() {
for (uint32_t *i = (uint32_t *)VGA_START; i < (uint32_t *)(VGA_END - VGA_COLUMNS); ++i)
*i = *(i + VGA_COLUMNS / 2);
diff --git a/src/kernel/vga.h b/src/kernel/vga.h
index fa97e11..dd1c906 100644
--- a/src/kernel/vga.h
+++ b/src/kernel/vga.h
@@ -7,5 +7,6 @@ void vga_print_at(uint16_t pos, const char *sz);
void vga_set_color(uint8_t color);
void vga_blank();
void vga_printch(char ch);
+void vga_swap_color(uint16_t pos);
#endif \ No newline at end of file
diff --git a/src/man/dev/kmemmap.pre b/src/man/dev/kmemmap.pre
new file mode 100644
index 0000000..73b4e09
--- /dev/null
+++ b/src/man/dev/kmemmap.pre
@@ -0,0 +1,34 @@
+\title{Portland Kernel Memory Map}
+
+This manual page describes the layout of the kernel area of memory. Unless you are doing kernel development, you do not need to know this. This is not guaranteed to remain backwards-compatible across versions. Unspecified memory under \color{07}0x0400.0000\color{0f} is reserved for future use.
+
+\color{0e}Passed from bootloader\color{0f}
+
+Starting at \color{07}0x0000.4000\color{0f} is information passed from the bootloader.
+
+\color{07}0x4000 byte:\color{0f} support flags
+- \color{07}0x80:\color{0f} PCI support
+- \color{07}0x40:\color{0f} PAE support
+- The other flags are reserved.
+\color{07}0x4001 byte:\color{0f} PCI's "hardware characteristics" byte
+\color{07}0x4002 byte:\color{0f} PCI's minor version
+\color{07}0x4003 byte:\color{0f} PCI's major version
+\color{07}0x4004 byte:\color{0f} last PCI bus
+\color{07}0x4006 word:\color{0f} length of BIOS's memory map
+
+From \color{07}0x0001.0000\color{0f} to \color{07}0x0001.ffff\color{0f} is the memory map from BIOS.
+
+\color{0e}Fixed kernel structures\color{0f}
+
+\color{07}0x0000.4f98 - 0x0000.4fff:\color{0f} the Task State Segment
+\color{07}0x0000.5000 - 0x0000.5fff:\color{0f} identity page directory
+\color{07}0x0004.0000 - 0x0005.ffff:\color{0f} a bitmap of allocated pages
+\color{07}0x0040.0000 - 0x007f.ffff:\color{0f} page tables referenced by identity page directory
+
+\color{0e}Others\color{0f}
+
+\color{07}0x000a.0000 - 0x000f.0000\color{0f} and \color{07}0x00f0.0000 - 0x00ff.0000\color{0f} are assumed to be reserved by the motherboard for either memory-mapped hardware or BIOS. The standard VGA area is used as such, and the rest are avoided.
+
+The kernel is loaded with the text and data sections at \color{07}0x0003.0000 - 0x0003.7fff\color{0f}, and the bss at \color{07}0x0400.0000 - 0x07ff.7fff\color{0f}. \color{07}0x0003.8000 - 0x0003.ffff\color{0f} is used as a stack by the kernel, and whatever part of the bss area is unused is used as a sort of page-resolution "heap" for the kernel.
+
+Everything after \color{07}0x0800.0000\color{0f} that the BIOS indicates is available for use is used for user pages. \ No newline at end of file
diff --git a/src/man/index.pre b/src/man/index.pre
new file mode 100644
index 0000000..49f3d13
--- /dev/null
+++ b/src/man/index.pre
@@ -0,0 +1,13 @@
+\title{Portland Manual Index}
+
+Use the \color{07}up\color{0f} and \color{07}down\color{0f} arrows to scroll the manual one line at a time, or the \color{07}page up\color{0f} and \color{07}page down\color{0f} buttons to scroll a whole page at a time. Use the \color{07}left\color{0f} and \color{07}right\color{0f} arrows to focus the previous or next link, and the \color{07}space\color{0f} or \color{07}enter\color{0f} keys to follow those links. Use \color{07}escape\color{0f} to go back to the previous page, and \color{07}q\color{0f} to quit.
+
+\color{0e}Programs\color{0f}
+\link{fileman (file manager):bin/fileman}
+\link{Highway (command shell):bin/highway}
+
+\color{0e}Development\color{0f}
+\link{System calls:dev/syscalls}
+\link{Keycodes:dev/keycodes}
+\link{Manual file format:dev/manfile}
+\link{Kernel memory map:dev/kmemmap} \ No newline at end of file
diff --git a/src/user/include/pland/syscall.h b/src/user/include/pland/syscall.h
index 14164aa..ead5fea 100644
--- a/src/user/include/pland/syscall.h
+++ b/src/user/include/pland/syscall.h
@@ -140,7 +140,8 @@ enum _scn {
_SCN_PRINT_AT,
_SCN_COUNT_OF_DIR,
_SCN_CLEAR_SCREEN,
- _SCN_SET_COLOR
+ _SCN_SET_COLOR,
+ _SCN_SWAP_COLOR
};
static inline uint32_t _sc0(enum _scn eax) {
@@ -285,4 +286,8 @@ static inline void _set_color(_vga_color_t color) {
_sc1(_SCN_SET_COLOR, color);
}
+static inline void _swap_color(uint8_t row, uint8_t col) {
+ _sc1(_SCN_SWAP_COLOR, (row << 8) | col);
+}
+
#endif \ No newline at end of file
diff --git a/src/user/manual/manual.c b/src/user/manual/manual.c
new file mode 100644
index 0000000..48f4f65
--- /dev/null
+++ b/src/user/manual/manual.c
@@ -0,0 +1,268 @@
+#include <knob/heap.h>
+#include <knob/file.h>
+#include <knob/block.h>
+#include <knob/format.h>
+#include <pland/syscall.h>
+
+#define ERROR_COLOR _COLOR_BG_LGRAY | _COLOR_FG_RED
+#define UI_COLOR _COLOR_BG_LGRAY | _COLOR_FG_BLACK
+#define DEFAULT_TEXT_COLOR _COLOR_BG_BLACK | _COLOR_FG_WHITE
+
+#define MAN_ROOT "man/"
+#define MRL 4
+#define MAN_EXT "man"
+
+#define MAX_PATH_LEN 255
+
+#define SP80 " "
+#define SP79 " "
+#define SP69 " "
+#define SP10 " "
+
+struct file *cur_file = 0;
+
+uint32_t *line_offsets = 0;
+uint32_t n_lines;
+
+struct link {
+ uint32_t line;
+ uint8_t col;
+ uint8_t len;
+ char *lto;
+};
+
+struct link *link_table_start = 0;
+struct link *link_table_end;
+
+struct link *cur_link = 0;
+
+uint32_t line_on;
+
+#define DATA_BUF_SIZE 2000
+
+void print_page() {
+ uint8_t buf[DATA_BUF_SIZE];//1840 + up to 160 color codes
+ seek_file_to(cur_file, line_offsets[line_on]);
+ uint8_t *bufp = buf + DATA_BUF_SIZE;
+ uint8_t *bufend;
+ uint8_t row = 1, col = 0;
+
+ _set_color(DEFAULT_TEXT_COLOR);
+ while (row != 24) {
+ if (bufp == buf + DATA_BUF_SIZE) {
+ bufp = buf;
+ uint16_t bl = read_from_file(cur_file, DATA_BUF_SIZE, buf);
+ bufend = bl == DATA_BUF_SIZE ? 0 : buf + bl;
+ }
+ if (bufp == bufend) {
+ uint32_t *i = buf;
+ uint16_t l = 80 - col + (23 - row) * 80;
+ uint32_t *e = i + l / 4 + 1;
+ while (i != e)
+ *(i++) = 0x20202020;
+ buf[l] = '\0';
+ _print_at(row, col, buf);
+ break;
+ }
+ if (*bufp & 0x80)
+ _set_color(*bufp & 0x7f);
+ else {
+ char bufpb[2] = {*bufp, '\0'};
+ _print_at(row, col, bufpb);
+ if (++col == 80) {
+ col = 0;
+ ++row;
+ }
+ }
+ ++bufp;
+ }
+
+ if (cur_link)
+ for (uint8_t c = cur_link->col; c < cur_link->col + cur_link->len; ++c)
+ _swap_color(cur_link->line - line_on + 1, c);
+}
+
+void scroll_to(uint32_t n) {
+ if (n > n_lines - 23)
+ n = n_lines - 23;
+
+ if (cur_link && ((cur_link->line < n) || (cur_link->line >= n + 23)))
+ cur_link = 0;
+
+ line_on = n;
+ print_page();
+
+ char b[16] = "Line ";
+ itosz(line_on, b + 5);
+
+ _set_color(UI_COLOR);
+ _print_at(24, 0, SP69);
+ _print_at(24, 0, b);
+}
+
+void scroll_link() {
+ if (cur_link->line < line_on)
+ scroll_to(cur_link->line);
+ else if (cur_link->line >= line_on + 23)
+ scroll_to(cur_link->line - 22);
+ else
+ print_page();
+}
+
+void load_file(const char *name) {
+ static char cur_page[MAX_PATH_LEN + 1] = MAN_ROOT;
+ uint32_t name_len = strcpy(cur_page + MRL, name);
+ strcpy(cur_page + MRL + name_len, "." MAN_EXT);
+
+ struct file *new_file = open_file(cur_page);
+ if (!new_file) {
+ _set_color(ERROR_COLOR);
+ _print_at(24, 0, SP79);
+ _print_at(24, 0, "Could not open file.");
+ return;
+ }
+
+ if (cur_file)
+ close_file(cur_file);
+ cur_file = new_file;
+
+ uint32_t tlen;
+ read_from_file(cur_file, 4, &tlen);
+ char title[81];
+ read_from_file(cur_file, tlen + 1, title);
+
+ _set_color(UI_COLOR);
+ _print_at(0, 0, SP80);
+ _print_at(0, 0, title);
+
+ if (link_table_start) {
+ for (struct link *l = link_table_start; l != link_table_end; ++l)
+ free_block(l->lto);
+ free_block(link_table_start);
+ }
+
+ uint32_t linktc;
+ read_from_file(cur_file, 4, &linktc);
+ if (linktc) {
+ link_table_start = get_block(sizeof(struct link) * linktc);
+ link_table_end = link_table_start + linktc;
+ read_from_file(cur_file, 4, &linktc);//dummy
+
+ for (struct link *l = link_table_start; l != link_table_end; ++l) {
+ read_from_file(cur_file, 4, &l->line);
+ read_from_file(cur_file, 1, &l->col);
+ read_from_file(cur_file, 1, &l->len);
+ uint32_t lto_l;
+ read_from_file(cur_file, 4, &lto_l);
+ l->lto = get_block(lto_l + 1);
+ read_from_file(cur_file, lto_l + 1, l->lto);
+ }
+ }
+ else {
+ link_table_start = 0;
+ read_from_file(cur_file, 4, &linktc);//dummy
+ }
+
+ cur_link = 0;
+
+ if (line_offsets)
+ free_block(line_offsets);
+
+ read_from_file(cur_file, 4, &n_lines);
+ line_offsets = get_block(n_lines * 4);
+ read_from_file(cur_file, n_lines * 4, line_offsets);
+
+ char b[11];
+ itosz(n_lines, b);
+
+ _set_color(UI_COLOR);
+ _print_at(24, 69, SP10);
+ _print_at(24, 69, b);
+
+ scroll_to(0);
+}
+
+void main() {
+ _set_color(UI_COLOR);
+ _print_at(24, 79, " ");
+
+ load_file("index");
+
+ while (true) {
+ switch (_get_key()) {
+ case 0:
+ default:
+ _yield_task();
+ break;
+ case _KEY_UP:
+ if (n_lines <= 23)
+ break;
+ if (line_on)
+ scroll_to(line_on - 1);
+ break;
+ case _KEY_DOWN:
+ if (n_lines <= 23)
+ break;
+ if (line_on < n_lines - 23)
+ scroll_to(line_on + 1);
+ break;
+ case _KEY_PUP:
+ if (n_lines <= 23)
+ break;
+ scroll_to(line_on <= 22 ? 0 : line_on - 22);
+ break;
+ case _KEY_PDOWN:
+ if (n_lines <= 23)
+ break;
+ scroll_to(line_on + 22);
+ break;
+ case _KEY_LEFT:
+ if (cur_link == link_table_start)
+ break;
+ if (cur_link) {
+ --cur_link;
+ scroll_link();
+ }
+ else if (link_table_start) {
+ struct link *l = link_table_end;
+ while (l != link_table_start) {
+ --l;
+ if (l->line <= line_on + 22)
+ break;
+ }
+ cur_link = l;
+ scroll_link();
+ }
+ break;
+ case _KEY_RIGHT:
+ if (cur_link == link_table_end - 1)
+ break;
+ if (cur_link) {
+ ++cur_link;
+ scroll_link();
+ }
+ else if (link_table_start) {
+ struct link *l = link_table_start;
+ while (l != link_table_end) {
+ if (l->line >= line_on)
+ break;
+ ++l;
+ }
+ cur_link = l;
+ scroll_link();
+ }
+ break;
+ case ' ':
+ case '\n':
+ case _KEY_NENTER:
+ if (cur_link)
+ load_file(cur_link->lto);
+ break;
+ case _KEY_ESC:
+ //TODO
+ break;
+ case 'q':
+ return;
+ }
+ }
+} \ No newline at end of file
diff --git a/tools/man-gen.py b/tools/man-gen.py
new file mode 100644
index 0000000..30ade8a
--- /dev/null
+++ b/tools/man-gen.py
@@ -0,0 +1,135 @@
+from sys import argv
+
+infn, outfn = argv[1:]
+
+inf = open(infn, 'r')
+
+title = infn[infn.rfind('/')+1:infn.rfind('.')]
+lines = []
+links = []
+
+coutl = bytes(0)
+cllen = 0
+cword = ''
+ccol = 0x0f
+
+def word_end():
+ global cword, cllen, coutl
+
+ if cword == '':
+ return
+
+ if cllen + len(cword) > 80:
+ line_end()
+
+ cllen += len(cword)
+ coutl += bytes(cword, 'ascii')
+ cword = ''
+
+ if cllen == 80:
+ line_end()
+
+def line_end():
+ global lines, cllen, coutl, ccol
+
+ if len(lines) == 0 and cllen == 0:
+ return
+ coutl += bytes([0x20] * (80 - cllen))
+
+ lines.append(coutl)
+ coutl = bytes(0)
+ cllen = 0
+ if ccol != 0x0f:
+ coutl += bytes([ccol | 0x80])
+
+while True:
+ ch = inf.read(1)
+ if ch == '':
+ word_end()
+ line_end()
+ break
+
+ elif ch == '\\':
+ word_end()
+
+ cmd = ''
+ while ch != '{':
+ cmd += ch
+ ch = inf.read(1)
+ cmd = cmd[1:]
+
+ content = ''
+ while ch != '}':
+ content += ch
+ ch = inf.read(1)
+ content = content[1:]
+
+ if cmd == 'title':
+ title = content
+ elif cmd == 'link':
+ lto = content
+ cpos = content.rfind(':')
+ if cpos != -1:
+ lto = content[cpos+1:]
+ content = content[:cpos]
+ links.append((len(lines), cllen, len(content), lto))
+ coutl += bytes([0x89])
+ cword = content
+ word_end()
+ coutl += bytes([0x8f])
+ elif cmd == 'color':
+ ncol = int(content, base=16)
+ if ccol != ncol:
+ ccol = ncol
+ coutl += bytes([ccol | 0x80])
+
+ elif ch == ' ':
+ word_end()
+ if cllen != 0:
+ coutl += bytes([0x20])
+ cllen += 1
+
+ elif ch == '\n':
+ word_end()
+ line_end()
+
+ else:
+ cword += ch
+
+inf.close()
+
+def dword(n):
+ return bytes([n % 256, (n // 256) % 256, (n // 65536) % 256, n // 16777216])
+
+outf = open(outfn, 'wb')
+
+outf.write(dword(len(title)))
+outf.write(bytes(title, 'ascii'))
+outf.write(bytes([0]))
+
+outf.write(dword(len(links)))
+
+ltable = bytes(0)
+for link in links:
+ line, scol, tlen, fpto = link
+
+ ltable += dword(line)
+ ltable += bytes([scol, tlen])
+ ltable += dword(len(fpto))
+ ltable += bytes(fpto, 'ascii')
+ ltable += bytes([0])
+
+outf.write(dword(len(ltable)))
+outf.write(ltable)
+
+outf.write(dword(len(lines)))
+
+off = 4 + len(title) + 1 + 4 + 4 + len(ltable) + 4 + len(lines) * 4
+for line in lines:
+ outf.write(dword(off))
+ off += len(line)
+
+for line in lines:
+ outf.write(line)
+
+outf.close() \ No newline at end of file