Add process scheduler, pipes, and separate terminal from shell

Freywar Ulvnaudgari 1 month ago
parent cbf21bafdc
commit 2aa39271da
  1. 1
      build.sh
  2. 50
      meson.build
  3. 60
      src/kernel/kernel.c
  4. 126
      src/kernel/pipe.c
  5. 5
      src/kernel/pipe.h
  6. 76
      src/kernel/process.c
  7. 13
      src/kernel/process.h
  8. 37
      src/kernel/syscall.c
  9. 1
      src/kernel/syscall.h
  10. 28
      src/kernel/timer.asm
  11. 20
      src/kernel/timer.c
  12. 3
      src/kernel/timer.h
  13. 2
      src/lib/memory.c
  14. 126
      src/user/app/shell/shell.c
  15. 86
      src/user/app/terminal/terminal.c
  16. 6
      src/user/syscall.asm
  17. 4
      src/user/syscall.h

@ -17,6 +17,7 @@ mcopy -i build/os.img@@"$((partition_offset * sector_size))" -s src ::src
mcopy -i build/os.img@@"$((partition_offset * sector_size))" build/kernel.bin ::kernel.bin
mmd -i build/os.img@@"$((partition_offset * sector_size))" ::bin
mcopy -i build/os.img@@"$((partition_offset * sector_size))" build/terminal ::bin/terminal
mcopy -i build/os.img@@"$((partition_offset * sector_size))" build/shell ::bin/shell
mcopy -i build/os.img@@"$((partition_offset * sector_size))" build/echo ::bin/echo
mcopy -i build/os.img@@"$((partition_offset * sector_size))" build/ls ::bin/ls
mcopy -i build/os.img@@"$((partition_offset * sector_size))" build/cat ::bin/cat

@ -38,6 +38,13 @@ kernel_entry_o = custom_target(
command: [nasm, '-f', 'elf64', '@INPUT@', '-o', '@OUTPUT@'],
)
timer_o = custom_target(
'timer',
input: 'src/kernel/timer.asm',
output: 'timer.o',
command: [nasm, '-f', 'elf64', '@INPUT@', '-o', '@OUTPUT@'],
)
process_o = custom_target(
'process',
input: 'src/kernel/process.asm',
@ -71,15 +78,17 @@ kernel_sources = files([
'src/kernel/panic.c',
'src/kernel/path.c',
'src/kernel/pic.c',
'src/kernel/pipe.c',
'src/kernel/process.c',
'src/kernel/syscall.c',
'src/kernel/timer.c',
'src/kernel/tss.c',
'src/kernel/vga.c',
])
kernel_elf = executable(
'kernel.elf',
sources: [kernel_entry_o, process_o, syscall_o, lib_sources, kernel_sources],
sources: [kernel_entry_o, timer_o, process_o, syscall_o, lib_sources, kernel_sources],
c_args: [
'-ffreestanding',
'-nostdlib',
@ -146,6 +155,45 @@ custom_target(
build_by_default: true,
)
shell_start = custom_target(
'shell_start',
input: 'src/user/start.asm',
output: 'shell_start.o',
command: [nasm, '-f', 'elf64', '-o', '@OUTPUT@', '@INPUT@'],
)
shell_syscall = custom_target(
'shell_syscall',
input: 'src/user/syscall.asm',
output: 'shell_syscall.o',
command: [nasm, '-f', 'elf64', '-o', '@OUTPUT@', '@INPUT@'],
)
shell_elf = executable(
'shell.elf',
sources: [shell_start, shell_syscall, lib_sources, 'src/user/app/shell/shell.c'],
c_args: [
'-ffreestanding',
'-nostdlib',
'-fno-stack-protector',
'-mcmodel=large',
'-DVERSION="' + meson.project_version() + '"',
],
link_args: [
'-T', meson.project_source_root() / 'src/user/linker.ld',
'-nostdlib',
],
link_depends: 'src/user/linker.ld',
)
custom_target(
'shell',
input: shell_elf,
output: 'shell',
command: ['objcopy', '-O', 'binary', '@INPUT@', '@OUTPUT@'],
build_by_default: true,
)
echo_start = custom_target(
'echo_start',
input: 'src/user/start.asm',

@ -5,8 +5,10 @@
#include "src/kernel/panic.h"
#include "src/kernel/path.h"
#include "src/kernel/pic.h"
#include "src/kernel/pipe.h"
#include "src/kernel/process.h"
#include "src/kernel/syscall.h"
#include "src/kernel/timer.h"
#include "src/kernel/tss.h"
#include "src/kernel/util.h"
#include "src/kernel/vga.h"
@ -44,46 +46,56 @@ void kernel_main() {
idt_set_entry(0x0E, isr_page_fault, 0x8E);
idt_set_entry(0x0D, isr_general_violation, 0x8E);
idt_set_entry(46, isr_ata_primary, 0x8E);
__asm__ volatile("sti");
gdt_init();
syscall_init();
process_t *kernel = memory_allocate(sizeof(process_t));
kernel->pml4 = (void *)KERNEL_VIRTUAL_PML4;
kernel->root = fs_mount();
kernel->pml4 = (uint64_t *)KERNEL_VIRTUAL_PML4;
kernel->pid = 0;
kernel->state = PROCESS_RUNNING;
kernel->kernel_stack = kernel->kernel_rsp = (uint8_t *)memory_allocate(PAGE_SIZE) + PAGE_SIZE;
kernel->user_stack = kernel->user_rsp = (uint8_t *)memory_allocate(PAGE_SIZE) + PAGE_SIZE;
kernel->cwd = memory_allocate(sizeof(path_t));
kernel->fds[0] = keyboard_init();
kernel->fds[1] = vga_init();
kernel->free_fd = 2;
kernel->root = fs_mount();
kernel->fds[kernel->free_fd++] = keyboard_init();
kernel->fds[kernel->free_fd++] = vga_init();
kernel->code = EXIT_CODE_OK;
fs_node_t *bin = path_open_file(kernel->root, kernel->cwd, "bin/terminal");
current_process = kernel;
tss.rsp0 = (uint64_t)kernel->kernel_stack;
ASSERT(bin, "kernel: terminal not found");
fs_node_t *terminal_node = path_open_file(kernel->root, kernel->cwd, "bin/terminal");
fs_node_t *shell_node = path_open_file(kernel->root, kernel->cwd, "bin/shell");
uint8_t *code = memory_allocate(bin->size);
fs_read(bin, 0, bin->size, code);
ASSERT(terminal_node, "kernel: terminal not found");
ASSERT(shell_node, "kernel: shell not found");
process_t *terminal = process_create(kernel, code, bin->size);
uint8_t *terminal_code = memory_allocate(terminal_node->size);
fs_read(terminal_node, 0, terminal_node->size, terminal_code);
fs_close(terminal_node);
memory_free(code);
fs_close(bin);
uint8_t *shell_code = memory_allocate(shell_node->size);
fs_read(shell_node, 0, shell_node->size, shell_code);
fs_close(shell_node);
__asm__ volatile("mov %0, %%cr3" : : "r"((uint64_t)VIRT_TO_PHYS((void *)KERNEL_VIRTUAL_PML4)) : "memory");
process_t *terminal = process_create(kernel, terminal_code, terminal_node->size);
memory_free(terminal_code);
uint8_t *stack = (uint8_t *)terminal->user_stack;
process_t *shell = process_create(kernel, shell_code, shell_node->size);
memory_free(shell_code);
stack -= sizeof(uint64_t);
*(uint64_t *)stack = 0;
uint64_t *terminal_stack = (uint64_t *)terminal->user_stack;
*(--terminal_stack) = 0;
terminal->user_rsp = (void *)(USER_VIRTUAL_STACK_TOP - ((uint64_t)terminal->user_stack - (uint64_t)terminal_stack));
terminal->user_rsp = (void *)(USER_VIRTUAL_STACK_TOP - ((uint64_t)terminal->user_stack - (uint64_t)stack));
uint64_t *shell_stack = (uint64_t *)shell->user_stack;
*(--shell_stack) = 0;
shell->user_rsp = (void *)(USER_VIRTUAL_STACK_TOP - ((uint64_t)shell->user_stack - (uint64_t)shell_stack));
current_process = terminal;
tss.rsp0 = (uint64_t)current_process->kernel_stack;
process_switch_to(&kernel->kernel_rsp, terminal->kernel_rsp, VIRT_TO_PHYS(terminal->pml4));
pipe_init(&(terminal->fds[terminal->free_fd++]), &(shell->fds[0]));
fs_unmount((fs_node_t *)kernel->root);
timer_init();
outw(0x604, 0x2000); // TODO: parse ACPI tables for real hardware
__asm__ volatile("cli; hlt");
__asm__ volatile("sti; hlt");
}

@ -0,0 +1,126 @@
#include "src/kernel/pipe.h"
#include "src/kernel/stream.h"
#include "src/lib/memory.h"
#define PIPE_BUFFER_SIZE 65536
typedef struct {
char buffer[PIPE_BUFFER_SIZE];
uint64_t begin;
uint64_t end;
uint8_t write_closed;
uint8_t read_closed;
} pipe_t;
typedef struct {
stream_t stream;
pipe_t *pipe;
} pipe_read_stream_t;
typedef struct {
stream_t stream;
pipe_t *pipe;
} pipe_write_stream_t;
static uint64_t null_read(__attribute__((unused)) const stream_t *self, __attribute__((unused)) uint64_t max,
__attribute__((unused)) char *to) {
return 0;
}
static uint64_t null_write(__attribute__((unused)) const stream_t *self, __attribute__((unused)) const char *from,
__attribute__((unused)) uint64_t bytes) {
return 0;
}
static uint64_t pipe_read(const stream_t *self, uint64_t max, char *to) {
pipe_t *pipe = ((pipe_read_stream_t *)self)->pipe;
uint64_t available = (pipe->end + PIPE_BUFFER_SIZE - pipe->begin) % PIPE_BUFFER_SIZE;
uint64_t to_read = available < max ? available : max;
if (pipe->write_closed && !to_read) {
return (uint64_t)-1;
}
if (!to_read) {
return 0;
}
if (pipe->begin + to_read <= PIPE_BUFFER_SIZE) {
memory_copy(pipe->buffer + pipe->begin, to_read, to);
} else {
uint64_t chunk = PIPE_BUFFER_SIZE - pipe->begin;
memory_copy(pipe->buffer + pipe->begin, chunk, to);
memory_copy(pipe->buffer, to_read - chunk, to + chunk);
}
pipe->begin = (pipe->begin + to_read) % PIPE_BUFFER_SIZE;
return to_read;
}
static uint64_t pipe_write(const stream_t *self, const char *from, uint64_t bytes) {
pipe_t *pipe = ((pipe_read_stream_t *)self)->pipe;
if (pipe->read_closed) {
return (uint64_t)-1;
}
uint64_t available = PIPE_BUFFER_SIZE - (pipe->end + PIPE_BUFFER_SIZE - pipe->begin) % PIPE_BUFFER_SIZE;
uint64_t to_write = available < bytes ? available : bytes;
if (to_write == 0) {
return 0;
}
if (pipe->end + to_write <= PIPE_BUFFER_SIZE) {
memory_copy(from, to_write, pipe->buffer + pipe->end);
} else {
uint64_t chunk = PIPE_BUFFER_SIZE - pipe->end;
memory_copy(from, chunk, pipe->buffer + pipe->end);
memory_copy(from + chunk, to_write - chunk, pipe->buffer);
}
pipe->end = (pipe->end + to_write) % PIPE_BUFFER_SIZE;
return to_write;
}
static void read_close(stream_t *self) {
pipe_t *pipe = ((pipe_read_stream_t *)self)->pipe;
pipe->read_closed = 1;
if (pipe->read_closed && pipe->write_closed) {
memory_free(pipe);
}
memory_free(self);
}
static void write_close(stream_t *self) {
pipe_t *pipe = ((pipe_write_stream_t *)self)->pipe;
pipe->write_closed = 1;
if (pipe->read_closed && pipe->write_closed) {
memory_free(pipe);
}
memory_free(self);
}
void pipe_init(stream_t **write, stream_t **read) {
pipe_t *pipe = memory_allocate(sizeof(pipe_t));
pipe_write_stream_t *ws = memory_allocate(sizeof(pipe_write_stream_t));
ws->stream.read = null_read;
ws->stream.write = pipe_write;
ws->stream.close = write_close;
ws->pipe = pipe;
pipe_read_stream_t *rs = memory_allocate(sizeof(pipe_read_stream_t));
rs->stream.read = pipe_read;
rs->stream.write = null_write;
rs->stream.close = read_close;
rs->pipe = pipe;
*write = (stream_t *)ws;
*read = (stream_t *)rs;
}

@ -0,0 +1,5 @@
#pragma once
#include "src/kernel/stream.h"
void pipe_init(stream_t **write, stream_t **read);

@ -1,17 +1,35 @@
#include "src/kernel/process.h"
#include "src/kernel/memory.h"
#include "src/kernel/panic.h"
#include "src/kernel/path.h"
#include "src/kernel/tss.h"
#include "src/kernel/util.h"
#include "src/lib/layout.h"
#include "src/lib/memory.h"
#include "src/lib/util.h"
#define MAX_PROCESSES 256
static process_t *processes[MAX_PROCESSES];
static uint64_t free_pid = 1;
process_t *current_process;
process_t *process_create(const process_t *parent, const uint8_t *code, uint64_t size) {
ASSERT(size <= USER_VIRTUAL_HEAP - USER_VIRTUAL_CODE, "process_create: binary too big");
if (size >= USER_VIRTUAL_HEAP - USER_VIRTUAL_CODE) {
return NUL;
}
uint64_t free_pi;
for (free_pi = 0; free_pi <= MAX_PROCESSES; free_pi++) {
if (!processes[free_pi]) {
break;
}
}
if (free_pi == MAX_PROCESSES) {
return NUL;
}
process_t *proc = memory_allocate(sizeof(process_t));
process_t *proc = processes[free_pi] = memory_allocate(sizeof(process_t));
proc->parent = parent;
@ -56,6 +74,8 @@ process_t *process_create(const process_t *parent, const uint8_t *code, uint64_t
cwd->stack[i] = fs_open_again(parent->cwd->stack[i]);
}
proc->pid = free_pid++;
proc->state = PROCESS_RUNNING;
proc->cwd = cwd;
proc->root = parent->root;
proc->fds[0] = parent->fds[0];
@ -66,6 +86,49 @@ process_t *process_create(const process_t *parent, const uint8_t *code, uint64_t
return proc;
}
process_t *process_get(uint64_t pid) {
for (uint64_t i = 0; i < MAX_PROCESSES; i++) {
if (processes[i] && processes[i]->pid == pid) {
return processes[i];
}
}
return NUL;
}
void process_next() {
process_t *next = NUL;
uint64_t cpi = 0;
for (uint64_t i = 0; i < MAX_PROCESSES; i++) {
if (processes[i] == current_process) {
cpi = i;
break;
}
}
for (uint64_t i = 1; i <= MAX_PROCESSES; i++) {
process_t *candidate = processes[(cpi + i) % MAX_PROCESSES];
if (candidate && candidate->state == PROCESS_RUNNING) {
next = candidate;
break;
}
}
if (!next) {
outw(0x604, 0x2000);
__asm__ volatile("cli; hlt");
}
if (next == current_process) {
return;
}
process_t *prev = current_process;
tss.rsp0 = (uint64_t)next->kernel_stack;
current_process = next;
process_switch_to(&prev->kernel_rsp, next->kernel_rsp, VIRT_TO_PHYS(next->pml4));
}
void process_destroy(process_t *proc) {
for (uint64_t i = 2; i < MAX_FDS; i++) {
if (proc->fds[i]) {
@ -117,5 +180,12 @@ void process_destroy(process_t *proc) {
memory_free(proc->kernel_stack - PAGE_SIZE);
for (uint64_t i = 0; i < MAX_PROCESSES; i++) {
if (processes[i] == proc) {
processes[i] = NUL;
break;
}
}
memory_free(proc);
}

@ -9,6 +9,12 @@
#define MAX_FDS 16
typedef enum {
PROCESS_RUNNING,
PROCESS_WAITING,
PROCESS_ZOMBIE,
} process_state_t;
typedef struct process {
const struct process *parent;
uint64_t *pml4;
@ -16,6 +22,9 @@ typedef struct process {
void *kernel_rsp;
void *user_stack;
void *user_rsp;
uint64_t pid;
process_state_t state;
uint64_t waiting_for;
const fs_node_t *root;
const path_t *cwd;
stream_t *fds[MAX_FDS];
@ -31,6 +40,10 @@ extern void process_trampoline();
process_t *process_create(const process_t *parent, const uint8_t *code, uint64_t size);
process_t *process_get(uint64_t pid);
extern void process_switch_to(void **save_rsp, void *new_rsp, void *new_pml4_phys);
void process_next();
void process_destroy(process_t *proc);

@ -94,7 +94,7 @@ static uint64_t chdir(const char *path) {
return current_process->cwd->depth;
}
static exit_code_t spawn(const char *path, uint64_t argc, const char **argv) {
static uint64_t spawn(const char *path, uint64_t argc, const char **argv) {
fs_node_t *node = path_open_file(current_process->root, current_process->cwd, path);
if (!node) {
return EXIT_CODE_NOT_FOUND;
@ -138,15 +138,25 @@ static exit_code_t spawn(const char *path, uint64_t argc, const char **argv) {
child->user_rsp = (void *)(USER_VIRTUAL_STACK_TOP - ((uint64_t)child->user_stack - (uint64_t)stack));
process_t *parent = current_process;
current_process = child;
tss.rsp0 = (uint64_t)child->kernel_stack;
__asm__ volatile("mov %0, %%cr3" : : "r"((uint64_t)VIRT_TO_PHYS((void *)current_process->pml4)) : "memory");
process_switch_to(&parent->kernel_rsp, child->kernel_rsp, VIRT_TO_PHYS(child->pml4));
return child->pid;
}
static exit_code_t wait(uint64_t pid) {
process_t *child = process_get(pid);
if (!child) {
return EXIT_CODE_GENERAL_FAILURE;
}
current_process->state = PROCESS_WAITING;
current_process->waiting_for = pid;
while (child->state != PROCESS_ZOMBIE) {
process_next();
}
current_process->state = PROCESS_RUNNING;
exit_code_t code = child->code;
tss.rsp0 = (uint64_t)parent->kernel_stack;
current_process = parent;
process_destroy(child);
return code;
@ -174,8 +184,17 @@ static uint64_t close(uint64_t fd) {
}
static void exit(exit_code_t code) {
current_process->state = PROCESS_ZOMBIE;
current_process->code = code;
process_switch_to(&current_process->kernel_rsp, current_process->parent->kernel_rsp, VIRT_TO_PHYS(current_process->parent->pml4));
if (current_process->parent) {
process_t *parent = (process_t *)current_process->parent;
if (parent->state == PROCESS_WAITING && parent->waiting_for == current_process->pid) {
parent->state = PROCESS_RUNNING;
}
}
process_next();
}
uint64_t syscall_dispatch(uint64_t func, uint64_t arg1, uint64_t arg2, uint64_t arg3, __attribute__((unused)) uint64_t arg4) {
@ -190,6 +209,8 @@ uint64_t syscall_dispatch(uint64_t func, uint64_t arg1, uint64_t arg2, uint64_t
return chdir((const char *)arg1);
case SYSCALL_SPAWN:
return spawn((const char *)arg1, arg2, (const char **)arg3);
case SYSCALL_WAIT:
return wait(arg1);
case SYSCALL_OPEN:
return open((const char *)arg1);
case SYSCALL_CLOSE:

@ -7,6 +7,7 @@
#define SYSCALL_GETCWD 2
#define SYSCALL_CHDIR 3
#define SYSCALL_SPAWN 4
#define SYSCALL_WAIT 5
#define SYSCALL_OPEN 6
#define SYSCALL_CLOSE 7
#define SYSCALL_EXIT 60

@ -0,0 +1,28 @@
bits 64
extern timer_handler
global timer_entry
timer_entry:
push rax
push rcx
push rdx
push rsi
push rdi
push r8
push r9
push r10
push r11
call timer_handler
pop r11
pop r10
pop r9
pop r8
pop rdi
pop rsi
pop rdx
pop rcx
pop rax
iretq

@ -0,0 +1,20 @@
#include "src/kernel/timer.h"
#include "src/kernel/idt.h"
#include "src/kernel/process.h"
#include "src/kernel/util.h"
extern void timer_entry();
void timer_init() {
// PIT channel 0, rate generator, ~100Hz
outb(0x43, 0x36);
outb(0x40, 0xA9); // divisor low byte (11932 for ~100Hz)
outb(0x40, 0x2E); // divisor high byte
outb(0x21, inb(0x21) & ~0x01); // unmask IRQ0
idt_set_entry(32, timer_entry, 0x8E);
}
void timer_handler() {
outb(0x20, 0x20);
process_next();
}

@ -0,0 +1,3 @@
#pragma once
void timer_init();

@ -22,7 +22,7 @@ void *memory_allocate(uint64_t size) {
free_list->next = NUL;
}
size = sizeof(free_chunk_t) + (size + 7) & (uint64_t)~7;
size = sizeof(free_chunk_t) + ((size + 7) & (uint64_t)~7);
free_chunk_t *prev = NUL;
free_chunk_t *curr = free_list;

@ -0,0 +1,126 @@
#include "src/lib/memory.h"
#include "src/lib/string.h"
#include "src/lib/util.h"
#include "src/user/syscall.h"
static void help(uint8_t argc, char **argv);
static void cd(uint8_t argc, char **argv);
#define PATH "/bin/"
#define PRINT_S(s) write(1, s, sizeof(s) - 1);
#define PRINT_D(s) write(1, s, string_length(s));
typedef void (*app_t)(uint8_t argc, char **argv);
typedef struct {
const char *name;
app_t app;
} app_entry_t;
static app_entry_t builtins[] = {
{"help", help},
{"cd", cd},
};
static void help(uint8_t argc, __attribute__((unused)) char **argv) {
if (argc > 1) {
PRINT_S("help: expects no arguments");
return;
}
PRINT_S("Available commands:\n");
for (uint64_t i = 0; i < sizeof(builtins) / sizeof(app_entry_t); i++) {
PRINT_D(builtins[i].name);
PRINT_S("\n");
}
}
static void cd(uint8_t argc, char **argv) {
if (argc != 2) {
PRINT_S("cd: requires a single path\n");
return;
}
if (chdir(argv[1]) == (uint64_t)-1) {
PRINT_S("cd: path does not exist\n");
}
}
static void print_prompt() {
char path[256];
uint8_t pl = getcwd(256, path);
char *components[16];
uint8_t cl = string_split(path, '/', 16, components);
PRINT_S("[")
PRINT_D(pl == 1 ? "/" : components[cl - 1]);
PRINT_S("]$ ");
}
static void execute(char *command) {
char *argv[16];
uint8_t argc = (uint8_t)string_split(command, ' ', 16, argv);
PRINT_S("\n");
if (string_equal(command, "^C")) {
print_prompt();
return;
}
if (string_equal(command, "^D")) {
exit(EXIT_CODE_OK);
}
uint8_t i;
for (i = 0; i < sizeof(builtins) / sizeof(app_entry_t); i++) {
if (string_equal(argv[0], builtins[i].name)) {
builtins[i].app(argc, argv);
break;
}
}
if (i == sizeof(builtins) / sizeof(app_entry_t)) {
uint64_t size = sizeof(PATH) + string_length(argv[0]) + 1;
char *path = memory_allocate(size);
memory_copy(PATH, sizeof(PATH), path);
memory_copy(argv[0], size - sizeof(PATH), path + sizeof(PATH) - 1);
uint64_t pid = spawn(path, argc, (const char **)argv);
memory_free(path);
if (pid == EXIT_CODE_NOT_FOUND) {
PRINT_S("shell: program not found\n");
} else {
waitpid(pid);
}
}
print_prompt();
}
uint64_t main() {
PRINT_D("Welcome to FreywarOS v" VERSION "!\n\n");
print_prompt();
char line[256];
uint64_t offset;
char chunk[64];
uint64_t received;
while (1) {
if ((received = read(0, sizeof(chunk), chunk))) {
for (uint64_t i = 0; i < received; i++) {
if (chunk[i] == '\n') {
line[offset] = '\0';
execute(line);
offset = 0;
} else if (offset < 255) {
line[offset++] = chunk[i];
}
}
}
}
return 0;
}

@ -1,13 +1,6 @@
#include "src/lib/memory.h"
#include "src/lib/string.h"
#include "src/lib/util.h"
#include "src/user/syscall.h"
#include <stdint.h>
static void help(uint8_t argc, char **argv);
static void cd(uint8_t argc, char **argv);
#define PATH "/bin/"
#define PRINT_S(s) write(1, s, sizeof(s) - 1);
#define PRINT_D(s) write(1, s, string_length(s));
@ -21,53 +14,6 @@ static char prompt[PROMPT_LENGTH + 1];
static uint8_t prompt_length = 0;
static uint8_t prompt_offset = 0;
typedef void (*app_t)(uint8_t argc, char **argv);
typedef struct {
const char *name;
app_t app;
} app_entry_t;
static app_entry_t builtins[] = {
{"help", help},
{"cd", cd},
};
static void help(uint8_t argc, __attribute__((unused)) char **argv) {
if (argc) {
PRINT_S("help: expects no arguments");
return;
}
PRINT_S("Available commands:\n");
for (uint64_t i = 0; i < sizeof(builtins) / sizeof(app_entry_t); i++) {
PRINT_D(builtins[i].name);
PRINT_S("\n");
}
}
static void cd(uint8_t argc, char **argv) {
if (argc != 2) {
PRINT_S("cd: requires a single path\n");
return;
}
if (chdir(argv[1]) == (uint64_t)-1) {
PRINT_S("cd: path does not exist\n");
}
}
static void print_prompt() {
char path[PROMPT_LENGTH];
uint8_t pl = getcwd(PROMPT_LENGTH, path);
char *components[16];
uint8_t cl = string_split(path, '/', 16, components);
PRINT_S("[")
PRINT_D(pl == 1 ? "/" : components[cl - 1]);
PRINT_S("]$ ");
}
static void on_home_pressed() {
if (!prompt_offset) {
return;
@ -105,42 +51,22 @@ static void on_end_pressed() {
}
static void on_enter_pressed() {
prompt[prompt_length] = '\0';
char *argv[16];
uint8_t argc = (uint8_t)string_split(prompt, ' ', 16, argv);
prompt[prompt_length] = '\n';
PRINT_S("\n");
write(2, prompt, prompt_length + 1);
uint8_t i;
for (i = 0; i < sizeof(builtins) / sizeof(app_entry_t); i++) {
if (string_equal(argv[0], builtins[i].name)) {
builtins[i].app(argc, argv);
break;
}
}
if (i == sizeof(builtins) / sizeof(app_entry_t)) {
uint64_t size = sizeof(PATH) + string_length(argv[0]) + 1;
char *path = memory_allocate(size);
memory_copy(PATH, sizeof(PATH), path);
memory_copy(argv[0], size - sizeof(PATH), path + sizeof(PATH) - 1);
if (spawn(path, argc, (const char **)argv) == EXIT_CODE_NOT_FOUND) {
PRINT_S("terminal: program not found\n");
}
memory_free(path);
}
prompt_length = prompt_offset = 0;
print_prompt();
}
static void on_cancel_pressed() {
PRINT_S("^C\n");
write(2, "^C\n", 3);
prompt_length = prompt_offset = 0;
print_prompt();
}
static void on_disconnect_pressed() {
PRINT_S("^D\n");
write(2, "^D\n", 3);
exit(EXIT_CODE_OK);
}
@ -270,10 +196,6 @@ uint64_t main() {
memory_set('\b', PROMPT_LENGTH, (char *)bs);
memory_set(' ', PROMPT_LENGTH, (char *)ws);
PRINT_D("Welcome to FreywarOS v" VERSION "!\n\n");
print_prompt();
while (1) {
char c;
if (read(0, 1, &c)) {

@ -30,6 +30,12 @@ spawn:
syscall
ret
global waitpid
waitpid:
mov rax, 5
syscall
ret
global open
open:
mov rax, 6

@ -11,7 +11,9 @@ uint64_t getcwd(uint64_t max, void *to);
uint64_t chdir(const char *path);
exit_code_t spawn(const char *path, uint64_t argc, const char **argv);
uint64_t spawn(const char *path, uint64_t argc, const char **argv);
exit_code_t waitpid(uint64_t pid);
uint64_t open(const char *path);

Loading…
Cancel
Save