diff --git a/include/aster_api.h b/include/aster_api.h index 71e227e..46b1d1a 100644 --- a/include/aster_api.h +++ b/include/aster_api.h @@ -15,21 +15,120 @@ #define ASTER_API_H #include "types.h" +#include "storage.h" -#define ASTER_APP_API_VERSION 1 +#define ASTER_APP_API_VERSION 2 + +#define ASTER_API_CAP_CONSOLE (1U << 0) +#define ASTER_API_CAP_TIME (1U << 1) +#define ASTER_API_CAP_MEMORY (1U << 2) +#define ASTER_API_CAP_INPUT (1U << 3) +#define ASTER_API_CAP_STORAGE (1U << 4) +#define ASTER_API_CAP_PROCESS (1U << 5) + +#define ASTER_API_OK 0 +#define ASTER_API_ERR_INVALID -1 +#define ASTER_API_ERR_NOT_FOUND -2 +#define ASTER_API_ERR_NO_SPACE -3 +#define ASTER_API_ERR_ALREADY -4 + +typedef struct { + usize total_pages; + usize free_pages; + usize used_pages; +} aster_api_memory_info_t; + +typedef struct { + u32 pid; + u8 state; + u8 priority; + const char *name; +} aster_api_process_info_t; + +typedef struct { + char name[ASTERFS_NAME_LEN]; + u8 is_dir; + u16 size; +} aster_api_dirent_t; + +typedef void (*aster_api_dirent_cb)(const aster_api_dirent_t *entry, void *user); typedef struct { u32 api_version; - u32 reserved; + u32 capabilities; + u64 boot_ticks; } aster_app_context_t; +/* + * Inicializuje kontext aplikace a vyplni verzi API, capability masku + * a aktualni hodnotu boot tiku. Vraci ASTER_API_OK nebo chybu. + */ +int aster_api_context_init(aster_app_context_t *ctx); + +/* + * Konzolove API pro vypis textu, cisteni obrazovky a praci s kurzorem. + */ int aster_api_print(const char *text); +int aster_api_print_line(const char *text); int aster_api_clear(void); +int aster_api_set_color(u8 fg, u8 bg); +int aster_api_get_cursor(usize *out_row, usize *out_col); +int aster_api_set_cursor(usize row, usize col); + +/* + * Casove API. Tick je globalni casovac jadra od bootu. + */ int aster_api_ticks(u64 *out_ticks); +u64 aster_api_ticks_now(void); +int aster_api_sleep_ms(u32 ms); + +/* + * Pametove API a jednoduche utility nad pameti bez zavislosti na libc. + */ void *aster_api_alloc(usize size); +void aster_api_memset(void *dst, u8 value, usize size); +void aster_api_memcpy(void *dst, const void *src, usize size); +int aster_api_memory_info(aster_api_memory_info_t *out_info); + +/* + * Vstupni API pro klavesnici. + * read_key blokuje, try_read_key je neblokujici, read_line cte cely radek. + */ +int aster_api_read_key(void); +int aster_api_try_read_key(void); +int aster_api_read_line(char *buffer, int max_len); + +/* + * AsterFS API pokryvajici bezne operace nad soubory a adresari. + * Textove helpery zajistuji nulovy terminator pri cteni textu. + */ int aster_api_file_create(const char *path); +int aster_api_dir_create(const char *path); +int aster_api_file_remove(const char *path); +int aster_api_dir_remove(const char *path); +int aster_api_path_exists(const char *path); +int aster_api_file_exists(const char *path); +int aster_api_dir_exists(const char *path); int aster_api_file_read(const char *path, u8 *out, u16 max_len); int aster_api_file_write(const char *path, const u8 *data, u16 len); +int aster_api_file_read_text(const char *path, char *out, u16 max_len); +int aster_api_file_write_text(const char *path, const char *text); +int aster_api_list_dir(const char *path, aster_api_dirent_cb cb, void *user); + +/* + * Procesove API pro spawn, introspekci tabulky procesu a voluntary yield. + */ int aster_api_process_spawn(void (*entry)(void), const char *name, u8 priority); +int aster_api_process_count(usize *out_count); +int aster_api_process_current(aster_api_process_info_t *out_info); +int aster_api_process_get(usize index, aster_api_process_info_t *out_info); +int aster_api_yield(void); + +/* + * String utility API urcene pro aplikace bez standardni knihovny C. + */ +usize aster_api_str_len(const char *text); +int aster_api_str_equal(const char *a, const char *b); +int aster_api_str_starts_with(const char *text, const char *prefix); #endif diff --git a/include/syscall.h b/include/syscall.h index 737cca1..70960c9 100644 --- a/include/syscall.h +++ b/include/syscall.h @@ -19,6 +19,21 @@ #define SYSCALL_WRITE 0 #define SYSCALL_ALLOC 1 #define SYSCALL_PROCESS_CREATE 2 +#define SYSCALL_CLEAR 3 +#define SYSCALL_TICKS 4 +#define SYSCALL_SLEEP_MS 5 +#define SYSCALL_READ_KEY 6 +#define SYSCALL_TRY_READ_KEY 7 +#define SYSCALL_READ_LINE 8 +#define SYSCALL_FS_CREATE_FILE 9 +#define SYSCALL_FS_READ_FILE 10 +#define SYSCALL_FS_WRITE_FILE 11 +#define SYSCALL_FS_CREATE_DIR 12 +#define SYSCALL_FS_REMOVE_FILE 13 +#define SYSCALL_FS_REMOVE_DIR 14 +#define SYSCALL_PROCESS_COUNT 15 +#define SYSCALL_PROCESS_CURPID 16 +#define SYSCALL_YIELD 17 void syscall_init(void); u64 syscall_dispatch(u64 id, u64 a1, u64 a2, u64 a3, u64 a4); @@ -26,5 +41,20 @@ u64 syscall_dispatch(u64 id, u64 a1, u64 a2, u64 a3, u64 a4); u64 aster_write(const char *text); void *aster_alloc(usize size); i64 aster_process_create(void (*entry)(void), const char *name, u8 priority); +u64 aster_clear(void); +u64 aster_ticks(void); +u64 aster_sleep_ms(u64 ms); +i64 aster_read_key(void); +i64 aster_try_read_key(void); +i64 aster_read_line(char *buffer, i64 max_len); +i64 asterfs_create_file_sys(const char *path); +i64 asterfs_read_file_sys(const char *path, u8 *out, u16 max_len); +i64 asterfs_write_file_sys(const char *path, const u8 *data, u16 len); +i64 asterfs_create_dir_sys(const char *path); +i64 asterfs_remove_file_sys(const char *path); +i64 asterfs_remove_dir_sys(const char *path); +i64 aster_process_count_sys(void); +i64 aster_process_current_pid(void); +u64 aster_yield(void); #endif diff --git a/kernel/aster_api.c b/kernel/aster_api.c index 725c489..698afd2 100644 --- a/kernel/aster_api.c +++ b/kernel/aster_api.c @@ -12,37 +12,182 @@ */ #include "aster_api.h" +#include "drivers.h" #include "display.h" +#include "memory.h" +#include "process.h" +#include "scheduler.h" #include "storage.h" +#include "string.h" #include "syscall.h" #include "timer.h" +static aster_api_dirent_cb g_list_cb = 0; +static void *g_list_user = 0; + +static void aster_api_list_bridge(const char *name, u8 is_dir, u16 size) { + aster_api_dirent_t entry; + usize len = 0; + + if (!g_list_cb || !name) { + return; + } + + aster_memset(&entry, 0, sizeof(entry)); + while (name[len] && len + 1 < ASTERFS_NAME_LEN) { + entry.name[len] = name[len]; + ++len; + } + entry.name[len] = '\0'; + entry.is_dir = is_dir; + entry.size = size; + g_list_cb(&entry, g_list_user); +} + +int aster_api_context_init(aster_app_context_t *ctx) { + if (!ctx) { + return ASTER_API_ERR_INVALID; + } + + ctx->api_version = ASTER_APP_API_VERSION; + ctx->capabilities = ASTER_API_CAP_CONSOLE | + ASTER_API_CAP_TIME | + ASTER_API_CAP_MEMORY | + ASTER_API_CAP_INPUT | + ASTER_API_CAP_STORAGE | + ASTER_API_CAP_PROCESS; + ctx->boot_ticks = (u64)timer_ticks(); + return ASTER_API_OK; +} + int aster_api_print(const char *text) { return (int)aster_write(text); } +int aster_api_print_line(const char *text) { + int rc; + + rc = aster_api_print(text ? text : ""); + if (rc != 0) { + return rc; + } + + return aster_api_print("\n"); +} + int aster_api_clear(void) { - display_clear(); - return 0; + return (int)aster_clear(); +} + +int aster_api_set_color(u8 fg, u8 bg) { + display_set_color(fg, bg); + return ASTER_API_OK; +} + +int aster_api_get_cursor(usize *out_row, usize *out_col) { + if (!out_row && !out_col) { + return ASTER_API_ERR_INVALID; + } + + display_get_cursor(out_row, out_col); + return ASTER_API_OK; +} + +int aster_api_set_cursor(usize row, usize col) { + display_set_cursor(row, col); + return ASTER_API_OK; } int aster_api_ticks(u64 *out_ticks) { if (!out_ticks) { - return -1; + return ASTER_API_ERR_INVALID; } - *out_ticks = (u64)timer_ticks(); - return 0; + *out_ticks = aster_api_ticks_now(); + return ASTER_API_OK; +} + +u64 aster_api_ticks_now(void) { + return aster_ticks(); +} + +int aster_api_sleep_ms(u32 ms) { + return (int)aster_sleep_ms((u64)ms); } void *aster_api_alloc(usize size) { return aster_alloc(size); } +void aster_api_memset(void *dst, u8 value, usize size) { + if (!dst || size == 0) { + return; + } + + aster_memset(dst, (int)value, size); +} + +void aster_api_memcpy(void *dst, const void *src, usize size) { + if (!dst || !src || size == 0) { + return; + } + + aster_memcpy(dst, src, size); +} + +int aster_api_memory_info(aster_api_memory_info_t *out_info) { + if (!out_info) { + return ASTER_API_ERR_INVALID; + } + + out_info->total_pages = memory_total_pages(); + out_info->free_pages = memory_free_pages(); + out_info->used_pages = out_info->total_pages >= out_info->free_pages + ? out_info->total_pages - out_info->free_pages + : 0; + return ASTER_API_OK; +} + +int aster_api_read_key(void) { + return (int)aster_read_key(); +} + +int aster_api_try_read_key(void) { + return (int)aster_try_read_key(); +} + +int aster_api_read_line(char *buffer, int max_len) { + return (int)aster_read_line(buffer, (i64)max_len); +} + int aster_api_file_create(const char *path) { return asterfs_create_file(path); } +int aster_api_dir_create(const char *path) { + return asterfs_create_dir(path); +} + +int aster_api_file_remove(const char *path) { + return asterfs_remove_file(path); +} + +int aster_api_dir_remove(const char *path) { + return asterfs_remove_dir(path); +} + +int aster_api_path_exists(const char *path) { + return asterfs_get_type(path) >= 0 ? 1 : 0; +} + +int aster_api_file_exists(const char *path) { + return asterfs_get_type(path) == 0 ? 1 : 0; +} + +int aster_api_dir_exists(const char *path) { + return asterfs_get_type(path) == 1 ? 1 : 0; +} + int aster_api_file_read(const char *path, u8 *out, u16 max_len) { return asterfs_read_file(path, out, max_len); } @@ -51,6 +196,128 @@ int aster_api_file_write(const char *path, const u8 *data, u16 len) { return asterfs_write_file(path, data, len); } +int aster_api_file_read_text(const char *path, char *out, u16 max_len) { + int n; + + if (!out || max_len == 0) { + return ASTER_API_ERR_INVALID; + } + + n = aster_api_file_read(path, (u8 *)out, (u16)(max_len - 1)); + if (n < 0) { + out[0] = '\0'; + return n; + } + + out[n] = '\0'; + return n; +} + +int aster_api_file_write_text(const char *path, const char *text) { + usize len; + + if (!text) { + return ASTER_API_ERR_INVALID; + } + + len = aster_strlen(text); + if (len > 0xFFFFUL) { + len = 0xFFFFUL; + } + + return aster_api_file_write(path, (const u8 *)text, (u16)len); +} + +int aster_api_list_dir(const char *path, aster_api_dirent_cb cb, void *user) { + if (!path || !cb) { + return ASTER_API_ERR_INVALID; + } + + g_list_cb = cb; + g_list_user = user; + asterfs_list_dir(path, aster_api_list_bridge); + g_list_cb = 0; + g_list_user = 0; + return ASTER_API_OK; +} + int aster_api_process_spawn(void (*entry)(void), const char *name, u8 priority) { return (int)aster_process_create(entry, name, priority); } + +int aster_api_process_count(usize *out_count) { + if (!out_count) { + return ASTER_API_ERR_INVALID; + } + + *out_count = process_count(); + return ASTER_API_OK; +} + +int aster_api_process_current(aster_api_process_info_t *out_info) { + process_t *p; + + if (!out_info) { + return ASTER_API_ERR_INVALID; + } + + p = process_current(); + if (!p) { + return ASTER_API_ERR_NOT_FOUND; + } + + out_info->pid = p->pid; + out_info->state = (u8)p->state; + out_info->priority = p->priority; + out_info->name = p->name; + return ASTER_API_OK; +} + +int aster_api_process_get(usize index, aster_api_process_info_t *out_info) { + process_t *table; + usize count; + + if (!out_info) { + return ASTER_API_ERR_INVALID; + } + + count = process_count(); + if (index >= count) { + return ASTER_API_ERR_NOT_FOUND; + } + + table = process_table(); + out_info->pid = table[index].pid; + out_info->state = (u8)table[index].state; + out_info->priority = table[index].priority; + out_info->name = table[index].name; + return ASTER_API_OK; +} + +int aster_api_yield(void) { + scheduler_yield(); + return ASTER_API_OK; +} + +usize aster_api_str_len(const char *text) { + return aster_strlen(text); +} + +int aster_api_str_equal(const char *a, const char *b) { + if (!a || !b) { + return 0; + } + + return aster_strcmp(a, b) == 0 ? 1 : 0; +} + +int aster_api_str_starts_with(const char *text, const char *prefix) { + usize n; + + if (!text || !prefix) { + return 0; + } + + n = aster_strlen(prefix); + return aster_strncmp(text, prefix, n) == 0 ? 1 : 0; +} diff --git a/kernel/syscall.c b/kernel/syscall.c index 07ec272..cb38303 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -11,9 +11,14 @@ * a implementuje zakladni syscall operace pro zapis, alokaci a procesy. */ +#include "display.h" +#include "drivers.h" #include "memory.h" #include "printk.h" #include "process.h" +#include "scheduler.h" +#include "storage.h" +#include "timer.h" #include "syscall.h" void syscall_init(void) { @@ -30,6 +35,36 @@ u64 syscall_dispatch(u64 id, u64 a1, u64 a2, u64 a3, u64 a4) { return (u64)aster_alloc((usize)a1); case SYSCALL_PROCESS_CREATE: return (u64)aster_process_create((void (*)(void))a1, (const char *)a2, (u8)a3); + case SYSCALL_CLEAR: + return aster_clear(); + case SYSCALL_TICKS: + return aster_ticks(); + case SYSCALL_SLEEP_MS: + return aster_sleep_ms(a1); + case SYSCALL_READ_KEY: + return (u64)aster_read_key(); + case SYSCALL_TRY_READ_KEY: + return (u64)aster_try_read_key(); + case SYSCALL_READ_LINE: + return (u64)aster_read_line((char *)a1, (i64)a2); + case SYSCALL_FS_CREATE_FILE: + return (u64)asterfs_create_file_sys((const char *)a1); + case SYSCALL_FS_READ_FILE: + return (u64)asterfs_read_file_sys((const char *)a1, (u8 *)a2, (u16)a3); + case SYSCALL_FS_WRITE_FILE: + return (u64)asterfs_write_file_sys((const char *)a1, (const u8 *)a2, (u16)a3); + case SYSCALL_FS_CREATE_DIR: + return (u64)asterfs_create_dir_sys((const char *)a1); + case SYSCALL_FS_REMOVE_FILE: + return (u64)asterfs_remove_file_sys((const char *)a1); + case SYSCALL_FS_REMOVE_DIR: + return (u64)asterfs_remove_dir_sys((const char *)a1); + case SYSCALL_PROCESS_COUNT: + return (u64)aster_process_count_sys(); + case SYSCALL_PROCESS_CURPID: + return (u64)aster_process_current_pid(); + case SYSCALL_YIELD: + return aster_yield(); default: return (u64)-1; } @@ -56,3 +91,76 @@ i64 aster_process_create(void (*entry)(void), const char *name, u8 priority) { return p->pid; } + +u64 aster_clear(void) { + display_clear(); + return 0; +} + +u64 aster_ticks(void) { + return (u64)timer_ticks(); +} + +u64 aster_sleep_ms(u64 ms) { + timer_sleep_ms((unsigned long)ms); + return 0; +} + +i64 aster_read_key(void) { + return (i64)keyboard_read_key(); +} + +i64 aster_try_read_key(void) { + return (i64)keyboard_try_read_key(); +} + +i64 aster_read_line(char *buffer, i64 max_len) { + if (!buffer || max_len <= 0) { + return -1; + } + + return (i64)keyboard_readline(buffer, (int)max_len); +} + +i64 asterfs_create_file_sys(const char *path) { + return (i64)asterfs_create_file(path); +} + +i64 asterfs_read_file_sys(const char *path, u8 *out, u16 max_len) { + return (i64)asterfs_read_file(path, out, max_len); +} + +i64 asterfs_write_file_sys(const char *path, const u8 *data, u16 len) { + return (i64)asterfs_write_file(path, data, len); +} + +i64 asterfs_create_dir_sys(const char *path) { + return (i64)asterfs_create_dir(path); +} + +i64 asterfs_remove_file_sys(const char *path) { + return (i64)asterfs_remove_file(path); +} + +i64 asterfs_remove_dir_sys(const char *path) { + return (i64)asterfs_remove_dir(path); +} + +i64 aster_process_count_sys(void) { + return (i64)process_count(); +} + +i64 aster_process_current_pid(void) { + process_t *p = process_current(); + + if (!p) { + return -1; + } + + return (i64)p->pid; +} + +u64 aster_yield(void) { + scheduler_yield(); + return 0; +}