summaryrefslogtreecommitdiff
path: root/stage3
diff options
context:
space:
mode:
authorLizzy Fleckenstein <eliasfleckenstein@web.de>2022-10-06 16:45:17 +0200
committerLizzy Fleckenstein <eliasfleckenstein@web.de>2022-10-06 16:45:17 +0200
commitf8397815545adb7d0da36614e0065aa68453a2e4 (patch)
treea771f526970c6724b2511577dceece8783450a49 /stage3
downloadcuddles-f8397815545adb7d0da36614e0065aa68453a2e4.tar.xz
Initial commit
Diffstat (limited to 'stage3')
-rw-r--r--stage3/colors.asm16
-rw-r--r--stage3/def.h21
-rw-r--r--stage3/font.asm243
-rw-r--r--stage3/framebuffer.asm176
-rwxr-xr-xstage3/fut/linkgen.lua101
-rw-r--r--stage3/fut/os161
-rw-r--r--stage3/fut/process.c77
-rw-r--r--stage3/fut/sys_kern.c21
-rw-r--r--stage3/fut/sys_kern.h91
-rw-r--r--stage3/fut/sys_user.c36
-rw-r--r--stage3/fut/sys_user.h91
-rw-r--r--stage3/fut/yield.asm49
-rw-r--r--stage3/gfx.c32
-rw-r--r--stage3/gfx.h21
-rw-r--r--stage3/halt.c7
-rw-r--r--stage3/halt.h6
-rw-r--r--stage3/main.c34
-rw-r--r--stage3/memory.asm59
-rw-r--r--stage3/paging.asm336
-rw-r--r--stage3/paging.h20
20 files changed, 1598 insertions, 0 deletions
diff --git a/stage3/colors.asm b/stage3/colors.asm
new file mode 100644
index 0000000..a53efff
--- /dev/null
+++ b/stage3/colors.asm
@@ -0,0 +1,16 @@
+%define COLOR_BLACK 0
+%define COLOR_BLUE 1
+%define COLOR_GREEN 2
+%define COLOR_CYAN 3
+%define COLOR_RED 4
+%define COLOR_MAGENTA 5
+%define COLOR_BROWN 6
+%define COLOR_LIGHT_GREY 7
+%define COLOR_DARK_GREY 8
+%define COLOR_LIGHT_BLUE 9
+%define COLOR_LIGHT_GREEN 10
+%define COLOR_LIGHT_CYAN 11
+%define COLOR_LIGHT_RED 12
+%define COLOR_LIGHT_MAGENTA 13
+%define COLOR_LIGHT_BROWN 14
+%define COLOR_WHITE 15
diff --git a/stage3/def.h b/stage3/def.h
new file mode 100644
index 0000000..c2f8311
--- /dev/null
+++ b/stage3/def.h
@@ -0,0 +1,21 @@
+#ifndef _DEF_H_
+#define _DEF_H_
+
+#define nil ((void *) 0x0)
+
+typedef unsigned char u8;
+typedef signed char i8;
+
+typedef unsigned short u16;
+typedef short i16;
+
+typedef unsigned int u32;
+typedef int i32;
+
+typedef unsigned long u64;
+typedef long i64;
+
+typedef u64 usize;
+typedef i64 isize;
+
+#endif
diff --git a/stage3/font.asm b/stage3/font.asm
new file mode 100644
index 0000000..b73edab
--- /dev/null
+++ b/stage3/font.asm
@@ -0,0 +1,243 @@
+global debug
+
+%define GFXINFO 0x1000-10
+%define PITCH GFXINFO+0
+%define WIDTH GFXINFO+2
+%define HEIGHT GFXINFO+4
+%define FRAMEBUFFER GFXINFO+6
+
+section .text
+
+; str in rdi
+debug:
+ mov r9, [line]
+
+ mov rax, rcx
+ mov rbx, 15
+ xor rdx, rdx
+ mul rbx
+
+ cmp rax, [HEIGHT]
+ jmp .char
+
+ xor rax, rax
+ xor r9, r9
+
+.char:
+ xor rax, rax
+
+ mov al, [rdi]
+ cmp al, 0
+ je .return
+
+ cmp al, ' '
+ je .space
+
+ cmp al, 'a'
+ jb .invalid
+
+ cmp al, 'z'
+ ja .invalid
+
+ sub al, 'a'
+ mov bl, 15
+ mul bl
+
+ add rax, letters
+ mov r8, rax
+
+ jmp .render
+
+.space:
+ mov r8, letters.space
+
+.render:
+
+.target:
+ xor rdx, rdx
+ mul [PITCH]
+
+ xor rbx, rbx
+ mov ebx, [FRAMEBUFFER]
+ add rax, rbx
+
+ inc rdi
+ jmp debug
+
+.return:
+ ret
+
+.invalid:
+ mov rdi, .invalid_msg
+ call debug
+ jmp $
+
+.invalid_msg: "invalid character in message", 0
+
+section .data
+
+line: dq 0
+
+letters:
+.a: db
+1, 1, 1,
+1, 0, 1,
+1, 1, 1,
+1, 0, 1,
+1, 0, 1
+.b: db
+1, 1, 0,
+1, 0, 1,
+1, 1, 1,
+1, 0, 1,
+1, 1, 1
+.c: db
+1, 1, 1,
+1, 0, 0,
+1, 0, 0,
+1, 0, 0,
+1, 1, 1
+.d: db
+1, 1, 0,
+1, 0, 1,
+1, 0, 1,
+1, 0, 1,
+1, 1, 1
+e: db
+1, 1, 1,
+1, 0, 0,
+1, 1, 1,
+1, 0, 0,
+1, 1, 1
+f: db
+1, 1, 1,
+1, 0, 0,
+1, 1, 1,
+1, 0, 0,
+1, 0, 0
+g: db
+1, 1, 1,
+1, 0, 0,
+1, 0, 1,
+1, 0, 1,
+1, 1, 1
+h: db
+1, 0, 1,
+1, 0, 1,
+1, 1, 1,
+1, 0, 1,
+1, 0, 1
+i: db
+0, 1, 0,
+0, 1, 0,
+0, 1, 0,
+0, 1, 0,
+0, 1, 0
+j: db
+0, 0, 1,
+0, 0, 1,
+0, 0, 1,
+0, 0, 1,
+1, 1, 1
+k: db
+1, 0, 1,
+1, 1, 0,
+1, 0, 0,
+1, 1, 0,
+1, 0, 1,
+l: db
+1, 0, 0,
+1, 0, 0,
+1, 0, 0,
+1, 0, 0,
+1, 1, 1
+m: db
+1, 0, 1,
+1, 1, 1,
+1, 0, 1,
+1, 0, 1,
+1, 0, 1
+n: db
+1, 0, 1,
+1, 0, 1,
+1, 1, 1,
+1, 1, 1,
+1, 0, 1
+o: db
+1, 1, 1,
+1, 0, 1,
+1, 0, 1,
+1, 0, 1,
+1, 1, 1
+p: db
+1, 1, 1,
+1, 0, 1,
+1, 1, 1,
+1, 0, 0,
+1, 0, 0
+q: db
+1, 1, 1,
+1, 0, 1,
+1, 1, 1,
+1, 1, 1,
+0, 0, 1
+r: db
+1, 1, 1,
+1, 0, 1,
+1, 1, 1,
+1, 1, 0,
+1, 0, 1
+s: db
+1, 1, 1,
+1, 0, 0,
+1, 1, 1,
+0, 0, 1,
+1, 1, 1
+t: db
+1, 1, 1,
+0, 1, 0,
+0, 1, 0,
+0, 1, 0,
+0, 1, 0
+u: db
+1, 0, 1,
+1, 0, 1,
+1, 0, 1,
+1, 0, 1,
+1, 1, 1
+v: db
+1, 0, 1,
+1, 0, 1,
+1, 0, 1,
+1, 0, 1,
+0, 1, 0
+w: db
+1, 0, 1,
+1, 0, 1,
+1, 0, 1,
+1, 1, 1,
+1, 0, 1
+x: db
+1, 0, 1,
+1, 0, 1,
+0, 1, 0,
+1, 0, 1,
+1, 0, 1
+y: db
+1, 0, 1,
+1, 0, 1,
+1, 1, 1,
+0, 1, 0,
+0, 1, 0
+z: db
+1, 1, 1,
+0, 0, 1,
+0, 1, 0
+1, 0, 0
+1, 1, 1
+.space:
+0, 0, 0,
+0, 0, 0,
+0, 0, 0,
+0, 0, 0,
+0, 0, 0
diff --git a/stage3/framebuffer.asm b/stage3/framebuffer.asm
new file mode 100644
index 0000000..e55ad04
--- /dev/null
+++ b/stage3/framebuffer.asm
@@ -0,0 +1,176 @@
+%include "stage3/colors.asm"
+global print_chr, print_str, print_dec, print_hex, clear_screen, newline
+extern memcpy
+
+section .data
+
+pos:
+.row: db 0
+.col: db 0
+
+cursor: dq 0xB8000
+color: db COLOR_WHITE | (COLOR_BLACK << 4)
+
+section .text
+
+set_color:
+ shl sil, 4
+ add dil, sil
+ mov [color], dil
+
+update_cursor:
+ mov rbx, [cursor]
+ sub rbx, 0xB8000
+ shr rbx, 1
+
+ mov dx, 0x3D4
+ mov al, 14
+ out dx, al
+
+ mov dx, 0x3D5
+ mov al, bh
+ out dx, al
+
+ mov dx, 0x3D4
+ mov al, 15
+ out dx, al
+
+ mov dx, 0x3D5
+ mov al, bl
+ out dx, al
+
+ ret
+
+set_chr:
+ mov rax, [cursor]
+ mov byte[rax], dil
+ inc rax
+ mov dil, [color]
+ mov [rax], dil
+ inc rax
+ mov [cursor], rax
+ jmp update_cursor
+
+vertical_tab:
+ mov al, [pos.row]
+ inc al
+ cmp al, 25
+ je .scroll
+ mov [pos.row], al
+ mov rax, [cursor]
+ add rax, 160
+ mov [cursor], rax
+ jmp update_cursor
+.scroll:
+ mov rdi, 0xB8000
+ mov rsi, 0xB80A0
+ mov rdx, 0xF00
+ jmp memcpy
+
+carriage_return:
+ mov rax, [cursor]
+ xor rbx, rbx
+ mov bl, [pos.col]
+ shl bl, 1
+ sub rax, rbx
+ mov [cursor], rax
+ mov byte[pos.col], 0
+ jmp update_cursor
+
+newline:
+ call vertical_tab
+ jmp carriage_return
+
+print_chr:
+ cmp dil, 10
+ je newline
+ cmp dil, 11
+ je vertical_tab
+ cmp dil, 13
+ je carriage_return
+ mov al, [pos.col]
+ inc al
+ cmp al, 80
+ je .newline
+ mov [pos.col], al
+ jmp set_chr
+.newline:
+ push rdi
+ call newline
+ pop rdi
+ jmp set_chr
+
+print_str:
+ mov rax, rdi
+.print:
+ mov dil, [rax]
+ cmp dil, 0
+ je .return
+ push rax
+ call print_chr
+ pop rax
+ inc rax
+ jmp .print
+.return:
+ ret
+
+print_hex:
+ mov rsi, 0x10
+ jmp print_num
+print_dec:
+ mov rsi, 10
+print_num:
+ mov rax, rdi
+ xor rcx, rcx
+.convert:
+ inc rcx
+ xor rdx, rdx
+ div rsi
+ cmp dl, 10
+ jb .digit
+ add dl, 'A'-10
+ jmp .next
+.digit:
+ add dl, '0'
+.next:
+ push rdx
+ cmp rax, 0
+ jne .convert
+.print:
+ cmp rcx, 0
+ je .return
+ dec rcx
+ pop rdi
+ push rcx
+ call print_chr
+ pop rcx
+ jmp .print
+.return:
+ ret
+
+clear_screen:
+ push rbx
+ push r12
+ push r13
+ push r14
+ push r15
+
+ mov qword[cursor], 0xB8000
+.clr:
+ cmp qword[cursor], 0xB8FA0
+ je .return
+ mov dil, ' '
+ call set_chr
+ jmp .clr
+.return:
+ mov qword[cursor], 0xB8000
+ mov byte[pos.row], 0
+ mov byte[pos.col], 0
+ call update_cursor
+
+ pop r15
+ pop r14
+ pop r13
+ pop r12
+ pop rbx
+ ret
diff --git a/stage3/fut/linkgen.lua b/stage3/fut/linkgen.lua
new file mode 100755
index 0000000..f7a6d21
--- /dev/null
+++ b/stage3/fut/linkgen.lua
@@ -0,0 +1,101 @@
+#!/usr/bin/env lua
+--[[
+
+--- trigger warning: brain damage ---
+
+BOGUS DYNAMIC LINKING v69.420 by LIZZY FLECKENSTEIN
+
+How this works:
+⠀⠀⠀⠀⠀⢰⡿⠋⠁⠀⠀⠈⠉⠙⠻⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
+⠀⠀⠀⠀⢀⣿⠇⠀⢀⣴⣶⡾⠿⠿⠿⢿⣿⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
+⠀⠀⣀⣀⣸⡿⠀⠀⢸⣿⣇⠀⠀⠀⠀⠀⠀⠙⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
+⠀⣾⡟⠛⣿⡇⠀⠀⢸⣿⣿⣷⣤⣤⣤⣤⣶⣶⣿⠇⠀⠀⠀⠀⠀⠀⠀⣀⠀⠀
+⢀⣿⠀⢀⣿⡇⠀⠀⠀⠻⢿⣿⣿⣿⣿⣿⠿⣿⡏⠀⠀⠀⠀⢴⣶⣶⣿⣿⣿⣆
+⢸⣿⠀⢸⣿⡇⠀⠀⠀⠀⠀⠈⠉⠁⠀⠀⠀⣿⡇⣀⣠⣴⣾⣮⣝⠿⠿⠿⣻⡟
+⢸⣿⠀⠘⣿⡇⠀⠀⠀⠀⠀⠀⠀⣠⣶⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠁⠉⠀
+⠸⣿⠀⠀⣿⡇⠀⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠟⠉⠀⠀⠀⠀
+⠀⠻⣷⣶⣿⣇⠀⠀⠀⢠⣼⣿⣿⣿⣿⣿⣿⣿⣛⣛⣻⠉⠁⠀⠀⠀⠀⠀⠀⠀
+⠀⠀⠀⠀⢸⣿⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀
+⠀⠀⠀⠀⢸⣿⣀⣀⣀⣼⡿⢿⣿⣿⣿⣿⣿⡿⣿⣿⡿
+
+Amogus sus 😳 ((impassta))
+
+I FUCKING HATE TEH ANTICRIST!!!!
+WE GOT YOU SURROUNDEND, USE DYNAMIC LINKING
+
+:trollface:
+
+]]
+
+-- in
+local hdr_kern = io.open("sys_kern.h", "r")
+-- out
+local hdr_user = io.open("sys_user.h", "w")
+local src_kern = io.open("sys_kern.c", "w")
+local src_user = io.open("sys_user.c", "w")
+
+local count = 0
+local calltable = "0x500"
+
+local body_kern = ""
+local body_user = ""
+
+src_kern:write("#include <sys_kern.h>\n")
+src_user:write("#include <sys_user.h>\n\n")
+
+local function process_line(line)
+ if line == "" or line:sub(1, 1) == "\t" then
+ return
+ end
+
+ local f, t = line:find("[%w_]+%(")
+
+ if not f then
+ return
+ end
+
+ local start, mid, fin = line:sub(1, f-1), line:sub(f, t-1), line:sub(t)
+
+ if mid == "__attribute__" or mid == "link" then
+ return
+ end
+
+ local decl = start .. "(*" .. mid .. ")" .. fin .. "\n"
+
+ hdr_user:write("extern " .. decl)
+ src_user:write(decl)
+
+ body_kern = body_kern .. "\tcalltable[" .. count .. "] = &" .. mid .. ";\n"
+ body_user = body_user .. "\t" .. mid .. " = calltable[" .. count .. "];\n"
+
+ count = count + 1
+
+ return true
+end
+
+while true do
+ local line = hdr_kern:read()
+
+ if not line then
+ break
+ end
+
+ if not process_line(line) then
+ hdr_user:write(line .. "\n")
+ end
+end
+
+local function write_link(f, content)
+ f:write("\nvoid link()\n{\n")
+ f:write("\tvoid **calltable = " .. calltable .. ";\n\n")
+ f:write(content)
+ f:write("}\n")
+end
+
+write_link(src_kern, body_kern)
+write_link(src_user, body_user)
+
+hdr_kern:close()
+hdr_user:close()
+src_kern:close()
+src_user:close()
diff --git a/stage3/fut/os b/stage3/fut/os
new file mode 100644
index 0000000..64d627f
--- /dev/null
+++ b/stage3/fut/os
@@ -0,0 +1,161 @@
+gfx
+ - modes text, pixel
+ - different buffers
+ - switch between them manually or thingily
+
+- similar to tmux
+- hierarchy
+
+- text input channel
+- keyboard input channel
+- mouse input channel
+
+- text output channel
+ -
+- graphics output channel
+
+- add text?
+- scrollback?
+
+init
+
+copy
+remove
+move
+list
+edit
+directory
+
+shell
+terminal
+
+mouse
+keyboard
+text
+
+tiler
+desktop
+
+--
+
+process, display, channel
+
+--
+
+display.x
+display.y
+display.width
+display.height
+display.index
+display.parent
+
+display = current_display()
+display = create_display(x, y, width, height)
+
+add_display(parent, child, -1)
+remove_display(parent, child)
+
+display.set_char(pos, color, text)
+display.set_pixel(pos, color)
+display.flush()
+
+channel = create_channel()
+add_channel(display, channel, name)
+channel = get_channel(display, name)
+
+--
+
+process = create_process(path, display)
+
+add_channel(process, channel)
+get_channel(process, "signal")
+get_channel(process, "status")
+
+--
+
+current_process()
+ .get_channel("status")
+ .send(finish)
+
+--
+void main()
+{
+ current_display()
+ .get_channel("text")
+ .send("hello, world\n");
+}
+
+--
+
+append(string self, string other)
+{
+ self.grow(other.len())
+ memcpy(self.ptr + self.len() - other.len(), other.ptr, other.len())
+}
+
+--
+string get_line(channel input)
+{
+ string s = "";
+
+ loop {
+ string c = input.recv();
+
+ if (c[0] == '\n')
+ break;
+
+ s.append(c);
+ }
+
+ return s;
+}
+
+--
+void main()
+{
+ channel input = current_display()
+ .get_channel("keyboard");
+
+ loop {
+ string command = get_line(input);
+
+ process proc = create_process(path, current_display());
+
+ receiver status = proc
+ .get_channel("status")
+ .subscribe();
+
+ proc.start();
+
+ while (!status.recv().equal("finish"))
+ yield();
+ }
+}
+
+--
+void main()
+{
+
+}
+
+-- channels
+void send(channel c, value v)
+{
+ listener l = c.listeners.pop();
+
+ if (l) {
+ listener.resume(v)
+ } else {
+ for (s in c.subscribers) {
+ if (s.active)
+ s.active.resume(v)
+ else
+ s.buffer.append(v)
+ }
+ }
+}
+
+-- queue
+
+- runqueue pointer at fixed address
+- processes must free all heap allocated memory before exit
diff --git a/stage3/fut/process.c b/stage3/fut/process.c
new file mode 100644
index 0000000..ea99ccf
--- /dev/null
+++ b/stage3/fut/process.c
@@ -0,0 +1,77 @@
+#define STACK_SIZE 65536
+#define CURRENT *((process *) 0x500)
+
+process process_current()
+{
+ return CURRENT;
+}
+
+static void process_delete(process p)
+{
+ free(p->stack);
+ free(p->code);
+ map_clear(&p->channels);
+}
+
+static void process_push(process p, u64 value)
+{
+ p->stack_ptr -= sizeof value;
+ *p->stack_ptr = value;
+}
+
+void process_exit()
+{
+ if (CURRENT->next == CURRENT)
+ panic("init exited");
+
+ CURRENT->prev->next = CURRENT->next;
+ CURRENT->next->prev = CURRENT->prev;
+ rc_drop(*current);
+
+ process_yield();
+}
+
+process process_create(char *path, display d)
+{
+ process p = rc_create(sizeof *p, &process_delete);
+
+ p->state = PROCESS_CREATED;
+
+ p->stack = malloc(STACK_SIZE);
+ p->stack_ptr = p->stack + STACK_SIZE;
+ p->code = p->code_ptr = file_read(path);
+
+ process_push(p, (u64) &process_exit);
+ // push 6 callee resaved registers - contents dont actually matter.
+ for (int i = 0; i < 6; i++)
+ process_push(p, 0);
+
+ p->displ = d;
+ p->next = p->prev = nil;
+ map_init(&p->channels);
+
+ channel sig = channel_create();
+ process_channel_add(p, "signal", sig);
+ rc_drop(sig);
+
+ channel stat = channel_create();
+ process_channel_add(p, "status", stat);
+ rc_drop(stat);
+
+ return p;
+}
+
+void process_start(process p)
+{
+ if (p->code_ptr == nil)
+ panic("attempt to start invalid process");
+
+ if (p->state != PROCESS_CREATED)
+ panic("attempt to start running or dead process");
+
+ rc_grab(p);
+
+ p->next = CURRENT->next;
+ CURRENT->next = p;
+ p->prev = CURRENT;
+}
diff --git a/stage3/fut/sys_kern.c b/stage3/fut/sys_kern.c
new file mode 100644
index 0000000..c7c5fcc
--- /dev/null
+++ b/stage3/fut/sys_kern.c
@@ -0,0 +1,21 @@
+#include <sys_kern.h>
+
+void link()
+{
+ void **calltable = 0x500;
+
+ calltable[0] = &display_current;
+ calltable[1] = &display_create;
+ calltable[2] = &display_add;
+ calltable[3] = &display_remove;
+ calltable[4] = &display_pixel;
+ calltable[5] = &display_channel_add;
+ calltable[6] = &display_channel_get;
+ calltable[7] = &rc_grab;
+ calltable[8] = &rc_drop;
+ calltable[9] = &rc_create;
+ calltable[10] = &weak_downgrade;
+ calltable[11] = &weak_upgrade;
+ calltable[12] = &weak_drop;
+ calltable[13] = &channel_create;
+}
diff --git a/stage3/fut/sys_kern.h b/stage3/fut/sys_kern.h
new file mode 100644
index 0000000..083fce3
--- /dev/null
+++ b/stage3/fut/sys_kern.h
@@ -0,0 +1,91 @@
+#ifndef _SYS_H_
+#define _SYS_H_
+
+// misc
+
+typedef struct {
+ i32 x, y;
+} pos;
+
+typedef struct {
+ u32 width, height;
+} bounds;
+
+typedef struct {
+ u8 r, g, b
+} color;
+
+// display
+
+typedef struct display {
+ pos p;
+ bounds b;
+ struct display *parent;
+ u64 index;
+} *display;
+
+display display_current();
+display display_create();
+void display_add(display parent, display child, i32 index);
+void display_remove(display child);
+
+void display_pixel(display d, pos p, color c);
+
+void display_channel_add(char *name, channel ch);
+channel display_channel_get(char *name);
+
+// rc
+
+typedef struct __attribute__((packed)) {
+ u32 ref;
+ u32 own;
+ void *data;
+ void (*delete)(void *data);
+} rc_header;
+
+void rc_grab(void *rc);
+void rc_drop(void *rc);
+
+void *rc_create(u64 siz, void *delete);
+void *weak_downgrade(void *rc);
+void *weak_upgrade(void *weak)
+void weak_drop(void *weak);
+
+// channel
+
+typedef struct {
+ array listeners;
+ array subscribers;
+} *channel;
+
+channel channel_create();
+
+// buffered
+
+typedef struct {
+ void *active;
+ array buffer;
+} buffered;
+
+// process
+
+typedef struct process __attribute__((packed)) {
+ void *code;
+ void *stack;
+ u64 *stack_ptr;
+ struct process *next;
+ struct process *prev;
+ map channels;
+ display displ;
+ enum {
+ PROCESS_CREATED,
+ PROCESS_RUNNING,
+ PROCESS_DEAD,
+ } state;
+} *process;
+
+// setup pointers
+
+void link();
+
+#endif
diff --git a/stage3/fut/sys_user.c b/stage3/fut/sys_user.c
new file mode 100644
index 0000000..4490513
--- /dev/null
+++ b/stage3/fut/sys_user.c
@@ -0,0 +1,36 @@
+#include <sys_user.h>
+
+display (*display_current)();
+display (*display_create)();
+void (*display_add)(display parent, display child, i32 index);
+void (*display_remove)(display child);
+void (*display_pixel)(display d, pos p, color c);
+void (*display_channel_add)(char *name, channel ch);
+channel (*display_channel_get)(char *name);
+void (*rc_grab)(void *rc);
+void (*rc_drop)(void *rc);
+void *(*rc_create)(u64 siz, void *delete);
+void *(*weak_downgrade)(void *rc);
+void *(*weak_upgrade)(void *weak)
+void (*weak_drop)(void *weak);
+channel (*channel_create)();
+
+void link()
+{
+ void **calltable = 0x500;
+
+ display_current = calltable[0];
+ display_create = calltable[1];
+ display_add = calltable[2];
+ display_remove = calltable[3];
+ display_pixel = calltable[4];
+ display_channel_add = calltable[5];
+ display_channel_get = calltable[6];
+ rc_grab = calltable[7];
+ rc_drop = calltable[8];
+ rc_create = calltable[9];
+ weak_downgrade = calltable[10];
+ weak_upgrade = calltable[11];
+ weak_drop = calltable[12];
+ channel_create = calltable[13];
+}
diff --git a/stage3/fut/sys_user.h b/stage3/fut/sys_user.h
new file mode 100644
index 0000000..3be3d58
--- /dev/null
+++ b/stage3/fut/sys_user.h
@@ -0,0 +1,91 @@
+#ifndef _SYS_H_
+#define _SYS_H_
+
+// misc
+
+typedef struct {
+ i32 x, y;
+} pos;
+
+typedef struct {
+ u32 width, height;
+} bounds;
+
+typedef struct {
+ u8 r, g, b
+} color;
+
+// display
+
+typedef struct display {
+ pos p;
+ bounds b;
+ struct display *parent;
+ u64 index;
+} *display;
+
+extern display (*display_current)();
+extern display (*display_create)();
+extern void (*display_add)(display parent, display child, i32 index);
+extern void (*display_remove)(display child);
+
+extern void (*display_pixel)(display d, pos p, color c);
+
+extern void (*display_channel_add)(char *name, channel ch);
+extern channel (*display_channel_get)(char *name);
+
+// rc
+
+typedef struct __attribute__((packed)) {
+ u32 ref;
+ u32 own;
+ void *data;
+ void (*delete)(void *data);
+} rc_header;
+
+extern void (*rc_grab)(void *rc);
+extern void (*rc_drop)(void *rc);
+
+extern void *(*rc_create)(u64 siz, void *delete);
+extern void *(*weak_downgrade)(void *rc);
+extern void *(*weak_upgrade)(void *weak)
+extern void (*weak_drop)(void *weak);
+
+// channel
+
+typedef struct {
+ array listeners;
+ array subscribers;
+} *channel;
+
+extern channel (*channel_create)();
+
+// buffered
+
+typedef struct {
+ void *active;
+ array buffer;
+} buffered;
+
+// process
+
+typedef struct process __attribute__((packed)) {
+ void *code;
+ void *stack;
+ u64 *stack_ptr;
+ struct process *next;
+ struct process *prev;
+ map channels;
+ display displ;
+ enum {
+ PROCESS_CREATED,
+ PROCESS_RUNNING,
+ PROCESS_DEAD,
+ } state;
+} *process;
+
+// setup pointers
+
+void link();
+
+#endif
diff --git a/stage3/fut/yield.asm b/stage3/fut/yield.asm
new file mode 100644
index 0000000..0c4a134
--- /dev/null
+++ b/stage3/fut/yield.asm
@@ -0,0 +1,49 @@
+global process_yield
+extern rc_drop
+
+%define CURRENT [0x500]
+
+section .text
+process_yield:
+ ; save callee reserved regs to old stack
+ push rbx
+ push rbp
+ push r12
+ push r13
+ push r14
+ push r15
+
+ ; get CURRENT
+ mov rdi, CURRENT
+
+ ; set CURRENT->stack_ptr
+ mov rax, rdi
+ add rax, 16
+ mov [rax], rsp
+
+ ; switch to new process
+ add rax, 8
+ mov rbx, [rax]
+ mov CURRENT, rbx
+
+ ; activate new stack
+ add rbx, 16
+ mov rsp, [rbx]
+
+ ; drop old process (=rdi)
+ call rc_drop
+
+ ; grab new process
+ mov rdi, CURRENT
+ call rc_grab
+
+ ; restore callee reserved registers
+ pop r15
+ pop r14
+ pop r13
+ pop r12
+ pop rbp
+ pop rbx
+
+ ; jump into new process, with style
+ ret
diff --git a/stage3/gfx.c b/stage3/gfx.c
new file mode 100644
index 0000000..0ecf423
--- /dev/null
+++ b/stage3/gfx.c
@@ -0,0 +1,32 @@
+#include "gfx.h"
+
+struct GfxInfo *gfxinfo = (void *) (0x1000-10);
+
+// byteswap
+u32 make_color(color col)
+{
+ return ((u32) 0)
+ & ((u32) col.r << 0)
+ & ((u32) col.g << 8)
+ & ((u32) col.b << 16)
+ & ((u32) col.a << 24);
+}
+
+void set_pixel(u16 x, u16 y, u32 col)
+{
+ *((u32 *) (u64) (gfxinfo->framebuffer + y * gfxinfo->pitch + x * sizeof col)) = col;
+}
+
+void set_region(u16 x, u16 y, u16 w, u16 h, u32 col)
+{
+ void *cbeg = (void *) (u64) (gfxinfo->framebuffer + y * gfxinfo->pitch + x * sizeof col);
+ void *cend = cbeg + h * gfxinfo->pitch;
+
+ for (; cbeg < cend; cbeg += gfxinfo->pitch) {
+ void *rbeg = cbeg;
+ void *rend = rbeg + w * sizeof col;
+
+ for (; rbeg < rend; rbeg += sizeof col)
+ *((u32 *) rbeg) = col;
+ }
+}
diff --git a/stage3/gfx.h b/stage3/gfx.h
new file mode 100644
index 0000000..e4e5d8b
--- /dev/null
+++ b/stage3/gfx.h
@@ -0,0 +1,21 @@
+#ifndef _GFX_H_
+#define _GFX_H_
+
+#include "def.h"
+
+extern struct __attribute__((packed)) GfxInfo {
+ u16 pitch;
+ u16 width;
+ u16 height;
+ u32 framebuffer;
+} *gfxinfo;
+
+typedef struct {
+ u8 r, g, b, a;
+} color;
+
+u32 make_color(color col);
+void set_pixel(u16 x, u16 y, u32 col);
+void set_region(u16 x, u16 y, u16 w, u16 h, u32 col);
+
+#endif
diff --git a/stage3/halt.c b/stage3/halt.c
new file mode 100644
index 0000000..63ad8e2
--- /dev/null
+++ b/stage3/halt.c
@@ -0,0 +1,7 @@
+#include "halt.h"
+
+void halt()
+{
+ for (;;)
+ ;
+}
diff --git a/stage3/halt.h b/stage3/halt.h
new file mode 100644
index 0000000..9521dd9
--- /dev/null
+++ b/stage3/halt.h
@@ -0,0 +1,6 @@
+#ifndef _HALT_H_
+#define _HALT_H_
+
+void halt();
+
+#endif
diff --git a/stage3/main.c b/stage3/main.c
new file mode 100644
index 0000000..7c84d05
--- /dev/null
+++ b/stage3/main.c
@@ -0,0 +1,34 @@
+#include "paging.h"
+#include "def.h"
+#include "gfx.h"
+#include "halt.h"
+
+void clear_screen(); // framebuffer.asm
+
+void kmain()
+{
+ clear_screen();
+
+ for (MemRegion *mmap = (void *) 0x500; mmap->start != nil; mmap++)
+ page_region(mmap);
+
+ page_region(&(MemRegion) {
+ .start = (void *) (u64) gfxinfo->framebuffer,
+ .size = gfxinfo->pitch * gfxinfo->height,
+ .type = MEM_RESERVED,
+ .zero = 0,
+ });
+
+ /*
+ for (u16 x = 0; x < gfxinfo->width; x++)
+ for (u16 y = 0; y < gfxinfo->height; y++)
+ set_pixel(x, y, 0x0087CEEB);
+ */
+
+ set_region(0, 0, gfxinfo->width, gfxinfo->height, 0x0087CEEB);
+
+ halt();
+}
+
+// 0xE0000000
+// 0xE03E8000
diff --git a/stage3/memory.asm b/stage3/memory.asm
new file mode 100644
index 0000000..b4410a3
--- /dev/null
+++ b/stage3/memory.asm
@@ -0,0 +1,59 @@
+global memcpy, memmove
+
+section .text
+
+memcpy:
+.bulk_copy:
+ cmp rdx, 8
+ jl .bytewise_copy
+ mov rax, qword[rsi]
+ mov qword[rdi], rax
+ sub rdx, 8
+ add rdi, 8
+ add rsi, 8
+.bytewise_copy:
+ cmp rdx, 0
+ je .return
+ mov al, byte[rsi]
+ mov byte[rdi], al
+ dec rdx
+ inc rdi
+ inc rsi
+ jmp .bytewise_copy
+.return:
+ ret
+
+memmove:
+ mov rcx, rdx
+.bulk_read:
+ cmp rdx, 8
+ jl .bytewise_read
+ push qword[rsi]
+ add rsi, 8
+ sub rdx, 8
+ jmp .bulk_read
+.bytewise_read:
+ cmp rdx, 0
+ je .bulk_write
+ dec rsp
+ mov al, byte[rsi]
+ mov byte[rsp], al
+ inc rsi
+ dec rdx
+ jmp .bytewise_read
+.bulk_write:
+ cmp rcx, 8
+ jl .bytewise_write
+ pop qword[rdi]
+ add rdi, 8
+ sub rcx, 8
+.bytewise_write:
+ cmp rcx, 0
+ je .return
+ mov al, byte[rsp]
+ mov byte[rdi], al
+ inc rsp
+ inc rdi
+ dec rcx
+.return:
+ ret
diff --git a/stage3/paging.asm b/stage3/paging.asm
new file mode 100644
index 0000000..8b1d571
--- /dev/null
+++ b/stage3/paging.asm
@@ -0,0 +1,336 @@
+global page_region
+extern print_hex, print_chr, newline, print_dec, print_str
+
+section .text
+
+pagebuf_init:
+ .start: dq 0x5000
+ .size: dq 0x2000
+ .used: dq 0
+
+pagebuf: dq pagebuf_init
+
+next_page: dq 0
+
+; allocate new page table buffer
+alloc:
+ ; rsi = buffer (result)
+ ; rdi = next_page
+ ; r8 = pagebuf
+ ; rbx = upper
+ ; rax = tmp; used_next
+
+ mov r8, [pagebuf] ; *pagebuf
+ mov rsi, [r8] ; start = pagebuf->start
+
+ mov rbx, [r8+8] ; size = pagebuf->size
+ add rbx, rsi ; upper_have = start + size
+
+ ; round *up* to 0x1000 align
+ mov rax, 0xfff
+ add rsi, rax
+ not rax
+ and rsi, rax ; aligned_start = (start + 0xfff) & (~0xfff)
+
+ mov rax, [r8+16] ; used = pagebuf->used
+ add rax, 0x1000
+ add rsi, rax ; upper_need = aligned_start + used + 0x1000
+
+ cmp rsi, rbx ; if upper_need > upper_have
+ ja .newbuf ; current region is full, get new
+
+ cmp rsi, r10 ; if upper_need >= next_page
+ jae .oom ; out of memory (target buffer isn't paged yet)
+
+ mov [r8+16], rax ; pagebuf->used = used + 0x1000
+
+ ; clear out buffer
+
+ mov rbx, rsi
+ sub rsi, 0x1000
+
+.clear:
+ sub rbx, 8
+ mov qword[rbx], 0
+ cmp rbx, rsi
+ jne .clear
+
+ ret
+
+; select next page buffer
+.newbuf:
+ cmp r8, pagebuf_init
+ jne .nextbuf
+
+ mov r8, 0x500
+ jmp .trybuf
+
+.nextbuf:
+ add r8, 24
+
+.trybuf:
+ cmp qword[r8], 0
+ je .oom ; last region reached
+
+ mov rax, [r8+16]
+
+ cmp rax, -1
+ je .nextbuf ; region is reserved
+
+ cmp rax, 0
+ jne .oom ; region has not been paged yet
+
+ mov [pagebuf], r8
+ jmp alloc
+
+.oom:
+ push rdi
+
+ mov rdi, .oom_msg
+ call print_str
+
+ pop rdi
+
+ call print_hex
+ call newline
+
+ jmp $
+
+.oom_msg: db "out of memory for page table", 10, "next_page = ", 0
+
+; get/create page tables
+get_tables:
+; level 4
+
+ ; rdi = address (arg, persist)
+ ; rax = tmp
+ ; rbx = mask
+ ; rcx = bits (persist)
+ ; rdx = level (persist)
+ ; r8 = table address
+ ; rsi = next offset (persist)
+
+ mov cl, 12+9*4
+ mov dl, 4
+
+ mov rsi, 0x1000
+
+; level 4
+.level:
+ dec dl
+ mov r8, rdi
+ mov rbx, -1 ; reset remainder mask
+ shl rbx, cl ; update remainder mask
+ not rbx ; negate remainder mask
+ and r8, rbx ; apply remainder mask
+
+ mov al, 9
+ mul dl
+ add al, 12
+ mov cl, al
+
+ shr r8, cl ; divide
+ shl r8, 3 ; multiply by 8
+
+ mov rbx, 0xfff ; 0x1000 alignment
+ not rbx ; offset mask
+
+ and rsi, rbx ; apply offset mask
+ add r8, rsi ; add offset
+ push r8 ; store
+
+ cmp dl, 0
+ je .done
+
+ mov rsi, [r8] ; next offset
+ cmp rsi, 0
+ jne .level
+
+ call alloc
+ or rsi, 3
+ mov r8, [rsp]
+ mov [r8], rsi
+
+ jmp .level
+
+.done:
+ pop r11
+ pop r12
+ pop r13
+ pop r14
+
+ ret
+
+space:
+ mov dil, ' '
+ jmp print_chr
+
+page_region:
+ push rbx
+ push r12
+ push r13
+ push r14
+ push r15
+
+ mov r9, rdi
+
+ mov rdi, [r9] ; ptr = mmap_entry->ptr
+ mov r10, [next_page]
+
+ push rdi
+
+ mov rax, 1 << 63
+
+ or rdi, rax
+ call print_hex
+ call space
+
+ mov rdi, [r9+8]
+ add rdi, [rsp]
+ or rdi, rax
+
+ call print_hex
+ call newline
+
+ pop rdi
+
+ ; for usable region (type = 1), set mmap_entry->used = 0
+ ; for reserved region (type = 2), set mmap_entry->used = -1
+ xor rax, rax
+ xor rbx, rbx
+ mov eax, dword[r9+16]
+ cmp rax, 1
+ je .set_used
+ dec rbx
+.set_used:
+ mov [r9+16], rbx
+
+ mov r10, rdi
+ mov r15, rdi ; r15 = end of region
+ add r15, [r9+8]
+
+ mov rax, 0xfff
+ not rax
+ and rdi, rax ; round down to 0x1000 aligned
+
+ cmp rdi, r10
+ jb .get_tables
+
+ mov r10, rdi
+
+.get_tables:
+ call get_tables ; page tables into r11-r14
+
+ ; start filling L1 map
+.l1:
+ mov rax, rdi
+ or rax, 3
+ mov [r11], rax
+
+ add rdi, 0x1000
+
+ cmp rdi, r10
+ jb .next
+
+ mov r10, rdi
+
+.next:
+ cmp rdi, r15 ; if next >= end
+ jae .done
+
+ ; prepare rcx mask for later
+ mov rcx, -1
+ shl rcx, 3
+
+ ; bump L1
+
+ add r11, 8
+ mov rax, r11
+ and rax, 0xfff
+ jnz .l1
+
+ ; bump L2
+
+ add r12, 8
+ mov rax, r12
+ and rax, 0xfff
+ jnz .l2
+
+ ; bump L3
+
+ add r13, 8
+ mov rax, r13
+ and rax, 0xfff
+ jnz .l3
+
+ ; bump L4
+
+ add r14, 8
+ mov rax, r14
+ and rax, 0xfff
+ jnz .l4
+
+ ; machine has more than 256TB of RAM, tell user to fuck off
+ jmp .bruh
+
+.l4:
+ mov r13, [r14]
+ and r13, rcx
+ jnz .l3
+
+ call alloc
+ mov r13, rsi
+ or rsi, 3
+ mov [r14], rsi
+
+.l3:
+ mov r12, [r13]
+ and r12, rcx
+ jnz .l2
+
+ call alloc
+ mov r12, rsi
+ or rsi, 3
+ mov [r13], rsi
+
+.l2:
+ mov r11, [r12]
+ and r11, rcx
+ jnz .l2
+
+ call alloc
+ mov r11, rsi
+ or rsi, 3
+ mov [r12], rsi
+
+ jmp .l1
+
+.done:
+ mov [next_page], r10
+
+ pop r15
+ pop r14
+ pop r13
+ pop r12
+ pop rbx
+
+ ret
+
+.bruh:
+ mov rdi, .bruh_msg
+ call print_str
+ jmp $
+
+.bruh_msg: db "bruh why do you have more than 256TB of RAM (you fucking glow)", 10, 0
+
+; identity map available memory
+old_page_map:
+ mov r9, 0x0500 ; mmap_entry
+.entry:
+ cmp qword[r9], 0
+ je .done
+ call page_region
+ add r9, 24
+ jmp .entry
+.done:
+ ret
diff --git a/stage3/paging.h b/stage3/paging.h
new file mode 100644
index 0000000..b9a3930
--- /dev/null
+++ b/stage3/paging.h
@@ -0,0 +1,20 @@
+#ifndef _PAGING_H_
+#define _PAGING_H_
+
+#include "def.h"
+
+typedef enum {
+ MEM_USABLE = 1,
+ MEM_RESERVED = 2,
+} MemRegionType;
+
+typedef struct __attribute__((packed)) {
+ void *start;
+ usize size;
+ u16 type;
+ u16 zero;
+} MemRegion;
+
+void page_region(MemRegion *region);
+
+#endif