mirror of
https://github.com/JannisHeydemann/BoredOS.git
synced 2026-05-30 02:16:58 +00:00
Notepad port to userspace and bug fixes
This commit is contained in:
@@ -257,6 +257,9 @@ int main(void) {
|
||||
} else if (ev.type == GUI_EVENT_CLOSE) {
|
||||
sys_exit(0);
|
||||
}
|
||||
} else {
|
||||
// Avoid high CPU usage
|
||||
for(volatile int i=0; i<10000; i++);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -12,9 +12,6 @@ _start:
|
||||
and rsp, -16
|
||||
|
||||
; Call main(argc, argv)
|
||||
; We don't have argc or argv yet, pass 0
|
||||
xor rdi, rdi
|
||||
xor rsi, rsi
|
||||
call main
|
||||
|
||||
; If main returns, call exit(status)
|
||||
|
||||
Binary file not shown.
@@ -1,7 +1,42 @@
|
||||
#include "syscall.h"
|
||||
|
||||
int main() {
|
||||
int strlen(const char* str) {
|
||||
int len = 0;
|
||||
while(str[len]) len++;
|
||||
return len;
|
||||
}
|
||||
|
||||
void print_int(int n) {
|
||||
char buf[16];
|
||||
if (n == 0) {
|
||||
sys_write(1, "0", 1);
|
||||
return;
|
||||
}
|
||||
int i = 0;
|
||||
while(n > 0) {
|
||||
buf[i++] = (n % 10) + '0';
|
||||
n /= 10;
|
||||
}
|
||||
for(int j = i - 1; j >= 0; j--) {
|
||||
sys_write(1, &buf[j], 1);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
const char* msg = "Hello from Userland ELF!\n";
|
||||
sys_write(1, msg, 25);
|
||||
|
||||
sys_write(1, "argc: ", 6);
|
||||
print_int(argc);
|
||||
sys_write(1, "\n", 1);
|
||||
|
||||
for (int i = 0; i < argc; i++) {
|
||||
sys_write(1, "argv[", 5);
|
||||
print_int(i);
|
||||
sys_write(1, "]: ", 3);
|
||||
sys_write(1, argv[i], strlen(argv[i]));
|
||||
sys_write(1, "\n", 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,5 +1,6 @@
|
||||
#include "libui.h"
|
||||
#include "syscall.h"
|
||||
#include "syscall_user.h"
|
||||
#include <stddef.h>
|
||||
|
||||
extern uint64_t syscall3(uint64_t sys_num, uint64_t arg1, uint64_t arg2, uint64_t arg3);
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#define GUI_EVENT_CLICK 2
|
||||
#define GUI_EVENT_RIGHT_CLICK 3
|
||||
#define GUI_EVENT_CLOSE 4
|
||||
#define GUI_EVENT_KEY 5
|
||||
|
||||
typedef struct {
|
||||
int type;
|
||||
@@ -26,7 +27,7 @@ typedef struct {
|
||||
} gui_event_t;
|
||||
|
||||
// Window Handle
|
||||
typedef int ui_window_t;
|
||||
typedef uint64_t ui_window_t;
|
||||
|
||||
// libui API
|
||||
ui_window_t ui_window_create(const char *title, int x, int y, int w, int h);
|
||||
|
||||
@@ -69,3 +69,48 @@ void sys_exit(int status) {
|
||||
int sys_write(int fd, const char *buf, int len) {
|
||||
return (int)syscall3(SYS_WRITE, (uint64_t)fd, (uint64_t)buf, (uint64_t)len);
|
||||
}
|
||||
|
||||
int sys_open(const char *path, const char *mode) {
|
||||
return (int)syscall3(SYS_FS, FS_CMD_OPEN, (uint64_t)path, (uint64_t)mode);
|
||||
}
|
||||
|
||||
int sys_read(int fd, void *buf, uint32_t len) {
|
||||
return (int)syscall4(SYS_FS, FS_CMD_READ, (uint64_t)fd, (uint64_t)buf, (uint64_t)len);
|
||||
}
|
||||
|
||||
int sys_write_fs(int fd, const void *buf, uint32_t len) {
|
||||
return (int)syscall4(SYS_FS, FS_CMD_WRITE, (uint64_t)fd, (uint64_t)buf, (uint64_t)len);
|
||||
}
|
||||
|
||||
void sys_close(int fd) {
|
||||
syscall2(SYS_FS, FS_CMD_CLOSE, (uint64_t)fd);
|
||||
}
|
||||
|
||||
int sys_seek(int fd, int offset, int whence) {
|
||||
return (int)syscall4(SYS_FS, FS_CMD_SEEK, (uint64_t)fd, (uint64_t)offset, (uint64_t)whence);
|
||||
}
|
||||
|
||||
uint32_t sys_tell(int fd) {
|
||||
return (uint32_t)syscall2(SYS_FS, FS_CMD_TELL, (uint64_t)fd);
|
||||
}
|
||||
|
||||
uint32_t sys_size(int fd) {
|
||||
return (uint32_t)syscall2(SYS_FS, FS_CMD_SIZE, (uint64_t)fd);
|
||||
}
|
||||
|
||||
int sys_list(const char *path, struct FAT32_FileInfo *entries, int max_entries) {
|
||||
return (int)syscall4(SYS_FS, FS_CMD_LIST, (uint64_t)path, (uint64_t)entries, (uint64_t)max_entries);
|
||||
}
|
||||
|
||||
int sys_delete(const char *path) {
|
||||
return (int)syscall2(SYS_FS, FS_CMD_DELETE, (uint64_t)path);
|
||||
}
|
||||
|
||||
int sys_mkdir(const char *path) {
|
||||
return (int)syscall2(SYS_FS, FS_CMD_MKDIR, (uint64_t)path);
|
||||
}
|
||||
|
||||
int sys_exists(const char *path) {
|
||||
return (int)syscall2(SYS_FS, FS_CMD_EXISTS, (uint64_t)path);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,21 @@
|
||||
// Standard syscalls available from Kernel mode
|
||||
#define SYS_EXIT 0
|
||||
#define SYS_WRITE 1
|
||||
#define SYS_GUI 3
|
||||
#define SYS_FS 4
|
||||
|
||||
// FS Commands
|
||||
#define FS_CMD_OPEN 1
|
||||
#define FS_CMD_READ 2
|
||||
#define FS_CMD_WRITE 3
|
||||
#define FS_CMD_CLOSE 4
|
||||
#define FS_CMD_SEEK 5
|
||||
#define FS_CMD_TELL 6
|
||||
#define FS_CMD_LIST 7
|
||||
#define FS_CMD_DELETE 8
|
||||
#define FS_CMD_SIZE 9
|
||||
#define FS_CMD_MKDIR 10
|
||||
#define FS_CMD_EXISTS 11
|
||||
|
||||
// Internal assembly entry into Ring 0
|
||||
extern uint64_t syscall0(uint64_t sys_num);
|
||||
@@ -19,4 +34,19 @@ extern uint64_t syscall5(uint64_t sys_num, uint64_t arg1, uint64_t arg2, uint64_
|
||||
void sys_exit(int status);
|
||||
int sys_write(int fd, const char *buf, int len);
|
||||
|
||||
// FS API
|
||||
int sys_open(const char *path, const char *mode);
|
||||
int sys_read(int fd, void *buf, uint32_t len);
|
||||
int sys_write_fs(int fd, const void *buf, uint32_t len);
|
||||
void sys_close(int fd);
|
||||
int sys_seek(int fd, int offset, int whence);
|
||||
uint32_t sys_tell(int fd);
|
||||
uint32_t sys_size(int fd);
|
||||
int sys_delete(const char *path);
|
||||
int sys_mkdir(const char *path);
|
||||
int sys_exists(const char *path);
|
||||
|
||||
struct FAT32_FileInfo;
|
||||
int sys_list(const char *path, struct FAT32_FileInfo *entries, int max_entries);
|
||||
|
||||
#endif
|
||||
|
||||
Binary file not shown.
11
src/kernel/userland/libc/syscall_user.h
Normal file
11
src/kernel/userland/libc/syscall_user.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#ifndef SYSCALL_USER_H
|
||||
#define SYSCALL_USER_H
|
||||
|
||||
#include "syscall.h"
|
||||
#include <stddef.h>
|
||||
|
||||
static inline void sys_serial_write(const char *str) {
|
||||
syscall2(8, 0, (uint64_t)str);
|
||||
}
|
||||
|
||||
#endif
|
||||
251
src/kernel/userland/notepad.c
Normal file
251
src/kernel/userland/notepad.c
Normal file
@@ -0,0 +1,251 @@
|
||||
#include "libc/syscall.h"
|
||||
#include "libc/libui.h"
|
||||
#include "libc/syscall_user.h"
|
||||
#include <stddef.h>
|
||||
|
||||
#define COLOR_NOTEPAD_BG 0xFFFFFFFF
|
||||
#define COLOR_BLACK 0xFF000000
|
||||
|
||||
#define NOTEPAD_BUF_SIZE (64 * 1024)
|
||||
static char buffer[NOTEPAD_BUF_SIZE];
|
||||
static int buf_len = 0;
|
||||
static int cursor_pos = 0;
|
||||
static int notepad_scroll_line = 0;
|
||||
|
||||
static void notepad_ensure_cursor_visible(int h) {
|
||||
int visible_lines = (h - 40) / 10 + 3;
|
||||
if (visible_lines < 1) visible_lines = 1;
|
||||
|
||||
int cursor_line = 0;
|
||||
for (int i = 0; i < cursor_pos && i < buf_len; i++) {
|
||||
if (buffer[i] == '\n') cursor_line++;
|
||||
}
|
||||
|
||||
if (cursor_line < notepad_scroll_line) {
|
||||
notepad_scroll_line = cursor_line;
|
||||
}
|
||||
|
||||
if (cursor_line >= notepad_scroll_line + visible_lines) {
|
||||
notepad_scroll_line = cursor_line - visible_lines + 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void notepad_load_state() {
|
||||
int fd = sys_open("A:/tmp/notepad_state.txt", "r");
|
||||
if (fd >= 0) {
|
||||
sys_serial_write("Notepad: Loading state...\n");
|
||||
buf_len = sys_read(fd, buffer, NOTEPAD_BUF_SIZE - 1);
|
||||
if (buf_len < 0) buf_len = 0;
|
||||
buffer[buf_len] = 0;
|
||||
sys_close(fd);
|
||||
}
|
||||
cursor_pos = buf_len;
|
||||
}
|
||||
|
||||
static void notepad_save_state() {
|
||||
// Ensure dir exists
|
||||
sys_mkdir("A:/tmp");
|
||||
int fd = sys_open("A:/tmp/notepad_state.txt", "w");
|
||||
if (fd >= 0) {
|
||||
sys_write_fs(fd, buffer, buf_len);
|
||||
sys_close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
static void notepad_paint(ui_window_t win, int w, int h) {
|
||||
ui_draw_rect(win, 4, 30, w - 8, h - 34, COLOR_NOTEPAD_BG);
|
||||
|
||||
int visual_line = 0;
|
||||
int current_x = 8;
|
||||
int current_y = 36;
|
||||
int window_right = w - 16;
|
||||
|
||||
for (int i = 0; i < buf_len; i++) {
|
||||
if (visual_line < notepad_scroll_line) {
|
||||
if (buffer[i] == '\n') {
|
||||
visual_line++;
|
||||
current_x = 8;
|
||||
current_y = 36;
|
||||
} else {
|
||||
if (current_x >= window_right) {
|
||||
visual_line++;
|
||||
current_x = 8;
|
||||
current_y += 10;
|
||||
}
|
||||
current_x += 8;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (visual_line >= notepad_scroll_line + (h - 40) / 10) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (buffer[i] == '\n') {
|
||||
current_x = 8;
|
||||
current_y += 10;
|
||||
visual_line++;
|
||||
} else {
|
||||
if (current_x >= window_right) {
|
||||
current_x = 8;
|
||||
current_y += 10;
|
||||
visual_line++;
|
||||
|
||||
if (visual_line >= notepad_scroll_line + (h - 40) / 10) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
char ch[2] = {buffer[i], 0};
|
||||
ui_draw_string(win, current_x, current_y, ch, COLOR_BLACK);
|
||||
current_x += 8;
|
||||
}
|
||||
}
|
||||
|
||||
// Cursor
|
||||
int cx = 8;
|
||||
int cy = 36;
|
||||
int c_visual_line = 0;
|
||||
|
||||
for (int i = 0; i < cursor_pos; i++) {
|
||||
if (buffer[i] == '\n') {
|
||||
cx = 8;
|
||||
cy += 10;
|
||||
c_visual_line++;
|
||||
} else {
|
||||
if (cx >= window_right) {
|
||||
cx = 8;
|
||||
cy += 10;
|
||||
c_visual_line++;
|
||||
}
|
||||
cx += 8;
|
||||
}
|
||||
}
|
||||
|
||||
if (c_visual_line >= notepad_scroll_line &&
|
||||
c_visual_line < notepad_scroll_line + (h - 40) / 10) {
|
||||
ui_draw_rect(win, cx, cy, 2, 8, COLOR_BLACK);
|
||||
}
|
||||
|
||||
ui_mark_dirty(win, 0, 0, w, h);
|
||||
}
|
||||
|
||||
static void notepad_key(ui_window_t win, int h, char c) {
|
||||
if (c == 17) { // UP
|
||||
if (cursor_pos > 0) {
|
||||
int curr = cursor_pos;
|
||||
int line_start = curr;
|
||||
while (line_start > 0 && buffer[line_start - 1] != '\n') {
|
||||
line_start--;
|
||||
}
|
||||
int col = curr - line_start;
|
||||
|
||||
if (line_start > 0) {
|
||||
int prev_line_end = line_start - 1;
|
||||
int prev_line_start = prev_line_end;
|
||||
while (prev_line_start > 0 && buffer[prev_line_start - 1] != '\n') {
|
||||
prev_line_start--;
|
||||
}
|
||||
int prev_line_len = prev_line_end - prev_line_start;
|
||||
if (col > prev_line_len) col = prev_line_len;
|
||||
cursor_pos = prev_line_start + col;
|
||||
}
|
||||
}
|
||||
} else if (c == 18) { // DOWN
|
||||
if (cursor_pos < buf_len) {
|
||||
int curr = cursor_pos;
|
||||
int line_start = curr;
|
||||
while (line_start > 0 && buffer[line_start - 1] != '\n') {
|
||||
line_start--;
|
||||
}
|
||||
int col = curr - line_start;
|
||||
|
||||
int next_line_start = curr;
|
||||
while (next_line_start < buf_len && buffer[next_line_start] != '\n') {
|
||||
next_line_start++;
|
||||
}
|
||||
|
||||
if (next_line_start < buf_len) {
|
||||
next_line_start++; // Skip newline
|
||||
int next_line_end = next_line_start;
|
||||
while (next_line_end < buf_len && buffer[next_line_end] != '\n') {
|
||||
next_line_end++;
|
||||
}
|
||||
int next_line_len = next_line_end - next_line_start;
|
||||
if (col > next_line_len) col = next_line_len;
|
||||
cursor_pos = next_line_start + col;
|
||||
} else {
|
||||
cursor_pos = buf_len;
|
||||
}
|
||||
}
|
||||
} else if (c == 19) { // LEFT
|
||||
if (cursor_pos > 0) cursor_pos--;
|
||||
} else if (c == 20) { // RIGHT
|
||||
if (cursor_pos < buf_len) cursor_pos++;
|
||||
} else if (c == '\b') { // Backspace
|
||||
if (cursor_pos > 0) {
|
||||
for (int i = cursor_pos; i < buf_len; i++) {
|
||||
buffer[i - 1] = buffer[i];
|
||||
}
|
||||
buf_len--;
|
||||
cursor_pos--;
|
||||
buffer[buf_len] = 0;
|
||||
}
|
||||
} else if (c == '\n') { // Enter
|
||||
if (buf_len < 1023) {
|
||||
for (int i = buf_len; i > cursor_pos; i--) {
|
||||
buffer[i] = buffer[i - 1];
|
||||
}
|
||||
buffer[cursor_pos] = c;
|
||||
buf_len++;
|
||||
cursor_pos++;
|
||||
buffer[buf_len] = 0;
|
||||
}
|
||||
} else {
|
||||
if (buf_len < NOTEPAD_BUF_SIZE - 1) {
|
||||
for (int i = buf_len; i > cursor_pos; i--) {
|
||||
buffer[i] = buffer[i - 1];
|
||||
}
|
||||
buffer[cursor_pos] = c;
|
||||
buf_len++;
|
||||
cursor_pos++;
|
||||
buffer[buf_len] = 0;
|
||||
}
|
||||
}
|
||||
notepad_ensure_cursor_visible(h);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
sys_serial_write("Notepad: Starting userspace main...\n");
|
||||
ui_window_t win = ui_window_create("Notepad", 100, 100, 400, 300);
|
||||
if (win == 0) {
|
||||
sys_serial_write("Notepad: Failed to create window!\n");
|
||||
return 1;
|
||||
}
|
||||
sys_serial_write("Notepad: Window created successfully.\n");
|
||||
|
||||
notepad_load_state();
|
||||
|
||||
gui_event_t ev;
|
||||
sys_serial_write("Notepad: Entering event loop...\n");
|
||||
while (1) {
|
||||
if (ui_get_event(win, &ev)) {
|
||||
if (ev.type == GUI_EVENT_PAINT) {
|
||||
notepad_paint(win, 400, 300);
|
||||
} else if (ev.type == GUI_EVENT_KEY) {
|
||||
notepad_key(win, 300, (char)ev.arg1);
|
||||
notepad_paint(win, 400, 300);
|
||||
} else if (ev.type == GUI_EVENT_CLOSE) {
|
||||
sys_serial_write("Notepad: CLOSE\n");
|
||||
notepad_save_state();
|
||||
sys_exit(0);
|
||||
}
|
||||
} else {
|
||||
// Optional: sys_yield() or similar to avoid high CPU
|
||||
// For now, just keep looping but it's better than nothing
|
||||
for(volatile int i=0; i<10000; i++);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
BIN
src/kernel/userland/notepad.elf
Executable file
BIN
src/kernel/userland/notepad.elf
Executable file
Binary file not shown.
Reference in New Issue
Block a user