summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bochsrc5
-rw-r--r--doc/internal/scantabs.txt17
-rw-r--r--doc/ints.txt58
-rw-r--r--doc/keys.txt26
-rw-r--r--doc/man.txt20
-rw-r--r--fs-skel/attribs.txt3
-rw-r--r--fs-skel/fonts/berry.bdf3286
-rw-r--r--fs-skel/sys/scantabs/qwerty.sctbin0 -> 3072 bytes
-rw-r--r--fs-skel/user/default.rc4
-rw-r--r--makefile66
-rw-r--r--qemu-debug.gdb8
-rw-r--r--src/boot.asm6
-rw-r--r--src/kernel/elf.c10
-rw-r--r--src/kernel/elf.h2
-rw-r--r--src/kernel/ide.c2
-rw-r--r--src/kernel/idt.c200
-rw-r--r--src/kernel/isrs.asm44
-rw-r--r--src/kernel/kbd.c410
-rw-r--r--src/kernel/kbd.h5
-rw-r--r--src/kernel/log.c103
-rw-r--r--src/kernel/log.h15
-rw-r--r--src/kernel/main.c118
-rw-r--r--src/kernel/panic.c18
-rw-r--r--src/kernel/pmap.h2
-rw-r--r--src/kernel/serial.c6
-rw-r--r--src/kernel/task.c203
-rw-r--r--src/kernel/task.h34
-rw-r--r--src/kernel/util.c93
-rw-r--r--src/kernel/util.h8
-rw-r--r--src/kernel/vga.c52
-rw-r--r--src/kernel/vga.h12
-rw-r--r--src/kernel/window.c253
-rw-r--r--src/kernel/window.h23
-rw-r--r--src/man/dev/kmemmap.pre34
-rw-r--r--src/man/index.pre13
-rw-r--r--src/shared/include/keypack.h137
-rw-r--r--src/shared/include/winact.h19
-rw-r--r--src/user/dirinfo/dirinfo.c49
-rw-r--r--src/user/dumphex/dumphex.c81
-rw-r--r--src/user/dumptext/dumptext.c15
-rw-r--r--src/user/fileman/fileman.c130
-rw-r--r--src/user/hello/hello.asm14
-rw-r--r--src/user/highway/cmds.c10
-rw-r--r--src/user/highway/line.c85
-rw-r--r--src/user/highway/line.h1
-rw-r--r--src/user/highway/main.c31
-rw-r--r--src/user/highway/vars.c28
-rw-r--r--src/user/include/knob/block.h5
-rw-r--r--src/user/include/knob/env.h9
-rw-r--r--src/user/include/knob/format.h27
-rw-r--r--src/user/include/knob/ipc.h16
-rw-r--r--src/user/include/knob/key.h8
-rw-r--r--src/user/include/knob/panic.h9
-rw-r--r--src/user/include/knob/task.h7
-rw-r--r--src/user/include/knob/user.h22
-rw-r--r--src/user/include/libfont/fonts.h21
-rw-r--r--src/user/include/pland/pcrt.h7
-rw-r--r--src/user/include/pland/syscall.h206
-rw-r--r--src/user/include/popups/info.h14
-rw-r--r--src/user/include/popups/popup.h23
-rw-r--r--src/user/include/terminal/readline.h10
-rw-r--r--src/user/include/terminal/terminal.h57
-rw-r--r--src/user/init/init.c29
-rw-r--r--src/user/knob/block.c24
-rw-r--r--src/user/knob/env.c3
-rw-r--r--src/user/knob/file.c26
-rw-r--r--src/user/knob/format.c257
-rw-r--r--src/user/knob/heap.c32
-rw-r--r--src/user/knob/ipc.c45
-rw-r--r--src/user/knob/key.c67
-rw-r--r--src/user/knob/panic.c12
-rw-r--r--src/user/knob/task.c20
-rw-r--r--src/user/knob/user.c299
-rw-r--r--src/user/libfont/bdf.c99
-rw-r--r--src/user/libfont/bdf.h8
-rw-r--r--src/user/libfont/filist.c33
-rw-r--r--src/user/libfont/filist.h8
-rw-r--r--src/user/libfont/fonts.c66
-rw-r--r--src/user/manual/manual.c303
-rw-r--r--src/user/meminfo/meminfo.c41
-rw-r--r--src/user/popups/info.c99
-rw-r--r--src/user/popups/popup.c45
-rw-r--r--src/user/runtimes/c/elf.ld1
-rw-r--r--src/user/runtimes/c/pcrt.asm (renamed from src/user/runtimes/c/entry.asm)11
-rw-r--r--src/user/terminal/readline.c104
-rw-r--r--src/user/terminal/terminal.c284
-rw-r--r--tools/man-gen.py135
87 files changed, 6058 insertions, 2193 deletions
diff --git a/bochsrc b/bochsrc
new file mode 100644
index 0000000..2c576c0
--- /dev/null
+++ b/bochsrc
@@ -0,0 +1,5 @@
+ata0-master: type=disk, mode=flat, path=out/disk.img
+boot: disk
+megs: 512
+
+com1: enabled=1, mode=socket-server, dev=localhost:2345 \ No newline at end of file
diff --git a/doc/internal/scantabs.txt b/doc/internal/scantabs.txt
new file mode 100644
index 0000000..208da08
--- /dev/null
+++ b/doc/internal/scantabs.txt
@@ -0,0 +1,17 @@
+scan table file header:
+ uint32_t: number of scan tables
+ 0x10 aligned scan table records
+
+scan table record:
+ uint32_t offset in file of table data / 0x200
+ uint8_t: length of prefix
+ uint8_t's: prefix
+
+table data (0x200 aligned):
+ first key down table then key up table
+ uint8_t's:
+ 0x00: bad scancode
+ 0x01: prefix (go to table)
+ 0x02: wrong polarity (go to other up or down)
+ 0x03: good scancode, no keycode
+ other: keycode
diff --git a/doc/ints.txt b/doc/ints.txt
index c89b433..ca4d91f 100644
--- a/doc/ints.txt
+++ b/doc/ints.txt
@@ -13,35 +13,49 @@ modifies ecx, edx
modifies eax even if no value is returned
see table 1
-file system calls have units of bytes unless otherwise specified
-functions returning handles or pointers use 0 to indicate error
-see keys.txt for the return type of the "get key" system call
+file system calls have units of bytes unless otherwise specified.
+functions returning handles or pointers use 0 to indicate error.
+see keys.txt for the return type of the "get key" system call.
the edx register of "start task" is a pointer to a null-terminated string.
a pointer to a readonly copy of this string is put into the new task's edx.
+ the esi register of the new task contains a handle to the caller's task.
+ the edi register is copied directly, and is intended to hold a task handle.
+ this task handle is who stdio ipc communication should be done with.
+ipc operations return 0xffffffff if the specified task doesn't exist.
+ "find unread ipc" system call returns 0 if there is no unread ipc.
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 | | | |
- swap color | 0xf | | row << 8 | col | | | |
+ function | eax | eax out | ebx | ecx | edx | esi | edi
+-------------------|------|-----------------|----------------|----------------|--------------|--------------|--------------
+ open file | 0x00 | handle | drive number | path | | |
+ close file | 0x01 | | handle | | | |
+ file read | 0x02 | read | handle | file offset | count | buffer |
+ get file size | 0x03 | size | handle | | | |
+ start task | 0x04 | handle | drive number | path | passed sz | | passed dword
+ ipc send | 0x05 | written | task handle | max count | buffer | |
+ ipc read | 0x06 | read | task handle | max count | buffer | |
+ allocate ram | 0x07 | start pointer | pages | | | |
+ memory info | 0x08 | see table 2 | see table 2 | | | |
+ wait for task | 0x09 | | handle | | | |
+ enumerate dir | 0x0a | count | drive number | path | see table 3 | max |
+ system log | 0x0b | | message sz | | | |
+ count of dir | 0x0c | number of files | drive number | path | | |
+ new window | 0x0d | window handle | width | height | pixel buffer | |
+ delete window | 0x0e | | window handle | | | |
+ resize window | 0x0f | | window handle | width | height | |
+ reassign pixbuf | 0x10 | | window handle | pixel buffer | | |
+ paint window | 0x11 | | window handle | | | |
+ get win action | 0x12 | | window handle | action pointer | | |
+ wait for action | 0x13 | | | | | |
+ wait ipc send | 0x14 | | sending task | | | |
+ wait any ipc send | 0x15 | | | | | |
+ find unread ipc | 0x16 | sending task | | | | |
+ wait ipc read | 0x17 | | reading task | | | |
+ is task running | 0x18 | boolean | task handle | | | |
table 2:
@@ -63,4 +77,4 @@ esi is the maximum number of "directory info"s to be placed in the buffer.
the "directory info" structure is 128 bytes long. The first 100 bytes are a null-terminated string
indicating the name of the file represented by this entry. The next four bytes are a 32-bit integer
indicating the size of the file represented in bytes. The next byte's lowest bit is a one if this
- entry is a directory, and a zero if this entry is not. The remainder of the structure is reserved. \ No newline at end of file
+ entry is a directory, and a zero if this entry is not. The remainder of the structure is reserved.
diff --git a/doc/keys.txt b/doc/keys.txt
index 8deb480..bccd47a 100644
--- a/doc/keys.txt
+++ b/doc/keys.txt
@@ -19,18 +19,18 @@ table 1:
code | key
------|---------------
- 0x80 | caps lock
- 0x81 | insert
- 0x82 | num lock
- 0x83 | scroll lock
- 0x84 | left shift
- 0x85 | right shift
- 0x86 | left alt
- 0x87 | right alt
- 0x88 | left control
- 0x89 | right control
- 0x8a | left meta
- 0x8b | right meta
+ 0x80 | left shift
+ 0x81 | right shift
+ 0x82 | left control
+ 0x83 | right control
+ 0x84 | left alt
+ 0x85 | right alt
+ 0x86 | left win
+ 0x87 | right win
+ 0x88 | caps lock
+ 0x89 | num lock
+ 0x8a | scroll lock
+ 0x8b | insert
0x8c | reserved
.... | reserved
0x97 | reserved
@@ -102,4 +102,4 @@ bit 10: left meta
bit 11: right meta
bits 12-23 are reserved for future versions. in this version, they should be set
-to zero when giving a keycode, and should be ignored when recieving a keycode. \ No newline at end of file
+to zero when giving a keycode, and should be ignored when recieving a keycode.
diff --git a/doc/man.txt b/doc/man.txt
deleted file mode 100644
index 37a2642..0000000
--- a/doc/man.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-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/fs-skel/attribs.txt b/fs-skel/attribs.txt
new file mode 100644
index 0000000..67e3dc1
--- /dev/null
+++ b/fs-skel/attribs.txt
@@ -0,0 +1,3 @@
+fonts/berry.bdf:
+Modified by me from cherry, by camille, which is under BSD Zero.
+Cherry is available at <https://github.com/turquoise-hexagon/cherry>. \ No newline at end of file
diff --git a/fs-skel/fonts/berry.bdf b/fs-skel/fonts/berry.bdf
new file mode 100644
index 0000000..4e19453
--- /dev/null
+++ b/fs-skel/fonts/berry.bdf
@@ -0,0 +1,3286 @@
+STARTFONT 2.1
+FONT -benji-berry-Medium-R-Normal--10-100-75-75-C-100-ISO10646-1
+SIZE 10 75 75
+FONTBOUNDINGBOX 6 10 0 -2
+STARTPROPERTIES 14
+POINT_SIZE 100
+PIXEL_SIZE 10
+RESOLUTION_X 75
+RESOLUTION_Y 75
+AVERAGE_WIDTH 100
+SPACING "C"
+CHARSET_ENCODING "1"
+CHARSET_REGISTRY "ISO10646"
+FOUNDRY "benji"
+FAMILY_NAME "berry"
+FONT_DESCENT 2
+FONT_ASCENT 8
+_GBDFED_INFO "Edited with gbdfed 1.6."
+COPYRIGHT "Public Domain. Based on cherry by camille."
+ENDPROPERTIES
+CHARS 192
+STARTCHAR UNKNOWN
+ENCODING 0
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+30
+48
+48
+10
+20
+00
+20
+00
+FC
+ENDCHAR
+STARTCHAR SPACE
+ENCODING 32
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+00
+00
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR EXCLAMATION MARK
+ENCODING 33
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+10
+10
+10
+10
+00
+10
+10
+00
+00
+ENDCHAR
+STARTCHAR QUOTATION MARK
+ENCODING 34
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+28
+28
+28
+00
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR NUMBER SIGN
+ENCODING 35
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+28
+28
+7C
+28
+7C
+28
+28
+00
+00
+ENDCHAR
+STARTCHAR DOLLAR SIGN
+ENCODING 36
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+10
+38
+54
+30
+18
+54
+38
+10
+00
+ENDCHAR
+STARTCHAR PERCENT SIGN
+ENCODING 37
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+24
+54
+28
+10
+28
+54
+48
+00
+00
+ENDCHAR
+STARTCHAR AMPERSAND
+ENCODING 38
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+20
+50
+50
+20
+54
+48
+34
+00
+00
+ENDCHAR
+STARTCHAR APOSTROPHE
+ENCODING 39
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+10
+10
+10
+00
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR LEFT PARENTHESIS
+ENCODING 40
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+18
+20
+20
+20
+20
+20
+20
+18
+00
+ENDCHAR
+STARTCHAR RIGHT PARENTHESIS
+ENCODING 41
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+60
+10
+10
+10
+10
+10
+10
+60
+00
+ENDCHAR
+STARTCHAR ASTERISK
+ENCODING 42
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+28
+10
+7C
+10
+28
+00
+00
+ENDCHAR
+STARTCHAR PLUS SIGN
+ENCODING 43
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+10
+10
+7C
+10
+10
+00
+00
+ENDCHAR
+STARTCHAR COMMA
+ENCODING 44
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+00
+00
+00
+10
+10
+20
+00
+ENDCHAR
+STARTCHAR HYPHEN-MINUS
+ENCODING 45
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+00
+00
+78
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR FULL STOP
+ENCODING 46
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+00
+00
+00
+10
+10
+00
+00
+ENDCHAR
+STARTCHAR SOLIDUS
+ENCODING 47
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+08
+08
+10
+10
+20
+20
+40
+40
+00
+ENDCHAR
+STARTCHAR DIGIT ZERO
+ENCODING 48
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+30
+48
+58
+68
+48
+48
+30
+00
+00
+ENDCHAR
+STARTCHAR DIGIT ONE
+ENCODING 49
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+10
+30
+50
+10
+10
+10
+10
+00
+00
+ENDCHAR
+STARTCHAR DIGIT TWO
+ENCODING 50
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+30
+48
+48
+10
+20
+40
+78
+00
+00
+ENDCHAR
+STARTCHAR DIGIT THREE
+ENCODING 51
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+70
+08
+08
+30
+08
+08
+70
+00
+00
+ENDCHAR
+STARTCHAR DIGIT FOUR
+ENCODING 52
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+10
+30
+30
+50
+78
+10
+10
+00
+00
+ENDCHAR
+STARTCHAR DIGIT FIVE
+ENCODING 53
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+78
+40
+40
+70
+08
+08
+70
+00
+00
+ENDCHAR
+STARTCHAR DIGIT SIX
+ENCODING 54
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+30
+40
+40
+70
+48
+48
+30
+00
+00
+ENDCHAR
+STARTCHAR DIGIT SEVEN
+ENCODING 55
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+78
+08
+10
+10
+20
+20
+20
+00
+00
+ENDCHAR
+STARTCHAR DIGIT EIGHT
+ENCODING 56
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+30
+48
+48
+30
+48
+48
+30
+00
+00
+ENDCHAR
+STARTCHAR DIGIT NINE
+ENCODING 57
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+30
+48
+48
+38
+08
+08
+30
+00
+00
+ENDCHAR
+STARTCHAR COLON
+ENCODING 58
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+10
+10
+00
+10
+10
+00
+00
+ENDCHAR
+STARTCHAR SEMICOLON
+ENCODING 59
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+10
+10
+00
+10
+10
+20
+00
+ENDCHAR
+STARTCHAR LESS-THAN SIGN
+ENCODING 60
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+08
+10
+20
+10
+08
+00
+00
+ENDCHAR
+STARTCHAR EQUALS SIGN
+ENCODING 61
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+00
+78
+00
+78
+00
+00
+00
+ENDCHAR
+STARTCHAR GREATER-THAN SIGN
+ENCODING 62
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+40
+20
+10
+20
+40
+00
+00
+ENDCHAR
+STARTCHAR QUESTION MARK
+ENCODING 63
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+30
+48
+48
+10
+20
+00
+20
+00
+00
+ENDCHAR
+STARTCHAR COMMERCIAL AT
+ENCODING 64
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+38
+44
+5C
+54
+4C
+40
+3C
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER A
+ENCODING 65
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+30
+30
+48
+48
+78
+48
+48
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER B
+ENCODING 66
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+70
+48
+48
+70
+48
+48
+70
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER C
+ENCODING 67
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+30
+48
+40
+40
+40
+48
+30
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER D
+ENCODING 68
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+70
+48
+48
+48
+48
+48
+70
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER E
+ENCODING 69
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+78
+40
+40
+70
+40
+40
+78
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER F
+ENCODING 70
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+78
+40
+40
+70
+40
+40
+40
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER G
+ENCODING 71
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+30
+48
+40
+58
+48
+48
+30
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER H
+ENCODING 72
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+48
+48
+48
+78
+48
+48
+48
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER I
+ENCODING 73
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+38
+10
+10
+10
+10
+10
+38
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER J
+ENCODING 74
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+38
+08
+08
+08
+08
+08
+30
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER K
+ENCODING 75
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+48
+48
+50
+70
+50
+48
+48
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER L
+ENCODING 76
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+40
+40
+40
+40
+40
+40
+78
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER M
+ENCODING 77
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+48
+78
+48
+48
+48
+48
+48
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER N
+ENCODING 78
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+48
+68
+68
+58
+58
+48
+48
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER O
+ENCODING 79
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+30
+48
+48
+48
+48
+48
+30
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER P
+ENCODING 80
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+70
+48
+48
+70
+40
+40
+40
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER Q
+ENCODING 81
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+30
+48
+48
+48
+48
+48
+30
+18
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER R
+ENCODING 82
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+70
+48
+48
+70
+48
+48
+48
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER S
+ENCODING 83
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+30
+48
+40
+30
+08
+48
+30
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER T
+ENCODING 84
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+7C
+10
+10
+10
+10
+10
+10
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER U
+ENCODING 85
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+48
+48
+48
+48
+48
+48
+30
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER V
+ENCODING 86
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+48
+48
+48
+48
+48
+30
+30
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER W
+ENCODING 87
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+48
+48
+48
+48
+48
+78
+48
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER X
+ENCODING 88
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+48
+48
+48
+30
+48
+48
+48
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER Y
+ENCODING 89
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+44
+44
+28
+28
+10
+10
+10
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER Z
+ENCODING 90
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+78
+08
+10
+20
+20
+40
+78
+00
+00
+ENDCHAR
+STARTCHAR LEFT SQUARE BRACKET
+ENCODING 91
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+38
+20
+20
+20
+20
+20
+20
+38
+00
+ENDCHAR
+STARTCHAR REVERSE SOLIDUS
+ENCODING 92
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+40
+40
+20
+20
+10
+10
+08
+08
+00
+ENDCHAR
+STARTCHAR RIGHT SQUARE BRACKET
+ENCODING 93
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+70
+10
+10
+10
+10
+10
+10
+70
+00
+ENDCHAR
+STARTCHAR CIRCUMFLEX ACCENT
+ENCODING 94
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+30
+48
+00
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR LOW LINE
+ENCODING 95
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+00
+00
+00
+00
+78
+00
+00
+ENDCHAR
+STARTCHAR GRAVE ACCENT
+ENCODING 96
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+20
+10
+08
+00
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER A
+ENCODING 97
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+38
+48
+48
+48
+38
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER B
+ENCODING 98
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+40
+40
+70
+48
+48
+48
+70
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER C
+ENCODING 99
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+30
+48
+40
+48
+30
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER D
+ENCODING 100
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+08
+08
+38
+48
+48
+48
+38
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER E
+ENCODING 101
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+30
+48
+78
+40
+38
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER F
+ENCODING 102
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+18
+20
+78
+20
+20
+20
+20
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER G
+ENCODING 103
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+38
+48
+48
+48
+38
+08
+30
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER H
+ENCODING 104
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+40
+40
+70
+48
+48
+48
+48
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER I
+ENCODING 105
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+10
+00
+30
+10
+10
+10
+10
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER J
+ENCODING 106
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+10
+10
+00
+30
+10
+10
+10
+10
+10
+60
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER K
+ENCODING 107
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+40
+40
+48
+50
+70
+50
+48
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER L
+ENCODING 108
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+30
+10
+10
+10
+10
+10
+10
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER M
+ENCODING 109
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+48
+78
+48
+48
+48
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER N
+ENCODING 110
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+70
+48
+48
+48
+48
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER O
+ENCODING 111
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+30
+48
+48
+48
+30
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER P
+ENCODING 112
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+70
+48
+48
+48
+70
+40
+40
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER Q
+ENCODING 113
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+38
+48
+48
+48
+38
+08
+08
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER R
+ENCODING 114
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+58
+60
+40
+40
+40
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER S
+ENCODING 115
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+38
+40
+30
+08
+70
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER T
+ENCODING 116
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+20
+20
+78
+20
+20
+20
+18
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER U
+ENCODING 117
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+48
+48
+48
+48
+38
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER V
+ENCODING 118
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+48
+48
+48
+30
+30
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER W
+ENCODING 119
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+48
+48
+48
+78
+48
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER X
+ENCODING 120
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+48
+48
+30
+48
+48
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER Y
+ENCODING 121
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+48
+48
+48
+48
+38
+08
+30
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER Z
+ENCODING 122
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+78
+10
+20
+40
+78
+00
+00
+ENDCHAR
+STARTCHAR LEFT CURLY BRACKET
+ENCODING 123
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+18
+20
+20
+C0
+C0
+20
+20
+18
+00
+ENDCHAR
+STARTCHAR VERTICAL LINE
+ENCODING 124
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+10
+10
+10
+10
+10
+10
+10
+10
+00
+ENDCHAR
+STARTCHAR RIGHT CURLY BRACKET
+ENCODING 125
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+60
+10
+10
+0C
+0C
+10
+10
+60
+00
+ENDCHAR
+STARTCHAR TILDE
+ENCODING 126
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+20
+54
+08
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR NO-BREAK SPACE
+ENCODING 160
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+00
+00
+00
+48
+78
+00
+00
+ENDCHAR
+STARTCHAR INVERTED EXCLAMATION MARK
+ENCODING 161
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+10
+10
+00
+10
+10
+10
+10
+00
+00
+ENDCHAR
+STARTCHAR CENT SIGN
+ENCODING 162
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+10
+38
+50
+50
+50
+38
+10
+00
+ENDCHAR
+STARTCHAR POUND SIGN
+ENCODING 163
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+18
+24
+20
+70
+20
+24
+7C
+00
+00
+ENDCHAR
+STARTCHAR CURRENCY SIGN
+ENCODING 164
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+44
+38
+28
+38
+44
+00
+00
+ENDCHAR
+STARTCHAR YEN SIGN
+ENCODING 165
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+44
+44
+28
+7C
+10
+7C
+10
+00
+00
+ENDCHAR
+STARTCHAR BROKEN BAR
+ENCODING 166
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+10
+10
+10
+00
+00
+10
+10
+10
+00
+ENDCHAR
+STARTCHAR SECTION SIGN
+ENCODING 167
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+30
+48
+60
+50
+48
+28
+18
+48
+30
+ENDCHAR
+STARTCHAR DIAERESIS
+ENCODING 168
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+28
+00
+00
+00
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR COPYRIGHT SIGN
+ENCODING 169
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+78
+84
+B4
+A4
+B4
+84
+78
+00
+00
+ENDCHAR
+STARTCHAR FEMININE ORDINAL INDICATOR
+ENCODING 170
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+38
+48
+48
+38
+00
+78
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+ENCODING 171
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+24
+48
+48
+24
+00
+00
+00
+ENDCHAR
+STARTCHAR NOT SIGN
+ENCODING 172
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+00
+00
+78
+08
+08
+00
+00
+ENDCHAR
+STARTCHAR SOFT HYPHEN
+ENCODING 173
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+00
+00
+38
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR REGISTERED SIGN
+ENCODING 174
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+78
+84
+B4
+B4
+AC
+84
+78
+00
+00
+ENDCHAR
+STARTCHAR MACRON
+ENCODING 175
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+78
+00
+00
+00
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR DEGREE SIGN
+ENCODING 176
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+30
+48
+48
+30
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR PLUS-MINUS SIGN
+ENCODING 177
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+10
+10
+7C
+10
+10
+7C
+00
+00
+ENDCHAR
+STARTCHAR SUPERSCRIPT TWO
+ENCODING 178
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+30
+48
+10
+20
+78
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR SUPERSCRIPT THREE
+ENCODING 179
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+70
+08
+30
+08
+70
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR ACUTE ACCENT
+ENCODING 180
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+10
+20
+00
+00
+00
+00
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR MICRO SIGN
+ENCODING 181
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+48
+48
+48
+48
+78
+44
+40
+ENDCHAR
+STARTCHAR PILCROW SIGN
+ENCODING 182
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+3C
+74
+74
+34
+14
+14
+14
+00
+00
+ENDCHAR
+STARTCHAR MIDDLE DOT
+ENCODING 183
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+00
+10
+10
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR CEDILLA
+ENCODING 184
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+00
+00
+00
+00
+00
+10
+20
+ENDCHAR
+STARTCHAR SUPERSCRIPT ONE
+ENCODING 185
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+10
+30
+10
+10
+10
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR MASCULINE ORDINAL INDICATOR
+ENCODING 186
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+30
+48
+48
+30
+00
+78
+00
+00
+00
+00
+ENDCHAR
+STARTCHAR RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+ENCODING 187
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+48
+24
+24
+48
+00
+00
+00
+ENDCHAR
+STARTCHAR VULGAR FRACTION ONE QUARTER
+ENCODING 188
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+40
+C4
+48
+50
+20
+54
+94
+1C
+04
+04
+ENDCHAR
+STARTCHAR VULGAR FRACTION ONE HALF
+ENCODING 189
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+40
+C4
+48
+50
+20
+58
+A4
+08
+10
+3C
+ENDCHAR
+STARTCHAR VULGAR FRACTION THREE QUARTERS
+ENCODING 190
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+C0
+24
+C8
+30
+E0
+54
+94
+1C
+04
+04
+ENDCHAR
+STARTCHAR INVERTED QUESTION MARK
+ENCODING 191
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+10
+00
+10
+20
+48
+48
+30
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER A WITH GRAVE
+ENCODING 192
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+20
+10
+00
+30
+48
+78
+48
+48
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER A WITH ACUTE
+ENCODING 193
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+10
+20
+00
+30
+48
+78
+48
+48
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER A WITH CIRCUMFLEX
+ENCODING 194
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+30
+48
+00
+30
+48
+78
+48
+48
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER A WITH TILDE
+ENCODING 195
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+28
+50
+00
+30
+48
+78
+48
+48
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER A WITH DIAERESIS
+ENCODING 196
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+48
+00
+30
+48
+78
+48
+48
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER A WITH RING ABOVE
+ENCODING 197
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+30
+48
+30
+30
+48
+78
+48
+48
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER AE
+ENCODING 198
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+1C
+30
+30
+5C
+70
+90
+9C
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER C WITH CEDILLA
+ENCODING 199
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+30
+48
+40
+40
+40
+48
+30
+10
+20
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER E WITH GRAVE
+ENCODING 200
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+20
+10
+00
+78
+40
+70
+40
+78
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER E WITH ACUTE
+ENCODING 201
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+10
+20
+00
+78
+40
+70
+40
+78
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER E WITH CIRCUMFLEX
+ENCODING 202
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+30
+48
+00
+78
+40
+70
+40
+78
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER E WITH DIAERESIS
+ENCODING 203
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+48
+00
+78
+40
+70
+40
+78
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER I WITH GRAVE
+ENCODING 204
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+20
+10
+00
+38
+10
+10
+10
+38
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER I WITH ACUTE
+ENCODING 205
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+08
+10
+00
+38
+10
+10
+10
+38
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER I WITH CIRCUMFLEX
+ENCODING 206
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+10
+28
+00
+38
+10
+10
+10
+38
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER I WITH DIAERESIS
+ENCODING 207
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+28
+00
+38
+10
+10
+10
+38
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER ETH
+ENCODING 208
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+38
+24
+24
+74
+24
+24
+38
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER N WITH TILDE
+ENCODING 209
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+28
+50
+00
+48
+68
+58
+48
+48
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER O WITH GRAVE
+ENCODING 210
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+20
+10
+00
+30
+48
+48
+48
+30
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER O WITH ACUTE
+ENCODING 211
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+10
+20
+00
+30
+48
+48
+48
+30
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER O WITH CIRCUMFLEX
+ENCODING 212
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+30
+48
+00
+30
+48
+48
+48
+30
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER O WITH TILDE
+ENCODING 213
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+28
+50
+00
+30
+48
+48
+48
+30
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER O WITH DIAERESIS
+ENCODING 214
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+48
+00
+30
+48
+48
+48
+30
+00
+00
+ENDCHAR
+STARTCHAR MULTIPLICATION SIGN
+ENCODING 215
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+00
+28
+10
+28
+00
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER O WITH STROKE
+ENCODING 216
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+34
+48
+58
+58
+68
+48
+B0
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER U WITH GRAVE
+ENCODING 217
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+20
+10
+00
+48
+48
+48
+48
+38
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER U WITH ACUTE
+ENCODING 218
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+10
+20
+00
+48
+48
+48
+48
+38
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER U WITH CIRCUMFLEX
+ENCODING 219
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+30
+48
+00
+48
+48
+48
+48
+38
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER U WITH DIAERESIS
+ENCODING 220
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+48
+00
+48
+48
+48
+48
+38
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER Y WITH ACUTE
+ENCODING 221
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+08
+10
+00
+44
+28
+10
+10
+10
+00
+00
+ENDCHAR
+STARTCHAR LATIN CAPITAL LETTER THORN
+ENCODING 222
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+40
+40
+70
+48
+48
+70
+40
+40
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER SHARP S
+ENCODING 223
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+30
+48
+50
+48
+48
+48
+50
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER A WITH GRAVE
+ENCODING 224
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+20
+10
+00
+38
+48
+48
+48
+38
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER A WITH ACUTE
+ENCODING 225
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+10
+20
+00
+38
+48
+48
+48
+38
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER A WITH CIRCUMFLEX
+ENCODING 226
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+10
+28
+00
+38
+48
+48
+48
+38
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER A WITH TILDE
+ENCODING 227
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+28
+50
+00
+38
+48
+48
+48
+38
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER A WITH DIAERESIS
+ENCODING 228
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+28
+00
+38
+48
+48
+48
+38
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER A WITH RING ABOVE
+ENCODING 229
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+10
+28
+10
+38
+48
+48
+48
+38
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER AE
+ENCODING 230
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+6C
+14
+38
+50
+6C
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER C WITH CEDILLA
+ENCODING 231
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+30
+48
+40
+48
+30
+10
+20
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER E WITH GRAVE
+ENCODING 232
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+20
+10
+00
+30
+48
+78
+40
+38
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER E WITH ACUTE
+ENCODING 233
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+10
+20
+00
+30
+48
+78
+40
+38
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER E WITH CIRCUMFLEX
+ENCODING 234
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+30
+48
+00
+30
+48
+78
+40
+38
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER E WITH DIAERESIS
+ENCODING 235
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+48
+00
+30
+48
+78
+40
+38
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER I WITH GRAVE
+ENCODING 236
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+20
+10
+00
+30
+10
+10
+10
+10
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER I WITH ACUTE
+ENCODING 237
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+08
+10
+00
+30
+10
+10
+10
+10
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER I WITH CIRCUMFLEX
+ENCODING 238
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+10
+28
+00
+30
+10
+10
+10
+10
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER I WITH DIAERESIS
+ENCODING 239
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+28
+00
+30
+10
+10
+10
+10
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER ETH
+ENCODING 240
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+60
+60
+10
+30
+48
+48
+48
+30
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER N WITH TILDE
+ENCODING 241
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+28
+50
+00
+70
+48
+48
+48
+48
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER O WITH GRAVE
+ENCODING 242
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+20
+10
+00
+00
+30
+48
+48
+30
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER O WITH ACUTE
+ENCODING 243
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+10
+20
+00
+00
+30
+48
+48
+30
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER O WITH CIRCUMFLEX
+ENCODING 244
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+30
+48
+00
+00
+30
+48
+48
+30
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER O WITH TILDE
+ENCODING 245
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+28
+50
+00
+00
+30
+48
+48
+30
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER O WITH DIAERESIS
+ENCODING 246
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+48
+00
+00
+30
+48
+48
+30
+00
+00
+ENDCHAR
+STARTCHAR DIVISION SIGN
+ENCODING 247
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+10
+00
+7C
+00
+10
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER O WITH STROKE
+ENCODING 248
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+00
+00
+34
+48
+78
+48
+B0
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER U WITH GRAVE
+ENCODING 249
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+20
+10
+00
+00
+48
+48
+48
+38
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER U WITH ACUTE
+ENCODING 250
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+10
+20
+00
+00
+48
+48
+48
+38
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER U WITH CIRCUMFLEX
+ENCODING 251
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+30
+48
+00
+00
+48
+48
+48
+38
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER U WITH DIAERESIS
+ENCODING 252
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+48
+00
+00
+48
+48
+48
+38
+00
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER Y WITH ACUTE
+ENCODING 253
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+10
+20
+00
+00
+48
+48
+48
+38
+08
+30
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER THORN
+ENCODING 254
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+40
+50
+68
+48
+48
+68
+50
+40
+00
+ENDCHAR
+STARTCHAR LATIN SMALL LETTER Y WITH DIAERESIS
+ENCODING 255
+SWIDTH 576 0
+DWIDTH 6 0
+BBX 6 10 0 -2
+BITMAP
+00
+48
+00
+00
+48
+48
+48
+38
+08
+30
+ENDCHAR
+ENDFONT
diff --git a/fs-skel/sys/scantabs/qwerty.sct b/fs-skel/sys/scantabs/qwerty.sct
new file mode 100644
index 0000000..3e363ea
--- /dev/null
+++ b/fs-skel/sys/scantabs/qwerty.sct
Binary files differ
diff --git a/fs-skel/user/default.rc b/fs-skel/user/default.rc
index 568c546..f26e558 100644
--- a/fs-skel/user/default.rc
+++ b/fs-skel/user/default.rc
@@ -1 +1,3 @@
-set _path bin/ \ No newline at end of file
+set _path bin/
+set _color_fg 10
+set _color_bg 61 \ No newline at end of file
diff --git a/makefile b/makefile
index 421f963..002dce3 100644
--- a/makefile
+++ b/makefile
@@ -1,5 +1,6 @@
-kgccargs = -Wall -Wsuggest-attribute=pure -Wsuggest-attribute=const -m32 -Og -ffreestanding -fno-asynchronous-unwind-tables
+kgccargs = -Wall -Wsuggest-attribute=pure -Wsuggest-attribute=const -m32 -mno-sse -Og -ggdb -ffreestanding -fno-asynchronous-unwind-tables -fno-pic -Isrc/shared/include -Isrc/lib
ugccargs = ${kgccargs} -Isrc/user/include
+ugppargs = ${ugccargs} -fno-rtti -Isrc/user/include/c++
nasmargs = -f elf32
partlink = -r -m elf_i386
@@ -9,7 +10,7 @@ out/disk.vdi: out/disk.img
out/disk.img: out/kernel.bin out/boot.bin 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
+ 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
dd if=obj/jmp.bin of=obj/shadow.img obs=2 conv=notrunc
dd if=out/boot.bin of=obj/shadow.img obs=1 seek=62 conv=notrunc
@@ -17,12 +18,15 @@ out/disk.img: out/kernel.bin out/boot.bin out/fs
mv obj/shadow.img out/disk.img
mcopy -i out/disk.img -s out/fs/* ::/
-debug: out/disk.img
- gdb -x qemu-debug.gdb
-
clean:
rm -r obj out || true
+qemu: out/disk.img
+ qemu-system-i386 -m 512 -s -S out/disk.img
+
+bochs: out/disk.img
+ bochs -q
+
out/fs/bin/%: obj/%.elf
mkdir -p $(shell dirname $@)
objcopy -S $< $@
@@ -31,10 +35,7 @@ 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 out/fs/bin/manual \
- out/fs/man/index.man out/fs/man/dev/kmemmap.man
+out/fs: out/fs/bin/init out/fs/bin/highway out/fs/bin/meminfo
touch out/fs
cp -r fs-skel/* out/fs/
@@ -50,7 +51,7 @@ out/kernel.bin: obj/kernel/drive.ko obj/kernel/fat.ko obj/kernel/ide.ko \
obj/kernel/idt.ko obj/kernel/log.ko obj/kernel/main.ko \
obj/kernel/panic.ko obj/kernel/pci.ko obj/kernel/elf.ko \
obj/kernel/serial.ko obj/kernel/task.ko obj/kernel/util.ko \
- obj/kernel/vga.ko obj/kernel/isrs.kao obj/kernel/kbd.ko \
+ obj/kernel/window.ko obj/kernel/isrs.kao obj/kernel/kbd.ko \
obj/kernel/pmap.ko obj/kernel/paging.ko
mkdir -p out
ld -T src/kernel/elf-link.ld $^ -o obj/kernel.elf
@@ -68,41 +69,38 @@ obj/%.ao: src/user/%.asm
mkdir -p $(shell dirname $@)
nasm ${nasmargs} $< -o $@
-obj/c.rto: obj/runtimes/c/entry.ao
- ld ${partlink} obj/runtimes/c/* -o obj/c.rto
+obj/%.po: src/user/%.cpp
+ mkdir -p $(shell dirname $@)
+ g++ ${ugppargs} -c $< -o $@
+
+obj/c.rto: obj/runtimes/c/pcrt.ao
+ ld ${partlink} $^ -o $@
obj/cpp.rto:
#TODO
-obj/knob.so: obj/knob/env.o obj/knob/file.o obj/knob/format.o \
- obj/knob/heap.o obj/knob/user.o obj/knob/task.o \
- obj/knob/block.o
+obj/knob.so: obj/knob/file.o obj/knob/format.o \
+ obj/knob/heap.o obj/knob/ipc.o obj/knob/task.o \
+ obj/knob/block.o obj/knob/key.o obj/knob/panic.o
ld ${partlink} $^ -o $@
-obj/init.elf: obj/init/init.o obj/knob.so obj/c.rto
- ld -T src/user/runtimes/c/elf.ld $^ -o $@
-
-obj/meminfo.elf: obj/meminfo/meminfo.o obj/knob.so obj/c.rto
- ld -T src/user/runtimes/c/elf.ld $^ -o $@
-
-obj/highway.elf: obj/highway/main.o obj/highway/cmds.o obj/highway/line.o \
- obj/highway/vars.o obj/knob.so obj/c.rto
- ld -T src/user/runtimes/c/elf.ld $^ -o $@
-
-obj/hello.elf: obj/hello/hello.ao
- ld -T src/user/runtimes/asm/elf.ld $^ -o $@
+obj/terminal.so: obj/terminal/readline.o obj/terminal/terminal.o
+ ld ${partlink} $^ -o $@
-obj/dumptext.elf: obj/dumptext/dumptext.o obj/knob.so obj/c.rto
- ld -T src/user/runtimes/c/elf.ld $^ -o $@
+obj/libfont.so: obj/libfont/bdf.o obj/libfont/fonts.o obj/libfont/filist.o
+ ld ${partlink} $^ -o $@
-obj/dumphex.elf: obj/dumphex/dumphex.o obj/knob.so obj/c.rto
- ld -T src/user/runtimes/c/elf.ld $^ -o $@
+obj/popups.so: obj/popups/info.o obj/popups/popup.o
+ ld ${partlink} $^ -o $@
-obj/dirinfo.elf: obj/dirinfo/dirinfo.o obj/knob.so obj/c.rto
+obj/init.elf: obj/init/init.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
+obj/highway.elf: obj/highway/main.o obj/highway/cmds.o obj/highway/line.o \
+ obj/highway/vars.o obj/knob.so obj/terminal.so \
+ obj/libfont.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
+obj/meminfo.elf: obj/meminfo/meminfo.o obj/popups.so obj/libfont.so \
+ obj/knob.so obj/c.rto
ld -T src/user/runtimes/c/elf.ld $^ -o $@ \ No newline at end of file
diff --git a/qemu-debug.gdb b/qemu-debug.gdb
deleted file mode 100644
index 8549210..0000000
--- a/qemu-debug.gdb
+++ /dev/null
@@ -1,8 +0,0 @@
-target remote | qemu-system-i386 -m 512 -S -gdb stdio out/disk.img
-add-symbol-file obj/kernel.elf
-set disassembly-flavor intel
-layout reg
-break main
-break panic
-break exception_halt
-cont
diff --git a/src/boot.asm b/src/boot.asm
index 28d1a89..08b2834 100644
--- a/src/boot.asm
+++ b/src/boot.asm
@@ -20,8 +20,7 @@ pae_support equ 0x40
mov ss, ax
mov sp, 0x7ffc
- mov ah, 0x01
- mov ch, 0x3f
+ mov ax, 0x0013
int 0x10
mov ax, kernel_segment
@@ -90,6 +89,7 @@ bits 32
pmode:
mov ax, 0x18
mov ds, ax
+ mov es, ax
mov ss, ax
mov esp, 0x00040000
@@ -115,4 +115,4 @@ gdt:
dq 0x00cf_f200_0000_ffff;0x28: user data
.e:
-dw 0xaa55 \ No newline at end of file
+dw 0xaa55
diff --git a/src/kernel/elf.c b/src/kernel/elf.c
index 60fa3a9..146035e 100644
--- a/src/kernel/elf.c
+++ b/src/kernel/elf.c
@@ -73,7 +73,7 @@ struct ph_entry {
uint32_t align;
} __attribute__ ((packed));
-uint32_t try_elf_run(const struct drive *d, const char *path, const char *pass_old_vma) {
+uint32_t try_elf_run(const struct drive *d, const char *path, const char *pass_old_vma, uint32_t io_handle) {
file_id_t h = d->get_file(d, path);
if (!h)
return 0;
@@ -127,8 +127,12 @@ uint32_t try_elf_run(const struct drive *d, const char *path, const char *pass_o
struct task_state tstate;
tstate.page_directory = pd;
tstate.ret_addr = ehead.entry_vma;
+ tstate.stack_bottom = 0;
+
tstate.edx = (uint32_t)pass_vma;
- tstate.wait_mode = NONE;
+ tstate.esi = active_task - tasks + 1;
+ tstate.edi = io_handle;
+ tstate.esp = 0;
const char *path_end_start = path;
for (const char *i = path; *i; ++i)
@@ -144,4 +148,4 @@ uint32_t try_elf_run(const struct drive *d, const char *path, const char *pass_o
tstate.name[i] = '\0';
return new_task(tstate);
-} \ No newline at end of file
+}
diff --git a/src/kernel/elf.h b/src/kernel/elf.h
index 89726c9..1f39afd 100644
--- a/src/kernel/elf.h
+++ b/src/kernel/elf.h
@@ -4,6 +4,6 @@
#include <stdint.h>
#include "drive.h"
-uint32_t try_elf_run(const struct drive *d, const char *path, const char *pass_old_vma);
+uint32_t try_elf_run(const struct drive *d, const char *path, const char *pass_old_vma, uint32_t io_handle);
#endif \ No newline at end of file
diff --git a/src/kernel/ide.c b/src/kernel/ide.c
index 4b6443a..39525ad 100644
--- a/src/kernel/ide.c
+++ b/src/kernel/ide.c
@@ -93,7 +93,6 @@ static uint32_t ide_ata_rs(const struct drive *d, uint32_t start, uint32_t count
static uint32_t ide_ata_ws(const struct drive *d, uint32_t start, uint32_t count, const void *buffer) {
PANIC("IDE ATA writing not implemented yet.");
- return 0;
}
static uint32_t ide_atapi_rs(const struct drive *d, uint32_t start, uint32_t count, void *buffer) {
@@ -109,7 +108,6 @@ static uint32_t ide_atapi_rs(const struct drive *d, uint32_t start, uint32_t cou
static uint32_t ide_atapi_ws(const struct drive *d, uint32_t start, uint32_t count, const void *buffer) {
PANIC("IDE ATAPI writing not implemented yet.");
- return 0;
}
static void nop(const struct drive *d) { }
diff --git a/src/kernel/idt.c b/src/kernel/idt.c
index ebeea17..b8990f2 100644
--- a/src/kernel/idt.c
+++ b/src/kernel/idt.c
@@ -1,14 +1,14 @@
+#include "paging.h"
+#include "window.h"
#include "drive.h"
-#include "elf.h"
-#include "util.h"
-#include "idt.h"
-#include "log.h"
#include "panic.h"
-#include "task.h"
-#include "paging.h"
#include "pmap.h"
+#include "task.h"
+#include "util.h"
+#include "elf.h"
+#include "idt.h"
#include "kbd.h"
-#include "vga.h"
+#include "log.h"
enum {
IDT_PRESENT = 0x80,
@@ -35,19 +35,27 @@ struct {
//file handles as (drive_number << 8) + file_id_t
-static uint32_t sc_open_file(uint32_t drive_number, char *path) {
+uint32_t sc_open_file(uint32_t drive_number, char *path) { //not static to ensure sysv abi
return (drive_number << 8) + drives[drive_number].get_file(drives + drive_number, path);
+ //logf(LOG_INFO, "sc_open_file(%d, \"%s\") -> %d", drive_number, path, handle);
}
-static void sc_close_file(uint32_t handle) {
+void sc_close_file(uint32_t handle) { //not static to ensure sysv abi
+ if (!handle)
+ return;
drives[handle >> 8].free_file(drives + (handle >> 8), handle & 0xff);
}
-static uint32_t sc_file_get_size(uint32_t handle) {
+uint32_t sc_file_get_size(uint32_t handle) { //not static to ensure sysv abi
+ //logf(LOG_INFO, "sc_file_get_size(%d)", handle);
+ if (!handle)
+ return 0;
return drives[handle >> 8].get_file_length(drives + (handle >> 8), handle & 0xff);
}
-static uint32_t sc_file_read(uint32_t handle, uint32_t file_offset, uint32_t count, void *buffer) {
+uint32_t sc_file_read(uint32_t handle, uint32_t file_offset, uint32_t count, void *buffer) { //not static to ensure sysv abi
+ if (!handle)
+ return 0;
uint32_t len = sc_file_get_size(handle);
if (file_offset + count > len)
count = len - file_offset;
@@ -55,14 +63,14 @@ static uint32_t sc_file_read(uint32_t handle, uint32_t file_offset, uint32_t cou
return count;
}
-static uint32_t sc_start_task(uint32_t drive_number, char *path, const char *pass) {
+uint32_t sc_start_task(uint32_t drive_number, char *path, const char *pass, uint32_t esi_dummy, uint32_t io_task) { //not static to ensure sysv abi
switch_to_kernel_cr3();
- uint32_t process_id = try_elf_run(drives + drive_number, vma_to_pma(active_task->page_directory, path), pass);
+ uint32_t process_id = try_elf_run(drives + drive_number, vma_to_pma(active_task->page_directory, path), pass, io_task);
switch_to_task_cr3();
return process_id;
}
-static void *sc_allocate_ram(uint32_t pages) {
+void *sc_allocate_ram(uint32_t pages) { //not static to ensure sysv abi
return pd_user_allocate_anywhere_writable(active_task->page_directory, pages);
}
@@ -75,7 +83,7 @@ enum mi_arg {
};
__attribute__ ((pure))
-static uint32_t sc_memory_info(enum mi_arg arg) {
+uint32_t sc_memory_info(enum mi_arg arg) { //not static to ensure sysv abi
switch (arg) {
case MI_KERNEL_MAX:
return max_kernel_pages;
@@ -92,36 +100,73 @@ static uint32_t sc_memory_info(enum mi_arg arg) {
}
}
-static void sc_wait_for_task(uint32_t handle) {
- active_task->wait_mode = PROCESS_END;
- active_task->wait_arg = handle;
+void sc_wait_for_task(uint32_t handle) { //not static to ensure sysv abi
+ add_wait((struct wait){.mode = PROCESS_END, .task = tasks + handle - 1});
}
-static uint32_t sc_enumerate_dir(uint32_t drive_number, const char *path, struct directory_content_info *buffer, uint32_t max_entries) {
+uint32_t sc_enumerate_dir(uint32_t drive_number, const char *path, struct directory_content_info *buffer, uint32_t max_entries) { //not static to ensure sysv abi
return drives[drive_number].enumerate_dir(drives + drive_number, path, buffer, max_entries);
}
-static uint32_t sc_count_of_dir(uint32_t drive_number, const char *path) {
+uint32_t sc_count_of_dir(uint32_t drive_number, const char *path) { //not static to ensure sysv abi
return drives[drive_number].n_dir_entries(drives + drive_number, path);
}
+void sc_get_next_window_action(struct window *w, struct window_action *action) { //not static to ensure sysv abi
+ *action = next_window_action(w);
+}
+
+void sc_wait_window_action() {
+ add_wait((struct wait){.mode = WINDOW_ACTION});
+}
+
+void sc_wait_ipc(uint32_t task_handle) {
+ add_wait((struct wait){.mode = IPC_RECEIVE, .task = tasks + task_handle - 1});
+}
+
+void sc_system_log(const char *sz) {
+ logf(LOG_USER, "[%s] %s", active_task->name, sz);
+}
+
+void sc_wait_any_ipc() {
+ add_wait((struct wait){.mode = IPC_RECEIVE_ANY});
+}
+
+void sc_wait_ipc_read(uint32_t handle) {
+ add_wait((struct wait){.mode = IPC_SEND, .task = tasks + handle - 1});
+}
+
+__attribute__ ((pure))
+bool sc_is_task_running(uint32_t handle) {
+ return tasks[handle - 1].page_directory;
+}
+
void const *syscall_table[] = {
&sc_open_file,
&sc_close_file,
&sc_file_read,
&sc_file_get_size,
&sc_start_task,
- &logsz,
- &get_key_code,
+ &ipc_send,
+ &ipc_read,
&sc_allocate_ram,
&sc_memory_info,
&sc_wait_for_task,
&sc_enumerate_dir,
- &vga_print_at,
+ &sc_system_log,
&sc_count_of_dir,
- &vga_blank,
- &vga_set_color,
- &vga_swap_color
+ &new_window,
+ &del_window,
+ &resize_window,
+ &reassign_pixel_buffer,
+ &push_window_paint,
+ &sc_get_next_window_action,
+ &sc_wait_window_action,
+ &sc_wait_ipc,
+ &sc_wait_any_ipc,
+ &find_unread_ipc,
+ &sc_wait_ipc_read,
+ &sc_is_task_running
};
//these aren't really void ()'s, but gcc complains if we take an address of a void, so we give it a type
@@ -141,38 +186,77 @@ extern isr_t ssf_isr;
extern isr_t gpf_isr;
extern isr_t pff_isr;
+enum {
+ F_ID = 0x00200000,
+ F_VIP = 0x00100000,
+ F_VIF = 0x00080000,
+ F_AC = 0x00040000,
+ F_VM = 0x00020000,
+ F_RF = 0x00010000,
+ F_NT = 0x00004000,
+ F_OF = 0x00000800,
+ F_DF = 0x00000400,
+ F_IF = 0x00000200,
+ F_TF = 0x00000100,
+ F_SF = 0x00000080,
+ F_ZF = 0x00000040,
+ F_AF = 0x00000010,
+ F_PF = 0x00000004,
+ F_CF = 0x00000001,
+
+ F_IOPL_MASK = 0x00003000
+};
+
__attribute__ ((noreturn))
-void exception_halt(const char *id, uint32_t code, uint32_t eip, uint32_t cs) {
- char nbuf[11];
-
- set_log_mode(LOG_PANIC);
- logsz("Exception #");
- logsz(id);
- logsz(" at 0x");
- u8_hex(cs, nbuf);
- logsz(nbuf);
- logsz(":0x");
- u32_hex(eip, nbuf);
- logsz(nbuf);
-
- logsz("\nerror code = 0x");
- u32_hex(code, nbuf);
- logsz(nbuf);
-
- logsz("\ntask name = ");
- logsz(active_task->name);
-
- logsz("\ncr3 = 0x");
- uint32_t cr3;
- asm (
- "mov %%cr3, %0"
- : "=r" (cr3));
- u32_hex(cr3, nbuf);
- logsz(nbuf);
-
- logsz("\nHalting.");
- while (1)
- asm ("hlt");
+void exception_halt(uint32_t eax, uint32_t ebx, uint32_t ecx,
+ uint32_t edx, uint32_t esi, uint32_t edi,
+ const char *id, uint32_t code,
+ uint32_t eip, uint32_t cs, uint32_t eflags,
+ uint32_t esp, uint32_t ss) {
+ if (code)
+ logf(LOG_ERROR, "Exception #%s (0x%h) in %s", id, code, active_task->name);
+ else
+ logf(LOG_ERROR, "Exception #%s in %s:", id, active_task->name);
+ logf(LOG_ERROR, " cs: 0x%hb ss: 0x%hb", cs, ss);
+ logf(LOG_ERROR, " eip: 0x%h esp: 0x%h", eip, esp);
+ logf(LOG_ERROR, " eax: 0x%h ebx: 0x%h", eax, ebx);
+ logf(LOG_ERROR, " ecx: 0x%h edx: 0x%h", ecx, edx);
+ logf(LOG_ERROR, " esi: 0x%h edi: 0x%h", esi, edi);
+ logf(LOG_ERROR, " eflags:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ eflags & F_ID ? " ID" : "", eflags & F_VIP ? " VIP" : "",
+ eflags & F_VIF ? " VIF" : "", eflags & F_AC ? " AC" : "",
+ eflags & F_VM ? " VM" : "", eflags & F_RF ? " RF" : "",
+ eflags & F_NT ? " NT" : "", eflags & F_OF ? " OF" : "",
+ eflags & F_DF ? " DF" : "", eflags & F_IF ? " IF" : "",
+ eflags & F_TF ? " TF" : "", eflags & F_SF ? " SF" : "",
+ eflags & F_ZF ? " ZF" : "", eflags & F_AF ? " AF" : "",
+ eflags & F_PF ? " PF" : "", eflags & F_CF ? " CF" : "",
+ eflags & ~F_IOPL_MASK ? "" : " none");
+ logf(LOG_ERROR, " iopl: %d", (eflags >> 12) & 3);
+
+ logf(LOG_INFO, "Killing %s.", active_task->name);
+ quit_isr();
+ __builtin_unreachable();
+}
+
+//returns true if stack was expanded
+bool pf_check_stack(uint32_t cr2/*, uint32_t edx, uint32_t ecx, uint32_t eax,
+ uint32_t code, uint32_t eip*/) {
+//logf(LOG_INFO, "page fault in %s at 0x%h trying to access 0x%h", active_task->name, eip, cr2);
+//logf(LOG_INFO, "stack bottom is 0x%h", active_task->stack_bottom);
+
+ if (cr2 >= active_task->stack_bottom - 0x1000) {
+ //logf(LOG_INFO, "expanding stack");
+ switch_to_kernel_cr3();
+ pd_user_allocate(active_task->page_directory, active_task->stack_bottom -= 4096, 1, true);
+ switch_to_task_cr3();
+ //logf(LOG_INFO, "new stack bottom is 0x%h", active_task->stack_bottom);
+ return true;
+ }
+ else {
+ logf(LOG_ERROR, "Illegal access of 0x%h", cr2);
+ return false;
+ }
}
static void register_int(uint8_t n, isr_t *isr, uint8_t dpl) {
@@ -231,4 +315,4 @@ void init_idt() {
asm volatile (
"lidt %0"
: : "m" (idtr) : "al");
-} \ No newline at end of file
+}
diff --git a/src/kernel/isrs.asm b/src/kernel/isrs.asm
index 472bb40..02b046d 100644
--- a/src/kernel/isrs.asm
+++ b/src/kernel/isrs.asm
@@ -22,8 +22,9 @@ extern advance_active_task
extern on_kbd_isr
extern make_sure_tasks
extern exception_halt
+extern pf_check_stack
-n_syscalls equ 0x10
+n_syscalls equ 0x19
;section .bss
;_debug_is_start_task resb 1
@@ -149,30 +150,59 @@ kbd_isr:
udf_isr:
push 0
push udid
- call exception_halt
+ jmp exception
dfa_isr:
push dfid
- call exception_halt
+ jmp exception
tsf_isr:
push tsid
- call exception_halt
+ jmp exception
npf_isr:
push npid
- call exception_halt
+ jmp exception
ssf_isr:
push ssid
- call exception_halt
+ jmp exception
gpf_isr:
push gpid
- call exception_halt
+ jmp exception
pff_isr:
+ push eax
+ push ecx
+ push edx
+
+ mov eax, cr2
+ push eax
+ call pf_check_stack
+ add esp, 4
+
+ pop edx
+ pop ecx
+ test eax, eax
+ jz .not_stack
+
+ pop eax
+ add esp, 4
+ iret
+
+.not_stack:
+ pop eax
push pfid
+ jmp exception
+
+exception:
+ push edi
+ push esi
+ push edx
+ push ecx
+ push ebx
+ push eax
call exception_halt
section .rodata
diff --git a/src/kernel/kbd.c b/src/kernel/kbd.c
index 8808b74..29c0350 100644
--- a/src/kernel/kbd.c
+++ b/src/kernel/kbd.c
@@ -1,14 +1,14 @@
#include <stdint.h>
+
+#include "window.h"
+#include "drive.h"
#include "panic.h"
+#include "pmap.h"
#include "util.h"
+#include "kbd.h"
-static uint32_t *kbd_in_pointer;
-static uint32_t *kbd_out_pointer;
-
-#define KBD_BUFFER_LENGTH 1024
-static uint32_t kbd_buffer[KBD_BUFFER_LENGTH];
-
-static uint32_t mod_mask;
+#define SCANTAB_DIR "sys/scantabs"
+#define LAYOUT_HARDCODE_TMP "qwerty"
enum {
PS2_CMD = 0x64,
@@ -30,274 +30,178 @@ enum {
PS2G_XT_COMPAT = 0x40
};
-void init_kbd() {
- outb(PS2_CMD, PS2C_READ_CONFIG);
- uint8_t config = inb(PS2_DATA);
- outb(PS2_CMD, PS2C_WRITE_CONFIG);
- outb(PS2_DATA, config | PS2G_XT_COMPAT);
-
- kbd_in_pointer = kbd_buffer;
- kbd_out_pointer = kbd_buffer;
- mod_mask = 0;
-}
-
-uint32_t get_key_code() {
- if (kbd_in_pointer == kbd_out_pointer)
- return 0;
- uint32_t code = *kbd_out_pointer;
- if (++kbd_out_pointer == kbd_buffer + KBD_BUFFER_LENGTH)
- kbd_out_pointer = kbd_buffer;
- return code;
-}
+static uint32_t n_scantabs;
-enum {
- MOD_LSHIFT = 0x00100,
- MOD_RSHIFT = 0x00200,
- MOD_CAPS = 0x00400,
- MOD_INSERT = 0x00800,
- MOD_NUMPAD = 0x01000,
- MOD_SCROLL = 0x02000,
- MOD_LALT = 0x04000,
- MOD_RALT = 0x08000,
- MOD_LCTRL = 0x10000,
- MOD_RCTRL = 0x20000,
- MOD_LMETA = 0x40000,
- MOD_RMETA = 0x80000
-};
+static struct scantab_info {
+ uint8_t *scantab;
+ uint8_t prefix_length;
+ uint8_t prefix[256];
+} *scantabs;
enum {
- CODE_CAPS = 0x80,
- CODE_INSERT,
- CODE_NUMPAD,
- CODE_SCROLL,
- CODE_LSHIFT,
- CODE_RSHIFT,
- CODE_LALT,
- CODE_RALT,
- CODE_LCTRL,
- CODE_RCTRL,
- CODE_LMETA,
- CODE_RMETA,
- /* 0x8c - 0x97 reserved */
- /* 0x98 - 0x9f unassigned */
- CODE_F1 = 0xa0,
- CODE_F2,
- CODE_F3,
- CODE_F4,
- CODE_F5,
- CODE_F6,
- CODE_F7,
- CODE_F8,
- CODE_F9,
- CODE_F10,
- CODE_F11,
- CODE_F12,
- /* 0xac - 0xaf unassigned */
- CODE_NUM0 = 0xb0,
- CODE_NUM1,
- CODE_NUM2,
- CODE_NUM3,
- CODE_NUM4,
- CODE_NUM5,
- CODE_NUM6,
- CODE_NUM7,
- CODE_NUM8,
- CODE_NUM9,
- CODE_NTIMES,
- CODE_NPLUS,
- CODE_NENTER,
- CODE_NMINUS,
- CODE_NDOT,
- CODE_NSLASH,
- /* 0xc0 unassigned */
- CODE_DELETE = 0xc1,
- CODE_HOME,
- CODE_END,
- CODE_PUP,
- CODE_PDOWN,
- CODE_UP,
- CODE_DOWN,
- CODE_LEFT,
- CODE_RIGHT,
- CODE_ESC,
- CODE_MENU,
- CODE_PAUSE,
- CODE_PRSCR,
- /* 0xce - 0xef unassigned */
- CODE_END_LSHIFT = 0xf0,
- CODE_END_RSHIFT,
- CODE_END_LALT,
- CODE_END_RALT,
- CODE_END_LCTRL,
- CODE_END_RCTRL,
- CODE_END_LMETA,
- CODE_END_RMETA
+ ST_ILLEGAL,
+ ST_SUBTABLE,
+ ST_FLIP,
+ ST_SKIP
};
-static const uint32_t mod_bits[] = {
- MOD_CAPS,
- MOD_INSERT,
- MOD_NUMPAD,
- MOD_SCROLL,
- MOD_LSHIFT,
- MOD_RSHIFT,
- MOD_LALT,
- MOD_RALT,
- MOD_LCTRL,
- MOD_RCTRL,
- MOD_LMETA,
- MOD_RMETA
-};
+void init_kbd() {
+ outb(PS2_CMD, PS2C_READ_CONFIG);
+ uint8_t config = inb(PS2_DATA);
+ outb(PS2_CMD, PS2C_WRITE_CONFIG);
+ outb(PS2_DATA, config | PS2G_XT_COMPAT);
-static const uint32_t *const unmod_bits = mod_bits + 4;
+ //TODO: get layout from some config file
+ file_id_t stf = drives->get_file(drives, SCANTAB_DIR "/" LAYOUT_HARDCODE_TMP ".sct");
-//in these tables, 0x00 represents an unknown key,
-// and 0xff represents a key release.
+ fmcpy(&n_scantabs, drives, stf, 0, 4);
+ scantabs = allocate_kernel_pages((sizeof(struct scantab_info) * n_scantabs - 1) / 4096 + 1);
+ uint32_t fi = 0x10;
+ void *st_data = allocate_kernel_pages((n_scantabs - 1) / 8 + 1);
-static const uint8_t codes[] = {
- 0, CODE_ESC, '1', '2', '3', '4', '5', '6',
- '7', '8', '9', '0', '-', '=', '\b', '\t',
- 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
- 'o', 'p', '[', ']', '\n', CODE_LCTRL, 'a', 's',
- 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
- '\'', '`', CODE_LSHIFT, '\\', 'z', 'x', 'c', 'v',
- 'b', 'n', 'm', ',', '.', '/', CODE_RSHIFT, CODE_NTIMES,
- CODE_LALT, ' ', CODE_CAPS, CODE_F1, CODE_F2, CODE_F3, CODE_F4, CODE_F5,
- CODE_F6, CODE_F7, CODE_F8, CODE_F9, CODE_F10, CODE_NUMPAD, CODE_SCROLL, CODE_NUM7,
- CODE_NUM8, CODE_NUM9, CODE_NMINUS, CODE_NUM4, CODE_NUM5, CODE_NUM6, CODE_NPLUS, CODE_NUM1,
- CODE_NUM2, CODE_NUM3, CODE_NUM0, CODE_NDOT, 0, 0, 0, CODE_F11,
- CODE_F12, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
+ for (uint32_t n = 0; n < n_scantabs; ++n) {
+ uint32_t data_sector;
+ fmcpy(&data_sector, drives, stf, fi, 4);
+ drives->load_sector(drives, stf, data_sector, st_data + 512 * n);
+ scantabs[n].scantab = st_data + 512 * n;
- 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, CODE_END_LCTRL, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, CODE_END_LSHIFT, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, CODE_END_RSHIFT, 0xff,
- CODE_END_LALT, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0xff,
- 0xff, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0
-};
+ uint8_t pl;
+ fmcpy(&pl, drives, stf, fi + 4, 1);
+ scantabs[n].prefix_length = pl;
+ fmcpy(scantabs[n].prefix, drives, stf, fi + 5, pl);
-static const uint8_t codes_e0[] = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, CODE_NENTER, CODE_RCTRL, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, CODE_NSLASH, 0, 0,
- CODE_RALT, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, CODE_HOME,
- CODE_UP, CODE_PUP, 0, CODE_LEFT, 0, CODE_RIGHT, 0, CODE_END,
- CODE_DOWN, CODE_PDOWN, CODE_INSERT, CODE_DELETE, 0, 0, 0, 0,
- 0, 0, 0, CODE_LMETA, CODE_RMETA, CODE_MENU, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
+ fi += 5 + pl;
+ if (fi & 0xf)
+ fi = (fi & ~0xf) + 0x10;
+ }
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0xff, CODE_END_RCTRL, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0xff, 0, 0,
- CODE_END_RALT, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0xff,
- 0xff, 0xff, 0, 0xff, 0, 0xff, 0, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0,
- 0, 0, 0, CODE_END_LMETA, CODE_END_RMETA, 0xff, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0
-};
+ drives->free_file(drives, stf);
+}
-#include "log.h"
-uint8_t get_code_byte() {
+static inline uint8_t get_next_code_byte() {
for (uint32_t spin = 0; spin < 10000000; ++spin)
;
return inb(PS2_DATA);
}
+static enum key_modifiers_t keymods = 0;
+
void on_kbd_isr() {
+//logf(LOG_INFO, "on_kbd_isr()");
while (inb(PS2_CMD) & PS2S_CODE_READY) {
- //char nbuf[11];
- uint8_t code = get_code_byte();
- //logsz("code: 0x");
- //u8_hex(code, nbuf);
- //logsz(nbuf);
- if (code == 0xe1) {
- code = get_code_byte();
- //logsz(" 0x");
- //u8_hex(code, nbuf);
- //logsz(nbuf);
- if (code == 0x1d) {
- if (get_code_byte() != 0x45)
- code = 0;
- else
- code = CODE_PAUSE;
- }
- else if (code == 0x9d) {
- if (get_code_byte() != 0xc5)
- code = 0;
- else
- code = 0xff;
- }
- else
- code = 0;
+ uint8_t code[256];
+ uint8_t code_i = 0;
+ sub_table:
+ code[code_i] = get_next_code_byte();
+ const uint8_t *table;
+ for (uint32_t i = 0; i < n_scantabs; ++i) {
+ if (scantabs[i].prefix_length != code_i)
+ continue;
+ for (uint8_t j = 0; j < code_i; ++j)
+ if (scantabs[i].prefix[j] != code[j])
+ goto next_table;
+ table = scantabs[i].scantab;
+ goto got_table;
+ next_table:;
}
- else if (code == 0xe0) {
- code = get_code_byte();
- //logsz(" 0x");
- //u8_hex(code, nbuf);
- //logsz(nbuf);
- if (code == 0x2a) {
- if ((get_code_byte() != 0xe0) ||
- (get_code_byte() != 0x37))
- code = 0;
- else
- code = CODE_PRSCR;
- }
- else if (code == 0xb7) {
- if ((get_code_byte() != 0xe0) ||
- (get_code_byte() != 0xaa))
- code = 0;
- else
- code = 0xff;
- }
- else
- code = codes_e0[code];
+ PANIC("Couldn't find scantable");
+
+ got_table:;
+ bool is_up = false;
+ flipped_table:;
+ uint8_t entry = table[code[code_i]];
+ switch (entry) {
+ case ST_ILLEGAL:
+ PANIC("Illegal scancode encountered");
+ case ST_SUBTABLE:
+ ++code_i;
+ goto sub_table;
+ case ST_FLIP:
+ if (is_up)
+ PANIC("Recursive flip in scantable");
+ table += 0x100;
+ is_up = true;
+ goto flipped_table;
+ case ST_SKIP:
+ continue;
}
- else
- code = codes[code];
- //logch('\n');
-
- if (!code)
- PANIC("Unknown scancode.");
+ switch ((enum key_id_t)entry) {
+ case KEY_LEFT_SHIFT:
+ if (is_up)
+ keymods &= ~LSHIFT;
+ else
+ keymods |= LSHIFT;
+ break;
+ case KEY_RIGHT_SHIFT:
+ if (is_up)
+ keymods &= ~RSHIFT;
+ else
+ keymods |= RSHIFT;
+ break;
+ case KEY_LEFT_CONTROL:
+ if (is_up)
+ keymods &= ~LCTRL;
+ else
+ keymods |= LCTRL;
+ break;
+ case KEY_RIGHT_CONTROL:
+ if (is_up)
+ keymods &= ~RCTRL;
+ else
+ keymods |= RCTRL;
+ break;
+ case KEY_LEFT_ALT:
+ if (is_up)
+ keymods &= ~LALT;
+ else
+ keymods |= LALT;
+ break;
+ case KEY_RIGHT_ALT:
+ if (is_up)
+ keymods &= ~RALT;
+ else
+ keymods |= RALT;
+ break;
+ case KEY_LEFT_WIN:
+ if (is_up)
+ keymods &= ~LWIN;
+ else
+ keymods |= LWIN;
+ break;
+ case KEY_RIGHT_WIN:
+ if (is_up)
+ keymods &= ~RWIN;
+ else
+ keymods |= RWIN;
+ break;
+ case KEY_CAPS_LOCK:
+ if (!is_up)
+ keymods ^= CAPS;
+ break;
+ case KEY_NUM_LOCK:
+ if (!is_up)
+ keymods ^= NUM;
+ break;
+ case KEY_SCROLL_LOCK:
+ if (!is_up)
+ keymods ^= SCROLL;
+ break;
+ case KEY_INSERT:
+ if (!is_up)
+ keymods ^= INSERT;
+ break;
+ default:
+ break;
+ }
- if (code < 0xf0)
- *kbd_in_pointer++ = mod_mask | code;
- if ((code >= 0x80) && (code <= 0x83))
- mod_mask ^= mod_bits[code & 0x03];
- else if ((code >= 0x84) && (code <= 0x8b))
- mod_mask |= mod_bits[code & 0x0f];
- else if (code >= 0xf0)
- mod_mask &= ~unmod_bits[code & 0x0f];
+ on_action((struct window_action){
+ .action_type = is_up ? KEY_UP : KEY_DOWN,
+ .as_key = (struct key_packet){
+ .key_id = entry,
+ .modifiers = keymods
+ }
+ });
}
-} \ No newline at end of file
+}
diff --git a/src/kernel/kbd.h b/src/kernel/kbd.h
index 8a4ed8b..e9affad 100644
--- a/src/kernel/kbd.h
+++ b/src/kernel/kbd.h
@@ -3,8 +3,9 @@
#include <stdint.h>
+#include <keypack.h>
+
void init_kbd();
-uint32_t get_key_code();
void on_kbd_isr();
-#endif \ No newline at end of file
+#endif
diff --git a/src/kernel/log.c b/src/kernel/log.c
index b5a96cb..8ef2baf 100644
--- a/src/kernel/log.c
+++ b/src/kernel/log.c
@@ -1,33 +1,92 @@
-#include "vga.h"
+#include <stdarg.h>
+#include <stdbool.h>
+
#include "serial.h"
#include "log.h"
#define LOG_COM COM1
-static const uint8_t log_mode_colors[] = {
- 0x30,
- 0x07,
- 0x4f
+void init_log() {
+ //TODO: move old "sys/current.log"
+ //TODO: open new "sys/current.log"
+}
+
+static const char *const log_prefixes[] = {
+ " [USER] ",
+ " [INFO] ",
+ " [WARN] ",
+ "[ERROR] ",
+ "[PANIC] ",
};
-void set_log_mode(enum log_mode mode) {
- vga_set_color(log_mode_colors[mode]);
- vga_printch('\n');
- vga_printch('\n');
+static inline void logch(char ch) {
+ sout(LOG_COM, ch);
+ //TODO: write to log file as well
}
-void logch(char ch) {
- if (ch == '\n') {
- sout(LOG_COM, (uint8_t)'\r');
- sout(LOG_COM, (uint8_t)'\n');
- }
- else
- sout(LOG_COM, (uint8_t)ch);
+static const char hex_table[] = "0123456789abcdef";
- vga_printch(ch);
-}
+void logf(enum log_level level, const char *format, ...) {
+ va_list args;
+ va_start(args, format);
-void logsz(const char *sz) {
- while (*sz)
- logch(*sz++);
-} \ No newline at end of file
+ const char *log_prefix = log_prefixes[level];
+ while (*log_prefix)
+ logch(*(log_prefix++));
+
+ for (const char *fi = format; *fi;)
+ if (*fi != '%')
+ logch(*(fi++));
+ else {
+ switch (*(fi + 1)) {
+ case '%':
+ logch('%');
+ break;
+ case 's':;
+ const char *s = va_arg(args, const char *);
+ while (*s)
+ logch(*(s++));
+ break;
+ case 'd':;
+ const uint32_t d = va_arg(args, uint32_t);
+ if (d == 0) {
+ logch('0');
+ break;
+ }
+ bool zeros = false;
+ for (uint32_t place = 1000000000; place; place /= 10) {
+ uint8_t digit = (d / place) % 10;
+ if (digit)
+ zeros = true;
+ if (zeros)
+ logch(digit | '0');
+ }
+ break;
+ case 'h':;
+ const uint32_t h = va_arg(args, uint32_t);
+ uint32_t shift = 32;
+ if (*(fi + 2) == 'b') {
+ shift = 8;
+ ++fi;
+ }
+ else if (*(fi + 2) == 'w') {
+ shift = 16;
+ ++fi;
+ }
+ else if (*(fi + 2) == 'd') {
+ ++fi;
+ }
+ while (shift)
+ logch(hex_table[(h >> (shift -= 4)) & 0xf]);
+ break;
+ default:
+ logch('%');
+ logch(*(fi + 1));
+ }
+ fi += 2;
+ }
+
+ logch('\n');
+
+ va_end(args);
+}
diff --git a/src/kernel/log.h b/src/kernel/log.h
index 90a94f4..c5c4da7 100644
--- a/src/kernel/log.h
+++ b/src/kernel/log.h
@@ -1,16 +1,17 @@
#ifndef LOG_H
#define LOG_H
-enum log_mode {
- LOG_SYSTEM,
+#include <stdarg.h>
+
+enum log_level {
LOG_USER,
+ LOG_INFO,
+ LOG_WARN,
+ LOG_ERROR,
LOG_PANIC
};
void init_log();
-void set_log_mode(enum log_mode mode);
-
-void logch(char ch);
-void logsz(const char *sz);
+void logf(enum log_level level, const char *format, ...);
-#endif \ No newline at end of file
+#endif
diff --git a/src/kernel/main.c b/src/kernel/main.c
index b34f816..26cc5e4 100644
--- a/src/kernel/main.c
+++ b/src/kernel/main.c
@@ -1,7 +1,8 @@
#include <stdint.h>
+#include "paging.h"
#include "serial.h"
+#include "window.h"
#include "panic.h"
-#include "paging.h"
#include "boot.h"
#include "util.h"
#include "fat.h"
@@ -12,57 +13,19 @@
#include "pci.h"
#include "elf.h"
#include "log.h"
-#include "vga.h"
#include "kbd.h"
void _start_user_mode() __attribute__ ((noreturn));
__attribute__ ((noreturn))
void main() {
- char nbuf[11];
-
init_pagemap();
init_paging();
init_tasks();
init_serial();
- set_log_mode(LOG_SYSTEM);
- vga_blank();
-
- logsz("Portland v0.0.11\n\n");
pci_init();
-/*
- u16_dec(n_pci_devices, nbuf);
- logsz(nbuf);
- logsz(" PCI device(s) found:\n");
-
- for (uint16_t n = 0; n < n_pci_devices; ++n) {
- struct pci_device *pd = nth_pci_device(n);
-
- u16_hex(pd->number, nbuf);
- logsz(" ");
- logsz(nbuf);
- logsz(": ");
-
- u16_hex(pd->id_vendor, nbuf);
- nbuf[4] = '.';
- u16_hex(pd->id_device, nbuf + 5);
- logsz(nbuf);
-
- u8_hex(pd->class, nbuf);
- nbuf[2] = '.';
- u8_hex(pd->subclass, nbuf + 3);
- nbuf[5] = '.';
- u8_hex(pd->iface, nbuf + 6);
- logsz(" (");
- logsz(nbuf);
- logsz(")\n");
- }
-
- logch('\n');
-*/
-
init_fat();
//other fs drivers
@@ -71,65 +34,36 @@ void main() {
init_ide();
//other drive drivers
-/*
- u8_dec(n_drives, nbuf);
- logsz(nbuf);
- logsz(" drive(s) found:\n");
-
- for (uint8_t n = 0; n < n_drives; ++n) {
- struct drive *d = drives + n;
-
- u8_dec(n, nbuf);
- logsz(" sd");
- logsz(nbuf);
- logsz(" (");
- logsz(d->drive_type);
- logsz(", ");
-
- u32_dec(d->n_sectors / 2, nbuf);
- logsz(nbuf);
- if (d->n_sectors % 2)
- logsz(".5");
- logsz("k): ");
-
- logsz(d->fs_type);
-
- uint32_t free_sectors = d->get_free_sectors(d);
- if (free_sectors != -1) {
- u32_dec(free_sectors / 2, nbuf);
- logsz(", ");
- logsz(nbuf);
- if (free_sectors % 2)
- logsz(".5");
- logsz("k free");
- }
-
- logsz(".\n");
- }
+ init_log();
- logch('\n');
-*/
+ init_kbd();
+ init_idt();
+
+ paint_bg();
+
+ logf(LOG_INFO, "Kernel initialization done.");
+ logf(LOG_INFO, "Available kernel memory: %dk", kernel_pages_left * 4);
+ logf(LOG_INFO, "Available user memory: %dk", user_pages_left * 4);
+
+ logf(LOG_INFO, "PCI devices:");
+ for (uint16_t i = 0; i < n_pci_devices; ++i) {
+ const struct pci_device *dev = nth_pci_device(i);
+ logf(LOG_INFO, " %hw:%hw (%hb:%hb)", dev->id_vendor, dev->id_device, dev->class, dev->subclass);
+ }
- if (BOOT_INFO->support_flags & BIS_PAE)
- logsz("Processor supports PAE (but Portland OS does not yet).\n");
- else
- logsz("Processor does not support PAE.\n");
+ logf(LOG_INFO, "Drives:");
+ for (uint8_t i = 0; i < n_drives; ++i) {
+ const struct drive *d = &drives[i];
+ const uint32_t free = d->get_free_sectors(d);
+ logf(LOG_INFO, " %s: %d%sk, %s (%d%sk free)", d->drive_type, d->n_sectors / 2, d->n_sectors % 2 ? ".5" : "", d->fs_type, free / 2, free % 2 ? ".5" : "");
+ }
- logsz("Kernel dynamic area size: ");
- u32_dec(max_kernel_pages * 4, nbuf);
- logsz(nbuf);
- logsz("k\nUserspace area size: ");
- u32_dec(max_user_pages * 4, nbuf);
- logsz(nbuf);
- logsz("k\n\n");
+ logf(LOG_INFO, "Loading init program.");
- if (!try_elf_run(drives, "bin/init", ""))
+ if (!try_elf_run(drives, "bin/init", "", 0))
PANIC("Failed to load init program.");
- init_kbd();
- init_idt();
+ logf(LOG_INFO, "Switching to init task.");
- logsz("Switching to init task.\n");
- set_log_mode(LOG_USER);
_start_user_mode();
} \ No newline at end of file
diff --git a/src/kernel/panic.c b/src/kernel/panic.c
index 5d32bf7..49fdac1 100644
--- a/src/kernel/panic.c
+++ b/src/kernel/panic.c
@@ -1,19 +1,11 @@
+#include <stdint.h>
+
#include "log.h"
-#include "vga.h"
-#include "util.h"
__attribute__ ((noreturn))
void panic(const char *filename, uint32_t line, const char *message) {
- set_log_mode(LOG_PANIC);
- vga_blank();
- logsz("Kernel panic [");
- logsz(filename);
- char nbuf[12] = ":";
- u32_dec(line, nbuf + 1);
- logsz(nbuf);
- logsz("]: ");
- logsz(message);
- logsz("\nHalting.");
+ logf(LOG_PANIC, "[%s:%d] %s", filename, line, message);
+ logf(LOG_INFO, "Halting");
while (1)
asm volatile ("hlt");
-} \ No newline at end of file
+}
diff --git a/src/kernel/pmap.h b/src/kernel/pmap.h
index 1016de3..ae58a6c 100644
--- a/src/kernel/pmap.h
+++ b/src/kernel/pmap.h
@@ -14,4 +14,4 @@ void *allocate_kernel_pages(uint32_t n) __attribute__ ((malloc));
void *allocate_user_pages(uint32_t n) __attribute__ ((malloc));
void free_pages(const void *ptr, uint32_t n);
-#endif \ No newline at end of file
+#endif
diff --git a/src/kernel/serial.c b/src/kernel/serial.c
index c492e1e..93bb081 100644
--- a/src/kernel/serial.c
+++ b/src/kernel/serial.c
@@ -78,8 +78,8 @@ void sout(enum serial_port n, uint8_t b) {
serial_spin_t spinner = -1;
while (!(inb(ports[n] | CP_LINE_S) & CLS_WRITE))
if (--spinner) {
- error[n] = true;
- return;
+ //error[n] = true;
+ //return;
}
outb(ports[n] | CP_DATA, b);
}
@@ -90,4 +90,4 @@ uint8_t sin(enum serial_port n) {
while (!(inb(ports[n] | CP_LINE_S) & CLS_READ))
;//spin
return inb(ports[n] | CP_DATA);
-} \ No newline at end of file
+}
diff --git a/src/kernel/task.c b/src/kernel/task.c
index 942d1c4..ab08e6b 100644
--- a/src/kernel/task.c
+++ b/src/kernel/task.c
@@ -1,6 +1,8 @@
+#include "paging.h"
#include "panic.h"
+#include "pmap.h"
#include "task.h"
-#include "paging.h"
+#include "util.h"
#include "log.h"
struct tss {
@@ -42,7 +44,7 @@ struct tss {
#define MAX_TASKS 64
-static struct task_state tasks[MAX_TASKS];
+struct task_state tasks[MAX_TASKS];
struct task_state *active_task;
void init_tasks() {
@@ -68,31 +70,68 @@ uint32_t new_task(struct task_state state) {
for (uint8_t n = 0; n < MAX_TASKS; ++n)
if (!tasks[n].page_directory) {
tasks[n] = state;
+ tasks[n].waiting = false;
+ for (uint8_t i = 0; i < MAX_WAITS; ++i)
+ tasks[n].waits[i].mode = NONE;
return n + 1;
}
PANIC("Maximum number of tasks reached.");
}
+static void tmp_halt() {
+//logf(LOG_INFO, "scheduler halting");
+ TSS->esp0 = 0x0003c000;
+ asm("sti\n"
+ "hlt\n"
+ "cli");
+ TSS->esp0 = 0x00040000;
+//logf(LOG_INFO, "scheduler resumed");
+}
+
void advance_active_task() {
- do
+//logf(LOG_INFO, "entered scheduler from \"%s\"", active_task->name);
+ struct task_state *old_task = active_task;
+ while (1) {
if (++active_task == tasks + MAX_TASKS)
active_task = tasks;
- while (!active_task->page_directory || active_task->wait_mode);
+ if (active_task->page_directory && !active_task->waiting) {
+ //logf(LOG_INFO, "exiting scheduler to \"%s\"", active_task->name);
+ return;
+ }
+ if (active_task == old_task)
+ tmp_halt();
+ }
}
void make_sure_tasks() {
for (uint8_t n = 0; n < MAX_TASKS; ++n)
if (tasks[n].page_directory)
- while (1) {
- for (uint8_t n = 0; n < MAX_TASKS; ++n)
- if (tasks[n].page_directory && !tasks[n].wait_mode)
- return;
- asm ("hlt");
- }
- set_log_mode(LOG_SYSTEM);
- logsz("No tasks, halting.");
+ return;
+ logf(LOG_INFO, "No tasks, halting.");
while (1)
- asm ("hlt");
+ asm("hlt");
+}
+
+//IPC stuff isn't fully implemented, or tested in this version.
+//i'm planning to finish and make use of it in the next version,
+//making the terminal its own application instead of a library.
+
+#define MAX_IPC_PIPES 1024
+#define IPC_BUFFER_PAGES 1
+
+struct ipc_pipe {
+ void *buffer;
+ void *buffer_next_send;
+ const void *buffer_next_read;
+
+ uint32_t sender_handle;
+ uint32_t reader_handle;
+ bool delete_when_empty;
+} ipc_pipes[MAX_IPC_PIPES];
+
+void delete_pipe(struct ipc_pipe *pipe) {
+ free_pages(pipe->buffer, IPC_BUFFER_PAGES);
+ pipe->buffer = 0;
}
void delete_task(struct task_state *state) {
@@ -101,10 +140,136 @@ void delete_task(struct task_state *state) {
switch_to_task_cr3();
state->page_directory = 0;
- uint32_t handle = state - tasks + 1;
- for (uint8_t n = 0; n < MAX_TASKS; ++n)
- if (tasks[n].page_directory &&
- (tasks[n].wait_mode == PROCESS_END) &&
- (tasks[n].wait_arg == handle))
- tasks[n].wait_mode = NONE;
+ unwait_any((struct wait){.mode = PROCESS_END, .task = state});
+ unwait_any((struct wait){.mode = IPC_RECEIVE, .task = state});
+ unwait_any((struct wait){.mode = IPC_SEND, .task = state});
+
+ const uint32_t handle = active_task - tasks + 1;
+ for (struct ipc_pipe *pipe = ipc_pipes; pipe < ipc_pipes + MAX_IPC_PIPES; ++pipe)
+ if (pipe->buffer) {
+ if (pipe->reader_handle == handle)
+ delete_pipe(pipe);
+ else if (pipe->sender_handle == handle) {
+ if (pipe->buffer_next_read == pipe->buffer_next_send)
+ delete_pipe(pipe);
+ else
+ pipe->delete_when_empty = true;
+ }
+ }
+}
+
+uint32_t find_unread_ipc() {
+ const uint32_t r_handle = active_task - tasks + 1;
+ for (struct ipc_pipe *pipe = ipc_pipes; pipe < ipc_pipes + MAX_IPC_PIPES; ++pipe)
+ if (pipe->buffer && (pipe->reader_handle == r_handle) &&
+ (pipe->buffer_next_read != pipe->buffer_next_send))
+ return pipe->sender_handle;
+ return 0;
+}
+
+struct ipc_pipe *get_existing_pipe(uint32_t sender_handle, uint32_t reader_handle) {
+ for (struct ipc_pipe *i = ipc_pipes; i < ipc_pipes + MAX_IPC_PIPES; ++i)
+ if (i->buffer && (i->sender_handle == sender_handle) &&
+ (i->reader_handle == reader_handle))
+ return i;
+ return 0;
+}
+
+uint32_t ipc_send(uint32_t reader_handle, uint32_t count, const void *buffer) {
+ if (!reader_handle || !tasks[reader_handle - 1].page_directory)
+ return -1;
+
+ const uint32_t our_handle = active_task - tasks + 1;
+ struct ipc_pipe *pipe = get_existing_pipe(our_handle, reader_handle);
+ if (!pipe) {
+ for (struct ipc_pipe *i = ipc_pipes; i < ipc_pipes + MAX_IPC_PIPES; ++i)
+ if (!i->buffer) {
+ i->buffer = allocate_kernel_pages(IPC_BUFFER_PAGES);
+ i->buffer_next_read = i->buffer;
+ i->buffer_next_send = i->buffer;
+ i->reader_handle = reader_handle;
+ i->sender_handle = our_handle;
+ i->delete_when_empty = false;
+ pipe = i;
+ break;
+ }
+ if (!pipe)
+ PANIC("out of ipc pipes");
+ }
+
+ unwait(tasks + reader_handle - 1, (struct wait){.mode = IPC_RECEIVE, .task = active_task});
+ unwait(tasks + reader_handle - 1, (struct wait){.mode = IPC_RECEIVE_ANY});
+
+ uint32_t send_left = pipe->buffer_next_read - pipe->buffer_next_send - 1;
+ if (send_left < 0)
+ send_left += 4096 * IPC_BUFFER_PAGES;
+ if (count > send_left)
+ count = send_left;
+
+ if (pipe->buffer_next_send + count < pipe->buffer + 4096 * IPC_BUFFER_PAGES) {
+ memcpy(pipe->buffer_next_send, buffer, count);
+ pipe->buffer_next_send += count;
+ return count;
+ }
+
+ const uint32_t first_batch = pipe->buffer + 4096 * IPC_BUFFER_PAGES - pipe->buffer_next_send;
+ memcpy(pipe->buffer_next_send, buffer, first_batch);
+ memcpy(pipe->buffer, buffer + first_batch, count - first_batch);
+ pipe->buffer_next_send += count - 4096;
+ return count;
+}
+
+uint32_t ipc_read(uint32_t sender_handle, uint32_t count, void *buffer) {
+ if (!sender_handle || !tasks[sender_handle - 1].page_directory)
+ return -1;
+
+ const uint32_t our_handle = active_task - tasks + 1;
+ struct ipc_pipe *pipe = get_existing_pipe(sender_handle, our_handle);
+ if (!pipe)
+ return 0;
+
+ unwait(tasks + sender_handle - 1, (struct wait){.mode = IPC_SEND, .task = active_task});
+
+ //TODO
+}
+
+void add_wait(struct wait wait) {
+ for (uint8_t i = 0; i < MAX_WAITS; ++i)
+ if (!active_task->waits[i].mode) {
+ active_task->waits[i] = wait;
+ active_task->waiting = true;
+ return;
+ }
+ PANIC("Out of waits for task.");
+}
+
+void unwait_any(struct wait wait) {
+ for (uint8_t i = 0; i < MAX_TASKS; ++i)
+ if (tasks[i].page_directory)
+ unwait(tasks + i, wait);
+}
+
+void unwait(struct task_state *task, struct wait wait) {
+ if (!task->waiting)
+ return;
+ for (uint8_t i = 0; i < MAX_WAITS; ++i) {
+ if (task->waits[i].mode != wait.mode)
+ continue;
+ switch (wait.mode) {
+ case PROCESS_END:
+ case IPC_RECEIVE:
+ if (task->waits[i].task != wait.task)
+ continue;
+ break;
+ case WINDOW_ACTION:
+ case IPC_RECEIVE_ANY:
+ break;
+ default:
+ PANIC("Unwait matched with unrecognized wait mode.");
+ }
+ for (uint8_t i = 0; i < MAX_WAITS; ++i)
+ task->waits[i].mode = NONE;
+ task->waiting = false;
+ return;
+ }
} \ No newline at end of file
diff --git a/src/kernel/task.h b/src/kernel/task.h
index 50be93a..574dfa7 100644
--- a/src/kernel/task.h
+++ b/src/kernel/task.h
@@ -5,10 +5,20 @@
#include <stdint.h>
#define TASK_NAME_LEN 15
-
-enum wait_mode {
- NONE,
- PROCESS_END,
+#define MAX_WAITS 16
+
+struct wait {
+ enum {
+ NONE,
+ PROCESS_END,
+ WINDOW_ACTION,
+ IPC_RECEIVE,
+ IPC_RECEIVE_ANY,
+ IPC_SEND
+ } mode;
+ union {
+ struct task_state *task;
+ };
};
struct task_state {
@@ -23,12 +33,19 @@ struct task_state {
uint32_t ebp;
uint32_t esp;
- enum wait_mode wait_mode;
- uint32_t wait_arg;
+ uint32_t stack_bottom;
+
+ struct wait waits[MAX_WAITS];
+ bool waiting;
char name[TASK_NAME_LEN + 1];
} __attribute__ ((packed));
+void add_wait(struct wait wait);
+void unwait_any(struct wait wait);
+void unwait(struct task_state *task, struct wait wait);
+
+extern struct task_state tasks[];
extern struct task_state *active_task;
void init_tasks();
@@ -38,4 +55,9 @@ void advance_active_task();
void delete_task(struct task_state *state);
+uint32_t ipc_send(uint32_t reader_handle, uint32_t count, const void *buffer);
+uint32_t ipc_read(uint32_t sender_handle, uint32_t count, void *buffer);
+
+uint32_t find_unread_ipc();
+
#endif \ No newline at end of file
diff --git a/src/kernel/util.c b/src/kernel/util.c
index 625622a..ea0496e 100644
--- a/src/kernel/util.c
+++ b/src/kernel/util.c
@@ -39,97 +39,4 @@ void fmcpy(void *to, const struct drive *d, file_id_t f, uint32_t from, uint32_t
d->load_sector(d, f, fsi, buf);
memcpy(to + i, buf, n);
-}
-
-void u32_dec(uint32_t n, char *b) {
- if (!n) {
- *(uint16_t *)b = (uint16_t)'0';
- return;
- }
- bool zero = false;
- for (uint32_t m = 1000000000; m; m /= 10) {
- uint8_t d = (n / m) % 10;
- if (zero)
- *(b++) = d + '0';
- else if (d) {
- zero = true;
- *(b++) = d + '0';
- }
- }
- *b = '\0';
-}
-
-void u16_dec(uint16_t n, char *b) {
- if (!n) {
- *(uint16_t *)b = (uint16_t)'0';
- return;
- }
- bool zero = false;
- for (uint32_t m = 10000; m; m /= 10) {
- uint8_t d = (n / m) % 10;
- if (zero)
- *(b++) = d + '0';
- else if (d) {
- zero = true;
- *(b++) = d + '0';
- }
- }
- *b = '\0';
-}
-
-void u8_dec(uint8_t n, char *b) {
- if (!n) {
- *(uint16_t *)b = (uint16_t)'0';
- return;
- }
- bool zero = false;
- for (uint32_t m = 100; m; m /= 10) {
- uint8_t d = (n / m) % 10;
- if (zero)
- *(b++) = d + '0';
- else if (d) {
- zero = true;
- *(b++) = d + '0';
- }
- }
- *b = '\0';
-}
-
-void u32_hex(uint32_t n, char *b) {
- uint8_t m = 28;
- while (1) {
- uint8_t d = (n >> m) & 0xf;
- *(b++) = d >= 10 ? 'a' + d - 10 : '0' + d;
- if (!m) {
- *b = '\0';
- return;
- }
- m -= 4;
- }
-}
-
-void u16_hex(uint16_t n, char *b) {
- uint8_t m = 12;
- while (1) {
- uint8_t d = (n >> m) & 0xf;
- *(b++) = d >= 10 ? 'a' + d - 10 : '0' + d;
- if (!m) {
- *b = '\0';
- return;
- }
- m -= 4;
- }
-}
-
-void u8_hex(uint8_t n, char *b) {
- uint8_t m = 4;
- while (1) {
- uint8_t d = (n >> m) & 0xf;
- *(b++) = d >= 10 ? 'a' + d - 10 : '0' + d;
- if (!m) {
- *b = '\0';
- return;
- }
- m -= 4;
- }
} \ No newline at end of file
diff --git a/src/kernel/util.h b/src/kernel/util.h
index 9fa8002..c5b784a 100644
--- a/src/kernel/util.h
+++ b/src/kernel/util.h
@@ -44,11 +44,11 @@ static inline uint32_t ind(uint16_t port) {
void memcpy(void *to, const void *from, uint32_t n);
void fmcpy(void *to, const struct drive *d, file_id_t f, uint32_t from, uint32_t n);
-void u32_dec(uint32_t n, char *b);
-void u16_dec(uint16_t n, char *b);
-void u8_dec(uint8_t n, char *b);
+uint8_t u32_dec(uint32_t n, char *b);
+uint8_t u16_dec(uint16_t n, char *b);
+uint8_t u8_dec(uint8_t n, char *b);
void u32_hex(uint32_t n, char *b);
void u16_hex(uint16_t n, char *b);
void u8_hex(uint8_t n, char *b);
-#endif \ No newline at end of file
+#endif
diff --git a/src/kernel/vga.c b/src/kernel/vga.c
deleted file mode 100644
index 6ae1588..0000000
--- a/src/kernel/vga.c
+++ /dev/null
@@ -1,52 +0,0 @@
-#include <stdbool.h>
-#include <stdint.h>
-
-#define VGA_COLUMNS 80
-#define VGA_ROWS 25
-#define VGA_START (uint16_t *)0x000b8000
-#define VGA_END (VGA_START + VGA_COLUMNS * VGA_ROWS)
-static uint16_t *cursor = VGA_START;
-static uint16_t mask;
-
-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);
- uint32_t f = (mask | (uint8_t)' ') * 0x00010001;
- for (uint32_t *i = (uint32_t *)(VGA_END - VGA_COLUMNS); i < (uint32_t *)VGA_END; ++i)
- *i = f;
- cursor -= VGA_COLUMNS;
-}
-
-void vga_blank() {
- uint32_t f = (mask | (uint8_t)' ') * 0x00010001;
- uint32_t *p = (uint32_t *)VGA_START;
- while (p < (uint32_t *)VGA_END)
- *p++ = f;
- cursor = VGA_END - VGA_COLUMNS;
-}
-
-void vga_printch(char ch) {
- if (ch == '\n')
- cursor = ((cursor - VGA_START) / VGA_COLUMNS + 1) * VGA_COLUMNS + VGA_START;
- else if (ch == '\b')
- *--cursor = mask | ' ';
- else
- *cursor++ = mask | (uint8_t)ch;
- if (cursor == VGA_END)
- vga_scroll();
-}
-
-void vga_print_at(uint16_t pos, const char *sz) {
- cursor = VGA_START + (pos >> 8) * VGA_COLUMNS + (pos & 0xff);
- while (*sz)
- vga_printch(*sz++);
-} \ No newline at end of file
diff --git a/src/kernel/vga.h b/src/kernel/vga.h
deleted file mode 100644
index dd1c906..0000000
--- a/src/kernel/vga.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef VGA_H
-#define VGA_H
-
-#include <stdint.h>
-
-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/kernel/window.c b/src/kernel/window.c
new file mode 100644
index 0000000..28798d1
--- /dev/null
+++ b/src/kernel/window.c
@@ -0,0 +1,253 @@
+#include "paging.h"
+#include "window.h"
+#include "drive.h"
+#include "task.h"
+#include "util.h"
+#include "pmap.h"
+#include "log.h"
+
+#define MAX_WINDOWS 64
+#define ACTION_BUFFER_PAGES 1
+#define AB_END(buf) (buf + (ACTION_BUFFER_PAGES * 4096) / sizeof(struct window_action))
+
+#define BACKGROUND(x, y) ((x / 16 + y / 16) % 2 ? 0x14 : 0x07)
+
+static struct window {
+ const volatile void *pixel_buffer_pma;
+ uint16_t width;
+ uint16_t height;
+
+ uint16_t xpos;
+ uint16_t ypos;
+
+ struct window_action *action_buffer;
+ struct window_action *next_action_read;
+ struct window_action *next_action_write;
+
+ struct window *above;
+ struct window *below;
+
+ struct task_state *from_task;
+} windows[MAX_WINDOWS];
+
+static struct window *bottom_window = 0;
+static struct window *top_window = 0;
+
+static inline void set_pix(uint16_t x, uint16_t y, uint8_t value) {
+ if ((x < 320) && (y < 200))
+ *(uint8_t *)(0xa0000 + y * 320 + x) = value;
+}
+
+static void paint_and_above(const struct window *w) {
+ switch_to_kernel_cr3();
+ for (const struct window *i = w; i; i = i->above)
+ for (uint16_t y = 0; y < i->height; ++y)
+ for (uint16_t x = 0; x < i->width; ++x) {
+ const uint8_t pixel = ((uint8_t *)i->pixel_buffer_pma)[y * i->width + x];
+ if (pixel)
+ set_pix(x + i->xpos, y + i->ypos, pixel);
+ }
+ switch_to_task_cr3();
+}
+
+void paint_bg() {
+ for (uint16_t y = 0; y < 200; ++y)
+ for (uint16_t x = 0; x < 320; ++x)
+ set_pix(x, y, BACKGROUND(x, y));
+}
+
+static void paint_all() {
+ paint_bg();
+ paint_and_above(bottom_window);
+}
+
+struct window *new_window(uint16_t width, uint16_t height, const void *pixel_buffer) {
+ if (!pixel_buffer) {
+ logf(LOG_WARN, "Refusing to create window with null pixel buffer for task %s.", active_task->name);
+ return 0;
+ }
+
+ struct window *w;
+ for (uint8_t i = 0; i < MAX_WINDOWS; ++i)
+ if (!windows[i].pixel_buffer_pma) {
+ w = &windows[i];
+ goto got_window;
+ }
+ return 0;
+got_window:
+
+ w->pixel_buffer_pma = vma_to_pma(active_task->page_directory, pixel_buffer);
+ w->width = width;
+ w->height = height;
+
+ struct window_action *const ab = allocate_kernel_pages(ACTION_BUFFER_PAGES);
+ w->action_buffer = ab;
+ w->next_action_read = ab;
+ w->next_action_write = ab;
+
+ if (top_window)
+ top_window->above = w;
+ else
+ bottom_window = w;
+ w->above = 0;
+ w->below = top_window;
+ top_window = w;
+
+ w->from_task = active_task;
+
+ paint_and_above(w);
+ return w;
+}
+
+void del_window(struct window *w) {
+ if (w == top_window)
+ top_window = w->below;
+ if (w == bottom_window)
+ bottom_window = w->above;
+ if (w->below)
+ w->below->above = w->above;
+ if (w->above)
+ w->above->below = w->below;
+
+ free_pages(w->action_buffer, ACTION_BUFFER_PAGES);
+ w->pixel_buffer_pma = 0;
+
+ paint_all();
+}
+
+void resize_window(struct window *w, uint16_t width, uint16_t height) {
+ const bool smaller = (width < w->width) || (height < w->height);
+
+ w->width = width;
+ w->height = height;
+
+ if (smaller)
+ paint_all();
+ else
+ paint_and_above(w);
+}
+
+void reassign_pixel_buffer(struct window *w, const void *pixel_buffer) {
+ w->pixel_buffer_pma = vma_to_pma(active_task->page_directory, pixel_buffer);
+}
+
+void push_window_paint(const struct window *w) {
+ paint_and_above(w);
+}
+
+struct window_action next_window_action(struct window *w) {
+ if (w->next_action_write == w->next_action_read)
+ return (struct window_action){.action_type = NONE};
+ const struct window_action *const action = w->next_action_read;
+ if (++(w->next_action_read) >= AB_END(w->action_buffer))
+ w->next_action_read = w->action_buffer;
+ return *action;
+}
+
+static void send_action(struct window *w, struct window_action packet) {
+ struct window_action *next_next = w->next_action_write + 1;
+ if (next_next >= AB_END(w->action_buffer))
+ next_next = w->action_buffer;
+ if (next_next != w->next_action_read) {
+ *(w->next_action_write) = packet;
+ w->next_action_write = next_next;
+ unwait(w->from_task, (struct wait){.mode = WINDOW_ACTION});
+ }
+}
+
+enum wm_action {
+ WM_SHUFFLE_UP,
+ WM_SHUFFLE_DOWN,
+ WM_MOVE_LEFT,
+ WM_MOVE_RIGHT,
+ WM_MOVE_UP,
+ WM_MOVE_DOWN,
+
+ N_WM_ACTIONS
+};
+
+static struct key_packet keybinds[] = {
+ {.key_id = KEY_PAGE_DOWN, .modifiers = WINS},
+ {.key_id = KEY_PAGE_UP, .modifiers = WINS},
+ {.key_id = KEY_LEFT_ARROW, .modifiers = WINS},
+ {.key_id = KEY_RIGHT_ARROW, .modifiers = WINS},
+ {.key_id = KEY_UP_ARROW, .modifiers = WINS},
+ {.key_id = KEY_DOWN_ARROW, .modifiers = WINS}
+};
+
+static inline bool fuzzy_key_match(struct key_packet t, struct key_packet a) {
+ if (t.key_id != a.key_id)
+ return false;
+
+ if (((t.modifiers & SHIFTS) == SHIFTS) && (a.modifiers & SHIFTS))
+ a.modifiers |= SHIFTS;
+ if (((t.modifiers & CTRLS) == CTRLS) && (a.modifiers & CTRLS))
+ a.modifiers |= CTRLS;
+ if (((t.modifiers & ALTS) == ALTS) && (a.modifiers & ALTS))
+ a.modifiers |= ALTS;
+ if (((t.modifiers & WINS) == WINS) && (a.modifiers & WINS))
+ a.modifiers |= WINS;
+
+ return a.modifiers == t.modifiers;
+}
+
+#include "log.h"
+
+void on_action(struct window_action packet) {
+//logf(LOG_INFO, "Window action, top window = 0x%d from %s.", top_window, top_window->from_task->name);
+
+ if (packet.action_type == NOT_READY)
+ return;
+
+ if (top_window) {
+ if (packet.action_type == KEY_DOWN)
+ for (uint8_t i = 0; i < N_WM_ACTIONS; ++i)
+ if (fuzzy_key_match(keybinds[i], packet.as_key)) {
+ switch_to_kernel_cr3();
+ struct window *old_top, *old_bottom;
+ switch (i) {
+ case WM_SHUFFLE_UP:
+ old_top = top_window;
+ old_bottom = bottom_window;
+ top_window = old_top->below;
+ top_window->above = 0;
+ old_top->below = 0;
+ old_top->above = old_bottom;
+ old_bottom->below = old_top;
+ bottom_window = old_top;
+ paint_and_above(bottom_window->above);
+ break;
+ case WM_SHUFFLE_DOWN:
+ old_top = top_window;
+ old_bottom = bottom_window;
+ bottom_window = old_bottom->above;
+ bottom_window->below = 0;
+ old_bottom->above = 0;
+ old_bottom->below = old_top;
+ old_top->above = old_bottom;
+ top_window = old_bottom;
+ paint_and_above(top_window);
+ break;
+ case WM_MOVE_LEFT:
+ --top_window->xpos;
+ paint_all();
+ break;
+ case WM_MOVE_RIGHT:
+ ++top_window->xpos;
+ paint_all();
+ break;
+ case WM_MOVE_UP:
+ --top_window->ypos;
+ paint_all();
+ break;
+ case WM_MOVE_DOWN:
+ ++top_window->ypos;
+ paint_all();
+ }
+ switch_to_task_cr3();
+ return;
+ }
+
+ send_action(top_window, packet);
+ }
+} \ No newline at end of file
diff --git a/src/kernel/window.h b/src/kernel/window.h
new file mode 100644
index 0000000..60b81ea
--- /dev/null
+++ b/src/kernel/window.h
@@ -0,0 +1,23 @@
+#ifndef WINDOW_H
+#define WINDOW_H
+
+#include <stdint.h>
+
+#include <winact.h>
+
+struct window;
+
+void paint_bg();
+
+struct window *new_window(uint16_t width, uint16_t height, const void *pixel_buffer);
+void del_window(struct window *w);
+
+void resize_window(struct window *w, uint16_t width, uint16_t height);
+void reassign_pixel_buffer(struct window *w, const void *pixel_buffer);
+void push_window_paint(const struct window *w);
+struct window_action next_window_action(struct window *w);
+void wait_window_action();
+
+void on_action(struct window_action packet);
+
+#endif
diff --git a/src/man/dev/kmemmap.pre b/src/man/dev/kmemmap.pre
deleted file mode 100644
index 73b4e09..0000000
--- a/src/man/dev/kmemmap.pre
+++ /dev/null
@@ -1,34 +0,0 @@
-\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
deleted file mode 100644
index 49f3d13..0000000
--- a/src/man/index.pre
+++ /dev/null
@@ -1,13 +0,0 @@
-\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/shared/include/keypack.h b/src/shared/include/keypack.h
new file mode 100644
index 0000000..1b356a3
--- /dev/null
+++ b/src/shared/include/keypack.h
@@ -0,0 +1,137 @@
+#ifndef SHARED_KEYPACK_H
+#define SHARED_KEYPACK_H
+
+struct key_packet {
+ enum key_id_t {
+ KEY_BSPACE = 0x08,
+ KEY_TAB,
+ KEY_ENTER,
+ KEY_SPACE = ' ',
+ KEY_APOSTRAPHE = '\'',
+ KEY_COMMA = ',',
+ KEY_HYPHEN,
+ KEY_PERIOD,
+ KEY_SLASH,
+ KEY_ZERO,
+ KEY_ONE,
+ KEY_TWO,
+ KEY_THREE,
+ KEY_FOUR,
+ KEY_FIVE,
+ KEY_SIX,
+ KEY_SEVEN,
+ KEY_EIGHT,
+ KEY_NINE,
+ KEY_SEMICOLON = ';',
+ KEY_EQUALS = '=',
+ KEY_OPEN_BRACKET = '[',
+ KEY_BACKSLASH,
+ KEY_CLOSE_BRACKET,
+ KEY_GRAVE = '`',
+ KEY_A,
+ KEY_B,
+ KEY_C,
+ KEY_D,
+ KEY_E,
+ KEY_F,
+ KEY_G,
+ KEY_H,
+ KEY_I,
+ KEY_J,
+ KEY_K,
+ KEY_L,
+ KEY_M,
+ KEY_N,
+ KEY_O,
+ KEY_P,
+ KEY_Q,
+ KEY_R,
+ KEY_S,
+ KEY_T,
+ KEY_U,
+ KEY_V,
+ KEY_W,
+ KEY_X,
+ KEY_Y,
+ KEY_Z,
+
+ KEY_LEFT_SHIFT = 0x80,
+ KEY_RIGHT_SHIFT,
+ KEY_LEFT_CONTROL,
+ KEY_RIGHT_CONTROL,
+ KEY_LEFT_ALT,
+ KEY_RIGHT_ALT,
+ KEY_LEFT_WIN,
+ KEY_RIGHT_WIN,
+ KEY_CAPS_LOCK,
+ KEY_NUM_LOCK,
+ KEY_SCROLL_LOCK,
+ KEY_INSERT,
+
+ KEY_F1 = 0xa0,
+ KEY_F2,
+ KEY_F3,
+ KEY_F4,
+ KEY_F5,
+ KEY_F6,
+ KEY_F7,
+ KEY_F8,
+ KEY_F9,
+ KEY_F10,
+ KEY_F11,
+ KEY_F12,
+ KEY_NUM_ZERO = 0xb0,
+ KEY_NUM_ONE,
+ KEY_NUM_TWO,
+ KEY_NUM_THREE,
+ KEY_NUM_FOUR,
+ KEY_NUM_FIVE,
+ KEY_NUM_SIX,
+ KEY_NUM_SEVEN,
+ KEY_NUM_EIGHT,
+ KEY_NUM_NINE,
+ KEY_NUM_TIMES,
+ KEY_NUM_PLUS,
+ KEY_NUM_ENTER,
+ KEY_NUM_MINUS,
+ KEY_NUM_DOT,
+ KEY_NUM_DIVIDE,
+ KEY_DELETE = 0xc1,
+ KEY_HOME,
+ KEY_END,
+ KEY_PAGE_UP,
+ KEY_PAGE_DOWN,
+ KEY_UP_ARROW,
+ KEY_DOWN_ARROW,
+ KEY_LEFT_ARROW,
+ KEY_RIGHT_ARROW,
+ KEY_ESCAPE,
+ KEY_MENU,
+ KEY_PAUSE,
+ KEY_PRINT_SCREEN
+ } key_id;
+ enum key_modifiers_t {
+ LSHIFT = 0x001,
+ RSHIFT = 0x002,
+ LCTRL = 0x004,
+ RCTRL = 0x008,
+ LALT = 0x010,
+ RALT = 0x020,
+ LWIN = 0x040,
+ RWIN = 0x080,
+
+ CAPS = 0x100,
+ NUM = 0x200,
+ SCROLL = 0x400,
+ INSERT = 0x800,
+
+ SHIFTS = 0x003,
+ CTRLS = 0x00c,
+ ALTS = 0x030,
+ WINS = 0x0c0,
+
+ NO_MODS = 0x000
+ } modifiers;
+} __attribute__ ((__packed__));
+
+#endif \ No newline at end of file
diff --git a/src/shared/include/winact.h b/src/shared/include/winact.h
new file mode 100644
index 0000000..bc18cb4
--- /dev/null
+++ b/src/shared/include/winact.h
@@ -0,0 +1,19 @@
+#ifndef SHARED_WINACT_H
+#define SHARED_WINACT_H
+
+#include <keypack.h>
+
+struct window_action {
+ enum {
+ NOT_READY,
+ KEY_DOWN,
+ KEY_UP,
+ FOCUS_ENTER,
+ FOCUS_LEAVE
+ } action_type;
+ union {
+ struct key_packet as_key;
+ };
+} __attribute__ ((__packed__));
+
+#endif \ No newline at end of file
diff --git a/src/user/dirinfo/dirinfo.c b/src/user/dirinfo/dirinfo.c
deleted file mode 100644
index 21afcc7..0000000
--- a/src/user/dirinfo/dirinfo.c
+++ /dev/null
@@ -1,49 +0,0 @@
-#include <pland/syscall.h>
-#include <knob/format.h>
-#include <knob/file.h>
-#include <knob/user.h>
-
-#define MAX_DIR_ENTRIES 20
-
-void main(const char *arg) {
- uint8_t dn;
- const char *path = remove_prefix(arg, &dn);
-
- tell_user_sz("Directory info for ");
- tell_user_sz(*arg ? arg : "drive root");
- tell_user_sz("\n");
-
- _dir_info_entry_t infos[MAX_DIR_ENTRIES];
- uint8_t count = _enumerate_dir(dn, path, infos, MAX_DIR_ENTRIES);
- tell_user_sz(
- count == MAX_DIR_ENTRIES
- ? "Truncated to 20 entries.\n\n"
- : "\n"
- );
-
- uint32_t total_size = 0;
-
- if (!count)
- tell_user_sz("(none)\n");
-
- for (uint8_t i = 0; i < count; ++i) {
- tell_user_sz(infos[i].name);
- tell_user_sz(": ");
- if (infos[i].is_dir)
- tell_user_sz("dir");
- else {
- char nbuf[11];
- itosz(infos[i].size, nbuf);
- tell_user_sz(nbuf);
- tell_user_sz(" bytes");
- total_size += infos[i].size;
- }
- tell_user_sz("\n");
- }
-
- tell_user_sz("\nTotal size without subdirectories: ");
- char nbuf[11];
- itosz(total_size, nbuf);
- tell_user_sz(nbuf);
- tell_user_sz(" bytes\n");
-} \ No newline at end of file
diff --git a/src/user/dumphex/dumphex.c b/src/user/dumphex/dumphex.c
deleted file mode 100644
index 2944a2f..0000000
--- a/src/user/dumphex/dumphex.c
+++ /dev/null
@@ -1,81 +0,0 @@
-#include <knob/file.h>
-#include <knob/user.h>
-#include <knob/format.h>
-
-#define LINE_LEN 16
-
-void print_zero_line(uint32_t offset) {
-}
-
-void main(const char *path) {
- struct file *f = open_file(path);
- if (!f) {
- tell_user_sz("Couldn't open file.\n");
- return;
- }
-
- uint8_t line[LINE_LEN + 2];
- uint8_t len;
- uint32_t offset = -LINE_LEN;
-
- enum {
- ZR_NO,
- ZR_FIRST,
- ZR_REST
- } zero_run;
-
- char nbuf[9];
-
- while ((len = read_from_file(f, LINE_LEN, line))) {
- offset += LINE_LEN;
-
- for (uint8_t i = 0; i < LINE_LEN; ++i)
- if (line[i]) {
- zero_run = ZR_NO;
- goto print_normal;
- }
-
- switch (zero_run) {
- case ZR_NO:
- zero_run = ZR_FIRST;
- _log_string("0x");
- itosz_h32(offset, nbuf);
- _log_string(nbuf);
- _log_string(" | 00 00 00 00 00 00 00 00 "
- "00 00 00 00 00 00 00 00 |\n");
- continue;
- case ZR_FIRST:
- zero_run = ZR_REST;
- tell_user_sz("...\n");
- case ZR_REST:
- continue;
- }
-
- print_normal:
- _log_string("0x");
- itosz_h32(offset, nbuf);
- _log_string(nbuf);
- _log_string(" |");
-
- nbuf[0] = ' ';
- for (uint8_t i = 0; i < len; ++i) {
- itosz_h8(line[i], nbuf + 1);
- _log_string(nbuf);
- }
-
- for (uint8_t i = len; i < LINE_LEN; ++i)
- _log_string(" ");
-
- _log_string(" | ");
-
- for (uint8_t i = 0; i < len; ++i)
- if ((line[i] < 0x20) || (line[i] > 0x7e))
- line[i] = ' ';
- line[len] = '\n';
- line[len + 1] = '\0';
-
- _log_string(line);
- }
-
- close_file(f);
-} \ No newline at end of file
diff --git a/src/user/dumptext/dumptext.c b/src/user/dumptext/dumptext.c
deleted file mode 100644
index b10375c..0000000
--- a/src/user/dumptext/dumptext.c
+++ /dev/null
@@ -1,15 +0,0 @@
-#include <knob/file.h>
-#include <knob/user.h>
-
-void main(const char *path) {
- struct file *f = open_file(path);
- if (!f) {
- tell_user_sz("Couldn't open file.\n");
- return;
- }
- char buf[] = { '\0', '\0' };
- while (read_from_file(f, 1, buf))
- tell_user_sz(buf);
- tell_user_sz("\n");
- close_file(f);
-} \ No newline at end of file
diff --git a/src/user/fileman/fileman.c b/src/user/fileman/fileman.c
deleted file mode 100644
index 0b28d1d..0000000
--- a/src/user/fileman/fileman.c
+++ /dev/null
@@ -1,130 +0,0 @@
-#include <pland/syscall.h>
-#include <knob/block.h>
-#include <knob/file.h>
-#include <knob/heap.h>
-#include <knob/task.h>
-
-char path_sz[1024] = "";
-uint32_t path_len = 0;
-
-_dir_info_entry_t *dir_info;
-uint32_t dir_info_len;
-
-uint32_t scroll;
-uint32_t selected;
-#define MAX_PER_SCREEN 18
-
-void paint_screen() {
- _clear_screen();
-
- _set_color(0x70);
- _print_at(0, 0, path_sz);
- _log_string("/");
- _set_color(0x07);
-
- for (uint32_t i = scroll, row = 2; (i < dir_info_len) && (row < MAX_PER_SCREEN + 2); ++i, ++row) {
- if (i == selected)
- _set_color(0x17);
- _print_at(row, 0, dir_info[i].name);
- if (dir_info[i].is_dir)
- _log_string("/");
- if (i == selected)
- _set_color(0x07);
- }
-
- _print_at(21, 0, "keybindings:\n"
- "UP, DOWN, PAGE UP, PAGE DOWN, HOME, END: move selection\n"
- "ENTER: enter selected directory, run selected program\n"
- "ESC: go up a directory Q: quit");
-}
-
-void load_dir() {
- free_block(dir_info);
- dir_info = get_directory_info(path_sz, &dir_info_len);
- scroll = 0;
- selected = 0;
-}
-
-void main(const char *sz) {
- path_len = strcpy(path_sz, sz);
- dir_info = get_directory_info(sz, &dir_info_len);
-
- paint_screen();
-
- while (true) {
- _key_code_t key;
- switch (key = _get_key()) {
- case 0:
- _yield_task();
- continue;
- case '\n':
- {
- uint32_t old_len = path_len;
- if (path_len)
- path_sz[path_len++] = '/';
- path_len += strcpy(path_sz + path_len, dir_info[selected].name);
- if (dir_info[selected].is_dir)
- load_dir();
- else {
- try_run_command_blocking(path_sz);
- //TODO: handle error
- path_sz[old_len] = '\0';
- path_len = old_len;
- }
- }
- break;
- case _KEY_ESC:
- {
- char *cutoff = path_sz;
- for (char *i = path_sz + path_len - 1; i >= path_sz; --i)
- if (*i == '/') {
- cutoff = i;
- break;
- }
- *cutoff = '\0';
- path_len = cutoff - path_sz;
- load_dir();
- }
- break;
- case _KEY_HOME:
- scroll = 0;
- selected = 0;
- break;
- case _KEY_END:
- selected = dir_info_len - 1;
- scroll = dir_info_len >= MAX_PER_SCREEN
- ? dir_info_len - MAX_PER_SCREEN : 0;
- break;
- case _KEY_UP:
- if (!selected)
- continue;
- if (--selected < scroll)
- scroll = selected;
- break;
- case _KEY_DOWN:
- if (selected == dir_info_len - 1)
- continue;
- if (++selected >= scroll + MAX_PER_SCREEN)
- ++scroll;
- break;
- case _KEY_PUP:
- selected = selected >= MAX_PER_SCREEN
- ? selected - MAX_PER_SCREEN : 0;
- scroll = scroll >= MAX_PER_SCREEN
- ? scroll - MAX_PER_SCREEN : 0;
- break;
- case _KEY_PDOWN:
- if ((selected += MAX_PER_SCREEN) >= dir_info_len)
- selected = dir_info_len - 1;
- if ((scroll += MAX_PER_SCREEN) > selected)
- scroll = selected;
- break;
- case 'q':
- _clear_screen();
- return;
- default:
- continue;
- }
- paint_screen();
- }
-} \ No newline at end of file
diff --git a/src/user/hello/hello.asm b/src/user/hello/hello.asm
deleted file mode 100644
index 65d32be..0000000
--- a/src/user/hello/hello.asm
+++ /dev/null
@@ -1,14 +0,0 @@
-bits 32
-
-global _entry
-
-section .text
-_entry:
- mov eax, 0x5
- mov ebx, hello
- int 0x30
-
- int 0x38
-
-section .data
-hello db "Hello, world!", 0x0a, 0 \ No newline at end of file
diff --git a/src/user/highway/cmds.c b/src/user/highway/cmds.c
index d7a89d1..0420ae1 100644
--- a/src/user/highway/cmds.c
+++ b/src/user/highway/cmds.c
@@ -1,12 +1,16 @@
+#include <terminal/terminal.h>
+
#include <knob/file.h>
-#include <knob/user.h>
+
#include "line.h"
#include "vars.h"
void source(const char *path) {
struct file *f = open_file(path);
- if (!f)
- tell_user_sz("couldn't open file.\n");
+ if (!f) {
+ term_addf("Could not open %s.\n", path);
+ return;
+ }
char buf[128];
while (read_line_from_file(f, buf, 127))
run_line(buf);
diff --git a/src/user/highway/line.c b/src/user/highway/line.c
index c8e5c60..bf171e5 100644
--- a/src/user/highway/line.c
+++ b/src/user/highway/line.c
@@ -1,19 +1,37 @@
-#include <pland/pcrt.h>
+#include <terminal/terminal.h>
+
#include <knob/block.h>
#include <knob/task.h>
-#include <knob/user.h>
+
+#include <pland/pcrt.h>
+
#include "cmds.h"
+#include "term.h"
#include "vars.h"
#define LINE_SIZE 4096
static char line[LINE_SIZE];
+static inline uint8_t hex_to_int(char ch) {
+ return ch - (ch <= '9' ? '0' : 'a' - 10);
+}
+
+void ensure_color() {
+ const struct no_null_sn *fg = get_var((struct no_null_sn){.data = "_color_fg", .length = 9});
+ const struct no_null_sn *bg = get_var((struct no_null_sn){.data = "_color_bg", .length = 9});
+ if (fg && bg)
+ set_color(
+ (hex_to_int(fg->data[0]) << 4) | hex_to_int(fg->data[1]),
+ (hex_to_int(bg->data[0]) << 4) | hex_to_int(bg->data[1])
+ );
+}
+
static void line_replace(const char *from) {
const char *fi = from;
char *ti = line;
while (*fi) {
if (ti == line + LINE_SIZE) {
- tell_user_sz("Line too long.\n");
+ term_add_sz("Line too long.\n");
line[0] = '\0';
return;
}
@@ -27,12 +45,15 @@ static void line_replace(const char *from) {
const char *var_end = var_start;
while (*var_end != '$')
if (!*var_end++) {
- tell_user_sz("Unterminated variable name.\n");
+ if (var_end - fi > 10)
+ term_addf("Unterminated variable at\"%10s...\".\n", fi);
+ else
+ term_addf("Unterminated variable at \"%s\".\n", fi);
line[0] = '\0';
return;
}
if (ti + (var_end - var_start) >= line + LINE_SIZE) {
- tell_user_sz("Line too long.\n");
+ term_add_sz("Line too long.\n");
line[0] = '\0';
return;
}
@@ -59,46 +80,50 @@ void run_line(const char *original_line) {
;
if (blockequ(line, "source ", 7))
source(space + 1);
- else if (blockequ(line, "set ", 4))
+ else if (blockequ(line, "set ", 4)) {
set(space + 1);
+ ensure_color();
+ }
else if (blockequ(line, "echo ", 5)) {
- tell_user_sz(space + 1);
- tell_user_sz("\n");
+ term_add_sz(space + 1);
+ term_add_char('\n');
}
else if (blockequ(line, "vars", 5))
dump_vars();
- else if (blockequ(line, "quit", 5))
+ else if (blockequ(line, "quit", 5)) {
+ del_term(active_term);
__pcrt_quit();
+ }
else if (blockequ(line, "clear", 6))
- _clear_screen();
+ clear_term();
else if (blockequ(line, "help", 5))
- tell_user_sz("Highway is a command shell for Portland OS. It includes variables and a couple\n"
- "of pseudo-commands. Variables are addressed by surrounding with \"$\". The\n"
- "following list shows each of the pseudo-commands.\n\n"
- " source FILE run each command in FILE\n"
- " clear clear the screen\n"
- " echo STRING print STRING\n"
- " set VAR VALUE set $VAR$ to VALUE\n"
- " vars dump variables\n"
- " quit exit highway\n"
- " help show this\n");
- else if (!try_run_command_blocking(line)) {
- struct no_null_sn arg = {
- .data = "_path",
- .length = 5
- };
- const struct no_null_sn *path = get_var(arg);
+ term_add_sz("Highway is a command shell for Portland OS. It includes variable support and a couple of pseudo-commands. Variables are addressed by surrounding with \"$\". The following list shows each of the pseudo-commands.\n\n"
+ " source FILE\t" "run each command in FILE\n"
+ " clear\t\t\t" "clear the screen\n"
+ " echo STRING\t" "print STRING\n"
+ " set VAR VALUE\t" "set $VAR$ to VALUE\n"
+ " vars\t\t\t" "dump variables\n"
+ " quit\t\t\t" "exit highway\n"
+ " help\t\t\t" "show this\n");
+ else if (!try_run_command_blocking(line, stdio_task)) {
+ const struct no_null_sn *path = get_var((struct no_null_sn){.data = "_path", .length = 5});
if (!path->length) {
- tell_user_sz("Could not run command.\n");
+ term_add_sz("Could not run command.\n");
return;
}
for (uint16_t to_i = LINE_SIZE - 1; to_i >= path->length; --to_i)
line[to_i] = line[to_i - path->length];
blockcpy(line, path->data, path->length);
- if (!try_run_command_blocking(line)) {
- tell_user_sz("Could not run command.\n");
+ if (!try_run_command_blocking(line, stdio_task)) {
+ term_add_sz("Could not run command.\n");
return;
}
+ else {
+ ensure_color();
+ if (active_term->cursor_x)
+ term_newline();
+ }
}
- _set_color(0x07);
+ else
+ ensure_color();
} \ No newline at end of file
diff --git a/src/user/highway/line.h b/src/user/highway/line.h
index 4785034..fc131ec 100644
--- a/src/user/highway/line.h
+++ b/src/user/highway/line.h
@@ -2,5 +2,6 @@
#define LINE_H
void run_line(const char *line);
+void ensure_color();
#endif \ No newline at end of file
diff --git a/src/user/highway/main.c b/src/user/highway/main.c
index 4599315..60d5a69 100644
--- a/src/user/highway/main.c
+++ b/src/user/highway/main.c
@@ -1,17 +1,36 @@
-#include <knob/user.h>
+#include <terminal/terminal.h>
+#include <terminal/readline.h>
+
+#include <libfont/fonts.h>
+
+#include <knob/format.h>
+#include <knob/heap.h>
#include <knob/task.h>
+
#include "cmds.h"
#include "line.h"
+#define FONT_NAME "berry"
+
void main(const char *arg) {
+ struct font_info *f = get_font(FONT_NAME);
+
+ if (!f)
+ return;
+
+ active_term = make_term(f, 50, 18);
+ if (!active_term)
+ return;
+
source(*arg ? arg : "user/default.rc");
+ ensure_color();
+
+ term_add_sz("Portland Highway\nType \"help\" for help.\n");
+ paint_term();
+
char cmd_buf[128];
- yield_task();
- struct history *cmd_hs = new_history(128);
- tell_user_sz("Portland Highway\nType \"help\" for help.\n");
while (1) {
- tell_user_sz("\n> ");
- ask_user_line_sz_with_history(cmd_buf, 127, cmd_hs);
+ read_line(cmd_buf, 127, "> ");
run_line(cmd_buf);
}
} \ No newline at end of file
diff --git a/src/user/highway/vars.c b/src/user/highway/vars.c
index 6090b76..5f56621 100644
--- a/src/user/highway/vars.c
+++ b/src/user/highway/vars.c
@@ -1,6 +1,10 @@
+#include <terminal/terminal.h>
+
+#include <knob/format.h>
#include <knob/block.h>
#include <knob/heap.h>
-#include <knob/user.h>
+
+#include <pland/pcrt.h>
struct no_null_sn {
char *data;
@@ -73,26 +77,6 @@ void del_var(struct no_null_sn name) {
void dump_vars() {
for (struct var_dict_node *node = var_dict_start; node; node = node->next) {
- tell_user_sz("$");
-
- char *buf = get_block(node->name.length + 1);
- blockcpy(buf, node->name.data, node->name.length);
- buf[node->name.length] = '\0';
-
- tell_user_sz(buf);
-
- free_block(buf);
-
- tell_user_sz("$ = ");
-
- buf = get_block(node->value.length + 1);
- blockcpy(buf, node->value.data, node->value.length);
- buf[node->value.length] = '\0';
-
- tell_user_sz(buf);
-
- free_block(buf);
-
- tell_user_sz("\n");
+ term_addf_no_ww("$%ns$ = %ns\n", node->name.length, node->name.data, node->value.length, node->value.data);
}
} \ No newline at end of file
diff --git a/src/user/include/knob/block.h b/src/user/include/knob/block.h
index 56d3740..f77709d 100644
--- a/src/user/include/knob/block.h
+++ b/src/user/include/knob/block.h
@@ -13,4 +13,9 @@ uint32_t strcpy(char *to, const char *from);
//allocates new memory
char *strdup(const char *from);
+//without null-terminator
+uint32_t strlen(const char *str) __attribute__ ((pure));
+
+bool strequ(const char *a, const char *b) __attribute__ ((pure));
+
#endif \ No newline at end of file
diff --git a/src/user/include/knob/env.h b/src/user/include/knob/env.h
deleted file mode 100644
index 6d750ae..0000000
--- a/src/user/include/knob/env.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef KNOB_ENV_H
-#define KNOB_ENV_H
-
-#include <stdint.h>
-
-//not implemented yet
-extern uint32_t current_drive;
-
-#endif \ No newline at end of file
diff --git a/src/user/include/knob/format.h b/src/user/include/knob/format.h
index d55036c..fed31c7 100644
--- a/src/user/include/knob/format.h
+++ b/src/user/include/knob/format.h
@@ -1,12 +1,29 @@
#ifndef KNOB_FORMAT_H
#define KNOB_FORMAT_H
-#include <stdbool.h>
+#include <knob/heap.h>
+
#include <stdint.h>
+#include <stdarg.h>
+
+//allocates new memory
+char *format_v(const char *fmt, va_list args);
+
+//allocates new memory
+char *format(const char *fmt, ...);
+
+void syslogf_v(const char *fmt, va_list args);
+
+void syslogf(const char *fmt, ...);
+
+//reads a unsigned decimal terminated by either null or whitespace
+//returns length of string plus length of whitespace
+//returns 0 on failure
+uint32_t try_swtou(const char *from, uint32_t *i_out);
-bool try_sntoi(const char *s, uint32_t n, uint32_t *out);
-void itosz(uint32_t i, char *out) __attribute__ ((access (write_only, 2)));
-void itosz_h8(uint8_t i, char *out) __attribute__ ((access (write_only, 2)));
-void itosz_h32(uint32_t i, char *out) __attribute__ ((access (write_only, 2)));
+//reads a hexadecimal terminated by either null or whitespace
+//returns length of string plus length of whitespace
+//returns 0 on failure
+uint32_t try_swtoh(const char *from, uint32_t *i_out);
#endif \ No newline at end of file
diff --git a/src/user/include/knob/ipc.h b/src/user/include/knob/ipc.h
new file mode 100644
index 0000000..3eab562
--- /dev/null
+++ b/src/user/include/knob/ipc.h
@@ -0,0 +1,16 @@
+#ifndef KNOB_IPC_H
+#define KNOB_IPC_H
+
+#include <pland/syscall.h>
+
+//blocking, returns early if other process is dead.
+//return value is number of bytes written.
+uint32_t try_send_ipc(_task_handle_t to, void *buffer, uint32_t size);
+
+//blocking, returns early if other process is dead.
+//return value is number of bytes read.
+uint32_t try_read_ipc(_task_handle_t from, void *buffer, uint32_t size);
+
+void flush_ipc(_task_handle_t from);
+
+#endif \ No newline at end of file
diff --git a/src/user/include/knob/key.h b/src/user/include/knob/key.h
new file mode 100644
index 0000000..90509fc
--- /dev/null
+++ b/src/user/include/knob/key.h
@@ -0,0 +1,8 @@
+#ifndef KNOB_KEY_H
+#define KNOB_KEY_H
+
+#include <keypack.h>
+
+char key_to_char(struct key_packet kp) __attribute__ ((pure));
+
+#endif \ No newline at end of file
diff --git a/src/user/include/knob/panic.h b/src/user/include/knob/panic.h
new file mode 100644
index 0000000..1dd33a0
--- /dev/null
+++ b/src/user/include/knob/panic.h
@@ -0,0 +1,9 @@
+#ifndef KNOB_PANIC_H
+#define KNOB_PANIC_H
+
+#include <stdint.h>
+
+#define PANIC(msg) panic(__FILE__, __LINE__, msg)
+void panic(const char *filename, uint32_t line, const char *message) __attribute__ ((noreturn));
+
+#endif \ No newline at end of file
diff --git a/src/user/include/knob/task.h b/src/user/include/knob/task.h
index 6539a00..cd51c37 100644
--- a/src/user/include/knob/task.h
+++ b/src/user/include/knob/task.h
@@ -1,11 +1,12 @@
#ifndef KNOB_TASK_H
#define KNOB_TASK_H
+#include <pland/syscall.h>
+
#include <stdint.h>
#include <stdbool.h>
-uint32_t run_command(const char *path);
-bool try_run_command_blocking(const char *path);
-void yield_task();
+uint32_t run_command(const char *path, _task_handle_t stdio_task);
+bool try_run_command_blocking(const char *path, _task_handle_t stdio_task);
#endif \ No newline at end of file
diff --git a/src/user/include/knob/user.h b/src/user/include/knob/user.h
deleted file mode 100644
index fb11c9b..0000000
--- a/src/user/include/knob/user.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef KNOB_USER_H
-#define KNOB_USER_H
-
-#include <stdint.h>
-#include <pland/syscall.h>
-
-struct history;
-
-char key_to_char(_key_code_t key) __attribute__ ((const));
-
-void tell_user_sz(const char *sz);
-
-//return value and max_length don't include null terminator
-//returns the real length of the string
-uint32_t ask_user_line_sz(char *sz, uint32_t max_length);
-
-struct history *new_history(uint32_t max_entries);
-void del_history(struct history *hs);
-
-uint32_t ask_user_line_sz_with_history(char *sz, uint32_t max_length, struct history *hs);
-
-#endif \ No newline at end of file
diff --git a/src/user/include/libfont/fonts.h b/src/user/include/libfont/fonts.h
new file mode 100644
index 0000000..b66659f
--- /dev/null
+++ b/src/user/include/libfont/fonts.h
@@ -0,0 +1,21 @@
+#ifndef LIBFONT_FONTS_H
+#define LIBFONT_FONTS_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+struct font_info {
+ uint32_t space_width;
+ uint32_t space_height;
+ uint32_t char_width;
+ uint32_t char_height;
+ bool *bitmaps[256];//left to right then top to bottom
+ //null pointer for unsupported character
+ //unsupported characters drawn as bitmaps[0]
+};
+
+struct font_info *get_font(const char *name);
+
+void put_char(const struct font_info *font, char ch, uint8_t *pb_ptr, uint32_t pb_pitch, uint8_t bg, uint8_t fg);
+
+#endif \ No newline at end of file
diff --git a/src/user/include/pland/pcrt.h b/src/user/include/pland/pcrt.h
index 07ad453..42158cd 100644
--- a/src/user/include/pland/pcrt.h
+++ b/src/user/include/pland/pcrt.h
@@ -1,6 +1,8 @@
#ifndef PLAND_PCRT_H
#define PLAND_PCRT_H
+#include <pland/syscall.h>
+
#define BEFORE_MAIN(f) \
__attribute__ ((section (".__pcrt_before_main"))) \
__attribute__ ((unused)) \
@@ -13,4 +15,7 @@
void __pcrt_quit() __attribute__ ((noreturn));
-#endif \ No newline at end of file
+extern _task_handle_t calling_task;
+extern _task_handle_t stdio_task;
+
+#endif
diff --git a/src/user/include/pland/syscall.h b/src/user/include/pland/syscall.h
index ead5fea..6d327d5 100644
--- a/src/user/include/pland/syscall.h
+++ b/src/user/include/pland/syscall.h
@@ -4,119 +4,12 @@
#include <stdint.h>
#include <stdbool.h>
+#include <winact.h>
+
typedef uint32_t _file_handle_t;
typedef uint32_t _task_handle_t;
typedef uint32_t _drive_number_t;
-typedef uint32_t _process_handle_t;
-
-typedef enum {
- _KEY_LSHIFT = 0x00000100,
- _KEY_RSHIFT = 0x00000200,
- _KEY_CAPS = 0x00000400,
- _KEY_INSERT = 0x00000800,
- _KEY_NUM = 0x00001000,
- _KEY_SCROLL = 0x00002000,
- _KEY_LALT = 0x00004000,
- _KEY_RALT = 0x00008000,
- _KEY_LCTRL = 0x00010000,
- _KEY_RCTRL = 0x00020000,
- _KEY_LMETA = 0x00040000,
- _KEY_RMETA = 0x00080000,
-
- _KEY_SHIFT = 0x00000300,
- _KEY_SCAPS = 0x00000700,
- _KEY_ALT = 0x0000c000,
- _KEY_CTRL = 0x00030000,
- _KEY_META = 0x000c0000,
-
- _KEY_BEGIN_CAPS = 0x80,
- _KEY_BEGIN_INSERT,
- _KEY_BEGIN_NUM,
- _KEY_BEGIN_SCROLL,
- _KEY_BEGIN_LSHIFT,
- _KEY_BEGIN_RSHIFT,
- _KEY_BEGIN_LALT,
- _KEY_BEGIN_RALT,
- _KEY_BEGIN_LCTRL,
- _KEY_BEGIN_RCTRL,
- _KEY_BEGIN_LMETA,
- _KEY_BEGIN_RMETA,
- /* 0x8c - 0x97 reserved */
- /* 0x98 - 0x9f unassigned */
- _KEY_F1 = 0xa0,
- _KEY_F2,
- _KEY_F3,
- _KEY_F4,
- _KEY_F5,
- _KEY_F6,
- _KEY_F7,
- _KEY_F8,
- _KEY_F9,
- _KEY_F10,
- _KEY_F11,
- _KEY_F12,
- /* 0xac - 0xaf unassigned */
- _KEY_NUM0 = 0xb0,
- _KEY_NUM1,
- _KEY_NUM2,
- _KEY_NUM3,
- _KEY_NUM4,
- _KEY_NUM5,
- _KEY_NUM6,
- _KEY_NUM7,
- _KEY_NUM8,
- _KEY_NUM9,
- _KEY_NTIMES,
- _KEY_NPLUS,
- _KEY_NENTER,
- _KEY_NMINUS,
- _KEY_NDOT,
- _KEY_NSLASH,
- /* 0xc0 unassigned */
- _KEY_DELETE = 0xc1,
- _KEY_HOME,
- _KEY_END,
- _KEY_PUP,
- _KEY_PDOWN,
- _KEY_UP,
- _KEY_DOWN,
- _KEY_LEFT,
- _KEY_RIGHT,
- _KEY_ESC,
- _KEY_MENU,
- _KEY_PAUSE,
- _KEY_PRSCR,
- /* 0xce - 0xef unassigned */
-} _key_code_t;
-
-typedef enum {
- _COLOR_FG_BLACK = 0x00,
- _COLOR_FG_BLUE = 0x01,
- _COLOR_FG_GREEN = 0x02,
- _COLOR_FG_CYAN = 0x03,
- _COLOR_FG_RED = 0x04,
- _COLOR_FG_MAGENTA = 0x05,
- _COLOR_FG_BROWN = 0x06,
- _COLOR_FG_LGRAY = 0x07,
-
- _COLOR_FG_DGRAY = 0x08,
- _COLOR_FG_LBLUE = 0x09,
- _COLOR_FG_LGREEN = 0x0a,
- _COLOR_FG_LCYAN = 0x0b,
- _COLOR_FG_LRED = 0x0c,
- _COLOR_FG_PINK = 0x0d,
- _COLOR_FG_YELLOW = 0x0e,
- _COLOR_FG_WHITE = 0x0f,
-
- _COLOR_BG_BLACK = 0x00,
- _COLOR_BG_BLUE = 0x10,
- _COLOR_BG_GREEN = 0x20,
- _COLOR_BG_CYAN = 0x30,
- _COLOR_BG_RED = 0x40,
- _COLOR_BG_MAGENTA = 0x50,
- _COLOR_BG_BROWN = 0x60,
- _COLOR_BG_LGRAY = 0x70
-} _vga_color_t;
+typedef void *_window_handle_t;
typedef struct __attribute__ ((packed)) {
char name[100];
@@ -131,17 +24,26 @@ enum _scn {
_SCN_FILE_READ,
_SCN_FILE_SIZE,
_SCN_START_TASK,
- _SCN_LOG_STRING,
- _SCN_GET_KEY,
+ _SCN_IPC_SEND,
+ _SCN_IPC_READ,
_SCN_ALLOCATE_RAM,
_SCN_MEMORY_INFO,
_SCN_WAIT_FOR_TASK,
_SCN_ENUMERATE_DIR,
- _SCN_PRINT_AT,
+ _SCN_SYSTEM_LOG,
_SCN_COUNT_OF_DIR,
- _SCN_CLEAR_SCREEN,
- _SCN_SET_COLOR,
- _SCN_SWAP_COLOR
+ _SCN_NEW_WINDOW,
+ _SCN_DELETE_WINDOW,
+ _SCN_RESIZE_WINDOW,
+ _SCN_REASSIGN_PIXBUF,
+ _SCN_PAINT_WINDOW,
+ _SCN_GET_WIN_ACTION,
+ _SCN_WAIT_FOR_ACTION,
+ _SCN_WAIT_IPC_SEND,
+ _SCN_WAIT_FOR_ANY_IPC,
+ _SCN_FIND_UNREAD_IPC,
+ _SCN_WAIT_IPC_READ,
+ _SCN_IS_TASK_RUNNING
};
static inline uint32_t _sc0(enum _scn eax) {
@@ -211,7 +113,7 @@ static inline void _exit_task() {
}
static inline _file_handle_t _open_file(_drive_number_t drive_number, const char *path) {
- return _sc2(_SCN_OPEN_FILE, drive_number, (uint32_t)path);
+ return (_file_handle_t)_sc2(_SCN_OPEN_FILE, drive_number, (uint32_t)path);
}
static inline void _close_file(_file_handle_t handle) {
@@ -226,16 +128,16 @@ static inline uint32_t _file_size(_file_handle_t handle) {
return _sc1(_SCN_FILE_SIZE, handle);
}
-static inline _process_handle_t _start_task(_drive_number_t drive_number, const char *path, const char *pass) {
- return _sc3(_SCN_START_TASK, drive_number, (uint32_t)path, (uint32_t)pass);
+static inline _task_handle_t _start_task(_drive_number_t drive_number, const char *path, const char *pass, _task_handle_t stdio_task) {
+ return (_task_handle_t)_sc4(_SCN_START_TASK, drive_number, (uint32_t)path, (uint32_t)pass, (uint32_t)stdio_task);
}
-static inline void _log_string(const char *sz) {
- _sc1(_SCN_LOG_STRING, (uint32_t)sz);
+static inline uint32_t _ipc_send(_task_handle_t handle, uint32_t count, const void *buffer) {
+ return _sc3(_SCN_IPC_SEND, handle, count, (uint32_t)buffer);
}
-static inline _key_code_t _get_key() {
- return _sc0(_SCN_GET_KEY);
+static inline uint32_t _ipc_read(_task_handle_t handle, uint32_t count, void *buffer) {
+ return _sc3(_SCN_IPC_SEND, handle, count, (uint32_t)buffer);
}
static inline void *_allocate_ram(uint32_t pages) {
@@ -262,7 +164,7 @@ static inline uint32_t _this_process_memory_left() {
return _sc1(_SCN_MEMORY_INFO, 0x4);
}
-static inline void _wait_for_task(_process_handle_t handle) {
+static inline void _wait_for_task(_task_handle_t handle) {
_sc1(_SCN_WAIT_FOR_TASK, handle);
}
@@ -270,24 +172,60 @@ static inline uint32_t _enumerate_dir(_drive_number_t drive_number, const char *
return _sc4(_SCN_ENUMERATE_DIR, drive_number, (uint32_t)path, (uint32_t)buffer, max_count);
}
-static inline void _print_at(uint8_t row, uint8_t col, const char *sz) {
- _sc2(_SCN_PRINT_AT, (row << 8) | col, (uint32_t)sz);
-}
-
static inline uint32_t _count_of_dir(uint8_t drive_number, const char *path) {
return _sc2(_SCN_COUNT_OF_DIR, drive_number, (uint32_t)path);
}
-static inline void _clear_screen() {
- _sc0(_SCN_CLEAR_SCREEN);
+static inline _window_handle_t _new_window(uint16_t width, uint16_t height, void *pixel_buffer) {
+ return (_window_handle_t)_sc3(_SCN_NEW_WINDOW, width, height, (uint32_t)pixel_buffer);
+}
+
+static inline void _delete_window(_window_handle_t window) {
+ _sc1(_SCN_DELETE_WINDOW, (uint32_t)window);
+}
+
+static inline void _resize_window(_window_handle_t window, uint16_t width, uint16_t height) {
+ _sc3(_SCN_RESIZE_WINDOW, (uint32_t)window, width, height);
+}
+
+static inline void _reassign_pixbuf(_window_handle_t window, void *pixel_buffer) {
+ _sc2(_SCN_REASSIGN_PIXBUF, (uint32_t)window, (uint32_t)pixel_buffer);
+}
+
+static inline void _paint_window(_window_handle_t window) {
+ _sc1(_SCN_PAINT_WINDOW, (uint32_t)window);
+}
+
+static inline void _get_win_action(_window_handle_t window, struct window_action *action_pointer) {
+ _sc2(_SCN_GET_WIN_ACTION, (uint32_t)window, (uint32_t)action_pointer);
+}
+
+static inline void _wait_for_action() {
+ _sc0(_SCN_WAIT_FOR_ACTION);
+}
+
+static inline void _wait_ipc_send(_task_handle_t sending_task) {
+ _sc1(_SCN_WAIT_IPC_SEND, sending_task);
+}
+
+static inline void _system_log(const char *sz) {
+ _sc1(_SCN_SYSTEM_LOG, (uint32_t)sz);
+}
+
+static inline void _wait_for_any_ipc() {
+ _sc0(_SCN_WAIT_FOR_ANY_IPC);
+}
+
+static inline _task_handle_t _find_unread_ipc() {
+ return _sc0(_SCN_FIND_UNREAD_IPC);
}
-static inline void _set_color(_vga_color_t color) {
- _sc1(_SCN_SET_COLOR, color);
+static inline void _wait_ipc_read(_task_handle_t reading_task) {
+ _sc1(_SCN_WAIT_IPC_READ, reading_task);
}
-static inline void _swap_color(uint8_t row, uint8_t col) {
- _sc1(_SCN_SWAP_COLOR, (row << 8) | col);
+static inline bool _is_task_running(_task_handle_t handle) {
+ return (bool)_sc1(_SCN_IS_TASK_RUNNING, handle);
}
#endif \ No newline at end of file
diff --git a/src/user/include/popups/info.h b/src/user/include/popups/info.h
new file mode 100644
index 0000000..2c4e83f
--- /dev/null
+++ b/src/user/include/popups/info.h
@@ -0,0 +1,14 @@
+#ifndef POPUPS_INFO_H
+#define POPUPS_INFO_H
+
+#include <popups/popup.h>
+
+#include <pland/syscall.h>
+
+#include <stdarg.h>
+
+void info_popup(struct popup *into, const char *text, uint8_t fg, uint8_t bg);
+void info_popupf(struct popup *into, const char *text, uint8_t fg, uint8_t bg, ...);
+void info_popupf_v(struct popup *into, const char *text, uint8_t fg, uint8_t bg, va_list args);
+
+#endif \ No newline at end of file
diff --git a/src/user/include/popups/popup.h b/src/user/include/popups/popup.h
new file mode 100644
index 0000000..1a3c531
--- /dev/null
+++ b/src/user/include/popups/popup.h
@@ -0,0 +1,23 @@
+#ifndef POPUPS_POPUP_H
+#define POPUPS_POPUP_H
+
+#include <pland/syscall.h>
+
+struct popup {
+ _window_handle_t handle;
+ uint8_t *pixbuf;
+
+ bool has_quit;
+ struct key_packet quit_as;
+
+ //terminated by one with .key_id == 0
+ struct key_packet *quit_binds;
+ bool free_quit_binds;
+};
+
+void handle_actions(struct popup *p);
+//deletes popup before returning
+void make_modal(struct popup *p);
+void delete_popup(struct popup *p);
+
+#endif \ No newline at end of file
diff --git a/src/user/include/terminal/readline.h b/src/user/include/terminal/readline.h
new file mode 100644
index 0000000..9046610
--- /dev/null
+++ b/src/user/include/terminal/readline.h
@@ -0,0 +1,10 @@
+#ifndef TERMINAL_READLINE_H
+#define TERMINAL_READLINE_H
+
+#include <stdint.h>
+
+//returns length of string without null terminator
+//max_length doesn't include null terminator
+uint32_t read_line(char *sz, uint32_t max_length, const char *prompt);
+
+#endif \ No newline at end of file
diff --git a/src/user/include/terminal/terminal.h b/src/user/include/terminal/terminal.h
new file mode 100644
index 0000000..1782173
--- /dev/null
+++ b/src/user/include/terminal/terminal.h
@@ -0,0 +1,57 @@
+#ifndef TERMINAL_TERMINAL_H
+#define TERMINAL_TERMINAL_H
+
+#include <libfont/fonts.h>
+
+#include <pland/syscall.h>
+
+#include <stdarg.h>
+#include <stdint.h>
+
+struct terminal {
+ _window_handle_t window;
+ uint8_t *pixbuf;
+ uint32_t window_width;
+ uint32_t window_height;
+
+ struct font_info *font;
+
+ uint32_t cols;
+ uint32_t rows;
+ char *charbuf;
+
+ uint32_t cursor_y;
+ uint32_t cursor_x;
+
+ uint8_t fg;
+ uint8_t bg;
+};
+
+struct terminal *make_term(struct font_info *font, uint32_t cols, uint32_t rows);
+void del_term(struct terminal *term);
+
+extern struct terminal *active_term;
+
+void paint_term();
+
+void set_color(uint8_t fg, uint8_t bg);
+void clear_term();
+
+void move_cursor(uint32_t new_y, uint32_t new_x);
+
+void cursor_left();
+void cursor_right();
+void cursor_up();
+void cursor_down();
+
+void term_newline();
+void term_add_char(char ch);
+void term_add_sz_no_ww(const char *sz);
+void term_add_sz(const char *sz);
+
+void term_addf_no_ww_v(const char *fmt, va_list args);
+void term_addf_no_ww(const char *fmt, ...);
+void term_addf_v(const char *fmt, va_list args);
+void term_addf(const char *fmt, ...);
+
+#endif \ No newline at end of file
diff --git a/src/user/init/init.c b/src/user/init/init.c
index fb231e0..860c45f 100644
--- a/src/user/init/init.c
+++ b/src/user/init/init.c
@@ -1,32 +1,29 @@
-#include <knob/user.h>
#include <knob/file.h>
#include <knob/task.h>
#define STARTUP_FILE_PATH "sys/startup.rc"
+#define CMD_BUF_LEN 1024
+
+char cmdbuf[CMD_BUF_LEN];
void main() {
struct file *f = open_file(STARTUP_FILE_PATH);
if (!f) {
- tell_user_sz("Could not open " STARTUP_FILE_PATH ".\n");
+ _system_log("Could not open " STARTUP_FILE_PATH ".\n");
return;
}
- tell_user_sz("[init] Reading from " STARTUP_FILE_PATH ".\n");
-
- char cmdbuf[128];
- while (read_line_from_file(f, cmdbuf, 127)) {
- tell_user_sz("[init] Starting ");
- tell_user_sz(cmdbuf);
- tell_user_sz(": ");
- if (run_command(cmdbuf)) {
- tell_user_sz("Succeded.\n");
- yield_task();
- }
- else
- tell_user_sz("Failed.\n");
+ while (read_line_from_file(f, cmdbuf, CMD_BUF_LEN - 1)) {
+ if (cmdbuf[0] == '#')
+ continue;
+ //syslogf(run_command(cmdbuf)
+ // ? "[init] Started %s."
+ // : "[init] Could not run %s."
+ //, cmdbuf);
+ run_command(cmdbuf, 0);
}
close_file(f);
- tell_user_sz("[init] Done starting programs.\n");
+ _system_log("Done starting startup tasks.");
}
diff --git a/src/user/knob/block.c b/src/user/knob/block.c
index 94bd073..90f79e3 100644
--- a/src/user/knob/block.c
+++ b/src/user/knob/block.c
@@ -33,4 +33,28 @@ char *strdup(const char *from) {
char *buf = get_block(end - from);
blockcpy(buf, from, end - from);
return buf;
+}
+
+__attribute__ ((pure))
+bool strequ(const char *a, const char *b) {
+ while (true) {
+ if ((*a == '\0') != (*b == '\0'))
+ return false;
+ if (*a == '\0')
+ return true;
+ if (*a != *b)
+ return false;
+ ++a;
+ ++b;
+ }
+}
+
+__attribute__ ((pure))
+uint32_t strlen(const char *str) {
+ uint32_t len = 0;
+ while (*str) {
+ ++len;
+ ++str;
+ }
+ return len;
} \ No newline at end of file
diff --git a/src/user/knob/env.c b/src/user/knob/env.c
deleted file mode 100644
index 952ab86..0000000
--- a/src/user/knob/env.c
+++ /dev/null
@@ -1,3 +0,0 @@
-#include <stdint.h>
-
-uint32_t current_drive; \ No newline at end of file
diff --git a/src/user/knob/file.c b/src/user/knob/file.c
index f1a039d..3083503 100644
--- a/src/user/knob/file.c
+++ b/src/user/knob/file.c
@@ -1,8 +1,9 @@
-#include <pland/syscall.h>
-#include <pland/pcrt.h>
#include <knob/format.h>
+#include <knob/panic.h>
#include <knob/heap.h>
-#include <knob/env.h>
+
+#include <pland/syscall.h>
+#include <pland/pcrt.h>
struct ofl_node {
struct ofl_node *next;
@@ -27,23 +28,10 @@ struct file {
};
const char *remove_prefix(const char *path, uint8_t *dn_out) {
- if ((path[0] != 's') || (path[1] != 'd'))
- goto no_prefix;
-
- const char *num_part = path + 2;
- for (uint32_t i = 0; num_part[i]; ++i)
- if (num_part[i] == ':') {
-
- uint32_t dn_large;
- if (!try_sntoi(num_part, i, &dn_large) || dn_large > 255)
- goto no_prefix;
-
- *dn_out = (uint8_t)dn_large;
- return num_part + i + 1;
- }
+ if ((path[0] == 's') && (path[1] == 'd'))
+ PANIC("remove_prefix not fully implemented");
-no_prefix:
- *dn_out = current_drive;
+ *dn_out = 0;//change this later to an "active drive" or something
return path;
}
diff --git a/src/user/knob/format.c b/src/user/knob/format.c
index 593b20c..54d50ef 100644
--- a/src/user/knob/format.c
+++ b/src/user/knob/format.c
@@ -1,48 +1,231 @@
-#include <stdbool.h>
-#include <stdint.h>
-
-bool try_sntoi(const char *s, uint32_t n, uint32_t *out) {
- uint32_t calc = 0;
- for (uint32_t i = 0; i < n; ++i) {
- if ((s[i] < '0') || (s[i] > '9'))
- return false;
- calc = calc * 10 + s[i] - '0';
- }
- *out = calc;
- return true;
-}
+#include <knob/block.h>
+#include <knob/panic.h>
+#include <knob/heap.h>
+
+#include <pland/syscall.h>
+#include <pland/pcrt.h>
+
+#include <stdarg.h>
+
+#define FORMAT_BUF_INIT_SIZE 200
+#define FORMAT_BUF_CHUNK_SIZE 50
-__attribute__ ((access (write_only, 2)))
-void itosz(uint32_t i, char *out) {
- if (!i) {
- *(uint16_t *)out = (uint16_t)'0';
+#define BAD_SPEC "%%UNKNOWN FORMAT SPEC%%"
+#define BAD_SPEC_LEN 23
+
+static char *buf;
+static uint32_t buf_s;
+static char *buf_i;
+
+static const char *const hextab = "0123456789abcdef";
+
+static void ensure(uint32_t extra) {
+ const uint32_t total_len = buf_i - buf + extra;
+ if (total_len < buf_s)
return;
+
+ buf_s = (total_len / FORMAT_BUF_CHUNK_SIZE + 1) * FORMAT_BUF_CHUNK_SIZE;
+
+ char *const new_buf = get_block(buf_s);
+ if (!new_buf)
+ PANIC("out of memory in knob format");
+ blockcpy(new_buf, buf, buf_i - buf);
+ free_block(buf);
+ buf_i += new_buf - buf;
+ buf = new_buf;
+}
+
+struct format_spec {
+ uint32_t len;
+ enum {
+ UNKNOWN,
+ CHAR,
+ STRING,
+ UNSIGNED_DECIMAL,
+ HEXADECIMAL
+ //TODO: signed decimal
+ } kind;
+};
+
+static const char *get_format(const char *from, struct format_spec *format_out) {
+ if (*from == 'n') {
+ ++from;
+ format_out->len = -1;
}
- bool zero = false;
- for (uint32_t m = 1000000000; m; m /= 10) {
- uint8_t d = (i / m) % 10;
- if (zero)
- *(out++) = d + '0';
- else if (d) {
- zero = true;
- *(out++) = d + '0';
+ else {
+ uint32_t len = 0;
+ while ((*from >= '0') && (*from <= '9'))
+ len = len * 10 + *(from++) - '0';
+ format_out->len = len;
+ }
+
+ switch (*from) {
+ case 'c':
+ format_out->kind = CHAR;
+ break;
+ case 's':
+ format_out->kind = STRING;
+ break;
+ case 'u':
+ format_out->kind = UNSIGNED_DECIMAL;
+ break;
+ case 'h':
+ case 'x':
+ format_out->kind = HEXADECIMAL;
+ break;
+ default:
+ format_out->kind = UNKNOWN;
+ break;
+ }
+
+ return from + 1;
+}
+
+//allocates new memory
+char *format_v(const char *fmt, va_list args) {
+ buf = get_block(FORMAT_BUF_INIT_SIZE);
+ if (!buf)
+ PANIC("out of memory in knob format");
+ buf_s = FORMAT_BUF_INIT_SIZE;
+ buf_i = buf;
+
+ while (*fmt) {
+ if (*fmt != '%') {
+ ensure(1);
+ *(buf_i++) = *(fmt++);
+ }
+ else if (fmt[1] == '%') {
+ ensure(1);
+ *(buf_i++) = '%';
+ fmt += 2;
+ }
+ else {
+ struct format_spec form;
+ fmt = get_format(fmt + 1, &form);
+ if (form.len == -1)
+ //should passing zero still have the special meaning?
+ form.len = va_arg(args, uint32_t);
+ switch (form.kind) {
+ case UNKNOWN:
+ ensure(BAD_SPEC_LEN);
+ blockcpy(buf_i, BAD_SPEC, BAD_SPEC_LEN);
+ buf_i += BAD_SPEC_LEN;
+ continue;
+
+ uint32_t ch;
+ case CHAR:
+ ch = va_arg(args, uint32_t);
+ ensure(1);
+ *(buf_i++) = (char)ch;
+ continue;
+
+ const char *str;
+ case STRING:
+ str = va_arg(args, const char *);
+ if (!form.len)
+ form.len = strlen(str);
+ ensure(form.len);
+ blockcpy(buf_i, str, form.len);
+ buf_i += form.len;
+ continue;
+
+ uint32_t k;
+ case UNSIGNED_DECIMAL:
+ k = va_arg(args, uint32_t);
+ if (!form.len) {
+ uint32_t n = 10;
+ ++form.len;
+ while (k >= n) {
+ ++form.len;
+ n *= 10;
+ }
+ }
+ ensure(form.len);
+ const uint32_t len_backup = form.len;
+ while (form.len--) {
+ buf_i[form.len] = (k % 10) + '0';
+ k /= 10;
+ }
+ buf_i += len_backup;
+ continue;
+
+ case HEXADECIMAL:
+ k = va_arg(args, uint32_t);
+ if (!form.len)
+ form.len = 8;
+ ensure(form.len);
+ const uint32_t hlen_backup = form.len;
+ while (form.len--) {
+ buf_i[form.len] = hextab[k % 16];
+ k >>= 4;
+ }
+ buf_i += hlen_backup;
+ continue;
+ }
}
}
- *out = '\0';
+
+ *buf_i = '\0';
+ return buf;
+}
+
+//allocates new memory
+char *format(const char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ char *const res = format_v(fmt, args);
+ va_end(args);
+ return res;
+}
+
+void syslogf_v(const char *fmt, va_list args) {
+ char *const msg = format_v(fmt, args);
+ _system_log(msg);
+ free_block(msg);
}
-const char *const hex_digits = "0123456789abcdef";
+void syslogf(const char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ syslogf_v(fmt, args);
+ va_end(args);
+}
-__attribute__ ((access (write_only, 2)))
-void itosz_h8(uint8_t i, char *out) {
- out[0] = hex_digits[i >> 4];
- out[1] = hex_digits[i & 0xf];
- out[2] = '\0';
+//reads a unsigned decimal terminated by either null or whitespace
+//returns length of string plus length of whitespace
+//returns 0 on failure
+uint32_t try_swtou(const char *from, uint32_t *i_out) {
+ const char *const old_from = from;
+ uint32_t v = 0;
+ while (*from && (*from != '\n') && (*from != ' ')) {
+ if ((*from < '0') || (*from > '9'))
+ return 0;
+ v = v * 10 + *(from++) - '0';
+ }
+ *i_out = v;
+ while ((*from == '\n') || (*from == ' '))
+ ++from;
+ return from - old_from;
}
-__attribute__ ((access (write_only, 2)))
-void itosz_h32(uint32_t i, char *out) {
- for (uint8_t digit = 0; digit < 8; ++digit)
- out[digit] = hex_digits[(i >> (28 - digit * 4)) & 0xf];
- out[8] = '\0';
+//reads a hexadecimal terminated by either null or whitespace
+//returns length of string plus length of whitespace
+//returns 0 on failure
+uint32_t try_swtoh(const char *from, uint32_t *i_out) {
+ const char *const old_from = from;
+ uint32_t v = 0;
+ while (*from && (*from != '\n') && (*from != ' ')) {
+ if ((*from >= '0') && (*from <= '9'))
+ v = v * 16 + *(from++) - '0';
+ else if ((*from >= 'a') && (*from <= 'f'))
+ v = v * 16 + *(from++) - 'a' + 10;
+ else if ((*from >= 'A') && (*from <= 'F'))
+ v = v * 16 + *(from++) - 'A' + 10;
+ else
+ return 0;
+ }
+ *i_out = v;
+ while ((*from == '\n') || (*from == ' '))
+ ++from;
+ return from - old_from;
} \ No newline at end of file
diff --git a/src/user/knob/heap.c b/src/user/knob/heap.c
index 49f9339..b770542 100644
--- a/src/user/knob/heap.c
+++ b/src/user/knob/heap.c
@@ -1,4 +1,7 @@
+#include <knob/format.h>
+
#include <pland/syscall.h>
+
#include <stdbool.h>
#include <stdint.h>
@@ -24,23 +27,8 @@ static void add_header(struct block_header *bh) {
__attribute__ ((malloc))
void *get_block(uint32_t bytes) {
-//char nbuf[11];
-//tell_user_sz("[heap::get_block]\n first_block = 0x");
-//itosz_h32((uint32_t)first_block, nbuf);
-//tell_user_sz(nbuf);
-//tell_user_sz("\n");
struct block_header *header = 0;
-
for (struct block_header *ptr = first_block; ptr; ptr = ptr->next) {
- //tell_user_sz(" ptr = 0x");
- //itosz_h32((uint32_t)ptr, nbuf);
- //tell_user_sz(nbuf);
- //tell_user_sz("\n &ptr->allocated = 0x");
- //itosz_h32((uint32_t)&ptr->allocated, nbuf);
- //tell_user_sz(nbuf);
- //tell_user_sz("\n ptr->allocated = ");
- //tell_user_sz(ptr->allocated ? "true\n" : "false\n");
-
if (ptr->allocated)
continue;
if (ptr->length == bytes) {
@@ -63,14 +51,7 @@ void *get_block(uint32_t bytes) {
if (!header) {
uint32_t size_with_header = bytes + sizeof(struct block_header);
if (!(size_with_header % 4096)) {
- //tell_user_sz(" allocate ");
- //itosz(size_with_header / 4096, nbuf);
- //tell_user_sz(nbuf);
- //tell_user_sz(" pages = 0x");
header = _allocate_ram(size_with_header / 4096);
- //itosz_h32((uint32_t)header, nbuf);
- //tell_user_sz(nbuf);
- //tell_user_sz("\n");
if (!header)
return 0;
header->length = bytes;
@@ -78,14 +59,7 @@ void *get_block(uint32_t bytes) {
}
else {
uint32_t pages = (bytes + sizeof(struct block_header) * 2) / 4096 + 1;
- //tell_user_sz(" allocate ");
- //itosz(pages, nbuf);
- //tell_user_sz(nbuf);
- //tell_user_sz(" pages = 0x");
header = _allocate_ram(pages);
- //itosz_h32((uint32_t)header, nbuf);
- //tell_user_sz(nbuf);
- //tell_user_sz("\n");
if (!header)
return 0;
header->length = bytes;
diff --git a/src/user/knob/ipc.c b/src/user/knob/ipc.c
new file mode 100644
index 0000000..dbf1a22
--- /dev/null
+++ b/src/user/knob/ipc.c
@@ -0,0 +1,45 @@
+#include <pland/syscall.h>
+
+//blocking, returns early if other process is dead.
+//return value is number of bytes written.
+uint32_t try_send_ipc(_task_handle_t to, void *buffer, uint32_t size) {
+ const uint32_t size_backup = size;
+ while (size) {
+ uint32_t res = _ipc_send(to, size, buffer);
+ if (!res) {
+ _wait_ipc_read(to);
+ _yield_task();
+ }
+ else if (res == -1)
+ return size_backup - size;
+ else {
+ size -= res;
+ buffer += res;
+ }
+ }
+}
+
+//blocking, returns early if other process is dead.
+//return value is number of bytes read.
+uint32_t read_ipc(_task_handle_t from, void *buffer, uint32_t size) {
+ const uint32_t size_backup = size;
+ while (size) {
+ uint32_t res = _ipc_read(from, size, buffer);
+ if (!res) {
+ _wait_ipc_send(from);
+ _yield_task();
+ }
+ else if (res == -1)
+ return size_backup - size;
+ else {
+ size -= res;
+ buffer += res;
+ }
+ }
+}
+
+void flush_ipc(_task_handle_t from) {
+ uint8_t buf[4096];
+ while (_ipc_read(from, 4096, buf))
+ ;
+} \ No newline at end of file
diff --git a/src/user/knob/key.c b/src/user/knob/key.c
new file mode 100644
index 0000000..1506f3b
--- /dev/null
+++ b/src/user/knob/key.c
@@ -0,0 +1,67 @@
+#include <keypack.h>
+
+static const char no_mod[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, '\t','\n', 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ ' ', 0, 0, 0, 0, 0, 0, '\'', 0, 0, 0, 0, ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 0, ';', 0, '=', 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '[','\\', ']', 0, 0,
+ '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, 0, 0
+};
+
+static const char shifted[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, '\t','\n', 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ ' ', 0, 0, 0, 0, 0, 0, '"', 0, 0, 0, 0, '<', '_', '>', '?',
+ ')', '!', '@', '#', '$', '%', '^', '&', '*', '(', 0, ':', 0, '+', 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '{', '|', '}', 0, 0,
+ '~', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 0, 0, 0, 0, 0
+};
+
+static const char caps[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, '\t','\n', 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ ' ', 0, 0, 0, 0, 0, 0, '\'', 0, 0, 0, 0, ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 0, ';', 0, '=', 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '[','\\', ']', 0, 0,
+ '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 0, 0, 0, 0, 0
+};
+
+static const char sh_caps[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, '\t','\n', 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ ' ', 0, 0, 0, 0, 0, 0, '"', 0, 0, 0, 0, '<', '_', '>', '?',
+ ')', '!', '@', '#', '$', '%', '^', '&', '*', '(', 0, ':', 0, '+', 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '{', '|', '}', 0, 0,
+ '~', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, 0, 0
+};
+
+static const char num[] = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '+', '\n', '-', '.', '/'
+};
+
+__attribute__ ((pure))
+char key_to_char(struct key_packet kp) {
+ if (kp.key_id < 0x80) {
+ const char ch = (kp.modifiers & SHIFTS
+ ? kp.modifiers & CAPS
+ ? sh_caps : shifted
+ : kp.modifiers & CAPS
+ ? caps : no_mod)[kp.key_id];
+ return ch ? kp.modifiers & ALTS ? 0x80 & ch : ch : 0;
+ }
+
+ else if ((kp.modifiers & NUM) && ((kp.key_id & 0xf0) == 0xb0))
+ return num[kp.key_id & 0x0f];
+
+ else
+ return 0;
+} \ No newline at end of file
diff --git a/src/user/knob/panic.c b/src/user/knob/panic.c
new file mode 100644
index 0000000..1ff663c
--- /dev/null
+++ b/src/user/knob/panic.c
@@ -0,0 +1,12 @@
+#include <knob/format.h>
+
+#include <pland/syscall.h>
+#include <pland/pcrt.h>
+
+#include <stdint.h>
+
+__attribute__ ((noreturn))
+void panic(const char *filename, uint32_t line, const char *message) {
+ _system_log(format("panic in %s on line %u: %s", filename, line, message));
+ __pcrt_quit();
+} \ No newline at end of file
diff --git a/src/user/knob/task.c b/src/user/knob/task.c
index df5d38f..3bf3e85 100644
--- a/src/user/knob/task.c
+++ b/src/user/knob/task.c
@@ -4,7 +4,7 @@
#include <knob/heap.h>
#include <knob/block.h>
-_task_handle_t run_command(const char *path) {
+_task_handle_t run_command(const char *path, _task_handle_t stdio_task) {
uint8_t dn;
path = remove_prefix(path, &dn);
@@ -14,23 +14,21 @@ _task_handle_t run_command(const char *path) {
blockcpy(new_path, path, ptr - path);
new_path[ptr - path] = '\0';
- bool succeded = _start_task(dn, new_path, ptr + 1);
+ bool succeded = _start_task(dn, new_path, ptr + 1, stdio_task);
free_block(new_path);
return succeded;
}
- return _start_task(dn, path, "");
+ return _start_task(dn, path, "", stdio_task);
}
-bool try_run_command_blocking(const char *path) {
- _task_handle_t handle = run_command(path);
+bool try_run_command_blocking(const char *path, _task_handle_t stdio_task) {
+ _task_handle_t handle = run_command(path, stdio_task);
if (!handle)
return false;
- _wait_for_task(handle);
- _yield_task();
+ while (_is_task_running(handle)) {
+ _wait_for_task(handle);
+ _yield_task();
+ }
return true;
-}
-
-void yield_task() {
- _yield_task();
} \ No newline at end of file
diff --git a/src/user/knob/user.c b/src/user/knob/user.c
deleted file mode 100644
index 1e273bb..0000000
--- a/src/user/knob/user.c
+++ /dev/null
@@ -1,299 +0,0 @@
-#include <pland/syscall.h>
-#include <knob/block.h>
-#include <knob/heap.h>
-#include <stdint.h>
-#include <stdbool.h>
-
-static const uint8_t caps_and_shift[] = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
- 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x22,
- 0x28, 0x29, 0x2a, 0x2b, 0x3c, 0x5f, 0x3e, 0x3f,
- 0x29, 0x21, 0x40, 0x23, 0x24, 0x25, 0x5e, 0x26,
- 0x2a, 0x28, 0x3a, 0x3a, 0x3c, 0x2d, 0x3e, 0x3f,
-
- 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
- 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
- 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
- 0x78, 0x79, 0x7a, 0x57, 0x7c, 0x7d, 0x5e, 0x5f,
- 0x7e, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
- 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
- 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
- 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x00,
-
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-static const uint8_t caps_no_shift[] = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
- 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
- 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
- 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
- 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
-
- 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
- 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
- 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
- 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
- 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
- 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
- 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
- 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x00,
-
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-static const uint8_t shifted[] = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
- 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x22,
- 0x28, 0x29, 0x2a, 0x2b, 0x3c, 0x5f, 0x3e, 0x3f,
- 0x29, 0x21, 0x40, 0x23, 0x24, 0x25, 0x5e, 0x26,
- 0x2a, 0x28, 0x3a, 0x3a, 0x3c, 0x2d, 0x3e, 0x3f,
-
- 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
- 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
- 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
- 0x78, 0x79, 0x7a, 0x57, 0x7c, 0x7d, 0x5e, 0x5f,
- 0x7e, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
- 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
- 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
- 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x00,
-
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-__attribute__ ((const))
-char key_to_char(_key_code_t key) {
- return
- key & _KEY_CAPS
- ? key & _KEY_SHIFT
- ? caps_and_shift[key & 0xff]
- : caps_no_shift[key & 0xff]
- : key & _KEY_SHIFT
- ? shifted[key & 0xff]
- : key & 0xff;
-}
-
-static char get_key_char() {
- _key_code_t key;
- while (!(key = _get_key()))
- _yield_task();
- return key_to_char(key);
-}
-
-void tell_user_sz(const char *sz) {
- _log_string(sz);
-}
-
-//return value and max_length don't include null terminator
-uint32_t ask_user_line_sz(char *sz, uint32_t max_length) {
- char log_buf[2];
- log_buf[1] = '\0';
-
- uint32_t i;
- for (i = 0; i != max_length; ++i) {
- char key;
- replace:
- key = get_key_char();
- if (!key)
- goto replace;
- if (key & 0x80)
- goto replace;//TODO
- if (key == '\b') {
- if (i) {
- --i;
- _log_string("\b");
- }
- goto replace;
- }
-
- log_buf[0] = key;
- _log_string(log_buf);
-
- if (key == '\n')
- break;
- sz[i] = key;
- }
-
- sz[i] = '\0';
- return i;
-}
-
-struct history_entry {
- struct history_entry *prev;
- struct history_entry *next;
- const char *contents;
-};
-
-struct history {
- struct history_entry *earliest_history_item;
- struct history_entry *latest_history_item;
- uint32_t max_entries;
- uint32_t cur_entries;
-};
-
-struct history *new_history(uint32_t max_entries) {
- struct history *new = get_block(sizeof(struct history));
- new->latest_history_item = 0;
- new->earliest_history_item = 0;
- new->max_entries = max_entries;
- new->cur_entries = 0;
- return new;
-}
-
-void del_history(struct history *hs) {
- free_block(hs);
- for (struct history_entry *he = hs->latest_history_item; he; he = he->prev) {
- free_block(he);
- free_block(he->contents);
- }
-}
-
-//return value and max_length don't include null terminator
-uint32_t ask_user_line_sz_with_history(char *sz, uint32_t max_length, struct history *hs) {
- char log_buf[2];
- log_buf[1] = '\0';
- struct history_entry *cur_he = 0;
-
- uint32_t i;
- for (i = 0; i != max_length; ++i) {
- char key;
- replace:
- key = get_key_char();
- if (!key)
- goto replace;
- if (key == (char)_KEY_UP) {
- struct history_entry *new_cur_he = cur_he ? cur_he->prev : hs->latest_history_item;
- if (new_cur_he) {
- cur_he = new_cur_he;
- for (uint32_t j = 0; j < i; ++j)
- _log_string("\b");
- i = strcpy(sz, cur_he->contents);
- _log_string(sz);
- }
- goto replace;
- }
- if (key == (char)_KEY_DOWN) {
- cur_he = cur_he ? cur_he->next : 0;
- for (uint32_t j = 0; j < i; ++j)
- _log_string("\b");
- if (cur_he) {
- i = strcpy(sz, cur_he->contents);
- _log_string(sz);
- }
- else
- i = 0;
- goto replace;
- }
- if (key & 0x80)
- goto replace;//TODO
- if (key == '\b') {
- if (i) {
- --i;
- _log_string("\b");
- }
- goto replace;
- }
-
- log_buf[0] = key;
- _log_string(log_buf);
-
- if (key == '\n')
- break;
- sz[i] = key;
- }
-
- sz[i] = '\0';
-
- struct history_entry *new_he = get_block(sizeof(struct history_entry));
- new_he->contents = strdup(sz);
-
- new_he->next = 0;
- if (hs->latest_history_item) {
- new_he->prev = hs->latest_history_item;
- hs->latest_history_item->next = new_he;
- }
- else
- new_he->prev = 0;
- hs->latest_history_item = new_he;
- if (!hs->earliest_history_item)
- hs->earliest_history_item = new_he;
- if (hs->max_entries == hs->cur_entries) {
- free_block(hs->earliest_history_item);
- free_block(hs->earliest_history_item->contents);
- hs->earliest_history_item->next->prev = 0;
- hs->earliest_history_item = hs->earliest_history_item->next;
- }
- else
- ++(hs->cur_entries);
-
- for (struct history_entry *check_he = hs->latest_history_item->prev; check_he; check_he = check_he->prev) {
- if (blockequ(check_he->contents, sz, i + 1)) {
- check_he->next->prev = check_he->prev;
- if (check_he->prev)
- check_he->prev->next = check_he->next;
- else
- hs->earliest_history_item = check_he->next;
- free_block(check_he);
- free_block(check_he->contents);
- }
- }
-
- return i;
-} \ No newline at end of file
diff --git a/src/user/libfont/bdf.c b/src/user/libfont/bdf.c
new file mode 100644
index 0000000..2c19a15
--- /dev/null
+++ b/src/user/libfont/bdf.c
@@ -0,0 +1,99 @@
+#include <libfont/fonts.h>
+
+#include <knob/format.h>
+#include <knob/panic.h>
+#include <knob/block.h>
+#include <knob/heap.h>
+#include <knob/file.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#define LINE_BUF_SIZE 1000
+char line_buf[LINE_BUF_SIZE];
+
+static inline uint8_t hex_to_n(char ch) {
+ return ch - (ch >= 'A' ? 'A' - 10 : '0');
+}
+
+//very minimal implementation
+bool try_load_bdf(const char *path, struct font_info *into) {
+ struct file *f = open_file(path);
+ if (!f)
+ PANIC("Can't open font file sent by get_font.");
+
+ read_line_from_file(f, line_buf, LINE_BUF_SIZE - 1);
+ if (!strequ(line_buf, "STARTFONT 2.1")) {
+ close_file(f);
+ return false;
+ }
+
+ for (uint16_t i = 0; i < 256; ++i)
+ into->bitmaps[i] = 0;
+ into->space_height = -1;
+ into->space_width = -1;
+ into->char_height = -1;
+ into->char_width = -1;
+
+ uint32_t current = 0;
+
+ while (read_line_from_file(f, line_buf, LINE_BUF_SIZE - 1)) {
+ if (blockequ(line_buf, "FONTBOUNDINGBOX ", 16)) {
+ uint32_t n;
+ uint32_t l = try_swtou(line_buf + 16, &n);
+ if (!l)
+ goto bad_format;
+ into->space_width = n;
+ into->char_width = n;
+ l = try_swtou(line_buf + 16 + l, &n);
+ if (!l)
+ goto bad_format;
+ into->space_height = n;
+ into->char_height = n;
+ }
+ else if (blockequ(line_buf, "ENCODING ", 9)) {
+ if (!try_swtou(line_buf + 9, &current))
+ goto bad_format;
+ }
+ else if (strequ(line_buf, "BITMAP")) {
+ if (current >= 256)
+ continue;
+ bool *bm = get_block(into->char_height * into->char_width);
+ if (!bm)
+ PANIC("could not allocate memory for font character bitmap");
+ into->bitmaps[current] = bm;
+
+ for (uint32_t y = 0; y < into->char_height; ++y) {
+ read_line_from_file(f, line_buf, LINE_BUF_SIZE - 1);
+ for (uint32_t x = 0; x < into->char_width; ++x)
+ bm[y * into->char_width + x] = (hex_to_n(line_buf[x / 4]) >> (3 - x % 4)) & 1;
+ }
+ }
+ }
+
+ close_file(f);
+ f = 0;
+
+ if ((into->char_height == -1) ||
+ (into->char_width == -1) ||
+ (into->space_height == -1) ||
+ (into->space_width == -1))
+ goto bad_format;
+
+ if (!into->bitmaps[0]) {
+ const uint32_t bytes = (into->char_height * into->char_width - 1) / 8 + 1;
+ into->bitmaps[0] = get_block(bytes);
+ for (uint32_t i = 0; i < bytes; ++i)
+ into->bitmaps[0][i] = 0b01011010;
+ }
+
+ return true;
+
+bad_format:
+ if (f)
+ close_file(f);
+ for (uint16_t i = 0; i < 256; ++i)
+ if (into->bitmaps[i])
+ free_block(into->bitmaps[i]);
+ return false;
+} \ No newline at end of file
diff --git a/src/user/libfont/bdf.h b/src/user/libfont/bdf.h
new file mode 100644
index 0000000..4ed4189
--- /dev/null
+++ b/src/user/libfont/bdf.h
@@ -0,0 +1,8 @@
+#ifndef LIBFONT_BDF_H
+#define LIBFONT_BDF_H
+
+#include <stdbool.h>
+
+bool try_load_bdf(const char *path, struct font_info *into);
+
+#endif \ No newline at end of file
diff --git a/src/user/libfont/filist.c b/src/user/libfont/filist.c
new file mode 100644
index 0000000..ae24429
--- /dev/null
+++ b/src/user/libfont/filist.c
@@ -0,0 +1,33 @@
+#include <libfont/fonts.h>
+#include <knob/block.h>
+#include <knob/heap.h>
+
+struct dict_entry {
+ char *name;
+ struct font_info *fi;
+ struct dict_entry *prev;
+} *last_entry = 0;
+
+__attribute__ ((pure))
+struct font_info *find_entry(const char *name) {
+ for (struct dict_entry *i = last_entry; i; i = i->prev)
+ if (strequ(i->name, name))
+ return i->fi;
+ return 0;
+}
+
+struct font_info *new_entry(const char *name) {
+ struct dict_entry *const nde = get_block(sizeof(struct dict_entry));
+ nde->name = strdup(name);
+ nde->fi = get_block(sizeof(struct font_info));
+ nde->prev = last_entry;
+ last_entry = nde;
+ return nde->fi;
+}
+
+void del_last() {//only called when last_entry isn't 0
+ free_block(last_entry->name);
+ free_block(last_entry->fi);
+ free_block(last_entry);
+ last_entry = last_entry->prev;
+} \ No newline at end of file
diff --git a/src/user/libfont/filist.h b/src/user/libfont/filist.h
new file mode 100644
index 0000000..c78c640
--- /dev/null
+++ b/src/user/libfont/filist.h
@@ -0,0 +1,8 @@
+#ifndef LIBFONT_FILIST_H
+#define LIBFONT_FILIST_H
+
+struct font_info *find_entry(const char *name) __attribute__ ((pure));
+struct font_info *new_entry(const char *name);
+void del_last();
+
+#endif \ No newline at end of file
diff --git a/src/user/libfont/fonts.c b/src/user/libfont/fonts.c
new file mode 100644
index 0000000..1692992
--- /dev/null
+++ b/src/user/libfont/fonts.c
@@ -0,0 +1,66 @@
+#include <libfont/fonts.h>
+#include <knob/format.h>
+#include <knob/block.h>
+#include <knob/heap.h>
+#include <knob/file.h>
+
+#include "filist.h"
+#include "bdf.h"
+
+#define FONT_PATH "fonts/"
+#define FONT_PATH_L 6
+
+struct font_loader_t {
+ const char *ext;
+ bool (*func)(const char *, struct font_info *);
+} font_loaders[] = {
+ { .ext = ".bdf",
+ .func = try_load_bdf
+ },
+ { .ext = ""
+ }
+};
+
+struct font_info *get_font(const char *name) {
+ struct font_info *font = find_entry(name);
+ if (font)
+ return font;
+ font = new_entry(name);
+ if (!font)
+ return 0;//out of memory?
+
+ const uint32_t name_len = strlen(name);
+ for (struct font_loader_t *i = font_loaders; i->ext[0]; ++i) {
+ char *buf = get_block(FONT_PATH_L + name_len + strlen(i->ext) + 1);
+ blockcpy(buf, FONT_PATH, FONT_PATH_L);
+ blockcpy(buf + FONT_PATH_L, name, name_len);
+ strcpy(buf + FONT_PATH_L + name_len, i->ext);
+ struct file *f = open_file(buf);
+ if (!f) {
+ free_block(buf);
+ continue;
+ }
+ syslogf("[libfont] Loading %s%s...", name, i->ext);
+ if (i->func(buf, font)) {
+ close_file(f);
+ free_block(buf);
+ syslogf("[libfont] Loaded %s%s.", name, i->ext);
+ return font;
+ }
+ close_file(f);
+ free_block(buf);
+ syslogf("[libfont] Failed to load %s%s.", name, i->ext);
+ }
+ del_last();
+ return 0;
+}
+
+void put_char(const struct font_info *font, char ch, uint8_t *pb_ptr, uint32_t pb_pitch, uint8_t bg, uint8_t fg) {
+//char *const msg = format("put_char(font = 0x%x, ch = '%c', pb_ptr = 0x%x, pb_pitch = %u, bg = 0x%2x, fg = 0x%2x);", font, ch, pb_ptr, pb_pitch, bg, fg);
+//_system_log(msg);
+//free_block(msg);
+ const bool *const bitmap = font->bitmaps[(uint8_t)ch] ? font->bitmaps[(uint8_t)ch] : font->bitmaps[0];
+ for (uint32_t y = 0; y < font->char_height; ++y)
+ for (uint32_t x = 0; x < font->char_width; ++x)
+ pb_ptr[y * pb_pitch + x] = bitmap[y * font->char_width + x] ? fg : bg;
+} \ No newline at end of file
diff --git a/src/user/manual/manual.c b/src/user/manual/manual.c
deleted file mode 100644
index d1af406..0000000
--- a/src/user/manual/manual.c
+++ /dev/null
@@ -1,303 +0,0 @@
-#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;
-
-char *name_backup = 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 (name_backup)
- free_block(name_backup);
- name_backup = strdup(name);
-
- 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);
-}
-
-struct stack_entry {
- struct stack_entry *down;
- char *name;
- uint32_t line;
-};
-
-struct stack_entry *stack_top = 0;
-
-void push() {
- struct stack_entry *new_entry = get_block(sizeof(struct stack_entry));
- new_entry->down = stack_top;
- new_entry->name = strdup(name_backup);
- new_entry->line = line_on;
- stack_top = new_entry;
-}
-
-void pop() {
- if (stack_top) {
- load_file(stack_top->name);
- scroll_to(stack_top->line);
- free_block(stack_top->name);
- free_block(stack_top);
- stack_top = stack_top->down;
- }
-}
-
-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) {
- push();
- load_file(cur_link->lto);
- }
- break;
- case _KEY_ESC:
- if (stack_top)
- pop();
- break;
- case 'q':
- return;
- }
- }
-} \ No newline at end of file
diff --git a/src/user/meminfo/meminfo.c b/src/user/meminfo/meminfo.c
index dd1d371..124a136 100644
--- a/src/user/meminfo/meminfo.c
+++ b/src/user/meminfo/meminfo.c
@@ -1,19 +1,30 @@
-#include <pland/syscall.h>
-#include <knob/user.h>
-#include <knob/format.h>
-
-void main() {
- char nbuf[11];
+#include <popups/info.h>
- tell_user_sz("Kernel dynamic memory remaining: ");
-
- itosz(_kernel_dynamic_area_left() * 4, nbuf);
- tell_user_sz(nbuf);
- tell_user_sz("k\n");
+#include <pland/syscall.h>
- tell_user_sz("Userspace memory remaining: ");
+static const struct key_packet meminfo_quits[] = {
+ { .key_id = KEY_ESCAPE, .modifiers = NO_MODS },
+ { .key_id = KEY_F5, .modifiers = NO_MODS },
+ { .key_id = 0 }
+};
- itosz(_total_userspace_left() * 4, nbuf);
- tell_user_sz(nbuf);
- tell_user_sz("k\n");
+void main() {
+ struct popup p;
+redo:
+ info_popupf(&p,
+ "kernel memory free: %uk\n"
+ "userspace memory free: %uk / %uk\n"
+ "Escape to quit, F5 to refresh.",
+ 0x10, 0x08,
+ _kernel_dynamic_area_left() * 4,
+ _total_userspace_left() * 4,
+ _total_userspace_size() * 4
+ );
+ //hacky, i should really make info_popup take an arg
+ p.quit_binds = meminfo_quits;
+ make_modal(&p);
+ if (p.quit_as.key_id == KEY_F5)
+ //i should make popups have changable text
+ //(make a new pixbuf but reuse the window)
+ goto redo;
} \ No newline at end of file
diff --git a/src/user/popups/info.c b/src/user/popups/info.c
new file mode 100644
index 0000000..81a09e9
--- /dev/null
+++ b/src/user/popups/info.c
@@ -0,0 +1,99 @@
+#include <popups/popup.h>
+
+#include <libfont/fonts.h>
+
+#include <knob/format.h>
+#include <knob/heap.h>
+
+#include <stdint.h>
+#include <stdarg.h>
+
+#define BORDER_SIZE 2
+//includes border
+#define PADDING 8
+#define FONT "berry"
+
+#define BORDER_COLOR 0x10
+#define BG_COLOR 0x07
+#define FG_COlOR 0x10
+
+static const struct font_info *info_font = 0;
+
+static const struct key_packet info_quits[] = {
+ { .key_id = KEY_ESCAPE, .modifiers = NO_MODS },
+ { .key_id = 0 }
+};
+
+void info_popup(struct popup *into, const char *msg, uint8_t fg, uint8_t bg) {
+ if (!info_font)
+ info_font = get_font(FONT);
+
+ uint32_t w = 0, h = 1, lw = 0;
+ for (const char *i = msg; *i; ++i)
+ if (*i == '\n') {
+ ++h;
+ if (lw > w)
+ w = lw;
+ lw = 0;
+ }
+ else
+ ++lw;
+ if (lw > w)
+ w = lw;
+
+ into->has_quit = false;
+ into->quit_binds = (struct key_packet *)info_quits;
+ into->free_quit_binds = false;
+
+ const uint32_t pitch = info_font->space_width * w + 2 * PADDING;
+ const uint32_t height = info_font->space_height * h + 2 * PADDING;
+
+ uint8_t *const pixbuf = get_block(pitch * height);
+
+ for (uint32_t i = 0; i < pitch * BORDER_SIZE; ++i)
+ pixbuf[i] = BORDER_COLOR;
+ for (uint32_t y = BORDER_SIZE; y < height - BORDER_SIZE; ++y) {
+ for (uint32_t x = 0; x < BORDER_SIZE; ++x)
+ pixbuf[y * pitch + x] = BORDER_COLOR;
+ for (uint32_t x = pitch - BORDER_SIZE; x < pitch; ++x)
+ pixbuf[y * pitch + x] = BORDER_COLOR;
+ }
+ for (uint32_t i = 0; i < pitch * BORDER_SIZE; ++i)
+ pixbuf[(height - BORDER_SIZE) * pitch + i] = BORDER_COLOR;
+
+ for (uint32_t y = BORDER_SIZE; y < height - BORDER_SIZE; ++y)
+ for (uint32_t x = BORDER_SIZE; x < pitch - BORDER_SIZE; ++x)
+ pixbuf[y * pitch + x] = BG_COLOR;
+
+ uint32_t my = 0;
+ uint32_t mx = 0;
+ --msg;
+ while (*++msg) {
+ if (*msg == '\n') {
+ ++my;
+ mx = 0;
+ }
+ else {
+ //syslogf("calling put_char(0x%x, '%c', pixbuf + %u, %u, 0x%2x, 0x%2x)", info_font, *msg,
+ // (my * info_font->space_height + PADDING) * pitch + mx * info_font->space_width + PADDING,
+ // pitch, BG_COLOR, FG_COlOR);
+ put_char(info_font, *msg, pixbuf + (my * info_font->space_height + PADDING) * pitch + mx++ * info_font->space_width + PADDING, pitch, BG_COLOR, FG_COlOR);
+ }
+ }
+
+ into->pixbuf = pixbuf;
+ into->handle = _new_window(pitch, height, pixbuf);
+}
+
+void info_popupf_v(struct popup *into, const char *text, uint8_t fg, uint8_t bg, va_list args) {
+ char *const msg = format_v(text, args);
+ info_popup(into, msg, fg, bg);
+ free_block(msg);
+}
+
+void info_popupf(struct popup *into, const char *text, uint8_t fg, uint8_t bg, ...) {
+ va_list args;
+ va_start(args, bg);
+ info_popupf_v(into, text, fg, bg, args);
+ va_end(args);
+} \ No newline at end of file
diff --git a/src/user/popups/popup.c b/src/user/popups/popup.c
new file mode 100644
index 0000000..d214f81
--- /dev/null
+++ b/src/user/popups/popup.c
@@ -0,0 +1,45 @@
+#include <popups/popup.h>
+
+#include <knob/format.h>
+#include <knob/heap.h>
+
+#include <pland/syscall.h>
+
+void handle_actions(struct popup *p) {
+ if (p->has_quit)
+ return;
+ struct window_action a;
+ while (1) {
+ _get_win_action(p->handle, &a);
+ if (a.action_type == NOT_READY)
+ return;
+ if ((a.action_type == KEY_DOWN)) {
+ //syslogf("got key 0x%2x, 0x%3x", a.as_key.key_id, a.as_key.modifiers);
+ for (const struct key_packet *kp = p->quit_binds; kp->key_id; ++kp) {
+ //syslogf("checking against 0x%2x, 0x%3x", kp->key_id, kp->modifiers);
+ if ((a.as_key.key_id == kp->key_id) && (a.as_key.modifiers == kp->modifiers)) {
+ p->has_quit = true;
+ p->quit_as = a.as_key;
+ return;
+ }
+ }
+ }
+ }
+}
+
+void delete_popup(struct popup *p) {
+ _delete_window(p->handle);
+ free_block(p->pixbuf);
+ if (p->free_quit_binds)
+ free_block(p->quit_binds);
+}
+
+void make_modal(struct popup *p) {
+ handle_actions(p);
+ while (!p->has_quit) {
+ _wait_for_action();
+ _yield_task();
+ handle_actions(p);
+ }
+ delete_popup(p);
+} \ No newline at end of file
diff --git a/src/user/runtimes/c/elf.ld b/src/user/runtimes/c/elf.ld
index f321be2..3e9a034 100644
--- a/src/user/runtimes/c/elf.ld
+++ b/src/user/runtimes/c/elf.ld
@@ -11,6 +11,7 @@ SECTIONS {
.__pcrt_before_main : {
__pcrt_before_main_start = .;
*(.__pcrt_before_main)
+ *(.init_array)
__pcrt_before_main_end = .;
}
diff --git a/src/user/runtimes/c/entry.asm b/src/user/runtimes/c/pcrt.asm
index bba8060..85c898c 100644
--- a/src/user/runtimes/c/entry.asm
+++ b/src/user/runtimes/c/pcrt.asm
@@ -2,6 +2,8 @@ bits 32
global __pcrt_entry
global __pcrt_quit
+global calling_task
+global stdio_task
extern main
extern __pcrt_before_main_start
@@ -11,7 +13,8 @@ extern __pcrt_before_quit_end
section .text
__pcrt_entry:
- mov esp, stack
+ mov dword [calling_task], esi
+ mov dword [stdio_task], edi
push edx
mov ebx, __pcrt_before_main_start
@@ -37,6 +40,6 @@ __pcrt_quit:
.end_task:
int 0x38
-section .stack nobits alloc noexec write align=16
-resb 4096
-stack: \ No newline at end of file
+section .bss
+calling_task resd 1
+stdio_task resd 1 \ No newline at end of file
diff --git a/src/user/terminal/readline.c b/src/user/terminal/readline.c
new file mode 100644
index 0000000..37ef54b
--- /dev/null
+++ b/src/user/terminal/readline.c
@@ -0,0 +1,104 @@
+#include <terminal/terminal.h>
+
+#include <knob/format.h>
+#include <knob/heap.h>
+#include <knob/key.h>
+
+#include <pland/syscall.h>
+
+#include <stdint.h>
+
+//returns length of string without null terminator
+//max_length doesn't include null terminator
+uint32_t read_line(char *sz, uint32_t max_length, const char *prompt) {
+ uint32_t i = 0;
+ uint32_t l = 0;
+
+ term_add_sz_no_ww(prompt);
+ paint_term();
+
+ const _window_handle_t handle = active_term->window;
+ struct window_action action;
+ while (1) {
+ _get_win_action(handle, &action);
+ switch (action.action_type) {
+ case NOT_READY:
+ _wait_for_action();
+ _yield_task();
+ continue;
+ case KEY_DOWN:
+ //;char *const debug_msg = format("got key 0x%2x, 0x%3x", action.as_key.key_id, action.as_key.modifiers);
+ // _system_log(debug_msg);
+ // free_block(debug_msg);
+ switch (action.as_key.key_id) {
+ case KEY_DELETE:
+ if (i != l) {
+ cursor_right();
+ ++i;
+ }
+ case KEY_BSPACE:
+ if (!i)
+ continue;
+ --l;
+ --i;
+ for (uint8_t j = i; j < l; ++j)
+ sz[j] = sz[j + 1];
+ sz[l] = '\0';
+ cursor_left();
+ uint32_t cursor_backup_x = active_term->cursor_x;
+ uint32_t cursor_backup_y = active_term->cursor_y;
+ term_add_sz_no_ww(sz + i);
+ term_add_char(' ');
+ move_cursor(cursor_backup_y, cursor_backup_x);
+ paint_term();
+ continue;
+ case KEY_ENTER:
+ term_newline();
+ paint_term();
+ sz[l] = '\0';
+ return l;
+ case KEY_HOME:
+ case KEY_UP_ARROW:
+ for (; i; --i)
+ cursor_left();
+ paint_term();
+ continue;
+ case KEY_END:
+ case KEY_DOWN_ARROW:
+ for (; i != l; ++i)
+ cursor_right();
+ paint_term();
+ continue;
+ case KEY_LEFT_ARROW:
+ if (i) {
+ cursor_left();
+ paint_term();
+ --i;
+ }
+ continue;
+ case KEY_RIGHT_ARROW:
+ if (i != l) {
+ cursor_right();
+ paint_term();
+ ++i;
+ }
+ continue;
+ default:
+ if (i == max_length)
+ continue;
+ char ch = key_to_char(action.as_key);
+ if (ch) {
+ term_add_char(ch);
+ paint_term();
+ sz[i] = ch;
+ if (i == l)
+ ++l;
+ ++i;
+ }
+ continue;
+ }
+ default:
+ continue;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/user/terminal/terminal.c b/src/user/terminal/terminal.c
new file mode 100644
index 0000000..7961fd5
--- /dev/null
+++ b/src/user/terminal/terminal.c
@@ -0,0 +1,284 @@
+#include <terminal/terminal.h>
+
+#include <libfont/fonts.h>
+
+#include <knob/format.h>
+#include <knob/heap.h>
+
+struct term_list_entry {
+ struct terminal term;
+ struct term_list_entry *next;
+ struct term_list_entry *prev;
+};
+
+struct term_list_entry *last_term = 0;
+struct terminal *active_term = 0;
+
+struct terminal *make_term(struct font_info *font, uint32_t cols, uint32_t rows) {
+ if (!font)
+ return 0;
+
+ struct term_list_entry *next_entry = get_block(sizeof(struct term_list_entry));
+ if (!next_entry)
+ return 0;
+
+ char *const cb = get_block(cols * rows);
+
+ if (!cb) {
+ free_block(next_entry);
+ return 0;
+ }
+
+ const uint32_t w = cols * font->space_width;
+ const uint32_t h = rows * font->space_height;
+
+ uint8_t *const pb = get_block(w * h);
+ if (!pb) {
+ free_block(next_entry);
+ free_block(cb);
+ return 0;
+ }
+
+ _window_handle_t win = _new_window(w, h, pb);
+ if (!win) {
+ free_block(next_entry);
+ free_block(cb);
+ free_block(pb);
+ return 0;
+ }
+
+ for (char *i = cb; i < cb + cols * rows; ++i)
+ *i = ' ';
+ for (uint8_t *i = pb; i < pb + w * h; ++i)
+ *i = 0x10;
+
+ next_entry->term.window = win;
+ next_entry->term.pixbuf = pb;
+ next_entry->term.window_width = w;
+ next_entry->term.window_height = h;
+
+ next_entry->term.font = font;
+
+ next_entry->term.cols = cols;
+ next_entry->term.rows = rows;
+ next_entry->term.charbuf = cb;
+
+ next_entry->term.cursor_y = 0;
+ next_entry->term.cursor_x = 0;
+
+ next_entry->term.fg = 0x0f;
+ next_entry->term.bg = 0x10;
+
+ next_entry->prev = last_term;
+ next_entry->next = 0;
+
+ if (last_term)
+ last_term->next = next_entry;
+ last_term = next_entry;
+
+ return (struct terminal *)next_entry;
+}
+
+void del_term(struct terminal *term) {
+ _delete_window(term->window);
+ free_block(term->pixbuf);
+ free_block(term->charbuf);
+
+ free_block(term);//coincides with the term_list_entry
+ if (active_term == term)
+ active_term = 0;
+
+ for (struct term_list_entry *i = last_term; i; i = i->prev)
+ if (i == (struct term_list_entry *)term) {
+ if (i->prev)
+ i->prev->next = i->next;
+ if (i->next)
+ i->next->prev = i->prev;
+ if (i == last_term)
+ last_term = i->prev;
+ return;
+ }
+}
+
+static void draw_char(uint32_t y, uint32_t x, bool inverted) {
+ put_char(active_term->font, active_term->charbuf[y * active_term->cols + x], active_term->pixbuf + (y * active_term->cols * active_term->font->space_height + x) * active_term->font->space_width, active_term->window_width, inverted ? active_term->fg : active_term->bg, inverted ? active_term->bg : active_term->fg);
+}
+
+static void draw_cursor() {
+ draw_char(active_term->cursor_y, active_term->cursor_x, true);
+}
+
+void paint_term() {
+ _paint_window(active_term->window);
+}
+
+void move_cursor(uint32_t new_y, uint32_t new_x) {
+ draw_char(active_term->cursor_y, active_term->cursor_x, false);
+ active_term->cursor_y = new_y;
+ active_term->cursor_x = new_x;
+ draw_cursor();
+}
+
+static void redraw_term() {
+ for (uint32_t y = 0; y < active_term->rows; ++y)
+ for (uint32_t x = 0; x < active_term->cols; ++x)
+ draw_char(y, x, false);
+ draw_cursor();
+}
+
+void set_color(uint8_t fg, uint8_t bg) {
+ active_term->fg = fg;
+ active_term->bg = bg;
+ redraw_term();
+}
+
+void clear_term() {
+ for (char *i = active_term->charbuf, *const e = i + active_term->cols * active_term->rows; i != e; ++i)
+ *i = ' ';
+ for (uint8_t *i = active_term->pixbuf, *const e = i + active_term->window_width * active_term->window_height; i != e; ++i)
+ *i = active_term->bg;
+ move_cursor(0, 0);
+}
+
+void cursor_up() {
+ draw_char(active_term->cursor_y, active_term->cursor_x, false);
+ if (active_term->cursor_y)
+ --active_term->cursor_y;
+ else
+ //eventually, maybe scroll back through a longer terminal buffer
+ active_term->cursor_x = 0;
+ draw_cursor();
+}
+
+void cursor_left() {
+ draw_char(active_term->cursor_y, active_term->cursor_x, false);
+ if (active_term->cursor_x) {
+ --active_term->cursor_x;
+ draw_cursor();
+ }
+ else {
+ active_term->cursor_x = active_term->cols - 1;
+ cursor_up();
+ }
+}
+
+void cursor_down() {
+ draw_char(active_term->cursor_y, active_term->cursor_x, false);
+
+ const uint32_t rows = active_term->rows;
+
+ if (++active_term->cursor_y == rows) {
+ --active_term->cursor_y;
+
+ char *const cb = active_term->charbuf;
+ uint8_t *const pb = active_term->pixbuf;
+ const uint32_t cols = active_term->cols;
+ const uint32_t fw = active_term->font->space_width;
+ const uint32_t fh = active_term->font->space_height;
+
+ char *to;
+ for (to = cb; to < cb + (rows - 1) * cols; ++to)
+ *to = *(to + cols);
+ for (; to < cb + rows * cols; ++to)
+ *to = ' ';
+ uint8_t *pto;
+ for (pto = pb; pto < pb + cols * fw * (rows - 1) * fh; ++pto)
+ *pto = *(pto + cols * fw * fh);
+ for (; pto < pb + cols * fw * rows * fh; ++pto)
+ *pto = active_term->bg;
+ }
+
+ draw_cursor();
+}
+
+void cursor_right() {
+ draw_char(active_term->cursor_y, active_term->cursor_x, false);
+
+ if (++active_term->cursor_x == active_term->cols)
+ term_newline();
+ else
+ draw_cursor();
+}
+
+void term_newline() {
+ draw_char(active_term->cursor_y, active_term->cursor_x, false);
+ active_term->cursor_x = 0;
+ cursor_down();
+}
+
+void term_add_char(char ch) {
+ if (ch == '\n') {
+ term_newline();
+ return;
+ }
+//char *const debug_msg = format("charbuf[%u] = '%c'", active_term->cursor_y * active_term->cols + active_term->cursor_x, ch);
+//_system_log(debug_msg);
+//free_block(debug_msg);
+ active_term->charbuf[active_term->cursor_y * active_term->cols + active_term->cursor_x] = ch;
+ cursor_right();
+}
+
+void term_add_sz_no_ww(const char *sz) {
+ while (*sz)
+ term_add_char(*(sz++));
+}
+
+#define MIN_TAB 3
+#define TAB_STEP 4
+
+void term_add_sz(const char *sz) {
+ //TODO: special hyphen handling
+ const char *word = sz;
+ while (1)
+ if (!*sz || (*sz == ' ') || (*sz == '\n') || (*sz == '\t')) {
+ const uint32_t len = sz - word;
+ if ((active_term->cursor_x + len > active_term->cols) && (len <= active_term->cols) && active_term->cols)
+ term_newline();
+ for (const char *i = word; i < sz; ++i)
+ term_add_char(*i);
+ while ((*sz == ' ') || (*sz == '\n') || (*sz == '\t')) {
+ if (*sz == '\n')
+ term_newline();
+ else if (*sz == '\t') {
+ for (uint8_t i = 0; i < MIN_TAB; ++i)
+ cursor_right();
+ while (active_term->cursor_x % TAB_STEP)
+ cursor_right();
+ }
+ ++sz;
+ }
+ if (!*sz)
+ return;
+ if (active_term->cursor_x)
+ term_add_char(' ');
+ word = sz;
+ }
+ else
+ ++sz;
+}
+
+void term_addf_no_ww_v(const char *fmt, va_list args) {
+ char *const msg = format_v(fmt, args);
+ term_add_sz_no_ww(msg);
+ free_block(msg);
+}
+
+void term_addf_no_ww(const char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ term_addf_no_ww_v(fmt, args);
+ va_end(args);
+}
+
+void term_addf_v(const char *fmt, va_list args) {
+ char *const msg = format_v(fmt, args);
+ term_add_sz(msg);
+ free_block(msg);
+}
+
+void term_addf(const char *fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ term_addf_v(fmt, args);
+ va_end(args);
+} \ No newline at end of file
diff --git a/tools/man-gen.py b/tools/man-gen.py
deleted file mode 100644
index 30ade8a..0000000
--- a/tools/man-gen.py
+++ /dev/null
@@ -1,135 +0,0 @@
-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