diff --git a/.gitignore b/.gitignore index d1cddb82..25ceb41d 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ compile_commands.json *.red trace screenlog.0 +feature_flags.mk \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index a26b51c7..479e1082 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "shared"] path = shared url = https://github.com/differrari/redlib.git -[submodule "libs/regex"] - path = libs/regex - url = git@github.com:differrari/regex.git +[submodule "libs/uno"] + path = libs/uno + url = git@github.com:differrari/uno.git diff --git a/Makefile b/Makefile index 993aa303..dc65ad4b 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,5 @@ include common.mk +include feature_flags.mk OS := $(shell uname) FS_DIRS := fs/redos/system @@ -11,7 +12,7 @@ endif .PHONY: all shared user kernel clean raspi virt run debug dump prepare-fs help install -all: kshared modules kernel shared user tools libs docs +all: kshared modules kernel shared user tools libs services docs @echo "Build complete." ./createfs @@ -24,7 +25,7 @@ modules: kshared shared: $(MAKE) -C shared BUILD_DIR=./build -user: shared prepare-fs +user: shared libs prepare-fs $(MAKE) -C user kernel: kshared modules @@ -33,6 +34,9 @@ kernel: kshared modules tools: shared libs prepare-fs $(MAKE) -C tools +services: shared libs prepare-fs + $(MAKE) -C services + libs: shared $(MAKE) -C libs @@ -50,6 +54,7 @@ clean: $(MAKE) -C tools $@ $(MAKE) -C modules $@ $(MAKE) -C libs $@ + $(MAKE) -C services $@ @echo "removing images" $(RM) kernel.img kernel.elf dump @@ -72,6 +77,7 @@ dump: $(ARCH)objdump -S -D kernel.elf > dump $(MAKE) -C user $@ $(MAKE) -C tools $@ + $(MAKE) -C services $@ install: $(MAKE) clean diff --git a/common.mk b/common.mk index 4e6aaace..e0ec194b 100644 --- a/common.mk +++ b/common.mk @@ -21,7 +21,7 @@ ifeq ($(ARCH), aarch64-none-elf-) COMMON_FLAGS += -mcpu=cortex-a72 -Wno-error=sized-deallocation endif -CFLAGS_BASE ?= $(COMMON_FLAGS) -std=c99 +CFLAGS_BASE += $(COMMON_FLAGS) -std=c99 CXXFLAGS_BASE ?= $(COMMON_FLAGS) -fno-rtti LDFLAGS_BASE ?= diff --git a/feature_flags.mk b/feature_flags.mk new file mode 100644 index 00000000..6bcb6718 --- /dev/null +++ b/feature_flags.mk @@ -0,0 +1,10 @@ +# Add extra compilation flags meant to enable or disable features at compile time. +# For runtime create a system.config inside ./fs/redos/system.config + +# CFLAGS_BASE += -DBUG_CRASH_FSUS # disable or enable a sometimes crashing launcher functionality using the package manager +# CFLAGS_BASE += -DBUG_RESET_TTBR0 # disable or enable a crashing cleanup function in virtual memory +CFLAGS_BASE += -DFEATURE_MENU # disable or enable the menubar +# CFLAGS_BASE += -DMODULE_STRICT # disable or enable strict checking for modules. May panic unnecessarily +CFLAGS_BASE += -DFEATURE_DEBUGGING # enable window button to attach debugger to currently running program +CFLAGS_BASE += -DFEATURE_NEW_PROCFS # enable cleaner /proc filesystem +# CFLAGS_BASE += -DFEATURE_JS_PROTECTION \ No newline at end of file diff --git a/kernel/Makefile b/kernel/Makefile index 05e90995..f7263b36 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -2,6 +2,7 @@ # toolchain (inherited from top-level) include ../common.mk +include ../feature_flags.mk CPPFLAGS := -I. -I../shared -I../user -DXHCI_CTX_SIZE=$(XHCI_CTX_SIZE) diff --git a/kernel/access/authorize.c b/kernel/access/authorize.c new file mode 100644 index 00000000..71971b15 --- /dev/null +++ b/kernel/access/authorize.c @@ -0,0 +1,112 @@ +#include "authorize.h" +#include "process/process.h" +#include "alloc/alloc.h" + +#define auth_fail { print("[AUTH error] Token %i is not in the %i'd files for resource %i. This incident will be reported.",owner,type,resource_id.id); return false; } + +#define AUTH_DEBUG +#ifdef AUTH_DEBUG +#define auth_print(...) print(__VA_ARGS__) +#else +#define auth_print(...) +#endif + +hash_map_t *auth_entries; +hash_map_t *auth_entitlements; + +static u32 auth_id_counter = 1; + +auth_token auth_new_token(){ + return auth_id_counter++; +} + +auth_token auth_get_proc_token(process_t *t){ + if (!t) return (auth_token){}; + if (!t->permissions.auth_id){ + t->permissions.auth_id = auth_new_token(); + auth_print("[AUTH] token %i assigned to process %i",t->permissions.auth_id,t->id); + } + return t->permissions.auth_id; +} + +bool auth_valid_proc(auth_token owner, auth_process_actions type, resource resource_id){ + hash_map_t *entitlement_entries = hash_map_get(auth_entitlements, &owner, sizeof(auth_token)); + if (entitlement_entries){ + const resource_types t = resource_process; + auth_entitlement_t *entry = hash_map_get(entitlement_entries, &t, sizeof(resource_types)); + if (entry){ + if ((entry->action_type & type) == type) return true; + } + } + + hash_map_t *resource_entries = hash_map_get(auth_entries, &resource_id, sizeof(resource)); + if (!resource_entries) auth_fail; + auth_entry *entry = hash_map_get(resource_entries, &owner, sizeof(auth_token)); + if (!entry) auth_fail; + return (entry->actions & type) == type; +} + +bool auth_valid(auth_token owner, u32 type, resource resource_id){ + if (resource_id.type == resource_process) + return auth_valid_proc(owner, type, resource_id); + auth_print("[AUTH error] Only process resource ids are allowed"); + return true; +} + +bool request_auth_proc(auth_token owner, auth_process_actions type, resource resource_id){ + auth_print("[AUTH debug] Token %i requesting resource %i for action %i",owner,resource_id.id, type); + if (type >= auth_process_count) return false; + hash_map_t *resource_entries = hash_map_get(auth_entries, &resource_id, sizeof(resource)); + if (!resource_entries) { + resource_entries = hash_map_create_alloc(64, alloc, release); + hash_map_put(auth_entries, &resource_id, sizeof(resource), resource_entries); + } + if (!resource_entries) return false; + auth_entry *entry = hash_map_get(resource_entries, &owner, sizeof(auth_token)); + if (!entry){ + entry = new(auth_entry); + hash_map_put(resource_entries, &owner, sizeof(auth_token), entry); + } + if (!entry) return false; + entry->auth_token = owner; + entry->actions |= type; + auth_print("[AUTH debug] Token %i authorized for item %i on resource %i",owner, type, resource_id.id); + return true; +} + +bool auth_request(auth_token owner, u32 type, resource resource_id){ + if (!auth_entries) auth_entries = hash_map_create_alloc(64,alloc,release); + if (resource_id.type == resource_process) + return request_auth_proc(owner, type, resource_id); + return false; +} + + +bool auth_entitlement_proc(auth_token owner, auth_process_actions type){ + auth_print("[AUTH debug] Token %i entitled to process action %i",owner,type); + if (type >= auth_process_count) return false; + hash_map_t *resource_entries = hash_map_get(auth_entitlements, &owner, sizeof(auth_token)); + if (!resource_entries) { + resource_entries = hash_map_create_alloc(64, alloc, release); + hash_map_put(auth_entitlements, &owner, sizeof(auth_token), resource_entries); + } + if (!resource_entries) return false; + const resource_types t = resource_process; + auth_entitlement_t *entry = hash_map_get(resource_entries, &t, sizeof(resource_types)); + if (!entry){ + entry = new(auth_entitlement_t); + hash_map_put(resource_entries, &t, sizeof(resource_types), entry); + } + if (!entry) return false; + entry->action_type |= type; + entry->auth_type = t; + auth_print("[AUTH debug] Token %i authorized for item %i with entitlement",owner, type); + return true; +} + +bool auth_entitlement(auth_token owner, u32 type, resource_types resource_type){ + if (!auth_entitlements) auth_entitlements = hash_map_create_alloc(64, alloc, release); + if (resource_type == resource_process) + return auth_entitlement_proc(owner, type); + return false; +} \ No newline at end of file diff --git a/kernel/access/authorize.h b/kernel/access/authorize.h new file mode 100644 index 00000000..62bf66cf --- /dev/null +++ b/kernel/access/authorize.h @@ -0,0 +1,40 @@ +#pragma once + +#include "types.h" +#include "resources.h" + +typedef u32 auth_token; + +typedef struct { + u32 auth_token; + u32 actions; +} auth_entry; + +typedef enum { + auth_process_send_signals = 1 << 0, + auth_process_intercept_exceptions = 1 << 1, + auth_process_input = 1 << 2, // /proc//in + auth_process_output = 1 << 3, // /proc//out + + auth_process_state = 1 << 4, // /proc//state + auth_process_info = 1 << 5, // /proc//info + + auth_process_count = 1 << 6 +} auth_process_actions; + +typedef union { + struct { + u64 auth_type: 8; + u64 rsvd: 24; + u64 action_type: 32; + }; + u64 entitlement; +} auth_entitlement_t; + +auth_token auth_get_proc_token(process_t *t); + +bool auth_valid(auth_token owner, u32 type, resource resource_id); + +bool auth_request(auth_token owner, u32 type, resource resource_id); + +bool auth_entitlement(auth_token owner, u32 type, resource_types resource_type); \ No newline at end of file diff --git a/kernel/access/entitlements.c b/kernel/access/entitlements.c new file mode 100644 index 00000000..4f89f95d --- /dev/null +++ b/kernel/access/entitlements.c @@ -0,0 +1,46 @@ +#include "entitlements.h" +#include "utils/package_info.h" +#include "files/helpers.h" +#include "authorize.h" + +#define PROC_ENT_PREF "com.redos.process" + +#define ENTITLEMENT_DEBUG +#ifdef ENTITLEMENT_DEBUG +#define ent_print(...) print(__VA_ARGS__) +#else +#define ent_print(...) +#endif + +void process_grant_entitlements(process_t *proc){ + if (!proc->bundle) return;//TODO: CLI tools don't have access to entitlements + + string path = string_format("%s/package.info",proc->bundle); + string_slice package = read_file_slice(path.data); + + package_info info = parse_package_info(package.data); + + if (!info.entitlements) return; + + size_t ents = chunk_array_count(info.entitlements); + auth_token tok = auth_get_proc_token(proc); + + for (u64 i = 0; i < ents; i++){ + string_slice ent = slice_from_string(CHUNK_ARRAY_GET(string, info.entitlements, i)); + if (slice_starts_with(ent, SLICE(PROC_ENT_PREF))){ + ent.data += sizeof(PROC_ENT_PREF)-1; + ent.length -= sizeof(PROC_ENT_PREF)-1; + if (ent.length && ent.data[0] == '.'){ + ent.data++; + ent.length--; + } + ent_print("[ENTITLEMENT debug] found process entitlement %v",ent); + if (slice_lit_match(ent, "signal", true)) auth_entitlement(tok, auth_process_send_signals, resource_process); + if (slice_lit_match(ent, "exceptions", true)) auth_entitlement(tok, auth_process_intercept_exceptions, resource_process); + if (slice_lit_match(ent, "input", true)) auth_entitlement(tok, auth_process_input, resource_process); + if (slice_lit_match(ent, "output", true)) auth_entitlement(tok, auth_process_output, resource_process); + if (slice_lit_match(ent, "info", true)) auth_entitlement(tok, auth_process_info, resource_process); + if (slice_lit_match(ent, "state", true)) auth_entitlement(tok, auth_process_state, resource_process); + } else print("[ENTITLEMENT error] Unknown entitlement %v",ent); + } +} \ No newline at end of file diff --git a/kernel/access/entitlements.h b/kernel/access/entitlements.h new file mode 100644 index 00000000..bd63540e --- /dev/null +++ b/kernel/access/entitlements.h @@ -0,0 +1,5 @@ +#pragma once + +#include "process/process.h" + +void process_grant_entitlements(process_t *proc); \ No newline at end of file diff --git a/kernel/access/mutex.c b/kernel/access/mutex.c new file mode 100644 index 00000000..4645b28c --- /dev/null +++ b/kernel/access/mutex.c @@ -0,0 +1,39 @@ +#include "mutex.h" +#include "exceptions/irq.h" +#define MOG_MODULE "mutex" +#define MOG_LEVEL MOG_VERBOSE +#include "utils/mog.h" + +hash_map_t *mutexed_resources; + +u32 mutex_owner_id = 1; + +mutex_owner new_mutex_owner(){ + return mutex_owner_id++; +} + +bool lock_mutex(mutex_owner owner, resource r){ + irq_flags_t irq = irq_save_disable(); + if (!mutexed_resources) mutexed_resources = hash_map_create(256); + mutex_owner locker = ((u64)hash_map_get(mutexed_resources, &r, sizeof(resource)) & UINT32_MAX); + if (locker) { + irq_restore(irq); + return false; + } + hash_map_put(mutexed_resources, &r, sizeof(resource), (void*)(u64)owner); + locker = ((u64)hash_map_get(mutexed_resources, &r, sizeof(resource)) & UINT32_MAX); + bool res = locker == owner; + irq_restore(irq); + return res; +} + +bool unlock_mutex(mutex_owner owner, resource r){ + if (!mutexed_resources) return false; + mutex_owner mutexer = ((u64)hash_map_get(mutexed_resources, &r, sizeof(resource)) & UINT32_MAX); + if (owner != mutexer){ + mog(ERROR,"mutex owner %i does not own resource %llx",owner,r.resource); + return false; + } + hash_map_remove(mutexed_resources, &r, sizeof(resource), 0); + return true; +} diff --git a/kernel/access/mutex.h b/kernel/access/mutex.h new file mode 100644 index 00000000..5d7a21d0 --- /dev/null +++ b/kernel/access/mutex.h @@ -0,0 +1,10 @@ +#pragma once + +#include "resources.h" + +typedef u32 mutex_owner; + +mutex_owner new_mutex_owner(); + +bool lock_mutex(mutex_owner owner, resource r); +bool unlock_mutex(mutex_owner owner, resource r); \ No newline at end of file diff --git a/kernel/access/resources.c b/kernel/access/resources.c new file mode 100644 index 00000000..4defe6fd --- /dev/null +++ b/kernel/access/resources.c @@ -0,0 +1,52 @@ +#include "resources.h" +#include "process/process.h" +#define MOG_MODULE "RESOURCE" +#define MOG_LEVEL MOG_ERROR +#include "utils/mog.h" + +static u64 resource_id_counter = 1; + +#define U56_MAX 0xFFFFFFFFFFFFFF + +hash_map_t *file_mappings; + +resource resource_new_rid(resource_types type){ + if (type > 255) return (resource){}; + if (resource_id_counter >= U56_MAX) return (resource){}; + return (resource){ + .type = type & 0xFF, + .id = resource_id_counter++ + }; +} + +resource resource_map_process(process_t *p){ + if (!p) return (resource){}; + if (!p->resource_id.id){ + p->resource_id = resource_new_rid(resource_process); + mog(VERBOSE, "resource id %i assigned to process %i",p->resource_id.id,p->id); + } + return p->resource_id; +} + +resource resource_map_file_id(system_module *mod, u64 id){ + mog(VERBOSE, "Mapping fd %llx from mod %llx",id, mod); + if (!file_mappings) file_mappings = hash_map_create(256); + hash_map_t *module_map = hash_map_get(file_mappings, mod, sizeof(uptr)); + if (!module_map){ + module_map = hash_map_create(64); + mog(VERBOSE, "New module map %llx",module_map); + hash_map_put(file_mappings, mod, sizeof(uptr), module_map); + } + if (!module_map) return (resource){}; + mog(VERBOSE, "Module map %llx. Fid %llx",module_map,id); + uptr resourceid = (u64)hash_map_get(module_map, (void*)&id, sizeof(u64)); + resource r = { .resource = resourceid }; + if (r.type == resource_invalid){ + r = resource_new_rid(resource_file); + mog(VERBOSE, "New resource %llx",r.resource); + resourceid = r.resource; + hash_map_put(module_map, (void*)&id, sizeof(u64), (void*)r.resource); + mog(VERBOSE, "New resource id %llx for file %llx of module %llx",r.resource,id,mod); + } else mog(VERBOSE, "Existing resource id %llx for file %llx of module %llx",r.resource,id,mod); + return r; +} \ No newline at end of file diff --git a/kernel/access/resources.h b/kernel/access/resources.h new file mode 100644 index 00000000..ceecf541 --- /dev/null +++ b/kernel/access/resources.h @@ -0,0 +1,28 @@ +#pragma once + +#include "types.h" +#include "files/system_module.h" + +typedef struct process_t process_t; + +typedef union { + struct { + u64 type: 8; + u64 id: 56; + }; + u64 resource; +} resource; + +typedef enum { + resource_invalid, + resource_process, + resource_file, +} resource_types; + +resource resource_map_process(process_t *p); +resource resource_map_file_id(system_module *mod, u64 id); + +static inline resource resource_map_file(system_module *mod, file *fd){ + if (!fd || !fd->id) return (resource){}; + return resource_map_file_id(mod, fd->id); +} \ No newline at end of file diff --git a/kernel/console/kio.c b/kernel/console/kio.c index a3b1094f..eab25625 100644 --- a/kernel/console/kio.c +++ b/kernel/console/kio.c @@ -69,10 +69,13 @@ static void init_print_buf(){ } } +bool console_ready = false; + bool console_init(){ init_print_buf(); enable_uart(); kprint("UART initialized"); + console_ready = true; return true; } @@ -211,6 +214,7 @@ void putc(const char c){ } void kprintf(const char *fmt, ...){ + if (!console_ready) return; if (!console_storage) init_print_buf(); if (!fmt) return; @@ -227,6 +231,7 @@ void kprintf(const char *fmt, ...){ } void kprint(const char *s){ + if (!console_ready) return; if (!console_storage) init_print_buf(); if (!s) return; diff --git a/kernel/debug/watchpoints.c b/kernel/debug/watchpoints.c new file mode 100644 index 00000000..8ab28987 --- /dev/null +++ b/kernel/debug/watchpoints.c @@ -0,0 +1,95 @@ +#include "watchpoints.h" +#include "syscalls/syscalls.h" + +#define MAX_WATCHPOINTS 4 + +uptr watchpoints[MAX_WATCHPOINTS] = {}; +size_t watchpoint_count = 0; + +#define STORE_VAL(i) case i: { asm volatile("msr DBGWVR"#i"_EL1, %0" :: "r"(address)); u64 readback = 0; asm volatile("mrs %0, DBGWVR"#i"_EL1" : "=r"(readback)); print("[DEBUGWP debug] Watchpoint value "#i" set to %llx",readback); } break; +#define STORE_CONFIG(i) case i: { asm volatile("msr DBGWCR"#i"_EL1, %0" :: "r"(config)); u64 readback = 0; asm volatile("mrs %0, DBGWCR"#i"_EL1" : "=r"(readback)); print("[DEBUGWP debug] Watchpoint config "#i" set to %llx",readback); } break; + +typedef union { + struct { + u32 enabled: 1; + u32 priv_access_control: 2; + u32 load_store: 2; + u32 byte_address_select: 8; + u32 higher_mode_control: 1; + u32 security_state_control: 1; + u32 linked_breakpoint_number: 4; + u32 watchpoint_type: 2;//linked or unlinked. TODO: add linked once breakpoints exist + u32 rsvd: 3; + u32 mask: 5; + u32 rsvd2: 3; + }; + u32 entry; +} +watchpoint_entry_t; + +void debug_store_watch_value(u64 index, uptr address){ + switch (index) { + STORE_VAL(0) + STORE_VAL(1) + STORE_VAL(2) + STORE_VAL(3) + } +} + +bool debug_store_watch_config(u64 index, debug_watchpoint_type type, u8 bit_mask, bool active){ + if (active && !(type & watchpoint_type_all)) return false; + watchpoint_entry_t entry = { + .enabled = active & 1, + .priv_access_control = active ? 0b11 : 0,//01 = EL1, 10 = EL0, 11 = both + .load_store = type, + .byte_address_select = bit_mask, + .higher_mode_control = 0, + .security_state_control = 0, + .linked_breakpoint_number = 0, + .watchpoint_type = 0, + .mask = 0, + }; + u64 config = entry.entry; + switch (index) { + STORE_CONFIG(0) + STORE_CONFIG(1) + STORE_CONFIG(2) + STORE_CONFIG(3) + } + return true; +} + +int debug_watch(uptr address, debug_watchpoint_type type, u8 bit_mask){ + asm volatile ("msr daifclr, #8"); + u64 mdscr = 0; + asm volatile ( + "msr oslar_el1, xzr\n" + "mrs %0, mdscr_el1\n" + "orr %0, %0, #(1 << 15)\n" + "msr mdscr_el1, %0\n" : "=r"(mdscr) + ); + if (watchpoint_count + 1 >= MAX_WATCHPOINTS) return -1; + for (u64 i = 0; i < MAX_WATCHPOINTS; i++){ + if (!watchpoints[i]){ + watchpoints[i] = address; + debug_store_watch_value(i, address); + if (!debug_store_watch_config(i, type, bit_mask, true)) return -1; + asm volatile("isb" ::: "memory"); + watchpoint_count++; + print("[DEBUG] Set debug watchpoint at %llx",address); + return i; + } + } + return -1; +} + +bool debug_unwatch(int index){ + if (!watchpoint_count) return false; + if (!watchpoints[index]) return false; + watchpoint_count--; + print("[DEBUG] Unset debug watchpoint for %llx",watchpoints[index]); + watchpoints[index] = 0; + debug_store_watch_config(index, 0, 0, false); + asm volatile("isb" ::: "memory"); + return true; +} \ No newline at end of file diff --git a/kernel/debug/watchpoints.h b/kernel/debug/watchpoints.h new file mode 100644 index 00000000..aeee7160 --- /dev/null +++ b/kernel/debug/watchpoints.h @@ -0,0 +1,12 @@ +#pragma once + +#include "types.h" + +typedef enum { + watchpoint_type_write = 0b10, + watchpoint_type_read = 0b01, + watchpoint_type_all = watchpoint_type_write | watchpoint_type_read +} debug_watchpoint_type; + +int debug_watch(uptr address, debug_watchpoint_type type, u8 bit_mask); +bool debug_unwatch(int index); \ No newline at end of file diff --git a/kernel/exceptions/exception_handler.c b/kernel/exceptions/exception_handler.c index 102feb16..0d1d5999 100644 --- a/kernel/exceptions/exception_handler.c +++ b/kernel/exceptions/exception_handler.c @@ -35,7 +35,7 @@ void fiq_el1_handler(){ handle_exception("FIQ EXCEPTION\r\n", 0); } void error_el1_handler(){ handle_exception("ERROR EXCEPTION\r\n", 0); } void draw_panic_screen(string s){ - gpu_clear(system_theme.err_color); + gpu_clear(system_theme.palette.error); uint32_t scale = 3; gpu_draw_string(*(string *)&s, (gpu_point){20,20}, scale, 0xFFFFFFFF); gpu_flush(); diff --git a/kernel/filesystem/fat32.cpp b/kernel/filesystem/fat32.cpp index 3ce9a314..a60e7fce 100644 --- a/kernel/filesystem/fat32.cpp +++ b/kernel/filesystem/fat32.cpp @@ -1,15 +1,16 @@ #include "fat32.hpp" +#include "alloc/mem_types.h" #include "disk.h" -#include "memory/page_allocator.h" +#include "files/system_module.h" #include "console/kio.h" -#include "std/memory_access.h" -#include "std/string.h" -#include "std/memory.h" +#include "memory/memory.h" +#include "memory/memory_access.h" #include "math/math.h" #include "syscalls/syscalls.h" #include "exceptions/irq.h" #include "files/dir_list.h" -#include "filesystem/modules/module_loader.h" +#include "modules/fs_isolation.h" +#include "alloc/allocate.h" #define kprintfv(fmt, ...) \ ({ \ @@ -18,10 +19,14 @@ }\ }) +void* f32palloc(size_t size){ + return palloc(size, MEM_PRIV_KERNEL, MEM_DEV | MEM_RW, true); +} + bool FAT32FS::init(uint32_t partition_sector){ - fs_page = palloc(0x1000, MEM_PRIV_KERNEL, MEM_DEV | MEM_RW, false); + fs_page = f32palloc(PAGE_SIZE); - mbs = (fat32_mbs*)kalloc(fs_page, 512, ALIGN_64B, MEM_PRIV_KERNEL); + mbs = (fat32_mbs*)allocate(fs_page, 512, f32palloc); if (!mbs) return false; partition_first_sector = partition_sector; @@ -65,7 +70,7 @@ sizedptr FAT32FS::read_cluster(uint32_t cluster_start, uint32_t cluster_size, ui if (root_index < 2 || root_index >= total_fat_entries) return (sizedptr){ 0, 0}; size_t size = cluster_count * cluster_size * 512; - void* buffer = kalloc(fs_page, size, ALIGN_64B, MEM_PRIV_KERNEL); + void *buffer = allocate(fs_page, size, f32palloc); if (!buffer) return (sizedptr){0, 0}; uint32_t next_index = root_index; @@ -114,7 +119,7 @@ bool FAT32FS::write_section_to_cluster(u32 cluster, u32 offset, void *buf, size_ u32 sector_count = ceil(((float)offset + size)/512); - void *initial = kalloc(fs_page, 512 * sector_count, ALIGN_64B, MEM_PRIV_KERNEL); + void *initial = allocate(fs_page, 512 * sector_count, f32palloc); disk_read(initial, sector, sector_count); @@ -175,7 +180,7 @@ f32_walk_result FAT32FS::walk_directory(uint32_t cluster_count, uint32_t root_in u32 cluster_byte_size = cluster_size * 512; for (uint64_t i = 0; i + sizeof(f32file_entry) <= buf_ptr.size;) { if (buffer[i] == 0) { - kfree(buffer, buf_ptr.size); + release(buffer); return {}; } if (buffer[i] == 0xE5){ @@ -183,7 +188,7 @@ f32_walk_result FAT32FS::walk_directory(uint32_t cluster_count, uint32_t root_in continue; } bool long_name = buffer[i + 0xB] == 0xF; - char filename[256] = {0}; + char filename[256] = {}; if (long_name){ f32longname *first_longname = (f32longname*)&buffer[i]; uint16_t count = 0; @@ -191,7 +196,7 @@ f32_walk_result FAT32FS::walk_directory(uint32_t cluster_count, uint32_t root_in i += sizeof(f32longname); count++; if (i + sizeof(f32file_entry) > buf_ptr.size) { - kfree(buffer, buf_ptr.size); + release(buffer); return {}; } } while (buffer[i + 0xB] == 0xF); @@ -215,16 +220,16 @@ f32_walk_result FAT32FS::walk_directory(uint32_t cluster_count, uint32_t root_in .offset = offset, .found = true, }; - kfree(buffer, buf_ptr.size); + release(buffer); return result; } - kfree(buffer, buf_ptr.size); + release(buffer); return found_entry; } i += sizeof(f32file_entry); } - kfree(buffer, buf_ptr.size); + release(buffer); return {}; } @@ -236,9 +241,9 @@ sizedptr FAT32FS::list_directory(uint32_t cluster_count, uint32_t root_index) { f32file_entry *entry = 0; if (!buffer || !buf_ptr.size) return { 0, 0}; size_t full_size = buf_ptr.size + 4; - void *list_buffer = kalloc(fs_page, full_size, ALIGN_64B, MEM_PRIV_KERNEL); + void *list_buffer = allocate(fs_page, full_size, f32palloc); if (!list_buffer) { - kfree(buffer, buf_ptr.size); + release(buffer); return { 0, 0}; } @@ -261,8 +266,8 @@ sizedptr FAT32FS::list_directory(uint32_t cluster_count, uint32_t root_index) { i += sizeof(f32longname); long_count++; if (i + sizeof(f32file_entry) > buf_ptr.size) { - kfree(buffer, buf_ptr.size); - kfree(list_buffer, full_size); + release(buffer); + release(list_buffer); return { 0, 0 }; } } while (buffer[i + 0xB] == 0xF); @@ -286,7 +291,7 @@ sizedptr FAT32FS::list_directory(uint32_t cluster_count, uint32_t root_index) { } *(uint32_t*)list_buffer = count; - kfree(buffer, buf_ptr.size); + release(buffer); return (sizedptr){(uintptr_t)list_buffer, full_size}; } @@ -299,22 +304,22 @@ sizedptr FAT32FS::read_full_file(uint32_t cluster_start, uint32_t cluster_size, char *buffer = (char*)buf_ptr.ptr; if (!buffer || !buf_ptr.size) return {0, 0}; - if (!file_page) file_page = page_alloc(PAGE_SIZE); + if (!file_page) file_page = f32palloc(PAGE_SIZE); - void *file = allocate(file_page, file_size ? file_size : 1, page_alloc); + void *file = allocate(file_page, file_size ? file_size : 1, f32palloc); if (!file) { - kfree(buffer, buf_ptr.size); + release(buffer); return {0, 0}; } if (file_size) memcpy(file, (void*)buffer, file_size); - kfree(buffer, buf_ptr.size); + release(buffer); return (sizedptr){(uintptr_t)file,file_size}; } void FAT32FS::read_FAT(uint32_t location, uint32_t size, uint8_t count){ - fat = (uint32_t*)kalloc(fs_page, size * 512, ALIGN_64B, MEM_PRIV_KERNEL); + fat = (uint32_t*)allocate(fs_page, size*512, f32palloc); if (!fat) { total_fat_entries = 0; return; @@ -402,7 +407,7 @@ u32 FAT32FS::alloc_fat(){ f32_walk_result FAT32FS::read_entry_handler(FAT32FS *instance, f32file_entry *entry, char *filename, const char *seek) { if (entry->flags.volume_id) return {}; - + size_t name_len = strlen_max(filename, 0); int matched = strstart_case(seek, filename, true); if (matched != (int)name_len) return {}; @@ -417,7 +422,7 @@ f32_walk_result FAT32FS::read_entry_handler(FAT32FS *instance, f32file_entry *en uint32_t bpc = bps * spc; uint32_t count = entry->filesize > 0 ? ((entry->filesize + bpc - 1) / bpc) : instance->count_FAT(filecluster); - if (entry->flags.directory) return instance->walk_directory(count, filecluster, next, read_entry_handler); + if (entry->flags.directory && *next) return instance->walk_directory(count, filecluster, next, read_entry_handler); if (*next != '\0') return {}; return {.entry = *entry, .cluster = 0, .offset = 0, .found = true}; } @@ -429,7 +434,7 @@ FS_RESULT FAT32FS::open_file(const char* path, file* descriptor){ module_file *mfile = (module_file*)hash_map_get(open_files, &fid, sizeof(uint64_t)); if (mfile){ descriptor->id = mfile->fid; - descriptor->size = mfile->file_size; + descriptor->size = mfile->file_buffer.buffer_size; mfile->references++; irq_restore(irq); return FS_RESULT_SUCCESS; @@ -448,13 +453,12 @@ FS_RESULT FAT32FS::open_file(const char* path, file* descriptor){ if (!buf || !buf_ptr.size) return FS_RESULT_NOTFOUND; descriptor->id = fid; descriptor->size = buf_ptr.size; - mfile = (module_file*)kalloc(fs_page, sizeof(module_file), ALIGN_64B, MEM_PRIV_KERNEL); + mfile = (module_file*)allocate(fs_page, sizeof(module_file), f32palloc); if (!mfile) { - kfree(buf, buf_ptr.size ? buf_ptr.size : 1); + release(buf); return FS_RESULT_DRIVER_ERROR; } memset(mfile, 0, sizeof(module_file)); - mfile->file_size = buf_ptr.size; mfile->name = string_from_literal(fullpath); mfile->file_buffer = (buffer){ .buffer = buf, @@ -464,7 +468,6 @@ FS_RESULT FAT32FS::open_file(const char* path, file* descriptor){ .cursor = 0, .data_type = 0, }; - mfile->ignore_cursor = false; mfile->fid = descriptor->id; mfile->serial = filecluster; mfile->references = 1; @@ -472,8 +475,8 @@ FS_RESULT FAT32FS::open_file(const char* path, file* descriptor){ int ok = hash_map_put(open_files, &fid, sizeof(uint64_t), mfile); irq_restore(irq); if (ok < 0) { - kfree(mfile->file_buffer.buffer, mfile->file_size ? mfile->file_size : 1); - kfree(mfile, sizeof(module_file)); + release(mfile->file_buffer.buffer); + release(mfile); return FS_RESULT_DRIVER_ERROR; } return FS_RESULT_SUCCESS; @@ -486,11 +489,11 @@ size_t FAT32FS::read_file(file *descriptor, void* buf, size_t size){ irq_restore(irq); return 0; } - if (descriptor->cursor > mfile->file_size) { + if (descriptor->cursor > mfile->file_buffer.buffer_size) { irq_restore(irq); return 0; } - if (size > mfile->file_size-descriptor->cursor) size = mfile->file_size-descriptor->cursor; + if (size > mfile->file_buffer.buffer_size-descriptor->cursor) size = mfile->file_buffer.buffer_size-descriptor->cursor; memcpy(buf, (char*)mfile->file_buffer.buffer + descriptor->cursor, size); irq_restore(irq); return size; @@ -499,14 +502,14 @@ size_t FAT32FS::read_file(file *descriptor, void* buf, size_t size){ size_t FAT32FS::write_file(file *descriptor, const char* buf, size_t size){ module_file *mfile = (module_file*)hash_map_get(open_files, &descriptor->id, sizeof(uint64_t)); if (!mfile) return 0; - if (mfile->read_only) return 0; + if (mfile->file_buffer.options & buffer_read_only) return 0; size_t written = buffer_write_to(&mfile->file_buffer, buf, size, descriptor->cursor); if (written) write_to_disk(mfile->serial, mfile->file_buffer.buffer, mfile->file_buffer.buffer_size); - descriptor->size = mfile->file_size; + descriptor->size = mfile->file_buffer.buffer_size; truncate(descriptor); return written; @@ -524,7 +527,7 @@ void FAT32FS::close_file(file* descriptor){ hash_map_remove(open_files, &descriptor->id, sizeof(uint64_t), 0); irq_restore(irq); buffer_destroy(&mfile->file_buffer); - kfree(mfile, sizeof(module_file)); + release(mfile); return; } irq_restore(irq); @@ -605,7 +608,7 @@ size_t FAT32FS::list_contents(const char *path, void* buf, size_t size, uint64_t } *(uint32_t*)buf = count; - kfree((void*)ptr.ptr, ptr.size); + release((void*)ptr.ptr); return (uintptr_t)write_ptr-(uintptr_t)buf; } @@ -703,6 +706,8 @@ system_module boot_fs_module = (system_module){ .truncate = boot_truncate, .getstat = boot_stat, .readdir = boot_partition_readdir, + .transform = 0, + //.permissions = fs_permission_shared, .alias_info = {} }; diff --git a/kernel/filesystem/filesystem.c b/kernel/filesystem/filesystem.c index e15488b1..22665097 100644 --- a/kernel/filesystem/filesystem.c +++ b/kernel/filesystem/filesystem.c @@ -1,12 +1,13 @@ #include "filesystem.h" #include "console/kio.h" -#include "filesystem/modules/module_loader.h" -#include "memory/page_allocator.h" #include "exceptions/irq.h" #include "process/scheduler.h" #include "pipe.h" #include "files/dir_list.h" #include "process/jobs/job_manager.h" +#include "modules/fs_isolation.h" +#include "access/mutex.h" +#include "sync.h" uint64_t fd_id = 256;//First byte reserved @@ -14,14 +15,6 @@ uint64_t reserve_fd_id(){ return ++fd_id; } -typedef struct { - uint64_t mfile_id; - uint64_t file_id; - size_t file_size; - uint16_t pid; - system_module* mod; -} open_file_descriptors; - hash_map_t *open_files; void* page; @@ -60,7 +53,7 @@ FS_RESULT open_file_global(module_root *root, const char* path, file* descriptor job_serialize_str(&app, 0, search_path); job_serialize_fd(&app, 1, descriptor, copy_on_end); }); - return j_ret; + result = j_ret; } else { result = mod->open(search_path, descriptor); } @@ -82,7 +75,10 @@ FS_RESULT instance_local_fd(system_module *mod, file *descriptor){ of->file_size = descriptor->size; of->mod = mod; of->pid = get_current_proc_pid(); + of->resource_id = resource_map_file(mod, descriptor); + of->last_sync = get_time(); descriptor->id = of->file_id; + sync_fd(descriptor,of, true); int put = hash_map_put(open_files, &of->file_id, sizeof(uint64_t), of); if (put != 1) { @@ -109,6 +105,12 @@ FS_RESULT open_file(module_root *root, const char* path, file* descriptor){ } size_t read_file(file *descriptor, char* buf, size_t size){ + if (descriptor->id == FD_IN){ + system_module *mod = &procfs_mod; + if (!mod || !mod->write) return 0; + return mod->read(descriptor, buf, size, descriptor->cursor); + //TODO: this handles its own cursor movement, but with the new sync policies it shouldn't have to + } if (!open_files){ kprintf("[FS] No open files"); return 0; @@ -119,6 +121,7 @@ size_t read_file(file *descriptor, char* buf, size_t size){ if (ofile) local = *ofile; irq_restore(irq); if (!ofile || !local.mod || !local.mod->read || local.pid != get_current_proc_pid()) return 0; + sync_fd(descriptor, ofile, false); size_t start_cursor = descriptor->cursor; file gfd = (file){ .id = local.mfile_id, @@ -141,6 +144,28 @@ size_t read_file(file *descriptor, char* buf, size_t size){ return amount_read; } +size_t transform_file(module_root *root, const char* path, void* buf, size_t size){ + const char *search_path = path; + if (*search_path == '/') search_path++; + if (!*search_path) return FS_RESULT_NOTFOUND; + system_module *mod = get_module_from(root, &search_path); + if (!mod) return FS_RESULT_NOTFOUND; + if (!mod->transform) return FS_RESULT_NOTFOUND; + FS_RESULT result = FS_RESULT_DRIVER_ERROR; + if (mod->owner != get_kernel_proc()->id){ + job_make(job_transform, mod, { + job_serialize_str(&app, 0, search_path); + job_serialize_buf(&app, 1, true, (void*)buf, size, copy_on_start | copy_on_end); + }); + return j_ret; + } else { + result = mod->transform(search_path, buf, size); + } + if (result != FS_RESULT_SUCCESS) return result; + if (!open_files) return FS_RESULT_DRIVER_ERROR; + return FS_RESULT_SUCCESS; +} + void close_file(file *descriptor){ if (!open_files || !descriptor) return; open_file_descriptors *ofile = 0; @@ -171,10 +196,19 @@ void close_file_global(file *descriptor, system_module *mod){ size_t write_file(file *descriptor, const char* buf, size_t size){ if (descriptor->id == FD_OUT){ - const char *search_path = "proc";//TODO: This is ugly - system_module *mod = get_module(&search_path); + system_module *mod = &procfs_mod; if (!mod || !mod->write) return 0; - return mod->write(descriptor, buf, size, descriptor->cursor); + mutex_owner own = new_mutex_owner(); + u64 out_desc = resolve_reserved_fd(FD_OUT); + resource rid = resource_map_file_id(mod, out_desc); + if (!lock_mutex(own, rid)){ + print("[FSWrite Implementation error] No fallback for concurrent writes yet, failing"); + return 0; + } + size_t amount_written = mod->write(descriptor, buf, size, descriptor->cursor); + update_pipes(out_desc, buf, amount_written); + unlock_mutex(own, rid); + return amount_written; //TODO: this handles its own cursor movement, but with the new sync policies it shouldn't have to } if (!open_files) return 0; @@ -185,10 +219,16 @@ size_t write_file(file *descriptor, const char* buf, size_t size){ if (ofile) local = *ofile; irq_restore(irq); if (!ofile || !local.mod || !local.mod->write || local.pid != get_current_proc_pid()) return 0; + mutex_owner own = new_mutex_owner(); + if (!lock_mutex(own, ofile->resource_id)){ + print("[FSWrite Implementation error] No fallback for concurrent writes yet, failing"); + return 0; + } + sync_fd(descriptor,ofile, false); size_t start_cursor = descriptor->cursor; file gfd = (file){ .id = local.mfile_id, - .size = descriptor->size, + .size = ofile->file_size, .cursor = start_cursor, .data_type = descriptor->data_type }; @@ -198,7 +238,7 @@ size_t write_file(file *descriptor, const char* buf, size_t size){ job_serialize_fd(&app, 0, &gfd, copy_on_start); job_serialize_buf(&app, 1, true, (void*)buf, size, copy_on_start); }); - return j_ret; + amount_written = j_ret; } else { amount_written = local.mod->write(&gfd, buf, size, 0); } @@ -206,18 +246,31 @@ size_t write_file(file *descriptor, const char* buf, size_t size){ descriptor->size = gfd.size; irq = irq_save_disable(); ofile = (open_file_descriptors *)hash_map_get(open_files, &descriptor->id, sizeof(uint64_t)); - if (ofile) ofile->file_size = gfd.size; + if (ofile) ofile->file_size += amount_written; irq_restore(irq); update_pipes(local.mfile_id, buf, amount_written); + if (amount_written && ofile){ + range_t modified = { .start = start_cursor, amount_written }; + u64 mod_time = get_time(); + ofile->last_sync = mod_time; + report_fd_mod(descriptor, ofile, mod_time, modified); + } + unlock_mutex(own, ofile->resource_id); return amount_written; } +void sync_file(file *descriptor, bool replace){ + open_file_descriptors *ofile = (open_file_descriptors *)hash_map_get(open_files, &descriptor->id, sizeof(uint64_t)); + if (!ofile || ofile->pid != get_current_proc_pid()) return; + sync_fd(descriptor, ofile, replace); +} + size_t simple_read(module_root *root, const char *path, void *buf, size_t size){ file fd = {}; FS_RESULT ores = open_file(root, path, &fd); if (ores != FS_RESULT_SUCCESS){ - kprintf("[FS error] Failed to open file for simple read (%i)",ores); + kprintf("[FS error] Failed to open file %s for simple read (%i)",path,ores); return 0; } size_t res = read_file(&fd, (char*)buf, size); @@ -252,7 +305,7 @@ size_t list_directory_contents(module_root *root, const char *path, void* buf, s } system_module *mod = get_module_from(root, &search_path); if (!mod){ - kprintf("No module for path %s",search_path); + kprintf("[LIST error] No module for path %s",path); return 0; } if (!mod->readdir) return 0; @@ -276,7 +329,7 @@ bool get_stat(module_root *root, const char *path, fs_stat *out_stat){ } system_module *mod = get_module_from(root, &search_path); if (!mod){ - kprintf("No module for path %s",search_path); + kprintf("[STAT error] No module for path %s",path); return false; } if (!mod->getstat) return false; @@ -317,13 +370,14 @@ bool truncate(file *descriptor, size_t size){ return j_ret; } else if (!local.mod->truncate(&gfd)) return false; - descriptor->size = gfd.size; + descriptor->size = size; + ofile->file_size = size; + //TODO: sync fd logic descriptor->cursor = gfd.cursor; if (descriptor->cursor > descriptor->size) descriptor->cursor = descriptor->size; irq = irq_save_disable(); ofile = (open_file_descriptors *)hash_map_get(open_files, &descriptor->id, sizeof(uint64_t)); - if (ofile) ofile->file_size = gfd.size; irq_restore(irq); return true; } diff --git a/kernel/filesystem/filesystem.h b/kernel/filesystem/filesystem.h index 54c2d786..d1214db9 100644 --- a/kernel/filesystem/filesystem.h +++ b/kernel/filesystem/filesystem.h @@ -3,22 +3,36 @@ #include "types.h" #include "std/string.h" #include "files/system_module.h" -#include "modules/module_loader.h" +#include "files/module_loader.h" +#include "access/resources.h" #ifdef __cplusplus extern "C" { #endif +typedef struct { + u64 mfile_id; + u64 file_id; + size_t file_size; + u16 pid; + system_module* mod; + resource resource_id; + u64 last_sync; +} open_file_descriptors; + FS_RESULT open_file_global(module_root *root, const char* path, file* descriptor, system_module **mod); FS_RESULT open_file(module_root *root, const char* path, file* descriptor); FS_RESULT instance_local_fd(system_module *mod, file *descriptor); size_t read_file(file *descriptor, char* buf, size_t size); +size_t transform_file(module_root *root, const char* path, void* buf, size_t size); size_t write_file(file *descriptor, const char* buf, size_t size); void close_file_global(file *descriptor, system_module *mod); void close_file(file *descriptor); size_t list_directory_contents(module_root *root, const char *path, void* buf, size_t size, uint64_t *offset); bool init_filesystem(); +void sync_file(file *descriptor, bool replace); + bool get_stat(module_root *root, const char *path, fs_stat *out_stat); bool truncate(file *descriptor, size_t size); diff --git a/kernel/filesystem/modules/fs_isolation.c b/kernel/filesystem/modules/fs_isolation.c index d0e95a4d..2c499c3b 100644 --- a/kernel/filesystem/modules/fs_isolation.c +++ b/kernel/filesystem/modules/fs_isolation.c @@ -1,21 +1,23 @@ #include "fs_isolation.h" #include "data/struct/chunk_array.h" -#include "module_loader.h" #include "console/kio.h" #include "memory/memory.h" +#include "alloc/alloc.h" +#include "process/scheduler.h" +#include "exceptions/exception_handler.h" chunk_array_t *fs_permissions; u64 register_fs_id(){ - if (!fs_permissions) fs_permissions = chunk_array_create(sizeof(uptr), 256); + if (!fs_permissions) fs_permissions = chunk_array_create(sizeof(module_root), 256); module_root *map = zalloc(sizeof(module_root)); map->map = hash_map_create(64); - return chunk_array_push(fs_permissions, map); + return chunk_array_push(fs_permissions, map)+1; } module_root* get_fs_for_id(u64 id){ if (!fs_permissions) return 0; - return (module_root*)chunk_array_get(fs_permissions, id); + return (module_root*)chunk_array_get(fs_permissions, id-1); } module_root kernel_modules = {}; @@ -26,7 +28,17 @@ module_root* kernel_fs(){ bool load_module(system_module *module){ if (!kernel_modules.map) kernel_modules.map = hash_map_create(64); - return load_module_to(&kernel_modules, module); + if (module->owner == get_kernel_proc()->id && !module->init){ + kprintf("[MODULE error] module not initialized due to missing initializer"); + return false; + } + if (!module->owner) module->owner = get_kernel_proc()->id; + bool res = load_module_to(&kernel_modules, module); + +#ifdef MODULE_STRICT + if (!res) panic("Failed to load module",(uptr)module); +#endif + return res; } bool unload_module(system_module *module){ @@ -71,5 +83,8 @@ string resolve_isolated_path(const char *path, u64 id, module_root *resolved, bo void destroy_fs(u64 fsid){ if (!fsid) return; - //TODO: STUB + module_root *root = get_fs_for_id(fsid); + if (!root) return; + destroy_root_module(root); + memset(root,0,sizeof(module_root)); } \ No newline at end of file diff --git a/kernel/filesystem/modules/fs_isolation.h b/kernel/filesystem/modules/fs_isolation.h index e4e754d1..8270b408 100644 --- a/kernel/filesystem/modules/fs_isolation.h +++ b/kernel/filesystem/modules/fs_isolation.h @@ -2,11 +2,7 @@ #include "data/struct/linked_list.h" #include "files/system_module.h" - -typedef struct { - hash_map_t *map; - hash_map_t *reserved; -} module_root; +#include "files/module_loader.h" u64 register_fs_id(); module_root* get_fs_for_id(u64 id); diff --git a/kernel/filesystem/modules/module_loader.c b/kernel/filesystem/modules/module_loader.c deleted file mode 100644 index 11215acb..00000000 --- a/kernel/filesystem/modules/module_loader.c +++ /dev/null @@ -1,135 +0,0 @@ -#include "module_loader.h" -#include "console/kio.h" -#include "string/string.h" -#include "sysregs.h" -#include "memory/page_allocator.h" -#include "syscalls/syscalls.h" -#include "files/dir_list.h" -#include "exceptions/exception_handler.h" -#include "files/vfs.h" -#include "process/scheduler.h" - -#define MODULE_STRICT - -bool root_stat(const char *path, fs_stat *out_stat){ - if (!out_stat) return false; - out_stat->size = 0; - out_stat->type = entry_directory; - return true; -} - -system_module root_module = { - .name = "root", - .mount = "/", - .getstat = root_stat, - .readdir = 0, -}; - -bool reserve_mount_point(module_root* modules, char* mount_point){ - if (!modules->reserved) modules->reserved = hash_map_create(64); - if (hash_map_get_dictionary(modules->reserved, mount_point)){ print("[MODULE] %s already reserved",mount_point); return false; } - hash_map_put_dictionary(modules->reserved, mount_point, (void*)((u64)get_kernel_proc()->id)); - print("[MODULE] Reserved %s",mount_point); - return false; -} - -bool load_module_to(module_root* modules, system_module *module){ - if (module->owner == get_kernel_proc()->id && !module->init){ - if (strcmp(module->mount,"/console")) kprintf("[MODULE error] module not initialized due to missing initializer");//TODO: can we make printf silently fail so logging becomes easier? - return false; - } - if (!module->version){ - string format = string_format("[MODULE error] Version number cannot be null for module /%s",module->mount); - if (strcmp(module->mount,"/console")) { - #ifdef MODULE_STRICT - if (module->owner != get_kernel_proc()->id){ - kprintf(format.data); - } else { - panic(format.data,0); - } - #else - kprintf(format.data); - #endif - } - string_free(format); - return false; - } - if (!module->owner) module->owner = get_kernel_proc()->id; - if (module->owner == get_kernel_proc()->id && !module->init(module)){ - if (strcmp(module->mount,"/console")) kprintf("[MODULE error] failed to load module %s. Init failed",module->name); - return false; - } - if (!modules->map) modules->map = hash_map_create(64); - if (modules->reserved && hash_map_get_dictionary(modules->reserved, module->mount)){ - kprintf("[MODULE error] mount point %s is reserved",module->mount); - return false; - } - hash_map_put_dictionary(modules->map, module->mount, PHYS_TO_VIRT_P(module)); - return true; -} - -bool unload_module_from(module_root* modules, system_module *module){ - if (!modules) return false; - if (module->owner == get_kernel_proc()->id){ - if (!module->init) return false; - if (module->fini) { - kprint("Can't deinit module yet"); - } else - module->fini(); - } - hash_map_remove(modules->map, module->mount, strlen(module->mount), 0); - return false; -} - -system_module* get_module_from(module_root* modules, const char **full_path){ - if (!modules) return 0; - if (!full_path || !*full_path) return 0; - const char *path = *full_path; - if (!strlen(path)) return 0; - if (*path == '/'){ - path++; - *full_path += 1; - } - string_slice mod_name = first_path_component(path); - if (!mod_name.length){ - return &root_module; - } - if (mod_name.data[0] == '/'){ - mod_name.data++; - mod_name.length--; - *full_path += 1; - } - *full_path += mod_name.length; - if (!mod_name.length){ - return &root_module; - } - return hash_map_get(modules->map, mod_name.data, mod_name.length); -} - -static u64 index = 0, count = 0; -static uint64_t *list_offset; - -static fs_dir_list_helper *dir_helper; - -void iterate_root(void* key, u64 keylen, void* value){ - count++; - if (count <= index) return; - - system_module *mod = value; - if (!mod || !mod->mount) return; - if (!dir_list_fill(dir_helper, mod->mount)){ - if (list_offset) *list_offset = index; - return; - } -} - -size_t list_root_from(module_root* modules, fs_dir_list_helper *helper, uint64_t *offset){ - - dir_helper = helper; - index = offset ? *offset : 0; - count = 0; - - hash_map_for_each(modules->map, iterate_root); - - return dir_buf_size(helper); -} diff --git a/kernel/filesystem/modules/module_loader.h b/kernel/filesystem/modules/module_loader.h deleted file mode 100644 index 82eadcb2..00000000 --- a/kernel/filesystem/modules/module_loader.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include "data/struct/hashmap.h" -#include "files/system_module.h" -#include "fs_isolation.h" -#include "files/dir_list.h" - -bool reserve_mount_point(module_root* modules, char* mount_point); -bool load_module_to(module_root* modules, system_module *module); -bool unload_module_from(module_root* modules, system_module *module); -system_module* get_module_from(module_root* modules, const char **full_path); -size_t list_root_from(module_root* modules, fs_dir_list_helper *helper, uint64_t *offset); -bool root_stat(const char *path, fs_stat *out_stat); - -extern system_module root_module; \ No newline at end of file diff --git a/kernel/filesystem/pipe.c b/kernel/filesystem/pipe.c index c48c44f0..6a34e486 100644 --- a/kernel/filesystem/pipe.c +++ b/kernel/filesystem/pipe.c @@ -4,39 +4,56 @@ #include "data/struct/hashmap.h" #include "data/struct/linked_list.h" #include "process/scheduler.h" +#define MOG_MODULE "Pipe" +#define MOG_LEVEL MOG_ALL +#include "utils/mog.h" static void *pipe_page; hash_map_t *pipe_map; -//TODO: options -FS_RESULT create_pipe(module_root *root, const char *source, const char* destination, PIPE_OPTIONS options, file *out_fd){ +FS_RESULT create_pipe(module_root *src_root, const char *source, module_root *dst_root, const char* destination, pipe_options options, file *out_fd){ + if (!src_root) { + mog(ERROR, "No source file filesystem root"); + return FS_RESULT_NOTFOUND; + } + if (!dst_root){ + mog(VERBOSE,"Using source module root as destination"); + dst_root = src_root; + } if (!pipe_page) pipe_page = palloc(PAGE_SIZE, MEM_PRIV_KERNEL, MEM_RW, false); pipe_t *pipe = (pipe_t*)kalloc(pipe_page, sizeof(pipe_t), ALIGN_16B, MEM_PRIV_KERNEL); pipe->pid = get_current_proc_pid(); - FS_RESULT result = open_file_global(root, source, &pipe->write_fd, &pipe->write_mod); + FS_RESULT result = open_file_global(src_root, source, &pipe->write_fd, &pipe->write_mod); if (result == FS_RESULT_SUCCESS){ - result = open_file(root, destination, &pipe->read_fd); + result = open_file(dst_root, destination, &pipe->read_fd); if (result == FS_RESULT_SUCCESS){ if (!pipe_map) pipe_map = hash_map_create(64); linked_list_t *list = hash_map_get(pipe_map, &pipe->write_fd.id, sizeof(uint64_t)); - bool add_entry = false; if (!list){ - add_entry = true; list = linked_list_create(); + hash_map_put(pipe_map, &pipe->write_fd.id, sizeof(uint64_t), list); } linked_list_push_front(list, pipe); - if (add_entry) - hash_map_put(pipe_map, &pipe->write_fd.id, sizeof(uint64_t), list); out_fd->cursor = 0; out_fd->id = pipe->read_fd.id; out_fd->size = pipe->read_fd.size; - } - } + mog(VERBOSE, "Opened pipe between %s and %s with fd %i and src fd %x",source,destination,out_fd->id,pipe->write_fd.id); + if (options & pipe_from_beginning){ + char *buf = zalloc(pipe->write_fd.size); + size_t l = pipe->write_mod->read(&pipe->write_fd, buf, pipe->write_fd.size, 0); + if (l){ + write_file(&pipe->read_fd, buf, l); + mog(VERBOSE, "Piped %i of existing input to pipe output",l); + } + } + } else mog(ERROR, "Failed to open destination of pipe"); + } else mog(ERROR, "Failed to open source of pipe %s",source); if (result != FS_RESULT_SUCCESS) kfree(pipe, sizeof(pipe_t)); return result; } FS_RESULT close_pipe(file *fd){ + mog(IMPLEMENTATION_ERROR, "Closing pipes not yet supported");//TODO: Close pipes, the fd is not the hashmap index return FS_RESULT_DRIVER_ERROR; } diff --git a/kernel/filesystem/pipe.h b/kernel/filesystem/pipe.h index 3a5e4c84..14ed19bc 100644 --- a/kernel/filesystem/pipe.h +++ b/kernel/filesystem/pipe.h @@ -3,7 +3,8 @@ #include "types.h" #include "files/fs.h" #include "files/system_module.h" -#include "filesystem/modules/module_loader.h" +#include "files/module_loader.h" +#include "files/pipes.h" typedef struct { file write_fd; @@ -12,15 +13,10 @@ typedef struct { system_module* write_mod; } pipe_t; -typedef enum { - PIPE_DEFAULT = 0,//Any writes to the source while the pipe is open get copied to the destination - PIPE_FROM_BEGINNING = 1,//Read the source file when creating the pipe and copy its contents -} PIPE_OPTIONS; - #ifdef __cplusplus extern "C" { #endif -FS_RESULT create_pipe(module_root *root, const char *source, const char* destination, PIPE_OPTIONS options, file *out_fd); +FS_RESULT create_pipe(module_root *src_root, const char *source, module_root *dst_root, const char* destination, pipe_options options, file *out_fd); FS_RESULT close_pipe(file *fd); void update_pipes(uint64_t mfid, const char *buf, size_t size); diff --git a/kernel/filesystem/sync.c b/kernel/filesystem/sync.c new file mode 100644 index 00000000..fa50c427 --- /dev/null +++ b/kernel/filesystem/sync.c @@ -0,0 +1,61 @@ +#include "sync.h" +#define MOG_MODULE "FSSYNC" +#define MOG_LEVEL MOG_ERROR +#include "utils/mog.h" +#include "syscalls/syscalls.h" +#include "data/struct/linked_list.h" + +hash_map_t *synced_files; + +void sync_fd(file *ifd, open_file_descriptors *ofile, bool replace){ + if (ifd->sync_type == cursor_sync_none) return; + if (!synced_files) synced_files = hash_map_create(64); + + if (ifd->sync_type == cursor_sync_head){ + mog(VERBOSE,"File %lli moved to head",ifd->id); + ifd->cursor = 0; + return; + } + if (ifd->sync_type == cursor_sync_tail){ + mog(VERBOSE,"File %lli moved to tail",ifd->id); + ifd->cursor = ofile->file_size; + return; + } + + hash_map_t *cursors = hash_map_get(synced_files, &ofile->resource_id, sizeof(resource)); + if (!cursors){ + cursors = hash_map_create(16); + hash_map_put(synced_files, &ofile->resource_id, sizeof(resource), cursors); + } + + u64 loc = 0; + if (hash_map_has_key(cursors, &ifd->id, sizeof(u64), (void**)&loc)){ + mog(VERBOSE,"Syncing cursor for %lli from %lli to %lli",ifd->id,ifd->cursor,loc); + if (replace){ + hash_map_remove(cursors, &ifd->id, sizeof(u64), 0); + hash_map_put(cursors, &ifd->id, sizeof(u64), (void*)ifd->cursor); + } else { + ifd->cursor = loc; + } + } else { + hash_map_put(cursors, &ifd->id, sizeof(u64), (void*)ifd->cursor); + } + + ofile->last_sync = get_time(); +} + +void report_fd_mod(file *ifd, open_file_descriptors *ofile, u64 time, range_t range){ + if (!synced_files) return; + hash_map_t *cursors = hash_map_get(synced_files, &ofile->resource_id, sizeof(resource)); + if (!cursors) return; + for (uint64_t i = 0; i < cursors->capacity; i++){ + hash_map_entry_t* e = cursors->buckets[i]; + while(e){ + hash_map_entry_t* next = e->next; + u64 loc = (u64)e->value; + if (ifd->id != (u64)e->key && range.start <= loc) loc += range.size; + e->value = (void*)loc; + e = next; + } + } +} \ No newline at end of file diff --git a/kernel/filesystem/sync.h b/kernel/filesystem/sync.h new file mode 100644 index 00000000..cf7d9a53 --- /dev/null +++ b/kernel/filesystem/sync.h @@ -0,0 +1,7 @@ +#pragma once + +#include "filesystem.h" + +void sync_fd(file *ifd, open_file_descriptors *ofile, bool replace); + +void report_fd_mod(file *ifd, open_file_descriptors *ofile, u64 time, range_t range); \ No newline at end of file diff --git a/kernel/filesystem/virtio_9p_pci.cpp b/kernel/filesystem/virtio_9p_pci.cpp index f13b5718..b726554c 100644 --- a/kernel/filesystem/virtio_9p_pci.cpp +++ b/kernel/filesystem/virtio_9p_pci.cpp @@ -8,7 +8,7 @@ #include "std/memory.h" #include "std/memory_access.h" #include "p9_helper.h" -#include "filesystem/modules/module_loader.h" +#include "modules/fs_isolation.h" #define VIRTIO_9P_ID 0x1009 @@ -62,7 +62,7 @@ FS_RESULT Virtio9PDriver::open_file(const char* path, file* descriptor){ module_file *cached = (module_file*)hash_map_get(open_files, &fid, sizeof(uint64_t)); if (cached) { cached->references++; - descriptor->size = cached->file_size; + descriptor->size = cached->file_buffer.buffer_size; irq_restore(irq); return FS_RESULT_SUCCESS; } @@ -120,8 +120,6 @@ FS_RESULT Virtio9PDriver::open_file(const char* path, file* descriptor){ if (mfile->serial != INVALID_FID) clunk(&np_dev, (uint32_t)mfile->serial); if (mfile->file_buffer.buffer) kfree(mfile->file_buffer.buffer, mfile->file_buffer.buffer_size ? mfile->file_buffer.buffer_size : 1); } - mfile->file_size = size; - mfile->buf = (uptr)file; mfile->file_buffer = (buffer){ .buffer = file, .buffer_size = size, @@ -130,7 +128,6 @@ FS_RESULT Virtio9PDriver::open_file(const char* path, file* descriptor){ .cursor = 0, .data_type = 0, }; - mfile->ignore_cursor = false; mfile->fid = descriptor->id; mfile->serial = f; mfile->references++; @@ -143,19 +140,19 @@ size_t Virtio9PDriver::read_file(file *descriptor, void* buf, size_t size){ module_file *mfile = (module_file*)hash_map_get(open_files, &descriptor->id, sizeof(uint64_t)); irq_restore(irq); if (!mfile) return 0; - if (!sync_file(mfile) && !mfile->file_buffer.buffer && mfile->file_size) return 0; - if (descriptor->cursor > mfile->file_size) return 0; - if (size > mfile->file_size-descriptor->cursor) size = mfile->file_size-descriptor->cursor; + if (!sync_file(mfile) && !mfile->file_buffer.buffer && mfile->file_buffer.buffer_size) return 0; + if (descriptor->cursor > mfile->file_buffer.buffer_size) return 0; + if (size > mfile->file_buffer.buffer_size-descriptor->cursor) size = mfile->file_buffer.buffer_size-descriptor->cursor; memcpy(buf, (char*)mfile->file_buffer.buffer + descriptor->cursor, size); descriptor->cursor += size; - descriptor->size = mfile->file_size; + descriptor->size = mfile->file_buffer.buffer_size; return size; } size_t Virtio9PDriver::write_file(file *descriptor, const char* buf, size_t size){ module_file *mfile = (module_file*)hash_map_get(open_files, &descriptor->id, sizeof(uint64_t)); if (!mfile) return 0; - if (mfile->read_only) return 0; + if (mfile->file_buffer.options & buffer_read_only) return 0; size_t start = descriptor->cursor; size_t written = write((u32)mfile->serial, start, size, buf); @@ -165,21 +162,20 @@ size_t Virtio9PDriver::write_file(file *descriptor, const char* buf, size_t size if (end > mfile->file_buffer.buffer_size) { void *new_buf = kalloc(np_dev.memory_page, end ? end : 1, ALIGN_64B, MEM_PRIV_KERNEL); if (new_buf) { - if (mfile->file_buffer.buffer && mfile->file_size) memcpy(new_buf, mfile->file_buffer.buffer, mfile->file_size); + if (mfile->file_buffer.buffer && mfile->file_buffer.buffer_size) memcpy(new_buf, mfile->file_buffer.buffer, mfile->file_buffer.buffer_size); if (mfile->file_buffer.buffer) kfree(mfile->file_buffer.buffer, mfile->file_buffer.buffer_size ? mfile->file_buffer.buffer_size : 1); mfile->file_buffer.buffer = new_buf; mfile->file_buffer.buffer_size = end; - mfile->buf = (uptr)new_buf; } } - if (end > mfile->file_size) mfile->file_size = end; - mfile->file_buffer.limit = mfile->file_size; + if (end > mfile->file_buffer.buffer_size) mfile->file_buffer.buffer_size = end; + mfile->file_buffer.limit = mfile->file_buffer.buffer_size; if (mfile->file_buffer.buffer && start + written <= mfile->file_buffer.buffer_size) memcpy((char*)mfile->file_buffer.buffer + start, buf, written); - descriptor->size = mfile->file_size; + descriptor->size = mfile->file_buffer.buffer_size; return written; } @@ -227,10 +223,10 @@ size_t Virtio9PDriver::list_contents(const char *path, void* buf, size_t size, u bool Virtio9PDriver::truncate(file *descriptor){ module_file *mfile = (module_file*)hash_map_get(open_files, &descriptor->id, sizeof(uint64_t)); if (!mfile) return false; - if (mfile->read_only) return false; + if (mfile->file_buffer.options & buffer_read_only) return false; if (!set_attribute((u32)mfile->serial, P9_SETATTR_SIZE, descriptor->size)) return false; if (!sync_file(mfile)) return false; - descriptor->size = mfile->file_size; + descriptor->size = mfile->file_buffer.buffer_size; if (descriptor->cursor > descriptor->size) descriptor->cursor = descriptor->size; return true; } @@ -520,8 +516,6 @@ bool Virtio9PDriver::sync_file(module_file *mfile){ mfile->file_buffer.buffer = 0; mfile->file_buffer.buffer_size = 0; mfile->file_buffer.limit = 0; - mfile->buf = 0; - mfile->file_size = 0; return true; } @@ -545,8 +539,7 @@ bool Virtio9PDriver::sync_file(module_file *mfile){ } mfile->file_buffer.limit = new_size; - mfile->buf = (uptr)mfile->file_buffer.buffer; - mfile->file_size = new_size; + mfile->file_buffer.buffer_size = new_size; return true; } @@ -606,6 +599,8 @@ system_module p9_fs_module = (system_module){ .truncate = shared_truncate, .getstat = shared_stat, .readdir = shared_readdir, + .transform = 0, + //.permissions = fs_permission_shared, .alias_info = {} }; diff --git a/kernel/graph/graphics.h b/kernel/graph/graphics.h index 7143c6c3..c2e0893f 100644 --- a/kernel/graph/graphics.h +++ b/kernel/graph/graphics.h @@ -7,7 +7,7 @@ extern "C" { #include "types.h" #include "graphic_types.h" #include "std/string.h" -#include "ui/draw/draw.h" +#include "draw/draw.h" #include "files/system_module.h" bool gpu_ready(); diff --git a/kernel/graph/tres.c b/kernel/graph/tres.c index f5913f91..7e05b7ca 100644 --- a/kernel/graph/tres.c +++ b/kernel/graph/tres.c @@ -55,15 +55,22 @@ gpu_point win_to_screen(window_frame *frame, gpu_point point){ extern process_t *win_system_proc; -gpu_point convert_mouse_position(gpu_point point){ +bool convert_mouse_position(mouse_data *in){ process_t *p = get_current_proc(); - if (p == win_system_proc) return point; + if (p == win_system_proc) return true; linked_list_node_t *node = linked_list_find(window_list, PHYS_TO_VIRT_P(&p->win_id), PHYS_TO_VIRT_P(find_window)); if (node && node->data){ window_frame* frame = (window_frame*)node->data; - return win_to_screen(frame, point); + gpu_rect rect = {{frame->x, frame->y + MENU_HEIGHT}, {frame->width, frame->height - MENU_HEIGHT}}; + if (mouse_in_rect(rect, in->position)){ + in->position.x -= frame->x; + in->position.y -= frame->y; + return true; + } } - return (gpu_point){}; + in->raw = (mouse_input){}; + in->position = (gpu_point){}; + return false; } i32 calculate_distance(i32 ep, i32 es, i32 np, i32 ns, i32 existing){ @@ -84,7 +91,6 @@ i32 calculate_distance(i32 ep, i32 es, i32 np, i32 ns, i32 existing){ } int_point window_frame_intersect(window_frame *new_frame, window_frame *existing_frame, int_point existing_move){ - i32 horizontal = calculate_distance(existing_frame->x, existing_frame->width, new_frame->x, new_frame->width,existing_move.x); i32 vertical = calculate_distance(existing_frame->y, existing_frame->height, new_frame->y, new_frame->height,existing_move.y); return (int_point){ abs(horizontal) < abs(vertical) ? horizontal : 0, abs(horizontal) < abs(vertical) ? 0 : vertical }; @@ -113,20 +119,21 @@ void check_collisions(window_frame *frame){ } } -bool create_window(i32 x, i32 y, u32 width, u32 height){ +window_frame* create_window_prog(i32 x, i32 y, u32 width, u32 height, char *prog, int argc, const char** argv){ height -= TOOLBAR_HEIGHT; irq_flags_t irq = irq_save_disable(); if (win_ids == UINT16_MAX){ irq_restore(irq); - return false; + return 0; } if (zoom_scale != 1){ irq_restore(irq); - return false; + return 0; } - if (width < 0x100 || height < 0x100){ + + if (!prog){ irq_restore(irq); - return false; + return 0; } window_frame *frame = (window_frame*)zalloc(sizeof(window_frame)); @@ -148,10 +155,10 @@ bool create_window(i32 x, i32 y, u32 width, u32 height){ linked_list_push_front(window_list, PHYS_TO_VIRT_P(frame)); gpu_create_window(x,y, width, height, &frame->win_ctx); - process_t *p = execute("/boot/redos/system/launcher.red", 0, 0, 0); + process_t *p = execute(prog, argc, argv, 0); if (!p){ irq_restore(irq); - return false; + return 0; } p->win_id = frame->win_id; frame->pid = p->id; @@ -159,7 +166,13 @@ bool create_window(i32 x, i32 y, u32 width, u32 height){ dirty_windows = true; irq_restore(irq); - return true; + return frame; +} + +window_frame* create_window(i32 x, i32 y, u32 width, u32 height){ + if (width < 0x100 || height < 0x100) return 0; + + return create_window_prog(x, y, width, height, "/boot/redos/system/launcher.red", 0, 0); } void resize_window_proc(process_t *proc, u32 width, u32 height){ @@ -328,6 +341,7 @@ u16 window_fallback_focus(u16 win_id, u16 skip_id){ } release(node->data); + ((window_frame*)node->data)->win_id = 0; linked_list_remove(window_list, node); dirty_windows = true; return 0; diff --git a/kernel/graph/tres.h b/kernel/graph/tres.h index e1c37088..6d3528ee 100644 --- a/kernel/graph/tres.h +++ b/kernel/graph/tres.h @@ -1,7 +1,7 @@ #pragma once #include "types.h" -#include "ui/draw/draw.h" +#include "draw/draw.h" #include "data/struct/linked_list.h" #include "process/process.h" @@ -9,13 +9,15 @@ extern "C" { #endif -typedef struct { +typedef struct window_frame { uint16_t win_id; int32_t x, y; uint32_t width, height; draw_ctx win_ctx; uint16_t pid; window_info_t info; + struct window_frame *aux; + bool is_aux; } window_frame; #define MENU_HEIGHT 50 @@ -24,7 +26,8 @@ typedef struct { void init_window_manager(); -bool create_window(int32_t x, int32_t y, uint32_t width, uint32_t height); +window_frame* create_window(int32_t x, int32_t y, uint32_t width, uint32_t height); +window_frame* create_window_prog(i32 x, i32 y, u32 width, u32 height, char *prog, int argc, const char** argv); gpu_point win_to_screen(window_frame *frame, gpu_point point); @@ -41,7 +44,13 @@ void set_window_focus(uint16_t win_id); void unset_window_focus(); void window_close_process(process_t *proc); -gpu_point convert_mouse_position(gpu_point p); +bool convert_mouse_position(mouse_data *in); + +static inline bool mouse_in_rect(gpu_rect rect, gpu_point click){ + if (click.x < rect.point.x || click.x >= rect.point.x + (i32)rect.size.width || + click.y < rect.point.y || click.y >= rect.point.y + (i32)rect.size.height) return false; + return true; +} extern linked_list_t *window_list; diff --git a/kernel/input/input_dispatch.c b/kernel/input/input_dispatch.c index a851d305..fd1c1795 100644 --- a/kernel/input/input_dispatch.c +++ b/kernel/input/input_dispatch.c @@ -125,6 +125,10 @@ mouse_input get_raw_mouse_in(){ return last_mouse_in; } +void render_cursor(){ + gpu_update_cursor(mouse_loc, false); +} + void register_mouse_input(mouse_input *rat){ last_mouse_in = *rat; if (!mouse_setup) return; @@ -134,13 +138,11 @@ void register_mouse_input(mouse_input *rat){ mouse_loc.y += dy; mouse_loc.x = min(max(0, mouse_loc.x), screen_bounds.width); mouse_loc.y = min(max(0, mouse_loc.y), screen_bounds.height); - gpu_update_cursor(mouse_loc, false); register_scroll(rat->scroll); uint8_t cursor_state = rat->buttons; if (cursor_state != last_cursor_state){ last_cursor_state = cursor_state; gpu_set_cursor_pressed(last_cursor_state); - gpu_update_cursor(mouse_loc, true); } } @@ -177,10 +179,10 @@ void sys_focus_current(){ #include "console/kio.h" #include "theme/theme.h" -void sys_set_focus(int pid){ +bool sys_set_focus(int pid){ process_t *target = get_proc_by_pid(pid); - if (!target || target->state == STOPPED || !target->id || !target->main_thread.pc || !target->main_thread.sp || (!is_privileged(target) && !target->mm.ttbr0)) return; - if (focused_proc && focused_proc->id == pid) return; + if (!target || target->state == STOPPED || !target->id || !target->main_thread.pc || !target->main_thread.sp || (!is_privileged(target) && !target->mm.ttbr0)) return false; + if (focused_proc && focused_proc->id == pid) return false; if (focused_proc) focused_proc->focused = false; focused_proc = target; focused_proc->focused = true; @@ -188,6 +190,7 @@ void sys_set_focus(int pid){ set_window_focus(focused_proc->win_id); refresh_menu(); } + return true; } void sys_unset_focus(bool close){ diff --git a/kernel/input/input_dispatch.h b/kernel/input/input_dispatch.h index 47fd04cf..00fe1149 100644 --- a/kernel/input/input_dispatch.h +++ b/kernel/input/input_dispatch.h @@ -16,13 +16,15 @@ void register_mouse_input(mouse_input *rat); mouse_input get_raw_mouse_in(); +void render_cursor(); + gpu_point get_mouse_pos(); bool mouse_button_pressed(int mb); bool mouse_any_button_pressed(); uint16_t sys_subscribe_shortcut(uint16_t pid, keypress kp); uint16_t sys_subscribe_shortcut_current(keypress kp); -void sys_set_focus(int pid); +bool sys_set_focus(int pid); void sys_focus_current(); void sys_unset_focus(bool close); u16 sys_get_focused_pid(); diff --git a/kernel/kernel.c b/kernel/kernel.c index 7aaa7ab1..0494740b 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -15,7 +15,7 @@ #include "memory/page_allocator.h" #include "networking/network.h" #include "filesystem/filesystem.h" -#include "filesystem/modules/module_loader.h" +#include "filesystem/modules/fs_isolation.h" #include "audio/audio.h" #include "mailbox/mailbox.h" #include "math/vector.h" @@ -92,7 +92,7 @@ void kernel_main(uint64_t board_type, uint64_t dtb_pa) { kprint("Kernel initialization finished"); - reserve_mount_point(kernel_fs(), "menu"); + reserve_mount_point(kernel_fs(), "menu", get_kernel_proc()->id); kprint("Starting processes"); diff --git a/kernel/kernel_processes/boot/bootprocess.c b/kernel/kernel_processes/boot/bootprocess.c index bbb36c9c..93ca381e 100644 --- a/kernel/kernel_processes/boot/bootprocess.c +++ b/kernel/kernel_processes/boot/bootprocess.c @@ -6,16 +6,18 @@ #include "input/input_dispatch.h" #include "usb/usb.h" #include "graph/graphics.h" -#include "exceptions/exception_handler.h" #include "kernel_processes/boot/screensaver.h" #include "kernel_processes/boot/login_screen.h" #include "kernel_processes/windows/dos.h" #include "tools/tools.h" +#include "files/helpers.h" +#include "process/scheduler.h" enum { bsm_none, bsm_screensaver, bsm_login, + bsm_services, bsm_userland } boot_state; @@ -27,16 +29,32 @@ void visual_init(){ mouse_config((gpu_point){(i32)screen_size.width/2,(i32)screen_size.height/2}, screen_size); } +void load_service(const char *directory, const char *service){ + if (strlen(service) && *service == '.') return; + string full_name = string_format("%s/%s",directory,service); + process_t *proc = execute(full_name.data, 0, 0, EXEC_MODE_KEEP_FOCUS); + proc->priority = PROC_PRIORITY_LOW; + string_free(full_name); + if (!proc) print("[BOOT error] failed to load service %s",service); +} + void bootsm_transition(int new_state){ boot_state = new_state; switch (boot_state) { case bsm_none: break; case bsm_screensaver: current_proc = start_screensaver(); break; case bsm_login: current_proc = present_login(); break; + case bsm_services: { + traverse_directory("/boot/redos/services", false, load_service); + current_proc = 0; + break; + } case bsm_userland: { - if (system_config.headless || !system_config.use_windows){ + if (system_config.headless){ const char *argv = system_config.headless ? "headless" : ""; current_proc = execute("/boot/redos/system/terminal.red", 1, &argv, EXEC_MODE_DEFAULT); + } else if (!system_config.use_windows){ + current_proc = execute("/boot/redos/system/launcher.red", 0, 0, EXEC_MODE_DEFAULT); } else current_proc = create_windowing_system(); @@ -55,9 +73,10 @@ void bootsm_advance(){ bootsm_transition(bsm_screensaver); break; } - bootsm_transition(bsm_userland); break; - case bsm_screensaver: bootsm_transition(bsm_userland); break; - case bsm_login: bootsm_transition(system_config.headless ? bsm_userland : bsm_screensaver); break; + bootsm_transition(bsm_services); break; + case bsm_screensaver: bootsm_transition(bsm_services); break; + case bsm_login: bootsm_transition(system_config.headless ? bsm_services : bsm_screensaver); break; + case bsm_services: bootsm_transition(bsm_userland); break; case bsm_userland: bootsm_transition(bsm_none); break; } } diff --git a/kernel/kernel_processes/boot/login_screen.c b/kernel/kernel_processes/boot/login_screen.c index be8714c0..d9371d85 100644 --- a/kernel/kernel_processes/boot/login_screen.c +++ b/kernel/kernel_processes/boot/login_screen.c @@ -16,7 +16,7 @@ int login_screen(){ char* buf = (char*)zalloc(256); int len = 0; keypress old_kp; - gpu_clear(system_theme.bg_color); + gpu_clear(system_theme.palette.background); while (1) { gpu_size screen_size = gpu_get_screen_size(); @@ -63,7 +63,7 @@ int login_screen(){ .size = { screen_size.width/3, height }, .horizontal_align = Leading, .vertical_align = VerticalCenter, - .background_color = system_theme.bg_color+0x111111, + .background_color = system_theme.palette.background+0x111111, .foreground_color = COLOR_WHITE, }); diff --git a/kernel/kernel_processes/boot/screensaver.c b/kernel/kernel_processes/boot/screensaver.c index 10ec5654..62c9ff4c 100644 --- a/kernel/kernel_processes/boot/screensaver.c +++ b/kernel/kernel_processes/boot/screensaver.c @@ -26,7 +26,7 @@ void boot_draw_name(gpu_size screen_size, int xoffset, int yoffset){ .size = { screen_size.width, (screen_size.height/2) - yoffset}, .horizontal_align = HorizontalCenter, .vertical_align = Top, - .background_color = system_theme.bg_color, + .background_color = system_theme.palette.background, .foreground_color = COLOR_WHITE, }); } @@ -129,7 +129,7 @@ int screensaver(){ time = (float)get_time(); while (1) { - gpu_clear(system_theme.bg_color); + gpu_clear(system_theme.palette.background); gpu_point screen_middle = {screen_size.width/2,screen_size.height/2}; gpu_point current_point = boot_calc_point(boot_theme.logo_points[boot_theme.logo_points_count-1],screen_size,screen_middle); diff --git a/kernel/kernel_processes/kprocess_loader.c b/kernel/kernel_processes/kprocess_loader.c index 3d01e78e..b51c7f31 100644 --- a/kernel/kernel_processes/kprocess_loader.c +++ b/kernel/kernel_processes/kprocess_loader.c @@ -10,7 +10,7 @@ #include "process/isolated_fs/isolated_fs.h" void kernel_thread_return_trampoline(int32_t exit_code){ - switch_proc(YIELD);//TODO: proper cleanup + switch_proc(YIELD); while (true){} } diff --git a/kernel/kernel_processes/windows/dos.c b/kernel/kernel_processes/windows/dos.c index 6f02633f..4b62a4d1 100644 --- a/kernel/kernel_processes/windows/dos.c +++ b/kernel/kernel_processes/windows/dos.c @@ -33,9 +33,16 @@ static draw_ctx *dos_ctx; extern float zoom_scale; -static void draw_solid_window(window_frame *frame, draw_ctx *ctx, int_point fixed_point, gpu_size fixed_size, bool fill, bool use_shadows, bool focused){ - int_point win_point = {fixed_point.x + BORDER_SIZE, fixed_point.y + BORDER_SIZE + TOOLBAR_HEIGHT}; - gpu_size win_size = {fixed_size.width - (BORDER_SIZE*2), fixed_size.height - TOOLBAR_HEIGHT - (BORDER_SIZE*2)}; +static void draw_window(window_frame *frame){ + int_point fixed_point = { global_win_offset.x + frame->x - BORDER_SIZE, global_win_offset.y + frame->y + (frame->is_aux ? TOOLBAR_HEIGHT-BORDER_SIZE : -BORDER_SIZE) }; + gpu_size fixed_size = { frame->width + BORDER_SIZE*2, frame->height + BORDER_SIZE*2 + (frame->is_aux ? 0 : TOOLBAR_HEIGHT) }; + fixed_point.x /= zoom_scale; + fixed_point.y /= zoom_scale; + fixed_size.width /= zoom_scale; + fixed_size.height /= zoom_scale; + bool use_shadows = system_theme.use_window_shadows; + bool focused = focused_window == frame; + gpu_size win_size = {fixed_size.width - (BORDER_SIZE*2), fixed_size.height - (frame->is_aux ? 0 : TOOLBAR_HEIGHT) - (BORDER_SIZE*2)}; if (use_shadows && focused) rectangle(dos_ctx, (rect_ui_config){ @@ -43,64 +50,64 @@ static void draw_solid_window(window_frame *frame, draw_ctx *ctx, int_point fixe .border_color = 0x44000000, }, (common_ui_config){ .point = (int_point){(uint32_t)fixed_point.x,(uint32_t)fixed_point.y}, .size = {fixed_size.width+BORDER_SIZE*1.5,fixed_size.height+BORDER_SIZE*1.5}, }); - DRAW(rectangle(ctx, (rect_ui_config){ + DRAW(rectangle(dos_ctx, (rect_ui_config){ .border_size = BORDER_SIZE, - .border_color = saturate(system_theme.bg_color + 0x222222, focused ? 0 : -90), + .border_color = saturate_color(system_theme.palette.background + 0x222222, focused ? 0 : -90), }, (common_ui_config){ .point = fixed_point, .size = fixed_size, - .background_color = saturate(system_theme.bg_color + 0x111111, focused ? 0 : -90), + .background_color = saturate_color(system_theme.palette.background + 0x111111, focused ? 0 : -90), .foreground_color = COLOR_WHITE, }), { - label(ctx, (text_ui_config){ - .slice = { frame->info.name, frame->info.name_length}, - .font_size = 3, - }, (common_ui_config){ - .point = RELATIVE(5, BORDER_SIZE+5), - .size = { parent.size.width-200, 30 }, - .foreground_color = system_theme.accent_color, - }); - bool close_pressed = false; - button(ctx, (rect_ui_config){}, (common_ui_config){ - .point = RELATIVE(parent.size.width - (BORDER_SIZE * 2) - 40 - BORDER_SIZE,BORDER_SIZE), - .size = {30, 30}, - .background_color = 0xFFB40000, - }, &close_pressed); - if (close_pressed){ - send_signal(SIG_QUIT, frame->pid); + if (!frame->is_aux){ + label(dos_ctx, (text_ui_config){ + .slice = { frame->info.name, frame->info.name_length}, + .font_size = 3, + }, (common_ui_config){ + .point = RELATIVE(5, BORDER_SIZE+5), + .size = { parent.size.width-200, 30 }, + .foreground_color = system_theme.palette.accent, + }); + bool close_pressed = false; + button(dos_ctx, (rect_ui_config){}, (common_ui_config){ + .point = RELATIVE(parent.size.width - (BORDER_SIZE * 2) - 40 - BORDER_SIZE,BORDER_SIZE), + .size = {30, 30}, + .background_color = 0xFFB40000, + }, &close_pressed); + if (close_pressed){ + send_signal(SIG_QUIT, frame->pid); + } +#ifdef FEATURE_DEBUGGING + bool aux_pressed = false; + button(dos_ctx, (rect_ui_config){}, (common_ui_config){ + .point = RELATIVE(parent.size.width - (BORDER_SIZE * 2) - 80 - BORDER_SIZE,BORDER_SIZE), + .size = {30, 30}, + .background_color = 0xFF40b0bc, + }, &aux_pressed); + if (aux_pressed){ + if (!frame->aux || !frame->aux->win_id){ + new_aux_window(frame); + print("New aux window with debugger and with this proc id, %x",frame->aux); + } + } +#endif + rectangle(dos_ctx, (rect_ui_config){}, (common_ui_config){ + .point = {fixed_point.x + BORDER_SIZE, fixed_point.y + (frame->is_aux ? 0 : TOOLBAR_HEIGHT)}, + .size = {win_size.width - (BORDER_SIZE), BORDER_SIZE}, + .background_color = 0x33000000, + }); } - rectangle(ctx, (rect_ui_config){}, (common_ui_config){ - .point = {fixed_point.x + BORDER_SIZE, fixed_point.y + TOOLBAR_HEIGHT}, - .size = {win_size.width - (BORDER_SIZE), BORDER_SIZE}, - .background_color = 0x33000000, - }); - rectangle(ctx, (rect_ui_config){}, (common_ui_config){ - .point = win_point, - .size = win_size, - .background_color = 0, - .foreground_color = COLOR_WHITE, - }); }); } -void draw_window(window_frame *frame){ - int_point fixed_point = { global_win_offset.x + frame->x - BORDER_SIZE, global_win_offset.y + frame->y - BORDER_SIZE }; - gpu_size fixed_size = { frame->width + BORDER_SIZE*2, frame->height + BORDER_SIZE*2 + TOOLBAR_HEIGHT }; - fixed_point.x /= zoom_scale; - fixed_point.y /= zoom_scale; - fixed_size.width /= zoom_scale; - fixed_size.height /= zoom_scale; - draw_solid_window(frame, dos_ctx, (int_point){(uint32_t)fixed_point.x,(uint32_t)fixed_point.y}, fixed_size, !frame->pid, system_theme.use_window_shadows, focused_window == frame); -} - gpu_point click_loc; window_frame* clicked_frame; static inline void calc_click(void *node){ window_frame* frame = (window_frame*)node; - gpu_point p = win_to_screen(frame, click_loc);//TODO: account for zoom - if (!p.x || !p.y) return; - clicked_frame = frame; + gpu_rect rect = {{global_win_offset.x + frame->x, global_win_offset.y + frame->y}, {frame->width, frame->height}}; + if (mouse_in_rect(rect, click_loc)) + clicked_frame = frame; } static inline void redraw_win(void *node){ @@ -161,12 +168,12 @@ void setup_desktop_bg(){ rescale_image(info.width, info.height, img_info.width, img_info.height, oimg, img); release(oimg); } - system_theme.bg_color = calc_average(img, img_info.width * img_info.height); - system_theme.accent_color = text_color_for_base(system_theme.bg_color); + system_theme.palette.background = calc_average(img, img_info.width * img_info.height); + system_theme.palette.accent = text_color_for_base(system_theme.palette.background); release(imgf); closef(&fd); } else { - fb_fill_rect(&img_draw_ctx, 0, 0, img_draw_ctx.width, img_draw_ctx.height, system_theme.bg_color); + fb_fill_rect(&img_draw_ctx, 0, 0, img_draw_ctx.width, img_draw_ctx.height, system_theme.palette.background); } } @@ -207,6 +214,11 @@ void setup_shortcuts(){ }); } +int window_mode_cursors[] = { + [window_mode] = cursor_crosshair, + [doodle_mode] = cursor_pencil +}; + void check_shortcuts(){ if (sys_shortcut_triggered_current(sid_g)){ global_win_offset = (int_point){0,0}; @@ -234,11 +246,7 @@ void check_shortcuts(){ for (int i = 0; i < mode_count; i++) if (sys_shortcut_triggered_current(mode_shortcuts[i])){ mode = i; - switch (mode) { - case window_mode: switch_cursor(cursor_crosshair); break; - case doodle_mode: switch_cursor(cursor_pencil); break; - default: break; - } + switch_cursor(window_mode_cursors[mode]); } } @@ -248,6 +256,13 @@ void refresh_desktop_colors(){ dirty_windows = true; } +static inline window_frame* get_current_mouse_window(gpu_point loc){ + click_loc = loc; + clicked_frame = 0; + linked_list_for_each(window_list, calc_click); + return clicked_frame; +} + int window_system(){ disable_visual(); dos_ctx = gpu_get_ctx(); @@ -259,6 +274,8 @@ int window_system(){ bool drawing = false; bool dragging = false; + int redraw_repeat = 0; + while (1){ bool active = false; check_shortcuts(); @@ -299,17 +316,16 @@ int window_system(){ case window_mode: { gpu_point end_point = get_mouse_pos(); gpu_size size = {abs(end_point.x - start_point.x), abs(end_point.y - start_point.y)}; - click_loc = start_point; - clicked_frame = 0; - linked_list_for_each(window_list, calc_click); - window_frame *ini_wf = clicked_frame; - click_loc = end_point; - clicked_frame = 0; - linked_list_for_each(window_list, calc_click); + window_frame *ini_wf = get_current_mouse_window(start_point); + window_frame *curr_win = get_current_mouse_window(end_point); if (size.width < 0x10 && size.height < 0x10){ //Small movements are counted as clicks - if (clicked_frame && focused_window != clicked_frame) sys_set_focus(clicked_frame->pid); - } else if (!linked_list_count(window_list) || ((clicked_frame != ini_wf || !clicked_frame) && clicked_frame != focused_window && ini_wf != focused_window)){ + if (curr_win && focused_window != curr_win) sys_set_focus(curr_win->pid); + } else if ( + !linked_list_count(window_list) || + !curr_win || + (curr_win != ini_wf && curr_win != focused_window && ini_wf != focused_window) + ){ //Others create a window unless they happen fully within a window or intersect with the focused window, as we consider those to happen inside the window itself int_point fixed_point = { min(end_point.x,start_point.x),min(end_point.y,start_point.y) }; disable_interrupt(); @@ -323,10 +339,7 @@ int window_system(){ if (system_theme.use_desktop_zoom){ i8 scroll = get_raw_mouse_in().scroll; if (scroll){ - click_loc = get_mouse_pos(); - clicked_frame = 0; - linked_list_for_each(window_list, calc_click); - if (!clicked_frame){ + if (!get_current_mouse_window(get_mouse_pos())){ zoom_scale += -scroll; zoom_scale = clampf(zoom_scale, 0.25f, 5); dirty_windows = true; @@ -334,14 +347,34 @@ int window_system(){ } } disable_interrupt(); - if (mouse_any_button_pressed()) dirty_windows = true; + gpu_point curr_mouse = get_mouse_pos(); + //TODO: move the window mouse position & button translation here so we can simplify that logic + bool in_menu = draw_menu(curr_mouse); + window_frame *curr_frame = get_current_mouse_window(curr_mouse); + if (curr_frame || in_menu){ + if (mouse_any_button_pressed() && curr_frame && curr_mouse.y-curr_frame->y <= MENU_HEIGHT) dirty_windows = true; + if (switch_cursor(cursor_pointer)){ + dirty_windows = true; + redraw_repeat = 5; + } + } else { + if (switch_cursor(window_mode_cursors[mode])){ + dirty_windows = true; + redraw_repeat = 5; + } + } if (dirty_windows){ active = true; draw_desktop(); + draw_menu(curr_mouse); linked_list_for_each(window_list, redraw_win); dirty_windows = false; } - draw_menu(); + if (redraw_repeat){ + redraw_repeat--; + gpu_get_ctx()->full_redraw = true; + } + render_cursor(); gpu_flush(); enable_interrupt(); if (!active && !dirty_windows && !mouse_button_pressed(LMB) && !mouse_button_pressed(MMB)) msleep(25); diff --git a/kernel/kernel_processes/windows/menu.c b/kernel/kernel_processes/windows/menu.c index 2e406121..4e7c781c 100644 --- a/kernel/kernel_processes/windows/menu.c +++ b/kernel/kernel_processes/windows/menu.c @@ -8,6 +8,9 @@ #include "input/input_dispatch.h" #include "filesystem/modules/fs_isolation.h" #include "filesystem/filesystem.h" +#include "data/struct/stack.h" +#include "math/math.h" +#include "memory/memory.h" #define draw_eye(x_off, blink, eyelid) fb_fill_rect(ctx, rect.point.x + eye_margin + x_off, rect.point.y + (rect.size.height * 0.1), eye_size.width, eye_size.height, (blink) ? eyelid : 0xFFcccccc);\ fb_fill_rect(ctx, rect.point.x + eye_margin + p.x + x_off, rect.point.y + (rect.size.height * 0.1) + p.y, eye_size.width-pupil_distance.width, eye_size.height-pupil_distance.height, (blink) ? eyelid : 0xFF333333); @@ -38,37 +41,242 @@ void test_widget(draw_ctx *ctx, gpu_rect rect, color bg){ bool menu_dirty = true; void refresh_menu(){ -#if false +#if FEATURE_MENU menu_dirty = true; #endif } -void load_menu(){ +#define MENU_MAX_NAME 64 +#define MENU_MAX_TOOLTIP 256 +#define MENU_MAX_FILEPATH 256 + +typedef struct menu_item_t { + u8 name_len; + char name[MENU_MAX_NAME]; + u8 tooltip_len; + char tooltip[MENU_MAX_TOOLTIP]; + u8 filepath_len; + char filepath[MENU_MAX_TOOLTIP]; + size_t num_children; + bool is_submenu; + module_root *module; + struct menu_item_t *parent; + struct menu_item_t *child; + struct menu_item_t *sibling; +} menu_item_t; + +arr_stack_t *menu_items = 0; + +menu_item_t *first_menu_item = 0, *last_menu_item = 0; + +menu_item_t* menu_add_entry(char *name, menu_item_t *parent){ + menu_item_t *item = stack_new_item(menu_items,menu_item_t); + string_slice sl = slice_from_literal(name); + item->name_len = min(MENU_MAX_NAME,sl.length); + memcpy(item->name, sl.data, item->name_len); + item->parent = parent; + if (last_menu_item){ + if (last_menu_item->parent == parent) last_menu_item->sibling = item; + else if (parent) parent->child = item; + if (parent) parent->num_children++; + } else first_menu_item = item; + last_menu_item = item; + return item; +} + +string menu_create_pathname(menu_item_t *parent){ + string prec = {}; + if (parent && parent->parent){ + prec = menu_create_pathname(parent->parent); + } else prec = string_from_literal("/menu"); + if (parent){ + string new_p = string_format("%S/%v",prec,(string_slice){parent->name,parent->name_len}); + string_free(prec); + prec = new_p; + } + return prec; +} + +void load_menu_level(menu_item_t *parent){ process_t *menu_proc = get_proc_by_pid(sys_get_focused_pid()); if (!menu_proc){ print("[MENU debug] no focused process"); return; } - const char *path = "/menu"; + string path = menu_create_pathname(parent); module_root *localfs = get_fs_for_id(menu_proc->permissions.fs_id); - if (!localfs) return; void *buf = zalloc(0x1000); u64 off = 0; - size_t s = list_directory_contents(localfs, path, buf, 0x1000, &off); - print("Size of read %x",s); + size_t s = list_directory_contents(localfs, path.data, buf, 0x1000, &off); + if (!s) return; + string_list *list = (string_list*)buf; + if (list){ + char* reader = (char*)list->array; + for (uint32_t i = 0; i < list->count; i++){ + char *file = reader; + if (*file){ + menu_item_t *item = menu_add_entry(file,parent); + item->module = localfs; + string_format_buf(item->filepath, MENU_MAX_FILEPATH, "%S/%s",path,file); + fs_stat stat = {}; + get_stat(localfs, item->filepath, &stat); + item->is_submenu = stat.type == entry_directory; + } + while (*reader) reader++; + reader++; + } + } + string_free(path); +} + +void menu_reset(){ + if (!menu_items) menu_items = stack_create(sizeof(menu_item_t), 64); + else stack_reset(menu_items); + + last_menu_item = 0; + first_menu_item = 0; +} + +void load_menu(){ + menu_reset(); + load_menu_level(0); +} - print("There are %i entries",*(u32*)buf); +size_t calc_children(menu_item_t *parent){ + if (!parent) return 0; + size_t acc = parent->num_children; + menu_item_t *child = parent->child; + while (child){ + acc += calc_children(child); + child = child->sibling; + } + return acc; +} + +void unload_menu_children(menu_item_t *parent){ + if (!parent) { + menu_item_t *child = first_menu_item; + size_t num_menu_items = 0; + while (child){ + if (child->parent) break; + num_menu_items++; + child->child = 0; + child->num_children = 0; + child = child->sibling; + } + stack_remove(menu_items,stack_count(menu_items)-num_menu_items); + last_menu_item = stack_get(menu_items,stack_count(menu_items)-1); + return; + } + size_t num_to_delete = calc_children(parent); + stack_remove(menu_items, num_to_delete); + parent->child = 0; + parent->num_children = 0; + last_menu_item = stack_get(menu_items,stack_count(menu_items)-1); +} + +typedef union { + struct { + u8 quit: 1; + u8 clicked: 1; + u8 inside: 1; + }; + u8 info; +} menu_info; + +menu_info draw_submenu(draw_ctx *ctx, gpu_point origin, menu_item_t *parent, bool did_click, gpu_point mouse_click){ + int width = 256; + fb_fill_rect(ctx, origin.x, origin.y, width, parent->num_children*MENU_HEIGHT, system_theme.palette.background+0x181818); + fb_outline_rect(ctx, origin.x, origin.y, width, parent->num_children*MENU_HEIGHT, 2, 0x44000000); + + menu_item_t *menu = parent->child; + + int y = (MENU_HEIGHT-fb_line_height(2))/2; + int y_top = 0; + menu_info info; + while (menu){ + int x = 10; + gpu_rect bounds = {{origin.x,origin.y + y_top },{width,MENU_HEIGHT}}; + bool clicked_inside = mouse_in_rect(bounds, mouse_click); + info.inside |= clicked_inside; + if (did_click && clicked_inside){ + if (menu->is_submenu){ + if (!menu->child) load_menu_level(menu); + else unload_menu_children(menu); + } else if (menu->module){ + transform_file(menu->module, menu->filepath, 0, 0); + info.quit = true; + } + info.clicked = true; + } + if (menu->child){ + draw_submenu(ctx, (gpu_point){ origin.x + width, origin.y + y_top }, menu, did_click, mouse_click); + fb_fill_rect(ctx, origin.x + 3, origin.y + y_top + 3, width - 6, MENU_HEIGHT-6, 0x44000000); + } + fb_draw_slice(ctx, (string_slice){menu->name,menu->name_len}, origin.x + x, origin.y + y, 2, 0xFFcccccc); + if (menu->is_submenu) fb_draw_slice(ctx, SLICE(">"), origin.x + width-fb_get_char_size(2)-10, origin.y + y, 2, 0xFFcccccc); + y += MENU_HEIGHT; + y_top += MENU_HEIGHT; + menu = menu->sibling; + } + return info; } -void draw_menu(){ +bool mouse_can_click = true; + +bool draw_menu(gpu_point mouse_pos){ if (menu_dirty){ load_menu(); menu_dirty = false; } draw_ctx *screen_ctx = gpu_get_ctx(); - fb_fill_rect(screen_ctx, 0, 0, screen_ctx->width, MENU_HEIGHT, system_theme.bg_color+0x111111); + fb_fill_rect(screen_ctx, 0, 0, screen_ctx->width, MENU_HEIGHT, system_theme.palette.background+0x111111); fb_fill_rect(screen_ctx, 0, MENU_HEIGHT-BORDER_SIZE, screen_ctx->width, BORDER_SIZE, 0x44000000); + + menu_item_t *menu = first_menu_item; + + int x = 10; + bool did_click = false, did_click_inside = false; + gpu_point mouse_click = {}; + + bool mouse_in = mouse_pos.y < MENU_HEIGHT; + + if (mouse_button_pressed(LMB)){ + if (mouse_can_click) + did_click = true; + mouse_can_click = false; + } else mouse_can_click = true; + mouse_click = mouse_pos; + while (menu){ + int y = (MENU_HEIGHT-fb_line_height(2))/2; + fb_draw_slice(screen_ctx, (string_slice){menu->name,menu->name_len}, x, y, 2, 0xFFcccccc); + gpu_rect bounds = {{x,y},{(menu->name_len * fb_get_char_size(2)),fb_line_height(2)}}; + if (did_click && mouse_in_rect(bounds, mouse_click)){ + did_click_inside = true; + if (!menu->child){ + unload_menu_children(0); + load_menu_level(menu); + } else unload_menu_children(menu); + } + if (menu->child){ + menu_info info = draw_submenu(screen_ctx, (gpu_point){ x, MENU_HEIGHT-BORDER_SIZE }, menu, did_click, mouse_click); + did_click_inside |= info.clicked; + mouse_in |= info.inside; + if (info.quit) { + unload_menu_children(0); + return mouse_in; + } + } + x += bounds.size.width + 10; + menu = menu->sibling; + } + + if (did_click && !did_click_inside) { + unload_menu_children(0); + } // fb_fill_rect(screen_ctx, screen_ctx->width/2 - 100, 0, screen_ctx->width/2 + 100, MENU_HEIGHT, 0xb4dd13); - test_widget(screen_ctx, (gpu_rect){{screen_ctx->width/2 - 100, 0}, {200, MENU_HEIGHT}},system_theme.bg_color+0x111111); + test_widget(screen_ctx, (gpu_rect){{screen_ctx->width/2 - 100, 0}, {200, MENU_HEIGHT}},system_theme.palette.background+0x111111); + + return mouse_in; } \ No newline at end of file diff --git a/kernel/kernel_processes/windows/menu.h b/kernel/kernel_processes/windows/menu.h index a37d4d19..60c814fd 100644 --- a/kernel/kernel_processes/windows/menu.h +++ b/kernel/kernel_processes/windows/menu.h @@ -1,4 +1,7 @@ #pragma once -void draw_menu(); +#include "types.h" +#include "graphic_types.h" + +bool draw_menu(gpu_point mouse); void refresh_menu(); \ No newline at end of file diff --git a/kernel/kernel_processes/windows/wincomp.c b/kernel/kernel_processes/windows/wincomp.c index 3cb761cf..103f2078 100644 --- a/kernel/kernel_processes/windows/wincomp.c +++ b/kernel/kernel_processes/windows/wincomp.c @@ -12,9 +12,25 @@ void new_managed_window(){ if (!cur) return; create_window(10 - current_win_offset.x, 10 - current_win_offset.y + MENU_HEIGHT, cur->width - 20, cur->height - 20 - MENU_HEIGHT); global_win_offset.x = current_win_offset.x; + global_win_offset.y = current_win_offset.y; current_win_offset.x -= cur->width; } +void new_aux_window(window_frame *main){ + draw_ctx *cur = gpu_get_ctx(); + if (!cur) return; + + string s = string_format("%i",main->pid); + + const char *args[] = { + "debugger.elf", + s.data + }; + main->aux = create_window_prog(main->x, main->y+main->height, main->width, 200, "/boot/redos/system/debugger.red", 2, args); + main->aux->is_aux = true; + string_free(s); +} + void switch_focus(int8_t x, int8_t y){ x = min(max(x,-1),1); y = min(max(y,-1),1); diff --git a/kernel/kernel_processes/windows/wincomp.h b/kernel/kernel_processes/windows/wincomp.h index eec1d25d..fe64d35f 100644 --- a/kernel/kernel_processes/windows/wincomp.h +++ b/kernel/kernel_processes/windows/wincomp.h @@ -1,6 +1,8 @@ #pragma once +#include "graph/tres.h" #include "types.h" void new_managed_window(); +void new_aux_window(window_frame *main); void switch_focus(int8_t x, int8_t y); \ No newline at end of file diff --git a/kernel/memory/mmu.c b/kernel/memory/mmu.c index 27f06933..f797dfa3 100644 --- a/kernel/memory/mmu.c +++ b/kernel/memory/mmu.c @@ -38,8 +38,6 @@ static uintptr_t *kernel_ttbr1; static uint64_t kernel_ttbr0_hw; static bool mmu_verbose; -static inline void mmu_flush_icache(); -static inline void mmu_flush_all(); static uint64_t asid_shift; @@ -296,24 +294,6 @@ void mmu_map_4kb(uint64_t *table, uint64_t va, uint64_t pa, uint64_t attr_index, l3[l3_index] = want; } -static inline void mmu_flush_all() { - asm volatile ( - "dsb ishst\n" // Ensure all memory accesses complete - "tlbi vmalle1is\n" // Invalidate all EL1 TLB entries (Inner Shareable) - "dsb ish\n" // Ensure completion of TLB invalidation - "isb\n" // Synchronize pipeline - ::: "memory" - ); -} - -static inline void mmu_flush_icache() { - asm volatile ( - "ic iallu\n" // Invalidate all instruction caches to PoU - "isb\n" // Ensure completion before continuing - ::: "memory" - ); -} - uintptr_t* mmu_default_ttbr(){ return kernel_ttbr1; } @@ -400,8 +380,6 @@ uint64_t *mmu_alloc(){ return p; } -extern void mmu_start(uint64_t *ttbr1, uint64_t *ttbr0); - uintptr_t heap_end; void mmu_init() { @@ -503,10 +481,7 @@ void mmu_init() { page_alloc_enable_high_va(); kernel_ttbr0_hw = pt_va_to_pa(kernel_ttbr0) & PTE_ADDR_MASK; - uint64_t ttbr1_pa = pt_va_to_pa(kernel_ttbr1) & PTE_ADDR_MASK; - asm volatile("msr ttbr1_el1, %0" :: "r"(ttbr1_pa)); - asm volatile("dsb ish"); - asm volatile("isb"); + mmu_swap_kttbr(0); mmu_swap_ttbr(0); @@ -538,6 +513,12 @@ void mmu_copy(uintptr_t *new_ttbr, uintptr_t *old_ttbr, int level){ } } +bool mmu_replace(uptr *table, uptr va, uptr new_pa){ + mmu_unmap_and_get_pa(table, va, 0); + mmu_map_4kb(table, va, new_pa, MAIR_IDX_NORMAL, MEM_RW | MEM_NORM, MEM_PRIV_KERNEL); + return true; +} + typedef struct { uintptr_t *table; int level; @@ -722,6 +703,44 @@ uintptr_t mmu_translate(uint64_t *root, uintptr_t va, int *status){ return (uintptr_t)((e3 & PTE_ADDR_MASK) | ((uint64_t)va & (GRANULE_4KB - 1))); } +//TODO: let's use this everywhere, to make code more readable +typedef union { + struct { + u64 vb: 1;//Validity descriptor + u64 tb: 1;//Table descriptor + u64 indx: 2;//Index into MAIR + u64 ns: 1; + u64 ap: 2; + u64 sh: 2; + u64 af: 1; + u64 rsvd3: 2; + u64 addr: 36; + u64 rsvd2: 5; + u64 pxn: 1; + u64 uxn: 1; + u64 sw: 4; + u64 rsvd: 5; + }; + u64 entry; +} +mmu_entry_t; + +void mmu_print_entry(mmu_entry_t entry){ + print("========="); + print("MMU entry %llb",entry); + print("UXN: %b",entry.uxn); + print("PXN: %b",entry.pxn); + print("ADDR: %llx",entry.addr); + print("AF: %b",entry.af); + print("SH: %b",entry.sh); + print("AP: %b",entry.ap); + print("NS: %b",entry.ns); + print("INDX: %i",entry.indx); + print("TB: %b",entry.tb); + print("VB: %b",entry.vb); + print("========="); +} + void debug_mmu_address(uint64_t va){ int tr = 0; uintptr_t pa = mmu_translate(0, (uintptr_t)va, &tr); @@ -771,7 +790,7 @@ void debug_mmu_address(uint64_t va){ if ((e2 & 0b11) == PD_BLOCK) { kprintf("Mapped as 2MB memory in L3"); - kprintf("Entry: %b", (uint64_t)e2); + mmu_print_entry((mmu_entry_t){ .entry = e2 }); return; } @@ -786,20 +805,24 @@ void debug_mmu_address(uint64_t va){ kprintf("L4 Table entry missing"); return; } - kprintf("Entry: %b", e3); + mmu_print_entry((mmu_entry_t){.entry = e3}); return; } -void mmu_ttbr0_disable_user() { - // asm volatile("msr ttbr0_el1, %0" :: "r"((uint64_t)kernel_ttbr0_hw)); - // asm volatile("dsb ish\n\tisb" ::: "memory"); - // ttbr0_user_on = false; -} - void mmu_ttbr0_enable_user() { uint64_t hw = kernel_ttbr0_hw; if (pttbr && pttbr != (uintptr_t*)kernel_ttbr0) hw = pttbr_hw; + asm volatile("dsb ish\n\tisb" ::: "memory"); asm volatile("msr ttbr0_el1, %0" :: "r"(hw)); +} + +void mmu_swap_kttbr(uptr *ttbr){ + uptr *current = 0; + asm volatile("mrs %0, ttbr1_el1" :: "r"(current)); + if (ttbr && current == ttbr) return; + uptr ttbr1_pa = pt_va_to_pa(ttbr ?: kernel_ttbr1); + asm volatile("dsb ish\n\tisb" ::: "memory"); + asm volatile("msr ttbr1_el1, %0" :: "r"(ttbr1_pa)); asm volatile("dsb ish\n\tisb" ::: "memory"); } @@ -813,7 +836,6 @@ void mmu_swap_ttbr(mm_struct *mm){ pttbr_asid = 0; pttbr_hw = kernel_ttbr0_hw; } - mmu_ttbr0_disable_user(); } void mmu_flush_asid(uint16_t asid) { diff --git a/kernel/memory/mmu.h b/kernel/memory/mmu.h index 80d150a1..e4e768ed 100644 --- a/kernel/memory/mmu.h +++ b/kernel/memory/mmu.h @@ -45,14 +45,16 @@ void mmu_map_4kb(uint64_t *table, uint64_t va, uint64_t pa, uint64_t attr_index, void mmu_unmap_table(uint64_t *table, uint64_t va, uint64_t pa); void debug_mmu_address(uint64_t va); void mmu_enable_verbose(); +void mmu_swap_kttbr(uptr *ttbr); void mmu_swap_ttbr(mm_struct *mm); -void mmu_ttbr0_disable_user(); void mmu_ttbr0_enable_user(); void mmu_flush_asid(uint16_t asid); void mmu_asid_ensure(mm_struct *mm); void mmu_asid_release(mm_struct *mm); bool mmu_unmap_and_get_pa(uint64_t *table, uint64_t va, uint64_t *pa); bool mmu_set_access_flag(uint64_t *table, uint64_t va); +void mmu_copy(uintptr_t *new_ttbr, uintptr_t *old_ttbr, int level); +bool mmu_replace(uptr *ttbr, uptr va, uptr new_pa); uintptr_t* mmu_default_ttbr(); void mmu_free_ttbr(uintptr_t *ttbr); uintptr_t mmu_translate(uint64_t *root, uintptr_t va, int *status); @@ -63,4 +65,22 @@ void mmu_map_all(paddr_t pa); void mmu_unmap(uint64_t va, uint64_t pa); -void mmu_init_kernel(); \ No newline at end of file +void mmu_init_kernel(); + +static inline void mmu_flush_all() { + asm volatile ( + "dsb ishst\n" // Ensure all memory accesses complete + "tlbi vmalle1is\n" // Invalidate all EL1 TLB entries (Inner Shareable) + "dsb ish\n" // Ensure completion of TLB invalidation + "isb\n" // Synchronize pipeline + ::: "memory" + ); +} + +static inline void mmu_flush_icache() { + asm volatile ( + "ic iallu\n" // Invalidate all instruction caches to PoU + "isb\n" // Ensure completion before continuing + ::: "memory" + ); +} \ No newline at end of file diff --git a/kernel/networking/network.cpp b/kernel/networking/network.cpp index c1b7e87e..3374fa6a 100644 --- a/kernel/networking/network.cpp +++ b/kernel/networking/network.cpp @@ -100,5 +100,7 @@ system_module net_module = (system_module){ .truncate = 0, .getstat = 0, .readdir = 0, + .transform = 0, + //.permissions = fs_permission_shared, .alias_info = {} }; \ No newline at end of file diff --git a/kernel/process/debug.c b/kernel/process/debug.c index bc0ce819..4f384777 100644 --- a/kernel/process/debug.c +++ b/kernel/process/debug.c @@ -3,28 +3,106 @@ #include "loading/elf_file.h" #include "scheduler.h" #include "console/kio.h" +#include "memory/mmu.h" +#include "memory/addr.h" +#include "loading/dwarf.h" +#include "access/authorize.h" +#define MOG_LEVEL MOG_INFO +#define MOG_MODULE "DEBUG_SYM" +#include "utils/mog.h" void debug_load(){ - kprint("[DEBUG] Loading debug information for kernel"); + mog(INFO,"Loading debug information for kernel"); file fd = {}; if (openf("/boot/kernel.elf", &fd) != FS_RESULT_SUCCESS) { - kprintf("[DEBUG] failed to open debug files"); + mog(INFO,"Failed to open debug files"); return; } - kprint("[DEBUG] .elf fopened"); + mog(INFO,".elf fopened"); void *file = zalloc(fd.size); - kprintf("[DEBUG] Malloced %x",fd.size); + mog(INFO,"alloc'd %x",fd.size); readf(&fd, file, fd.size); closef(&fd); - kprintf("[DEBUG] Reading debug info from %x",file); + mog(INFO,"Reading debug info from %x",file); get_elf_debug_info(get_kernel_proc(), file, fd.size); - kprintf("[DEBUG] .debug_line %x .debug_line_str %x", get_kernel_proc()->debug_lines.ptr, get_kernel_proc()->debug_line_str.ptr); + mog(INFO,".debug_line %x .debug_line_str %x", get_kernel_proc()->debug_lines.ptr, get_kernel_proc()->debug_line_str.ptr); } + +bool decode_crash_address_with_info(uint8_t depth, uintptr_t address, sizedptr debug_line, sizedptr debug_line_str){ + if (!debug_line.ptr || !debug_line.size) return false; + debug_line_info info = dwarf_decode_lines(debug_line.ptr, debug_line.size, debug_line_str.ptr, debug_line_str.size, address); + if (info.address == address){ + kprintf("[%.16x] %i: %s %i:%i", address, depth, info.file, info.line, info.column); + return true; + } + return false; +} + +bool decode_crash_address(uint8_t depth, uintptr_t address, sizedptr debug_line, sizedptr debug_line_str){ + return decode_crash_address_with_info(depth, address, debug_line, debug_line_str) || + decode_crash_address_with_info(depth, address, get_kernel_proc()->debug_lines, get_kernel_proc()->debug_line_str); +} + + +void backtrace(uptr *ttbr, uintptr_t fp, uintptr_t elr, sizedptr debug_line, sizedptr debug_line_str) { + if (elr){ + if (!decode_crash_address(0, elr, debug_line, debug_line_str)) + kprintf("Exception triggered by %llx",(elr)); + } + + for (uint8_t depth = 1; depth < 10 && fp; depth++) { + int tr_ra = 0; + uintptr_t ra_pa = mmu_translate(ttbr, fp + 8, &tr_ra); + if (tr_ra) return; + + uintptr_t return_address = (*(uintptr_t*)dmap_pa_to_kva((paddr_t)ra_pa)); + if (!return_address) return; + return_address -= 4;//Return address is the next instruction after branching + if (!decode_crash_address(depth, return_address, debug_line, debug_line_str)) + kprintf("%i: caller address: %llx", depth, return_address); + int tr = 0; + uintptr_t fp_pa = mmu_translate(ttbr, fp, &tr); + if (tr) return; + fp = *(uintptr_t*)dmap_pa_to_kva((paddr_t)fp_pa); + } +} + +void debug_snapshot(process_t *proc, thread_t *t){ + backtrace(proc->mm.ttbr0, t->sp, t->pc, proc->debug_lines, proc->debug_line_str); +} + +bool set_inspect(debug_inspect_types types, process_t *inspector, thread_t *inspector_thread, u16 inspected_pid, u16 inspected_tid){ + if (!inspector || !inspector_thread) return false; + process_t *inspected = get_proc_by_pid(inspected_pid); + if (!inspected || inspected->id != inspected_pid) return false; + thread_t *inspected_thread = get_thread_from_proc(inspected, inspected_tid); + if (!inspected_thread || inspected_thread->pid != inspected_pid || inspected_thread->tid != inspected_tid) return false; + auth_token tok = auth_get_proc_token(inspector); + resource res = resource_map_process(inspected); + if (!tok || !res.id) return false; + if (types & TINSPECT_CONTROL) + if (!auth_request(tok, auth_process_send_signals, res)) return false; + if (types & TINSPECT_TRACE) + if (!auth_request(tok, auth_process_intercept_exceptions, res)) return false; + if (types & TINSPECT_INFO) + if (!auth_request(tok, auth_process_info, res)) return false; + if (types & TINSPECT_STATE) + if (!auth_request(tok, auth_process_state, res)) return false; + if (types & TINSPECT_INPUT) + if (!auth_request(tok, auth_process_input, res)) return false; + if (types & TINSPECT_OUTPUT) + if (!auth_request(tok, auth_process_output, res)) return false; + inspected_thread->inspector = (proc_addr){ + .pid = inspector->id, + .tid = inspector_thread->tid + }; + return true; +} \ No newline at end of file diff --git a/kernel/process/debug.h b/kernel/process/debug.h index 869098a9..fdb5aa55 100644 --- a/kernel/process/debug.h +++ b/kernel/process/debug.h @@ -1,3 +1,11 @@ #pragma once -void debug_load(); \ No newline at end of file +#include "process.h" +#include "debug/inspect.h" + +void debug_load(); + +void backtrace(uptr *ttbr, uintptr_t fp, uintptr_t elr, sizedptr debug_line, sizedptr debug_line_str); +void debug_snapshot(process_t *proc, thread_t *t); + +bool set_inspect(debug_inspect_types types, process_t *inspector, thread_t *inspector_thread, u16 inspected_pid, u16 inspected_tid); \ No newline at end of file diff --git a/kernel/process/isolated_fs/isolated_fs.c b/kernel/process/isolated_fs/isolated_fs.c index 8a6be745..872ea5f4 100644 --- a/kernel/process/isolated_fs/isolated_fs.c +++ b/kernel/process/isolated_fs/isolated_fs.c @@ -1,12 +1,9 @@ #include "isolated_fs.h" #include "filesystem/modules/fs_isolation.h" -#include "filesystem/modules/module_loader.h" #include "process/environment/environment.h" +#include "alloc/alloc.h" -char *bundle_redirect = 0; - -bool resources_init(system_module *module){ - module->alias_info.alias_path = string_format("%s/resources",bundle_redirect); +bool stub_init(system_module *module){ return true; } @@ -14,11 +11,11 @@ system_module bundle_module = { .name = "resources", .mount = "resources", .version = VERSION_NUM(0, 1, 0, 0), - .init = resources_init, + .init = stub_init, }; bool shared_init(system_module *module){ - module->alias_info.alias_path = string_from_literal("/home"); + if (!module->alias_info.alias_path.length) module->alias_info.alias_path = string_from_literal("/home"); return true; } @@ -30,7 +27,7 @@ system_module shared_module = { }; bool docs_init(system_module *mod){ - mod->alias_info.alias_path = string_from_literal("/home/docs"); + if (!mod->alias_info.alias_path.length) mod->alias_info.alias_path = string_from_literal("/home/docs"); return true; } @@ -41,32 +38,56 @@ system_module doc_module = { .init = docs_init }; -static u16 procid; - -bool env_init(system_module *module){ - if (!procid) return false; - register_environment(procid); - module->alias_info.alias_path = string_format("/environments/%i",procid); - return true; -} - system_module env_module = { .name = "environment", .mount = "environment", .version = VERSION_NUM(0, 1, 0, 0), - .init = env_init, + .init = stub_init, .fini = 0,//TODO: These modules need to be unloaded too }; +static inline system_module* clone_mod(system_module *mod){ + system_module *m = new(system_module); + memcpy(m, mod, sizeof(system_module)); + return m; +} + void make_process_fs(process_t* proc, char *bundle){ proc->permissions.fs_id = register_fs_id(); + +#ifdef FEATURE_NEW_PROCFS + register_procfs(proc->id); +#endif + module_root *root = get_fs_for_id(proc->permissions.fs_id); - procid = proc->id; + if (bundle){ - bundle_redirect = bundle; - load_module_to(root, &bundle_module); + system_module *local_bun = clone_mod(&bundle_module); + local_bun->alias_info.alias_path = string_format("%s/resources",bundle); + load_module_to(root, local_bun); } - load_module_to(root, &shared_module); - load_module_to(root, &env_module); - load_module_to(root, &doc_module); + + load_module_to(root, clone_mod(&shared_module)); + + register_environment(proc->id); + system_module *local_env = clone_mod(&env_module); + local_env->alias_info.alias_path = string_format("/environments/%i",proc->id); + load_module_to(root, local_env); + + load_module_to(root, clone_mod(&doc_module)); +} + +bool load_process_module(process_t *p, system_module *m, bool global){ + if (!p->permissions.owned_fs_id) p->permissions.owned_fs_id = register_fs_id(); + module_root *root = get_fs_for_id(p->permissions.fs_id); + system_module *mod = zalloc(sizeof(system_module)); + if (m->init) m->init = 0;//TODO: This function can be called again thanks to kctx switch + memcpy(mod, m, sizeof(system_module)); + mod->name = string_from_literal(m->name).data; + mod->mount = string_from_literal(m->mount).data; + mod->owner = p->id; + bool ret = load_module_to(root, mod); + if (!ret) return false; + if (!global) return true; + return load_module(mod); } \ No newline at end of file diff --git a/kernel/process/jobs/job_manager.c b/kernel/process/jobs/job_manager.c index 7878d6e8..7df80099 100644 --- a/kernel/process/jobs/job_manager.c +++ b/kernel/process/jobs/job_manager.c @@ -6,11 +6,19 @@ #include "memory/addr.h" #include "memory/memory.h" #include "filesystem/filesystem.h" +#include "process/stack_manager.h" job_id_t job_id_counter = 1; +// #define JOB_DEBUG + +#ifdef JOB_DEBUG +#define job_print(...) print(__VA_ARGS__) +#else +#define job_print(...) +#endif + uptr job_kpec = 0; -uptr job_ksp = 0; sizedptr job_kstack = {}; extern int syscall_depth; extern void job_restore_kernel(); @@ -20,7 +28,6 @@ typedef struct { thread_t *requester; thread_t *worker; thread_t kernel_ctx; - sizedptr kstack; job_id_t id; job_buffer buffers[8]; size_t buffer_count; @@ -30,7 +37,7 @@ typedef struct { linked_list_t *job_list; -void *job_page; +void *job_page = 0; void* job_man_alloc(size_t size){ return allocate(job_page, size, page_alloc); @@ -55,7 +62,8 @@ bool prepare_thread(job_state_t *job, system_module *mod, job_application_t appl case job_read: entry = (uptr)mod->read; break; case job_write: entry = (uptr)mod->write; break; case job_trunc: entry = (uptr)mod->truncate; break; - default: return false; + case job_transform: entry = (uptr)mod->transform; break; + default: print("[JOB error] unknown type %i",application.type); return false; } if (!entry) return false; new_thread(proc, t, proc->spsr, entry); @@ -66,11 +74,15 @@ bool prepare_thread(job_state_t *job, system_module *mod, job_application_t appl uptr buffers = mm_alloc_mmap(&proc->mm, total_size, MEM_RW, VMA_KIND_SPECIAL, 0); uptr pbuffers = (uptr)palloc_inner(total_size, MEM_PRIV_SHARED, MEM_RW, true, false); for (size_t i = 0; i < num_pages; i++){ - mmu_map_4kb(proc->mm.ttbr0, buffers + (i * PAGE_SIZE), pbuffers + (i * PAGE_SIZE), MAIR_IDX_NORMAL, MEM_RW, MEM_PRIV_USER); - register_proc_memory(PHYS_TO_VIRT(pbuffers + (i * PAGE_SIZE)), pbuffers + (i * PAGE_SIZE), MEM_RW, MEM_PRIV_KERNEL); + int st = 0; + if (!mmu_translate(proc->mm.ttbr0, buffers + (i * PAGE_SIZE), &st) || st){ + mmu_map_4kb(proc->mm.ttbr0, buffers + (i * PAGE_SIZE), pbuffers + (i * PAGE_SIZE), MAIR_IDX_NORMAL, MEM_RW, MEM_PRIV_USER); + register_proc_memory(PHYS_TO_VIRT(pbuffers + (i * PAGE_SIZE)), pbuffers + (i * PAGE_SIZE), MEM_RW, MEM_PRIV_KERNEL); + } + //TODO: buffers created for the fsus are not cleaned up } memset((void*)PHYS_TO_VIRT(pbuffers), 0, total_size); - print("[JOB debug] buffers will go to %llx - %llx",buffers,pbuffers); + job_print("[JOB debug] buffers will go to %llx - %llx",buffers,pbuffers); uptr next_addr_pa = PHYS_TO_VIRT(pbuffers); uptr next_addr_va = buffers; @@ -93,31 +105,41 @@ u64 create_new_job(job_application_t application, system_module *mod, thread_t * process_t *requesting_proc = get_proc_by_pid(application.requesting_pid); if (!requesting_proc){ print("[JOB error] Unknown requesting proc %i",application.requesting_pid); - return (job_id_t){}; + return 0; } job_state_t *job = job_alloc(); job->type = application.type; job->mod = mod; thread_t *requester = (thread_t*)get_thread_from_proc(requesting_proc, application.requesting_tid); - if (job_ksp != (uptr)ksp) requester->kstack_top = job_ksp; job->requester = requester; process_t *fs_owner = get_proc_by_pid(application.worker_pid); thread_t *new_t = alloc_thread(); if (!prepare_thread(job, mod, application, fs_owner, new_t)){ print("[JOB error] failed to prepare thread for job %i",job->id); - return false; + return 0; } - print("[JOB debug] Sync between %i - %i will happen with job %i of type %i using thread %i",requester->pid,application.worker_pid,job->id,application.type,new_t->tid); + job_print("[JOB debug] Sync between %i - %i will happen with job %i of type %i using thread %i",requester->pid,application.worker_pid,job->id,application.type,new_t->tid); new_t->job_id = job->id; job->worker = new_t; requester->state = BLOCKED; - if (syscall_depth >= 1){ - print("[JOB debug] kstack has been saved to %llx - %x",job_kstack.ptr,job_kstack.size); - memcpy(&job->kernel_ctx, kthread, sizeof(thread_t)); - job->kernel_ctx.job_id = job->id; - job->kernel_ctx.pc = job_save_ret(); - job->kstack = job_kstack; - } else memset(&job->kernel_ctx, 0, sizeof(thread_t)); + job_print("[JOB debug] kstack has been saved to %llx - %x",kthread->stack_info.top,kthread->stack_info.size); + memcpy(&job->kernel_ctx, kthread, sizeof(thread_t)); + job->kernel_ctx.job_id = job->id; + job->kernel_ctx.pc = job_save_ret(); + if (kthread->stack_info.top && kthread->stack_info.size){ + uptr* ttbr1k = mmu_default_ttbr(); + uptr* newttbr1 = mmu_new_ttbr(); + requester->special_mm = newttbr1; + mmu_copy(newttbr1, ttbr1k, 0); + uptr base = (uptr)ksp - kstack_max; + uptr stack = kthread->stack_info.top-kstack_max; + for (uptr a = 0; a < kstack_max; a += PAGE_SIZE){ + int st = 0; + uptr addr = mmu_translate(newttbr1, stack + a, &st); + if (st) return 0;//TODO: release table + mmu_replace(newttbr1, base + a, addr); + } + } schedule_thread(fs_owner, new_t); switch_proc(YIELD); return 0; @@ -146,10 +168,6 @@ void* quick_translate(thread_t *thread, process_t *proc, uptr ptr){ extern uptr cpec; -static inline uptr translate_stack(uptr new_top, uptr ptr){ - return new_top-((uptr)ksp-ptr); -} - void fulfill_job(job_id_t job_id, u64 ret, thread_t *thread){ job_state_t *st = get_job_state(job_id); if (!st) { @@ -164,48 +182,36 @@ void fulfill_job(job_id_t job_id, u64 ret, thread_t *thread){ for (size_t i = 0; i < st->buffer_count; i++){ job_buffer buf = st->buffers[i]; if (buf.sync & copy_on_end && buf.worker_ptr.ptr){ - print("[JOB debug] Copy buffer %x into %x",buf.worker_ptr.ptr,buf.orig_ptr.ptr); - void* addr = quick_translate(st->requester, proc, buf.orig_ptr.ptr); - if (!addr) continue; - memcpy(addr, (void*)buf.worker_ptr.ptr, buf.worker_ptr.size); - file *fd = addr; - if (buf.fd){ - print("[JOB DEBUG] fd %i size %i signature %s",fd->id,fd->size,&fd->data_type); - if (st->type == job_open){ - instance_local_fd(st->mod, addr); + job_print("[JOB debug] Copy buffer %llx into %llx",buf.worker_ptr.ptr,buf.orig_ptr.ptr); + size_t size = buf.orig_ptr.size; + uptr src = buf.worker_ptr.ptr; + for (uptr page = buf.orig_ptr.ptr; page < buf.orig_ptr.ptr + buf.orig_ptr.size; page += PAGE_SIZE){ + job_print("[JOB debug] doing translation for %llx",page); + void* addr = quick_translate(st->requester, proc, page); + if (!addr){ + if (page & HIGH_VA){ + int stb = 0; + addr = (void*)PHYS_TO_VIRT(mmu_translate(st->requester->special_mm, page, &stb)); + } + } + if (!addr){ + print("[JOB error] failed to translate destination va %llx",page); + continue; } + size_t amount = size > PAGE_SIZE ? PAGE_SIZE : size; + memcpy(addr, (void*)src, amount); + src += amount; + size -= amount; } } } - print("[JOB] %i fulfilled by %i",job_id,thread->tid); - if (st->kernel_ctx.job_id){ - st->kernel_ctx.PROC_X0 = ret; - job_kpec = (uptr)&st->kernel_ctx; - cpec = (uptr)st->requester; - - if (st->kstack.ptr){ - st->kernel_ctx.sp = translate_stack((st->kstack.ptr+0x10000), st->kernel_ctx.sp); - print("[JOB debug] Initial Address %llx",st->kernel_ctx.regs[29]); - st->kernel_ctx.regs[29] = translate_stack((st->kstack.ptr+0x10000), st->kernel_ctx.regs[29]); - - uptr addr = st->kernel_ctx.regs[29]; - uptr fp = 0; - do { - print("[JOB debug] Address %llx",addr); - fp = *(uptr*)addr; - print("[JOB debug] Link %llx",fp); - fp = translate_stack(st->kstack.ptr+0x10000, fp); - print("[JOB debug] In new stack %llx",fp); - *(uptr*)addr = fp; - addr = fp; - } while(addr && (addr & 0xfffff00000000000) == 0xffffc00000000000); - } - st->requester->state = RUNNING; - prepare_process_restore(proc); - job_ksp = st->kstack.ptr+0x10000; - job_restore_kernel(); - } else { - ready_thread(st->requester); - st->requester->PROC_X0 = ret; - } + job_print("[JOB] %i fulfilled by %i with return value %llx",job_id,thread->tid,thread->regs[0]); + st->kernel_ctx.PROC_X0 = ret; + job_kpec = (uptr)&st->kernel_ctx; + cpec = (uptr)st->requester; + + st->requester->state = RUNNING; + prepare_process_restore(proc); + mmu_swap_kttbr(st->requester->special_mm); + job_restore_kernel(); } \ No newline at end of file diff --git a/kernel/process/jobs/job_manager.h b/kernel/process/jobs/job_manager.h index f8842116..a0c947b1 100644 --- a/kernel/process/jobs/job_manager.h +++ b/kernel/process/jobs/job_manager.h @@ -2,23 +2,21 @@ #include "files/jobs.h" #include "process/process.h" +#include "process/stack_manager.h" extern uptr job_kpec; -extern uptr job_ksp; -extern sizedptr job_kstack; extern void job_save_kernel(); -extern void save_kstack(); +extern void save_kstack(uptr stack); //TODO: if the owner is the current process, we can downgrade the syscall into a function call without async #define job_make(job_type,mod,action)\ thread_t kthread = {};\ - job_kstack = (sizedptr){};\ job_kpec = (uptr)&kthread;\ - if (!job_ksp) job_ksp = (uptr)ksp;\ job_save_kernel();\ - print("KStack save to %llx",job_ksp);\ - save_kstack();\ - print("KStack saved to %llx of size %llx from %llx",job_kstack.ptr,job_kstack.size,ksp);\ + if (!get_current_thread()->special_mm && !is_privileged(get_current_proc())){\ + kthread.stack_info = new_stack(get_proc_by_pid(1));\ + save_kstack(kthread.stack_info.top);\ + }\ process_t *owner_proc = get_proc_by_pid(mod->owner);\ job_application_t app = (job_application_t){\ .requesting_pid = get_current_proc()->id,\ @@ -93,4 +91,4 @@ static inline void job_serialize_off(job_application_t *application, int arg_num } u64 create_new_job(job_application_t application, system_module *mod, thread_t *kthread); -void fulfill_job(job_id_t job_id, u64 ret, thread_t *thread); +void fulfill_job(job_id_t job_id, u64 ret, thread_t *thread); \ No newline at end of file diff --git a/kernel/process/jobs/job_save.S b/kernel/process/jobs/job_save.S index 2cbfbb58..77d257b6 100644 --- a/kernel/process/jobs/job_save.S +++ b/kernel/process/jobs/job_save.S @@ -1,6 +1,5 @@ .global job_save_kernel job_save_kernel: - msr daifset, #2 stp x17, x18, [sp, #-16]! add x17, sp, #16 @@ -45,40 +44,23 @@ add sp, sp, #16 ret .global save_kstack -save_kstack: +save_kstack: //x0 = new stack sub sp, sp, #32 -stp x0, x1, [sp, #0] +stp x2, x1, [sp, #0] stp x21,x30, [sp, #16] -adrp x0, job_ksp -add x0, x0, :lo12:job_ksp -ldr x0, [x0] - -adrp x1, ksp -add x1, x1, :lo12:ksp -cmp x0, x1 - -b.ne 2f +adrp x2, ksp +add x2, x2, :lo12:ksp mov x1, sp -sub x21, x0, x1 -mov x0, #0x10000 -bl zalloc - -adrp x1, job_kstack -add x1, x1, :lo12:job_kstack -stp x0, x21, [x1, #0] +sub x2, x2, x1 -add x0,x0,#0x10000 -sub x0,x0,x21 +sub x0,x0,x2 -mov x1, sp -mov x2, x21 bl memcpy -2: -ldp x0, x1, [sp, #0] +ldp x2, x1, [sp, #0] ldp x21,x30, [sp, #16] add sp, sp, #32 @@ -120,6 +102,11 @@ job_restore_kernel: ldr x30, [x18, #(8 * 32)] ldr x18, [x18, #(8 * 18)] + dsb ishst + tlbi vmalle1is + dsb ish + isb + ret .global job_save_ret diff --git a/kernel/process/kernel_syscall_impl.c b/kernel/process/kernel_syscall_impl.c index f9c35be9..7cc89c5d 100644 --- a/kernel/process/kernel_syscall_impl.c +++ b/kernel/process/kernel_syscall_impl.c @@ -15,6 +15,9 @@ #include "memory/mmu.h" #include "memory/addr.h" #include "process/signals/signals.h" +#include "jobs/job_manager.h" +#include "filesystem/modules/fs_isolation.h" + extern page_index *p_index; void* page_alloc(size_t size){ @@ -45,6 +48,12 @@ void page_free(void *ptr){ void printl(const char *str){ kprint(str); + if (is_privileged(get_current_proc())){ + size_t len = strlen(str); + file fd2 = { .id = 2 }; + write_file(&fd2, str, len); + write_file(&fd2, "\r\n", 2); + } } bool read_key(keypress *kp){ @@ -58,7 +67,8 @@ bool read_event(kbd_event *event){ void get_mouse_status(mouse_data *in){ in->raw = get_raw_mouse_in(); in->raw.scroll = sys_read_scroll_current(); - in->position = convert_mouse_position(get_mouse_pos()); + in->position = get_mouse_pos(); + convert_mouse_position(in); } int32_t exec(const char* prog_name, int argc, const char* argv[], uint32_t mode){ @@ -80,7 +90,6 @@ void resize_draw_ctx(draw_ctx* d_ctx, uint32_t width, uint32_t height){ gpu_flush(); } - uint32_t gpu_char_size(uint32_t scale){ return gpu_get_char_size(scale); } @@ -135,6 +144,13 @@ size_t readf(file *descriptor, char* buf, size_t size){ return read_file(descriptor, buf, size); } +size_t transformf(const char *path, void* buf, size_t size){ + module_root rootfs = {}; + string s = resolve_isolated_path(path, get_current_proc()->permissions.fs_id, &rootfs, true); + if (!s.data || !s.length) return transform_file(kernel_fs(), path, buf, size); + return transform_file(&rootfs, path, buf, size); +} + size_t writef(file *descriptor, const char* buf, size_t size){ return write_file(descriptor, buf, size); } @@ -194,10 +210,39 @@ bool statf(const char *path, fs_stat *out_stat){ return ret; } +void syncf(file *descriptor, bool replace){ + sync_file(descriptor, replace); +} + bool send_signal(signal_types type, u16 proc_id){ return send_signal_proc_id(type, 0, get_current_proc(), proc_id); } bool handle_signal(signal_types type, signal_handler handler){ return register_signal_handler(get_current_proc(), type, handler); +} + +void msleep(uint64_t time){ + //print(">>>>>> Attempt to sleep from %i",get_current_proc()->id); + // sleep_thread(time); +} + +void __attribute__((noreturn)) halt(int32_t exit_code){ + stop_current_process(exit_code); + kernel_process_return_trampoline(exit_code); +} + +void __attribute__((noreturn)) halt_thread(int32_t exit_code){ + thread_t* current_thread = get_current_thread(); + if (current_thread->job_id){ + fulfill_job(current_thread->job_id, current_thread->PROC_X0, current_thread); + } + if (current_thread->tid == 1) + stop_current_process(current_thread->PROC_X0); + else { + current_thread->state = STOPPED; + unmap_stack(get_current_proc(), current_thread->stack_info); + switch_proc(YIELD);//TODO: proper cleanup + } + kernel_process_return_trampoline(exit_code); } \ No newline at end of file diff --git a/kernel/process/loading/elf_file.c b/kernel/process/loading/elf_file.c index ad6e90b9..4c8c4527 100644 --- a/kernel/process/loading/elf_file.c +++ b/kernel/process/loading/elf_file.c @@ -12,6 +12,7 @@ #include "process/scheduler.h" #include "filesystem/filesystem.h" #include "process/uaccess.h" +#include "filesystem/modules/fs_isolation.h" typedef struct elf_header { char magic[4];//should be " ELF" @@ -65,7 +66,7 @@ void get_elf_debug_info(process_t* proc, void* file, size_t filesize){ if (!file) return; if (filesize < sizeof(elf_header)) return; - elf_header *header = (elf_header*)file; + elf_header *header = (elf_header*)file; if (memcmp(header->magic, "\x7f" "ELF", 4) != 0) return; @@ -199,15 +200,17 @@ process_t* load_elf_process_path(const char *name, const char *bundle, const cha if (!path || !*path) return 0; file fd = {}; - if (open_file(kernel_fs(), path, &fd) != FS_RESULT_SUCCESS) return 0; + if (open_file(kernel_fs(), path, &fd) != FS_RESULT_SUCCESS || fd.size == 0) return 0; char *program = (char*)zalloc(fd.size); if (!program) { close_file(&fd); return 0; } + + size_t amt = read_file(&fd, program, fd.size); + bool ok = amt && amt == fd.size; - bool ok = read_file(&fd, program, fd.size) == fd.size; close_file(&fd); if (!ok) { release(program); diff --git a/kernel/process/loading/process_loader.c b/kernel/process/loading/process_loader.c index 9b1b74f5..4c96cd7f 100644 --- a/kernel/process/loading/process_loader.c +++ b/kernel/process/loading/process_loader.c @@ -13,6 +13,7 @@ #include "syscalls/syscall_codes.h" #include "process/isolated_fs/isolated_fs.h" #include "process/stack_manager.h" +#include "access/entitlements.h" typedef struct { uint64_t code_base_start; @@ -405,11 +406,13 @@ process_t* create_process(const char *name, const char *bundle, program_load_dat proc->mm.rss_stack_pages = 0; - proc->shared_page = shared_base; proc->main_thread.regs[30] = proc->shared_page; kprintf("[NEW PROC:U]: %s (pid: %i, main tid: %i) allocated at %llx entry=%llx stack=%llx-%llx anon=%llx (phys=%llx)", name, proc->id, proc->main_thread.tid, proc, (uint64_t)proc->main_thread.pc, (uint64_t)proc->mm.stack_limit, (uint64_t)proc->mm.stack_top, (uint64_t)proc->mm.mmap_bottom, (uint64_t)proc->heap_phys); proc->state = BLOCKED; + proc->priority = PROC_PRIORITY_HIGH; + + process_grant_entitlements(proc); make_process_fs(proc,proc->bundle); diff --git a/kernel/process/process.h b/kernel/process/process.h index b1a2a2cf..65d7740c 100644 --- a/kernel/process/process.h +++ b/kernel/process/process.h @@ -13,10 +13,13 @@ extern "C" { #include "signals/signals.h" #include "environment/environment.h" #include "files/jobs.h" +#include "access/authorize.h" +#include "process_fs.h" +#include "debug/proc.h" #define INPUT_BUFFER_CAPACITY 64 #define PACKET_BUFFER_CAPACITY 128 -#define PROC_OUT_BUF 0x10000 +#define PROC_STDIO_BUF 0x10000 typedef struct { volatile u32 write_index; @@ -42,8 +45,6 @@ typedef struct { sizedptr entries[PACKET_BUFFER_CAPACITY]; } packet_buffer_t; -#define MAX_PROC_NAME_LENGTH 256 - #define SIGNAL_BUFFER_CAPACITY 64 typedef struct { @@ -55,6 +56,7 @@ typedef struct { typedef struct { u64 fs_id;//Filesystem this process has access to u64 owned_fs_id;//Filesystem this process owns, not automapped to fs_id due to isolation not being enforced yet + auth_token auth_id; } system_permissions; typedef enum { STOPPED, READY, RUNNING, BLOCKED, SLEEPING } process_state; @@ -65,6 +67,14 @@ typedef struct { size_t size; } stack_t; +typedef union { + struct { + u32 pid: 16; + u32 tid: 16; + }; + u32 addr; +} proc_addr; + struct thread_t { uint64_t regs[31]; // x0–x30 uintptr_t sp; @@ -72,13 +82,14 @@ struct thread_t { uint64_t spsr; //Not used in context saving stack_t stack_info; - uptr kstack_top; + uptr *special_mm; u16 pid; u16 tid; process_state state; u64 wake_at_msec; - thread_t *next; job_id_t job_id; + proc_addr inspector; + thread_t *next; }; struct process_t { @@ -90,9 +101,12 @@ struct process_t { size_t output_size; kaddr_t postmortem_output; size_t postmortem_output_size; + + kaddr_t input; + size_t input_size; + uint16_t procfs_refs; bool pending_reset; - file out_fd; int32_t exit_code; bool focused; paddr_t code; @@ -109,6 +123,7 @@ struct process_t { __attribute__((aligned(16))) thread_t signal_handlers[NUMBER_SIGNALS]; uint8_t priority; system_permissions permissions; + resource resource_id; uint16_t win_id; uaddr_t win_fb_va; paddr_t win_fb_phys; @@ -122,6 +137,7 @@ struct process_t { int thread_count; int thread_ids; environment_data environment; + procfs_files procfs; uptr shared_page; process_t *process_next; }; diff --git a/kernel/process/process_fs.c b/kernel/process/process_fs.c new file mode 100644 index 00000000..989b6493 --- /dev/null +++ b/kernel/process/process_fs.c @@ -0,0 +1,217 @@ +#include "files/system_module.h" +#include "files/folderfs.h" +#include "scheduler.h" +#include "console/kio.h" + +typedef enum { procfs_type_none, procfs_type_id, procfs_type_in, procfs_type_out, procfs_type_state, procfs_type_info } procfs_data_types; + +typedef struct { + u16 procid; +} proc_data; + +void procfs_list(void *ctx, u64 original_index, u64 *out_offset){ + proc_data *data = ctx; + string s = string_format("%i",data->procid); + if (!dir_list_fill(router_fs_dir_helper, s.data)){ + if (out_offset) *out_offset = current_offset; + string_free(s); + return; + } + string_free(s); +} + +static inline buffer procfs_make_info_buffer(process_t *proc){ + return buffer_create(sizeof(proc_info), buffer_static); +} + +FS_RESULT procfs_open_output(process_t *proc, file *fd){ + fd->id = ((procfs_type_out & 0xFFFF) << 16) | proc->id; + fd->data_type = DATA_SIG_TEXT; + if (!proc->procfs.output.buffer_size){ + proc->procfs.output = (buffer){ + .buffer = (char*)(proc->output ? proc->output : proc->postmortem_output), + .buffer_size = proc->output ? proc->output_size : proc->postmortem_output_size, + .limit = proc->output ? PROC_STDIO_BUF : proc->postmortem_output_size, + .options = proc->output ? buffer_circular : buffer_static, + .cursor = proc->output ? proc->output_size : 0, + }; + } + fd->size = proc->procfs.output.buffer_size; + return FS_RESULT_SUCCESS; +} + +FS_RESULT procfs_open_input(process_t *proc, file *fd){ + fd->id = ((procfs_type_in & 0xFFFF) << 16) | proc->id; + fd->data_type = DATA_SIG_TEXT; + if (!proc->procfs.input.buffer_size && proc->input){ + proc->procfs.input = (buffer){ + .buffer = (char*)proc->input, + .buffer_size = proc->input_size, + .limit = PROC_STDIO_BUF, + .options = buffer_circular, + .cursor = proc->input_size, + }; + } + fd->size = proc->procfs.output.buffer_size; + return FS_RESULT_SUCCESS; +} + +FS_RESULT procfs_open(u64 id, string_slice file_name, file *fd){ + process_t *proc = get_proc_by_pid(id); + if (!proc) return FS_RESULT_NOTFOUND; + process_t *cproc = get_current_proc(); + if (slice_lit_match(file_name, "out", true)){ + if (proc != cproc && !auth_valid(auth_get_proc_token(cproc), auth_process_output, resource_map_process(proc))) + return FS_RESULT_NOTFOUND; + return procfs_open_output(proc, fd); + } + if (slice_lit_match(file_name, "state", true)){ + if (proc != cproc && !auth_valid(auth_get_proc_token(cproc), auth_process_state, resource_map_process(proc))){ + print("Auth failure for reading state"); + return FS_RESULT_NOTFOUND; + } + fd->id = ((procfs_type_state & 0xFFFF) << 16) | id; + fd->data_type = DATA_SIG_PROC_ST; + fd->size = sizeof(process_state); + if (!proc->procfs.state.buffer_size){ + buffer_map_value(&proc->procfs.state, &proc->state, sizeof(process_state), DATA_SIG_PROC_ST); + } + return FS_RESULT_SUCCESS; + } + if (slice_lit_match(file_name, "info", true)){ + if (proc != cproc && !auth_valid(auth_get_proc_token(cproc), auth_process_info, resource_map_process(proc))){ + print("Auth failure for reading info"); + return FS_RESULT_NOTFOUND; + } + fd->id = ((procfs_type_info & 0xFFFF) << 16) | id; + fd->data_type = DATA_SIG_PROC_INFO; + fd->size = sizeof(proc_info); + if (!proc->procfs.info.buffer_size){ + proc->procfs.info = procfs_make_info_buffer(proc); + } + return FS_RESULT_SUCCESS; + } + if (slice_lit_match(file_name, "in", true)){ + if (!auth_valid(auth_get_proc_token(cproc), auth_process_input, resource_map_process(proc))) + return FS_RESULT_NOTFOUND; + return procfs_open_input(proc, fd); + } + return FS_RESULT_NOTFOUND; +} + +void procfs_fill_info(process_t *proc, buffer *buf){ + size_t expected_size = sizeof(proc_info); + if (!buf || !buf->buffer || buf->limit < expected_size){ + if (buf) buffer_destroy(buf); + proc->procfs.info = procfs_make_info_buffer(proc); + } + size_t namelen = strlen(proc->name); + if (namelen >= MAX_PROC_NAME_LENGTH) namelen = MAX_PROC_NAME_LENGTH-1; + proc_info info = { + .id = proc->id, + .procnamelen = namelen, + .stack = {proc->main_thread.stack_info.top,proc->main_thread.stack_info.size}, + .sp = proc->main_thread.sp, + .heap = {proc->mm.mmap_bottom,proc->mm.mmap_top-proc->mm.mmap_bottom}, + .pc = proc->main_thread.pc, + .privilege = is_privileged(proc), + .state = proc->state + }; + memcpy(info.procname, proc->name, namelen); + buffer_write_lim(buf, (char*)&info, expected_size); +} + +buffer* procfs_resolve_fd(file *fd){ + if (fd->id == FD_OUT){ + process_t *proc = get_current_proc(); + if (!proc) return 0; + procfs_open_output(proc, fd); + return &proc->procfs.output; + } + if (fd->id == FD_IN){ + process_t *proc = get_current_proc(); + if (!proc) return 0; + procfs_open_input(proc, fd); + return &proc->procfs.input; + } + u16 procid = fd->id & 0xFFFF; + process_t *proc = get_proc_by_pid(procid); + if (!proc) return 0; + u16 file_type = (fd->id >> 16) & 0xFFFF; + switch (file_type){ + case procfs_type_out: + return &proc->procfs.output; + case procfs_type_state: + return &proc->procfs.state; + case procfs_type_info: + procfs_fill_info(proc, &proc->procfs.info); + return &proc->procfs.info; + case procfs_type_id: + return &proc->procfs.id; + case procfs_type_in: + return &proc->procfs.input; + default: return 0; + } + return 0; +} + +u64 resolve_reserved_fd(u64 fd){ + if (fd == FD_OUT){ + return ((procfs_type_out & 0xFFFF) << 16) | get_current_proc_pid(); + } + if (fd == FD_IN){ + return ((procfs_type_in & 0xFFFF) << 16) | get_current_proc_pid(); + } + return 0; +} + +bool init_procfs(){ + if (!folderfs_init()) return false; + folderfs_custom_list = procfs_list; + folderfs_custom_open = procfs_open; + folderfs_resolve_fd = procfs_resolve_fd; + static_entries += make_entry("id", backing_virtual, entry_file, DATA_SIG_RAW, (buffer){}) != 0; + static_entries += make_entry(":id/in", backing_virtual, entry_file, DATA_SIG_RAW, (buffer){}) != 0; + static_entries += make_entry(":id/out", backing_virtual, entry_file, DATA_SIG_TEXT, (buffer){}) != 0; + static_entries += make_entry(":id/state", backing_virtual, entry_file, DATA_SIG_PROC_ST, (buffer){}) != 0; + static_entries += make_entry(":id/info", backing_virtual, entry_file, DATA_SIG_PROC_INFO, (buffer){}) != 0; + return true; +} + +void register_procfs(u16 procid){ + process_t *proc = get_proc_by_pid(procid); + if (!proc) return; + proc->output = (kaddr_t)palloc(PROC_STDIO_BUF, MEM_PRIV_KERNEL, MEM_RW, true);//TODO: only do this when it's written to + proc->input = (kaddr_t)palloc(PROC_STDIO_BUF, MEM_PRIV_KERNEL, MEM_RW, true);//TODO: only do this when it's written to + proc_data *data = zalloc(sizeof(proc_data)); + data->procid = procid; + folderfs_create_folder(data); +} + +static inline FS_RESULT procfs_main_open(const char *path, file *fd){ + if (strncmp(path,"/id", 3) == 0){ + process_t *proc = get_current_proc(); + fd->id = ((procfs_type_id & 0xFFFF) << 16) | proc->id; + fd->data_type = DATA_SIG_RAW; + fd->size = sizeof(u16); + if (!proc->procfs.id.buffer_size){ + buffer_map_value(&proc->procfs.id, &proc->id, sizeof(u16), DATA_SIG_RAW); + } + return FS_RESULT_SUCCESS; + } + return folderfs_open(path, fd); +} + +system_module procfs_mod = (system_module){ + .name = "procfs", + .mount = "proc", + .version = VERSION_NUM(0, 1, 0, 1), + .init = init_procfs, + .fini = 0, + .open = procfs_main_open, + .read = folderfs_read, + .write = folderfs_write, + // .close = folderfs_close, + .getstat = folderfs_stat, + .readdir = folderfs_readdir, +}; diff --git a/kernel/process/process_fs.h b/kernel/process/process_fs.h new file mode 100644 index 00000000..1def9ea8 --- /dev/null +++ b/kernel/process/process_fs.h @@ -0,0 +1,17 @@ +#pragma once + +#include "files/system_module.h" + +void register_procfs(u16 procid); + +typedef struct { + buffer output; + buffer state; + buffer info; + buffer id; + buffer input; +} procfs_files; + +u64 resolve_reserved_fd(u64 fd); + +extern system_module procfs_mod; \ No newline at end of file diff --git a/kernel/process/procfs.c b/kernel/process/procfs.c deleted file mode 100644 index a5f63293..00000000 --- a/kernel/process/procfs.c +++ /dev/null @@ -1,375 +0,0 @@ -#include "procfs.h" -#include "files/dir_list.h" -#include "process.h" -#include "exceptions/irq.h" -#include "console/kio.h" -#include "scheduler.h" -#include "math/math.h" - -extern process_t *process_list; -hash_map_t *proc_opened_files; - -typedef struct { - process_t *proc; - uint16_t pid; -} procfs_owner; - -void* proc_page; - -void* procfs_alloc(size_t size){ - return allocate(proc_page, size, page_alloc); -} - -bool init_procfs(){ - proc_page = page_alloc(PAGE_SIZE*16); - if (!proc_opened_files) { - proc_opened_files = hash_map_create(1024); - proc_opened_files->free = release; - proc_opened_files->alloc = procfs_alloc; - } - return true; -} - -size_t list_processes(void *buf, size_t size, file_offset *offset){ - - if (!buf || !offset || size < sizeof(uint32_t)) return 0; - - fs_dir_list_helper helper = create_dir_list_helper(buf, size); - - process_t *proc = process_list; - if (*offset) { - while (proc && proc->id != *offset) proc = proc->process_next; - } - - while (proc) { - if (proc->id != 0 && proc->state != STOPPED) { - char name[6]; - string_format_buf(name, 6, "%i", proc->id); - - if (!dir_list_fill(&helper, name)){ - if (offset){ - *offset = proc->id; - return dir_buf_size(&helper); - } - } - } - proc = proc->process_next; - } - - return dir_buf_size(&helper); -} - -#define NUM_PROC_FILES 2 - -char* proc_files[NUM_PROC_FILES] = { - "out", - "state" -}; - -size_t list_proc_files(void *buf, size_t size, file_offset *offset){ - - if (!buf || !offset || size < sizeof(uint32_t)) return 0; - - fs_dir_list_helper helper = create_dir_list_helper(buf, size); - - u64 index = offset ? *offset : 0; - - for (int i = index; i < NUM_PROC_FILES; i++){ - kprint(proc_files[i]); - char *name = (char*)((uptr)helper.list + 4 + helper.offset); - if (!dir_list_fill(&helper, proc_files[i])){ - if (offset) *offset = i; - return dir_buf_size(&helper); - } - kprint(name); - } - return dir_buf_size(&helper); -} - -size_t readdir_proc(const char *path, void *buf, size_t size, file_offset *offset){ - irq_flags_t irq = irq_save_disable(); - if (!strlen(path)){ - size_t res = list_processes(buf, size, offset); - irq_restore(irq); - return res; - } - const char *pid_s = seek_to(path, '/'); - path = seek_to(pid_s, '/'); - uint64_t pid = parse_int_u64(pid_s, path - pid_s); - process_t *proc = get_proc_by_pid(pid); - if (!proc) { - irq_restore(irq); - return false; - } - if (!strlen(path)){ - size_t res = list_proc_files(buf, size, offset); - irq_restore(irq); - return res; - } - irq_restore(irq); - return false; -} - -FS_RESULT open_proc(const char *path, file *descriptor){ - uint64_t fid = reserve_fd_gid(path); - irq_flags_t irq = irq_save_disable(); - module_file *mfile = (module_file*)hash_map_get(proc_opened_files, &fid, sizeof(uint64_t)); - if (mfile){ - descriptor->id = mfile->fid; - descriptor->size = mfile->file_size; - descriptor->cursor = 0; - mfile->references++; - procfs_owner *owner_info = (procfs_owner*)mfile->private_data; - if (owner_info && owner_info->proc && owner_info->proc->id == owner_info->pid) owner_info->proc->procfs_refs++; - irq_restore(irq); - return FS_RESULT_SUCCESS; - } - const char *pid_s = seek_to(path, '/'); - path = seek_to(pid_s, '/'); - uint64_t pid = parse_int_u64(pid_s, path - pid_s); - process_t *proc = get_proc_by_pid(pid); - if (!proc) { - irq_restore(irq); - return FS_RESULT_NOTFOUND; - } - descriptor->id = fid; - descriptor->cursor = 0; - module_file *file = procfs_alloc(sizeof(module_file)); - if (!file) { - irq_restore(irq); - return FS_RESULT_DRIVER_ERROR; - } - procfs_owner *owner_info = procfs_alloc(sizeof(procfs_owner)); - if (!owner_info) { - irq_restore(irq); - release(file); - return FS_RESULT_DRIVER_ERROR; - } - owner_info->proc = proc; - owner_info->pid = proc->id; - file->fid = fid; - file->private_data = owner_info; - file->references = 1; - if (strcmp_case(path, "out",true) == 0){ - descriptor->size = proc->output ? proc->output_size : proc->postmortem_output_size; - file->read_only = true; - file->buf = (uptr)(proc->output ? proc->output : proc->postmortem_output); - file->file_buffer = (buffer){ - .buffer = (char*)(proc->output ? proc->output : proc->postmortem_output), - .buffer_size = proc->output ? proc->output_size : proc->postmortem_output_size, - .limit = proc->output ? PROC_OUT_BUF : proc->postmortem_output_size, - .options = proc->output ? buffer_circular : buffer_static, - .cursor = proc->output ? proc->output_size : 0, - }; - proc->procfs_refs++; - } else if (strcmp_case(path, "state",true) == 0){ - descriptor->size = sizeof(proc->state); - file->read_only = true; - file->buf = (uptr)&proc->state; - file->file_buffer = (buffer){ - .buffer = (char*)&proc->state, - .limit = sizeof(proc->state), - .options = buffer_static, - .buffer_size = sizeof(proc->state), - .cursor = 0, - }; - proc->procfs_refs++; - } else { - irq_restore(irq); - release((void*)owner_info); - release(file); - return FS_RESULT_NOTFOUND; - } - file->file_size = descriptor->size; - int put = hash_map_put(proc_opened_files, &descriptor->id, sizeof(uint64_t), file); - irq_restore(irq); - if (put >= 0) return FS_RESULT_SUCCESS; - if ((uintptr_t)file->file_buffer.buffer == (uintptr_t)proc->output || (uintptr_t)file->file_buffer.buffer == (uintptr_t)proc->postmortem_output || (uintptr_t)file->file_buffer.buffer == (uintptr_t)&proc->state) { - if (proc->procfs_refs) proc->procfs_refs--; - } - release((void*)owner_info); - release(file); - return FS_RESULT_DRIVER_ERROR; -} - -bool stat_proc(const char *path, fs_stat *out_stat){ - if (!out_stat) return false; - irq_flags_t irq = irq_save_disable(); - if (!strlen(path)){ - bool res = stat_dir(out_stat); - irq_restore(irq); - return res; - } - const char *pid_s = seek_to(path, '/'); - path = seek_to(pid_s, '/'); - uint64_t pid = parse_int_u64(pid_s, path - pid_s); - process_t *proc = get_proc_by_pid(pid); - if (!proc) { - irq_restore(irq); - return false; - } - if (!strlen(path)){ - bool res = stat_dir(out_stat); - irq_restore(irq); - return res; - } - out_stat->type = entry_file; - if (strcmp_case(path, "out",true) == 0){ - out_stat->size = proc->output_size; - out_stat->data_type = DATA_SIG_TEXT; - } - if (strcmp_case(path, "state",true) == 0){ - out_stat->size = sizeof(proc->state); - out_stat->data_type = DATA_SIG_PROC_ST; - } - irq_restore(irq); - return true; -} - -int find_open_proc_file(void *node, void* key){ - uint64_t *fid = (uint64_t*)key; - module_file *file = (module_file*)node; - if (file->fid == *fid) return 0; - return -1; -} - -int find_open_proc_file_buffer(void *node, void* key){ - uintptr_t *buf = (uintptr_t*)key; - module_file *file = (module_file*)node; - if ((uintptr_t)file->file_buffer.buffer == *buf) return 0; - return -1; -} - -size_t read_proc(file* fd, char *buf, size_t size, file_offset offset){ - if (!proc_opened_files){ - kprint("No files open"); - return 0; - } - irq_flags_t irq = irq_save_disable(); - module_file *file = (module_file*)hash_map_get(proc_opened_files, &fd->id, sizeof(uint64_t)); - if (!file) { - irq_restore(irq); - return 0; - } - size_t s = buffer_read(&file->file_buffer, buf, size, offset); - fd->size = file->file_size; - irq_restore(irq); - return s; -} - -size_t write_proc(file* fd, const char *buf, size_t size, file_offset offset){ - process_t *proc = get_current_proc(); - if (fd->id == FD_OUT){ - if (!proc || !size) return 0; - if (!proc->output) { - proc->output = (kaddr_t)palloc(PROC_OUT_BUF, MEM_PRIV_KERNEL, MEM_RW, true); - if (!proc->output) return 0; - } - irq_flags_t irq = irq_save_disable(); - - buffer file_buffer = { - .buffer = (char*)proc->output, - .buffer_size = proc->output_size, - .limit = PROC_OUT_BUF, - .options = buffer_circular, - .cursor = proc->output_size, - }; - - size = min(size, file_buffer.limit); - size_t written = buffer_write_lim(&file_buffer, buf, size); - - proc->output_size = file_buffer.buffer_size; - fd->size = proc->output_size; - - if (proc_opened_files){ - char fullpath[48] = {}; - string_format_buf(fullpath, sizeof(fullpath), "/%i/out", proc->id); - uint64_t fid = reserve_fd_gid(fullpath); - module_file *file = (module_file*)hash_map_get(proc_opened_files, &fid, sizeof(fid)); - if (file) { - file->buf = (uptr)proc->output; - file->file_buffer.buffer = (char*)proc->output; - file->file_buffer.buffer_size = proc->output_size; - file->file_buffer.limit = PROC_OUT_BUF; - file->file_buffer.cursor = proc->output_size; - file->file_buffer.options = buffer_circular; - file->file_size = proc->output_size; - } - } - - irq_restore(irq); - return written; - } - - if (!proc_opened_files){ - kprint("No files open"); - return 0; - } - irq_flags_t irq = irq_save_disable(); - module_file *file = (module_file*)hash_map_get(proc_opened_files, &fd->id, sizeof(uint64_t)); - bool ro = file && file->read_only; - irq_restore(irq); - if (!file) return 0; - if (ro) return 0; - return 0; -} - -extern bool process_can_reset(process_t *proc); -extern bool process_has_runtime_state(process_t *proc); - -void close_proc(file *fd) { - if (!fd) return; - if (!proc_opened_files) return; - - uint64_t fid = fd->id; - process_t *reset_proc = 0; - irq_flags_t irq = irq_save_disable(); - module_file *mfile = (module_file*)hash_map_get(proc_opened_files, &fid, sizeof(fid)); - if (!mfile) { - irq_restore(irq); - return; - } - - procfs_owner *owner_info = (procfs_owner*)mfile->private_data; - process_t *owner = 0; - if (owner_info && owner_info->proc && owner_info->proc->id == owner_info->pid) owner = owner_info->proc; - if (owner) { - if (owner->procfs_refs) owner->procfs_refs--; - if (process_can_reset(owner) && process_has_runtime_state(owner)) reset_proc = owner; - } - - if (mfile->references > 0) mfile->references--; - if (mfile->references == 0) { - void *owned = mfile->file_buffer.buffer; - buffer_options options = mfile->file_buffer.options; - bool owned_postmortem = owner && owned == (void*)owner->postmortem_output; - hash_map_remove(proc_opened_files, &fid, sizeof(fid), 0); - irq_restore(irq); - if (owned && options == buffer_opt_none && !(reset_proc && owned_postmortem)) { - release(owned); - if (owned_postmortem) { - owner->postmortem_output = 0; - owner->postmortem_output_size = 0; - } - } - if (mfile->private_data) release(mfile->private_data); - release(mfile); - if (reset_proc) reset_process(reset_proc); - return; - } - irq_restore(irq); -} - -system_module procfs_mod = (system_module){ - .name = "scheduler", - .mount = "proc", - .version = VERSION_NUM(0, 1, 0, 1), - .init = init_procfs, - .fini = 0, - .open = open_proc, - .read = read_proc, - .write = write_proc, - .close = close_proc, - .getstat = stat_proc, - .readdir = readdir_proc, -}; diff --git a/kernel/process/procfs.h b/kernel/process/procfs.h deleted file mode 100644 index 4949e529..00000000 --- a/kernel/process/procfs.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -#include "files/system_module.h" - -extern system_module procfs_mod; \ No newline at end of file diff --git a/kernel/process/scheduler.c b/kernel/process/scheduler.c index 5bab0b64..72f34af5 100644 --- a/kernel/process/scheduler.c +++ b/kernel/process/scheduler.c @@ -15,7 +15,7 @@ #include "memory/addr.h" #include "sysregs.h" #include "filesystem/filesystem.h" -#include "filesystem/modules/module_loader.h" +#include "filesystem/modules/fs_isolation.h" #include "string/string.h" #include "alloc/allocate.h" #include "files/dir_list.h" @@ -25,7 +25,7 @@ extern void save_pc_interrupt(uintptr_t ptr); extern void restore_context(uintptr_t ptr); -void *proc_mem_page; +void *proc_mem_page = 0; static inline void* proc_palloc(size_t s){ return palloc(s, MEM_PRIV_KERNEL, MEM_RW, true); @@ -124,8 +124,6 @@ void update_sleep_timer() { } else virtual_timer_disable(); } -extern uptr job_ksp; - void switch_proc(ProcSwitchReason reason) { syscall_depth = 0; if (proc_count == 0) @@ -158,9 +156,11 @@ void switch_proc(ProcSwitchReason reason) { next_proc = idle_proc; next_thread = &idle_proc->main_thread; } - if (!next_proc || !process_can_run(next_proc)) panic("no runnable process", 0); + + //TODO: the next two checks could be more lenient, just ensuring that we do panic if it happens a second time + if (!next_proc || !process_can_run(next_proc)) panic("No runnable process", 0); + if (!next_thread || next_thread->pid != next_proc->id) panic("No runnable thread", next_proc->id); - if (!next_thread || next_thread->pid != next_proc->id) next_thread = &next_proc->main_thread; next_proc->state = RUNNING; next_thread->state = RUNNING; current_proc = next_proc; @@ -172,10 +172,10 @@ void switch_proc(ProcSwitchReason reason) { } if (current_proc->mm.ttbr0) mmu_asid_ensure(¤t_proc->mm); + mmu_swap_kttbr(0); mmu_swap_ttbr(current_proc->mm.ttbr0 ? ¤t_proc->mm : 0); if (prev && prev != current_proc && prev != idle_proc && process_can_reset(prev)) reset_process(prev); - job_ksp = (uptr)ksp; process_restore(); } @@ -204,7 +204,7 @@ void prepare_process_restore(process_t *proc){ if (proc->main_thread.pc >= HIGH_VA) panic("user pc in kernel VA", proc->main_thread.pc); mmu_swap_ttbr(&proc->mm); mmu_ttbr0_enable_user(); - } else mmu_ttbr0_disable_user(); + } } void process_restore(){ @@ -333,7 +333,7 @@ void reset_process(process_t *proc){ sizedptr p = proc->packet_buffer.entries[k]; if (p.ptr) free_sizedptr(p); - proc->packet_buffer.entries[k] = (sizedptr){0}; + proc->packet_buffer.entries[k] = (sizedptr){}; } close_files_for_process(pid); @@ -354,78 +354,82 @@ void reset_process(process_t *proc){ if (proc->debug_lines.ptr) { pfree((void*)proc->debug_lines.ptr, proc->debug_lines.size); - proc->debug_lines = (sizedptr){0}; + proc->debug_lines = (sizedptr){}; } if (proc->debug_line_str.ptr) { pfree((void*)proc->debug_line_str.ptr, proc->debug_line_str.size); - proc->debug_line_str = (sizedptr){0}; - } - - if (proc_opened_files) { - //irq_flags_t irq = irq_save_disable(); - char proc_path[48] = {}; - string_format_buf(proc_path, sizeof(proc_path), "/%i/out", pid); - uint64_t fid = reserve_fd_gid(proc_path); - module_file *out_file = (module_file*)hash_map_get(proc_opened_files, &fid, sizeof(fid)); - if (out_file && (uintptr_t)out_file->file_buffer.buffer == (uintptr_t)proc->output) { - size_t snapshot_size = proc->output_size; - if (!snapshot_size) { - out_file->buf = 0; - out_file->file_buffer = (buffer){0}; - out_file->file_size = 0; - } else { - void *snapshot = zalloc(snapshot_size+1); + proc->debug_line_str = (sizedptr){}; + } + +#ifndef FEATURE_NEW_PROCFS + if (proc_opened_files) { + //irq_flags_t irq = irq_save_disable(); + char proc_path[48] = {}; + string_format_buf(proc_path, sizeof(proc_path), "/%i/out", pid); + uint64_t fid = reserve_fd_gid(proc_path); + module_file *out_file = (module_file*)hash_map_get(proc_opened_files, &fid, sizeof(fid)); + if (out_file && (uintptr_t)out_file->file_buffer.buffer == (uintptr_t)proc->output) { + size_t snapshot_size = proc->output_size; + if (!snapshot_size) { + out_file->buf = 0; + out_file->file_buffer = (buffer){0}; + } else { + void *snapshot = zalloc(snapshot_size+1); + if (snapshot) { + memcpy(snapshot, (void*)proc->output, snapshot_size); + ((char*)snapshot)[snapshot_size] = 0; + out_file->buf = (uptr)snapshot; + out_file->file_buffer = (buffer){ + .buffer = snapshot, + .buffer_size = snapshot_size, + .limit = snapshot_size, + .options = buffer_opt_none, + .cursor = 0, + }; + } else { + out_file->buf = 0; + out_file->file_buffer = (buffer){0}; + } + } + } + + string_format_buf(proc_path, sizeof(proc_path), "/%i/state", pid); + fid = reserve_fd_gid(proc_path); + module_file *state_file = (module_file*)hash_map_get(proc_opened_files, &fid, sizeof(fid)); + if (state_file && (uintptr_t)state_file->file_buffer.buffer == (uintptr_t)&proc->state) { + process_state *snapshot = (process_state*)zalloc(sizeof(proc->state)); if (snapshot) { - memcpy(snapshot, (void*)proc->output, snapshot_size); - ((char*)snapshot)[snapshot_size] = 0; - out_file->buf = (uptr)snapshot; - out_file->file_buffer = (buffer){ + *snapshot = STOPPED; + state_file->buf = (uptr)snapshot; + state_file->file_buffer = (buffer){ .buffer = snapshot, - .buffer_size = snapshot_size, - .limit = snapshot_size, + .buffer_size = sizeof(proc->state), + .limit = sizeof(proc->state), .options = buffer_opt_none, .cursor = 0, }; - out_file->file_size = snapshot_size; } else { - out_file->buf = 0; - out_file->file_buffer = (buffer){0}; - out_file->file_size = 0; + state_file->buf = 0; + state_file->file_buffer = (buffer){0}; } } - } - - string_format_buf(proc_path, sizeof(proc_path), "/%i/state", pid); - fid = reserve_fd_gid(proc_path); - module_file *state_file = (module_file*)hash_map_get(proc_opened_files, &fid, sizeof(fid)); - if (state_file && (uintptr_t)state_file->file_buffer.buffer == (uintptr_t)&proc->state) { - process_state *snapshot = (process_state*)zalloc(sizeof(proc->state)); - if (snapshot) { - *snapshot = STOPPED; - state_file->buf = (uptr)snapshot; - state_file->file_buffer = (buffer){ - .buffer = snapshot, - .buffer_size = sizeof(proc->state), - .limit = sizeof(proc->state), - .options = buffer_opt_none, - .cursor = 0, - }; - state_file->file_size = sizeof(proc->state); - } else { - state_file->buf = 0; - state_file->file_buffer = (buffer){0}; - state_file->file_size = 0; - } - } //irq_restore(irq); } +#endif if (proc->output) { - pfree((void*)proc->output, PROC_OUT_BUF); + pfree((void*)proc->output, PROC_STDIO_BUF); proc->output = 0; proc->output_size = 0; } + + if (proc->input) { + pfree((void*)proc->input, PROC_STDIO_BUF); + proc->input = 0; + proc->input_size = 0; + } +#ifdef BUG_RESET_TTBR0 if (proc->mm.ttbr0) { for (uint16_t i = 0; i < proc->mm.vma_count; i++) { vma *m = &proc->mm.vmas[i]; @@ -451,6 +455,7 @@ void reset_process(process_t *proc){ } proc->mm.vma_count = 0; } +#endif if (proc->alloc_map) { if (proc->mm.ttbr0) { @@ -478,7 +483,6 @@ void reset_process(process_t *proc){ proc->code = 0; proc->code_size = 0; proc->va = 0; - proc->out_fd = (file){0}; proc->win_id = 0; proc->win_fb_va = 0; @@ -572,7 +576,7 @@ process_t* init_process(){ return proc; } -void name_process(process_t *proc, const char *name){ +void name_process(process_t *proc, const char *name){//TEST: try making the name longer than 256 and ensure it's properly truncated and null-terminated if (!proc) return; memset(proc->name, 0, sizeof(proc->name)); @@ -629,6 +633,7 @@ void block_process(process_t *proc){ void resume_blocked_process(process_t *proc){ proc->suspended = false; enqueue_ready_thread(&proc->main_thread); + //TODO: this only executes the main thread, not other threads } uint16_t process_count(){ @@ -717,17 +722,3 @@ thread_t* new_thread(process_t *proc, thread_t *addr, u64 spsr, uptr entry_point addr->regs[30] = is_privileged(proc) ? (uptr)kernel_thread_return_trampoline : proc->shared_page+sizeof(u32); return addr; } - -bool load_process_module(process_t *p, system_module *m, bool global){//TODO: this doesn't belong here - if (!p->permissions.owned_fs_id) p->permissions.owned_fs_id = register_fs_id(); - module_root *root = get_fs_for_id(p->permissions.fs_id); - system_module *mod = zalloc(sizeof(system_module)); - memcpy(mod, m, sizeof(system_module)); - mod->name = string_from_literal(m->name).data; - mod->mount = string_from_literal(m->mount).data; - mod->owner = p->id; - bool ret = load_module_to(root, mod); - if (!ret) return false; - if (!global) return true; - return load_module(mod); -} diff --git a/kernel/process/scheduler.h b/kernel/process/scheduler.h index 01d7f99e..01aeaceb 100644 --- a/kernel/process/scheduler.h +++ b/kernel/process/scheduler.h @@ -3,7 +3,7 @@ #include "types.h" #include "process/process.h" #include "files/system_module.h" -#include "procfs.h" +#include "process_fs.h" typedef enum { INTERRUPT, diff --git a/kernel/process/signals/signals.c b/kernel/process/signals/signals.c index e42b54db..1bd963a9 100644 --- a/kernel/process/signals/signals.c +++ b/kernel/process/signals/signals.c @@ -1,19 +1,27 @@ #include "signals.h" #include "process/process.h" #include "process/scheduler.h" - +#include "process/debug.h" #include "console/kio.h" +#include "access/authorize.h" + +#define SIGNAL_DEBUG +#ifdef SIGNAL_DEBUG +#define sig_print(...) print(__VA_ARGS__) +#else +#define sig_print(...) +#endif bool register_signal_handler(process_t *proc, signal_types type, signal_handler handler){ if (proc->signal_handlers[type].pc){ - kprint("Signal already exists"); + kprint("[SIGNAL error] already exists"); return false; } if (!can_signal_be_handled(type)){ - kprint("Signal cannot be handled"); + kprint("[SIGNAL error] cannot be handled"); return false; } - kprint("Signal handler added"); + sig_print("[SIGNAL debug] handler added"); new_thread(proc, &proc->signal_handlers[type], proc->main_thread.spsr, (uptr)handler); return true; } @@ -21,12 +29,15 @@ bool register_signal_handler(process_t *proc, signal_types type, signal_handler bool send_signal_proc_proc(signal_types type, i64 value, process_t *source, process_t *destination){ if (!source || !destination || !type) return false; + if (!source->permissions.auth_id || !auth_valid(source->permissions.auth_id, auth_process_send_signals, resource_map_process(destination))) return false; + if (signal_is_immediate(type)){ handle_signal_default(destination, &(signal_info_t){ .sender = source->id, .type = type, .value = value, }); + sig_print("[SIGNAL] sent immediate signal by %i to %i",source->id, destination->id); return true; } @@ -41,7 +52,7 @@ bool send_signal_proc_proc(signal_types type, i64 value, process_t *source, proc }); switch_proc(YIELD); - + sig_print("[SIGNAL] sent signal by %i to %i",source->id, destination->id); return true; } @@ -53,11 +64,12 @@ bool handle_signal_default(process_t *proc, signal_info_t *info){ stop_process(proc->id, -SIG_KILL); return true; case SIG_STOP: - kprintf("Stop %s",proc->name); + sig_print("[SIGNAL debug] Stop %s",proc->name); block_process(proc); + debug_snapshot(proc, &proc->main_thread); return true; case SIG_CONT: - kprintf("Ready proc %s",proc->name); + sig_print("[SIGNAL debug] Ready proc %s",proc->name); resume_blocked_process(proc); return true; default: return false; diff --git a/kernel/process/stack_manager.c b/kernel/process/stack_manager.c index aed049a5..fe36726c 100644 --- a/kernel/process/stack_manager.c +++ b/kernel/process/stack_manager.c @@ -1,6 +1,7 @@ #include "stack_manager.h" #include "exceptions/exception_handler.h" #include "memory/mmu.h" +#include uptr next_stack_addr(process_t *proc){ if (is_privileged(proc)) return 0; @@ -29,15 +30,20 @@ void unmap_stack(process_t *proc, stack_t stack){ stack_t new_stack(process_t *proc){ uptr stack_top = 0; + size_t size = 0; if (is_privileged(proc)) { - void *st = palloc(stack_max, MEM_PRIV_KERNEL, MEM_RW, true); - stack_top = (uptr)st + stack_max; - register_allocation(proc->alloc_map, st, stack_max); - } else stack_top = next_stack_addr(proc); + size = kstack_max; + void *st = palloc(size, MEM_PRIV_KERNEL, MEM_RW, true); + stack_top = (uptr)st + size; + register_allocation(proc->alloc_map, st, size); + } else { + stack_top = next_stack_addr(proc); + size = stack_max; + } if (!stack_top) return (stack_t){}; - uptr stack_limit = stack_top - stack_max; - print("New stack at %llx-%llx",stack_limit,stack_top); + uptr stack_limit = stack_top - size; if (!is_privileged(proc) && !mm_add_vma(&proc->mm, stack_limit, stack_top, MEM_RW, VMA_KIND_STACK, VMA_FLAG_DEMAND)) return (stack_t){}; - return (stack_t){.top = stack_top, .size = stack_max, .max = stack_max}; + // print("New stack at %llx-%llx",stack_limit,stack_top); + return (stack_t){.top = stack_top, .size = size, .max = size}; } \ No newline at end of file diff --git a/kernel/process/stack_manager.h b/kernel/process/stack_manager.h index 96e7883c..e6d8cd58 100644 --- a/kernel/process/stack_manager.h +++ b/kernel/process/stack_manager.h @@ -4,6 +4,7 @@ #include "process.h" #define stack_max 0x100000 +#define kstack_max 0x10000 #define stack_max_addr 0x7ffffffff000ULL #define stack_distance (stack_max + PAGE_SIZE) #define stack_min_addr 0x100000000000ULL diff --git a/kernel/process/syscall.c b/kernel/process/syscall.c index 87739089..bbe44924 100644 --- a/kernel/process/syscall.c +++ b/kernel/process/syscall.c @@ -28,7 +28,6 @@ #include "sysregs.h" #include "memory/addr.h" #include "graphic_types.h" -#include "filesystem/modules/module_loader.h" #include "alloc/page_index.h" #include "process/uaccess.h" #include "filesystem/modules/fs_isolation.h" @@ -36,6 +35,9 @@ #include "theme/theme.h" #include "jobs/job_manager.h" #include "stack_manager.h" +#include "debug.h" +#include "debug/inspect.h" +#include "filesystem/pipe.h" int syscall_depth = 0; uintptr_t cpec; @@ -115,7 +117,12 @@ u64 syscall_pfree(process_t *ctx, thread_t *current_thread){ u64 syscall_printl(process_t *ctx, thread_t *current_thread){ SYSCALL_STR(str, PROC_X0, false); + size_t len = strlen(str); + if (len > UINT16_MAX) return 0; kprint((char*)str); + file fd2 = { .id = 2 }; + write_file(&fd2, str, len); + write_file(&fd2, "\r\n", 2); return 0; } @@ -142,22 +149,24 @@ u64 syscall_read_shortcut(process_t *ctx, thread_t *current_thread){ } u64 syscall_get_mouse(process_t *ctx, thread_t *current_thread){ - //TODO: we're not fully preventing the mouse from being read outside of proc's window (raw & buttons) if (sys_get_focused_pid() != ctx->id) return 0; SYSCALL_ARG(mouse_data, inp, PROC_X0, true); inp->raw = get_raw_mouse_in(); inp->raw.scroll = sys_read_scroll_current(); - inp->position = convert_mouse_position(get_mouse_pos()); + inp->position = get_mouse_pos(); + convert_mouse_position(inp); return 0; } uptr syscall_gpu_request_ctx(process_t *ctx, thread_t *current_thread){ + if (system_config.headless) return 0; SYSCALL_ARG(draw_ctx, win, PROC_X0, true); get_window_ctx(win); return 0; } u64 syscall_gpu_flush(process_t *ctx, thread_t *current_thread){ + if (system_config.headless) return 0; SYSCALL_ARG(draw_ctx, win, PROC_X0, true); commit_frame(win, 0, false); gpu_flush(); @@ -165,6 +174,7 @@ u64 syscall_gpu_flush(process_t *ctx, thread_t *current_thread){ } u64 syscall_gpu_resize_ctx(process_t *ctx, thread_t *current_thread){ + if (!system_config.use_windows) return 0; uint32_t width = (uint32_t)current_thread->PROC_X1; uint32_t height = (uint32_t)current_thread->PROC_X2; resize_window(width, height); @@ -192,7 +202,7 @@ u64 syscall_halt(process_t *ctx, thread_t *current_thread){ } u64 syscall_halt_thread(process_t *ctx, thread_t *current_thread){ - kprintf("Thread has ended with code %i",current_thread->PROC_X0); + // kprintf("Thread has ended with code %i",current_thread->PROC_X0); syscall_depth--; if (current_thread->job_id){ fulfill_job(current_thread->job_id, current_thread->PROC_X0, current_thread); @@ -365,6 +375,22 @@ u64 syscall_openf(process_t *ctx, thread_t *current_thread){ #endif } +u64 syscall_pipef(process_t *ctx, thread_t *current_thread){ + SYSCALL_STR(src, PROC_X0, false); + SYSCALL_STR(dst, PROC_X1, false); + pipe_options options = current_thread->PROC_X2; + SYSCALL_ARG(file,descriptor,PROC_X3, true); + module_root srcfs = {}, dstfs = {}; + string s = resolve_isolated_path(src, ctx->permissions.fs_id, &srcfs, ISOLATEDFS_ALLOW_KFS); + if (!s.data || !s.length || !srcfs.map) return 0; + string d = resolve_isolated_path(dst, ctx->permissions.fs_id, &dstfs, ISOLATEDFS_ALLOW_KFS); + if (!d.data || !d.length || !dstfs.map) return 0; + FS_RESULT res = create_pipe(&srcfs, s.data, &dstfs, d.data, options, descriptor); + string_free(s); + string_free(d); + return res; +} + u64 syscall_readf(process_t *ctx, thread_t *current_thread){ SYSCALL_ARG(file, descriptor, PROC_X0, true); size_t size = (size_t)current_thread->PROC_X2; @@ -379,6 +405,29 @@ u64 syscall_writef(process_t *ctx, thread_t *current_thread){ return write_file(descriptor, buf, size); } +u64 syscall_transf(process_t *ctx, thread_t *current_thread){ + SYSCALL_STR(path, PROC_X0, false); + size_t size = (size_t)current_thread->PROC_X2; + SYSCALL_ARG_SIZE(void, buf, size, PROC_X1, true); +#ifdef ISOLATEDFS + module_root rootfs = {}; + string s = resolve_isolated_path(path, ctx->permissions.fs_id, &rootfs, ISOLATEDFS_ALLOW_KFS); + if (!s.data || !s.length) return 0; + size_t ret = transform_file(&rootfs, s.data, buf, size); + string_free(s); + return ret; +#else + return transform_file(kernel_fs(), path, buf, size); +#endif +} + +u64 syscall_syncfd(process_t *ctx, thread_t *current_thread){ + SYSCALL_ARG(file, descriptor, PROC_X0, true); + bool replace = current_thread->PROC_X1; + sync_file(descriptor, replace); + return 0; +} + u64 syscall_sreadf(process_t *ctx, thread_t *current_thread){ SYSCALL_STR(path, PROC_X0, false); size_t size = (size_t)current_thread->PROC_X2; @@ -498,7 +547,12 @@ uint64_t syscall_unload_fsmod(process_t *ctx, thread_t *current_thread){ } u64 syscall_in_case_of_js(process_t *ctx, thread_t *current_thread){ - panic("Shame on you\r\n\ +#ifdef FEATURE_JS_PROTECTION +#define handle_js(...) panic(__VA_ARGS__) +#else +#define handle_js(N,...) print(N) +#endif + handle_js("Shame on you\r\n\ Don't ever do that again\r\n\ ....................../'¯/) \r\n\ ....................,/¯../ \r\n\ @@ -513,6 +567,13 @@ Don't ever do that again\r\n\ return 0; } +u64 syscall_thread_inspect(process_t *ctx, thread_t *current_thread){ + debug_inspect_types type = current_thread->PROC_X0; + u16 pid = current_thread->PROC_X1; + u16 tid = current_thread->PROC_X2; + return set_inspect(type, ctx, current_thread, pid, tid); +} + syscall_entry syscalls[] = { [PALLOC_CODE] = syscall_palloc, [PFREE_CODE] = syscall_pfree, @@ -540,6 +601,7 @@ syscall_entry syscalls[] = { [SOCKET_SEND_CODE] = syscall_socket_send, [SOCKET_RECEIVE_CODE] = syscall_socket_receive, [SOCKET_CLOSE_CODE] = syscall_socket_close, + [PIPE_OPEN_CODE] = syscall_pipef, [FILE_OPEN_CODE] = syscall_openf, [FILE_READ_CODE] = syscall_readf, [FILE_WRITE_CODE] = syscall_writef, @@ -549,6 +611,8 @@ syscall_entry syscalls[] = { [DIR_LIST_CODE] = syscall_dir_list, [FILE_STAT_CODE] = syscall_stat, [FILE_TRNC_CODE] = syscall_trunc, + [FILE_TRANS_CODE] = syscall_transf, + [FILE_SYNC_CODE] = syscall_syncfd, [LOAD_FSMODULE_CODE] = syscall_load_fsmod, [UNLOAD_FSMODULE_CODE] = syscall_unload_fsmod, @@ -556,47 +620,9 @@ syscall_entry syscalls[] = { [SIGNAL_HANDLER_CODE] = syscall_signal_handler, [IN_CASE_OF_JS_CODE] = syscall_in_case_of_js, + [THREAD_INSPECT_CODE] = syscall_thread_inspect, }; -bool decode_crash_address_with_info(uint8_t depth, uintptr_t address, sizedptr debug_line, sizedptr debug_line_str){ - if (!debug_line.ptr || !debug_line.size) return false; - debug_line_info info = dwarf_decode_lines(debug_line.ptr, debug_line.size, debug_line_str.ptr, debug_line_str.size, address); - if (info.address == address){ - kprintf("[%.16x] %i: %s %i:%i", address, depth, info.file, info.line, info.column); - return true; - } - return false; -} - -bool decode_crash_address(uint8_t depth, uintptr_t address, sizedptr debug_line, sizedptr debug_line_str){ - return decode_crash_address_with_info(depth, address, debug_line, debug_line_str) || - decode_crash_address_with_info(depth, address, get_kernel_proc()->debug_lines, get_kernel_proc()->debug_line_str); -} - -void backtrace(uintptr_t fp, uintptr_t elr, sizedptr debug_line, sizedptr debug_line_str) { - - if (elr){ - if (!decode_crash_address(0, elr, debug_line, debug_line_str)) - kprintf("Exception triggered by %llx",(elr)); - } - - for (uint8_t depth = 1; depth < 10 && fp; depth++) { - int tr_ra = 0; - uintptr_t ra_pa = mmu_translate(0, fp + 8, &tr_ra); - if (tr_ra) return; - - uintptr_t return_address = (*(uintptr_t*)dmap_pa_to_kva((paddr_t)ra_pa)); - if (!return_address) return; - return_address -= 4;//Return address is the next instruction after branching - if (!decode_crash_address(depth, return_address, debug_line, debug_line_str)) - kprintf("%i: caller address: %llx", depth, return_address); - int tr = 0; - uintptr_t fp_pa = mmu_translate(0, fp, &tr); - if (tr) return; - fp = *(uintptr_t*)dmap_pa_to_kva((paddr_t)fp_pa); - } -} - const char* fault_messages[] = { [0b000000] = "Address size fault in TTBR0 or TTBR1", [0b000100] = "Translation fault, 0th level", @@ -629,7 +655,7 @@ void coredump(uintptr_t esr, uintptr_t elr, uintptr_t far, uintptr_t sp){ if (!m) m = "Unknown fault"; kprint(m); process_t *proc = get_current_proc(); - backtrace(sp, elr, proc->debug_lines, proc->debug_line_str); + backtrace(proc->mm.ttbr0, sp, elr, proc->debug_lines, proc->debug_line_str); // for (int i = 0; i < 31; i++) // kprintf("Reg[%i - %x] = %x",i,&proc->regs[i],proc->regs[i]); @@ -688,7 +714,7 @@ void sync_el0_handler_c(){ if (syscall_depth < 3){ uint64_t ksp = 0; asm volatile ("mov %0, sp" : "=r"(ksp)); - kprintf("System has crashed. ESR: %llx. ELR: %llx. FAR: %llx. KSP: %llx", esr, elr, far, ksp); + kprintf("System has crashed. ESR: %llx. ELR: %llx. FAR: %llx. SP: %llx", esr, elr, far, ksp); coredump(esr, elr, far, ksp); } handle_exception("UNEXPECTED EXCEPTION", ec); @@ -702,10 +728,12 @@ void sync_el0_handler_c(){ } syscall_depth--; save_syscall_return(result); - // print("Return to %i",current_thread->pid); - if (current_thread->kstack_top) { - //TODO: schedule kstack_top to cleanup, but don't do immediately as we're in it - current_thread->kstack_top = 0; + if (current_thread->special_mm) { + //TODO: schedule specialmm to cleanup, but don't do immediately as we're in it + current_thread->special_mm = 0; + mmu_swap_kttbr(0); + mmu_flush_all(); + mmu_flush_icache(); } process_restore(); } @@ -719,5 +747,5 @@ void trace(){ asm volatile ("mrs %0, far_el1" : "=r"(far)); uint64_t sp; asm volatile ("mov %0, sp" : "=r"(sp)); - backtrace(sp, elr, (sizedptr){0,0}, (sizedptr){0,0}); + backtrace(0, sp, elr, (sizedptr){0,0}, (sizedptr){0,0}); } diff --git a/kernel/tests/allocation/alloc_tests.c b/kernel/tests/allocation/alloc_tests.c index fdbd86e0..f8e97087 100644 --- a/kernel/tests/allocation/alloc_tests.c +++ b/kernel/tests/allocation/alloc_tests.c @@ -102,9 +102,9 @@ bool test_kalloc_fragment_reuse() { } bool test_after_free(){ - uint64_t *a = malloc(64); + uint64_t *a = zalloc(64); a[3] = 12345678; - free_sized(a,64); + release(a); assert_eq(a[3], 0xDEADBEEFDEADBEEF, "Use after free failed: %x",a[3]); return true; } diff --git a/kernel/theme/default.h b/kernel/theme/default.h index 3b8cc3c3..b69afc1f 100644 --- a/kernel/theme/default.h +++ b/kernel/theme/default.h @@ -32,5 +32,6 @@ #define DEFAULT_PWD "hi" #define BG_COLOR 0xFF222233 +#define FG_COLOR 0xFFCCCCCC #define CURSOR_COLOR_DESELECTED 0xFFFFFFFF #define CURSOR_COLOR_SELECTED 0xFF9714DE \ No newline at end of file diff --git a/kernel/theme/theme.c b/kernel/theme/theme.c index 4cb7bc7f..a639a1fb 100644 --- a/kernel/theme/theme.c +++ b/kernel/theme/theme.c @@ -25,9 +25,11 @@ boot_theme_t boot_theme = { }; system_theme_t system_theme = { - .bg_color = BG_COLOR, - .accent_color = COLOR_WHITE, - .err_color = 0xFF000000, + .palette = { + .background = BG_COLOR, + .foreground = FG_COLOR, + .error = 0xFF000000, + }, .cursor_color_deselected = CURSOR_COLOR_DESELECTED, .cursor_color_selected = CURSOR_COLOR_SELECTED, .use_window_shadows = true, @@ -98,9 +100,10 @@ gpu_point* parse_gpu_point_array(char *value, size_t value_len){ #define parse_toml_str(k,dest) if ((size_t)strstart_case(#k, key.data,true) == key.length) dest.k = string_from_literal_length(value.data,value.length).data void parse_theme_kvp(string_slice key, string_slice value, void *context){ - parse_toml(bg_color, system_theme, parse_hex_u64); - parse_toml(accent_color, system_theme, parse_hex_u64); - parse_toml(err_color, system_theme, parse_hex_u64); + parse_toml(background, system_theme.palette, parse_hex_u64); + parse_toml(foreground, system_theme.palette, parse_hex_u64); + parse_toml(accent, system_theme.palette, parse_hex_u64); + parse_toml(error, system_theme.palette, parse_hex_u64); parse_toml(cursor_color_deselected, system_theme, parse_hex_u64); parse_toml(cursor_color_selected, system_theme, parse_hex_u64); parse_toml(use_window_shadows, system_theme, parse_int_u64); @@ -149,9 +152,9 @@ bool load_theme(){ read_toml(buf, parse_theme_kvp, 0); make_entry(DIR_AS_FILE, backing_virtual, entry_file, DATA_SIG_THEME, (buffer){ - .buffer = &system_theme, - .buffer_size = sizeof(system_theme_t), - .limit = sizeof(system_theme_t), + .buffer = &system_theme.palette, + .buffer_size = sizeof(theme_palette), + .limit = sizeof(theme_palette), .options = buffer_read_only }); diff --git a/kernel/theme/theme.h b/kernel/theme/theme.h index 2e866156..1bfcf8b2 100644 --- a/kernel/theme/theme.h +++ b/kernel/theme/theme.h @@ -3,6 +3,7 @@ #include "types.h" #include "graphic_types.h" #include "files/system_module.h" +#include "utils/theme.h" typedef struct { int logo_repeat; @@ -19,10 +20,9 @@ typedef struct { bool play_startup_sound; } boot_theme_t; + typedef struct { - u32 bg_color; - u32 accent_color; - u32 err_color; + theme_palette palette; u32 cursor_color_deselected; u32 cursor_color_selected; bool use_window_shadows; diff --git a/kernel/tools/monitor_processes.c b/kernel/tools/monitor_processes.c index 24dee29a..b48c3b3d 100644 --- a/kernel/tools/monitor_processes.c +++ b/kernel/tools/monitor_processes.c @@ -5,7 +5,7 @@ #include "input_keycodes.h" #include "syscalls/syscalls.h" #include "input/input_dispatch.h" -#include "ui/draw/draw.h" +#include "draw/draw.h" #include "std/string.h" #include "theme/theme.h" #include "memory/addr.h" @@ -70,15 +70,15 @@ void draw_memory(char *name,int x, int y, int width, int full_height, int used, int used_height = max((used * height) / size,1); - fb_fill_rect(&ctx,stack_top.x + 1, stack_top.y + height - used_height + 1, width - 2, used_height-1, system_theme.bg_color); + fb_fill_rect(&ctx,stack_top.x + 1, stack_top.y + height - used_height + 1, width - 2, used_height-1, system_theme.palette.background); string str = string_format("%s\n%x",(uintptr_t)name, used); - fb_draw_string(&ctx,str.data, stack_top.x, stack_top.y + height + 5, 2, system_theme.bg_color); + fb_draw_string(&ctx,str.data, stack_top.x, stack_top.y + height + 5, 2, system_theme.palette.foreground); string_free(str); } void draw_process_view(){ - fb_clear(&ctx,system_theme.bg_color+0x112211); + fb_clear(&ctx,system_theme.palette.background+0x112211); gpu_size screen_size = (gpu_size){ctx.width,ctx.height}; gpu_point screen_middle = {screen_size.width / 2, screen_size.height / 2}; @@ -123,11 +123,11 @@ void draw_process_view(){ int xo = (i * (screen_size.width / PROCS_PER_SCREEN)) + 50; - fb_draw_string(&ctx,name.data, xo, name_y, scale, system_theme.bg_color); - fb_draw_string(&ctx,state.data, xo, state_y, scale, system_theme.bg_color); + fb_draw_string(&ctx,name.data, xo, name_y, scale, system_theme.palette.foreground); + fb_draw_string(&ctx,state.data, xo, state_y, scale, system_theme.palette.foreground); string pc = string_from_hex(proc->main_thread.pc); - fb_draw_string(&ctx,pc.data, xo, pc_y, scale, system_theme.bg_color); + fb_draw_string(&ctx,pc.data, xo, pc_y, scale, system_theme.palette.foreground); string_free(pc); draw_memory("Stack", xo, stack_y, stack_width, stack_height, proc->main_thread.stack_info.top - proc->main_thread.sp, proc->main_thread.stack_info.size ? proc->main_thread.stack_info.size : 1); @@ -136,7 +136,7 @@ void draw_process_view(){ draw_memory("Heap", xo + stack_width + 50, stack_y, stack_width, stack_height, heap, heap_limit ? heap_limit : PAGE_SIZE); string flags = string_format("Flags: %x", proc->main_thread.spsr); - fb_draw_string(&ctx, flags.data, xo, flags_y, scale, system_theme.bg_color); + fb_draw_string(&ctx, flags.data, xo, flags_y, scale, system_theme.palette.foreground); string_free(name); string_free(state); string_free(flags); @@ -154,8 +154,6 @@ bool parse_args(int argc, char* argv[]){ for (int i = 1; i < argc; i++){ if (strcmp(argv[i],"gui") == 0){ visual = true; - ctx.width = 300; - ctx.height = 300; request_draw_ctx(&ctx); } else if (strcmp(argv[i],"-help") == 0 || strcmp(argv[i],"-h") == 0){ diff --git a/kernel/tools/tools.c b/kernel/tools/tools.c index 4a00bc52..f1cc3407 100644 --- a/kernel/tools/tools.c +++ b/kernel/tools/tools.c @@ -48,10 +48,14 @@ process_t* execute(const char* prog_name, int argc, const char* argv[], uint32_t i++; } - string executable = string_format("%s/%s.elf",prog_name,proc_name); - process_t *proc = load_elf_process_path(proc_name, prog_name, executable.data, argc, argv); - release(executable.data); - if (!proc) return 0; + process_t *proc = load_elf_process_path(proc_name, prog_name, prog_name, argc, argv); + if (!proc) { + //TODO: this should only be for .red + string executable = string_format("%s/%s.elf",prog_name,proc_name); + proc = load_elf_process_path(proc_name, prog_name, executable.data, argc, argv); + release(executable.data); + if (!proc) return 0; + } if (win_id) proc->win_id = win_id; if (transfer_focus) sys_set_focus(proc->id); @@ -84,27 +88,44 @@ process_t* execute(const char* prog_name, int argc, const char* argv[], uint32_t return 0; } -FS_RESULT open_tools(){ - return FS_RESULT_DRIVER_ERROR; -} - -size_t read_tools(){ - return 0; +size_t ktools_list(const char *path, void *buf, size_t size, file_offset *offset){ + file_offset off = offset ? *offset : 0; + fs_dir_list_helper helper = create_dir_list_helper(buf, size); + for (u64 i = off; i < N_ARR(available_cmds); i++){ + if (!dir_list_fill(&helper, available_cmds[i].name)){ + if (offset) *offset = i; + return dir_buf_size(&helper); + } + } + return dir_buf_size(&helper); } -size_t list_tools(const char *path, void *buf, size_t size, file_offset offset){ - return 0; +bool ktools_stat(const char *path, fs_stat *out_stat){ + if (strlen(path) && *path == '/') path++; + if (!strlen(path)){ + stat_dir(out_stat); + return true; + } + for (u64 i = 0; i < N_ARR(available_cmds); i++){ + if (strncmp(available_cmds[i].name, path, strlen(available_cmds[i].name)) == 0){ + out_stat->size = 0; + out_stat->data_type = DATA_SIGNATURE("KPROC"); + out_stat->type = entry_file; + return true; + } + } + return true; } -//TODO: finish listing tool module system_module tool_module = (system_module){ .name = "tools", - .mount = "tools", + .mount = "ktools", .version = VERSION_NUM(0, 1, 0, 1), .init = init_tools, .fini = 0, .open = 0, .read = 0, .write = 0, - .readdir = 0, + .getstat = ktools_stat, + .readdir = ktools_list, }; diff --git a/kernel/usb/USBKeyboard.cpp b/kernel/usb/USBKeyboard.cpp index 4f613401..6d25083c 100644 --- a/kernel/usb/USBKeyboard.cpp +++ b/kernel/usb/USBKeyboard.cpp @@ -113,7 +113,7 @@ void USBKeyboard::process_keypress(keypress *rkp){ if (now < next_repeat[key]) continue; kbd_event event = {}; - event.type = KEY_PRESS; + event.type = KEY_CONTINUE; event.key = (char)key; register_event(event); diff --git a/kernel/utils/clipboard/clipboard.c b/kernel/utils/clipboard/clipboard.c index f4d067e6..f889b974 100644 --- a/kernel/utils/clipboard/clipboard.c +++ b/kernel/utils/clipboard/clipboard.c @@ -1,9 +1,5 @@ #include "clipboard.h" -#include "data/struct/ring_buffer.h" -#include "files/buffer.h" -#include "syscalls/syscalls.h" #include "files/stack_fs.h" -#include "console/kio.h" system_module clipboard_mod = { .name = "clipboard", diff --git a/kernel/utils/cursor/cursor_manager.c b/kernel/utils/cursor/cursor_manager.c index 179d68e1..f44c8305 100644 --- a/kernel/utils/cursor/cursor_manager.c +++ b/kernel/utils/cursor/cursor_manager.c @@ -2,10 +2,18 @@ #include "syscalls/syscalls.h" #include "files/helpers.h" #include "image/bmp.h" +#include "draw/draw.h" +#include "graph/graphics.h" draw_ctx current_cursor; cursor_types current_cursor_type; +gpu_point cursor_offset; + +gpu_point cursor_offsets[cursor_count] = { + [cursor_crosshair] = {-32,-32} +}; + char *cursor_names[] = { [cursor_pointer] = "pointer.bmp", [cursor_crosshair] = "crosshair.bmp", @@ -23,7 +31,7 @@ void default_cursor(){ } bool switch_cursor(cursor_types type){ - if (current_cursor_type == type) return true; + if (current_cursor_type == type) return false; if (current_cursor.fb) release(current_cursor.fb); image_info info = {}; char *name = cursor_names[type]; @@ -31,6 +39,7 @@ bool switch_cursor(cursor_types type){ print("Cursor type %i not found",name); return false; } + cursor_offset = cursor_offsets[type]; string s = string_format("%s/%s",CURSOR_DIR,name); void *pixels = load_bmp(s.data, &info); string_free(s); diff --git a/kernel/utils/cursor/cursor_manager.h b/kernel/utils/cursor/cursor_manager.h index 95326d37..dde08013 100644 --- a/kernel/utils/cursor/cursor_manager.h +++ b/kernel/utils/cursor/cursor_manager.h @@ -17,9 +17,11 @@ typedef enum { // cursor_hresize, // cursor_wresize, // cursor_dresize, + cursor_count } cursor_types; extern cursor_types current_cursor_type; +extern gpu_point cursor_offset; void default_cursor(); bool switch_cursor(cursor_types); diff --git a/kernel/utils/language_support/language.c b/kernel/utils/language_support/language.c deleted file mode 100644 index 69c6c0c2..00000000 --- a/kernel/utils/language_support/language.c +++ /dev/null @@ -1,92 +0,0 @@ -#include "language.h" -#include "files/vfs.h" - -#define DATA_SYNTAX DATA_SIGNATURE("CODESNTX") -#define DATA_FORMAT DATA_SIGNATURE("CODEFMT") -#define DATA_AUTOCOMPLETE DATA_SIGNATURE("CODECMPL") -#define DATA_TEMPLATE DATA_SIGNATURE("CODETMPL") - -FS_RESULT syntax_highlight_open(const char *path, file *fd){ - if (path && *path == '/') path++; - if (!path || !strlen(path)) path = DIR_AS_FILE; - path_resolution resolution = parse_path(entries, path, path_resolution_forward, 0); - module_file *mfile = resolution.file; - if (!mfile) return FS_RESULT_NOTFOUND; - - if (!mfile->alias_info.alias_path.length){ - print("syntax highlighter should be aliased onto src"); - return FS_RESULT_SUCCESS; - } - - vfs_open_aliased(mfile, resolution, fd); - - fd->id = mfile->fid; - fd->size = 0x1000; - fd->data_type = DATA_SYNTAX; - fd->cursor = 0; - return FS_RESULT_SUCCESS; -} - -bool syntax_highlight_stat(const char *path, fs_stat *fstat){ - if (!fstat) return false; - if (path && *path == '/') path++; - if (!path || !strlen(path)) path = DIR_AS_FILE; - path_resolution resolution = parse_path(entries, path, path_resolution_forward, 0); - module_file *mfile = resolution.file; - if (!mfile) return false; - fstat->data_type = DATA_SYNTAX; - fstat->type = mfile->entry_type; - fstat->size = mfile->entry_type == entry_file ? 0x1000 : 0; - return true; -} - -size_t syntax_highlight(file *fd, char *buf, size_t size, file_offset off){ - module_file *mfile = find_entry(fd->id); - if (!mfile->alias_info.alias_fd.id) { - print("File should be aliased onto code"); - return 0; - } - char *contents = zalloc(mfile->alias_info.alias_fd.size); - readf(&mfile->alias_info.alias_fd, contents, mfile->alias_info.alias_fd.size); - - buffer write_buf = (buffer){.buffer = buf, .buffer_size = size, .limit = size}; - - size_t total = 0; - for (size_t i = 0; i < size; i++){ - char *instance = memmem(contents + i, size - i, "#include", 8); - if (!instance) break; - size_t new_i = instance - contents; - i = new_i; - size_t written = buffer_write_lim(&write_buf,(char*)&(text_format){ .foreground = 0xFFfcba03, .bounds = { i, 8 }}, sizeof(text_format)); - total += written; - if (written != sizeof(text_format)) return total; - } - - return total; -} - -bool lfsp_init(){ - make_complex_entry("src", backing_transform, entry_directory, DATA_SIG_RAW, (file_actions){}, string_from_literal("/home/projects/code/braincode")); - make_complex_entry("syntax", backing_transform, entry_directory, DATA_SYNTAX, (file_actions){ - .open = syntax_highlight_open, - .read = syntax_highlight, - .getstat = syntax_highlight_stat, - }, string_from_literal("/language/src")); - make_complex_entry("format", backing_transform, entry_directory, DATA_FORMAT, (file_actions){}, string_from_literal("/language/src")); - make_complex_entry("complete", backing_transform, entry_directory, DATA_AUTOCOMPLETE, (file_actions){}, string_from_literal("/language/src")); - make_complex_entry("template", backing_transform, entry_directory, DATA_TEMPLATE, (file_actions){}, string_from_literal("/language/src")); - return true; -} - -system_module language_mod = { - .name = "language support filesystem protocol", - .mount = "language", - .version = VERSION_NUM(0, 1, 0, 0), - .init = lfsp_init, - .open = vfs_open, - .close = vfs_close, - .read = vfs_read, - .write = vfs_write, - .getstat = vfs_stat, - .readdir = vfs_readdir, -}; \ No newline at end of file diff --git a/kernel/utils/language_support/language.h b/kernel/utils/language_support/language.h deleted file mode 100644 index 876be9f8..00000000 --- a/kernel/utils/language_support/language.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -#include "files/system_module.h" - -extern system_module language_mod; \ No newline at end of file diff --git a/kernel/utils/utils.h b/kernel/utils/utils.h index d76fea3c..5cc72b75 100644 --- a/kernel/utils/utils.h +++ b/kernel/utils/utils.h @@ -1,9 +1,8 @@ #pragma once -#include "filesystem/modules/module_loader.h" +#include "filesystem/modules/fs_isolation.h" #include "clipboard/clipboard.h" -#include "language_support/language.h" #include "random/random.h" extern system_module termhistory_mod; @@ -11,7 +10,6 @@ extern system_module termhistory_mod; static inline bool load_util_mods(){ return load_module(&clipboard_mod) && - load_module(&language_mod) && load_module(&rng_module) && true; } \ No newline at end of file diff --git a/libs/LibMakefile b/libs/LibMakefile index 4e6a584c..9e5802a7 100644 --- a/libs/LibMakefile +++ b/libs/LibMakefile @@ -10,7 +10,7 @@ endif CFLAGS := $(CFLAGS_BASE) $(BASE_FLAGS) CLEAN_OBJS := $(shell find -name "*.o") -C_SRC := $(shell cat simplemake | xargs -n1 find . -name) +C_SRC := $(shell xargs -r -n1 printf './%s\n' < simplemake) OBJ := $(C_SRC:%.c=$(BUILD_DIR)/%.o) TARGET := $(shell echo "../lib$(notdir $(CURDIR)).a") diff --git a/libs/regex b/libs/regex deleted file mode 160000 index 85bc5e9f..00000000 --- a/libs/regex +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 85bc5e9ffbc390e7b41aadc98951a017cfe26861 diff --git a/libs/uno b/libs/uno new file mode 160000 index 00000000..183d751a --- /dev/null +++ b/libs/uno @@ -0,0 +1 @@ +Subproject commit 183d751a416b0b215e8ec1f5463e1c0eebcc8334 diff --git a/modules/MakefileModule b/modules/MakefileModule index 434ec1fd..987a4b25 100644 --- a/modules/MakefileModule +++ b/modules/MakefileModule @@ -1,4 +1,5 @@ include ../../common.mk +include ../../feature_flags.mk BASE_FLAGS := -I. -I../../kernel -I../../shared -DXHCI_CTX_SIZE=$(XHCI_CTX_SIZE) diff --git a/modules/audio/virt/audio.cpp b/modules/audio/virt/audio.cpp index f6d38000..21230ac6 100644 --- a/modules/audio/virt/audio.cpp +++ b/modules/audio/virt/audio.cpp @@ -65,7 +65,7 @@ static mixer_line mixin[MIXER_INPUTS]; static void mixer_reset_line(int8_t lineId){ if (lineId < 0 || lineId >= MIXER_INPUTS) return; - memset(mixin + lineId, 0, sizeof(mixer_line)); + memset(&mixin[lineId], 0, sizeof(mixer_line)); mixin[lineId].life = AUDIO_OFF; } @@ -110,7 +110,7 @@ static inline void buffer_exhausted(mixer_line* line, sizedptr* inbuf){ break; case AUDIO_ONESHOT_FREE: inbuf->ptr = NULL; - free_sized((void*)line->source.ptr, line->source.size); + release((void*)line->source.ptr); mixer_reset_line(line - mixin); break; case AUDIO_LOOP: @@ -314,5 +314,7 @@ system_module audio_module = (system_module){ .truncate = 0, .getstat = 0,//TODO: stat .readdir = 0, + .transform = 0, + //.permissions = fs_permission_shared, .alias_info = {} }; diff --git a/modules/disk/raspi/disk.cpp b/modules/disk/raspi/disk.cpp index 2d221c4b..7657ed89 100644 --- a/modules/disk/raspi/disk.cpp +++ b/modules/disk/raspi/disk.cpp @@ -36,5 +36,7 @@ system_module disk_module = (system_module){ .truncate = 0, .getstat = 0, .readdir = 0, + .transform = 0, + //.permissions = fs_permission_shared, .alias_info = {} }; \ No newline at end of file diff --git a/modules/graph/common/framebuffer/fbgpu.cpp b/modules/graph/common/framebuffer/fbgpu.cpp index 7bac66e7..ba3a9c09 100644 --- a/modules/graph/common/framebuffer/fbgpu.cpp +++ b/modules/graph/common/framebuffer/fbgpu.cpp @@ -60,26 +60,41 @@ void FBGPUDriver::setup_cursor(){ cursor_updated = true; } -#define cursor_loc(x,y,row) (((y + cy) * row) + (cx + x)) +#define cursor_loc(x,y,row) void FBGPUDriver::restore_below_cursor(){ if (!ctx.full_redraw){ - mark_dirty(&ctx, cursor_x, cursor_y, cursor_dim, cursor_dim); - flush(); + i32 x = cursor_x + cursor_offset.x; + i32 overfx = 0; + if (x < 0){ + overfx = x; + x = 0; + } + i32 y = cursor_y + cursor_offset.y; + i32 overfy = 0; + if (y < 0){ + overfy = y; + y = 0; + } + mark_dirty(&ctx, x, y, cursor_dim-overfx, cursor_dim-overfy); } + flush(); } void FBGPUDriver::update_cursor(uint32_t x, uint32_t y, bool full){ - if (x + cursor_dim >= screen_size.width || y + cursor_dim >= screen_size.height) return; draw_ctx cursor_ctx = cursor_pressed ? cursor_pressed_ctx : cursor_unpressed_ctx; if (cursor_updated){ restore_below_cursor(); } for (unsigned int cy = 0; cy < cursor_dim; cy++){ for (unsigned int cx = 0; cx < cursor_dim; cx++){ - uint32_t val = cursor_ctx.fb[cursor_loc(0, 0, cursor_dim)]; - if (val) - framebuffer[cursor_loc(x, y, screen_size.width)] = val; + uint32_t val = cursor_ctx.fb[((cy * cursor_dim) + cx)]; + if (val){ + i32 x_loc = ((x + cursor_offset.x) + cx); + i32 y_loc = ((y + cursor_offset.y) + cy); + if (y_loc < 0 || y_loc >= (i32)screen_size.height || x_loc < 0 || x_loc >= (i32)screen_size.width) continue; + framebuffer[(y_loc * screen_size.width) + x_loc] = val; + } } } cursor_x = x; diff --git a/modules/graph/common/gpu_driver.hpp b/modules/graph/common/gpu_driver.hpp index 73a37da3..2720d5a9 100644 --- a/modules/graph/common/gpu_driver.hpp +++ b/modules/graph/common/gpu_driver.hpp @@ -3,7 +3,7 @@ #include "types.h" #include "std/string.h" #include "graphic_types.h" -#include "ui/draw/draw.h" +#include "draw/draw.h" #define bpp 4 diff --git a/modules/graph/raspi/graphics.cpp b/modules/graph/raspi/graphics.cpp index 5f356d92..15b997ce 100644 --- a/modules/graph/raspi/graphics.cpp +++ b/modules/graph/raspi/graphics.cpp @@ -121,5 +121,7 @@ system_module graphics_module = { .truncate = 0, .getstat = 0,//TODO: stat .readdir = 0, + .transform = 0, + //.permissions = fs_permission_shared, .alias_info = {} }; \ No newline at end of file diff --git a/modules/graph/raspi/videocore.cpp b/modules/graph/raspi/videocore.cpp index 27b35e35..ddded7fc 100644 --- a/modules/graph/raspi/videocore.cpp +++ b/modules/graph/raspi/videocore.cpp @@ -2,7 +2,7 @@ #include "fw/fw_cfg.h" #include "memory/talloc.h" #include "console/kio.h" -#include "ui/draw/draw.h" +#include "draw/draw.h" #include "std/memory_access.h" #include "std/std.h" #include "std/memory.h" diff --git a/modules/graph/virt/graphics.cpp b/modules/graph/virt/graphics.cpp index 0c0dad13..b63d48a0 100644 --- a/modules/graph/virt/graphics.cpp +++ b/modules/graph/virt/graphics.cpp @@ -131,5 +131,7 @@ system_module graphics_module = { .truncate = 0, .getstat = 0, .readdir = 0, + .transform = 0, + //.permissions = fs_permission_shared, .alias_info = {} }; \ No newline at end of file diff --git a/modules/graph/virt/ramfb.cpp b/modules/graph/virt/ramfb.cpp index 1bda5887..906efd09 100644 --- a/modules/graph/virt/ramfb.cpp +++ b/modules/graph/virt/ramfb.cpp @@ -1,6 +1,6 @@ #include "ramfb.hpp" #include "console/kio.h" -#include "ui/draw/draw.h" +#include "draw/draw.h" #include "std/memory_access.h" #include "std/std.h" #include "std/memory.h" diff --git a/modules/graph/virt/virtio_gpu_pci.cpp b/modules/graph/virt/virtio_gpu_pci.cpp index 77ec8429..6499cc4f 100644 --- a/modules/graph/virt/virtio_gpu_pci.cpp +++ b/modules/graph/virt/virtio_gpu_pci.cpp @@ -1,7 +1,7 @@ #include "virtio_gpu_pci.hpp" #include "pci.h" #include "console/kio.h" -#include "ui/draw/draw.h" +#include "draw/draw.h" #include "std/std.h" #include "theme/theme.h" #include "memory/page_allocator.h" diff --git a/modules/serial/common/uart_base.c b/modules/serial/common/uart_base.c index f66453ec..3001c98e 100644 --- a/modules/serial/common/uart_base.c +++ b/modules/serial/common/uart_base.c @@ -80,6 +80,7 @@ u8 uart_get_byte(){ void uart_read_in(){ u8 c = uart_get_byte(); process_serial_input(c); + uart_putc(c); } void uart_puthex(uint64_t value) { diff --git a/modules/usb/common/usb_common.cpp b/modules/usb/common/usb_common.cpp index 9527131e..4c1eb1f8 100644 --- a/modules/usb/common/usb_common.cpp +++ b/modules/usb/common/usb_common.cpp @@ -86,5 +86,7 @@ system_module usb_module = (system_module){ .truncate = 0, .getstat = 0,//TODO: stat .readdir = 0, + .transform = 0, + //.permissions = fs_permission_shared, .alias_info = {} }; \ No newline at end of file diff --git a/services/Makefile b/services/Makefile new file mode 100644 index 00000000..85ecd230 --- /dev/null +++ b/services/Makefile @@ -0,0 +1,25 @@ +include ../common.mk + +SUBDIRS := $(wildcard */.) +SUBCLEAN = $(addsuffix .clean,$(SUBDIRS)) +SUBDUMP = $(addsuffix .dump,$(SUBDIRS)) +MAKEFILE := $(shell pwd)/ServiceMakefile + +all: $(SUBDIRS) + +dump: $(SUBDUMP) + +$(SUBDIRS): + $(MAKE) -f $(MAKEFILE) -C $@ + +clean: $(SUBCLEAN) + +$(SUBCLEAN): %.clean: + $(MAKE) -f $(MAKEFILE) -C $* clean + +$(SUBDUMP): %.dump: + $(MAKE) -f $(MAKEFILE) -C $* dump + +clean: $(SUBCLEAN) + +.PHONY: all $(SUBDIRS) diff --git a/services/ServiceMakefile b/services/ServiceMakefile new file mode 100644 index 00000000..e2639d2c --- /dev/null +++ b/services/ServiceMakefile @@ -0,0 +1,49 @@ +include ../../common.mk +include ../../feature_flags.mk + +CPPFLAGS := -I. -I../../shared -I../../libs +CFLAGS := $(CFLAGS_BASE) $(CPPFLAGS) +CXXFLAGS := $(CXXFLAGS_BASE) $(CPPFLAGS) +LDFLAGS := -emain + +CLEAN_OBJS := $(shell find . -name '*.o') +CLEAN_DEPS := $(shell find . -name '*.d') +C_SRC := $(shell find . -name '*.c') +OBJ := $(C_SRC:%.c=$(BUILD_DIR)/%.o) +DEP := $(C_SRC:%.c=$(BUILD_DIR)/%.d) + +NAME := $(notdir $(CURDIR)) +ELF := $(NAME).elf +TARGET := $(NAME).bin +LOCATION := ../../fs/redos/services/ +LIBRARIES := $(wildcard ../../libs/*.a) + +.PHONY: prepare all clean + +all: prepare $(TARGET) + +prepare: + mkdir -p $(LOCATION) + mkdir -p $(BUILD_DIR) + +$(TARGET): ../../shared/libshared.a $(OBJ) + $(VLD) $(LDFLAGS) -o $(ELF) $(addprefix $(BUILD_DIR)/,$(notdir $(OBJ))) $(LIBRARIES) ../../shared/libshared.a + $(OBJCOPY) -O binary $(ELF) $@ + cp -r $(ELF) $(LOCATION)/$(NAME) + +$(BUILD_DIR)/%.o: %.S + @mkdir -p $(dir $@) + $(VAS) $(CFLAGS) -c $< -o $@ + +$(BUILD_DIR)/%.o: %.c + @mkdir -p $(dir $@) + $(VCC) $(CFLAGS) -c -MMD -MP $< -o $@ + +clean: + $(RM) $(CLEAN_OBJS) $(CLEAN_DEPS) $(TARGET) $(ELF) + $(RM) -r $(BUILD_DIR) + +dump: all + $(ARCH)objdump -S $(ELF) > dump + +-include $(DEP) diff --git a/services/pacguy/apps.c b/services/pacguy/apps.c new file mode 100644 index 00000000..13d04263 --- /dev/null +++ b/services/pacguy/apps.c @@ -0,0 +1,70 @@ +#include "files/vfs.h" +#include "files/helpers.h" +#include "utils/package_info.h" +#include "data/format/toml.h" + +int manual_entries = 0; + +void handle_entry(const char *directory, const char *file) { + if (strlen(file) && *file == '.') return; + string fullpath = string_format("%s/%s",directory, file); + uint16_t ext_loc = find_find_extension_index((char*)file); + string_slice name = make_string_slice(fullpath.data, fullpath.length - strlen(file), ext_loc); + uint16_t extra = ext_loc ? 1 : 0; + string_slice ext = make_string_slice(name.data + ext_loc + 1, 0, strlen(file)-ext_loc-extra); + if (slice_lit_match(ext,"red",true)){ + print("Found file %s/%s",directory,file); + make_complex_entry(file, backing_virtual, entry_directory, DATA_SIG_REDPKG, (file_actions){}, fullpath); + } else string_free(fullpath); +} + +size_t resolve_fs(const char *path, void* buf, size_t size){ + char *prompt = buf; + (void)prompt; + size_t count = stack_count(entries); + for (u32 i = manual_entries; i < count; i++){ + module_file *file = chunk_array_get(entries, i); + if (file->alias_info.alias_path.data){ + string s = string_format("%S/package.info",file->alias_info.alias_path); + char *package = read_full_file(s.data, 0); + package_info pkg_info = parse_package_info(package); + if (slice_lit_match(slice_from_string(pkg_info.id), prompt, true)){ + if (size < file->alias_info.alias_path.length) { + package_info_dispose(&pkg_info); + return 0; + } + memcpy(buf, file->alias_info.alias_path.data, file->alias_info.alias_path.length); + package_info_dispose(&pkg_info); + return file->alias_info.alias_path.length; + } else package_info_dispose(&pkg_info); + release(package); + } + } + return 0; +} + +void refresh_apps(){ + if (!entries) entries = stack_create(sizeof(module_file),32); + size_t count = stack_count(entries); + for (size_t i = 0; i < count; i++){ + string_free(STACK_GET(module_file, entries, i).name); + string_free(STACK_GET(module_file, entries, i).alias_info.alias_path); + } + stack_reset(entries); + manual_entries += make_complex_entry("resolve", backing_virtual, entry_file, 0, (file_actions){.transform = resolve_fs}, (string){}) != 0; + traverse_directory("/home/applications", false, handle_entry); + traverse_directory("/boot/redos/system", false, handle_entry); +} + +system_module apps_mod = { + .name = "apps folder", + .mount = "apps", + //TODO: can init be brought back now? + .version = VERSION_NUM(0, 1, 0, 0), + .open = vfs_open, + .read = vfs_read, + .write = vfs_write, + .getstat = vfs_stat, + .readdir = vfs_readdir, + .transform = vfs_trace_transform, +}; \ No newline at end of file diff --git a/services/pacguy/main.c b/services/pacguy/main.c new file mode 100644 index 00000000..5e722bda --- /dev/null +++ b/services/pacguy/main.c @@ -0,0 +1,20 @@ +#include "syscalls/syscalls.h" +#include "files/system_module.h" + +extern void refresh_apps(); +extern system_module apps_mod; + +extern void refresh_tools(); +extern system_module tools_mod; + +int main(int argc, char* argv[]){ + refresh_apps(); + load_fsmodule(&apps_mod, true); + + refresh_tools(); + load_fsmodule(&tools_mod, true); + + while (true){} + + return 0; +} \ No newline at end of file diff --git a/services/pacguy/tools.c b/services/pacguy/tools.c new file mode 100644 index 00000000..c803c2be --- /dev/null +++ b/services/pacguy/tools.c @@ -0,0 +1,35 @@ +#include "files/system_module.h" +#include "files/vfs.h" +#include "files/helpers.h" + +void tools_handle_entry(const char *directory, const char *file) { + print("Found tool %s",file); + if (strlen(file) && *file == '.') return; + string fullpath = string_format("%s/%s",directory, file); + make_complex_entry(file, backing_virtual, entry_file, DATA_SIG_REDPKG, (file_actions){}, fullpath); +} + +void refresh_tools(){ + if (!entries) entries = stack_create(sizeof(module_file),32); + size_t count = stack_count(entries); + for (size_t i = 0; i < count; i++){ + string_free(STACK_GET(module_file, entries, i).name); + string_free(STACK_GET(module_file, entries, i).alias_info.alias_path); + } + stack_reset(entries); + traverse_directory("/home/tools", false, tools_handle_entry); + traverse_directory("/boot/redos/tools", false, tools_handle_entry); + traverse_directory("/ktools", false, tools_handle_entry); +} + +system_module tools_mod = { + .name = "tools folder", + .mount = "tools", + //TODO: can init be brought back now? + .version = VERSION_NUM(0, 1, 0, 0), + .open = vfs_trace_open, + .read = vfs_trace_read, + .write = vfs_trace_write, + .getstat = vfs_trace_stat, + .readdir = vfs_trace_readdir, +}; \ No newline at end of file diff --git a/shared b/shared index 1442cef4..0ab96dc6 160000 --- a/shared +++ b/shared @@ -1 +1 @@ -Subproject commit 1442cef44fcf72143332558c5f86be9f7d9f6ca6 +Subproject commit 0ab96dc642636feb6e171734f692660f470cb4aa diff --git a/tools/ToolMakefile b/tools/ToolMakefile index babdadd5..f38244a3 100644 --- a/tools/ToolMakefile +++ b/tools/ToolMakefile @@ -1,4 +1,5 @@ include ../../common.mk +include ../../feature_flags.mk CPPFLAGS := -I. -I../../shared -I../../libs CFLAGS := $(CFLAGS_BASE) $(CPPFLAGS) diff --git a/tools/launch/launch.c b/tools/launch/launch.c new file mode 100644 index 00000000..164753e7 --- /dev/null +++ b/tools/launch/launch.c @@ -0,0 +1,33 @@ +#include "syscalls/syscalls.h" +#include "memory/memory.h" + +int main(int argc, const char* argv[]){ + + if (argc < 2){ + print("Usage: launch bundle.id"); + return -1; + } + + const char* bundle_id = argv[1]; + size_t bsize = strlen(bundle_id)+1; + + if (bsize > 64){ + print("Bundle id too large"); + return -1; + } + + char *buf = zalloc(512); + memcpy(buf, bundle_id, bsize); + + transformf("/apps/resolve", buf, 512); + + print("Resolved id to %s",buf); + + fs_stat out_stat = {}; + if (statf(buf, &out_stat)){ + exec(buf, 0, 0, EXEC_MODE_DEFAULT); + return 0; + } + + return -1; +} diff --git a/tools/manual/main.c b/tools/manual/main.c index d627465f..9c60841d 100644 --- a/tools/manual/main.c +++ b/tools/manual/main.c @@ -2,6 +2,7 @@ #include "files/helpers.h" #include "data/format/scanner/scanner.h" #include "regex/regex.h" +#include "regex/regexlang.h" #include "memory/memory.h" void markdown_sections(string_slice document, void (*on_section)(int size, string_slice title, string_slice content)){ @@ -82,9 +83,23 @@ void find_page_file(const char *directory, const char *file){ string_free(s); } +regex_node annotation_pattern[] = { + REGEX_MATCH('!', REGEX_ADVANCE, REGEX_FAIL), + REGEX_MATCH('[', REGEX_ADVANCE, REGEX_FAIL), + REGEX_CAPTURE( + REGEX_NOT(']', REGEX_STAY, REGEX_ADVANCE) + ), + REGEX_MATCH(']', REGEX_ADVANCE, REGEX_FAIL), + REGEX_MATCH('(', REGEX_ADVANCE, REGEX_FAIL), + REGEX_CAPTURE( + REGEX_NOT(')', REGEX_STAY, REGEX_ADVANCE) + ), + REGEX_MATCH(')', REGEX_ADVANCE, REGEX_FAIL), +}; + int main(int argc, strarr argv){ - annotation_regex = init_regex("!\\[(^\\]*)\\]\\((^\\)*)\\)"); + annotation_regex = init_manual_regex(annotation_pattern, N_ARR(annotation_pattern)); if (argc > 1){ seek_section = slice_from_literal(argv[1]); diff --git a/user/UserMakefile b/user/UserMakefile index da135fa9..fa6e5829 100644 --- a/user/UserMakefile +++ b/user/UserMakefile @@ -1,6 +1,6 @@ include ../../common.mk -CPPFLAGS := -I. -I../../shared +CPPFLAGS := -I. -I../../shared -I../../libs CFLAGS := $(CFLAGS_BASE) $(CPPFLAGS) CXXFLAGS := $(CXXFLAGS_BASE) $(CPPFLAGS) LDFLAGS := -emain @@ -17,6 +17,7 @@ ELF := $(NAME).elf TARGET := $(NAME).bin PACKAGE := $(NAME).red LOCATION := ../../fs/redos/system/ +LIBRARIES := $(wildcard ../../libs/*.a) .PHONY: prepare all clean @@ -27,9 +28,10 @@ prepare: mkdir -p $(BUILD_DIR) mkdir -p $(PACKAGE) cp -r resources $(PACKAGE) + cp package.info $(PACKAGE)/package.info 2>/dev/null || : $(PACKAGE)/$(TARGET): ../../shared/libshared.a $(OBJ) - $(VLD) $(LDFLAGS) -o $(PACKAGE)/$(ELF) $(addprefix $(BUILD_DIR)/,$(notdir $(OBJ))) ../../shared/libshared.a + $(VLD) $(LDFLAGS) -o $(PACKAGE)/$(ELF) $(addprefix $(BUILD_DIR)/,$(notdir $(OBJ))) $(LIBRARIES) ../../shared/libshared.a $(OBJCOPY) -O binary $(PACKAGE)/$(ELF) $@ cp -r $(PACKAGE) $(LOCATION) diff --git a/user/debugger/main.c b/user/debugger/main.c new file mode 100644 index 00000000..eb2aec89 --- /dev/null +++ b/user/debugger/main.c @@ -0,0 +1,155 @@ +#include "syscalls/syscalls.h" +#include "input_keycodes.h" +#include "memory/memory.h" +#include "uno/uno.h" +#include "utils/theme.h" +#include "debug/proc.h" + +// - [x] control the program's execution +// - [] get proc's information /proc/id/info +// - [x] read the log +// - [-] trace +// - [] step +// - [] exception handling +// - [] inspect memory /proc/id/mem/addr <- read +// - [] modify memory /proc/id/mem/addr <- write + +// - [] breakpoints +// - [] watchpoints +// + +buffer proc_out_buf; + +enum { + button_none, + button_pauseplay, +}; + +void toggle_proc(int tag, gpu_point loc){ + print("Pressed"); +} + +i32 proc_state = 0; +u16 proc_id = 0; + +button_info pp_button = {.press = toggle_proc }; + +theme_palette theme; + +gpu_point log_scroll = {.x = -30}; + +proc_info info = {}; + +text_field_info log_text_info = { + .content = &proc_out_buf, +}; + +void view_builder(){ + VERTICAL(((node_info){.bg_color = theme.background, .sizing_rule = size_fill}), { + HORIZONTAL((node_info){},{ + uno_button(button_pauseplay, (node_info){.bg_color = proc_state == PROC_READY || proc_state == PROC_RUNNING ? 0xFFcc0000 : 0xFF00cc00, .padding = 5}, &pp_button, SLICE(proc_state == PROC_READY || proc_state == PROC_RUNNING ? "|" : ">")); + uno_label((node_info){.fg_color = theme.foreground, .padding = 5}, doc_text_body, (string_slice){info.procname,info.procnamelen}); + }); + uno_text_field(2, (node_info){ .sizing_rule = size_fill, .fg_color = theme.foreground, .offset = &log_scroll, .type = doc_text_body }, &log_text_info); + }); +} + +int main(int argc, char* argv[]){ + + if (argc < 2) return -1; + + char *proc_id_str = argv[1]; + + proc_id = parse_int_u64(proc_id_str, strlen(proc_id_str)); + + get_theme(&theme); + + thread_inspect(TINSPECT_CONTROL | TINSPECT_TRACE | TINSPECT_INFO | TINSPECT_STATE | TINSPECT_OUTPUT, proc_id, 1); + + string proc_out_s = string_format("/proc/%i/out", proc_id); + string proc_state_s = string_format("/proc/%i/state", proc_id);//TODO: Don't use sread, open and read + string proc_info_s = string_format("/proc/%i/info", proc_id); + sreadf(proc_state_s.data, &proc_state, sizeof(proc_state)); + + file proc_out_fd = {}; + if (openf(proc_out_s.data, &proc_out_fd) != FS_RESULT_SUCCESS) return false; + + file proc_info_fd = {}; + if (openf(proc_info_s.data, &proc_info_fd) != FS_RESULT_SUCCESS){ + print("Failed to open %S",proc_info_s); + return false; + } + + proc_out_buf = buffer_create(0x1000, buffer_can_grow); + + if (!proc_state){ + return 0; + } + + draw_ctx ctx = {}; + + request_draw_ctx(&ctx); + + uno_set_document_view(view_builder, draw_ctx_rect(&ctx)); + + bool running = true;//TODO: tie this with proc_state + + // char *prog_buf = zalloc(256); + // const char *bundle = "com.idsoftware.doom"; + // memcpy(prog_buf, bundle, strlen(bundle)); + + // transformf("/apps/resolve", prog_buf, 256); + + // exec(prog_buf, 0, 0, EXEC_MODE_DEFAULT); + + // print("App location: %s",prog_buf); + + while (true){ + + uno_draw(&ctx); + + char buf[256]; + size_t n = readf(&proc_out_fd, buf, 256); + + readf(&proc_info_fd, (char*)&info, proc_info_fd.size); + uno_refresh(); + + if (n){ + buffer_write_lim(&proc_out_buf, buf, n); + // for (u64 i = 0; i < n; i++) + // if (buf[i] == '\n') + log_scroll.y += fb_line_height(3);//TODO: this is too verbose + uno_refresh(); + } + + sreadf(proc_state_s.data, &proc_state, sizeof(proc_state)); + if (!proc_state){ + fb_clear(&ctx,0xff123456); + fb_draw_slice(&ctx, SLICE("Program exited. Goodbye"), 10, 50, 2, 0xFFcccccc); + commit_draw_ctx(&ctx); + msleep(3000); + return 0; + } + + commit_draw_ctx(&ctx); + + // if (running){ + // print("Sending sig"); + // send_signal(SIG_STOP, proc_id); + // running = false; + // } + + kbd_event ev = {}; + if (read_event(&ev)){ + if (ev.key == KEY_ESC) halt(0); + if (ev.key == KEY_F1 && ev.type == KEY_PRESS){ + if (running){ + send_signal(SIG_STOP, proc_id); + } else { + send_signal(SIG_CONT, proc_id); + } + running = !running; + } + } + } +} \ No newline at end of file diff --git a/user/debugger/package.info b/user/debugger/package.info new file mode 100644 index 00000000..5d33613b --- /dev/null +++ b/user/debugger/package.info @@ -0,0 +1,3 @@ +app_name = "Debugger" +app_author="[REDACTED]" +app_bundle_id="com.redos.debug" \ No newline at end of file diff --git a/user/demo/default_process.c b/user/demo/default_process.c index ca841dc2..2e1e2c37 100644 --- a/user/demo/default_process.c +++ b/user/demo/default_process.c @@ -13,6 +13,7 @@ #include "math/math.h" #include "draw/textdraw.h" #include "environment/env_types.h" +#include "utils/theme.h" draw_ctx ctx = {}; @@ -127,8 +128,8 @@ int file_sync(){ } int concurrent_write(){ - file fd1 = {}; - file fd2 = {}; + file fd1 = { .sync_type = cursor_sync_follow }; + file fd2 = { .sync_type = cursor_sync_follow }; openf("/tmp/std", &fd1); openf("/tmp/std", &fd2); @@ -147,13 +148,65 @@ int concurrent_write(){ seek(&fd1, 0, SEEK_ABSOLUTE); - readf(&fd1, buf, 64); - - print("Buffer now %s",buf); + size_t n = readf(&fd1, buf, 64); + + if (!slice_lit_match((string_slice){buf,n}, "firstonetwothree", false)){ + print("Slice |%v| does not match firstonetwothree",(string_slice){buf,n}); + shame(); + } return 0; } +int concurrent_write_proc(bool spawn){ + + if (spawn){ + const char* arg = "0xC0CE717E2"; + exec("/boot/redos/system/demo.red", 1, &arg, EXEC_MODE_KEEP_FOCUS); + } + + file fd = {.sync_type = cursor_sync_follow}; + + openf("/tmp/std", &fd); + + int total_written = 0; + + for (int i = 0; i < 100; i++){ + char buf[4]; + size_t n = string_format_buf(buf, 4, "%i\n", i); + size_t r = writef(&fd, buf, n); + total_written += r; + print("Writing %v: %i",(string_slice){buf,n},r); + msleep(0); + } + + msleep(0); + print("Total written by %i = %i",spawn,total_written); + + if (spawn){ + // fs_stat out_stat = {}; + // statf("/tmp/std", &out_stat); + // fd.size = out_stat.size; + // print("> %i %i",fd.cursor,fd.size); + // seek(&fd, 0, SEEK_ABSOLUTE); + // print("> %i %i",fd.cursor,fd.size); + // char *buf = zalloc(fd.size); + // size_t n = readf(&fd, buf, fd.size); + // print("Final result %i %s",n,buf); + print("%v",read_file_slice("/tmp/std")); + } + + return 0; +} + +int concurrent_write_parent(){ + return concurrent_write_proc(true); +} + +int concurrent_write_child(){ + return concurrent_write_proc(false); +} + int write_large_file(){ void *buf = zalloc(1024); @@ -184,6 +237,24 @@ int copypaste(){ } +int test_mouse(){ + while (true){ + mouse_data data = {}; + get_mouse_status(&data); + fb_clear(&ctx, 0xff0c0c0c); + kbd_event ev; + if (read_event(&ev)){ + if (ev.key == KEY_ESC) return 0; + } + color col = 0xffb4dd13; + if (data.raw.buttons & 1) col = 0xff674928; + if ((data.raw.buttons >> 1) & 1) col = 0xff398019; + if ((data.raw.buttons >> 2) & 1) col = 0xff029387; + fb_fill_rect(&ctx, data.position.x, data.position.y, 128 + data.raw.x, 128 + data.raw.y, col); + commit_draw_ctx(&ctx); + } +} + bool should_quit = false; bool on_quit(signal_info_t *do_not_use_this){ @@ -193,16 +264,86 @@ bool on_quit(signal_info_t *do_not_use_this){ return true; } -struct { char* name; int (*fn)(); } demos[] = { - {"Display image on screen", img_example}, - {"Networking demo", net_example}, - {"Audio demo", audio_example}, - {"Shared folder demo (requires 9Pfs)", file_sync}, - {"Concurrent writing to file (WIP)", concurrent_write}, - {"Write large file", write_large_file}, - {"Copy-paste to clipboard", copypaste}, +int log_test(){ + int count = 0; + while (true){ + fb_clear(&ctx, 0xff0c0c0c); + kbd_event ev; + if (read_event(&ev)){ + if (ev.key == KEY_ESC) return 0; + } + print("Log %i",count++); + commit_draw_ctx(&ctx); + } +} + +int pipe_source(){ + const char* arg = "0x919ED"; + print("Hello from source pipe"); + u16 id = exec("/boot/redos/system/demo.red", 1, &arg, EXEC_MODE_KEEP_FOCUS);//TODO: exec does not automatically add argv[0] as it should + thread_inspect(TINSPECT_INPUT, id, 1); + u16 own_id = 0; + sreadf("/proc/id",&own_id,sizeof(u16)); + string src = string_format("/proc/%i/out",own_id); + string dst = string_format("/proc/%i/in",id); + file pipe = {}; + pipef(src.data,dst.data, pipe_from_beginning, &pipe); + print("Piping %S into %S with fd %i",src,dst,pipe.id); + msleep(2000); + return 0; +} + +int pipe_destination(){ + print("Hello from destination pipe"); + size_t n = 0; + char buf[256]; + while (!n){ + n = readf(&(file){ + .id = FD_IN, + }, buf, 256); + } + string_slice msg = {buf,n}; + print("Received message %v",msg); + msleep(1000); + return 0; +} + +struct { u64 code; char* name; int (*fn)(); } demos[] = { + {0xC0CE717E1, "Concurrent write [Parent]", concurrent_write_parent}, + {0xC0CE717E2, "Concurrent write [Child]", concurrent_write_child}, + {0x919E5,"Pipe source", pipe_source}, + {0x919ED,"Pipe destination", pipe_destination}, + {0xD1591A1,"Display image on screen", img_example}, + // {0x0000000000000000,"Networking demo", net_example}, + {0xAD10,"Audio demo", audio_example}, + {0x5F01DE9,"Shared folder demo (requires 9Pfs)", file_sync}, + {0xC0CE7F11E,"Concurrent writing to file (WIP)", concurrent_write}, + {0xC0501E07,"Console output test",log_test}, + {0x917E1A96EF11E,"Write large file", write_large_file}, + {0xC099A57E,"Copy-paste to clipboard", copypaste}, + {0x05E7E57,"Mouse test",test_mouse}, }; +int run_code(u64 code){ + for (u64 i = 0; i < N_ARR(demos); i++){ + if (demos[i].code == code) + return demos[i].fn(); + } + return 0; +} + +char code_buf[18]; +u8 code_size = 0; + +void print_code(char c, gpu_point *cursor,gpu_rect rect, gpu_size *size, text_format text_fmt){ + if (code_size >= 18) return; + if ((c >= 'a' && c >= 'f') || (c >= '0' && c >= '9')) code_buf[code_size++] = c; + range_t range = {0,1}; + fb_continuous_draw_text(&ctx, draw_text_render, cursor, (string_slice){&c,1}, &range, rect, size, (gpu_point){}, text_fmt, (text_format_arr){ }); + ctx.full_redraw = true; + commit_draw_ctx(&ctx); +} + int main(int argc, char* argv[]){ handle_signal(SIG_QUIT, on_quit); @@ -226,7 +367,25 @@ int main(int argc, char* argv[]){ text_format text_fmt = {.scale = 3,.foreground = 0xFFFFFFFF,.background = 0xFF354657,.wrap = wrap_word}; - fb_clear(&ctx, 0xFF354657); + theme_palette palette = {}; + get_theme(&palette); + + fb_clear(&ctx, palette.background); + + if (argc > 0){ + char *id = argv[0]; + size_t l = strlen(id); + if (l >= 2 && !strncmp(id, "0x", 2)){ + u64 code = parse_hex_u64(id, l); + print("Executing code %llx",code); + return run_code(code); + } else { + u16 selection = parse_int_u64(id, 1); + if (selection < N_ARR(demos)){ + return demos[selection].fn(); + } + } + } gpu_size size = {}; fb_continuous_draw_text(&ctx, draw_text_render, &cursor, initial, &range, rect, &size, (gpu_point){}, text_fmt, (text_format_arr){ }); @@ -239,6 +398,7 @@ int main(int argc, char* argv[]){ string_free(f); } + bool code_mode = false; while (true) { commit_draw_ctx(&ctx); if (should_quit) { @@ -248,12 +408,34 @@ int main(int argc, char* argv[]){ kbd_event ev = {}; if (read_event(&ev)){ if (ev.type == KEY_PRESS){ - if (ev.key >= KEY_1 && ev.key <= (KEY_1 + count - 1)){ - int index = ev.key - KEY_1; - if (index >= 0 && index < count){ - fb_clear(&ctx, 0); - commit_draw_ctx(&ctx); - return demos[index].fn(); + if (ev.key == KEY_TAB){ + code_mode = !code_mode; + code_size = 0; + if (code_mode){ + print_code('\n',&cursor,rect,&size,text_fmt); + print_code('0',&cursor,rect,&size,text_fmt); + print_code('x',&cursor,rect,&size,text_fmt); + } + } + if (!code_mode){ + if (ev.key >= KEY_1 && ev.key <= (KEY_1 + count - 1)){ + int index = ev.key - KEY_1; + if (index >= 0 && index < count){ + fb_clear(&ctx, 0); + commit_draw_ctx(&ctx); + return demos[index].fn(); + } + } + } else { + if ((ev.key >= KEY_1 && ev.key <= KEY_0) || (hid_keycode_to_char[ev.key] >= 'a' && hid_keycode_to_char[ev.key] <= 'f')){ + if (code_size < 18){ + char c = hid_keycode_to_char[ev.key]; + print_code(c,&cursor,rect,&size,text_fmt); + } + } + if (ev.key == KEY_ENTER){ + u64 code = parse_hex_u64(code_buf, code_size); + return run_code(code); } } if (ev.key == KEY_ESC) halt(0); diff --git a/user/demo/package.info b/user/demo/package.info index 09b2ff74..cbe80f6f 100644 --- a/user/demo/package.info +++ b/user/demo/package.info @@ -1,10 +1,10 @@ # Name app_name = "Demo" -app_author="[REDACTED]" # Comments are allowed -unknown values="will be ignored" +unknown_values="will be ignored" -// C-style comments are allowed too + indentation="is ok" +app_author="[REDACTED]" - "indentation"=and no quotes \ No newline at end of file +app_bundle_id="com.redos.demo" \ No newline at end of file diff --git a/user/filebrowser/main.c b/user/filebrowser/main.c index 51b1b96f..4cf884a6 100644 --- a/user/filebrowser/main.c +++ b/user/filebrowser/main.c @@ -3,45 +3,27 @@ #include "input_keycodes.h" #include "data/struct/stack.h" #include "header_utils/filebrowser.h" -#include "files/vfs.h" +#include "utils/menu.h" -size_t test_fn(file *fd, const char *c, size_t s, file_offset off){ +size_t test_fn(const char *path, void *c, size_t s){ print("Test button pressed"); return 0; } -void menu_init(){ - make_entry("File", backing_virtual, entry_directory, 0, (buffer){}); - make_entry("File" "/" "Hello", backing_virtual, entry_file, 0, (buffer){}); - make_entry("Edit", backing_virtual, entry_directory, 0, (buffer){}); - make_entry("Edit/World", backing_virtual, entry_directory, 0, (buffer){}); - make_complex_entry("File/Test", backing_transform, entry_file, 0, (file_actions){.write = test_fn}, (string){}); -} - -size_t custom_readdir(const char *path, void *buf, size_t size, file_offset *offset){ - print(">>>>>>>Hello"); - size_t ret = vfs_readdir(path, buf, size, offset); - print(">>> %x",ret); - return ret; -} - -system_module menu_mod = { - .name = "demo menu", - .mount = "menu", - //TODO: can init be brought back now? - .version = VERSION_NUM(0, 1, 0, 0), - .open = vfs_open, - .read = vfs_read, - .write = vfs_write, - .getstat = vfs_stat, - .readdir = custom_readdir, -}; +MAKE_MENU({ + MENU_SUBMENU("File", { + MENU_SUBMENU("Hello", { + MENU_ITEM("World", 0) + }) + MENU_ITEM("Test", test_fn) + }) + MENU_SUBMENU("Edit", { + MENU_ITEM("Delete", 0) + }) +}) int main(){ menu_init(); - load_fsmodule(&menu_mod, false); - - swritef("/environment/menu", 0, 0, false); request_draw_ctx(&filebrowser_ctx); diff --git a/user/filebrowser/package.info b/user/filebrowser/package.info new file mode 100644 index 00000000..62c72342 --- /dev/null +++ b/user/filebrowser/package.info @@ -0,0 +1,3 @@ +app_name="File browser" +app_author="[REDACTED]" +app_bundle_id="com.redos.filebrowser" \ No newline at end of file diff --git a/user/launcher/Makefile b/user/launcher/Makefile index f169e16b..7b5caddb 100644 --- a/user/launcher/Makefile +++ b/user/launcher/Makefile @@ -1,4 +1,5 @@ include ../../common.mk +include ../../feature_flags.mk CPPFLAGS := -I. -I../../shared CFLAGS := $(CFLAGS_BASE) $(CPPFLAGS) diff --git a/user/launcher/main.c b/user/launcher/main.c index 5ae2c64b..7b48752a 100644 --- a/user/launcher/main.c +++ b/user/launcher/main.c @@ -6,7 +6,8 @@ #include "memory/memory.h" #include "input_keycodes.h" #include "string/slice.h" -#include "package_info.h" +#include "utils/package_info.h" +#include "utils/theme.h" #define MAX_COLS 3 #define MAX_ROWS 3 @@ -32,8 +33,8 @@ file active_proc; chunk_array_t *entries; bool process_active = false; draw_ctx ctx; -i32 bg_color; -i32 text_color; + +theme_palette palette; void *launcher_page = 0; @@ -63,6 +64,7 @@ package_info get_pkg_info(char* info_path){ package_info pkg = {}; char *info = read_full_file(info_path, 0); if (!info) return pkg; + print("Exists %s",info_path); pkg = parse_package_info(info); release(info); return pkg; @@ -76,7 +78,7 @@ void handle_entry(const char *directory, const char *file) { uint16_t extra = ext_loc ? 1 : 0; string_slice ext = make_string_slice(name.data + ext_loc + 1, 0, strlen(file)-ext_loc-extra); if (slice_lit_match(ext,"red",true)){ - string pkg_info = string_concat(fullpath, string_from_literal("/package.info")); + string pkg_info = string_format("%S/package.info", fullpath); add_entry(name, ext, fullpath, get_pkg_info(pkg_info.data)); // string_free(pkg_info); } @@ -94,8 +96,12 @@ void load_entries(){ string_free(entry->info.author); } chunk_array_reset(entries); - traverse_directory("/home/applications", false, handle_entry); +#ifdef BUG_CRASH_FSUS + traverse_directory("/apps",false, handle_entry); +#else traverse_directory("/boot/redos/system", false, handle_entry); + traverse_directory("/home/applications", false, handle_entry); +#endif } void draw_desktop(){ @@ -117,7 +123,7 @@ void draw_desktop(){ gpu_point old_selected = selected; kbd_event event; while (read_event(&event)){ - if (event.type == KEY_PRESS){ + if (event.type == KEY_PRESS || event.type == KEY_CONTINUE){ switch (event.key) { case KEY_ENTER: case KEY_KPENTER: @@ -145,7 +151,7 @@ void draw_desktop(){ void draw_full(){ if (!await_gpu()) return; - fb_clear(&ctx, bg_color+0x050505); + fb_clear(&ctx, palette.background+0x050505); for (uint32_t column = 0; column < MAX_COLS; column++){ for (uint32_t row = 0; row < MAX_ROWS; row++){ draw_tile(column, row); @@ -159,10 +165,8 @@ bool await_gpu(){ gpu_size screen_size = {ctx.width, ctx.height}; tile_size = (gpu_size){screen_size.width/MAX_COLS - 20, screen_size.height/(MAX_ROWS+1) - 20}; ready = true; - u32 color_buf[2] = { 0xFF222233, 0xFFFFFFFF }; - sreadf("/theme", &color_buf, sizeof(uint64_t)); - bg_color = color_buf[0]; - text_color = color_buf[1]; + palette = (theme_palette){ .background = 0xFF222233, .foreground = 0xFFFFFFFF }; + get_theme(&palette); } return ready; } @@ -200,14 +204,14 @@ void draw_tile(uint32_t column, uint32_t row){ DRAW( rectangle(&ctx, (rect_ui_config){ .border_size = (uint8_t)(sel ? 4 : 0), - .border_color = bg_color+0x333333, + .border_color = palette.background+0x333333, .border_padding = 0, }, (common_ui_config){ .point = (int_point){10 + (int32_t)((tile_size.width + 10)*column), 50 + (int32_t)((tile_size.height + 10) *row)}, .size = {tile_size.width, tile_size.height}, .horizontal_align = Leading, .vertical_align = Top, - .background_color = bg_color+0x111111, + .background_color = palette.background+0x111111, .foreground_color = 0 }), { diff --git a/user/launcher/package.info b/user/launcher/package.info new file mode 100644 index 00000000..ce7b7cd0 --- /dev/null +++ b/user/launcher/package.info @@ -0,0 +1,3 @@ +app_name="App launcher" +app_author="[REDACTED]" +app_bundle_id="com.redos.launcher" \ No newline at end of file diff --git a/user/launcher/package_info.c b/user/launcher/package_info.c deleted file mode 100644 index 88182067..00000000 --- a/user/launcher/package_info.c +++ /dev/null @@ -1,18 +0,0 @@ -#include "package_info.h" -#include "data/format/toml.h" - -static inline void handle_package_kvp(string_slice key, string_slice value, void* ctx){ - package_info *pkg_info = (package_info*)ctx; - if ((size_t)strstart_case("app_name", key.data,true) == key.length) - pkg_info->name = string_from_literal_length(value.data, value.length); - if ((size_t)strstart_case("app_author", key.data,true) == key.length) - pkg_info->author = string_from_literal_length(value.data, value.length); - if ((size_t)strstart_case("app_version", key.data,true) == key.length) - pkg_info->version = string_from_literal_length(value.data, value.length); -} - -package_info parse_package_info(char *info){ - package_info pkg_info = {}; - read_toml(info, handle_package_kvp, (void*)&pkg_info); - return pkg_info; -} \ No newline at end of file diff --git a/user/launcher/package_info.h b/user/launcher/package_info.h deleted file mode 100644 index 4a396f40..00000000 --- a/user/launcher/package_info.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include "types.h" -#include "std/string.h" - -typedef struct { - bool valid; - string name; - string author; - string version; -} package_info; - -#ifdef __cplusplus -extern "C" { -#endif -package_info parse_package_info(char *info); -#ifdef __cplusplus -} -#endif \ No newline at end of file diff --git a/user/monitor/main.c b/user/monitor/main.c new file mode 100644 index 00000000..efd0be11 --- /dev/null +++ b/user/monitor/main.c @@ -0,0 +1,138 @@ +#include "syscalls/syscalls.h" +#include "files/helpers.h" +#include "debug/proc.h" +#include "math/math.h" +#include "uno/uno.h" +#include "utils/theme.h" +#include "kbd_helper.h" +#include "debug/profiler.h" + +chunk_array_t *active_procs; + +void on_proc(const char *dir, const char *file){ + print("Process id %s",file); + + i64 proc_id = parse_int_u64(file, min(5,strlen(file))); + + if (proc_id > UINT16_MAX) return; + + string fmt = string_format("/proc/%i/info",proc_id); + + proc_info inf = {}; + + if (sreadf(fmt.data, &inf, sizeof(proc_info)) == sizeof(proc_info)){ + chunk_array_push(active_procs, &inf); + } + + string_free(fmt); +} + +theme_palette palette; + +chunk_array_t *strings_list; + +void render(){ + size_t proc_count = chunk_array_count(active_procs); + + if (!strings_list) strings_list = chunk_array_create(sizeof(string), 64); + else { + size_t string_count = chunk_array_count(strings_list); + for (u64 i = 0; i < string_count; i++) + string_free(CHUNK_ARRAY_GET(string, strings_list, i)); + chunk_array_reset(strings_list); + } + + VERTICAL((node_info){ + + }, { + for (u64 i = 0; i < proc_count; i++){ + proc_info *info = chunk_array_get(active_procs, i); + HORIZONTAL((node_info){}, { + uno_label((node_info){.fg_color = palette.foreground }, doc_text_body, SLICE("[")); + string id = string_format("%i ",info->id); + chunk_array_push(strings_list, &id); + uno_label((node_info){.fg_color = palette.foreground }, doc_text_body, slice_from_string(id)); + uno_label((node_info){.fg_color = palette.foreground }, doc_text_body, SLICE(info->state == PROC_READY || info->state == PROC_RUNNING ? "RUNNING" : "STOPPED")); + uno_label((node_info){.fg_color = palette.foreground }, doc_text_body, info->privilege ? SLICE(" K") : SLICE(" U")); + uno_label((node_info){.fg_color = palette.foreground }, doc_text_body, SLICE("] ")); + uno_label((node_info){.fg_color = palette.foreground }, doc_text_body, (string_slice){.data = info->procname, .length = info->procnamelen}); + string heap = string_format(" Memory: %llx",info->heap.size); + chunk_array_push(strings_list, &heap); + uno_label((node_info){.fg_color = palette.foreground}, doc_text_body, slice_from_string(heap)); + // string stack = string_format(" Stack: %llx",info->stack.size); + // chunk_array_push(strings_list, &stack); + // uno_label((node_info){.fg_color = palette.foreground}, doc_text_body, slice_from_string(stack)); + DEPTH((node_info){}, { + size_t total_size = 75; + uno_begin_horizontal((node_info){ + .sizing_rule = size_absolute, /* .padding = 10,*/ .bg_color = palette.background + 0x111111, .rect = (gpu_rect){ .size = {total_size,fb_line_height(text_to_scale(doc_text_body))}} + }); + uno_end_horizontal(); + size_t used_stack = (info->stack.ptr-info->sp); + size_t fill_size = total_size*((float)used_stack/info->stack.size); + if (used_stack && !fill_size) fill_size = 1; + uno_begin_horizontal((node_info){ + .sizing_rule = size_absolute, /* .padding = 10,*/ .bg_color = palette.background + 0x444444, .rect = (gpu_rect){ .size = {fill_size,fb_line_height(text_to_scale(doc_text_body))}} + }); + uno_end_horizontal(); + }); + }); + } + }); +} + +void refresh(){ + chunk_array_reset(active_procs); + traverse_directory("/proc", false, on_proc); + + uno_refresh(); +} + +void input(){ + kbd_event ev = {}; + if (read_event(&ev)){ + if (handle_modifier(&ev)) return; + if (ev.type != KEY_PRESS) return; + if (ev.key == KEY_ESC && is_mod_pressed(KEY_LEFTCTRL, true)){ + halt(0); + } + } +} + +int main(){ + + active_procs = chunk_array_create(sizeof(proc_info), 64); + + draw_ctx ctx = {}; + + request_draw_ctx(&ctx); + + uno_set_document_view(render, draw_ctx_rect(&ctx)); + + if (!get_theme(&palette)){ + palette.background = 0xFF222233; + palette.foreground = 0xFFCCCCCC; + } + + uno_clear_color(palette.background); + + refresh(); + + profiler_init(); + + i64 refresh_delta = 1000; + + while (true){ + uno_draw(&ctx); + commit_draw_ctx(&ctx); + refresh_delta -= profiler_delta(); + if (refresh_delta < 0){ + refresh(); + refresh_delta = 1000; + } + input(); + } + + return 0; + +} \ No newline at end of file diff --git a/user/monitor/package.info b/user/monitor/package.info new file mode 100644 index 00000000..4ef27ed4 --- /dev/null +++ b/user/monitor/package.info @@ -0,0 +1,7 @@ +app_name = "System Monitor" +app_author="[REDACTED]" +app_bundle_id="com.redos.monitor" + +app_entitlements=[ + "com.redos.process.info" +] \ No newline at end of file diff --git a/user/terminal/main.c b/user/terminal/main.c new file mode 100644 index 00000000..6082ea3e --- /dev/null +++ b/user/terminal/main.c @@ -0,0 +1,357 @@ +#include "syscalls/syscalls.h" +#include "draw/textdraw.h" +#include "shell/shell.h" +#include "shell/sheldon/sheldon.h" +#include "environment/env_types.h" +#include "data/serialize/binary_serial.h" +#include "kbd_helper.h" +#include "memory/memory.h" +#include "utils/embedded_fmt/tcf.h" +#include "files/helpers.h" +#include "header_utils/screenprinter.h" +#include "header_utils/composite.h" +#include "files/system_module.h" +#include "files/stack_fs.h" +#include "utils/theme.h" + +embedded_fmt input_format = {}; + +#define INPUT_MARGIN 10 +#define INPUT_HEIGHT (line_height+(INPUT_MARGIN*2)) + +int history_ptr = 0; +int history_count = 0; + +bool headless = false; + +bool cursor_on = false; +u64 cursor_blink_time = 500; + +theme_palette palette; + +buffer input_buf = {}; + +draw_ctx ctx = {}; + +gpu_rect screen_rect = {}; + +shell_handle* main_shell; + +void flush(shell_handle *handle, bool can_scroll); + +static char log_buf[1024]; + +int debug_print(const char *fmt, ...){ + __attribute__((aligned(16))) va_list args; + va_start(args, fmt); + memset(log_buf, 0, 1024); + size_t n = string_format_va_buf(fmt, log_buf, sizeof(log_buf), args); + va_end(args); + if (n >= sizeof(log_buf)) log_buf[sizeof(log_buf)-1] = '\0'; + printl(log_buf); + return 0; +} + +shell_handle* make_default_shell(shell_bindings bindings){ + return create_sheldon(bindings, 0, 0); +} + +void clear(shell_handle *handle){ + if (main_shell && main_shell != handle) return; + // buffer_wipe(&contents); + fb_clear(&ctx, screen_printer_formatting.current_bg_color); +} + +bool return_from_parse = false; + +void put_char(shell_handle *handle, char c){ + // print("New char %c %x %x %i",c,handle,main_shell,contents.cursor); + if (!c || (main_shell && main_shell != handle)) return; + bool render = true; + if (embedded_fmt_parse(&screen_printer_formatting, c)){ + render = false; + return_from_parse = true; + if (screen_printer_formatting.wipe){ + screen_printer_formatting.wipe = false; + clear(handle); + return; + } + } + if (!render) + return; + if (headless) + serial_transmit(c); + else { + screen_printer_put_char(c); + if (return_from_parse) flush(handle, true); + return_from_parse = false; + } +} + +void flush(shell_handle *handle, bool can_scroll){ + // print("Flush %v {%i,%i}",slice_from_buffer(&contents),rerender_range.start,rerender_range.size); + if (main_shell && main_shell != handle) return; + + screen_print_flush(can_scroll); +} + +void refresh_input(){ + fb_fill_rect(&ctx, 0, ctx.height-INPUT_HEIGHT, ctx.width, INPUT_HEIGHT, input_format.current_bg_color); + gpu_size offset = fb_draw_slice(&ctx, SLICE("> "), 0, ctx.height-INPUT_HEIGHT+INPUT_MARGIN, TEXT_SCALE, input_format.current_text_color); + fb_draw_slice(&ctx, slice_from_buffer(&input_buf), offset.width, ctx.height-INPUT_HEIGHT+INPUT_MARGIN, TEXT_SCALE, input_format.current_text_color); + if (cursor_on) + fb_fill_rect(&ctx, offset.width + (char_width * input_buf.cursor), ctx.height-INPUT_HEIGHT+INPUT_MARGIN, char_width, INPUT_HEIGHT-(INPUT_MARGIN*2), input_format.current_text_color); + commit_draw_ctx(&ctx); +} + +void bell(shell_handle *handle){ + if (main_shell && main_shell != handle) return; + print("DING"); +} + +void ascii_cmd(shell_handle *handle, char cmd, u16 proc_id){ + if (main_shell && main_shell != handle) return; + switch (cmd){ + case ASCII_CMD_ETX: + send_signal(SIG_QUIT, proc_id); + break; + case ASCII_CMD_SUB: + send_signal(SIG_STOP, proc_id); + break; + case ASCII_CMD_CAN: + send_signal(SIG_CONT, proc_id); + break; + default: break; + } +} + +void console_ctrl(shell_handle *handle, console_ctrls ctrl){ + if (main_shell && main_shell != handle) return; + switch (ctrl) { + case console_ctrl_close: halt(0); + default: break; + } +} + +void emit_data(structdef field, sizedptr data, bool is_allocated){ + // if (main_shell && main_shell != handle) return; + print("[TERMINAL implementation error] structured data displaying not implemented"); + // if (!data.ptr || !data.size) return; + // switch (field.type) { + // case binary_type_i8: print("%S: %i",field.name,*(i8*)data.ptr); break; + // case binary_type_i16: print("%S: %i",field.name,*(i16*)data.ptr); break; + // case binary_type_i32: print("%S: %i",field.name,*(i32*)data.ptr); break; + // case binary_type_i64: print("%S: %i",field.name,*(i64*)data.ptr); break; + // case binary_type_float: print("%S: %f",field.name,*(float*)data.ptr); break; + // case binary_type_double: print("%S: %f",field.name,*(double*)data.ptr); break; + // case binary_type_string: print("%S: %v",field.name,data); break; + // default: return; + // } + // if (is_allocated) release((void*)data.ptr); +} + +void flush_proxy(shell_handle *handle){ + flush(handle, true); +} + +shell_bindings terminal_bindings = (shell_bindings){ + .console_output = put_char, + .console_flush = flush_proxy, + .console_clean = clear, + .console_bell = bell, + .console_ascii_cmd = ascii_cmd, + .console_control = console_ctrl +}; + +shell_handle* create_shell(){ + shell_handle *handle = make_default_shell(terminal_bindings); + if (!handle) return 0; + return handle; +} + +bool erase(bool forward){ + if (forward && input_buf.cursor >= input_buf.buffer_size) return false; + if (!buffer_delete(&input_buf, input_buf.cursor + forward, 1)) return false; + + refresh_input(); + return true; +} + +bool run_command(){ + + bool success = false; + + screen_printer_append("\r\n"); + + write_full_file("/termhistory", input_buf.buffer, input_buf.buffer_size); + history_count++; + history_ptr = history_count; + + if (run_cmd(main_shell, slice_from_buffer(&input_buf))) success = true; + + buffer_wipe(&input_buf); + return success; +} + +bool move_buf_cursor(i64 amount){ + if (!amount) return false; + uptr old_in_c = input_buf.cursor; + if (buffer_seek(&input_buf, amount, false) == old_in_c) return false; + refresh_input(); + return true; +} + +bool scroll_history(i64 amount){ + int new_history_ptr = history_ptr + amount; + if (new_history_ptr < 0) new_history_ptr = 0; + string file = string_format("/termhistory/%i",new_history_ptr); + fs_stat st = {}; + if (statf(file.data, &st)){ + size_t hist_size = 0; + char *history = read_full_file(file.data, &hist_size); + if (input_buf.buffer) buffer_destroy(&input_buf); + input_buf = (buffer){ + .buffer = history, + .buffer_size = hist_size, + .limit = hist_size, + .options = buffer_can_grow, + .cursor = hist_size + }; + history_ptr = new_history_ptr; + return true; + } + buffer_wipe(&input_buf); + return false; +} + +void handle_mouse(){ + mouse_data data = {}; + get_mouse_status(&data); + if (data.raw.scroll){ + screen_print_scroll(data.raw.scroll, false); + } +} + +bool handle_input(){ + + handle_mouse(); + + kbd_event event; + if (!read_event(&event)) return false; + if (event.type == KEY_RELEASE) return true; + if (handle_modifier(&event)) return true; + + char key = event.key; + char readable = hid_to_char((uint8_t)key, current_modifier, special_key); + + if (key == KEY_ENTER || key == KEY_KPENTER) return run_command(); + + if (key == KEY_BACKSPACE) return erase(false); + if (key == KEY_DELETE) return erase(true); + + if (key == KEY_UP) return scroll_history(-1); + if (key == KEY_DOWN) return scroll_history(1); + + if (key == KEY_LEFT) return move_buf_cursor(-1); + if (key == KEY_RIGHT) return move_buf_cursor(1); + + if (key == KEY_PAGEDOWN || key == KEY_PAGEUP) + screen_print_scroll(key == KEY_PAGEDOWN ? -1 : 1, false); + + if (!readable) return false; + + if (!input_buf.buffer) input_buf = buffer_create(0x100, buffer_can_grow); + + buffer_write_lim(&input_buf, &readable, 1); + refresh_input(); + + flush(main_shell, true); + + return true; + +} + +void toggle_cursor(){ + cursor_on = !cursor_on; + refresh_input(); +} + +bool quit = false; + +bool termhistory_init(system_module *mod){ + printl("Mounting mod"); + // while (true) printl("I'm told to quit %i"); + return true; +} + +bool custom_stat(const char *path, fs_stat *out_stat){ + print("Stat %s into %x",path, out_stat); + stat_dir(out_stat); + return true; +} + +size_t custom_readdir(const char *path, void *buf, size_t size, file_offset *offset){ + print("READDIR %s info %x (%i) (%x)",path,buf,size,offset); + fs_dir_list_helper helper = create_dir_list_helper(buf, size); + dir_list_fill(&helper, "test"); + return dir_buf_size(&helper); +} + +system_module termhistory_mod = { + .name = "terminal history", + .mount = "termhistory", + .version = VERSION_NUM(0, 1, 0, 0), + .open = stackfs_open, + .read = stackfs_read, + .write = stackfs_write, + .readdir = custom_readdir, + .getstat = custom_stat +}; + +int main(){ + request_app_ctx(&ctx); + + screen_printer_init(dummy_draw_ctx(ctx.width, ctx.height-INPUT_HEIGHT)); + + stackfs_init(); + load_fsmodule(&termhistory_mod, true); + + get_theme(&palette); + if ((palette.background & 0xFF000000) == 0) palette.background |= 0xFF000000; + if ((palette.foreground & 0xFF000000) == 0) palette.foreground |= 0xFF000000; + screen_printer_formatting.default_bg_color = screen_printer_formatting.current_bg_color = palette.background; + screen_printer_formatting.default_text_color = screen_printer_formatting.current_text_color = palette.foreground; + + init_tcf(&screen_printer_formatting); + + memcpy(&input_format, &screen_printer_formatting, sizeof(text_format)); + + fb_clear(&ctx, screen_printer_formatting.current_bg_color); + + main_shell = create_shell(); + + current_shell = main_shell; + + u64 cursor_current = 0; + + u64 last_time = get_time(); + refresh_input(); + while (true){ + if (quit) halt(0); + // append("Bonjour %.3i \t",i++); + u64 current_time = get_time(); + cursor_current += (current_time-last_time); + if (cursor_current >= cursor_blink_time){ + toggle_cursor(); + cursor_current = 0; + } + last_time = current_time; + handle_input(); + msleep(1); + ctx.full_redraw = true; + composite(&printer_ctx, (int_point){}, 1, &ctx, draw_ctx_rect(&ctx)); + commit_draw_ctx(&ctx); + } + + return 0; +} \ No newline at end of file diff --git a/user/terminal/main.cpp b/user/terminal/main.cpp deleted file mode 100644 index f7c04074..00000000 --- a/user/terminal/main.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include "terminal.hpp" -#include "string/string.h" - -Terminal *term; - -int main(int argc, char **argv){ - term = new Terminal(); - if (argc && strncmp_case(argv[0], "headless", true, 8) == 0){ - print("Terminal in headless mode"); - term->headless = true; - } - while (1){ - term->update(); - } -} - -void term_put_char(shell_handle *handle, char c){ - if (!term || (term->term_current_shell && term->term_current_shell != handle)) return; - if (term->headless && c) - serial_transmit(c); - else - term->put_char(c); -} - -void term_clear(shell_handle *handle){ - if (!term || (term->term_current_shell && term->term_current_shell != handle)) return; - term->clear(); -} - -void term_flush(shell_handle *handle){ - if (!term || (term->term_current_shell && term->term_current_shell != handle)) return; - term->refresh(); -} - -void term_bell(shell_handle *handle){ - if (!term || (term->term_current_shell && term->term_current_shell != handle)) return; - term->bell(); -} - -void term_ascii_cmd(shell_handle *handle, char cmd, u16 proc_id){ - if (!term || (term->term_current_shell && term->term_current_shell != handle)) return; - term->interpret_cmd_code(cmd, proc_id); -} - -void term_console_ctrl(shell_handle *handle, console_ctrls ctrl){ - if (!term || (term->term_current_shell && term->term_current_shell != handle)) return; - term->ctrl(ctrl); -} - -void term_emit_data(structdef field, sizedptr data, bool is_allocated){ - if (!term) return; - term->emit_data(field,data,is_allocated); -} \ No newline at end of file diff --git a/user/terminal/package.info b/user/terminal/package.info new file mode 100644 index 00000000..05091c24 --- /dev/null +++ b/user/terminal/package.info @@ -0,0 +1,3 @@ +app_name="Terminal" +app_author="[REDACTED]" +app_bundle_id="com.redos.legacy.terminal" \ No newline at end of file diff --git a/user/terminal/terminal.cpp b/user/terminal/terminal.cpp deleted file mode 100644 index af67631c..00000000 --- a/user/terminal/terminal.cpp +++ /dev/null @@ -1,400 +0,0 @@ -#include "terminal.hpp" -#include "alloc/allocate.h" -#include "memory/memory.h" -#include "input_keycodes.h" -#include "shell/sheldon/sheldon.h" -#include "data/serialize/binary_serial.h" -#include "utils/embedded_fmt/tcf.h" - -Terminal::Terminal() : Console() { - uint32_t color_buf[2] = {}; - sreadf("/theme", &color_buf, sizeof(uint64_t)); - if ((color_buf[0] & 0xFF000000) == 0) color_buf[0] |= 0xFF000000; - current_format.default_bg_color = color_buf[0]; - current_format.current_bg_color = color_buf[0]; - current_format.default_text_color = color_buf[1]; - - char_scale = 2; - prompt_length = 2; - command_running = false; - - input_len = 0; - input_cursor = 0; - input_buf[0] = 0; - - history_len = 0; - history_index = 0; - for (uint32_t i = 0; i < history_max; i++) history[i] = nullptr; - - last_blink_ms = get_time(); - cursor_visible = true; - - dirty = false; - - term_current_shell = create_shell(); - init_tcf(¤t_format); - put_string("> "); - redraw_input_line(); - if (dirty) { - flush(dctx); - dirty = false; - } -} - -extern void term_put_char(shell_handle *handle, char c); -extern void term_clear(shell_handle *handle); -extern void term_flush(shell_handle *handle); -extern void term_bell(shell_handle *handle); -extern void term_ascii_cmd(shell_handle *handle, char cmd, u16 proc_id); -extern void term_console_ctrl(shell_handle *handle, console_ctrls ctrl); - -shell_handle* Terminal::create_shell(){ - shell_bindings terminal_bindings = (shell_bindings){ - .console_output = term_put_char, - .console_flush = term_flush, - .console_clean = term_clear, - .console_bell = term_bell, - .console_ascii_cmd = term_ascii_cmd, - .console_control = term_console_ctrl - }; - return create_sheldon(terminal_bindings, 0, 0); -} - -void Terminal::ctrl(console_ctrls ctrl){ - switch (ctrl) { - case console_ctrl_close: halt(0); - default: break; - } -} - -void Terminal::update(){ - if (!command_running) { - bool did = handle_input(); - if (!did) cursor_tick(); - } else { - end_command(); - } - - if (dirty) { - flush(dctx); - dirty = false; - } -} - -void Terminal::cursor_set_visible(bool visible){ - if (visible == cursor_visible) { - if (!visible) return; - if (last_drawn_cursor_x == (int32_t)current_format.cursor_x && last_drawn_cursor_y == (int32_t)current_format.cursor_y) return; - } - - cursor_visible = visible; - - if (last_drawn_cursor_x >= 0 && last_drawn_cursor_y >= 0) { - if ((uint32_t)last_drawn_cursor_x < columns && (uint32_t)last_drawn_cursor_y < rows) { - char *prev_line = &row_data[((scroll_row_offset + (u32)last_drawn_cursor_y) % rows) * columns]; - render_glyph(last_drawn_cursor_x*char_width, last_drawn_cursor_y * line_height, prev_line[last_drawn_cursor_x], current_format.current_text_color, current_format.current_bg_color, true); - } - last_drawn_cursor_x = -1; - last_drawn_cursor_y = -1; - } - - if (cursor_visible) { - fb_fill_rect(dctx, current_format.cursor_x * char_width, current_format.cursor_y * line_height, char_width, line_height, 0xFFFFFFFF); - last_drawn_cursor_x = (int32_t)current_format.cursor_x; - last_drawn_cursor_y = (int32_t)current_format.cursor_y; - } - - dirty = true; -} - -void Terminal::cursor_tick(){ - uint64_t now = get_time(); - if ((now - last_blink_ms) < 500) return; - last_blink_ms = now; - cursor_set_visible(!cursor_visible); -} - -void Terminal::redraw_input_line(){ - if (!check_ready()) return; - - uint32_t cw = (uint32_t)char_scale * CHAR_SIZE; - uint32_t lh = (uint32_t)char_scale * CHAR_SIZE * 2; - - fb_fill_rect(dctx, 0, current_format.cursor_y * lh, columns * cw, lh, current_format.current_bg_color); - - char* line = row_data + (((scroll_row_offset + current_format.cursor_y) % rows) * columns); - memset(line, 0, columns); - - if (columns == 0) return; - if (prompt_length >= (int)columns) return; - - line[0] = '>'; - line[1] = ' '; - - uint32_t max_input = columns - (uint32_t)prompt_length - 1; - uint32_t draw_len = input_len; - if (draw_len > max_input) draw_len = max_input; - - for (uint32_t i = 0; i < draw_len; i++) line[prompt_length + i] = input_buf[i]; - line[prompt_length + draw_len] = 0; - - uint32_t ypix = (current_format.cursor_y * lh) + (lh / 2); - fb_draw_char(dctx, 0, ypix, '>', char_scale, current_format.current_text_color); - fb_draw_char(dctx, cw, ypix, ' ', char_scale, current_format.current_text_color); - for (uint32_t i = 0; i < draw_len; i++) fb_draw_char(dctx, (prompt_length + i) * cw, ypix, input_buf[i], char_scale, current_format.current_text_color); - - if (input_cursor > draw_len) input_cursor = draw_len; - current_format.cursor_x = (uint32_t)prompt_length + input_cursor; - - last_blink_ms = get_time(); - cursor_set_visible(true); -} - -void Terminal::set_input_line(const char *s){ - input_len = 0; - input_cursor = 0; - - if (s) { - uint32_t i = 0; - while (s[i] && (i + 1) < input_max) { - input_buf[i] = s[i]; - i++; - } - input_len = i; - } - - input_buf[input_len] = 0; - input_cursor = input_len; - redraw_input_line(); -} - -void Terminal::end_command(){ - command_running = false; - if (last_char != '\r' && last_char != '\n'){ - put_char('\r'); - put_char('\n'); - } - put_string("> "); - prompt_length = 2; - - set_input_line(""); -} - -void Terminal::emit_data(structdef field, sizedptr data, bool is_allocated){ - if (!data.ptr || !data.size) return; - switch (field.type) { - case binary_type_i8: print("%S: %i",field.name,*(i8*)data.ptr); break; - case binary_type_i16: print("%S: %i",field.name,*(i16*)data.ptr); break; - case binary_type_i32: print("%S: %i",field.name,*(i32*)data.ptr); break; - case binary_type_i64: print("%S: %i",field.name,*(i64*)data.ptr); break; - case binary_type_float: print("%S: %f",field.name,*(float*)data.ptr); break; - case binary_type_double: print("%S: %f",field.name,*(double*)data.ptr); break; - case binary_type_string: print("%S: %v",field.name,data); break; - default: return; - } - if (is_allocated) release((void*)data.ptr); -} - -bool Terminal::exec_cmd(const char *cmd){ - if (!term_current_shell) return false; - - current_shell = term_current_shell; - - if (run_cmd(current_shell, slice_from_literal(cmd))) return true; - - return true; -} - -void Terminal::bell(){ - put_string("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); - refresh(); -} - -void Terminal::run_command(){ - if (input_len) { - if (history_len == history_max) { - if (history[0]) release(history[0]); - for (uint32_t i = 1; i < history_max; i++) history[i - 1] = history[i]; - history_len = history_max - 1; - } - - uint32_t n = input_len; - char *copy = (char*)zalloc(n + 1); - if (copy) { - memcpy(copy, input_buf, n); - copy[n] = 0; - history[history_len++] = copy; - } - } - history_index = history_len; - - put_char('\r'); - put_char('\n'); - - const char* fullcmd = input_buf; - while (*fullcmd == ' ' || *fullcmd == '\t') fullcmd++; - - if (*fullcmd == 0) { - command_running = true; - return; - } - - if (!exec_cmd(fullcmd)){ - const char *next = seek_to(fullcmd, ' '); - size_t len = next - fullcmd - (next && *(next-1) == ' ' ? 1 : 0); - string_slice cmd = (string_slice){ .data = (char*)fullcmd, .length = len }; - if (slice_lit_match(cmd, "exit", true) || slice_lit_match(cmd, "q", true)){ - halt(0); - } else { - string s = string_format("Unknown command %v", cmd); - put_string(s.data); - string_free(s); - } - } - - command_running = true; -} - -bool Terminal::interpret_cmd_code(char code, u16 proc){ - if (code == ASCII_CMD_ETX){ - send_signal(SIG_QUIT, proc); - return true; - } - if (code == ASCII_CMD_SUB){ - send_signal(SIG_STOP, proc); - return true; - } - if (code == ASCII_CMD_CAN){ - send_signal(SIG_CONT, proc); - } - return false; -} - -bool Terminal::handle_input(){ - kbd_event event; - if (!read_event(&event)) return false; - if (event.type == KEY_RELEASE) return true; - if (event.type != KEY_PRESS) return handle_modifier(&event); - - char key = event.key; - char readable = hid_to_char((uint8_t)key, current_modifier, special_key); - - if (command_running){ - return interpret_cmd_code(readable, 0); - } - - if (key == KEY_ENTER || key == KEY_KPENTER){ - run_command(); - return true; - } - - if (key == KEY_LEFT) { - if (input_cursor) input_cursor--; - current_format.cursor_x = (uint32_t)prompt_length + input_cursor; - last_blink_ms = get_time(); - cursor_set_visible(true); - return true; - } - - if (key == KEY_RIGHT) { - if (input_cursor < input_len) input_cursor++; - current_format.cursor_x = (uint32_t)prompt_length + input_cursor; - last_blink_ms = get_time(); - cursor_set_visible(true); - return true; - } - - if (key == KEY_UP) { - if (history_len && history_index) { - history_index--; - set_input_line(history[history_index]); - } - return true; - } - - if (key == KEY_DOWN) { - if (history_len) { - if (history_index + 1 < history_len) { - history_index++; - set_input_line(history[history_index]); - } else { - history_index = history_len; - set_input_line(""); - } - } - return true; - } - - if (key == KEY_BACKSPACE){ - if (!input_cursor) return true; - for (uint32_t i = input_cursor; i < input_len; i++) input_buf[i - 1] = input_buf[i]; - input_len--; - input_cursor--; - input_buf[input_len] = 0; - redraw_input_line(); - return true; - } - - if (key == KEY_DELETE) { - if (input_cursor >= input_len) return true; - for (uint32_t i = input_cursor + 1; i <= input_len; i++) input_buf[i - 1] = input_buf[i]; - input_len--; - redraw_input_line(); - return true; - } - - if (!readable) return true; - - uint32_t max_visible = 0; - if (columns > (uint32_t)prompt_length + 1) max_visible = columns - (uint32_t)prompt_length - 1; - if (input_len >= input_max - 1) return true; - if (max_visible && input_len >= max_visible) return true; - - for (uint32_t i = input_len; i > input_cursor; i--) input_buf[i] = input_buf[i - 1]; - input_buf[input_cursor] = readable; - input_len++; - input_cursor++; - input_buf[input_len] = 0; - redraw_input_line(); - return true; -} - -draw_ctx* Terminal::get_ctx(){ - if (dctx) release(dctx); - draw_ctx *ctx = (draw_ctx*)zalloc(sizeof(draw_ctx)); - if (!ctx) return nullptr; - request_draw_ctx(ctx); - return ctx; -} - -void Terminal::put_char(char c){ - if (headless){ - serial_transmit(c); - return; - } - Console::put_char(c); -} - -void Terminal::put_slice(string_slice slice){ - if (!check_ready()) return; - for (u32 i = 0; i < slice.length; i++) Terminal::put_char(slice.data[i]); - flush(dctx); -} - -void Terminal::put_string(const char* str){ - Terminal::put_slice(slice_from_literal(str)); -} - -void Terminal::flush(draw_ctx *ctx){ - if (headless) return; - commit_draw_ctx(ctx); -} - -void Terminal::refresh(){ - if (headless) return; - flush(dctx); -} - -bool Terminal::screen_ready(){ - return !headless; -} \ No newline at end of file diff --git a/user/terminal/terminal.hpp b/user/terminal/terminal.hpp deleted file mode 100644 index a0f6cd86..00000000 --- a/user/terminal/terminal.hpp +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once - -#include "utils/console.hpp" -#include "shell/shell.h" -#include "kbd_helper.h" -#include "environment/env_types.h" -#include "data/serialize/binary_serial.h" - -class Terminal: public Console { -public: - Terminal(); - void update(); - shell_handle *term_current_shell; - void emit_data(structdef, sizedptr, bool); - void refresh(); - void bell(); - bool interpret_cmd_code(char code, u16 proc); - void ctrl(console_ctrls ctrl); - void put_char(char c) override; - void put_string(const char* str) override; - void put_slice(string_slice slice) override; - bool headless; -protected: - bool handle_input(); - void repeat_tick(); - void end_command(); - int prompt_length; - void run_command(); - - void redraw_input_line(); - void set_input_line(const char *s); - void cursor_tick(); - void cursor_set_visible(bool visible); - - bool exec_cmd(const char *cmd); - - draw_ctx* get_ctx() override; - void flush(draw_ctx *ctx) override; - bool screen_ready() override; - - shell_handle* create_shell(); - - bool command_running; - - static constexpr uint32_t input_max = 1024; - char input_buf[input_max]; - uint32_t input_len; - uint32_t input_cursor; - - static constexpr uint32_t history_max = 32; - char *history[history_max]; - uint32_t history_len; - uint32_t history_index; - - uint64_t last_blink_ms; - bool cursor_visible; - - bool dirty; -}; \ No newline at end of file diff --git a/user/theme/main.c b/user/theme/main.c index fb103e5d..3f7ebd7a 100755 --- a/user/theme/main.c +++ b/user/theme/main.c @@ -1,6 +1,7 @@ #include "syscalls/syscalls.h" #include "files/helpers.h" #include "input_keycodes.h" +#include "utils/theme.h" string files[16]; int file_count; @@ -9,10 +10,7 @@ int selected = 0; draw_ctx ctx; -struct { - color background; - color accent; -} color_theme; +theme_palette palette; void on_entry(const char* path, const char* name){ if (strend(name, ".config")) return; @@ -25,14 +23,16 @@ void refresh(){ file_count = 0; traverse_directory("/boot/redos/", false, on_entry); - sreadf("/theme", &color_theme, sizeof(color_theme)); + get_theme(&palette); - fb_clear(&ctx, color_theme.background); + if (!palette.accent) palette.accent = palette.foreground; + + fb_clear(&ctx, palette.background); for (int i = 0; i < file_count; i++){ if (selected == i){ - fb_draw_string(&ctx, ">", 0, 10 + (i * 30), 3, color_theme.accent); + fb_draw_string(&ctx, ">", 0, 10 + (i * 30), 3, palette.accent); } - fb_draw_string(&ctx, files[i].data, 30, 10 + (i * 30), 3, color_theme.accent); + fb_draw_string(&ctx, files[i].data, 30, 10 + (i * 30), 3, palette.foreground); } commit_draw_ctx(&ctx); } diff --git a/user/theme/package.info b/user/theme/package.info new file mode 100644 index 00000000..8a1c0613 --- /dev/null +++ b/user/theme/package.info @@ -0,0 +1,3 @@ +app_name="Theme selector" +app_author="[REDACTED]" +app_bundle_id="com.redos.theme" \ No newline at end of file