aboutsummaryrefslogtreecommitdiff
path: root/kernel/features
diff options
context:
space:
mode:
authorMarvin Borner2020-08-09 16:51:01 +0200
committerMarvin Borner2020-08-09 16:51:01 +0200
commit162d024a53e1e31e00ff0b6f47dd4590edebc551 (patch)
tree711d3886c300dfaddffdafaa89b690b45eb2101d /kernel/features
parent79f2fa136f26a0b87917336e089485712ee49bd6 (diff)
Heavy restructuring of libc, kernel and apps
Diffstat (limited to 'kernel/features')
-rw-r--r--kernel/features/fs.c184
-rw-r--r--kernel/features/gui.c68
-rw-r--r--kernel/features/load.c19
-rw-r--r--kernel/features/proc.asm25
-rw-r--r--kernel/features/proc.c104
-rw-r--r--kernel/features/psf.c58
-rw-r--r--kernel/features/syscall.c25
7 files changed, 483 insertions, 0 deletions
diff --git a/kernel/features/fs.c b/kernel/features/fs.c
new file mode 100644
index 0000000..ab2a6eb
--- /dev/null
+++ b/kernel/features/fs.c
@@ -0,0 +1,184 @@
+// MIT License, Copyright (c) 2020 Marvin Borner
+// EXT2 based filesystem
+
+#include <assert.h>
+#include <def.h>
+#include <fs.h>
+#include <ide.h>
+#include <mem.h>
+#include <print.h>
+#include <str.h>
+
+void *buffer_read(int block)
+{
+ return ide_read(malloc(BLOCK_SIZE), block);
+}
+
+struct superblock *get_superblock()
+{
+ struct superblock *sb = buffer_read(EXT2_SUPER);
+ if (sb->magic != EXT2_MAGIC)
+ return NULL;
+ return sb;
+}
+
+struct bgd *get_bgd()
+{
+ return buffer_read(EXT2_SUPER + 1);
+}
+
+struct inode *get_inode(int i)
+{
+ struct superblock *s = get_superblock();
+ assert(s);
+ struct bgd *b = get_bgd();
+ assert(b);
+
+ int block_group = (i - 1) / s->inodes_per_group;
+ int index = (i - 1) % s->inodes_per_group;
+ int block = (index * INODE_SIZE) / BLOCK_SIZE;
+ b += block_group;
+
+ u32 *data = buffer_read(b->inode_table + block);
+ struct inode *in =
+ (struct inode *)((u32)data + (index % (BLOCK_SIZE / INODE_SIZE)) * INODE_SIZE);
+ return in;
+}
+
+u32 read_indirect(u32 indirect, u32 block_num)
+{
+ char *data = buffer_read(indirect);
+ return *(u32 *)((u32)data + block_num * 4);
+}
+
+void *read_inode(struct inode *in)
+{
+ assert(in);
+ if (!in)
+ return NULL;
+
+ int num_blocks = in->blocks / (BLOCK_SIZE / SECTOR_SIZE);
+
+ assert(num_blocks != 0);
+ if (!num_blocks)
+ return NULL;
+
+ u32 sz = BLOCK_SIZE * num_blocks;
+ void *buf = malloc(sz);
+ printf("Loading %dKiB\n", sz >> 10);
+ assert(buf != NULL);
+
+ int indirect;
+
+ int blocknum = 0;
+ char *data;
+ for (int i = 0; i < num_blocks; i++) {
+ if (i < 12) {
+ blocknum = in->block[i];
+ data = buffer_read(blocknum);
+ memcpy((u32 *)((u32)buf + i * BLOCK_SIZE), data, BLOCK_SIZE);
+ } else {
+ // TODO: Support doubly and triply pointers
+ indirect = in->block[12];
+ blocknum = read_indirect(indirect, i - 12);
+ data = buffer_read(blocknum);
+ memcpy((u32 *)((u32)buf + (i - 1) * BLOCK_SIZE), data, BLOCK_SIZE);
+ }
+ }
+
+ return buf;
+}
+
+void *read_file(char *path)
+{
+ if (path[0] != '/')
+ return 0;
+
+ path++;
+ u32 current_inode = EXT2_ROOT;
+
+ int i;
+ while (1) {
+ for (i = 0; path[i] != '/' && path[i] != '\0'; i++)
+ ;
+
+ if (path[i] == '\0')
+ break;
+
+ path[i] = '\0';
+ current_inode = find_inode(path, current_inode);
+ path[i] = '/';
+
+ if (current_inode == 0)
+ return 0;
+
+ path += i + 1;
+ }
+
+ u32 inode = find_inode(path, current_inode);
+ if (inode == 0)
+ return 0;
+
+ return read_inode(get_inode(inode));
+}
+
+int find_inode(const char *name, int dir_inode)
+{
+ if (!dir_inode)
+ return -1;
+
+ struct inode *i = get_inode(dir_inode);
+
+ char *buf = malloc(BLOCK_SIZE * i->blocks / 2);
+ memset(buf, 0, BLOCK_SIZE * i->blocks / 2);
+
+ for (u32 q = 0; q < i->blocks / 2; q++) {
+ char *data = buffer_read(i->block[q]);
+ memcpy((u32 *)((u32)buf + q * BLOCK_SIZE), data, BLOCK_SIZE);
+ }
+
+ struct dirent *d = (struct dirent *)buf;
+
+ u32 sum = 0;
+ do {
+ // Calculate the 4byte aligned size of each entry
+ sum += d->total_len;
+ if (strncmp((void *)d->name, name, d->name_len) == 0) {
+ free(buf);
+ return d->inode_num;
+ }
+ d = (struct dirent *)((u32)d + d->total_len);
+
+ } while (sum < (1024 * i->blocks / 2));
+ free(buf);
+ return -1;
+}
+
+void ls_root()
+{
+ struct inode *i = get_inode(2);
+
+ char *buf = malloc(BLOCK_SIZE * i->blocks / 2);
+
+ for (u32 q = 0; q < i->blocks / 2; q++) {
+ char *data = buffer_read(i->block[q]);
+ memcpy((u32 *)((u32)buf + q * BLOCK_SIZE), data, BLOCK_SIZE);
+ }
+
+ struct dirent *d = (struct dirent *)buf;
+
+ int sum = 0;
+ int calc = 0;
+ printf("\nRoot directory:\n");
+ do {
+ calc = (sizeof(struct dirent) + d->name_len + 4) & ~0x3;
+ sum += d->total_len;
+ printf("/%s\n", d->name);
+ if (d->total_len != calc && sum == 1024)
+ d->total_len = calc;
+
+ d = (struct dirent *)((u32)d + d->total_len);
+
+ } while (sum < 1024);
+ printf("\n");
+}
diff --git a/kernel/features/gui.c b/kernel/features/gui.c
new file mode 100644
index 0000000..d080cb1
--- /dev/null
+++ b/kernel/features/gui.c
@@ -0,0 +1,68 @@
+// MIT License, Copyright (c) 2020 Marvin Borner
+// Some GUI functions
+
+#include <fs.h>
+#include <gui.h>
+#include <psf.h>
+#include <str.h>
+#include <vesa.h>
+
+struct font *font;
+
+void gui_write_char(int x, int y, const u32 c[3], char ch)
+{
+ int pos = x * vbe_bpl + y * vbe_pitch;
+ char *draw = (char *)&fb[pos];
+
+ u32 stride = font->char_size / font->height;
+ for (int cy = 0; cy < font->height; cy++) {
+ for (int cx = 0; cx < font->width; cx++) {
+ u8 bits = font->chars[ch * font->char_size + cy * stride + cx / 8];
+ u8 bit = bits >> (7 - cx % 8) & 1;
+ if (bit) {
+ draw[vbe_bpl * cx] = c[2];
+ draw[vbe_bpl * cx + 1] = c[1];
+ draw[vbe_bpl * cx + 2] = c[0];
+ }
+ }
+ draw += vbe_pitch;
+ }
+}
+
+void gui_write(int x, int y, const u32 c[3], char *text)
+{
+ for (u32 i = 0; i < strlen(text); i++) {
+ gui_write_char(x + i * font->width, y, c, text[i]);
+ }
+}
+
+// Abstraction
+int x, y = 0;
+const u32 c[3] = { 0xff, 0xff, 0xff };
+void gui_term_write_char(char ch)
+{
+ if (x + font->width > vbe_width) {
+ x = 0;
+ y += font->height;
+ }
+
+ if (ch >= ' ' && ch <= '~') {
+ gui_write_char(x, y, c, ch);
+ x += font->width;
+ } else if (ch == '\n') {
+ x = 0;
+ y += font->height;
+ }
+}
+
+void gui_term_write(char *text)
+{
+ for (u32 i = 0; i < strlen(text); i++) {
+ gui_term_write_char(text[i]);
+ }
+}
+
+void gui_init(char *font_path)
+{
+ font = psf_parse(read_file(font_path));
+}
diff --git a/kernel/features/load.c b/kernel/features/load.c
new file mode 100644
index 0000000..cc1a094
--- /dev/null
+++ b/kernel/features/load.c
@@ -0,0 +1,19 @@
+// MIT License, Copyright (c) 2020 Marvin Borner
+
+#include <def.h>
+#include <fs.h>
+#include <load.h>
+#include <mem.h>
+#include <print.h>
+#include <proc.h>
+
+void bin_load(char *path, struct proc *proc)
+{
+ char *data = read_file(path);
+ u32 stack = (u32)malloc(0x1000) + 0x1000;
+
+ proc->regs.ebp = (u32)stack;
+ proc->regs.esp = (u32)stack;
+ proc->regs.useresp = (u32)stack;
+ proc->regs.eip = (u32)data;
+}
diff --git a/kernel/features/proc.asm b/kernel/features/proc.asm
new file mode 100644
index 0000000..3d6bbc4
--- /dev/null
+++ b/kernel/features/proc.asm
@@ -0,0 +1,25 @@
+%define USER_CODE_SEGMENT 0x18
+%define USER_DATA_SEGMENT 0x20
+%define RING3_MASK 0b11
+
+global proc_jump_userspace
+extern _esp
+extern _eip
+proc_jump_userspace:
+ mov ax, USER_DATA_SEGMENT | RING3_MASK
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+
+ mov eax, dword [_esp]
+ push USER_DATA_SEGMENT | RING3_MASK
+ push eax
+ pushf
+
+ sti
+
+ push USER_CODE_SEGMENT | RING3_MASK
+ push dword [_eip]
+
+ iret
diff --git a/kernel/features/proc.c b/kernel/features/proc.c
new file mode 100644
index 0000000..a14aaea
--- /dev/null
+++ b/kernel/features/proc.c
@@ -0,0 +1,104 @@
+// MIT License, Copyright (c) 2020 Marvin Borner
+
+#include <cpu.h>
+#include <interrupts.h>
+#include <load.h>
+#include <mem.h>
+#include <print.h>
+#include <proc.h>
+#include <str.h>
+#include <timer.h>
+
+u32 pid = 0;
+struct proc *root;
+struct proc *current;
+struct proc *last;
+
+void scheduler(struct regs *regs)
+{
+ if (current)
+ memcpy(&current->regs, regs, sizeof(struct regs));
+
+ timer_handler();
+
+ if (current && current->next)
+ current = current->next;
+ else
+ current = root;
+
+ while (current->state == PROC_ASLEEP)
+ if (!current->next)
+ current = root;
+ else
+ current = current->next;
+
+ /* proc_print(); */
+ memcpy(regs, &current->regs, sizeof(struct regs));
+
+ if (regs->cs != GDT_USER_CODE_OFFSET) {
+ regs->gs = GDT_USER_DATA_OFFSET;
+ regs->fs = GDT_USER_DATA_OFFSET;
+ regs->es = GDT_USER_DATA_OFFSET;
+ regs->ds = GDT_USER_DATA_OFFSET;
+ regs->ss = GDT_USER_DATA_OFFSET;
+ regs->cs = GDT_USER_CODE_OFFSET;
+ regs->eflags = EFLAGS_ALWAYS | EFLAGS_INTERRUPTS;
+ }
+ printf("%d", current->pid);
+}
+
+void proc_print()
+{
+ struct proc *proc = root;
+
+ printf("\n");
+ while (proc) {
+ printf("Process %d [%s]: %s\n", proc->pid,
+ proc->state == PROC_RUNNING ? "running" : "sleeping", proc->name);
+ proc = proc->next;
+ }
+ printf("\n");
+}
+
+void proc_attach(struct proc *proc)
+{
+ if (!last->next) {
+ last->next = proc;
+ } else {
+ struct proc *save = last;
+ while (save->next)
+ save = save->next;
+ save->next = proc;
+ }
+}
+
+struct proc *proc_make()
+{
+ struct proc *proc = malloc(sizeof(*proc));
+ proc->pid = pid++;
+ proc->state = PROC_RUNNING;
+ proc->next = NULL;
+
+ if (current)
+ proc_attach(proc);
+ last = proc;
+ return proc;
+}
+
+extern void proc_jump_userspace();
+
+u32 _esp, _eip;
+void proc_init()
+{
+ cli();
+ irq_install_handler(0, scheduler);
+
+ root = proc_make();
+ bin_load("/init", root);
+ strcpy(root->name, "root");
+ proc_print();
+
+ _eip = root->regs.eip;
+ _esp = root->regs.esp;
+ proc_jump_userspace();
+}
diff --git a/kernel/features/psf.c b/kernel/features/psf.c
new file mode 100644
index 0000000..adf2aa2
--- /dev/null
+++ b/kernel/features/psf.c
@@ -0,0 +1,58 @@
+// MIT License, Copyright (c) 2020 Marvin Borner
+// PSF parser
+
+#include <def.h>
+#include <gui.h>
+#include <mem.h>
+#include <print.h>
+#include <psf.h>
+#include <vesa.h>
+
+// Verifies the PSF magics
+// Returns the PSF version or 0
+int psf_verify(char *data)
+{
+ struct psf1_header *header1 = (struct psf1_header *)data;
+ struct psf2_header *header2 = (struct psf2_header *)data;
+
+ if (header1->magic[0] == PSF1_MAGIC_0 && header1->magic[1] == PSF1_MAGIC_1)
+ return 1;
+ else if (header2->magic[0] == PSF2_MAGIC_0 && header2->magic[1] == PSF2_MAGIC_1 &&
+ header2->magic[2] == PSF2_MAGIC_2 && header2->magic[3] == PSF2_MAGIC_3)
+ return 2;
+ else
+ return 0;
+}
+
+struct font *psf_parse(char *data)
+{
+ int version = psf_verify(data);
+
+ char *chars;
+ int height;
+ int width;
+ int char_size;
+
+ if (version == 1) {
+ chars = data + sizeof(struct psf1_header);
+ height = ((struct psf1_header *)data)->char_size;
+ width = 8;
+ char_size = ((struct psf1_header *)data)->char_size;
+ } else if (version == 2) {
+ chars = data + ((struct psf2_header *)data)->size;
+ height = ((struct psf2_header *)data)->height;
+ width = ((struct psf2_header *)data)->width;
+ char_size = ((struct psf2_header *)data)->char_size;
+ } else {
+ printf("Unknown font!\n");
+ return 0;
+ }
+
+ struct font *font = malloc(sizeof(*font));
+ font->chars = chars;
+ font->height = height;
+ font->width = width;
+ font->char_size = char_size;
+
+ return font;
+}
diff --git a/kernel/features/syscall.c b/kernel/features/syscall.c
new file mode 100644
index 0000000..3d012cf
--- /dev/null
+++ b/kernel/features/syscall.c
@@ -0,0 +1,25 @@
+// MIT License, Copyright (c) 2020 Marvin Borner
+
+#include <cpu.h>
+#include <interrupts.h>
+#include <load.h>
+#include <print.h>
+#include <proc.h>
+#include <str.h>
+
+int i = 0;
+void syscall_handler(struct regs *r)
+{
+ printf("[SYSCALL] %d\n", r->eax);
+
+ struct proc *a = proc_make();
+ bin_load(++i ? "/a" : "/b", a);
+ strcpy(a->name, "a");
+ proc_print();
+}
+
+void syscall_init()
+{
+ idt_set_gate(0x80, (u32)isr128, 0x08, 0x8E);
+ isr_install_handler(0x80, syscall_handler);
+}