summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenji Dial <benji6283@gmail.com>2021-02-16 20:38:53 -0500
committerBenji Dial <benji6283@gmail.com>2021-02-16 20:38:53 -0500
commit47513bd32c256c4f35e3a8ced7d9fd7e15903530 (patch)
treecafdf75d52a954814726e07445063c41bb6599f9
parentbd7facc4b5f53481dc85a15ba123361b2758655b (diff)
downloadportland-os-47513bd32c256c4f35e3a8ced7d9fd7e15903530.tar.gz
terminal application with ipc, shift+pause state dumper, hello world for terminal, meminfo popup program
-rw-r--r--.gitignore1
-rw-r--r--doc/internal/mem.txt1
-rw-r--r--doc/ints.txt15
-rw-r--r--fs-skel/sys/startup.rc2
-rw-r--r--makefile20
-rw-r--r--src/kernel/dump.c187
-rw-r--r--src/kernel/elf-link.ld2
-rw-r--r--src/kernel/elf.c9
-rw-r--r--src/kernel/idt.c50
-rw-r--r--src/kernel/isrs.asm12
-rw-r--r--src/kernel/kbd.c6
-rw-r--r--src/kernel/kbd.h8
-rw-r--r--src/kernel/log.c5
-rw-r--r--src/kernel/log.h1
-rw-r--r--src/kernel/paging.c5
-rw-r--r--src/kernel/paging.h4
-rw-r--r--src/kernel/task.c101
-rw-r--r--src/kernel/task.h12
-rw-r--r--src/kernel/window.c25
-rw-r--r--src/kernel/window.h6
-rw-r--r--src/user/hello/hello.asm28
-rw-r--r--src/user/highway/cmds.c2
-rw-r--r--src/user/highway/line.c30
-rw-r--r--src/user/highway/main.c23
-rw-r--r--src/user/highway/vars.c5
-rw-r--r--src/user/include/knob/ipc.h2
-rw-r--r--src/user/include/libterm/command.h68
-rw-r--r--src/user/include/libterm/readline.h (renamed from src/user/include/terminal/readline.h)4
-rw-r--r--src/user/include/libterm/terminal.h35
-rw-r--r--src/user/include/pland/pcrt.h1
-rw-r--r--src/user/include/pland/syscall.h20
-rw-r--r--src/user/include/popups/popup.h3
-rw-r--r--src/user/include/terminal/terminal.h57
-rw-r--r--src/user/knob/format.c19
-rw-r--r--src/user/knob/ipc.c12
-rw-r--r--src/user/knob/task.c16
-rw-r--r--src/user/libterm/readline.c106
-rw-r--r--src/user/libterm/terminal.c179
-rw-r--r--src/user/libterm/termtask.c9
-rw-r--r--src/user/popups/info.c1
-rw-r--r--src/user/popups/popup.c2
-rw-r--r--src/user/runtimes/c/pcrt.asm9
-rw-r--r--src/user/terminal/main.c373
-rw-r--r--src/user/terminal/readline.c104
-rw-r--r--src/user/terminal/terminal.c284
45 files changed, 1261 insertions, 603 deletions
diff --git a/.gitignore b/.gitignore
index 38e34c6..61698b4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
obj/
out/
+.vscode/ \ No newline at end of file
diff --git a/doc/internal/mem.txt b/doc/internal/mem.txt
index c5f5e8b..1606ca1 100644
--- a/doc/internal/mem.txt
+++ b/doc/internal/mem.txt
@@ -17,6 +17,7 @@
0x0003.0000 - 0x0003.7fff (32k): kernel text, data, rodata
0x0003.8000 - 0x0003.ffff (32k): kernel stack
0x0004.0000 - 0x0005.ffff (128k): pagemap
+0x0006.0000 - 0x0007.ffff (128k): shared kernel page tables
0x000a.0000 - 0x000f.ffff (384k): VGA and BIOS memory
diff --git a/doc/ints.txt b/doc/ints.txt
index ca4d91f..fff08fb 100644
--- a/doc/ints.txt
+++ b/doc/ints.txt
@@ -18,9 +18,10 @@ 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.
+ the esi register is passed through directly, and is meant to be a task handle.
+ this is a task handle who stdio ipc communication should be done with.
+ the new task receives the calling task's handle in edi
+ the new task receives its own handle in ecx.
ipc operations return 0xffffffff if the specified task doesn't exist.
"find unread ipc" system call returns 0 if there is no unread ipc.
@@ -35,7 +36,7 @@ table 1:
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
+ 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 | | | |
@@ -46,13 +47,13 @@ table 1:
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 | |
+ resize window | 0x0f | | window handle | width | height | pixel buffer |
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 | | | | | |
+ wait ipc sent | 0x14 | | sending task | | | |
+ wait any ipc sent | 0x15 | | | | | |
find unread ipc | 0x16 | sending task | | | | |
wait ipc read | 0x17 | | reading task | | | |
is task running | 0x18 | boolean | task handle | | | |
diff --git a/fs-skel/sys/startup.rc b/fs-skel/sys/startup.rc
index 713d523..3d038c5 100644
--- a/fs-skel/sys/startup.rc
+++ b/fs-skel/sys/startup.rc
@@ -1 +1 @@
-bin/highway \ No newline at end of file
+bin/terminal bin/highway \ No newline at end of file
diff --git a/makefile b/makefile
index 002dce3..5261284 100644
--- a/makefile
+++ b/makefile
@@ -35,7 +35,8 @@ 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/highway out/fs/bin/meminfo
+out/fs: out/fs/bin/init out/fs/bin/highway out/fs/bin/meminfo \
+ out/fs/bin/terminal out/fs/bin/hello
touch out/fs
cp -r fs-skel/* out/fs/
@@ -52,7 +53,7 @@ out/kernel.bin: obj/kernel/drive.ko obj/kernel/fat.ko obj/kernel/ide.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/window.ko obj/kernel/isrs.kao obj/kernel/kbd.ko \
- obj/kernel/pmap.ko obj/kernel/paging.ko
+ obj/kernel/pmap.ko obj/kernel/paging.ko obj/kernel/dump.ko
mkdir -p out
ld -T src/kernel/elf-link.ld $^ -o obj/kernel.elf
objcopy -O binary obj/kernel.elf out/kernel.bin
@@ -84,7 +85,7 @@ obj/knob.so: obj/knob/file.o obj/knob/format.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
+obj/libterm.so: obj/libterm/terminal.o obj/libterm/termtask.o obj/libterm/readline.o
ld ${partlink} $^ -o $@
obj/libfont.so: obj/libfont/bdf.o obj/libfont/fonts.o obj/libfont/filist.o
@@ -97,10 +98,17 @@ obj/init.elf: obj/init/init.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/terminal.so \
- obj/libfont.so obj/c.rto
+ obj/highway/vars.o obj/knob.so obj/libterm.so \
+ obj/c.rto
ld -T src/user/runtimes/c/elf.ld $^ -o $@
obj/meminfo.elf: obj/meminfo/meminfo.o obj/popups.so obj/libfont.so \
obj/knob.so obj/c.rto
- ld -T src/user/runtimes/c/elf.ld $^ -o $@ \ No newline at end of file
+ ld -T src/user/runtimes/c/elf.ld $^ -o $@
+
+obj/terminal.elf: obj/terminal/main.o obj/libfont.so obj/knob.so \
+ obj/c.rto
+ ld -T src/user/runtimes/c/elf.ld $^ -o $@
+
+obj/hello.elf: obj/hello/hello.ao
+ ld -T src/user/runtimes/asm/elf.ld $^ -o $@ \ No newline at end of file
diff --git a/src/kernel/dump.c b/src/kernel/dump.c
new file mode 100644
index 0000000..d0c02e6
--- /dev/null
+++ b/src/kernel/dump.c
@@ -0,0 +1,187 @@
+#include <stdint.h>
+
+#include "paging.h"
+#include "task.h"
+#include "log.h"
+
+extern const void _kernel_data_start;
+extern const void _kernel_data_end;
+extern const void _kernel_bss_end;
+
+static inline char c(uint8_t n) {
+ return (n > 0x20) && (n < 0x7f) ? (char)n : '.';
+}
+
+static uint8_t last_line[16];
+enum {
+ SECTION_START,
+ DOT_DOT_DOT,
+ SKIP
+} last_line_mode;
+
+static void write_mem_line(uint32_t addr) {
+ const uint8_t *const at = (const uint8_t *)addr;
+ if (last_line_mode != SECTION_START) {
+ for (uint8_t i = 0; i < 16; ++i)
+ if (at[i] != last_line[i])
+ goto diff_line;
+ if (last_line_mode == DOT_DOT_DOT) {
+ logf(LOG_DUMP, " 0x%h ...", addr);
+ last_line_mode = SKIP;
+ }
+ return;
+ }
+diff_line:
+ logf(LOG_DUMP,
+ " 0x%h %hb %hb %hb %hb %hb %hb %hb %hb %hb %hb %hb %hb %hb %hb %hb %hb %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c", addr,
+ at[0], at[1], at[2], at[3], at[4], at[5], at[6], at[7],
+ at[9], at[9], at[10], at[11], at[12], at[13], at[14], at[15],
+ c(at[0]), c(at[1]), c(at[2]), c(at[3]),
+ c(at[4]), c(at[5]), c(at[6]), c(at[7]),
+ c(at[8]), c(at[9]), c(at[10]), c(at[11]),
+ c(at[12]), c(at[13]), c(at[14]), c(at[15])
+ );
+ for (uint8_t i = 0; i < 16; ++i)
+ last_line[i] = at[1];
+ last_line_mode = DOT_DOT_DOT;
+}
+
+static void write_mem_page(uint32_t page) {
+ for (uint32_t i = page << 12; i < (page + 1) << 12; i += 16)
+ write_mem_line(i);
+}
+
+#include "kbd.h"
+
+#define WAIT_TASK tasks[i].waits[t].task - tasks + 1, tasks[i].waits[t].task->name
+
+void dump(enum kbd_isr_result kind, const uint32_t edi, const uint32_t esi, const uint32_t ebx, const uint32_t edx, const uint32_t ecx, const uint32_t eax, const uint32_t eip, const uint32_t cs, const uint32_t eflags, const uint32_t esp, const uint32_t ss) {
+ uint32_t cr3;
+ asm volatile (
+ "mov %%cr3, %0"
+ : "=a" (cr3));
+
+ logf(LOG_INFO, "Dump state...");
+
+ switch (kind) {
+ case DUMP:
+ logf(LOG_DUMP, "Tasks:");
+ for (uint8_t t = 0; t < MAX_TASKS; ++t)
+ if (tasks[t].page_directory) {
+ logf(LOG_DUMP, " %s (0x%hb):", tasks[t].name, t + 1);
+ if (tasks + t == active_task) {
+ logf(LOG_DUMP, " *Active task*");
+ logf(LOG_DUMP, " cr3: 0x%h", cr3);
+ logf(LOG_DUMP, " eip: 0x%h", eip);
+ logf(LOG_DUMP, " eax: 0x%h", eax);
+ logf(LOG_DUMP, " ebx: 0x%h", ebx);
+ logf(LOG_DUMP, " ecx: 0x%h", ecx);
+ logf(LOG_DUMP, " edx: 0x%h", edx);
+ logf(LOG_DUMP, " esi: 0x%h", esi);
+ logf(LOG_DUMP, " edi: 0x%h", edi);
+ logf(LOG_DUMP, " esp: 0x%h", esp);
+ logf(LOG_DUMP, " cs: 0x%hb", cs);
+ logf(LOG_DUMP, " ss: 0x%hb", ss);
+ logf(LOG_DUMP, " eflags: 0x%h", eflags);
+ }
+ else {
+ logf(LOG_DUMP, " Stored cr3: 0x%h", tasks[t].page_directory);
+ logf(LOG_DUMP, " Stored eip: 0x%h", tasks[t].ret_addr);
+ logf(LOG_DUMP, " Stored ebx: 0x%h", tasks[t].ebx);
+ logf(LOG_DUMP, " Stored ecx: 0x%h", tasks[t].ecx);
+ logf(LOG_DUMP, " Stored edx: 0x%h", tasks[t].edx);
+ logf(LOG_DUMP, " Stored esi: 0x%h", tasks[t].esi);
+ logf(LOG_DUMP, " Stored edi: 0x%h", tasks[t].edi);
+ logf(LOG_DUMP, " Stored ebp: 0x%h", tasks[t].ebp);
+ logf(LOG_DUMP, " Stored esp: 0x%h", tasks[t].esp);
+ }
+ logf(LOG_DUMP, " Stack size: %d kibibytes", -tasks[t].stack_bottom / 1024);
+ if (tasks[t].waiting) {
+ logf(LOG_DUMP, " Waits:");
+ for (uint8_t i = 0; i < MAX_WAITS; ++i)
+ switch (tasks[i].waits[t].mode) {
+ case NONE:
+ continue;
+ case PROCESS_END:
+ logf(LOG_DUMP, " Waiting for task 0x%hb (%s) to end", WAIT_TASK);
+ continue;
+ case WINDOW_ACTION:
+ logf(LOG_DUMP, " Waiting for window action");
+ continue;
+ case IPC_SENT:
+ logf(LOG_DUMP, " Waiting for IPC to be sent by 0x%hb (%s)", WAIT_TASK);
+ continue;
+ case IPC_SENT_ANY:
+ logf(LOG_DUMP, " Waiting for IPC to be sent by anyone");
+ continue;
+ case IPC_READ:
+ logf(LOG_DUMP, " Waiting for IPC to be read by 0x%hb (%s)", WAIT_TASK);
+ continue;
+ default:
+ logf(LOG_DUMP, " Other (corrupted?)");
+ continue;
+ }
+ }
+ else
+ logf(LOG_DUMP, " Not waiting.");
+ }
+ break;
+
+ case SHIFT_DUMP:
+
+ logf(LOG_DUMP, "Current task: 0x%hb (%s)", active_task - tasks + 1, active_task->name);
+ logf(LOG_DUMP, "Registers:");
+ logf(LOG_DUMP, " cr3: 0x%h", cr3);
+ logf(LOG_DUMP, " eip: 0x%h", eip);
+ logf(LOG_DUMP, " esp: 0x%h", esp);
+ logf(LOG_DUMP, " eax: 0x%h", eax);
+ logf(LOG_DUMP, " ebx: 0x%h", ebx);
+ logf(LOG_DUMP, " ecx: 0x%h", ecx);
+ logf(LOG_DUMP, " edx: 0x%h", edx);
+ logf(LOG_DUMP, " esi: 0x%h", esi);
+ logf(LOG_DUMP, " edi: 0x%h", edi);
+ logf(LOG_DUMP, " eflags: 0x%h", eflags);
+ logf(LOG_DUMP, " cs: 0x%hb", cs);
+ logf(LOG_DUMP, " ss: 0x%hb", ss);
+
+ logf(LOG_DUMP, "Kernel data section:");
+ last_line_mode = SECTION_START;
+ for (uint32_t i = (uint32_t)&_kernel_data_start & ~0xf; i < (((uint32_t)&_kernel_data_end - 1) & ~0xf) + 0x10; i += 0x10)
+ write_mem_line(i);
+ logf(LOG_DUMP, "Kernel bss section:");
+ last_line_mode = SECTION_START;
+ for (uint32_t i = 0x4000000; i < (((uint32_t)&_kernel_bss_end - 1) & ~0xf) + 1; i += 0x10)
+ write_mem_line(i);
+ logf(LOG_DUMP, "Kernel heap:");
+ last_line_mode = SECTION_START;
+ const uint32_t first_heap_page = (((uint32_t)&_kernel_bss_end - 1) >> 12) + 1;
+ for (uint8_t n = first_heap_page & 7; n < 8; ++n)
+ if (*(uint8_t *)(0x40000 + (first_heap_page >> 3)) & (1 << n))
+ write_mem_page((first_heap_page & ~7) | n);
+ for (uint8_t *i = (uint8_t *)(0x40000 + (first_heap_page >> 3) + 1); i < (uint8_t *)0x41000; ++i)
+ for (uint8_t n = 0; n < 8; ++n)
+ if (*i & (1 << n))
+ write_mem_page((i - (uint8_t *)0x40000) * 8 + n);
+
+ for (uint8_t t = 0; t < MAX_TASKS; ++t)
+ if (tasks[t].page_directory) {
+ logf(LOG_DUMP, "Task 0x%hb (%s)'s memory:", t + 1, tasks[t].name);
+ last_line_mode = SECTION_START;
+ const void *const pd = tasks[t].page_directory;
+ asm (
+ "mov %0, %%cr3"
+ : : "a" (pd));
+ for (uint32_t i = 0x08000000; i; i += 4096)
+ if (pd_is_mapped(pd, i))
+ for (uint32_t j = i; j < i + 4096; j += 16)
+ write_mem_line(j);
+ }
+ break;
+ }
+
+ logf(LOG_INFO, "Dumped state.");
+
+ asm (
+ "mov %0, %%cr3"
+ : : "a" (cr3));
+} \ No newline at end of file
diff --git a/src/kernel/elf-link.ld b/src/kernel/elf-link.ld
index 84d3f92..d0c6723 100644
--- a/src/kernel/elf-link.ld
+++ b/src/kernel/elf-link.ld
@@ -11,7 +11,9 @@ SECTIONS {
*(.rodata)
}
.data : {
+ _kernel_data_start = .;
*(.data)
+ _kernel_data_end = .;
}
. = 0x04000000;
.bss : {
diff --git a/src/kernel/elf.c b/src/kernel/elf.c
index 146035e..f601654 100644
--- a/src/kernel/elf.c
+++ b/src/kernel/elf.c
@@ -6,6 +6,8 @@
#include "paging.h"
#include "pmap.h"
+#include "log.h"
+
#define ELF_MAGIC 0x464c457f
enum {
@@ -129,9 +131,12 @@ uint32_t try_elf_run(const struct drive *d, const char *path, const char *pass_o
tstate.ret_addr = ehead.entry_vma;
tstate.stack_bottom = 0;
+//logf(LOG_INFO, " tasks: 0x%h", tasks);
+//logf(LOG_INFO, "active_task: 0x%h", active_task);
+//logf(LOG_INFO, " new edi: 0x%hb", active_task - tasks + 1);
tstate.edx = (uint32_t)pass_vma;
- tstate.esi = active_task - tasks + 1;
- tstate.edi = io_handle;
+ tstate.esi = io_handle;
+ tstate.edi = active_task - tasks + 1;
tstate.esp = 0;
const char *path_end_start = path;
diff --git a/src/kernel/idt.c b/src/kernel/idt.c
index b8990f2..9b3ba96 100644
--- a/src/kernel/idt.c
+++ b/src/kernel/idt.c
@@ -35,25 +35,23 @@ struct {
//file handles as (drive_number << 8) + file_id_t
-uint32_t sc_open_file(uint32_t drive_number, char *path) { //not static to ensure sysv abi
+uint32_t sc_open_file(uint32_t drive_number, char *path) {
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);
}
-void sc_close_file(uint32_t handle) { //not static to ensure sysv abi
+void sc_close_file(uint32_t handle) {
if (!handle)
return;
drives[handle >> 8].free_file(drives + (handle >> 8), handle & 0xff);
}
-uint32_t sc_file_get_size(uint32_t handle) { //not static to ensure sysv abi
- //logf(LOG_INFO, "sc_file_get_size(%d)", handle);
+uint32_t sc_file_get_size(uint32_t handle) {
if (!handle)
return 0;
return drives[handle >> 8].get_file_length(drives + (handle >> 8), handle & 0xff);
}
-uint32_t sc_file_read(uint32_t handle, uint32_t file_offset, uint32_t count, void *buffer) { //not static to ensure sysv abi
+uint32_t sc_file_read(uint32_t handle, uint32_t file_offset, uint32_t count, void *buffer) {
if (!handle)
return 0;
uint32_t len = sc_file_get_size(handle);
@@ -63,14 +61,14 @@ uint32_t sc_file_read(uint32_t handle, uint32_t file_offset, uint32_t count, voi
return count;
}
-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
+uint32_t sc_start_task(uint32_t drive_number, char *path, const char *pass, uint32_t io_task) {
switch_to_kernel_cr3();
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;
}
-void *sc_allocate_ram(uint32_t pages) { //not static to ensure sysv abi
+void *sc_allocate_ram(uint32_t pages) {
return pd_user_allocate_anywhere_writable(active_task->page_directory, pages);
}
@@ -83,7 +81,7 @@ enum mi_arg {
};
__attribute__ ((pure))
-uint32_t sc_memory_info(enum mi_arg arg) { //not static to ensure sysv abi
+uint32_t sc_memory_info(enum mi_arg arg) {
switch (arg) {
case MI_KERNEL_MAX:
return max_kernel_pages;
@@ -100,7 +98,7 @@ uint32_t sc_memory_info(enum mi_arg arg) { //not static to ensure sysv abi
}
}
-void sc_wait_for_task(uint32_t handle) { //not static to ensure sysv abi
+void sc_wait_for_task(uint32_t handle) {
add_wait((struct wait){.mode = PROCESS_END, .task = tasks + handle - 1});
}
@@ -108,11 +106,11 @@ uint32_t sc_enumerate_dir(uint32_t drive_number, const char *path, struct direct
return drives[drive_number].enumerate_dir(drives + drive_number, path, buffer, max_entries);
}
-uint32_t sc_count_of_dir(uint32_t drive_number, const char *path) { //not static to ensure sysv abi
+uint32_t sc_count_of_dir(uint32_t drive_number, const char *path) {
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
+void sc_get_next_window_action(struct window *w, struct window_action *action) {
*action = next_window_action(w);
}
@@ -120,25 +118,27 @@ 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_wait_ipc_sent(uint32_t task_handle) {
+ add_wait((struct wait){.mode = IPC_SENT, .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_any_ipc_sent() {
+ add_wait((struct wait){.mode = IPC_SENT_ANY});
}
void sc_wait_ipc_read(uint32_t handle) {
- add_wait((struct wait){.mode = IPC_SEND, .task = tasks + handle - 1});
+ add_wait((struct wait){.mode = IPC_READ, .task = tasks + handle - 1});
}
+//returns a uint32_t to ensure upper twenty-four bits of
+// eax are set to zero - otherwise userland stuff break
__attribute__ ((pure))
-bool sc_is_task_running(uint32_t handle) {
- return tasks[handle - 1].page_directory;
+uint32_t sc_is_task_running(uint32_t handle) {
+ return tasks[handle - 1].page_directory ? 1 : 0;
}
void const *syscall_table[] = {
@@ -162,8 +162,8 @@ void const *syscall_table[] = {
&push_window_paint,
&sc_get_next_window_action,
&sc_wait_window_action,
- &sc_wait_ipc,
- &sc_wait_any_ipc,
+ &sc_wait_ipc_sent,
+ &sc_wait_any_ipc_sent,
&find_unread_ipc,
&sc_wait_ipc_read,
&sc_is_task_running
@@ -240,17 +240,11 @@ void exception_halt(uint32_t eax, uint32_t ebx, uint32_t ecx,
}
//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);
-
+bool pf_check_stack(uint32_t cr2) {
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 {
diff --git a/src/kernel/isrs.asm b/src/kernel/isrs.asm
index 02b046d..a4eb988 100644
--- a/src/kernel/isrs.asm
+++ b/src/kernel/isrs.asm
@@ -23,6 +23,7 @@ extern on_kbd_isr
extern make_sure_tasks
extern exception_halt
extern pf_check_stack
+extern dump
n_syscalls equ 0x19
@@ -139,6 +140,17 @@ kbd_isr:
call on_kbd_isr
+ test eax, eax
+ jz .no_debug
+
+ push ebx
+ push esi
+ push edi
+ push eax
+ call dump
+ add esp, 16
+
+.no_debug:
mov al, 0x20
out 0x0020, al
diff --git a/src/kernel/kbd.c b/src/kernel/kbd.c
index f7158bb..c09684d 100644
--- a/src/kernel/kbd.c
+++ b/src/kernel/kbd.c
@@ -91,7 +91,7 @@ static inline uint8_t get_next_code_byte() {
static enum key_modifiers_t keymods = 0;
-void on_kbd_isr() {
+enum kbd_isr_result on_kbd_isr() {
//logf(LOG_INFO, "on_kbd_isr()");
while (inb(PS2_CMD) & PS2S_CODE_READY) {
last_code_byte = 0;
@@ -201,6 +201,9 @@ void on_kbd_isr() {
break;
}
+ if (!is_up && (entry == KEY_PAUSE) && (keymods & ALTS))
+ return (keymods & SHIFTS) ? SHIFT_DUMP : DUMP;
+
on_action((struct window_action){
.action_type = is_up ? KEY_UP : KEY_DOWN,
.as_key = (struct key_packet){
@@ -209,4 +212,5 @@ void on_kbd_isr() {
}
});
}
+ return NORMAL;
}
diff --git a/src/kernel/kbd.h b/src/kernel/kbd.h
index e9affad..7e03fd7 100644
--- a/src/kernel/kbd.h
+++ b/src/kernel/kbd.h
@@ -1,11 +1,17 @@
#ifndef KBD_H
#define KBD_H
+#include <stdbool.h>
#include <stdint.h>
#include <keypack.h>
void init_kbd();
-void on_kbd_isr();
+
+enum kbd_isr_result {
+ NORMAL,
+ DUMP,
+ SHIFT_DUMP
+} on_kbd_isr();
#endif
diff --git a/src/kernel/log.c b/src/kernel/log.c
index 8ef2baf..6bad1cc 100644
--- a/src/kernel/log.c
+++ b/src/kernel/log.c
@@ -14,6 +14,7 @@ void init_log() {
static const char *const log_prefixes[] = {
" [USER] ",
" [INFO] ",
+ " [DUMP] ",
" [WARN] ",
"[ERROR] ",
"[PANIC] ",
@@ -42,6 +43,10 @@ void logf(enum log_level level, const char *format, ...) {
case '%':
logch('%');
break;
+ case 'c':;
+ const char c = (char)va_arg(args, uint32_t);
+ logch(c);
+ break;
case 's':;
const char *s = va_arg(args, const char *);
while (*s)
diff --git a/src/kernel/log.h b/src/kernel/log.h
index c5c4da7..daf90dd 100644
--- a/src/kernel/log.h
+++ b/src/kernel/log.h
@@ -6,6 +6,7 @@
enum log_level {
LOG_USER,
LOG_INFO,
+ LOG_DUMP,
LOG_WARN,
LOG_ERROR,
LOG_PANIC
diff --git a/src/kernel/paging.c b/src/kernel/paging.c
index fbc33de..4672788 100644
--- a/src/kernel/paging.c
+++ b/src/kernel/paging.c
@@ -34,7 +34,7 @@ static void pd_map(void *pd, uint32_t physical_addr, uint32_t virtual_addr, bool
}
__attribute__ ((pure))
-static bool pd_is_mapped(void *pd, uint32_t vma) {
+bool pd_is_mapped(const void *pd, uint32_t vma) {
uint32_t pde = ((uint32_t *)pd)[vma >> 22];
return (pde & PE_PRESENT) && (((uint32_t *)(pde & PE_ADDR_MASK))[(vma >> 12) % 1024] & PE_PRESENT);
}
@@ -52,8 +52,7 @@ void free_task_pd(void *pd) {
free_pages(pd, 1);
}
-__attribute__ ((aligned (4096)))
-static uint32_t kmap[KERNEL_END / 4096];
+#define kmap ((uint32_t *)0x00060000)
void *new_task_pd() {
uint32_t *pd = allocate_kernel_pages(1);
diff --git a/src/kernel/paging.h b/src/kernel/paging.h
index 6c1a6f5..082f6c2 100644
--- a/src/kernel/paging.h
+++ b/src/kernel/paging.h
@@ -12,4 +12,6 @@ void user_allocate_anywhere_readonly_together(void *pd, uint32_t pages, void **v
void *vma_to_pma(void *pd, const void *vma) __attribute__ ((pure));
void switch_to_kernel_cr3();
-void switch_to_task_cr3(); \ No newline at end of file
+void switch_to_task_cr3();
+
+bool pd_is_mapped(const void *pd, uint32_t vma) __attribute__ ((pure)); \ No newline at end of file
diff --git a/src/kernel/task.c b/src/kernel/task.c
index ab08e6b..e2412e1 100644
--- a/src/kernel/task.c
+++ b/src/kernel/task.c
@@ -1,4 +1,5 @@
#include "paging.h"
+#include "window.h"
#include "panic.h"
#include "pmap.h"
#include "task.h"
@@ -42,34 +43,15 @@ struct tss {
#define TSS ((struct tss *)0x00004f98)
-#define MAX_TASKS 64
-
struct task_state tasks[MAX_TASKS];
struct task_state *active_task;
-void init_tasks() {
- active_task = tasks;
-
- for (uint8_t i = 0; i < MAX_TASKS; ++i)
- tasks[i].page_directory = 0;
-
- TSS->ss0 = 0x18;
- TSS->esp0 = 0x00040000;
-//TSS->cs = 0x13;
-//TSS->ds = 0x1b;
-//TSS->ss = 0x1b;
- TSS->iomp = sizeof(struct tss);
-
- asm volatile (
- "mov $0x08, %%ax\n"
- "ltr %%ax"
- : : : "ax");
-}
-
+//puts the handle into ecx
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].ecx = n + 1;
tasks[n].waiting = false;
for (uint8_t i = 0; i < MAX_WAITS; ++i)
tasks[n].waits[i].mode = NONE;
@@ -129,22 +111,47 @@ struct ipc_pipe {
bool delete_when_empty;
} ipc_pipes[MAX_IPC_PIPES];
+void init_tasks() {
+ active_task = tasks;
+
+ for (uint8_t i = 0; i < MAX_TASKS; ++i)
+ tasks[i].page_directory = 0;
+
+ for (uint16_t i = 0; i < MAX_IPC_PIPES; ++i)
+ ipc_pipes[i].buffer = 0;
+
+ TSS->ss0 = 0x18;
+ TSS->esp0 = 0x00040000;
+//TSS->cs = 0x13;
+//TSS->ds = 0x1b;
+//TSS->ss = 0x1b;
+ TSS->iomp = sizeof(struct tss);
+
+ asm volatile (
+ "mov $0x08, %%ax\n"
+ "ltr %%ax"
+ : : : "ax");
+}
+
void delete_pipe(struct ipc_pipe *pipe) {
free_pages(pipe->buffer, IPC_BUFFER_PAGES);
pipe->buffer = 0;
}
void delete_task(struct task_state *state) {
+//logf(LOG_INFO, "-- deleting 0x%h", state);
switch_to_kernel_cr3();
free_task_pd(state->page_directory);
switch_to_task_cr3();
+
+ delete_any_windows_from(state);
state->page_directory = 0;
+//logf(LOG_INFO, "-- unwaiting any waiting for 0x%h", state);
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});
+ unwait_any((struct wait){.mode = IPC_SENT, .task = state});
- const uint32_t handle = active_task - tasks + 1;
+ const uint32_t handle = state - tasks + 1;
for (struct ipc_pipe *pipe = ipc_pipes; pipe < ipc_pipes + MAX_IPC_PIPES; ++pipe)
if (pipe->buffer) {
if (pipe->reader_handle == handle)
@@ -158,15 +165,19 @@ void delete_task(struct task_state *state) {
}
}
+__attribute__ ((pure))
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))
+ (pipe->buffer_next_read != pipe->buffer_next_send)) {
+ //logf(LOG_INFO, "found %d bytes of unread ipc from 0x%hb to 0x%hb", pipe->buffer_next_send - pipe->buffer_next_read + (pipe->buffer_next_read < pipe->buffer_next_send ? 0 : IPC_BUFFER_PAGES * 4096), pipe->sender_handle, pipe->reader_handle);
return pipe->sender_handle;
+ }
return 0;
}
+__attribute__ ((pure))
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) &&
@@ -176,7 +187,7 @@ struct ipc_pipe *get_existing_pipe(uint32_t sender_handle, uint32_t reader_handl
}
uint32_t ipc_send(uint32_t reader_handle, uint32_t count, const void *buffer) {
- if (!reader_handle || !tasks[reader_handle - 1].page_directory)
+ if (!reader_handle || (reader_handle > MAX_TASKS) || !tasks[reader_handle - 1].page_directory)
return -1;
const uint32_t our_handle = active_task - tasks + 1;
@@ -197,8 +208,8 @@ uint32_t ipc_send(uint32_t reader_handle, uint32_t count, const void *buffer) {
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});
+ unwait(tasks + reader_handle - 1, (struct wait){.mode = IPC_SENT, .task = active_task});
+ unwait(tasks + reader_handle - 1, (struct wait){.mode = IPC_SENT_ANY});
uint32_t send_left = pipe->buffer_next_read - pipe->buffer_next_send - 1;
if (send_left < 0)
@@ -220,17 +231,34 @@ 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) {
- if (!sender_handle || !tasks[sender_handle - 1].page_directory)
+//logf(LOG_INFO, "kernel ipc_read(0x%hb, %u, 0x%h)", sender_handle, count, buffer);
+ if (!sender_handle || (sender_handle > MAX_TASKS))
return -1;
const uint32_t our_handle = active_task - tasks + 1;
- struct ipc_pipe *pipe = get_existing_pipe(sender_handle, our_handle);
+ struct ipc_pipe *const pipe = get_existing_pipe(sender_handle, our_handle);
if (!pipe)
- return 0;
+ return tasks[sender_handle - 1].page_directory ? 0 : -1;
- unwait(tasks + sender_handle - 1, (struct wait){.mode = IPC_SEND, .task = active_task});
+//logf(LOG_INFO, "found pipe from 0x%hb to 0x%hb", pipe->sender_handle, pipe->reader_handle);
- //TODO
+ unwait(tasks + sender_handle - 1, (struct wait){.mode = IPC_READ, .task = active_task});
+
+ uint8_t *write_to = buffer;
+ const uint8_t *read_from = pipe->buffer_next_read;
+
+ //change this to memcpys like ipc_send once memcpy is more efficient
+ while ((read_from != pipe->buffer_next_send) && count--) {
+ *(write_to++) = *(read_from++);
+ if (read_from == pipe->buffer + IPC_BUFFER_PAGES * 4096)
+ read_from = pipe->buffer;
+ }
+
+ if (pipe->delete_when_empty && (read_from == pipe->buffer_next_send))
+ delete_pipe(pipe);
+ else
+ pipe->buffer_next_read = read_from;
+ return write_to - (uint8_t *)buffer;
}
void add_wait(struct wait wait) {
@@ -257,12 +285,13 @@ void unwait(struct task_state *task, struct wait wait) {
continue;
switch (wait.mode) {
case PROCESS_END:
- case IPC_RECEIVE:
+ case IPC_SENT:
+ case IPC_READ:
if (task->waits[i].task != wait.task)
continue;
break;
case WINDOW_ACTION:
- case IPC_RECEIVE_ANY:
+ case IPC_SENT_ANY:
break;
default:
PANIC("Unwait matched with unrecognized wait mode.");
@@ -272,4 +301,4 @@ void unwait(struct task_state *task, struct wait wait) {
task->waiting = false;
return;
}
-} \ No newline at end of file
+}
diff --git a/src/kernel/task.h b/src/kernel/task.h
index 574dfa7..643c88e 100644
--- a/src/kernel/task.h
+++ b/src/kernel/task.h
@@ -4,17 +4,18 @@
#include <stdbool.h>
#include <stdint.h>
-#define TASK_NAME_LEN 15
+#define TASK_NAME_LEN 86
#define MAX_WAITS 16
+#define MAX_TASKS 64
struct wait {
enum {
NONE,
PROCESS_END,
WINDOW_ACTION,
- IPC_RECEIVE,
- IPC_RECEIVE_ANY,
- IPC_SEND
+ IPC_SENT,
+ IPC_SENT_ANY,
+ IPC_READ
} mode;
union {
struct task_state *task;
@@ -50,6 +51,7 @@ extern struct task_state *active_task;
void init_tasks();
+//puts the handle into ecx
uint32_t new_task(struct task_state state);
void advance_active_task();
@@ -58,6 +60,6 @@ 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();
+uint32_t find_unread_ipc() __attribute__ ((pure));
#endif \ No newline at end of file
diff --git a/src/kernel/window.c b/src/kernel/window.c
index 28798d1..078a194 100644
--- a/src/kernel/window.c
+++ b/src/kernel/window.c
@@ -99,7 +99,8 @@ got_window:
return w;
}
-void del_window(struct window *w) {
+static void del_no_paint(struct window *w) {
+//logf(LOG_INFO, "-- deleting window 0x%h", w);
if (w == top_window)
top_window = w->below;
if (w == bottom_window)
@@ -109,17 +110,37 @@ void del_window(struct window *w) {
if (w->above)
w->above->below = w->below;
+//logf(LOG_INFO, " -- action buffer was 0x%h", w->action_buffer);
free_pages(w->action_buffer, ACTION_BUFFER_PAGES);
w->pixel_buffer_pma = 0;
+}
+void del_window(struct window *w) {
+ del_no_paint(w);
paint_all();
}
-void resize_window(struct window *w, uint16_t width, uint16_t height) {
+void delete_any_windows_from(struct task_state *tstate) {
+//logf(LOG_INFO, "-- deleting windows from 0x%h", tstate);
+ bool need_to_paint = false;
+ for (struct window *w = windows; w < windows + MAX_WINDOWS; ++w)
+ if (w->pixel_buffer_pma && (w->from_task == tstate)) {
+ //logf(LOG_INFO, " -- found match at 0x%h", w);
+ del_no_paint(w);
+ need_to_paint = true;
+ }
+ if (need_to_paint) {
+ //logf(LOG_INFO, "-- trying to paint after deleting windows");
+ paint_all();
+ }
+}
+
+void resize_window(struct window *w, uint16_t width, uint16_t height, const void *pixel_buffer) {
const bool smaller = (width < w->width) || (height < w->height);
w->width = width;
w->height = height;
+ reassign_pixel_buffer(w, pixel_buffer);
if (smaller)
paint_all();
diff --git a/src/kernel/window.h b/src/kernel/window.h
index 60b81ea..0aa9b0f 100644
--- a/src/kernel/window.h
+++ b/src/kernel/window.h
@@ -5,6 +5,8 @@
#include <winact.h>
+#include "task.h"
+
struct window;
void paint_bg();
@@ -12,7 +14,7 @@ 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 resize_window(struct window *w, uint16_t width, uint16_t height, const void *pixel_buffer);
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);
@@ -20,4 +22,6 @@ void wait_window_action();
void on_action(struct window_action packet);
+void delete_any_windows_from(struct task_state *tstate);
+
#endif
diff --git a/src/user/hello/hello.asm b/src/user/hello/hello.asm
new file mode 100644
index 0000000..cc0645a
--- /dev/null
+++ b/src/user/hello/hello.asm
@@ -0,0 +1,28 @@
+bits 32
+
+global _entry
+
+section .text
+_entry:
+ mov eax, 0x05
+ mov ebx, esi
+ mov ecx, data.len
+ mov edx, data
+ int 0x30
+
+ int 0x38
+
+section .rodata
+data:
+ dd 0xb
+ dd .str_len
+ dd 0
+
+.str:
+ db "Hello, world!", 0x0a
+.str_len equ $ - .str
+
+ dd 0x02
+ dd 0
+ dd 0
+.len equ $ - data \ No newline at end of file
diff --git a/src/user/highway/cmds.c b/src/user/highway/cmds.c
index 0420ae1..53198df 100644
--- a/src/user/highway/cmds.c
+++ b/src/user/highway/cmds.c
@@ -1,4 +1,4 @@
-#include <terminal/terminal.h>
+#include <libterm/terminal.h>
#include <knob/file.h>
diff --git a/src/user/highway/line.c b/src/user/highway/line.c
index bf171e5..cefdf92 100644
--- a/src/user/highway/line.c
+++ b/src/user/highway/line.c
@@ -1,4 +1,4 @@
-#include <terminal/terminal.h>
+#include <libterm/terminal.h>
#include <knob/block.h>
#include <knob/task.h>
@@ -20,7 +20,7 @@ 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(
+ term_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])
);
@@ -32,6 +32,7 @@ static void line_replace(const char *from) {
while (*fi) {
if (ti == line + LINE_SIZE) {
term_add_sz("Line too long.\n");
+ term_paint();
line[0] = '\0';
return;
}
@@ -49,11 +50,13 @@ static void line_replace(const char *from) {
term_addf("Unterminated variable at\"%10s...\".\n", fi);
else
term_addf("Unterminated variable at \"%s\".\n", fi);
+ term_paint();
line[0] = '\0';
return;
}
if (ti + (var_end - var_start) >= line + LINE_SIZE) {
term_add_sz("Line too long.\n");
+ term_paint();
line[0] = '\0';
return;
}
@@ -87,16 +90,17 @@ void run_line(const char *original_line) {
else if (blockequ(line, "echo ", 5)) {
term_add_sz(space + 1);
term_add_char('\n');
+ term_paint();
}
else if (blockequ(line, "vars", 5))
dump_vars();
- else if (blockequ(line, "quit", 5)) {
- del_term(active_term);
+ else if (blockequ(line, "quit", 5))
__pcrt_quit();
+ else if (blockequ(line, "clear", 6)) {
+ term_clear();
+ term_paint();
}
- else if (blockequ(line, "clear", 6))
- clear_term();
- else if (blockequ(line, "help", 5))
+ else if (blockequ(line, "help", 5)) {
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"
@@ -105,10 +109,13 @@ void run_line(const char *original_line) {
" vars\t\t\t" "dump variables\n"
" quit\t\t\t" "exit highway\n"
" help\t\t\t" "show this\n");
+ term_paint();
+ }
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) {
term_add_sz("Could not run command.\n");
+ term_paint();
return;
}
for (uint16_t to_i = LINE_SIZE - 1; to_i >= path->length; --to_i)
@@ -116,14 +123,17 @@ void run_line(const char *original_line) {
blockcpy(line, path->data, path->length);
if (!try_run_command_blocking(line, stdio_task)) {
term_add_sz("Could not run command.\n");
+ term_paint();
return;
}
else {
+ _yield_task();
+ term_add_char('\n');
ensure_color();
- if (active_term->cursor_x)
- term_newline();
}
}
- else
+ else {
+ _yield_task();
ensure_color();
+ }
} \ No newline at end of file
diff --git a/src/user/highway/main.c b/src/user/highway/main.c
index 60d5a69..c9ceee2 100644
--- a/src/user/highway/main.c
+++ b/src/user/highway/main.c
@@ -1,32 +1,21 @@
-#include <terminal/terminal.h>
-#include <terminal/readline.h>
+#include <libterm/terminal.h>
+#include <libterm/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;
+//syslogf(" this task: 0x%2h", this_task);
+//syslogf(" stdio task: 0x%2h", stdio_task);
+//syslogf("calling task: 0x%2h", calling_task);
source(*arg ? arg : "user/default.rc");
ensure_color();
term_add_sz("Portland Highway\nType \"help\" for help.\n");
- paint_term();
+ term_paint();
char cmd_buf[128];
while (1) {
diff --git a/src/user/highway/vars.c b/src/user/highway/vars.c
index 5f56621..82062c4 100644
--- a/src/user/highway/vars.c
+++ b/src/user/highway/vars.c
@@ -1,4 +1,4 @@
-#include <terminal/terminal.h>
+#include <libterm/terminal.h>
#include <knob/format.h>
#include <knob/block.h>
@@ -77,6 +77,7 @@ void del_var(struct no_null_sn name) {
void dump_vars() {
for (struct var_dict_node *node = var_dict_start; node; node = node->next) {
- term_addf_no_ww("$%ns$ = %ns\n", node->name.length, node->name.data, node->value.length, node->value.data);
+ term_addf_no_ww("$%ns$\t= %ns\n", node->name.length, node->name.data, node->value.length, node->value.data);
+ term_paint();
}
} \ No newline at end of file
diff --git a/src/user/include/knob/ipc.h b/src/user/include/knob/ipc.h
index 3eab562..335959d 100644
--- a/src/user/include/knob/ipc.h
+++ b/src/user/include/knob/ipc.h
@@ -5,7 +5,7 @@
//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);
+uint32_t try_send_ipc(_task_handle_t to, const void *buffer, uint32_t size);
//blocking, returns early if other process is dead.
//return value is number of bytes read.
diff --git a/src/user/include/libterm/command.h b/src/user/include/libterm/command.h
new file mode 100644
index 0000000..7587306
--- /dev/null
+++ b/src/user/include/libterm/command.h
@@ -0,0 +1,68 @@
+#ifndef LIBTERM_COMMAND_H
+#define LIBTERM_COMMAND_H
+
+#include <libterm/terminal.h>
+
+#include <knob/ipc.h>
+
+#include <keypack.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+
+//set to stdio task by default
+extern _task_handle_t term_task;
+
+struct terminal_command {
+ enum {
+ SET_DIMENSIONS,
+ GET_DIMENSIONS,
+ PAINT,
+ CLEAR,
+ SET_COLOR,
+ SET_CURSOR,
+ CURSOR_LEFT,
+ CURSOR_RIGHT,
+ CURSOR_UP,
+ CURSOR_DOWN,
+ ADD_CHAR,
+ ADD_SN,
+ ADD_SN_NO_WORDWRAP,
+ GET_KEY
+ } kind;
+
+ union {
+ struct {
+ uint32_t y;
+ uint32_t x;
+ } as_coords;
+ struct {
+ uint8_t fg;
+ uint8_t bg;
+ } as_color;
+ char as_char;
+ uint32_t as_uint;
+ };
+} __attribute__ ((__packed__));
+
+union terminal_response {
+ struct {
+ uint32_t y;
+ uint32_t x;
+ } as_coords;
+ struct key_packet as_key;
+} __attribute__ ((__packed__));
+
+//returns false if terminal has died
+static inline bool try_send_command(struct terminal_command *cmd) {
+ return try_send_ipc(term_task, cmd, sizeof(struct terminal_command))
+ == sizeof(struct terminal_command);
+}
+
+//returns false if terminal has died
+static inline bool try_get_response(union terminal_response *rs) {
+ return try_read_ipc(term_task, rs, sizeof(union terminal_response))
+ == sizeof(union terminal_response);
+}
+
+#endif \ No newline at end of file
diff --git a/src/user/include/terminal/readline.h b/src/user/include/libterm/readline.h
index 9046610..b1d5b0a 100644
--- a/src/user/include/terminal/readline.h
+++ b/src/user/include/libterm/readline.h
@@ -1,5 +1,5 @@
-#ifndef TERMINAL_READLINE_H
-#define TERMINAL_READLINE_H
+#ifndef LIBTERM_READLINE_H
+#define LIBTERM_READLINE_H
#include <stdint.h>
diff --git a/src/user/include/libterm/terminal.h b/src/user/include/libterm/terminal.h
new file mode 100644
index 0000000..19bd517
--- /dev/null
+++ b/src/user/include/libterm/terminal.h
@@ -0,0 +1,35 @@
+#ifndef LIBTERM_TERMINAL_H
+#define LIBTERM_TERMINAL_H
+
+#include <pland/syscall.h>
+
+#include <stdarg.h>
+#include <stdint.h>
+
+void term_set_dimensions(uint32_t width, uint32_t height);
+void term_get_dimensions(uint32_t *width, uint32_t *height);
+
+void term_paint();
+void term_clear();
+
+void term_set_color(uint8_t fg, uint8_t bg);
+void term_set_cursor(uint32_t new_y, uint32_t new_x);
+
+void term_cursor_left();
+void term_cursor_right();
+void term_cursor_up();
+void term_cursor_down();
+
+void term_add_char(char ch);
+void term_add_sn_no_ww(const char *s, uint32_t n);
+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, ...);
+
+struct key_packet term_get_key_blocking();
+
+#endif \ No newline at end of file
diff --git a/src/user/include/pland/pcrt.h b/src/user/include/pland/pcrt.h
index 42158cd..795738e 100644
--- a/src/user/include/pland/pcrt.h
+++ b/src/user/include/pland/pcrt.h
@@ -17,5 +17,6 @@ void __pcrt_quit() __attribute__ ((noreturn));
extern _task_handle_t calling_task;
extern _task_handle_t stdio_task;
+extern _task_handle_t this_task;
#endif
diff --git a/src/user/include/pland/syscall.h b/src/user/include/pland/syscall.h
index 6d327d5..6870865 100644
--- a/src/user/include/pland/syscall.h
+++ b/src/user/include/pland/syscall.h
@@ -39,8 +39,8 @@ enum _scn {
_SCN_PAINT_WINDOW,
_SCN_GET_WIN_ACTION,
_SCN_WAIT_FOR_ACTION,
- _SCN_WAIT_IPC_SEND,
- _SCN_WAIT_FOR_ANY_IPC,
+ _SCN_WAIT_IPC_SENT,
+ _SCN_WAIT_ANY_IPC_SENT,
_SCN_FIND_UNREAD_IPC,
_SCN_WAIT_IPC_READ,
_SCN_IS_TASK_RUNNING
@@ -137,7 +137,7 @@ static inline uint32_t _ipc_send(_task_handle_t handle, uint32_t count, const vo
}
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);
+ return _sc3(_SCN_IPC_READ, handle, count, (uint32_t)buffer);
}
static inline void *_allocate_ram(uint32_t pages) {
@@ -184,11 +184,11 @@ static inline void _delete_window(_window_handle_t window) {
_sc1(_SCN_DELETE_WINDOW, (uint32_t)window);
}
-static inline void _resize_window(_window_handle_t window, uint16_t width, uint16_t height) {
- _sc3(_SCN_RESIZE_WINDOW, (uint32_t)window, width, height);
+static inline void _resize_window(_window_handle_t window, uint16_t width, uint16_t height, const void *pixel_buffer) {
+ _sc4(_SCN_RESIZE_WINDOW, (uint32_t)window, width, height, (uint32_t)pixel_buffer);
}
-static inline void _reassign_pixbuf(_window_handle_t window, void *pixel_buffer) {
+static inline void _reassign_pixbuf(_window_handle_t window, const void *pixel_buffer) {
_sc2(_SCN_REASSIGN_PIXBUF, (uint32_t)window, (uint32_t)pixel_buffer);
}
@@ -204,16 +204,16 @@ 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 _wait_ipc_sent(_task_handle_t sending_task) {
+ _sc1(_SCN_WAIT_IPC_SENT, 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 void _wait_for_any_ipc_sent() {
+ _sc0(_SCN_WAIT_ANY_IPC_SENT);
}
static inline _task_handle_t _find_unread_ipc() {
diff --git a/src/user/include/popups/popup.h b/src/user/include/popups/popup.h
index 1a3c531..9a39997 100644
--- a/src/user/include/popups/popup.h
+++ b/src/user/include/popups/popup.h
@@ -11,8 +11,7 @@ struct popup {
struct key_packet quit_as;
//terminated by one with .key_id == 0
- struct key_packet *quit_binds;
- bool free_quit_binds;
+ const struct key_packet *quit_binds;
};
void handle_actions(struct popup *p);
diff --git a/src/user/include/terminal/terminal.h b/src/user/include/terminal/terminal.h
deleted file mode 100644
index 1782173..0000000
--- a/src/user/include/terminal/terminal.h
+++ /dev/null
@@ -1,57 +0,0 @@
-#ifndef TERMINAL_TERMINAL_H
-#define TERMINAL_TERMINAL_H
-
-#include <libfont/fonts.h>
-
-#include <pland/syscall.h>
-
-#include <stdarg.h>
-#include <stdint.h>
-
-struct terminal {
- _window_handle_t window;
- uint8_t *pixbuf;
- uint32_t window_width;
- uint32_t window_height;
-
- struct font_info *font;
-
- uint32_t cols;
- uint32_t rows;
- char *charbuf;
-
- uint32_t cursor_y;
- uint32_t cursor_x;
-
- uint8_t fg;
- uint8_t bg;
-};
-
-struct terminal *make_term(struct font_info *font, uint32_t cols, uint32_t rows);
-void del_term(struct terminal *term);
-
-extern struct terminal *active_term;
-
-void paint_term();
-
-void set_color(uint8_t fg, uint8_t bg);
-void clear_term();
-
-void move_cursor(uint32_t new_y, uint32_t new_x);
-
-void cursor_left();
-void cursor_right();
-void cursor_up();
-void cursor_down();
-
-void term_newline();
-void term_add_char(char ch);
-void term_add_sz_no_ww(const char *sz);
-void term_add_sz(const char *sz);
-
-void term_addf_no_ww_v(const char *fmt, va_list args);
-void term_addf_no_ww(const char *fmt, ...);
-void term_addf_v(const char *fmt, va_list args);
-void term_addf(const char *fmt, ...);
-
-#endif \ No newline at end of file
diff --git a/src/user/knob/format.c b/src/user/knob/format.c
index 54d50ef..c5d2447 100644
--- a/src/user/knob/format.c
+++ b/src/user/knob/format.c
@@ -81,6 +81,8 @@ static const char *get_format(const char *from, struct format_spec *format_out)
return from + 1;
}
+//char debug[] = "-- format_v: fmt = \" \"...";
+
//allocates new memory
char *format_v(const char *fmt, va_list args) {
buf = get_block(FORMAT_BUF_INIT_SIZE);
@@ -90,6 +92,11 @@ char *format_v(const char *fmt, va_list args) {
buf_i = buf;
while (*fmt) {
+ //debug[20] = *fmt;
+ //debug[21] = fmt[1];
+ //debug[22] = fmt[2];
+ //_system_log(debug);
+
if (*fmt != '%') {
ensure(1);
*(buf_i++) = *(fmt++);
@@ -133,11 +140,15 @@ char *format_v(const char *fmt, va_list args) {
case UNSIGNED_DECIMAL:
k = va_arg(args, uint32_t);
if (!form.len) {
- uint32_t n = 10;
- ++form.len;
- while (k >= n) {
+ if (k >= 1000000000)
+ form.len = 10;
+ else {
+ uint32_t n = 10;
++form.len;
- n *= 10;
+ while (k >= n) {
+ ++form.len;
+ n *= 10;
+ }
}
}
ensure(form.len);
diff --git a/src/user/knob/ipc.c b/src/user/knob/ipc.c
index dbf1a22..5ca4bb4 100644
--- a/src/user/knob/ipc.c
+++ b/src/user/knob/ipc.c
@@ -2,10 +2,12 @@
//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) {
+uint32_t try_send_ipc(_task_handle_t to, const void *buffer, uint32_t size) {
const uint32_t size_backup = size;
while (size) {
+ //syslogf("_ipc_send(0x%2h, 0x%h, %u)", to, buffer, size);
uint32_t res = _ipc_send(to, size, buffer);
+ //syslogf("=> %u", res);
if (!res) {
_wait_ipc_read(to);
_yield_task();
@@ -17,16 +19,19 @@ uint32_t try_send_ipc(_task_handle_t to, void *buffer, uint32_t size) {
buffer += res;
}
}
+ return size_backup;
}
//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) {
+uint32_t try_read_ipc(_task_handle_t from, void *buffer, uint32_t size) {
const uint32_t size_backup = size;
while (size) {
+ //syslogf("_ipc_read(0x%2h, 0x%h, %u)", from, buffer, size);
uint32_t res = _ipc_read(from, size, buffer);
+ //syslogf("=> %u", res);
if (!res) {
- _wait_ipc_send(from);
+ _wait_ipc_sent(from);
_yield_task();
}
else if (res == -1)
@@ -36,6 +41,7 @@ uint32_t read_ipc(_task_handle_t from, void *buffer, uint32_t size) {
buffer += res;
}
}
+ return size_backup;
}
void flush_ipc(_task_handle_t from) {
diff --git a/src/user/knob/task.c b/src/user/knob/task.c
index 3bf3e85..9a49386 100644
--- a/src/user/knob/task.c
+++ b/src/user/knob/task.c
@@ -1,9 +1,12 @@
-#include <stdbool.h>
#include <pland/syscall.h>
#include <knob/file.h>
#include <knob/heap.h>
#include <knob/block.h>
+#include <stdbool.h>
+
+#include <knob/format.h>
+
_task_handle_t run_command(const char *path, _task_handle_t stdio_task) {
uint8_t dn;
path = remove_prefix(path, &dn);
@@ -14,9 +17,9 @@ _task_handle_t run_command(const char *path, _task_handle_t stdio_task) {
blockcpy(new_path, path, ptr - path);
new_path[ptr - path] = '\0';
- bool succeded = _start_task(dn, new_path, ptr + 1, stdio_task);
+ _task_handle_t handle = _start_task(dn, new_path, ptr + 1, stdio_task);
free_block(new_path);
- return succeded;
+ return handle;
}
return _start_task(dn, path, "", stdio_task);
@@ -24,11 +27,12 @@ _task_handle_t run_command(const char *path, _task_handle_t stdio_task) {
bool try_run_command_blocking(const char *path, _task_handle_t stdio_task) {
_task_handle_t handle = run_command(path, stdio_task);
- if (!handle)
+ if (!handle) {
return false;
- while (_is_task_running(handle)) {
+ }
+ do {
_wait_for_task(handle);
_yield_task();
- }
+ } while (_is_task_running(handle));
return true;
} \ No newline at end of file
diff --git a/src/user/libterm/readline.c b/src/user/libterm/readline.c
new file mode 100644
index 0000000..b37801d
--- /dev/null
+++ b/src/user/libterm/readline.c
@@ -0,0 +1,106 @@
+#include <libterm/terminal.h>
+
+#include <knob/block.h>
+#include <knob/key.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) {
+ term_add_sz(prompt);
+ term_add_char(' ');
+ term_paint();
+
+ uint32_t l = 0;
+ uint32_t c = 0;
+
+ while (1) {
+ struct key_packet kp = term_get_key_blocking();
+ switch (kp.key_id) {
+ case KEY_LEFT_ARROW:
+ if (c) {
+ --c;
+ term_cursor_left();
+ term_paint();
+ }
+ continue;
+ case KEY_RIGHT_ARROW:
+ if (c != l) {
+ ++c;
+ term_cursor_right();
+ term_paint();
+ }
+ continue;
+ case KEY_HOME:
+ while (c) {
+ --c;
+ term_cursor_left();
+ }
+ term_paint();
+ continue;
+ case KEY_END:
+ while (c != l) {
+ ++c;
+ term_cursor_right();
+ }
+ term_paint();
+ continue;
+ case KEY_DELETE:
+ if (c != l) {
+ ++c;
+ term_cursor_right();
+ }
+ case KEY_BSPACE:
+ if (!c)
+ continue;
+ --c;
+ --l;
+ for (uint32_t i = c; i < l; ++i)
+ sz[i] = sz[i + 1];
+ term_cursor_left();
+ term_add_sn_no_ww(sz + c, l - c);
+ term_add_char(' ');
+ for (uint32_t i = l + 1; i > c; --i)
+ term_cursor_left();
+ term_paint();
+ continue;
+ case KEY_ENTER:
+ while (c != l) {
+ ++c;
+ term_cursor_right();
+ }
+ sz[l] = '\0';
+ term_add_char('\n');
+ term_paint();
+ return l;
+ default:
+ if (l == max_length)
+ continue;
+ char ch = key_to_char(kp);
+ if (!ch)
+ continue;
+ if (c == l) {
+ ++l;
+ term_add_char(sz[c++] = ch);
+ term_paint();
+ continue;
+ }
+ if (!(kp.modifiers & INSERT)) {
+ term_add_char(sz[c++] = ch);
+ term_paint();
+ continue;
+ }
+ for (uint32_t i = l; i > c; --i)
+ sz[i] = sz[i - 1];
+ sz[c] = ch;
+ ++l;
+ term_add_sn_no_ww(sz + c, l - c);
+ ++c;
+ for (uint32_t i = l; i > c; --i)
+ term_cursor_left();
+ term_paint();
+ continue;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/user/libterm/terminal.c b/src/user/libterm/terminal.c
new file mode 100644
index 0000000..387d63f
--- /dev/null
+++ b/src/user/libterm/terminal.c
@@ -0,0 +1,179 @@
+#include <libterm/command.h>
+
+#include <knob/format.h>
+#include <knob/block.h>
+#include <knob/ipc.h>
+
+_task_handle_t term_task;
+
+void term_set_dimensions(uint32_t width, uint32_t height) {
+ struct terminal_command cmd = {
+ .kind = SET_DIMENSIONS,
+ .as_coords = {
+ .x = width,
+ .y = height
+ }
+ };
+
+ try_send_command(&cmd);
+}
+
+void term_get_dimensions(uint32_t *width, uint32_t *height) {
+ struct terminal_command cmd = {
+ .kind = GET_DIMENSIONS
+ };
+
+ if (try_send_command(&cmd)) {
+ union terminal_response rs;
+ if (try_get_response(&rs)) {
+ *width = rs.as_coords.x;
+ *height = rs.as_coords.y;
+ }
+ }
+}
+
+void term_paint() {
+ struct terminal_command cmd = {
+ .kind = PAINT
+ };
+
+ try_send_command(&cmd);
+}
+
+void term_clear() {
+ struct terminal_command cmd = {
+ .kind = CLEAR
+ };
+
+ try_send_command(&cmd);
+}
+
+void term_set_color(uint8_t fg, uint8_t bg) {
+ struct terminal_command cmd = {
+ .kind = SET_COLOR,
+ .as_color = {
+ .fg = fg,
+ .bg = bg
+ }
+ };
+
+ try_send_command(&cmd);
+}
+
+void term_set_cursor(uint32_t new_y, uint32_t new_x) {
+ struct terminal_command cmd = {
+ .kind = SET_CURSOR,
+ .as_coords = {
+ .y = new_y,
+ .x = new_x
+ }
+ };
+
+ try_send_command(&cmd);
+}
+
+void term_cursor_left() {
+ struct terminal_command cmd = {
+ .kind = CURSOR_LEFT
+ };
+
+ try_send_command(&cmd);
+}
+
+void term_cursor_right() {
+ struct terminal_command cmd = {
+ .kind = CURSOR_RIGHT
+ };
+
+ try_send_command(&cmd);
+}
+
+void term_cursor_up() {
+ struct terminal_command cmd = {
+ .kind = CURSOR_UP
+ };
+
+ try_send_command(&cmd);
+}
+
+void term_cursor_down() {
+ struct terminal_command cmd = {
+ .kind = CURSOR_DOWN
+ };
+
+ try_send_command(&cmd);
+}
+
+void term_add_char(char ch) {
+ struct terminal_command cmd = {
+ .kind = ADD_CHAR,
+ .as_char = ch
+ };
+
+ try_send_command(&cmd);
+}
+
+void term_add_sn_no_ww(const char *s, uint32_t n) {
+ struct terminal_command cmd = {
+ .kind = ADD_SN_NO_WORDWRAP,
+ .as_uint = n
+ };
+
+ if (try_send_command(&cmd))
+ try_send_ipc(term_task, s, n);
+}
+
+void term_add_sz_no_ww(const char *sz) {
+ term_add_sn_no_ww(sz, strlen(sz));
+}
+
+void term_add_sz(const char *sz) {
+ const uint32_t len = strlen(sz);
+
+ struct terminal_command cmd = {
+ .kind = ADD_SN,
+ .as_uint = len
+ };
+
+ if (try_send_command(&cmd))
+ try_send_ipc(term_task, sz, len);
+}
+
+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);
+}
+
+struct key_packet term_get_key_blocking() {
+ struct terminal_command cmd = {
+ .kind = GET_KEY
+ };
+
+ try_send_command(&cmd);
+
+ union terminal_response rs;
+ try_get_response(&rs);
+
+ return rs.as_key;
+}
diff --git a/src/user/libterm/termtask.c b/src/user/libterm/termtask.c
new file mode 100644
index 0000000..cc853a6
--- /dev/null
+++ b/src/user/libterm/termtask.c
@@ -0,0 +1,9 @@
+#include <libterm/command.h>
+
+#include <pland/pcrt.h>
+
+void set_term_task_to_stdio() {
+ term_task = stdio_task;
+}
+
+BEFORE_MAIN(set_term_task_to_stdio); \ No newline at end of file
diff --git a/src/user/popups/info.c b/src/user/popups/info.c
index 81a09e9..58903c8 100644
--- a/src/user/popups/info.c
+++ b/src/user/popups/info.c
@@ -43,7 +43,6 @@ void info_popup(struct popup *into, const char *msg, uint8_t fg, uint8_t bg) {
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;
diff --git a/src/user/popups/popup.c b/src/user/popups/popup.c
index d214f81..9cdccb4 100644
--- a/src/user/popups/popup.c
+++ b/src/user/popups/popup.c
@@ -30,8 +30,6 @@ void handle_actions(struct popup *p) {
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) {
diff --git a/src/user/runtimes/c/pcrt.asm b/src/user/runtimes/c/pcrt.asm
index 85c898c..0f06236 100644
--- a/src/user/runtimes/c/pcrt.asm
+++ b/src/user/runtimes/c/pcrt.asm
@@ -4,6 +4,7 @@ global __pcrt_entry
global __pcrt_quit
global calling_task
global stdio_task
+global this_task
extern main
extern __pcrt_before_main_start
@@ -13,8 +14,9 @@ extern __pcrt_before_quit_end
section .text
__pcrt_entry:
- mov dword [calling_task], esi
- mov dword [stdio_task], edi
+ mov dword [calling_task], edi
+ mov dword [stdio_task], esi
+ mov dword [this_task], ecx
push edx
mov ebx, __pcrt_before_main_start
@@ -42,4 +44,5 @@ __pcrt_quit:
section .bss
calling_task resd 1
-stdio_task resd 1 \ No newline at end of file
+stdio_task resd 1
+this_task resd 1 \ No newline at end of file
diff --git a/src/user/terminal/main.c b/src/user/terminal/main.c
new file mode 100644
index 0000000..15ca6a1
--- /dev/null
+++ b/src/user/terminal/main.c
@@ -0,0 +1,373 @@
+#include <libterm/command.h>
+
+#include <libfont/fonts.h>
+
+#include <knob/format.h>
+#include <knob/heap.h>
+#include <knob/task.h>
+#include <knob/ipc.h>
+
+#include <pland/syscall.h>
+#include <pland/pcrt.h>
+
+#define FONT_HARDCODE "berry"
+
+_window_handle_t window;
+uint8_t *pixbuf;
+char *termbuf;
+struct font_info *font;
+
+uint32_t width;
+uint32_t height;
+uint32_t cols = 50;
+uint32_t rows = 15;
+
+uint32_t cursor_y = 0;
+uint32_t cursor_x = 0;
+
+uint8_t bg_color = 0x10;
+uint8_t fg_color = 0x07;
+
+struct waiting_for_key_record {
+ _task_handle_t task;
+ struct waiting_for_key_record *next;
+} *first_key_waiting = 0, *last_key_waiting = 0;
+
+static void draw_char(uint32_t y, uint32_t x, bool inverted) {
+//syslogf("drawing 0x%2h%s at %u, %u", termbuf[y * cols + x], inverted ? " inverted" : "", y, x);
+ put_char(font, termbuf[y * cols + x], pixbuf + y * font->space_height * width + x * font->space_width, width, inverted ? fg_color : bg_color, inverted ? bg_color : fg_color);
+}
+
+static void clear() {
+ for (uint32_t i = 0; i < cols * rows; ++i)
+ termbuf[i] = ' ';
+ for (uint32_t i = 0; i < width * height; ++i)
+ pixbuf[i] = bg_color;
+}
+
+static void scroll_fw() {
+ uint32_t i;
+ for (i = 0; i < cols * (rows - 1); ++i)
+ termbuf[i] = termbuf[i + cols];
+ for (; i < cols * rows; ++i)
+ termbuf[i] = ' ';
+ const uint32_t row_height = font->space_height;
+ for (i = 0; i < width * (height - row_height); ++i)
+ pixbuf[i] = pixbuf[i + width * row_height];
+ for (; i < width * height; ++i)
+ pixbuf[i] = bg_color;
+}
+
+static void cursor_down() {
+ if (cursor_y == rows - 1)
+ scroll_fw();
+ else
+ ++cursor_y;
+}
+
+static void cursor_right() {
+ if (cursor_x == cols - 1) {
+ cursor_x = 0;
+ cursor_down();
+ }
+ else
+ ++cursor_x;
+}
+
+__attribute__ ((pure))
+static uint32_t word_len(const char *sz) {
+ const char *const back = sz;
+ while ((*sz != ' ') && (*sz != '\n') && *sz && (*sz != '\t'))
+ ++sz;
+ return sz - back;
+}
+
+#define MIN_TAB 3
+#define TAB_STOP 4
+
+static void on_newline() {
+ draw_char(cursor_y, cursor_x, false);
+ cursor_x = 0;
+ cursor_down();
+}
+
+static void add_char(char ch);
+
+static void on_tab() {
+ for (uint32_t i = 0; i < MIN_TAB; ++i)
+ add_char(' ');
+ while (cursor_x % TAB_STOP)
+ add_char(' ');
+}
+
+static void add_char(char ch) {
+ if (ch == '\n')
+ on_newline();
+ else if (ch == '\t')
+ on_tab();
+ else {
+ termbuf[cursor_y * cols + cursor_x] = ch;
+ draw_char(cursor_y, cursor_x, false);
+ cursor_right();
+ }
+}
+
+static void add_sz_no_ww(const char *sz) {
+ while (*sz)
+ add_char(*(sz++));
+}
+
+static void add_sn_no_ww(const char *sz, uint32_t l) {
+ for (uint32_t i = 0; i < l; ++i)
+ add_char(sz[i]);
+}
+
+static void add_sz_ww(const char *sz) {
+ while (*sz) {
+ if (*sz == ' ') {
+ ++sz;
+ continue;
+ }
+ if (*sz == '\n') {
+ on_newline();
+ ++sz;
+ continue;
+ }
+ if (*sz == '\t') {
+ on_tab();
+ ++sz;
+ continue;
+ }
+
+ if (cursor_x)
+ add_char(' ');
+
+ const uint32_t len = word_len(sz);
+
+ if ((len > cols - cursor_x) && (len <= cols)) {
+ cursor_x = 0;
+ cursor_down();
+ }
+ add_sn_no_ww(sz, len);
+
+ sz += len;
+ }
+}
+
+char *const sz_empty_backup = "";
+char *sz_from_task = 0;
+uint32_t sz_buf_size = 0;
+
+#define BUF_INCREMENTS 1024
+
+static void get_sn(uint32_t len, _task_handle_t from) {
+ if (sz_buf_size <= len) {
+ if (sz_from_task && (sz_from_task != sz_empty_backup))
+ free_block(sz_from_task);
+ sz_from_task = get_block(sz_buf_size += 1024);
+ if (!sz_from_task) {
+ add_sz_ww("Could not allocate enough memory for sent string. Treating as empty string.\n");
+ sz_buf_size = 0;
+ sz_from_task = sz_empty_backup;
+ return;
+ }
+ }
+
+ const uint32_t real_len = try_read_ipc(from, sz_from_task, len);
+ sz_from_task[real_len] = '\0';
+}
+
+static void set_dimensions(uint32_t new_rows, uint32_t new_cols) {
+ free_block(termbuf);
+ free_block(pixbuf);
+ //from here until _resize, the kernel may draw garbage if it
+ // needs to redraw the window. it won't page fault though.
+
+ rows = new_rows;
+ cols = new_cols;
+ termbuf = get_block(rows * cols);
+
+ width = cols * font->space_width;
+ height = cols * font->space_height;
+ pixbuf = get_block(width * height);
+
+ cursor_y = 0;
+ cursor_x = 0;
+ clear();
+
+ _resize_window(window, width, height, pixbuf);
+}
+
+void draw_all() {
+ for (uint32_t y = 0; y < rows; ++y)
+ for (uint32_t x = 0; x < cols; ++x)
+ draw_char(y, x, false);
+ draw_char(cursor_y, cursor_x, true);
+}
+
+//#include <knob/format.h>
+
+void main(const char *cmd) {
+//syslogf(" this task: 0x%2h", this_task);
+//syslogf(" stdio task: 0x%2h", stdio_task);
+//syslogf("calling task: 0x%2h", calling_task);
+
+ font = get_font(FONT_HARDCODE);
+ if (!font)
+ return;
+
+ termbuf = get_block(cols * rows);
+ width = cols * font->space_width;
+ height = rows * font->space_height;
+ pixbuf = get_block(width * height);
+ clear();
+ add_sz_ww("Portland Terminal\n");
+ window = _new_window(width, height, pixbuf);
+ _paint_window(window);
+
+ _task_handle_t child_handle = run_command(cmd, this_task);
+ if (!child_handle) {
+ add_sz_ww("Failed to run passed command. Press any key to close.\n");
+ _paint_window(window);
+ while (1) {
+ struct window_action action;
+ _get_win_action(window, &action);
+ if (action.action_type == NOT_READY) {
+ _wait_for_action();
+ _yield_task();
+ }
+ else if (action.action_type == KEY_DOWN)
+ return;
+ }
+ }
+
+ while (1) {
+ if (first_key_waiting) {
+ struct window_action action;
+ _get_win_action(window, &action);
+ if (action.action_type == KEY_DOWN) {
+ union terminal_response rs = {
+ .as_key = action.as_key
+ };
+ try_send_ipc(first_key_waiting->task, &rs, sizeof(union terminal_response));
+ free_block(first_key_waiting);
+ first_key_waiting = first_key_waiting->next;
+ if (!first_key_waiting)
+ last_key_waiting = 0;
+ continue;
+ }
+ }
+
+ _task_handle_t from = _find_unread_ipc();
+ if (!from) {
+ if (!_is_task_running(child_handle))
+ return;
+
+ _wait_for_action();
+ _wait_for_any_ipc_sent();
+ _wait_for_task(child_handle);
+ _yield_task();
+ continue;
+ }
+
+ struct terminal_command request;
+ const uint32_t read = try_read_ipc(from, &request, sizeof(struct terminal_command));
+ if (read != sizeof(struct terminal_command)) {
+ syslogf("received %u / %u bytes of a command from 0x%2x", read, sizeof(struct terminal_command), from);
+ continue;
+ }
+ //syslogf("received full command from 0x%2x", from);
+
+ switch (request.kind) {
+ case SET_DIMENSIONS:
+ set_dimensions(request.as_coords.y, request.as_coords.x);
+ continue;
+ union terminal_response rs;
+ case GET_DIMENSIONS:
+ rs.as_coords.y = rows;
+ rs.as_coords.x = cols;
+ try_send_ipc(from, &rs, sizeof(union terminal_response));
+ continue;
+ case PAINT:
+ _paint_window(window);
+ continue;
+ case CLEAR:
+ clear();
+ cursor_y = 0;
+ cursor_x = 0;
+ draw_char(0, 0, true);
+ continue;
+ case SET_COLOR:
+ fg_color = request.as_color.fg;
+ bg_color = request.as_color.bg;
+ draw_all();
+ continue;
+ case SET_CURSOR:
+ draw_char(cursor_y, cursor_x, false);
+ cursor_y = request.as_coords.y;
+ cursor_x = request.as_coords.x;
+ draw_char(cursor_y, cursor_x, true);
+ continue;
+ case CURSOR_LEFT:
+ draw_char(cursor_y, cursor_x, false);
+ if (cursor_x)
+ --cursor_x;
+ else if (cursor_y) {
+ cursor_x = cols - 1;
+ --cursor_y;
+ }
+ draw_char(cursor_y, cursor_x, true);
+ continue;
+ case CURSOR_RIGHT:
+ draw_char(cursor_y, cursor_x, false);
+ cursor_right();
+ draw_char(cursor_y, cursor_x, true);
+ continue;
+ case CURSOR_UP:
+ if (cursor_y) {
+ draw_char(cursor_y, cursor_x, false);
+ --cursor_y;
+ draw_char(cursor_y, cursor_x, true);
+ }
+ continue;
+ case CURSOR_DOWN:
+ draw_char(cursor_y, cursor_x, false);
+ if (cursor_y == rows - 1)
+ scroll_fw();
+ else
+ ++cursor_y;
+ draw_char(cursor_y, cursor_x, true);
+ continue;
+ case ADD_CHAR:
+ add_char(request.as_char);
+ draw_char(cursor_y, cursor_x, true);
+ continue;
+ case ADD_SN:
+ draw_char(cursor_y, cursor_x, false);
+ get_sn(request.as_uint, from);
+ add_sz_ww(sz_from_task);
+ draw_char(cursor_y, cursor_x, true);
+ continue;
+ case ADD_SN_NO_WORDWRAP:
+ draw_char(cursor_y, cursor_x, false);
+ get_sn(request.as_uint, from);
+ add_sz_no_ww(sz_from_task);
+ draw_char(cursor_y, cursor_x, true);
+ continue;
+ struct waiting_for_key_record *new_record;
+ case GET_KEY:
+ new_record = get_block(sizeof(struct waiting_for_key_record));
+ if (last_key_waiting)
+ last_key_waiting->next = new_record;
+ else
+ first_key_waiting = new_record;
+ last_key_waiting = new_record;
+ new_record->task = from;
+ new_record->next = 0;
+ continue;
+ default:
+ add_sz_ww("Bad terminal command received, ignoring.\n");
+ continue;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/user/terminal/readline.c b/src/user/terminal/readline.c
deleted file mode 100644
index 37ef54b..0000000
--- a/src/user/terminal/readline.c
+++ /dev/null
@@ -1,104 +0,0 @@
-#include <terminal/terminal.h>
-
-#include <knob/format.h>
-#include <knob/heap.h>
-#include <knob/key.h>
-
-#include <pland/syscall.h>
-
-#include <stdint.h>
-
-//returns length of string without null terminator
-//max_length doesn't include null terminator
-uint32_t read_line(char *sz, uint32_t max_length, const char *prompt) {
- uint32_t i = 0;
- uint32_t l = 0;
-
- term_add_sz_no_ww(prompt);
- paint_term();
-
- const _window_handle_t handle = active_term->window;
- struct window_action action;
- while (1) {
- _get_win_action(handle, &action);
- switch (action.action_type) {
- case NOT_READY:
- _wait_for_action();
- _yield_task();
- continue;
- case KEY_DOWN:
- //;char *const debug_msg = format("got key 0x%2x, 0x%3x", action.as_key.key_id, action.as_key.modifiers);
- // _system_log(debug_msg);
- // free_block(debug_msg);
- switch (action.as_key.key_id) {
- case KEY_DELETE:
- if (i != l) {
- cursor_right();
- ++i;
- }
- case KEY_BSPACE:
- if (!i)
- continue;
- --l;
- --i;
- for (uint8_t j = i; j < l; ++j)
- sz[j] = sz[j + 1];
- sz[l] = '\0';
- cursor_left();
- uint32_t cursor_backup_x = active_term->cursor_x;
- uint32_t cursor_backup_y = active_term->cursor_y;
- term_add_sz_no_ww(sz + i);
- term_add_char(' ');
- move_cursor(cursor_backup_y, cursor_backup_x);
- paint_term();
- continue;
- case KEY_ENTER:
- term_newline();
- paint_term();
- sz[l] = '\0';
- return l;
- case KEY_HOME:
- case KEY_UP_ARROW:
- for (; i; --i)
- cursor_left();
- paint_term();
- continue;
- case KEY_END:
- case KEY_DOWN_ARROW:
- for (; i != l; ++i)
- cursor_right();
- paint_term();
- continue;
- case KEY_LEFT_ARROW:
- if (i) {
- cursor_left();
- paint_term();
- --i;
- }
- continue;
- case KEY_RIGHT_ARROW:
- if (i != l) {
- cursor_right();
- paint_term();
- ++i;
- }
- continue;
- default:
- if (i == max_length)
- continue;
- char ch = key_to_char(action.as_key);
- if (ch) {
- term_add_char(ch);
- paint_term();
- sz[i] = ch;
- if (i == l)
- ++l;
- ++i;
- }
- continue;
- }
- default:
- continue;
- }
- }
-} \ No newline at end of file
diff --git a/src/user/terminal/terminal.c b/src/user/terminal/terminal.c
deleted file mode 100644
index 7961fd5..0000000
--- a/src/user/terminal/terminal.c
+++ /dev/null
@@ -1,284 +0,0 @@
-#include <terminal/terminal.h>
-
-#include <libfont/fonts.h>
-
-#include <knob/format.h>
-#include <knob/heap.h>
-
-struct term_list_entry {
- struct terminal term;
- struct term_list_entry *next;
- struct term_list_entry *prev;
-};
-
-struct term_list_entry *last_term = 0;
-struct terminal *active_term = 0;
-
-struct terminal *make_term(struct font_info *font, uint32_t cols, uint32_t rows) {
- if (!font)
- return 0;
-
- struct term_list_entry *next_entry = get_block(sizeof(struct term_list_entry));
- if (!next_entry)
- return 0;
-
- char *const cb = get_block(cols * rows);
-
- if (!cb) {
- free_block(next_entry);
- return 0;
- }
-
- const uint32_t w = cols * font->space_width;
- const uint32_t h = rows * font->space_height;
-
- uint8_t *const pb = get_block(w * h);
- if (!pb) {
- free_block(next_entry);
- free_block(cb);
- return 0;
- }
-
- _window_handle_t win = _new_window(w, h, pb);
- if (!win) {
- free_block(next_entry);
- free_block(cb);
- free_block(pb);
- return 0;
- }
-
- for (char *i = cb; i < cb + cols * rows; ++i)
- *i = ' ';
- for (uint8_t *i = pb; i < pb + w * h; ++i)
- *i = 0x10;
-
- next_entry->term.window = win;
- next_entry->term.pixbuf = pb;
- next_entry->term.window_width = w;
- next_entry->term.window_height = h;
-
- next_entry->term.font = font;
-
- next_entry->term.cols = cols;
- next_entry->term.rows = rows;
- next_entry->term.charbuf = cb;
-
- next_entry->term.cursor_y = 0;
- next_entry->term.cursor_x = 0;
-
- next_entry->term.fg = 0x0f;
- next_entry->term.bg = 0x10;
-
- next_entry->prev = last_term;
- next_entry->next = 0;
-
- if (last_term)
- last_term->next = next_entry;
- last_term = next_entry;
-
- return (struct terminal *)next_entry;
-}
-
-void del_term(struct terminal *term) {
- _delete_window(term->window);
- free_block(term->pixbuf);
- free_block(term->charbuf);
-
- free_block(term);//coincides with the term_list_entry
- if (active_term == term)
- active_term = 0;
-
- for (struct term_list_entry *i = last_term; i; i = i->prev)
- if (i == (struct term_list_entry *)term) {
- if (i->prev)
- i->prev->next = i->next;
- if (i->next)
- i->next->prev = i->prev;
- if (i == last_term)
- last_term = i->prev;
- return;
- }
-}
-
-static void draw_char(uint32_t y, uint32_t x, bool inverted) {
- put_char(active_term->font, active_term->charbuf[y * active_term->cols + x], active_term->pixbuf + (y * active_term->cols * active_term->font->space_height + x) * active_term->font->space_width, active_term->window_width, inverted ? active_term->fg : active_term->bg, inverted ? active_term->bg : active_term->fg);
-}
-
-static void draw_cursor() {
- draw_char(active_term->cursor_y, active_term->cursor_x, true);
-}
-
-void paint_term() {
- _paint_window(active_term->window);
-}
-
-void move_cursor(uint32_t new_y, uint32_t new_x) {
- draw_char(active_term->cursor_y, active_term->cursor_x, false);
- active_term->cursor_y = new_y;
- active_term->cursor_x = new_x;
- draw_cursor();
-}
-
-static void redraw_term() {
- for (uint32_t y = 0; y < active_term->rows; ++y)
- for (uint32_t x = 0; x < active_term->cols; ++x)
- draw_char(y, x, false);
- draw_cursor();
-}
-
-void set_color(uint8_t fg, uint8_t bg) {
- active_term->fg = fg;
- active_term->bg = bg;
- redraw_term();
-}
-
-void clear_term() {
- for (char *i = active_term->charbuf, *const e = i + active_term->cols * active_term->rows; i != e; ++i)
- *i = ' ';
- for (uint8_t *i = active_term->pixbuf, *const e = i + active_term->window_width * active_term->window_height; i != e; ++i)
- *i = active_term->bg;
- move_cursor(0, 0);
-}
-
-void cursor_up() {
- draw_char(active_term->cursor_y, active_term->cursor_x, false);
- if (active_term->cursor_y)
- --active_term->cursor_y;
- else
- //eventually, maybe scroll back through a longer terminal buffer
- active_term->cursor_x = 0;
- draw_cursor();
-}
-
-void cursor_left() {
- draw_char(active_term->cursor_y, active_term->cursor_x, false);
- if (active_term->cursor_x) {
- --active_term->cursor_x;
- draw_cursor();
- }
- else {
- active_term->cursor_x = active_term->cols - 1;
- cursor_up();
- }
-}
-
-void cursor_down() {
- draw_char(active_term->cursor_y, active_term->cursor_x, false);
-
- const uint32_t rows = active_term->rows;
-
- if (++active_term->cursor_y == rows) {
- --active_term->cursor_y;
-
- char *const cb = active_term->charbuf;
- uint8_t *const pb = active_term->pixbuf;
- const uint32_t cols = active_term->cols;
- const uint32_t fw = active_term->font->space_width;
- const uint32_t fh = active_term->font->space_height;
-
- char *to;
- for (to = cb; to < cb + (rows - 1) * cols; ++to)
- *to = *(to + cols);
- for (; to < cb + rows * cols; ++to)
- *to = ' ';
- uint8_t *pto;
- for (pto = pb; pto < pb + cols * fw * (rows - 1) * fh; ++pto)
- *pto = *(pto + cols * fw * fh);
- for (; pto < pb + cols * fw * rows * fh; ++pto)
- *pto = active_term->bg;
- }
-
- draw_cursor();
-}
-
-void cursor_right() {
- draw_char(active_term->cursor_y, active_term->cursor_x, false);
-
- if (++active_term->cursor_x == active_term->cols)
- term_newline();
- else
- draw_cursor();
-}
-
-void term_newline() {
- draw_char(active_term->cursor_y, active_term->cursor_x, false);
- active_term->cursor_x = 0;
- cursor_down();
-}
-
-void term_add_char(char ch) {
- if (ch == '\n') {
- term_newline();
- return;
- }
-//char *const debug_msg = format("charbuf[%u] = '%c'", active_term->cursor_y * active_term->cols + active_term->cursor_x, ch);
-//_system_log(debug_msg);
-//free_block(debug_msg);
- active_term->charbuf[active_term->cursor_y * active_term->cols + active_term->cursor_x] = ch;
- cursor_right();
-}
-
-void term_add_sz_no_ww(const char *sz) {
- while (*sz)
- term_add_char(*(sz++));
-}
-
-#define MIN_TAB 3
-#define TAB_STEP 4
-
-void term_add_sz(const char *sz) {
- //TODO: special hyphen handling
- const char *word = sz;
- while (1)
- if (!*sz || (*sz == ' ') || (*sz == '\n') || (*sz == '\t')) {
- const uint32_t len = sz - word;
- if ((active_term->cursor_x + len > active_term->cols) && (len <= active_term->cols) && active_term->cols)
- term_newline();
- for (const char *i = word; i < sz; ++i)
- term_add_char(*i);
- while ((*sz == ' ') || (*sz == '\n') || (*sz == '\t')) {
- if (*sz == '\n')
- term_newline();
- else if (*sz == '\t') {
- for (uint8_t i = 0; i < MIN_TAB; ++i)
- cursor_right();
- while (active_term->cursor_x % TAB_STEP)
- cursor_right();
- }
- ++sz;
- }
- if (!*sz)
- return;
- if (active_term->cursor_x)
- term_add_char(' ');
- word = sz;
- }
- else
- ++sz;
-}
-
-void term_addf_no_ww_v(const char *fmt, va_list args) {
- char *const msg = format_v(fmt, args);
- term_add_sz_no_ww(msg);
- free_block(msg);
-}
-
-void term_addf_no_ww(const char *fmt, ...) {
- va_list args;
- va_start(args, fmt);
- term_addf_no_ww_v(fmt, args);
- va_end(args);
-}
-
-void term_addf_v(const char *fmt, va_list args) {
- char *const msg = format_v(fmt, args);
- term_add_sz(msg);
- free_block(msg);
-}
-
-void term_addf(const char *fmt, ...) {
- va_list args;
- va_start(args, fmt);
- term_addf_v(fmt, args);
- va_end(args);
-} \ No newline at end of file