graphics!

This commit is contained in:
Benji Dial 2021-01-24 12:00:11 -05:00
parent ca731aa747
commit bce944d149
87 changed files with 6066 additions and 2201 deletions

5
bochsrc Normal file
View file

@ -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

17
doc/internal/scantabs.txt Normal file
View file

@ -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

View file

@ -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.
entry is a directory, and a zero if this entry is not. The remainder of the structure is reserved.

View file

@ -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.
to zero when giving a keycode, and should be ignored when recieving a keycode.

View file

@ -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

3
fs-skel/attribs.txt Normal file
View file

@ -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>.

3286
fs-skel/fonts/berry.bdf Normal file

File diff suppressed because it is too large Load diff

Binary file not shown.

View file

@ -1 +1,3 @@
set _path bin/
set _path bin/
set _color_fg 10
set _color_bg 61

View file

@ -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/terminal.so: obj/terminal/readline.o obj/terminal/terminal.o
ld ${partlink} $^ -o $@
obj/libfont.so: obj/libfont/bdf.o obj/libfont/fonts.o obj/libfont/filist.o
ld ${partlink} $^ -o $@
obj/popups.so: obj/popups/info.o obj/popups/popup.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
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/hello.elf: obj/hello/hello.ao
ld -T src/user/runtimes/asm/elf.ld $^ -o $@
obj/dumptext.elf: obj/dumptext/dumptext.o obj/knob.so obj/c.rto
ld -T src/user/runtimes/c/elf.ld $^ -o $@
obj/dumphex.elf: obj/dumphex/dumphex.o obj/knob.so obj/c.rto
ld -T src/user/runtimes/c/elf.ld $^ -o $@
obj/dirinfo.elf: obj/dirinfo/dirinfo.o obj/knob.so obj/c.rto
ld -T src/user/runtimes/c/elf.ld $^ -o $@
obj/fileman.elf: obj/fileman/fileman.o obj/knob.so obj/c.rto
ld -T src/user/runtimes/c/elf.ld $^ -o $@
obj/manual.elf: obj/manual/manual.o obj/knob.so obj/c.rto
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 $@

View file

@ -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

View file

@ -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
dw 0xaa55

View file

@ -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);
}
}

View file

@ -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

View file

@ -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) { }

View file

@ -1,14 +1,14 @@
#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 "window.h"
#include "drive.h"
#include "panic.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];
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);
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);
logf(LOG_INFO, "Killing %s.", active_task->name);
quit_isr();
__builtin_unreachable();
}
logsz("\nerror code = 0x");
u32_hex(code, nbuf);
logsz(nbuf);
//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);
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");
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");
}
}

View file

@ -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

View file

@ -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
};
static uint32_t n_scantabs;
static struct scantab_info {
uint8_t *scantab;
uint8_t prefix_length;
uint8_t prefix[256];
} *scantabs;
enum {
ST_ILLEGAL,
ST_SUBTABLE,
ST_FLIP,
ST_SKIP
};
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;
//TODO: get layout from some config file
file_id_t stf = drives->get_file(drives, SCANTAB_DIR "/" LAYOUT_HARDCODE_TMP ".sct");
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);
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;
uint8_t pl;
fmcpy(&pl, drives, stf, fi + 4, 1);
scantabs[n].prefix_length = pl;
fmcpy(scantabs[n].prefix, drives, stf, fi + 5, pl);
fi += 5 + pl;
if (fi & 0xf)
fi = (fi & ~0xf) + 0x10;
}
drives->free_file(drives, stf);
}
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;
}
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
};
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
};
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
};
static const uint32_t *const unmod_bits = mod_bits + 4;
//in these tables, 0x00 represents an unknown key,
// and 0xff represents a key release.
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,
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
};
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,
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
};
#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');
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)
PANIC("Unknown scancode.");
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
}
});
}
}
}

View file

@ -3,8 +3,9 @@
#include <stdint.h>
#include <keypack.h>
void init_kbd();
uint32_t get_key_code();
void on_kbd_isr();
#endif
#endif

View file

@ -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);
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);
}
void logsz(const char *sz) {
while (*sz)
logch(*sz++);
}

View file

@ -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 logf(enum log_level level, const char *format, ...);
void logch(char ch);
void logsz(const char *sz);
#endif
#endif

View file

@ -1,7 +1,8 @@
#include <stdint.h>
#include "serial.h"
#include "panic.h"
#include "paging.h"
#include "serial.h"
#include "window.h"
#include "panic.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");
}
logch('\n');
*/
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");
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");
if (!try_elf_run(drives, "bin/init", ""))
PANIC("Failed to load init program.");
init_log();
init_kbd();
init_idt();
logsz("Switching to init task.\n");
set_log_mode(LOG_USER);
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);
}
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" : "");
}
logf(LOG_INFO, "Loading init program.");
if (!try_elf_run(drives, "bin/init", "", 0))
PANIC("Failed to load init program.");
logf(LOG_INFO, "Switching to init task.");
_start_user_mode();
}

View file

@ -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");
}
}

View file

@ -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
#endif

View file

@ -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);
}
}

View file

@ -1,6 +1,8 @@
#include "panic.h"
#include "task.h"
#include "paging.h"
#include "panic.h"
#include "pmap.h"
#include "task.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;
}
}

View file

@ -5,10 +5,20 @@
#include <stdint.h>
#define TASK_NAME_LEN 15
#define MAX_WAITS 16
enum wait_mode {
NONE,
PROCESS_END,
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

View file

@ -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;
}
}

View file

@ -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
#endif

View file

@ -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++);
}

View file

@ -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

253
src/kernel/window.c Normal file
View file

@ -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);
}
}

23
src/kernel/window.h Normal file
View file

@ -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

View file

@ -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.

View file

@ -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}

View file

@ -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

View file

@ -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

View file

@ -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");
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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();
}
}

View file

@ -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

View file

@ -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);

View file

@ -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();
}

View file

@ -2,5 +2,6 @@
#define LINE_H
void run_line(const char *line);
void ensure_color();
#endif

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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

View file

@ -1,9 +0,0 @@
#ifndef KNOB_ENV_H
#define KNOB_ENV_H
#include <stdint.h>
//not implemented yet
extern uint32_t current_drive;
#endif

View file

@ -1,12 +1,29 @@
#ifndef KNOB_FORMAT_H
#define KNOB_FORMAT_H
#include <stdbool.h>
#include <stdint.h>
#include <knob/heap.h>
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)));
#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);
//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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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
extern _task_handle_t calling_task;
extern _task_handle_t stdio_task;
#endif

View file

@ -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 _set_color(_vga_color_t color) {
_sc1(_SCN_SET_COLOR, color);
static inline void _delete_window(_window_handle_t window) {
_sc1(_SCN_DELETE_WINDOW, (uint32_t)window);
}
static inline void _swap_color(uint8_t row, uint8_t col) {
_sc1(_SCN_SWAP_COLOR, (row << 8) | col);
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 _wait_ipc_read(_task_handle_t reading_task) {
_sc1(_SCN_WAIT_IPC_READ, reading_task);
}
static inline bool _is_task_running(_task_handle_t handle) {
return (bool)_sc1(_SCN_IS_TASK_RUNNING, handle);
}
#endif

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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.");
}

View file

@ -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;
}

View file

@ -1,3 +0,0 @@
#include <stdint.h>
uint32_t current_drive;

View file

@ -1,8 +1,9 @@
#include <knob/format.h>
#include <knob/panic.h>
#include <knob/heap.h>
#include <pland/syscall.h>
#include <pland/pcrt.h>
#include <knob/format.h>
#include <knob/heap.h>
#include <knob/env.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;
if ((path[0] == 's') && (path[1] == 'd'))
PANIC("remove_prefix not fully implemented");
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;
}
no_prefix:
*dn_out = current_drive;
*dn_out = 0;//change this later to an "active drive" or something
return path;
}

View file

@ -1,48 +1,231 @@
#include <stdbool.h>
#include <stdint.h>
#include <knob/block.h>
#include <knob/panic.h>
#include <knob/heap.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 <pland/syscall.h>
#include <pland/pcrt.h>
#include <stdarg.h>
#define FORMAT_BUF_INIT_SIZE 200
#define FORMAT_BUF_CHUNK_SIZE 50
#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;
}
__attribute__ ((access (write_only, 2)))
void itosz(uint32_t i, char *out) {
if (!i) {
*(uint16_t *)out = (uint16_t)'0';
return;
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;
}
const char *const hex_digits = "0123456789abcdef";
__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';
//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;
}
__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';
void syslogf_v(const char *fmt, va_list args) {
char *const msg = format_v(fmt, args);
_system_log(msg);
free_block(msg);
}
void syslogf(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
syslogf_v(fmt, args);
va_end(args);
}
//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;
}
//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;
}

View file

@ -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;

45
src/user/knob/ipc.c Normal file
View file

@ -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))
;
}

67
src/user/knob/key.c Normal file
View file

@ -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;
}

12
src/user/knob/panic.c Normal file
View file

@ -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();
}

View file

@ -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();
}

View file

@ -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;
}

99
src/user/libfont/bdf.c Normal file
View file

@ -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;
}

8
src/user/libfont/bdf.h Normal file
View file

@ -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

33
src/user/libfont/filist.c Normal file
View file

@ -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;
}

View file

@ -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

66
src/user/libfont/fonts.c Normal file
View file

@ -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;
}

View file

@ -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;
}
}
}

View file

@ -1,19 +1,30 @@
#include <popups/info.h>
#include <pland/syscall.h>
#include <knob/user.h>
#include <knob/format.h>
static const struct key_packet meminfo_quits[] = {
{ .key_id = KEY_ESCAPE, .modifiers = NO_MODS },
{ .key_id = KEY_F5, .modifiers = NO_MODS },
{ .key_id = 0 }
};
void main() {
char nbuf[11];
tell_user_sz("Kernel dynamic memory remaining: ");
itosz(_kernel_dynamic_area_left() * 4, nbuf);
tell_user_sz(nbuf);
tell_user_sz("k\n");
tell_user_sz("Userspace memory remaining: ");
itosz(_total_userspace_left() * 4, nbuf);
tell_user_sz(nbuf);
tell_user_sz("k\n");
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;
}

99
src/user/popups/info.c Normal file
View file

@ -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);
}

45
src/user/popups/popup.c Normal file
View file

@ -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);
}

View file

@ -11,6 +11,7 @@ SECTIONS {
.__pcrt_before_main : {
__pcrt_before_main_start = .;
*(.__pcrt_before_main)
*(.init_array)
__pcrt_before_main_end = .;
}

View file

@ -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:
section .bss
calling_task resd 1
stdio_task resd 1

View file

@ -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;
}
}
}

View file

@ -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);
}

View file

@ -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()