diff options
Diffstat (limited to 'kernel/features')
-rw-r--r-- | kernel/features/fs.c | 184 | ||||
-rw-r--r-- | kernel/features/gui.c | 68 | ||||
-rw-r--r-- | kernel/features/load.c | 19 | ||||
-rw-r--r-- | kernel/features/proc.asm | 25 | ||||
-rw-r--r-- | kernel/features/proc.c | 104 | ||||
-rw-r--r-- | kernel/features/psf.c | 58 | ||||
-rw-r--r-- | kernel/features/syscall.c | 25 |
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(¤t->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, ¤t->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); +} |