parent
cbf21bafdc
commit
2aa39271da
@ -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); |
||||||
@ -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(); |
||||||
@ -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; |
||||||
|
} |
||||||
Loading…
Reference in new issue