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